From: Jin-Seong Kim Date: Mon, 20 Mar 2017 06:26:39 +0000 (+0900) Subject: netutils/er-coap: add to support TCP/TLS as per the RFC X-Git-Tag: 1.1_Public_Release~614^2~187 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1fcee7646abe5caba5db02e4710b8e16e57b3595;p=rtos%2Ftinyara.git netutils/er-coap: add to support TCP/TLS as per the RFC RFC reference : https://tools.ietf.org/html/draft-ietf-core-coap-tcp-tls-02 - patch is available from https://github.com/artikcloud/artikcloud-lwm2m-c - Author: Gregory Lemercier Implementation required the following modifications: - Passing the token as an argument to the registration frame - Implementation of the "nibble" variable length header in CoAP for TCP as detailed in the current draft of the specification. Note that this might change later as the RFC undergoes changes Change-Id: Ie94defbc30272c6a1e88c09dc246ebfd09d3bb48 Signed-off-by: Jin-Seong Kim --- diff --git a/apps/include/netutils/er-coap/er-coap-13.h b/apps/include/netutils/er-coap/er-coap-13.h index 430dba2..818cfef 100644 --- a/apps/include/netutils/er-coap/er-coap-13.h +++ b/apps/include/netutils/er-coap/er-coap-13.h @@ -57,9 +57,12 @@ #define COAP_RESPONSE_TIMEOUT 2 #define COAP_MAX_RETRANSMIT 4 +#define COAP_TCP_SHIM_LEN 4 /* 32bit Length shim header for TCP */ #define COAP_HEADER_LEN 4 /* | version:0x03 type:0x0C tkl:0xF0 | code | mid:0x00FF | mid:0xFF00 | */ #define COAP_ETAG_LEN 8 /* The maximum number of bytes for the ETag */ #define COAP_TOKEN_LEN 8 /* The maximum number of bytes for the Token */ +#define COAP_OPTIONS_MARKER_LEN 1 /* Length of marker (0xFF) between options and payload */ + #define COAP_MAX_ACCEPT_NUM 2 /* The maximum number of accept preferences to parse/store */ #define COAP_MAX_OPTION_HEADER_LEN 5 @@ -79,14 +82,14 @@ */ #ifndef COAP_MAX_HEADER_SIZE /* Hdr CoT Age Tag Obs Tok Blo strings */ -#define COAP_MAX_HEADER_SIZE (4 + 3 + 5 + 1+COAP_ETAG_LEN + 3 + 1+COAP_TOKEN_LEN + 4 + 30) /* 70 */ +#define COAP_MAX_HEADER_SIZE (COAP_HEADER_LEN + 3 + 5 + 1+COAP_ETAG_LEN + 3 + 1+COAP_TOKEN_LEN + 4 + 30) /* 70 */ #endif /* COAP_MAX_HEADER_SIZE */ #define COAP_MAX_PACKET_SIZE (COAP_MAX_HEADER_SIZE + REST_MAX_CHUNK_SIZE) /* 0/14 48 for IPv6 (28 for IPv4) */ -// #if COAP_MAX_PACKET_SIZE > (UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPUDPH_LEN) +#if COAP_MAX_PACKET_SIZE > (UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPUDPH_LEN) //#error "UIP_CONF_BUFFER_SIZE too small for REST_MAX_CHUNK_SIZE" -// #endif +#endif /* Bitmap for set options */ @@ -98,6 +101,14 @@ enum { OPTION_MAP_SIZE = sizeof(uint8_t) * 8 }; #define MIN(a, b) ((a) < (b)? (a) : (b)) #endif /* MIN */ +/* CoAP protocols */ +typedef enum { + COAP_UDP, + COAP_UDP_DTLS, + COAP_TCP, + COAP_TCP_TLS +} coap_protocol_t; + /* CoAP message types */ typedef enum { COAP_TYPE_CON, /* confirmables */ @@ -196,8 +207,7 @@ typedef enum { APPLICATION_FASTINFOSET = 48, APPLICATION_SOAP_FASTINFOSET = 49, APPLICATION_JSON = 50, - APPLICATION_X_OBIX_BINARY = 51, - APPLICATION_FILLER=65535, + APPLICATION_X_OBIX_BINARY = 51 } coap_content_type_t; typedef struct _multi_option_t { @@ -217,6 +227,7 @@ typedef struct { uint16_t mid; uint8_t options[COAP_OPTION_PROXY_URI / OPTION_MAP_SIZE + 1]; /* Bitmap to check if option is set */ + uint16_t options_len; coap_content_type_t content_type; /* Parse options once and store; allows setting options in random order */ uint32_t max_age; @@ -253,6 +264,8 @@ typedef struct { uint16_t payload_len; uint8_t *payload; + coap_protocol_t protocol; + } coap_packet_t; /* Option format serialization*/ @@ -316,10 +329,10 @@ extern const char *coap_error_message; uint16_t coap_get_mid(void); -void coap_init_message(void *packet, coap_message_type_t type, uint8_t code, uint16_t mid); +void coap_init_message(void *packet, coap_protocol_t protocol, coap_message_type_t type, uint8_t code, uint16_t mid); size_t coap_serialize_get_size(void *packet); size_t coap_serialize_message(void *packet, uint8_t *buffer); -coap_status_t coap_parse_message(void *request, uint8_t *data, uint16_t data_len); +coap_status_t coap_parse_message(void *request, coap_protocol_t protocol, uint8_t *data, uint16_t data_len); void coap_free_header(void *packet); char * coap_get_multi_option_as_string(multi_option_t * option); diff --git a/apps/include/netutils/er-coap/er-coap-conf.h b/apps/include/netutils/er-coap/er-coap-conf.h index b5fcd89..e0ae6b1 100644 --- a/apps/include/netutils/er-coap/er-coap-conf.h +++ b/apps/include/netutils/er-coap/er-coap-conf.h @@ -84,22 +84,4 @@ /* Interval in notifies in which NON notifies are changed to CON notifies to check client. */ #define COAP_OBSERVE_REFRESH_INTERVAL 20 -/** - * @brief This definition describes that CoAP message will be sent over TCP - */ -#ifdef CONFIG_NETUTILS_ERCOAP_TCP_SUPPORT -#define COAP_TCP_SUPPORT 1 -#else -#define COAP_TCP_SUPPORT 0 -#endif - -/** - * @brief This definition describes that CoAP library supports TLS - */ -#ifdef CONFIG_NETUTILS_ERCOAP_TLS_SUPPORT -#define COAP_TLS_SUPPORT 1 -#else -#define COAP_TLS_SUPPORT 0 -#endif - #endif /* ER_COAP_CONF_H_ */ diff --git a/apps/netutils/er-coap/er-coap-13.c b/apps/netutils/er-coap/er-coap-13.c index 8771522..09bfd8f 100644 --- a/apps/netutils/er-coap/er-coap-13.c +++ b/apps/netutils/er-coap/er-coap-13.c @@ -387,13 +387,14 @@ coap_get_mid() /*- MEASSAGE PROCESSING -------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/ void -coap_init_message(void *packet, coap_message_type_t type, uint8_t code, uint16_t mid) +coap_init_message(void *packet, coap_protocol_t protocol, coap_message_type_t type, uint8_t code, uint16_t mid) { coap_packet_t *const coap_pkt = (coap_packet_t *) packet; /* Important thing */ memset(coap_pkt, 0, sizeof(coap_packet_t)); + coap_pkt->protocol = protocol; coap_pkt->type = type; coap_pkt->code = code; coap_pkt->mid = mid; @@ -415,37 +416,38 @@ coap_free_header(void *packet) /*-----------------------------------------------------------------------------------*/ size_t coap_serialize_get_size(void *packet) { + if (packet == NULL) return 0; + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; size_t length = 0; - length = COAP_HEADER_LEN + coap_pkt->payload_len + coap_pkt->token_len; - + coap_pkt->options_len = 0; if (IS_OPTION(coap_pkt, COAP_OPTION_IF_MATCH)) { - length += COAP_MAX_OPTION_HEADER_LEN + coap_pkt->if_match_len; + coap_pkt->options_len += COAP_MAX_OPTION_HEADER_LEN + coap_pkt->if_match_len; } if (IS_OPTION(coap_pkt, COAP_OPTION_URI_HOST)) { - length += COAP_MAX_OPTION_HEADER_LEN + coap_pkt->uri_host_len; + coap_pkt->options_len += COAP_MAX_OPTION_HEADER_LEN + coap_pkt->uri_host_len; } if (IS_OPTION(coap_pkt, COAP_OPTION_ETAG)) { - length += COAP_MAX_OPTION_HEADER_LEN + coap_pkt->etag_len; + coap_pkt->options_len += COAP_MAX_OPTION_HEADER_LEN + coap_pkt->etag_len; } if (IS_OPTION(coap_pkt, COAP_OPTION_IF_NONE_MATCH)) { // can be stored in extended fields - length += COAP_MAX_OPTION_HEADER_LEN; + coap_pkt->options_len += COAP_MAX_OPTION_HEADER_LEN; } if (IS_OPTION(coap_pkt, COAP_OPTION_OBSERVE)) { // can be stored in extended fields - length += COAP_MAX_OPTION_HEADER_LEN; + coap_pkt->options_len += COAP_MAX_OPTION_HEADER_LEN; } if (IS_OPTION(coap_pkt, COAP_OPTION_URI_PORT)) { // can be stored in extended fields - length += COAP_MAX_OPTION_HEADER_LEN; + coap_pkt->options_len += COAP_MAX_OPTION_HEADER_LEN; } if (IS_OPTION(coap_pkt, COAP_OPTION_LOCATION_PATH)) { @@ -453,7 +455,7 @@ size_t coap_serialize_get_size(void *packet) for (optP = coap_pkt->location_path ; optP != NULL ; optP = optP->next) { - length += COAP_MAX_OPTION_HEADER_LEN + optP->len; + coap_pkt->options_len += COAP_MAX_OPTION_HEADER_LEN + optP->len; } } if (IS_OPTION(coap_pkt, COAP_OPTION_URI_PATH)) @@ -462,18 +464,18 @@ size_t coap_serialize_get_size(void *packet) for (optP = coap_pkt->uri_path ; optP != NULL ; optP = optP->next) { - length += COAP_MAX_OPTION_HEADER_LEN + optP->len; + coap_pkt->options_len += COAP_MAX_OPTION_HEADER_LEN + optP->len; } } if (IS_OPTION(coap_pkt, COAP_OPTION_CONTENT_TYPE)) { // can be stored in extended fields - length += COAP_MAX_OPTION_HEADER_LEN; + coap_pkt->options_len += COAP_MAX_OPTION_HEADER_LEN; } if (IS_OPTION(coap_pkt, COAP_OPTION_MAX_AGE)) { // can be stored in extended fields - length += COAP_MAX_OPTION_HEADER_LEN; + coap_pkt->options_len += COAP_MAX_OPTION_HEADER_LEN; } if (IS_OPTION(coap_pkt, COAP_OPTION_URI_QUERY)) { @@ -481,35 +483,73 @@ size_t coap_serialize_get_size(void *packet) for (optP = coap_pkt->uri_query ; optP != NULL ; optP = optP->next) { - length += COAP_MAX_OPTION_HEADER_LEN + optP->len; + coap_pkt->options_len += COAP_MAX_OPTION_HEADER_LEN + optP->len; } } if (IS_OPTION(coap_pkt, COAP_OPTION_ACCEPT)) { - length += coap_pkt->accept_num * COAP_MAX_OPTION_HEADER_LEN; + coap_pkt->options_len += coap_pkt->accept_num * COAP_MAX_OPTION_HEADER_LEN; } if (IS_OPTION(coap_pkt, COAP_OPTION_LOCATION_QUERY)) { - length += COAP_MAX_OPTION_HEADER_LEN + coap_pkt->location_query_len; + coap_pkt->options_len += COAP_MAX_OPTION_HEADER_LEN + coap_pkt->location_query_len; } if (IS_OPTION(coap_pkt, COAP_OPTION_BLOCK2)) { // can be stored in extended fields - length += COAP_MAX_OPTION_HEADER_LEN; + coap_pkt->options_len += COAP_MAX_OPTION_HEADER_LEN; } if (IS_OPTION(coap_pkt, COAP_OPTION_BLOCK1)) { // can be stored in extended fields - length += COAP_MAX_OPTION_HEADER_LEN; + coap_pkt->options_len += COAP_MAX_OPTION_HEADER_LEN; } if (IS_OPTION(coap_pkt, COAP_OPTION_SIZE)) { // can be stored in extended fields - length += COAP_MAX_OPTION_HEADER_LEN; + coap_pkt->options_len += COAP_MAX_OPTION_HEADER_LEN; } if (IS_OPTION(coap_pkt, COAP_OPTION_PROXY_URI)) { - length += COAP_MAX_OPTION_HEADER_LEN + coap_pkt->proxy_uri_len; + coap_pkt->options_len += COAP_MAX_OPTION_HEADER_LEN + coap_pkt->proxy_uri_len; + } + + switch (coap_pkt->protocol) + { + case COAP_TCP: + case COAP_TCP_TLS: + { + int len = coap_pkt->options_len + coap_pkt->payload_len; + if (len < 13) + { + length += 1; + } + else if (len < ((1 << 8) + 13)) + { + length += 2; + } + else if (len < ((1 << 16) + 269)) + { + length += 3; + } + else + { + length += 5; + } + + length += coap_pkt->token_len + coap_pkt->options_len; + if (coap_pkt->payload_len > 0) + length += COAP_OPTIONS_MARKER_LEN + coap_pkt->payload_len; + } + break; + case COAP_UDP: + case COAP_UDP_DTLS: + length += COAP_HEADER_LEN + coap_pkt->token_len + coap_pkt->options_len; + if (coap_pkt->payload_len > 0) + length += COAP_OPTIONS_MARKER_LEN + coap_pkt->payload_len; + break; + default: + break; } return length; @@ -521,6 +561,7 @@ coap_serialize_message(void *packet, uint8_t *buffer) { coap_packet_t *const coap_pkt = (coap_packet_t *) packet; uint8_t *option; + uint8_t *options_buf; unsigned int current_number = 0; /* Initialize */ @@ -529,28 +570,12 @@ coap_serialize_message(void *packet, uint8_t *buffer) PRINTF("-Serializing MID %u to %p, ", coap_pkt->mid, coap_pkt->buffer); - /* set header fields */ - coap_pkt->buffer[0] = 0x00; - coap_pkt->buffer[0] |= COAP_HEADER_VERSION_MASK & (coap_pkt->version)<buffer[0] |= COAP_HEADER_TYPE_MASK & (coap_pkt->type)<buffer[0] |= COAP_HEADER_TOKEN_LEN_MASK & (coap_pkt->token_len)<buffer[1] = coap_pkt->code; - coap_pkt->buffer[2] = (uint8_t) ((coap_pkt->mid)>>8); - coap_pkt->buffer[3] = (uint8_t) (coap_pkt->mid); - - /* set Token */ - PRINTF("Token (len %u)", coap_pkt->token_len); - option = coap_pkt->buffer + COAP_HEADER_LEN; - for (current_number=0; current_numbertoken_len; ++current_number) - { - PRINTF(" %02X", coap_pkt->token[current_number]); - *option = coap_pkt->token[current_number]; - ++option; - } - PRINTF("-\n"); - - /* Serialize options */ + /* First serialize the options to get their exact size */ current_number = 0; + options_buf = malloc(coap_pkt->options_len); + if (!options_buf) + return 0; + option = options_buf; PRINTF("-Serializing options at %p-\n", option); @@ -573,8 +598,89 @@ coap_serialize_message(void *packet, uint8_t *buffer) COAP_SERIALIZE_INT_OPTION( COAP_OPTION_SIZE, size, "Size") COAP_SERIALIZE_STRING_OPTION( COAP_OPTION_PROXY_URI, proxy_uri, '\0', "Proxy-Uri") + coap_pkt->options_len = option - options_buf; + PRINTF("-Done serializing at %p----\n", option); + switch (coap_pkt->protocol) + { + case COAP_UDP: + case COAP_UDP_DTLS: + coap_pkt->buffer[0] = 0x00; + coap_pkt->buffer[0] |= COAP_HEADER_VERSION_MASK & (coap_pkt->version)<buffer[0] |= COAP_HEADER_TYPE_MASK & (coap_pkt->type)<buffer[0] |= COAP_HEADER_TOKEN_LEN_MASK & (coap_pkt->token_len)<buffer[1] = coap_pkt->code; + coap_pkt->buffer[2] = (uint8_t) ((coap_pkt->mid)>>8); + coap_pkt->buffer[3] = (uint8_t) (coap_pkt->mid); + option = coap_pkt->buffer + COAP_HEADER_LEN; + break; + + case COAP_TCP: + case COAP_TCP_TLS: + { + uint32_t len = coap_pkt->options_len; + if (coap_pkt->payload_len > 0) + len += COAP_OPTIONS_MARKER_LEN + coap_pkt->payload_len; + + PRINTF("Options+Payload (len %u)", len); + if (len < 13) + { + coap_pkt->buffer[0] = (COAP_HEADER_TOKEN_LEN_MASK & coap_pkt->token_len); + coap_pkt->buffer[0] |= (len << 4); + coap_pkt->buffer[1] = coap_pkt->code; + option = coap_pkt->buffer + 2; + } + else if (len < ((1 << 8) + 13)) + { + coap_pkt->buffer[0] = (COAP_HEADER_TOKEN_LEN_MASK & coap_pkt->token_len); + coap_pkt->buffer[0] |= (13 << 4); + coap_pkt->buffer[1] = len - 13; + coap_pkt->buffer[2] = coap_pkt->code; + option = coap_pkt->buffer + 3; + } + else if (len < ((1 << 16) + 269)) + { + coap_pkt->buffer[0] = (COAP_HEADER_TOKEN_LEN_MASK & coap_pkt->token_len); + coap_pkt->buffer[0] |= (14 << 4); + coap_pkt->buffer[1] = ((len - 269) & 0xFF00) >> 8; + coap_pkt->buffer[2] = (len - 269) & 0x00FF; + coap_pkt->buffer[3] = coap_pkt->code; + option = coap_pkt->buffer + 4; + } + else + { + coap_pkt->buffer[0] = (COAP_HEADER_TOKEN_LEN_MASK & coap_pkt->token_len); + coap_pkt->buffer[0] |= (15 << 4); + coap_pkt->buffer[1] = ((len - 65805) & 0xFF000000) >> 24; + coap_pkt->buffer[2] = ((len - 65805) & 0x00FF0000) >> 16; + coap_pkt->buffer[3] = ((len - 65805) & 0x0000FF00) >> 8; + coap_pkt->buffer[4] = (len - 65805) & 0x00FF; + coap_pkt->buffer[5] = coap_pkt->code; + option = coap_pkt->buffer + 6; + } + } + break; + default: + break; + } + + /* set Token */ + PRINTF("Token (len %u)", coap_pkt->token_len); + + for (current_number=0; current_numbertoken_len; ++current_number) + { + PRINTF(" %02X", coap_pkt->token[current_number]); + *option = coap_pkt->token[current_number]; + ++option; + } + PRINTF("-\n"); + + /* Copy options */ + memcpy(option, options_buf, coap_pkt->options_len); + option += coap_pkt->options_len; + free(options_buf); + /* Free allocated header fields */ coap_free_header(packet); @@ -605,22 +711,66 @@ coap_serialize_message(void *packet, uint8_t *buffer) } /*-----------------------------------------------------------------------------------*/ coap_status_t -coap_parse_message(void *packet, uint8_t *data, uint16_t data_len) +coap_parse_message(void *packet, coap_protocol_t protocol, uint8_t *data, uint16_t data_len) { coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + uint8_t *current_option; + + current_option = NULL; /* Initialize packet */ memset(coap_pkt, 0, sizeof(coap_packet_t)); + coap_pkt->protocol = protocol; + /* pointer to packet bytes */ coap_pkt->buffer = data; /* parse header fields */ - coap_pkt->version = (COAP_HEADER_VERSION_MASK & coap_pkt->buffer[0])>>COAP_HEADER_VERSION_POSITION; - coap_pkt->type = (COAP_HEADER_TYPE_MASK & coap_pkt->buffer[0])>>COAP_HEADER_TYPE_POSITION; - coap_pkt->token_len = MIN(COAP_TOKEN_LEN, (COAP_HEADER_TOKEN_LEN_MASK & coap_pkt->buffer[0])>>COAP_HEADER_TOKEN_LEN_POSITION); - coap_pkt->code = coap_pkt->buffer[1]; - coap_pkt->mid = coap_pkt->buffer[2]<<8 | coap_pkt->buffer[3]; + switch(coap_pkt->protocol) + { + case COAP_UDP: + case COAP_UDP_DTLS: + coap_pkt->version = (COAP_HEADER_VERSION_MASK & coap_pkt->buffer[0])>>COAP_HEADER_VERSION_POSITION; + coap_pkt->type = (COAP_HEADER_TYPE_MASK & coap_pkt->buffer[0])>>COAP_HEADER_TYPE_POSITION; + coap_pkt->token_len = MIN(COAP_TOKEN_LEN, (COAP_HEADER_TOKEN_LEN_MASK & coap_pkt->buffer[0])>>COAP_HEADER_TOKEN_LEN_POSITION); + coap_pkt->code = coap_pkt->buffer[1]; + coap_pkt->mid = coap_pkt->buffer[2]<<8 | coap_pkt->buffer[3]; + current_option = data + COAP_HEADER_LEN; + break; + case COAP_TCP: + case COAP_TCP_TLS: + coap_pkt->token_len = coap_pkt->buffer[0] & COAP_HEADER_TOKEN_LEN_MASK; + int nibble = (coap_pkt->buffer[0] & 0xF0) >> 4; + if (nibble < 13) + { + coap_pkt->code = coap_pkt->buffer[1]; + current_option = data + 2; + } + else if (nibble == 13) + { + coap_pkt->code = coap_pkt->buffer[2]; + current_option = data + 3; + } + else if (nibble == 14) + { + coap_pkt->code = coap_pkt->buffer[3]; + current_option = data + 4; + } + else + { + coap_pkt->code = coap_pkt->buffer[5]; + current_option = data + 6; + } + + /* Not passed in TCP, just set defaults */ + coap_pkt->version = 1; + coap_pkt->type = COAP_TYPE_CON; + coap_pkt->mid = 0; + break; + default: + break; + } if (coap_pkt->version != 1) { @@ -628,8 +778,6 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len) return BAD_REQUEST_4_00; } - uint8_t *current_option = data + COAP_HEADER_LEN; - if (coap_pkt->token_len != 0) { memcpy(coap_pkt->token, current_option, coap_pkt->token_len); @@ -1032,7 +1180,7 @@ coap_get_header_proxy_uri(void *packet, const char **uri) if (!IS_OPTION(coap_pkt, COAP_OPTION_PROXY_URI)) return 0; - *uri = (const char *)coap_pkt->proxy_uri; + *uri = (const char*)coap_pkt->proxy_uri; return coap_pkt->proxy_uri_len; } @@ -1041,7 +1189,7 @@ coap_set_header_proxy_uri(void *packet, const char *uri) { coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - coap_pkt->proxy_uri = (const uint8_t *)uri; + coap_pkt->proxy_uri = (const uint8_t*)uri; coap_pkt->proxy_uri_len = strlen(uri); SET_OPTION(coap_pkt, COAP_OPTION_PROXY_URI); @@ -1213,7 +1361,7 @@ coap_get_header_location_query(void *packet, const char **query) if (!IS_OPTION(coap_pkt, COAP_OPTION_LOCATION_QUERY)) return 0; - *query = (const char *)coap_pkt->location_query; + *query = (const char*)coap_pkt->location_query; return coap_pkt->location_query_len; } @@ -1224,7 +1372,7 @@ coap_set_header_location_query(void *packet, char *query) while (query[0]=='?') ++query; - coap_pkt->location_query = (uint8_t *)query; + coap_pkt->location_query = (uint8_t*)query; coap_pkt->location_query_len = strlen(query); SET_OPTION(coap_pkt, COAP_OPTION_LOCATION_QUERY);