Skip to content

net/unicoap: Gardening 01: RFC 7252 PDU Fixes and Corrections - #23084

Draft
carl-tud wants to merge 11 commits into
RIOT-OS:masterfrom
carl-tud:unicoap-gardening-01-rfc7252
Draft

carl-tud wants to merge 11 commits into
RIOT-OS:masterfrom
carl-tud:unicoap-gardening-01-rfc7252

Conversation

@carl-tud

@carl-tud carl-tud commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

This PR introduces support for extended tokens (https://www.rfc-editor.org/info/rfc8974/#name-extended-tokens), fixes missing ACKs from reliable resources, reduces overhead when ACKing and RSTing, and moves PDU message header definitions into a private C header.

Testing procedure

make -C tests/unittests -j tests-unicoap flash term

Issues/PRs references

Preparation for #23074 and #22277

Declaration of AI-Tools / LLMs usage:

AI-Tools / LLMs that were used are:

  • Claude Opus 5.5 helped write unit tests, then fixed things like excessive buffers and naming myself
    • TIL: you can write [upper .. lower] in designated initialisers
    • FYI: After having already written the extended token logic, I asked Claude to do it -- and it produced spaghetti code with like 100 different magic numbers and unnecessarily nested ifs.

@carl-tud
carl-tud requested a review from mguetschow November 7, 2026 21:13
@carl-tud carl-tud added Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors) Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation Impact: minor The PR is small in size and might only require a quick look of a knowledgeable reviewer Type: cleanup The issue proposes a clean-up / The PR cleans-up parts of the codebase / documentation Area: CoAP Area: Constrained Application Protocol implementations AI: Helped PR/Issue uses AI sparingly, e.g. code inline assistant, debugging with AI, etc. labels Nov 7, 2026
@github-actions github-actions Bot added Area: network Area: Networking Area: tests Area: tests and testing framework Area: sys Area: System labels Nov 7, 2026
Comment on lines 1312 to +1341
@@ -1314,8 +1335,10 @@ static inline ssize_t unicoap_pdu_build_rfc7252(uint8_t* pdu, size_t capacity,
const unicoap_message_properties_t* properties)
{
ssize_t res = 0;

if ((res = unicoap_pdu_build_header_rfc7252(pdu, capacity, message, properties)) < 0) {
if ((res = unicoap_pdu_build_header_rfc7252(pdu, capacity, message, properties)) < 0 ||
unlikely(!message)
) {
/* If failed, return. Also, if no message, there're no options and no payload, so return. */

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Purpose: be able to build PDU without needing to allocate a message structure, which can be larger than the actual on-the-wire PDU we're trying to create. Would be kinda laughable if a helper struct was bigger than the actual on-the-wire PDU...

Comment on lines +473 to +477
/* Require allocated message struct unless it's an empty message. This saves memory at the call
* site when sending an (empty) ACK or RST. */
assert(packet->message ||
_get_type(packet) == UNICOAP_TYPE_ACK ||
_get_type(packet) == UNICOAP_TYPE_RST);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same purpose here.

Comment on lines +659 to +683
static int _acknowledge_or_reset(unicoap_packet_t* packet, unicoap_rfc7252_message_type_t type)
{
packet->message->code = UNICOAP_CODE_EMPTY;
packet->message->options = NULL;
packet->message->payload = NULL;
packet->message->payload_size = 0;

packet->properties.token = NULL;
packet->properties.token_length = 0;

return (int)_build_and_send_pdu(packet, NULL);
/* This is all faster than going through the PDU builder for an empty message. And it saves us
* stack allocations that we'd need to prepare for an arbitrary message (more iolist structs and
* bigger header buffer for additional token. */
unicoap_rfc7252_header_t empty_message = {
.version = UNICOAP_COAP_VERSION_1,
.code = UNICOAP_CODE_EMPTY,
};

iolist_t vector = {
.iol_base = &empty_message,
.iol_len = sizeof(empty_message)
};

unicoap_rfc7252_header_set_message_id(&empty_message, _get_id(packet));
unicoap_rfc7252_header_set_type(&empty_message, type);

/* We do not reconnect here for messaging-layer-only PDUs (empty ACKs and RSTs).
* Reason: If we send an ACK or RST that means we got a message before. This implies
* there was a DTLS session. RFC 7252 mandates ACKs and RSTs must be sent within the
* same epoch. A new DTLS session always leads to a new epoch. So sending an ACK or RST
* after reconnecting is pointless. Hence, we do not need to call _connect here and can
* just send, possibly getting an error from the DTLS transport layer if there's no session. */
return _sendv(&vector, packet->remote, packet->local, _packet_get_dtls_session(packet));

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Faster than going through the PDU builder, allocating iolists, a scratch buffer, etc. The message we're trying to send is 4 bytes, so let's not be silly.

Comment on lines +845 to +850
if (_get_type(packet) == UNICOAP_TYPE_CON) {
MESSAGING_7252_DEBUG(UNICOAP_MESSAGE_ID_FORMAT "have not ACKed yet\n", _get_id(packet));
assert(_state._unacknowledged_packet == NULL);
_state._unacknowledged_packet = packet;
/* TODO: Deferred responses (proxy) require space for more than one outstanding ACK. */
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is safe because state access is synchronised by an event_queue_t.

Comment on lines -837 to -841
unicoap_message_t* message = packet->message;
unicoap_message_t m = *packet->message;
packet->message = &m;
_acknowledge(packet);
packet->message = message;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overhead: q.e.d.

@@ -0,0 +1,207 @@
/*

@carl-tud carl-tud Nov 7, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically, I can see people wanting to do some CoAP PDU trickery in the future, and providing a header here that exists but is hidden prevent's me from having that headache in the future.

@carl-tud
carl-tud force-pushed the unicoap-gardening-01-rfc7252 branch from 924cd88 to 021d3eb Compare November 7, 2026 21:25
@github-actions github-actions Bot added the Area: Kconfig Area: Kconfig integration label Nov 7, 2026
@carl-tud carl-tud added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Nov 7, 2026
@riot-ci

riot-ci commented Nov 7, 2026 •

Copy link
Copy Markdown

Murdock results

❌ FAILED

a5bb29f fixup! token bit width

Success Failures Total Runtime
6290 1 13599 05m:02s
Build failures (1)
Application Target Toolchain Runtime (s) Worker
examples/networking/coap/unicoap_client atxmega-a1u-xpro gnu 2.53 mobi5

Artifacts

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI: Helped PR/Issue uses AI sparingly, e.g. code inline assistant, debugging with AI, etc. Area: CoAP Area: Constrained Application Protocol implementations Area: Kconfig Area: Kconfig integration Area: network Area: Networking Area: sys Area: System Area: tests Area: tests and testing framework CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Impact: minor The PR is small in size and might only require a quick look of a knowledgeable reviewer Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors) Type: cleanup The issue proposes a clean-up / The PR cleans-up parts of the codebase / documentation Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants