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

RFC8768: Add in support for CoAP Option Hop Limit loop detection #476

Merged
merged 1 commit into from
Sep 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,11 @@ coap_dtls_session_update_mtu \
coap_dtls_shutdown \
coap_dtls_startup \
coap_epoll_ctl_mod \
coap_insert_option \
coap_io_do_events \
coap_mfree_endpoint \
coap_packet_extract_pbuf \
coap_pdu_check_resize \
coap_pdu_from_pbuf \
coap_session_mfree \
coap_session_new_dtls_session \
Expand All @@ -199,6 +201,7 @@ coap_tls_new_client_session \
coap_tls_new_server_session \
coap_tls_read \
coap_tls_write \
coap_update_option \
"

# This helper is called by libcoap-$(LIBCOAP_API_VERSION).{map,sym} to see if
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ The following RFCs are supported
* RFC8132: PATCH and FETCH Methods for the Constrained Application Protocol (CoAP)

* RFC8323: CoAP (Constrained Application Protocol) over TCP, TLS, and WebSockets
[No WebSockets support]

* RFC8768: Constrained Application Protocol (CoAP) Hop-Limit Option

There is (D)TLS support for the following libraries

Expand Down
65 changes: 47 additions & 18 deletions examples/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,15 +251,16 @@ clear_obs(coap_context_t *ctx, coap_session_t *session) {

for (option = optlist; option; option = option->next ) {
switch (option->number) {
case COAP_OPTION_URI_PORT :
case COAP_OPTION_URI_PATH :
case COAP_OPTION_URI_QUERY :
case COAP_OPTION_URI_PORT : /* 7 */
case COAP_OPTION_URI_PATH : /* 11 */
case COAP_OPTION_URI_QUERY : /* 15 */
case COAP_OPTION_HOP_LIMIT : /* 16 */
if (!coap_add_option(pdu, option->number, option->length,
option->data)) {
goto error;
}
break;
default:
default:
;
}
}
Expand Down Expand Up @@ -453,13 +454,14 @@ message_handler(struct coap_context_t *ctx,
/* create pdu with request for next block */
pdu = coap_new_request(ctx, session, method, NULL, NULL, 0); /* first, create bare PDU w/o any option */
if ( pdu ) {
/* add URI components from optlist */
/* add URI components from optlist in ascending order */
for (option = optlist; option; option = option->next ) {
switch (option->number) {
case COAP_OPTION_URI_HOST :
case COAP_OPTION_URI_PORT :
case COAP_OPTION_URI_PATH :
case COAP_OPTION_URI_QUERY :
case COAP_OPTION_URI_HOST : /* 3 */
case COAP_OPTION_URI_PORT : /* 7 */
case COAP_OPTION_URI_PATH : /* 11 */
case COAP_OPTION_URI_QUERY : /* 15 */
case COAP_OPTION_HOP_LIMIT : /* 16 */
coap_add_option(pdu, option->number, option->length,
option->data);
break;
Expand Down Expand Up @@ -550,11 +552,12 @@ message_handler(struct coap_context_t *ctx,
/* add URI components from optlist */
for (option = optlist; option; option = option->next ) {
switch (option->number) {
case COAP_OPTION_URI_HOST :
case COAP_OPTION_URI_PORT :
case COAP_OPTION_URI_PATH :
case COAP_OPTION_CONTENT_FORMAT :
case COAP_OPTION_URI_QUERY :
case COAP_OPTION_URI_HOST : /* 3 */
case COAP_OPTION_URI_PORT : /* 7 */
case COAP_OPTION_URI_PATH : /* 11 */
case COAP_OPTION_CONTENT_FORMAT : /* 12 */
case COAP_OPTION_URI_QUERY : /* 15 */
case COAP_OPTION_HOP_LIMIT : /* 16 */
coap_add_option(pdu, option->number, option->length,
option->data);
break;
Expand Down Expand Up @@ -641,8 +644,8 @@ usage( const char *program, const char *version) {
"%s\n\n"
"Usage: %s [-a addr] [-b [num,]size] [-e text] [-f file] [-l loss]\n"
"\t\t[-m method] [-o file] [-p port] [-r] [-s duration] [-t type]\n"
"\t\t[-v num] [-A type] [-B seconds] [-K interval] [-N] [-O num,text]\n"
"\t\t[-P addr[:port]] [-T token] [-U]\n"
"\t\t[-v num] [-A type] [-B seconds] [-H hoplimit] [-K interval] [-N]\n"
"\t\t[-O num,text] [-P addr[:port]] [-T token] [-U]\n"
"\t\t[[-h match_hint_file] [-k key] [-u user]]\n"
"\t\t[[-c certfile] [-j keyfile] [-C cafile] [-J pkcs11_pin]\n"
"\t\t[-R root_cafile] [-S match_pki_sni_file]] URI\n"
Expand Down Expand Up @@ -674,6 +677,9 @@ usage( const char *program, const char *version) {
"\t-A type\t\tAccepted media type\n"
"\t-B seconds\tBreak operation after waiting given seconds\n"
"\t \t\t(default is %d)\n"
"\t-H hoplimit\tSet the Hop Limit count to hoplimit for proxies. Must\n"
"\t \t\thave a value between 1 and 255 inclusive.\n"
"\t \t\tDefault is '16'\n"
"\t-K interval\tsend a ping after interval seconds of inactivity\n"
"\t-N \t\tSend NON-confirmable message\n"
"\t-O num,text\tAdd option num with contents text to request. If the\n"
Expand Down Expand Up @@ -722,7 +728,8 @@ usage( const char *program, const char *version) {
"\t \t\t'trusted' for the verification.\n"
"\t \t\tAlternatively, this can point to a directory containing\n"
"\t \t\ta set of CA PEM files\n"
"\n"
);
fprintf( stderr,
"Examples:\n"
"\tcoap-client -m get coap://[::1]/\n"
"\tcoap-client -m get coap://[::1]/.well-known/core\n"
Expand Down Expand Up @@ -788,6 +795,24 @@ cmdline_content_type(char *arg, uint16_t key) {
}
}

static int
cmdline_hop_limit(char *arg) {
coap_optlist_t *node;
uint32_t value;
uint8_t buf[4];

value = strtol(arg, NULL, 10);
if (value < 1 || value > 255) {
return 0;
}
node = coap_new_optlist(COAP_OPTION_HOP_LIMIT, coap_encode_var_safe(buf, sizeof(buf), value), buf);
if (node) {
coap_insert_optlist(&optlist, node);
}
return 1;
}


static uint16_t
get_default_port(const coap_uri_t *u) {
return coap_uri_scheme_is_secure(u) ? COAPS_DEFAULT_PORT : COAP_DEFAULT_PORT;
Expand Down Expand Up @@ -1533,7 +1558,7 @@ main(int argc, char **argv) {
struct sigaction sa;
#endif

while ((opt = getopt(argc, argv, "a:b:c:e:f:h:j:k:l:m:o:p:rs:t:u:v:A:B:C:J:K:NO:P:R:T:U")) != -1) {
while ((opt = getopt(argc, argv, "a:b:c:e:f:h:j:k:l:m:o:p:rs:t:u:v:A:B:C:J:K:H:NO:P:R:T:U")) != -1) {
switch (opt) {
case 'a':
strncpy(node_str, optarg, NI_MAXHOST - 1);
Expand Down Expand Up @@ -1643,6 +1668,10 @@ main(int argc, char **argv) {
exit(1);
}
break;
case 'H':
if (!cmdline_hop_limit(optarg))
fprintf(stderr, "Hop Limit has to be > 0 and < 256\n");
break;
default:
usage( argv[0], LIBCOAP_PACKAGE_VERSION );
exit( 1 );
Expand Down
123 changes: 89 additions & 34 deletions include/coap2/pdu.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ struct coap_session_t;
#define COAP_DEFAULT_MTU 1152
#endif /* COAP_DEFAULT_MTU */

#ifndef COAP_DEFAULT_HOP_LIMIT
#define COAP_DEFAULT_HOP_LIMIT 16
#endif /* COAP_DEFAULT_HOP_LIMIT */

/* TCP Message format constants, do not modify */
#define COAP_MESSAGE_SIZE_OFFSET_TCP8 13
#define COAP_MESSAGE_SIZE_OFFSET_TCP16 269 /* 13 + 256 */
Expand Down Expand Up @@ -87,41 +91,60 @@ typedef enum coap_request_t {
} coap_request_t;

/*
* CoAP option types (be sure to update coap_option_check_critical() when
* adding options
* CoAP option types (be sure to update coap_option_check_critical() and
* coap_add_option() when adding options
*/

#define COAP_OPTION_IF_MATCH 1 /* C, opaque, 0-8 B, (none) */
#define COAP_OPTION_URI_HOST 3 /* C, String, 1-255 B, destination address */
#define COAP_OPTION_ETAG 4 /* E, opaque, 1-8 B, (none) */
#define COAP_OPTION_IF_NONE_MATCH 5 /* empty, 0 B, (none) */
#define COAP_OPTION_URI_PORT 7 /* C, uint, 0-2 B, destination port */
#define COAP_OPTION_LOCATION_PATH 8 /* E, String, 0-255 B, - */
#define COAP_OPTION_URI_PATH 11 /* C, String, 0-255 B, (none) */
#define COAP_OPTION_CONTENT_FORMAT 12 /* E, uint, 0-2 B, (none) */
#define COAP_OPTION_CONTENT_TYPE COAP_OPTION_CONTENT_FORMAT
#define COAP_OPTION_MAXAGE 14 /* E, uint, 0--4 B, 60 Seconds */
#define COAP_OPTION_URI_QUERY 15 /* C, String, 1-255 B, (none) */
#define COAP_OPTION_ACCEPT 17 /* C, uint, 0-2 B, (none) */
#define COAP_OPTION_LOCATION_QUERY 20 /* E, String, 0-255 B, (none) */
#define COAP_OPTION_SIZE2 28 /* E, uint, 0-4 B, (none) */
#define COAP_OPTION_PROXY_URI 35 /* C, String, 1-1034 B, (none) */
#define COAP_OPTION_PROXY_SCHEME 39 /* C, String, 1-255 B, (none) */
#define COAP_OPTION_SIZE1 60 /* E, uint, 0-4 B, (none) */

/* option types from RFC 7641 */

#define COAP_OPTION_OBSERVE 6 /* E, empty/uint, 0 B/0-3 B, (none) */
#define COAP_OPTION_SUBSCRIPTION COAP_OPTION_OBSERVE

/* selected option types from RFC 7959 */

#define COAP_OPTION_BLOCK2 23 /* C, uint, 0--3 B, (none) */
#define COAP_OPTION_BLOCK1 27 /* C, uint, 0--3 B, (none) */

/* selected option types from RFC 7967 */
/*
* The C, U, and N flags indicate the properties
* Critical, Unsafe, and NoCacheKey, respectively.
* If U is set, then N has no meaning as per
* https://tools.ietf.org/html/rfc7252#section-5.10
* and is set to a -.
*
* Separately, R is for the options that can be repeated
*
* The least significant byte of the option is set as followed
* as per https://tools.ietf.org/html/rfc7252#section-5.4.6
*
* 0 1 2 3 4 5 6 7
* --+---+---+---+---+---+---+---+
* | NoCacheKey| U | C |
* --+---+---+---+---+---+---+---+
*
* https://tools.ietf.org/html/rfc8613#section-4 goes on to define E, I and U
obgm marked this conversation as resolved.
Show resolved Hide resolved
* properties Encrypted and Integrity Protected, Integrity Protected Only and
* Unprotected respectively. Integretity Protected Only is not currently used.
*
* An Option is tagged with CUNREIU with any of the letters replaced with _ if
* not set, or - for N if U is set (see above) for aiding understanding of the
* Option.
*/

#define COAP_OPTION_NORESPONSE 258 /* N, uint, 0--1 B, 0 */
#define COAP_OPTION_IF_MATCH 1 /* C__RE__, opaque, 0-8 B, RFC7252 */
#define COAP_OPTION_URI_HOST 3 /* CU-___U, String, 1-255 B, RFC7252 */
#define COAP_OPTION_ETAG 4 /* ___RE__, opaque, 1-8 B, RFC7252 */
#define COAP_OPTION_IF_NONE_MATCH 5 /* C___E__, empty, 0 B, RFC7252 */
#define COAP_OPTION_OBSERVE 6 /* _U-_E_U, empty/uint,0/0-3 B, RFC7641 */
#define COAP_OPTION_URI_PORT 7 /* CU-___U, uint, 0-2 B, RFC7252 */
#define COAP_OPTION_LOCATION_PATH 8 /* ___RE__, String, 0-255 B, RFC7252 */
#define COAP_OPTION_OSCORE 9 /* C_____U, *, 0-255 B, RFC8613 */
#define COAP_OPTION_URI_PATH 11 /* CU-RE__, String, 0-255 B, RFC7252 */
#define COAP_OPTION_CONTENT_FORMAT 12 /* ____E__, uint, 0-2 B, RFC7252 */
#define COAP_OPTION_CONTENT_TYPE COAP_OPTION_CONTENT_FORMAT
/* COAP_OPTION_MAXAGE default 60 seconds if not set */
#define COAP_OPTION_MAXAGE 14 /* _U-_E_U, uint, 0-4 B, RFC7252 */
#define COAP_OPTION_URI_QUERY 15 /* CU-RE__, String, 1-255 B, RFC7252 */
#define COAP_OPTION_HOP_LIMIT 16 /* ______U, uint, 1 B, RFC8768 */
#define COAP_OPTION_ACCEPT 17 /* C___E__, uint, 0-2 B, RFC7252 */
#define COAP_OPTION_LOCATION_QUERY 20 /* ___RE__, String, 0-255 B, RFC7252 */
#define COAP_OPTION_BLOCK2 23 /* CU-_E_U, uint, 0-3 B, RFC7959 */
#define COAP_OPTION_BLOCK1 27 /* CU-_E_U, uint, 0-3 B, RFC7959 */
#define COAP_OPTION_SIZE2 28 /* __N_E_U, uint, 0-4 B, RFC7959 */
#define COAP_OPTION_PROXY_URI 35 /* CU-___U, String, 1-1034 B, RFC7252 */
#define COAP_OPTION_PROXY_SCHEME 39 /* CU-___U, String, 1-255 B, RFC7252 */
#define COAP_OPTION_SIZE1 60 /* __N_E_U, uint, 0-4 B, RFC7252 */
#define COAP_OPTION_NORESPONSE 258 /* _U-_E_U, uint, 0-1 B, RFC7967 */

#define COAP_MAX_OPT 65535 /**< the highest option number we know */

Expand Down Expand Up @@ -273,7 +296,7 @@ typedef struct coap_pdu_t {
uint8_t type; /**< message type */
uint8_t code; /**< request method (value 1--31) or response code (value 64-255) */
uint8_t max_hdr_size; /**< space reserved for protocol-specific header */
uint8_t hdr_size; /**< actaul size used for protocol-specific header */
uint8_t hdr_size; /**< actual size used for protocol-specific header */
uint8_t token_length; /**< length of Token */
uint16_t tid; /**< transaction id, if any, in regular host byte order */
uint16_t max_delta; /**< highest option number */
Expand Down Expand Up @@ -359,6 +382,19 @@ coap_pdu_init(uint8_t type, uint8_t code, uint16_t tid, size_t size);
*/
int coap_pdu_resize(coap_pdu_t *pdu, size_t new_size);

/**
* Dynamically grows the size of @p pdu to @p new_size if needed. The new size
* must not exceed the PDU's configure maximum size. On success, this
* function returns 1, otherwise 0.
*
* Internal use only.
*
* @param pdu The PDU to resize.
* @param new_size The new size in bytes.
* @return 1 if the operation succeeded, 0 otherwise.
*/
int coap_pdu_check_resize(coap_pdu_t *pdu, size_t new_size);

/**
* Clears any contents from @p pdu and resets @c used_size,
* and @c data pointers. @c max_size is set to @p size, any
Expand Down Expand Up @@ -489,6 +525,25 @@ uint8_t *coap_add_option_later(coap_pdu_t *pdu,
uint16_t type,
size_t len);


/**
* Inserts option of given type in the @p pdu with the appropriate data.
* The option will be inserted in the appropriate place in the options in the pdu.
*
* Internal use only.
*/
size_t coap_insert_option(coap_pdu_t *pdu, uint16_t type,
size_t len, const uint8_t *data);

/**
* Updates existing first option of given type in the @p pdu with the new data.
*
* Internal use only.
*/
int coap_update_option(coap_pdu_t *pdu,
uint16_t type,
size_t len,
const uint8_t *data);
/**
* Adds given data to the pdu that is passed as first parameter. Note that the
* PDU's data is destroyed by coap_add_option(). coap_add_data() must be called
Expand All @@ -500,7 +555,7 @@ int coap_add_data(coap_pdu_t *pdu,

/**
* Adds given data to the pdu that is passed as first parameter but does not
* copyt it. Note that the PDU's data is destroyed by coap_add_option().
* copy it. Note that the PDU's data is destroyed by coap_add_option().
* coap_add_data() must be have been called once for this PDU, otherwise the
* result is undefined.
* The actual data must be copied at the returned location.
Expand Down
9 changes: 7 additions & 2 deletions man/coap-client.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ SYNOPSIS
--------
*coap-client* [*-a* addr] [*-b* [num,]size] [*-e* text] [*-f* file] [*-l* loss]
[*-m* method] [*-o* file] [*-p* port] [*-r*] [*-s duration*]
[*-t* type] [*-v* num] [*-A* type] [*-B* seconds] [*-K* interval]
[*-N*] [*-O* num,text] [*-P* addr[:port]] [*-T* token] [*-U*]
[*-t* type] [*-v* num] [*-A* type] [*-B* seconds]
[*-H* hoplimit] [*-K* interval] [*-N*] [*-O* num,text]
[*-P* addr[:port]] [*-T* token] [*-U*]
[[*-h* match_hint_file] [*-k* key] [*-u* user]]
[[*-c* certfile] [*-j* keyfile] [*-C* cafile] [*-J* pkcs11_pin]
[*-R* root_cafile]] URI
Expand Down Expand Up @@ -109,6 +110,10 @@ OPTIONS - General
*-B* seconds::
Break operation after waiting given seconds (default is 90).

*-H* hoplimit::
Set the Hop Limit count to hoplimit for proxies. Must have a value between
1 and 255 inclusive. Default is '16'.

*-K* interval::
Send a ping after interval seconds of inactivity.
If not specified (or 0), keep-alive is disabled (default).
Expand Down
2 changes: 2 additions & 0 deletions man/coap.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ See

"RFC8323: CoAP (Constrained Application Protocol) over TCP, TLS, and WebSockets"

"RFC8768: Constrained Application Protocol (CoAP) Hop-Limit Option"

for further information.

BUGS
Expand Down