a) the current situation of having two popular CoAP stacks that have highly ambiguous borders and compatibility lines is confusing (and getting worse because while there is some unification going on, at the same time features are added without regard for any unification attempts), and
b) to do any transports outside UDP and DTLS (and the DTLS is already subtly non-compliant), we’ll need some more driver-ish access to messages. As elaborated in my CoAP plumbing talk, lots of things can differ by transport, so all access to messages needs to go through functions that can eventually dispatch to a driver that serializes messages the way the transport needs it. There have been some changes already that reduce how often CoAP users need to reach into a coap_pkt_t struct (rather than treating it as an opaque item), but eventually those will all need to be gone before we can support CoAP over TCP, over BLE or OSCORE – at least without the applications specializing on the transport in the code, which is possible but I’d consider that an abomination (and am deeply saddened that that’s still the only way to use libOSCORE).
One point that I was only reminded of again on this weekend: We have a similarly invisible divide between “parsed CoAP packet” and “written CoAP packet”, which both use the same coap_pkt_t, but have different invariants, so that only some functions work with them. That, too, could need some cleanup; unlike on the nanocoap/gcoap side where I advocate unification, I’m unsure as to whether a clear distinction (different types, even if in the implementation it boils down to the same struct) wouldn’t be the better choice.
I agree, I’ve attempted to do this before but because nanoCoAP and GCoAP use coap_pkt_t in subtly different ways, this would solidify the divide between the two implementations (or require an even larger undertaking at unification).