|  | /* | 
|  | * 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 <errno.h> | 
|  | #include <misc/printk.h> | 
|  |  | 
|  | #include <zephyr.h> | 
|  |  | 
|  | #include <misc/byteorder.h> | 
|  | #include <misc/util.h> | 
|  | #include <net/buf.h> | 
|  | #include <net/net_pkt.h> | 
|  | #include <net/net_ip.h> | 
|  |  | 
|  | #include <net/zoap.h> | 
|  | #include <net/zoap_link_format.h> | 
|  |  | 
|  | #if defined(CONFIG_NET_L2_BLUETOOTH) | 
|  | #include <bluetooth/bluetooth.h> | 
|  | #include <gatt/ipss.h> | 
|  | #endif | 
|  |  | 
|  | #if defined(CONFIG_NET_L2_IEEE802154) | 
|  | #include <ieee802154_settings.h> | 
|  | #endif | 
|  |  | 
|  | #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++) { | 
|  | zoap_add_option(&response, ZOAP_OPTION_LOCATION_PATH, | 
|  | *p, strlen(*p)); | 
|  | } | 
|  |  | 
|  | 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++) { | 
|  | zoap_add_option(&response, ZOAP_OPTION_LOCATION_QUERY, | 
|  | *p, strlen(*p)); | 
|  | } | 
|  |  | 
|  | 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(&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) { | 
|  | zoap_add_option_int(&response, ZOAP_OPTION_OBSERVE, age); | 
|  | } | 
|  |  | 
|  | 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; | 
|  | int r, header_len; | 
|  |  | 
|  | net_ipaddr_copy(&from.sin6_addr, &NET_IPV6_HDR(pkt)->src); | 
|  | from.sin6_port = NET_UDP_HDR(pkt)->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); | 
|  | 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 defined(CONFIG_NET_L2_BLUETOOTH) | 
|  | if (bt_enable(NULL)) { | 
|  | NET_ERR("Bluetooth init failed"); | 
|  | return; | 
|  | } | 
|  | ipss_init(); | 
|  |  | 
|  | ipss_advertise(); | 
|  | #endif | 
|  |  | 
|  | #if defined(CONFIG_NET_L2_IEEE802154) | 
|  | if (ieee802154_sample_setup()) { | 
|  | NET_ERR("IEEE 802.15.4 setup failed"); | 
|  | return; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | 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; | 
|  | } | 
|  | } |