Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net: coap: Fix response matching algorithm #84160

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

rlubos
Copy link
Contributor

@rlubos rlubos commented Jan 17, 2025

  • Add test case for matching pending replies with received responses.
    Cover corner cases that are failing with the current implementation.

  • Fix response matching algorithm

Fixes #84100

Add test case for matching pending replies with received responses.
Cover corner cases that are failing with the current implementation.

Signed-off-by: Robert Lubos <[email protected]>
The algorithm for matching request with response was incorrect, which
could lead to false matches (for example if request had a token, and
piggybacked reply had no token but matching message ID only, that would
still be counted as a match).

This commit fixes it. The request/reply matching is implemented based on
RFC now, with separate conditions for piggybacked/separate responses.

Signed-off-by: Robert Lubos <[email protected]>
id = coap_header_get_id(response);
tkl = coap_header_get_token(response, token);

if (type == COAP_TYPE_ACK || type == COAP_TYPE_RESET) {
piggybacked = true;
Copy link

Choose a reason for hiding this comment

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

A RST is always a empty message and no piggybacked response.

See RFC 7252, page 23, table 1

+----------+-----+-----+-----+-----+
|          | CON | NON | ACK | RST |
+----------+-----+-----+-----+-----+
| Request  | X   | X   | -   | -   |
| Response | X   | X   | X   | -   |
| Empty    | *   | -   | X   | X   |
+----------+-----+-----+-----+-----+
  Table 1: Usage of Message Types

if (memcmp(r->token, token, r->tkl) != 0) {
continue;
}
}
Copy link

Choose a reason for hiding this comment

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

if (piggybacked) {
   if ((r->id != id) {
      continue;
   }   
}

if ((r->tkl != tkl) {
   continue;
}   

if (r->tkl > 0) {
   if (memcmp(r->token, token, r->tkl) != 0) {
      continue;
   }
}

will use less code-duplicates.

@@ -1817,23 +1819,44 @@ struct coap_reply *coap_response_received(
return NULL;
}
Copy link

@boaks boaks Jan 17, 2025

Choose a reason for hiding this comment

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

	if (!is_empty_message(response) && coap_packet_is_request(response)) {
		/* Request can't be response */
		return NULL;
	}

The ! before is_empty_message is wrong. Both requests and empty messages can't be responses, see table above.

if (type == COAP_TYPE_ACK || type == COAP_TYPE_RESET) {
piggybacked = true;
}

for (i = 0, r = replies; i < len; i++, r++) {
int age;

if ((r->id == 0U) && (r->tkl == 0U)) {
Copy link

Choose a reason for hiding this comment

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

Is the message ID 0 used to indicate something special in the zephyr implementation?
if not, what is the purpose of this check?

FMPOV, it's wrong. I don't see this is related to RFC 7252.
Considering a separate response with empty token, assumptions about the used MIDs will fail. The other implementation may use 0 without considering any special processing, as I don't see one in RFC 7252

{ .id = 102, .type = COAP_TYPE_ACK, .match = NULL,
.token = { 1, 2, 3, 4 }, .tkl = 4 },
/* Separate reply, no token */
{ .id = 100, .type = COAP_TYPE_CON, .match = NULL },
Copy link

@boaks boaks Jan 17, 2025

Choose a reason for hiding this comment

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

For separate replies, there is no relation in the MIDs!
Using different MIDs for this test, e.g. 1000, would show that.

I'm not common with the used test framework, but for me this piggybacked response matches the first reply ".id = 100," (empty token).

"no token" never applies, that case is called "empty token" and all rules for tokens applies for empty tokens as well.

/* Separate reply, no token */
{ .id = 100, .type = COAP_TYPE_CON, .match = NULL },
/* Separate reply, no token 2 */
{ .id = 101, .type = COAP_TYPE_CON, .match = NULL },
Copy link

Choose a reason for hiding this comment

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

separate response, MID must be ignored, empty token matches first reply.

/* In a separate response, just the tokens of the
* response and original request MUST match.
*/
if ((r->tkl == 0) || (r->tkl != tkl) ||
Copy link

@boaks boaks Jan 17, 2025

Choose a reason for hiding this comment

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

If the code-duplicates are intended, then the (r->tkl == 0) is wrong and must be removed. That will then also change the results of the tests, as I commended there.

if ((r->tkl != tkl) || ((r->tkl > 0) && (memcmp(r->token, token, r->tkl) != 0))) {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

net: coap: Request/Response Matching Rules (RFC 7252 section-5.3.2) are not applied correctly
5 participants