From adfdf621b340cb6b7182389a31fb93bcda216857 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Fri, 1 Sep 2017 01:11:43 -0700 Subject: [PATCH 01/37] net: lwm2m: refactor engine to use lwm2m_message structure Sending an lwm2m message is too difficult. It requires pending / reply and other structures to be configured and set by various portions of the library. There is also no way to know if a pending message ever encounters a timeout. Let's fix this by simplifying the internal LwM2M engine APIs for handling lwm2m messages: 1. A user calls lwm2m_get_message(lwm2m_ctx) which returns the first available lwm2m message from an array of messages per lwm2m_ctx (total # of messages per lwm2m_ctx is set via CONFIG_LWM2M_ENGINE_MAX_MESSAGES). 2. Next the user sets all of the fields in the message that are required (type, code message id, token, etc) 3. Then the user calls lwm2m_init_message(msg). This initializes the underlying zoap_packet, pending and reply structures. 4. Once initialized, the user creates their payload in msg->zpkt. 5. When the user is ready to send, the call lwm2m_send_message(msg). 6. And if for some reason an error occurs at any point, they can free up the entire set of structures with: lwm2m_release_message(msg). Included in the refactoring is a timeout_cb field which can be set in the LwM2M messages. If a pending structure ever expires the engine will call the timeout_cb passing in the msg structure before it's automatically released. Signed-off-by: Michael Scott --- include/net/lwm2m.h | 39 ++ subsys/net/lib/lwm2m/Kconfig | 6 + subsys/net/lib/lwm2m/lwm2m_engine.c | 449 +++++++++++------- subsys/net/lib/lwm2m/lwm2m_engine.h | 28 +- .../net/lib/lwm2m/lwm2m_obj_firmware_pull.c | 83 +--- subsys/net/lib/lwm2m/lwm2m_rd_client.c | 178 +++---- 6 files changed, 439 insertions(+), 344 deletions(-) diff --git a/include/net/lwm2m.h b/include/net/lwm2m.h index ae730e093dcbe..fab071b2e3ae7 100644 --- a/include/net/lwm2m.h +++ b/include/net/lwm2m.h @@ -7,6 +7,7 @@ #ifndef __LWM2M_H__ #define __LWM2M_H__ +#include #include #include @@ -26,6 +27,43 @@ #define IPSO_OBJECT_TEMP_SENSOR_ID 3303 #define IPSO_OBJECT_LIGHT_CONTROL_ID 3311 +struct lwm2m_ctx; +struct lwm2m_message; + +/* Establish a message timeout callback type */ +typedef void (*lwm2m_message_timeout_cb_t)(struct lwm2m_message *msg); + +/** + * Internal LwM2M message structure + * + * @details Structure to track in-flight messages. + * + * Users should not need to manipulate this structure directly. + * This definition is here so that an LwM2M context can have a + * pool of messages for the library to use. + */ +struct lwm2m_message { + /** LwM2M context related to this message */ + struct lwm2m_ctx *ctx; + + /** ZoAP packet data related to this message */ + struct zoap_packet zpkt; + + /** Message configuration */ + const u8_t *token; + zoap_reply_t reply_cb; + lwm2m_message_timeout_cb_t message_timeout_cb; + u16_t mid; + u8_t type; + u8_t code; + u8_t tkl; + + /** ZoAP transmission handling structures */ + struct zoap_pending *pending; + struct zoap_reply *reply; + u8_t send_attempts; +}; + /** * LwM2M context structure * @@ -52,6 +90,7 @@ struct lwm2m_ctx { /** Private ZoAP and networking structures */ struct zoap_pending pendings[CONFIG_LWM2M_ENGINE_MAX_PENDING]; struct zoap_reply replies[CONFIG_LWM2M_ENGINE_MAX_REPLIES]; + struct lwm2m_message messages[CONFIG_LWM2M_ENGINE_MAX_MESSAGES]; struct k_delayed_work retransmit_work; }; diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 0b736cf2e78a1..197a25ca2a3f5 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -29,6 +29,12 @@ config LWM2M_ENGINE_STACK_SIZE Set the stack size for the LWM2M library engine (used for handling OBSERVE and NOTIFY events) +config LWM2M_ENGINE_MAX_MESSAGES + int "LWM2M engine max. message object" + default 5 + help + Set the maximum message objects for the LWM2M library client + config LWM2M_ENGINE_MAX_PENDING int "LWM2M engine max. pending objects" default 5 diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index f7514a3e1ac6a..855acf4365338 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -79,11 +79,13 @@ #define BUF_ALLOC_TIMEOUT K_SECONDS(1) +#define MAX_TOKEN_LEN 8 + struct observe_node { sys_snode_t node; struct lwm2m_ctx *ctx; struct lwm2m_obj_path path; - u8_t token[8]; + u8_t token[MAX_TOKEN_LEN]; s64_t event_timestamp; s64_t last_timestamp; u32_t min_period_sec; @@ -138,10 +140,17 @@ static char *sprint_token(const u8_t *token, u8_t tkl) static char buf[32]; int pos = 0; - for (i = 0; i < tkl; i++) { - pos += snprintf(&buf[pos], 31 - pos, "%x", token[i]); + if (token && tkl != LWM2M_MSG_TOKEN_LEN_SKIP) { + for (i = 0; i < tkl; i++) { + pos += snprintf(&buf[pos], 31 - pos, "%x", token[i]); + } + buf[pos] = '\0'; + } else if (tkl == LWM2M_MSG_TOKEN_LEN_SKIP) { + strcpy(buf, "[skip-token]"); + } else { + strcpy(buf, "[no-token]"); } - buf[pos] = '\0'; + return buf; } #endif @@ -178,7 +187,7 @@ int lwm2m_notify_observer_path(struct lwm2m_obj_path *path) path->res_id); } -static int engine_add_observer(struct net_app_ctx *app_ctx, +static int engine_add_observer(struct lwm2m_message *msg, const u8_t *token, u8_t tkl, struct lwm2m_obj_path *path, u16_t format) @@ -188,8 +197,19 @@ static int engine_add_observer(struct net_app_ctx *app_ctx, struct sockaddr *addr; int i; + if (!msg || !msg->ctx) { + SYS_LOG_ERR("valid lwm2m message is required"); + return -EINVAL; + } + + if (!token || (tkl == 0 || tkl > MAX_TOKEN_LEN)) { + SYS_LOG_ERR("token(%p) and token length(%u) must be valid.", + token, tkl); + return -EINVAL; + } + /* remote addr */ - addr = &app_ctx->default_ctx->remote; + addr = &msg->ctx->net_app_ctx.default_ctx->remote; /* check if object exists */ if (!get_engine_obj(path->obj_id)) { @@ -226,7 +246,7 @@ static int engine_add_observer(struct net_app_ctx *app_ctx, /* make sure this observer doesn't exist already */ SYS_SLIST_FOR_EACH_CONTAINER(&engine_observer_list, obs, node) { - if (&obs->ctx->net_app_ctx == app_ctx && + if (obs->ctx == msg->ctx && memcmp(&obs->path, path, sizeof(*path)) == 0) { /* quietly update the token information */ memcpy(obs->token, token, tkl); @@ -255,8 +275,7 @@ static int engine_add_observer(struct net_app_ctx *app_ctx, /* copy the values and add it to the list */ observe_node_data[i].used = true; - observe_node_data[i].ctx = CONTAINER_OF(app_ctx, - struct lwm2m_ctx, net_app_ctx); + observe_node_data[i].ctx = msg->ctx; memcpy(&observe_node_data[i].path, path, sizeof(*path)); memcpy(observe_node_data[i].token, token, tkl); observe_node_data[i].tkl = tkl; @@ -283,7 +302,7 @@ static int engine_remove_observer(const u8_t *token, u8_t tkl) struct observe_node *obs, *found_obj = NULL; sys_snode_t *prev_node = NULL; - if (!token || tkl == 0) { + if (!token || (tkl == 0 || tkl > MAX_TOKEN_LEN)) { SYS_LOG_ERR("token(%p) and token length(%u) must be valid.", token, tkl); return -EINVAL; @@ -571,100 +590,194 @@ static void zoap_options_to_path(struct zoap_option *opt, int options_count, } } -int lwm2m_init_message(struct net_app_ctx *app_ctx, struct zoap_packet *zpkt, - struct net_pkt **pkt, u8_t type, u8_t code, u16_t mid, - const u8_t *token, u8_t tkl) +struct lwm2m_message *find_msg_from_pending(struct zoap_pending *pending, + struct lwm2m_message *messages, + size_t len) +{ + size_t i; + + if (!pending || !messages) { + return NULL; + } + + for (i = 0; i < len; i++) { + if (messages[i].ctx && messages[i].pending == pending) { + return &messages[i]; + } + } + + return NULL; +} + +struct lwm2m_message *lwm2m_get_message(struct lwm2m_ctx *client_ctx) +{ + size_t i; + + for (i = 0; i < CONFIG_LWM2M_ENGINE_MAX_MESSAGES; i++) { + if (!client_ctx->messages[i].ctx) { + client_ctx->messages[i].ctx = client_ctx; + return &client_ctx->messages[i]; + } + } + + return NULL; +} + +void lwm2m_release_message(struct lwm2m_message *msg) +{ + if (!msg) { + return; + } + + if (msg->pending) { + zoap_pending_clear(msg->pending); + msg->pending = NULL; + } + + if (msg->reply) { + /* make sure we want to clear the reply */ + zoap_reply_clear(msg->reply); + msg->reply = NULL; + } + + memset(msg, 0, sizeof(*msg)); +} + +int lwm2m_init_message(struct lwm2m_message *msg) { + struct net_pkt *pkt; + struct net_app_ctx *app_ctx; struct net_buf *frag; int r; - *pkt = net_app_get_net_pkt(app_ctx, AF_UNSPEC, BUF_ALLOC_TIMEOUT); - if (!*pkt) { + if (!msg || !msg->ctx) { + SYS_LOG_ERR("LwM2M message is invalid."); + return -EINVAL; + } + + app_ctx = &msg->ctx->net_app_ctx; + pkt = net_app_get_net_pkt(app_ctx, AF_UNSPEC, BUF_ALLOC_TIMEOUT); + if (!pkt) { SYS_LOG_ERR("Unable to get TX packet, not enough memory."); return -ENOMEM; } - frag = net_app_get_net_buf(app_ctx, *pkt, + frag = net_app_get_net_buf(app_ctx, pkt, BUF_ALLOC_TIMEOUT); if (!frag) { SYS_LOG_ERR("Unable to get DATA buffer, not enough memory."); - net_pkt_unref(*pkt); - *pkt = NULL; - return -ENOMEM; + r = -ENOMEM; + goto cleanup; } - r = zoap_packet_init(zpkt, *pkt); + r = zoap_packet_init(&msg->zpkt, pkt); if (r < 0) { SYS_LOG_ERR("zoap packet init error (err:%d)", r); - return r; + goto cleanup; } /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(zpkt, 1); - zoap_header_set_type(zpkt, type); - zoap_header_set_code(zpkt, code); + zoap_header_set_version(&msg->zpkt, 1); + zoap_header_set_type(&msg->zpkt, msg->type); + zoap_header_set_code(&msg->zpkt, msg->code); - if (mid > 0) { - zoap_header_set_id(zpkt, mid); + if (msg->mid > 0) { + zoap_header_set_id(&msg->zpkt, msg->mid); } else { - zoap_header_set_id(zpkt, zoap_next_id()); + zoap_header_set_id(&msg->zpkt, zoap_next_id()); } - /* tkl == 0 is for a new TOKEN, tkl == -1 means dont set */ - if (token && tkl > 0) { - zoap_header_set_token(zpkt, token, tkl); - } else if (tkl == 0) { - zoap_header_set_token(zpkt, zoap_next_token(), 8); + /* + * tkl == 0 is for a new TOKEN + * tkl == LWM2M_MSG_TOKEN_LEN_SKIP means dont set + */ + if (msg->tkl == 0) { + zoap_header_set_token(&msg->zpkt, zoap_next_token(), + MAX_TOKEN_LEN); + } else if (msg->token && msg->tkl != LWM2M_MSG_TOKEN_LEN_SKIP) { + zoap_header_set_token(&msg->zpkt, msg->token, msg->tkl); + } + + if (msg->type == ZOAP_TYPE_CON) { + msg->pending = zoap_pending_next_unused( + msg->ctx->pendings, + CONFIG_LWM2M_ENGINE_MAX_PENDING); + if (!msg->pending) { + SYS_LOG_ERR("Unable to find a free pending to track " + "retransmissions."); + r = -ENOMEM; + goto cleanup; + } + + r = zoap_pending_init(msg->pending, &msg->zpkt, + &app_ctx->default_ctx->remote); + if (r < 0) { + SYS_LOG_ERR("Unable to initialize a pending " + "retransmission (err:%d).", r); + goto cleanup; + } + + /* clear out pkt to avoid double unref */ + pkt = NULL; + + if (msg->reply_cb) { + msg->reply = zoap_reply_next_unused( + msg->ctx->replies, + CONFIG_LWM2M_ENGINE_MAX_REPLIES); + if (!msg->reply) { + SYS_LOG_ERR("No resources for " + "waiting for replies."); + r = -ENOMEM; + goto cleanup; + } + + zoap_reply_init(msg->reply, &msg->zpkt); + msg->reply->reply = msg->reply_cb; + } } return 0; + +cleanup: + lwm2m_release_message(msg); + if (pkt) { + net_pkt_unref(pkt); + } + + return r; } -struct zoap_pending *lwm2m_init_message_pending(struct lwm2m_ctx *client_ctx, - struct zoap_packet *zpkt) +int lwm2m_send_message(struct lwm2m_message *msg) { - struct zoap_pending *pending = NULL; int ret; - pending = zoap_pending_next_unused(client_ctx->pendings, - CONFIG_LWM2M_ENGINE_MAX_PENDING); - if (!pending) { - SYS_LOG_ERR("Unable to find a free pending to track " - "retransmissions."); - return NULL; + if (!msg || !msg->ctx) { + SYS_LOG_ERR("LwM2M message is invalid."); + return -EINVAL; } - ret = zoap_pending_init(pending, zpkt, - &client_ctx->net_app_ctx.default_ctx->remote); + msg->send_attempts++; + ret = net_app_send_pkt(&msg->ctx->net_app_ctx, msg->zpkt.pkt, + &msg->ctx->net_app_ctx.default_ctx->remote, + NET_SOCKADDR_MAX_SIZE, K_NO_WAIT, NULL); if (ret < 0) { - SYS_LOG_ERR("Unable to initialize a pending " - "retransmission (err:%d).", ret); - pending->pkt = NULL; - return NULL; + return ret; } - return pending; -} - -void lwm2m_init_message_cleanup(struct net_pkt *pkt, - struct zoap_pending *pending, - struct zoap_reply *reply) -{ - if (pending) { - zoap_pending_clear(pending); - /* don't unref attached pkt twice */ - if (!pending->pkt) { - pkt = NULL; + if (msg->type == ZOAP_TYPE_CON) { + if (msg->send_attempts > 1) { + return 0; } - } - if (reply) { - zoap_reply_clear(reply); + zoap_pending_cycle(msg->pending); + k_delayed_work_submit(&msg->ctx->retransmit_work, + msg->pending->timeout); + } else { + /* if we're not expecting an ACK, free up the msg data */ + lwm2m_release_message(msg); } - if (pkt) { - net_pkt_unref(pkt); - } + return 0; } u16_t lwm2m_get_rd_data(u8_t *client_data, u16_t size) @@ -1994,9 +2107,8 @@ static int get_observe_option(const struct zoap_packet *zpkt) return zoap_option_value_to_int(&option); } -static int handle_request(struct net_app_ctx *app_ctx, - struct zoap_packet *request, - struct zoap_packet *response) +static int handle_request(struct zoap_packet *request, + struct lwm2m_message *msg) { int r; u8_t code; @@ -2019,9 +2131,9 @@ static int handle_request(struct net_app_ctx *app_ctx, context.path = &path; engine_clear_context(&context); - /* set ZoAP request / response */ + /* set ZoAP request / message */ in.in_zpkt = request; - out.out_zpkt = response; + out.out_zpkt = &msg->zpkt; /* set default reader/writer */ in.reader = &plain_text_reader; @@ -2138,8 +2250,7 @@ static int handle_request(struct net_app_ctx *app_ctx, r); } - r = engine_add_observer(app_ctx, - token, tkl, &path, + r = engine_add_observer(msg, token, tkl, &path, accept); if (r < 0) { SYS_LOG_ERR("add OBSERVE error: %d", r); @@ -2227,25 +2338,16 @@ static int handle_request(struct net_app_ctx *app_ctx, return r; } -int lwm2m_udp_sendto(struct net_app_ctx *app_ctx, struct net_pkt *pkt) -{ - return net_app_send_pkt(app_ctx, pkt, &app_ctx->default_ctx->remote, - NET_SOCKADDR_MAX_SIZE, K_NO_WAIT, NULL); -} - void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, bool handle_separate_response, - int (*udp_request_handler)(struct net_app_ctx *app_ctx, - struct zoap_packet *, - struct zoap_packet *)) + udp_request_handler_cb_t udp_request_handler) { struct net_udp_hdr hdr, *udp_hdr; struct zoap_pending *pending; struct zoap_reply *reply; struct zoap_packet response; struct sockaddr from_addr; - struct zoap_packet response2; - struct net_pkt *pkt2; + struct lwm2m_message *msg = NULL; int header_len, r; const u8_t *token; u8_t tkl; @@ -2291,8 +2393,18 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, token = zoap_header_get_token(&response, &tkl); pending = zoap_pending_received(&response, client_ctx->pendings, CONFIG_LWM2M_ENGINE_MAX_PENDING); + /* + * Clear pending pointer because zoap_pending_received() calls + * zoap_pending_clear, and later when we call lwm2m_release_message() + * it will try and call zoap_pending_clear() again if msg->pending + * is != NULL. + */ if (pending) { - /* TODO: If necessary cancel retransmissions */ + msg = find_msg_from_pending(pending, client_ctx->messages, + CONFIG_LWM2M_ENGINE_MAX_MESSAGES); + if (msg) { + msg->pending = NULL; + } } SYS_LOG_DBG("checking for reply from [%s]", @@ -2300,47 +2412,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, reply = zoap_response_received(&response, &from_addr, client_ctx->replies, CONFIG_LWM2M_ENGINE_MAX_REPLIES); - if (!reply) { - /* - * If no normal response handler is found, then this is - * a new request coming from the server. Let's look - * at registered objects to find a handler. - */ - if (udp_request_handler && - zoap_header_get_type(&response) == ZOAP_TYPE_CON) { - /* Create a response packet if we reach this point */ - r = lwm2m_init_message(&client_ctx->net_app_ctx, - &response2, &pkt2, - ZOAP_TYPE_ACK, - zoap_header_get_code(&response), - zoap_header_get_id(&response), - NULL, -1); - if (r < 0) { - if (pkt2) { - net_pkt_unref(pkt2); - } - goto cleanup; - } - - /* - * The "response" here is actually a new request - */ - r = udp_request_handler(&client_ctx->net_app_ctx, - &response, &response2); - if (r < 0) { - SYS_LOG_ERR("Request handler error: %d", r); - } else { - r = lwm2m_udp_sendto(&client_ctx->net_app_ctx, - pkt2); - if (r < 0) { - SYS_LOG_ERR("Err sending response: %d", - r); - } - } - } else { - SYS_LOG_ERR("No handler for response"); - } - } else { + if (reply) { /* * Separate response is composed of 2 messages, empty ACK with * no token and an additional message with a matching token id @@ -2354,10 +2426,59 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, if (handle_separate_response && !tkl && zoap_header_get_type(&response) == ZOAP_TYPE_ACK) { SYS_LOG_DBG("separated response, not removing reply"); + goto cleanup; + } + } + + if (reply || pending) { + /* free up msg resources */ + if (msg) { + lwm2m_release_message(msg); + } + + SYS_LOG_DBG("reply %p handled and removed", reply); + goto cleanup; + } + + /* + * If no normal response handler is found, then this is + * a new request coming from the server. Let's look + * at registered objects to find a handler. + */ + if (udp_request_handler && + zoap_header_get_type(&response) == ZOAP_TYPE_CON) { + msg = lwm2m_get_message(client_ctx); + if (!msg) { + SYS_LOG_ERR("Unable to get a lwm2m message!"); + goto cleanup; + } + + /* Create a response message if we reach this point */ + msg->type = ZOAP_TYPE_ACK; + msg->code = zoap_header_get_code(&response); + msg->mid = zoap_header_get_id(&response); + /* skip token generation by default */ + msg->tkl = LWM2M_MSG_TOKEN_LEN_SKIP; + + r = lwm2m_init_message(msg); + if (r < 0) { + goto cleanup; + } + + /* process the response to this request */ + r = udp_request_handler(&response, msg); + if (r < 0) { + SYS_LOG_ERR("Request handler error: %d", r); } else { - SYS_LOG_DBG("reply %p handled and removed", reply); - zoap_reply_clear(reply); + r = lwm2m_send_message(msg); + if (r < 0) { + SYS_LOG_ERR("Err sending response: %d", + r); + lwm2m_release_message(msg); + } } + } else { + SYS_LOG_ERR("No handler for response"); } cleanup: @@ -2379,6 +2500,7 @@ static void udp_receive(struct net_app_ctx *app_ctx, struct net_pkt *pkt, static void retransmit_request(struct k_work *work) { struct lwm2m_ctx *client_ctx; + struct lwm2m_message *msg; struct zoap_pending *pending; int r; @@ -2389,17 +2511,29 @@ static void retransmit_request(struct k_work *work) return; } - r = lwm2m_udp_sendto(&client_ctx->net_app_ctx, - pending->pkt); - if (r < 0) { + msg = find_msg_from_pending(pending, client_ctx->messages, + CONFIG_LWM2M_ENGINE_MAX_MESSAGES); + if (!msg) { + SYS_LOG_ERR("pending has no valid LwM2M message!"); return; } if (!zoap_pending_cycle(pending)) { - zoap_pending_clear(pending); + /* pending request has expired */ + if (msg->message_timeout_cb) { + msg->message_timeout_cb(msg); + } + + lwm2m_release_message(msg); return; } + r = lwm2m_send_message(msg); + if (r < 0) { + SYS_LOG_ERR("Error sending lwm2m message: %d", r); + /* don't error here, retry until timeout */ + } + k_delayed_work_submit(&client_ctx->retransmit_work, pending->timeout); } @@ -2437,10 +2571,7 @@ static int notify_message_reply_cb(const struct zoap_packet *response, static int generate_notify_message(struct observe_node *obs, bool manual_trigger) { - struct net_pkt *pkt = NULL; - struct zoap_pending *pending = NULL; - struct zoap_reply *reply = NULL; - struct zoap_packet request; + struct lwm2m_message *msg; struct lwm2m_engine_obj_inst *obj_inst; struct lwm2m_output_context out; struct lwm2m_engine_context context; @@ -2460,7 +2591,6 @@ static int generate_notify_message(struct observe_node *obs, memcpy(&path, &obs->path, sizeof(struct lwm2m_obj_path)); context.path = &path; context.operation = LWM2M_OP_READ; - out.out_zpkt = &request; SYS_LOG_DBG("[%s] NOTIFY MSG START: %u/%u/%u(%u) token:'%s' [%s] %lld", manual_trigger ? "MANUAL" : "AUTO", @@ -2482,11 +2612,23 @@ static int generate_notify_message(struct observe_node *obs, return -EINVAL; } - ret = lwm2m_init_message(&obs->ctx->net_app_ctx, out.out_zpkt, &pkt, - ZOAP_TYPE_CON, ZOAP_RESPONSE_CODE_CONTENT, - 0, obs->token, obs->tkl); + msg = lwm2m_get_message(obs->ctx); + if (!msg) { + SYS_LOG_ERR("Unable to get a lwm2m message!"); + return -ENOMEM; + } + + out.out_zpkt = &msg->zpkt; + msg->type = ZOAP_TYPE_CON; + msg->code = ZOAP_RESPONSE_CODE_CONTENT; + msg->mid = 0; + msg->token = obs->token; + msg->tkl = obs->tkl; + msg->reply_cb = notify_message_reply_cb; + + ret = lwm2m_init_message(msg); if (ret) { - goto cleanup; + return ret; } /* each notification should increment the obs counter */ @@ -2521,36 +2663,17 @@ static int generate_notify_message(struct observe_node *obs, goto cleanup; } - pending = lwm2m_init_message_pending(obs->ctx, out.out_zpkt); - if (!pending) { - ret = -ENOMEM; - goto cleanup; - } - - reply = zoap_reply_next_unused(obs->ctx->replies, - CONFIG_LWM2M_ENGINE_MAX_REPLIES); - if (!reply) { - SYS_LOG_ERR("No resources for waiting for replies."); - ret = -ENOMEM; - goto cleanup; - } - - zoap_reply_init(reply, &request); - reply->reply = notify_message_reply_cb; - - ret = lwm2m_udp_sendto(&obs->ctx->net_app_ctx, pkt); + ret = lwm2m_send_message(msg); if (ret < 0) { SYS_LOG_ERR("Error sending LWM2M packet (err:%d).", ret); goto cleanup; } - SYS_LOG_DBG("NOTIFY MSG: SENT"); - zoap_pending_cycle(pending); - k_delayed_work_submit(&obs->ctx->retransmit_work, pending->timeout); - return ret; + SYS_LOG_DBG("NOTIFY MSG: SENT"); + return 0; cleanup: - lwm2m_init_message_cleanup(pkt, pending, reply); + lwm2m_release_message(msg); return ret; } diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index 829977989a608..76b08a35c2691 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -32,6 +32,13 @@ #define NOTIFY_OBSERVER(o, i, r) lwm2m_notify_observer(o, i, r) #define NOTIFY_OBSERVER_PATH(path) lwm2m_notify_observer_path(path) +/* Use this value to skip token generation in an lwm2m_msg */ +#define LWM2M_MSG_TOKEN_LEN_SKIP 0xFF + +/* Establish a request handler callback type */ +typedef int (*udp_request_handler_cb_t)(struct zoap_packet *request, + struct lwm2m_message *msg); + char *lwm2m_sprint_ip_addr(const struct sockaddr *addr); int lwm2m_notify_observer(u16_t obj_id, u16_t obj_inst_id, u16_t res_id); @@ -48,14 +55,14 @@ int lwm2m_get_or_create_engine_obj(struct lwm2m_engine_context *context, struct lwm2m_engine_obj_inst **obj_inst, u8_t *created); -int lwm2m_init_message(struct net_app_ctx *app_ctx, struct zoap_packet *zpkt, - struct net_pkt **pkt, u8_t type, u8_t code, u16_t mid, - const u8_t *token, u8_t tkl); -struct zoap_pending *lwm2m_init_message_pending(struct lwm2m_ctx *client_ctx, - struct zoap_packet *zpkt); -void lwm2m_init_message_cleanup(struct net_pkt *pkt, - struct zoap_pending *pending, - struct zoap_reply *reply); +/* LwM2M message functions */ +struct lwm2m_message *find_msg_from_pending(struct zoap_pending *pending, + struct lwm2m_message *messages, + size_t len); +struct lwm2m_message *lwm2m_get_message(struct lwm2m_ctx *client_ctx); +void lwm2m_release_message(struct lwm2m_message *msg); +int lwm2m_init_message(struct lwm2m_message *msg); +int lwm2m_send_message(struct lwm2m_message *msg); u16_t lwm2m_get_rd_data(u8_t *client_data, u16_t size); @@ -64,11 +71,8 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, struct lwm2m_engine_obj_field *obj_field, struct lwm2m_engine_context *context); -int lwm2m_udp_sendto(struct net_app_ctx *app_ctx, struct net_pkt *pkt); void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, bool handle_separate_response, - int (*udp_request_handler)(struct net_app_ctx *app_ctx, - struct zoap_packet *request, - struct zoap_packet *response)); + udp_request_handler_cb_t udp_request_handler); #endif /* LWM2M_ENGINE_H */ diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c index bb28b919054d9..43e20bd4d581a 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c @@ -46,97 +46,64 @@ firmware_udp_receive(struct net_app_ctx *app_ctx, struct net_pkt *pkt, lwm2m_udp_receive(&firmware_ctx, pkt, true, NULL); } -static void retransmit_request(struct k_work *work) +static void do_transmit_timeout_cb(struct lwm2m_message *msg) { - struct zoap_pending *pending; - int r; - - pending = zoap_pending_next_to_expire(firmware_ctx.pendings, - CONFIG_LWM2M_ENGINE_MAX_PENDING); - if (!pending) { - return; - } - - r = lwm2m_udp_sendto(&firmware_ctx.net_app_ctx, pending->pkt); - if (r < 0) { - return; - } - - if (!zoap_pending_cycle(pending)) { - zoap_pending_clear(pending); - return; - } - - k_delayed_work_submit(&firmware_ctx.retransmit_work, pending->timeout); + /* TODO: Handle timeout */ } static int transfer_request(struct zoap_block_context *ctx, const u8_t *token, u8_t tkl, zoap_reply_t reply_cb) { - struct zoap_packet request; - struct net_pkt *pkt = NULL; - struct zoap_pending *pending = NULL; - struct zoap_reply *reply = NULL; + struct lwm2m_message *msg; int ret; - ret = lwm2m_init_message(&firmware_ctx.net_app_ctx, &request, &pkt, - ZOAP_TYPE_CON, ZOAP_METHOD_GET, - 0, token, tkl); + msg = lwm2m_get_message(&firmware_ctx); + if (!msg) { + SYS_LOG_ERR("Unable to get a lwm2m message!"); + return -ENOMEM; + } + + msg->type = ZOAP_TYPE_CON; + msg->code = ZOAP_METHOD_GET; + msg->mid = 0; + msg->token = token; + msg->tkl = tkl; + msg->reply_cb = reply_cb; + msg->message_timeout_cb = do_transmit_timeout_cb; + + ret = lwm2m_init_message(msg); if (ret) { goto cleanup; } /* hard code URI path here -- should be pulled from package_uri */ - ret = zoap_add_option(&request, ZOAP_OPTION_URI_PATH, + ret = zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_PATH, "large-create", sizeof("large-create") - 1); - ret = zoap_add_option(&request, ZOAP_OPTION_URI_PATH, + ret = zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_PATH, "1", sizeof("1") - 1); if (ret < 0) { SYS_LOG_ERR("Error adding URI_QUERY 'large'"); goto cleanup; } - ret = zoap_add_block2_option(&request, ctx); + ret = zoap_add_block2_option(&msg->zpkt, ctx); if (ret) { SYS_LOG_ERR("Unable to add block2 option."); goto cleanup; } - pending = lwm2m_init_message_pending(&firmware_ctx, &request); - if (!pending) { - ret = -ENOMEM; - goto cleanup; - } - - /* set the reply handler */ - if (reply_cb) { - reply = zoap_reply_next_unused(firmware_ctx.replies, - CONFIG_LWM2M_ENGINE_MAX_REPLIES); - if (!reply) { - SYS_LOG_ERR("No resources for waiting for replies."); - ret = -ENOMEM; - goto cleanup; - } - - zoap_reply_init(reply, &request); - reply->reply = reply_cb; - } - /* send request */ - ret = lwm2m_udp_sendto(&firmware_ctx.net_app_ctx, pkt); + ret = lwm2m_send_message(msg); if (ret < 0) { - SYS_LOG_ERR("Error sending LWM2M packet (err:%d).", - ret); + SYS_LOG_ERR("Error sending LWM2M packet (err:%d).", ret); goto cleanup; } - zoap_pending_cycle(pending); - k_delayed_work_submit(&firmware_ctx.retransmit_work, pending->timeout); return 0; cleanup: - lwm2m_init_message_cleanup(pkt, pending, reply); + lwm2m_release_message(msg); return ret; } @@ -299,8 +266,6 @@ int lwm2m_firmware_start_transfer(char *package_uri) firmware_ctx.net_init_timeout = NETWORK_INIT_TIMEOUT; firmware_ctx.net_timeout = NETWORK_CONNECT_TIMEOUT; k_work_init(&firmware_work, firmware_transfer); - k_delayed_work_init(&firmware_ctx.retransmit_work, - retransmit_request); /* start file transfer work */ strncpy(firmware_uri, package_uri, PACKAGE_URI_LEN - 1); diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index 6ea1a7c6275e2..fe7399bf90e73 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -398,72 +398,57 @@ static int sm_do_init(int index) static int sm_do_bootstrap(int index) { - struct zoap_packet request; - struct net_pkt *pkt = NULL; - struct zoap_pending *pending = NULL; - struct zoap_reply *reply = NULL; + struct lwm2m_message *msg; struct net_app_ctx *app_ctx = NULL; - int ret = 0; + int ret; if (clients[index].use_bootstrap && clients[index].bootstrapped == 0 && clients[index].has_bs_server_info) { app_ctx = &clients[index].ctx->net_app_ctx; - ret = lwm2m_init_message(app_ctx, - &request, &pkt, ZOAP_TYPE_CON, - ZOAP_METHOD_POST, 0, NULL, 0); + msg = lwm2m_get_message(clients[index].ctx); + if (!msg) { + SYS_LOG_ERR("Unable to get a lwm2m message!"); + return -ENOMEM; + } + + msg->type = ZOAP_TYPE_CON; + msg->code = ZOAP_METHOD_POST; + msg->mid = 0; + msg->reply_cb = do_bootstrap_reply_cb; + + ret = lwm2m_init_message(msg); if (ret) { goto cleanup; } - zoap_add_option(&request, ZOAP_OPTION_URI_PATH, + zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_PATH, "bs", strlen("bs")); snprintf(query_buffer, sizeof(query_buffer) - 1, "ep=%s", clients[index].ep_name); - zoap_add_option(&request, ZOAP_OPTION_URI_QUERY, + zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_QUERY, query_buffer, strlen(query_buffer)); - pending = lwm2m_init_message_pending(clients[index].ctx, - &request); - if (!pending) { - ret = -ENOMEM; - goto cleanup; - } - - reply = zoap_reply_next_unused(clients[index].ctx->replies, - CONFIG_LWM2M_ENGINE_MAX_REPLIES); - if (!reply) { - SYS_LOG_ERR("No resources for waiting for replies."); - ret = -ENOMEM; - goto cleanup; - } - - zoap_reply_init(reply, &request); - reply->reply = do_bootstrap_reply_cb; - /* log the bootstrap attempt */ SYS_LOG_DBG("Register ID with bootstrap server [%s] as '%s'", lwm2m_sprint_ip_addr( &app_ctx->default_ctx->remote), query_buffer); - ret = lwm2m_udp_sendto(app_ctx, pkt); + ret = lwm2m_send_message(msg); if (ret < 0) { SYS_LOG_ERR("Error sending LWM2M packet (err:%d).", ret); goto cleanup; } - zoap_pending_cycle(pending); - k_delayed_work_submit(&clients[index].ctx->retransmit_work, - pending->timeout); set_sm_state(index, ENGINE_BOOTSTRAP_SENT); } - return ret; + return 0; cleanup: - lwm2m_init_message_cleanup(pkt, pending, reply); + lwm2m_release_message(msg); return ret; } @@ -512,54 +497,62 @@ static int sm_bootstrap_done(int index) } static int sm_send_registration(int index, bool send_obj_support_data, - zoap_reply_t reply_cb) + zoap_reply_t reply_cb, + lwm2m_message_timeout_cb_t timeout_cb) { struct net_app_ctx *app_ctx = NULL; - struct zoap_packet request; - struct net_pkt *pkt = NULL; - struct zoap_pending *pending = NULL; - struct zoap_reply *reply = NULL; + struct lwm2m_message *msg; u8_t *payload; u16_t client_data_len, len; - int ret = 0; + int ret; app_ctx = &clients[index].ctx->net_app_ctx; + msg = lwm2m_get_message(clients[index].ctx); + if (!msg) { + SYS_LOG_ERR("Unable to get a lwm2m message!"); + return -ENOMEM; + } /* remember the last reg time */ clients[index].last_update = k_uptime_get(); - ret = lwm2m_init_message(app_ctx, - &request, &pkt, ZOAP_TYPE_CON, - ZOAP_METHOD_POST, 0, NULL, 0); + + msg->type = ZOAP_TYPE_CON; + msg->code = ZOAP_METHOD_POST; + msg->mid = 0; + msg->reply_cb = reply_cb; + msg->message_timeout_cb = timeout_cb; + + ret = lwm2m_init_message(msg); if (ret) { goto cleanup; } - zoap_add_option(&request, ZOAP_OPTION_URI_PATH, + zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_PATH, LWM2M_RD_CLIENT_URI, strlen(LWM2M_RD_CLIENT_URI)); if (!sm_is_registered(index)) { /* include client endpoint in URI QUERY on 1st registration */ - zoap_add_option_int(&request, ZOAP_OPTION_CONTENT_FORMAT, + zoap_add_option_int(&msg->zpkt, ZOAP_OPTION_CONTENT_FORMAT, LWM2M_FORMAT_APP_LINK_FORMAT); snprintf(query_buffer, sizeof(query_buffer) - 1, "lwm2m=%s", LWM2M_PROTOCOL_VERSION); - zoap_add_option(&request, ZOAP_OPTION_URI_QUERY, + zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_QUERY, query_buffer, strlen(query_buffer)); snprintf(query_buffer, sizeof(query_buffer) - 1, "ep=%s", clients[index].ep_name); - zoap_add_option(&request, ZOAP_OPTION_URI_QUERY, + zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_QUERY, query_buffer, strlen(query_buffer)); } else { /* include server endpoint in URI PATH otherwise */ - zoap_add_option(&request, ZOAP_OPTION_URI_PATH, + zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_PATH, clients[index].server_ep, strlen(clients[index].server_ep)); } snprintf(query_buffer, sizeof(query_buffer) - 1, "lt=%d", clients[index].lifetime); - zoap_add_option(&request, ZOAP_OPTION_URI_QUERY, + zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_QUERY, query_buffer, strlen(query_buffer)); /* TODO: add supported binding query string */ @@ -567,54 +560,34 @@ static int sm_send_registration(int index, bool send_obj_support_data, /* generate the rd data */ client_data_len = lwm2m_get_rd_data(client_data, sizeof(client_data)); - payload = zoap_packet_get_payload(&request, &len); + payload = zoap_packet_get_payload(&msg->zpkt, &len); if (!payload) { ret = -EINVAL; goto cleanup; } memcpy(payload, client_data, client_data_len); - ret = zoap_packet_set_used(&request, client_data_len); + ret = zoap_packet_set_used(&msg->zpkt, client_data_len); if (ret) { goto cleanup; } } - pending = lwm2m_init_message_pending(clients[index].ctx, &request); - if (!pending) { - ret = -ENOMEM; - goto cleanup; - } - - reply = zoap_reply_next_unused(clients[index].ctx->replies, - CONFIG_LWM2M_ENGINE_MAX_REPLIES); - if (!reply) { - SYS_LOG_ERR("No resources for waiting for replies."); - ret = -ENOMEM; + ret = lwm2m_send_message(msg); + if (ret < 0) { + SYS_LOG_ERR("Error sending LWM2M packet (err:%d).", + ret); goto cleanup; } - zoap_reply_init(reply, &request); - reply->reply = reply_cb; - /* log the registration attempt */ SYS_LOG_DBG("registration sent [%s]", lwm2m_sprint_ip_addr(&app_ctx->default_ctx->remote)); - ret = lwm2m_udp_sendto(app_ctx, pkt); - if (ret < 0) { - SYS_LOG_ERR("Error sending LWM2M packet (err:%d).", - ret); - goto cleanup; - } - - zoap_pending_cycle(pending); - k_delayed_work_submit(&clients[index].ctx->retransmit_work, - pending->timeout); - return ret; + return 0; cleanup: - lwm2m_init_message_cleanup(pkt, pending, reply); + lwm2m_release_message(msg); return ret; } @@ -626,7 +599,7 @@ static int sm_do_registration(int index) !sm_is_registered(index) && clients[index].has_registration_info) { ret = sm_send_registration(index, true, - do_registration_reply_cb); + do_registration_reply_cb, NULL); if (!ret) { set_sm_state(index, ENGINE_REGISTRATION_SENT); } else { @@ -650,7 +623,7 @@ static int sm_registration_done(int index) forced_update = clients[index].trigger_update; clients[index].trigger_update = 0; ret = sm_send_registration(index, forced_update, - do_update_reply_cb); + do_update_reply_cb, NULL); if (!ret) { set_sm_state(index, ENGINE_UPDATE_SENT); } else { @@ -664,59 +637,44 @@ static int sm_registration_done(int index) static int sm_do_deregister(int index) { struct net_app_ctx *app_ctx = NULL; - struct zoap_packet request; - struct net_pkt *pkt = NULL; - struct zoap_pending *pending = NULL; - struct zoap_reply *reply = NULL; + struct lwm2m_message *msg; int ret; app_ctx = &clients[index].ctx->net_app_ctx; + msg = lwm2m_get_message(clients[index].ctx); + if (!msg) { + SYS_LOG_ERR("Unable to get a lwm2m message!"); + return -ENOMEM; + } + + msg->type = ZOAP_TYPE_CON; + msg->code = ZOAP_METHOD_DELETE; + msg->mid = 0; + msg->reply_cb = do_deregister_reply_cb; - ret = lwm2m_init_message(app_ctx, - &request, &pkt, ZOAP_TYPE_CON, - ZOAP_METHOD_DELETE, 0, NULL, 0); + ret = lwm2m_init_message(msg); if (ret) { goto cleanup; } - zoap_add_option(&request, ZOAP_OPTION_URI_PATH, + zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_PATH, clients[index].server_ep, strlen(clients[index].server_ep)); - pending = lwm2m_init_message_pending(clients[index].ctx, &request); - if (!pending) { - ret = -ENOMEM; - goto cleanup; - } - - reply = zoap_reply_next_unused(clients[index].ctx->replies, - CONFIG_LWM2M_ENGINE_MAX_REPLIES); - if (!reply) { - SYS_LOG_ERR("No resources for waiting for replies."); - ret = -ENOMEM; - goto cleanup; - } - - zoap_reply_init(reply, &request); - reply->reply = do_deregister_reply_cb; - SYS_LOG_INF("Deregister from '%s'", clients[index].server_ep); - ret = lwm2m_udp_sendto(app_ctx, pkt); + ret = lwm2m_send_message(msg); if (ret < 0) { SYS_LOG_ERR("Error sending LWM2M packet (err:%d).", ret); goto cleanup; } - zoap_pending_cycle(pending); - k_delayed_work_submit(&clients[index].ctx->retransmit_work, - pending->timeout); set_sm_state(index, ENGINE_DEREGISTER_SENT); - return ret; + return 0; cleanup: - lwm2m_init_message_cleanup(pkt, pending, reply); + lwm2m_release_message(msg); return ret; } From 2c3fa94711a1d0c433c0bca78638198b52b96e0f Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Fri, 1 Sep 2017 01:22:30 -0700 Subject: [PATCH 02/37] net: lwm2m: add timeout callbacks to registration client Callbacks are setup for the following states: - ENGINE_DO_BOOTSTRAP - ENGINE_DO_REGISTRATION (first registration) - ENGINE_REGISTRATION_DONE (subsequent client updates) - ENGINE_DEREGISTER In most cases, if a timeout occurs the registration engine goes back to ENGINE_INIT. The exception is a timeout during client update, which forces the state machine back to ENGINE_DO_REGISTRATION (skipping a boostrap). Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_rd_client.c | 80 ++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 5 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index fe7399bf90e73..dcc50ab007449 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -177,6 +177,39 @@ static int find_clients_index(const struct sockaddr *addr) return index; } +static int find_rd_client_from_msg(struct lwm2m_message *msg, + struct lwm2m_rd_client_info *rd_clients, + size_t len) +{ + size_t i; + + if (!msg || !rd_clients) { + return -1; + } + + for (i = 0; i < len; i++) { + if (rd_clients[i].ctx && rd_clients[i].ctx == msg->ctx) { + return i; + } + } + + return -1; +} + +static void sm_handle_timeout_state(struct lwm2m_message *msg, + enum sm_engine_state sm_state) +{ + int index; + + index = find_rd_client_from_msg(msg, clients, CLIENT_INSTANCE_COUNT); + if (index < 0) { + SYS_LOG_ERR("Can't find RD client from msg: %p!", msg); + return; + } + + set_sm_state(index, sm_state); +} + /* force re-update with remote peer(s) */ void engine_trigger_update(void) { @@ -228,6 +261,14 @@ static int do_bootstrap_reply_cb(const struct zoap_packet *response, return 0; } +static void do_bootstrap_timeout_cb(struct lwm2m_message *msg) +{ + SYS_LOG_WRN("Bootstrap Timeout"); + + /* Restart from scratch */ + sm_handle_timeout_state(msg, ENGINE_INIT); +} + static int do_registration_reply_cb(const struct zoap_packet *response, struct zoap_reply *reply, const struct sockaddr *from) @@ -297,6 +338,14 @@ static int do_registration_reply_cb(const struct zoap_packet *response, return 0; } +static void do_registration_timeout_cb(struct lwm2m_message *msg) +{ + SYS_LOG_WRN("Registration Timeout"); + + /* Restart from scratch */ + sm_handle_timeout_state(msg, ENGINE_INIT); +} + static int do_update_reply_cb(const struct zoap_packet *response, struct zoap_reply *reply, const struct sockaddr *from) @@ -333,6 +382,14 @@ static int do_update_reply_cb(const struct zoap_packet *response, return 0; } +static void do_update_timeout_cb(struct lwm2m_message *msg) +{ + SYS_LOG_WRN("Registration Update Timeout"); + + /* Re-do registration */ + sm_handle_timeout_state(msg, ENGINE_DO_REGISTRATION); +} + static int do_deregister_reply_cb(const struct zoap_packet *response, struct zoap_reply *reply, const struct sockaddr *from) @@ -366,6 +423,14 @@ static int do_deregister_reply_cb(const struct zoap_packet *response, return 0; } +static void do_deregister_timeout_cb(struct lwm2m_message *msg) +{ + SYS_LOG_WRN("De-Registration Timeout"); + + /* Abort de-registration and start from scratch */ + sm_handle_timeout_state(msg, ENGINE_INIT); +} + /* state machine step functions */ static int sm_do_init(int index) @@ -416,6 +481,7 @@ static int sm_do_bootstrap(int index) msg->code = ZOAP_METHOD_POST; msg->mid = 0; msg->reply_cb = do_bootstrap_reply_cb; + msg->message_timeout_cb = do_bootstrap_timeout_cb; ret = lwm2m_init_message(msg); if (ret) { @@ -599,7 +665,8 @@ static int sm_do_registration(int index) !sm_is_registered(index) && clients[index].has_registration_info) { ret = sm_send_registration(index, true, - do_registration_reply_cb, NULL); + do_registration_reply_cb, + do_registration_timeout_cb); if (!ret) { set_sm_state(index, ENGINE_REGISTRATION_SENT); } else { @@ -623,7 +690,8 @@ static int sm_registration_done(int index) forced_update = clients[index].trigger_update; clients[index].trigger_update = 0; ret = sm_send_registration(index, forced_update, - do_update_reply_cb, NULL); + do_update_reply_cb, + do_update_timeout_cb); if (!ret) { set_sm_state(index, ENGINE_UPDATE_SENT); } else { @@ -651,6 +719,7 @@ static int sm_do_deregister(int index) msg->code = ZOAP_METHOD_DELETE; msg->mid = 0; msg->reply_cb = do_deregister_reply_cb; + msg->message_timeout_cb = do_deregister_timeout_cb; ret = lwm2m_init_message(msg); if (ret) { @@ -695,7 +764,7 @@ static void lwm2m_rd_client_service(void) break; case ENGINE_BOOTSTRAP_SENT: - /* wait for bootstrap to be done */ + /* wait for bootstrap to be done or timeout */ break; case ENGINE_BOOTSTRAP_DONE: @@ -707,7 +776,7 @@ static void lwm2m_rd_client_service(void) break; case ENGINE_REGISTRATION_SENT: - /* wait registration to be done */ + /* wait registration to be done or timeout */ break; case ENGINE_REGISTRATION_DONE: @@ -715,7 +784,7 @@ static void lwm2m_rd_client_service(void) break; case ENGINE_UPDATE_SENT: - /* wait update to be done */ + /* wait update to be done or abort */ break; case ENGINE_DEREGISTER: @@ -723,6 +792,7 @@ static void lwm2m_rd_client_service(void) break; case ENGINE_DEREGISTER_SENT: + /* wait for deregister to be done or reset */ break; case ENGINE_DEREGISTER_FAILED: From bb4cdc3b41d23d565b30e4db5c81389dacdf3ccf Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Fri, 25 Aug 2017 14:04:51 -0700 Subject: [PATCH 03/37] net: lwm2m: set range for client lifetime config Due to timeout checking the minimum lifetime must be 15 seconds, and we're storing the lifetime as an unsigned short so set the maximum to 65535. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 197a25ca2a3f5..1e8ea9dd14f97 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -58,6 +58,7 @@ config LWM2M_ENGINE_MAX_OBSERVER config LWM2M_ENGINE_DEFAULT_LIFETIME int "LWM2M engine default server connection lifetime" default 30 + range 15 65535 help Set the default lifetime (in seconds) for the LWM2M library engine From 27bf1f3dc112284400d2ecff56309735dc25bccd Mon Sep 17 00:00:00 2001 From: Robert Chou Date: Thu, 10 Aug 2017 16:54:15 +0800 Subject: [PATCH 04/37] net: http: add config to separate URL only parser Add HTTP_PARSER_URL_ONLY to separate URL only parser Signed-off-by: Robert Chou --- include/net/http_parser.h | 8 ++++++++ subsys/net/lib/http/Kconfig | 7 +++++++ subsys/net/lib/http/http_parser.c | 12 ++++++++++++ 3 files changed, 27 insertions(+) diff --git a/include/net/http_parser.h b/include/net/http_parser.h index ea31fff128cba..95cb5b1b046d5 100644 --- a/include/net/http_parser.h +++ b/include/net/http_parser.h @@ -24,10 +24,12 @@ extern "C" { #endif +#if !defined(CONFIG_HTTP_PARSER_URL_ONLY) /* Also update SONAME in the Makefile whenever you change these. */ #define HTTP_PARSER_VERSION_MAJOR 2 #define HTTP_PARSER_VERSION_MINOR 7 #define HTTP_PARSER_VERSION_PATCH 1 +#endif #include #if defined(_WIN32) && !defined(__MINGW32__) && \ @@ -47,6 +49,7 @@ typedef unsigned __int64 u64_t; #include #endif +#if !defined(CONFIG_HTTP_PARSER_URL_ONLY) /* Maximium header size allowed. If the macro is not defined * before including this header then the default is used. To * change the maximum header size, define the macro in the build @@ -227,6 +230,7 @@ struct http_parser_settings { http_cb on_chunk_header; http_cb on_chunk_complete; }; +#endif /* !CONFIG_HTTP_PARSER_URL_ONLY */ enum http_parser_url_fields { @@ -261,6 +265,7 @@ struct http_parser_url { }; +#if !defined(CONFIG_HTTP_PARSER_URL_ONLY) /* Returns the library version. Bits 16-23 contain the major version number, * bits 8-15 the minor version number and bits 0-7 the patch level. * Usage example: @@ -305,6 +310,7 @@ const char *http_errno_name(enum http_errno err); /* Return a string description of the given error */ const char *http_errno_description(enum http_errno err); +#endif /* !CONFIG_HTTP_PARSER_URL_ONLY */ /* Initialize all http_parser_url members to 0 */ void http_parser_url_init(struct http_parser_url *u); @@ -313,11 +319,13 @@ void http_parser_url_init(struct http_parser_url *u); int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, struct http_parser_url *u); +#if !defined(CONFIG_HTTP_PARSER_URL_ONLY) /* Pause or un-pause the parser; a nonzero value pauses */ void http_parser_pause(struct http_parser *parser, int paused); /* Checks if this is the final chunk of the body. */ int http_body_is_final(const struct http_parser *parser); +#endif #ifdef __cplusplus } diff --git a/subsys/net/lib/http/Kconfig b/subsys/net/lib/http/Kconfig index 2bc269f5b1a22..8ac28a7b9770d 100644 --- a/subsys/net/lib/http/Kconfig +++ b/subsys/net/lib/http/Kconfig @@ -65,6 +65,13 @@ config HTTP_PARSER This parser requires some string-related routines commonly provided by a libc implementation. +config HTTP_PARSER_URL_ONLY + bool "HTTP URL parser only support" + default n + select HTTP_PARSER + help + This option only enables URL parser of the http_parser library. + config HTTP_PARSER_STRICT bool "HTTP strict parsing" default n diff --git a/subsys/net/lib/http/http_parser.c b/subsys/net/lib/http/http_parser.c index eab6ca065b292..56cf2de990caf 100644 --- a/subsys/net/lib/http/http_parser.c +++ b/subsys/net/lib/http/http_parser.c @@ -71,6 +71,7 @@ do { \ } \ } while (0) +#if !defined(CONFIG_HTTP_PARSER_URL_ONLY) /* Don't allow the total size of the HTTP headers (including the status * line) to exceed HTTP_MAX_HEADER_SIZE. This check is here to protect * embedders against denial-of-service attacks where the attacker feeds @@ -169,6 +170,7 @@ s8_t unhex[256] = { -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +#endif /* !CONFIG_HTTP_PARSER_URL_ONLY */ #ifdef HTTP_PARSER_STRICT @@ -284,6 +286,7 @@ enum state { s_message_done }; +#if !defined(CONFIG_HTTP_PARSER_URL_ONLY) #define PARSING_HEADER(state) (state <= s_headers_done) enum header_states { @@ -311,6 +314,7 @@ enum header_states { h_connection_close, h_connection_upgrade }; +#endif /* !CONFIG_HTTP_PARSER_URL_ONLY */ enum http_host_state { s_http_host_dead = 1, @@ -327,6 +331,7 @@ enum http_host_state { s_http_host_port }; +#if !defined(CONFIG_HTTP_PARSER_URL_ONLY) static inline int cb_notify(struct http_parser *parser, enum state *current_state, http_cb cb, int cb_error, size_t *parsed, size_t already_parsed) @@ -382,6 +387,7 @@ int cb_data(struct http_parser *parser, http_data_cb cb, int cb_error, return 0; } +#endif /* !CONFIG_HTTP_PARSER_URL_ONLY */ /* Macros for character classes; depends on strict-mode */ @@ -416,6 +422,7 @@ int cb_data(struct http_parser *parser, http_data_cb cb, int cb_error, (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') #endif +#if !defined(CONFIG_HTTP_PARSER_URL_ONLY) /** * Verify that a char is a valid visible (printable) US-ASCII * character or %x80-FF @@ -493,6 +500,7 @@ static struct { }; int http_message_needs_eof(const struct http_parser *parser); +#endif /* !CONFIG_HTTP_PARSER_URL_ONLY */ /* Our URL parser. * @@ -655,6 +663,7 @@ static enum state parse_url_char(enum state s, const char ch) return s_dead; } +#if !defined(CONFIG_HTTP_PARSER_URL_ONLY) static int parser_header_state(struct http_parser *parser, char ch, char c) { @@ -2624,6 +2633,7 @@ const char *http_errno_description(enum http_errno err) return http_strerror_tab[err].description; } +#endif /* !CONFIG_HTTP_PARSER_URL_ONLY */ static enum http_host_state http_parse_host_char(enum http_host_state s, const char ch) @@ -2906,6 +2916,7 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, return 0; } +#if !defined(CONFIG_HTTP_PARSER_URL_ONLY) void http_parser_pause(struct http_parser *parser, int paused) { /* Users should only be pausing/unpausing a parser that is not in an @@ -2933,3 +2944,4 @@ unsigned long http_parser_version(void) HTTP_PARSER_VERSION_MINOR * 0x00100 | HTTP_PARSER_VERSION_PATCH * 0x00001; } +#endif /* !CONFIG_HTTP_PARSER_URL_ONLY */ From 9720fa0ea4340a170c7afc0978d545599bab1cbd Mon Sep 17 00:00:00 2001 From: Robert Chou Date: Wed, 5 Jul 2017 23:07:41 +0800 Subject: [PATCH 05/37] net: lwm2m: add state machine for firmware pull update 1. Parse firmware pull URI 2. Add lwm2m_firmware_get/set_update_cb() for applicaiton to register callback. This is because we want to check the update_state before we pass to the application 3. Add lwm2m_firmware_get/set_update_result() and lwm2m_firmware_get/set_update_stat() to manage the state trasnition as well as the sanity check Signed-off-by: Robert Chou [michael.scott@linaro.org: rebased on net_app framework and lwm2m_message refactoring.] Signed-off-by: Michael Scott --- include/net/lwm2m.h | 6 + samples/net/lwm2m_client/src/lwm2m-client.c | 10 +- subsys/net/lib/lwm2m/Kconfig | 1 + subsys/net/lib/lwm2m/lwm2m_engine.h | 7 + subsys/net/lib/lwm2m/lwm2m_obj_firmware.c | 179 ++++++++++++- .../net/lib/lwm2m/lwm2m_obj_firmware_pull.c | 252 +++++++++++++----- 6 files changed, 389 insertions(+), 66 deletions(-) diff --git a/include/net/lwm2m.h b/include/net/lwm2m.h index fab071b2e3ae7..69eb503c21422 100644 --- a/include/net/lwm2m.h +++ b/include/net/lwm2m.h @@ -158,9 +158,15 @@ int lwm2m_device_add_err(u8_t error_code); #define RESULT_UPDATE_FAILED 8 #define RESULT_UNSUP_PROTO 9 +#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT) +#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT) void lwm2m_firmware_set_write_cb(lwm2m_engine_set_data_cb_t cb); lwm2m_engine_set_data_cb_t lwm2m_firmware_get_write_cb(void); +void lwm2m_firmware_set_update_cb(lwm2m_engine_exec_cb_t cb); +lwm2m_engine_exec_cb_t lwm2m_firmware_get_update_cb(void); +#endif +#endif /* LWM2M Engine */ diff --git a/samples/net/lwm2m_client/src/lwm2m-client.c b/samples/net/lwm2m_client/src/lwm2m-client.c index c95f449176d13..6ffbcc57c2849 100644 --- a/samples/net/lwm2m_client/src/lwm2m-client.c +++ b/samples/net/lwm2m_client/src/lwm2m-client.c @@ -150,6 +150,14 @@ static int device_factory_default_cb(u16_t obj_inst_id) static int firmware_update_cb(u16_t obj_inst_id) { SYS_LOG_DBG("UPDATE"); + + /* TODO: kick off update process */ + + /* If success, set the update result as RESULT_SUCCESS. + * In reality, it should be set at function lwm2m_setup() + */ + lwm2m_engine_set_u8("5/0/3", STATE_IDLE); + lwm2m_engine_set_u8("5/0/5", RESULT_SUCCESS); return 1; } @@ -207,7 +215,7 @@ static int lwm2m_setup(void) lwm2m_engine_register_post_write_callback("5/0/0", firmware_block_received_cb); lwm2m_firmware_set_write_cb(firmware_block_received_cb); - lwm2m_engine_register_exec_callback("5/0/2", firmware_update_cb); + lwm2m_firmware_set_update_cb(firmware_update_cb); /* setup TEMP SENSOR object */ diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 1e8ea9dd14f97..6def7217e8f7d 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -130,6 +130,7 @@ config LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT bool "Firmware Update object pull support" default y depends on LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT + select HTTP_PARSER_URL_ONLY help Include support for pulling a file from a remote server via block transfer and "FIRMWARE PACKAGE URI" resource. This option diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index 76b08a35c2691..d7763adb51f40 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -75,4 +75,11 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, bool handle_separate_response, udp_request_handler_cb_t udp_request_handler); +#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT) +u8_t lwm2m_firmware_get_update_state(void); +void lwm2m_firmware_set_update_state(u8_t state); +void lwm2m_firmware_set_update_result(u8_t result); +u8_t lwm2m_firmware_get_update_result(void); +#endif + #endif /* LWM2M_ENGINE_H */ diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c index 7c611bae0f330..883c45139b971 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c @@ -59,11 +59,124 @@ static struct lwm2m_engine_obj_inst inst; static struct lwm2m_engine_res_inst res[FIRMWARE_MAX_ID]; static lwm2m_engine_set_data_cb_t write_cb; +static lwm2m_engine_exec_cb_t update_cb; #ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT extern int lwm2m_firmware_start_transfer(char *package_uri); #endif +u8_t lwm2m_firmware_get_update_state(void) +{ + return update_state; +} + +void lwm2m_firmware_set_update_state(u8_t state) +{ + bool error = false; + + /* Check LWM2M SPEC appendix E.6.1 */ + switch (state) { + case STATE_DOWNLOADING: + if (update_state != STATE_IDLE) { + error = true; + } + break; + case STATE_DOWNLOADED: + if (update_state != STATE_DOWNLOADING && + update_state != STATE_UPDATING) { + error = true; + } + break; + case STATE_UPDATING: + if (update_state != STATE_DOWNLOADED) { + error = true; + } + break; + case STATE_IDLE: + break; + default: + SYS_LOG_ERR("Unhandled state: %u", state); + return; + } + + if (error) { + SYS_LOG_ERR("Invalid state transition: %u -> %u", + update_state, state); + } + + update_state = state; + NOTIFY_OBSERVER(LWM2M_OBJECT_FIRMWARE_ID, 0, FIRMWARE_STATE_ID); + SYS_LOG_DBG("Update state = %d", update_state); +} + +u8_t lwm2m_firmware_get_update_result(void) +{ + return update_result; +} + +void lwm2m_firmware_set_update_result(u8_t result) +{ + u8_t state; + bool error = false; + + /* Check LWM2M SPEC appendix E.6.1 */ + switch (result) { + case RESULT_DEFAULT: + lwm2m_firmware_set_update_state(STATE_IDLE); + break; + case RESULT_SUCCESS: + if (update_state != STATE_UPDATING) { + error = true; + state = update_state; + } + + lwm2m_firmware_set_update_state(STATE_IDLE); + break; + case RESULT_NO_STORAGE: + case RESULT_OUT_OF_MEM: + case RESULT_CONNECTION_LOST: + case RESULT_UNSUP_FW: + case RESULT_INVALID_URI: + case RESULT_UNSUP_PROTO: + if (update_state != STATE_DOWNLOADING) { + error = true; + state = update_state; + } + + lwm2m_firmware_set_update_state(STATE_IDLE); + break; + case RESULT_INTEGRITY_FAILED: + if (update_state != STATE_DOWNLOADING && + update_state != STATE_UPDATING) { + error = true; + state = update_state; + } + + lwm2m_firmware_set_update_state(STATE_IDLE); + break; + case RESULT_UPDATE_FAILED: + if (update_state != STATE_UPDATING) { + error = true; + state = update_state; + } + + /* Next state could be idle or downloaded */ + break; + default: + SYS_LOG_ERR("Unhandled result: %u", result); + return; + } + + if (error) { + SYS_LOG_ERR("Unexpected result(%u) set while state is %u", + result, state); + } + + update_result = result; + NOTIFY_OBSERVER(LWM2M_OBJECT_FIRMWARE_ID, 0, FIRMWARE_UPDATE_RESULT_ID); + SYS_LOG_DBG("Update result = %d", update_result); +} + static int package_write_cb(u16_t obj_inst_id, u8_t *data, u16_t data_len, bool last_block, size_t total_size) @@ -82,10 +195,21 @@ static int package_uri_write_cb(u16_t obj_inst_id, bool last_block, size_t total_size) { SYS_LOG_DBG("PACKAGE_URI WRITE: %s", package_uri); -#ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT - lwm2m_firmware_start_transfer(package_uri); - return 1; -#endif + + if (IS_ENABLED(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT)) { + u8_t state = lwm2m_firmware_get_update_state(); + + if (state == STATE_IDLE) { + lwm2m_firmware_set_update_result(RESULT_DEFAULT); + lwm2m_firmware_start_transfer(package_uri); + } else if (state == STATE_DOWNLOADED && data_len == 0) { + /* reset to state idle and result default */ + lwm2m_firmware_set_update_result(RESULT_DEFAULT); + } + + return 1; + } + return 0; } @@ -99,6 +223,48 @@ lwm2m_engine_set_data_cb_t lwm2m_firmware_get_write_cb(void) return write_cb; } +void lwm2m_firmware_set_update_cb(lwm2m_engine_exec_cb_t cb) +{ + update_cb = cb; +} + +lwm2m_engine_exec_cb_t lwm2m_firmware_get_update_cb(void) +{ + return update_cb; +} + +static int firmware_update_cb(u16_t obj_inst_id) +{ + lwm2m_engine_exec_cb_t callback; + u8_t state; + int ret; + + state = lwm2m_firmware_get_update_state(); + if (state != STATE_DOWNLOADED) { + /* TODO: pass response code to caller, -1 will be shown as + * 4.05 method not allowed in current implementation + */ + SYS_LOG_ERR("State other than downloaded: %d", state); + return -1; + } + + lwm2m_firmware_set_update_state(STATE_UPDATING); + + callback = lwm2m_firmware_get_update_cb(); + if (callback) { + ret = callback(obj_inst_id); + if (ret < 0) { + SYS_LOG_ERR("Failed to update firmware: %d", ret); + lwm2m_firmware_set_update_result( + ret == -EINVAL ? RESULT_INTEGRITY_FAILED : + RESULT_UPDATE_FAILED); + return 0; + } + } + + return 0; +} + static struct lwm2m_engine_obj_inst *firmware_create(u16_t obj_inst_id) { int i = 0; @@ -109,7 +275,8 @@ static struct lwm2m_engine_obj_inst *firmware_create(u16_t obj_inst_id) INIT_OBJ_RES(res, i, FIRMWARE_PACKAGE_URI_ID, 0, package_uri, PACKAGE_URI_LEN, NULL, NULL, package_uri_write_cb, NULL); - INIT_OBJ_RES_DUMMY(res, i, FIRMWARE_UPDATE_ID); + INIT_OBJ_RES_EXECUTE(res, i, FIRMWARE_UPDATE_ID, + firmware_update_cb); INIT_OBJ_RES_DATA(res, i, FIRMWARE_STATE_ID, &update_state, sizeof(update_state)); INIT_OBJ_RES_DATA(res, i, FIRMWARE_UPDATE_RESULT_ID, @@ -130,6 +297,8 @@ static int lwm2m_firmware_init(struct device *dev) /* Set default values */ package_uri[0] = '\0'; + /* Initialize state machine */ + /* TODO: should be restored from the permanent storage */ update_state = STATE_IDLE; update_result = RESULT_DEFAULT; #ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c index 43e20bd4d581a..eeae34d125c16 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c @@ -4,38 +4,33 @@ * SPDX-License-Identifier: Apache-2.0 */ -/* - * TODO: - * Support PULL transfer method (from server) - */ - #define SYS_LOG_DOMAIN "lwm2m_obj_firmware_pull" #define SYS_LOG_LEVEL CONFIG_SYS_LOG_LWM2M_LEVEL #include +#include #include +#include #include #include #include +#include #include #include #include "lwm2m_object.h" #include "lwm2m_engine.h" -#define STATE_IDLE 0 -#define STATE_CONNECTING 1 - #define PACKAGE_URI_LEN 255 #define BUF_ALLOC_TIMEOUT K_SECONDS(1) #define NETWORK_INIT_TIMEOUT K_SECONDS(10) #define NETWORK_CONNECT_TIMEOUT K_SECONDS(10) -static u8_t transfer_state; static struct k_work firmware_work; static char firmware_uri[PACKAGE_URI_LEN]; static struct sockaddr firmware_addr; +static struct http_parser_url parsed_uri; static struct lwm2m_ctx firmware_ctx; static struct zoap_block_context firmware_block_ctx; @@ -48,7 +43,7 @@ firmware_udp_receive(struct net_app_ctx *app_ctx, struct net_pkt *pkt, static void do_transmit_timeout_cb(struct lwm2m_message *msg) { - /* TODO: Handle timeout */ + lwm2m_firmware_set_update_result(RESULT_CONNECTION_LOST); } static int transfer_request(struct zoap_block_context *ctx, @@ -57,6 +52,11 @@ static int transfer_request(struct zoap_block_context *ctx, { struct lwm2m_message *msg; int ret; + int i; + int path_len; + char *cursor; + u16_t off; + u16_t len; msg = lwm2m_get_message(&firmware_ctx); if (!msg) { @@ -77,14 +77,43 @@ static int transfer_request(struct zoap_block_context *ctx, goto cleanup; } - /* hard code URI path here -- should be pulled from package_uri */ - ret = zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_PATH, - "large-create", sizeof("large-create") - 1); - ret = zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_PATH, - "1", sizeof("1") - 1); - if (ret < 0) { - SYS_LOG_ERR("Error adding URI_QUERY 'large'"); - goto cleanup; + /* if path is not available, off/len will be zero */ + off = parsed_uri.field_data[UF_PATH].off; + len = parsed_uri.field_data[UF_PATH].len; + cursor = firmware_uri + off; + path_len = 0; + + for (i = 0; i < len; i++) { + if (firmware_uri[off + i] == '/') { + if (path_len > 0) { + ret = zoap_add_option(&msg->zpkt, + ZOAP_OPTION_URI_PATH, + cursor, path_len); + if (ret < 0) { + SYS_LOG_ERR("Error adding URI_PATH"); + goto cleanup; + } + + cursor += path_len + 1; + path_len = 0; + } else { + /* skip current slash */ + cursor += 1; + } + continue; + } + + if (i == len - 1) { + /* flush the rest */ + ret = zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_PATH, + cursor, path_len + 1); + if (ret < 0) { + SYS_LOG_ERR("Error adding URI_PATH"); + goto cleanup; + } + break; + } + path_len += 1; } ret = zoap_add_block2_option(&msg->zpkt, ctx); @@ -93,6 +122,13 @@ static int transfer_request(struct zoap_block_context *ctx, goto cleanup; } + /* Ask the server to provide a size estimate */ + ret = zoap_add_option_int(&msg->zpkt, ZOAP_OPTION_SIZE2, 0); + if (ret) { + SYS_LOG_ERR("Unable to add size2 option."); + goto cleanup; + } + /* send request */ ret = lwm2m_send_message(msg); if (ret < 0) { @@ -104,6 +140,13 @@ static int transfer_request(struct zoap_block_context *ctx, cleanup: lwm2m_release_message(msg); + + if (ret == -ENOMEM) { + lwm2m_firmware_set_update_result(RESULT_OUT_OF_MEM); + } else { + lwm2m_firmware_set_update_result(RESULT_CONNECTION_LOST); + } + return ret; } @@ -120,40 +163,64 @@ do_firmware_transfer_reply_cb(const struct zoap_packet *response, u8_t *payload; struct zoap_packet *check_response = (struct zoap_packet *)response; lwm2m_engine_set_data_cb_t callback; - - SYS_LOG_DBG("TRANSFER REPLY"); + u8_t resp_code; + + /* Check response code from server. Expecting (2.05) */ + resp_code = zoap_header_get_code(check_response); + if (resp_code != ZOAP_RESPONSE_CODE_CONTENT) { + SYS_LOG_ERR("Unexpected response from server: %d.%d", + ZOAP_RESPONSE_CODE_CLASS(resp_code), + ZOAP_RESPONSE_CODE_DETAIL(resp_code)); + lwm2m_firmware_set_update_result(RESULT_CONNECTION_LOST); + return -ENOENT; + } ret = zoap_update_from_block(check_response, &firmware_block_ctx); if (ret < 0) { SYS_LOG_ERR("Error from block update: %d", ret); + lwm2m_firmware_set_update_result(RESULT_INTEGRITY_FAILED); return ret; } - /* TODO: Process incoming data */ + /* Reach last block if transfer_offset equals to 0 */ + transfer_offset = zoap_next_block(check_response, &firmware_block_ctx); + + /* Process incoming data */ payload = zoap_packet_get_payload(check_response, &payload_len); if (payload_len > 0) { - /* TODO: Determine when to actually advance to next block */ - transfer_offset = zoap_next_block(response, - &firmware_block_ctx); - SYS_LOG_DBG("total: %zd, current: %zd", firmware_block_ctx.total_size, firmware_block_ctx.current); - /* callback */ callback = lwm2m_firmware_get_write_cb(); if (callback) { - callback(0, payload, payload_len, - transfer_offset == 0, - firmware_block_ctx.total_size); + ret = callback(0, payload, payload_len, + transfer_offset == 0, + firmware_block_ctx.total_size); + if (ret == -ENOMEM) { + lwm2m_firmware_set_update_result( + RESULT_OUT_OF_MEM); + return ret; + } else if (ret == -ENOSPC) { + lwm2m_firmware_set_update_result( + RESULT_NO_STORAGE); + return ret; + } else if (ret < 0) { + lwm2m_firmware_set_update_result( + RESULT_INTEGRITY_FAILED); + return ret; + } } } - /* TODO: Determine actual completion criteria */ if (transfer_offset > 0) { + /* More block(s) to come, setup next transfer */ token = zoap_header_get_token(check_response, &tkl); ret = transfer_request(&firmware_block_ctx, token, tkl, do_firmware_transfer_reply_cb); + } else { + /* Download finished */ + lwm2m_firmware_set_update_state(STATE_DOWNLOADED); } return ret; @@ -183,48 +250,116 @@ static enum zoap_block_size default_block_size(void) static void firmware_transfer(struct k_work *work) { - int ret, port, family; + int ret, family; + u16_t off; + u16_t len; + char tmp; /* Server Peer IP information */ - /* TODO: use parser on firmware_uri to determine IP version + port */ - /* TODO: hard code IPv4 + port for now */ - port = 5685; family = AF_INET; -#if defined(CONFIG_NET_IPV6) - if (family == AF_INET6) { + http_parser_url_init(&parsed_uri); + ret = http_parser_parse_url(firmware_uri, + strlen(firmware_uri), + 0, + &parsed_uri); + if (ret != 0) { + SYS_LOG_ERR("Invalid firmware URI: %s", firmware_uri); + lwm2m_firmware_set_update_result(RESULT_INVALID_URI); + return; + } + + /* Check schema and only support coap for now */ + if (!(parsed_uri.field_set & (1 << UF_SCHEMA))) { + SYS_LOG_ERR("No schema in package uri"); + lwm2m_firmware_set_update_result(RESULT_INVALID_URI); + return; + } + + /* TODO: enable coaps when DTLS is ready */ + off = parsed_uri.field_data[UF_SCHEMA].off; + len = parsed_uri.field_data[UF_SCHEMA].len; + if (len != 4 || memcmp(firmware_uri + off, "coap", 4)) { + SYS_LOG_ERR("Unsupported schema"); + lwm2m_firmware_set_update_result(RESULT_UNSUP_PROTO); + return; + } + + if (!(parsed_uri.field_set & (1 << UF_PORT))) { + /* Set to default port of CoAP */ + parsed_uri.port = 5683; + } + + off = parsed_uri.field_data[UF_HOST].off; + len = parsed_uri.field_data[UF_HOST].len; + + /* IPv6 is wrapped by brackets */ + if (off > 0 && firmware_uri[off - 1] == '[') { + if (!IS_ENABLED(CONFIG_NET_IPV6)) { + SYS_LOG_ERR("Doesn't support IPv6"); + lwm2m_firmware_set_update_result(RESULT_UNSUP_PROTO); + return; + } + + family = AF_INET6; + } else { + /* Distinguish IPv4 or DNS */ + for (int i = off; i < off + len; i++) { + if (!isdigit(firmware_uri[i]) && + firmware_uri[i] != '.') { + SYS_LOG_ERR("Doesn't support DNS lookup"); + lwm2m_firmware_set_update_result( + RESULT_UNSUP_PROTO); + return; + } + } + + if (!IS_ENABLED(CONFIG_NET_IPV4)) { + SYS_LOG_ERR("Doesn't support IPv4"); + lwm2m_firmware_set_update_result(RESULT_UNSUP_PROTO); + return; + } + + family = AF_INET; + } + + tmp = firmware_uri[off + len]; + firmware_uri[off + len] = '\0'; + + if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) { firmware_addr.sa_family = family; - /* HACK: use firmware_uri directly as IP address */ - net_addr_pton(firmware_addr.sa_family, firmware_uri, + net_addr_pton(firmware_addr.sa_family, firmware_uri + off, &net_sin6(&firmware_addr)->sin6_addr); - net_sin6(&firmware_addr)->sin6_port = htons(5685); + net_sin6(&firmware_addr)->sin6_port = htons(parsed_uri.port); } -#endif -#if defined(CONFIG_NET_IPV4) - if (family == AF_INET) { + if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) { firmware_addr.sa_family = family; - net_addr_pton(firmware_addr.sa_family, firmware_uri, + net_addr_pton(firmware_addr.sa_family, firmware_uri + off, &net_sin(&firmware_addr)->sin_addr); - net_sin(&firmware_addr)->sin_port = htons(5685); + net_sin(&firmware_addr)->sin_port = htons(parsed_uri.port); } -#endif + + /* restore firmware_uri */ + firmware_uri[off + len] = tmp; ret = net_app_init_udp_client(&firmware_ctx.net_app_ctx, NULL, - &firmware_addr, NULL, port, + &firmware_addr, NULL, parsed_uri.port, firmware_ctx.net_init_timeout, NULL); if (ret) { - NET_ERR("Could not get an UDP context (err:%d)", ret); + SYS_LOG_ERR("Could not get an UDP context (err:%d)", ret); + lwm2m_firmware_set_update_result(RESULT_CONNECTION_LOST); return; } - SYS_LOG_DBG("Attached to port: %d", port); + SYS_LOG_DBG("Attached to port: %d", parsed_uri.port); /* set net_app callbacks */ ret = net_app_set_cb(&firmware_ctx.net_app_ctx, NULL, firmware_udp_receive, NULL, NULL); if (ret) { SYS_LOG_ERR("Could not set receive callback (err:%d)", ret); + lwm2m_firmware_set_update_result(RESULT_CONNECTION_LOST); goto cleanup; } @@ -237,7 +372,6 @@ static void firmware_transfer(struct k_work *work) /* reset block transfer context */ zoap_block_transfer_init(&firmware_block_ctx, default_block_size(), 0); - transfer_request(&firmware_block_ctx, NULL, 0, do_firmware_transfer_reply_cb); return; @@ -261,17 +395,15 @@ int lwm2m_firmware_start_transfer(char *package_uri) net_app_release(&firmware_ctx.net_app_ctx); } - if (transfer_state == STATE_IDLE) { - memset(&firmware_ctx, 0, sizeof(struct lwm2m_ctx)); - firmware_ctx.net_init_timeout = NETWORK_INIT_TIMEOUT; - firmware_ctx.net_timeout = NETWORK_CONNECT_TIMEOUT; - k_work_init(&firmware_work, firmware_transfer); + memset(&firmware_ctx, 0, sizeof(struct lwm2m_ctx)); + firmware_ctx.net_init_timeout = NETWORK_INIT_TIMEOUT; + firmware_ctx.net_timeout = NETWORK_CONNECT_TIMEOUT; + k_work_init(&firmware_work, firmware_transfer); + lwm2m_firmware_set_update_state(STATE_DOWNLOADING); - /* start file transfer work */ - strncpy(firmware_uri, package_uri, PACKAGE_URI_LEN - 1); - k_work_submit(&firmware_work); - return 0; - } + /* start file transfer work */ + strncpy(firmware_uri, package_uri, PACKAGE_URI_LEN - 1); + k_work_submit(&firmware_work); - return -1; + return 0; } From c5c578d8d7ec82d88056b71aa2a1258eb332eed3 Mon Sep 17 00:00:00 2001 From: Robert Chou Date: Wed, 23 Aug 2017 10:37:57 +0800 Subject: [PATCH 06/37] net: lwm2m: setup data_ptr/len for OPAQUE resource when none given OPAQUE resource type might/might not have data_ptr/data_len setup depending on the implementation. This introduce an issue that when OPAQUE resource is written from the server side, the ones w/ none setup will not be able to get the data at post_write_cb() Modify to setup data_ptr/data_len as incoming buffer and buffer size Signed-off-by: Robert Chou --- subsys/net/lib/lwm2m/lwm2m_engine.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 855acf4365338..c86d4f85a65fb 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -1704,6 +1704,13 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, data_ptr = res->data_ptr; data_len = res->data_len; + /* setup data_ptr/data_len for OPAQUE when it has none setup */ + if (obj_field->data_type == LWM2M_RES_TYPE_OPAQUE && + data_ptr == NULL && data_len == 0) { + data_ptr = in->inbuf; + data_len = in->insize; + } + /* allow user to override data elements via callback */ if (res->pre_write_cb) { data_ptr = res->pre_write_cb(obj_inst->obj_inst_id, &data_len); From e72bfed394b9cc0e7a326054a2ab3c5a1e2a4117 Mon Sep 17 00:00:00 2001 From: Robert Chou Date: Tue, 25 Jul 2017 16:54:25 +0800 Subject: [PATCH 07/37] net: lwm2m: add firmware push support 1. Add handling block1 option in handle_request(). The basic idea is to declare structure block_context at compiled time and use "token" as a key to pick up the on-going block cotext. It should be able to support multiple blockwise transfer concurrently 2. Use write callback implemented in lwm2m_obj_firmware to deal w/ the update state transition and than call the callback registered by the application 3. move default_block_size to lwm2m_engine.c to share btw lwm2m_engine and lwm2m_obj_firmware_pull Signed-off-by: Robert Chou [michael.scott@linaro.org: rebased on LwM2M net_app changes.] Signed-off-by: Michael Scott --- include/net/lwm2m.h | 2 +- samples/net/lwm2m_client/src/lwm2m-client.c | 10 +- subsys/net/lib/lwm2m/Kconfig | 14 +- subsys/net/lib/lwm2m/lwm2m_engine.c | 283 +++++++++++++++--- subsys/net/lib/lwm2m/lwm2m_engine.h | 2 + subsys/net/lib/lwm2m/lwm2m_obj_firmware.c | 36 ++- .../net/lib/lwm2m/lwm2m_obj_firmware_pull.c | 25 +- 7 files changed, 290 insertions(+), 82 deletions(-) diff --git a/include/net/lwm2m.h b/include/net/lwm2m.h index 69eb503c21422..b1d5c23f9a7a5 100644 --- a/include/net/lwm2m.h +++ b/include/net/lwm2m.h @@ -159,10 +159,10 @@ int lwm2m_device_add_err(u8_t error_code); #define RESULT_UNSUP_PROTO 9 #if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT) -#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT) void lwm2m_firmware_set_write_cb(lwm2m_engine_set_data_cb_t cb); lwm2m_engine_set_data_cb_t lwm2m_firmware_get_write_cb(void); +#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT) void lwm2m_firmware_set_update_cb(lwm2m_engine_exec_cb_t cb); lwm2m_engine_exec_cb_t lwm2m_firmware_get_update_cb(void); #endif diff --git a/samples/net/lwm2m_client/src/lwm2m-client.c b/samples/net/lwm2m_client/src/lwm2m-client.c index 6ffbcc57c2849..347bb667a49af 100644 --- a/samples/net/lwm2m_client/src/lwm2m-client.c +++ b/samples/net/lwm2m_client/src/lwm2m-client.c @@ -147,6 +147,7 @@ static int device_factory_default_cb(u16_t obj_inst_id) return 1; } +#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT) static int firmware_update_cb(u16_t obj_inst_id) { SYS_LOG_DBG("UPDATE"); @@ -160,7 +161,9 @@ static int firmware_update_cb(u16_t obj_inst_id) lwm2m_engine_set_u8("5/0/5", RESULT_SUCCESS); return 1; } +#endif +#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT) static int firmware_block_received_cb(u16_t obj_inst_id, u8_t *data, u16_t data_len, bool last_block, size_t total_size) @@ -169,6 +172,7 @@ static int firmware_block_received_cb(u16_t obj_inst_id, data_len, last_block); return 1; } +#endif static int lwm2m_setup(void) { @@ -212,10 +216,12 @@ static int lwm2m_setup(void) /* setup FIRMWARE object */ - lwm2m_engine_register_post_write_callback("5/0/0", - firmware_block_received_cb); +#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT) lwm2m_firmware_set_write_cb(firmware_block_received_cb); +#endif +#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT) lwm2m_firmware_set_update_cb(firmware_update_cb); +#endif /* setup TEMP SENSOR object */ diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 6def7217e8f7d..99dd3b229552f 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -136,17 +136,23 @@ config LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT block transfer and "FIRMWARE PACKAGE URI" resource. This option adds another UDP context and packet handling. -config LWM2M_FIRMWARE_UPDATE_PULL_COAP_BLOCK_SIZE - int "Firmware Update object pull CoAP block size" - depends on LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT +config LWM2M_COAP_BLOCK_SIZE + int "LWM2M CoAP block-wise transfer size" default 256 default 64 if NET_L2_BT default 64 if NET_L2_IEEE802154 range 16 1024 help - CoAP block size used by firmware pull when performing block-wise + CoAP block size used by LWM2M when performing block-wise transfers. Possible values: 16, 32, 64, 128, 256, 512 and 1024. +config LWM2M_NUM_BLOCK1_CONTEXT + int "Maximum # of LWM2M block1 contexts" + default 3 + help + This value sets up the maximum number of block1 contexts for + CoAP block-wise transfer we can handle at the same time. + config LWM2M_RW_JSON_SUPPORT bool "support for JSON writer" default y diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index c86d4f85a65fb..093440d2105c5 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -16,8 +16,6 @@ * * - Use server / security object instance 0 for initial connection * - Add DNS support for security uri parsing - * - Block-transfer support / Large response messages - * (use Block2 to limit message size to 64 bytes for 6LOWPAN compat.) * - BOOTSTRAP/DTLS cleanup * - Handle WRITE_ATTRIBUTES (pmin=10&pmax=60) * - Handle Resource ObjLink type @@ -102,6 +100,24 @@ static sys_slist_t engine_obj_list; static sys_slist_t engine_obj_inst_list; static sys_slist_t engine_observer_list; +#define NUM_BLOCK1_CONTEXT CONFIG_LWM2M_NUM_BLOCK1_CONTEXT + +/* TODO: figure out what's correct value */ +#define TIMEOUT_BLOCKWISE_TRANSFER K_SECONDS(30) + +#define GET_BLOCK_NUM(v) ((v) >> 4) +#define GET_BLOCK_SIZE(v) (((v) & 0x7)) +#define GET_MORE(v) (!!((v) & 0x08)) + +struct block_context { + struct zoap_block_context ctx; + s64_t timestamp; + u8_t token[8]; + u8_t tkl; +}; + +static struct block_context block1_contexts[NUM_BLOCK1_CONTEXT]; + /* periodic / notify / observe handling stack */ static K_THREAD_STACK_DEFINE(engine_thread_stack, CONFIG_LWM2M_ENGINE_STACK_SIZE); @@ -155,6 +171,101 @@ static char *sprint_token(const u8_t *token, u8_t tkl) } #endif +/* block-wise transfer functions */ + +enum zoap_block_size lwm2m_default_block_size(void) +{ + switch (CONFIG_LWM2M_COAP_BLOCK_SIZE) { + case 16: + return ZOAP_BLOCK_16; + case 32: + return ZOAP_BLOCK_32; + case 64: + return ZOAP_BLOCK_64; + case 128: + return ZOAP_BLOCK_128; + case 256: + return ZOAP_BLOCK_256; + case 512: + return ZOAP_BLOCK_512; + case 1024: + return ZOAP_BLOCK_1024; + } + + return ZOAP_BLOCK_256; +} + +static int +init_block_ctx(const u8_t *token, u8_t tkl, struct block_context **ctx) +{ + int i; + s64_t timestamp; + + *ctx = NULL; + timestamp = k_uptime_get(); + for (i = 0; i < NUM_BLOCK1_CONTEXT; i++) { + if (block1_contexts[i].tkl == 0) { + *ctx = &block1_contexts[i]; + break; + } + + if (timestamp - block1_contexts[i].timestamp > + TIMEOUT_BLOCKWISE_TRANSFER) { + *ctx = &block1_contexts[i]; + /* TODO: notify application for block + * transfer timeout + */ + break; + } + } + + if (*ctx == NULL) { + SYS_LOG_ERR("Cannot find free block context"); + return -ENOMEM; + } + + (*ctx)->tkl = tkl; + memcpy((*ctx)->token, token, tkl); + zoap_block_transfer_init(&(*ctx)->ctx, lwm2m_default_block_size(), 0); + (*ctx)->timestamp = timestamp; + + return 0; +} + +static int +get_block_ctx(const u8_t *token, u8_t tkl, struct block_context **ctx) +{ + int i; + + *ctx = NULL; + + for (i = 0; i < NUM_BLOCK1_CONTEXT; i++) { + if (block1_contexts[i].tkl == tkl && + memcmp(token, block1_contexts[i].token, tkl) == 0) { + *ctx = &block1_contexts[i]; + /* refresh timestmap */ + (*ctx)->timestamp = k_uptime_get(); + break; + } + } + + if (*ctx == NULL) { + SYS_LOG_ERR("Cannot find block context"); + return -ENOENT; + } + + return 0; +} + +static void free_block_ctx(struct block_context *ctx) +{ + if (ctx == NULL) { + return; + } + + ctx->tkl = 0; +} + /* observer functions */ int lwm2m_notify_observer(u16_t obj_id, u16_t obj_inst_id, u16_t res_id) @@ -525,6 +636,20 @@ int lwm2m_delete_obj_inst(u16_t obj_id, u16_t obj_inst_id) /* utility functions */ +static int get_option_int(const struct zoap_packet *zpkt, u8_t opt) +{ + struct zoap_option option = {}; + u16_t count = 1; + int r; + + r = zoap_find_options(zpkt, opt, &option, count); + if (r <= 0) { + return -ENOENT; + } + + return zoap_option_value_to_int(&option); +} + static void engine_clear_context(struct lwm2m_engine_context *context) { if (context->in) { @@ -1695,6 +1820,12 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, void *data_ptr = NULL; size_t data_len = 0; size_t len = 0; + size_t total_size = 0; + int ret = 0; + u8_t tkl = 0; + const u8_t *token; + bool last_block = true; + struct block_context *block_ctx = NULL; if (!obj_inst || !res || !obj_field || !context) { return -EINVAL; @@ -1716,8 +1847,6 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, data_ptr = res->pre_write_cb(obj_inst->obj_inst_id, &data_len); } - /* TODO: check for block transfer fields here */ - if (data_ptr && data_len > 0) { switch (obj_field->data_type) { @@ -1805,14 +1934,30 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, } if (res->post_write_cb) { + /* Get block1 option for checking MORE block flag */ + ret = get_option_int(in->in_zpkt, ZOAP_OPTION_BLOCK1); + if (ret >= 0) { + last_block = !GET_MORE(ret); + + /* Get block_ctx for total_size (might be zero) */ + token = zoap_header_get_token(in->in_zpkt, &tkl); + if (token != NULL && + !get_block_ctx(token, tkl, &block_ctx)) { + total_size = block_ctx->ctx.total_size; + } + } + /* ignore return value here */ - res->post_write_cb(obj_inst->obj_inst_id, data_ptr, len, - false, 0); + ret = res->post_write_cb(obj_inst->obj_inst_id, data_ptr, len, + last_block, total_size); + if (ret >= 0) { + ret = 0; + } } NOTIFY_OBSERVER_PATH(path); - return 0; + return ret; } static int lwm2m_write_attr_handler(struct lwm2m_engine_obj *obj, @@ -2100,20 +2245,6 @@ static int do_write_op(struct lwm2m_engine_obj *obj, } } -static int get_observe_option(const struct zoap_packet *zpkt) -{ - struct zoap_option option = {}; - u16_t count = 1; - int r; - - r = zoap_find_options(zpkt, ZOAP_OPTION_OBSERVE, &option, count); - if (r <= 0) { - return -ENOENT; - } - - return zoap_option_value_to_int(&option); -} - static int handle_request(struct zoap_packet *request, struct lwm2m_message *msg) { @@ -2130,6 +2261,9 @@ static int handle_request(struct zoap_packet *request, struct lwm2m_engine_context context; int observe = -1; /* default to -1, 0 = ENABLE, 1 = DISABLE */ bool discover = false; + struct block_context *block_ctx = NULL; + size_t block_offset = 0; + enum zoap_block_size block_size; /* setup engine context */ memset(&context, 0, sizeof(struct lwm2m_engine_context)); @@ -2205,7 +2339,7 @@ static int handle_request(struct zoap_packet *request, context.operation = LWM2M_OP_READ; } /* check for observe */ - observe = get_observe_option(in.in_zpkt); + observe = get_option_int(in.in_zpkt, ZOAP_OPTION_OBSERVE); zoap_header_set_code(out.out_zpkt, ZOAP_RESPONSE_CODE_CONTENT); break; @@ -2242,7 +2376,31 @@ static int handle_request(struct zoap_packet *request, in.inpos = 0; in.inbuf = zoap_packet_get_payload(in.in_zpkt, &in.insize); - /* TODO: check for block transfer? */ + /* Check for block transfer */ + r = get_option_int(in.in_zpkt, ZOAP_OPTION_BLOCK1); + if (r > 0) { + /* RFC7252: 4.6. Message Size */ + block_size = GET_BLOCK_SIZE(r); + if (GET_MORE(r) && + zoap_block_size_to_bytes(block_size) > in.insize) { + SYS_LOG_DBG("Trailing payload is discarded!"); + r = -EFBIG; + goto error; + } + + if (GET_BLOCK_NUM(r) == 0) { + r = init_block_ctx(token, tkl, &block_ctx); + } else { + r = get_block_ctx(token, tkl, &block_ctx); + } + + if (r < 0) { + goto error; + } + + /* 0 will be returned if it's the last block */ + block_offset = zoap_next_block(in.in_zpkt, &block_ctx->ctx); + } switch (context.operation) { @@ -2312,37 +2470,63 @@ static int handle_request(struct zoap_packet *request, return -EINVAL; } - if (r == 0) { - /* TODO: Handle blockwise 1 */ + if (r) { + goto error; + } - if (out.outlen > 0) { - SYS_LOG_DBG("replying with %u bytes", out.outlen); - zoap_packet_set_used(out.out_zpkt, out.outlen); + /* Handle blockwise 1 */ + if (block_ctx) { + if (block_offset > 0) { + /* More to come, ack with correspond block # */ + r = zoap_add_block1_option( + out.out_zpkt, &block_ctx->ctx); + if (r) { + /* report as internal server error */ + SYS_LOG_ERR("Fail adding block1 option: %d", r); + r = -EINVAL; + goto error; + } else { + zoap_header_set_code(out.out_zpkt, + ZOAP_RESPONSE_CODE_CONTINUE); + } } else { - SYS_LOG_DBG("no data in reply"); + /* Free context when finished */ + free_block_ctx(block_ctx); } + } + + if (out.outlen > 0) { + SYS_LOG_DBG("replying with %u bytes", out.outlen); + zoap_packet_set_used(out.out_zpkt, out.outlen); } else { - if (r == -ENOENT) { - zoap_header_set_code(out.out_zpkt, - ZOAP_RESPONSE_CODE_NOT_FOUND); - r = 0; - } else if (r == -EPERM) { - zoap_header_set_code(out.out_zpkt, - ZOAP_RESPONSE_CODE_NOT_ALLOWED); - r = 0; - } else if (r == -EEXIST) { - zoap_header_set_code(out.out_zpkt, - ZOAP_RESPONSE_CODE_BAD_REQUEST); - r = 0; - } else { - /* Failed to handle the request */ - zoap_header_set_code(out.out_zpkt, - ZOAP_RESPONSE_CODE_INTERNAL_ERROR); - r = 0; - } + SYS_LOG_DBG("no data in reply"); } - return r; + return 0; + +error: + if (r == -ENOENT) { + zoap_header_set_code(out.out_zpkt, + ZOAP_RESPONSE_CODE_NOT_FOUND); + } else if (r == -EPERM) { + zoap_header_set_code(out.out_zpkt, + ZOAP_RESPONSE_CODE_NOT_ALLOWED); + } else if (r == -EEXIST) { + zoap_header_set_code(out.out_zpkt, + ZOAP_RESPONSE_CODE_BAD_REQUEST); + } else if (r == -EFBIG) { + zoap_header_set_code(out.out_zpkt, + ZOAP_RESPONSE_CODE_REQUEST_TOO_LARGE); + } else { + /* Failed to handle the request */ + zoap_header_set_code(out.out_zpkt, + ZOAP_RESPONSE_CODE_INTERNAL_ERROR); + } + + /* Free block context when error happened */ + free_block_ctx(block_ctx); + + return 0; } void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, @@ -2787,6 +2971,9 @@ int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, static int lwm2m_engine_init(struct device *dev) { + memset(block1_contexts, 0, + sizeof(struct block_context) * NUM_BLOCK1_CONTEXT); + /* start thread to handle OBSERVER / NOTIFY events */ k_thread_create(&engine_thread_data, &engine_thread_stack[0], diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index d7763adb51f40..ab9616d69d61a 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -75,6 +75,8 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, bool handle_separate_response, udp_request_handler_cb_t udp_request_handler); +enum zoap_block_size lwm2m_default_block_size(void); + #if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT) u8_t lwm2m_firmware_get_update_state(void); void lwm2m_firmware_set_update_state(u8_t state); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c index 883c45139b971..f4b0e70ff1aac 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c @@ -181,13 +181,41 @@ static int package_write_cb(u16_t obj_inst_id, u8_t *data, u16_t data_len, bool last_block, size_t total_size) { - SYS_LOG_DBG("PACKAGE WRITE"); + u8_t state; + int ret = 0; + + state = lwm2m_firmware_get_update_state(); + if (state == STATE_IDLE) { + /* TODO: setup timer to check download status, + * make sure it fail after timeout + */ + lwm2m_firmware_set_update_state(STATE_DOWNLOADING); + } else if (state != STATE_DOWNLOADING) { + if (data_len == 0 && state == STATE_DOWNLOADED) { + /* reset to state idle and result default */ + lwm2m_firmware_set_update_result(RESULT_DEFAULT); + return 1; + } + + SYS_LOG_DBG("Cannot download: state = %d", state); + return -EPERM; + } + if (write_cb) { - write_cb(obj_inst_id, data, data_len, last_block, total_size); - return 1; + ret = write_cb(obj_inst_id, data, data_len, + last_block, total_size); + if (ret < 0) { + SYS_LOG_ERR("Failed to store firmware: %d", ret); + lwm2m_firmware_set_update_result( + RESULT_INTEGRITY_FAILED); + } } - return 0; + if (last_block) { + lwm2m_firmware_set_update_state(STATE_DOWNLOADED); + } + + return 1; } static int package_uri_write_cb(u16_t obj_inst_id, diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c index eeae34d125c16..2cf437ec430f9 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c @@ -226,28 +226,6 @@ do_firmware_transfer_reply_cb(const struct zoap_packet *response, return ret; } -static enum zoap_block_size default_block_size(void) -{ - switch (CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_BLOCK_SIZE) { - case 16: - return ZOAP_BLOCK_16; - case 32: - return ZOAP_BLOCK_32; - case 64: - return ZOAP_BLOCK_64; - case 128: - return ZOAP_BLOCK_128; - case 256: - return ZOAP_BLOCK_256; - case 512: - return ZOAP_BLOCK_512; - case 1024: - return ZOAP_BLOCK_1024; - } - - return ZOAP_BLOCK_256; -} - static void firmware_transfer(struct k_work *work) { int ret, family; @@ -371,7 +349,8 @@ static void firmware_transfer(struct k_work *work) } /* reset block transfer context */ - zoap_block_transfer_init(&firmware_block_ctx, default_block_size(), 0); + zoap_block_transfer_init(&firmware_block_ctx, + lwm2m_default_block_size(), 0); transfer_request(&firmware_block_ctx, NULL, 0, do_firmware_transfer_reply_cb); return; From d0981fc229218b61c8be72bf68f206bd151b1430 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Wed, 6 Sep 2017 14:34:52 -0700 Subject: [PATCH 08/37] net: lwm2m: RD client start message should be INFO not DEBUG This is a useful message announcing that the RD client state machine is starting for a particular connection. If the log level is set low so that DBG messages are hidden, then this message goes away. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_rd_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index dcc50ab007449..6f8814c28a81f 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -435,7 +435,7 @@ static void do_deregister_timeout_cb(struct lwm2m_message *msg) static int sm_do_init(int index) { - SYS_LOG_DBG("RD Client started with endpoint " + SYS_LOG_INF("RD Client started with endpoint " "'%s' and client lifetime %d", clients[index].ep_name, clients[index].lifetime); From 34a2dccd4a1386b32a8996c9819993ef24fb8fb6 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Thu, 7 Sep 2017 08:29:36 -0700 Subject: [PATCH 09/37] net: lwm2m: change registraion update messages to INFO Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_rd_client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index 6f8814c28a81f..fca90d8a99749 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -354,7 +354,7 @@ static int do_update_reply_cb(const struct zoap_packet *response, int index; code = zoap_header_get_code(response); - SYS_LOG_DBG("Update callback (code:%u.%u)", + SYS_LOG_INF("Update callback (code:%u.%u)", ZOAP_RESPONSE_CODE_CLASS(code), ZOAP_RESPONSE_CODE_DETAIL(code)); @@ -368,7 +368,7 @@ static int do_update_reply_cb(const struct zoap_packet *response, if ((code == ZOAP_RESPONSE_CODE_CHANGED) || (code == ZOAP_RESPONSE_CODE_CREATED)) { set_sm_state(index, ENGINE_REGISTRATION_DONE); - SYS_LOG_DBG("Update Done"); + SYS_LOG_INF("Update Done"); return 0; } From 86df78a4e1ba08c2b6e16ac03b2b348f716af3e0 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Tue, 5 Sep 2017 21:03:49 -0700 Subject: [PATCH 10/37] net: lwm2m: fix message release for separate reply In the case of a proxy server translating HTTP -> COAP (known in the code as "separate reply"), we were leaking lwm2m_message structures. This was due to pending objects being cleared out during the first ACK, and no other way of finding a matching message when the follow up packet was received. Let's add a second match for reply to make sure we can find our matching message resources. NOTE: This change renames find_msg_from_pending() to find_msg() and makes it a static function as it's only used by the lwm2m_engine. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_engine.c | 26 ++++++++++++++++++-------- subsys/net/lib/lwm2m/lwm2m_engine.h | 3 --- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 093440d2105c5..f41cc416e0eb6 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -715,13 +715,14 @@ static void zoap_options_to_path(struct zoap_option *opt, int options_count, } } -struct lwm2m_message *find_msg_from_pending(struct zoap_pending *pending, - struct lwm2m_message *messages, - size_t len) +static struct lwm2m_message *find_msg(struct zoap_pending *pending, + struct zoap_reply *reply, + struct lwm2m_message *messages, + size_t len) { size_t i; - if (!pending || !messages) { + if (!messages || (!pending && !reply)) { return NULL; } @@ -729,6 +730,10 @@ struct lwm2m_message *find_msg_from_pending(struct zoap_pending *pending, if (messages[i].ctx && messages[i].pending == pending) { return &messages[i]; } + + if (messages[i].ctx && messages[i].reply == reply) { + return &messages[i]; + } } return NULL; @@ -2591,8 +2596,8 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, * is != NULL. */ if (pending) { - msg = find_msg_from_pending(pending, client_ctx->messages, - CONFIG_LWM2M_ENGINE_MAX_MESSAGES); + msg = find_msg(pending, NULL, client_ctx->messages, + CONFIG_LWM2M_ENGINE_MAX_MESSAGES); if (msg) { msg->pending = NULL; } @@ -2619,6 +2624,11 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, SYS_LOG_DBG("separated response, not removing reply"); goto cleanup; } + + if (!msg) { + msg = find_msg(pending, reply, client_ctx->messages, + CONFIG_LWM2M_ENGINE_MAX_MESSAGES); + } } if (reply || pending) { @@ -2702,8 +2712,8 @@ static void retransmit_request(struct k_work *work) return; } - msg = find_msg_from_pending(pending, client_ctx->messages, - CONFIG_LWM2M_ENGINE_MAX_MESSAGES); + msg = find_msg(pending, NULL, client_ctx->messages, + CONFIG_LWM2M_ENGINE_MAX_MESSAGES); if (!msg) { SYS_LOG_ERR("pending has no valid LwM2M message!"); return; diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index ab9616d69d61a..34c42dff1b84a 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -56,9 +56,6 @@ int lwm2m_get_or_create_engine_obj(struct lwm2m_engine_context *context, u8_t *created); /* LwM2M message functions */ -struct lwm2m_message *find_msg_from_pending(struct zoap_pending *pending, - struct lwm2m_message *messages, - size_t len); struct lwm2m_message *lwm2m_get_message(struct lwm2m_ctx *client_ctx); void lwm2m_release_message(struct lwm2m_message *msg); int lwm2m_init_message(struct lwm2m_message *msg); From 40ba2ba35a5a27dfa78168e0eba0290bbc464ddf Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Fri, 8 Sep 2017 08:22:59 -0700 Subject: [PATCH 11/37] net: lwm2m: split out lwm2m context initialization Create an internal function lwm2m_engine_context_init() which sets the extra packet pools and initializes retransmit work internal to the LwM2M engine. This function will be used by firmware pull support which establishes a new LwM2M context for downloading firmware. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_engine.c | 17 +++++++++++------ subsys/net/lib/lwm2m/lwm2m_engine.h | 3 +++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index f41cc416e0eb6..05fcc5d8a971d 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -2932,6 +2932,16 @@ int lwm2m_engine_set_net_pkt_pool(struct lwm2m_ctx *ctx, } #endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */ +void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx) +{ + k_delayed_work_init(&client_ctx->retransmit_work, retransmit_request); + +#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) + net_app_set_net_pkt_pool(&client_ctx->net_app_ctx, + client_ctx->tx_slab, client_ctx->data_pool); +#endif +} + int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, char *peer_str, u16_t peer_port) { @@ -2949,12 +2959,7 @@ int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, goto error_start; } - k_delayed_work_init(&client_ctx->retransmit_work, retransmit_request); - -#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) - net_app_set_net_pkt_pool(&client_ctx->net_app_ctx, - client_ctx->tx_slab, client_ctx->data_pool); -#endif + lwm2m_engine_context_init(client_ctx); /* set net_app callbacks */ ret = net_app_set_cb(&client_ctx->net_app_ctx, diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index 34c42dff1b84a..3255bab7a75cd 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -55,6 +55,9 @@ int lwm2m_get_or_create_engine_obj(struct lwm2m_engine_context *context, struct lwm2m_engine_obj_inst **obj_inst, u8_t *created); +/* LwM2M context functions */ +void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx); + /* LwM2M message functions */ struct lwm2m_message *lwm2m_get_message(struct lwm2m_ctx *client_ctx); void lwm2m_release_message(struct lwm2m_message *msg); From bc31a4c242bdcd95408736d89b63f9ff4d2fdf91 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Fri, 8 Sep 2017 08:27:45 -0700 Subject: [PATCH 12/37] net: lwm2m: setup lwm2m ctx for firmware download Previously, firmware support wasn't initializing the retransmit work or the extra network packet pools. Let's fix that. NOTE: While this fixes the setup of retransmit work, the actual attempts to re-send packets which are pending is failing. Needs another follow-up fix. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c index 2cf437ec430f9..fa3aa03c1c59b 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c @@ -332,6 +332,8 @@ static void firmware_transfer(struct k_work *work) SYS_LOG_DBG("Attached to port: %d", parsed_uri.port); + lwm2m_engine_context_init(&firmware_ctx); + /* set net_app callbacks */ ret = net_app_set_cb(&firmware_ctx.net_app_ctx, NULL, firmware_udp_receive, NULL, NULL); From a75fa550c99ab3bc58a635405283f7a07bf29679 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Fri, 8 Sep 2017 08:32:16 -0700 Subject: [PATCH 13/37] net: lwm2m: fix packet leak in timeout work When a packet expires after the pending retries we call lwm2m_release_message() to free up resources. This includes cleanup of the pending structure which calls net_pkt_unref on the pending packet. This would normally free up the packet memory. However, earlier in the pending processing we add a ref to the packet so that normal send processing doesn't free up the memory. This meant we were leaking packet memory every time we had an expiration due to timeout. Let's do an unref prior to calling lwm2m_release_message() to make sure the packet memory is freed correctly. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_engine.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 05fcc5d8a971d..6b36e901321c5 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -2725,6 +2725,8 @@ static void retransmit_request(struct k_work *work) msg->message_timeout_cb(msg); } + /* final unref to release pkt */ + net_pkt_unref(pending->pkt); lwm2m_release_message(msg); return; } From cf0ccbc499c642aed0a6f7e7101ee5e830928d94 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Fri, 8 Sep 2017 08:37:48 -0700 Subject: [PATCH 14/37] net: lwm2m: add full block-wise retries for firmware download UDP packets can be lost in heavy traffic. Normally we can handle this with pending packet processing for packets which have not been responded to with an ACK. However, due to the time it takes for firmware to download via CoAP, an extra level of retries should be added. The process works like this: Normal pending packets will try to send 3 times fairly quickly. If that fails, then the timeout callback is called for the firmware download process. A retry counter is incremented and the timeout callback perform a new packet send of the block-wise transfer packet that is missing, until the retry counter hits a limit (3) and then the transfer is aborted. This allows for a longer "outage" to happen during firmware transfer and the process can still succeed. NOTE: This patch does not fix a current bug where the pending process is not re-sending the packets correctly, it only makes the process more stable with a better chance to work. Signed-off-by: Michael Scott --- .../net/lib/lwm2m/lwm2m_obj_firmware_pull.c | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c index fa3aa03c1c59b..c85b2f33a6b13 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c @@ -26,14 +26,18 @@ #define BUF_ALLOC_TIMEOUT K_SECONDS(1) #define NETWORK_INIT_TIMEOUT K_SECONDS(10) #define NETWORK_CONNECT_TIMEOUT K_SECONDS(10) +#define PACKET_TRANSFER_RETRY_MAX 3 static struct k_work firmware_work; static char firmware_uri[PACKAGE_URI_LEN]; static struct sockaddr firmware_addr; static struct http_parser_url parsed_uri; static struct lwm2m_ctx firmware_ctx; +static int firmware_retry; static struct zoap_block_context firmware_block_ctx; +static void do_transmit_timeout_cb(struct lwm2m_message *msg); + static void firmware_udp_receive(struct net_app_ctx *app_ctx, struct net_pkt *pkt, int status, void *user_data) @@ -41,11 +45,6 @@ firmware_udp_receive(struct net_app_ctx *app_ctx, struct net_pkt *pkt, lwm2m_udp_receive(&firmware_ctx, pkt, true, NULL); } -static void do_transmit_timeout_cb(struct lwm2m_message *msg) -{ - lwm2m_firmware_set_update_result(RESULT_CONNECTION_LOST); -} - static int transfer_request(struct zoap_block_context *ctx, const u8_t *token, u8_t tkl, zoap_reply_t reply_cb) @@ -226,6 +225,26 @@ do_firmware_transfer_reply_cb(const struct zoap_packet *response, return ret; } +static void do_transmit_timeout_cb(struct lwm2m_message *msg) +{ + const u8_t *token; + u8_t tkl; + + if (firmware_retry < PACKET_TRANSFER_RETRY_MAX) { + /* retry block */ + SYS_LOG_WRN("TIMEOUT - Sending a retry packet!"); + token = zoap_header_get_token(&msg->zpkt, &tkl); + + transfer_request(&firmware_block_ctx, token, tkl, + do_firmware_transfer_reply_cb); + firmware_retry++; + } else { + SYS_LOG_ERR("TIMEOUT - Too many retry packet attempts! " + "Aborting firmware download."); + lwm2m_firmware_set_update_result(RESULT_CONNECTION_LOST); + } +} + static void firmware_transfer(struct k_work *work) { int ret, family; @@ -377,6 +396,7 @@ int lwm2m_firmware_start_transfer(char *package_uri) } memset(&firmware_ctx, 0, sizeof(struct lwm2m_ctx)); + firmware_retry = 0; firmware_ctx.net_init_timeout = NETWORK_INIT_TIMEOUT; firmware_ctx.net_timeout = NETWORK_CONNECT_TIMEOUT; k_work_init(&firmware_work, firmware_transfer); From bcb0de8ba4d52aa2b5c322a0d7aea636606e6de3 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Fri, 8 Sep 2017 14:03:56 -0700 Subject: [PATCH 15/37] net: lwm2m: ignore duplicate/older block transfers During firmware download via block-wise transfer, we can see packets occaionally get re-transmitted (normal logic in the pending / retry functions). However, Both of these packets end up coming through the reply handler and we should ignore any block-wise transfer that has a current value less than where we expect to be. NOTE: This fixes K64F ethernet transfers where we were getting too many packets back in the handler. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c index c85b2f33a6b13..3f3c053c15cbe 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c @@ -163,6 +163,7 @@ do_firmware_transfer_reply_cb(const struct zoap_packet *response, struct zoap_packet *check_response = (struct zoap_packet *)response; lwm2m_engine_set_data_cb_t callback; u8_t resp_code; + struct zoap_block_context received_block_ctx; /* Check response code from server. Expecting (2.05) */ resp_code = zoap_header_get_code(check_response); @@ -174,6 +175,10 @@ do_firmware_transfer_reply_cb(const struct zoap_packet *response, return -ENOENT; } + /* save main firmware block context */ + memcpy(&received_block_ctx, &firmware_block_ctx, + sizeof(firmware_block_ctx)); + ret = zoap_update_from_block(check_response, &firmware_block_ctx); if (ret < 0) { SYS_LOG_ERR("Error from block update: %d", ret); @@ -181,6 +186,15 @@ do_firmware_transfer_reply_cb(const struct zoap_packet *response, return ret; } + /* test for duplicate transfer */ + if (firmware_block_ctx.current < received_block_ctx.current) { + SYS_LOG_WRN("Duplicate packet ignored"); + /* restore main firmware block context */ + memcpy(&firmware_block_ctx, &received_block_ctx, + sizeof(firmware_block_ctx)); + return 0; + } + /* Reach last block if transfer_offset equals to 0 */ transfer_offset = zoap_next_block(check_response, &firmware_block_ctx); From 1f2ea63bd8578c2954a92858064edf7f3213b14a Mon Sep 17 00:00:00 2001 From: Ricardo Salveti Date: Thu, 27 Jul 2017 18:30:44 -0300 Subject: [PATCH 16/37] net: lwm2m: firmware: add support for firmware pull over CoAP proxy CoAP allows a proxy to be used when transferring data (CoAP-CoAP and/or CoAP-HTTP) by creating request on a specific URI path and by using the Proxy URI CoAP option. Create specific Kconfig options for the proxy server address and port, until a parser gets implemented. Code tested with Californium acting as CoAP proxy. Signed-off-by: Ricardo Salveti [michael.scott@linaro.org: rebased on net_app + lwm2m_message refactoring + firmware update changes.] Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/Kconfig | 24 ++++ .../net/lib/lwm2m/lwm2m_obj_firmware_pull.c | 125 +++++++++++++++--- 2 files changed, 133 insertions(+), 16 deletions(-) diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 99dd3b229552f..aec49b3fb6ea2 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -153,6 +153,30 @@ config LWM2M_NUM_BLOCK1_CONTEXT This value sets up the maximum number of block1 contexts for CoAP block-wise transfer we can handle at the same time. +config LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT + bool "Firmware Update object pull via CoAP-CoAP/HTTP proxy support" + depends on LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT + default n + help + Include support for pulling firmware file via a CoAP-CoAP/HTTP proxy. + +if LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT + +config LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_ADDR + string "CoAP proxy network address" + help + Network address of the CoAP proxy server. + +config LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_URI_PATH + string "CoAP URI path element used by the proxy" + default "coap2http" + help + CoAP URI path element exported by the CoAP proxy server. + Defaults to coap2http, which is the URI path used by the + Californium CoAP-HTTP proxy. + +endif # LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT + config LWM2M_RW_JSON_SUPPORT bool "support for JSON writer" default y diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c index 3f3c053c15cbe..d590b774401ca 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c @@ -36,6 +36,11 @@ static struct lwm2m_ctx firmware_ctx; static int firmware_retry; static struct zoap_block_context firmware_block_ctx; +#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT) +#define PROXY_URI_LEN 255 +static char proxy_uri[PROXY_URI_LEN]; +#endif + static void do_transmit_timeout_cb(struct lwm2m_message *msg); static void @@ -51,11 +56,13 @@ static int transfer_request(struct zoap_block_context *ctx, { struct lwm2m_message *msg; int ret; +#if !defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT) int i; int path_len; char *cursor; u16_t off; u16_t len; +#endif msg = lwm2m_get_message(&firmware_ctx); if (!msg) { @@ -76,6 +83,16 @@ static int transfer_request(struct zoap_block_context *ctx, goto cleanup; } +#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT) + char *uri_path = + CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_URI_PATH; + ret = zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_PATH, + uri_path, strlen(uri_path)); + if (ret < 0) { + SYS_LOG_ERR("Error adding URI_PATH '%s'", uri_path); + goto cleanup; + } +#else /* if path is not available, off/len will be zero */ off = parsed_uri.field_data[UF_PATH].off; len = parsed_uri.field_data[UF_PATH].len; @@ -114,6 +131,7 @@ static int transfer_request(struct zoap_block_context *ctx, } path_len += 1; } +#endif ret = zoap_add_block2_option(&msg->zpkt, ctx); if (ret) { @@ -121,12 +139,21 @@ static int transfer_request(struct zoap_block_context *ctx, goto cleanup; } +#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT) + ret = zoap_add_option(&msg->zpkt, ZOAP_OPTION_PROXY_URI, + firmware_uri, strlen(firmware_uri)); + if (ret < 0) { + SYS_LOG_ERR("Error adding PROXY_URI '%s'", firmware_uri); + goto cleanup; + } +#else /* Ask the server to provide a size estimate */ ret = zoap_add_option_int(&msg->zpkt, ZOAP_OPTION_SIZE2, 0); if (ret) { SYS_LOG_ERR("Unable to add size2 option."); goto cleanup; } +#endif /* send request */ ret = lwm2m_send_message(msg); @@ -149,6 +176,40 @@ static int transfer_request(struct zoap_block_context *ctx, return ret; } +static int transfer_empty_ack(u16_t mid) +{ + struct lwm2m_message *msg; + int ret; + + msg = lwm2m_get_message(&firmware_ctx); + if (!msg) { + SYS_LOG_ERR("Unable to get a lwm2m message!"); + return -ENOMEM; + } + + msg->type = ZOAP_TYPE_ACK; + msg->code = ZOAP_CODE_EMPTY; + msg->mid = mid; + + ret = lwm2m_init_message(msg); + if (ret) { + goto cleanup; + } + + ret = lwm2m_send_message(msg); + if (ret < 0) { + SYS_LOG_ERR("Error sending LWM2M packet (err:%d).", + ret); + goto cleanup; + } + + return 0; + +cleanup: + lwm2m_release_message(msg); + return ret; +} + static int do_firmware_transfer_reply_cb(const struct zoap_packet *response, struct zoap_reply *reply, @@ -165,6 +226,21 @@ do_firmware_transfer_reply_cb(const struct zoap_packet *response, u8_t resp_code; struct zoap_block_context received_block_ctx; + /* token is used to determine a valid ACK vs a separated response */ + token = zoap_header_get_token(check_response, &tkl); + + /* If separated response (ACK) return and wait for response */ + if (!tkl && zoap_header_get_type(response) == ZOAP_TYPE_ACK) { + return 0; + } else if (zoap_header_get_type(response) == ZOAP_TYPE_CON) { + /* Send back ACK so the server knows we received the pkt */ + ret = transfer_empty_ack(zoap_header_get_id(check_response)); + if (ret < 0) { + SYS_LOG_ERR("Error transmitting ACK"); + return ret; + } + } + /* Check response code from server. Expecting (2.05) */ resp_code = zoap_header_get_code(check_response); if (resp_code != ZOAP_RESPONSE_CODE_CONTENT) { @@ -228,7 +304,6 @@ do_firmware_transfer_reply_cb(const struct zoap_packet *response, if (transfer_offset > 0) { /* More block(s) to come, setup next transfer */ - token = zoap_header_get_token(check_response, &tkl); ret = transfer_request(&firmware_block_ctx, token, tkl, do_firmware_transfer_reply_cb); } else { @@ -265,17 +340,33 @@ static void firmware_transfer(struct k_work *work) u16_t off; u16_t len; char tmp; + char *server_addr; /* Server Peer IP information */ family = AF_INET; +#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT) + server_addr = CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_ADDR; + if (strlen(server_addr) >= PROXY_URI_LEN) { + SYS_LOG_ERR("Invalid Proxy URI: %s", server_addr); + lwm2m_firmware_set_update_result(RESULT_UNSUP_PROTO); + return; + } + + /* Copy required as it gets modified when port is available */ + strcpy(proxy_uri, server_addr); + server_addr = proxy_uri; +#else + server_addr = firmware_uri; +#endif + http_parser_url_init(&parsed_uri); - ret = http_parser_parse_url(firmware_uri, - strlen(firmware_uri), + ret = http_parser_parse_url(server_addr, + strlen(server_addr), 0, &parsed_uri); if (ret != 0) { - SYS_LOG_ERR("Invalid firmware URI: %s", firmware_uri); + SYS_LOG_ERR("Invalid firmware URI: %s", server_addr); lwm2m_firmware_set_update_result(RESULT_INVALID_URI); return; } @@ -290,7 +381,7 @@ static void firmware_transfer(struct k_work *work) /* TODO: enable coaps when DTLS is ready */ off = parsed_uri.field_data[UF_SCHEMA].off; len = parsed_uri.field_data[UF_SCHEMA].len; - if (len != 4 || memcmp(firmware_uri + off, "coap", 4)) { + if (len != 4 || memcmp(server_addr + off, "coap", 4)) { SYS_LOG_ERR("Unsupported schema"); lwm2m_firmware_set_update_result(RESULT_UNSUP_PROTO); return; @@ -305,7 +396,7 @@ static void firmware_transfer(struct k_work *work) len = parsed_uri.field_data[UF_HOST].len; /* IPv6 is wrapped by brackets */ - if (off > 0 && firmware_uri[off - 1] == '[') { + if (off > 0 && server_addr[off - 1] == '[') { if (!IS_ENABLED(CONFIG_NET_IPV6)) { SYS_LOG_ERR("Doesn't support IPv6"); lwm2m_firmware_set_update_result(RESULT_UNSUP_PROTO); @@ -316,8 +407,8 @@ static void firmware_transfer(struct k_work *work) } else { /* Distinguish IPv4 or DNS */ for (int i = off; i < off + len; i++) { - if (!isdigit(firmware_uri[i]) && - firmware_uri[i] != '.') { + if (!isdigit(server_addr[i]) && + server_addr[i] != '.') { SYS_LOG_ERR("Doesn't support DNS lookup"); lwm2m_firmware_set_update_result( RESULT_UNSUP_PROTO); @@ -334,25 +425,26 @@ static void firmware_transfer(struct k_work *work) family = AF_INET; } - tmp = firmware_uri[off + len]; - firmware_uri[off + len] = '\0'; + tmp = server_addr[off + len]; + server_addr[off + len] = '\0'; if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) { firmware_addr.sa_family = family; - net_addr_pton(firmware_addr.sa_family, firmware_uri + off, + net_addr_pton(firmware_addr.sa_family, server_addr + off, &net_sin6(&firmware_addr)->sin6_addr); net_sin6(&firmware_addr)->sin6_port = htons(parsed_uri.port); } if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) { firmware_addr.sa_family = family; - net_addr_pton(firmware_addr.sa_family, firmware_uri + off, + net_addr_pton(firmware_addr.sa_family, server_addr + off, &net_sin(&firmware_addr)->sin_addr); net_sin(&firmware_addr)->sin_port = htons(parsed_uri.port); } - /* restore firmware_uri */ - firmware_uri[off + len] = tmp; + + /* restore server_addr */ + server_addr[off + len] = tmp; ret = net_app_init_udp_client(&firmware_ctx.net_app_ctx, NULL, &firmware_addr, NULL, parsed_uri.port, @@ -363,7 +455,8 @@ static void firmware_transfer(struct k_work *work) return; } - SYS_LOG_DBG("Attached to port: %d", parsed_uri.port); + SYS_LOG_INF("Connecting to server %s, port %d", server_addr + off, + parsed_uri.port); lwm2m_engine_context_init(&firmware_ctx); @@ -386,7 +479,7 @@ static void firmware_transfer(struct k_work *work) /* reset block transfer context */ zoap_block_transfer_init(&firmware_block_ctx, lwm2m_default_block_size(), 0); - transfer_request(&firmware_block_ctx, NULL, 0, + transfer_request(&firmware_block_ctx, zoap_next_token(), 8, do_firmware_transfer_reply_cb); return; From 3f6b20d8a18e53e2e0597485edba6e456febef3f Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Mon, 11 Sep 2017 22:20:36 -0700 Subject: [PATCH 17/37] net: lwm2m: add RD client callbacks for app Applications may want to be notified when various events happen in the LwM2M rd client. Let's implement an event callback which sends: connect, disconnect and update events. Signed-off-by: Michael Scott --- include/net/lwm2m.h | 20 ++++++++- samples/net/lwm2m_client/src/lwm2m-client.c | 50 ++++++++++++++++++++- subsys/net/lib/lwm2m/lwm2m_rd_client.c | 48 ++++++++++++++++++-- 3 files changed, 112 insertions(+), 6 deletions(-) diff --git a/include/net/lwm2m.h b/include/net/lwm2m.h index b1d5c23f9a7a5..203e341712cec 100644 --- a/include/net/lwm2m.h +++ b/include/net/lwm2m.h @@ -234,8 +234,26 @@ int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, /* LWM2M RD Client */ +/* Client events */ +enum lwm2m_rd_client_event { + LWM2M_RD_CLIENT_EVENT_NONE, + LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_FAILURE, + LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_COMPLETE, + LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE, + LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE, + LWM2M_RD_CLIENT_EVENT_REG_UPDATE_FAILURE, + LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE, + LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE, + LWM2M_RD_CLIENT_EVENT_DISCONNECT +}; + +/* Event callback */ +typedef void (*lwm2m_ctx_event_cb_t)(struct lwm2m_ctx *ctx, + enum lwm2m_rd_client_event event); + int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, char *peer_str, u16_t peer_port, - const char *ep_name); + const char *ep_name, + lwm2m_ctx_event_cb_t event_cb); #endif /* __LWM2M_H__ */ diff --git a/samples/net/lwm2m_client/src/lwm2m-client.c b/samples/net/lwm2m_client/src/lwm2m-client.c index 347bb667a49af..ea77695b75741 100644 --- a/samples/net/lwm2m_client/src/lwm2m-client.c +++ b/samples/net/lwm2m_client/src/lwm2m-client.c @@ -241,6 +241,50 @@ static int lwm2m_setup(void) return 0; } +static void rd_client_event(struct lwm2m_ctx *client, + enum lwm2m_rd_client_event client_event) +{ + switch (client_event) { + + case LWM2M_RD_CLIENT_EVENT_NONE: + /* do nothing */ + break; + + case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_FAILURE: + SYS_LOG_DBG("Bootstrap failure!"); + break; + + case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_COMPLETE: + SYS_LOG_DBG("Bootstrap complete"); + break; + + case LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE: + SYS_LOG_DBG("Registration failure!"); + break; + + case LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE: + SYS_LOG_DBG("Registration complete"); + break; + + case LWM2M_RD_CLIENT_EVENT_REG_UPDATE_FAILURE: + SYS_LOG_DBG("Registration update failure!"); + break; + + case LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE: + SYS_LOG_DBG("Registration update complete"); + break; + + case LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE: + SYS_LOG_DBG("Deregister failure!"); + break; + + case LWM2M_RD_CLIENT_EVENT_DISCONNECT: + SYS_LOG_DBG("Disconnected"); + break; + + } +} + void main(void) { int ret; @@ -265,10 +309,12 @@ void main(void) #if defined(CONFIG_NET_IPV6) ret = lwm2m_rd_client_start(&client, CONFIG_NET_APP_PEER_IPV6_ADDR, - CONFIG_LWM2M_PEER_PORT, CONFIG_BOARD); + CONFIG_LWM2M_PEER_PORT, CONFIG_BOARD, + rd_client_event); #elif defined(CONFIG_NET_IPV4) ret = lwm2m_rd_client_start(&client, CONFIG_NET_APP_PEER_IPV4_ADDR, - CONFIG_LWM2M_PEER_PORT, CONFIG_BOARD); + CONFIG_LWM2M_PEER_PORT, CONFIG_BOARD, + rd_client_event); #else SYS_LOG_ERR("LwM2M client requires IPv4 or IPv6."); ret = -EPROTONOSUPPORT; diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index fca90d8a99749..a723bd5184004 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -106,6 +106,8 @@ struct lwm2m_rd_client_info { char ep_name[CLIENT_EP_LEN]; char server_ep[CLIENT_EP_LEN]; + + lwm2m_ctx_event_cb_t event_cb; }; static K_THREAD_STACK_DEFINE(lwm2m_rd_client_thread_stack, @@ -120,10 +122,31 @@ static u8_t client_data[256]; /* allocate some data for the RD */ static struct lwm2m_rd_client_info clients[CLIENT_INSTANCE_COUNT]; static int client_count; -static void set_sm_state(int index, u8_t state) +static void set_sm_state(int index, u8_t sm_state) { + enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_NONE; + + /* Determine if a callback to the app is needed */ + if (sm_state == ENGINE_BOOTSTRAP_DONE) { + event = LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_COMPLETE; + } else if (clients[index].engine_state == ENGINE_UPDATE_SENT && + sm_state == ENGINE_REGISTRATION_DONE) { + event = LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE; + } else if (sm_state == ENGINE_REGISTRATION_DONE) { + event = LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE; + } else if ((sm_state == ENGINE_INIT || + sm_state == ENGINE_DEREGISTERED) && + (clients[index].engine_state > ENGINE_BOOTSTRAP_DONE && + clients[index].engine_state < ENGINE_DEREGISTER)) { + event = LWM2M_RD_CLIENT_EVENT_DISCONNECT; + } + /* TODO: add locking? */ - clients[index].engine_state = state; + clients[index].engine_state = sm_state; + + if (event > LWM2M_RD_CLIENT_EVENT_NONE && clients[index].event_cb) { + clients[index].event_cb(clients[index].ctx, event); + } } static bool sm_is_registered(int index) @@ -200,6 +223,7 @@ static void sm_handle_timeout_state(struct lwm2m_message *msg, enum sm_engine_state sm_state) { int index; + enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_NONE; index = find_rd_client_from_msg(msg, clients, CLIENT_INSTANCE_COUNT); if (index < 0) { @@ -207,7 +231,23 @@ static void sm_handle_timeout_state(struct lwm2m_message *msg, return; } + if (clients[index].engine_state == ENGINE_BOOTSTRAP_SENT) { + event = LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_FAILURE; + } else if (clients[index].engine_state == ENGINE_REGISTRATION_SENT) { + event = LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE; + } else if (clients[index].engine_state == ENGINE_UPDATE_SENT) { + event = LWM2M_RD_CLIENT_EVENT_REG_UPDATE_FAILURE; + } else if (clients[index].engine_state == ENGINE_DEREGISTER_SENT) { + event = LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE; + } else { + /* TODO: unknown timeout state */ + } + set_sm_state(index, sm_state); + + if (event > LWM2M_RD_CLIENT_EVENT_NONE && clients[index].event_cb) { + clients[index].event_cb(clients[index].ctx, event); + } } /* force re-update with remote peer(s) */ @@ -820,7 +860,8 @@ static void lwm2m_rd_client_service(void) int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, char *peer_str, u16_t peer_port, - const char *ep_name) + const char *ep_name, + lwm2m_ctx_event_cb_t event_cb) { int index, ret = 0; @@ -843,6 +884,7 @@ int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, index = client_count; client_count++; clients[index].ctx = client_ctx; + clients[index].event_cb = event_cb; set_sm_state(index, ENGINE_INIT); strncpy(clients[index].ep_name, ep_name, CLIENT_EP_LEN - 1); SYS_LOG_INF("LWM2M Client: %s", clients[index].ep_name); From 84cf1173b185452a043cb6020daa16f3c3b88120 Mon Sep 17 00:00:00 2001 From: Ravi kumar Veeramally Date: Mon, 28 Aug 2017 12:19:32 +0300 Subject: [PATCH 18/37] net: coap: Rename ZOAP library ZOAP library has certain limitations in parsing and preparation of coap messages. It can handle only on single network fragment. If network packet is split between multiple fragments it fails. This patch is just copy and rename of 'zoap' to 'coap'. Signed-off-by: Ravi kumar Veeramally --- doc/api/networking.rst | 2 +- doc/zephyr.doxyfile | 2 +- include/net/coap.h | 823 +++++++++++++++ include/net/coap_link_format.h | 59 ++ subsys/net/lib/Kbuild | 1 + subsys/net/lib/Kconfig | 2 + subsys/net/lib/Makefile | 4 + subsys/net/lib/coap/Kbuild | 4 + subsys/net/lib/coap/Kconfig | 43 + subsys/net/lib/coap/Makefile | 1 + subsys/net/lib/coap/coap.c | 1311 ++++++++++++++++++++++++ subsys/net/lib/coap/coap_link_format.c | 726 +++++++++++++ 12 files changed, 2976 insertions(+), 2 deletions(-) create mode 100644 include/net/coap.h create mode 100644 include/net/coap_link_format.h create mode 100644 subsys/net/lib/coap/Kbuild create mode 100644 subsys/net/lib/coap/Kconfig create mode 100644 subsys/net/lib/coap/Makefile create mode 100644 subsys/net/lib/coap/coap.c create mode 100644 subsys/net/lib/coap/coap_link_format.c diff --git a/doc/api/networking.rst b/doc/api/networking.rst index 4f06fcb2b6f62..871714b55fe96 100644 --- a/doc/api/networking.rst +++ b/doc/api/networking.rst @@ -136,7 +136,7 @@ MQTT 3.1.1 CoAP ==== -.. doxygengroup:: zoap +.. doxygengroup:: coap :project: Zephyr DNS Resolve diff --git a/doc/zephyr.doxyfile b/doc/zephyr.doxyfile index a13588243cabc..03a5597bdbae0 100644 --- a/doc/zephyr.doxyfile +++ b/doc/zephyr.doxyfile @@ -107,7 +107,7 @@ INPUT = \ ../include/arch/arm/cortex_m \ ../include/arch/nios2/ \ ../lib/libc/minimal/include/ \ - ../include/net/zoap.h \ + ../include/net/coap.h \ ../include/net/dns_resolve.h \ ../tests/ztest/include/ INPUT_ENCODING = UTF-8 diff --git a/include/net/coap.h b/include/net/coap.h new file mode 100644 index 0000000000000..80d9583638a0b --- /dev/null +++ b/include/net/coap.h @@ -0,0 +1,823 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * + * @brief CoAP implementation for Zephyr. + */ + +#ifndef __COAP_H__ +#define __COAP_H__ + +#include +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief COAP library + * @defgroup coap COAP Library + * @{ + */ + +/** + * @brief Set of CoAP packet options we are aware of. + * + * Users may add options other than these to their packets, provided + * they know how to format them correctly. The only restriction is + * that all options must be added to a packet in numeric order. + * + * Refer to RFC 7252, section 12.2 for more information. + */ +enum coap_option_num { + COAP_OPTION_IF_MATCH = 1, + COAP_OPTION_URI_HOST = 3, + COAP_OPTION_ETAG = 4, + COAP_OPTION_IF_NONE_MATCH = 5, + COAP_OPTION_OBSERVE = 6, + COAP_OPTION_URI_PORT = 7, + COAP_OPTION_LOCATION_PATH = 8, + COAP_OPTION_URI_PATH = 11, + COAP_OPTION_CONTENT_FORMAT = 12, + COAP_OPTION_MAX_AGE = 14, + COAP_OPTION_URI_QUERY = 15, + COAP_OPTION_ACCEPT = 17, + COAP_OPTION_LOCATION_QUERY = 20, + COAP_OPTION_BLOCK2 = 23, + COAP_OPTION_BLOCK1 = 27, + COAP_OPTION_SIZE2 = 28, + COAP_OPTION_PROXY_URI = 35, + COAP_OPTION_PROXY_SCHEME = 39, + COAP_OPTION_SIZE1 = 60, +}; + +/** + * @brief Available request methods. + * + * To be used with coap_header_set_code() when creating a request + * or a response. + */ +enum coap_method { + COAP_METHOD_GET = 1, + COAP_METHOD_POST = 2, + COAP_METHOD_PUT = 3, + COAP_METHOD_DELETE = 4, +}; + +#define COAP_REQUEST_MASK 0x07 + +/** + * @brief CoAP packets may be of one of these types. + */ +enum coap_msgtype { + /** + * Confirmable message. + * + * The packet is a request or response the destination end-point must + * acknowledge. + */ + COAP_TYPE_CON = 0, + /** + * Non-confirmable message. + * + * The packet is a request or response that doesn't + * require acknowledgements. + */ + COAP_TYPE_NON_CON = 1, + /** + * Acknowledge. + * + * Response to a confirmable message. + */ + COAP_TYPE_ACK = 2, + /** + * Reset. + * + * Rejecting a packet for any reason is done by sending a message + * of this type. + */ + COAP_TYPE_RESET = 3 +}; + +#define coap_make_response_code(clas, det) ((clas << 5) | (det)) + +/** + * @brief Set of response codes available for a response packet. + * + * To be used with coap_header_set_code() when creating a response. + */ +enum coap_response_code { + COAP_RESPONSE_CODE_OK = coap_make_response_code(2, 0), + COAP_RESPONSE_CODE_CREATED = coap_make_response_code(2, 1), + COAP_RESPONSE_CODE_DELETED = coap_make_response_code(2, 2), + COAP_RESPONSE_CODE_VALID = coap_make_response_code(2, 3), + COAP_RESPONSE_CODE_CHANGED = coap_make_response_code(2, 4), + COAP_RESPONSE_CODE_CONTENT = coap_make_response_code(2, 5), + COAP_RESPONSE_CODE_CONTINUE = coap_make_response_code(2, 31), + COAP_RESPONSE_CODE_BAD_REQUEST = coap_make_response_code(4, 0), + COAP_RESPONSE_CODE_UNAUTHORIZED = coap_make_response_code(4, 1), + COAP_RESPONSE_CODE_BAD_OPTION = coap_make_response_code(4, 2), + COAP_RESPONSE_CODE_FORBIDDEN = coap_make_response_code(4, 3), + COAP_RESPONSE_CODE_NOT_FOUND = coap_make_response_code(4, 4), + COAP_RESPONSE_CODE_NOT_ALLOWED = coap_make_response_code(4, 5), + COAP_RESPONSE_CODE_NOT_ACCEPTABLE = coap_make_response_code(4, 6), + COAP_RESPONSE_CODE_INCOMPLETE = coap_make_response_code(4, 8), + COAP_RESPONSE_CODE_PRECONDITION_FAILED = coap_make_response_code(4, 12), + COAP_RESPONSE_CODE_REQUEST_TOO_LARGE = coap_make_response_code(4, 13), + COAP_RESPONSE_CODE_UNSUPPORTED_CONTENT_FORMAT = coap_make_response_code(4, 15), + COAP_RESPONSE_CODE_INTERNAL_ERROR = coap_make_response_code(5, 0), + COAP_RESPONSE_CODE_NOT_IMPLEMENTED = coap_make_response_code(5, 1), + COAP_RESPONSE_CODE_BAD_GATEWAY = coap_make_response_code(5, 2), + COAP_RESPONSE_CODE_SERVICE_UNAVAILABLE = coap_make_response_code(5, 3), + COAP_RESPONSE_CODE_GATEWAY_TIMEOUT = coap_make_response_code(5, 4), + COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED = coap_make_response_code(5, 5) +}; + +#define COAP_CODE_EMPTY (0) + +struct coap_observer; +struct coap_packet; +struct coap_pending; +struct coap_reply; +struct coap_resource; + +/** + * @typedef coap_method_t + * @brief Type of the callback being called when a resource's method is + * invoked by the remote entity. + */ +typedef int (*coap_method_t)(struct coap_resource *resource, + struct coap_packet *request, + const struct sockaddr *from); + +/** + * @typedef coap_notify_t + * @brief Type of the callback being called when a resource's has observers + * to be informed when an update happens. + */ +typedef void (*coap_notify_t)(struct coap_resource *resource, + struct coap_observer *observer); + +/** + * @brief Description of CoAP resource. + * + * CoAP servers often want to register resources, so that clients can act on + * them, by fetching their state or requesting updates to them. + */ +struct coap_resource { + /** Which function to be called for each CoAP method */ + coap_method_t get, post, put, del; + coap_notify_t notify; + const char * const *path; + void *user_data; + sys_slist_t observers; + int age; +}; + +/** + * @brief Represents a remote device that is observing a local resource. + */ +struct coap_observer { + sys_snode_t list; + struct sockaddr addr; + u8_t token[8]; + u8_t tkl; +}; + +/** + * @brief Representation of a CoAP packet. + */ +struct coap_packet { + struct net_pkt *pkt; + u8_t *start; /* Start of the payload */ + u16_t total_size; +}; + +/** + * @typedef coap_reply_t + * @brief Helper function to be called when a response matches the + * a pending request. + */ +typedef int (*coap_reply_t)(const struct coap_packet *response, + struct coap_reply *reply, + const struct sockaddr *from); + +/** + * @brief Represents a request awaiting for an acknowledgment (ACK). + */ +struct coap_pending { + struct net_pkt *pkt; + struct sockaddr addr; + s32_t timeout; + u16_t id; +}; + +/** + * @brief Represents the handler for the reply of a request, it is + * also used when observing resources. + */ +struct coap_reply { + coap_reply_t reply; + void *user_data; + int age; + u8_t token[8]; + u16_t id; + u8_t tkl; +}; + +/** + * @brief Indicates that the remote device referenced by @a addr, with + * @a request, wants to observe a resource. + * + * @param observer Observer to be initialized + * @param request Request on which the observer will be based + * @param addr Address of the remote device + */ +void coap_observer_init(struct coap_observer *observer, + const struct coap_packet *request, + const struct sockaddr *addr); + +/** + * @brief After the observer is initialized, associate the observer + * with an resource. + * + * @param resource Resource to add an observer + * @param observer Observer to be added + * + * @return true if this is the first observer added to this resource. + */ +bool coap_register_observer(struct coap_resource *resource, + struct coap_observer *observer); + +/** + * @brief Remove this observer from the list of registered observers + * of that resource. + * + * @param resource Resource in which to remove the observer + * @param observer Observer to be removed + */ +void coap_remove_observer(struct coap_resource *resource, + struct coap_observer *observer); + +/** + * @brief Returns the observer that matches address @a addr. + * + * @param observers Pointer to the array of observers + * @param len Size of the array of observers + * @param addr Address of the endpoint observing a resource + * + * @return A pointer to a observer if a match is found, NULL + * otherwise. + */ +struct coap_observer *coap_find_observer_by_addr( + struct coap_observer *observers, size_t len, + const struct sockaddr *addr); + +/** + * @brief Returns the next available observer representation. + * + * @param observers Pointer to the array of observers + * @param len Size of the array of observers + * + * @return A pointer to a observer if there's an available observer, + * NULL otherwise. + */ +struct coap_observer *coap_observer_next_unused( + struct coap_observer *observers, size_t len); + +/** + * @brief Indicates that a reply is expected for @a request. + * + * @param reply Reply structure to be initialized + * @param request Request from which @a reply will be based + */ +void coap_reply_init(struct coap_reply *reply, + const struct coap_packet *request); + +/** + * @brief Represents the value of a CoAP option. + * + * To be used with coap_find_options(). + */ +struct coap_option { + u8_t *value; + u16_t len; +}; + +/** + * @brief Parses the CoAP packet in @a pkt, validating it and + * initializing @a cpkt. @a pkt must remain valid while @a cpkt is used. + * + * @param cpkt Packet to be initialized from received @a pkt. + * @param pkt Network Packet containing a CoAP packet, its @a data pointer is + * positioned on the start of the CoAP packet. + * + * @return 0 in case of success or negative in case of error. + */ +int coap_packet_parse(struct coap_packet *cpkt, struct net_pkt *pkt); + +/** + * @brief Creates a new CoAP packet from a net_pkt. @a pkt must remain + * valid while @a cpkt is used. + * + * @param cpkt New packet to be initialized using the storage from @a + * pkt. + * @param pkt Network Packet that will contain a CoAP packet + * + * @return 0 in case of success or negative in case of error. + */ +int coap_packet_init(struct coap_packet *cpkt, struct net_pkt *pkt); + +/** + * @brief Initialize a pending request with a request. + * + * The request's fields are copied into the pending struct, so @a + * request doesn't have to live for as long as the pending struct + * lives, but net_pkt needs to live for at least that long. + * + * @param pending Structure representing the waiting for a + * confirmation message, initialized with data from @a request + * @param request Message waiting for confirmation + * @param addr Address to send the retransmission + * + * @return 0 in case of success or negative in case of error. + */ +int coap_pending_init(struct coap_pending *pending, + const struct coap_packet *request, + const struct sockaddr *addr); + +/** + * @brief Returns the next available pending struct, that can be used + * to track the retransmission status of a request. + * + * @param pendings Pointer to the array of #coap_pending structures + * @param len Size of the array of #coap_pending structures + * + * @return pointer to a free #coap_pending structure, NULL in case + * none could be found. + */ +struct coap_pending *coap_pending_next_unused( + struct coap_pending *pendings, size_t len); + +/** + * @brief Returns the next available reply struct, so it can be used + * to track replies and notifications received. + * + * @param replies Pointer to the array of #coap_reply structures + * @param len Size of the array of #coap_reply structures + * + * @return pointer to a free #coap_reply structure, NULL in case + * none could be found. + */ +struct coap_reply *coap_reply_next_unused( + struct coap_reply *replies, size_t len); + +/** + * @brief After a response is received, clear all pending + * retransmissions related to that response. + * + * @param response The received response + * @param pendings Pointer to the array of #coap_reply structures + * @param len Size of the array of #coap_reply structures + * + * @return pointer to the associated #coap_pending structure, NULL in + * case none could be found. + */ +struct coap_pending *coap_pending_received( + const struct coap_packet *response, + struct coap_pending *pendings, size_t len); + +/** + * @brief After a response is received, call coap_reply_t handler + * registered in #coap_reply structure + * + * @param response A response received + * @param from Address from which the response was received + * @param replies Pointer to the array of #coap_reply structures + * @param len Size of the array of #coap_reply structures + * + * @return Pointer to the reply matching the packet received, NULL if + * none could be found. + */ +struct coap_reply *coap_response_received( + const struct coap_packet *response, + const struct sockaddr *from, + struct coap_reply *replies, size_t len); + +/** + * @brief Returns the next pending about to expire, pending->timeout + * informs how many ms to next expiration. + * + * @param pendings Pointer to the array of #coap_pending structures + * @param len Size of the array of #coap_pending structures + * + * @return The next #coap_pending to expire, NULL if none is about to + * expire. + */ +struct coap_pending *coap_pending_next_to_expire( + struct coap_pending *pendings, size_t len); + +/** + * @brief After a request is sent, user may want to cycle the pending + * retransmission so the timeout is updated. + * + * @param pending Pending representation to have its timeout updated + * + * @return false if this is the last retransmission. + */ +bool coap_pending_cycle(struct coap_pending *pending); + +/** + * @brief Cancels the pending retransmission, so it again becomes + * available. + * + * @param pending Pending representation to be canceled + */ +void coap_pending_clear(struct coap_pending *pending); + +/** + * @brief Cancels awaiting for this reply, so it becomes available + * again. + * + * @param reply The reply to be canceled + */ +void coap_reply_clear(struct coap_reply *reply); + +/** + * @brief When a request is received, call the appropriate methods of + * the matching resources. + * + * @param cpkt Packet received + * @param resources Array of known resources + * @param from Address from which the packet was received + * + * @return 0 in case of success or negative in case of error. + */ +int coap_handle_request(struct coap_packet *cpkt, + struct coap_resource *resources, + const struct sockaddr *from); + +/** + * @brief Indicates that this resource was updated and that the @a + * notify callback should be called for every registered observer. + * + * @param resource Resource that was updated + * + * @return 0 in case of success or negative in case of error. + */ +int coap_resource_notify(struct coap_resource *resource); + +/** + * @brief Returns if this request is enabling observing a resource. + * + * @param request Request to be checked + * + * @return True if the request is enabling observing a resource, False + * otherwise + */ +bool coap_request_is_observe(const struct coap_packet *request); + +/** + * @brief Returns a pointer to the start of the payload and its size + * + * It will insert the COAP_MARKER (0xFF), if its not set, and return the + * available size for the payload. + * + * @param cpkt Packet to get (or insert) the payload + * @param len Amount of space for the payload + * + * @return pointer to the start of the payload, NULL in case of error. + */ +u8_t *coap_packet_get_payload(struct coap_packet *cpkt, u16_t *len); + +/** + * @brief Sets how much space was used by the payload. + * + * Used for outgoing packets, after coap_packet_get_payload(), to + * update the internal representation with the amount of data that was + * added to the packet. + * + * @param cpkt Packet to be updated + * @param len Amount of data that was added to the payload + * + * @return 0 in case of success or negative in case of error. + */ +int coap_packet_set_used(struct coap_packet *cpkt, u16_t len); + +/** + * @brief Adds an option to the packet. + * + * Note: options must be added in numeric order of their codes. + * + * @param cpkt Packet to be updated + * @param code Option code to add to the packet, see #coap_option_num + * @param value Pointer to the value of the option, will be copied to the packet + * @param len Size of the data to be added + * + * @return 0 in case of success or negative in case of error. + */ +int coap_add_option(struct coap_packet *cpkt, u16_t code, + const void *value, u16_t len); + +/** + * @brief Converts an option to its integer representation. + * + * Assumes that the number is encoded in the network byte order in the + * option. + * + * @param option Pointer to the option value, retrieved by + * coap_find_options() + * + * @return The integer representation of the option + */ +unsigned int coap_option_value_to_int(const struct coap_option *option); + +/** + * @brief Adds an integer value option to the packet. + * + * The option must be added in numeric order of their codes, and the + * least amount of bytes will be used to encode the value. + * + * @param cpkt Packet to be updated + * @param code Option code to add to the packet, see #coap_option_num + * @param val Integer value to be added + * + * @return 0 in case of success or negative in case of error. + */ +int coap_add_option_int(struct coap_packet *cpkt, u16_t code, + unsigned int val); + +/** + * @brief Return the values associated with the option of value @a + * code. + * + * @param cpkt CoAP packet representation + * @param code Option number to look for + * @param options Array of #coap_option where to store the value + * of the options found + * @param veclen Number of elements in the options array + * + * @return The number of options found in packet matching code, + * negative on error. + */ +int coap_find_options(const struct coap_packet *cpkt, u16_t code, + struct coap_option *options, u16_t veclen); + +/** + * Represents the size of each block that will be transferred using + * block-wise transfers [RFC7959]: + * + * Each entry maps directly to the value that is used in the wire. + * + * https://tools.ietf.org/html/rfc7959 + */ +enum coap_block_size { + COAP_BLOCK_16, + COAP_BLOCK_32, + COAP_BLOCK_64, + COAP_BLOCK_128, + COAP_BLOCK_256, + COAP_BLOCK_512, + COAP_BLOCK_1024, +}; + +/** + * @brief Helper for converting the enumeration to the size expressed + * in bytes. + * + * @param block_size The block size to be converted + * + * @return The size in bytes that the block_size represents + */ +static inline u16_t coap_block_size_to_bytes( + enum coap_block_size block_size) +{ + return (1 << (block_size + 4)); +} + +/** + * @brief Represents the current state of a block-wise transaction. + */ +struct coap_block_context { + size_t total_size; + size_t current; + enum coap_block_size block_size; +}; + +/** + * @brief Initializes the context of a block-wise transfer. + * + * @param ctx The context to be initialized + * @param block_size The size of the block + * @param total_size The total size of the transfer, if known + * + * @return 0 in case of success or negative in case of error. + */ +int coap_block_transfer_init(struct coap_block_context *ctx, + enum coap_block_size block_size, + size_t total_size); + +/** + * @brief Add BLOCK1 option to the packet. + * + * @param cpkt Packet to be updated + * @param ctx Block context from which to retrieve the + * information for the Block1 option + * + * @return 0 in case of success or negative in case of error. + */ +int coap_add_block1_option(struct coap_packet *cpkt, + struct coap_block_context *ctx); + +/** + * @brief Add BLOCK2 option to the packet. + * + * @param cpkt Packet to be updated + * @param ctx Block context from which to retrieve the + * information for the Block2 option + * + * @return 0 in case of success or negative in case of error. + */ +int coap_add_block2_option(struct coap_packet *cpkt, + struct coap_block_context *ctx); + +/** + * @brief Add SIZE1 option to the packet. + * + * @param cpkt Packet to be updated + * @param ctx Block context from which to retrieve the + * information for the Size1 option + * + * @return 0 in case of success or negative in case of error. + */ +int coap_add_size1_option(struct coap_packet *cpkt, + struct coap_block_context *ctx); + +/** + * @brief Add SIZE2 option to the packet. + * + * @param cpkt Packet to be updated + * @param ctx Block context from which to retrieve the + * information for the Size2 option + * + * @return 0 in case of success or negative in case of error. + */ +int coap_add_size2_option(struct coap_packet *cpkt, + struct coap_block_context *ctx); + +/** + * @brief Retrieves BLOCK{1,2} and SIZE{1,2} from @a cpkt and updates + * @a ctx accordingly. + * + * @param cpkt Packet in which to look for block-wise transfers options + * @param ctx Block context to be updated + * + * @return 0 in case of success or negative in case of error. + */ +int coap_update_from_block(const struct coap_packet *cpkt, + struct coap_block_context *ctx); + +/** + * @brief Updates @a ctx so after this is called the current entry + * indicates the correct offset in the body of data being + * transferred. + * + * @param cpkt Packet in which to look for block-wise transfers options + * @param ctx Block context to be updated + * + * @return The offset in the block-wise transfer, 0 if the transfer + * has finished. + */ +size_t coap_next_block(const struct coap_packet *cpkt, + struct coap_block_context *ctx); + +/** + * @brief Returns the version present in a CoAP packet. + * + * @param cpkt CoAP packet representation + * + * @return the CoAP version in packet + */ +u8_t coap_header_get_version(const struct coap_packet *cpkt); + +/** + * @brief Returns the type of the CoAP packet. + * + * @param cpkt CoAP packet representation + * + * @return the type of the packet + */ +u8_t coap_header_get_type(const struct coap_packet *cpkt); + +/** + * @brief Returns the token (if any) in the CoAP packet. + * + * @param cpkt CoAP packet representation + * @param len Where to store the length of the token + * + * @return pointer to the start of the token in the CoAP packet. + */ +const u8_t *coap_header_get_token(const struct coap_packet *cpkt, + u8_t *len); + +/** + * @brief Returns the code of the CoAP packet. + * + * @param cpkt CoAP packet representation + * + * @return the code present in the packet + */ +u8_t coap_header_get_code(const struct coap_packet *cpkt); + +/** + * @brief Returns the message id associated with the CoAP packet. + * + * @param cpkt CoAP packet representation + * + * @return the message id present in the packet + */ +u16_t coap_header_get_id(const struct coap_packet *cpkt); + +/** + * @brief Sets the version of the CoAP packet. + * + * @param cpkt CoAP packet representation + * @param ver The CoAP version to set in the packet + */ +void coap_header_set_version(struct coap_packet *cpkt, u8_t ver); + +/** + * @brief Sets the type of the CoAP packet. + * + * @param cpkt CoAP packet representation + * @param type The packet type to set + */ +void coap_header_set_type(struct coap_packet *cpkt, u8_t type); + +/** + * @brief Sets the token in the CoAP packet. + * + * @param cpkt CoAP packet representation + * @param token Token to set in the packet, will be copied + * @param tokenlen Size of the token to be set, 8 bytes maximum + * + * @return 0 in case of success or negative in case of error. + */ +int coap_header_set_token(struct coap_packet *cpkt, const u8_t *token, + u8_t tokenlen); + +/** + * @brief Sets the code present in the CoAP packet. + * + * @param cpkt CoAP packet representation + * @param code The code set in the packet + */ +void coap_header_set_code(struct coap_packet *cpkt, u8_t code); + +/** + * @brief Sets the message id present in the CoAP packet. + * + * @param cpkt CoAP packet representation + * @param id The message id to set in the packet + */ +void coap_header_set_id(struct coap_packet *cpkt, u16_t id); + +/** + * @brief Helper to generate message ids + * + * @return a new message id + */ +static inline u16_t coap_next_id(void) +{ + static u16_t message_id; + + return ++message_id; +} + +/** + * @brief Returns a randomly generated array of 8 bytes, that can be + * used as a message's token. + * + * @return a 8-byte pseudo-random token. + */ +u8_t *coap_next_token(void); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __COAP_H__ */ diff --git a/include/net/coap_link_format.h b/include/net/coap_link_format.h new file mode 100644 index 0000000000000..5bebd629f0b91 --- /dev/null +++ b/include/net/coap_link_format.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * + * @brief CoAP implementation for Zephyr. + */ + +#ifndef __LINK_FORMAT_H__ +#define __LINK_FORMAT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup coap COAP Library + * @{ + */ + +#define _COAP_WELL_KNOWN_CORE_PATH \ + ((const char * const[]) { ".well-known", "core", NULL }) + +int _coap_well_known_core_get(struct coap_resource *resource, + struct coap_packet *request, + const struct sockaddr *from); + +/** + * This resource should be added before all other resources that should be + * included in the responses of the .well-known/core resource. + */ +#define COAP_WELL_KNOWN_CORE_RESOURCE \ + { .get = _coap_well_known_core_get, \ + .path = _COAP_WELL_KNOWN_CORE_PATH, \ + } + +/** + * In case you want to add attributes to the resources included in the + * 'well-known/core' "virtual" resource, the 'user_data' field should point + * to a valid coap_core_metadata structure. + */ +struct coap_core_metadata { + const char * const *attributes; + void *user_data; +}; + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LINK_FORMAT_H__ */ diff --git a/subsys/net/lib/Kbuild b/subsys/net/lib/Kbuild index cc297ac8d350a..9104db2eccee1 100644 --- a/subsys/net/lib/Kbuild +++ b/subsys/net/lib/Kbuild @@ -1,5 +1,6 @@ obj-$(CONFIG_NET_SOCKETS) += sockets/ obj-$(CONFIG_ZOAP) += zoap/ +obj-$(CONFIG_COAP) += coap/ obj-$(CONFIG_DNS_RESOLVER) += dns/ obj-$(CONFIG_MQTT_LIB) += mqtt/ obj-$(CONFIG_HTTP) += http/ diff --git a/subsys/net/lib/Kconfig b/subsys/net/lib/Kconfig index ea638f4d6d280..18b188f2b5e38 100644 --- a/subsys/net/lib/Kconfig +++ b/subsys/net/lib/Kconfig @@ -8,6 +8,8 @@ menu "Network Protocols" source "subsys/net/lib/zoap/Kconfig" +source "subsys/net/lib/coap/Kconfig" + source "subsys/net/lib/dns/Kconfig" source "subsys/net/lib/mqtt/Kconfig" diff --git a/subsys/net/lib/Makefile b/subsys/net/lib/Makefile index d90e6d6b24976..af0f21b6e704d 100644 --- a/subsys/net/lib/Makefile +++ b/subsys/net/lib/Makefile @@ -6,6 +6,10 @@ ifdef CONFIG_ZOAP include $(srctree)/subsys/net/lib/zoap/Makefile endif +ifdef CONFIG_COAP +include $(srctree)/subsys/net/lib/coap/Makefile +endif + ifdef CONFIG_DNS_RESOLVER include $(srctree)/subsys/net/lib/dns/Makefile endif diff --git a/subsys/net/lib/coap/Kbuild b/subsys/net/lib/coap/Kbuild new file mode 100644 index 0000000000000..825f8bfcc0abe --- /dev/null +++ b/subsys/net/lib/coap/Kbuild @@ -0,0 +1,4 @@ +subdir-ccflags-y +=-I$(srctree)/subsys/net/lib/coap +ccflags-y += -I${srctree}/net/ip + +obj-y := coap.o coap_link_format.o diff --git a/subsys/net/lib/coap/Kconfig b/subsys/net/lib/coap/Kconfig new file mode 100644 index 0000000000000..127f37eed2ede --- /dev/null +++ b/subsys/net/lib/coap/Kconfig @@ -0,0 +1,43 @@ +# Kconfig - Coap, CoAP implementation for Zephyr + +# +# Copyright (c) 2017 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +config COAP + bool + prompt "CoAP Support" + default n + help + This option enables the implementation of CoAP. + +# This setting is only used by unit test. Do not enable it in applications +config COAP_TEST_API_ENABLE + bool "Enable test API for CoAP unit tests" + default n + depends on COAP + help + Do not enable this for normal use. + +config COAP_WELL_KNOWN_BLOCK_WISE + bool + prompt "CoAP ./well-known/core services block wise support" + default n + depends on COAP + help + This option enables the block wise support of CoAP response + to ./well-known/core request. Without this option all resource's + information will be sent in a single IP packet (can be multiple + fragments depends on MTU size). This will be useful in mesh kind + of networks. + +config COAP_WELL_KNOWN_BLOCK_WISE_SIZE + int + prompt "CoAP ./well-known/core services block wise support" + default 32 + depends on COAP_WELL_KNOWN_BLOCK_WISE + help + Maximum size of CoAP block. Valid values are 16, 32, 64, 128, + 256, 512 and 1024. diff --git a/subsys/net/lib/coap/Makefile b/subsys/net/lib/coap/Makefile new file mode 100644 index 0000000000000..ff88030c66204 --- /dev/null +++ b/subsys/net/lib/coap/Makefile @@ -0,0 +1 @@ +ZEPHYRINCLUDE += -I$(srctree)/subsys/net/lib/coap diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c new file mode 100644 index 0000000000000..80c55f28f6d0d --- /dev/null +++ b/subsys/net/lib/coap/coap.c @@ -0,0 +1,1311 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +struct option_context { + u8_t *buf; + int delta; + int used; /* size used of options */ + int buflen; +}; + +#define COAP_VERSION 1 + +#define COAP_MARKER 0xFF + +#define BASIC_HEADER_SIZE 4 + +static u8_t coap_option_header_get_delta(u8_t buf) +{ + return (buf & 0xF0) >> 4; +} + +static u8_t coap_option_header_get_len(u8_t buf) +{ + return buf & 0x0F; +} + +static void coap_option_header_set_delta(u8_t *buf, u8_t delta) +{ + *buf = (delta & 0xF) << 4; +} + +static void coap_option_header_set_len(u8_t *buf, u8_t len) +{ + *buf |= (len & 0xF); +} + +static int decode_delta(int num, const u8_t *buf, s16_t buflen, + u16_t *decoded) +{ + int hdrlen = 0; + + switch (num) { + case 13: + if (buflen < 1) { + return -EINVAL; + } + + num = *buf + 13; + hdrlen += 1; + break; + case 14: + if (buflen < 2) { + return -EINVAL; + } + + num = sys_get_be16(buf) + 269; + hdrlen += 2; + break; + case 15: + return -EINVAL; + } + + *decoded = num; + + return hdrlen; +} + +static int coap_parse_option(const struct coap_packet *cpkt, + struct option_context *context, + u8_t **value, u16_t *vlen) +{ + u16_t delta, len; + int r; + + if (context->buflen < 1) { + return 0; + } + + /* This indicates that options have ended */ + if (context->buf[0] == COAP_MARKER) { + return 0; + } + + delta = coap_option_header_get_delta(context->buf[0]); + len = coap_option_header_get_len(context->buf[0]); + context->buf += 1; + context->used += 1; + context->buflen -= 1; + + /* In case 'delta' doesn't fit the option fixed header. */ + r = decode_delta(delta, context->buf, context->buflen, &delta); + if (r < 0) { + return -EINVAL; + } + + context->buf += r; + context->used += r; + context->buflen -= r; + + /* In case 'len' doesn't fit the option fixed header. */ + r = decode_delta(len, context->buf, context->buflen, &len); + if (r < 0) { + return -EINVAL; + } + + if (context->buflen < r + len) { + return -EINVAL; + } + + if (value) { + *value = context->buf + r; + } + + if (vlen) { + *vlen = len; + } + + context->buf += r + len; + context->used += r + len; + context->buflen -= r + len; + + context->delta += delta; + + return context->used; +} + +static int coap_parse_options(struct coap_packet *cpkt, unsigned int offset) +{ + struct option_context context = { + .delta = 0, + .used = 0, + .buflen = cpkt->pkt->frags->len - offset, + .buf = &cpkt->pkt->frags->data[offset] }; + + while (true) { + int r = coap_parse_option(cpkt, &context, NULL, NULL); + + if (r < 0) { + return -EINVAL; + } + + if (r == 0) { + break; + } + } + return context.used; +} + +static u8_t coap_header_get_tkl(const struct coap_packet *cpkt) +{ + return cpkt->pkt->frags->data[0] & 0xF; +} + +static int coap_get_header_len(const struct coap_packet *cpkt) +{ + unsigned int hdrlen; + u8_t tkl; + + hdrlen = BASIC_HEADER_SIZE; + + if (cpkt->pkt->frags->len < hdrlen) { + return -EINVAL; + } + + tkl = coap_header_get_tkl(cpkt); + + /* Token lenghts 9-15 are reserved. */ + if (tkl > 8) { + return -EINVAL; + } + + if (cpkt->pkt->frags->len < hdrlen + tkl) { + return -EINVAL; + } + + return hdrlen + tkl; +} + +int coap_packet_parse(struct coap_packet *cpkt, struct net_pkt *pkt) +{ + int optlen, hdrlen; + + if (!pkt || !pkt->frags) { + return -EINVAL; + } + + memset(cpkt, 0, sizeof(*cpkt)); + cpkt->pkt = pkt; + + hdrlen = coap_get_header_len(cpkt); + if (hdrlen < 0) { + return -EINVAL; + } + + optlen = coap_parse_options(cpkt, hdrlen); + if (optlen < 0) { + return -EINVAL; + } + + if (pkt->frags->len < hdrlen + optlen) { + return -EINVAL; + } + + if (pkt->frags->len <= hdrlen + optlen + 1) { + cpkt->start = NULL; + return 0; + } + + cpkt->start = pkt->frags->data + hdrlen + optlen + 1; + cpkt->total_size = pkt->frags->len; + + return 0; +} + +static int delta_encode(int num, u8_t *value, u8_t *buf, size_t buflen) +{ + u16_t v; + + if (num < 13) { + *value = num; + return 0; + } + + if (num < 269) { + if (buflen < 1) { + return -EINVAL; + } + + *value = 13; + *buf = num - 13; + return 1; + } + + if (buflen < 2) { + return -EINVAL; + } + + *value = 14; + + v = sys_cpu_to_be16(num - 269); + memcpy(buf, &v, sizeof(v)); + + return 2; +} + +static int coap_option_encode(struct option_context *context, u16_t code, + const void *value, u16_t len) +{ + int delta, offset, r; + u8_t data; + + delta = code - context->delta; + + offset = 1; + + r = delta_encode(delta, &data, context->buf + offset, + context->buflen - offset); + + if (r < 0) { + return -EINVAL; + } + + offset += r; + coap_option_header_set_delta(context->buf, data); + + r = delta_encode(len, &data, context->buf + offset, + context->buflen - offset); + if (r < 0) { + return -EINVAL; + } + + offset += r; + coap_option_header_set_len(context->buf, data); + + if (context->buflen < offset + len) { + return -EINVAL; + } + + memcpy(context->buf + offset, value, len); + + return offset + len; +} + +int coap_packet_init(struct coap_packet *cpkt, + struct net_pkt *pkt) +{ + void *data; + + if (!pkt || !pkt->frags) { + return -EINVAL; + } + + if (net_buf_tailroom(pkt->frags) < BASIC_HEADER_SIZE) { + return -ENOMEM; + } + + memset(cpkt, 0, sizeof(*cpkt)); + cpkt->total_size = net_buf_tailroom(pkt->frags); + + data = net_buf_add(pkt->frags, BASIC_HEADER_SIZE); + + /* + * As some header data is built by OR operations, we zero + * the header to be sure. + */ + memset(data, 0, BASIC_HEADER_SIZE); + cpkt->pkt = pkt; + + return 0; +} + +int coap_pending_init(struct coap_pending *pending, + const struct coap_packet *request, + const struct sockaddr *addr) +{ + memset(pending, 0, sizeof(*pending)); + pending->id = coap_header_get_id(request); + memcpy(&pending->addr, addr, sizeof(*addr)); + + /* Will increase the reference count when the pending is cycled */ + pending->pkt = request->pkt; + + return 0; +} + +struct coap_pending *coap_pending_next_unused( + struct coap_pending *pendings, size_t len) +{ + struct coap_pending *p; + size_t i; + + for (i = 0, p = pendings; i < len; i++, p++) { + if (p->timeout == 0 && !p->pkt) { + return p; + } + } + + return NULL; +} + +struct coap_reply *coap_reply_next_unused( + struct coap_reply *replies, size_t len) +{ + struct coap_reply *r; + size_t i; + + for (i = 0, r = replies; i < len; i++, r++) { + if (!r->reply) { + return r; + } + } + + return NULL; +} + +static inline bool is_addr_unspecified(const struct sockaddr *addr) +{ + if (addr->sa_family == AF_UNSPEC) { + return true; + } + + if (addr->sa_family == AF_INET6) { + return net_is_ipv6_addr_unspecified( + &(net_sin6(addr)->sin6_addr)); + } else if (addr->sa_family == AF_INET) { + return net_sin(addr)->sin_addr.s4_addr32[0] == 0; + } + + return false; +} + +struct coap_observer *coap_observer_next_unused( + struct coap_observer *observers, size_t len) +{ + struct coap_observer *o; + size_t i; + + for (i = 0, o = observers; i < len; i++, o++) { + if (is_addr_unspecified(&o->addr)) { + return o; + } + } + + return NULL; +} + +struct coap_pending *coap_pending_received( + const struct coap_packet *response, + struct coap_pending *pendings, size_t len) +{ + struct coap_pending *p; + u16_t resp_id = coap_header_get_id(response); + size_t i; + + for (i = 0, p = pendings; i < len; i++, p++) { + if (!p->timeout) { + continue; + } + + if (resp_id != p->id) { + continue; + } + + coap_pending_clear(p); + return p; + } + + return NULL; +} + +struct coap_pending *coap_pending_next_to_expire( + struct coap_pending *pendings, size_t len) +{ + struct coap_pending *p, *found = NULL; + size_t i; + + for (i = 0, p = pendings; i < len; i++, p++) { + if (p->timeout && (!found || found->timeout < p->timeout)) { + found = p; + } + } + + return found; +} + +#define LAST_TIMEOUT (2345 * 4) + +static s32_t next_timeout(s32_t previous) +{ + switch (previous) { + case 0: + return 2345; + case 2345: + return 2345 * 2; + case (2345 * 2): + return LAST_TIMEOUT; + case LAST_TIMEOUT: + return LAST_TIMEOUT; + } + + return 2345; +} + +bool coap_pending_cycle(struct coap_pending *pending) +{ + s32_t old = pending->timeout; + bool cont; + + pending->timeout = next_timeout(pending->timeout); + + /* If the timeout changed, it's not the last, continue... */ + cont = (old != pending->timeout); + if (cont) { + /* + * When it it is the last retransmission, the buffer + * will be destroyed when it is transmitted. + */ + net_pkt_ref(pending->pkt); + } + + return cont; +} + +void coap_pending_clear(struct coap_pending *pending) +{ + pending->timeout = 0; + net_pkt_unref(pending->pkt); + pending->pkt = NULL; +} + +static bool uri_path_eq(const struct coap_packet *cpkt, + const char * const *path) +{ + struct coap_option options[16]; + u16_t count = 16; + int i, r; + + r = coap_find_options(cpkt, COAP_OPTION_URI_PATH, options, count); + if (r < 0) { + return false; + } + + count = r; + + for (i = 0; i < count && path[i]; i++) { + size_t len; + + len = strlen(path[i]); + + if (options[i].len != len) { + return false; + } + + if (memcmp(options[i].value, path[i], len)) { + return false; + } + } + + return i == count && !path[i]; +} + +static coap_method_t method_from_code(const struct coap_resource *resource, + u8_t code) +{ + switch (code) { + case COAP_METHOD_GET: + return resource->get; + case COAP_METHOD_POST: + return resource->post; + case COAP_METHOD_PUT: + return resource->put; + case COAP_METHOD_DELETE: + return resource->del; + default: + return NULL; + } +} + +static bool is_request(const struct coap_packet *cpkt) +{ + u8_t code = coap_header_get_code(cpkt); + + return !(code & ~COAP_REQUEST_MASK); +} + +int coap_handle_request(struct coap_packet *cpkt, + struct coap_resource *resources, + const struct sockaddr *from) +{ + struct coap_resource *resource; + + if (!is_request(cpkt)) { + return 0; + } + + for (resource = resources; resource && resource->path; resource++) { + coap_method_t method; + u8_t code; + + /* FIXME: deal with hierarchical resources */ + if (!uri_path_eq(cpkt, resource->path)) { + continue; + } + + code = coap_header_get_code(cpkt); + method = method_from_code(resource, code); + + if (!method) { + return 0; + } + + return method(resource, cpkt, from); + } + + return -ENOENT; +} + +unsigned int coap_option_value_to_int(const struct coap_option *option) +{ + switch (option->len) { + case 0: + return 0; + case 1: + return option->value[0]; + case 2: + return (option->value[1] << 0) | (option->value[0] << 8); + case 3: + return (option->value[2] << 0) | (option->value[1] << 8) | + (option->value[0] << 16); + case 4: + return (option->value[2] << 0) | (option->value[2] << 8) | + (option->value[1] << 16) | (option->value[0] << 24); + default: + return 0; + } + + return 0; +} + +static int get_observe_option(const struct coap_packet *cpkt) +{ + struct coap_option option = {}; + u16_t count = 1; + int r; + + r = coap_find_options(cpkt, COAP_OPTION_OBSERVE, &option, count); + if (r <= 0) { + return -ENOENT; + } + + return coap_option_value_to_int(&option); +} + +struct coap_reply *coap_response_received( + const struct coap_packet *response, + const struct sockaddr *from, + struct coap_reply *replies, size_t len) +{ + struct coap_reply *r; + const u8_t *token; + u16_t id; + u8_t tkl; + size_t i; + + id = coap_header_get_id(response); + token = coap_header_get_token(response, &tkl); + + for (i = 0, r = replies; i < len; i++, r++) { + int age; + + if ((r->id == 0) && (r->tkl == 0)) { + continue; + } + + /* Piggybacked must match id when token is empty */ + if ((r->id != id) && (tkl == 0)) { + continue; + } + + /* Separate response must only match token */ + if (tkl > 0 && memcmp(r->token, token, tkl)) { + continue; + } + + age = get_observe_option(response); + if (age > 0) { + /* + * age == 2 means that the notifications wrapped, + * or this is the first one + */ + if (r->age > age && age != 2) { + continue; + } + + r->age = age; + } + + r->reply(response, r, from); + return r; + } + + return NULL; +} + +void coap_reply_init(struct coap_reply *reply, + const struct coap_packet *request) +{ + const u8_t *token; + u8_t tkl; + int age; + + reply->id = coap_header_get_id(request); + token = coap_header_get_token(request, &tkl); + + if (tkl > 0) { + memcpy(reply->token, token, tkl); + } + reply->tkl = tkl; + + age = get_observe_option(request); + + /* It means that the request enabled observing a resource */ + if (age == 0) { + reply->age = 2; + } +} + +void coap_reply_clear(struct coap_reply *reply) +{ + reply->id = 0; + reply->tkl = 0; + reply->reply = NULL; +} + +int coap_resource_notify(struct coap_resource *resource) +{ + struct coap_observer *o; + + resource->age++; + + if (!resource->notify) { + return -ENOENT; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&resource->observers, o, list) { + resource->notify(resource, o); + } + + return 0; +} + +bool coap_request_is_observe(const struct coap_packet *request) +{ + return get_observe_option(request) == 0; +} + +void coap_observer_init(struct coap_observer *observer, + const struct coap_packet *request, + const struct sockaddr *addr) +{ + const u8_t *token; + u8_t tkl; + + token = coap_header_get_token(request, &tkl); + + if (tkl > 0) { + memcpy(observer->token, token, tkl); + } + + observer->tkl = tkl; + + net_ipaddr_copy(&observer->addr, addr); +} + +bool coap_register_observer(struct coap_resource *resource, + struct coap_observer *observer) +{ + bool first; + + sys_slist_append(&resource->observers, &observer->list); + + first = resource->age == 0; + if (first) { + resource->age = 2; + } + + return first; +} + +void coap_remove_observer(struct coap_resource *resource, + struct coap_observer *observer) +{ + sys_slist_find_and_remove(&resource->observers, &observer->list); +} + +static bool sockaddr_equal(const struct sockaddr *a, + const struct sockaddr *b) +{ + /* + * FIXME: Should we consider ipv6-mapped ipv4 addresses as equal to + * ipv4 addresses? + */ + if (a->sa_family != b->sa_family) { + return false; + } + + if (a->sa_family == AF_INET) { + const struct sockaddr_in *a4 = net_sin(a); + const struct sockaddr_in *b4 = net_sin(b); + + if (a4->sin_port != b4->sin_port) { + return false; + } + + return net_ipv4_addr_cmp(&a4->sin_addr, &b4->sin_addr); + } + + if (b->sa_family == AF_INET6) { + const struct sockaddr_in6 *a6 = net_sin6(a); + const struct sockaddr_in6 *b6 = net_sin6(b); + + if (a6->sin6_scope_id != b6->sin6_scope_id) { + return false; + } + + if (a6->sin6_port != b6->sin6_port) { + return false; + } + + return net_ipv6_addr_cmp(&a6->sin6_addr, &b6->sin6_addr); + } + + /* Invalid address family */ + return false; +} + +struct coap_observer *coap_find_observer_by_addr( + struct coap_observer *observers, size_t len, + const struct sockaddr *addr) +{ + size_t i; + + for (i = 0; i < len; i++) { + struct coap_observer *o = &observers[i]; + + if (sockaddr_equal(&o->addr, addr)) { + return o; + } + } + + return NULL; +} + +u8_t *coap_packet_get_payload(struct coap_packet *cpkt, u16_t *len) +{ + u8_t *appdata = cpkt->pkt->frags->data; + u16_t appdatalen = cpkt->pkt->frags->len; + + if (!cpkt || !len) { + return NULL; + } + + if (!cpkt->start) { + if (appdatalen + 1 >= cpkt->total_size) { + return NULL; + } + + appdata[appdatalen] = COAP_MARKER; + cpkt->pkt->frags->len += 1; + + cpkt->start = appdata + cpkt->pkt->frags->len; + } + + *len = appdata + cpkt->total_size - cpkt->start; + + return cpkt->start; +} + +int coap_packet_set_used(struct coap_packet *cpkt, u16_t len) +{ + if ((cpkt->pkt->frags->len + len) > + net_buf_tailroom(cpkt->pkt->frags)) { + return -ENOMEM; + } + + cpkt->pkt->frags->len += len; + + return 0; +} + +int coap_add_option(struct coap_packet *cpkt, u16_t code, + const void *value, u16_t len) +{ + struct net_buf *frag = cpkt->pkt->frags; + struct option_context context = { .delta = 0, + .used = 0 }; + int r, offset; + + if (cpkt->start) { + return -EINVAL; + } + + offset = coap_get_header_len(cpkt); + if (offset < 0) { + return -EINVAL; + } + + /* We check for options in all the 'used' space. */ + context.buflen = frag->len - offset; + context.buf = frag->data + offset; + + while (context.delta <= code) { + r = coap_parse_option(cpkt, &context, NULL, NULL); + if (r < 0) { + return -ENOENT; + } + + if (r == 0) { + break; + } + + /* If the new option code is out of order. */ + if (code < context.delta) { + return -EINVAL; + } + } + /* We can now add options using all the available space. */ + context.buflen = net_buf_tailroom(frag) - (offset + context.used); + + r = coap_option_encode(&context, code, value, len); + if (r < 0) { + return -EINVAL; + } + + frag->len += r; + + return 0; +} + +int coap_add_option_int(struct coap_packet *cpkt, u16_t code, + unsigned int val) +{ + u8_t data[4], len; + + if (val == 0) { + data[0] = 0; + len = 0; + } else if (val < 0xFF) { + data[0] = (u8_t) val; + len = 1; + } else if (val < 0xFFFF) { + sys_put_be16(val, data); + len = 2; + } else if (val < 0xFFFFFF) { + sys_put_be16(val, data); + data[2] = val >> 16; + len = 3; + } else { + sys_put_be32(val, data); + len = 4; + } + + return coap_add_option(cpkt, code, data, len); +} + +int coap_find_options(const struct coap_packet *cpkt, u16_t code, + struct coap_option *options, u16_t veclen) +{ + struct net_buf *frag = cpkt->pkt->frags; + struct option_context context = { .delta = 0, + .used = 0 }; + int hdrlen, count = 0; + u16_t len; + + hdrlen = coap_get_header_len(cpkt); + if (hdrlen < 0) { + return -EINVAL; + } + + context.buflen = frag->len - hdrlen; + context.buf = (u8_t *)frag->data + hdrlen; + + while (context.delta <= code && count < veclen) { + int used = coap_parse_option(cpkt, &context, + (u8_t **)&options[count].value, + &len); + options[count].len = len; + if (used < 0) { + return -ENOENT; + } + + if (used == 0) { + break; + } + + if (code != context.delta) { + continue; + } + + count++; + } + + return count; +} + +u8_t coap_header_get_version(const struct coap_packet *cpkt) +{ + return (cpkt->pkt->frags->data[0] & 0xC0) >> 6; +} + +u8_t coap_header_get_type(const struct coap_packet *cpkt) +{ + return (cpkt->pkt->frags->data[0] & 0x30) >> 4; +} + +u8_t coap_header_get_code(const struct coap_packet *cpkt) +{ + return cpkt->pkt->frags->data[1]; +} + +const u8_t *coap_header_get_token(const struct coap_packet *cpkt, + u8_t *len) +{ + struct net_buf *frag = cpkt->pkt->frags; + u8_t tkl = coap_header_get_tkl(cpkt); + + if (len) { + *len = 0; + } + + if (tkl == 0) { + return NULL; + } + + if (len) { + *len = tkl; + } + + return (u8_t *)frag->data + BASIC_HEADER_SIZE; +} + +u8_t coap_header_get_code(const struct coap_packet *cpkt) +{ + u8_t code = coap_header_get_code(cpkt); + + switch (code) { + /* Methods are encoded in the code field too */ + case COAP_METHOD_GET: + case COAP_METHOD_POST: + case COAP_METHOD_PUT: + case COAP_METHOD_DELETE: + + /* All the defined response codes */ + case COAP_RESPONSE_CODE_OK: + case COAP_RESPONSE_CODE_CREATED: + case COAP_RESPONSE_CODE_DELETED: + case COAP_RESPONSE_CODE_VALID: + case COAP_RESPONSE_CODE_CHANGED: + case COAP_RESPONSE_CODE_CONTENT: + case COAP_RESPONSE_CODE_CONTINUE: + case COAP_RESPONSE_CODE_BAD_REQUEST: + case COAP_RESPONSE_CODE_UNAUTHORIZED: + case COAP_RESPONSE_CODE_BAD_OPTION: + case COAP_RESPONSE_CODE_FORBIDDEN: + case COAP_RESPONSE_CODE_NOT_FOUND: + case COAP_RESPONSE_CODE_NOT_ALLOWED: + case COAP_RESPONSE_CODE_NOT_ACCEPTABLE: + case COAP_RESPONSE_CODE_INCOMPLETE: + case COAP_RESPONSE_CODE_PRECONDITION_FAILED: + case COAP_RESPONSE_CODE_REQUEST_TOO_LARGE: + case COAP_RESPONSE_CODE_UNSUPPORTED_CONTENT_FORMAT: + case COAP_RESPONSE_CODE_INTERNAL_ERROR: + case COAP_RESPONSE_CODE_NOT_IMPLEMENTED: + case COAP_RESPONSE_CODE_BAD_GATEWAY: + case COAP_RESPONSE_CODE_SERVICE_UNAVAILABLE: + case COAP_RESPONSE_CODE_GATEWAY_TIMEOUT: + case COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED: + case COAP_CODE_EMPTY: + return code; + default: + return COAP_CODE_EMPTY; + } +} + +u16_t coap_header_get_id(const struct coap_packet *cpkt) +{ + return sys_get_be16(&cpkt->pkt->frags->data[2]); +} + +void coap_header_set_version(struct coap_packet *cpkt, u8_t ver) +{ + cpkt->pkt->frags->data[0] |= (ver & 0x3) << 6; +} + +void coap_header_set_type(struct coap_packet *cpkt, u8_t type) +{ + cpkt->pkt->frags->data[0] |= (type & 0x3) << 4; +} + +int coap_header_set_token(struct coap_packet *cpkt, const u8_t *token, + u8_t tokenlen) +{ + struct net_buf *frag = cpkt->pkt->frags; + u8_t *appdata = frag->data; + + if (net_buf_tailroom(frag) < BASIC_HEADER_SIZE + tokenlen) { + return -EINVAL; + } + + if (tokenlen > 8) { + return -EINVAL; + } + + frag->len += tokenlen; + + appdata[0] |= tokenlen & 0xF; + + memcpy(frag->data + BASIC_HEADER_SIZE, token, tokenlen); + + return 0; +} + +void coap_header_set_code(struct coap_packet *cpkt, u8_t code) +{ + cpkt->pkt->frags->data[1] = code; +} + +void coap_header_set_id(struct coap_packet *cpkt, u16_t id) +{ + sys_put_be16(id, &cpkt->pkt->frags->data[2]); +} + +int coap_block_transfer_init(struct coap_block_context *ctx, + enum coap_block_size block_size, + size_t total_size) +{ + ctx->block_size = block_size; + ctx->total_size = total_size; + ctx->current = 0; + + return 0; +} + +#define GET_BLOCK_SIZE(v) (((v) & 0x7)) +#define GET_MORE(v) (!!((v) & 0x08)) +#define GET_NUM(v) ((v) >> 4) + +#define SET_BLOCK_SIZE(v, b) (v |= ((b) & 0x07)) +#define SET_MORE(v, m) ((v) |= (m) ? 0x08 : 0x00) +#define SET_NUM(v, n) ((v) |= ((n) << 4)) + +int coap_add_block1_option(struct coap_packet *cpkt, + struct coap_block_context *ctx) +{ + u16_t bytes = coap_block_size_to_bytes(ctx->block_size); + unsigned int val = 0; + int r; + + if (is_request(cpkt)) { + SET_BLOCK_SIZE(val, ctx->block_size); + SET_MORE(val, ctx->current + bytes < ctx->total_size); + SET_NUM(val, ctx->current / bytes); + } else { + SET_BLOCK_SIZE(val, ctx->block_size); + SET_NUM(val, ctx->current / bytes); + } + + r = coap_add_option_int(cpkt, COAP_OPTION_BLOCK1, val); + + return r; +} + +int coap_add_block2_option(struct coap_packet *cpkt, + struct coap_block_context *ctx) +{ + int r, val = 0; + u16_t bytes = coap_block_size_to_bytes(ctx->block_size); + + if (is_request(cpkt)) { + SET_BLOCK_SIZE(val, ctx->block_size); + SET_NUM(val, ctx->current / bytes); + } else { + SET_BLOCK_SIZE(val, ctx->block_size); + SET_MORE(val, ctx->current + bytes < ctx->total_size); + SET_NUM(val, ctx->current / bytes); + } + + r = coap_add_option_int(cpkt, COAP_OPTION_BLOCK2, val); + + return r; +} + +int coap_add_size1_option(struct coap_packet *cpkt, + struct coap_block_context *ctx) +{ + return coap_add_option_int(cpkt, COAP_OPTION_SIZE1, ctx->total_size); +} + +int coap_add_size2_option(struct coap_packet *cpkt, + struct coap_block_context *ctx) +{ + return coap_add_option_int(cpkt, COAP_OPTION_SIZE2, ctx->total_size); +} + +static int get_block_option(const struct coap_packet *cpkt, u16_t code) +{ + struct coap_option option; + unsigned int val; + int count = 1; + + count = coap_find_options(cpkt, code, &option, count); + if (count <= 0) { + return -ENOENT; + } + + val = coap_option_value_to_int(&option); + + return val; +} + +static int update_descriptive_block(struct coap_block_context *ctx, + int block, int size) +{ + size_t new_current = GET_NUM(block) << (GET_BLOCK_SIZE(block) + 4); + + if (block == -ENOENT) { + return 0; + } + + if (size && ctx->total_size && ctx->total_size != size) { + return -EINVAL; + } + + if (ctx->current > 0 && GET_BLOCK_SIZE(block) > ctx->block_size) { + return -EINVAL; + } + + if (ctx->total_size && new_current > ctx->total_size) { + return -EINVAL; + } + + if (size) { + ctx->total_size = size; + } + ctx->current = new_current; + ctx->block_size = min(GET_BLOCK_SIZE(block), ctx->block_size); + + return 0; +} + +static int update_control_block1(struct coap_block_context *ctx, + int block, int size) +{ + size_t new_current = GET_NUM(block) << (GET_BLOCK_SIZE(block) + 4); + + if (block == -ENOENT) { + return 0; + } + + if (new_current != ctx->current) { + return -EINVAL; + } + + if (GET_BLOCK_SIZE(block) > ctx->block_size) { + return -EINVAL; + } + + ctx->block_size = GET_BLOCK_SIZE(block); + ctx->total_size = size; + + return 0; +} + +static int update_control_block2(struct coap_block_context *ctx, + int block, int size) +{ + size_t new_current = GET_NUM(block) << (GET_BLOCK_SIZE(block) + 4); + + if (block == -ENOENT) { + return 0; + } + + if (GET_MORE(block)) { + return -EINVAL; + } + + if (GET_NUM(block) > 0 && GET_BLOCK_SIZE(block) != ctx->block_size) { + return -EINVAL; + } + + ctx->current = new_current; + ctx->block_size = min(GET_BLOCK_SIZE(block), ctx->block_size); + + return 0; +} + +int coap_update_from_block(const struct coap_packet *cpkt, + struct coap_block_context *ctx) +{ + int r, block1, block2, size1, size2; + + block1 = get_block_option(cpkt, COAP_OPTION_BLOCK1); + block2 = get_block_option(cpkt, COAP_OPTION_BLOCK2); + size1 = get_block_option(cpkt, COAP_OPTION_SIZE1); + size2 = get_block_option(cpkt, COAP_OPTION_SIZE2); + + size1 = size1 == -ENOENT ? 0 : size1; + size2 = size2 == -ENOENT ? 0 : size2; + + if (is_request(cpkt)) { + r = update_control_block2(ctx, block2, size2); + if (r) { + return r; + } + + return update_descriptive_block(ctx, block1, size1); + } + + r = update_control_block1(ctx, block1, size1); + if (r) { + return r; + } + + return update_descriptive_block(ctx, block2, size2); +} + +size_t coap_next_block(const struct coap_packet *cpkt, + struct coap_block_context *ctx) +{ + int block; + if (is_request(cpkt)) { + block = get_block_option(cpkt, COAP_OPTION_BLOCK1); + } else { + block = get_block_option(cpkt, COAP_OPTION_BLOCK2); + } + + if (!GET_MORE(block)) { + return 0; + } + + ctx->current += coap_block_size_to_bytes(ctx->block_size); + + return ctx->current; +} + +u8_t *coap_next_token(void) +{ + static u32_t rand[2]; + + rand[0] = sys_rand32_get(); + rand[1] = sys_rand32_get(); + + return (u8_t *) rand; +} diff --git a/subsys/net/lib/coap/coap_link_format.c b/subsys/net/lib/coap/coap_link_format.c new file mode 100644 index 0000000000000..f5ebc729de24a --- /dev/null +++ b/subsys/net/lib/coap/coap_link_format.c @@ -0,0 +1,726 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#define PKT_WAIT_TIME K_SECONDS(1) +/* CoAP End Of Options Marker */ +#define COAP_MARKER 0xFF + +static bool match_path_uri(const char * const *path, + const char *uri, u16_t len) +{ + const char * const *p = NULL; + int i, j, k, plen; + + if (!path) { + return false; + } + + if (len <= 1 || uri[0] != '/') { + return false; + } + + p = path; + plen = *p ? strlen(*p) : 0; + j = 0; + + if (plen == 0) { + return false; + } + + /* Go through uri and try to find a matching path */ + for (i = 1; i < len; i++) { + while (*p) { + plen = strlen(*p); + + k = i; + + for (j = 0; j < plen; j++) { + if (uri[k] == '*') { + if ((k + 1) == len) { + return true; + } + } + + if (uri[k] != (*p)[j]) { + goto next; + } + + k++; + } + + if (i == (k - 1) && j == plen) { + return true; + } + + if (k == len && j == plen) { + return true; + } + + next: + p++; + } + } + + /* Did we find the resource or not */ + if (i == len && !*p) { + return false; + } + + return true; +} + +static bool match_attributes(const char * const *attributes, + const struct coap_option *query) +{ + const char * const *attr; + + /* FIXME: deal with the case when there are multiple options in a + * query, for example: 'rt=lux temperature', if I want to list + * resources with resource type lux or temperature. + */ + for (attr = attributes; attr && *attr; attr++) { + u16_t attr_len = strlen(*attr); + + if (query->len != attr_len) { + continue; + } + + if (!strncmp((char *) query->value, *attr, attr_len)) { + return true; + } + } + + return false; +} + +static bool match_queries_resource(const struct coap_resource *resource, + const struct coap_option *query, + int num_queries) +{ + struct coap_core_metadata *meta = resource->user_data; + const char * const *attributes = NULL; + const int href_len = strlen("href"); + + if (num_queries == 0) { + return true; + } + + if (meta && meta->attributes) { + attributes = meta->attributes; + } + + if (!attributes) { + return false; + } + + if (query->len > href_len + 1 && + !strncmp((char *) query->value, "href", href_len)) { + /* The stuff after 'href=' */ + const char *uri = (char *) query->value + href_len + 1; + u16_t uri_len = query->len - (href_len + 1); + + return match_path_uri(resource->path, uri, uri_len); + } + + return match_attributes(attributes, query); +} + +static int send_error_response(struct coap_resource *resource, + struct coap_packet *request, + const struct sockaddr *from) +{ + struct net_context *context; + struct coap_packet response; + struct net_pkt *pkt; + struct net_buf *frag; + u16_t id; + int r; + + id = coap_header_get_id(request); + + context = net_pkt_context(request->pkt); + + pkt = net_pkt_get_tx(context, PKT_WAIT_TIME); + if (!pkt) { + return -ENOMEM; + } + + frag = net_pkt_get_data(context, PKT_WAIT_TIME); + if (!frag) { + net_pkt_unref(pkt); + return -ENOMEM; + } + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt); + if (r < 0) { + net_pkt_unref(pkt); + return r; + } + + /* FIXME: Could be that coap_packet_init() sets some defaults */ + coap_header_set_version(&response, 1); + coap_header_set_type(&response, COAP_TYPE_ACK); + coap_header_set_code(&response, COAP_RESPONSE_CODE_BAD_REQUEST); + coap_header_set_id(&response, id); + + r = net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); + if (r < 0) { + net_pkt_unref(pkt); + } + + return r; +} + +#if defined(CONFIG_COAP_WELL_KNOWN_BLOCK_WISE) + +#define MAX_BLOCK_WISE_TRANSFER_SIZE 2048 + +enum coap_block_size default_block_size(void) +{ + switch (CONFIG_COAP_WELL_KNOWN_BLOCK_WISE_SIZE) { + case 16: + return COAP_BLOCK_16; + case 32: + return COAP_BLOCK_32; + case 64: + return COAP_BLOCK_64; + case 128: + return COAP_BLOCK_128; + case 256: + return COAP_BLOCK_256; + case 512: + return COAP_BLOCK_512; + case 1024: + return COAP_BLOCK_1024; + } + + return COAP_BLOCK_64; +} + +static void add_to_net_buf(struct net_buf *buf, const char *str, u16_t len, + u16_t *remaining, size_t *offset, size_t current) +{ + u16_t pos; + char *ptr; + + if (!*remaining) { + return; + } + + pos = 0; + + if (*offset < current) { + pos = current - *offset; + + if (len >= pos) { + len -= pos; + *offset += pos; + } else { + *offset += len; + return; + } + } + + if (len > *remaining) { + len = *remaining; + } + + ptr = net_buf_add(buf, len); + strncpy(ptr, str + pos, len); + + *remaining -= len; + *offset += len; +} + +static int format_uri(const char * const *path, struct net_buf *buf, + u16_t *remaining, size_t *offset, + size_t current, bool *more) +{ + static const char prefix[] = "", 1, remaining, offset, current); + *more = false; + + return 0; +} + +static int format_attributes(const char * const *attributes, + struct net_buf *buf, + u16_t *remaining, size_t *offset, + size_t current, bool *more) +{ + const char * const *attr; + + if (!attributes) { + goto terminator; + } + + for (attr = attributes; *attr; ) { + int attr_len = strlen(*attr); + + add_to_net_buf(buf, *attr, attr_len, + remaining, offset, current); + if (!*remaining) { + *more = true; + return 0; + } + + attr++; + if (!*attr) { + continue; + } + + add_to_net_buf(buf, ";", 1, + remaining, offset, current); + if (!*remaining) { + *more = true; + return 0; + } + } + +terminator: + add_to_net_buf(buf, ";", 1, remaining, offset, current); + *more = false; + + return 0; +} + +static int format_resource(const struct coap_resource *resource, + struct net_buf *buf, + u16_t *remaining, size_t *offset, + size_t current, bool *more) +{ + struct coap_core_metadata *meta = resource->user_data; + const char * const *attributes = NULL; + int r; + + r = format_uri(resource->path, buf, remaining, offset, current, more); + if (r < 0) { + return r; + } + + if (!*remaining) { + *more = true; + return 0; + } + + if (meta && meta->attributes) { + attributes = meta->attributes; + } + + return format_attributes(attributes, buf, remaining, offset, current, + more); +} + +int _coap_well_known_core_get(struct coap_resource *resource, + struct coap_packet *request, + const struct sockaddr *from) +{ + /* FIXME: Add support for concurrent connections at same time, + * Maintain separate Context for each client (from addr) through slist + * and match it with 'from' address. + */ + static struct coap_block_context ctx; + struct net_context *context; + struct coap_packet response; + struct coap_option query; + struct net_pkt *pkt; + struct net_buf *frag; + unsigned int num_queries; + size_t offset; + const u8_t *token; + bool more; + u16_t remaining; + u16_t id; + u8_t tkl; + u8_t format = 40; /* application/link-format */ + u8_t *str; + int r; + + if (ctx.total_size == 0) { + coap_block_transfer_init(&ctx, default_block_size(), + MAX_BLOCK_WISE_TRANSFER_SIZE); + } + + r = coap_update_from_block(request, &ctx); + if (r < 0) { + return -EINVAL; + } + + id = coap_header_get_id(request); + token = coap_header_get_token(request, &tkl); + + /* Per RFC 6690, Section 4.1, only one (or none) query parameter may be + * provided, use the first if multiple. + */ + r = coap_find_options(request, COAP_OPTION_URI_QUERY, &query, 1); + if (r < 0) { + return r; + } + + num_queries = r; + + context = net_pkt_context(request->pkt); + + pkt = net_pkt_get_tx(context, PKT_WAIT_TIME); + if (!pkt) { + return -ENOMEM; + } + + frag = net_pkt_get_data(context, PKT_WAIT_TIME); + if (!frag) { + net_pkt_unref(pkt); + return -ENOMEM; + } + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt); + if (r < 0) { + goto done; + } + + /* FIXME: Could be that coap_packet_init() sets some defaults */ + coap_header_set_version(&response, 1); + coap_header_set_type(&response, COAP_TYPE_ACK); + coap_header_set_code(&response, COAP_RESPONSE_CODE_CONTENT); + coap_header_set_id(&response, id); + coap_header_set_token(&response, token, tkl); + + r = coap_add_option(&response, COAP_OPTION_CONTENT_FORMAT, + &format, sizeof(format)); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + offset = 0; + more = false; + remaining = coap_block_size_to_bytes(ctx.block_size); + + while (resource++ && resource->path) { + struct net_buf *temp; + + if (!match_queries_resource(resource, &query, num_queries)) { + continue; + } + + if (!remaining) { + more = true; + break; + } + + temp = net_pkt_get_data(context, PKT_WAIT_TIME); + if (!temp) { + net_pkt_unref(pkt); + return -ENOMEM; + } + + net_pkt_frag_add(pkt, temp); + + r = format_resource(resource, temp, &remaining, &offset, + ctx.current, &more); + if (r < 0) { + goto done; + } + } + + if (!response.pkt->frags->frags) { + r = -ENOENT; + goto done; + } + + if (!more) { + ctx.total_size = offset; + } + + r = coap_add_block2_option(&response, &ctx); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + str = net_buf_add(response.pkt->frags, 1); + *str = COAP_MARKER; + response.start = str + 1; + + net_pkt_compact(pkt); + +done: + if (r < 0) { + net_pkt_unref(pkt); + return send_error_response(resource, request, from); + } + + r = net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); + if (r < 0) { + net_pkt_unref(pkt); + } + + if (!more) { + /* So it's a last block, reset context */ + memset(&ctx, 0, sizeof(ctx)); + } + + return r; +} + +#else + +static int format_uri(const char * const *path, struct net_buf *buf) +{ + static const char prefix[] = "'; + + return 0; +} + +static int format_attributes(const char * const *attributes, + struct net_buf *buf) +{ + const char * const *attr; + char *str; + + if (!attributes) { + goto terminator; + } + + for (attr = attributes; *attr; ) { + int attr_len = strlen(*attr); + + str = net_buf_add(buf, attr_len); + strncpy(str, *attr, attr_len); + + attr++; + if (*attr) { + str = net_buf_add(buf, 1); + *str = ';'; + } + } + +terminator: + str = net_buf_add(buf, 1); + *str = ';'; + + return 0; +} + +static int format_resource(const struct coap_resource *resource, + struct net_buf *buf) +{ + struct coap_core_metadata *meta = resource->user_data; + const char * const *attributes = NULL; + int r; + + r = format_uri(resource->path, buf); + if (r < 0) { + return r; + } + + if (meta && meta->attributes) { + attributes = meta->attributes; + } + + return format_attributes(attributes, buf); +} + +int _coap_well_known_core_get(struct coap_resource *resource, + struct coap_packet *request, + const struct sockaddr *from) +{ + struct net_context *context; + struct coap_packet response; + struct coap_option query; + struct net_pkt *pkt; + struct net_buf *frag; + const u8_t *token; + unsigned int num_queries; + u16_t id; + u8_t tkl; + u8_t format = 40; /* application/link-format */ + u8_t *str; + int r; + + id = coap_header_get_id(request); + token = coap_header_get_token(request, &tkl); + + /* Per RFC 6690, Section 4.1, only one (or none) query parameter may be + * provided, use the first if multiple. + */ + r = coap_find_options(request, COAP_OPTION_URI_QUERY, &query, 1); + if (r < 0) { + return r; + } + + num_queries = r; + + context = net_pkt_context(request->pkt); + + pkt = net_pkt_get_tx(context, PKT_WAIT_TIME); + if (!pkt) { + return -ENOMEM; + } + + frag = net_pkt_get_data(context, PKT_WAIT_TIME); + if (!frag) { + net_pkt_unref(pkt); + return -ENOMEM; + } + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt); + if (r < 0) { + goto done; + } + + /* FIXME: Could be that coap_packet_init() sets some defaults */ + coap_header_set_version(&response, 1); + coap_header_set_type(&response, COAP_TYPE_ACK); + coap_header_set_code(&response, COAP_RESPONSE_CODE_CONTENT); + coap_header_set_id(&response, id); + coap_header_set_token(&response, token, tkl); + + r = coap_add_option(&response, COAP_OPTION_CONTENT_FORMAT, + &format, sizeof(format)); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = -ENOENT; + + str = net_buf_add(response.pkt->frags, 1); + *str = COAP_MARKER; + response.start = str + 1; + + while (resource++ && resource->path) { + struct net_buf *temp; + + if (!match_queries_resource(resource, &query, num_queries)) { + continue; + } + + temp = net_pkt_get_data(context, PKT_WAIT_TIME); + if (!temp) { + net_pkt_unref(pkt); + return -ENOMEM; + } + + net_pkt_frag_add(pkt, temp); + + r = format_resource(resource, temp); + if (r < 0) { + goto done; + } + } + + net_pkt_compact(pkt); + +done: + if (r < 0) { + net_pkt_unref(pkt); + return send_error_response(resource, request, from); + } + + r = net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); + if (r < 0) { + net_pkt_unref(pkt); + } + + return r; +} +#endif + +/* Exposing some of the APIs to ZoAP unit tests in tests/net/lib/coap */ +#if defined(CONFIG_COAP_TEST_API_ENABLE) +bool _coap_match_path_uri(const char * const *path, + const char *uri, u16_t len) +{ + return match_path_uri(path, uri, len); +} +#endif From b41d0cb8d98a6ea67b1420d87eb70c7d18e30b2c Mon Sep 17 00:00:00 2001 From: Ravi kumar Veeramally Date: Mon, 28 Aug 2017 12:44:27 +0300 Subject: [PATCH 19/37] net: coap: Add multi fragment support to CoAP library Current coap library fails to parse or prepare if packet is more than one fragment. Added support to handle multi fragment packet. Also well-known/core api used to prepare coap packet and send it through net context api immediately. This is goind to be problematic if user doesn't enable net context. Also user can not encrypt coap packets. Now api will return prepared coap packet to application. Application will send it to peer. Jira: ZEP-2210 Signed-off-by: Ravi kumar Veeramally --- include/net/coap.h | 187 +++--- include/net/coap_link_format.h | 19 +- subsys/net/lib/coap/Kconfig | 31 +- subsys/net/lib/coap/coap.c | 798 +++++++++++++++---------- subsys/net/lib/coap/coap_link_format.c | 473 +++++++-------- 5 files changed, 805 insertions(+), 703 deletions(-) diff --git a/include/net/coap.h b/include/net/coap.h index 80d9583638a0b..6a7c173c8986c 100644 --- a/include/net/coap.h +++ b/include/net/coap.h @@ -26,7 +26,7 @@ extern "C" { /** * @brief COAP library - * @defgroup coap COAP Library + * @defgroup COAP Library * @{ */ @@ -64,8 +64,7 @@ enum coap_option_num { /** * @brief Available request methods. * - * To be used with coap_header_set_code() when creating a request - * or a response. + * To be used when creating a request or a response. */ enum coap_method { COAP_METHOD_GET = 1, @@ -114,7 +113,7 @@ enum coap_msgtype { /** * @brief Set of response codes available for a response packet. * - * To be used with coap_header_set_code() when creating a response. + * To be used when creating a response. */ enum coap_response_code { COAP_RESPONSE_CODE_OK = coap_make_response_code(2, 0), @@ -134,13 +133,15 @@ enum coap_response_code { COAP_RESPONSE_CODE_INCOMPLETE = coap_make_response_code(4, 8), COAP_RESPONSE_CODE_PRECONDITION_FAILED = coap_make_response_code(4, 12), COAP_RESPONSE_CODE_REQUEST_TOO_LARGE = coap_make_response_code(4, 13), - COAP_RESPONSE_CODE_UNSUPPORTED_CONTENT_FORMAT = coap_make_response_code(4, 15), + COAP_RESPONSE_CODE_UNSUPPORTED_CONTENT_FORMAT = + coap_make_response_code(4, 15), COAP_RESPONSE_CODE_INTERNAL_ERROR = coap_make_response_code(5, 0), COAP_RESPONSE_CODE_NOT_IMPLEMENTED = coap_make_response_code(5, 1), COAP_RESPONSE_CODE_BAD_GATEWAY = coap_make_response_code(5, 2), COAP_RESPONSE_CODE_SERVICE_UNAVAILABLE = coap_make_response_code(5, 3), COAP_RESPONSE_CODE_GATEWAY_TIMEOUT = coap_make_response_code(5, 4), - COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED = coap_make_response_code(5, 5) + COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED = + coap_make_response_code(5, 5) }; #define COAP_CODE_EMPTY (0) @@ -157,8 +158,7 @@ struct coap_resource; * invoked by the remote entity. */ typedef int (*coap_method_t)(struct coap_resource *resource, - struct coap_packet *request, - const struct sockaddr *from); + struct coap_packet *request); /** * @typedef coap_notify_t @@ -199,8 +199,11 @@ struct coap_observer { */ struct coap_packet { struct net_pkt *pkt; - u8_t *start; /* Start of the payload */ - u16_t total_size; + struct net_buf *frag; /* Where CoAP header resides */ + u16_t offset; /* Where CoAP header starts.*/ + u8_t hdr_len; /* CoAP header length */ + u8_t opt_len; /* Total options length (delta + len + value) */ + u16_t last_delta; /* Used only when preparing CoAP packet */ }; /** @@ -310,8 +313,15 @@ void coap_reply_init(struct coap_reply *reply, * To be used with coap_find_options(). */ struct coap_option { - u8_t *value; + u16_t delta; + +#if defined(CONFIG_COAP_EXTENDED_OPTIONS_LEN) u16_t len; + u8_t value[CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE]; +#else + u8_t len; + u8_t value[12]; +#endif }; /** @@ -321,10 +331,13 @@ struct coap_option { * @param cpkt Packet to be initialized from received @a pkt. * @param pkt Network Packet containing a CoAP packet, its @a data pointer is * positioned on the start of the CoAP packet. + * @param options Parse options and cache its details. + * @param opt_num Number of options * * @return 0 in case of success or negative in case of error. */ -int coap_packet_parse(struct coap_packet *cpkt, struct net_pkt *pkt); +int coap_packet_parse(struct coap_packet *cpkt, struct net_pkt *pkt, + struct coap_option *options, u8_t opt_num); /** * @brief Creates a new CoAP packet from a net_pkt. @a pkt must remain @@ -333,10 +346,18 @@ int coap_packet_parse(struct coap_packet *cpkt, struct net_pkt *pkt); * @param cpkt New packet to be initialized using the storage from @a * pkt. * @param pkt Network Packet that will contain a CoAP packet + * @param ver CoAP header version + * @param type CoAP header type + * @param tokenlen CoAP header token length + * @param token CoAP header token + * @param code CoAP header code + * @param id CoAP header message id * * @return 0 in case of success or negative in case of error. */ -int coap_packet_init(struct coap_packet *cpkt, struct net_pkt *pkt); +int coap_packet_init(struct coap_packet *cpkt, struct net_pkt *pkt, + u8_t ver, u8_t type, u8_t tokenlen, + u8_t *token, u8_t code, u16_t id); /** * @brief Initialize a pending request with a request. @@ -459,13 +480,15 @@ void coap_reply_clear(struct coap_reply *reply); * * @param cpkt Packet received * @param resources Array of known resources - * @param from Address from which the packet was received + * @param options Parsed options from coap_packet_parse() + * @param opt_num Number of options * * @return 0 in case of success or negative in case of error. */ int coap_handle_request(struct coap_packet *cpkt, struct coap_resource *resources, - const struct sockaddr *from); + struct coap_option *options, + u8_t opt_num); /** * @brief Indicates that this resource was updated and that the @a @@ -488,36 +511,32 @@ int coap_resource_notify(struct coap_resource *resource); bool coap_request_is_observe(const struct coap_packet *request); /** - * @brief Returns a pointer to the start of the payload and its size - * - * It will insert the COAP_MARKER (0xFF), if its not set, and return the - * available size for the payload. + * @brief Append payload marker to CoAP packet * - * @param cpkt Packet to get (or insert) the payload - * @param len Amount of space for the payload + * @param cpkt Packet to append the payload marker (0xFF) * - * @return pointer to the start of the payload, NULL in case of error. + * @return 0 in case of success or negative in case of error. */ -u8_t *coap_packet_get_payload(struct coap_packet *cpkt, u16_t *len); +int coap_packet_append_payload_marker(struct coap_packet *cpkt); /** - * @brief Sets how much space was used by the payload. - * - * Used for outgoing packets, after coap_packet_get_payload(), to - * update the internal representation with the amount of data that was - * added to the packet. + * @brief Append payload to CoAP packet * - * @param cpkt Packet to be updated - * @param len Amount of data that was added to the payload + * @param cpkt Packet to append the payload + * @param payload CoAP packet payload + * @param payload_len CoAP packet payload len * * @return 0 in case of success or negative in case of error. */ -int coap_packet_set_used(struct coap_packet *cpkt, u16_t len); +int coap_packet_append_payload(struct coap_packet *cpkt, u8_t *payload, + u16_t payload_len); /** - * @brief Adds an option to the packet. + * @brief Appends an option to the packet. * - * Note: options must be added in numeric order of their codes. + * Note: options must be added in numeric order of their codes. Otherwise + * error will be returned. + * TODO: Add support for placing options according to its delta value. * * @param cpkt Packet to be updated * @param code Option code to add to the packet, see #coap_option_num @@ -526,8 +545,8 @@ int coap_packet_set_used(struct coap_packet *cpkt, u16_t len); * * @return 0 in case of success or negative in case of error. */ -int coap_add_option(struct coap_packet *cpkt, u16_t code, - const void *value, u16_t len); +int coap_packet_append_option(struct coap_packet *cpkt, u16_t code, + const u8_t *value, u16_t len); /** * @brief Converts an option to its integer representation. @@ -543,7 +562,7 @@ int coap_add_option(struct coap_packet *cpkt, u16_t code, unsigned int coap_option_value_to_int(const struct coap_option *option); /** - * @brief Adds an integer value option to the packet. + * @brief Appends an integer value option to the packet. * * The option must be added in numeric order of their codes, and the * least amount of bytes will be used to encode the value. @@ -554,8 +573,8 @@ unsigned int coap_option_value_to_int(const struct coap_option *option); * * @return 0 in case of success or negative in case of error. */ -int coap_add_option_int(struct coap_packet *cpkt, u16_t code, - unsigned int val); +int coap_append_option_int(struct coap_packet *cpkt, u16_t code, + unsigned int val); /** * @brief Return the values associated with the option of value @a @@ -628,7 +647,7 @@ int coap_block_transfer_init(struct coap_block_context *ctx, size_t total_size); /** - * @brief Add BLOCK1 option to the packet. + * @brief Append BLOCK1 option to the packet. * * @param cpkt Packet to be updated * @param ctx Block context from which to retrieve the @@ -636,11 +655,11 @@ int coap_block_transfer_init(struct coap_block_context *ctx, * * @return 0 in case of success or negative in case of error. */ -int coap_add_block1_option(struct coap_packet *cpkt, - struct coap_block_context *ctx); +int coap_append_block1_option(struct coap_packet *cpkt, + struct coap_block_context *ctx); /** - * @brief Add BLOCK2 option to the packet. + * @brief Append BLOCK2 option to the packet. * * @param cpkt Packet to be updated * @param ctx Block context from which to retrieve the @@ -648,11 +667,11 @@ int coap_add_block1_option(struct coap_packet *cpkt, * * @return 0 in case of success or negative in case of error. */ -int coap_add_block2_option(struct coap_packet *cpkt, - struct coap_block_context *ctx); +int coap_append_block2_option(struct coap_packet *cpkt, + struct coap_block_context *ctx); /** - * @brief Add SIZE1 option to the packet. + * @brief Append SIZE1 option to the packet. * * @param cpkt Packet to be updated * @param ctx Block context from which to retrieve the @@ -660,11 +679,11 @@ int coap_add_block2_option(struct coap_packet *cpkt, * * @return 0 in case of success or negative in case of error. */ -int coap_add_size1_option(struct coap_packet *cpkt, - struct coap_block_context *ctx); +int coap_append_size1_option(struct coap_packet *cpkt, + struct coap_block_context *ctx); /** - * @brief Add SIZE2 option to the packet. + * @brief Append SIZE2 option to the packet. * * @param cpkt Packet to be updated * @param ctx Block context from which to retrieve the @@ -672,8 +691,8 @@ int coap_add_size1_option(struct coap_packet *cpkt, * * @return 0 in case of success or negative in case of error. */ -int coap_add_size2_option(struct coap_packet *cpkt, - struct coap_block_context *ctx); +int coap_append_size2_option(struct coap_packet *cpkt, + struct coap_block_context *ctx); /** * @brief Retrieves BLOCK{1,2} and SIZE{1,2} from @a cpkt and updates @@ -723,12 +742,11 @@ u8_t coap_header_get_type(const struct coap_packet *cpkt); * @brief Returns the token (if any) in the CoAP packet. * * @param cpkt CoAP packet representation - * @param len Where to store the length of the token + * @param token Where to store the token * - * @return pointer to the start of the token in the CoAP packet. + * @return Token length in the CoAP packet. */ -const u8_t *coap_header_get_token(const struct coap_packet *cpkt, - u8_t *len); +u8_t coap_header_get_token(const struct coap_packet *cpkt, u8_t *token); /** * @brief Returns the code of the CoAP packet. @@ -748,50 +766,6 @@ u8_t coap_header_get_code(const struct coap_packet *cpkt); */ u16_t coap_header_get_id(const struct coap_packet *cpkt); -/** - * @brief Sets the version of the CoAP packet. - * - * @param cpkt CoAP packet representation - * @param ver The CoAP version to set in the packet - */ -void coap_header_set_version(struct coap_packet *cpkt, u8_t ver); - -/** - * @brief Sets the type of the CoAP packet. - * - * @param cpkt CoAP packet representation - * @param type The packet type to set - */ -void coap_header_set_type(struct coap_packet *cpkt, u8_t type); - -/** - * @brief Sets the token in the CoAP packet. - * - * @param cpkt CoAP packet representation - * @param token Token to set in the packet, will be copied - * @param tokenlen Size of the token to be set, 8 bytes maximum - * - * @return 0 in case of success or negative in case of error. - */ -int coap_header_set_token(struct coap_packet *cpkt, const u8_t *token, - u8_t tokenlen); - -/** - * @brief Sets the code present in the CoAP packet. - * - * @param cpkt CoAP packet representation - * @param code The code set in the packet - */ -void coap_header_set_code(struct coap_packet *cpkt, u8_t code); - -/** - * @brief Sets the message id present in the CoAP packet. - * - * @param cpkt CoAP packet representation - * @param id The message id to set in the packet - */ -void coap_header_set_id(struct coap_packet *cpkt, u16_t id); - /** * @brief Helper to generate message ids * @@ -804,6 +778,23 @@ static inline u16_t coap_next_id(void) return ++message_id; } +/** + * @brief Returns the fragment pointer and offset where payload starts + * in the CoAP packet. + * + * @param cpkt CoAP packet representation + * @param offset Stores the offset value where payload starts + * @param len Total length of CoAP payload + * + * @return the net_buf fragment pointer and offset value if payload exists + * NULL pointer and offset set to 0 in case there is no payload + * NULL pointer and offset value 0xffff incase of an error + */ +struct net_buf *coap_packet_get_payload(const struct coap_packet *cpkt, + u16_t *offset, + u16_t *len); + + /** * @brief Returns a randomly generated array of 8 bytes, that can be * used as a message's token. diff --git a/include/net/coap_link_format.h b/include/net/coap_link_format.h index 5bebd629f0b91..f8440ff718214 100644 --- a/include/net/coap_link_format.h +++ b/include/net/coap_link_format.h @@ -21,22 +21,17 @@ extern "C" { * @addtogroup coap COAP Library * @{ */ - -#define _COAP_WELL_KNOWN_CORE_PATH \ - ((const char * const[]) { ".well-known", "core", NULL }) - -int _coap_well_known_core_get(struct coap_resource *resource, - struct coap_packet *request, - const struct sockaddr *from); - /** * This resource should be added before all other resources that should be * included in the responses of the .well-known/core resource. */ -#define COAP_WELL_KNOWN_CORE_RESOURCE \ - { .get = _coap_well_known_core_get, \ - .path = _COAP_WELL_KNOWN_CORE_PATH, \ - } +#define COAP_WELL_KNOWN_CORE_PATH \ + ((const char * const[]) { ".well-known", "core", NULL }) + +int coap_well_known_core_get(struct coap_resource *resource, + struct coap_packet *request, + struct coap_packet *response, + struct net_pkt *pkt); /** * In case you want to add attributes to the resources included in the diff --git a/subsys/net/lib/coap/Kconfig b/subsys/net/lib/coap/Kconfig index 127f37eed2ede..15914994778cd 100644 --- a/subsys/net/lib/coap/Kconfig +++ b/subsys/net/lib/coap/Kconfig @@ -1,4 +1,4 @@ -# Kconfig - Coap, CoAP implementation for Zephyr +# Kconfig - CoAP implementation for Zephyr # # Copyright (c) 2017 Intel Corporation @@ -11,7 +11,7 @@ config COAP prompt "CoAP Support" default n help - This option enables the implementation of CoAP. + This option enables the CoAP implementation. # This setting is only used by unit test. Do not enable it in applications config COAP_TEST_API_ENABLE @@ -41,3 +41,30 @@ config COAP_WELL_KNOWN_BLOCK_WISE_SIZE help Maximum size of CoAP block. Valid values are 16, 32, 64, 128, 256, 512 and 1024. + +config COAP_EXTENDED_OPTIONS_LEN + bool "Support for CoAP extended options" + default n + depends on COAP + help + This option enables the parsing of extended CoAP options length. + CoAP extended options length can be 2 byte value, which + requires more memory. User can save memory by disabling this. + That means only length of maximum 12 bytes are supported by default. + Enable this if length field going to bigger that 12. + +config COAP_EXTENDED_OPTIONS_LEN_VALUE + int "CoAP extended options length value" + default 13 + depends on COAP_EXTENDED_OPTIONS_LEN + help + This option specifies the maximum value of length field when + COAP_EXTENDED_OPTIONS_LEN is enabled. Define the value according to + user requirement. + +config NET_DEBUG_COAP + bool "Debug COAP" + default n + depends on COAP && NET_LOG + help + Enables CoaP output debug messages diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index 80c55f28f6d0d..a8be0300f715b 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -4,6 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +#if defined(CONFIG_NET_DEBUG_COAP) +#define SYS_LOG_DOMAIN "coap" +#define NET_LOG_ENABLED 1 +#endif + #include #include #include @@ -19,10 +24,9 @@ #include struct option_context { - u8_t *buf; - int delta; - int used; /* size used of options */ - int buflen; + u16_t delta; + u16_t offset; + struct net_buf *frag; }; #define COAP_VERSION 1 @@ -31,49 +35,74 @@ struct option_context { #define BASIC_HEADER_SIZE 4 -static u8_t coap_option_header_get_delta(u8_t buf) +#define PKT_WAIT_TIME K_SECONDS(1) + +static u8_t option_header_get_delta(u8_t opt) { - return (buf & 0xF0) >> 4; + return (opt & 0xF0) >> 4; } -static u8_t coap_option_header_get_len(u8_t buf) +static u8_t option_header_get_len(u8_t opt) { - return buf & 0x0F; + return opt & 0x0F; } -static void coap_option_header_set_delta(u8_t *buf, u8_t delta) +static void option_header_set_delta(u8_t *opt, u8_t delta) { - *buf = (delta & 0xF) << 4; + *opt = (delta & 0xF) << 4; } -static void coap_option_header_set_len(u8_t *buf, u8_t len) +static void option_header_set_len(u8_t *opt, u8_t len) { - *buf |= (len & 0xF); + *opt |= (len & 0xF); +} + +static int get_coap_packet_len(struct net_pkt *pkt) +{ + struct net_buf *frag; + u16_t offset; + u16_t len; + + frag = net_frag_read_be16(pkt->frags, + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) + + 4, &offset, &len); + if (!frag && offset == 0xffff) { + return -1; + } + + return len - NET_UDPH_LEN; } -static int decode_delta(int num, const u8_t *buf, s16_t buflen, +static int decode_delta(u16_t num, struct option_context *context, u16_t *decoded) { int hdrlen = 0; - switch (num) { - case 13: - if (buflen < 1) { + if (num == 13) { + u8_t val; + + context->frag = net_frag_read_u8(context->frag, context->offset, + &context->offset, &val); + if (!context->frag && context->offset == 0xffff) { return -EINVAL; } - num = *buf + 13; + num = val + 13; hdrlen += 1; - break; - case 14: - if (buflen < 2) { + } else if (num == 14) { + u16_t val; + + context->frag = net_frag_read_be16(context->frag, + context->offset, + &context->offset, &val); + if (!context->frag && context->offset == 0xffff) { return -EINVAL; } - num = sys_get_be16(buf) + 269; + num = val + 269; hdrlen += 2; - break; - case 15: + } else if (num == 15) { return -EINVAL; } @@ -82,246 +111,257 @@ static int decode_delta(int num, const u8_t *buf, s16_t buflen, return hdrlen; } -static int coap_parse_option(const struct coap_packet *cpkt, - struct option_context *context, - u8_t **value, u16_t *vlen) +static int parse_option(const struct coap_packet *cpkt, + struct option_context *context, + struct coap_option *option) { - u16_t delta, len; + u16_t opt_len; + u16_t delta; + u16_t len; + u8_t opt; int r; - if (context->buflen < 1) { - return 0; + context->frag = net_frag_read_u8(context->frag, context->offset, + &context->offset, &opt); + if (!context->frag && context->offset == 0xffff) { + return -EINVAL; } + opt_len = 1; + /* This indicates that options have ended */ - if (context->buf[0] == COAP_MARKER) { + if (opt == COAP_MARKER) { return 0; } - delta = coap_option_header_get_delta(context->buf[0]); - len = coap_option_header_get_len(context->buf[0]); - context->buf += 1; - context->used += 1; - context->buflen -= 1; + delta = option_header_get_delta(opt); + len = option_header_get_len(opt); /* In case 'delta' doesn't fit the option fixed header. */ - r = decode_delta(delta, context->buf, context->buflen, &delta); + r = decode_delta(delta, context, &delta); if (r < 0) { return -EINVAL; } - context->buf += r; - context->used += r; - context->buflen -= r; + opt_len += r; /* In case 'len' doesn't fit the option fixed header. */ - r = decode_delta(len, context->buf, context->buflen, &len); + r = decode_delta(len, context, &len); if (r < 0) { return -EINVAL; } - if (context->buflen < r + len) { - return -EINVAL; - } + opt_len += r + len; - if (value) { - *value = context->buf + r; - } + if (option) { + if (delta) { + option->delta = context->delta + delta; + } else { + option->delta = context->delta; + } - if (vlen) { - *vlen = len; - } + option->len = len; + context->frag = net_frag_read(context->frag, context->offset, + &context->offset, len, + &option->value[0]); + if (!context->frag && context->offset == 0xffff) { + return -EINVAL; + } - context->buf += r + len; - context->used += r + len; - context->buflen -= r + len; + } else { + context->frag = net_frag_skip(context->frag, context->offset, + &context->offset, len); + if (!context->frag && context->offset == 0xffff) { + return -EINVAL; + } + } context->delta += delta; - return context->used; + return opt_len; } -static int coap_parse_options(struct coap_packet *cpkt, unsigned int offset) +static int parse_options(const struct coap_packet *cpkt, + struct coap_option *options, u8_t opt_num) { struct option_context context = { - .delta = 0, - .used = 0, - .buflen = cpkt->pkt->frags->len - offset, - .buf = &cpkt->pkt->frags->data[offset] }; + .delta = 0, + .frag = NULL, + .offset = 0 + }; + u8_t num; + u16_t opt_len; + int coap_len; + + coap_len = get_coap_packet_len(cpkt->pkt); + if (coap_len < 0) { + return -EINVAL; + } + + /* Skip CoAP header */ + context.frag = net_frag_skip(cpkt->frag, cpkt->offset, + &context.offset, cpkt->hdr_len); + if (!context.frag && context.offset == 0xffff) { + return -EINVAL; + } + + coap_len -= cpkt->hdr_len; + num = 0; + opt_len = 0; while (true) { - int r = coap_parse_option(cpkt, &context, NULL, NULL); + struct coap_option *option; + int r; + + if (opt_len >= coap_len) { + break; + } + option = num < opt_num ? &options[num++] : NULL; + r = parse_option(cpkt, &context, option); if (r < 0) { - return -EINVAL; + return r; } + opt_len += r; + + /* Reached End of Options (0xFF), + * r is zero, so increase opt_len + 1. + */ if (r == 0) { + opt_len++; break; } } - return context.used; -} -static u8_t coap_header_get_tkl(const struct coap_packet *cpkt) -{ - return cpkt->pkt->frags->data[0] & 0xF; + return opt_len; } -static int coap_get_header_len(const struct coap_packet *cpkt) +static u8_t get_header_tkl(const struct coap_packet *cpkt) { - unsigned int hdrlen; + struct net_buf *frag; + u16_t offset; u8_t tkl; - hdrlen = BASIC_HEADER_SIZE; + frag = net_frag_read_u8(cpkt->frag, cpkt->offset, &offset, &tkl); - if (cpkt->pkt->frags->len < hdrlen) { - return -EINVAL; - } + return tkl & 0xF; +} - tkl = coap_header_get_tkl(cpkt); +static u16_t get_pkt_len(const struct coap_packet *cpkt) +{ + struct net_buf *frag; + u16_t len; - /* Token lenghts 9-15 are reserved. */ - if (tkl > 8) { - return -EINVAL; - } + len = cpkt->frag->len - cpkt->offset; - if (cpkt->pkt->frags->len < hdrlen + tkl) { - return -EINVAL; + for (frag = cpkt->frag->frags; frag; frag = frag->frags) { + len += frag->len; } - return hdrlen + tkl; + return len; } -int coap_packet_parse(struct coap_packet *cpkt, struct net_pkt *pkt) +static int get_header_len(struct coap_packet *cpkt) { - int optlen, hdrlen; + u8_t tkl; + u16_t len; + int hdrlen; - if (!pkt || !pkt->frags) { - return -EINVAL; - } + len = get_pkt_len(cpkt); - memset(cpkt, 0, sizeof(*cpkt)); - cpkt->pkt = pkt; + hdrlen = BASIC_HEADER_SIZE; - hdrlen = coap_get_header_len(cpkt); - if (hdrlen < 0) { + if (len < hdrlen) { return -EINVAL; } - optlen = coap_parse_options(cpkt, hdrlen); - if (optlen < 0) { - return -EINVAL; - } + tkl = get_header_tkl(cpkt); - if (pkt->frags->len < hdrlen + optlen) { + /* Token lenghts 9-15 are reserved. */ + if (tkl > 8) { return -EINVAL; } - if (pkt->frags->len <= hdrlen + optlen + 1) { - cpkt->start = NULL; - return 0; + if (len < hdrlen + tkl) { + return -EINVAL; } - cpkt->start = pkt->frags->data + hdrlen + optlen + 1; - cpkt->total_size = pkt->frags->len; + cpkt->hdr_len = hdrlen + tkl; return 0; } -static int delta_encode(int num, u8_t *value, u8_t *buf, size_t buflen) +int coap_packet_parse(struct coap_packet *cpkt, struct net_pkt *pkt, + struct coap_option *options, u8_t opt_num) { - u16_t v; + int ret; - if (num < 13) { - *value = num; - return 0; - } - - if (num < 269) { - if (buflen < 1) { - return -EINVAL; - } - - *value = 13; - *buf = num - 13; - return 1; - } - - if (buflen < 2) { + if (!cpkt || !pkt || !pkt->frags) { return -EINVAL; } - *value = 14; - - v = sys_cpu_to_be16(num - 269); - memcpy(buf, &v, sizeof(v)); - - return 2; -} - -static int coap_option_encode(struct option_context *context, u16_t code, - const void *value, u16_t len) -{ - int delta, offset, r; - u8_t data; - - delta = code - context->delta; - - offset = 1; - - r = delta_encode(delta, &data, context->buf + offset, - context->buflen - offset); - - if (r < 0) { + cpkt->pkt = pkt; + cpkt->hdr_len = 0; + cpkt->opt_len = 0; + + cpkt->frag = net_frag_skip(pkt->frags, 0, &cpkt->offset, + net_pkt_ip_hdr_len(pkt) + + NET_UDPH_LEN + + net_pkt_ipv6_ext_len(pkt)); + if (!cpkt->frag && cpkt->offset == 0xffff) { return -EINVAL; } - offset += r; - coap_option_header_set_delta(context->buf, data); - - r = delta_encode(len, &data, context->buf + offset, - context->buflen - offset); - if (r < 0) { + ret = get_header_len(cpkt); + if (ret < 0) { return -EINVAL; } - offset += r; - coap_option_header_set_len(context->buf, data); - - if (context->buflen < offset + len) { + ret = parse_options(cpkt, options, opt_num); + if (ret < 0) { return -EINVAL; } - memcpy(context->buf + offset, value, len); + cpkt->opt_len = ret; - return offset + len; + return 0; } -int coap_packet_init(struct coap_packet *cpkt, - struct net_pkt *pkt) +int coap_packet_init(struct coap_packet *cpkt, struct net_pkt *pkt, + u8_t ver, u8_t type, u8_t tokenlen, + u8_t *token, u8_t code, u16_t id) { - void *data; + u8_t hdr; + bool res; - if (!pkt || !pkt->frags) { + if (!cpkt || !pkt || !pkt->frags) { return -EINVAL; } - if (net_buf_tailroom(pkt->frags) < BASIC_HEADER_SIZE) { - return -ENOMEM; - } - memset(cpkt, 0, sizeof(*cpkt)); - cpkt->total_size = net_buf_tailroom(pkt->frags); - - data = net_buf_add(pkt->frags, BASIC_HEADER_SIZE); - - /* - * As some header data is built by OR operations, we zero - * the header to be sure. - */ - memset(data, 0, BASIC_HEADER_SIZE); cpkt->pkt = pkt; + cpkt->frag = pkt->frags; + cpkt->offset = 0; + cpkt->last_delta = 0; + + hdr = (ver & 0x3) << 6; + hdr |= (type & 0x3) << 4; + hdr |= tokenlen & 0xF; + + net_pkt_append_u8(pkt, hdr); + net_pkt_append_u8(pkt, code); + net_pkt_append_be16(pkt, id); + + if (token && tokenlen) { + res = net_pkt_append_all(pkt, tokenlen, token, PKT_WAIT_TIME); + if (!res) { + return -ENOMEM; + } + } + + /* Header length : (version + type + tkl) + code + id + [token] */ + cpkt->hdr_len = 1 + 1 + 2 + tokenlen; return 0; } @@ -468,8 +508,7 @@ bool coap_pending_cycle(struct coap_pending *pending) /* If the timeout changed, it's not the last, continue... */ cont = (old != pending->timeout); if (cont) { - /* - * When it it is the last retransmission, the buffer + /* When it it is the last retransmission, the buffer * will be destroyed when it is transmitted. */ net_pkt_ref(pending->pkt); @@ -486,34 +525,40 @@ void coap_pending_clear(struct coap_pending *pending) } static bool uri_path_eq(const struct coap_packet *cpkt, - const char * const *path) + const char * const *path, + struct coap_option *options, + u8_t opt_num) { - struct coap_option options[16]; - u16_t count = 16; - int i, r; + u8_t i; + u8_t j = 0; - r = coap_find_options(cpkt, COAP_OPTION_URI_PATH, options, count); - if (r < 0) { - return false; - } - - count = r; - - for (i = 0; i < count && path[i]; i++) { - size_t len; + for (i = 0; i < opt_num && path[j]; i++) { + if (options[i].delta != COAP_OPTION_URI_PATH) { + continue; + } - len = strlen(path[i]); + if (options[i].len != strlen(path[j])) { + return false; + } - if (options[i].len != len) { + if (memcmp(options[i].value, path[j], options[i].len)) { return false; } - if (memcmp(options[i].value, path[i], len)) { + j++; + } + + if (path[j]) { + return false; + } + + for (; i < opt_num; i++) { + if (options[i].delta == COAP_OPTION_URI_PATH) { return false; } } - return i == count && !path[i]; + return true; } static coap_method_t method_from_code(const struct coap_resource *resource, @@ -542,7 +587,8 @@ static bool is_request(const struct coap_packet *cpkt) int coap_handle_request(struct coap_packet *cpkt, struct coap_resource *resources, - const struct sockaddr *from) + struct coap_option *options, + u8_t opt_num) { struct coap_resource *resource; @@ -550,23 +596,22 @@ int coap_handle_request(struct coap_packet *cpkt, return 0; } + /* FIXME: deal with hierarchical resources */ for (resource = resources; resource && resource->path; resource++) { coap_method_t method; u8_t code; - /* FIXME: deal with hierarchical resources */ - if (!uri_path_eq(cpkt, resource->path)) { + if (!uri_path_eq(cpkt, resource->path, options, opt_num)) { continue; } code = coap_header_get_code(cpkt); method = method_from_code(resource, code); - if (!method) { return 0; } - return method(resource, cpkt, from); + return method(resource, cpkt); } return -ENOENT; @@ -614,13 +659,13 @@ struct coap_reply *coap_response_received( struct coap_reply *replies, size_t len) { struct coap_reply *r; - const u8_t *token; + u8_t token[8]; u16_t id; u8_t tkl; size_t i; id = coap_header_get_id(response); - token = coap_header_get_token(response, &tkl); + tkl = coap_header_get_token(response, (u8_t *)token); for (i = 0, r = replies; i < len; i++, r++) { int age; @@ -634,15 +679,13 @@ struct coap_reply *coap_response_received( continue; } - /* Separate response must only match token */ if (tkl > 0 && memcmp(r->token, token, tkl)) { continue; } age = get_observe_option(response); if (age > 0) { - /* - * age == 2 means that the notifications wrapped, + /* age == 2 means that the notifications wrapped, * or this is the first one */ if (r->age > age && age != 2) { @@ -662,16 +705,17 @@ struct coap_reply *coap_response_received( void coap_reply_init(struct coap_reply *reply, const struct coap_packet *request) { - const u8_t *token; + u8_t token[8]; u8_t tkl; int age; reply->id = coap_header_get_id(request); - token = coap_header_get_token(request, &tkl); + tkl = coap_header_get_token(request, (u8_t *)&token); if (tkl > 0) { memcpy(reply->token, token, tkl); } + reply->tkl = tkl; age = get_observe_option(request); @@ -715,10 +759,10 @@ void coap_observer_init(struct coap_observer *observer, const struct coap_packet *request, const struct sockaddr *addr) { - const u8_t *token; + u8_t token[8]; u8_t tkl; - token = coap_header_get_token(request, &tkl); + tkl = coap_header_get_token(request, (u8_t *)&token); if (tkl > 0) { memcpy(observer->token, token, tkl); @@ -753,8 +797,7 @@ void coap_remove_observer(struct coap_resource *resource, static bool sockaddr_equal(const struct sockaddr *a, const struct sockaddr *b) { - /* - * FIXME: Should we consider ipv6-mapped ipv4 addresses as equal to + /* FIXME: Should we consider ipv6-mapped ipv4 addresses as equal to * ipv4 addresses? */ if (a->sa_family != b->sa_family) { @@ -808,94 +851,140 @@ struct coap_observer *coap_find_observer_by_addr( return NULL; } -u8_t *coap_packet_get_payload(struct coap_packet *cpkt, u16_t *len) +int coap_packet_append_payload_marker(struct coap_packet *cpkt) { - u8_t *appdata = cpkt->pkt->frags->data; - u16_t appdatalen = cpkt->pkt->frags->len; + return net_pkt_append_u8(cpkt->pkt, COAP_MARKER) ? 0 : -EINVAL; +} - if (!cpkt || !len) { - return NULL; - } +int coap_packet_append_payload(struct coap_packet *cpkt, u8_t *payload, + u16_t payload_len) +{ + bool status; - if (!cpkt->start) { - if (appdatalen + 1 >= cpkt->total_size) { - return NULL; - } + status = net_pkt_append_all(cpkt->pkt, payload_len, payload, + PKT_WAIT_TIME); - appdata[appdatalen] = COAP_MARKER; - cpkt->pkt->frags->len += 1; + return status ? 0 : -EINVAL; +} - cpkt->start = appdata + cpkt->pkt->frags->len; +static u8_t encode_extended_option(u16_t num, u8_t *opt, u16_t *ext) +{ + if (num < 13) { + *opt = num; + *ext = 0; + + return 0; + } else if (num < 269) { + *opt = 13; + *ext = num - 13; + + return 1; } - *len = appdata + cpkt->total_size - cpkt->start; + *opt = 14; + *ext = num - 269; - return cpkt->start; + return 2; } -int coap_packet_set_used(struct coap_packet *cpkt, u16_t len) +static int encode_option(struct coap_packet *cpkt, u16_t code, + const u8_t *value, u16_t len) { - if ((cpkt->pkt->frags->len + len) > - net_buf_tailroom(cpkt->pkt->frags)) { - return -ENOMEM; + u16_t delta_ext; /* Extended delta */ + u16_t len_ext; /* Extended length */ + u8_t opt; /* delta | len */ + u8_t opt_delta; + u8_t opt_len; + u8_t delta_size; + u8_t len_size; + bool res; + + delta_size = encode_extended_option(code, &opt_delta, &delta_ext); + len_size = encode_extended_option(len, &opt_len, &len_ext); + + option_header_set_delta(&opt, opt_delta); + option_header_set_len(&opt, opt_len); + + net_pkt_append_u8(cpkt->pkt, opt); + + if (delta_size == 1) { + net_pkt_append_u8(cpkt->pkt, (u8_t) delta_ext); + } else if (delta_size == 2) { + net_pkt_append_be16(cpkt->pkt, delta_ext); } - cpkt->pkt->frags->len += len; + if (len_size == 1) { + net_pkt_append_u8(cpkt->pkt, (u8_t) len_ext); + } else if (delta_size == 2) { + net_pkt_append_be16(cpkt->pkt, len_ext); + } - return 0; + if (len && value) { + res = net_pkt_append_all(cpkt->pkt, len, value, PKT_WAIT_TIME); + if (!res) { + return -EINVAL; + } + } + + return (1 + delta_size + len_size + len); } -int coap_add_option(struct coap_packet *cpkt, u16_t code, - const void *value, u16_t len) +/* TODO Add support for inserting options in proper place + * and modify other option's delta accordingly. + */ +int coap_packet_append_option(struct coap_packet *cpkt, u16_t code, + const u8_t *value, u16_t len) { - struct net_buf *frag = cpkt->pkt->frags; - struct option_context context = { .delta = 0, - .used = 0 }; - int r, offset; + struct net_buf *frag; + u16_t offset; + int r; - if (cpkt->start) { + if (!cpkt) { return -EINVAL; } - offset = coap_get_header_len(cpkt); - if (offset < 0) { + if (len && !value) { return -EINVAL; } - /* We check for options in all the 'used' space. */ - context.buflen = frag->len - offset; - context.buf = frag->data + offset; + if (len > 13) { +#if !defined(CONFIG_COAP_EXTENDED_OPTIONS_LEN) + NET_ERR("Enable CONFIG_COAP_EXTENDED_OPTIONS_LEN to support " + "if length is more than 13"); + return -EINVAL; +#endif + } - while (context.delta <= code) { - r = coap_parse_option(cpkt, &context, NULL, NULL); - if (r < 0) { - return -ENOENT; - } + if (code < cpkt->last_delta) { + NET_ERR("Options should be in ascending order"); + return -EINVAL; + } - if (r == 0) { - break; - } + /* Skip CoAP packet header */ + frag = net_frag_skip(cpkt->frag, cpkt->offset, &offset, cpkt->hdr_len); + if (!frag && offset == 0xffff) { + return -EINVAL; + } - /* If the new option code is out of order. */ - if (code < context.delta) { - return -EINVAL; - } + /* Calculate delta, if this option is not the first one */ + if (cpkt->opt_len) { + code = (code == cpkt->last_delta) ? 0 : + code - cpkt->last_delta; } - /* We can now add options using all the available space. */ - context.buflen = net_buf_tailroom(frag) - (offset + context.used); - r = coap_option_encode(&context, code, value, len); + r = encode_option(cpkt, code, value, len); if (r < 0) { return -EINVAL; } - frag->len += r; + cpkt->opt_len += r; + cpkt->last_delta += code; return 0; } -int coap_add_option_int(struct coap_packet *cpkt, u16_t code, - unsigned int val) +int coap_append_option_int(struct coap_packet *cpkt, u16_t code, + unsigned int val) { u8_t data[4], len; @@ -917,40 +1006,62 @@ int coap_add_option_int(struct coap_packet *cpkt, u16_t code, len = 4; } - return coap_add_option(cpkt, code, data, len); + return coap_packet_append_option(cpkt, code, data, len); } int coap_find_options(const struct coap_packet *cpkt, u16_t code, struct coap_option *options, u16_t veclen) { - struct net_buf *frag = cpkt->pkt->frags; - struct option_context context = { .delta = 0, - .used = 0 }; - int hdrlen, count = 0; - u16_t len; + struct option_context context = { + .delta = 0, + .frag = NULL, + .offset = 0 + }; + u16_t opt_len; + int coap_len; + int count = 0; + int r; + + if (!cpkt || !cpkt->pkt || !cpkt->pkt->frags) { + return -EINVAL; + } - hdrlen = coap_get_header_len(cpkt); - if (hdrlen < 0) { + if (!cpkt->hdr_len) { return -EINVAL; } - context.buflen = frag->len - hdrlen; - context.buf = (u8_t *)frag->data + hdrlen; + coap_len = get_coap_packet_len(cpkt->pkt); + if (coap_len < 0) { + return -EINVAL; + } + + coap_len -= cpkt->hdr_len; + opt_len = 0; + + /* Skip CoAP header */ + context.frag = net_frag_skip(cpkt->frag, cpkt->offset, + &context.offset, cpkt->hdr_len); + if (!context.frag && context.offset == 0xffff) { + return -EINVAL; + } while (context.delta <= code && count < veclen) { - int used = coap_parse_option(cpkt, &context, - (u8_t **)&options[count].value, - &len); - options[count].len = len; - if (used < 0) { + if (opt_len >= coap_len) { + break; + } + + r = parse_option(cpkt, &context, &options[count]); + if (r < 0) { return -ENOENT; } - if (used == 0) { + opt_len += r; + + if (r == 0) { break; } - if (code != context.delta) { + if (code != options[count].delta) { continue; } @@ -962,43 +1073,75 @@ int coap_find_options(const struct coap_packet *cpkt, u16_t code, u8_t coap_header_get_version(const struct coap_packet *cpkt) { - return (cpkt->pkt->frags->data[0] & 0xC0) >> 6; + struct net_buf *frag; + u16_t offset; + u8_t version; + + frag = net_frag_read_u8(cpkt->frag, cpkt->offset, &offset, &version); + if (!frag && offset == 0xffff) { + return 0; + } + + return (version & 0xC0) >> 6; } u8_t coap_header_get_type(const struct coap_packet *cpkt) { - return (cpkt->pkt->frags->data[0] & 0x30) >> 4; + struct net_buf *frag; + u16_t offset; + u8_t type; + + frag = net_frag_read_u8(cpkt->frag, cpkt->offset, &offset, &type); + if (!frag && offset == 0xffff) { + return 0; + } + + return (type & 0x30) >> 4; } -u8_t coap_header_get_code(const struct coap_packet *cpkt) +static u8_t __coap_header_get_code(const struct coap_packet *cpkt) { - return cpkt->pkt->frags->data[1]; + struct net_buf *frag; + u16_t offset; + u8_t code; + + frag = net_frag_skip(cpkt->frag, cpkt->offset, &offset, 1); + frag = net_frag_read_u8(frag, offset, &offset, &code); + if (!frag && offset == 0xffff) { + return 0; + } + + return code; } -const u8_t *coap_header_get_token(const struct coap_packet *cpkt, - u8_t *len) +u8_t coap_header_get_token(const struct coap_packet *cpkt, u8_t *token) { - struct net_buf *frag = cpkt->pkt->frags; - u8_t tkl = coap_header_get_tkl(cpkt); + struct net_buf *frag; + u16_t offset; + u8_t tkl; - if (len) { - *len = 0; + if (!cpkt || !token) { + return 0; } - if (tkl == 0) { - return NULL; + tkl = get_header_tkl(cpkt); + if (!tkl) { + return 0; } - if (len) { - *len = tkl; + frag = net_frag_skip(cpkt->frag, cpkt->offset, &offset, + BASIC_HEADER_SIZE); + frag = net_frag_read(frag, offset, &offset, tkl, token); + if (!frag && offset == 0xffff) { + return 0; } - return (u8_t *)frag->data + BASIC_HEADER_SIZE; + return tkl; } u8_t coap_header_get_code(const struct coap_packet *cpkt) { - u8_t code = coap_header_get_code(cpkt); + u8_t code = __coap_header_get_code(cpkt); switch (code) { /* Methods are encoded in the code field too */ @@ -1041,51 +1184,45 @@ u8_t coap_header_get_code(const struct coap_packet *cpkt) u16_t coap_header_get_id(const struct coap_packet *cpkt) { - return sys_get_be16(&cpkt->pkt->frags->data[2]); -} + struct net_buf *frag; + u16_t offset; + u16_t id; -void coap_header_set_version(struct coap_packet *cpkt, u8_t ver) -{ - cpkt->pkt->frags->data[0] |= (ver & 0x3) << 6; -} + frag = net_frag_skip(cpkt->frag, cpkt->offset, &offset, 2); + frag = net_frag_read_be16(frag, offset, &offset, &id); + if (!frag && offset == 0xffff) { + return 0; + } -void coap_header_set_type(struct coap_packet *cpkt, u8_t type) -{ - cpkt->pkt->frags->data[0] |= (type & 0x3) << 4; + return id; } -int coap_header_set_token(struct coap_packet *cpkt, const u8_t *token, - u8_t tokenlen) +struct net_buf *coap_packet_get_payload(const struct coap_packet *cpkt, + u16_t *offset, u16_t *len) { - struct net_buf *frag = cpkt->pkt->frags; - u8_t *appdata = frag->data; - - if (net_buf_tailroom(frag) < BASIC_HEADER_SIZE + tokenlen) { - return -EINVAL; - } + struct net_buf *frag; + int r; - if (tokenlen > 8) { - return -EINVAL; + if (!cpkt || !offset) { + return NULL; } - frag->len += tokenlen; + frag = NULL; + *offset = 0xffff; + *len = 0; - appdata[0] |= tokenlen & 0xF; + r = get_coap_packet_len(cpkt->pkt); + if (r < 0) { + return frag; + } - memcpy(frag->data + BASIC_HEADER_SIZE, token, tokenlen); + frag = net_frag_skip(cpkt->frag, cpkt->offset, offset, + cpkt->hdr_len + cpkt->opt_len); + *len = r - cpkt->hdr_len - cpkt->opt_len; - return 0; + return frag; } -void coap_header_set_code(struct coap_packet *cpkt, u8_t code) -{ - cpkt->pkt->frags->data[1] = code; -} - -void coap_header_set_id(struct coap_packet *cpkt, u16_t id) -{ - sys_put_be16(id, &cpkt->pkt->frags->data[2]); -} int coap_block_transfer_init(struct coap_block_context *ctx, enum coap_block_size block_size, @@ -1106,8 +1243,8 @@ int coap_block_transfer_init(struct coap_block_context *ctx, #define SET_MORE(v, m) ((v) |= (m) ? 0x08 : 0x00) #define SET_NUM(v, n) ((v) |= ((n) << 4)) -int coap_add_block1_option(struct coap_packet *cpkt, - struct coap_block_context *ctx) +int coap_append_block1_option(struct coap_packet *cpkt, + struct coap_block_context *ctx) { u16_t bytes = coap_block_size_to_bytes(ctx->block_size); unsigned int val = 0; @@ -1122,13 +1259,13 @@ int coap_add_block1_option(struct coap_packet *cpkt, SET_NUM(val, ctx->current / bytes); } - r = coap_add_option_int(cpkt, COAP_OPTION_BLOCK1, val); + r = coap_append_option_int(cpkt, COAP_OPTION_BLOCK1, val); return r; } -int coap_add_block2_option(struct coap_packet *cpkt, - struct coap_block_context *ctx) +int coap_append_block2_option(struct coap_packet *cpkt, + struct coap_block_context *ctx) { int r, val = 0; u16_t bytes = coap_block_size_to_bytes(ctx->block_size); @@ -1142,21 +1279,21 @@ int coap_add_block2_option(struct coap_packet *cpkt, SET_NUM(val, ctx->current / bytes); } - r = coap_add_option_int(cpkt, COAP_OPTION_BLOCK2, val); + r = coap_append_option_int(cpkt, COAP_OPTION_BLOCK2, val); return r; } -int coap_add_size1_option(struct coap_packet *cpkt, - struct coap_block_context *ctx) +int coap_append_size1_option(struct coap_packet *cpkt, + struct coap_block_context *ctx) { - return coap_add_option_int(cpkt, COAP_OPTION_SIZE1, ctx->total_size); + return coap_append_option_int(cpkt, COAP_OPTION_SIZE1, ctx->total_size); } -int coap_add_size2_option(struct coap_packet *cpkt, - struct coap_block_context *ctx) +int coap_append_size2_option(struct coap_packet *cpkt, + struct coap_block_context *ctx) { - return coap_add_option_int(cpkt, COAP_OPTION_SIZE2, ctx->total_size); + return coap_append_option_int(cpkt, COAP_OPTION_SIZE2, ctx->total_size); } static int get_block_option(const struct coap_packet *cpkt, u16_t code) @@ -1285,6 +1422,7 @@ size_t coap_next_block(const struct coap_packet *cpkt, struct coap_block_context *ctx) { int block; + if (is_request(cpkt)) { block = get_block_option(cpkt, COAP_OPTION_BLOCK1); } else { diff --git a/subsys/net/lib/coap/coap_link_format.c b/subsys/net/lib/coap/coap_link_format.c index f5ebc729de24a..4b1c58a3203ac 100644 --- a/subsys/net/lib/coap/coap_link_format.c +++ b/subsys/net/lib/coap/coap_link_format.c @@ -4,6 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +#if defined(CONFIG_NET_DEBUG_COAP) +#define SYS_LOG_DOMAIN "coap" +#define NET_LOG_ENABLED 1 +#endif + #include #include #include @@ -21,8 +26,6 @@ #include #define PKT_WAIT_TIME K_SECONDS(1) -/* CoAP End Of Options Marker */ -#define COAP_MARKER 0xFF static bool match_path_uri(const char * const *path, const char *uri, u16_t len) @@ -75,7 +78,7 @@ static bool match_path_uri(const char * const *path, return true; } - next: +next: p++; } } @@ -144,55 +147,6 @@ static bool match_queries_resource(const struct coap_resource *resource, return match_attributes(attributes, query); } -static int send_error_response(struct coap_resource *resource, - struct coap_packet *request, - const struct sockaddr *from) -{ - struct net_context *context; - struct coap_packet response; - struct net_pkt *pkt; - struct net_buf *frag; - u16_t id; - int r; - - id = coap_header_get_id(request); - - context = net_pkt_context(request->pkt); - - pkt = net_pkt_get_tx(context, PKT_WAIT_TIME); - if (!pkt) { - return -ENOMEM; - } - - frag = net_pkt_get_data(context, PKT_WAIT_TIME); - if (!frag) { - net_pkt_unref(pkt); - return -ENOMEM; - } - - net_pkt_frag_add(pkt, frag); - - r = coap_packet_init(&response, pkt); - if (r < 0) { - net_pkt_unref(pkt); - return r; - } - - /* FIXME: Could be that coap_packet_init() sets some defaults */ - coap_header_set_version(&response, 1); - coap_header_set_type(&response, COAP_TYPE_ACK); - coap_header_set_code(&response, COAP_RESPONSE_CODE_BAD_REQUEST); - coap_header_set_id(&response, id); - - r = net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), - NULL, 0, NULL, NULL); - if (r < 0) { - net_pkt_unref(pkt); - } - - return r; -} - #if defined(CONFIG_COAP_WELL_KNOWN_BLOCK_WISE) #define MAX_BLOCK_WISE_TRANSFER_SIZE 2048 @@ -219,18 +173,16 @@ enum coap_block_size default_block_size(void) return COAP_BLOCK_64; } -static void add_to_net_buf(struct net_buf *buf, const char *str, u16_t len, - u16_t *remaining, size_t *offset, size_t current) +static bool append_to_net_pkt(struct net_pkt *pkt, const char *str, u16_t len, + u16_t *remaining, size_t *offset, size_t current) { - u16_t pos; - char *ptr; + u16_t pos = 0; + bool res; if (!*remaining) { - return; + return true; } - pos = 0; - if (*offset < current) { pos = current - *offset; @@ -239,7 +191,7 @@ static void add_to_net_buf(struct net_buf *buf, const char *str, u16_t len, *offset += pos; } else { *offset += len; - return; + return true; } } @@ -247,26 +199,32 @@ static void add_to_net_buf(struct net_buf *buf, const char *str, u16_t len, len = *remaining; } - ptr = net_buf_add(buf, len); - strncpy(ptr, str + pos, len); + res = net_pkt_append_all(pkt, len, str + pos, PKT_WAIT_TIME); *remaining -= len; *offset += len; + + return res; } -static int format_uri(const char * const *path, struct net_buf *buf, +static int format_uri(const char * const *path, struct net_pkt *pkt, u16_t *remaining, size_t *offset, size_t current, bool *more) { static const char prefix[] = "", 1, remaining, offset, current); + res = append_to_net_pkt(pkt, ">", 1, remaining, offset, current); + if (!res) { + return -ENOMEM; + } + + if (!*remaining) { + *more = true; + return 0; + } + *more = false; return 0; } static int format_attributes(const char * const *attributes, - struct net_buf *buf, + struct net_pkt *pkt, u16_t *remaining, size_t *offset, size_t current, bool *more) { const char * const *attr; + bool res; if (!attributes) { goto terminator; @@ -316,8 +292,12 @@ static int format_attributes(const char * const *attributes, for (attr = attributes; *attr; ) { int attr_len = strlen(*attr); - add_to_net_buf(buf, *attr, attr_len, - remaining, offset, current); + res = append_to_net_pkt(pkt, *attr, attr_len, + remaining, offset, current); + if (!res) { + return -ENOMEM; + } + if (!*remaining) { *more = true; return 0; @@ -328,8 +308,12 @@ static int format_attributes(const char * const *attributes, continue; } - add_to_net_buf(buf, ";", 1, - remaining, offset, current); + res = append_to_net_pkt(pkt, ";", 1, + remaining, offset, current); + if (!res) { + return -ENOMEM; + } + if (!*remaining) { *more = true; return 0; @@ -337,14 +321,23 @@ static int format_attributes(const char * const *attributes, } terminator: - add_to_net_buf(buf, ";", 1, remaining, offset, current); + res = append_to_net_pkt(pkt, ";", 1, remaining, offset, current); + if (!res) { + return -ENOMEM; + } + + if (!*remaining) { + *more = true; + return 0; + } + *more = false; return 0; } static int format_resource(const struct coap_resource *resource, - struct net_buf *buf, + struct net_pkt *pkt, u16_t *remaining, size_t *offset, size_t current, bool *more) { @@ -352,7 +345,7 @@ static int format_resource(const struct coap_resource *resource, const char * const *attributes = NULL; int r; - r = format_uri(resource->path, buf, remaining, offset, current, more); + r = format_uri(resource->path, pkt, remaining, offset, current, more); if (r < 0) { return r; } @@ -366,158 +359,161 @@ static int format_resource(const struct coap_resource *resource, attributes = meta->attributes; } - return format_attributes(attributes, buf, remaining, offset, current, + return format_attributes(attributes, pkt, remaining, offset, current, more); } -int _coap_well_known_core_get(struct coap_resource *resource, - struct coap_packet *request, - const struct sockaddr *from) +int clear_more_flag(struct coap_packet *cpkt) { - /* FIXME: Add support for concurrent connections at same time, - * Maintain separate Context for each client (from addr) through slist - * and match it with 'from' address. + struct net_buf *frag; + u16_t offset; + u8_t opt; + u8_t delta; + u8_t len; + + frag = net_frag_skip(cpkt->frag, 0, &offset, cpkt->hdr_len); + if (!frag && offset == 0xffff) { + return -EINVAL; + } + + delta = 0; + /* Note: coap_well_known_core_get() added Option (delta and len) witho + * out any extended options so parsing will not consider at the moment. */ + while (1) { + frag = net_frag_read_u8(frag, offset, &offset, &opt); + if (!frag && offset == 0xffff) { + return -EINVAL; + } + + delta += ((opt & 0xF0) >> 4); + len = (opt & 0xF); + + if (delta == COAP_OPTION_BLOCK2) { + break; + } + + frag = net_frag_skip(frag, offset, &offset, len); + if (!frag && offset == 0xffff) { + return -EINVAL; + } + } + + /* As per RFC 7959 Sec 2.2 : NUM filed can be on 0-3 bytes. + * Skip NUM field to update M bit. + */ + if (len > 1) { + frag = net_frag_skip(frag, offset, &offset, len - 1); + if (!frag && offset == 0xffff) { + return -EINVAL; + } + } + + frag->data[offset] = frag->data[offset] & 0xF7; + + return 0; +} + +int coap_well_known_core_get(struct coap_resource *resource, + struct coap_packet *request, + struct coap_packet *response, + struct net_pkt *pkt) +{ static struct coap_block_context ctx; - struct net_context *context; - struct coap_packet response; struct coap_option query; - struct net_pkt *pkt; - struct net_buf *frag; unsigned int num_queries; size_t offset; - const u8_t *token; - bool more; + u8_t token[8]; u16_t remaining; u16_t id; u8_t tkl; - u8_t format = 40; /* application/link-format */ - u8_t *str; + u8_t format; int r; + bool more = false; if (ctx.total_size == 0) { + /* We have to iterate through resources and it's attributes, + * total size is unknown, so initialize it to + * MAX_BLOCK_WISE_TRANSFER_SIZE and update it according to + * offset. + */ coap_block_transfer_init(&ctx, default_block_size(), MAX_BLOCK_WISE_TRANSFER_SIZE); } r = coap_update_from_block(request, &ctx); if (r < 0) { - return -EINVAL; + goto end; } id = coap_header_get_id(request); - token = coap_header_get_token(request, &tkl); + tkl = coap_header_get_token(request, token); /* Per RFC 6690, Section 4.1, only one (or none) query parameter may be * provided, use the first if multiple. */ r = coap_find_options(request, COAP_OPTION_URI_QUERY, &query, 1); if (r < 0) { - return r; + goto end; } num_queries = r; - context = net_pkt_context(request->pkt); - - pkt = net_pkt_get_tx(context, PKT_WAIT_TIME); - if (!pkt) { - return -ENOMEM; - } - - frag = net_pkt_get_data(context, PKT_WAIT_TIME); - if (!frag) { - net_pkt_unref(pkt); - return -ENOMEM; + r = coap_packet_init(response, pkt, 1, COAP_TYPE_ACK, + tkl, token, COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + goto end; } - net_pkt_frag_add(pkt, frag); + format = 40; /* application/link-format */ - r = coap_packet_init(&response, pkt); + r = coap_packet_append_option(response, COAP_OPTION_CONTENT_FORMAT, + &format, sizeof(format)); if (r < 0) { - goto done; + goto end; } - /* FIXME: Could be that coap_packet_init() sets some defaults */ - coap_header_set_version(&response, 1); - coap_header_set_type(&response, COAP_TYPE_ACK); - coap_header_set_code(&response, COAP_RESPONSE_CODE_CONTENT); - coap_header_set_id(&response, id); - coap_header_set_token(&response, token, tkl); + r = coap_append_block2_option(response, &ctx); + if (r < 0) { + goto end; + } - r = coap_add_option(&response, COAP_OPTION_CONTENT_FORMAT, - &format, sizeof(format)); + r = coap_packet_append_payload_marker(response); if (r < 0) { - net_pkt_unref(pkt); - return -EINVAL; + goto end; } offset = 0; - more = false; remaining = coap_block_size_to_bytes(ctx.block_size); while (resource++ && resource->path) { - struct net_buf *temp; - - if (!match_queries_resource(resource, &query, num_queries)) { - continue; - } - if (!remaining) { more = true; break; } - temp = net_pkt_get_data(context, PKT_WAIT_TIME); - if (!temp) { - net_pkt_unref(pkt); - return -ENOMEM; + if (!match_queries_resource(resource, &query, num_queries)) { + continue; } - net_pkt_frag_add(pkt, temp); - - r = format_resource(resource, temp, &remaining, &offset, + r = format_resource(resource, pkt, &remaining, &offset, ctx.current, &more); if (r < 0) { - goto done; + goto end; } } - if (!response.pkt->frags->frags) { - r = -ENOENT; - goto done; - } - + /* Offset is the total size now, but block2 option is already + * appended. So update only 'more' flag. + */ if (!more) { ctx.total_size = offset; + r = clear_more_flag(response); } - r = coap_add_block2_option(&response, &ctx); - if (r < 0) { - net_pkt_unref(pkt); - return -EINVAL; - } - - str = net_buf_add(response.pkt->frags, 1); - *str = COAP_MARKER; - response.start = str + 1; - - net_pkt_compact(pkt); - -done: - if (r < 0) { - net_pkt_unref(pkt); - return send_error_response(resource, request, from); - } - - r = net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), - NULL, 0, NULL, NULL); - if (r < 0) { - net_pkt_unref(pkt); - } - +end: + /* So it's a last block, reset context */ if (!more) { - /* So it's a last block, reset context */ memset(&ctx, 0, sizeof(ctx)); } @@ -526,76 +522,77 @@ int _coap_well_known_core_get(struct coap_resource *resource, #else -static int format_uri(const char * const *path, struct net_buf *buf) +static int format_uri(const char * const *path, struct net_pkt *pkt) { - static const char prefix[] = "'; + net_pkt_append_u8(pkt, (u8_t) '>'); return 0; } static int format_attributes(const char * const *attributes, - struct net_buf *buf) + struct net_pkt *pkt) { const char * const *attr; - char *str; + bool res; if (!attributes) { goto terminator; } for (attr = attributes; *attr; ) { - int attr_len = strlen(*attr); - - str = net_buf_add(buf, attr_len); - strncpy(str, *attr, attr_len); + res = net_pkt_append_all(pkt, strlen(*attr), (u8_t *) *attr, + PKT_WAIT_TIME); + if (!res) { + return -ENOMEM; + } attr++; if (*attr) { - str = net_buf_add(buf, 1); - *str = ';'; + net_pkt_append_u8(pkt, (u8_t) ';'); } } terminator: - str = net_buf_add(buf, 1); - *str = ';'; + net_pkt_append_u8(pkt, (u8_t) ';'); return 0; } static int format_resource(const struct coap_resource *resource, - struct net_buf *buf) + struct net_pkt *pkt) { struct coap_core_metadata *meta = resource->user_data; const char * const *attributes = NULL; int r; - r = format_uri(resource->path, buf); + r = format_uri(resource->path, pkt); if (r < 0) { return r; } @@ -604,28 +601,28 @@ static int format_resource(const struct coap_resource *resource, attributes = meta->attributes; } - return format_attributes(attributes, buf); + return format_attributes(attributes, pkt); } -int _coap_well_known_core_get(struct coap_resource *resource, - struct coap_packet *request, - const struct sockaddr *from) +int coap_well_known_core_get(struct coap_resource *resource, + struct coap_packet *request, + struct coap_packet *response, + struct net_pkt *pkt) { - struct net_context *context; - struct coap_packet response; struct coap_option query; - struct net_pkt *pkt; - struct net_buf *frag; - const u8_t *token; - unsigned int num_queries; + u8_t token[8]; u16_t id; u8_t tkl; - u8_t format = 40; /* application/link-format */ - u8_t *str; + u8_t format; + u8_t num_queries; int r; + if (!resource || !request || !response || !pkt) { + return -EINVAL; + } + id = coap_header_get_id(request); - token = coap_header_get_token(request, &tkl); + tkl = coap_header_get_token(request, token); /* Per RFC 6690, Section 4.1, only one (or none) query parameter may be * provided, use the first if multiple. @@ -637,82 +634,36 @@ int _coap_well_known_core_get(struct coap_resource *resource, num_queries = r; - context = net_pkt_context(request->pkt); - - pkt = net_pkt_get_tx(context, PKT_WAIT_TIME); - if (!pkt) { - return -ENOMEM; - } - - frag = net_pkt_get_data(context, PKT_WAIT_TIME); - if (!frag) { - net_pkt_unref(pkt); - return -ENOMEM; + r = coap_packet_init(response, pkt, 1, COAP_TYPE_ACK, + tkl, token, COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + return r; } - net_pkt_frag_add(pkt, frag); - - r = coap_packet_init(&response, pkt); + format = 40; /* application/link-format */ + r = coap_packet_append_option(response, COAP_OPTION_CONTENT_FORMAT, + &format, sizeof(format)); if (r < 0) { - goto done; + return -EINVAL; } - /* FIXME: Could be that coap_packet_init() sets some defaults */ - coap_header_set_version(&response, 1); - coap_header_set_type(&response, COAP_TYPE_ACK); - coap_header_set_code(&response, COAP_RESPONSE_CODE_CONTENT); - coap_header_set_id(&response, id); - coap_header_set_token(&response, token, tkl); - - r = coap_add_option(&response, COAP_OPTION_CONTENT_FORMAT, - &format, sizeof(format)); + r = coap_packet_append_payload_marker(response); if (r < 0) { - net_pkt_unref(pkt); return -EINVAL; } - r = -ENOENT; - - str = net_buf_add(response.pkt->frags, 1); - *str = COAP_MARKER; - response.start = str + 1; - while (resource++ && resource->path) { - struct net_buf *temp; - if (!match_queries_resource(resource, &query, num_queries)) { continue; } - temp = net_pkt_get_data(context, PKT_WAIT_TIME); - if (!temp) { - net_pkt_unref(pkt); - return -ENOMEM; - } - - net_pkt_frag_add(pkt, temp); - - r = format_resource(resource, temp); + r = format_resource(resource, pkt); if (r < 0) { - goto done; + return r; } } - net_pkt_compact(pkt); - -done: - if (r < 0) { - net_pkt_unref(pkt); - return send_error_response(resource, request, from); - } - - r = net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), - NULL, 0, NULL, NULL); - if (r < 0) { - net_pkt_unref(pkt); - } - - return r; + return 0; } #endif From 6b27b035aca41632f4ae3cb84e0084fdee1427f9 Mon Sep 17 00:00:00 2001 From: Ravi kumar Veeramally Date: Mon, 28 Aug 2017 13:55:28 +0300 Subject: [PATCH 20/37] net: tests: Update CoAP tests to use new API ZoAP tests are modified to use new CoAP API. Also modified tests name from 'zoap' to 'coap'. Signed-off-by: Ravi kumar Veeramally --- tests/net/lib/{zoap => coap}/Makefile | 0 tests/net/lib/{zoap => coap}/prj.conf | 14 +- tests/net/lib/{zoap => coap}/src/Makefile | 0 tests/net/lib/coap/src/main.c | 1208 ++++++++++++++++++++ tests/net/lib/{zoap => coap}/testcase.yaml | 0 tests/net/lib/zoap/src/main.c | 1169 ------------------- 6 files changed, 1217 insertions(+), 1174 deletions(-) rename tests/net/lib/{zoap => coap}/Makefile (100%) rename tests/net/lib/{zoap => coap}/prj.conf (50%) rename tests/net/lib/{zoap => coap}/src/Makefile (100%) create mode 100644 tests/net/lib/coap/src/main.c rename tests/net/lib/{zoap => coap}/testcase.yaml (100%) delete mode 100644 tests/net/lib/zoap/src/main.c diff --git a/tests/net/lib/zoap/Makefile b/tests/net/lib/coap/Makefile similarity index 100% rename from tests/net/lib/zoap/Makefile rename to tests/net/lib/coap/Makefile diff --git a/tests/net/lib/zoap/prj.conf b/tests/net/lib/coap/prj.conf similarity index 50% rename from tests/net/lib/zoap/prj.conf rename to tests/net/lib/coap/prj.conf index 37f70469b3fa3..21d11421395cc 100644 --- a/tests/net/lib/zoap/prj.conf +++ b/tests/net/lib/coap/prj.conf @@ -1,9 +1,13 @@ -CONFIG_NET_BUF_LOG=y CONFIG_NET_TEST=y -CONFIG_SYS_LOG_NET_BUF_LEVEL=2 CONFIG_NETWORKING=y -CONFIG_NETWORKING_WITH_IPV6=y +CONFIG_NET_IPV6=y +CONFIG_NET_UDP=y +CONFIG_NET_TCP=n +CONFIG_NET_IPV4=n +CONFIG_NET_BUF_LOG=y +CONFIG_SYS_LOG_NET_BUF_LEVEL=2 CONFIG_RANDOM_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_ZOAP=y -CONFIG_ZOAP_TEST_API_ENABLE=y +CONFIG_COAP=y +CONFIG_COAP_TEST_API_ENABLE=y +CONFIG_MAIN_STACK_SIZE=2048 diff --git a/tests/net/lib/zoap/src/Makefile b/tests/net/lib/coap/src/Makefile similarity index 100% rename from tests/net/lib/zoap/src/Makefile rename to tests/net/lib/coap/src/Makefile diff --git a/tests/net/lib/coap/src/main.c b/tests/net/lib/coap/src/main.c new file mode 100644 index 0000000000000..b661c8a0d593b --- /dev/null +++ b/tests/net/lib/coap/src/main.c @@ -0,0 +1,1208 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include + +#define COAP_BUF_SIZE 128 +#define COAP_LIMITED_BUF_SIZE 13 + +#define NUM_PENDINGS 3 +#define NUM_OBSERVERS 3 +#define NUM_REPLIES 3 + +NET_PKT_TX_SLAB_DEFINE(coap_pkt_slab, 4); + +NET_BUF_POOL_DEFINE(coap_data_pool, 4, COAP_BUF_SIZE, 0, NULL); + +NET_BUF_POOL_DEFINE(coap_limited_data_pool, 4, COAP_LIMITED_BUF_SIZE, 0, NULL); + +static struct coap_pending pendings[NUM_PENDINGS]; +static struct coap_observer observers[NUM_OBSERVERS]; +static struct coap_reply replies[NUM_REPLIES]; + +/* This is exposed for this test in subsys/net/lib/coap/coap_link_format.c */ +bool _coap_match_path_uri(const char * const *path, + const char *uri, u16_t len); + +/* Some forward declarations */ +static void server_notify_callback(struct coap_resource *resource, + struct coap_observer *observer); + +static int server_resource_1_get(struct coap_resource *resource, + struct coap_packet *request); + +static const char * const server_resource_1_path[] = { "s", "1", NULL }; +static struct coap_resource server_resources[] = { + { .path = server_resource_1_path, + .get = server_resource_1_get, + .notify = server_notify_callback }, + { }, +}; + +#define MY_PORT 12345 +#define peer_addr { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0x2 } } } +static struct sockaddr_in6 dummy_addr = { + .sin6_family = AF_INET6, + .sin6_addr = peer_addr }; + +static int test_build_empty_pdu(void) +{ + u8_t result_pdu[] = { 0x40, 0x01, 0x0, 0x0 }; + struct coap_packet cpkt; + struct net_pkt *pkt; + struct net_buf *frag; + int result = TC_FAIL; + int r; + + pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); + if (!pkt) { + TC_PRINT("Could not get packet from pool\n"); + goto done; + } + + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); + if (!frag) { + TC_PRINT("Could not get buffer from pool\n"); + goto done; + } + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&cpkt, pkt, 1, COAP_TYPE_CON, + 0, NULL, COAP_METHOD_GET, 0); + if (r) { + TC_PRINT("Could not initialize packet\n"); + goto done; + } + + if (frag->len != sizeof(result_pdu)) { + TC_PRINT("Different size from the reference packet\n"); + goto done; + } + + if (memcmp(result_pdu, frag->data, frag->len)) { + TC_PRINT("Built packet doesn't match reference packet\n"); + goto done; + } + + result = TC_PASS; + +done: + net_pkt_unref(pkt); + + TC_END_RESULT(result); + + return result; +} + +static int test_build_simple_pdu(void) +{ + u8_t result_pdu[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', + 'n', 0xC1, 0x00, 0xFF, 'p', 'a', 'y', 'l', + 'o', 'a', 'd', 0x00 }; + struct coap_packet cpkt; + struct net_pkt *pkt; + struct net_buf *frag; + const char token[] = "token"; + u8_t format = 0; + int result = TC_FAIL; + int r; + + pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); + if (!pkt) { + TC_PRINT("Could not get packet from pool\n"); + goto done; + } + + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); + if (!frag) { + TC_PRINT("Could not get buffer from pool\n"); + goto done; + } + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&cpkt, pkt, 1, COAP_TYPE_NON_CON, + strlen(token), (u8_t *)token, + COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED, + 0x1234); + if (r) { + TC_PRINT("Could not initialize packet\n"); + goto done; + } + + r = coap_packet_append_option(&cpkt, COAP_OPTION_CONTENT_FORMAT, + &format, sizeof(format)); + if (r) { + TC_PRINT("Could not append option\n"); + goto done; + } + + r = coap_packet_append_payload_marker(&cpkt); + if (r) { + TC_PRINT("Failed to set the payload marker\n"); + goto done; + } + + if (memcmp(result_pdu, frag->data, frag->len)) { + TC_PRINT("Built packet doesn't match reference packet\n"); + goto done; + } + + result = TC_PASS; + +done: + net_pkt_unref(pkt); + + TC_END_RESULT(result); + + return result; +} + +/* IPv6 + UDP frame (48 bytes) */ +static const unsigned char ipv6_empty_pdu[] = { + /* IPv6 header starts here */ + 0x60, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x11, 0xFF, + 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + /* UDP */ + 0xd8, 0xb4, 0x16, 0x33, 0x00, 0x0c, 0x00, 0x00, + /* CoAP */ +}; + +static int test_parse_empty_pdu(void) +{ + u8_t pdu[] = { 0x40, 0x01, 0, 0 }; + struct net_pkt *pkt; + struct net_buf *frag; + struct coap_packet cpkt; + u8_t ver, type, code; + u16_t id; + int result = TC_FAIL; + int r; + + pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); + if (!pkt) { + TC_PRINT("Could not get packet from pool\n"); + goto done; + } + + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); + if (!frag) { + TC_PRINT("Could not get buffer from pool\n"); + goto done; + } + + net_pkt_frag_add(pkt, frag); + + net_pkt_append_all(pkt, sizeof(ipv6_empty_pdu), + (u8_t *)ipv6_empty_pdu, K_FOREVER); + net_pkt_append_all(pkt, sizeof(pdu), (u8_t *)pdu, K_FOREVER); + + net_pkt_set_ip_hdr_len(pkt, NET_IPV6H_LEN); + net_pkt_set_ipv6_ext_len(pkt, 0); + + memcpy(frag->data, pdu, sizeof(pdu)); + frag->len = NET_IPV6UDPH_LEN + sizeof(pdu); + + r = coap_packet_parse(&cpkt, pkt, NULL, 0); + if (r) { + TC_PRINT("Could not parse packet\n"); + goto done; + } + + ver = coap_header_get_version(&cpkt); + type = coap_header_get_type(&cpkt); + code = coap_header_get_code(&cpkt); + id = coap_header_get_id(&cpkt); + + if (ver != 1) { + TC_PRINT("Invalid version for parsed packet\n"); + goto done; + } + + if (type != COAP_TYPE_CON) { + TC_PRINT("Packet type doesn't match reference\n"); + goto done; + } + + if (code != COAP_METHOD_GET) { + TC_PRINT("Packet code doesn't match reference\n"); + goto done; + } + + if (id != 0) { + TC_PRINT("Packet id doesn't match reference\n"); + goto done; + } + + result = TC_PASS; + +done: + net_pkt_unref(pkt); + + TC_END_RESULT(result); + + return result; +} + +/* IPv6 + UDP frame (48 bytes) */ +static const unsigned char ipv6_simple_pdu[] = { + /* IPv6 header starts here */ + 0x60, 0x00, 0x00, 0x00, 0x00, 0x15, 0x11, 0xFF, + 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + /* UDP */ + 0xd8, 0xb4, 0x16, 0x33, 0x00, 0x15, 0x00, 0x00, + /* CoAP */ +}; + +static int test_parse_simple_pdu(void) +{ + u8_t pdu[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', + 'n', 0x00, 0xc1, 0x00, 0xff, 'p', 'a', 'y', + 'l', 'o', 'a', 'd', 0x00 }; + struct coap_packet cpkt; + struct net_pkt *pkt; + struct net_buf *frag; + struct coap_option options[16]; + u8_t ver, type, code, tkl; + const u8_t token[8]; + u16_t id; + int result = TC_FAIL; + int r, count = 16; + + pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); + if (!pkt) { + TC_PRINT("Could not get packet from pool\n"); + goto done; + } + + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); + if (!frag) { + TC_PRINT("Could not get buffer from pool\n"); + goto done; + } + + net_pkt_frag_add(pkt, frag); + + net_pkt_append_all(pkt, sizeof(ipv6_simple_pdu), + (u8_t *)ipv6_simple_pdu, K_FOREVER); + net_pkt_append_all(pkt, sizeof(pdu), (u8_t *)pdu, K_FOREVER); + + net_pkt_set_ip_hdr_len(pkt, NET_IPV6H_LEN); + net_pkt_set_ipv6_ext_len(pkt, 0); + + r = coap_packet_parse(&cpkt, pkt, NULL, 0); + if (r) { + TC_PRINT("Could not parse packet\n"); + goto done; + } + + ver = coap_header_get_version(&cpkt); + type = coap_header_get_type(&cpkt); + code = coap_header_get_code(&cpkt); + id = coap_header_get_id(&cpkt); + + if (ver != 1) { + TC_PRINT("Invalid version for parsed packet\n"); + goto done; + } + + if (type != COAP_TYPE_NON_CON) { + TC_PRINT("Packet type doesn't match reference\n"); + goto done; + } + + if (code != COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED) { + TC_PRINT("Packet code doesn't match reference\n"); + goto done; + } + + if (id != 0x1234) { + TC_PRINT("Packet id doesn't match reference\n"); + goto done; + } + + tkl = coap_header_get_token(&cpkt, (u8_t *)token); + + if (tkl != 5) { + TC_PRINT("Token length doesn't match reference\n"); + goto done; + } + + if (memcmp(token, "token", tkl)) { + TC_PRINT("Token value doesn't match the reference\n"); + goto done; + } + + count = coap_find_options(&cpkt, COAP_OPTION_CONTENT_FORMAT, + options, count); + if (count != 1) { + TC_PRINT("Unexpected number of options in the packet\n"); + goto done; + } + + if (options[0].len != 1) { + TC_PRINT("Option length doesn't match the reference\n"); + goto done; + } + + if (((u8_t *)options[0].value)[0] != 0) { + TC_PRINT("Option value doesn't match the reference\n"); + goto done; + } + + /* Not existent */ + count = coap_find_options(&cpkt, COAP_OPTION_ETAG, options, count); + if (count) { + TC_PRINT("There shouldn't be any ETAG option in the packet\n"); + goto done; + } + + result = TC_PASS; + +done: + net_pkt_unref(pkt); + + TC_END_RESULT(result); + + return result; +} + +static int test_retransmit_second_round(void) +{ + struct coap_packet cpkt, resp; + struct coap_pending *pending, *resp_pending; + struct net_pkt *pkt, *resp_pkt = NULL; + struct net_buf *frag; + int result = TC_FAIL; + int r; + u16_t id; + + pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); + if (!pkt) { + TC_PRINT("Could not get packet from pool\n"); + goto done; + } + + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); + if (!frag) { + TC_PRINT("Could not get buffer from pool\n"); + goto done; + } + + net_pkt_frag_add(pkt, frag); + id = coap_next_id(); + + r = coap_packet_init(&cpkt, pkt, 1, COAP_TYPE_CON, 0, NULL, + COAP_METHOD_GET, id); + if (r) { + TC_PRINT("Could not initialize packet\n"); + goto done; + } + + pending = coap_pending_next_unused(pendings, NUM_PENDINGS); + if (!pending) { + TC_PRINT("No free pending\n"); + goto done; + } + + r = coap_pending_init(pending, &cpkt, (struct sockaddr *) &dummy_addr); + if (r) { + TC_PRINT("Could not initialize packet\n"); + goto done; + } + + /* We "send" the packet the first time here */ + if (!coap_pending_cycle(pending)) { + TC_PRINT("Pending expired too early\n"); + goto done; + } + + /* We simulate that the first transmission got lost */ + if (!coap_pending_cycle(pending)) { + TC_PRINT("Pending expired too early\n"); + goto done; + } + + resp_pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); + if (!resp_pkt) { + TC_PRINT("Could not get packet from pool\n"); + goto done; + } + + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); + if (!frag) { + TC_PRINT("Could not get buffer from pool\n"); + goto done; + } + + net_pkt_frag_add(resp_pkt, frag); + + r = coap_packet_init(&resp, resp_pkt, 1, COAP_TYPE_ACK, + 0, NULL, COAP_METHOD_GET, id); + if (r) { + TC_PRINT("Could not initialize packet\n"); + goto done; + } + + /* Now we get the ack from the remote side */ + resp_pending = coap_pending_received(&resp, pendings, NUM_PENDINGS); + if (pending != resp_pending) { + TC_PRINT("Invalid pending %p should be %p\n", + resp_pending, pending); + goto done; + } + + resp_pending = coap_pending_next_to_expire(pendings, NUM_PENDINGS); + if (resp_pending) { + TC_PRINT("There should be no active pendings\n"); + goto done; + } + + result = TC_PASS; + +done: + net_pkt_unref(pkt); + if (resp_pkt) { + net_pkt_unref(resp_pkt); + } + + TC_END_RESULT(result); + + return result; +} + +static void get_from_ip_addr(struct coap_packet *cpkt, + struct sockaddr_in6 *from) +{ + struct net_udp_hdr hdr, *udp_hdr; + + udp_hdr = net_udp_get_hdr(cpkt->pkt, &hdr); + if (!udp_hdr) { + return; + } + + net_ipaddr_copy(&from->sin6_addr, &NET_IPV6_HDR(cpkt->pkt)->src); + from->sin6_port = udp_hdr->src_port; + from->sin6_family = AF_INET6; +} + +static bool ipaddr_cmp(const struct sockaddr *a, const struct sockaddr *b) +{ + if (a->sa_family != b->sa_family) { + return false; + } + + if (a->sa_family == AF_INET6) { + return net_ipv6_addr_cmp(&net_sin6(a)->sin6_addr, + &net_sin6(b)->sin6_addr); + } else if (a->sa_family == AF_INET) { + return net_ipv4_addr_cmp(&net_sin(a)->sin_addr, + &net_sin(b)->sin_addr); + } + + return false; +} + +static void server_notify_callback(struct coap_resource *resource, + struct coap_observer *observer) +{ + if (!ipaddr_cmp(&observer->addr, + (const struct sockaddr *) &dummy_addr)) { + TC_ERROR("The address of the observer doesn't match.\n"); + return; + } + + coap_remove_observer(resource, observer); + + TC_PRINT("You should see this\n"); +} + +/* IPv6 + UDP frame (48 bytes) */ +static const unsigned char ipv6_resource1[] = { + /* IPv6 header starts here */ + 0x60, 0x00, 0x00, 0x00, 0x00, 0x16, 0x11, 0xFF, + 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + /* UDP */ + 0xd8, 0xb4, 0x16, 0x33, 0x00, 0x16, 0x00, 0x00, + /* CoAP */ +}; + +static int server_resource_1_get(struct coap_resource *resource, + struct coap_packet *request) +{ + struct coap_packet response; + struct coap_observer *observer; + struct sockaddr_in6 from; + struct net_pkt *pkt; + struct net_buf *frag; + char payload[] = "This is the payload"; + u8_t token[8]; + u8_t tkl; + u16_t id; + int r; + + if (!coap_request_is_observe(request)) { + TC_PRINT("The request should enable observing\n"); + return -EINVAL; + } + + observer = coap_observer_next_unused(observers, NUM_OBSERVERS); + if (!observer) { + TC_PRINT("There should be an available observer.\n"); + return -EINVAL; + } + + tkl = coap_header_get_token(request, (u8_t *) token); + id = coap_header_get_id(request); + get_from_ip_addr(request, &from); + + coap_observer_init(observer, request, + (const struct sockaddr *)&from); + + coap_register_observer(resource, observer); + + pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); + if (!pkt) { + TC_PRINT("Could not get packet from pool\n"); + return -ENOMEM; + } + + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); + if (!frag) { + TC_PRINT("Could not get buffer from pool\n"); + return -ENOMEM; + } + + net_pkt_frag_add(pkt, frag); + + net_pkt_append_all(pkt, sizeof(ipv6_resource1), + (u8_t *)ipv6_resource1, K_FOREVER); + + net_pkt_set_ip_hdr_len(pkt, NET_IPV6H_LEN); + net_pkt_set_ipv6_ext_len(pkt, 0); + + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, tkl, token, + COAP_RESPONSE_CODE_OK, id); + if (r < 0) { + TC_PRINT("Unable to initialize packet.\n"); + return -EINVAL; + } + + coap_append_option_int(&response, COAP_OPTION_OBSERVE, resource->age); + + r = coap_packet_append_payload_marker(&response); + if (r) { + TC_PRINT("Failed to set the payload marker\n"); + return -EINVAL; + } + + if (!net_pkt_append_all(pkt, strlen(payload), (u8_t *) payload, + K_FOREVER)) { + TC_PRINT("Failed to append the payload\n"); + return -EINVAL; + } + + resource->user_data = pkt; + + return 0; +} + +/* IPv6 + UDP frame (48 bytes) */ +static const unsigned char ipv6_valid_req[] = { + /* IPv6 header starts here */ + 0x60, 0x00, 0x00, 0x00, 0x00, 0x16, 0x11, 0xFF, + 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + /* UDP */ + 0xd8, 0xb4, 0x16, 0x33, 0x00, 0x16, 0x00, 0x00, + /* CoAP */ +}; + +/* IPv6 + UDP frame (48 bytes) */ +static const unsigned char ipv6_not_found_req[] = { + /* IPv6 header starts here */ + 0x60, 0x00, 0x00, 0x00, 0x00, 0x16, 0x11, 0xFF, + 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + /* UDP */ + 0xd8, 0xb4, 0x16, 0x33, 0x00, 0x16, 0x00, 0x00, + /* CoAP */ +}; + +static int test_observer_server(void) +{ + u8_t valid_request_pdu[] = { + 0x45, 0x01, 0x12, 0x34, + 't', 'o', 'k', 'e', 'n', + 0x60, /* enable observe option */ + 0x51, 's', 0x01, '1', /* path */ + }; + u8_t not_found_request_pdu[] = { + 0x45, 0x01, 0x12, 0x34, + 't', 'o', 'k', 'e', 'n', + 0x60, /* enable observe option */ + 0x51, 's', 0x01, '2', /* path */ + }; + struct coap_packet req; + struct coap_option options[4]; + struct net_pkt *pkt; + struct net_buf *frag; + u8_t opt_num = 4; + int result = TC_FAIL; + int r; + + pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); + if (!pkt) { + TC_PRINT("Could not get packet from pool\n"); + goto done; + } + + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); + if (!frag) { + TC_PRINT("Could not get buffer from pool\n"); + goto done; + } + + net_pkt_frag_add(pkt, frag); + + net_pkt_append_all(pkt, sizeof(ipv6_valid_req), + (u8_t *)ipv6_valid_req, K_FOREVER); + net_pkt_append_all(pkt, sizeof(valid_request_pdu), + (u8_t *)valid_request_pdu, K_FOREVER); + + net_pkt_set_ip_hdr_len(pkt, NET_IPV6H_LEN); + net_pkt_set_ipv6_ext_len(pkt, 0); + + r = coap_packet_parse(&req, pkt, options, opt_num); + if (r) { + TC_PRINT("Could not initialize packet\n"); + goto done; + } + + r = coap_handle_request(&req, server_resources, options, opt_num); + if (r) { + TC_PRINT("Could not handle packet\n"); + goto done; + } + + /* Suppose some time passes */ + + r = coap_resource_notify(&server_resources[0]); + if (r) { + TC_PRINT("Could not notify resource\n"); + goto done; + } + + net_pkt_unref(pkt); + + pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); + if (!pkt) { + TC_PRINT("Could not get packet from pool\n"); + goto done; + } + + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); + if (!frag) { + TC_PRINT("Could not get buffer from pool\n"); + goto done; + } + + net_pkt_frag_add(pkt, frag); + + net_pkt_append_all(pkt, sizeof(ipv6_not_found_req), + (u8_t *)ipv6_not_found_req, K_FOREVER); + net_pkt_append_all(pkt, sizeof(not_found_request_pdu), + (u8_t *)not_found_request_pdu, K_FOREVER); + + net_pkt_set_ip_hdr_len(pkt, NET_IPV6H_LEN); + net_pkt_set_ipv6_ext_len(pkt, 0); + + r = coap_packet_parse(&req, pkt, options, opt_num); + if (r) { + TC_PRINT("Could not initialize packet\n"); + goto done; + } + + r = coap_handle_request(&req, server_resources, options, opt_num); + if (r != -ENOENT) { + TC_PRINT("There should be no handler for this resource\n"); + goto done; + } + + result = TC_PASS; + +done: + net_pkt_unref(pkt); + + TC_END_RESULT(result); + + return result; +} + +/* IPv6 + UDP frame (48 bytes) */ +static const unsigned char ipv6_obs_client[] = { + /* IPv6 header starts here */ + 0x60, 0x00, 0x00, 0x00, 0x00, 0x15, 0x11, 0xFF, + 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + /* UDP */ + 0xd8, 0xb4, 0x16, 0x33, 0x00, 0x15, 0x00, 0x00, + /* CoAP */ +}; + +static int resource_reply_cb(const struct coap_packet *response, + struct coap_reply *reply, + const struct sockaddr *from) +{ + TC_PRINT("You should see this\n"); + + return 0; +} + +static int test_observer_client(void) +{ + struct coap_packet req, rsp; + struct coap_reply *reply; + struct coap_option options[4]; + struct net_pkt *pkt, *rsp_pkt = NULL; + struct net_buf *frag; + const char token[] = "token"; + const char * const *p; + u8_t opt_num = 4; + int observe = 0; + int result = TC_FAIL; + int r; + + pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); + if (!pkt) { + TC_PRINT("Could not get packet from pool\n"); + goto done; + } + + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); + if (!frag) { + TC_PRINT("Could not get buffer from pool\n"); + goto done; + } + + net_pkt_frag_add(pkt, frag); + net_pkt_set_ip_hdr_len(pkt, NET_IPV6H_LEN); + net_pkt_set_ipv6_ext_len(pkt, 0); + + if (!net_pkt_append_all(pkt, sizeof(ipv6_obs_client), + (u8_t *)ipv6_obs_client, K_FOREVER)) { + TC_PRINT("Unable to append IPv6 header\n"); + goto done; + } + + r = coap_packet_init(&req, pkt, 1, COAP_TYPE_CON, + strlen(token), (u8_t *)token, + COAP_METHOD_GET, coap_next_id()); + if (r < 0) { + TC_PRINT("Unable to initialize request\n"); + goto done; + } + + req.offset = sizeof(ipv6_obs_client); + + /* Enable observing the resource. */ + r = coap_append_option_int(&req, COAP_OPTION_OBSERVE, observe); + if (r < 0) { + TC_PRINT("Unable to add option to request int.\n"); + goto done; + } + + for (p = server_resource_1_path; p && *p; p++) { + r = coap_packet_append_option(&req, COAP_OPTION_URI_PATH, + *p, strlen(*p)); + if (r < 0) { + TC_PRINT("Unable to add option to request.\n"); + goto done; + } + } + + reply = coap_reply_next_unused(replies, NUM_REPLIES); + if (!reply) { + printk("No resources for waiting for replies.\n"); + goto done; + } + + coap_reply_init(reply, &req); + reply->reply = resource_reply_cb; + + /* Server side, not interesting for this test */ + r = coap_packet_parse(&req, pkt, options, opt_num); + if (r) { + TC_PRINT("Could not parse req packet\n"); + goto done; + } + + r = coap_handle_request(&req, server_resources, options, opt_num); + if (r) { + TC_PRINT("Could not handle packet\n"); + goto done; + } + + /* We cheat, and communicate using the resource's user_data */ + rsp_pkt = server_resources[0].user_data; + + /* 'rsp_pkt' contains the response now */ + + r = coap_packet_parse(&rsp, rsp_pkt, options, opt_num); + if (r) { + TC_PRINT("Could not parse rsp packet\n"); + goto done; + } + + reply = coap_response_received(&rsp, + (const struct sockaddr *) &dummy_addr, + replies, NUM_REPLIES); + if (!reply) { + TC_PRINT("Couldn't find a matching waiting reply\n"); + goto done; + } + + result = TC_PASS; + +done: + net_pkt_unref(pkt); + if (rsp_pkt) { + net_pkt_unref(rsp_pkt); + } + + TC_END_RESULT(result); + + return result; +} + +/* IPv6 + UDP frame (48 bytes) */ +static const unsigned char ipv6_block[] = { + /* IPv6 header starts here */ + 0x60, 0x00, 0x00, 0x00, 0x00, 0x17, 0x11, 0xFF, + 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + /* UDP */ + 0xd8, 0xb4, 0x16, 0x33, 0x00, 0x17, 0x00, 0x00, + /* CoAP */ +}; + +static int test_block_size(void) +{ + struct coap_block_context req_ctx, rsp_ctx; + struct coap_packet req; + struct net_pkt *pkt = NULL; + struct net_buf *frag; + const char token[] = "token"; + u8_t payload = 0xFE; + int result = TC_FAIL; + int r; + + pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); + if (!pkt) { + TC_PRINT("Could not get packet from pool\n"); + goto done; + } + + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); + if (!frag) { + TC_PRINT("Could not get buffer from pool\n"); + goto done; + } + + net_pkt_frag_add(pkt, frag); + net_pkt_set_ip_hdr_len(pkt, NET_IPV6H_LEN); + net_pkt_set_ipv6_ext_len(pkt, 0); + + if (!net_pkt_append_all(pkt, sizeof(ipv6_block), + (u8_t *)ipv6_block, K_FOREVER)) { + TC_PRINT("Unable to append IPv6 header\n"); + goto done; + } + + r = coap_packet_init(&req, pkt, 1, COAP_TYPE_CON, + strlen(token), (u8_t *) token, + COAP_METHOD_POST, coap_next_id()); + if (r < 0) { + TC_PRINT("Unable to initialize request\n"); + goto done; + } + + req.offset = sizeof(ipv6_block); + + coap_block_transfer_init(&req_ctx, COAP_BLOCK_32, 127); + + r = coap_append_block1_option(&req, &req_ctx); + if (r) { + TC_PRINT("Unable to append block1 option\n"); + goto done; + } + + r = coap_append_size1_option(&req, &req_ctx); + if (r) { + TC_PRINT("Unable to append size1 option\n"); + goto done; + } + + r = coap_packet_append_payload_marker(&req); + if (r) { + TC_PRINT("Unable to append payload marker\n"); + goto done; + } + + r = coap_packet_append_payload(&req, (u8_t *)&payload, + coap_block_size_to_bytes(COAP_BLOCK_32)); + if (r) { + TC_PRINT("Unable to append payload marker\n"); + goto done; + } + + coap_block_transfer_init(&rsp_ctx, COAP_BLOCK_1024, 0); + + r = coap_update_from_block(&req, &rsp_ctx); + if (r < 0) { + TC_PRINT("Couldn't parse Block options\n"); + goto done; + } + + if (rsp_ctx.block_size != COAP_BLOCK_32) { + TC_PRINT("Couldn't get block size from request\n"); + goto done; + } + + if (rsp_ctx.current != 0) { + TC_PRINT("Couldn't get the current block size position\n"); + goto done; + } + + if (rsp_ctx.total_size != 127) { + TC_PRINT("Couldn't packet total size from request\n"); + goto done; + } + + /* Suppose that pkt was sent */ + net_pkt_unref(pkt); + + /* Let's try the second packet */ + coap_next_block(&req, &req_ctx); + + pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); + if (!pkt) { + TC_PRINT("Could not get packet from pool\n"); + goto done; + } + + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); + if (!frag) { + TC_PRINT("Could not get buffer from pool\n"); + goto done; + } + + net_pkt_frag_add(pkt, frag); + net_pkt_set_ip_hdr_len(pkt, NET_IPV6H_LEN); + net_pkt_set_ipv6_ext_len(pkt, 0); + + if (!net_pkt_append_all(pkt, sizeof(ipv6_block), + (u8_t *)ipv6_block, K_FOREVER)) { + TC_PRINT("Unable to append IPv6 header\n"); + goto done; + } + + r = coap_packet_init(&req, pkt, 1, COAP_TYPE_CON, + strlen(token), (u8_t *) token, + COAP_METHOD_POST, coap_next_id()); + if (r < 0) { + TC_PRINT("Unable to initialize request\n"); + goto done; + } + + req.offset = sizeof(ipv6_block); + + r = coap_append_block1_option(&req, &req_ctx); + if (r) { + TC_PRINT("Unable to append block1 option\n"); + goto done; + } + + r = coap_packet_append_payload_marker(&req); + if (r) { + TC_PRINT("Unable to append payload marker\n"); + goto done; + } + + r = coap_packet_append_payload(&req, (u8_t *)&payload, + coap_block_size_to_bytes(COAP_BLOCK_32)); + if (r) { + TC_PRINT("Unable to append payload marker\n"); + goto done; + } + + r = coap_update_from_block(&req, &rsp_ctx); + if (r < 0) { + TC_PRINT("Couldn't parse Block options\n"); + goto done; + } + + if (rsp_ctx.block_size != COAP_BLOCK_32) { + TC_PRINT("Couldn't get block size from request\n"); + goto done; + } + + if (rsp_ctx.current != coap_block_size_to_bytes(COAP_BLOCK_32)) { + TC_PRINT("Couldn't get the current block size position\n"); + goto done; + } + + if (rsp_ctx.total_size != 127) { + TC_PRINT("Couldn't packet total size from request\n"); + goto done; + } + + result = TC_PASS; + +done: + net_pkt_unref(pkt); + + TC_END_RESULT(result); + + return result; +} + +static int test_match_path_uri(void) +{ + int result = TC_FAIL; + const char * const resource_path[] = { + "s", + "1", + "foobar", + "foobar3a", + "foobar3", + "devnull", + NULL + }; + const char *uri; + + uri = "/k"; + if (_coap_match_path_uri(resource_path, uri, strlen(uri))) { + TC_PRINT("Matching %s failed\n", uri); + goto out; + } + + uri = "/s"; + if (!_coap_match_path_uri(resource_path, uri, strlen(uri))) { + TC_PRINT("Matching %s failed\n", uri); + goto out; + } + + uri = "/foobar"; + if (!_coap_match_path_uri(resource_path, uri, strlen(uri))) { + TC_PRINT("Matching %s failed\n", uri); + goto out; + } + + uri = "/foobar2"; + if (_coap_match_path_uri(resource_path, uri, strlen(uri))) { + TC_PRINT("Matching %s failed\n", uri); + goto out; + } + + uri = "/foobar*"; + if (!_coap_match_path_uri(resource_path, uri, strlen(uri))) { + TC_PRINT("Matching %s failed\n", uri); + goto out; + } + + uri = "/foobar3*"; + if (!_coap_match_path_uri(resource_path, uri, strlen(uri))) { + TC_PRINT("Matching %s failed\n", uri); + goto out; + } + + uri = "/devnull*"; + if (_coap_match_path_uri(resource_path, uri, strlen(uri))) { + TC_PRINT("Matching %s failed\n", uri); + goto out; + } + + result = TC_PASS; + +out: + TC_END_RESULT(result); + + return result; + +} + +static const struct { + const char *name; + int (*func)(void); +} tests[] = { + { "Build empty PDU test", test_build_empty_pdu, }, + { "Build simple PDU test", test_build_simple_pdu, }, + { "Parse emtpy PDU test", test_parse_empty_pdu, }, + { "Parse simple PDU test", test_parse_simple_pdu, }, + { "Test retransmission", test_retransmit_second_round, }, + { "Test observer server", test_observer_server, }, + { "Test observer client", test_observer_client, }, + { "Test block sized transfer", test_block_size, }, + { "Test match path uri", test_match_path_uri, }, +}; + +int main(int argc, char *argv[]) +{ + int count, pass, result; + + TC_START("Test Zoap CoAP PDU parsing and building"); + + for (count = 0, pass = 0; count < ARRAY_SIZE(tests); count++) { + if (tests[count].func() == TC_PASS) { + pass++; + } + } + + TC_PRINT("%d / %d tests passed\n", pass, count); + + result = pass == count ? TC_PASS : TC_FAIL; + + TC_END_REPORT(result); + + return 0; +} diff --git a/tests/net/lib/zoap/testcase.yaml b/tests/net/lib/coap/testcase.yaml similarity index 100% rename from tests/net/lib/zoap/testcase.yaml rename to tests/net/lib/coap/testcase.yaml diff --git a/tests/net/lib/zoap/src/main.c b/tests/net/lib/zoap/src/main.c deleted file mode 100644 index 6e15bd194c7f7..0000000000000 --- a/tests/net/lib/zoap/src/main.c +++ /dev/null @@ -1,1169 +0,0 @@ -/* - * Copyright (c) 2016 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include - -#include - -#define ZOAP_BUF_SIZE 128 -#define ZOAP_LIMITED_BUF_SIZE 13 - -#define NUM_PENDINGS 3 -#define NUM_OBSERVERS 3 -#define NUM_REPLIES 3 - -NET_PKT_TX_SLAB_DEFINE(zoap_pkt_slab, 4); - -NET_BUF_POOL_DEFINE(zoap_data_pool, 4, ZOAP_BUF_SIZE, 0, NULL); - -NET_BUF_POOL_DEFINE(zoap_limited_data_pool, 4, ZOAP_LIMITED_BUF_SIZE, 0, NULL); - -static struct zoap_pending pendings[NUM_PENDINGS]; -static struct zoap_observer observers[NUM_OBSERVERS]; -static struct zoap_reply replies[NUM_REPLIES]; - -/* This is exposed for this test in subsys/net/lib/zoap/zoap_link_format.c */ -bool _zoap_match_path_uri(const char * const *path, - const char *uri, u16_t len); - -/* Some forward declarations */ -static void server_notify_callback(struct zoap_resource *resource, - struct zoap_observer *observer); - -static int server_resource_1_get(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from); - -static const char * const server_resource_1_path[] = { "s", "1", NULL }; -static struct zoap_resource server_resources[] = { - { .path = server_resource_1_path, - .get = server_resource_1_get, - .notify = server_notify_callback }, - { }, -}; - -#define MY_PORT 12345 -static struct sockaddr_in6 dummy_addr = { - .sin6_family = AF_INET6, - .sin6_addr = IN6ADDR_LOOPBACK_INIT }; - -static int test_build_empty_pdu(void) -{ - u8_t result_pdu[] = { 0x40, 0x01, 0x0, 0x0 }; - struct zoap_packet zpkt; - struct net_pkt *pkt; - struct net_buf *frag; - int result = TC_FAIL; - int r; - - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); - if (!pkt) { - TC_PRINT("Could not get packet from pool\n"); - goto done; - } - - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); - if (!frag) { - TC_PRINT("Could not get buffer from pool\n"); - goto done; - } - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&zpkt, pkt); - if (r) { - TC_PRINT("Could not initialize packet\n"); - goto done; - } - - zoap_header_set_version(&zpkt, 1); - zoap_header_set_type(&zpkt, ZOAP_TYPE_CON); - zoap_header_set_code(&zpkt, ZOAP_METHOD_GET); - zoap_header_set_id(&zpkt, 0); - - if (frag->len != sizeof(result_pdu)) { - TC_PRINT("Different size from the reference packet\n"); - goto done; - } - - if (memcmp(result_pdu, frag->data, frag->len)) { - TC_PRINT("Built packet doesn't match reference packet\n"); - goto done; - } - - result = TC_PASS; - -done: - net_pkt_unref(pkt); - - TC_END_RESULT(result); - - return result; -} - -static int test_build_simple_pdu(void) -{ - u8_t result_pdu[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', - 'n', 0xC1, 0x00, 0xFF, 'p', 'a', 'y', 'l', - 'o', 'a', 'd', 0x00 }; - struct zoap_packet zpkt; - struct net_pkt *pkt; - struct net_buf *frag; - const char token[] = "token"; - u8_t *appdata, payload[] = "payload"; - u16_t buflen; - u8_t format = 0; - int result = TC_FAIL; - int r; - - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); - if (!pkt) { - TC_PRINT("Could not get packet from pool\n"); - goto done; - } - - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); - if (!frag) { - TC_PRINT("Could not get buffer from pool\n"); - goto done; - } - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&zpkt, pkt); - if (r) { - TC_PRINT("Could not initialize packet\n"); - goto done; - } - - zoap_header_set_version(&zpkt, 1); - zoap_header_set_type(&zpkt, ZOAP_TYPE_NON_CON); - zoap_header_set_code(&zpkt, - ZOAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED); - zoap_header_set_id(&zpkt, 0x1234); - - r = zoap_header_set_token(&zpkt, (u8_t *)token, strlen(token)); - if (r) { - TC_PRINT("Could not set token\n"); - goto done; - } - - r = zoap_add_option(&zpkt, ZOAP_OPTION_CONTENT_FORMAT, - &format, sizeof(format)); - if (r) { - TC_PRINT("Could not add option\n"); - goto done; - } - - appdata = zoap_packet_get_payload(&zpkt, &buflen); - if (!appdata || buflen <= sizeof(payload)) { - TC_PRINT("Not enough space to insert payload\n"); - goto done; - } - - if (buflen != (ZOAP_BUF_SIZE - 4 - strlen(token) - 2 - 1)) { - /* - * The remaining length will be the buffer size less - * 4: basic CoAP header - * strlen(token): token length - * 2: options (content-format) - * 1: payload marker (added by zoap_packet_get_payload()) - */ - TC_PRINT("Invalid packet length\n"); - goto done; - } - - memcpy(appdata, payload, sizeof(payload)); - - r = zoap_packet_set_used(&zpkt, sizeof(payload)); - if (r) { - TC_PRINT("Failed to set the amount of bytes used\n"); - goto done; - } - - if (frag->len != sizeof(result_pdu)) { - TC_PRINT("Different size from the reference packet\n"); - goto done; - } - - if (memcmp(result_pdu, frag->data, frag->len)) { - TC_PRINT("Built packet doesn't match reference packet\n"); - goto done; - } - - result = TC_PASS; - -done: - net_pkt_unref(pkt); - - TC_END_RESULT(result); - - return result; -} - -static int test_build_no_size_for_options(void) -{ - struct zoap_packet zpkt; - struct net_pkt *pkt; - struct net_buf *frag; - const char token[] = "token"; - u8_t format = 0; - int result = TC_FAIL; - int r; - - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); - if (!pkt) { - TC_PRINT("Could not get packet from pool\n"); - goto done; - } - - frag = net_buf_alloc(&zoap_limited_data_pool, K_NO_WAIT); - if (!frag) { - TC_PRINT("Could not get buffer from pool\n"); - goto done; - } - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&zpkt, pkt); - if (r) { - TC_PRINT("Could not initialize packet\n"); - goto done; - } - - zoap_header_set_version(&zpkt, 1); - zoap_header_set_type(&zpkt, ZOAP_TYPE_NON_CON); - zoap_header_set_code(&zpkt, - ZOAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED); - zoap_header_set_id(&zpkt, 0x1234); - - r = zoap_header_set_token(&zpkt, (u8_t *)token, strlen(token)); - if (r) { - TC_PRINT("Could not set token\n"); - goto done; - } - - /* There won't be enough space for the option value */ - r = zoap_add_option(&zpkt, ZOAP_OPTION_CONTENT_FORMAT, - &format, sizeof(format)); - if (!r) { - TC_PRINT("Shouldn't have added the option, not enough space\n"); - goto done; - } - - result = TC_PASS; - -done: - net_pkt_unref(pkt); - - TC_END_RESULT(result); - - return result; -} - -static int test_parse_empty_pdu(void) -{ - u8_t pdu[] = { 0x40, 0x01, 0, 0 }; - struct net_pkt *pkt; - struct net_buf *frag; - struct zoap_packet zpkt; - u8_t ver, type, code; - u16_t id; - int result = TC_FAIL; - int r; - - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); - if (!pkt) { - TC_PRINT("Could not get packet from pool\n"); - goto done; - } - - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); - if (!frag) { - TC_PRINT("Could not get buffer from pool\n"); - goto done; - } - - net_pkt_frag_add(pkt, frag); - - memcpy(frag->data, pdu, sizeof(pdu)); - frag->len = sizeof(pdu); - - r = zoap_packet_parse(&zpkt, pkt); - if (r) { - TC_PRINT("Could not parse packet\n"); - goto done; - } - - ver = zoap_header_get_version(&zpkt); - type = zoap_header_get_type(&zpkt); - code = zoap_header_get_code(&zpkt); - id = zoap_header_get_id(&zpkt); - - if (ver != 1) { - TC_PRINT("Invalid version for parsed packet\n"); - goto done; - } - - if (type != ZOAP_TYPE_CON) { - TC_PRINT("Packet type doesn't match reference\n"); - goto done; - } - - if (code != ZOAP_METHOD_GET) { - TC_PRINT("Packet code doesn't match reference\n"); - goto done; - } - - if (id != 0) { - TC_PRINT("Packet id doesn't match reference\n"); - goto done; - } - - result = TC_PASS; - -done: - net_pkt_unref(pkt); - - TC_END_RESULT(result); - - return result; -} - -static int test_parse_simple_pdu(void) -{ - u8_t pdu[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', - 'n', 0x00, 0xc1, 0x00, 0xff, 'p', 'a', 'y', - 'l', 'o', 'a', 'd', 0x00 }; - struct zoap_packet zpkt; - struct net_pkt *pkt; - struct net_buf *frag; - struct zoap_option options[16]; - u8_t ver, type, code, tkl; - const u8_t *token, *payload; - u16_t id, len; - int result = TC_FAIL; - int r, count = 16; - - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); - if (!pkt) { - TC_PRINT("Could not get packet from pool\n"); - goto done; - } - - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); - if (!frag) { - TC_PRINT("Could not get buffer from pool\n"); - goto done; - } - - net_pkt_frag_add(pkt, frag); - - memcpy(frag->data, pdu, sizeof(pdu)); - frag->len = sizeof(pdu); - - r = zoap_packet_parse(&zpkt, pkt); - if (r) { - TC_PRINT("Could not parse packet\n"); - goto done; - } - - ver = zoap_header_get_version(&zpkt); - type = zoap_header_get_type(&zpkt); - code = zoap_header_get_code(&zpkt); - id = zoap_header_get_id(&zpkt); - - if (ver != 1) { - TC_PRINT("Invalid version for parsed packet\n"); - goto done; - } - - if (type != ZOAP_TYPE_NON_CON) { - TC_PRINT("Packet type doesn't match reference\n"); - goto done; - } - - if (code != ZOAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED) { - TC_PRINT("Packet code doesn't match reference\n"); - goto done; - } - - if (id != 0x1234) { - TC_PRINT("Packet id doesn't match reference\n"); - goto done; - } - - token = zoap_header_get_token(&zpkt, &tkl); - - if (!token) { - TC_PRINT("Couldn't extract token from packet\n"); - goto done; - } - - if (tkl != 5) { - TC_PRINT("Token length doesn't match reference\n"); - goto done; - } - - if (memcmp(token, "token", tkl)) { - TC_PRINT("Token value doesn't match the reference\n"); - goto done; - } - - count = zoap_find_options(&zpkt, ZOAP_OPTION_CONTENT_FORMAT, - options, count); - if (count != 1) { - TC_PRINT("Unexpected number of options in the packet\n"); - goto done; - } - - if (options[0].len != 1) { - TC_PRINT("Option length doesn't match the reference\n"); - goto done; - } - - if (((u8_t *)options[0].value)[0] != 0) { - TC_PRINT("Option value doesn't match the reference\n"); - goto done; - } - - /* Not existent */ - count = zoap_find_options(&zpkt, ZOAP_OPTION_ETAG, options, count); - if (count) { - TC_PRINT("There shouldn't be any ETAG option in the packet\n"); - goto done; - } - - payload = zoap_packet_get_payload(&zpkt, &len); - if (!payload || !len) { - TC_PRINT("There should be a payload in the packet\n"); - goto done; - } - - if (len != (strlen("payload") + 1)) { - TC_PRINT("Invalid payload in the packet\n"); - goto done; - } - - result = TC_PASS; - -done: - net_pkt_unref(pkt); - - TC_END_RESULT(result); - - return result; -} - -static int test_retransmit_second_round(void) -{ - struct zoap_packet zpkt, resp; - struct zoap_pending *pending, *resp_pending; - struct net_pkt *pkt, *resp_pkt = NULL; - struct net_buf *frag; - int result = TC_FAIL; - int r; - u16_t id; - - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); - if (!pkt) { - TC_PRINT("Could not get packet from pool\n"); - goto done; - } - - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); - if (!frag) { - TC_PRINT("Could not get buffer from pool\n"); - goto done; - } - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&zpkt, pkt); - if (r) { - TC_PRINT("Could not initialize packet\n"); - goto done; - } - - id = zoap_next_id(); - - zoap_header_set_version(&zpkt, 1); - zoap_header_set_type(&zpkt, ZOAP_TYPE_CON); - zoap_header_set_code(&zpkt, ZOAP_METHOD_GET); - zoap_header_set_id(&zpkt, id); - - pending = zoap_pending_next_unused(pendings, NUM_PENDINGS); - if (!pending) { - TC_PRINT("No free pending\n"); - goto done; - } - - r = zoap_pending_init(pending, &zpkt, (struct sockaddr *) &dummy_addr); - if (r) { - TC_PRINT("Could not initialize packet\n"); - goto done; - } - - /* We "send" the packet the first time here */ - if (!zoap_pending_cycle(pending)) { - TC_PRINT("Pending expired too early\n"); - goto done; - } - - /* We simulate that the first transmission got lost */ - - if (!zoap_pending_cycle(pending)) { - TC_PRINT("Pending expired too early\n"); - goto done; - } - - resp_pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); - if (!resp_pkt) { - TC_PRINT("Could not get packet from pool\n"); - goto done; - } - - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); - if (!frag) { - TC_PRINT("Could not get buffer from pool\n"); - goto done; - } - - net_pkt_frag_add(resp_pkt, frag); - - r = zoap_packet_init(&resp, resp_pkt); - if (r) { - TC_PRINT("Could not initialize packet\n"); - goto done; - } - - zoap_header_set_version(&resp, 1); - zoap_header_set_type(&resp, ZOAP_TYPE_ACK); - zoap_header_set_id(&resp, id); /* So it matches the request */ - - /* Now we get the ack from the remote side */ - resp_pending = zoap_pending_received(&resp, pendings, NUM_PENDINGS); - if (pending != resp_pending) { - TC_PRINT("Invalid pending %p should be %p\n", - resp_pending, pending); - goto done; - } - - resp_pending = zoap_pending_next_to_expire(pendings, NUM_PENDINGS); - if (resp_pending) { - TC_PRINT("There should be no active pendings\n"); - goto done; - } - - result = TC_PASS; - -done: - net_pkt_unref(pkt); - if (resp_pkt) { - net_pkt_unref(resp_pkt); - } - - TC_END_RESULT(result); - - return result; -} - -static bool ipaddr_cmp(const struct sockaddr *a, const struct sockaddr *b) -{ - if (a->sa_family != b->sa_family) { - return false; - } - - if (a->sa_family == AF_INET6) { - return net_ipv6_addr_cmp(&net_sin6(a)->sin6_addr, - &net_sin6(b)->sin6_addr); - } else if (a->sa_family == AF_INET) { - return net_ipv4_addr_cmp(&net_sin(a)->sin_addr, - &net_sin(b)->sin_addr); - } - - return false; -} - -static void server_notify_callback(struct zoap_resource *resource, - struct zoap_observer *observer) -{ - if (!ipaddr_cmp(&observer->addr, - (const struct sockaddr *) &dummy_addr)) { - TC_ERROR("The address of the observer doesn't match.\n"); - return; - } - - zoap_remove_observer(resource, observer); - - TC_PRINT("You should see this\n"); -} - -static int server_resource_1_get(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) -{ - struct zoap_packet response; - struct zoap_observer *observer; - struct net_pkt *pkt; - struct net_buf *frag; - char payload[] = "This is the payload"; - const u8_t *token; - u8_t tkl, *p; - u16_t id, len; - int r; - - if (!zoap_request_is_observe(request)) { - TC_PRINT("The request should enable observing\n"); - return -EINVAL; - } - - observer = zoap_observer_next_unused(observers, NUM_OBSERVERS); - if (!observer) { - TC_PRINT("There should be an available observer.\n"); - return -EINVAL; - } - - token = zoap_header_get_token(request, &tkl); - id = zoap_header_get_id(request); - - zoap_observer_init(observer, request, from); - - zoap_register_observer(resource, observer); - - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); - if (!pkt) { - TC_PRINT("Could not get packet from pool\n"); - return -ENOMEM; - } - - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); - if (!frag) { - TC_PRINT("Could not get buffer from pool\n"); - return -ENOMEM; - } - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&response, pkt); - if (r < 0) { - TC_PRINT("Unable to initialize packet.\n"); - return -EINVAL; - } - - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, ZOAP_TYPE_ACK); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_OK); - zoap_header_set_id(&response, id); - zoap_header_set_token(&response, token, tkl); - - zoap_add_option_int(&response, ZOAP_OPTION_OBSERVE, - resource->age); - - p = zoap_packet_get_payload(&response, &len); - if (p) { - memcpy(p, payload, sizeof(payload)); - } - - r = zoap_packet_set_used(&response, sizeof(payload)); - if (r < 0) { - TC_PRINT("Not enough room for payload.\n"); - return -EINVAL; - } - - resource->user_data = pkt; - - return 0; -} - -static int test_observer_server(void) -{ - u8_t valid_request_pdu[] = { - 0x45, 0x01, 0x12, 0x34, - 't', 'o', 'k', 'e', 'n', - 0x60, /* enable observe option */ - 0x51, 's', 0x01, '1', /* path */ - }; - u8_t not_found_request_pdu[] = { - 0x45, 0x01, 0x12, 0x34, - 't', 'o', 'k', 'e', 'n', - 0x60, /* enable observe option */ - 0x51, 's', 0x01, '2', /* path */ - }; - struct zoap_packet req; - struct net_pkt *pkt; - struct net_buf *frag; - int result = TC_FAIL; - int r; - - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); - if (!pkt) { - TC_PRINT("Could not get packet from pool\n"); - goto done; - } - - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); - if (!frag) { - TC_PRINT("Could not get buffer from pool\n"); - goto done; - } - - net_pkt_frag_add(pkt, frag); - - memcpy(frag->data, valid_request_pdu, sizeof(valid_request_pdu)); - frag->len = sizeof(valid_request_pdu); - - r = zoap_packet_parse(&req, pkt); - if (r) { - TC_PRINT("Could not initialize packet\n"); - goto done; - } - - r = zoap_handle_request(&req, server_resources, - (const struct sockaddr *) &dummy_addr); - if (r) { - TC_PRINT("Could not handle packet\n"); - goto done; - } - - /* Suppose some time passes */ - - r = zoap_resource_notify(&server_resources[0]); - if (r) { - TC_PRINT("Could not notify resource\n"); - goto done; - } - - net_pkt_unref(pkt); - - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); - if (!pkt) { - TC_PRINT("Could not get packet from pool\n"); - goto done; - } - - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); - if (!frag) { - TC_PRINT("Could not get buffer from pool\n"); - goto done; - } - - net_pkt_frag_add(pkt, frag); - - memcpy(frag->data, not_found_request_pdu, - sizeof(not_found_request_pdu)); - frag->len = sizeof(not_found_request_pdu); - - r = zoap_packet_parse(&req, pkt); - if (r) { - TC_PRINT("Could not initialize packet\n"); - goto done; - } - - r = zoap_handle_request(&req, server_resources, - (const struct sockaddr *) &dummy_addr); - if (r != -ENOENT) { - TC_PRINT("There should be no handler for this resource\n"); - goto done; - } - - result = TC_PASS; - -done: - net_pkt_unref(pkt); - - TC_END_RESULT(result); - - return result; -} - -static int resource_reply_cb(const struct zoap_packet *response, - struct zoap_reply *reply, - const struct sockaddr *from) -{ - TC_PRINT("You should see this\n"); - - return 0; -} - -static int test_observer_client(void) -{ - struct zoap_packet req, rsp; - struct zoap_reply *reply; - struct net_pkt *pkt, *rsp_pkt = NULL; - struct net_buf *frag; - const char token[] = "rndtoken"; - const char * const *p; - int observe = 0; - int result = TC_FAIL; - int r; - - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); - if (!pkt) { - TC_PRINT("Could not get packet from pool\n"); - goto done; - } - - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); - if (!frag) { - TC_PRINT("Could not get buffer from pool\n"); - goto done; - } - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&req, pkt); - if (r < 0) { - TC_PRINT("Unable to initialize request\n"); - goto done; - } - - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&req, 1); - zoap_header_set_type(&req, ZOAP_TYPE_CON); - zoap_header_set_code(&req, ZOAP_METHOD_GET); - zoap_header_set_id(&req, zoap_next_id()); - zoap_header_set_token(&req, - (const u8_t *) token, strlen(token)); - - /* Enable observing the resource. */ - r = zoap_add_option_int(&req, ZOAP_OPTION_OBSERVE, - observe); - if (r < 0) { - TC_PRINT("Unable to add option to request.\n"); - goto done; - } - - for (p = server_resource_1_path; p && *p; p++) { - r = zoap_add_option(&req, ZOAP_OPTION_URI_PATH, - *p, strlen(*p)); - if (r < 0) { - TC_PRINT("Unable to add option to request.\n"); - goto done; - } - } - - reply = zoap_reply_next_unused(replies, NUM_REPLIES); - if (!reply) { - printk("No resources for waiting for replies.\n"); - goto done; - } - - zoap_reply_init(reply, &req); - reply->reply = resource_reply_cb; - - /* Server side, not interesting for this test */ - r = zoap_packet_parse(&req, pkt); - if (r) { - TC_PRINT("Could not initialize packet\n"); - goto done; - } - - r = zoap_handle_request(&req, server_resources, - (const struct sockaddr *) &dummy_addr); - if (r) { - TC_PRINT("Could not handle packet\n"); - goto done; - } - - /* We cheat, and communicate using the resource's user_data */ - rsp_pkt = server_resources[0].user_data; - - /* The uninteresting part ends here */ - - /* 'rsp_pkt' contains the response now */ - - r = zoap_packet_parse(&rsp, rsp_pkt); - if (r) { - TC_PRINT("Could not initialize packet\n"); - goto done; - } - - reply = zoap_response_received(&rsp, - (const struct sockaddr *) &dummy_addr, - replies, NUM_REPLIES); - if (!reply) { - TC_PRINT("Couldn't find a matching waiting reply\n"); - goto done; - } - - result = TC_PASS; - -done: - net_pkt_unref(pkt); - if (rsp_pkt) { - net_pkt_unref(rsp_pkt); - } - - TC_END_RESULT(result); - - return result; -} - -static int test_block_size(void) -{ - struct zoap_block_context req_ctx, rsp_ctx; - struct zoap_packet req; - struct net_pkt *pkt = NULL; - struct net_buf *frag; - const char token[] = "rndtoken"; - u8_t *payload; - u16_t len; - int result = TC_FAIL; - int r; - - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); - if (!pkt) { - TC_PRINT("Could not get packet from pool\n"); - goto done; - } - - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); - if (!frag) { - TC_PRINT("Could not get buffer from pool\n"); - goto done; - } - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&req, pkt); - if (r < 0) { - TC_PRINT("Unable to initialize request\n"); - goto done; - } - - zoap_block_transfer_init(&req_ctx, ZOAP_BLOCK_32, 127); - - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&req, 1); - zoap_header_set_type(&req, ZOAP_TYPE_CON); - zoap_header_set_code(&req, ZOAP_METHOD_POST); - zoap_header_set_id(&req, zoap_next_id()); - zoap_header_set_token(&req, - (const u8_t *) token, strlen(token)); - - zoap_add_block1_option(&req, &req_ctx); - zoap_add_size1_option(&req, &req_ctx); - - payload = zoap_packet_get_payload(&req, &len); - if (!payload) { - TC_PRINT("There's no space for payload in the packet\n"); - goto done; - } - - memset(payload, 0xFE, zoap_block_size_to_bytes(ZOAP_BLOCK_32)); - - zoap_packet_set_used(&req, zoap_block_size_to_bytes(ZOAP_BLOCK_32)); - - zoap_block_transfer_init(&rsp_ctx, ZOAP_BLOCK_1024, 0); - - r = zoap_update_from_block(&req, &rsp_ctx); - if (r < 0) { - TC_PRINT("Couldn't parse Block options\n"); - goto done; - } - - if (rsp_ctx.block_size != ZOAP_BLOCK_32) { - TC_PRINT("Couldn't get block size from request\n"); - goto done; - } - - if (rsp_ctx.current != 0) { - TC_PRINT("Couldn't get the current block size position\n"); - goto done; - } - - if (rsp_ctx.total_size != 127) { - TC_PRINT("Couldn't packet total size from request\n"); - goto done; - } - - /* Suppose that pkt was sent */ - net_pkt_unref(pkt); - - /* Let's try the second packet */ - zoap_next_block(&req, &req_ctx); - - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); - if (!pkt) { - TC_PRINT("Could not get packet from pool\n"); - goto done; - } - - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); - if (!frag) { - TC_PRINT("Could not get buffer from pool\n"); - goto done; - } - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&req, pkt); - if (r < 0) { - TC_PRINT("Unable to initialize request\n"); - goto done; - } - - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&req, 1); - zoap_header_set_type(&req, ZOAP_TYPE_CON); - zoap_header_set_code(&req, ZOAP_METHOD_POST); - zoap_header_set_id(&req, zoap_next_id()); - zoap_header_set_token(&req, - (const u8_t *) token, strlen(token)); - - zoap_add_block1_option(&req, &req_ctx); - - memset(payload, 0xFE, ZOAP_BLOCK_32); - - zoap_packet_set_used(&req, zoap_block_size_to_bytes(ZOAP_BLOCK_32)); - - r = zoap_update_from_block(&req, &rsp_ctx); - if (r < 0) { - TC_PRINT("Couldn't parse Block options\n"); - goto done; - } - - if (rsp_ctx.block_size != ZOAP_BLOCK_32) { - TC_PRINT("Couldn't get block size from request\n"); - goto done; - } - - if (rsp_ctx.current != zoap_block_size_to_bytes(ZOAP_BLOCK_32)) { - TC_PRINT("Couldn't get the current block size position\n"); - goto done; - } - - if (rsp_ctx.total_size != 127) { - TC_PRINT("Couldn't packet total size from request\n"); - goto done; - } - - result = TC_PASS; - -done: - net_pkt_unref(pkt); - - TC_END_RESULT(result); - - return result; -} - -static int test_match_path_uri(void) -{ - int result = TC_FAIL; - const char * const resource_path[] = { - "s", - "1", - "foobar", - "foobar3a", - "foobar3", - "devnull", - NULL - }; - const char *uri; - - uri = "/k"; - if (_zoap_match_path_uri(resource_path, uri, strlen(uri))) { - TC_PRINT("Matching %s failed\n", uri); - goto out; - } - - uri = "/s"; - if (!_zoap_match_path_uri(resource_path, uri, strlen(uri))) { - TC_PRINT("Matching %s failed\n", uri); - goto out; - } - - uri = "/foobar"; - if (!_zoap_match_path_uri(resource_path, uri, strlen(uri))) { - TC_PRINT("Matching %s failed\n", uri); - goto out; - } - - uri = "/foobar2"; - if (_zoap_match_path_uri(resource_path, uri, strlen(uri))) { - TC_PRINT("Matching %s failed\n", uri); - goto out; - } - - uri = "/foobar*"; - if (!_zoap_match_path_uri(resource_path, uri, strlen(uri))) { - TC_PRINT("Matching %s failed\n", uri); - goto out; - } - - uri = "/foobar3*"; - if (!_zoap_match_path_uri(resource_path, uri, strlen(uri))) { - TC_PRINT("Matching %s failed\n", uri); - goto out; - } - - uri = "/devnull*"; - if (_zoap_match_path_uri(resource_path, uri, strlen(uri))) { - TC_PRINT("Matching %s failed\n", uri); - goto out; - } - - result = TC_PASS; - -out: - TC_END_RESULT(result); - - return result; - -} - -static const struct { - const char *name; - int (*func)(void); -} tests[] = { - { "Build empty PDU test", test_build_empty_pdu, }, - { "Build simple PDU test", test_build_simple_pdu, }, - { "No size for options test", test_build_no_size_for_options, }, - { "Parse emtpy PDU test", test_parse_empty_pdu, }, - { "Parse simple PDU test", test_parse_simple_pdu, }, - { "Test retransmission", test_retransmit_second_round, }, - { "Test observer server", test_observer_server, }, - { "Test observer client", test_observer_client, }, - { "Test block sized transfer", test_block_size, }, - { "Test match path uri", test_match_path_uri, }, -}; - -int main(int argc, char *argv[]) -{ - int count, pass, result; - - TC_START("Test Zoap CoAP PDU parsing and building"); - - for (count = 0, pass = 0; count < ARRAY_SIZE(tests); count++) { - if (tests[count].func() == TC_PASS) { - pass++; - } - } - - TC_PRINT("%d / %d tests passed\n", pass, count); - - result = pass == count ? TC_PASS : TC_FAIL; - - TC_END_REPORT(result); - - return 0; -} From def0d457499d72825918a36e39a4a15742d86294 Mon Sep 17 00:00:00 2001 From: Ravi kumar Veeramally Date: Mon, 28 Aug 2017 13:56:38 +0300 Subject: [PATCH 21/37] net: samples: Modify leds_demo to use new CoAP api's Signed-off-by: Ravi kumar Veeramally --- samples/net/leds_demo/prj.conf | 2 +- samples/net/leds_demo/prj_802154.conf | 2 +- samples/net/leds_demo/src/leds-demo.c | 335 ++++++++++++++------------ 3 files changed, 188 insertions(+), 151 deletions(-) diff --git a/samples/net/leds_demo/prj.conf b/samples/net/leds_demo/prj.conf index be2d0dbdd0650..708b60c247755 100644 --- a/samples/net/leds_demo/prj.conf +++ b/samples/net/leds_demo/prj.conf @@ -7,6 +7,6 @@ CONFIG_SYS_LOG=y CONFIG_SYS_LOG_SHOW_COLOR=y CONFIG_RANDOM_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_ZOAP=y +CONFIG_COAP=y CONFIG_NET_APP_SETTINGS=y CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" diff --git a/samples/net/leds_demo/prj_802154.conf b/samples/net/leds_demo/prj_802154.conf index 083e365e49777..ce29dda54faf3 100644 --- a/samples/net/leds_demo/prj_802154.conf +++ b/samples/net/leds_demo/prj_802154.conf @@ -8,6 +8,6 @@ CONFIG_NET_LOG=y CONFIG_NET_UDP=y CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_IEEE802154_CC2520=y -CONFIG_ZOAP=y +CONFIG_COAP=y CONFIG_NET_APP_SETTINGS=y CONFIG_NET_APP_IEEE802154_CHANNEL=20 diff --git a/samples/net/leds_demo/src/leds-demo.c b/samples/net/leds_demo/src/leds-demo.c index b42b884146c8d..c82970a246b17 100644 --- a/samples/net/leds_demo/src/leds-demo.c +++ b/samples/net/leds_demo/src/leds-demo.c @@ -5,7 +5,7 @@ */ #if 1 -#define SYS_LOG_DOMAIN "zoap-server" +#define SYS_LOG_DOMAIN "coap-server" #define NET_SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG #define NET_LOG_ENABLED 1 #endif @@ -26,8 +26,8 @@ #include -#include -#include +#include +#include #define MY_COAP_PORT 5683 @@ -56,6 +56,54 @@ static const char led_toggle_off[] = "LED Toggle OFF\n"; static bool fake_led; +static void get_from_ip_addr(struct coap_packet *cpkt, + struct sockaddr_in6 *from) +{ + struct net_udp_hdr hdr, *udp_hdr; + + udp_hdr = net_udp_get_hdr(cpkt->pkt, &hdr); + if (!udp_hdr) { + return; + } + + net_ipaddr_copy(&from->sin6_addr, &NET_IPV6_HDR(cpkt->pkt)->src); + + from->sin6_port = udp_hdr->src_port; + from->sin6_family = AF_INET6; +} + +static int well_known_core_get(struct coap_resource *resource, + struct coap_packet *request) +{ + struct coap_packet response; + struct sockaddr_in6 from; + struct net_pkt *pkt; + struct net_buf *frag; + int r; + + NET_DBG(""); + + pkt = net_pkt_get_tx(context, K_FOREVER); + frag = net_pkt_get_data(context, K_FOREVER); + net_pkt_frag_add(pkt, frag); + + r = coap_well_known_core_get(resource, request, &response, pkt); + if (r < 0) { + net_pkt_unref(response.pkt); + return r; + } + + get_from_ip_addr(request, &from); + r = net_context_sendto(response.pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); + if (r < 0) { + net_pkt_unref(response.pkt); + } + + return r; +} + static bool read_led(void) { u32_t led = 0; @@ -83,19 +131,18 @@ static void write_led(bool led) gpio_pin_write(led0, LED_PIN, !led); } -static int led_get(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) +static int led_get(struct coap_resource *resource, + struct coap_packet *request) { struct net_pkt *pkt; struct net_buf *frag; - struct zoap_packet response; + struct sockaddr_in6 from; + struct coap_packet response; const char *str; - u8_t *payload; u16_t len, id; int r; - id = zoap_header_get_id(request); + id = coap_header_get_id(request); pkt = net_pkt_get_tx(context, K_FOREVER); if (!pkt) { @@ -109,38 +156,35 @@ static int led_get(struct zoap_resource *resource, net_pkt_frag_add(pkt, frag); - r = zoap_packet_init(&response, pkt); + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + 0, NULL, COAP_RESPONSE_CODE_CONTENT, id); if (r < 0) { return -EINVAL; } - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, ZOAP_TYPE_ACK); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CONTENT); - zoap_header_set_id(&response, id); - - payload = zoap_packet_get_payload(&response, &len); - if (!payload) { - return -EINVAL; - } - if (read_led()) { str = led_on; - r = sizeof(led_on); + len = sizeof(led_on); } else { str = led_off; - r = sizeof(led_off); + len = sizeof(led_off); } - memcpy(payload, str, r); + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } - r = zoap_packet_set_used(&response, r); - if (r) { + r = coap_packet_append_payload(&response, (u8_t *)str, len); + if (r < 0) { + net_pkt_unref(pkt); return -EINVAL; } - r = net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), + get_from_ip_addr(request, &from); + r = net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), NULL, 0, NULL, NULL); if (r < 0) { net_pkt_unref(pkt); @@ -149,26 +193,42 @@ static int led_get(struct zoap_resource *resource, return r; } -static int led_post(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) +static int led_post(struct coap_resource *resource, + struct coap_packet *request) { struct net_pkt *pkt; struct net_buf *frag; - struct zoap_packet response; + struct sockaddr_in6 from; + struct coap_packet response; const char *str; - u8_t *payload; - u16_t len, id; + u8_t payload; + u8_t len; + u16_t id; + u16_t offset; u32_t led; int r; - payload = zoap_packet_get_payload(request, &len); - if (!payload) { - printk("packet without payload"); + led = 0; + frag = net_frag_skip(request->frag, request->offset, &offset, + request->hdr_len + request->opt_len); + if (!frag && offset == 0xffff) { return -EINVAL; } - id = zoap_header_get_id(request); + frag = net_frag_read_u8(frag, offset, &offset, &payload); + if (!frag && offset == 0xffff) { + printk("packet without payload, so toggle the led"); + led = read_led(); + led = !led; + } else { + if (payload == 0x31) { + led = 1; + } + } + + write_led(led); + + id = coap_header_get_id(request); pkt = net_pkt_get_tx(context, K_FOREVER); if (!pkt) { @@ -182,44 +242,35 @@ static int led_post(struct zoap_resource *resource, net_pkt_frag_add(pkt, frag); - r = zoap_packet_init(&response, pkt); + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + 0, NULL, COAP_RESPONSE_CODE_CONTENT, id); if (r < 0) { return -EINVAL; } - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, ZOAP_TYPE_ACK); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CONTENT); - zoap_header_set_id(&response, id); - - payload = zoap_packet_get_payload(&response, &len); - if (!payload) { - return -EINVAL; - } - - led = read_led(); - - led = !led; - - write_led(led); - if (led) { str = led_toggle_on; - r = sizeof(led_toggle_on); + len = sizeof(led_toggle_on); } else { str = led_toggle_off; - r = sizeof(led_toggle_off); + len = sizeof(led_toggle_off); } - memcpy(payload, str, r); + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } - r = zoap_packet_set_used(&response, r); - if (r) { + r = coap_packet_append_payload(&response, (u8_t *)str, len); + if (r < 0) { + net_pkt_unref(pkt); return -EINVAL; } - r = net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), + get_from_ip_addr(request, &from); + r = net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), NULL, 0, NULL, NULL); if (r < 0) { net_pkt_unref(pkt); @@ -228,31 +279,42 @@ static int led_post(struct zoap_resource *resource, return r; } -static int led_put(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) +static int led_put(struct coap_resource *resource, + struct coap_packet *request) { struct net_pkt *pkt; struct net_buf *frag; - struct zoap_packet response; + struct sockaddr_in6 from; + struct coap_packet response; const char *str; - u8_t *payload; - u16_t len, id; + u8_t payload; + u8_t len; + u16_t id; + u16_t offset; u32_t led; int r; - payload = zoap_packet_get_payload(request, &len); - if (!payload) { - printk("packet without payload"); + led = 0; + frag = net_frag_skip(request->frag, request->offset, &offset, + request->hdr_len + request->opt_len); + if (!frag && offset == 0xffff) { return -EINVAL; } - led = 0; - if (len > 0 && payload[0] == '1') { - led = 1; + frag = net_frag_read_u8(frag, offset, &offset, &payload); + if (!frag && offset == 0xffff) { + printk("packet without payload, so toggle the led"); + led = read_led(); + led = !led; + } else { + if (payload == 0x31) { + led = 1; + } } - id = zoap_header_get_id(request); + write_led(led); + + id = coap_header_get_id(request); pkt = net_pkt_get_tx(context, K_FOREVER); if (!pkt) { @@ -266,40 +328,35 @@ static int led_put(struct zoap_resource *resource, net_pkt_frag_add(pkt, frag); - r = zoap_packet_init(&response, pkt); + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + 0, NULL, COAP_RESPONSE_CODE_CHANGED, id); if (r < 0) { return -EINVAL; } - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, ZOAP_TYPE_ACK); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CHANGED); - zoap_header_set_id(&response, id); - - payload = zoap_packet_get_payload(&response, &len); - if (!payload) { - return -EINVAL; - } - - write_led(led); - if (led) { str = led_on; - r = sizeof(led_on); + len = sizeof(led_on); } else { str = led_off; - r = sizeof(led_off); + len = sizeof(led_off); } - memcpy(payload, str, r); + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } - r = zoap_packet_set_used(&response, r); - if (r) { + r = coap_packet_append_payload(&response, (u8_t *)str, len); + if (r < 0) { + net_pkt_unref(pkt); return -EINVAL; } - r = net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), + get_from_ip_addr(request, &from); + r = net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), NULL, 0, NULL, NULL); if (r < 0) { net_pkt_unref(pkt); @@ -308,19 +365,18 @@ static int led_put(struct zoap_resource *resource, return r; } -static int dummy_get(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) +static int dummy_get(struct coap_resource *resource, + struct coap_packet *request) { static const char dummy_str[] = "Just a test\n"; struct net_pkt *pkt; struct net_buf *frag; - struct zoap_packet response; - u8_t *payload; - u16_t len, id; + struct sockaddr_in6 from; + struct coap_packet response; + u16_t id; int r; - id = zoap_header_get_id(request); + id = coap_header_get_id(request); pkt = net_pkt_get_tx(context, K_FOREVER); if (!pkt) { @@ -334,30 +390,28 @@ static int dummy_get(struct zoap_resource *resource, net_pkt_frag_add(pkt, frag); - r = zoap_packet_init(&response, pkt); + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + 0, NULL, COAP_RESPONSE_CODE_CONTENT, id); if (r < 0) { return -EINVAL; } - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, ZOAP_TYPE_ACK); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CONTENT); - zoap_header_set_id(&response, id); - - payload = zoap_packet_get_payload(&response, &len); - if (!payload) { + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + net_pkt_unref(pkt); return -EINVAL; } - memcpy(payload, dummy_str, sizeof(dummy_str)); - - r = zoap_packet_set_used(&response, sizeof(dummy_str)); - if (r) { + r = coap_packet_append_payload(&response, (u8_t *)dummy_str, + sizeof(dummy_str)); + if (r < 0) { + net_pkt_unref(pkt); return -EINVAL; } - r = net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), + get_from_ip_addr(request, &from); + r = net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), NULL, 0, NULL, NULL); if (r < 0) { net_pkt_unref(pkt); @@ -378,19 +432,24 @@ static const char * const dummy_attributes[] = { "rt=dummy", NULL }; -static struct zoap_resource resources[] = { - ZOAP_WELL_KNOWN_CORE_RESOURCE, +static struct coap_resource resources[] = { + { .get = well_known_core_get, + .post = NULL, + .put = NULL, + .path = COAP_WELL_KNOWN_CORE_PATH, + .user_data = NULL, + }, { .get = led_get, .post = led_post, .put = led_put, .path = led_default_path, - .user_data = &((struct zoap_core_metadata) { + .user_data = &((struct coap_core_metadata) { .attributes = led_default_attributes, }), }, { .get = dummy_get, .path = dummy_path, - .user_data = &((struct zoap_core_metadata) { + .user_data = &((struct coap_core_metadata) { .attributes = dummy_attributes, }), }, @@ -402,46 +461,24 @@ static void udp_receive(struct net_context *context, int status, void *user_data) { - struct zoap_packet request; - struct sockaddr_in6 from; - struct net_udp_hdr hdr, *udp_hdr; - int r, header_len; - - net_ipaddr_copy(&from.sin6_addr, &NET_IPV6_HDR(pkt)->src); - - udp_hdr = net_udp_get_hdr(pkt, &hdr); - if (!udp_hdr) { - printk("Invalid UDP data received\n"); - net_pkt_unref(pkt); - return; - } - - from.sin6_port = udp_hdr->src_port; - from.sin6_family = AF_INET6; - - /* - * zoap expects that buffer->data starts at the - * beginning of the CoAP header - */ - header_len = net_pkt_appdata(pkt) - pkt->frags->data; - net_buf_pull(pkt->frags, header_len); + struct coap_packet request; + struct coap_option options[16] = { 0 }; + u8_t opt_num = 16; + int r; - r = zoap_packet_parse(&request, pkt); + r = coap_packet_parse(&request, pkt, options, opt_num); if (r < 0) { NET_ERR("Invalid data received (%d)\n", r); net_pkt_unref(pkt); return; } - r = zoap_handle_request(&request, resources, - (const struct sockaddr *) &from); - - net_pkt_unref(pkt); - + r = coap_handle_request(&request, resources, options, opt_num); if (r < 0) { NET_ERR("No handler for such request (%d)\n", r); - return; } + + net_pkt_unref(pkt); } static bool join_coap_multicast_group(void) From 6b6077eb503abdc2ffde265a5d8eb99f60765f48 Mon Sep 17 00:00:00 2001 From: Ravi kumar Veeramally Date: Mon, 28 Aug 2017 13:59:16 +0300 Subject: [PATCH 22/37] net: samples: Modify zoap_server to new CoAP api's Signed-off-by: Ravi kumar Veeramally --- doc/subsystems/networking/overview.rst | 4 +- .../net/{zoap_server => coap_server}/Makefile | 0 .../{zoap_server => coap_server}/README.rst | 4 +- .../net/{zoap_server => coap_server}/prj.conf | 2 +- .../{zoap_server => coap_server}/prj_bt.conf | 2 +- .../prj_cc2520.conf | 2 +- .../{zoap_server => coap_server}/sample.yaml | 0 .../{zoap_server => coap_server}/src/Makefile | 2 +- samples/net/coap_server/src/coap-server.c | 1310 +++++++++++++++++ .../src/ieee802154_settings.c | 0 samples/net/zoap_server/src/zoap-server.c | 1289 ---------------- 11 files changed, 1318 insertions(+), 1297 deletions(-) rename samples/net/{zoap_server => coap_server}/Makefile (100%) rename samples/net/{zoap_server => coap_server}/README.rst (96%) rename samples/net/{zoap_server => coap_server}/prj.conf (95%) rename samples/net/{zoap_server => coap_server}/prj_bt.conf (96%) rename samples/net/{zoap_server => coap_server}/prj_cc2520.conf (96%) rename samples/net/{zoap_server => coap_server}/sample.yaml (100%) rename samples/net/{zoap_server => coap_server}/src/Makefile (92%) create mode 100644 samples/net/coap_server/src/coap-server.c rename samples/net/{zoap_server => coap_server}/src/ieee802154_settings.c (100%) delete mode 100644 samples/net/zoap_server/src/zoap-server.c diff --git a/doc/subsystems/networking/overview.rst b/doc/subsystems/networking/overview.rst index 7366736060e61..5bdfc418c1969 100644 --- a/doc/subsystems/networking/overview.rst +++ b/doc/subsystems/networking/overview.rst @@ -63,8 +63,8 @@ can be disabled if not needed. A sample :ref:`mqtt-publisher-sample` client application for MQTT v3.1.1 is implemented. -* **CoAP** Constrained Application Protocol (RFC 7252) is supported. Both - Both :ref:`zoap-client-sample` and :ref:`zoap-server-sample` sample +* **CoAP** Constrained Application Protocol (RFC 7252) is supported. + Both :ref:`zoap-client-sample` and :ref:`coap-server-sample` sample applications are implemented. A :ref:`coap-client-sample` and :ref:`coap-server-sample` using DTLS (Datagram Transport Layer Security) (RFC 6347) are also implemented. diff --git a/samples/net/zoap_server/Makefile b/samples/net/coap_server/Makefile similarity index 100% rename from samples/net/zoap_server/Makefile rename to samples/net/coap_server/Makefile diff --git a/samples/net/zoap_server/README.rst b/samples/net/coap_server/README.rst similarity index 96% rename from samples/net/zoap_server/README.rst rename to samples/net/coap_server/README.rst index 556484f324966..46fc3ebc7d1f6 100644 --- a/samples/net/zoap_server/README.rst +++ b/samples/net/coap_server/README.rst @@ -1,4 +1,4 @@ -.. _zoap-server-sample: +.. _coap-server-sample: CoAP Server ########### @@ -27,7 +27,7 @@ The sample exports the following resources: /large-update These resources allow a good part of the ETSI test cases to be run -against zoap-server. +against coap-server. Building And Running ******************** diff --git a/samples/net/zoap_server/prj.conf b/samples/net/coap_server/prj.conf similarity index 95% rename from samples/net/zoap_server/prj.conf rename to samples/net/coap_server/prj.conf index e073b4a7c26dc..d9c6f81285191 100644 --- a/samples/net/zoap_server/prj.conf +++ b/samples/net/coap_server/prj.conf @@ -6,7 +6,7 @@ CONFIG_SYS_LOG=y CONFIG_SYS_LOG_SHOW_COLOR=y CONFIG_RANDOM_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_ZOAP=y +CONFIG_COAP=y CONFIG_NET_APP_SETTINGS=y CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=5 diff --git a/samples/net/zoap_server/prj_bt.conf b/samples/net/coap_server/prj_bt.conf similarity index 96% rename from samples/net/zoap_server/prj_bt.conf rename to samples/net/coap_server/prj_bt.conf index 00817826a1b5a..9aaf4e8819e57 100644 --- a/samples/net/zoap_server/prj_bt.conf +++ b/samples/net/coap_server/prj_bt.conf @@ -17,4 +17,4 @@ CONFIG_SYS_LOG=y CONFIG_SYS_LOG_SHOW_COLOR=y CONFIG_RANDOM_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_ZOAP=y +CONFIG_COAP=y diff --git a/samples/net/zoap_server/prj_cc2520.conf b/samples/net/coap_server/prj_cc2520.conf similarity index 96% rename from samples/net/zoap_server/prj_cc2520.conf rename to samples/net/coap_server/prj_cc2520.conf index e63cd48e3d22d..669621bc0fe6c 100644 --- a/samples/net/zoap_server/prj_cc2520.conf +++ b/samples/net/coap_server/prj_cc2520.conf @@ -7,7 +7,7 @@ CONFIG_NET_LOG=y CONFIG_NET_UDP=y CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_IEEE802154_CC2520=y -CONFIG_ZOAP=y +CONFIG_COAP=y CONFIG_NET_APP_SETTINGS=y CONFIG_NET_APP_IEEE802154_CHANNEL=20 CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" diff --git a/samples/net/zoap_server/sample.yaml b/samples/net/coap_server/sample.yaml similarity index 100% rename from samples/net/zoap_server/sample.yaml rename to samples/net/coap_server/sample.yaml diff --git a/samples/net/zoap_server/src/Makefile b/samples/net/coap_server/src/Makefile similarity index 92% rename from samples/net/zoap_server/src/Makefile rename to samples/net/coap_server/src/Makefile index 2b65cdce545c3..abbe66864e969 100644 --- a/samples/net/zoap_server/src/Makefile +++ b/samples/net/coap_server/src/Makefile @@ -3,7 +3,7 @@ ccflags-y +=-I${ZEPHYR_BASE}/samples/net/common/ ccflags-y +=-DNET_TESTING_SERVER=1 endif -obj-y = zoap-server.o +obj-y = coap-server.o ifeq ($(CONFIG_NET_L2_IEEE802154), y) ccflags-y +=-I${ZEPHYR_BASE}/samples/net/common/ diff --git a/samples/net/coap_server/src/coap-server.c b/samples/net/coap_server/src/coap-server.c new file mode 100644 index 0000000000000..4d092f99f08f3 --- /dev/null +++ b/samples/net/coap_server/src/coap-server.c @@ -0,0 +1,1310 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if 1 +#define SYS_LOG_DOMAIN "coap-server" +#define SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG +#define NET_LOG_ENABLED 1 +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define MY_COAP_PORT 5683 + +#define STACKSIZE 2000 + +/* FIXME */ +#define BLOCK_WISE_TRANSFER_SIZE_GET 2048 + +#define ALL_NODES_LOCAL_COAP_MCAST \ + { { { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xfd } } } + +#define MY_IP6ADDR \ + { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } } + +#define NUM_OBSERVERS 3 + +#define NUM_PENDINGS 3 + +static struct net_context *context; + +static const u8_t plain_text_format; + +static struct coap_observer observers[NUM_OBSERVERS]; + +static struct coap_pending pendings[NUM_PENDINGS]; + +static struct net_context *context; + +static struct k_delayed_work observer_work; + +static int obs_counter; + +static struct coap_resource *resource_to_notify; + +struct k_delayed_work retransmit_work; + +static void get_from_ip_addr(struct coap_packet *cpkt, + struct sockaddr_in6 *from) +{ + struct net_udp_hdr hdr, *udp_hdr; + + udp_hdr = net_udp_get_hdr(cpkt->pkt, &hdr); + if (!udp_hdr) { + return; + } + + net_ipaddr_copy(&from->sin6_addr, &NET_IPV6_HDR(cpkt->pkt)->src); + from->sin6_port = udp_hdr->src_port; + from->sin6_family = AF_INET6; +} + +static int well_known_core_get(struct coap_resource *resource, + struct coap_packet *request) +{ + struct coap_packet response; + struct sockaddr_in6 from; + struct net_pkt *pkt; + struct net_buf *frag; + int r; + + NET_DBG(""); + + pkt = net_pkt_get_tx(context, K_FOREVER); + frag = net_pkt_get_data(context, K_FOREVER); + + net_pkt_frag_add(pkt, frag); + + r = coap_well_known_core_get(resource, request, &response, pkt); + if (r < 0) { + net_pkt_unref(response.pkt); + return r; + } + + get_from_ip_addr(request, &from); + r = net_context_sendto(response.pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); + if (r < 0) { + net_pkt_unref(response.pkt); + } + + return r; +} + +static int test_del(struct coap_resource *resource, + struct coap_packet *request) +{ + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + u8_t tkl, code, type; + u8_t token[8]; + u16_t id; + int r; + + get_from_ip_addr(request, &from); + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + NET_INFO("*******\n"); + NET_INFO("type: %u code %u id %u\n", type, code, id); + NET_INFO("*******\n"); + + pkt = net_pkt_get_tx(context, K_FOREVER); + frag = net_pkt_get_data(context, K_FOREVER); + + net_pkt_frag_add(pkt, frag); + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_NON_CON; + } + + r = coap_packet_init(&response, pkt, 1, type, + tkl, (u8_t *)token, + COAP_RESPONSE_CODE_DELETED, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + return net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); +} + +static int test_put(struct coap_resource *resource, + struct coap_packet *request) +{ + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + u8_t code, type, tkl; + u8_t token[8]; + u16_t id; + int r; + + /* TODO: Check for payload, empty payload is an error case. */ + + get_from_ip_addr(request, &from); + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + NET_INFO("*******\n"); + NET_INFO("type: %u code %u id %u\n", type, code, id); + NET_INFO("*******\n"); + + pkt = net_pkt_get_tx(context, K_FOREVER); + frag = net_pkt_get_data(context, K_FOREVER); + + net_pkt_frag_add(pkt, frag); + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_NON_CON; + } + + r = coap_packet_init(&response, pkt, 1, type, + tkl, (u8_t *)token, + COAP_RESPONSE_CODE_CHANGED, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + return net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); +} + +static int test_post(struct coap_resource *resource, + struct coap_packet *request) +{ + static const char * const location_path[] = { "location1", + "location2", + "location3", + NULL }; + const char * const *p; + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + u8_t code, type, tkl; + u8_t token[8]; + u16_t id; + int r; + + /* TODO: Check for payload, empty payload is an error case. */ + + get_from_ip_addr(request, &from); + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + NET_INFO("*******\n"); + NET_INFO("type: %u code %u id %u\n", type, code, id); + NET_INFO("*******\n"); + + pkt = net_pkt_get_tx(context, K_FOREVER); + frag = net_pkt_get_data(context, K_FOREVER); + + net_pkt_frag_add(pkt, frag); + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_NON_CON; + } + + r = coap_packet_init(&response, pkt, 1, type, + tkl, (u8_t *)token, + COAP_RESPONSE_CODE_CREATED, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + for (p = location_path; *p; p++) { + r = coap_packet_append_option(&response, + COAP_OPTION_LOCATION_PATH, + *p, strlen(*p)); + if (r < 0) { + return -EINVAL; + } + } + + return net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); +} + +static int location_query_post(struct coap_resource *resource, + struct coap_packet *request) +{ + static const char *const location_query[] = { "first=1", + "second=2", + NULL }; + const char * const *p; + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + u8_t code, type, tkl; + u8_t token[8]; + u16_t id; + int r; + + /* TODO: Check for payload, empty payload is an error case. */ + + get_from_ip_addr(request, &from); + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + NET_INFO("*******\n"); + NET_INFO("type: %u code %u id %u\n", type, code, id); + NET_INFO("*******\n"); + + pkt = net_pkt_get_tx(context, K_FOREVER); + frag = net_pkt_get_data(context, K_FOREVER); + + net_pkt_frag_add(pkt, frag); + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_NON_CON; + } + + r = coap_packet_init(&response, pkt, 1, type, + tkl, (u8_t *)token, + COAP_RESPONSE_CODE_CREATED, id); + if (r < 0) { + return -EINVAL; + } + + for (p = location_query; *p; p++) { + r = coap_packet_append_option(&response, + COAP_OPTION_LOCATION_QUERY, + *p, strlen(*p)); + if (r < 0) { + return -EINVAL; + } + } + + return net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); +} + +static int piggyback_get(struct coap_resource *resource, + struct coap_packet *request) +{ + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + u8_t token[8]; + u8_t payload[40], code, type; + u16_t id; + u8_t tkl; + int r; + + get_from_ip_addr(request, &from); + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + NET_INFO("*******\n"); + NET_INFO("type: %u code %u id %u\n", type, code, id); + NET_INFO("*******\n"); + + pkt = net_pkt_get_tx(context, K_FOREVER); + frag = net_pkt_get_data(context, K_FOREVER); + + net_pkt_frag_add(pkt, frag); + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_NON_CON; + } + + r = coap_packet_init(&response, pkt, 1, type, + tkl, (u8_t *)token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_option(&response, COAP_OPTION_CONTENT_FORMAT, + &plain_text_format, + sizeof(plain_text_format)); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_payload_marker(&response); + if (r) { + net_pkt_unref(pkt); + return -EINVAL; + } + + /* The response that coap-client expects */ + r = snprintk((char *) payload, sizeof(payload), + "Type: %u\nCode: %u\nMID: %u\n", type, code, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_payload(&response, (u8_t *)payload, + strlen(payload)); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + return net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); +} + +static int query_get(struct coap_resource *resource, + struct coap_packet *request) +{ + struct coap_option options[4]; + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + u8_t payload[40], code, type, tkl; + u8_t token[8]; + u16_t id; + int i, r; + + get_from_ip_addr(request, &from); + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + r = coap_find_options(request, COAP_OPTION_URI_QUERY, options, 4); + if (r < 0) { + return -EINVAL; + } + + NET_INFO("*******\n"); + NET_INFO("type: %u code %u id %u\n", type, code, id); + NET_INFO("num queries: %d\n", r); + + for (i = 0; i < r; i++) { + char str[16]; + + if (options[i].len + 1 > sizeof(str)) { + NET_INFO("Unexpected length of query: " + "%d (expected %zu)\n", + options[i].len, sizeof(str)); + break; + } + + memcpy(str, options[i].value, options[i].len); + str[options[i].len] = '\0'; + + NET_INFO("query[%d]: %s\n", i + 1, str); + } + + NET_INFO("*******\n"); + + pkt = net_pkt_get_tx(context, K_FOREVER); + frag = net_pkt_get_data(context, K_FOREVER); + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + tkl, (u8_t *) token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_option(&response, COAP_OPTION_CONTENT_FORMAT, + &plain_text_format, + sizeof(plain_text_format)); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_payload_marker(&response); + if (r) { + net_pkt_unref(pkt); + return -EINVAL; + } + + /* The response that coap-client expects */ + r = snprintk((char *) payload, sizeof(payload), + "Type: %u\nCode: %u\nMID: %u\n", type, code, id); + if (r < 0) { + return -EINVAL; + } + + r = coap_packet_append_payload(&response, (u8_t *)payload, + strlen(payload)); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + return net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); +} + +static int separate_get(struct coap_resource *resource, + struct coap_packet *request) +{ + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + struct coap_pending *pending; + u8_t payload[40], code, type, tkl; + u8_t token[8]; + u16_t id; + int r; + + get_from_ip_addr(request, &from); + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + NET_INFO("*******\n"); + NET_INFO("type: %u code %u id %u\n", type, code, id); + NET_INFO("*******\n"); + + if (type == COAP_TYPE_NON_CON) { + goto done; + } + + pkt = net_pkt_get_tx(context, K_FOREVER); + frag = net_pkt_get_data(context, K_FOREVER); + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + tkl, (u8_t *)token, 0, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + +done: + pkt = net_pkt_get_tx(context, K_FOREVER); + frag = net_pkt_get_data(context, K_FOREVER); + + net_pkt_frag_add(pkt, frag); + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_CON; + } else { + type = COAP_TYPE_NON_CON; + } + + r = coap_packet_init(&response, pkt, 1, type, + tkl, (u8_t *)token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_option(&response, COAP_OPTION_CONTENT_FORMAT, + &plain_text_format, + sizeof(plain_text_format)); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_payload_marker(&response); + if (r) { + net_pkt_unref(pkt); + return -EINVAL; + } + + /* The response that coap-client expects */ + r = snprintk((char *) payload, sizeof(payload), + "Type: %u\nCode: %u\nMID: %u\n", type, code, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_payload(&response, (u8_t *)payload, + strlen(payload)); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + if (type == COAP_TYPE_CON) { + pending = coap_pending_next_unused(pendings, NUM_PENDINGS); + if (!pending) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_pending_init(pending, &response, + (const struct sockaddr *)&from); + if (r) { + net_pkt_unref(pkt); + return -EINVAL; + } + + coap_pending_cycle(pending); + pending = coap_pending_next_to_expire(pendings, NUM_PENDINGS); + + k_delayed_work_submit(&retransmit_work, pending->timeout); + } + + return net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); +} + +static int large_get(struct coap_resource *resource, + struct coap_packet *request) +{ + static struct coap_block_context ctx; + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + u8_t token[8], code, type; + u8_t payload[64]; + u16_t size; + u16_t id; + u8_t tkl; + int r; + + if (ctx.total_size == 0) { + coap_block_transfer_init(&ctx, COAP_BLOCK_64, + BLOCK_WISE_TRANSFER_SIZE_GET); + } + + r = coap_update_from_block(request, &ctx); + if (r < 0) { + return -EINVAL; + } + + get_from_ip_addr(request, &from); + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + NET_INFO("*******\n"); + NET_INFO("type: %u code %u id %u\n", type, code, id); + NET_INFO("*******\n"); + + pkt = net_pkt_get_tx(context, K_FOREVER); + frag = net_pkt_get_data(context, K_FOREVER); + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + tkl, (u8_t *) token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + return -EINVAL; + } + + r = coap_packet_append_option(&response, COAP_OPTION_CONTENT_FORMAT, + &plain_text_format, + sizeof(plain_text_format)); + if (r < 0) { + return -EINVAL; + } + + r = coap_append_block2_option(&response, &ctx); + if (r < 0) { + return -EINVAL; + } + + r = coap_packet_append_payload_marker(&response); + if (r) { + net_pkt_unref(pkt); + return -EINVAL; + } + + size = min(coap_block_size_to_bytes(ctx.block_size), + ctx.total_size - ctx.current); + + memset(payload, 'A', size); + + r = coap_packet_append_payload(&response, (u8_t *)payload, size); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_next_block(&response, &ctx); + if (!r) { + /* Will return 0 when it's the last block. */ + memset(&ctx, 0, sizeof(ctx)); + } + + return net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); +} + +static int large_update_put(struct coap_resource *resource, + struct coap_packet *request) +{ + static struct coap_block_context ctx; + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + u8_t token[8]; + u16_t offset; + u16_t id; + u8_t payload; + u8_t code; + u8_t type; + u8_t tkl; + int r; + + frag = net_frag_skip(request->frag, request->offset, &offset, + request->hdr_len + request->opt_len); + if (!frag && offset == 0xffff) { + return -EINVAL; + } + + frag = net_frag_read_u8(frag, offset, &offset, &payload); + if (frag && offset != 0xffff) { + NET_ERR("packet has payload, wrong"); + return -EINVAL; + } + + if (ctx.total_size == 0) { + coap_block_transfer_init(&ctx, COAP_BLOCK_64, 0); + } + + r = coap_update_from_block(request, &ctx); + if (r < 0) { + NET_ERR("Invalid block size option from request"); + return -EINVAL; + } + + NET_INFO("**************\n"); + NET_INFO("[ctx] current %u block_size %u total_size %u\n", + ctx.current, coap_block_size_to_bytes(ctx.block_size), + ctx.total_size); + NET_INFO("**************\n"); + + get_from_ip_addr(request, &from); + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + NET_INFO("*******\n"); + NET_INFO("type: %u code %u id %u\n", type, code, id); + NET_INFO("*******\n"); + + /* Do something with the payload */ + + pkt = net_pkt_get_tx(context, K_FOREVER); + frag = net_pkt_get_data(context, K_FOREVER); + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + tkl, (u8_t *) token, + COAP_RESPONSE_CODE_CHANGED, id); + if (r < 0) { + return -EINVAL; + } + + r = coap_append_block2_option(&response, &ctx); + if (r < 0) { + NET_ERR("Could not add Block2 option to response"); + return -EINVAL; + } + + r = coap_append_block1_option(&response, &ctx); + if (r < 0) { + NET_ERR("Could not add Block1 option to response"); + return -EINVAL; + } + + return net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); +} + +static int large_create_post(struct coap_resource *resource, + struct coap_packet *request) +{ + static struct coap_block_context ctx; + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + u8_t token[8]; + u8_t code, type; + u16_t id; + u8_t tkl; + int r; + + if (ctx.total_size == 0) { + coap_block_transfer_init(&ctx, COAP_BLOCK_32, 0); + } + + r = coap_update_from_block(request, &ctx); + if (r < 0) { + return -EINVAL; + } + + /* TODO: Check for payload, empty payload is an error case. */ + + get_from_ip_addr(request, &from); + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + NET_INFO("*******\n"); + NET_INFO("type: %u code %u id %u\n", type, code, id); + NET_INFO("*******\n"); + + pkt = net_pkt_get_tx(context, K_FOREVER); + frag = net_pkt_get_data(context, K_FOREVER); + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + tkl, (u8_t *)token, + COAP_RESPONSE_CODE_CONTINUE, id); + if (r < 0) { + return -EINVAL; + } + + r = coap_append_block2_option(&response, &ctx); + if (r < 0) { + NET_ERR("Could not add Block2 option to response"); + return -EINVAL; + } + + r = coap_append_block1_option(&response, &ctx); + if (r < 0) { + NET_ERR("Could not add Block1 option to response"); + return -EINVAL; + } + + return net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); +} + +static void update_counter(struct k_work *work) +{ + obs_counter++; + + if (resource_to_notify) { + coap_resource_notify(resource_to_notify); + } + + k_delayed_work_submit(&observer_work, 5 * MSEC_PER_SEC); +} + +static int send_notification_packet(const struct sockaddr *addr, u16_t age, + socklen_t addrlen, u16_t id, + const u8_t *token, u8_t tkl, + bool is_response) +{ + struct coap_packet response; + struct coap_pending *pending; + struct net_pkt *pkt; + struct net_buf *frag; + char payload[14]; + u8_t type = COAP_TYPE_CON; + int r; + + if (is_response) { + type = COAP_TYPE_ACK; + } + + if (!is_response) { + id = coap_next_id(); + } + + pkt = net_pkt_get_tx(context, K_FOREVER); + frag = net_pkt_get_data(context, K_FOREVER); + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt, 1, type, + tkl, (u8_t *)token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + if (age >= 2) { + coap_append_option_int(&response, COAP_OPTION_OBSERVE, age); + } + + r = coap_packet_append_option(&response, COAP_OPTION_CONTENT_FORMAT, + &plain_text_format, + sizeof(plain_text_format)); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_payload_marker(&response); + if (r) { + net_pkt_unref(pkt); + return -EINVAL; + } + + /* The response that coap-client expects */ + r = snprintk((char *) payload, sizeof(payload), + "Counter: %d\n", obs_counter); + if (r < 0) { + return -EINVAL; + } + + r = coap_packet_append_payload(&response, (u8_t *)payload, + strlen(payload)); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + if (type == COAP_TYPE_CON) { + pending = coap_pending_next_unused(pendings, NUM_PENDINGS); + if (!pending) { + return -EINVAL; + } + + r = coap_pending_init(pending, &response, addr); + if (r) { + return -EINVAL; + } + + coap_pending_cycle(pending); + pending = coap_pending_next_to_expire(pendings, NUM_PENDINGS); + + k_delayed_work_submit(&retransmit_work, pending->timeout); + } + + return net_context_sendto(pkt, addr, addrlen, NULL, 0, NULL, NULL); +} + +static int obs_get(struct coap_resource *resource, + struct coap_packet *request) +{ + struct coap_observer *observer; + struct sockaddr_in6 from; + u8_t token[8]; + u8_t code, type; + u16_t id; + u8_t tkl; + bool observe = true; + + get_from_ip_addr(request, &from); + + if (!coap_request_is_observe(request)) { + observe = false; + goto done; + } + + observer = coap_observer_next_unused(observers, NUM_OBSERVERS); + if (!observer) { + return -ENOMEM; + } + + coap_observer_init(observer, request, + (const struct sockaddr *)&from); + + coap_register_observer(resource, observer); + + resource_to_notify = resource; + +done: + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + NET_INFO("*******\n"); + NET_INFO("type: %u code %u id %u\n", type, code, id); + NET_INFO("*******\n"); + + return send_notification_packet((const struct sockaddr *)&from, + observe ? resource->age : 0, + sizeof(struct sockaddr_in6), id, + token, tkl, true); +} + +static void obs_notify(struct coap_resource *resource, + struct coap_observer *observer) +{ + send_notification_packet(&observer->addr, resource->age, + sizeof(observer->addr), 0, + observer->token, observer->tkl, false); +} + +static int core_get(struct coap_resource *resource, + struct coap_packet *request) +{ + static const char dummy_str[] = "Just a test\n"; + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + u8_t tkl; + u8_t token[8]; + u16_t id; + int r; + + get_from_ip_addr(request, &from); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + pkt = net_pkt_get_tx(context, K_FOREVER); + frag = net_pkt_get_data(context, K_FOREVER); + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + tkl, (u8_t *)token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + return -EINVAL; + } + + r = coap_packet_append_payload_marker(&response); + if (r) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_payload(&response, (u8_t *)dummy_str, + sizeof(dummy_str)); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + return net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); +} + +static const char * const test_path[] = { "test", NULL }; + +static const char * const segments_path[] = { "seg1", "seg2", "seg3", NULL }; + +static const char * const query_path[] = { "query", NULL }; + +static const char * const separate_path[] = { "separate", NULL }; + +static const char * const large_path[] = { "large", NULL }; + +static const char * const location_query_path[] = { "location-query", NULL }; + +static const char * const large_update_path[] = { "large-update", NULL }; + +static const char * const large_create_path[] = { "large-create", NULL }; + +static const char * const obs_path[] = { "obs", NULL }; + +static const char * const core_1_path[] = { "core1", NULL }; +static const char * const core_1_attributes[] = { + "title=\"Core 1\"", + "rt=core1", + NULL }; + +static const char * const core_2_path[] = { "core2", NULL }; +static const char * const core_2_attributes[] = { + "title=\"Core 1\"", + "rt=core1", + NULL }; + +static struct coap_resource resources[] = { + { .get = piggyback_get, + .post = test_post, + .del = test_del, + .put = test_put, + .path = test_path + }, + { .get = piggyback_get, + .path = segments_path, + }, + { .get = query_get, + .path = query_path, + }, + { .get = separate_get, + .path = separate_path, + }, + { .path = large_path, + .get = large_get, + }, + { .path = location_query_path, + .post = location_query_post, + }, + { .path = large_update_path, + .put = large_update_put, + }, + { .path = large_create_path, + .post = large_create_post, + }, + { .path = obs_path, + .get = obs_get, + .notify = obs_notify, + }, + { .get = well_known_core_get, + .path = COAP_WELL_KNOWN_CORE_PATH, + }, + { .get = well_known_core_get, + .path = COAP_WELL_KNOWN_CORE_PATH, + }, + { .get = core_get, + .path = core_1_path, + .user_data = &((struct coap_core_metadata) { + .attributes = core_1_attributes, + }), + }, + { .get = core_get, + .path = core_2_path, + .user_data = &((struct coap_core_metadata) { + .attributes = core_2_attributes, + }), + }, + { }, +}; + +static struct coap_resource *find_resouce_by_observer( + struct coap_resource *resources, struct coap_observer *o) +{ + struct coap_resource *r; + + for (r = resources; r && r->path; r++) { + sys_snode_t *node; + + SYS_SLIST_FOR_EACH_NODE(&r->observers, node) { + if (&o->list == node) { + return r; + } + } + } + + return NULL; +} + +static void udp_receive(struct net_context *context, + struct net_pkt *pkt, + int status, + void *user_data) +{ + struct coap_packet request; + struct coap_pending *pending; + struct sockaddr_in6 from; + struct coap_option options[16] = { 0 }; + u8_t opt_num = 16; + int r; + + r = coap_packet_parse(&request, pkt, options, opt_num); + if (r < 0) { + NET_ERR("Invalid data received (%d)\n", r); + net_pkt_unref(pkt); + return; + } + + get_from_ip_addr(&request, &from); + pending = coap_pending_received(&request, pendings, + NUM_PENDINGS); + if (pending) { + net_pkt_unref(pkt); + return; + } + + if (coap_header_get_type(&request) == COAP_TYPE_RESET) { + struct coap_resource *r; + struct coap_observer *o; + + o = coap_find_observer_by_addr(observers, NUM_OBSERVERS, + (struct sockaddr *)&from); + if (!o) { + goto not_found; + } + + r = find_resouce_by_observer(resources, o); + if (!r) { + goto not_found; + } + + coap_remove_observer(r, o); + } + +not_found: + r = coap_handle_request(&request, resources, options, opt_num); + if (r < 0) { + NET_ERR("No handler for such request (%d)\n", r); + } + + net_pkt_unref(pkt); +} + +static bool join_coap_multicast_group(void) +{ + static struct in6_addr my_addr = MY_IP6ADDR; + static struct sockaddr_in6 mcast_addr = { + .sin6_family = AF_INET6, + .sin6_addr = ALL_NODES_LOCAL_COAP_MCAST, + .sin6_port = htons(MY_COAP_PORT) }; + struct net_if_mcast_addr *mcast; + struct net_if_addr *ifaddr; + struct net_if *iface; + + iface = net_if_get_default(); + if (!iface) { + NET_ERR("Could not get te default interface\n"); + return false; + } + +#if defined(CONFIG_NET_APP_SETTINGS) + if (net_addr_pton(AF_INET6, + CONFIG_NET_APP_MY_IPV6_ADDR, + &my_addr) < 0) { + NET_ERR("Invalid IPv6 address %s", + CONFIG_NET_APP_MY_IPV6_ADDR); + } +#endif + + ifaddr = net_if_ipv6_addr_add(iface, &my_addr, NET_ADDR_MANUAL, 0); + if (!ifaddr) { + NET_ERR("Could not add unicast address to interface"); + return false; + } + + ifaddr->addr_state = NET_ADDR_PREFERRED; + + mcast = net_if_ipv6_maddr_add(iface, &mcast_addr.sin6_addr); + if (!mcast) { + NET_ERR("Could not add multicast address to interface\n"); + return false; + } + + return true; +} + +static void retransmit_request(struct k_work *work) +{ + struct coap_pending *pending; + int r; + + pending = coap_pending_next_to_expire(pendings, NUM_PENDINGS); + if (!pending) { + return; + } + + r = net_context_sendto(pending->pkt, &pending->addr, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); + if (r < 0) { + return; + } + + if (!coap_pending_cycle(pending)) { + coap_pending_clear(pending); + return; + } + + k_delayed_work_submit(&retransmit_work, pending->timeout); +} + +void main(void) +{ + static struct sockaddr_in6 any_addr = { + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_ANY_INIT, + .sin6_port = htons(MY_COAP_PORT) }; + int r; + + if (!join_coap_multicast_group()) { + NET_ERR("Could not join CoAP multicast group\n"); + return; + } + + r = net_context_get(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &context); + if (r) { + NET_ERR("Could not get an UDP context\n"); + return; + } + + r = net_context_bind(context, (struct sockaddr *) &any_addr, + sizeof(any_addr)); + if (r) { + NET_ERR("Could not bind the context\n"); + return; + } + + k_delayed_work_init(&retransmit_work, retransmit_request); + + k_delayed_work_init(&observer_work, update_counter); + k_delayed_work_submit(&observer_work, 5 * MSEC_PER_SEC); + + r = net_context_recv(context, udp_receive, 0, NULL); + if (r) { + NET_ERR("Could not receive in the context\n"); + return; + } +} diff --git a/samples/net/zoap_server/src/ieee802154_settings.c b/samples/net/coap_server/src/ieee802154_settings.c similarity index 100% rename from samples/net/zoap_server/src/ieee802154_settings.c rename to samples/net/coap_server/src/ieee802154_settings.c diff --git a/samples/net/zoap_server/src/zoap-server.c b/samples/net/zoap_server/src/zoap-server.c deleted file mode 100644 index b251672ce0590..0000000000000 --- a/samples/net/zoap_server/src/zoap-server.c +++ /dev/null @@ -1,1289 +0,0 @@ -/* - * Copyright (c) 2016 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#if 1 -#define SYS_LOG_DOMAIN "zoap-server" -#define SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG -#define NET_LOG_ENABLED 1 -#endif - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#define MY_COAP_PORT 5683 - -#define STACKSIZE 2000 - -/* FIXME */ -#define BLOCK_WISE_TRANSFER_SIZE_GET 2048 - -#define ALL_NODES_LOCAL_COAP_MCAST \ - { { { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xfd } } } - -#define MY_IP6ADDR \ - { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } } - -#define NUM_OBSERVERS 3 - -#define NUM_PENDINGS 3 - -static struct net_context *context; - -static const u8_t plain_text_format; - -static struct zoap_observer observers[NUM_OBSERVERS]; - -static struct zoap_pending pendings[NUM_PENDINGS]; - -static struct net_context *context; - -static struct k_delayed_work observer_work; - -static int obs_counter; - -static struct zoap_resource *resource_to_notify; - -struct k_delayed_work retransmit_work; - -static int test_del(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) -{ - struct net_pkt *pkt; - struct net_buf *frag; - struct zoap_packet response; - u8_t tkl, code, type; - const u8_t *token; - u16_t id; - int r; - - code = zoap_header_get_code(request); - type = zoap_header_get_type(request); - id = zoap_header_get_id(request); - token = zoap_header_get_token(request, &tkl); - - NET_INFO("*******\n"); - NET_INFO("type: %u code %u id %u\n", type, code, id); - NET_INFO("*******\n"); - - pkt = net_pkt_get_tx(context, K_FOREVER); - frag = net_pkt_get_data(context, K_FOREVER); - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&response, pkt); - if (r < 0) { - return -EINVAL; - } - - if (type == ZOAP_TYPE_CON) { - type = ZOAP_TYPE_ACK; - } else { - type = ZOAP_TYPE_NON_CON; - } - - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, type); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_DELETED); - zoap_header_set_id(&response, id); - zoap_header_set_token(&response, token, tkl); - - return net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), - NULL, 0, NULL, NULL); -} - -static int test_put(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) -{ - struct net_pkt *pkt; - struct net_buf *frag; - struct zoap_packet response; - u8_t *payload, code, type, tkl; - const u8_t *token; - u16_t len, id; - int r; - - payload = zoap_packet_get_payload(request, &len); - if (!payload) { - return -EINVAL; - } - - code = zoap_header_get_code(request); - type = zoap_header_get_type(request); - id = zoap_header_get_id(request); - token = zoap_header_get_token(request, &tkl); - - NET_INFO("*******\n"); - NET_INFO("type: %u code %u id %u\n", type, code, id); - NET_INFO("*******\n"); - - pkt = net_pkt_get_tx(context, K_FOREVER); - frag = net_pkt_get_data(context, K_FOREVER); - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&response, pkt); - if (r < 0) { - return -EINVAL; - } - - if (type == ZOAP_TYPE_CON) { - type = ZOAP_TYPE_ACK; - } else { - type = ZOAP_TYPE_NON_CON; - } - - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, type); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CHANGED); - zoap_header_set_id(&response, id); - zoap_header_set_token(&response, token, tkl); - - return net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), - NULL, 0, NULL, NULL); -} - -static int test_post(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) -{ - static const char * const location_path[] = { "location1", - "location2", - "location3", - NULL }; - const char * const *p; - struct net_pkt *pkt; - struct net_buf *frag; - struct zoap_packet response; - u8_t *payload, code, type, tkl; - const u8_t *token; - u16_t len, id; - int r; - - payload = zoap_packet_get_payload(request, &len); - if (!payload) { - NET_ERR("Packet without payload\n"); - return -EINVAL; - } - - code = zoap_header_get_code(request); - type = zoap_header_get_type(request); - id = zoap_header_get_id(request); - token = zoap_header_get_token(request, &tkl); - - NET_INFO("*******\n"); - NET_INFO("type: %u code %u id %u\n", type, code, id); - NET_INFO("*******\n"); - - pkt = net_pkt_get_tx(context, K_FOREVER); - frag = net_pkt_get_data(context, K_FOREVER); - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&response, pkt); - if (r < 0) { - return -EINVAL; - } - - if (type == ZOAP_TYPE_CON) { - type = ZOAP_TYPE_ACK; - } else { - type = ZOAP_TYPE_NON_CON; - } - - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, type); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CREATED); - zoap_header_set_id(&response, id); - zoap_header_set_token(&response, token, tkl); - - for (p = location_path; *p; p++) { - r = zoap_add_option(&response, ZOAP_OPTION_LOCATION_PATH, - *p, strlen(*p)); - if (r < 0) { - return -EINVAL; - } - } - - return net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), - NULL, 0, NULL, NULL); -} - -static int location_query_post(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) -{ - static const char *const location_query[] = { "first=1", - "second=2", - NULL }; - const char * const *p; - struct net_pkt *pkt; - struct net_buf *frag; - struct zoap_packet response; - u8_t *payload, code, type, tkl; - const u8_t *token; - u16_t len, id; - int r; - - payload = zoap_packet_get_payload(request, &len); - if (!payload) { - NET_ERR("Packet without payload\n"); - return -EINVAL; - } - - code = zoap_header_get_code(request); - type = zoap_header_get_type(request); - id = zoap_header_get_id(request); - token = zoap_header_get_token(request, &tkl); - - NET_INFO("*******\n"); - NET_INFO("type: %u code %u id %u\n", type, code, id); - NET_INFO("*******\n"); - - pkt = net_pkt_get_tx(context, K_FOREVER); - frag = net_pkt_get_data(context, K_FOREVER); - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&response, pkt); - if (r < 0) { - return -EINVAL; - } - - if (type == ZOAP_TYPE_CON) { - type = ZOAP_TYPE_ACK; - } else { - type = ZOAP_TYPE_NON_CON; - } - - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, type); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CREATED); - zoap_header_set_id(&response, id); - zoap_header_set_token(&response, token, tkl); - - for (p = location_query; *p; p++) { - r = zoap_add_option(&response, ZOAP_OPTION_LOCATION_QUERY, - *p, strlen(*p)); - if (r < 0) { - return -EINVAL; - } - } - - return net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), - NULL, 0, NULL, NULL); -} - -static int piggyback_get(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) -{ - struct net_pkt *pkt; - struct net_buf *frag; - struct zoap_packet response; - const u8_t *token; - u8_t *payload, code, type; - u16_t len, id; - u8_t tkl; - int r; - - code = zoap_header_get_code(request); - type = zoap_header_get_type(request); - id = zoap_header_get_id(request); - token = zoap_header_get_token(request, &tkl); - - NET_INFO("*******\n"); - NET_INFO("type: %u code %u id %u\n", type, code, id); - NET_INFO("*******\n"); - - pkt = net_pkt_get_tx(context, K_FOREVER); - frag = net_pkt_get_data(context, K_FOREVER); - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&response, pkt); - if (r < 0) { - return -EINVAL; - } - - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - - if (type == ZOAP_TYPE_CON) { - type = ZOAP_TYPE_ACK; - } else { - type = ZOAP_TYPE_NON_CON; - } - - zoap_header_set_type(&response, type); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CONTENT); - zoap_header_set_id(&response, id); - zoap_header_set_token(&response, token, tkl); - - r = zoap_add_option(&response, ZOAP_OPTION_CONTENT_FORMAT, - &plain_text_format, sizeof(plain_text_format)); - if (r < 0) { - return -EINVAL; - } - - payload = zoap_packet_get_payload(&response, &len); - if (!payload) { - return -EINVAL; - } - - /* The response that coap-client expects */ - r = snprintk((char *) payload, len, - "Type: %u\nCode: %u\nMID: %u\n", type, code, id); - if (r < 0 || r > len) { - return -EINVAL; - } - - r = zoap_packet_set_used(&response, r); - if (r) { - return -EINVAL; - } - - return net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), - NULL, 0, NULL, NULL); -} - -static int query_get(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) -{ - struct zoap_option options[4]; - struct net_pkt *pkt; - struct net_buf *frag; - struct zoap_packet response; - u8_t *payload, code, type, tkl; - const u8_t *token; - u16_t len, id; - int i, r; - - code = zoap_header_get_code(request); - type = zoap_header_get_type(request); - id = zoap_header_get_id(request); - token = zoap_header_get_token(request, &tkl); - - r = zoap_find_options(request, ZOAP_OPTION_URI_QUERY, options, 4); - if (r < 0) { - return -EINVAL; - } - - NET_INFO("*******\n"); - NET_INFO("type: %u code %u id %u\n", type, code, id); - NET_INFO("num queries: %d\n", r); - - for (i = 0; i < r; i++) { - char str[16]; - - if (options[i].len + 1 > sizeof(str)) { - NET_INFO("Unexpected length of query: " - "%d (expected %zu)\n", - options[i].len, sizeof(str)); - break; - } - - memcpy(str, options[i].value, options[i].len); - str[options[i].len] = '\0'; - - NET_INFO("query[%d]: %s\n", i + 1, str); - } - - NET_INFO("*******\n"); - - pkt = net_pkt_get_tx(context, K_FOREVER); - frag = net_pkt_get_data(context, K_FOREVER); - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&response, pkt); - if (r < 0) { - return -EINVAL; - } - - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, ZOAP_TYPE_ACK); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CONTENT); - zoap_header_set_id(&response, id); - zoap_header_set_token(&response, token, tkl); - - r = zoap_add_option(&response, ZOAP_OPTION_CONTENT_FORMAT, - &plain_text_format, sizeof(plain_text_format)); - if (r < 0) { - return -EINVAL; - } - - payload = zoap_packet_get_payload(&response, &len); - if (!payload) { - return -EINVAL; - } - - /* The response that coap-client expects */ - r = snprintk((char *) payload, len, - "Type: %u\nCode: %u\nMID: %u\n", type, code, id); - if (r < 0 || r > len) { - return -EINVAL; - } - - r = zoap_packet_set_used(&response, r); - if (r) { - return -EINVAL; - } - - return net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), - NULL, 0, NULL, NULL); -} - -static int separate_get(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) -{ - struct net_pkt *pkt; - struct net_buf *frag; - struct zoap_packet response; - struct zoap_pending *pending; - u8_t *payload, code, type, tkl; - const u8_t *token; - u16_t len, id; - int r; - - code = zoap_header_get_code(request); - type = zoap_header_get_type(request); - id = zoap_header_get_id(request); - token = zoap_header_get_token(request, &tkl); - - NET_INFO("*******\n"); - NET_INFO("type: %u code %u id %u\n", type, code, id); - NET_INFO("*******\n"); - - if (type == ZOAP_TYPE_NON_CON) { - goto done; - } - - pkt = net_pkt_get_tx(context, K_FOREVER); - frag = net_pkt_get_data(context, K_FOREVER); - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&response, pkt); - if (r < 0) { - return -EINVAL; - } - - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, ZOAP_TYPE_ACK); - zoap_header_set_code(&response, 0); - zoap_header_set_id(&response, id); - zoap_header_set_token(&response, token, tkl); - - r = net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), - NULL, 0, NULL, NULL); - if (r < 0) { - return -EINVAL; - } - -done: - pkt = net_pkt_get_tx(context, K_FOREVER); - frag = net_pkt_get_data(context, K_FOREVER); - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&response, pkt); - if (r < 0) { - return -EINVAL; - } - - if (type == ZOAP_TYPE_CON) { - type = ZOAP_TYPE_CON; - } else { - type = ZOAP_TYPE_NON_CON; - } - - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, type); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CONTENT); - zoap_header_set_id(&response, id); - zoap_header_set_token(&response, token, tkl); - - r = zoap_add_option(&response, ZOAP_OPTION_CONTENT_FORMAT, - &plain_text_format, sizeof(plain_text_format)); - if (r < 0) { - return -EINVAL; - } - - payload = zoap_packet_get_payload(&response, &len); - if (!payload) { - return -EINVAL; - } - - /* The response that coap-client expects */ - r = snprintk((char *) payload, len, - "Type: %u\nCode: %u\nMID: %u\n", type, code, id); - if (r < 0 || r > len) { - return -EINVAL; - } - - r = zoap_packet_set_used(&response, r); - if (r) { - return -EINVAL; - } - - if (type == ZOAP_TYPE_CON) { - pending = zoap_pending_next_unused(pendings, NUM_PENDINGS); - if (!pending) { - return -EINVAL; - } - - r = zoap_pending_init(pending, &response, from); - if (r) { - return -EINVAL; - } - - zoap_pending_cycle(pending); - pending = zoap_pending_next_to_expire(pendings, NUM_PENDINGS); - - k_delayed_work_submit(&retransmit_work, pending->timeout); - } - - return net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), - NULL, 0, NULL, NULL); -} - -static int large_get(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) -{ - static struct zoap_block_context ctx; - struct net_pkt *pkt; - struct net_buf *frag; - struct zoap_packet response; - const u8_t *token; - u8_t *payload, code, type; - u16_t len, id, size; - u8_t tkl; - int r; - - if (ctx.total_size == 0) { - zoap_block_transfer_init(&ctx, ZOAP_BLOCK_64, - BLOCK_WISE_TRANSFER_SIZE_GET); - } - - r = zoap_update_from_block(request, &ctx); - if (r < 0) { - return -EINVAL; - } - - code = zoap_header_get_code(request); - type = zoap_header_get_type(request); - id = zoap_header_get_id(request); - token = zoap_header_get_token(request, &tkl); - - NET_INFO("*******\n"); - NET_INFO("type: %u code %u id %u\n", type, code, id); - NET_INFO("*******\n"); - - pkt = net_pkt_get_tx(context, K_FOREVER); - frag = net_pkt_get_data(context, K_FOREVER); - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&response, pkt); - if (r < 0) { - return -EINVAL; - } - - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, ZOAP_TYPE_ACK); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CONTENT); - zoap_header_set_id(&response, id); - zoap_header_set_token(&response, token, tkl); - - r = zoap_add_option(&response, ZOAP_OPTION_CONTENT_FORMAT, - &plain_text_format, sizeof(plain_text_format)); - if (r < 0) { - return -EINVAL; - } - - r = zoap_add_block2_option(&response, &ctx); - if (r < 0) { - return -EINVAL; - } - - payload = zoap_packet_get_payload(&response, &len); - if (!payload) { - return -EINVAL; - } - - size = min(zoap_block_size_to_bytes(ctx.block_size), - ctx.total_size - ctx.current); - - if (len < size) { - return -ENOMEM; - } - - memset(payload, 'A', size); - - r = zoap_packet_set_used(&response, size); - if (r) { - return -EINVAL; - } - - r = zoap_next_block(&response, &ctx); - if (!r) { - /* Will return 0 when it's the last block. */ - memset(&ctx, 0, sizeof(ctx)); - } - - return net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), - NULL, 0, NULL, NULL); -} - -static int large_update_put(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) -{ - static struct zoap_block_context ctx; - struct net_pkt *pkt; - struct net_buf *frag; - struct zoap_packet response; - const u8_t *token; - u8_t *payload, code, type; - u16_t len, id; - u8_t tkl; - int r; - - if (ctx.total_size == 0) { - zoap_block_transfer_init(&ctx, ZOAP_BLOCK_64, 0); - } - - r = zoap_update_from_block(request, &ctx); - if (r < 0) { - NET_ERR("Invalid block size option from request"); - return -EINVAL; - } - - NET_INFO("**************\n"); - NET_INFO("[ctx] current %u block_size %u total_size %u\n", - ctx.current, zoap_block_size_to_bytes(ctx.block_size), - ctx.total_size); - NET_INFO("**************\n"); - - payload = zoap_packet_get_payload(request, &len); - if (!payload) { - NET_ERR("Packet without payload\n"); - return -EINVAL; - } - - code = zoap_header_get_code(request); - type = zoap_header_get_type(request); - id = zoap_header_get_id(request); - token = zoap_header_get_token(request, &tkl); - - NET_INFO("*******\n"); - NET_INFO("type: %u code %u id %u\n", type, code, id); - NET_INFO("*******\n"); - - /* Do something with the payload */ - - pkt = net_pkt_get_tx(context, K_FOREVER); - frag = net_pkt_get_data(context, K_FOREVER); - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&response, pkt); - if (r < 0) { - return -EINVAL; - } - - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, ZOAP_TYPE_ACK); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CHANGED); - zoap_header_set_id(&response, id); - zoap_header_set_token(&response, token, tkl); - - r = zoap_add_block2_option(&response, &ctx); - if (r < 0) { - NET_ERR("Could not add Block2 option to response"); - return -EINVAL; - } - - r = zoap_add_block1_option(&response, &ctx); - if (r < 0) { - NET_ERR("Could not add Block1 option to response"); - return -EINVAL; - } - - return net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), - NULL, 0, NULL, NULL); -} - -static int large_create_post(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) -{ - static struct zoap_block_context ctx; - struct net_pkt *pkt; - struct net_buf *frag; - struct zoap_packet response; - const u8_t *token; - u8_t *payload, code, type; - u16_t len, id; - u8_t tkl; - int r; - - if (ctx.total_size == 0) { - zoap_block_transfer_init(&ctx, ZOAP_BLOCK_32, 0); - } - - r = zoap_update_from_block(request, &ctx); - if (r < 0) { - return -EINVAL; - } - - payload = zoap_packet_get_payload(request, &len); - if (!payload) { - NET_ERR("Packet without payload\n"); - return -EINVAL; - } - - code = zoap_header_get_code(request); - type = zoap_header_get_type(request); - id = zoap_header_get_id(request); - token = zoap_header_get_token(request, &tkl); - - NET_INFO("*******\n"); - NET_INFO("type: %u code %u id %u\n", type, code, id); - NET_INFO("*******\n"); - - pkt = net_pkt_get_tx(context, K_FOREVER); - frag = net_pkt_get_data(context, K_FOREVER); - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&response, pkt); - if (r < 0) { - return -EINVAL; - } - - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, ZOAP_TYPE_ACK); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CONTINUE); - zoap_header_set_id(&response, id); - zoap_header_set_token(&response, token, tkl); - - r = zoap_add_block2_option(&response, &ctx); - if (r < 0) { - NET_ERR("Could not add Block2 option to response"); - return -EINVAL; - } - - r = zoap_add_block1_option(&response, &ctx); - if (r < 0) { - NET_ERR("Could not add Block1 option to response"); - return -EINVAL; - } - - return net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), - NULL, 0, NULL, NULL); -} - -static void update_counter(struct k_work *work) -{ - obs_counter++; - - if (resource_to_notify) { - zoap_resource_notify(resource_to_notify); - } - - k_delayed_work_submit(&observer_work, 5 * MSEC_PER_SEC); -} - -static int send_notification_packet(const struct sockaddr *addr, u16_t age, - socklen_t addrlen, u16_t id, - const u8_t *token, u8_t tkl, - bool is_response) -{ - struct zoap_packet response; - struct zoap_pending *pending; - struct net_pkt *pkt; - struct net_buf *frag; - u8_t *payload, type = ZOAP_TYPE_CON; - u16_t len; - int r; - - pkt = net_pkt_get_tx(context, K_FOREVER); - frag = net_pkt_get_data(context, K_FOREVER); - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&response, pkt); - if (r < 0) { - return -EINVAL; - } - - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - - if (is_response) { - type = ZOAP_TYPE_ACK; - } - - zoap_header_set_type(&response, type); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CONTENT); - - if (!is_response) { - id = zoap_next_id(); - } - - zoap_header_set_id(&response, id); - zoap_header_set_token(&response, token, tkl); - - if (age >= 2) { - r = zoap_add_option_int(&response, ZOAP_OPTION_OBSERVE, age); - if (r < 0) { - return -EINVAL; - } - } - - r = zoap_add_option(&response, ZOAP_OPTION_CONTENT_FORMAT, - &plain_text_format, sizeof(plain_text_format)); - if (r < 0) { - return -EINVAL; - } - - payload = zoap_packet_get_payload(&response, &len); - if (!payload) { - return -EINVAL; - } - - /* The response that coap-client expects */ - r = snprintk((char *) payload, len, "Counter: %d\n", obs_counter); - if (r < 0 || r > len) { - return -EINVAL; - } - - r = zoap_packet_set_used(&response, r); - if (r) { - return -EINVAL; - } - - if (type == ZOAP_TYPE_CON) { - pending = zoap_pending_next_unused(pendings, NUM_PENDINGS); - if (!pending) { - return -EINVAL; - } - - r = zoap_pending_init(pending, &response, addr); - if (r) { - return -EINVAL; - } - - zoap_pending_cycle(pending); - pending = zoap_pending_next_to_expire(pendings, NUM_PENDINGS); - - k_delayed_work_submit(&retransmit_work, pending->timeout); - } - - return net_context_sendto(pkt, addr, addrlen, NULL, 0, NULL, NULL); -} - -static int obs_get(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) -{ - struct zoap_observer *observer; - const u8_t *token; - u8_t code, type; - u16_t id; - u8_t tkl; - bool observe = true; - - if (!zoap_request_is_observe(request)) { - observe = false; - goto done; - } - - observer = zoap_observer_next_unused(observers, NUM_OBSERVERS); - if (!observer) { - return -ENOMEM; - } - - zoap_observer_init(observer, request, from); - - zoap_register_observer(resource, observer); - - resource_to_notify = resource; - -done: - code = zoap_header_get_code(request); - type = zoap_header_get_type(request); - id = zoap_header_get_id(request); - token = zoap_header_get_token(request, &tkl); - - NET_INFO("*******\n"); - NET_INFO("type: %u code %u id %u\n", type, code, id); - NET_INFO("*******\n"); - - return send_notification_packet(from, observe ? resource->age : 0, - sizeof(struct sockaddr_in6), id, - token, tkl, true); -} - -static void obs_notify(struct zoap_resource *resource, - struct zoap_observer *observer) -{ - send_notification_packet(&observer->addr, resource->age, - sizeof(observer->addr), 0, - observer->token, observer->tkl, false); -} - -static int core_get(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) -{ - static const char dummy_str[] = "Just a test\n"; - struct net_pkt *pkt; - struct net_buf *frag; - struct zoap_packet response; - u8_t *payload, tkl; - const u8_t *token; - u16_t len, id; - int r; - - id = zoap_header_get_id(request); - token = zoap_header_get_token(request, &tkl); - - pkt = net_pkt_get_tx(context, K_FOREVER); - frag = net_pkt_get_data(context, K_FOREVER); - - net_pkt_frag_add(pkt, frag); - - r = zoap_packet_init(&response, pkt); - if (r < 0) { - return -EINVAL; - } - - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, ZOAP_TYPE_ACK); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CONTENT); - zoap_header_set_id(&response, id); - zoap_header_set_token(&response, token, tkl); - - payload = zoap_packet_get_payload(&response, &len); - if (!payload) { - return -EINVAL; - } - - memcpy(payload, dummy_str, sizeof(dummy_str)); - - r = zoap_packet_set_used(&response, sizeof(dummy_str)); - if (r) { - return -EINVAL; - } - - return net_context_sendto(pkt, from, sizeof(struct sockaddr_in6), - NULL, 0, NULL, NULL); -} - -static const char * const test_path[] = { "test", NULL }; - -static const char * const segments_path[] = { "seg1", "seg2", "seg3", NULL }; - -static const char * const query_path[] = { "query", NULL }; - -static const char * const separate_path[] = { "separate", NULL }; - -static const char * const large_path[] = { "large", NULL }; - -static const char * const location_query_path[] = { "location-query", NULL }; - -static const char * const large_update_path[] = { "large-update", NULL }; - -static const char * const large_create_path[] = { "large-create", NULL }; - -static const char * const obs_path[] = { "obs", NULL }; - -static const char * const core_1_path[] = { "core1", NULL }; -static const char * const core_1_attributes[] = { - "title=\"Core 1\"", - "rt=core1", - NULL }; - -static const char * const core_2_path[] = { "core2", NULL }; -static const char * const core_2_attributes[] = { - "title=\"Core 1\"", - "rt=core1", - NULL }; - -static struct zoap_resource resources[] = { - { .get = piggyback_get, - .post = test_post, - .del = test_del, - .put = test_put, - .path = test_path }, - { .get = piggyback_get, - .path = segments_path, - }, - { .get = query_get, - .path = query_path, - }, - { .get = separate_get, - .path = separate_path, - }, - { .path = large_path, - .get = large_get, - }, - { .path = location_query_path, - .post = location_query_post, - }, - { .path = large_update_path, - .put = large_update_put, - }, - { .path = large_create_path, - .post = large_create_post, - }, - { .path = obs_path, - .get = obs_get, - .notify = obs_notify, - }, - ZOAP_WELL_KNOWN_CORE_RESOURCE, - { .get = core_get, - .path = core_1_path, - .user_data = &((struct zoap_core_metadata) { - .attributes = core_1_attributes, - }), - }, - { .get = core_get, - .path = core_2_path, - .user_data = &((struct zoap_core_metadata) { - .attributes = core_2_attributes, - }), - }, - { }, -}; - -static struct zoap_resource *find_resouce_by_observer( - struct zoap_resource *resources, struct zoap_observer *o) -{ - struct zoap_resource *r; - - for (r = resources; r && r->path; r++) { - sys_snode_t *node; - - SYS_SLIST_FOR_EACH_NODE(&r->observers, node) { - if (&o->list == node) { - return r; - } - } - } - - return NULL; -} - -static void udp_receive(struct net_context *context, - struct net_pkt *pkt, - int status, - void *user_data) -{ - struct zoap_packet request; - struct zoap_pending *pending; - struct sockaddr_in6 from; - struct net_udp_hdr hdr, *udp_hdr; - int r, header_len; - - net_ipaddr_copy(&from.sin6_addr, &NET_IPV6_HDR(pkt)->src); - - udp_hdr = net_udp_get_hdr(pkt, &hdr); - if (!udp_hdr) { - printk("Invalid UDP data received\n"); - net_pkt_unref(pkt); - return; - } - - from.sin6_port = udp_hdr->src_port; - from.sin6_family = AF_INET6; - - /* - * zoap expects that buffer->data starts at the - * beginning of the CoAP header - */ - header_len = net_pkt_appdata(pkt) - pkt->frags->data; - net_buf_pull(pkt->frags, header_len); - - r = zoap_packet_parse(&request, pkt); - if (r < 0) { - NET_ERR("Invalid data received (%d)\n", r); - net_pkt_unref(pkt); - return; - } - - pending = zoap_pending_received(&request, pendings, - NUM_PENDINGS); - if (pending) { - net_pkt_unref(pkt); - return; - } - - if (zoap_header_get_type(&request) == ZOAP_TYPE_RESET) { - struct zoap_resource *r; - struct zoap_observer *o; - - o = zoap_find_observer_by_addr(observers, NUM_OBSERVERS, - (struct sockaddr *)&from); - if (!o) { - goto not_found; - } - - r = find_resouce_by_observer(resources, o); - if (!r) { - goto not_found; - } - - zoap_remove_observer(r, o); - } - -not_found: - r = zoap_handle_request(&request, resources, - (const struct sockaddr *) &from); - - net_pkt_unref(pkt); - - if (r < 0) { - NET_ERR("No handler for such request (%d)\n", r); - return; - } -} - -static bool join_coap_multicast_group(void) -{ - static struct in6_addr my_addr = MY_IP6ADDR; - static struct sockaddr_in6 mcast_addr = { - .sin6_family = AF_INET6, - .sin6_addr = ALL_NODES_LOCAL_COAP_MCAST, - .sin6_port = htons(MY_COAP_PORT) }; - struct net_if_mcast_addr *mcast; - struct net_if_addr *ifaddr; - struct net_if *iface; - - iface = net_if_get_default(); - if (!iface) { - NET_ERR("Could not get te default interface\n"); - return false; - } - -#if defined(CONFIG_NET_APP_SETTINGS) - if (net_addr_pton(AF_INET6, - CONFIG_NET_APP_MY_IPV6_ADDR, - &my_addr) < 0) { - NET_ERR("Invalid IPv6 address %s", - CONFIG_NET_APP_MY_IPV6_ADDR); - } -#endif - - ifaddr = net_if_ipv6_addr_add(iface, &my_addr, NET_ADDR_MANUAL, 0); - if (!ifaddr) { - NET_ERR("Could not add unicast address to interface"); - return false; - } - - ifaddr->addr_state = NET_ADDR_PREFERRED; - - mcast = net_if_ipv6_maddr_add(iface, &mcast_addr.sin6_addr); - if (!mcast) { - NET_ERR("Could not add multicast address to interface\n"); - return false; - } - - return true; -} - -static void retransmit_request(struct k_work *work) -{ - struct zoap_pending *pending; - int r; - - pending = zoap_pending_next_to_expire(pendings, NUM_PENDINGS); - if (!pending) { - return; - } - - r = net_context_sendto(pending->pkt, &pending->addr, - sizeof(struct sockaddr_in6), - NULL, 0, NULL, NULL); - if (r < 0) { - return; - } - - if (!zoap_pending_cycle(pending)) { - zoap_pending_clear(pending); - return; - } - - k_delayed_work_submit(&retransmit_work, pending->timeout); -} - -void main(void) -{ - static struct sockaddr_in6 any_addr = { - .sin6_family = AF_INET6, - .sin6_addr = IN6ADDR_ANY_INIT, - .sin6_port = htons(MY_COAP_PORT) }; - int r; - - if (!join_coap_multicast_group()) { - NET_ERR("Could not join CoAP multicast group\n"); - return; - } - - r = net_context_get(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &context); - if (r) { - NET_ERR("Could not get an UDP context\n"); - return; - } - - r = net_context_bind(context, (struct sockaddr *) &any_addr, - sizeof(any_addr)); - if (r) { - NET_ERR("Could not bind the context\n"); - return; - } - - k_delayed_work_init(&retransmit_work, retransmit_request); - - k_delayed_work_init(&observer_work, update_counter); - k_delayed_work_submit(&observer_work, 5 * MSEC_PER_SEC); - - r = net_context_recv(context, udp_receive, 0, NULL); - if (r) { - NET_ERR("Could not receive in the context\n"); - return; - } -} From 6a1ea81432b358bd0107c6b5260cfbe7d937d4db Mon Sep 17 00:00:00 2001 From: Ravi kumar Veeramally Date: Mon, 28 Aug 2017 14:00:35 +0300 Subject: [PATCH 23/37] net: samples: Modify zoap_client to new CoAP api's Signed-off-by: Ravi kumar Veeramally --- doc/subsystems/networking/overview.rst | 2 +- .../net/{zoap_client => coap_client}/Makefile | 0 .../{zoap_client => coap_client}/README.rst | 2 +- .../net/{zoap_client => coap_client}/prj.conf | 2 +- .../{zoap_client => coap_client}/prj_bt.conf | 2 +- .../{zoap_client => coap_client}/sample.yaml | 0 .../{zoap_client => coap_client}/src/Makefile | 2 +- .../src/coap-client.c} | 101 ++++++++---------- 8 files changed, 52 insertions(+), 59 deletions(-) rename samples/net/{zoap_client => coap_client}/Makefile (100%) rename samples/net/{zoap_client => coap_client}/README.rst (98%) rename samples/net/{zoap_client => coap_client}/prj.conf (93%) rename samples/net/{zoap_client => coap_client}/prj_bt.conf (97%) rename samples/net/{zoap_client => coap_client}/sample.yaml (100%) rename samples/net/{zoap_client => coap_client}/src/Makefile (84%) rename samples/net/{zoap_client/src/zoap-client.c => coap_client/src/coap-client.c} (71%) diff --git a/doc/subsystems/networking/overview.rst b/doc/subsystems/networking/overview.rst index 5bdfc418c1969..239d643410e97 100644 --- a/doc/subsystems/networking/overview.rst +++ b/doc/subsystems/networking/overview.rst @@ -64,7 +64,7 @@ can be disabled if not needed. implemented. * **CoAP** Constrained Application Protocol (RFC 7252) is supported. - Both :ref:`zoap-client-sample` and :ref:`coap-server-sample` sample + Both :ref:`coap-client-sample` and :ref:`coap-server-sample` sample applications are implemented. A :ref:`coap-client-sample` and :ref:`coap-server-sample` using DTLS (Datagram Transport Layer Security) (RFC 6347) are also implemented. diff --git a/samples/net/zoap_client/Makefile b/samples/net/coap_client/Makefile similarity index 100% rename from samples/net/zoap_client/Makefile rename to samples/net/coap_client/Makefile diff --git a/samples/net/zoap_client/README.rst b/samples/net/coap_client/README.rst similarity index 98% rename from samples/net/zoap_client/README.rst rename to samples/net/coap_client/README.rst index 081301f84f177..04f44113c10ab 100644 --- a/samples/net/zoap_client/README.rst +++ b/samples/net/coap_client/README.rst @@ -1,4 +1,4 @@ -.. _zoap-client-sample: +.. _coap-client-sample: CoAP client ########### diff --git a/samples/net/zoap_client/prj.conf b/samples/net/coap_client/prj.conf similarity index 93% rename from samples/net/zoap_client/prj.conf rename to samples/net/coap_client/prj.conf index 614dbe3886620..363603a8e12e6 100644 --- a/samples/net/zoap_client/prj.conf +++ b/samples/net/coap_client/prj.conf @@ -7,4 +7,4 @@ CONFIG_SYS_LOG=y CONFIG_SYS_LOG_SHOW_COLOR=y CONFIG_RANDOM_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_ZOAP=y +CONFIG_COAP=y diff --git a/samples/net/zoap_client/prj_bt.conf b/samples/net/coap_client/prj_bt.conf similarity index 97% rename from samples/net/zoap_client/prj_bt.conf rename to samples/net/coap_client/prj_bt.conf index 5911d18a58084..ac7f224f1c8ef 100644 --- a/samples/net/zoap_client/prj_bt.conf +++ b/samples/net/coap_client/prj_bt.conf @@ -6,7 +6,7 @@ CONFIG_SYS_LOG=y CONFIG_SYS_LOG_SHOW_COLOR=y CONFIG_RANDOM_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_ZOAP=y +CONFIG_COAP=y CONFIG_NET_L2_BT=y CONFIG_NET_L2_BT_ZEP1656=y CONFIG_NET_DEBUG_L2_BT=y diff --git a/samples/net/zoap_client/sample.yaml b/samples/net/coap_client/sample.yaml similarity index 100% rename from samples/net/zoap_client/sample.yaml rename to samples/net/coap_client/sample.yaml diff --git a/samples/net/zoap_client/src/Makefile b/samples/net/coap_client/src/Makefile similarity index 84% rename from samples/net/zoap_client/src/Makefile rename to samples/net/coap_client/src/Makefile index d799baf118d18..e631cb66382f9 100644 --- a/samples/net/zoap_client/src/Makefile +++ b/samples/net/coap_client/src/Makefile @@ -3,4 +3,4 @@ ccflags-y +=-I${ZEPHYR_BASE}/samples/net/common/ ccflags-y +=-DNET_TESTING_SERVER=1 endif -obj-y = zoap-client.o +obj-y = coap-client.o diff --git a/samples/net/zoap_client/src/zoap-client.c b/samples/net/coap_client/src/coap-client.c similarity index 71% rename from samples/net/zoap_client/src/zoap-client.c rename to samples/net/coap_client/src/coap-client.c index 585d373b77219..9c256c0a2a906 100644 --- a/samples/net/zoap_client/src/zoap-client.c +++ b/samples/net/coap_client/src/coap-client.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #define MY_COAP_PORT 5683 @@ -32,8 +32,8 @@ static const struct sockaddr_in6 mcast_addr = { static struct net_context *context; -struct zoap_pending pendings[NUM_PENDINGS]; -struct zoap_reply replies[NUM_REPLIES]; +struct coap_pending pendings[NUM_PENDINGS]; +struct coap_reply replies[NUM_REPLIES]; struct k_delayed_work retransmit_work; #if defined(CONFIG_NET_MGMT_EVENT) @@ -52,8 +52,8 @@ static void msg_dump(const char *s, u8_t *data, unsigned len) printk("(%u bytes)\n", len); } -static int resource_reply_cb(const struct zoap_packet *response, - struct zoap_reply *reply, +static int resource_reply_cb(const struct coap_packet *response, + struct coap_reply *reply, const struct sockaddr *from) { struct net_pkt *pkt = response->pkt; @@ -63,48 +63,46 @@ static int resource_reply_cb(const struct zoap_packet *response, return 0; } +static void get_from_ip_addr(struct coap_packet *cpkt, + struct sockaddr_in6 *from) +{ + struct net_udp_hdr hdr, *udp_hdr; + + udp_hdr = net_udp_get_hdr(cpkt->pkt, &hdr); + if (!udp_hdr) { + return; + } + + net_ipaddr_copy(&from->sin6_addr, &NET_IPV6_HDR(cpkt->pkt)->src); + from->sin6_port = udp_hdr->src_port; + from->sin6_family = AF_INET6; +} + static void udp_receive(struct net_context *context, struct net_pkt *pkt, int status, void *user_data) { - struct zoap_pending *pending; - struct zoap_reply *reply; - struct zoap_packet response; + struct coap_pending *pending; + struct coap_reply *reply; + struct coap_packet response; struct sockaddr_in6 from; - struct net_udp_hdr hdr, *udp_hdr; - int header_len, r; - - /* - * zoap expects that buffer->data starts at the - * beginning of the CoAP header - */ - header_len = net_pkt_appdata(pkt) - pkt->frags->data; - net_buf_pull(pkt->frags, header_len); + int r; - r = zoap_packet_parse(&response, pkt); + r = coap_packet_parse(&response, pkt, NULL, 0); if (r < 0) { printk("Invalid data received (%d)\n", r); return; } - pending = zoap_pending_received(&response, pendings, + pending = coap_pending_received(&response, pendings, NUM_PENDINGS); if (pending) { /* If necessary cancel retransmissions */ } - net_ipaddr_copy(&from.sin6_addr, &NET_IPV6_HDR(pkt)->src); - - udp_hdr = net_udp_get_hdr(pkt, &hdr); - if (!udp_hdr) { - printk("Invalid UDP data received\n"); - return; - } - - from.sin6_port = udp_hdr->src_port; - - reply = zoap_response_received(&response, + get_from_ip_addr(&response, &from); + reply = coap_response_received(&response, (const struct sockaddr *) &from, replies, NUM_REPLIES); if (!reply) { @@ -115,10 +113,10 @@ static void udp_receive(struct net_context *context, static void retransmit_request(struct k_work *work) { - struct zoap_pending *pending; + struct coap_pending *pending; int r; - pending = zoap_pending_next_to_expire(pendings, NUM_PENDINGS); + pending = coap_pending_next_to_expire(pendings, NUM_PENDINGS); if (!pending) { return; } @@ -129,8 +127,8 @@ static void retransmit_request(struct k_work *work) return; } - if (!zoap_pending_cycle(pending)) { - zoap_pending_clear(pending); + if (!coap_pending_cycle(pending)) { + coap_pending_clear(pending); return; } @@ -142,9 +140,9 @@ static void event_iface_up(struct net_mgmt_event_callback *cb, { static struct sockaddr_in6 any_addr = { .sin6_addr = IN6ADDR_ANY_INIT, .sin6_family = AF_INET6 }; - struct zoap_packet request; - struct zoap_pending *pending; - struct zoap_reply *reply; + struct coap_packet request; + struct coap_pending *pending; + struct coap_reply *reply; const char * const *p; struct net_pkt *pkt; struct net_buf *frag; @@ -186,56 +184,51 @@ static void event_iface_up(struct net_mgmt_event_callback *cb, net_pkt_frag_add(pkt, frag); - r = zoap_packet_init(&request, pkt); + r = coap_packet_init(&request, pkt, 1, COAP_TYPE_CON, + 8, coap_next_token(), + COAP_METHOD_GET, coap_next_id()); if (r < 0) { return; } - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&request, 1); - zoap_header_set_type(&request, ZOAP_TYPE_CON); - zoap_header_set_code(&request, ZOAP_METHOD_GET); - zoap_header_set_id(&request, zoap_next_id()); - zoap_header_set_token(&request, zoap_next_token(), 8); - /* Enable observing the resource. */ - r = zoap_add_option(&request, ZOAP_OPTION_OBSERVE, - &observe, sizeof(observe)); + r = coap_packet_append_option(&request, COAP_OPTION_OBSERVE, + &observe, sizeof(observe)); if (r < 0) { printk("Unable add option to request.\n"); return; } for (p = test_path; p && *p; p++) { - r = zoap_add_option(&request, ZOAP_OPTION_URI_PATH, - *p, strlen(*p)); + r = coap_packet_append_option(&request, COAP_OPTION_URI_PATH, + *p, strlen(*p)); if (r < 0) { printk("Unable add option to request.\n"); return; } } - pending = zoap_pending_next_unused(pendings, NUM_PENDINGS); + pending = coap_pending_next_unused(pendings, NUM_PENDINGS); if (!pending) { printk("Unable to find a free pending to track " "retransmissions.\n"); return; } - r = zoap_pending_init(pending, &request, + r = coap_pending_init(pending, &request, (struct sockaddr *) &mcast_addr); if (r < 0) { printk("Unable to initialize a pending retransmission.\n"); return; } - reply = zoap_reply_next_unused(replies, NUM_REPLIES); + reply = coap_reply_next_unused(replies, NUM_REPLIES); if (!reply) { printk("No resources for waiting for replies.\n"); return; } - zoap_reply_init(reply, &request); + coap_reply_init(reply, &request); reply->reply = resource_reply_cb; r = net_context_sendto(pkt, (struct sockaddr *) &mcast_addr, @@ -246,7 +239,7 @@ static void event_iface_up(struct net_mgmt_event_callback *cb, return; } - zoap_pending_cycle(pending); + coap_pending_cycle(pending); k_delayed_work_submit(&retransmit_work, pending->timeout); From e0992750db18ce0dcb35134f5588cd0214b7a137 Mon Sep 17 00:00:00 2001 From: Ravi kumar Veeramally Date: Mon, 28 Aug 2017 11:25:11 +0300 Subject: [PATCH 24/37] net: samples: Modify coaps_server to new CoAP api's Signed-off-by: Ravi kumar Veeramally --- doc/subsystems/networking/overview.rst | 2 +- samples/net/coaps_server/README.rst | 2 +- samples/net/coaps_server/prj.conf | 2 +- samples/net/coaps_server/src/coaps_server.c | 171 ++++++++++---------- 4 files changed, 89 insertions(+), 88 deletions(-) diff --git a/doc/subsystems/networking/overview.rst b/doc/subsystems/networking/overview.rst index 239d643410e97..7dbf67bb9a49d 100644 --- a/doc/subsystems/networking/overview.rst +++ b/doc/subsystems/networking/overview.rst @@ -66,7 +66,7 @@ can be disabled if not needed. * **CoAP** Constrained Application Protocol (RFC 7252) is supported. Both :ref:`coap-client-sample` and :ref:`coap-server-sample` sample applications are implemented. A :ref:`coap-client-sample` and - :ref:`coap-server-sample` using DTLS (Datagram Transport Layer Security) + :ref:`coaps-server-sample` using DTLS (Datagram Transport Layer Security) (RFC 6347) are also implemented. * **LWM2M** OMA Lightweight Machine-to-Machine Protocol (V1.0 Feb 2017) is diff --git a/samples/net/coaps_server/README.rst b/samples/net/coaps_server/README.rst index 15bf27f096e15..bd997d1b63e35 100644 --- a/samples/net/coaps_server/README.rst +++ b/samples/net/coaps_server/README.rst @@ -1,4 +1,4 @@ -.. _coap-server-sample: +.. _coaps-server-sample: CoAP over DTLS sample server ############################ diff --git a/samples/net/coaps_server/prj.conf b/samples/net/coaps_server/prj.conf index a2f54a84f69c8..5a322a4efeb2f 100644 --- a/samples/net/coaps_server/prj.conf +++ b/samples/net/coaps_server/prj.conf @@ -16,7 +16,7 @@ CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=5 CONFIG_NET_MAX_CONTEXTS=10 -CONFIG_ZOAP=y +CONFIG_COAP=y CONFIG_MBEDTLS=y CONFIG_MBEDTLS_BUILTIN=y diff --git a/samples/net/coaps_server/src/coaps_server.c b/samples/net/coaps_server/src/coaps_server.c index 70cb19a36a243..9ef76547cb266 100644 --- a/samples/net/coaps_server/src/coaps_server.c +++ b/samples/net/coaps_server/src/coaps_server.c @@ -37,7 +37,7 @@ #include #include -#include +#include #include "udp.h" #include "udp_cfg.h" @@ -58,10 +58,10 @@ static unsigned char heap[8192]; #endif -#define ZOAP_BUF_SIZE 128 +#define COAP_BUF_SIZE 128 -NET_PKT_TX_SLAB_DEFINE(zoap_pkt_slab, 4); -NET_BUF_POOL_DEFINE(zoap_data_pool, 4, ZOAP_BUF_SIZE, 0, NULL); +NET_PKT_TX_SLAB_DEFINE(coap_pkt_slab, 4); +NET_BUF_POOL_DEFINE(coap_data_pool, 4, COAP_BUF_SIZE, 0, NULL); /* * Hardcoded values for server host and port @@ -76,45 +76,43 @@ const char psk_id[] = "Client_identity\0"; static mbedtls_ssl_context *curr_ctx; -static int send_response(struct zoap_packet *request, u8_t response_code) +static int send_response(struct coap_packet *request, u8_t response_code) { struct net_pkt *pkt; struct net_buf *frag; - struct zoap_packet response; + struct coap_packet response; u8_t code, type; u16_t id; int r; - code = zoap_header_get_code(request); - type = zoap_header_get_type(request); - id = zoap_header_get_id(request); + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); printk("*******\n"); printk("type: %u code %u id %u\n", type, code, id); printk("*******\n"); - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); + pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); if (!pkt) { return -ENOMEM; } - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); if (!frag) { + net_pkt_unref(pkt); return -ENOMEM; } net_pkt_frag_add(pkt, frag); - r = zoap_packet_init(&response, pkt); + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + 0, NULL, response_code, id); if (r < 0) { + net_pkt_unref(pkt); return -EINVAL; } - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, ZOAP_TYPE_ACK); - zoap_header_set_code(&response, response_code); - zoap_header_set_id(&response, id); - do { r = mbedtls_ssl_write(curr_ctx, frag->data, frag->len); } while (r == MBEDTLS_ERR_SSL_WANT_READ @@ -129,79 +127,80 @@ static int send_response(struct zoap_packet *request, u8_t response_code) return r; } -static int test_del(struct zoap_resource *resource, - struct zoap_packet *request, const struct sockaddr *from) +static int test_del(struct coap_resource *resource, + struct coap_packet *request) { - return send_response(request, ZOAP_RESPONSE_CODE_DELETED); + return send_response(request, COAP_RESPONSE_CODE_DELETED); } -static int test_put(struct zoap_resource *resource, - struct zoap_packet *request, const struct sockaddr *from) +static int test_put(struct coap_resource *resource, + struct coap_packet *request) { - return send_response(request, ZOAP_RESPONSE_CODE_CHANGED); + return send_response(request, COAP_RESPONSE_CODE_CHANGED); } -static int test_post(struct zoap_resource *resource, - struct zoap_packet *request, const struct sockaddr *from) +static int test_post(struct coap_resource *resource, + struct coap_packet *request) { - return send_response(request, ZOAP_RESPONSE_CODE_CREATED); + return send_response(request, COAP_RESPONSE_CODE_CREATED); } -static int piggyback_get(struct zoap_resource *resource, - struct zoap_packet *request, - const struct sockaddr *from) +static int piggyback_get(struct coap_resource *resource, + struct coap_packet *request) { struct net_pkt *pkt; struct net_buf *frag; - struct zoap_packet response; - u8_t *payload, code, type; - u16_t len, id; + struct coap_packet response; + u8_t payload[40], code, type; + u16_t id; int r; - code = zoap_header_get_code(request); - type = zoap_header_get_type(request); - id = zoap_header_get_id(request); + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); printk("*******\n"); printk("type: %u code %u id %u\n", type, code, id); printk("*******\n"); - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); + pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); if (!pkt) { return -ENOMEM; } - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); if (!frag) { + net_pkt_unref(pkt); return -ENOMEM; } net_pkt_frag_add(pkt, frag); - r = zoap_packet_init(&response, pkt); + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + 0, NULL, COAP_RESPONSE_CODE_CONTENT, id); if (r < 0) { + net_pkt_unref(pkt); return -EINVAL; } - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, ZOAP_TYPE_ACK); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CONTENT); - zoap_header_set_id(&response, id); - - payload = zoap_packet_get_payload(&response, &len); - if (!payload) { + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + net_pkt_unref(pkt); return -EINVAL; } /* The response that coap-client expects */ - r = snprintk((char *)payload, len, "Type: %u\nCode: %u\nMID: %u\n", - type, code, id); - if (r < 0 || r > len) { + r = snprintk((char *)payload, sizeof(payload), + "Type: %u\nCode: %u\nMID: %u\n", type, code, id); + if (r < 0) { + net_pkt_unref(pkt); return -EINVAL; } - r = zoap_packet_set_used(&response, r); - if (r) { + r = coap_packet_append_payload(&response, (u8_t *)payload, + strlen(payload)); + if (r < 0) { + net_pkt_unref(pkt); return -EINVAL; } @@ -219,22 +218,22 @@ static int piggyback_get(struct zoap_resource *resource, return r; } -static int query_get(struct zoap_resource *resource, - struct zoap_packet *request, const struct sockaddr *from) +static int query_get(struct coap_resource *resource, + struct coap_packet *request) { - struct zoap_option options[4]; + struct coap_option options[4]; struct net_pkt *pkt; struct net_buf *frag; - struct zoap_packet response; - u8_t *payload, code, type; - u16_t len, id; + struct coap_packet response; + u8_t payload[40], code, type; + u16_t id; int i, r; - code = zoap_header_get_code(request); - type = zoap_header_get_type(request); - id = zoap_header_get_id(request); + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); - r = zoap_find_options(request, ZOAP_OPTION_URI_QUERY, options, 4); + r = coap_find_options(request, COAP_OPTION_URI_QUERY, options, 4); if (r <= 0) { return -EINVAL; } @@ -261,43 +260,44 @@ static int query_get(struct zoap_resource *resource, printk("*******\n"); - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); + pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); if (!pkt) { return -ENOMEM; } - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); if (!frag) { + net_pkt_unref(pkt); return -ENOMEM; } net_pkt_frag_add(pkt, frag); - r = zoap_packet_init(&response, pkt); + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + 0, NULL, COAP_RESPONSE_CODE_CONTENT, id); if (r < 0) { + net_pkt_unref(pkt); return -EINVAL; } - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&response, 1); - zoap_header_set_type(&response, ZOAP_TYPE_ACK); - zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_CONTENT); - zoap_header_set_id(&response, id); - - payload = zoap_packet_get_payload(&response, &len); - if (!payload) { + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + net_pkt_unref(pkt); return -EINVAL; } /* The response that coap-client expects */ - r = snprintk((char *)payload, len, "Type: %u\nCode: %u\nMID: %u\n", - type, code, id); - if (r < 0 || r > len) { + r = snprintk((char *)payload, sizeof(payload), + "Type: %u\nCode: %u\nMID: %u\n", type, code, id); + if (r < 0) { + net_pkt_unref(pkt); return -EINVAL; } - r = zoap_packet_set_used(&response, r); - if (r) { + r = coap_packet_append_payload(&response, (u8_t *)payload, + strlen(payload)); + if (r < 0) { + net_pkt_unref(pkt); return -EINVAL; } @@ -321,7 +321,7 @@ static const char *const segments_path[] = { "seg1", "seg2", "seg3", NULL }; static const char *const query_path[] = { "query", NULL }; -static struct zoap_resource resources[] = { +static struct coap_resource resources[] = { {.get = piggyback_get, .post = test_post, .del = test_del, @@ -419,9 +419,11 @@ void dtls_server(void) int len, ret = 0; struct udp_context ctx; struct dtls_timing_context timer; - struct zoap_packet zpkt; + struct coap_packet zpkt; struct net_pkt *pkt; struct net_buf *frag; + struct coap_option options[16]; + u8_t opt_num = 16; mbedtls_ssl_cookie_ctx cookie_ctx; mbedtls_entropy_context entropy; @@ -553,21 +555,21 @@ void dtls_server(void) do { /* Read the request */ - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); + pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); if (!pkt) { mbedtls_printf("Could not get packet from slab\n"); goto exit; } - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); if (!frag) { mbedtls_printf("Could not get frag from pool\n"); goto exit; } net_pkt_frag_add(pkt, frag); - len = ZOAP_BUF_SIZE - 1; - memset(frag->data, 0, ZOAP_BUF_SIZE); + len = COAP_BUF_SIZE - 1; + memset(frag->data, 0, COAP_BUF_SIZE); ret = mbedtls_ssl_read(&ssl, frag->data, len); if (ret == MBEDTLS_ERR_SSL_WANT_READ || @@ -598,14 +600,13 @@ void dtls_server(void) len = ret; frag->len = len; - ret = zoap_packet_parse(&zpkt, pkt); + ret = coap_packet_parse(&zpkt, pkt, options, opt_num); if (ret) { mbedtls_printf("Could not parse packet\n"); goto exit; } - ret = zoap_handle_request(&zpkt, resources, - (const struct sockaddr *)&ssl); + ret = coap_handle_request(&zpkt, resources, options, opt_num); if (ret < 0) { mbedtls_printf("No handler for such request (%d)\n", ret); From 00a441a8ee2be6962f32c302d41fd996693704e4 Mon Sep 17 00:00:00 2001 From: Ravi kumar Veeramally Date: Mon, 28 Aug 2017 11:25:30 +0300 Subject: [PATCH 25/37] net: samples: Modify coaps_client to new CoAP api's Signed-off-by: Ravi kumar Veeramally --- doc/subsystems/networking/overview.rst | 2 +- samples/net/coaps_client/README.rst | 2 +- samples/net/coaps_client/prj.conf | 2 +- samples/net/coaps_client/src/coaps_client.c | 57 ++++++++++----------- 4 files changed, 29 insertions(+), 34 deletions(-) diff --git a/doc/subsystems/networking/overview.rst b/doc/subsystems/networking/overview.rst index 7dbf67bb9a49d..c82abd39b0132 100644 --- a/doc/subsystems/networking/overview.rst +++ b/doc/subsystems/networking/overview.rst @@ -65,7 +65,7 @@ can be disabled if not needed. * **CoAP** Constrained Application Protocol (RFC 7252) is supported. Both :ref:`coap-client-sample` and :ref:`coap-server-sample` sample - applications are implemented. A :ref:`coap-client-sample` and + applications are implemented. A :ref:`coaps-client-sample` and :ref:`coaps-server-sample` using DTLS (Datagram Transport Layer Security) (RFC 6347) are also implemented. diff --git a/samples/net/coaps_client/README.rst b/samples/net/coaps_client/README.rst index cadd12efe1692..a4c1e9ad9239a 100644 --- a/samples/net/coaps_client/README.rst +++ b/samples/net/coaps_client/README.rst @@ -1,4 +1,4 @@ -.. _coap-client-sample: +.. _coaps-client-sample: CoAP over DTLS sample client ############################ diff --git a/samples/net/coaps_client/prj.conf b/samples/net/coaps_client/prj.conf index c37694e773870..4fc6728ae02c4 100644 --- a/samples/net/coaps_client/prj.conf +++ b/samples/net/coaps_client/prj.conf @@ -20,7 +20,7 @@ CONFIG_MBEDTLS=y CONFIG_MBEDTLS_BUILTIN=y CONFIG_MBEDTLS_CFG_FILE="config-coap.h" -CONFIG_ZOAP=y +CONFIG_COAP=y CONFIG_NET_APP_SETTINGS=y CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::3" diff --git a/samples/net/coaps_client/src/coaps_client.c b/samples/net/coaps_client/src/coaps_client.c index 391727e42aa10..b18d85ef997ec 100644 --- a/samples/net/coaps_client/src/coaps_client.c +++ b/samples/net/coaps_client/src/coaps_client.c @@ -41,7 +41,7 @@ #include "mbedtls/entropy.h" #include "mbedtls/ctr_drbg.h" -#include +#include #if defined(MBEDTLS_DEBUG_C) #include "mbedtls/debug.h" @@ -66,12 +66,12 @@ const char *pers = "mini_client"; static unsigned char payload[128]; #define NUM_REPLIES 3 -struct zoap_reply replies[NUM_REPLIES]; +struct coap_reply replies[NUM_REPLIES]; -#define ZOAP_BUF_SIZE 128 +#define COAP_BUF_SIZE 128 -NET_PKT_TX_SLAB_DEFINE(zoap_pkt_slab, 4); -NET_BUF_POOL_DEFINE(zoap_data_pool, 4, ZOAP_BUF_SIZE, 0, NULL); +NET_PKT_TX_SLAB_DEFINE(coap_pkt_slab, 4); +NET_BUF_POOL_DEFINE(coap_data_pool, 4, COAP_BUF_SIZE, 0, NULL); static const char *const test_path[] = { "test", NULL }; @@ -95,8 +95,8 @@ static void msg_dump(const char *s, u8_t *data, unsigned int len) printk("(%u bytes)\n", len); } -static int resource_reply_cb(const struct zoap_packet *response, - struct zoap_reply *reply, +static int resource_reply_cb(const struct coap_packet *response, + struct coap_reply *reply, const struct sockaddr *from) { @@ -184,8 +184,8 @@ void dtls_client(void) int ret; struct udp_context ctx; struct dtls_timing_context timer; - struct zoap_packet request, zpkt; - struct zoap_reply *reply; + struct coap_packet request, zpkt; + struct coap_reply *reply; struct net_pkt *pkt; struct net_buf *frag; u8_t observe = 0; @@ -283,53 +283,48 @@ void dtls_client(void) /* Write to server */ retry: - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); + pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); if (!pkt) { goto exit; } - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); if (!frag) { goto exit; } net_pkt_frag_add(pkt, frag); - ret = zoap_packet_init(&request, pkt); + ret = coap_packet_init(&request, pkt, 1, COAP_TYPE_CON, + 0, NULL, COAP_METHOD_GET, coap_next_id()); if (ret < 0) { goto exit; } - zoap_header_set_version(&request, 1); - zoap_header_set_type(&request, ZOAP_TYPE_CON); - zoap_header_set_code(&request, ZOAP_METHOD_GET); - zoap_header_set_id(&request, zoap_next_id()); - zoap_header_set_token(&request, zoap_next_token(), 0); - /* Enable observing the resource. */ - ret = zoap_add_option(&request, ZOAP_OPTION_OBSERVE, - &observe, sizeof(observe)); + ret = coap_packet_append_option(&request, COAP_OPTION_OBSERVE, + &observe, sizeof(observe)); if (ret < 0) { mbedtls_printf("Unable add option to request.\n"); goto exit; } for (p = test_path; p && *p; p++) { - ret = zoap_add_option(&request, ZOAP_OPTION_URI_PATH, - *p, strlen(*p)); + ret = coap_packet_append_option(&request, COAP_OPTION_URI_PATH, + *p, strlen(*p)); if (ret < 0) { mbedtls_printf("Unable add option/path to request.\n"); goto exit; } } - reply = zoap_reply_next_unused(replies, NUM_REPLIES); + reply = coap_reply_next_unused(replies, NUM_REPLIES); if (!reply) { mbedtls_printf("No resources for waiting for replies.\n"); goto exit; } - zoap_reply_init(reply, &request); + coap_reply_init(reply, &request); reply->reply = resource_reply_cb; len = frag->len; @@ -346,24 +341,24 @@ void dtls_client(void) goto exit; } - pkt = net_pkt_get_reserve(&zoap_pkt_slab, 0, K_NO_WAIT); + pkt = net_pkt_get_reserve(&coap_pkt_slab, 0, K_NO_WAIT); if (!pkt) { mbedtls_printf("Could not get packet from pool\n"); goto exit; } - frag = net_buf_alloc(&zoap_data_pool, K_NO_WAIT); + frag = net_buf_alloc(&coap_data_pool, K_NO_WAIT); if (!frag) { mbedtls_printf("Could not get frag from pool\n"); goto exit; } net_pkt_frag_add(pkt, frag); - len = ZOAP_BUF_SIZE - 1; - memset(frag->data, 0, ZOAP_BUF_SIZE); + len = COAP_BUF_SIZE - 1; + memset(frag->data, 0, COAP_BUF_SIZE); do { - ret = mbedtls_ssl_read(&ssl, frag->data, ZOAP_BUF_SIZE - 1); + ret = mbedtls_ssl_read(&ssl, frag->data, COAP_BUF_SIZE - 1); } while (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE); @@ -390,13 +385,13 @@ void dtls_client(void) len = ret; frag->len = len; - ret = zoap_packet_parse(&zpkt, pkt); + ret = coap_packet_parse(&zpkt, pkt, NULL, 0); if (ret) { mbedtls_printf("Could not parse packet\n"); goto exit; } - reply = zoap_response_received(&zpkt, NULL, replies, NUM_REPLIES); + reply = coap_response_received(&zpkt, NULL, replies, NUM_REPLIES); if (!reply) { mbedtls_printf("No handler for response (%d)\n", ret); } From e38a1dd02e0e4d911212b3f30385628177d7c651 Mon Sep 17 00:00:00 2001 From: Ravi kumar Veeramally Date: Wed, 23 Aug 2017 14:57:06 +0300 Subject: [PATCH 26/37] net: samples: Add leds demo app over RPL and CoAP Signed-off-by: Ravi kumar Veeramally --- ...AP-support-for-Sparrow-Border-Router.patch | 272 ++++ samples/net/rpl-node/Makefile | 15 + samples/net/rpl-node/README.rst | 73 ++ samples/net/rpl-node/prj.conf | 88 ++ samples/net/rpl-node/src/Makefile | 9 + samples/net/rpl-node/src/main.c | 1165 +++++++++++++++++ samples/net/rpl-node/testcase.ini | 5 + 7 files changed, 1627 insertions(+) create mode 100644 samples/net/rpl-node/0001-Added-CoAP-support-for-Sparrow-Border-Router.patch create mode 100644 samples/net/rpl-node/Makefile create mode 100644 samples/net/rpl-node/README.rst create mode 100644 samples/net/rpl-node/prj.conf create mode 100644 samples/net/rpl-node/src/Makefile create mode 100644 samples/net/rpl-node/src/main.c create mode 100644 samples/net/rpl-node/testcase.ini diff --git a/samples/net/rpl-node/0001-Added-CoAP-support-for-Sparrow-Border-Router.patch b/samples/net/rpl-node/0001-Added-CoAP-support-for-Sparrow-Border-Router.patch new file mode 100644 index 0000000000000..9d2481c68fac9 --- /dev/null +++ b/samples/net/rpl-node/0001-Added-CoAP-support-for-Sparrow-Border-Router.patch @@ -0,0 +1,272 @@ +From cb38f06f84e8d3c1e021265d40a21bc16b5a8a44 Mon Sep 17 00:00:00 2001 +From: Ravi kumar Veeramally +Date: Fri, 9 Jun 2017 13:08:52 +0300 +Subject: [PATCH] Added CoAP support for Sparrow Border Router + +Sparrow border router communicates with only TLV messages. But +there are other implementations which does not support TLV. +Support added with generic CoAP based commands to retrieve +RPL and IPv6 information with CoAP commands. Also supported +LED's control methods. + +Signed-off-by: Ravi kumar Veeramally +--- + examples/sparrow/wsdemoserver.py | 4 +- + examples/sparrow/wspcoap.py | 81 +++++++++++++++++++++++++++ + examples/sparrow/wspnodes.py | 38 +++++++------ + examples/sparrow/www/index.html | 12 ++++ + products/sparrow-border-router/project-conf.h | 3 + + tools/sparrow/deviceserver.py | 1 + + 6 files changed, 120 insertions(+), 19 deletions(-) + create mode 100644 examples/sparrow/wspcoap.py + +diff --git a/examples/sparrow/wsdemoserver.py b/examples/sparrow/wsdemoserver.py +index 8db1db7..67127fa 100755 +--- a/examples/sparrow/wsdemoserver.py ++++ b/examples/sparrow/wsdemoserver.py +@@ -40,7 +40,7 @@ DEBUG = 0 + + import sys, subprocess, thread, string, tlvlib, socket, binascii + from SimpleWebSocketServer import WebSocket, SimpleWebSocketServer +-import json, deviceserver, struct, wspserial, wsptlvs, wspnodes ++import json, deviceserver, struct, wspserial, wsptlvs, wspnodes, wspcoap + import httpd + + # Some global vaiables +@@ -304,5 +304,5 @@ if __name__ == "__main__": + print "Starting demo server" + setup_state() + server = SimpleWebSocketServer('', 8001, DemoSocket) +- plugins = plugins + [wspserial.SerialCommands(), wsptlvs.TLVCommands(), wspnodes.NodeCommands()] ++ plugins = plugins + [wspserial.SerialCommands(), wsptlvs.TLVCommands(), wspnodes.NodeCommands(), wspcoap.CoAPCommands()] + server.serveforever() +diff --git a/examples/sparrow/wspcoap.py b/examples/sparrow/wspcoap.py +new file mode 100644 +index 0000000..a1b2899 +--- /dev/null ++++ b/examples/sparrow/wspcoap.py +@@ -0,0 +1,81 @@ ++import wsplugin, thread, subprocess, json, re, os.path ++ ++def coap_is_supported(): ++ return os.path.isfile("/home/rveerama/src/libcoap-develop/examples/coap-client") ++ ++def coap_get(ws, uri): ++ ws.stop = False ++ p=subprocess.Popen(["/home/rveerama/src/libcoap-develop/examples/coap-client", "-m", "get", uri], ++ stdout=subprocess.PIPE, stderr=subprocess.PIPE) ++ data = "" ++ try: ++ while not ws.stop: ++ line = p.stdout.readline() ++ if line == '': break ++ data = data + line ++ except Exception as e: ++ print e ++ print "CoAP Unexpected error:", sys.exc_info()[0] ++ p.terminate() ++ return data ++ ++# This assumes that data is ascii! ++def coap_put(ws, uri, data): ++ ws.stop = False ++ p=subprocess.Popen(["/home/rveerama/src/libcoap-develop/examples/coap-client", "-e" + data, ++ "-m", "put", uri], ++ stdout=subprocess.PIPE, stderr=subprocess.PIPE) ++ line = "" ++ try: ++ while not ws.stop: ++ line = p.stdout.readline() ++ if line == '': break ++ print line ++ except Exception as e: ++ print e ++ print "CoAP Unexpected error:", sys.exc_info()[0] ++ p.terminate() ++ return line ++ ++def coap_check(ws): ++ if not coap_is_supported(): ++ print "Error: can not find libcoap at /home/rveerama/src/libcoap-develop/examples/coap-client" ++ ws.sendMessage(json.dumps({"error":"Can not find libcoap. Please install libcoap in the server and try again."})) ++ return False ++ return True ++ ++# The plugin class ++class CoAPCommands(wsplugin.DemoPlugin): ++ ++ def get_commands(self): ++ return ["coapled", "coaptemp"] ++ ++ def handle_command(self, wsdemo, cmds): ++ if cmds[0] == "coapled": ++ if coap_check(wsdemo): ++ ip = cmds[1] ++ led = cmds[2] ++ on = cmds[3] ++ thread.start_new_thread(coapled, (wsdemo, ip, led, on)) ++ return True ++ elif cmds[0] == "coaptemp": ++ if coap_check(wsdemo): ++ ip = cmds[1] ++ thread.start_new_thread(coaptemp, (wsdemo, ip)) ++ return True ++ return False ++ ++# Toggle a LED on a Yanzi IoT-U10 node (or other node with LEDs) ++def coapled(ws, ip, led, on): ++ coap_put(ws, "coap://[" + ip + "]/led/" + led, on) ++ ++# Read the temperature from a Yanzi IoT-U10 node ++def coaptemp(ws, ip): ++ temperature = coap_get(ws, "coap://[" + ip + "]/temperature") ++ print "\t",temperature ++ # get the temperature from the coap response ++ m = re.search("Temperature .+: (.+)", temperature) ++ if m: ++ ws.sendMessage(json.dumps({"temp":m.group(1),"address":ip})) ++ else: ++ ws.sendMessage(json.dumps({"error":"Failed to fetch temperature via CoAP"})) +diff --git a/examples/sparrow/wspnodes.py b/examples/sparrow/wspnodes.py +index 3f5dc13..abfd1ae 100644 +--- a/examples/sparrow/wspnodes.py ++++ b/examples/sparrow/wspnodes.py +@@ -28,6 +28,7 @@ + # + + import socket, binascii, wsplugin, tlvlib, thread, deviceserver, json, struct, urllib2, time ++import wspcoap + + RANK_DIVISOR = 128.0 + +@@ -102,37 +103,40 @@ class NodeCommands(wsplugin.DemoPlugin): + node = 2 + nodes[endfix] = 1 + for device in devs: +- rpl = device.nstats_rpl +- parent = None ++ rpl = wspcoap.coap_get(ws, "coap://[" + device.address + "]/rpl-info") + if rpl is None: + rank = "unknown" + else: +- rank = rpl.dag_rank() / RANK_DIVISOR +- parent = rpl.parent_as_string() ++ parent1 = rpl.split('\n', 4)[1] ++ rank1 = rpl.split('\n', 4)[2] ++ rank = rank1.split('-', 2)[1], ++ parent = parent1.split('-', 2)[1] + addr = socket.inet_pton(socket.AF_INET6, device.address) + endfix = binascii.hexlify(addr[-4:]) + # First we add the parent as level - second round we will + # change this to "level" instead +- topology["nodes"] = topology["nodes"] + [{"id":node, "label":"N" + str(node), "title":"Rank " + str(rank) + "
" + device.address, +- "level":-1, "parent":parent, "address":endfix}] ++ topology["nodes"] = topology["nodes"] + [{"id":node, "label":"N" + str(node), ++ "title":"Rank " + str(rank) + "
" + device.address, ++ "level":-1, "parent":str(parent), "address":endfix}] + nodes[endfix] = node + node = node + 1 + +- changed = True +- i = 0 + edges = [] +- while changed and i < 10: +- changed = False ++ i = 0 ++ while i < 3: + i = i + 1 + for n in topology["nodes"]: + if n["level"] is -1: +- p = topology["nodes"][nodes[n["parent"]] - 1] +- # add an edge +- edges = edges + [{"from":p["id"],"to":n["id"]}] +- if p["level"] is not -1: +- n["level"] = p["level"] + 1 +- #print "level should be ", p["level"] + 1 +- changed = True ++ parent = socket.inet_pton(socket.AF_INET6, n["parent"]) ++ endfix = binascii.hexlify(parent[-4:]) ++ for k in topology["nodes"]: ++ if k["address"] == endfix: ++ # add an edge ++ edges = edges + [{"from":k["id"],"to":n["id"]}] ++ if k["level"] is not -1: ++ n["level"] = k["level"] + 1 ++ break ++ + topology["edges"] = edges + print "Sending json: ",json.dumps({'topology':topology}) + ws.sendMessage(json.dumps({'topology':topology})) +diff --git a/examples/sparrow/www/index.html b/examples/sparrow/www/index.html +index 685fb64..631f597 100644 +--- a/examples/sparrow/www/index.html ++++ b/examples/sparrow/www/index.html +@@ -292,6 +292,9 @@ function getTypeButtons(type, address) { + ' ' + + ' ' + + ''; ++ } else { ++ buttons = buttons + ++ ' '; + } + return buttons; + } +@@ -305,6 +308,14 @@ function temp_read(address) { + doSend("tlvtemp " + address); + } + ++function coap_led_control(address, led, val) { ++ doSend("coapled " + address + " " + led + " " + val); ++} ++ ++function coap_temp_read(address) { ++ doSend("coaptemp " + address); ++} ++ + function handleEvent(json) { + if (json.event.type == "discovery") { + addr = json.event.address.replace(new RegExp(":", 'g'), "\\:"); +@@ -563,6 +574,7 @@ function updateRSSI(rssi) { +
  • Javascript-surface-plot by Greg Ross (New BSD License) +
  • Vis.js for Network Topology Graphs (Apache 2.0 and MIT License) +
  • SimpleWebSocketServer - Python library by Dave Pallot (MIT License) ++
  • libcoap - a CoAP library by Olaf Bergmann (BSD License) + + + +diff --git a/products/sparrow-border-router/project-conf.h b/products/sparrow-border-router/project-conf.h +index 0921f13..1a8f32e 100644 +--- a/products/sparrow-border-router/project-conf.h ++++ b/products/sparrow-border-router/project-conf.h +@@ -88,6 +88,8 @@ + #undef WEBSERVER_CONF_CFS_CONNS + #define WEBSERVER_CONF_CFS_CONNS 2 + ++#define WEBSERVER 1 ++ + #define CMD_CONF_OUTPUT border_router_cmd_output + #define CMD_CONF_ERROR border_router_cmd_error + +@@ -100,6 +102,7 @@ + /* Configure DAO routes to have a lifetime of 30 x 60 seconds */ + #define RPL_CONF_DEFAULT_LIFETIME_UNIT 60 + #define RPL_CONF_DEFAULT_LIFETIME 30 ++#define RPL_CONF_WITH_DAO_ACK 1 + + #undef NBR_TABLE_CONF_MAX_NEIGHBORS + #define NBR_TABLE_CONF_MAX_NEIGHBORS 1000 +diff --git a/tools/sparrow/deviceserver.py b/tools/sparrow/deviceserver.py +index 754e872..3796ad5 100755 +--- a/tools/sparrow/deviceserver.py ++++ b/tools/sparrow/deviceserver.py +@@ -595,6 +595,7 @@ class DeviceServer: + + p = re.compile(" ([a-fA-F0-9:]+)(/| prefixlen )") + m = p.search(output) ++ return default_host + if m: + return m.group(1) + else: +-- +2.11.0 + diff --git a/samples/net/rpl-node/Makefile b/samples/net/rpl-node/Makefile new file mode 100644 index 0000000000000..7d0723ff32823 --- /dev/null +++ b/samples/net/rpl-node/Makefile @@ -0,0 +1,15 @@ +# Makefile - RPL node test application + +# +# Copyright (c) 2017 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +BOARD ?= quark_se_c1000_devboard +CONF_FILE ?= prj.conf + +include $(ZEPHYR_BASE)/Makefile.inc +include $(ZEPHYR_BASE)/samples/net/common/Makefile.ipstack + +# QEMU_EXTRA_FLAGS = -serial unix:/tmp/bt-server-bredr diff --git a/samples/net/rpl-node/README.rst b/samples/net/rpl-node/README.rst new file mode 100644 index 0000000000000..27663824dcb7d --- /dev/null +++ b/samples/net/rpl-node/README.rst @@ -0,0 +1,73 @@ +.. _rpl-node-sample: + +RPL node +########### + +Overview +******** + +This sample builds a simple RPL node and shows how to join into an RPL +mesh network. + +This sample assumes that your chosen platform has networking support. +Some code configuration adjustments may be needed. + +The sample will listen for RPL multicast messages and joins with the RPL +Border Router node in DAG network. + +The sample exports the following resources through a CoAP server role: + +.. code-block:: none + + /led + /ipv6/neighbors + /rpl-info + /rpl-info/parent + /rpl-info/rank + /rpl-info/link-metric + +These resources allow you to toggle an on-board LED (if available) and build +the RPL mesh network topology from node RPL information. + +Building And Running +******************** + +If you're using a Sparrow border router, follow the steps below to build and +run Sparrow BR. (Sparrow has its own TLV mechanism to build topology that +Zephyr doesn't support.) A patch is provided in the sample folder to to support +building topology with CoAP-based responses. + +Running Sparrow BR +================== + +.. code-block:: console + + git clone https://github.com/sics-iot/sparrow.git + cd sparrow + git am 0001-Added-CoAP-support-for-Sparrow-Border-Router.patch + cd products/sparrow-border-router + sudo make connect-high PORT=/dev/ttyACM0 + +If your PC is using an http proxy, you should unset it for this sample. +Wait until the border router is up and running. The python script used below +will run a web-based UI. + +.. code-block:: console + + cd examples/sparrow + ./wsdemoserver.py + +Wait until you see "Connected" message on console. Unset proxy in browser +and open 127.0.0.1:8000. + +Running RPL node +================ + +To build and run RPL node, follow the below steps to build and install +it on IEEE 802.15.4 radio supported board. + +.. code-block:: console + + $ make pristine and make flash + +Wait until the RPL node joins with Border-Router and updates the list in the web UI. diff --git a/samples/net/rpl-node/prj.conf b/samples/net/rpl-node/prj.conf new file mode 100644 index 0000000000000..02fde29c40b03 --- /dev/null +++ b/samples/net/rpl-node/prj.conf @@ -0,0 +1,88 @@ +CONFIG_ARC_INIT=n + +CONFIG_NETWORKING=y + +CONFIG_RANDOM_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y + +CONFIG_NET_PKT_RX_COUNT=15 +CONFIG_NET_PKT_TX_COUNT=15 +CONFIG_NET_BUF_RX_COUNT=25 +CONFIG_NET_BUF_TX_COUNT=25 + +CONFIG_NET_IPV6=y +CONFIG_NET_IPV6_RA_RDNSS=n +CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 +CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4 +CONFIG_NET_IF_IPV6_PREFIX_COUNT=5 + +CONFIG_NET_IPV6_ND=n +CONFIG_NET_IPV6_DAD=y +CONFIG_NET_IPV6_MLD=n + +CONFIG_NET_UDP=y + +CONFIG_NET_6LO=y +CONFIG_NET_6LO_CONTEXT=y +CONFIG_NET_MAX_6LO_CONTEXTS=3 + +CONFIG_NET_LOG=y +CONFIG_SYS_LOG_SHOW_COLOR=y +CONFIG_SYS_LOG_NET_LEVEL=4 +CONFIG_INIT_STACKS=y +CONFIG_PRINTK=y + +CONFIG_NET_BUF_LOG=n +CONFIG_SYS_LOG_NET_BUF_LEVEL=1 + +CONFIG_GPIO=y + +CONFIG_COAP=y +CONFIG_COAP_WELL_KNOWN_BLOCK_WISE=y +CONFIG_COAP_WELL_KNOWN_BLOCK_WISE_SIZE=64 +CONFIG_NET_DEBUG_COAP=y + +CONFIG_NET_RPL=y +CONFIG_NET_RPL_PROBING=y +CONFIG_NET_RPL_STATS=y +CONFIG_NET_RPL_MIN_HOP_RANK_INC=128 + +CONFIG_NET_L2_IEEE802154=y +CONFIG_NET_L2_IEEE802154_FRAGMENT=y +CONFIG_IEEE802154_CC2520=y +CONFIG_IEEE802154_CC2520_AUTO_ACK=n + +# IP core debug +CONFIG_NET_DEBUG_CORE=y +CONFIG_NET_DEBUG_IPV6_NBR_CACHE=y +CONFIG_NET_DEBUG_IPV6=y +CONFIG_NET_DEBUG_NET_BUF=n +CONFIG_NET_DEBUG_UTILS=n +CONFIG_NET_DEBUG_IF=y +CONFIG_NET_DEBUG_ICMPV6=y +CONFIG_NET_DEBUG_CONN=n +CONFIG_NET_DEBUG_UDP=n +CONFIG_NET_DEBUG_CONTEXT=n +CONFIG_NET_DEBUG_ROUTE=y +CONFIG_NET_DEBUG_6LO=n +CONFIG_NET_DEBUG_RPL=y + +CONFIG_NET_STATISTICS=n +CONFIG_NET_STATISTICS_PERIODIC_OUTPUT=n + +CONFIG_NET_SHELL=y + +# L2 Debug +CONFIG_NET_DEBUG_L2_IEEE802154=n +CONFIG_NET_DEBUG_L2_IEEE802154_FRAGMENT=n +CONFIG_SYS_LOG_IEEE802154_DRIVER_LEVEL=0 + +CONFIG_NET_APP_SETTINGS=y +CONFIG_NET_APP_IEEE802154_CHANNEL=18 +CONFIG_NET_APP_IEEE802154_DEV_NAME="cc2520" + +CONFIG_IEEE802154_CC2520_RANDOM_MAC=n +CONFIG_IEEE802154_CC2520_MAC4=0x00 +CONFIG_IEEE802154_CC2520_MAC5=0x00 +CONFIG_IEEE802154_CC2520_MAC6=0x00 +CONFIG_IEEE802154_CC2520_MAC7=0x03 diff --git a/samples/net/rpl-node/src/Makefile b/samples/net/rpl-node/src/Makefile new file mode 100644 index 0000000000000..5887fb498172b --- /dev/null +++ b/samples/net/rpl-node/src/Makefile @@ -0,0 +1,9 @@ +ccflags-y += -I${ZEPHYR_BASE}/subsys/net/ip +obj-y = main.o + +ifeq ($(CONFIG_NET_L2_IEEE802154), y) +ccflags-y +=-I${ZEPHYR_BASE}/samples/net/common/ +ifeq ($(CONFIG_NET_APP_SETTINGS), y) +obj-y += ../../common/ieee802154_settings.o +endif +endif diff --git a/samples/net/rpl-node/src/main.c b/samples/net/rpl-node/src/main.c new file mode 100644 index 0000000000000..0668a8e93537d --- /dev/null +++ b/samples/net/rpl-node/src/main.c @@ -0,0 +1,1165 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if 1 +#define SYS_LOG_DOMAIN "rpl-node" +#define NET_SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG +#define NET_LOG_ENABLED 1 +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include <6lo.h> +#include + +#include + +#include +#include + +#if defined(CONFIG_NET_L2_IEEE802154) +#include +#endif + +#define MY_COAP_PORT 5683 + +#define ALL_NODES_LOCAL_COAP_MCAST \ + { { { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xfd } } } + +#if defined(LED0_GPIO_PORT) +#define LED_GPIO_NAME LED0_GPIO_PORT +#define LED_PIN LED0_GPIO_PIN +#else +#define LED_GPIO_NAME "(fail)" +#define LED_PIN 0 +#endif + +#define RPL_MAX_REPLY 75 + +#define PKT_WAIT_TIME K_SECONDS(1) + +static struct net_context *context; +static struct device *led0; +static const u8_t plain_text_format; + +/* LED */ +static const char led_on[] = "LED0 ON"; +static const char led_off[] = "LED0 OFF"; +static const char led_toggle_on[] = "LED Toggle ON"; +static const char led_toggle_off[] = "LED Toggle OFF"; + +static bool fake_led; + +/* RPL */ +static const char rpl_parent[] = "RPL Parent:"; +static const char rpl_no_parent[] = "No parent yet"; + +static const char rpl_rank[] = "RPL Rank:"; +static const char rpl_no_rank[] = "No rank yet"; + +static const char rpl_link[] = "Link Metric:"; +static const char rpl_no_link[] = "No link metric yet"; + +static const char ipv6_no_nbr[] = "No IPv6 Neighbors"; + +static void get_from_ip_addr(struct coap_packet *cpkt, + struct sockaddr_in6 *from) +{ + struct net_udp_hdr hdr, *udp_hdr; + + udp_hdr = net_udp_get_hdr(cpkt->pkt, &hdr); + if (!udp_hdr) { + return; + } + + net_ipaddr_copy(&from->sin6_addr, &NET_IPV6_HDR(cpkt->pkt)->src); + from->sin6_port = udp_hdr->src_port; + from->sin6_family = AF_INET6; +} + +static void send_error_response(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr_in6 *from) +{ + struct net_context *context; + struct coap_packet response; + struct net_pkt *pkt; + struct net_buf *frag; + u16_t id; + int r; + + id = coap_header_get_id(request); + context = net_pkt_context(request->pkt); + + pkt = net_pkt_get_tx(context, PKT_WAIT_TIME); + if (!pkt) { + return; + } + + frag = net_pkt_get_data(context, PKT_WAIT_TIME); + if (!frag) { + net_pkt_unref(pkt); + return; + } + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + 0, NULL, COAP_RESPONSE_CODE_BAD_REQUEST, id); + if (r < 0) { + net_pkt_unref(pkt); + return; + } + + r = net_context_sendto(pkt, (const struct sockaddr *)from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); + if (r < 0) { + net_pkt_unref(pkt); + } +} + +static int well_known_core_get(struct coap_resource *resource, + struct coap_packet *request) +{ + struct coap_packet response; + struct sockaddr_in6 from; + struct net_pkt *pkt; + struct net_buf *frag; + int r; + + NET_DBG(""); + + pkt = net_pkt_get_tx(context, K_FOREVER); + if (!pkt) { + return -ENOMEM; + } + + frag = net_pkt_get_data(context, K_FOREVER); + if (!frag) { + net_pkt_unref(pkt); + return -ENOMEM; + } + + net_pkt_frag_add(pkt, frag); + + r = coap_well_known_core_get(resource, request, &response, pkt); + if (r < 0) { + net_pkt_unref(response.pkt); + send_error_response(resource, request, &from); + + return r; + } + + get_from_ip_addr(request, &from); + + r = net_context_sendto(response.pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); + if (r < 0) { + net_pkt_unref(response.pkt); + } + + return r; +} + +static bool read_led(void) +{ + u32_t led = 0; + int r; + + if (!led0) { + return fake_led; + } + + r = gpio_pin_read(led0, LED_PIN, &led); + if (r < 0) { + return false; + } + + return led; +} + +static void write_led(bool led) +{ + if (!led0) { + fake_led = led; + return; + } + + gpio_pin_write(led0, LED_PIN, led); +} + +static int led_get(struct coap_resource *resource, + struct coap_packet *request) +{ + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + const char *str; + u16_t len, id; + int r; + + NET_DBG(""); + + id = coap_header_get_id(request); + + pkt = net_pkt_get_tx(context, K_FOREVER); + if (!pkt) { + return -ENOMEM; + } + + frag = net_pkt_get_data(context, K_FOREVER); + if (!frag) { + net_pkt_unref(pkt); + return -ENOMEM; + } + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + 0, NULL, COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + if (read_led()) { + str = led_on; + len = sizeof(led_on); + } else { + str = led_off; + len = sizeof(led_off); + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_payload(&response, (u8_t *)str, len); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + get_from_ip_addr(request, &from); + r = net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); + if (r < 0) { + net_pkt_unref(pkt); + } + + return r; +} + +static int led_post(struct coap_resource *resource, + struct coap_packet *request) +{ + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + const char *str; + u16_t offset; + u16_t len; + u16_t id; + u32_t led; + u8_t payload; + int r; + + NET_DBG(""); + + led = 0; + + frag = net_frag_skip(request->frag, request->offset, &offset, + request->hdr_len + request->opt_len); + if (!frag && offset == 0xffff) { + return -EINVAL; + } + + frag = net_frag_read_u8(frag, offset, &offset, &payload); + if (!frag && offset == 0xffff) { + printk("packet without payload, so toggle the led"); + + led = read_led(); + led = !led; + } else { + if (payload == 0x31) { + led = 1; + } + } + + write_led(led); + + id = coap_header_get_id(request); + + pkt = net_pkt_get_tx(context, K_FOREVER); + if (!pkt) { + return -ENOMEM; + } + + frag = net_pkt_get_data(context, K_FOREVER); + if (!frag) { + net_pkt_unref(pkt); + return -ENOMEM; + } + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + 0, NULL, COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + if (led) { + str = led_toggle_on; + len = sizeof(led_toggle_on); + } else { + str = led_toggle_off; + len = sizeof(led_toggle_off); + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_payload(&response, (u8_t *)str, len); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + get_from_ip_addr(request, &from); + r = net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); + if (r < 0) { + net_pkt_unref(pkt); + } + + return r; +} + +static int led_put(struct coap_resource *resource, + struct coap_packet *request) +{ + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + const char *str; + u16_t offset; + u16_t len; + u16_t id; + u32_t led; + u8_t payload; + int r; + + NET_DBG(""); + + led = 0; + + frag = net_frag_skip(request->frag, request->offset, &offset, + request->hdr_len + request->opt_len); + if (!frag && offset == 0xffff) { + return -EINVAL; + } + + frag = net_frag_read_u8(frag, offset, &offset, &payload); + if (!frag && offset == 0xffff) { + printk("packet without payload, so toggle the led"); + + led = read_led(); + led = !led; + } else { + if (payload == 0x31) { + led = 1; + } + } + + write_led(led); + + id = coap_header_get_id(request); + + pkt = net_pkt_get_tx(context, K_FOREVER); + if (!pkt) { + return -ENOMEM; + } + + frag = net_pkt_get_data(context, K_FOREVER); + if (!frag) { + net_pkt_unref(pkt); + return -ENOMEM; + } + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + 0, NULL, COAP_RESPONSE_CODE_CHANGED, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + if (led) { + str = led_on; + len = sizeof(led_on); + } else { + str = led_off; + len = sizeof(led_off); + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_payload(&response, (u8_t *)str, len); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + get_from_ip_addr(request, &from); + r = net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); + if (r < 0) { + net_pkt_unref(pkt); + } + + return r; +} + +struct ipv6_nbr_str { + char str[(sizeof("xx:xx:xx:xx:xx:xx:xx:xx") * + CONFIG_NET_IPV6_MAX_NEIGHBORS) + + CONFIG_NET_IPV6_MAX_NEIGHBORS]; + u8_t len; +}; + +static void ipv6_nbr_cb(struct net_nbr *nbr, void *user_data) +{ + struct ipv6_nbr_str *nbr_str = user_data; + char temp[sizeof("xx:xx:xx:xx:xx:xx:xx:xx") + sizeof("\n")]; + + snprintk(temp, sizeof(temp), "%s\n", + net_sprint_ipv6_addr(&net_ipv6_nbr_data(nbr)->addr)); + + memcpy(nbr_str->str + nbr_str->len, temp, strlen(temp)); + nbr_str->len += strlen(temp); +} + +/* IPv6 Neighbors */ +static int ipv6_neighbors_get(struct coap_resource *resource, + struct coap_packet *request) +{ + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + struct ipv6_nbr_str nbr_str; + u8_t token[8]; + const char *str; + u16_t len, id; + u8_t tkl; + int r; + + NET_DBG(""); + + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, (u8_t *)token); + + pkt = net_pkt_get_tx(context, K_FOREVER); + if (!pkt) { + return -ENOMEM; + } + + frag = net_pkt_get_data(context, K_FOREVER); + if (!frag) { + net_pkt_unref(pkt); + return -ENOMEM; + } + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + tkl, token, COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_option(&response, COAP_OPTION_CONTENT_FORMAT, + &plain_text_format, + sizeof(plain_text_format)); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + nbr_str.len = 0; + net_ipv6_nbr_foreach(ipv6_nbr_cb, &nbr_str); + + if (nbr_str.len) { + str = nbr_str.str; + len = nbr_str.len; + } else { + str = ipv6_no_nbr; + len = strlen(ipv6_no_nbr); + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_payload(&response, (u8_t *)str, len); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + get_from_ip_addr(request, &from); + r = net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); + if (r < 0) { + net_pkt_unref(pkt); + } + + return r; +} + +/* RPL Information */ +static int rpl_info_get(struct coap_resource *resource, + struct coap_packet *request) +{ + struct net_rpl_instance *rpl; + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + struct in6_addr *parent; + struct net_nbr *nbr; + const char *str; + u8_t token[8]; + u16_t len, id; + u16_t out_len; + u8_t tkl; + int r; + char out[RPL_MAX_REPLY]; + + NET_DBG(""); + + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, (u8_t *)token); + + pkt = net_pkt_get_tx(context, K_FOREVER); + if (!pkt) { + net_pkt_unref(pkt); + return -ENOMEM; + } + + frag = net_pkt_get_data(context, K_FOREVER); + if (!frag) { + net_pkt_unref(pkt); + return -ENOMEM; + } + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + tkl, token, COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_option(&response, COAP_OPTION_CONTENT_FORMAT, + &plain_text_format, + sizeof(plain_text_format)); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + rpl = net_rpl_get_default_instance(); + if (rpl && rpl->current_dag && rpl->current_dag->preferred_parent) { + nbr = net_rpl_get_nbr(rpl->current_dag->preferred_parent); + } else { + nbr = NULL; + } + + /* Write all RPL info in JSON format */ + snprintk(out, sizeof(out) - 1, "parent-"); + out_len = strlen(out); + + if (!rpl || !rpl->current_dag || !rpl->current_dag->preferred_parent) { + snprintk(&out[out_len], sizeof(out) - out_len - 1, "None"); + } else { + parent = net_rpl_get_parent_addr(net_pkt_iface(pkt), + rpl->current_dag->preferred_parent); + snprintk(&out[out_len], sizeof(out) - out_len - 1, "%s", + net_sprint_ipv6_addr(parent)); + } + + out_len = strlen(out); + + snprintk(&out[out_len], sizeof(out) - out_len - 1, "\nrank-"); + out_len = strlen(out); + + if (!rpl || !rpl->current_dag) { + snprintk(&out[out_len], sizeof(out) - out_len - 1, "inf"); + } else { + snprintk(&out[out_len], sizeof(out) - out_len - 1, "%u.%02u", + rpl->current_dag->rank / NET_RPL_MC_ETX_DIVISOR, + (100 * (rpl->current_dag->rank % + NET_RPL_MC_ETX_DIVISOR)) / + NET_RPL_MC_ETX_DIVISOR); + } + + out_len = strlen(out); + + snprintk(&out[out_len], sizeof(out) - out_len - 1, "\nlinkmetric-"); + out_len = strlen(out); + + if (!nbr) { + snprintk(&out[out_len], sizeof(out) - out_len - 1, "inf"); + } else { + snprintk(&out[out_len], sizeof(out) - out_len - 1, "%u.%02u", + (net_ipv6_nbr_data(nbr)->link_metric) / + NET_RPL_MC_ETX_DIVISOR, + (100 * ((net_ipv6_nbr_data(nbr)->link_metric) % + NET_RPL_MC_ETX_DIVISOR)) / + NET_RPL_MC_ETX_DIVISOR); + } + + out_len = strlen(out); + + str = out; + len = out_len; + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_payload(&response, (u8_t *)str, len); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + get_from_ip_addr(request, &from); + r = net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); + if (r < 0) { + net_pkt_unref(pkt); + } + + return r; +} + +/* RPL Parent */ +static int rpl_parent_get(struct coap_resource *resource, + struct coap_packet *request) +{ + struct net_rpl_instance *rpl; + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + struct in6_addr *parent; + const char *str; + u8_t token[8]; + u16_t len, id; + u8_t tkl; + int r; + char out[RPL_MAX_REPLY]; + + NET_DBG(""); + + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, (u8_t *)token); + + pkt = net_pkt_get_tx(context, K_FOREVER); + if (!pkt) { + return -ENOMEM; + } + + frag = net_pkt_get_data(context, K_FOREVER); + if (!frag) { + net_pkt_unref(pkt); + return -ENOMEM; + } + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + tkl, token, COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_option(&response, COAP_OPTION_CONTENT_FORMAT, + &plain_text_format, + sizeof(plain_text_format)); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + rpl = net_rpl_get_default_instance(); + if (!rpl || !rpl->current_dag || !rpl->current_dag->preferred_parent) { + str = rpl_no_parent; + len = sizeof(rpl_no_parent); + + } else { + parent = net_rpl_get_parent_addr(net_pkt_iface(pkt), + rpl->current_dag->preferred_parent); + snprintk(out, sizeof(out), "%s %s", rpl_parent, + net_sprint_ipv6_addr(parent)); + str = out; + len = strlen(out); + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_payload(&response, (u8_t *)str, len); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + get_from_ip_addr(request, &from); + r = net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); + if (r < 0) { + net_pkt_unref(pkt); + } + + return r; +} + +/* RPL Rank */ +static int rpl_rank_get(struct coap_resource *resource, + struct coap_packet *request) +{ + struct net_rpl_instance *rpl; + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + const char *str; + u8_t token[8]; + u16_t len, id; + u8_t tkl; + int r; + char out[RPL_MAX_REPLY]; + + NET_DBG(""); + + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, (u8_t *)token); + + pkt = net_pkt_get_tx(context, K_FOREVER); + if (!pkt) { + return -ENOMEM; + } + + frag = net_pkt_get_data(context, K_FOREVER); + if (!frag) { + net_pkt_unref(pkt); + return -ENOMEM; + } + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + tkl, token, COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_option(&response, COAP_OPTION_CONTENT_FORMAT, + &plain_text_format, + sizeof(plain_text_format)); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + rpl = net_rpl_get_default_instance(); + if (!rpl || !rpl->current_dag) { + str = rpl_no_rank; + len = sizeof(rpl_no_rank); + + } else { + snprintk(out, sizeof(out), "%s %u.%02u", rpl_rank, + rpl->current_dag->rank / NET_RPL_MC_ETX_DIVISOR, + (100 * (rpl->current_dag->rank % + NET_RPL_MC_ETX_DIVISOR)) / + NET_RPL_MC_ETX_DIVISOR); + str = out; + len = strlen(out); + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_payload(&response, (u8_t *)str, len); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + get_from_ip_addr(request, &from); + r = net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); + if (r < 0) { + net_pkt_unref(pkt); + } + + return r; +} + +/* RPL Link Metric */ +static int rpl_link_metric_get(struct coap_resource *resource, + struct coap_packet *request) +{ + struct net_rpl_instance *rpl; + struct net_pkt *pkt; + struct net_buf *frag; + struct sockaddr_in6 from; + struct coap_packet response; + struct net_nbr *nbr; + const char *str; + u8_t token[8]; + u16_t len, id; + u8_t tkl; + int r; + char out[RPL_MAX_REPLY]; + + NET_DBG(""); + + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, (u8_t *)token); + + pkt = net_pkt_get_tx(context, K_FOREVER); + if (!pkt) { + return -ENOMEM; + } + + frag = net_pkt_get_data(context, K_FOREVER); + if (!frag) { + net_pkt_unref(pkt); + return -ENOMEM; + } + + net_pkt_frag_add(pkt, frag); + + r = coap_packet_init(&response, pkt, 1, COAP_TYPE_ACK, + tkl, token, COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_option(&response, COAP_OPTION_CONTENT_FORMAT, + &plain_text_format, + sizeof(plain_text_format)); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + rpl = net_rpl_get_default_instance(); + if (rpl && rpl->current_dag && + rpl->current_dag->preferred_parent) { + nbr = net_rpl_get_nbr(rpl->current_dag->preferred_parent); + if (nbr) { + snprintk(out, sizeof(out), "%s %u.%02u", rpl_link, + (net_ipv6_nbr_data(nbr)->link_metric) / + NET_RPL_MC_ETX_DIVISOR, + (100 * ((net_ipv6_nbr_data(nbr)->link_metric) % + NET_RPL_MC_ETX_DIVISOR)) / + NET_RPL_MC_ETX_DIVISOR); + + str = out; + len = strlen(out); + } else { + str = rpl_no_link; + len = sizeof(rpl_no_link); + } + } else { + str = rpl_no_link; + len = sizeof(rpl_no_link); + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + r = coap_packet_append_payload(&response, (u8_t *)str, len); + if (r < 0) { + net_pkt_unref(pkt); + return -EINVAL; + } + + get_from_ip_addr(request, &from); + r = net_context_sendto(pkt, (const struct sockaddr *)&from, + sizeof(struct sockaddr_in6), + NULL, 0, NULL, NULL); + if (r < 0) { + net_pkt_unref(pkt); + } + + return r; +} + +static const char * const led_default_path[] = { "led", "0", NULL }; +static const char * const led_default_attributes[] = { + "title=\"LED0: led=toggle ?len=0..\"", + "rt=\"Text\"", + NULL }; + +static const char * const ipv6_neighbors_default_path[] = { "ipv6", + "neighbors", + NULL }; +static const char * const ipv6_neighbors_default_attributes[] = { + "title=\"IPv6 Neighbors\"", + "rt=Text", + NULL }; + +static const char * const rpl_info_default_path[] = { "rpl-info", NULL }; +static const char * const rpl_info_default_attributes[] = { + "title=\"RPL Information\"", + "rt=Text", + NULL }; + +static const char * const rpl_parent_default_path[] = { "rpl-info", + "parent", + NULL }; +static const char * const rpl_parent_default_attributes[] = { + "title=\"RPL Parent\"", + "rt=Text", + NULL }; + +static const char * const rpl_rank_default_path[] = { "rpl-info", + "rank", + NULL }; +static const char * const rpl_rank_default_attributes[] = { + "title=\"RPL Rank\"", + "rt=Text", + NULL }; + +static const char * const rpl_link_default_path[] = { "rpl-info", + "link-metric", + NULL }; +static const char * const rpl_link_default_attributes[] = { + "title=\"RPL Link Metric\"", + "rt=Text", + NULL }; + +static struct coap_resource resources[] = { + { .get = well_known_core_get, + .post = NULL, + .put = NULL, + .path = COAP_WELL_KNOWN_CORE_PATH, + .user_data = NULL, + }, + { .get = led_get, + .post = led_post, + .put = led_put, + .path = led_default_path, + .user_data = &((struct coap_core_metadata) { + .attributes = led_default_attributes, + }), + }, + { .get = ipv6_neighbors_get, + .post = NULL, + .put = NULL, + .path = ipv6_neighbors_default_path, + .user_data = &((struct coap_core_metadata) { + .attributes = ipv6_neighbors_default_attributes, + }), + }, + { .get = rpl_info_get, + .post = NULL, + .put = NULL, + .path = rpl_info_default_path, + .user_data = &((struct coap_core_metadata) { + .attributes = rpl_info_default_attributes, + }), + }, + { .get = rpl_parent_get, + .post = NULL, + .put = NULL, + .path = rpl_parent_default_path, + .user_data = &((struct coap_core_metadata) { + .attributes = rpl_parent_default_attributes, + }), + }, + { .get = rpl_rank_get, + .post = NULL, + .put = NULL, + .path = rpl_rank_default_path, + .user_data = &((struct coap_core_metadata) { + .attributes = rpl_rank_default_attributes, + }), + }, + { .get = rpl_link_metric_get, + .post = NULL, + .put = NULL, + .path = rpl_link_default_path, + .user_data = &((struct coap_core_metadata) { + .attributes = rpl_link_default_attributes, + }), + }, + { }, +}; + +static void udp_receive(struct net_context *context, + struct net_pkt *pkt, + int status, + void *user_data) +{ + struct coap_packet request; + struct coap_option options[16] = { 0 }; + u8_t opt_num = 16; + int r; + + r = coap_packet_parse(&request, pkt, options, opt_num); + if (r < 0) { + NET_ERR("Invalid data received (%d)\n", r); + goto end; + } + + r = coap_handle_request(&request, resources, options, opt_num); + if (r < 0) { + NET_ERR("No handler for such request (%d)\n", r); + } + +end: + net_pkt_unref(pkt); +} + +static bool join_coap_multicast_group(void) +{ + static struct sockaddr_in6 mcast_addr = { + .sin6_family = AF_INET6, + .sin6_addr = ALL_NODES_LOCAL_COAP_MCAST, + .sin6_port = htons(MY_COAP_PORT) }; + struct net_if_mcast_addr *mcast; + struct net_if *iface; + + iface = net_if_get_default(); + if (!iface) { + NET_ERR("Could not get te default interface\n"); + return false; + } + + mcast = net_if_ipv6_maddr_add(iface, &mcast_addr.sin6_addr); + if (!mcast) { + NET_ERR("Could not add multicast address to interface\n"); + return false; + } + + return true; +} + +static void init_app(void) +{ + static struct sockaddr_in6 any_addr = { + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_ANY_INIT, + .sin6_port = htons(MY_COAP_PORT) }; + int r; + +#if defined(CONFIG_NET_L2_IEEE802154) + if (ieee802154_sample_setup()) { + NET_ERR("IEEE 802.15.4 setup failed"); + return; + } +#endif + + led0 = device_get_binding(LED_GPIO_NAME); + if (led0) { + gpio_pin_configure(led0, LED_PIN, GPIO_DIR_OUT); + } else { + NET_WARN("Failed to bind '%s'" + "fake_led will provide dummpy replies", + LED_GPIO_NAME); + } + + if (!join_coap_multicast_group()) { + NET_ERR("Could not join CoAP multicast group"); + return; + } + + r = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &context); + if (r) { + NET_ERR("Could not get an UDP context"); + return; + } + + r = net_context_bind(context, (struct sockaddr *) &any_addr, + sizeof(any_addr)); + if (r) { + NET_ERR("Could not bind the context"); + return; + } + + r = net_context_recv(context, udp_receive, 0, NULL); + if (r) { + NET_ERR("Could not receive in the context"); + } +} + +void main(void) +{ + NET_DBG("Start Demo"); + + init_app(); +} diff --git a/samples/net/rpl-node/testcase.ini b/samples/net/rpl-node/testcase.ini new file mode 100644 index 0000000000000..9deee8c5b5e8a --- /dev/null +++ b/samples/net/rpl-node/testcase.ini @@ -0,0 +1,5 @@ +[test] +tags = net zoap +build_only = true +arch_whitelist = x86 +platform_exclude = quark_d2000_crb # not enough RAM From 54f9b22b9482f47840c9dbf6eafb2b2be6d0ed11 Mon Sep 17 00:00:00 2001 From: Ravi kumar Veeramally Date: Mon, 2 Oct 2017 12:16:54 +0300 Subject: [PATCH 27/37] net: Deprecate ZOAP library Added deprecated statements to ZOAP library api, structs and enums. Signed-off-by: Ravi kumar Veeramally --- include/net/zoap.h | 200 +++++++++++++++++++++++++++++++++ include/net/zoap_link_format.h | 12 ++ 2 files changed, 212 insertions(+) diff --git a/include/net/zoap.h b/include/net/zoap.h index e3d3e98631c6b..840d38e2f6b45 100644 --- a/include/net/zoap.h +++ b/include/net/zoap.h @@ -30,6 +30,10 @@ extern "C" { * @{ */ +/** + * @deprecated This library is deprecated. + */ + /** * @brief Set of CoAP packet options we are aware of. * @@ -39,6 +43,10 @@ extern "C" { * * Refer to RFC 7252, section 12.2 for more information. */ + +/** + * @deprecated This enum is deprecated. + */ enum zoap_option_num { ZOAP_OPTION_IF_MATCH = 1, ZOAP_OPTION_URI_HOST = 3, @@ -67,6 +75,10 @@ enum zoap_option_num { * To be used with zoap_header_set_code() when creating a request * or a response. */ + +/** + * @deprecated This enum is deprecated. + */ enum zoap_method { ZOAP_METHOD_GET = 1, ZOAP_METHOD_POST = 2, @@ -74,11 +86,19 @@ enum zoap_method { ZOAP_METHOD_DELETE = 4, }; + +/** + * @deprecated This macro is deprecated. + */ + #define ZOAP_REQUEST_MASK 0x07 /** * @brief CoAP packets may be of one of these types. */ +/** + * @deprecated This enum is deprecated. + */ enum zoap_msgtype { /** * Confirmable message. @@ -109,6 +129,9 @@ enum zoap_msgtype { ZOAP_TYPE_RESET = 3 }; +/** + * @deprecated This macro is deprecated. + */ #define zoap_make_response_code(clas, det) ((clas << 5) | (det)) /** @@ -116,6 +139,9 @@ enum zoap_msgtype { * * To be used with zoap_header_set_code() when creating a response. */ +/** + * @deprecated This enum is deprecated. + */ enum zoap_response_code { ZOAP_RESPONSE_CODE_OK = zoap_make_response_code(2, 0), ZOAP_RESPONSE_CODE_CREATED = zoap_make_response_code(2, 1), @@ -143,6 +169,9 @@ enum zoap_response_code { ZOAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED = zoap_make_response_code(5, 5) }; +/** + * @deprecated This macro is deprecated. + */ #define ZOAP_CODE_EMPTY (0) struct zoap_observer; @@ -156,6 +185,9 @@ struct zoap_resource; * @brief Type of the callback being called when a resource's method is * invoked by the remote entity. */ +/** + * @deprecated This callback is deprecated. + */ typedef int (*zoap_method_t)(struct zoap_resource *resource, struct zoap_packet *request, const struct sockaddr *from); @@ -165,6 +197,9 @@ typedef int (*zoap_method_t)(struct zoap_resource *resource, * @brief Type of the callback being called when a resource's has observers * to be informed when an update happens. */ +/** + * @deprecated This callback is deprecated. + */ typedef void (*zoap_notify_t)(struct zoap_resource *resource, struct zoap_observer *observer); @@ -174,6 +209,9 @@ typedef void (*zoap_notify_t)(struct zoap_resource *resource, * CoAP servers often want to register resources, so that clients can act on * them, by fetching their state or requesting updates to them. */ +/** + * @deprecated This struct is deprecated. + */ struct zoap_resource { /** Which function to be called for each CoAP method */ zoap_method_t get, post, put, del; @@ -187,6 +225,9 @@ struct zoap_resource { /** * @brief Represents a remote device that is observing a local resource. */ +/** + * @deprecated This struct is deprecated. + */ struct zoap_observer { sys_snode_t list; struct sockaddr addr; @@ -197,6 +238,9 @@ struct zoap_observer { /** * @brief Representation of a CoAP packet. */ +/** + * @deprecated This struct is deprecated. + */ struct zoap_packet { struct net_pkt *pkt; u8_t *start; /* Start of the payload */ @@ -208,6 +252,9 @@ struct zoap_packet { * @brief Helper function to be called when a response matches the * a pending request. */ +/** + * @deprecated This callback is deprecated. + */ typedef int (*zoap_reply_t)(const struct zoap_packet *response, struct zoap_reply *reply, const struct sockaddr *from); @@ -215,6 +262,9 @@ typedef int (*zoap_reply_t)(const struct zoap_packet *response, /** * @brief Represents a request awaiting for an acknowledgment (ACK). */ +/** + * @deprecated This struct is deprecated. + */ struct zoap_pending { struct net_pkt *pkt; struct sockaddr addr; @@ -226,6 +276,9 @@ struct zoap_pending { * @brief Represents the handler for the reply of a request, it is * also used when observing resources. */ +/** + * @deprecated This struct is deprecated. + */ struct zoap_reply { zoap_reply_t reply; void *user_data; @@ -243,6 +296,9 @@ struct zoap_reply { * @param request Request on which the observer will be based * @param addr Address of the remote device */ +/** + * @deprecated This api is deprecated. + */ void zoap_observer_init(struct zoap_observer *observer, const struct zoap_packet *request, const struct sockaddr *addr); @@ -256,6 +312,9 @@ void zoap_observer_init(struct zoap_observer *observer, * * @return true if this is the first observer added to this resource. */ +/** + * @deprecated This api is deprecated. + */ bool zoap_register_observer(struct zoap_resource *resource, struct zoap_observer *observer); @@ -266,6 +325,9 @@ bool zoap_register_observer(struct zoap_resource *resource, * @param resource Resource in which to remove the observer * @param observer Observer to be removed */ +/** + * @deprecated This api is deprecated. + */ void zoap_remove_observer(struct zoap_resource *resource, struct zoap_observer *observer); @@ -279,6 +341,9 @@ void zoap_remove_observer(struct zoap_resource *resource, * @return A pointer to a observer if a match is found, NULL * otherwise. */ +/** + * @deprecated This api is deprecated. + */ struct zoap_observer *zoap_find_observer_by_addr( struct zoap_observer *observers, size_t len, const struct sockaddr *addr); @@ -292,6 +357,9 @@ struct zoap_observer *zoap_find_observer_by_addr( * @return A pointer to a observer if there's an available observer, * NULL otherwise. */ +/** + * @deprecated This api is deprecated. + */ struct zoap_observer *zoap_observer_next_unused( struct zoap_observer *observers, size_t len); @@ -301,6 +369,9 @@ struct zoap_observer *zoap_observer_next_unused( * @param reply Reply structure to be initialized * @param request Request from which @a reply will be based */ +/** + * @deprecated This api is deprecated. + */ void zoap_reply_init(struct zoap_reply *reply, const struct zoap_packet *request); @@ -309,6 +380,9 @@ void zoap_reply_init(struct zoap_reply *reply, * * To be used with zoap_find_options(). */ +/** + * @deprecated This struct is deprecated. + */ struct zoap_option { u8_t *value; u16_t len; @@ -324,6 +398,9 @@ struct zoap_option { * * @return 0 in case of success or negative in case of error. */ +/** + * @deprecated This api is deprecated. + */ int zoap_packet_parse(struct zoap_packet *zpkt, struct net_pkt *pkt); /** @@ -336,6 +413,9 @@ int zoap_packet_parse(struct zoap_packet *zpkt, struct net_pkt *pkt); * * @return 0 in case of success or negative in case of error. */ +/** + * @deprecated This api is deprecated. + */ int zoap_packet_init(struct zoap_packet *zpkt, struct net_pkt *pkt); /** @@ -352,6 +432,9 @@ int zoap_packet_init(struct zoap_packet *zpkt, struct net_pkt *pkt); * * @return 0 in case of success or negative in case of error. */ +/** + * @deprecated This api is deprecated. + */ int zoap_pending_init(struct zoap_pending *pending, const struct zoap_packet *request, const struct sockaddr *addr); @@ -366,6 +449,9 @@ int zoap_pending_init(struct zoap_pending *pending, * @return pointer to a free #zoap_pending structure, NULL in case * none could be found. */ +/** + * @deprecated This api is deprecated. + */ struct zoap_pending *zoap_pending_next_unused( struct zoap_pending *pendings, size_t len); @@ -379,6 +465,9 @@ struct zoap_pending *zoap_pending_next_unused( * @return pointer to a free #zoap_reply structure, NULL in case * none could be found. */ +/** + * @deprecated This api is deprecated. + */ struct zoap_reply *zoap_reply_next_unused( struct zoap_reply *replies, size_t len); @@ -393,6 +482,9 @@ struct zoap_reply *zoap_reply_next_unused( * @return pointer to the associated #zoap_pending structure, NULL in * case none could be found. */ +/** + * @deprecated This api is deprecated. + */ struct zoap_pending *zoap_pending_received( const struct zoap_packet *response, struct zoap_pending *pendings, size_t len); @@ -409,6 +501,9 @@ struct zoap_pending *zoap_pending_received( * @return Pointer to the reply matching the packet received, NULL if * none could be found. */ +/** + * @deprecated This api is deprecated. + */ struct zoap_reply *zoap_response_received( const struct zoap_packet *response, const struct sockaddr *from, @@ -424,6 +519,9 @@ struct zoap_reply *zoap_response_received( * @return The next #zoap_pending to expire, NULL if none is about to * expire. */ +/** + * @deprecated This api is deprecated. + */ struct zoap_pending *zoap_pending_next_to_expire( struct zoap_pending *pendings, size_t len); @@ -435,6 +533,9 @@ struct zoap_pending *zoap_pending_next_to_expire( * * @return false if this is the last retransmission. */ +/** + * @deprecated This api is deprecated. + */ bool zoap_pending_cycle(struct zoap_pending *pending); /** @@ -443,6 +544,9 @@ bool zoap_pending_cycle(struct zoap_pending *pending); * * @param pending Pending representation to be canceled */ +/** + * @deprecated This api is deprecated. + */ void zoap_pending_clear(struct zoap_pending *pending); /** @@ -451,6 +555,9 @@ void zoap_pending_clear(struct zoap_pending *pending); * * @param reply The reply to be canceled */ +/** + * @deprecated This api is deprecated. + */ void zoap_reply_clear(struct zoap_reply *reply); /** @@ -463,6 +570,9 @@ void zoap_reply_clear(struct zoap_reply *reply); * * @return 0 in case of success or negative in case of error. */ +/** + * @deprecated This api is deprecated. + */ int zoap_handle_request(struct zoap_packet *zpkt, struct zoap_resource *resources, const struct sockaddr *from); @@ -475,6 +585,9 @@ int zoap_handle_request(struct zoap_packet *zpkt, * * @return 0 in case of success or negative in case of error. */ +/** + * @deprecated This api is deprecated. + */ int zoap_resource_notify(struct zoap_resource *resource); /** @@ -485,6 +598,9 @@ int zoap_resource_notify(struct zoap_resource *resource); * @return True if the request is enabling observing a resource, False * otherwise */ +/** + * @deprecated This api is deprecated. + */ bool zoap_request_is_observe(const struct zoap_packet *request); /** @@ -498,6 +614,9 @@ bool zoap_request_is_observe(const struct zoap_packet *request); * * @return pointer to the start of the payload, NULL in case of error. */ +/** + * @deprecated This api is deprecated. + */ u8_t *zoap_packet_get_payload(struct zoap_packet *zpkt, u16_t *len); /** @@ -512,6 +631,9 @@ u8_t *zoap_packet_get_payload(struct zoap_packet *zpkt, u16_t *len); * * @return 0 in case of success or negative in case of error. */ +/** + * @deprecated This api is deprecated. + */ int zoap_packet_set_used(struct zoap_packet *zpkt, u16_t len); /** @@ -526,6 +648,9 @@ int zoap_packet_set_used(struct zoap_packet *zpkt, u16_t len); * * @return 0 in case of success or negative in case of error. */ +/** + * @deprecated This api is deprecated. + */ int zoap_add_option(struct zoap_packet *zpkt, u16_t code, const void *value, u16_t len); @@ -540,6 +665,9 @@ int zoap_add_option(struct zoap_packet *zpkt, u16_t code, * * @return The integer representation of the option */ +/** + * @deprecated This api is deprecated. + */ unsigned int zoap_option_value_to_int(const struct zoap_option *option); /** @@ -554,6 +682,9 @@ unsigned int zoap_option_value_to_int(const struct zoap_option *option); * * @return 0 in case of success or negative in case of error. */ +/** + * @deprecated This api is deprecated. + */ int zoap_add_option_int(struct zoap_packet *zpkt, u16_t code, unsigned int val); @@ -570,6 +701,9 @@ int zoap_add_option_int(struct zoap_packet *zpkt, u16_t code, * @return The number of options found in packet matching code, * negative on error. */ +/** + * @deprecated This api is deprecated. + */ int zoap_find_options(const struct zoap_packet *zpkt, u16_t code, struct zoap_option *options, u16_t veclen); @@ -581,6 +715,9 @@ int zoap_find_options(const struct zoap_packet *zpkt, u16_t code, * * https://tools.ietf.org/html/rfc7959 */ +/** + * @deprecated This enum is deprecated. + */ enum zoap_block_size { ZOAP_BLOCK_16, ZOAP_BLOCK_32, @@ -599,6 +736,9 @@ enum zoap_block_size { * * @return The size in bytes that the block_size represents */ +/** + * @deprecated This api is deprecated. + */ static inline u16_t zoap_block_size_to_bytes( enum zoap_block_size block_size) { @@ -608,6 +748,9 @@ static inline u16_t zoap_block_size_to_bytes( /** * @brief Represents the current state of a block-wise transaction. */ +/** + * @deprecated This struct is deprecated. + */ struct zoap_block_context { size_t total_size; size_t current; @@ -623,6 +766,9 @@ struct zoap_block_context { * * @return 0 in case of success or negative in case of error. */ +/** + * @deprecated This api is deprecated. + */ int zoap_block_transfer_init(struct zoap_block_context *ctx, enum zoap_block_size block_size, size_t total_size); @@ -636,6 +782,9 @@ int zoap_block_transfer_init(struct zoap_block_context *ctx, * * @return 0 in case of success or negative in case of error. */ +/** + * @deprecated This api is deprecated. + */ int zoap_add_block1_option(struct zoap_packet *zpkt, struct zoap_block_context *ctx); @@ -648,6 +797,9 @@ int zoap_add_block1_option(struct zoap_packet *zpkt, * * @return 0 in case of success or negative in case of error. */ +/** + * @deprecated This api is deprecated. + */ int zoap_add_block2_option(struct zoap_packet *zpkt, struct zoap_block_context *ctx); @@ -660,6 +812,9 @@ int zoap_add_block2_option(struct zoap_packet *zpkt, * * @return 0 in case of success or negative in case of error. */ +/** + * @deprecated This api is deprecated. + */ int zoap_add_size1_option(struct zoap_packet *zpkt, struct zoap_block_context *ctx); @@ -672,6 +827,9 @@ int zoap_add_size1_option(struct zoap_packet *zpkt, * * @return 0 in case of success or negative in case of error. */ +/** + * @deprecated This api is deprecated. + */ int zoap_add_size2_option(struct zoap_packet *zpkt, struct zoap_block_context *ctx); @@ -684,6 +842,9 @@ int zoap_add_size2_option(struct zoap_packet *zpkt, * * @return 0 in case of success or negative in case of error. */ +/** + * @deprecated This api is deprecated. + */ int zoap_update_from_block(const struct zoap_packet *zpkt, struct zoap_block_context *ctx); @@ -698,6 +859,9 @@ int zoap_update_from_block(const struct zoap_packet *zpkt, * @return The offset in the block-wise transfer, 0 if the transfer * has finished. */ +/** + * @deprecated This api is deprecated. + */ size_t zoap_next_block(const struct zoap_packet *zpkt, struct zoap_block_context *ctx); @@ -708,6 +872,9 @@ size_t zoap_next_block(const struct zoap_packet *zpkt, * * @return the CoAP version in packet */ +/** + * @deprecated This api is deprecated. + */ u8_t zoap_header_get_version(const struct zoap_packet *zpkt); /** @@ -717,6 +884,9 @@ u8_t zoap_header_get_version(const struct zoap_packet *zpkt); * * @return the type of the packet */ +/** + * @deprecated This api is deprecated. + */ u8_t zoap_header_get_type(const struct zoap_packet *zpkt); /** @@ -727,6 +897,9 @@ u8_t zoap_header_get_type(const struct zoap_packet *zpkt); * * @return pointer to the start of the token in the CoAP packet. */ +/** + * @deprecated This api is deprecated. + */ const u8_t *zoap_header_get_token(const struct zoap_packet *zpkt, u8_t *len); @@ -737,6 +910,9 @@ const u8_t *zoap_header_get_token(const struct zoap_packet *zpkt, * * @return the code present in the packet */ +/** + * @deprecated This api is deprecated. + */ u8_t zoap_header_get_code(const struct zoap_packet *zpkt); /** @@ -746,6 +922,9 @@ u8_t zoap_header_get_code(const struct zoap_packet *zpkt); * * @return the message id present in the packet */ +/** + * @deprecated This api is deprecated. + */ u16_t zoap_header_get_id(const struct zoap_packet *zpkt); /** @@ -754,6 +933,9 @@ u16_t zoap_header_get_id(const struct zoap_packet *zpkt); * @param zpkt CoAP packet representation * @param ver The CoAP version to set in the packet */ +/** + * @deprecated This api is deprecated. + */ void zoap_header_set_version(struct zoap_packet *zpkt, u8_t ver); /** @@ -762,6 +944,9 @@ void zoap_header_set_version(struct zoap_packet *zpkt, u8_t ver); * @param zpkt CoAP packet representation * @param type The packet type to set */ +/** + * @deprecated This api is deprecated. + */ void zoap_header_set_type(struct zoap_packet *zpkt, u8_t type); /** @@ -773,6 +958,9 @@ void zoap_header_set_type(struct zoap_packet *zpkt, u8_t type); * * @return 0 in case of success or negative in case of error. */ +/** + * @deprecated This api is deprecated. + */ int zoap_header_set_token(struct zoap_packet *zpkt, const u8_t *token, u8_t tokenlen); @@ -782,6 +970,9 @@ int zoap_header_set_token(struct zoap_packet *zpkt, const u8_t *token, * @param zpkt CoAP packet representation * @param code The code set in the packet */ +/** + * @deprecated This api is deprecated. + */ void zoap_header_set_code(struct zoap_packet *zpkt, u8_t code); /** @@ -790,6 +981,9 @@ void zoap_header_set_code(struct zoap_packet *zpkt, u8_t code); * @param zpkt CoAP packet representation * @param id The message id to set in the packet */ +/** + * @deprecated This api is deprecated. + */ void zoap_header_set_id(struct zoap_packet *zpkt, u16_t id); /** @@ -797,6 +991,9 @@ void zoap_header_set_id(struct zoap_packet *zpkt, u16_t id); * * @return a new message id */ +/** + * @deprecated This api is deprecated. + */ static inline u16_t zoap_next_id(void) { static u16_t message_id; @@ -810,6 +1007,9 @@ static inline u16_t zoap_next_id(void) * * @return a 8-byte pseudo-random token. */ +/** + * @deprecated This api is deprecated. + */ u8_t *zoap_next_token(void); /** diff --git a/include/net/zoap_link_format.h b/include/net/zoap_link_format.h index ce4ec577ab776..7970fe459da29 100644 --- a/include/net/zoap_link_format.h +++ b/include/net/zoap_link_format.h @@ -22,9 +22,15 @@ extern "C" { * @{ */ +/** + * @deprecated This macro is deprecated. + */ #define _ZOAP_WELL_KNOWN_CORE_PATH \ ((const char * const[]) { ".well-known", "core", NULL }) +/** + * @deprecated This api is deprecated. + */ int _zoap_well_known_core_get(struct zoap_resource *resource, struct zoap_packet *request, const struct sockaddr *from); @@ -33,6 +39,9 @@ int _zoap_well_known_core_get(struct zoap_resource *resource, * This resource should be added before all other resources that should be * included in the responses of the .well-known/core resource. */ +/** + * @deprecated This macro is deprecated. + */ #define ZOAP_WELL_KNOWN_CORE_RESOURCE \ { .get = _zoap_well_known_core_get, \ .path = _ZOAP_WELL_KNOWN_CORE_PATH, \ @@ -43,6 +52,9 @@ int _zoap_well_known_core_get(struct zoap_resource *resource, * 'well-known/core' "virtual" resource, the 'user_data' field should point * to a valid zoap_core_metadata structure. */ +/** + * @deprecated This struct is deprecated. + */ struct zoap_core_metadata { const char * const *attributes; void *user_data; From f56faa59f85b3d4d8a0dfb9ed79caff4567baa32 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Tue, 19 Sep 2017 16:01:36 -0700 Subject: [PATCH 28/37] net: coap: parse_option() exit gracefully when no payload Instead of generating an EINVAL error when there's no payload let's check for an offset == 0 and exit gracefully. Signed-off-by: Michael Scott --- subsys/net/lib/coap/coap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index a8be0300f715b..fcb3e50343a79 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -130,7 +130,7 @@ static int parse_option(const struct coap_packet *cpkt, opt_len = 1; /* This indicates that options have ended */ - if (opt == COAP_MARKER) { + if (context->offset == 0 || opt == COAP_MARKER) { return 0; } From f6fcbc833f743975f1c31e6815701ed0433331cf Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Tue, 19 Sep 2017 16:04:32 -0700 Subject: [PATCH 29/37] net: lwm2m: move to using the new multi-packet CoAP API This patch moves from the ZoAP API in subsys/net/lib/zoap to the CoAP API in subsys/net/lib/coap which handles multiple fragments for sending / receiving data. NOTE: This patch moves the LwM2M library over to the CoAP APIs but there will be a follow-up patch which re-writes the content formatter reader / writers to use net_pkt APIs for parsing across multiple net buffers. The current implementation assumes all of the data will land in 1 buffer. Samples using the library still need a fairly large NET_BUF_DATA_SIZE setting. (Example: CONFIG_NET_BUF_DATA_SIZE=384) Signed-off-by: Michael Scott --- include/net/lwm2m.h | 18 +- subsys/net/lib/lwm2m/Kconfig | 3 +- subsys/net/lib/lwm2m/lwm2m_engine.c | 445 ++++++++++-------- subsys/net/lib/lwm2m/lwm2m_engine.h | 13 +- subsys/net/lib/lwm2m/lwm2m_obj_firmware.c | 2 +- .../net/lib/lwm2m/lwm2m_obj_firmware_pull.c | 80 ++-- subsys/net/lib/lwm2m/lwm2m_object.h | 6 +- subsys/net/lib/lwm2m/lwm2m_rd_client.c | 151 +++--- subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c | 4 +- 9 files changed, 401 insertions(+), 321 deletions(-) diff --git a/include/net/lwm2m.h b/include/net/lwm2m.h index 203e341712cec..d7d01946cc6c5 100644 --- a/include/net/lwm2m.h +++ b/include/net/lwm2m.h @@ -9,7 +9,7 @@ #include #include -#include +#include /* LWM2M Objects defined by OMA */ @@ -47,11 +47,11 @@ struct lwm2m_message { struct lwm2m_ctx *ctx; /** ZoAP packet data related to this message */ - struct zoap_packet zpkt; + struct coap_packet cpkt; /** Message configuration */ - const u8_t *token; - zoap_reply_t reply_cb; + u8_t *token; + coap_reply_t reply_cb; lwm2m_message_timeout_cb_t message_timeout_cb; u16_t mid; u8_t type; @@ -59,8 +59,8 @@ struct lwm2m_message { u8_t tkl; /** ZoAP transmission handling structures */ - struct zoap_pending *pending; - struct zoap_reply *reply; + struct coap_pending *pending; + struct coap_reply *reply; u8_t send_attempts; }; @@ -87,9 +87,9 @@ struct lwm2m_ctx { net_pkt_get_pool_func_t data_pool; #endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */ - /** Private ZoAP and networking structures */ - struct zoap_pending pendings[CONFIG_LWM2M_ENGINE_MAX_PENDING]; - struct zoap_reply replies[CONFIG_LWM2M_ENGINE_MAX_REPLIES]; + /** Private CoAP and networking structures */ + struct coap_pending pendings[CONFIG_LWM2M_ENGINE_MAX_PENDING]; + struct coap_reply replies[CONFIG_LWM2M_ENGINE_MAX_REPLIES]; struct lwm2m_message messages[CONFIG_LWM2M_ENGINE_MAX_MESSAGES]; struct k_delayed_work retransmit_work; }; diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index aec49b3fb6ea2..52832a9a117f5 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -7,7 +7,8 @@ menuconfig LWM2M bool "OMA LWM2M protocol stack" default n - select ZOAP + select COAP + select COAP_EXTENDED_OPTIONS_LEN select NET_APP_CLIENT help This option adds logic for managing OMA LWM2M data diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 6b36e901321c5..8f6789f75f8a1 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include "lwm2m_object.h" @@ -110,7 +110,7 @@ static sys_slist_t engine_observer_list; #define GET_MORE(v) (!!((v) & 0x08)) struct block_context { - struct zoap_block_context ctx; + struct coap_block_context ctx; s64_t timestamp; u8_t token[8]; u8_t tkl; @@ -173,26 +173,26 @@ static char *sprint_token(const u8_t *token, u8_t tkl) /* block-wise transfer functions */ -enum zoap_block_size lwm2m_default_block_size(void) +enum coap_block_size lwm2m_default_block_size(void) { switch (CONFIG_LWM2M_COAP_BLOCK_SIZE) { case 16: - return ZOAP_BLOCK_16; + return COAP_BLOCK_16; case 32: - return ZOAP_BLOCK_32; + return COAP_BLOCK_32; case 64: - return ZOAP_BLOCK_64; + return COAP_BLOCK_64; case 128: - return ZOAP_BLOCK_128; + return COAP_BLOCK_128; case 256: - return ZOAP_BLOCK_256; + return COAP_BLOCK_256; case 512: - return ZOAP_BLOCK_512; + return COAP_BLOCK_512; case 1024: - return ZOAP_BLOCK_1024; + return COAP_BLOCK_1024; } - return ZOAP_BLOCK_256; + return COAP_BLOCK_256; } static int @@ -226,7 +226,7 @@ init_block_ctx(const u8_t *token, u8_t tkl, struct block_context **ctx) (*ctx)->tkl = tkl; memcpy((*ctx)->token, token, tkl); - zoap_block_transfer_init(&(*ctx)->ctx, lwm2m_default_block_size(), 0); + coap_block_transfer_init(&(*ctx)->ctx, lwm2m_default_block_size(), 0); (*ctx)->timestamp = timestamp; return 0; @@ -636,18 +636,18 @@ int lwm2m_delete_obj_inst(u16_t obj_id, u16_t obj_inst_id) /* utility functions */ -static int get_option_int(const struct zoap_packet *zpkt, u8_t opt) +static int get_option_int(const struct coap_packet *cpkt, u8_t opt) { - struct zoap_option option = {}; + struct coap_option option = {}; u16_t count = 1; int r; - r = zoap_find_options(zpkt, opt, &option, count); + r = coap_find_options(cpkt, opt, &option, count); if (r <= 0) { return -ENOENT; } - return zoap_option_value_to_int(&option); + return coap_option_value_to_int(&option); } static void engine_clear_context(struct lwm2m_engine_context *context) @@ -682,7 +682,7 @@ static u16_t atou16(u8_t *buf, u16_t buflen, u16_t *len) return val; } -static void zoap_options_to_path(struct zoap_option *opt, int options_count, +static void coap_options_to_path(struct coap_option *opt, int options_count, struct lwm2m_obj_path *path) { u16_t len; @@ -715,8 +715,8 @@ static void zoap_options_to_path(struct zoap_option *opt, int options_count, } } -static struct lwm2m_message *find_msg(struct zoap_pending *pending, - struct zoap_reply *reply, +static struct lwm2m_message *find_msg(struct coap_pending *pending, + struct coap_reply *reply, struct lwm2m_message *messages, size_t len) { @@ -760,13 +760,13 @@ void lwm2m_release_message(struct lwm2m_message *msg) } if (msg->pending) { - zoap_pending_clear(msg->pending); + coap_pending_clear(msg->pending); msg->pending = NULL; } if (msg->reply) { /* make sure we want to clear the reply */ - zoap_reply_clear(msg->reply); + coap_reply_clear(msg->reply); msg->reply = NULL; } @@ -778,7 +778,9 @@ int lwm2m_init_message(struct lwm2m_message *msg) struct net_pkt *pkt; struct net_app_ctx *app_ctx; struct net_buf *frag; - int r; + u8_t tokenlen = 0; + u8_t *token = NULL; + int r = 0; if (!msg || !msg->ctx) { SYS_LOG_ERR("LwM2M message is invalid."); @@ -800,36 +802,28 @@ int lwm2m_init_message(struct lwm2m_message *msg) goto cleanup; } - r = zoap_packet_init(&msg->zpkt, pkt); - if (r < 0) { - SYS_LOG_ERR("zoap packet init error (err:%d)", r); - goto cleanup; - } - - /* FIXME: Could be that zoap_packet_init() sets some defaults */ - zoap_header_set_version(&msg->zpkt, 1); - zoap_header_set_type(&msg->zpkt, msg->type); - zoap_header_set_code(&msg->zpkt, msg->code); - - if (msg->mid > 0) { - zoap_header_set_id(&msg->zpkt, msg->mid); - } else { - zoap_header_set_id(&msg->zpkt, zoap_next_id()); - } - /* - * tkl == 0 is for a new TOKEN - * tkl == LWM2M_MSG_TOKEN_LEN_SKIP means dont set + * msg->tkl == 0 is for a new TOKEN + * msg->tkl == LWM2M_MSG_TOKEN_LEN_SKIP means dont set */ if (msg->tkl == 0) { - zoap_header_set_token(&msg->zpkt, zoap_next_token(), - MAX_TOKEN_LEN); + tokenlen = 0; + token = coap_next_token(); } else if (msg->token && msg->tkl != LWM2M_MSG_TOKEN_LEN_SKIP) { - zoap_header_set_token(&msg->zpkt, msg->token, msg->tkl); + tokenlen = msg->tkl; + token = msg->token; + } + + r = coap_packet_init(&msg->cpkt, pkt, 1, msg->type, + tokenlen, token, msg->code, + (msg->mid > 0 ? msg->mid : coap_next_id())); + if (r < 0) { + SYS_LOG_ERR("coap packet init error (err:%d)", r); + goto cleanup; } - if (msg->type == ZOAP_TYPE_CON) { - msg->pending = zoap_pending_next_unused( + if (msg->type == COAP_TYPE_CON) { + msg->pending = coap_pending_next_unused( msg->ctx->pendings, CONFIG_LWM2M_ENGINE_MAX_PENDING); if (!msg->pending) { @@ -839,19 +833,16 @@ int lwm2m_init_message(struct lwm2m_message *msg) goto cleanup; } - r = zoap_pending_init(msg->pending, &msg->zpkt, - &app_ctx->default_ctx->remote); + r = coap_pending_init(msg->pending, &msg->cpkt, + &app_ctx->default_ctx->remote); if (r < 0) { SYS_LOG_ERR("Unable to initialize a pending " "retransmission (err:%d).", r); goto cleanup; } - /* clear out pkt to avoid double unref */ - pkt = NULL; - if (msg->reply_cb) { - msg->reply = zoap_reply_next_unused( + msg->reply = coap_reply_next_unused( msg->ctx->replies, CONFIG_LWM2M_ENGINE_MAX_REPLIES); if (!msg->reply) { @@ -861,7 +852,7 @@ int lwm2m_init_message(struct lwm2m_message *msg) goto cleanup; } - zoap_reply_init(msg->reply, &msg->zpkt); + coap_reply_init(msg->reply, &msg->cpkt); msg->reply->reply = msg->reply_cb; } } @@ -887,19 +878,19 @@ int lwm2m_send_message(struct lwm2m_message *msg) } msg->send_attempts++; - ret = net_app_send_pkt(&msg->ctx->net_app_ctx, msg->zpkt.pkt, + ret = net_app_send_pkt(&msg->ctx->net_app_ctx, msg->cpkt.pkt, &msg->ctx->net_app_ctx.default_ctx->remote, NET_SOCKADDR_MAX_SIZE, K_NO_WAIT, NULL); if (ret < 0) { return ret; } - if (msg->type == ZOAP_TYPE_CON) { + if (msg->type == COAP_TYPE_CON) { if (msg->send_attempts > 1) { return 0; } - zoap_pending_cycle(msg->pending); + coap_pending_cycle(msg->pending); k_delayed_work_submit(&msg->ctx->retransmit_work, msg->pending->timeout); } else { @@ -1828,7 +1819,7 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, size_t total_size = 0; int ret = 0; u8_t tkl = 0; - const u8_t *token; + u8_t token[8]; bool last_block = true; struct block_context *block_ctx = NULL; @@ -1940,12 +1931,12 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, if (res->post_write_cb) { /* Get block1 option for checking MORE block flag */ - ret = get_option_int(in->in_zpkt, ZOAP_OPTION_BLOCK1); + ret = get_option_int(in->in_cpkt, COAP_OPTION_BLOCK1); if (ret >= 0) { last_block = !GET_MORE(ret); /* Get block_ctx for total_size (might be zero) */ - token = zoap_header_get_token(in->in_zpkt, &tkl); + tkl = coap_header_get_token(in->in_cpkt, token); if (token != NULL && !get_block_ctx(token, tkl, &block_ctx)) { total_size = block_ctx->ctx.total_size; @@ -2018,15 +2009,88 @@ static int lwm2m_delete_handler(struct lwm2m_engine_obj *obj, context->path->obj_inst_id); } +static int get_coap_packet_len(struct net_pkt *pkt) +{ + struct net_buf *frag; + u16_t offset; + u16_t len; + + frag = net_frag_read_be16(pkt->frags, + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt) + + 4, &offset, &len); + if (!frag && offset == 0xffff) { + return -1; + } + + return len - NET_UDPH_LEN; +} + +#define COAP_MARKER 0xFF + +/* TODO: Remove in favor of using net_buf pointer to payload */ +u8_t *coap_packet_get_payload_ptr(struct coap_packet *cpkt, u16_t *len, + bool start_marker) +{ + u8_t *appdata = cpkt->pkt->frags->data; + u16_t appdatalen = cpkt->pkt->frags->len; + u8_t *start = NULL; /* Start of the payload */ + s32_t payload_size = 0; + + if (!cpkt || !len) { + return NULL; + } + + *len = 0; + if (start_marker) { + if (appdatalen + 1 >= net_buf_tailroom(cpkt->pkt->frags)) { + return NULL; + } + + appdata[appdatalen] = COAP_MARKER; + cpkt->pkt->frags->len += 1; + start = appdata + appdatalen + 1; + payload_size = appdata + net_buf_tailroom(cpkt->pkt->frags) - start; + } else { + payload_size = get_coap_packet_len(cpkt->pkt); + payload_size -= (cpkt->hdr_len + cpkt->opt_len); + if (payload_size > 0) { + start = appdata; + start += net_pkt_ip_hdr_len(cpkt->pkt); + start += net_pkt_ipv6_ext_len(cpkt->pkt); + start += NET_UDPH_LEN; + start += cpkt->hdr_len + cpkt->opt_len; + } else { + payload_size = 0; + } + } + + *len = payload_size; + return start; +} + +/* TODO: Remove in favor of using net_pkt APIs to add data to payload */ +int coap_packet_set_used(struct coap_packet *cpkt, u16_t len) +{ + if ((cpkt->pkt->frags->len + len) > + net_buf_tailroom(cpkt->pkt->frags)) { + return -ENOMEM; + } + + cpkt->pkt->frags->len += len; + + return 0; +} + /* - * ZoAP API needs to create the net_pkt buffer in the correct order. + * CoAP API needs to create the net_pkt buffer in the correct order. * This function performs last minute verification that outbuf is initialized. */ static void outbuf_init_check(struct lwm2m_output_context *out) { if (!out->outbuf) { - out->outbuf = zoap_packet_get_payload(out->out_zpkt, - &out->outsize); + out->outbuf = coap_packet_get_payload_ptr(out->out_cpkt, + &out->outsize, true); } } @@ -2153,16 +2217,19 @@ static int do_discover_op(struct lwm2m_engine_context *context) { struct lwm2m_output_context *out = context->out; struct lwm2m_engine_obj_inst *obj_inst; - int i = 0; + int i = 0, ret; /* set output content-format */ - zoap_add_option_int(out->out_zpkt, - ZOAP_OPTION_CONTENT_FORMAT, - LWM2M_FORMAT_APP_LINK_FORMAT); + ret = coap_append_option_int(out->out_cpkt, + COAP_OPTION_CONTENT_FORMAT, + LWM2M_FORMAT_APP_LINK_FORMAT); + if (ret < 0) { + return ret; + } /* init the outbuffer */ - out->outbuf = zoap_packet_get_payload(out->out_zpkt, - &out->outsize); + out->outbuf = coap_packet_get_payload_ptr(out->out_cpkt, + &out->outsize, true); /* ,**;ct=40 */ memcpy(out->outbuf, DISCOVER_PREFACE, strlen(DISCOVER_PREFACE)); @@ -2212,8 +2279,6 @@ int lwm2m_get_or_create_engine_obj(struct lwm2m_engine_context *context, return ret; } - zoap_header_set_code(context->in->in_zpkt, - ZOAP_RESPONSE_CODE_CREATED); /* set created flag to one */ if (created) { *created = 1; @@ -2250,14 +2315,14 @@ static int do_write_op(struct lwm2m_engine_obj *obj, } } -static int handle_request(struct zoap_packet *request, +static int handle_request(struct coap_packet *request, struct lwm2m_message *msg) { int r; u8_t code; - struct zoap_option options[4]; + struct coap_option options[4]; struct lwm2m_engine_obj *obj; - const u8_t *token; + u8_t token[8]; u8_t tkl = 0; u16_t format, accept; struct lwm2m_input_context in; @@ -2268,7 +2333,7 @@ static int handle_request(struct zoap_packet *request, bool discover = false; struct block_context *block_ctx = NULL; size_t block_offset = 0; - enum zoap_block_size block_size; + enum coap_block_size block_size; /* setup engine context */ memset(&context, 0, sizeof(struct lwm2m_engine_context)); @@ -2277,16 +2342,16 @@ static int handle_request(struct zoap_packet *request, context.path = &path; engine_clear_context(&context); - /* set ZoAP request / message */ - in.in_zpkt = request; - out.out_zpkt = &msg->zpkt; + /* set CoAP request / message */ + in.in_cpkt = request; + out.out_cpkt = &msg->cpkt; /* set default reader/writer */ in.reader = &plain_text_reader; out.writer = &plain_text_writer; /* parse the URL path into components */ - r = zoap_find_options(in.in_zpkt, ZOAP_OPTION_URI_PATH, options, 4); + r = coap_find_options(in.in_cpkt, COAP_OPTION_URI_PATH, options, 4); if (r > 0) { /* check for .well-known/core URI query (DISCOVER) */ if (r == 2 && @@ -2296,24 +2361,24 @@ static int handle_request(struct zoap_packet *request, strncmp(options[1].value, "core", 4) == 0)) { discover = true; } else { - zoap_options_to_path(options, r, &path); + coap_options_to_path(options, r, &path); } } /* read Content Format */ - r = zoap_find_options(in.in_zpkt, ZOAP_OPTION_CONTENT_FORMAT, + r = coap_find_options(in.in_cpkt, COAP_OPTION_CONTENT_FORMAT, options, 1); if (r > 0) { - format = zoap_option_value_to_int(&options[0]); + format = coap_option_value_to_int(&options[0]); } else { SYS_LOG_DBG("No content-format given. Assume text plain."); format = LWM2M_FORMAT_PLAIN_TEXT; } /* read Accept */ - r = zoap_find_options(in.in_zpkt, ZOAP_OPTION_ACCEPT, options, 1); + r = coap_find_options(in.in_cpkt, COAP_OPTION_ACCEPT, options, 1); if (r > 0) { - accept = zoap_option_value_to_int(&options[0]); + accept = coap_option_value_to_int(&options[0]); } else { SYS_LOG_DBG("No accept option given. Assume OMA TLV."); accept = LWM2M_FORMAT_OMA_TLV; @@ -2321,7 +2386,7 @@ static int handle_request(struct zoap_packet *request, /* TODO: Handle bootstrap deleted -- re-add when DTLS support ready */ - code = zoap_header_get_code(in.in_zpkt); + code = coap_header_get_code(in.in_cpkt); /* find registered obj */ obj = get_engine_obj(path.obj_id); @@ -2334,9 +2399,9 @@ static int handle_request(struct zoap_packet *request, accept = select_writer(&out, accept); /* set the operation */ - switch (code & ZOAP_REQUEST_MASK) { + switch (code & COAP_REQUEST_MASK) { - case ZOAP_METHOD_GET: + case COAP_METHOD_GET: if (discover || format == LWM2M_FORMAT_APP_LINK_FORMAT) { context.operation = LWM2M_OP_DISCOVER; accept = LWM2M_FORMAT_APP_LINK_FORMAT; @@ -2344,50 +2409,51 @@ static int handle_request(struct zoap_packet *request, context.operation = LWM2M_OP_READ; } /* check for observe */ - observe = get_option_int(in.in_zpkt, ZOAP_OPTION_OBSERVE); - zoap_header_set_code(out.out_zpkt, ZOAP_RESPONSE_CODE_CONTENT); + observe = get_option_int(in.in_cpkt, COAP_OPTION_OBSERVE); + msg->code = COAP_RESPONSE_CODE_CONTENT; break; - case ZOAP_METHOD_POST: + case COAP_METHOD_POST: if (path.level < 2) { /* write/create a object instance */ context.operation = LWM2M_OP_CREATE; } else { context.operation = LWM2M_OP_EXECUTE; } - zoap_header_set_code(out.out_zpkt, ZOAP_RESPONSE_CODE_CHANGED); + msg->code = COAP_RESPONSE_CODE_CHANGED; break; - case ZOAP_METHOD_PUT: + case COAP_METHOD_PUT: context.operation = LWM2M_OP_WRITE; - zoap_header_set_code(out.out_zpkt, ZOAP_RESPONSE_CODE_CHANGED); + msg->code = COAP_RESPONSE_CODE_CHANGED; break; - case ZOAP_METHOD_DELETE: + case COAP_METHOD_DELETE: context.operation = LWM2M_OP_DELETE; - zoap_header_set_code(out.out_zpkt, ZOAP_RESPONSE_CODE_DELETED); + msg->code = COAP_RESPONSE_CODE_DELETED; break; default: break; } - /* set response token */ - token = zoap_header_get_token(in.in_zpkt, &tkl); + /* setup response token */ + tkl = coap_header_get_token(in.in_cpkt, token); if (tkl) { - zoap_header_set_token(out.out_zpkt, token, tkl); + msg->tkl = tkl; + msg->token = token; } in.inpos = 0; - in.inbuf = zoap_packet_get_payload(in.in_zpkt, &in.insize); + in.inbuf = coap_packet_get_payload_ptr(in.in_cpkt, &in.insize, false); /* Check for block transfer */ - r = get_option_int(in.in_zpkt, ZOAP_OPTION_BLOCK1); + r = get_option_int(in.in_cpkt, COAP_OPTION_BLOCK1); if (r > 0) { /* RFC7252: 4.6. Message Size */ block_size = GET_BLOCK_SIZE(r); if (GET_MORE(r) && - zoap_block_size_to_bytes(block_size) > in.insize) { + coap_block_size_to_bytes(block_size) > in.insize) { SYS_LOG_DBG("Trailing payload is discarded!"); r = -EFBIG; goto error; @@ -2404,17 +2470,31 @@ static int handle_request(struct zoap_packet *request, } /* 0 will be returned if it's the last block */ - block_offset = zoap_next_block(in.in_zpkt, &block_ctx->ctx); + block_offset = coap_next_block(in.in_cpkt, &block_ctx->ctx); + } + + /* Handle blockwise 1 (Part 1): Set response code / free context */ + if (block_ctx) { + if (block_offset > 0) { + msg->code = COAP_RESPONSE_CODE_CONTINUE; + } else { + /* Free context when finished */ + free_block_ctx(block_ctx); + } } + /* render CoAP packet header */ + lwm2m_init_message(msg); + switch (context.operation) { case LWM2M_OP_READ: if (observe == 0) { /* add new observer */ - if (token) { - r = zoap_add_option_int(out.out_zpkt, - ZOAP_OPTION_OBSERVE, 1); + if (msg->token) { + r = coap_append_option_int(out.out_cpkt, + COAP_OPTION_OBSERVE, + 1); if (r) { SYS_LOG_ERR("OBSERVE option error: %d", r); @@ -2430,7 +2510,7 @@ static int handle_request(struct zoap_packet *request, } } else if (observe == 1) { /* use token from this request */ - token = zoap_header_get_token(in.in_zpkt, &tkl); + tkl = coap_header_get_token(in.in_cpkt, token); /* remove observer */ r = engine_remove_observer(token, tkl); if (r < 0) { @@ -2439,8 +2519,9 @@ static int handle_request(struct zoap_packet *request, } /* set output content-format */ - r = zoap_add_option_int(out.out_zpkt, - ZOAP_OPTION_CONTENT_FORMAT, accept); + r = coap_append_option_int(out.out_cpkt, + COAP_OPTION_CONTENT_FORMAT, + accept); if (r > 0) { SYS_LOG_ERR("Error setting response content-format: %d", r); @@ -2479,30 +2560,24 @@ static int handle_request(struct zoap_packet *request, goto error; } - /* Handle blockwise 1 */ + /* Handle blockwise 1 (Part 2): Append BLOCK1 option */ if (block_ctx) { if (block_offset > 0) { /* More to come, ack with correspond block # */ - r = zoap_add_block1_option( - out.out_zpkt, &block_ctx->ctx); + r = coap_append_block1_option(out.out_cpkt, + &block_ctx->ctx); if (r) { /* report as internal server error */ SYS_LOG_ERR("Fail adding block1 option: %d", r); r = -EINVAL; goto error; - } else { - zoap_header_set_code(out.out_zpkt, - ZOAP_RESPONSE_CODE_CONTINUE); } - } else { - /* Free context when finished */ - free_block_ctx(block_ctx); } } if (out.outlen > 0) { SYS_LOG_DBG("replying with %u bytes", out.outlen); - zoap_packet_set_used(out.out_zpkt, out.outlen); + coap_packet_set_used(out.out_cpkt, out.outlen); } else { SYS_LOG_DBG("no data in reply"); } @@ -2510,22 +2585,20 @@ static int handle_request(struct zoap_packet *request, return 0; error: - if (r == -ENOENT) { - zoap_header_set_code(out.out_zpkt, - ZOAP_RESPONSE_CODE_NOT_FOUND); - } else if (r == -EPERM) { - zoap_header_set_code(out.out_zpkt, - ZOAP_RESPONSE_CODE_NOT_ALLOWED); - } else if (r == -EEXIST) { - zoap_header_set_code(out.out_zpkt, - ZOAP_RESPONSE_CODE_BAD_REQUEST); - } else if (r == -EFBIG) { - zoap_header_set_code(out.out_zpkt, - ZOAP_RESPONSE_CODE_REQUEST_TOO_LARGE); - } else { - /* Failed to handle the request */ - zoap_header_set_code(out.out_zpkt, - ZOAP_RESPONSE_CODE_INTERNAL_ERROR); + if (r < 0) { + /* TODO: reset CoAP packet and empty payload */ + if (r == -ENOENT) { + msg->code = COAP_RESPONSE_CODE_NOT_FOUND; + } else if (r == -EPERM) { + msg->code = COAP_RESPONSE_CODE_NOT_ALLOWED; + } else if (r == -EEXIST) { + msg->code = COAP_RESPONSE_CODE_BAD_REQUEST; + } else if (r == -EFBIG) { + msg->code = COAP_RESPONSE_CODE_REQUEST_TOO_LARGE; + } else { + /* Failed to handle the request */ + msg->code = COAP_RESPONSE_CODE_INTERNAL_ERROR; + } } /* Free block context when error happened */ @@ -2539,13 +2612,14 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, udp_request_handler_cb_t udp_request_handler) { struct net_udp_hdr hdr, *udp_hdr; - struct zoap_pending *pending; - struct zoap_reply *reply; - struct zoap_packet response; + struct coap_pending *pending; + struct coap_reply *reply; + struct coap_packet response; struct sockaddr from_addr; struct lwm2m_message *msg = NULL; - int header_len, r; - const u8_t *token; + struct coap_option options[4]; + int r; + u8_t token[8]; u8_t tkl; udp_hdr = net_udp_get_hdr(pkt, &hdr); @@ -2573,26 +2647,19 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, } #endif - /* - * zoap expects that buffer->data starts at the - * beginning of the CoAP header - */ - header_len = net_pkt_appdata(pkt) - pkt->frags->data; - net_buf_pull(pkt->frags, header_len); - - r = zoap_packet_parse(&response, pkt); + r = coap_packet_parse(&response, pkt, options, 4); if (r < 0) { SYS_LOG_ERR("Invalid data received (err:%d)", r); goto cleanup; } - token = zoap_header_get_token(&response, &tkl); - pending = zoap_pending_received(&response, client_ctx->pendings, + tkl = coap_header_get_token(&response, token); + pending = coap_pending_received(&response, client_ctx->pendings, CONFIG_LWM2M_ENGINE_MAX_PENDING); /* - * Clear pending pointer because zoap_pending_received() calls - * zoap_pending_clear, and later when we call lwm2m_release_message() - * it will try and call zoap_pending_clear() again if msg->pending + * Clear pending pointer because coap_pending_received() calls + * coap_pending_clear, and later when we call lwm2m_release_message() + * it will try and call coap_pending_clear() again if msg->pending * is != NULL. */ if (pending) { @@ -2605,7 +2672,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, SYS_LOG_DBG("checking for reply from [%s]", lwm2m_sprint_ip_addr(&from_addr)); - reply = zoap_response_received(&response, &from_addr, + reply = coap_response_received(&response, &from_addr, client_ctx->replies, CONFIG_LWM2M_ENGINE_MAX_REPLIES); if (reply) { @@ -2620,7 +2687,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, * additional flag to decide when to clear the reply callback. */ if (handle_separate_response && !tkl && - zoap_header_get_type(&response) == ZOAP_TYPE_ACK) { + coap_header_get_type(&response) == COAP_TYPE_ACK) { SYS_LOG_DBG("separated response, not removing reply"); goto cleanup; } @@ -2647,7 +2714,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, * at registered objects to find a handler. */ if (udp_request_handler && - zoap_header_get_type(&response) == ZOAP_TYPE_CON) { + coap_header_get_type(&response) == COAP_TYPE_CON) { msg = lwm2m_get_message(client_ctx); if (!msg) { SYS_LOG_ERR("Unable to get a lwm2m message!"); @@ -2655,28 +2722,23 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, } /* Create a response message if we reach this point */ - msg->type = ZOAP_TYPE_ACK; - msg->code = zoap_header_get_code(&response); - msg->mid = zoap_header_get_id(&response); + msg->type = COAP_TYPE_ACK; + msg->code = coap_header_get_code(&response); + msg->mid = coap_header_get_id(&response); /* skip token generation by default */ msg->tkl = LWM2M_MSG_TOKEN_LEN_SKIP; - r = lwm2m_init_message(msg); + /* process the response to this request */ + r = udp_request_handler(&response, msg); if (r < 0) { goto cleanup; } - /* process the response to this request */ - r = udp_request_handler(&response, msg); + r = lwm2m_send_message(msg); if (r < 0) { - SYS_LOG_ERR("Request handler error: %d", r); - } else { - r = lwm2m_send_message(msg); - if (r < 0) { - SYS_LOG_ERR("Err sending response: %d", - r); - lwm2m_release_message(msg); - } + SYS_LOG_ERR("Err sending response: %d", + r); + lwm2m_release_message(msg); } } else { SYS_LOG_ERR("No handler for response"); @@ -2702,11 +2764,11 @@ static void retransmit_request(struct k_work *work) { struct lwm2m_ctx *client_ctx; struct lwm2m_message *msg; - struct zoap_pending *pending; + struct coap_pending *pending; int r; client_ctx = CONTAINER_OF(work, struct lwm2m_ctx, retransmit_work); - pending = zoap_pending_next_to_expire(client_ctx->pendings, + pending = coap_pending_next_to_expire(client_ctx->pendings, CONFIG_LWM2M_ENGINE_MAX_PENDING); if (!pending) { return; @@ -2719,7 +2781,7 @@ static void retransmit_request(struct k_work *work) return; } - if (!zoap_pending_cycle(pending)) { + if (!coap_pending_cycle(pending)) { /* pending request has expired */ if (msg->message_timeout_cb) { msg->message_timeout_cb(msg); @@ -2740,24 +2802,24 @@ static void retransmit_request(struct k_work *work) k_delayed_work_submit(&client_ctx->retransmit_work, pending->timeout); } -static int notify_message_reply_cb(const struct zoap_packet *response, - struct zoap_reply *reply, +static int notify_message_reply_cb(const struct coap_packet *response, + struct coap_reply *reply, const struct sockaddr *from) { int ret = 0; u8_t type, code; - type = zoap_header_get_type(response); - code = zoap_header_get_code(response); + type = coap_header_get_type(response); + code = coap_header_get_code(response); SYS_LOG_DBG("NOTIFY ACK type:%u code:%d.%d reply_token:'%s'", type, - ZOAP_RESPONSE_CODE_CLASS(code), - ZOAP_RESPONSE_CODE_DETAIL(code), + COAP_RESPONSE_CODE_CLASS(code), + COAP_RESPONSE_CODE_DETAIL(code), sprint_token(reply->token, reply->tkl)); - /* remove observer on ZOAP_TYPE_RESET */ - if (type == ZOAP_TYPE_RESET) { + /* remove observer on COAP_TYPE_RESET */ + if (type == COAP_TYPE_RESET) { if (reply->tkl > 0) { ret = engine_remove_observer(reply->token, reply->tkl); if (ret) { @@ -2821,24 +2883,25 @@ static int generate_notify_message(struct observe_node *obs, return -ENOMEM; } - out.out_zpkt = &msg->zpkt; - msg->type = ZOAP_TYPE_CON; - msg->code = ZOAP_RESPONSE_CODE_CONTENT; + msg->type = COAP_TYPE_CON; + msg->code = COAP_RESPONSE_CODE_CONTENT; msg->mid = 0; msg->token = obs->token; msg->tkl = obs->tkl; msg->reply_cb = notify_message_reply_cb; + out.out_cpkt = &msg->cpkt; ret = lwm2m_init_message(msg); - if (ret) { - return ret; + if (ret < 0) { + SYS_LOG_ERR("Unable to init lwm2m message! (err: %d)", ret); + goto cleanup; } /* each notification should increment the obs counter */ obs->counter++; - ret = zoap_add_option_int(out.out_zpkt, ZOAP_OPTION_OBSERVE, - obs->counter); - if (ret) { + ret = coap_append_option_int(&msg->cpkt, COAP_OPTION_OBSERVE, + obs->counter); + if (ret < 0) { SYS_LOG_ERR("OBSERVE option error: %d", ret); goto cleanup; } @@ -2847,9 +2910,9 @@ static int generate_notify_message(struct observe_node *obs, select_writer(&out, obs->format); /* set response content-format */ - ret = zoap_add_option_int(out.out_zpkt, ZOAP_OPTION_CONTENT_FORMAT, - obs->format); - if (ret > 0) { + ret = coap_append_option_int(&msg->cpkt, COAP_OPTION_CONTENT_FORMAT, + obs->format); + if (ret < 0) { SYS_LOG_ERR("error setting content-format (err:%d)", ret); goto cleanup; } @@ -2857,7 +2920,7 @@ static int generate_notify_message(struct observe_node *obs, ret = do_read_op(obj_inst->obj, &context); if (ret == 0) { if (out.outlen > 0) { - zoap_packet_set_used(out.out_zpkt, out.outlen); + coap_packet_set_used(out.out_cpkt, out.outlen); } else { SYS_LOG_DBG("no data in reply"); } diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index 3255bab7a75cd..0ac01147c33ff 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -25,8 +25,8 @@ #define LWM2M_FORMAT_OMA_JSON 11543 -#define ZOAP_RESPONSE_CODE_CLASS(x) (x >> 5) -#define ZOAP_RESPONSE_CODE_DETAIL(x) (x & 0x1F) +#define COAP_RESPONSE_CODE_CLASS(x) (x >> 5) +#define COAP_RESPONSE_CODE_DETAIL(x) (x & 0x1F) /* TODO: */ #define NOTIFY_OBSERVER(o, i, r) lwm2m_notify_observer(o, i, r) @@ -36,7 +36,7 @@ #define LWM2M_MSG_TOKEN_LEN_SKIP 0xFF /* Establish a request handler callback type */ -typedef int (*udp_request_handler_cb_t)(struct zoap_packet *request, +typedef int (*udp_request_handler_cb_t)(struct coap_packet *request, struct lwm2m_message *msg); char *lwm2m_sprint_ip_addr(const struct sockaddr *addr); @@ -71,11 +71,16 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, struct lwm2m_engine_obj_field *obj_field, struct lwm2m_engine_context *context); +/* CoAP payload functions */ +u8_t *coap_packet_get_payload_ptr(struct coap_packet *cpkt, u16_t *len, + bool start_marker); +int coap_packet_set_used(struct coap_packet *cpkt, u16_t len); + void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, bool handle_separate_response, udp_request_handler_cb_t udp_request_handler); -enum zoap_block_size lwm2m_default_block_size(void); +enum coap_block_size lwm2m_default_block_size(void); #if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT) u8_t lwm2m_firmware_get_update_state(void); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c index f4b0e70ff1aac..828363c0e9e78 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c @@ -12,7 +12,7 @@ #define SYS_LOG_DOMAIN "lwm2m_obj_firmware" #define SYS_LOG_LEVEL CONFIG_SYS_LOG_LWM2M_LEVEL #include -#include +#include #include #include diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c index d590b774401ca..02e679a240cd2 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -34,7 +34,7 @@ static struct sockaddr firmware_addr; static struct http_parser_url parsed_uri; static struct lwm2m_ctx firmware_ctx; static int firmware_retry; -static struct zoap_block_context firmware_block_ctx; +static struct coap_block_context firmware_block_ctx; #if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT) #define PROXY_URI_LEN 255 @@ -50,9 +50,9 @@ firmware_udp_receive(struct net_app_ctx *app_ctx, struct net_pkt *pkt, lwm2m_udp_receive(&firmware_ctx, pkt, true, NULL); } -static int transfer_request(struct zoap_block_context *ctx, - const u8_t *token, u8_t tkl, - zoap_reply_t reply_cb) +static int transfer_request(struct coap_block_context *ctx, + u8_t *token, u8_t tkl, + coap_reply_t reply_cb) { struct lwm2m_message *msg; int ret; @@ -70,8 +70,8 @@ static int transfer_request(struct zoap_block_context *ctx, return -ENOMEM; } - msg->type = ZOAP_TYPE_CON; - msg->code = ZOAP_METHOD_GET; + msg->type = COAP_TYPE_CON; + msg->code = COAP_METHOD_GET; msg->mid = 0; msg->token = token; msg->tkl = tkl; @@ -86,8 +86,8 @@ static int transfer_request(struct zoap_block_context *ctx, #if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT) char *uri_path = CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_URI_PATH; - ret = zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_PATH, - uri_path, strlen(uri_path)); + ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH, + uri_path, strlen(uri_path)); if (ret < 0) { SYS_LOG_ERR("Error adding URI_PATH '%s'", uri_path); goto cleanup; @@ -102,8 +102,8 @@ static int transfer_request(struct zoap_block_context *ctx, for (i = 0; i < len; i++) { if (firmware_uri[off + i] == '/') { if (path_len > 0) { - ret = zoap_add_option(&msg->zpkt, - ZOAP_OPTION_URI_PATH, + ret = coap_packet_append_option(&msg->cpkt, + COAP_OPTION_URI_PATH, cursor, path_len); if (ret < 0) { SYS_LOG_ERR("Error adding URI_PATH"); @@ -121,8 +121,9 @@ static int transfer_request(struct zoap_block_context *ctx, if (i == len - 1) { /* flush the rest */ - ret = zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_PATH, - cursor, path_len + 1); + ret = coap_packet_append_option(&msg->cpkt, + COAP_OPTION_URI_PATH, + cursor, path_len + 1); if (ret < 0) { SYS_LOG_ERR("Error adding URI_PATH"); goto cleanup; @@ -133,22 +134,22 @@ static int transfer_request(struct zoap_block_context *ctx, } #endif - ret = zoap_add_block2_option(&msg->zpkt, ctx); + ret = coap_append_block2_option(&msg->cpkt, ctx); if (ret) { SYS_LOG_ERR("Unable to add block2 option."); goto cleanup; } #if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT) - ret = zoap_add_option(&msg->zpkt, ZOAP_OPTION_PROXY_URI, - firmware_uri, strlen(firmware_uri)); + ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_PROXY_URI, + firmware_uri, strlen(firmware_uri)); if (ret < 0) { SYS_LOG_ERR("Error adding PROXY_URI '%s'", firmware_uri); goto cleanup; } #else /* Ask the server to provide a size estimate */ - ret = zoap_add_option_int(&msg->zpkt, ZOAP_OPTION_SIZE2, 0); + ret = coap_append_option_int(&msg->cpkt, COAP_OPTION_SIZE2, 0); if (ret) { SYS_LOG_ERR("Unable to add size2 option."); goto cleanup; @@ -187,8 +188,8 @@ static int transfer_empty_ack(u16_t mid) return -ENOMEM; } - msg->type = ZOAP_TYPE_ACK; - msg->code = ZOAP_CODE_EMPTY; + msg->type = COAP_TYPE_ACK; + msg->code = COAP_CODE_EMPTY; msg->mid = mid; ret = lwm2m_init_message(msg); @@ -211,30 +212,30 @@ static int transfer_empty_ack(u16_t mid) } static int -do_firmware_transfer_reply_cb(const struct zoap_packet *response, - struct zoap_reply *reply, +do_firmware_transfer_reply_cb(const struct coap_packet *response, + struct coap_reply *reply, const struct sockaddr *from) { int ret; size_t transfer_offset = 0; - const u8_t *token; + u8_t token[8]; u8_t tkl; u16_t payload_len; u8_t *payload; - struct zoap_packet *check_response = (struct zoap_packet *)response; + struct coap_packet *check_response = (struct coap_packet *)response; lwm2m_engine_set_data_cb_t callback; u8_t resp_code; - struct zoap_block_context received_block_ctx; + struct coap_block_context received_block_ctx; /* token is used to determine a valid ACK vs a separated response */ - token = zoap_header_get_token(check_response, &tkl); + tkl = coap_header_get_token(check_response, token); /* If separated response (ACK) return and wait for response */ - if (!tkl && zoap_header_get_type(response) == ZOAP_TYPE_ACK) { + if (!tkl && coap_header_get_type(response) == COAP_TYPE_ACK) { return 0; - } else if (zoap_header_get_type(response) == ZOAP_TYPE_CON) { + } else if (coap_header_get_type(response) == COAP_TYPE_CON) { /* Send back ACK so the server knows we received the pkt */ - ret = transfer_empty_ack(zoap_header_get_id(check_response)); + ret = transfer_empty_ack(coap_header_get_id(check_response)); if (ret < 0) { SYS_LOG_ERR("Error transmitting ACK"); return ret; @@ -242,11 +243,11 @@ do_firmware_transfer_reply_cb(const struct zoap_packet *response, } /* Check response code from server. Expecting (2.05) */ - resp_code = zoap_header_get_code(check_response); - if (resp_code != ZOAP_RESPONSE_CODE_CONTENT) { + resp_code = coap_header_get_code(check_response); + if (resp_code != COAP_RESPONSE_CODE_CONTENT) { SYS_LOG_ERR("Unexpected response from server: %d.%d", - ZOAP_RESPONSE_CODE_CLASS(resp_code), - ZOAP_RESPONSE_CODE_DETAIL(resp_code)); + COAP_RESPONSE_CODE_CLASS(resp_code), + COAP_RESPONSE_CODE_DETAIL(resp_code)); lwm2m_firmware_set_update_result(RESULT_CONNECTION_LOST); return -ENOENT; } @@ -255,7 +256,7 @@ do_firmware_transfer_reply_cb(const struct zoap_packet *response, memcpy(&received_block_ctx, &firmware_block_ctx, sizeof(firmware_block_ctx)); - ret = zoap_update_from_block(check_response, &firmware_block_ctx); + ret = coap_update_from_block(check_response, &firmware_block_ctx); if (ret < 0) { SYS_LOG_ERR("Error from block update: %d", ret); lwm2m_firmware_set_update_result(RESULT_INTEGRITY_FAILED); @@ -272,10 +273,11 @@ do_firmware_transfer_reply_cb(const struct zoap_packet *response, } /* Reach last block if transfer_offset equals to 0 */ - transfer_offset = zoap_next_block(check_response, &firmware_block_ctx); + transfer_offset = coap_next_block(check_response, &firmware_block_ctx); /* Process incoming data */ - payload = zoap_packet_get_payload(check_response, &payload_len); + payload = coap_packet_get_payload_ptr(check_response, &payload_len, + false); if (payload_len > 0) { SYS_LOG_DBG("total: %zd, current: %zd", firmware_block_ctx.total_size, @@ -316,13 +318,13 @@ do_firmware_transfer_reply_cb(const struct zoap_packet *response, static void do_transmit_timeout_cb(struct lwm2m_message *msg) { - const u8_t *token; + u8_t token[8]; u8_t tkl; if (firmware_retry < PACKET_TRANSFER_RETRY_MAX) { /* retry block */ SYS_LOG_WRN("TIMEOUT - Sending a retry packet!"); - token = zoap_header_get_token(&msg->zpkt, &tkl); + tkl = coap_header_get_token(&msg->cpkt, token); transfer_request(&firmware_block_ctx, token, tkl, do_firmware_transfer_reply_cb); @@ -477,9 +479,9 @@ static void firmware_transfer(struct k_work *work) } /* reset block transfer context */ - zoap_block_transfer_init(&firmware_block_ctx, + coap_block_transfer_init(&firmware_block_ctx, lwm2m_default_block_size(), 0); - transfer_request(&firmware_block_ctx, zoap_next_token(), 8, + transfer_request(&firmware_block_ctx, coap_next_token(), 8, do_firmware_transfer_reply_cb); return; diff --git a/subsys/net/lib/lwm2m/lwm2m_object.h b/subsys/net/lib/lwm2m/lwm2m_object.h index 96d2033e6e035..d47e55d884af7 100644 --- a/subsys/net/lib/lwm2m/lwm2m_object.h +++ b/subsys/net/lib/lwm2m/lwm2m_object.h @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include #include @@ -204,7 +204,7 @@ struct lwm2m_engine_obj_inst { }; struct lwm2m_output_context { - struct zoap_packet *out_zpkt; + struct coap_packet *out_cpkt; u8_t writer_flags; /* flags for reader/writer */ u8_t *outbuf; u16_t outsize; @@ -214,7 +214,7 @@ struct lwm2m_output_context { }; struct lwm2m_input_context { - struct zoap_packet *in_zpkt; + struct coap_packet *in_cpkt; u8_t *inbuf; u16_t insize; s32_t inpos; diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index a723bd5184004..48ff3a4bb1893 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -53,7 +53,7 @@ #include #include #include -#include +#include #include #include "lwm2m_object.h" @@ -263,17 +263,17 @@ void engine_trigger_update(void) /* state machine reply callbacks */ -static int do_bootstrap_reply_cb(const struct zoap_packet *response, - struct zoap_reply *reply, +static int do_bootstrap_reply_cb(const struct coap_packet *response, + struct coap_reply *reply, const struct sockaddr *from) { u8_t code; int index; - code = zoap_header_get_code(response); + code = coap_header_get_code(response); SYS_LOG_DBG("Bootstrap callback (code:%u.%u)", - ZOAP_RESPONSE_CODE_CLASS(code), - ZOAP_RESPONSE_CODE_DETAIL(code)); + COAP_RESPONSE_CODE_CLASS(code), + COAP_RESPONSE_CODE_DETAIL(code)); index = find_clients_index(from); if (index < 0) { @@ -281,20 +281,20 @@ static int do_bootstrap_reply_cb(const struct zoap_packet *response, return 0; } - if (code == ZOAP_RESPONSE_CODE_CHANGED) { + if (code == COAP_RESPONSE_CODE_CHANGED) { SYS_LOG_DBG("Considered done!"); set_sm_state(index, ENGINE_BOOTSTRAP_DONE); - } else if (code == ZOAP_RESPONSE_CODE_NOT_FOUND) { + } else if (code == COAP_RESPONSE_CODE_NOT_FOUND) { SYS_LOG_ERR("Failed: NOT_FOUND. Not Retrying."); set_sm_state(index, ENGINE_DO_REGISTRATION); - } else if (code == ZOAP_RESPONSE_CODE_FORBIDDEN) { + } else if (code == COAP_RESPONSE_CODE_FORBIDDEN) { SYS_LOG_ERR("Failed: 4.03 - Forbidden. Not Retrying."); set_sm_state(index, ENGINE_DO_REGISTRATION); } else { /* TODO: Read payload for error message? */ SYS_LOG_ERR("Failed with code %u.%u. Retrying ...", - ZOAP_RESPONSE_CODE_CLASS(code), - ZOAP_RESPONSE_CODE_DETAIL(code)); + COAP_RESPONSE_CODE_CLASS(code), + COAP_RESPONSE_CODE_DETAIL(code)); set_sm_state(index, ENGINE_INIT); } @@ -309,18 +309,18 @@ static void do_bootstrap_timeout_cb(struct lwm2m_message *msg) sm_handle_timeout_state(msg, ENGINE_INIT); } -static int do_registration_reply_cb(const struct zoap_packet *response, - struct zoap_reply *reply, +static int do_registration_reply_cb(const struct coap_packet *response, + struct coap_reply *reply, const struct sockaddr *from) { - struct zoap_option options[2]; + struct coap_option options[2]; u8_t code; int ret, index; - code = zoap_header_get_code(response); + code = coap_header_get_code(response); SYS_LOG_DBG("Registration callback (code:%u.%u)", - ZOAP_RESPONSE_CODE_CLASS(code), - ZOAP_RESPONSE_CODE_DETAIL(code)); + COAP_RESPONSE_CODE_CLASS(code), + COAP_RESPONSE_CODE_DETAIL(code)); index = find_clients_index(from); if (index < 0) { @@ -329,8 +329,8 @@ static int do_registration_reply_cb(const struct zoap_packet *response, } /* check state and possibly set registration to done */ - if (code == ZOAP_RESPONSE_CODE_CREATED) { - ret = zoap_find_options(response, ZOAP_OPTION_LOCATION_PATH, + if (code == COAP_RESPONSE_CODE_CREATED) { + ret = coap_find_options(response, COAP_OPTION_LOCATION_PATH, options, 2); if (ret < 0) { return ret; @@ -359,11 +359,11 @@ static int do_registration_reply_cb(const struct zoap_packet *response, clients[index].server_ep); return 0; - } else if (code == ZOAP_RESPONSE_CODE_NOT_FOUND) { + } else if (code == COAP_RESPONSE_CODE_NOT_FOUND) { SYS_LOG_ERR("Failed: NOT_FOUND. Not Retrying."); set_sm_state(index, ENGINE_REGISTRATION_DONE); return 0; - } else if (code == ZOAP_RESPONSE_CODE_FORBIDDEN) { + } else if (code == COAP_RESPONSE_CODE_FORBIDDEN) { SYS_LOG_ERR("Failed: 4.03 - Forbidden. Not Retrying."); set_sm_state(index, ENGINE_REGISTRATION_DONE); return 0; @@ -372,8 +372,8 @@ static int do_registration_reply_cb(const struct zoap_packet *response, /* TODO: Read payload for error message? */ /* Possible error response codes: 4.00 Bad request */ SYS_LOG_ERR("failed with code %u.%u. Re-init network", - ZOAP_RESPONSE_CODE_CLASS(code), - ZOAP_RESPONSE_CODE_DETAIL(code)); + COAP_RESPONSE_CODE_CLASS(code), + COAP_RESPONSE_CODE_DETAIL(code)); set_sm_state(index, ENGINE_INIT); return 0; } @@ -386,17 +386,17 @@ static void do_registration_timeout_cb(struct lwm2m_message *msg) sm_handle_timeout_state(msg, ENGINE_INIT); } -static int do_update_reply_cb(const struct zoap_packet *response, - struct zoap_reply *reply, +static int do_update_reply_cb(const struct coap_packet *response, + struct coap_reply *reply, const struct sockaddr *from) { u8_t code; int index; - code = zoap_header_get_code(response); + code = coap_header_get_code(response); SYS_LOG_INF("Update callback (code:%u.%u)", - ZOAP_RESPONSE_CODE_CLASS(code), - ZOAP_RESPONSE_CODE_DETAIL(code)); + COAP_RESPONSE_CODE_CLASS(code), + COAP_RESPONSE_CODE_DETAIL(code)); index = find_clients_index(from); if (index < 0) { @@ -405,8 +405,8 @@ static int do_update_reply_cb(const struct zoap_packet *response, } /* If NOT_FOUND just continue on */ - if ((code == ZOAP_RESPONSE_CODE_CHANGED) || - (code == ZOAP_RESPONSE_CODE_CREATED)) { + if ((code == COAP_RESPONSE_CODE_CHANGED) || + (code == COAP_RESPONSE_CODE_CREATED)) { set_sm_state(index, ENGINE_REGISTRATION_DONE); SYS_LOG_INF("Update Done"); return 0; @@ -415,8 +415,8 @@ static int do_update_reply_cb(const struct zoap_packet *response, /* TODO: Read payload for error message? */ /* Possible error response codes: 4.00 Bad request & 4.04 Not Found */ SYS_LOG_ERR("Failed with code %u.%u. Retrying registration", - ZOAP_RESPONSE_CODE_CLASS(code), - ZOAP_RESPONSE_CODE_DETAIL(code)); + COAP_RESPONSE_CODE_CLASS(code), + COAP_RESPONSE_CODE_DETAIL(code)); set_sm_state(index, ENGINE_DO_REGISTRATION); return 0; @@ -430,17 +430,17 @@ static void do_update_timeout_cb(struct lwm2m_message *msg) sm_handle_timeout_state(msg, ENGINE_DO_REGISTRATION); } -static int do_deregister_reply_cb(const struct zoap_packet *response, - struct zoap_reply *reply, +static int do_deregister_reply_cb(const struct coap_packet *response, + struct coap_reply *reply, const struct sockaddr *from) { u8_t code; int index; - code = zoap_header_get_code(response); + code = coap_header_get_code(response); SYS_LOG_DBG("Deregister callback (code:%u.%u)", - ZOAP_RESPONSE_CODE_CLASS(code), - ZOAP_RESPONSE_CODE_DETAIL(code)); + COAP_RESPONSE_CODE_CLASS(code), + COAP_RESPONSE_CODE_DETAIL(code)); index = find_clients_index(from); if (index < 0) { @@ -448,13 +448,13 @@ static int do_deregister_reply_cb(const struct zoap_packet *response, return 0; } - if (code == ZOAP_RESPONSE_CODE_DELETED) { + if (code == COAP_RESPONSE_CODE_DELETED) { SYS_LOG_DBG("Deregistration success"); set_sm_state(index, ENGINE_DEREGISTERED); } else { SYS_LOG_ERR("failed with code %u.%u", - ZOAP_RESPONSE_CODE_CLASS(code), - ZOAP_RESPONSE_CODE_DETAIL(code)); + COAP_RESPONSE_CODE_CLASS(code), + COAP_RESPONSE_CODE_DETAIL(code)); if (get_sm_state(index) == ENGINE_DEREGISTER_SENT) { set_sm_state(index, ENGINE_DEREGISTER_FAILED); } @@ -517,8 +517,8 @@ static int sm_do_bootstrap(int index) return -ENOMEM; } - msg->type = ZOAP_TYPE_CON; - msg->code = ZOAP_METHOD_POST; + msg->type = COAP_TYPE_CON; + msg->code = COAP_METHOD_POST; msg->mid = 0; msg->reply_cb = do_bootstrap_reply_cb; msg->message_timeout_cb = do_bootstrap_timeout_cb; @@ -528,13 +528,15 @@ static int sm_do_bootstrap(int index) goto cleanup; } - zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_PATH, - "bs", strlen("bs")); + /* TODO: handle return error */ + coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH, + "bs", strlen("bs")); snprintf(query_buffer, sizeof(query_buffer) - 1, "ep=%s", clients[index].ep_name); - zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_QUERY, - query_buffer, strlen(query_buffer)); + /* TODO: handle return error */ + coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_QUERY, + query_buffer, strlen(query_buffer)); /* log the bootstrap attempt */ SYS_LOG_DBG("Register ID with bootstrap server [%s] as '%s'", @@ -603,7 +605,7 @@ static int sm_bootstrap_done(int index) } static int sm_send_registration(int index, bool send_obj_support_data, - zoap_reply_t reply_cb, + coap_reply_t reply_cb, lwm2m_message_timeout_cb_t timeout_cb) { struct net_app_ctx *app_ctx = NULL; @@ -622,8 +624,8 @@ static int sm_send_registration(int index, bool send_obj_support_data, /* remember the last reg time */ clients[index].last_update = k_uptime_get(); - msg->type = ZOAP_TYPE_CON; - msg->code = ZOAP_METHOD_POST; + msg->type = COAP_TYPE_CON; + msg->code = COAP_METHOD_POST; msg->mid = 0; msg->reply_cb = reply_cb; msg->message_timeout_cb = timeout_cb; @@ -633,47 +635,53 @@ static int sm_send_registration(int index, bool send_obj_support_data, goto cleanup; } - zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_PATH, - LWM2M_RD_CLIENT_URI, - strlen(LWM2M_RD_CLIENT_URI)); + /* TODO: handle return error */ + coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH, + LWM2M_RD_CLIENT_URI, + strlen(LWM2M_RD_CLIENT_URI)); if (!sm_is_registered(index)) { /* include client endpoint in URI QUERY on 1st registration */ - zoap_add_option_int(&msg->zpkt, ZOAP_OPTION_CONTENT_FORMAT, - LWM2M_FORMAT_APP_LINK_FORMAT); + coap_append_option_int(&msg->cpkt, COAP_OPTION_CONTENT_FORMAT, + LWM2M_FORMAT_APP_LINK_FORMAT); snprintf(query_buffer, sizeof(query_buffer) - 1, "lwm2m=%s", LWM2M_PROTOCOL_VERSION); - zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_QUERY, - query_buffer, strlen(query_buffer)); + /* TODO: handle return error */ + coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_QUERY, + query_buffer, strlen(query_buffer)); snprintf(query_buffer, sizeof(query_buffer) - 1, "ep=%s", clients[index].ep_name); - zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_QUERY, - query_buffer, strlen(query_buffer)); + /* TODO: handle return error */ + coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_QUERY, + query_buffer, strlen(query_buffer)); } else { /* include server endpoint in URI PATH otherwise */ - zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_PATH, - clients[index].server_ep, - strlen(clients[index].server_ep)); + /* TODO: handle return error */ + coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH, + clients[index].server_ep, + strlen(clients[index].server_ep)); } snprintf(query_buffer, sizeof(query_buffer) - 1, "lt=%d", clients[index].lifetime); - zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_QUERY, - query_buffer, strlen(query_buffer)); + /* TODO: handle return error */ + coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_QUERY, + query_buffer, strlen(query_buffer)); + /* TODO: add supported binding query string */ if (send_obj_support_data) { /* generate the rd data */ client_data_len = lwm2m_get_rd_data(client_data, - sizeof(client_data)); - payload = zoap_packet_get_payload(&msg->zpkt, &len); + sizeof(client_data)); + payload = coap_packet_get_payload_ptr(&msg->cpkt, &len, true); if (!payload) { ret = -EINVAL; goto cleanup; } memcpy(payload, client_data, client_data_len); - ret = zoap_packet_set_used(&msg->zpkt, client_data_len); + ret = coap_packet_set_used(&msg->cpkt, client_data_len); if (ret) { goto cleanup; } @@ -755,8 +763,8 @@ static int sm_do_deregister(int index) return -ENOMEM; } - msg->type = ZOAP_TYPE_CON; - msg->code = ZOAP_METHOD_DELETE; + msg->type = COAP_TYPE_CON; + msg->code = COAP_METHOD_DELETE; msg->mid = 0; msg->reply_cb = do_deregister_reply_cb; msg->message_timeout_cb = do_deregister_timeout_cb; @@ -766,9 +774,10 @@ static int sm_do_deregister(int index) goto cleanup; } - zoap_add_option(&msg->zpkt, ZOAP_OPTION_URI_PATH, - clients[index].server_ep, - strlen(clients[index].server_ep)); + /* TODO: handle return error */ + coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH, + clients[index].server_ep, + strlen(clients[index].server_ep)); SYS_LOG_INF("Deregister from '%s'", clients[index].server_ep); diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c b/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c index 3db0f770d17be..31c56897085b6 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c +++ b/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c @@ -711,8 +711,8 @@ int do_write_op_tlv(struct lwm2m_engine_obj *obj, pos += len2; } - zoap_header_set_code(context->out->out_zpkt, - ZOAP_RESPONSE_CODE_CREATED); + /* TODO: Fix me */ + /* context->out->out_msg->code = COAP_RESPONSE_CODE_CREATED; */ } else if (tlv.type == OMA_TLV_TYPE_RESOURCE) { path->res_id = tlv.id; path->level = 3; From 9ebb3eb3be77e7f59ddd09e6f03e87f17e6b65cf Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Fri, 25 Aug 2017 09:31:23 -0700 Subject: [PATCH 30/37] net: lwm2m: add support for DTLS Signed-off-by: Michael Scott --- include/net/lwm2m.h | 16 ++++++++++++ subsys/net/lib/lwm2m/lwm2m_engine.c | 40 +++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/include/net/lwm2m.h b/include/net/lwm2m.h index d7d01946cc6c5..7044dfef4e990 100644 --- a/include/net/lwm2m.h +++ b/include/net/lwm2m.h @@ -92,6 +92,22 @@ struct lwm2m_ctx { struct coap_reply replies[CONFIG_LWM2M_ENGINE_MAX_REPLIES]; struct lwm2m_message messages[CONFIG_LWM2M_ENGINE_MAX_MESSAGES]; struct k_delayed_work retransmit_work; + +#if defined(CONFIG_NET_APP_DTLS) + /** Pre-Shared Key Information*/ + unsigned char *client_psk; + size_t client_psk_len; + char *client_psk_id; + size_t client_psk_id_len; + + /** DTLS support structures */ + char *cert_host; + u8_t *dtls_result_buf; + size_t dtls_result_buf_len; + struct k_mem_pool *dtls_pool; + k_thread_stack_t dtls_stack; + size_t dtls_stack_len; +#endif }; /* callback can return 1 if handled (don't update value) */ diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 8f6789f75f8a1..c8794c3509481 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -77,6 +77,10 @@ #define BUF_ALLOC_TIMEOUT K_SECONDS(1) +#if defined(CONFIG_NET_APP_DTLS) +#define INSTANCE_INFO "Zephyr DTLS LwM2M-client" +#endif + #define MAX_TOKEN_LEN 8 struct observe_node { @@ -3007,6 +3011,24 @@ void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx) #endif } +#if defined(CONFIG_NET_APP_DTLS) +static int setup_cert(struct net_app_ctx *app_ctx, void *cert) +{ +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + struct lwm2m_ctx *client_ctx = CONTAINER_OF(app_ctx, + struct lwm2m_ctx, + net_app_ctx); + + mbedtls_ssl_conf_psk(&app_ctx->tls.mbedtls.conf, + (const unsigned char *)client_ctx->client_psk, + client_ctx->client_psk_len, + (const unsigned char *)client_ctx->client_psk_id, + client_ctx->client_psk_id_len); +#endif + return 0; +} +#endif /* CONFIG_NET_APP_DTLS */ + int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, char *peer_str, u16_t peer_port) { @@ -3034,6 +3056,24 @@ int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, goto error_start; } +#if defined(CONFIG_NET_APP_DTLS) + ret = net_app_client_tls(&client_ctx->net_app_ctx, + client_ctx->dtls_result_buf, + client_ctx->dtls_result_buf_len, + INSTANCE_INFO, + strlen(INSTANCE_INFO), + setup_cert, + client_ctx->cert_host, + NULL, + client_ctx->dtls_pool, + client_ctx->dtls_stack, + client_ctx->dtls_stack_len); + if (ret < 0) { + SYS_LOG_ERR("Cannot init DTLS (%d)", ret); + goto error_start; + } +#endif + ret = net_app_connect(&client_ctx->net_app_ctx, client_ctx->net_timeout); if (ret < 0) { From 757d93b3a3ccb13b9e482004ad0d39125c219ee6 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Wed, 27 Sep 2017 15:45:03 -0700 Subject: [PATCH 31/37] mbedtls: add lwm2m config for DTLS support This config is used with samples/net/lwm2m_client. It varies slightly from the config-coap.h file used with the COAP samples in that it has a larger SSL request size. Signed-off-by: Michael Scott --- ext/lib/crypto/mbedtls/configs/config-lwm2m.h | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 ext/lib/crypto/mbedtls/configs/config-lwm2m.h diff --git a/ext/lib/crypto/mbedtls/configs/config-lwm2m.h b/ext/lib/crypto/mbedtls/configs/config-lwm2m.h new file mode 100644 index 0000000000000..d16a5d1060003 --- /dev/null +++ b/ext/lib/crypto/mbedtls/configs/config-lwm2m.h @@ -0,0 +1,97 @@ +/* + * Minimal configuration for DTLS 1.2 with PSK and AES-CCM ciphersuites + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * Minimal configuration for TLS 1.2 with PSK and AES-CCM ciphersuites + * Distinguishing features: + * - no bignum, no PK, no X509 + * - fully modern and secure (provided the pre-shared keys have high entropy) + * - very low record overhead with CCM-8 + * - optimized for low RAM usage + * + * See README.txt for usage instructions. + */ +#ifndef MBEDTLS_CONFIG_H +#define MBEDTLS_CONFIG_H + +/* System support */ +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_MEMORY_BUFFER_ALLOC_C +#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#define MBEDTLS_PLATFORM_EXIT_ALT +#define MBEDTLS_NO_PLATFORM_ENTROPY +#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES +#define MBEDTLS_PLATFORM_PRINTF_ALT + +#if defined(CONFIG_MBEDTLS_TEST) +#define MBEDTLS_SELF_TEST +#define MBEDTLS_DEBUG_C +#else +#define MBEDTLS_ENTROPY_C +#endif + + +/* mbed TLS feature support */ +#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#define MBEDTLS_SSL_PROTO_TLS1_2 +#define MBEDTLS_SSL_PROTO_DTLS +#define MBEDTLS_SSL_DTLS_ANTI_REPLAY +#define MBEDTLS_SSL_DTLS_HELLO_VERIFY + + +/* mbed TLS modules */ +#define MBEDTLS_AES_C +#define MBEDTLS_CCM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CTR_DRBG_C +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_MD_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SSL_COOKIE_C +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_SRV_C +#define MBEDTLS_SSL_TLS_C + +/* Save RAM at the expense of ROM */ +#define MBEDTLS_AES_ROM_TABLES + +/* Save some RAM by adjusting to your exact needs */ +#define MBEDTLS_PSK_MAX_LEN 16 /* 128-bits keys are generally enough */ + +#if defined(CONFIG_MBEDTLS_DEBUG) +#define MBEDTLS_ERROR_C +#define MBEDTLS_DEBUG_C +#define MBEDTLS_SSL_DEBUG_ALL +#define MBEDTLS_SSL_ALL_ALERT_MESSAGES +#endif + +/* + * Use only CCM_8 ciphersuites, and + * save ROM and a few bytes of RAM by specifying our own ciphersuite list + */ +#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8 + +#define MBEDTLS_SSL_MAX_CONTENT_LEN 1500 + +#include "mbedtls/check_config.h" + +#endif /* MBEDTLS_CONFIG_H */ From 36faa44f48a0242e961872ff10efd59dccbf8a58 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Fri, 25 Aug 2017 09:31:45 -0700 Subject: [PATCH 32/37] samples: lwm2m: add support for DTLS For QEMU testing use CONF_FILE=prj_qemu_x86_dtls.conf For K64F testing use CONF_FILE=prj_frdm_k64f_dtls.conf Signed-off-by: Michael Scott --- .../net/lwm2m_client/prj_frdm_k64f_dtls.conf | 52 +++++++++++++++++++ .../net/lwm2m_client/prj_qemu_x86_dtls.conf | 52 +++++++++++++++++++ samples/net/lwm2m_client/src/lwm2m-client.c | 43 +++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 samples/net/lwm2m_client/prj_frdm_k64f_dtls.conf create mode 100644 samples/net/lwm2m_client/prj_qemu_x86_dtls.conf diff --git a/samples/net/lwm2m_client/prj_frdm_k64f_dtls.conf b/samples/net/lwm2m_client/prj_frdm_k64f_dtls.conf new file mode 100644 index 0000000000000..2563b132852c6 --- /dev/null +++ b/samples/net/lwm2m_client/prj_frdm_k64f_dtls.conf @@ -0,0 +1,52 @@ +CONFIG_NETWORKING=y +CONFIG_NET_LOG=y +CONFIG_NET_BUF_LOG=y +CONFIG_SYS_LOG_NET_LEVEL=4 +CONFIG_SYS_LOG_NET_BUF_LEVEL=2 +CONFIG_SYS_LOG_LWM2M_LEVEL=4 +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_NET_IPV6=y +CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 +CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=2 +CONFIG_NET_IPV4=y +CONFIG_NET_DHCPV4=n +CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=3 +CONFIG_NET_IF_MCAST_IPV4_ADDR_COUNT=2 +CONFIG_SYS_LOG_SHOW_COLOR=y +CONFIG_INIT_STACKS=y +CONFIG_PRINTK=y +CONFIG_NET_STATISTICS=y +CONFIG_NET_BUF_DATA_SIZE=384 +CONFIG_NET_PKT_RX_COUNT=50 +CONFIG_NET_PKT_TX_COUNT=50 +CONFIG_NET_BUF_RX_COUNT=50 +CONFIG_NET_BUF_TX_COUNT=50 +CONFIG_NET_MAX_CONTEXTS=10 +CONFIG_NET_CONTEXT_NET_PKT_POOL=y + +CONFIG_NET_SHELL=y + +CONFIG_NET_APP_NEED_IPV6=y +CONFIG_NET_APP_NEED_IPV4=y +CONFIG_NET_APP_SETTINGS=y +CONFIG_NET_APP_DTLS=y + +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_BUILTIN=y +CONFIG_MBEDTLS_ENABLE_HEAP=y +CONFIG_MBEDTLS_HEAP_SIZE=8192 +CONFIG_MBEDTLS_CFG_FILE="config-lwm2m.h" + +CONFIG_LWM2M=y +CONFIG_LWM2M_PEER_PORT=5684 +CONFIG_LWM2M_RD_CLIENT_INSTANCE_COUNT=2 +CONFIG_LWM2M_IPSO_SUPPORT=y +CONFIG_LWM2M_IPSO_TEMP_SENSOR=y +CONFIG_LWM2M_IPSO_LIGHT_CONTROL=y + +CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" +CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2" +CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1" +CONFIG_NET_APP_PEER_IPV4_ADDR="192.0.2.2" + +CONFIG_NET_L2_ETHERNET=y diff --git a/samples/net/lwm2m_client/prj_qemu_x86_dtls.conf b/samples/net/lwm2m_client/prj_qemu_x86_dtls.conf new file mode 100644 index 0000000000000..07748fbd7b013 --- /dev/null +++ b/samples/net/lwm2m_client/prj_qemu_x86_dtls.conf @@ -0,0 +1,52 @@ +CONFIG_NETWORKING=y +CONFIG_NET_LOG=y +CONFIG_NET_BUF_LOG=y +CONFIG_SYS_LOG_NET_LEVEL=4 +CONFIG_SYS_LOG_NET_BUF_LEVEL=2 +CONFIG_SYS_LOG_LWM2M_LEVEL=4 +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_NET_IPV6=y +CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 +CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=2 +CONFIG_NET_IPV4=y +CONFIG_NET_DHCPV4=n +CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=3 +CONFIG_NET_IF_MCAST_IPV4_ADDR_COUNT=2 +CONFIG_SYS_LOG_SHOW_COLOR=y +CONFIG_INIT_STACKS=y +CONFIG_PRINTK=y +CONFIG_NET_STATISTICS=y +CONFIG_NET_BUF_DATA_SIZE=384 +CONFIG_NET_PKT_RX_COUNT=50 +CONFIG_NET_PKT_TX_COUNT=50 +CONFIG_NET_BUF_RX_COUNT=50 +CONFIG_NET_BUF_TX_COUNT=50 +CONFIG_NET_MAX_CONTEXTS=10 +CONFIG_NET_CONTEXT_NET_PKT_POOL=y + +CONFIG_NET_SHELL=y + +CONFIG_NET_APP_NEED_IPV6=y +CONFIG_NET_APP_NEED_IPV4=y +CONFIG_NET_APP_SETTINGS=y +CONFIG_NET_APP_DTLS=y + +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_BUILTIN=y +CONFIG_MBEDTLS_ENABLE_HEAP=y +CONFIG_MBEDTLS_HEAP_SIZE=8192 +CONFIG_MBEDTLS_CFG_FILE="config-lwm2m.h" + +CONFIG_LWM2M=y +CONFIG_LWM2M_PEER_PORT=5684 +CONFIG_LWM2M_RD_CLIENT_INSTANCE_COUNT=2 +CONFIG_LWM2M_IPSO_SUPPORT=y +CONFIG_LWM2M_IPSO_TEMP_SENSOR=y +CONFIG_LWM2M_IPSO_LIGHT_CONTROL=y + +CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" +CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2" +CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1" +CONFIG_NET_APP_PEER_IPV4_ADDR="192.0.2.2" + +CONFIG_NET_SLIP_TAP=y diff --git a/samples/net/lwm2m_client/src/lwm2m-client.c b/samples/net/lwm2m_client/src/lwm2m-client.c index ea77695b75741..49fba71a4149b 100644 --- a/samples/net/lwm2m_client/src/lwm2m-client.c +++ b/samples/net/lwm2m_client/src/lwm2m-client.c @@ -54,6 +54,36 @@ static struct device *led_dev; static u32_t led_state; static struct lwm2m_ctx client; + +#if defined(CONFIG_NET_APP_DTLS) +#if !defined(CONFIG_NET_APP_TLS_STACK_SIZE) +#define CONFIG_NET_APP_TLS_STACK_SIZE 30000 +#endif /* CONFIG_NET_APP_TLS_STACK_SIZE */ + +#define HOSTNAME "localhost" /* for cert verification if that is enabled */ + +/* The result buf size is set to large enough so that we can receive max size + * buf back. Note that mbedtls needs also be configured to have equal size + * value for its buffer size. See MBEDTLS_SSL_MAX_CONTENT_LEN option in DTLS + * config file. + */ +#define RESULT_BUF_SIZE 1500 + +NET_APP_TLS_POOL_DEFINE(dtls_pool, 10); + +/* "000102030405060708090a0b0c0d0e0f" */ +static unsigned char client_psk[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f +}; + +static char client_psk_id[] = "Client_identity"; + +static u8_t dtls_result[RESULT_BUF_SIZE]; +NET_STACK_DEFINE(NET_APP_DTLS, net_app_dtls_stack, + CONFIG_NET_APP_TLS_STACK_SIZE, CONFIG_NET_APP_TLS_STACK_SIZE); +#endif /* CONFIG_NET_APP_DTLS */ + static struct k_sem quit_lock; #if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) @@ -307,6 +337,19 @@ void main(void) client.data_pool = data_udp_pool; #endif +#if defined(CONFIG_NET_APP_DTLS) + client.client_psk = client_psk; + client.client_psk_len = 16; + client.client_psk_id = client_psk_id; + client.client_psk_id_len = strlen(client_psk_id); + client.cert_host = HOSTNAME; + client.dtls_pool = &dtls_pool; + client.dtls_result_buf = dtls_result; + client.dtls_result_buf_len = RESULT_BUF_SIZE; + client.dtls_stack = net_app_dtls_stack; + client.dtls_stack_len = K_THREAD_STACK_SIZEOF(net_app_dtls_stack); +#endif /* CONFIG_NET_APP_DTLS */ + #if defined(CONFIG_NET_IPV6) ret = lwm2m_rd_client_start(&client, CONFIG_NET_APP_PEER_IPV6_ADDR, CONFIG_LWM2M_PEER_PORT, CONFIG_BOARD, From 3d39de5a34384afe3284e8c0c1f35d0a88cd33b7 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Wed, 27 Sep 2017 15:48:47 -0700 Subject: [PATCH 33/37] net: coap: fix coap packet length calculation This calculation reads the length portion of the COAP header to determine the length of the coap packet. However, when encrypted via DTLS this value seems to be getting corrupted. Let's change this calculation so that it will work for when DTLS is both enabled and disabled. Use the total length of the fragment data and substract back out the headers to get a correct value. Signed-off-by: Michael Scott --- subsys/net/lib/coap/coap.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index fcb3e50343a79..f6cd750e65aad 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -59,19 +59,15 @@ static void option_header_set_len(u8_t *opt, u8_t len) static int get_coap_packet_len(struct net_pkt *pkt) { - struct net_buf *frag; - u16_t offset; u16_t len; - frag = net_frag_read_be16(pkt->frags, - net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt) + - 4, &offset, &len); - if (!frag && offset == 0xffff) { - return -1; - } + /* TODO: verify with smaller packets */ + len = net_pkt_get_len(pkt) + - net_pkt_ip_hdr_len(pkt) + - net_pkt_ipv6_ext_len(pkt) + - NET_UDPH_LEN; - return len - NET_UDPH_LEN; + return len; } static int decode_delta(u16_t num, struct option_context *context, From c51cc0aa000849dbf57cbe67a4e88e1896d600d5 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Wed, 27 Sep 2017 15:53:24 -0700 Subject: [PATCH 34/37] net: lib: lwm2m: use correct remote address when DTLS is enabled The default net_context remote address is scrambled when using a connection via DTLS. Instead let's use the dtls context remote. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_rd_client.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index 48ff3a4bb1893..e6412858fac13 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -167,7 +167,11 @@ static int find_clients_index(const struct sockaddr *addr) struct sockaddr *remote; for (i = 0; i < client_count; i++) { +#if defined(CONFIG_MBEDTLS) + remote = &clients[i].ctx->net_app_ctx.dtls.ctx->remote; +#else remote = &clients[i].ctx->net_app_ctx.default_ctx->remote; +#endif if (clients[i].ctx) { if (remote->sa_family != addr->sa_family) { continue; @@ -506,6 +510,7 @@ static int sm_do_bootstrap(int index) struct lwm2m_message *msg; struct net_app_ctx *app_ctx = NULL; int ret; + struct sockaddr *remote; if (clients[index].use_bootstrap && clients[index].bootstrapped == 0 && @@ -539,9 +544,13 @@ static int sm_do_bootstrap(int index) query_buffer, strlen(query_buffer)); /* log the bootstrap attempt */ +#if defined(CONFIG_MBEDTLS) + remote = &app_ctx->dtls.ctx->remote; +#else + remote = &app_ctx->default_ctx->remote; +#endif SYS_LOG_DBG("Register ID with bootstrap server [%s] as '%s'", - lwm2m_sprint_ip_addr( - &app_ctx->default_ctx->remote), + lwm2m_sprint_ip_addr(remote), query_buffer); ret = lwm2m_send_message(msg); @@ -613,6 +622,7 @@ static int sm_send_registration(int index, bool send_obj_support_data, u8_t *payload; u16_t client_data_len, len; int ret; + struct sockaddr *remote; app_ctx = &clients[index].ctx->net_app_ctx; msg = lwm2m_get_message(clients[index].ctx); @@ -695,8 +705,13 @@ static int sm_send_registration(int index, bool send_obj_support_data, } /* log the registration attempt */ +#if defined(CONFIG_MBEDTLS) + remote = &app_ctx->dtls.ctx->remote; +#else + remote = &app_ctx->default_ctx->remote; +#endif SYS_LOG_DBG("registration sent [%s]", - lwm2m_sprint_ip_addr(&app_ctx->default_ctx->remote)); + lwm2m_sprint_ip_addr(remote)); return 0; From 57a82d68c51905d2e923c4f8569e52b9c1f4cb12 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Sun, 1 Oct 2017 13:29:23 -0700 Subject: [PATCH 35/37] net: lwm2m: reduce LwM2M footprint via lower defaults in Kconfig Let's use conservative defaults for the LwM2M library to enable hardware with constrained resources. Users can increase where necessary. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 52832a9a117f5..5a3cf6731396d 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -51,7 +51,7 @@ config LWM2M_ENGINE_MAX_REPLIES config LWM2M_ENGINE_MAX_OBSERVER int "Maximum # of observable LWM2M resources" default 50 - range 10 200 + range 5 200 help This value sets the maximum number of resources which can be added to the observe notification list. @@ -72,7 +72,7 @@ config LWM2M_LOCAL_PORT config LWM2M_SECURITY_INSTANCE_COUNT int "Maximum # of LWM2M Security object instances" - default 3 + default 1 range 1 10 help This setting establishes the total count of LWM2M Security instances @@ -80,7 +80,7 @@ config LWM2M_SECURITY_INSTANCE_COUNT config LWM2M_SERVER_INSTANCE_COUNT int "Maximum # of LWM2M Server object instances" - default 3 + default 1 range 1 10 help This setting establishes the total count of LWM2M Server instances @@ -101,7 +101,7 @@ config LWM2M_RD_CLIENT_STACK_SIZE config LWM2M_RD_CLIENT_INSTANCE_COUNT int "Maximum # of LWM2M RD client instances" - default 2 + default 1 help This setting establishes the total count of LWM2M RD client instances available. From ac0120460c350a21a5f20fffc6e2ef7951da6a7a Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Mon, 2 Oct 2017 13:33:46 -0700 Subject: [PATCH 36/37] samples: lwm2m: cleanup prj_*.conf files Support multiple HW with only 2 configs: 1) default operation w/o DTLS support 2) enable DTLS support NOTE: This also adjusts README.rst Signed-off-by: Michael Scott --- samples/net/lwm2m_client/Makefile | 2 +- samples/net/lwm2m_client/README.rst | 12 ++--- .../{prj_qemu_x86.conf => prj.conf} | 2 - .../{prj_qemu_x86_dtls.conf => prj_dtls.conf} | 2 - samples/net/lwm2m_client/prj_frdm_k64f.conf | 44 ---------------- .../net/lwm2m_client/prj_frdm_k64f_dtls.conf | 52 ------------------- 6 files changed, 7 insertions(+), 107 deletions(-) rename samples/net/lwm2m_client/{prj_qemu_x86.conf => prj.conf} (97%) rename samples/net/lwm2m_client/{prj_qemu_x86_dtls.conf => prj_dtls.conf} (98%) delete mode 100644 samples/net/lwm2m_client/prj_frdm_k64f.conf delete mode 100644 samples/net/lwm2m_client/prj_frdm_k64f_dtls.conf diff --git a/samples/net/lwm2m_client/Makefile b/samples/net/lwm2m_client/Makefile index df07b43961752..7af342361d3fb 100644 --- a/samples/net/lwm2m_client/Makefile +++ b/samples/net/lwm2m_client/Makefile @@ -7,7 +7,7 @@ # BOARD ?= qemu_x86 -CONF_FILE ?= prj_$(BOARD).conf +CONF_FILE ?= prj.conf include $(ZEPHYR_BASE)/Makefile.inc include $(ZEPHYR_BASE)/samples/net/common/Makefile.ipstack diff --git a/samples/net/lwm2m_client/README.rst b/samples/net/lwm2m_client/README.rst index 3f928d5019295..a0522646f53f3 100644 --- a/samples/net/lwm2m_client/README.rst +++ b/samples/net/lwm2m_client/README.rst @@ -31,14 +31,14 @@ Requirements Building and Running ******************** -There are configuration files for various hardware setups in the +There are configuration files for various setups in the samples/net/lwm2m_client directory: -- :file:`prj_frdm_k64f.conf` - Use this for FRDM-K64F board with built-in ethernet. +- :file:`prj.conf` + This is the standard default config. -- :file:`prj_qemu_x86.conf` - Use this for x86 QEMU. +- :file:`prj_dtls.conf` + Use this for enabling DTLS support. Build the lwm2m-client sample application like this: @@ -49,7 +49,7 @@ Build the lwm2m-client sample application like this: BOARD= The easiest way to setup this sample application is to build and run it -via QEMU using the configuration :file:`prj_qemu_x86.conf`. +via QEMU using the default configuration :file:`prj.conf`. This requires a small amount of setup described in :ref:`networking_with_qemu`. Download and run the latest build of the Leshan Demo Server: diff --git a/samples/net/lwm2m_client/prj_qemu_x86.conf b/samples/net/lwm2m_client/prj.conf similarity index 97% rename from samples/net/lwm2m_client/prj_qemu_x86.conf rename to samples/net/lwm2m_client/prj.conf index 84fa4dabb2de6..fd707d5608966 100644 --- a/samples/net/lwm2m_client/prj_qemu_x86.conf +++ b/samples/net/lwm2m_client/prj.conf @@ -40,5 +40,3 @@ CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2" CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1" CONFIG_NET_APP_PEER_IPV4_ADDR="192.0.2.2" - -CONFIG_NET_SLIP_TAP=y diff --git a/samples/net/lwm2m_client/prj_qemu_x86_dtls.conf b/samples/net/lwm2m_client/prj_dtls.conf similarity index 98% rename from samples/net/lwm2m_client/prj_qemu_x86_dtls.conf rename to samples/net/lwm2m_client/prj_dtls.conf index 07748fbd7b013..0a71ae3486a4a 100644 --- a/samples/net/lwm2m_client/prj_qemu_x86_dtls.conf +++ b/samples/net/lwm2m_client/prj_dtls.conf @@ -48,5 +48,3 @@ CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2" CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1" CONFIG_NET_APP_PEER_IPV4_ADDR="192.0.2.2" - -CONFIG_NET_SLIP_TAP=y diff --git a/samples/net/lwm2m_client/prj_frdm_k64f.conf b/samples/net/lwm2m_client/prj_frdm_k64f.conf deleted file mode 100644 index d159f59f06f64..0000000000000 --- a/samples/net/lwm2m_client/prj_frdm_k64f.conf +++ /dev/null @@ -1,44 +0,0 @@ -CONFIG_NETWORKING=y -CONFIG_NET_LOG=y -CONFIG_NET_BUF_LOG=y -CONFIG_SYS_LOG_NET_LEVEL=4 -CONFIG_SYS_LOG_NET_BUF_LEVEL=2 -CONFIG_SYS_LOG_LWM2M_LEVEL=4 -CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NET_IPV6=y -CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 -CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=2 -CONFIG_NET_IPV4=y -CONFIG_NET_DHCPV4=n -CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=3 -CONFIG_NET_IF_MCAST_IPV4_ADDR_COUNT=2 -CONFIG_SYS_LOG_SHOW_COLOR=y -CONFIG_INIT_STACKS=y -CONFIG_PRINTK=y -CONFIG_NET_STATISTICS=y -CONFIG_NET_BUF_DATA_SIZE=384 -CONFIG_NET_PKT_RX_COUNT=50 -CONFIG_NET_PKT_TX_COUNT=50 -CONFIG_NET_BUF_RX_COUNT=50 -CONFIG_NET_BUF_TX_COUNT=50 -CONFIG_NET_MAX_CONTEXTS=10 -CONFIG_NET_CONTEXT_NET_PKT_POOL=y - -CONFIG_NET_SHELL=y - -CONFIG_NET_APP_NEED_IPV6=y -CONFIG_NET_APP_NEED_IPV4=y -CONFIG_NET_APP_SETTINGS=y - -CONFIG_LWM2M=y -CONFIG_LWM2M_RD_CLIENT_INSTANCE_COUNT=2 -CONFIG_LWM2M_IPSO_SUPPORT=y -CONFIG_LWM2M_IPSO_TEMP_SENSOR=y -CONFIG_LWM2M_IPSO_LIGHT_CONTROL=y - -CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" -CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2" -CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1" -CONFIG_NET_APP_PEER_IPV4_ADDR="192.0.2.2" - -CONFIG_NET_L2_ETHERNET=y diff --git a/samples/net/lwm2m_client/prj_frdm_k64f_dtls.conf b/samples/net/lwm2m_client/prj_frdm_k64f_dtls.conf deleted file mode 100644 index 2563b132852c6..0000000000000 --- a/samples/net/lwm2m_client/prj_frdm_k64f_dtls.conf +++ /dev/null @@ -1,52 +0,0 @@ -CONFIG_NETWORKING=y -CONFIG_NET_LOG=y -CONFIG_NET_BUF_LOG=y -CONFIG_SYS_LOG_NET_LEVEL=4 -CONFIG_SYS_LOG_NET_BUF_LEVEL=2 -CONFIG_SYS_LOG_LWM2M_LEVEL=4 -CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NET_IPV6=y -CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 -CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=2 -CONFIG_NET_IPV4=y -CONFIG_NET_DHCPV4=n -CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=3 -CONFIG_NET_IF_MCAST_IPV4_ADDR_COUNT=2 -CONFIG_SYS_LOG_SHOW_COLOR=y -CONFIG_INIT_STACKS=y -CONFIG_PRINTK=y -CONFIG_NET_STATISTICS=y -CONFIG_NET_BUF_DATA_SIZE=384 -CONFIG_NET_PKT_RX_COUNT=50 -CONFIG_NET_PKT_TX_COUNT=50 -CONFIG_NET_BUF_RX_COUNT=50 -CONFIG_NET_BUF_TX_COUNT=50 -CONFIG_NET_MAX_CONTEXTS=10 -CONFIG_NET_CONTEXT_NET_PKT_POOL=y - -CONFIG_NET_SHELL=y - -CONFIG_NET_APP_NEED_IPV6=y -CONFIG_NET_APP_NEED_IPV4=y -CONFIG_NET_APP_SETTINGS=y -CONFIG_NET_APP_DTLS=y - -CONFIG_MBEDTLS=y -CONFIG_MBEDTLS_BUILTIN=y -CONFIG_MBEDTLS_ENABLE_HEAP=y -CONFIG_MBEDTLS_HEAP_SIZE=8192 -CONFIG_MBEDTLS_CFG_FILE="config-lwm2m.h" - -CONFIG_LWM2M=y -CONFIG_LWM2M_PEER_PORT=5684 -CONFIG_LWM2M_RD_CLIENT_INSTANCE_COUNT=2 -CONFIG_LWM2M_IPSO_SUPPORT=y -CONFIG_LWM2M_IPSO_TEMP_SENSOR=y -CONFIG_LWM2M_IPSO_LIGHT_CONTROL=y - -CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" -CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2" -CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1" -CONFIG_NET_APP_PEER_IPV4_ADDR="192.0.2.2" - -CONFIG_NET_L2_ETHERNET=y From c7969eb655d6cc19ce1ec56d4a412b6c6dd5979c Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Mon, 2 Oct 2017 13:40:33 -0700 Subject: [PATCH 37/37] samples: lwm2m: reduce footprint of lwm2m configs LwM2M is intended for constrained devices. The default samples settings are quite large by that standard and can be reduced to reflect actual usage. Signed-off-by: Michael Scott --- samples/net/lwm2m_client/prj.conf | 11 +++++------ samples/net/lwm2m_client/prj_dtls.conf | 11 +++++------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/samples/net/lwm2m_client/prj.conf b/samples/net/lwm2m_client/prj.conf index fd707d5608966..e97e9ff98ccbe 100644 --- a/samples/net/lwm2m_client/prj.conf +++ b/samples/net/lwm2m_client/prj.conf @@ -17,11 +17,11 @@ CONFIG_INIT_STACKS=y CONFIG_PRINTK=y CONFIG_NET_STATISTICS=y CONFIG_NET_BUF_DATA_SIZE=384 -CONFIG_NET_PKT_RX_COUNT=50 -CONFIG_NET_PKT_TX_COUNT=50 -CONFIG_NET_BUF_RX_COUNT=50 -CONFIG_NET_BUF_TX_COUNT=50 -CONFIG_NET_MAX_CONTEXTS=10 +CONFIG_NET_PKT_RX_COUNT=10 +CONFIG_NET_PKT_TX_COUNT=10 +CONFIG_NET_BUF_RX_COUNT=10 +CONFIG_NET_BUF_TX_COUNT=10 +CONFIG_NET_MAX_CONTEXTS=3 CONFIG_NET_CONTEXT_NET_PKT_POOL=y CONFIG_NET_SHELL=y @@ -31,7 +31,6 @@ CONFIG_NET_APP_NEED_IPV4=y CONFIG_NET_APP_SETTINGS=y CONFIG_LWM2M=y -CONFIG_LWM2M_RD_CLIENT_INSTANCE_COUNT=2 CONFIG_LWM2M_IPSO_SUPPORT=y CONFIG_LWM2M_IPSO_TEMP_SENSOR=y CONFIG_LWM2M_IPSO_LIGHT_CONTROL=y diff --git a/samples/net/lwm2m_client/prj_dtls.conf b/samples/net/lwm2m_client/prj_dtls.conf index 0a71ae3486a4a..3a0c882daf6ca 100644 --- a/samples/net/lwm2m_client/prj_dtls.conf +++ b/samples/net/lwm2m_client/prj_dtls.conf @@ -17,11 +17,11 @@ CONFIG_INIT_STACKS=y CONFIG_PRINTK=y CONFIG_NET_STATISTICS=y CONFIG_NET_BUF_DATA_SIZE=384 -CONFIG_NET_PKT_RX_COUNT=50 -CONFIG_NET_PKT_TX_COUNT=50 -CONFIG_NET_BUF_RX_COUNT=50 -CONFIG_NET_BUF_TX_COUNT=50 -CONFIG_NET_MAX_CONTEXTS=10 +CONFIG_NET_PKT_RX_COUNT=10 +CONFIG_NET_PKT_TX_COUNT=10 +CONFIG_NET_BUF_RX_COUNT=10 +CONFIG_NET_BUF_TX_COUNT=10 +CONFIG_NET_MAX_CONTEXTS=3 CONFIG_NET_CONTEXT_NET_PKT_POOL=y CONFIG_NET_SHELL=y @@ -39,7 +39,6 @@ CONFIG_MBEDTLS_CFG_FILE="config-lwm2m.h" CONFIG_LWM2M=y CONFIG_LWM2M_PEER_PORT=5684 -CONFIG_LWM2M_RD_CLIENT_INSTANCE_COUNT=2 CONFIG_LWM2M_IPSO_SUPPORT=y CONFIG_LWM2M_IPSO_TEMP_SENSOR=y CONFIG_LWM2M_IPSO_LIGHT_CONTROL=y