From RFC 7252, section 3 "The absence of the Payload Marker denotes a zero-length payload. The presence of a marker followed by a zero-length payload MUST be processed as a message format error." Check empty payload when COAP_MARKER is found and add a test case to cover it Signed-off-by: Robert Chou <robert.ch.chou@acer.com>
1598 lines
37 KiB
C
1598 lines
37 KiB
C
/*
|
|
* Copyright (c) 2017 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <zephyr/types.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <misc/printk.h>
|
|
|
|
#include <kernel.h>
|
|
|
|
#include <net/buf.h>
|
|
#include <net/net_pkt.h>
|
|
#include <net/net_ip.h>
|
|
#include <net/udp.h>
|
|
|
|
#include <tc_util.h>
|
|
|
|
#include <net/coap.h>
|
|
|
|
#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 */
|
|
};
|
|
|
|
/* No options, No payload */
|
|
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_empty_pdu_1[] = {
|
|
/* IPv6 header starts here */
|
|
0x60, 0x00, 0x00, 0x00, 0x00, 0x0D, 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, 0x0D, 0x00, 0x00,
|
|
/* CoAP */
|
|
};
|
|
|
|
/* 1 option, No payload (No payload marker) */
|
|
static int test_parse_empty_pdu_1(void)
|
|
{
|
|
u8_t pdu[] = { 0x40, 0x01, 0, 0, 0x40};
|
|
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_1),
|
|
(u8_t *)ipv6_empty_pdu_1, 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, 0x1D, 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, 0x1D, 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[32] = { 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_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, 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, 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;
|
|
|
|
}
|
|
|
|
/* IPv6 + UDP frame (48 bytes) */
|
|
static const unsigned char ipv6_wrong_opt[] = {
|
|
/* IPv6 header starts here */
|
|
0x60, 0x00, 0x00, 0x00, 0x00, 0x12, 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, 0x12, 0x00, 0x00,
|
|
/* CoAP */
|
|
};
|
|
|
|
static int test_parse_malformed_opt(void)
|
|
{
|
|
u8_t opt[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n',
|
|
0xD0 };
|
|
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);
|
|
|
|
net_pkt_append_all(pkt, sizeof(ipv6_wrong_opt),
|
|
(u8_t *)ipv6_wrong_opt, K_FOREVER);
|
|
net_pkt_append_all(pkt, sizeof(opt), (u8_t *)opt, 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 < 0) {
|
|
result = TC_PASS;
|
|
}
|
|
|
|
done:
|
|
net_pkt_unref(pkt);
|
|
|
|
TC_END_RESULT(result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/* IPv6 + UDP frame (48 bytes) */
|
|
static const unsigned char ipv6_wrong_opt_len[] = {
|
|
/* IPv6 header starts here */
|
|
0x60, 0x00, 0x00, 0x00, 0x00, 0x12, 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, 0x12, 0x00, 0x00,
|
|
/* CoAP */
|
|
};
|
|
|
|
static int test_parse_malformed_opt_len(void)
|
|
{
|
|
u8_t opt[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n',
|
|
0xC1 };
|
|
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);
|
|
|
|
net_pkt_append_all(pkt, sizeof(ipv6_wrong_opt_len),
|
|
(u8_t *)ipv6_wrong_opt_len, K_FOREVER);
|
|
net_pkt_append_all(pkt, sizeof(opt), (u8_t *)opt, 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 < 0) {
|
|
result = TC_PASS;
|
|
}
|
|
|
|
done:
|
|
net_pkt_unref(pkt);
|
|
|
|
TC_END_RESULT(result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/* IPv6 + UDP frame (48 bytes) */
|
|
static const unsigned char ipv6_wrong_opt_ext[] = {
|
|
/* IPv6 header starts here */
|
|
0x60, 0x00, 0x00, 0x00, 0x00, 0x13, 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, 0x13, 0x00, 0x00,
|
|
/* CoAP */
|
|
};
|
|
|
|
static int test_parse_malformed_opt_ext(void)
|
|
{
|
|
u8_t opt[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n',
|
|
0xE0, 0x01 };
|
|
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);
|
|
|
|
net_pkt_append_all(pkt, sizeof(ipv6_wrong_opt_ext),
|
|
(u8_t *)ipv6_wrong_opt_ext, K_FOREVER);
|
|
net_pkt_append_all(pkt, sizeof(opt), (u8_t *)opt, 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 < 0) {
|
|
result = TC_PASS;
|
|
}
|
|
|
|
done:
|
|
net_pkt_unref(pkt);
|
|
|
|
TC_END_RESULT(result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/* IPv6 + UDP frame (48 bytes) */
|
|
static const unsigned char ipv6_wrong_opt_len_ext[] = {
|
|
/* 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_malformed_opt_len_ext(void)
|
|
{
|
|
u8_t opt[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n',
|
|
0xEE, 0x01, 0x02, 0x01};
|
|
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);
|
|
|
|
net_pkt_append_all(pkt, sizeof(ipv6_wrong_opt_len_ext),
|
|
(u8_t *)ipv6_wrong_opt_len_ext, K_FOREVER);
|
|
net_pkt_append_all(pkt, sizeof(opt), (u8_t *)opt, 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 < 0) {
|
|
result = TC_PASS;
|
|
}
|
|
|
|
done:
|
|
net_pkt_unref(pkt);
|
|
|
|
TC_END_RESULT(result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/* IPv6 + UDP frame (48 bytes) */
|
|
static const unsigned char ipv6_malformed_marker[] = {
|
|
/* IPv6 header starts here */
|
|
0x60, 0x00, 0x00, 0x00, 0x00, 0x0E, 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, 0x0E, 0x00, 0x00,
|
|
/* CoAP */
|
|
};
|
|
|
|
/* 1 option, No payload (with payload marker) */
|
|
static int test_parse_malformed_marker(void)
|
|
{
|
|
u8_t pdu[] = { 0x40, 0x01, 0, 0, 0x40, 0xFF};
|
|
struct net_pkt *pkt;
|
|
struct net_buf *frag;
|
|
struct coap_packet cpkt;
|
|
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_malformed_marker),
|
|
(u8_t *)ipv6_malformed_marker, 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);
|
|
|
|
/* an empty payload packet with payload marker is malformed */
|
|
r = coap_packet_parse(&cpkt, pkt, NULL, 0);
|
|
if (r) {
|
|
result = TC_PASS;
|
|
}
|
|
|
|
done:
|
|
net_pkt_unref(pkt);
|
|
|
|
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 empty PDU test no marker", test_parse_empty_pdu_1, },
|
|
{ "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, },
|
|
{ "Parse malformed option", test_parse_malformed_opt },
|
|
{ "Parse malformed option length", test_parse_malformed_opt_len },
|
|
{ "Parse malformed option ext", test_parse_malformed_opt_ext },
|
|
{ "Parse malformed option length ext",
|
|
test_parse_malformed_opt_len_ext },
|
|
{ "Parse malformed empty payload with marker",
|
|
test_parse_malformed_marker, },
|
|
};
|
|
|
|
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;
|
|
}
|