/* * Copyright (c) 2018 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include LOG_MODULE_REGISTER(net_test, LOG_LEVEL_DBG); #include #include #include #include #include #include #include #include #include #include #include #include #include "net_private.h" #define COAP_BUF_SIZE 128 #define COAP_FIXED_HEADER_SIZE 4 #define NUM_PENDINGS 3 #define NUM_OBSERVERS 3 #define NUM_REPLIES 3 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, uint16_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, struct sockaddr *addr, socklen_t addr_len); 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 uint8_t data_buf[2][COAP_BUF_SIZE]; ZTEST(coap, test_build_empty_pdu) { uint8_t result_pdu[] = { 0x40, 0x01, 0x0, 0x0 }; struct coap_packet cpkt; uint8_t *data = data_buf[0]; int r; r = coap_packet_init(&cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON, 0, NULL, COAP_METHOD_GET, 0); zassert_equal(r, 0, "Could not initialize packet"); zassert_equal(cpkt.offset, sizeof(result_pdu), "Different size from the reference packet"); zassert_equal(cpkt.hdr_len, COAP_FIXED_HEADER_SIZE, "Invalid header length"); zassert_equal(cpkt.opt_len, 0, "Invalid options length"); zassert_mem_equal(result_pdu, cpkt.data, cpkt.offset, "Built packet doesn't match reference packet"); } ZTEST(coap, test_build_simple_pdu) { uint8_t result_pdu[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0xC0, 0xFF, 'p', 'a', 'y', 'l', 'o', 'a', 'd', 0x00 }; struct coap_packet cpkt; const char token[] = "token"; static const char payload[] = "payload"; uint8_t *data = data_buf[0]; const uint8_t *payload_start; uint16_t payload_len; int r; r = coap_packet_init(&cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_NON_CON, strlen(token), token, COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED, 0x1234); zassert_equal(r, 0, "Could not initialize packet"); r = coap_append_option_int(&cpkt, COAP_OPTION_CONTENT_FORMAT, COAP_CONTENT_FORMAT_TEXT_PLAIN); zassert_equal(r, 0, "Could not append option"); r = coap_packet_append_payload_marker(&cpkt); zassert_equal(r, 0, "Failed to set the payload marker"); r = coap_packet_append_payload(&cpkt, payload, sizeof(payload)); zassert_equal(r, 0, "Failed to set the payload"); zassert_equal(cpkt.offset, sizeof(result_pdu), "Different size from the reference packet"); zassert_equal(cpkt.hdr_len, COAP_FIXED_HEADER_SIZE + strlen(token), "Invalid header length"); zassert_equal(cpkt.opt_len, 1, "Invalid options length"); zassert_mem_equal(result_pdu, cpkt.data, cpkt.offset, "Built packet doesn't match reference packet"); payload_start = coap_packet_get_payload(&cpkt, &payload_len); zassert_equal(payload_len, sizeof(payload), "Invalid payload length"); zassert_equal_ptr(payload_start, cpkt.data + cpkt.offset - payload_len, "Invalid payload pointer"); } /* No options, No payload */ ZTEST(coap, test_parse_empty_pdu) { uint8_t pdu[] = { 0x40, 0x01, 0, 0 }; struct coap_packet cpkt; uint8_t *data = data_buf[0]; uint8_t ver; uint8_t type; uint8_t code; uint16_t id; int r; memcpy(data, pdu, sizeof(pdu)); r = coap_packet_parse(&cpkt, data, sizeof(pdu), NULL, 0); zassert_equal(r, 0, "Could not parse packet"); zassert_equal(cpkt.offset, sizeof(pdu), "Different size from the reference packet"); zassert_equal(cpkt.hdr_len, COAP_FIXED_HEADER_SIZE, "Invalid header length"); zassert_equal(cpkt.opt_len, 0, "Invalid options length"); ver = coap_header_get_version(&cpkt); type = coap_header_get_type(&cpkt); code = coap_header_get_code(&cpkt); id = coap_header_get_id(&cpkt); zassert_equal(ver, 1U, "Invalid version for parsed packet"); zassert_equal(type, COAP_TYPE_CON, "Packet type doesn't match reference"); zassert_equal(code, COAP_METHOD_GET, "Packet code doesn't match reference"); zassert_equal(id, 0U, "Packet id doesn't match reference"); } /* 1 option, No payload (No payload marker) */ ZTEST(coap, test_parse_empty_pdu_1) { uint8_t pdu[] = { 0x40, 0x01, 0, 0, 0x40}; struct coap_packet cpkt; uint8_t *data = data_buf[0]; uint8_t ver; uint8_t type; uint8_t code; uint16_t id; int r; memcpy(data, pdu, sizeof(pdu)); r = coap_packet_parse(&cpkt, data, sizeof(pdu), NULL, 0); zassert_equal(r, 0, "Could not parse packet"); zassert_equal(cpkt.offset, sizeof(pdu), "Different size from the reference packet"); zassert_equal(cpkt.hdr_len, COAP_FIXED_HEADER_SIZE, "Invalid header length"); zassert_equal(cpkt.opt_len, 1, "Invalid options length"); ver = coap_header_get_version(&cpkt); type = coap_header_get_type(&cpkt); code = coap_header_get_code(&cpkt); id = coap_header_get_id(&cpkt); zassert_equal(ver, 1U, "Invalid version for parsed packet"); zassert_equal(type, COAP_TYPE_CON, "Packet type doesn't match reference"); zassert_equal(code, COAP_METHOD_GET, "Packet code doesn't match reference"); zassert_equal(id, 0U, "Packet id doesn't match reference"); } ZTEST(coap, test_parse_simple_pdu) { uint8_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 coap_option options[16] = {}; const uint8_t token[8]; const uint8_t payload[] = "payload"; uint8_t *data = data_buf[0]; uint8_t ver; uint8_t type; uint8_t code; uint8_t tkl; uint16_t id; const uint8_t *payload_start; uint16_t payload_len; int r, count = ARRAY_SIZE(options) - 1; memcpy(data, pdu, sizeof(pdu)); r = coap_packet_parse(&cpkt, data, sizeof(pdu), NULL, 0); zassert_equal(r, 0, "Could not parse packet"); zassert_equal(cpkt.offset, sizeof(pdu), "Different size from the reference packet"); zassert_equal(cpkt.hdr_len, COAP_FIXED_HEADER_SIZE + strlen("token"), "Invalid header length"); zassert_equal(cpkt.opt_len, 3, "Invalid options length"); payload_start = coap_packet_get_payload(&cpkt, &payload_len); zassert_equal(payload_len, sizeof(payload), "Invalid payload length"); zassert_equal_ptr(payload_start, cpkt.data + cpkt.offset - payload_len, "Invalid payload pointer"); ver = coap_header_get_version(&cpkt); type = coap_header_get_type(&cpkt); code = coap_header_get_code(&cpkt); id = coap_header_get_id(&cpkt); zassert_equal(ver, 1U, "Invalid version for parsed packet"); zassert_equal(type, COAP_TYPE_NON_CON, "Packet type doesn't match reference"); zassert_equal(code, COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED, "Packet code doesn't match reference"); zassert_equal(id, 0x1234, "Packet id doesn't match reference"); tkl = coap_header_get_token(&cpkt, (uint8_t *)token); zassert_equal(tkl, 5U, "Token length doesn't match reference"); zassert_mem_equal(token, "token", tkl, "Token value doesn't match the reference"); count = coap_find_options(&cpkt, COAP_OPTION_CONTENT_FORMAT, options, count); zassert_equal(count, 1, "Unexpected number of options in the packet"); zassert_equal(options[0].len, 1U, "Option length doesn't match the reference"); zassert_equal(((uint8_t *)options[0].value)[0], COAP_CONTENT_FORMAT_TEXT_PLAIN, "Option value doesn't match the reference"); /* Not existent */ count = coap_find_options(&cpkt, COAP_OPTION_ETAG, options, count); zassert_equal(count, 0, "There shouldn't be any ETAG option in the packet"); } ZTEST(coap, test_parse_malformed_pkt) { uint8_t opt[] = { 0x55, 0xA5, 0x12 }; struct coap_packet cpkt; uint8_t *data = data_buf[0]; int r; r = coap_packet_parse(&cpkt, NULL, sizeof(opt), NULL, 0); zassert_equal(r, -EINVAL, "Should've failed to parse a packet"); r = coap_packet_parse(&cpkt, data, 0, NULL, 0); zassert_equal(r, -EINVAL, "Should've failed to parse a packet"); memcpy(data, opt, sizeof(opt)); r = coap_packet_parse(&cpkt, data, sizeof(opt), NULL, 0); zassert_equal(r, -EINVAL, "Should've failed to parse a packet"); } ZTEST(coap, test_parse_malformed_coap_hdr) { uint8_t opt[] = { 0x55, 0x24, 0x49, 0x55, 0xff, 0x66, 0x77, 0x99}; struct coap_packet cpkt; uint8_t *data = data_buf[0]; int r; memcpy(data, opt, sizeof(opt)); r = coap_packet_parse(&cpkt, data, sizeof(opt), NULL, 0); zassert_equal(r, -EBADMSG, "Should've failed to parse a packet"); } ZTEST(coap, test_parse_malformed_opt) { uint8_t opt[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0xD0 }; struct coap_packet cpkt; uint8_t *data = data_buf[0]; int r; memcpy(data, opt, sizeof(opt)); r = coap_packet_parse(&cpkt, data, sizeof(opt), NULL, 0); zassert_equal(r, -EILSEQ, "Should've failed to parse a packet"); } ZTEST(coap, test_parse_malformed_opt_len) { uint8_t opt[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0xC1 }; struct coap_packet cpkt; uint8_t *data = data_buf[0]; int r; memcpy(data, opt, sizeof(opt)); r = coap_packet_parse(&cpkt, data, sizeof(opt), NULL, 0); zassert_equal(r, -EILSEQ, "Should've failed to parse a packet"); } ZTEST(coap, test_parse_malformed_opt_ext) { uint8_t opt[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0xE0, 0x01 }; struct coap_packet cpkt; uint8_t *data = data_buf[0]; int r; memcpy(data, opt, sizeof(opt)); r = coap_packet_parse(&cpkt, data, sizeof(opt), NULL, 0); zassert_equal(r, -EILSEQ, "Should've failed to parse a packet"); } ZTEST(coap, test_parse_malformed_opt_len_ext) { uint8_t opt[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0xEE, 0x01, 0x02, 0x01}; struct coap_packet cpkt; uint8_t *data = data_buf[0]; int r; memcpy(data, opt, sizeof(opt)); r = coap_packet_parse(&cpkt, data, sizeof(opt), NULL, 0); zassert_equal(r, -EILSEQ, "Should've failed to parse a packet"); } /* 1 option, No payload (with payload marker) */ ZTEST(coap, test_parse_malformed_marker) { uint8_t pdu[] = { 0x40, 0x01, 0, 0, 0x40, 0xFF}; struct coap_packet cpkt; uint8_t *data = data_buf[0]; int r; memcpy(data, pdu, sizeof(pdu)); r = coap_packet_parse(&cpkt, data, sizeof(pdu), NULL, 0); zassert_not_equal(r, 0, "Should've failed to parse a packet"); } ZTEST(coap, test_parse_req_build_ack) { uint8_t pdu[] = { 0x45, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0x00, 0xc1, 0x00, 0xff, 'p', 'a', 'y', 'l', 'o', 'a', 'd', 0x00 }; uint8_t ack_pdu[] = { 0x65, 0x80, 0x12, 0x34, 't', 'o', 'k', 'e', 'n' }; struct coap_packet cpkt; struct coap_packet ack_cpkt; uint8_t *data = data_buf[0]; uint8_t *ack_data = data_buf[1]; int r; memcpy(data, pdu, sizeof(pdu)); r = coap_packet_parse(&cpkt, data, sizeof(pdu), NULL, 0); zassert_equal(r, 0, "Could not parse packet"); r = coap_ack_init(&ack_cpkt, &cpkt, ack_data, COAP_BUF_SIZE, COAP_RESPONSE_CODE_BAD_REQUEST); zassert_equal(r, 0, "Could not initialize ACK packet"); zassert_equal(ack_cpkt.offset, sizeof(ack_pdu), "Different size from the reference packet"); zassert_mem_equal(ack_pdu, ack_cpkt.data, ack_cpkt.offset, "Built packet doesn't match reference packet"); } ZTEST(coap, test_parse_req_build_empty_ack) { uint8_t pdu[] = { 0x45, 0xA5, 0xDE, 0xAD, 't', 'o', 'k', 'e', 'n', 0x00, 0xc1, 0x00, 0xff, 'p', 'a', 'y', 'l', 'o', 'a', 'd', 0x00 }; uint8_t ack_pdu[] = { 0x60, 0x00, 0xDE, 0xAD }; struct coap_packet cpkt; struct coap_packet ack_cpkt; uint8_t *data = data_buf[0]; uint8_t *ack_data = data_buf[1]; int r; memcpy(data, pdu, sizeof(pdu)); r = coap_packet_parse(&cpkt, data, sizeof(pdu), NULL, 0); zassert_equal(r, 0, "Could not parse packet"); r = coap_ack_init(&ack_cpkt, &cpkt, ack_data, COAP_BUF_SIZE, COAP_CODE_EMPTY); zassert_equal(r, 0, "Could not initialize ACK packet"); zassert_equal(ack_cpkt.offset, sizeof(ack_pdu), "Different size from the reference packet"); zassert_mem_equal(ack_pdu, ack_cpkt.data, ack_cpkt.offset, "Built packet doesn't match reference packet"); } ZTEST(coap, test_match_path_uri) { const char * const resource_path[] = { "s", "1", "foobar", "foobar3a", "foobar3", "devnull", NULL }; const char *uri; int r; uri = "/k"; r = _coap_match_path_uri(resource_path, uri, strlen(uri)); zassert_false(r, "Matching %s failed", uri); uri = "/s"; r = _coap_match_path_uri(resource_path, uri, strlen(uri)); zassert_true(r, "Matching %s failed", uri); uri = "/foobar"; r = _coap_match_path_uri(resource_path, uri, strlen(uri)); zassert_true(r, "Matching %s failed", uri); uri = "/foobar2"; r = _coap_match_path_uri(resource_path, uri, strlen(uri)); zassert_false(r, "Matching %s failed", uri); uri = "/foobar*"; r = _coap_match_path_uri(resource_path, uri, strlen(uri)); zassert_true(r, "Matching %s failed", uri); uri = "/foobar3*"; r = _coap_match_path_uri(resource_path, uri, strlen(uri)); zassert_true(r, "Matching %s failed", uri); uri = "/devnull*"; r = _coap_match_path_uri(resource_path, uri, strlen(uri)); zassert_false(r, "Matching %s failed", uri); } #define BLOCK_WISE_TRANSFER_SIZE_GET 150 static void prepare_block1_request(struct coap_packet *req, struct coap_block_context *req_ctx, int *more) { const char token[] = "token"; uint8_t payload[32] = { 0 }; uint8_t *data = data_buf[0]; bool first; int r; int block_size = coap_block_size_to_bytes(COAP_BLOCK_32); int payload_len; /* Request Context */ if (req_ctx->total_size == 0) { first = true; coap_block_transfer_init(req_ctx, COAP_BLOCK_32, BLOCK_WISE_TRANSFER_SIZE_GET); } else { first = false; } r = coap_packet_init(req, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON, strlen(token), token, COAP_METHOD_POST, coap_next_id()); zassert_equal(r, 0, "Unable to initialize request"); r = coap_append_block1_option(req, req_ctx); zassert_equal(r, 0, "Unable to append block1 option"); if (first) { r = coap_append_size1_option(req, req_ctx); zassert_equal(r, 0, "Unable to append size1 option"); } r = coap_packet_append_payload_marker(req); zassert_equal(r, 0, "Unable to append payload marker"); payload_len = req_ctx->total_size - req_ctx->current; if (payload_len > block_size) { payload_len = block_size; } r = coap_packet_append_payload(req, payload, payload_len); zassert_equal(r, 0, "Unable to append payload"); *more = coap_next_block(req, req_ctx); } static void prepare_block1_response(struct coap_packet *rsp, struct coap_block_context *rsp_ctx, struct coap_packet *req) { uint8_t token[8]; uint8_t *data = data_buf[1]; uint16_t id; uint8_t tkl; int r; if (rsp_ctx->total_size == 0) { coap_block_transfer_init(rsp_ctx, COAP_BLOCK_32, BLOCK_WISE_TRANSFER_SIZE_GET); } r = coap_update_from_block(req, rsp_ctx); zassert_equal(r, 0, "Failed to read block option"); id = coap_header_get_id(req); tkl = coap_header_get_token(req, token); r = coap_packet_init(rsp, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, COAP_RESPONSE_CODE_CREATED, id); zassert_equal(r, 0, "Unable to initialize request"); r = coap_append_block1_option(rsp, rsp_ctx); zassert_equal(r, 0, "Unable to append block1 option"); } #define ITER_COUNT(len, block_len) DIV_ROUND_UP(len, block_len) static void verify_block1_request(struct coap_block_context *req_ctx, uint8_t iter) { int block_size = coap_block_size_to_bytes(COAP_BLOCK_32); int iter_max = ITER_COUNT(BLOCK_WISE_TRANSFER_SIZE_GET, block_size); zassert_equal(req_ctx->block_size, COAP_BLOCK_32, "req:%d,Couldn't get block size", iter); /* In last iteration "current" must match "total_size" */ if (iter < iter_max) { zassert_equal( req_ctx->current, block_size * iter, "req:%d,Couldn't get the current block position", iter); } else { zassert_equal( req_ctx->current, req_ctx->total_size, "req:%d,Couldn't get the current block position", iter); } zassert_equal(req_ctx->total_size, BLOCK_WISE_TRANSFER_SIZE_GET, "req:%d,Couldn't packet total size", iter); } static void verify_block1_response(struct coap_block_context *rsp_ctx, uint8_t iter) { zassert_equal(rsp_ctx->block_size, COAP_BLOCK_32, "rsp:%d,Couldn't get block size", iter); zassert_equal(rsp_ctx->current, coap_block_size_to_bytes(COAP_BLOCK_32) * (iter - 1U), "rsp:%d, Couldn't get the current block position", iter); zassert_equal(rsp_ctx->total_size, BLOCK_WISE_TRANSFER_SIZE_GET, "rsp:%d, Couldn't packet total size", iter); } ZTEST(coap, test_block1_size) { struct coap_block_context req_ctx; struct coap_block_context rsp_ctx; struct coap_packet req; struct coap_packet rsp; int more; uint8_t i; i = 0U; more = 1; memset(&req_ctx, 0, sizeof(req_ctx)); memset(&rsp_ctx, 0, sizeof(rsp_ctx)); while (more) { prepare_block1_request(&req, &req_ctx, &more); prepare_block1_response(&rsp, &rsp_ctx, &req); i++; verify_block1_request(&req_ctx, i); verify_block1_response(&rsp_ctx, i); } } #define BLOCK2_WISE_TRANSFER_SIZE_GET 300 static void prepare_block2_request(struct coap_packet *req, struct coap_block_context *req_ctx, struct coap_packet *rsp) { const char token[] = "token"; uint8_t *data = data_buf[0]; int r; /* Request Context */ if (req_ctx->total_size == 0) { coap_block_transfer_init(req_ctx, COAP_BLOCK_64, BLOCK2_WISE_TRANSFER_SIZE_GET); } else { coap_next_block(rsp, req_ctx); } r = coap_packet_init(req, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON, strlen(token), token, COAP_METHOD_GET, coap_next_id()); zassert_equal(r, 0, "Unable to initialize request"); r = coap_append_block2_option(req, req_ctx); zassert_equal(r, 0, "Unable to append block2 option"); } static void prepare_block2_response(struct coap_packet *rsp, struct coap_block_context *rsp_ctx, struct coap_packet *req, int *more) { uint8_t payload[64]; uint8_t token[8]; uint8_t *data = data_buf[1]; uint16_t id; uint8_t tkl; bool first; int r; int block_size = coap_block_size_to_bytes(COAP_BLOCK_64); int payload_len; if (rsp_ctx->total_size == 0) { first = true; coap_block_transfer_init(rsp_ctx, COAP_BLOCK_64, BLOCK2_WISE_TRANSFER_SIZE_GET); } else { first = false; } id = coap_header_get_id(req); tkl = coap_header_get_token(req, token); r = coap_packet_init(rsp, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, COAP_RESPONSE_CODE_CONTENT, id); zassert_equal(r, 0, "Unable to initialize request"); r = coap_append_block2_option(rsp, rsp_ctx); zassert_equal(r, 0, "Unable to append block2 option"); if (first) { r = coap_append_size2_option(rsp, rsp_ctx); zassert_equal(r, 0, "Unable to append size2 option"); } r = coap_packet_append_payload_marker(rsp); zassert_equal(r, 0, "Unable to append payload marker"); payload_len = rsp_ctx->total_size - rsp_ctx->current; if (payload_len > block_size) { payload_len = block_size; } r = coap_packet_append_payload(rsp, payload, payload_len); zassert_equal(r, 0, "Unable to append payload"); *more = coap_next_block(rsp, rsp_ctx); } static void verify_block2_request(struct coap_block_context *req_ctx, uint8_t iter) { zassert_equal(req_ctx->block_size, COAP_BLOCK_64, "req:%d,Couldn't get block size", iter); zassert_equal(req_ctx->current, coap_block_size_to_bytes(COAP_BLOCK_64) * (iter - 1U), "req:%d, Couldn't get the current block position", iter); zassert_equal(req_ctx->total_size, BLOCK2_WISE_TRANSFER_SIZE_GET, "req:%d,Couldn't packet total size", iter); } static void verify_block2_response(struct coap_block_context *rsp_ctx, uint8_t iter) { int block_size = coap_block_size_to_bytes(COAP_BLOCK_64); int iter_max = ITER_COUNT(BLOCK2_WISE_TRANSFER_SIZE_GET, block_size); zassert_equal(rsp_ctx->block_size, COAP_BLOCK_64, "rsp:%d,Couldn't get block size", iter); /* In last iteration "current" must match "total_size" */ if (iter < iter_max) { zassert_equal( rsp_ctx->current, block_size * iter, "req:%d,Couldn't get the current block position", iter); } else { zassert_equal( rsp_ctx->current, rsp_ctx->total_size, "req:%d,Current block position does not match total size", iter); } zassert_equal(rsp_ctx->total_size, BLOCK2_WISE_TRANSFER_SIZE_GET, "rsp:%d, Couldn't packet total size", iter); } ZTEST(coap, test_block2_size) { struct coap_block_context req_ctx; struct coap_block_context rsp_ctx; struct coap_packet req; struct coap_packet rsp; int more; uint8_t i; i = 0U; more = 1; memset(&req_ctx, 0, sizeof(req_ctx)); memset(&rsp_ctx, 0, sizeof(rsp_ctx)); while (more) { prepare_block2_request(&req, &req_ctx, &rsp); prepare_block2_response(&rsp, &rsp_ctx, &req, &more); i++; verify_block2_request(&req_ctx, i); verify_block2_response(&rsp_ctx, i); } } ZTEST(coap, test_retransmit_second_round) { struct coap_packet cpkt; struct coap_packet rsp; struct coap_pending *pending; struct coap_pending *rsp_pending; uint8_t *data = data_buf[0]; uint8_t *rsp_data = data_buf[1]; int r; uint16_t id; id = coap_next_id(); r = coap_packet_init(&cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON, 0, coap_next_token(), COAP_METHOD_GET, id); zassert_equal(r, 0, "Could not initialize packet"); pending = coap_pending_next_unused(pendings, NUM_PENDINGS); zassert_not_null(pending, "No free pending"); r = coap_pending_init(pending, &cpkt, (struct sockaddr *) &dummy_addr, CONFIG_COAP_MAX_RETRANSMIT); zassert_equal(r, 0, "Could not initialize packet"); /* We "send" the packet the first time here */ zassert_true(coap_pending_cycle(pending), "Pending expired too early"); /* We simulate that the first transmission got lost */ zassert_true(coap_pending_cycle(pending), "Pending expired too early"); r = coap_packet_init(&rsp, rsp_data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_ACK, 0, NULL, COAP_METHOD_GET, id); zassert_equal(r, 0, "Could not initialize packet"); /* Now we get the ack from the remote side */ rsp_pending = coap_pending_received(&rsp, pendings, NUM_PENDINGS); zassert_equal_ptr(pending, rsp_pending, "Invalid pending %p should be %p", rsp_pending, pending); coap_pending_clear(rsp_pending); rsp_pending = coap_pending_next_to_expire(pendings, NUM_PENDINGS); zassert_is_null(rsp_pending, "There should be no active pendings"); } 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) { bool r; r = ipaddr_cmp(&observer->addr, (const struct sockaddr *)&dummy_addr); zassert_true(r, "The address of the observer doesn't match"); coap_remove_observer(resource, observer); } static int server_resource_1_get(struct coap_resource *resource, struct coap_packet *request, struct sockaddr *addr, socklen_t addr_len) { struct coap_packet response; struct coap_observer *observer; uint8_t *data = data_buf[1]; char payload[] = "This is the payload"; uint8_t token[8]; uint8_t tkl; uint16_t id; int r; zassert_true(coap_request_is_observe(request), "The request should enable observing"); observer = coap_observer_next_unused(observers, NUM_OBSERVERS); zassert_not_null(observer, "There should be an available observer"); tkl = coap_header_get_token(request, (uint8_t *) token); id = coap_header_get_id(request); coap_observer_init(observer, request, addr); coap_register_observer(resource, observer); r = coap_packet_init(&response, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, COAP_RESPONSE_CODE_OK, id); zassert_equal(r, 0, "Unable to initialize packet"); r = coap_append_option_int(&response, COAP_OPTION_OBSERVE, resource->age); zassert_equal(r, 0, "Failed to append observe option"); r = coap_packet_append_payload_marker(&response); zassert_equal(r, 0, "Failed to set the payload marker"); r = coap_packet_append_payload(&response, (uint8_t *)payload, strlen(payload)); zassert_equal(r, 0, "Unable to append payload"); resource->user_data = data; return 0; } ZTEST(coap, test_observer_server) { uint8_t valid_request_pdu[] = { 0x45, 0x01, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0x60, /* enable observe option */ 0x51, 's', 0x01, '1', /* path */ }; uint8_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] = {}; uint8_t *data = data_buf[0]; uint8_t opt_num = ARRAY_SIZE(options) - 1; int r; memcpy(data, valid_request_pdu, sizeof(valid_request_pdu)); r = coap_packet_parse(&req, data, sizeof(valid_request_pdu), options, opt_num); zassert_equal(r, 0, "Could not initialize packet"); r = coap_handle_request(&req, server_resources, options, opt_num, (struct sockaddr *) &dummy_addr, sizeof(dummy_addr)); zassert_equal(r, 0, "Could not handle packet"); /* Suppose some time passes */ r = coap_resource_notify(&server_resources[0]); zassert_equal(r, 0, "Could not notify resource"); memcpy(data, not_found_request_pdu, sizeof(not_found_request_pdu)); r = coap_packet_parse(&req, data, sizeof(not_found_request_pdu), options, opt_num); zassert_equal(r, 0, "Could not initialize packet"); r = coap_handle_request(&req, server_resources, options, opt_num, (struct sockaddr *) &dummy_addr, sizeof(dummy_addr)); zassert_equal(r, -ENOENT, "There should be no handler for this resource"); } static int resource_reply_cb(const struct coap_packet *response, struct coap_reply *reply, const struct sockaddr *from) { TC_PRINT("You should see this"); return 0; } ZTEST(coap, test_observer_client) { struct coap_packet req; struct coap_packet rsp; struct coap_reply *reply; struct coap_option options[4] = {}; const char token[] = "token"; const char * const *p; uint8_t *data = data_buf[0]; uint8_t *rsp_data = data_buf[1]; uint8_t opt_num = ARRAY_SIZE(options) - 1; int observe = 0; int r; r = coap_packet_init(&req, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON, strlen(token), token, COAP_METHOD_GET, coap_next_id()); zassert_equal(r, 0, "Unable to initialize request"); /* Enable observing the resource. */ r = coap_append_option_int(&req, COAP_OPTION_OBSERVE, observe); zassert_equal(r, 0, "Unable to add option to request int"); for (p = server_resource_1_path; p && *p; p++) { r = coap_packet_append_option(&req, COAP_OPTION_URI_PATH, *p, strlen(*p)); zassert_equal(r, 0, "Unable to add option to request"); } reply = coap_reply_next_unused(replies, NUM_REPLIES); zassert_not_null(reply, "No resources for waiting for replies"); coap_reply_init(reply, &req); reply->reply = resource_reply_cb; /* Server side, not interesting for this test */ r = coap_packet_parse(&req, data, req.offset, options, opt_num); zassert_equal(r, 0, "Could not parse req packet"); r = coap_handle_request(&req, server_resources, options, opt_num, (struct sockaddr *) &dummy_addr, sizeof(dummy_addr)); zassert_equal(r, 0, "Could not handle packet"); /* We cheat, and communicate using the resource's user_data */ rsp_data = server_resources[0].user_data; /* 'rsp_pkt' contains the response now */ r = coap_packet_parse(&rsp, rsp_data, req.offset, options, opt_num); zassert_equal(r, 0, "Could not parse rsp packet"); reply = coap_response_received(&rsp, (const struct sockaddr *) &dummy_addr, replies, NUM_REPLIES); zassert_not_null(reply, "Couldn't find a matching waiting reply"); } ZTEST(coap, test_handle_invalid_coap_req) { struct coap_packet pkt; uint8_t *data = data_buf[0]; struct coap_option options[4] = {}; uint8_t opt_num = 4; int r; const char *const *p; r = coap_packet_init(&pkt, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON, 0, NULL, 0xFF, coap_next_id()); zassert_equal(r, 0, "Unable to init req"); for (p = server_resource_1_path; p && *p; p++) { r = coap_packet_append_option(&pkt, COAP_OPTION_URI_PATH, *p, strlen(*p)); zassert_equal(r, 0, "Unable to append option"); } r = coap_packet_parse(&pkt, data, pkt.offset, options, opt_num); zassert_equal(r, 0, "Could not parse req packet"); r = coap_handle_request(&pkt, server_resources, options, opt_num, (struct sockaddr *) &dummy_addr, sizeof(dummy_addr)); zassert_equal(r, -ENOTSUP, "Request handling should fail with -ENOTSUP"); } ZTEST(coap, test_build_options_out_of_order_0) { uint8_t result[] = {0x45, 0x02, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0xC0, 0xB1, 0x19, 0xC5, 'p', 'r', 'o', 'x', 'y', 0x44, 'c', 'o', 'a', 'p'}; struct coap_packet cpkt; static const char token[] = "token"; uint8_t *data = data_buf[0]; int r; r = coap_packet_init(&cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON, strlen(token), token, COAP_METHOD_POST, 0x1234); zassert_equal(r, 0, "Could not initialize packet"); r = coap_append_option_int(&cpkt, COAP_OPTION_CONTENT_FORMAT, COAP_CONTENT_FORMAT_TEXT_PLAIN); zassert_equal(r, 0, "Could not append option"); static const uint8_t expected_options_0 = 0xc0; /* content format */ zassert_mem_equal(&expected_options_0, &cpkt.data[cpkt.hdr_len], cpkt.opt_len); const char *proxy_uri = "proxy"; r = coap_packet_append_option(&cpkt, COAP_OPTION_PROXY_URI, proxy_uri, strlen(proxy_uri)); zassert_equal(r, 0, "Could not append option"); static const uint8_t expected_options_1[] = { 0xc0, /* content format */ 0xd5, 0x0a, 'p', 'r', 'o', 'x', 'y' /* proxy url */ }; zassert_mem_equal(expected_options_1, &cpkt.data[cpkt.hdr_len], cpkt.opt_len); const char *proxy_scheme = "coap"; r = coap_packet_append_option(&cpkt, COAP_OPTION_PROXY_SCHEME, proxy_scheme, strlen(proxy_scheme)); zassert_equal(r, 0, "Could not append option"); static const uint8_t expected_options_2[] = { 0xc0, /* content format */ 0xd5, 0x0a, 'p', 'r', 'o', 'x', 'y', /* proxy url */ 0x44, 'c', 'o', 'a', 'p' /* proxy scheme */ }; zassert_mem_equal(expected_options_2, &cpkt.data[cpkt.hdr_len], cpkt.opt_len); /* option out of order */ const uint8_t block_option = 0b11001; r = coap_append_option_int(&cpkt, COAP_OPTION_BLOCK2, block_option); zassert_equal(r, 0, "Could not append option"); static const uint8_t expected_options_3[] = { 0xc0, /* content format */ 0xb1, 0x19, /* block2 */ 0xc5, 'p', 'r', 'o', 'x', 'y', /* proxy url */ 0x44, 'c', 'o', 'a', 'p' /* proxy scheme */ }; zassert_mem_equal(expected_options_3, &cpkt.data[cpkt.hdr_len], cpkt.opt_len); /* look for options */ struct coap_option opt; r = coap_find_options(&cpkt, COAP_OPTION_CONTENT_FORMAT, &opt, 1); zassert_equal(r, 1, "Could not find option"); r = coap_find_options(&cpkt, COAP_OPTION_PROXY_URI, &opt, 1); zassert_equal(r, 1, "Could not find option"); zassert_equal(opt.len, strlen(proxy_uri), "Wrong option len"); zassert_mem_equal(opt.value, proxy_uri, strlen(proxy_uri), "Wrong option content"); r = coap_find_options(&cpkt, COAP_OPTION_PROXY_SCHEME, &opt, 1); zassert_equal(r, 1, "Could not find option"); zassert_equal(opt.len, strlen(proxy_scheme), "Wrong option len"); zassert_mem_equal(opt.value, proxy_scheme, strlen(proxy_scheme), "Wrong option content"); r = coap_find_options(&cpkt, COAP_OPTION_BLOCK2, &opt, 1); zassert_equal(r, 1, "Could not find option"); zassert_equal(opt.len, 1, "Wrong option len"); zassert_equal(*opt.value, block_option, "Wrong option content"); zassert_equal(cpkt.hdr_len, 9, "Wrong header len"); zassert_equal(cpkt.opt_len, 14, "Wrong options size"); zassert_equal(cpkt.delta, 39, "Wrong delta"); zassert_equal(cpkt.offset, 23, "Wrong data size"); zassert_mem_equal(result, cpkt.data, cpkt.offset, "Built packet doesn't match reference packet"); } #define ASSERT_OPTIONS(cpkt, expected_opt_len, expected_data, expected_data_len) \ do { \ static const uint8_t expected_hdr_len = 9; \ zassert_equal(expected_hdr_len, cpkt.hdr_len, "Wrong header length"); \ zassert_equal(expected_opt_len, cpkt.opt_len, "Wrong option length"); \ zassert_equal(expected_hdr_len + expected_opt_len, cpkt.offset, "Wrong offset"); \ zassert_equal(expected_data_len, cpkt.offset, "Wrong offset"); \ zassert_mem_equal(expected_data, cpkt.data, expected_data_len, "Wrong data"); \ } while (0) ZTEST(coap, test_build_options_out_of_order_1) { struct coap_packet cpkt; static const char token[] = "token"; uint8_t *data = data_buf[0]; memset(data_buf[0], 0, ARRAY_SIZE(data_buf[0])); int r; r = coap_packet_init(&cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON, strlen(token), token, COAP_METHOD_POST, 0x1234); zassert_equal(r, 0, "Could not initialize packet"); r = coap_append_option_int(&cpkt, COAP_OPTION_SIZE2, coap_block_size_to_bytes(COAP_BLOCK_128)); zassert_equal(r, 0, "Could not append option"); static const uint8_t expected_0[] = {0x45, 0x02, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0xd1, 0x0f, 0x80}; ASSERT_OPTIONS(cpkt, 3, expected_0, 12); const char *uri_path = "path"; r = coap_packet_append_option(&cpkt, COAP_OPTION_URI_PATH, uri_path, strlen(uri_path)); zassert_equal(r, 0, "Could not append option"); static const uint8_t expected_1[] = { 0x45, 0x02, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0xb4, 'p', 'a', 't', 'h', 0xd1, 0x04, 0x80, }; ASSERT_OPTIONS(cpkt, 8, expected_1, 17); r = coap_append_option_int(&cpkt, COAP_OPTION_CONTENT_FORMAT, COAP_CONTENT_FORMAT_APP_JSON); zassert_equal(r, 0, "Could not append option"); static const uint8_t expected_2[] = { 0x45, 0x02, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0xb4, 'p', 'a', 't', 'h', 0x11, 0x32, 0xd1, 0x03, 0x80, }; ASSERT_OPTIONS(cpkt, 10, expected_2, 19); const char *uri_host = "hostname"; r = coap_packet_append_option(&cpkt, COAP_OPTION_URI_HOST, uri_host, strlen(uri_host)); zassert_equal(r, 0, "Could not append option"); static const uint8_t expected_3[] = { 0x45, 0x02, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0x38, 'h', 'o', 's', 't', 'n', 'a', 'm', 'e', 0x84, 'p', 'a', 't', 'h', 0x11, 0x32, 0xd1, 0x03, 0x80, }; ASSERT_OPTIONS(cpkt, 19, expected_3, 28); r = coap_append_option_int(&cpkt, COAP_OPTION_URI_PORT, 5638); zassert_equal(r, 0, "Could not append option"); static const uint8_t expected_4[] = { 0x45, 0x02, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0x38, 'h', 'o', 's', 't', 'n', 'a', 'm', 'e', 'B', 0x16, 0x06, 'D', 'p', 'a', 't', 'h', 0x11, 0x32, 0xd1, 0x03, 0x80, }; ASSERT_OPTIONS(cpkt, 22, expected_4, 31); const char *uri_query0 = "query0"; r = coap_packet_append_option(&cpkt, COAP_OPTION_URI_QUERY, uri_query0, strlen(uri_query0)); zassert_equal(r, 0, "Could not append option"); const char *uri_query1 = "query1"; r = coap_packet_append_option(&cpkt, COAP_OPTION_URI_QUERY, uri_query1, strlen(uri_query1)); zassert_equal(r, 0, "Could not append option"); static const uint8_t expected_5[] = { 0x45, 0x02, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0x38, 'h', 'o', 's', 't', 'n', 'a', 'm', 'e', 'B', 0x16, 0x06, 'D', 'p', 'a', 't', 'h', 0x11, 0x32, 0x36, 'q', 'u', 'e', 'r', 'y', 0x30, 0x06, 'q', 'u', 'e', 'r', 'y', 0x31, 0xd1, 0x00, 0x80, }; ASSERT_OPTIONS(cpkt, 36, expected_5, 45); r = coap_append_option_int(&cpkt, COAP_OPTION_ACCEPT, COAP_CONTENT_FORMAT_APP_CBOR); zassert_equal(r, 0, "Could not append option"); static const uint8_t expected_6[] = { 0x45, 0x02, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0x38, 'h', 'o', 's', 't', 'n', 'a', 'm', 'e', 'B', 0x16, 0x06, 'D', 'p', 'a', 't', 'h', 0x11, 0x32, 0x36, 'q', 'u', 'e', 'r', 'y', 0x30, 0x06, 'q', 'u', 'e', 'r', 'y', 0x31, 0x21, 0x3c, 0xb1, 0x80, }; ASSERT_OPTIONS(cpkt, 37, expected_6, 46); r = coap_append_option_int(&cpkt, COAP_OPTION_OBSERVE, 0); zassert_equal(r, 0, "Could not append option"); static const uint8_t expected_7[] = { 0x45, 0x02, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0x38, 'h', 'o', 's', 't', 'n', 'a', 'm', 'e', 0x30, 0x12, 0x16, 0x06, 'D', 'p', 'a', 't', 'h', 0x11, 0x32, 0x36, 'q', 'u', 'e', 'r', 'y', 0x30, 0x06, 'q', 'u', 'e', 'r', 'y', 0x31, 0x21, 0x3c, 0xb1, 0x80, }; ASSERT_OPTIONS(cpkt, 38, expected_7, 47); r = coap_append_option_int(&cpkt, COAP_OPTION_MAX_AGE, 3); zassert_equal(r, 0, "Could not append option"); static const uint8_t expected_8[] = { 0x45, 0x02, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0x38, 'h', 'o', 's', 't', 'n', 'a', 'm', 'e', 0x30, 0x12, 0x16, 0x06, 'D', 'p', 'a', 't', 'h', 0x11, 0x32, 0x21, 0x03, 0x16, 'q', 'u', 'e', 'r', 'y', 0x30, 0x06, 'q', 'u', 'e', 'r', 'y', 0x31, 0x21, 0x3c, 0xb1, 0x80, }; ASSERT_OPTIONS(cpkt, 40, expected_8, 49); r = coap_append_option_int(&cpkt, COAP_OPTION_SIZE1, 64); zassert_equal(r, 0, "Could not append option"); static const uint8_t expected_9[] = { 0x45, 0x02, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0x38, 'h', 'o', 's', 't', 'n', 'a', 'm', 'e', 0x30, 0x12, 0x16, 0x06, 'D', 'p', 'a', 't', 'h', 0x11, 0x32, 0x21, 0x03, 0x16, 'q', 'u', 'e', 'r', 'y', 0x30, 0x06, 'q', 'u', 'e', 'r', 'y', 0x31, 0x21, 0x3c, 0xb1, 0x80, 0xd1, 0x13, 0x40, }; ASSERT_OPTIONS(cpkt, 43, expected_9, 52); zassert_equal(cpkt.hdr_len, 9, "Wrong header len"); zassert_equal(cpkt.opt_len, 43, "Wrong options size"); zassert_equal(cpkt.delta, 60, "Wrong delta"); zassert_equal(cpkt.offset, 52, "Wrong data size"); } #define ASSERT_OPTIONS_AND_PAYLOAD(cpkt, expected_opt_len, expected_data, expected_offset, \ expected_delta) \ do { \ size_t expected_data_l = ARRAY_SIZE(expected_data); \ zassert_equal(expected_offset, expected_data_l); \ static const uint8_t expected_hdr_len = 9; \ zassert_equal(expected_hdr_len, cpkt.hdr_len, "Wrong header length"); \ zassert_equal(expected_opt_len, cpkt.opt_len, "Wrong option length"); \ zassert_equal(expected_offset, cpkt.offset, "Wrong offset"); \ zassert_mem_equal(expected_data, cpkt.data, expected_offset, "Wrong data"); \ zassert_equal(expected_delta, cpkt.delta, "Wrong delta"); \ } while (0) static void init_basic_test_msg(struct coap_packet *cpkt, uint8_t *data) { static const char token[] = "token"; const char *uri_path = "path"; const char *uri_host = "hostname"; const char *uri_query0 = "query0"; const char *uri_query1 = "query1"; memset(data_buf[0], 0, ARRAY_SIZE(data_buf[0])); int r; r = coap_packet_init(cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON, strlen(token), token, COAP_METHOD_POST, 0x1234); zassert_equal(r, 0, "Could not initialize packet"); r = coap_append_option_int(cpkt, COAP_OPTION_SIZE2, coap_block_size_to_bytes(COAP_BLOCK_128)); zassert_equal(r, 0, "Could not append option"); r = coap_packet_append_option(cpkt, COAP_OPTION_URI_PATH, uri_path, strlen(uri_path)); zassert_equal(r, 0, "Could not append option"); r = coap_append_option_int(cpkt, COAP_OPTION_CONTENT_FORMAT, COAP_CONTENT_FORMAT_APP_JSON); zassert_equal(r, 0, "Could not append option"); r = coap_packet_append_option(cpkt, COAP_OPTION_URI_HOST, uri_host, strlen(uri_host)); zassert_equal(r, 0, "Could not append option"); r = coap_append_option_int(cpkt, COAP_OPTION_URI_PORT, 5638); zassert_equal(r, 0, "Could not append option"); r = coap_packet_append_option(cpkt, COAP_OPTION_URI_QUERY, uri_query0, strlen(uri_query0)); zassert_equal(r, 0, "Could not append option"); r = coap_packet_append_option(cpkt, COAP_OPTION_URI_QUERY, uri_query1, strlen(uri_query1)); zassert_equal(r, 0, "Could not append option"); r = coap_append_option_int(cpkt, COAP_OPTION_ACCEPT, COAP_CONTENT_FORMAT_APP_CBOR); zassert_equal(r, 0, "Could not append option"); r = coap_append_option_int(cpkt, COAP_OPTION_OBSERVE, 0); zassert_equal(r, 0, "Could not append option"); r = coap_append_option_int(cpkt, COAP_OPTION_MAX_AGE, 3); zassert_equal(r, 0, "Could not append option"); r = coap_append_option_int(cpkt, COAP_OPTION_SIZE1, 64); zassert_equal(r, 0, "Could not append option"); static const uint8_t expected_9[] = { 0x45, 0x02, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0x38, 'h', 'o', 's', 't', 'n', 'a', 'm', 'e', 0x30, 0x12, 0x16, 0x06, 'D', 'p', 'a', 't', 'h', 0x11, 0x32, 0x21, 0x03, 0x16, 'q', 'u', 'e', 'r', 'y', 0x30, 0x06, 'q', 'u', 'e', 'r', 'y', 0x31, 0x21, 0x3c, 0xb1, 0x80, 0xd1, 0x13, 0x40, }; ASSERT_OPTIONS((*cpkt), 43, expected_9, 52); r = coap_packet_append_payload_marker(cpkt); zassert_equal(r, 0, "Could not append payload marker"); static const uint8_t test_payload[] = {0xde, 0xad, 0xbe, 0xef}; r = coap_packet_append_payload(cpkt, test_payload, ARRAY_SIZE(test_payload)); zassert_equal(r, 0, "Could not append test payload"); zassert_equal((*cpkt).hdr_len, 9, "Wrong header len"); zassert_equal((*cpkt).opt_len, 43, "Wrong options size"); zassert_equal((*cpkt).delta, 60, "Wrong delta"); zassert_equal((*cpkt).offset, 57, "Wrong data size"); } ZTEST(coap, test_remove_first_coap_option) { int r; struct coap_packet cpkt; uint8_t *data = data_buf[0]; init_basic_test_msg(&cpkt, data); r = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_HOST); zassert_equal(r, 0, "Could not remove option"); static const uint8_t expected_0[] = { 0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x60, 0x12, 0x16, 0x06, 0x44, 0x70, 0x61, 0x74, 0x68, 0x11, 0x32, 0x21, 0x03, 0x16, 0x71, 0x75, 0x65, 0x72, 0x79, 0x30, 0x06, 0x71, 0x75, 0x65, 0x72, 0x79, 0x31, 0x21, 0x3c, 0xb1, 0x80, 0xd1, 0x13, 0x40, 0xff, 0xde, 0xad, 0xbe, 0xef}; ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 34, expected_0, 48, 60); } ZTEST(coap, test_remove_middle_coap_option) { int r; struct coap_packet cpkt; uint8_t *data = data_buf[0]; init_basic_test_msg(&cpkt, data); r = coap_packet_remove_option(&cpkt, COAP_OPTION_OBSERVE); zassert_equal(r, 0, "Could not remove option"); static const uint8_t expected_0[] = { 0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x38, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x16, 0x06, 0x44, 0x70, 0x61, 0x74, 0x68, 0x11, 0x32, 0x21, 0x03, 0x16, 0x71, 0x75, 0x65, 0x72, 0x79, 0x30, 0x06, 0x71, 0x75, 0x65, 0x72, 0x79, 0x31, 0x21, 0x3c, 0xb1, 0x80, 0xd1, 0x13, 0x40, 0xff, 0xde, 0xad, 0xbe, 0xef}; ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 42, expected_0, 56, 60); } ZTEST(coap, test_remove_last_coap_option) { int r; struct coap_packet cpkt; uint8_t *data = data_buf[0]; init_basic_test_msg(&cpkt, data); r = coap_packet_remove_option(&cpkt, COAP_OPTION_SIZE1); zassert_equal(r, 0, "Could not remove option"); static const uint8_t expected_0[] = { 0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x38, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x30, 0x12, 0x16, 0x06, 0x44, 0x70, 0x61, 0x74, 0x68, 0x11, 0x32, 0x21, 0x03, 0x16, 0x71, 0x75, 0x65, 0x72, 0x79, 0x30, 0x06, 0x71, 0x75, 0x65, 0x72, 0x79, 0x31, 0x21, 0x3c, 0xb1, 0x80, 0xff, 0xde, 0xad, 0xbe, 0xef}; ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 40, expected_0, 54, 28); r = coap_append_option_int(&cpkt, COAP_OPTION_SIZE1, 65); zassert_equal(r, 0, "Could not add option at end"); static const uint8_t expected_1[] = { 0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x38, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x30, 0x12, 0x16, 0x06, 0x44, 0x70, 0x61, 0x74, 0x68, 0x11, 0x32, 0x21, 0x03, 0x16, 0x71, 0x75, 0x65, 0x72, 0x79, 0x30, 0x06, 0x71, 0x75, 0x65, 0x72, 0x79, 0x31, 0x21, 0x3c, 0xb1, 0x80, 0xd1, 0x13, 0x41, 0xff, 0xde, 0xad, 0xbe, 0xef}; ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 43, expected_1, 57, 60); } ZTEST(coap, test_remove_single_coap_option) { struct coap_packet cpkt; uint8_t *data = data_buf[0]; static const char token[] = "token"; const char *uri_path = "path"; memset(data_buf[0], 0, ARRAY_SIZE(data_buf[0])); int r1; r1 = coap_packet_init(&cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON, strlen(token), token, COAP_METHOD_POST, 0x1234); zassert_equal(r1, 0, "Could not initialize packet"); r1 = coap_packet_append_option(&cpkt, COAP_OPTION_URI_PATH, uri_path, strlen(uri_path)); zassert_equal(r1, 0, "Could not append option"); r1 = coap_packet_append_payload_marker(&cpkt); zassert_equal(r1, 0, "Could not append payload marker"); static const uint8_t test_payload[] = {0xde, 0xad, 0xbe, 0xef}; r1 = coap_packet_append_payload(&cpkt, test_payload, ARRAY_SIZE(test_payload)); zassert_equal(r1, 0, "Could not append test payload"); static const uint8_t expected_0[] = {0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xb4, 0x70, 0x61, 0x74, 0x68, 0xff, 0xde, 0xad, 0xbe, 0xef}; ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 5, expected_0, 19, 11); /* remove the one and only option */ r1 = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_PATH); zassert_equal(r1, 0, "Could not remove option"); static const uint8_t expected_1[] = {0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xff, 0xde, 0xad, 0xbe, 0xef}; ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 0, expected_1, 14, 0); } ZTEST(coap, test_remove_repeatable_coap_option) { int r; struct coap_packet cpkt; uint8_t *data = data_buf[0]; init_basic_test_msg(&cpkt, data); r = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_QUERY); zassert_equal(r, 0, "Could not remove option"); static const uint8_t expected_0[] = { 0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x38, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x30, 0x12, 0x16, 0x06, 0x44, 0x70, 0x61, 0x74, 0x68, 0x11, 0x32, 0x21, 0x03, 0x16, 0x71, 0x75, 0x65, 0x72, 0x79, 0x31, 0x21, 0x3c, 0xb1, 0x80, 0xd1, 0x13, 0x40, 0xff, 0xde, 0xad, 0xbe, 0xef}; ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 36, expected_0, 50, 60); } ZTEST(coap, test_remove_all_coap_options) { int r; struct coap_packet cpkt; uint8_t *data = data_buf[0]; init_basic_test_msg(&cpkt, data); r = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_PORT); zassert_equal(r, 0, "Could not remove option"); r = coap_packet_remove_option(&cpkt, COAP_OPTION_OBSERVE); zassert_equal(r, 0, "Could not remove option"); r = coap_packet_remove_option(&cpkt, COAP_OPTION_SIZE1); zassert_equal(r, 0, "Could not remove option"); static const uint8_t expected_0[] = { 0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x38, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x84, 0x70, 0x61, 0x74, 0x68, 0x11, 0x32, 0x21, 0x03, 0x16, 0x71, 0x75, 0x65, 0x72, 0x79, 0x30, 0x06, 0x71, 0x75, 0x65, 0x72, 0x79, 0x31, 0x21, 0x3c, 0xb1, 0x80, 0xff, 0xde, 0xad, 0xbe, 0xef}; ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 36, expected_0, 50, 28); r = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_HOST); zassert_equal(r, 0, "Could not remove option"); r = coap_packet_remove_option(&cpkt, COAP_OPTION_SIZE2); zassert_equal(r, 0, "Could not remove option"); r = coap_packet_remove_option(&cpkt, COAP_OPTION_CONTENT_FORMAT); zassert_equal(r, 0, "Could not remove option"); static const uint8_t expected_1[] = { 0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xb4, 0x70, 0x61, 0x74, 0x68, 0x31, 0x03, 0x16, 0x71, 0x75, 0x65, 0x72, 0x79, 0x30, 0x06, 0x71, 0x75, 0x65, 0x72, 0x79, 0x31, 0x21, 0x3c, 0xff, 0xde, 0xad, 0xbe, 0xef}; ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 23, expected_1, 37, 17); r = coap_packet_remove_option(&cpkt, COAP_OPTION_ACCEPT); zassert_equal(r, 0, "Could not remove option"); r = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_PATH); zassert_equal(r, 0, "Could not remove option"); r = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_QUERY); zassert_equal(r, 0, "Could not remove option"); static const uint8_t expected_2[] = {0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xd1, 0x01, 0x03, 0x16, 0x71, 0x75, 0x65, 0x72, 0x79, 0x31, 0xff, 0xde, 0xad, 0xbe, 0xef}; ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 10, expected_2, 24, 15); r = coap_packet_remove_option(&cpkt, COAP_OPTION_MAX_AGE); zassert_equal(r, 0, "Could not remove option"); r = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_QUERY); zassert_equal(r, 0, "Could not remove option"); static const uint8_t expected_3[] = {0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xff, 0xde, 0xad, 0xbe, 0xef}; ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 0, expected_3, 14, 0); /* remove option that is not there anymore */ r = coap_packet_remove_option(&cpkt, COAP_OPTION_MAX_AGE); zassert_equal(r, 0, "Could not remove option"); ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 0, expected_3, 14, 0); } ZTEST(coap, test_remove_non_existent_coap_option) { int r; struct coap_packet cpkt; uint8_t *data = data_buf[0]; static const char token[] = "token"; memset(data_buf[0], 0, ARRAY_SIZE(data_buf[0])); r = coap_packet_init(&cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON, strlen(token), token, COAP_METHOD_POST, 0x1234); zassert_equal(r, 0, "Could not initialize packet"); r = coap_append_option_int(&cpkt, COAP_OPTION_CONTENT_FORMAT, COAP_CONTENT_FORMAT_APP_CBOR); zassert_equal(r, 0, "Could not append option"); r = coap_append_option_int(&cpkt, COAP_OPTION_ACCEPT, COAP_CONTENT_FORMAT_APP_OCTET_STREAM); zassert_equal(r, 0, "Could not append option"); r = coap_packet_append_payload_marker(&cpkt); zassert_equal(r, 0, "Could not append payload marker"); static const uint8_t test_payload[] = {0xde, 0xad, 0xbe, 0xef}; r = coap_packet_append_payload(&cpkt, test_payload, ARRAY_SIZE(test_payload)); static const uint8_t expected_original_msg[] = {0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xc1, 0x3c, 0x51, 0x2a, 0xff, 0xde, 0xad, 0xbe, 0xef}; ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 4, expected_original_msg, 18, 17); /* remove option that is not there but would be before existing options */ r = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_PATH); zassert_equal(r, 0, "Could not remove option"); ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 4, expected_original_msg, 18, 17); /* remove option that is not there but would be between existing options */ r = coap_packet_remove_option(&cpkt, COAP_OPTION_MAX_AGE); zassert_equal(r, 0, "Could not remove option"); ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 4, expected_original_msg, 18, 17); /* remove option that is not there but would be after existing options */ r = coap_packet_remove_option(&cpkt, COAP_OPTION_LOCATION_QUERY); zassert_equal(r, 0, "Could not remove option"); ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 4, expected_original_msg, 18, 17); } static void assert_coap_packet_set_path_query_options(const char *path, const char * const *expected, size_t expected_len, uint16_t code) { struct coap_packet cpkt; uint8_t *data = data_buf[0]; struct coap_option options[16] = {0}; int res; memset(data_buf[0], 0, ARRAY_SIZE(data_buf[0])); TC_PRINT("Assert path: %s\n", path); res = coap_packet_init(&cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON, COAP_TOKEN_MAX_LEN, coap_next_token(), COAP_METHOD_GET, 0x1234); zassert_equal(res, 0, "Could not initialize packet"); res = coap_packet_set_path(&cpkt, path); zassert_equal(res, 0, "Could not set path/query, path: %s", path); res = coap_find_options(&cpkt, code, options, ARRAY_SIZE(options)); if (res <= 0) { /* fail if we expect options */ zassert_true(((expected == NULL) && (expected_len == 0U)), "Expected options but found none, path: %s", path); } for (unsigned int i = 0U; i < expected_len; ++i) { /* validate expected options, the rest shall be 0 */ if (i < expected_len) { zassert_true((options[i].len == strlen(expected[i])), "Expected and parsed option lengths don't match" ", path: %s", path); zassert_mem_equal(options[i].value, expected[i], options[i].len, "Expected and parsed option values don't match" ", path: %s", path); } else { zassert_true((options[i].len == 0U), "Unexpected options shall be empty" ", path: %s", path); } } } ZTEST(coap, test_coap_packet_set_path) { assert_coap_packet_set_path_query_options(" ", NULL, 0U, COAP_OPTION_URI_PATH); assert_coap_packet_set_path_query_options("", NULL, 0U, COAP_OPTION_URI_PATH); assert_coap_packet_set_path_query_options("/", NULL, 0U, COAP_OPTION_URI_PATH); assert_coap_packet_set_path_query_options("?", NULL, 0U, COAP_OPTION_URI_QUERY); assert_coap_packet_set_path_query_options("?a", (const char *const[]){"a"}, 1U, COAP_OPTION_URI_QUERY); assert_coap_packet_set_path_query_options("?a&b", (const char *const[]){"a", "b"}, 2U, COAP_OPTION_URI_QUERY); assert_coap_packet_set_path_query_options("a", (const char *const[]){"a"}, 1U, COAP_OPTION_URI_PATH); assert_coap_packet_set_path_query_options("a", NULL, 0, COAP_OPTION_URI_QUERY); assert_coap_packet_set_path_query_options("a/", (const char *const[]){"a"}, 1U, COAP_OPTION_URI_PATH); assert_coap_packet_set_path_query_options("a?b=t&a", (const char *const[]){"a"}, 1U, COAP_OPTION_URI_PATH); assert_coap_packet_set_path_query_options("a?b=t&a", (const char *const[]){"b=t", "a"}, 2U, COAP_OPTION_URI_QUERY); assert_coap_packet_set_path_query_options("a?b=t&aa", (const char *const[]){"b=t", "aa"}, 2U, COAP_OPTION_URI_QUERY); assert_coap_packet_set_path_query_options("a?b&a", (const char *const[]){"a"}, 1U, COAP_OPTION_URI_PATH); assert_coap_packet_set_path_query_options("a?b&a", (const char *const[]){"b", "a"}, 2U, COAP_OPTION_URI_QUERY); assert_coap_packet_set_path_query_options("a?b&aa", (const char *const[]){"b", "aa"}, 2U, COAP_OPTION_URI_QUERY); assert_coap_packet_set_path_query_options("a/b", (const char *const[]){"a", "b"}, 2U, COAP_OPTION_URI_PATH); assert_coap_packet_set_path_query_options("a/b/", (const char *const[]){"a", "b"}, 2U, COAP_OPTION_URI_PATH); assert_coap_packet_set_path_query_options("a/b?b&a", (const char *const[]){"b", "a"}, 2U, COAP_OPTION_URI_QUERY); assert_coap_packet_set_path_query_options("a/b?b&aa", (const char *const[]){"b", "aa"}, 2U, COAP_OPTION_URI_QUERY); assert_coap_packet_set_path_query_options("a/bb", (const char *const[]){"a", "bb"}, 2U, COAP_OPTION_URI_PATH); assert_coap_packet_set_path_query_options("a/bb/", (const char *const[]){"a", "bb"}, 2U, COAP_OPTION_URI_PATH); } ZTEST_SUITE(coap, NULL, NULL, NULL, NULL, NULL);