blob: c790b45a40d4fa7fba767ce127c14271d49aa3b5 [file] [log] [blame]
/* main.c - Application main entry point */
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <misc/printk.h>
#include <ztest.h>
#include <net/net_pkt.h>
#include <net/net_ip.h>
#if defined(CONFIG_NET_DEBUG_NET_PKT)
#define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
#define NET_LOG_ENABLED 1
#else
#define DBG(fmt, ...)
#endif
#define NET_LOG_ENABLED 1
#include "net_private.h"
#define LL_RESERVE 28
#define FRAG_COUNT 7
struct ipv6_hdr {
u8_t vtc;
u8_t tcflow;
u16_t flow;
u8_t len[2];
u8_t nexthdr;
u8_t hop_limit;
struct in6_addr src;
struct in6_addr dst;
} __packed;
struct udp_hdr {
u16_t src_port;
u16_t dst_port;
u16_t len;
u16_t chksum;
} __packed;
struct icmp_hdr {
u8_t type;
u8_t code;
u16_t chksum;
} __packed;
static const char example_data[] =
"0123456789abcdefghijklmnopqrstuvxyz!#¤%&/()=?"
"0123456789abcdefghijklmnopqrstuvxyz!#¤%&/()=?"
"0123456789abcdefghijklmnopqrstuvxyz!#¤%&/()=?"
"0123456789abcdefghijklmnopqrstuvxyz!#¤%&/()=?"
"0123456789abcdefghijklmnopqrstuvxyz!#¤%&/()=?"
"0123456789abcdefghijklmnopqrstuvxyz!#¤%&/()=?";
static void test_ipv6_multi_frags(void)
{
struct net_pkt *pkt;
struct net_buf *frag;
struct ipv6_hdr *ipv6;
struct udp_hdr *udp;
int bytes, remaining = strlen(example_data), pos = 0;
/* Example of multi fragment scenario with IPv6 */
pkt = net_pkt_get_reserve_rx(0, K_FOREVER);
frag = net_pkt_get_reserve_rx_data(LL_RESERVE, K_FOREVER);
/* Place the IP + UDP header in the first fragment */
if (!net_buf_tailroom(frag)) {
ipv6 = (struct ipv6_hdr *)(frag->data);
udp = (struct udp_hdr *)((void *)ipv6 + sizeof(*ipv6));
if (net_buf_tailroom(frag) < sizeof(ipv6)) {
printk("Not enough space for IPv6 header, "
"needed %zd bytes, has %zd bytes\n",
sizeof(ipv6), net_buf_tailroom(frag));
zassert_true(false, "No space for IPv6 header");
}
net_buf_add(frag, sizeof(ipv6));
if (net_buf_tailroom(frag) < sizeof(udp)) {
printk("Not enough space for UDP header, "
"needed %zd bytes, has %zd bytes\n",
sizeof(udp), net_buf_tailroom(frag));
zassert_true(false, "No space for UDP header");
}
net_pkt_set_appdata(pkt, (void *)udp + sizeof(*udp));
net_pkt_set_appdatalen(pkt, 0);
}
net_pkt_frag_add(pkt, frag);
/* Put some data to rest of the fragments */
frag = net_pkt_get_reserve_rx_data(LL_RESERVE, K_FOREVER);
if (net_buf_tailroom(frag) -
(CONFIG_NET_BUF_DATA_SIZE - LL_RESERVE)) {
printk("Invalid number of bytes available in the buf, "
"should be 0 but was %zd - %d\n",
net_buf_tailroom(frag),
CONFIG_NET_BUF_DATA_SIZE - LL_RESERVE);
zassert_true(false, "Invalid byte count");
}
if (((int)net_buf_tailroom(frag) - remaining) > 0) {
printk("We should have been out of space now, "
"tailroom %zd user data len %zd\n",
net_buf_tailroom(frag),
strlen(example_data));
zassert_true(false, "Still space");
}
while (remaining > 0) {
int copy;
bytes = net_buf_tailroom(frag);
copy = remaining > bytes ? bytes : remaining;
memcpy(net_buf_add(frag, copy), &example_data[pos], copy);
DBG("Remaining %d left %d copy %d\n", remaining, bytes, copy);
pos += bytes;
remaining -= bytes;
if (net_buf_tailroom(frag) - (bytes - copy)) {
printk("There should have not been any tailroom left, "
"tailroom %zd\n",
net_buf_tailroom(frag) - (bytes - copy));
zassert_true(false, "There is still tailroom left");
}
net_pkt_frag_add(pkt, frag);
if (remaining > 0) {
frag = net_pkt_get_reserve_rx_data(LL_RESERVE,
K_FOREVER);
}
}
bytes = net_pkt_get_len(pkt);
if (bytes != strlen(example_data)) {
printk("Invalid number of bytes in message, %zd vs %d\n",
strlen(example_data), bytes);
zassert_true(false, "Invalid number of bytes");
}
/* Normally one should not unref the fragment list like this
* because it will leave the pkt->frags pointing to already
* freed fragment.
*/
net_pkt_frag_unref(pkt->frags);
zassert_not_null(pkt->frags, "Frag list empty");
pkt->frags = NULL; /* to prevent double free */
net_pkt_unref(pkt);
}
static char buf_orig[200];
static char buf_copy[200];
static void linearize(struct net_pkt *pkt, char *buffer, int len)
{
struct net_buf *frag;
char *ptr = buffer;
frag = pkt->frags;
while (frag && len > 0) {
memcpy(ptr, frag->data, frag->len);
ptr += frag->len;
len -= frag->len;
frag = frag->frags;
}
}
static void test_fragment_copy(void)
{
struct net_pkt *pkt, *new_pkt;
struct net_buf *frag, *new_frag;
struct ipv6_hdr *ipv6;
struct udp_hdr *udp;
size_t orig_len, reserve;
int pos;
pkt = net_pkt_get_reserve_rx(0, K_FOREVER);
frag = net_pkt_get_reserve_rx_data(LL_RESERVE, K_FOREVER);
/* Place the IP + UDP header in the first fragment */
if (net_buf_tailroom(frag)) {
ipv6 = (struct ipv6_hdr *)(frag->data);
udp = (struct udp_hdr *)((void *)ipv6 + sizeof(*ipv6));
if (net_buf_tailroom(frag) < sizeof(*ipv6)) {
printk("Not enough space for IPv6 header, "
"needed %zd bytes, has %zd bytes\n",
sizeof(ipv6), net_buf_tailroom(frag));
zassert_true(false, "No space for IPv6 header");
}
net_buf_add(frag, sizeof(*ipv6));
if (net_buf_tailroom(frag) < sizeof(*udp)) {
printk("Not enough space for UDP header, "
"needed %zd bytes, has %zd bytes\n",
sizeof(udp), net_buf_tailroom(frag));
zassert_true(false, "No space for UDP header");
}
net_buf_add(frag, sizeof(*udp));
memcpy(net_buf_add(frag, 15), example_data, 15);
net_pkt_set_appdata(pkt, (void *)udp + sizeof(*udp) + 15);
net_pkt_set_appdatalen(pkt, 0);
}
net_pkt_frag_add(pkt, frag);
orig_len = net_pkt_get_len(pkt);
DBG("Total copy data len %zd\n", orig_len);
linearize(pkt, buf_orig, orig_len);
/* Then copy a fragment list to a new fragment list.
* Reserve some space in front of the buffers.
*/
reserve = sizeof(struct ipv6_hdr) + sizeof(struct icmp_hdr);
new_frag = net_pkt_copy_all(pkt, reserve, K_FOREVER);
zassert_not_null(new_frag, "Cannot copy fragment list");
new_pkt = net_pkt_get_reserve_tx(0, K_FOREVER);
new_pkt->frags = net_buf_frag_add(new_pkt->frags, new_frag);
DBG("Total new data len %zd\n", net_pkt_get_len(new_pkt));
if ((net_pkt_get_len(pkt) + reserve) != net_pkt_get_len(new_pkt)) {
int diff;
diff = net_pkt_get_len(new_pkt) - reserve -
net_pkt_get_len(pkt);
printk("Fragment list missing data, %d bytes not copied "
"(%zd vs %zd)\n", diff,
net_pkt_get_len(pkt) + reserve,
net_pkt_get_len(new_pkt));
zassert_true(false, "Frag list missing");
}
if (net_pkt_get_len(new_pkt) != (orig_len + sizeof(struct ipv6_hdr) +
sizeof(struct icmp_hdr))) {
printk("Fragment list missing data, new pkt len %zd "
"should be %zd\n", net_pkt_get_len(new_pkt),
orig_len + sizeof(struct ipv6_hdr) +
sizeof(struct icmp_hdr));
zassert_true(false, "Frag list missing data");
}
linearize(new_pkt, buf_copy, sizeof(buf_copy));
zassert_true(memcmp(buf_orig, buf_copy, sizeof(buf_orig)),
"Buffer copy failed, buffers are same");
pos = memcmp(buf_orig, buf_copy + sizeof(struct ipv6_hdr) +
sizeof(struct icmp_hdr), orig_len);
if (pos) {
printk("Buffer copy failed at pos %d\n", pos);
zassert_true(false, "Buf copy failed");
}
}
/* Empty data and test data must be the same size in order the test to work */
static const char test_data[] = { '0', '1', '2', '3', '4',
'5', '6', '7' };
static const char sample_data[] =
"abcdefghijklmnopqrstuvxyz "
"abcdefghijklmnopqrstuvxyz "
"abcdefghijklmnopqrstuvxyz "
"abcdefghijklmnopqrstuvxyz "
"abcdefghijklmnopqrstuvxyz "
"abcdefghijklmnopqrstuvxyz "
"abcdefghijklmnopqrstuvxyz "
"abcdefghijklmnopqrstuvxyz "
"abcdefghijklmnopqrstuvxyz "
"abcdefghijklmnopqrstuvxyz "
"abcdefghijklmnopqrstuvxyz "
"abcdefghijklmnopqrstuvxyz "
"abcdefghijklmnopqrstuvxyz";
static char test_rw_short[] =
"abcdefghijklmnopqrstuvwxyz";
static char test_rw_long[] =
"abcdefghijklmnopqrstuvwxyz "
"abcdefghijklmnopqrstuvwxyz "
"abcdefghijklmnopqrstuvwxyz "
"abcdefghijklmnopqrstuvwxyz "
"abcdefghijklmnopqrstuvwxyz "
"abcdefghijklmnopqrstuvwxyz "
"abcdefghijklmnopqrstuvwxyz ";
static void test_pkt_read_append(void)
{
int remaining = strlen(sample_data);
u8_t verify_rw_short[sizeof(test_rw_short)];
u8_t verify_rw_long[sizeof(test_rw_long)];
struct net_pkt *pkt;
struct net_buf *frag;
struct net_buf *tfrag;
struct ipv6_hdr *ipv6;
struct udp_hdr *udp;
u8_t data[10];
int pos = 0;
int bytes;
u16_t off;
u16_t tpos;
u16_t fail_pos;
/* Example of multi fragment read, append and skip APS's */
pkt = net_pkt_get_reserve_rx(0, K_FOREVER);
frag = net_pkt_get_reserve_rx_data(LL_RESERVE, K_FOREVER);
/* Place the IP + UDP header in the first fragment */
if (!net_buf_tailroom(frag)) {
ipv6 = (struct ipv6_hdr *)(frag->data);
udp = (struct udp_hdr *)((void *)ipv6 + sizeof(*ipv6));
if (net_buf_tailroom(frag) < sizeof(ipv6)) {
printk("Not enough space for IPv6 header, "
"needed %zd bytes, has %zd bytes\n",
sizeof(ipv6), net_buf_tailroom(frag));
zassert_true(false, "No space for IPv6 header");
}
net_buf_add(frag, sizeof(ipv6));
if (net_buf_tailroom(frag) < sizeof(udp)) {
printk("Not enough space for UDP header, "
"needed %zd bytes, has %zd bytes\n",
sizeof(udp), net_buf_tailroom(frag));
zassert_true(false, "No space for UDP header");
}
net_pkt_set_appdata(pkt, (void *)udp + sizeof(*udp));
net_pkt_set_appdatalen(pkt, 0);
}
net_pkt_frag_add(pkt, frag);
/* Put some data to rest of the fragments */
frag = net_pkt_get_reserve_rx_data(LL_RESERVE, K_FOREVER);
if (net_buf_tailroom(frag) -
(CONFIG_NET_BUF_DATA_SIZE - LL_RESERVE)) {
printk("Invalid number of bytes available in the buf, "
"should be 0 but was %zd - %d\n",
net_buf_tailroom(frag),
CONFIG_NET_BUF_DATA_SIZE - LL_RESERVE);
zassert_true(false, "Invalid number of bytes avail");
}
if (((int)net_buf_tailroom(frag) - remaining) > 0) {
printk("We should have been out of space now, "
"tailroom %zd user data len %zd\n",
net_buf_tailroom(frag),
strlen(sample_data));
zassert_true(false, "Not out of space");
}
while (remaining > 0) {
int copy;
bytes = net_buf_tailroom(frag);
copy = remaining > bytes ? bytes : remaining;
memcpy(net_buf_add(frag, copy), &sample_data[pos], copy);
DBG("Remaining %d left %d copy %d\n", remaining, bytes, copy);
pos += bytes;
remaining -= bytes;
if (net_buf_tailroom(frag) - (bytes - copy)) {
printk("There should have not been any tailroom left, "
"tailroom %zd\n",
net_buf_tailroom(frag) - (bytes - copy));
zassert_true(false, "Still tailroom left");
}
net_pkt_frag_add(pkt, frag);
if (remaining > 0) {
frag = net_pkt_get_reserve_rx_data(LL_RESERVE,
K_FOREVER);
}
}
bytes = net_pkt_get_len(pkt);
if (bytes != strlen(sample_data)) {
printk("Invalid number of bytes in message, %zd vs %d\n",
strlen(sample_data), bytes);
zassert_true(false, "Message size wrong");
}
/* Failure cases */
/* Invalid buffer */
tfrag = net_frag_skip(NULL, 10, &fail_pos, 10);
zassert_true(!tfrag && fail_pos == 0xffff, "Invalid case NULL buffer");
/* Invalid: Skip more than a buffer length.*/
tfrag = net_buf_frag_last(pkt->frags);
tfrag = net_frag_skip(tfrag, tfrag->len - 1, &fail_pos, tfrag->len + 2);
if (!(!tfrag && fail_pos == 0xffff)) {
printk("Invalid case offset %d length to skip %d,"
"frag length %d\n",
tfrag->len - 1, tfrag->len + 2, tfrag->len);
zassert_true(false, "Invalid offset");
}
/* Invalid offset */
tfrag = net_buf_frag_last(pkt->frags);
tfrag = net_frag_skip(tfrag, tfrag->len + 10, &fail_pos, 10);
if (!(!tfrag && fail_pos == 0xffff)) {
printk("Invalid case offset %d length to skip %d,"
"frag length %d\n",
tfrag->len + 10, 10, tfrag->len);
zassert_true(false, "Invalid offset");
}
/* Valid cases */
/* Offset is more than single fragment length */
/* Get the first data fragment */
tfrag = pkt->frags;
tfrag = tfrag->frags;
off = tfrag->len;
tfrag = net_frag_read(tfrag, off + 10, &tpos, 10, data);
if (!tfrag ||
memcmp(sample_data + off + 10, data, 10)) {
printk("Failed to read from offset %d, frag length %d "
"read length %d\n",
tfrag->len + 10, tfrag->len, 10);
zassert_true(false, "Fail offset read");
}
/* Skip till end of all fragments */
/* Get the first data fragment */
tfrag = pkt->frags;
tfrag = tfrag->frags;
tfrag = net_frag_skip(tfrag, 0, &tpos, strlen(sample_data));
zassert_true(!tfrag && tpos == 0,
"Invalid skip till end of all fragments");
/* Short data test case */
/* Test case scenario:
* 1) Cache the current fragment and offset
* 2) Append short data
* 3) Append short data again
* 4) Skip first short data from cached frag or offset
* 5) Read short data and compare
*/
tfrag = net_buf_frag_last(pkt->frags);
off = tfrag->len;
zassert_true(net_pkt_append_all(pkt, (u16_t)sizeof(test_rw_short),
test_rw_short, K_FOREVER),
"net_pkt_append failed");
zassert_true(net_pkt_append_all(pkt, (u16_t)sizeof(test_rw_short),
test_rw_short, K_FOREVER),
"net_pkt_append failed");
tfrag = net_frag_skip(tfrag, off, &tpos,
(u16_t)sizeof(test_rw_short));
zassert_not_null(tfrag, "net_frag_skip failed");
tfrag = net_frag_read(tfrag, tpos, &tpos,
(u16_t)sizeof(test_rw_short),
verify_rw_short);
zassert_true(!tfrag && tpos == 0, "net_frag_read failed");
zassert_false(memcmp(test_rw_short, verify_rw_short,
sizeof(test_rw_short)),
"net_frag_read failed with mismatch data");
/* Long data test case */
/* Test case scenario:
* 1) Cache the current fragment and offset
* 2) Append long data
* 3) Append long data again
* 4) Skip first long data from cached frag or offset
* 5) Read long data and compare
*/
tfrag = net_buf_frag_last(pkt->frags);
off = tfrag->len;
zassert_true(net_pkt_append_all(pkt, (u16_t)sizeof(test_rw_long),
test_rw_long, K_FOREVER),
"net_pkt_append failed");
zassert_true(net_pkt_append_all(pkt, (u16_t)sizeof(test_rw_long),
test_rw_long, K_FOREVER),
"net_pkt_append failed");
tfrag = net_frag_skip(tfrag, off, &tpos,
(u16_t)sizeof(test_rw_long));
zassert_not_null(tfrag, "net_frag_skip failed");
tfrag = net_frag_read(tfrag, tpos, &tpos,
(u16_t)sizeof(test_rw_long),
verify_rw_long);
zassert_true(!tfrag && tpos == 0, "net_frag_read failed");
zassert_false(memcmp(test_rw_long, verify_rw_long,
sizeof(test_rw_long)),
"net_frag_read failed with mismatch data");
net_pkt_unref(pkt);
DBG("test_pkt_read_append passed\n");
}
static void test_pkt_read_write_insert(void)
{
struct net_buf *read_frag;
struct net_buf *temp_frag;
struct net_pkt *pkt;
struct net_buf *frag;
u8_t read_data[100];
u16_t read_pos;
u16_t len;
u16_t pos;
/* Example of multi fragment read, append and skip APS's */
pkt = net_pkt_get_reserve_rx(0, K_FOREVER);
net_pkt_set_ll_reserve(pkt, LL_RESERVE);
frag = net_pkt_get_reserve_rx_data(net_pkt_ll_reserve(pkt),
K_FOREVER);
net_pkt_frag_add(pkt, frag);
/* 1) Offset is with in input fragment.
* Write app data after IPv6 and UDP header. (If the offset is after
* IPv6 + UDP header size, api will create empty space till offset
* and write data).
*/
frag = net_pkt_write(pkt, frag, NET_IPV6UDPH_LEN, &pos, 10,
(u8_t *)sample_data, K_FOREVER);
zassert_false(!frag || pos != 58, "Usecase 1: Write failed");
read_frag = net_frag_read(frag, NET_IPV6UDPH_LEN, &read_pos, 10,
read_data);
zassert_false(!read_frag && read_pos == 0xffff,
"Usecase 1: Read failed");
zassert_false(memcmp(read_data, sample_data, 10),
"Usecase 1: Read data mismatch");
/* 2) Write IPv6 and UDP header at offset 0. (Empty space is created
* already in Usecase 1, just need to fill the header, at this point
* there shouldn't be any length change).
*/
frag = net_pkt_write(pkt, frag, 0, &pos, NET_IPV6UDPH_LEN,
(u8_t *)sample_data, K_FOREVER);
zassert_false(!frag || pos != 48, "Usecase 2: Write failed");
read_frag = net_frag_read(frag, 0, &read_pos, NET_IPV6UDPH_LEN,
read_data);
zassert_false(!read_frag && read_pos == 0xffff,
"Usecase 2: Read failed");
zassert_false(memcmp(read_data, sample_data, NET_IPV6UDPH_LEN),
"Usecase 2: Read data mismatch");
net_pkt_unref(pkt);
pkt = net_pkt_get_reserve_rx(0, K_FOREVER);
net_pkt_set_ll_reserve(pkt, LL_RESERVE);
/* 3) Offset is in next to next fragment.
* Write app data after 2 fragments. (If the offset far away, api will
* create empty fragments(space) till offset and write data).
*/
frag = net_pkt_write(pkt, pkt->frags, 200, &pos, 10,
(u8_t *)sample_data + 10, K_FOREVER);
zassert_not_null(frag, "Usecase 3: Write failed");
read_frag = net_frag_read(frag, pos - 10, &read_pos, 10,
read_data);
zassert_false(!read_frag && read_pos == 0xffff,
"Usecase 3: Read failed");
zassert_false(memcmp(read_data, sample_data + 10, 10),
"Usecase 3: Read data mismatch");
/* 4) Offset is in next to next fragment (overwrite).
* Write app data after 2 fragments. (Space is already available from
* Usecase 3, this scenatio doesn't create any space, it just overwrites
* the existing data.
*/
frag = net_pkt_write(pkt, pkt->frags, 190, &pos, 10,
(u8_t *)sample_data, K_FOREVER);
zassert_not_null(frag, "Usecase 4: Write failed");
read_frag = net_frag_read(frag, pos - 10, &read_pos, 20,
read_data);
zassert_false(!read_frag && read_pos == 0xffff,
"Usecase 4: Read failed");
zassert_false(memcmp(read_data, sample_data, 20),
"Usecase 4: Read data mismatch");
net_pkt_unref(pkt);
/* 5) Write 20 bytes in fragment which has only 10 bytes space.
* API should overwrite on first 10 bytes and create extra 10 bytes
* and write there.
*/
pkt = net_pkt_get_reserve_rx(0, K_FOREVER);
net_pkt_set_ll_reserve(pkt, LL_RESERVE);
frag = net_pkt_get_reserve_rx_data(net_pkt_ll_reserve(pkt),
K_FOREVER);
net_pkt_frag_add(pkt, frag);
/* Create 10 bytes space. */
net_buf_add(frag, 10);
frag = net_pkt_write(pkt, frag, 0, &pos, 20, (u8_t *)sample_data,
K_FOREVER);
zassert_false(!frag && pos != 20, "Usecase 5: Write failed");
read_frag = net_frag_read(frag, 0, &read_pos, 20, read_data);
zassert_false(!read_frag && read_pos == 0xffff,
"Usecase 5: Read failed");
zassert_false(memcmp(read_data, sample_data, 20),
"USecase 5: Read data mismatch");
net_pkt_unref(pkt);
/* 6) First fragment is full, second fragment has 10 bytes tail room,
* third fragment has 5 bytes.
* Write data (30 bytes) in second fragment where offset is 10 bytes
* before the tailroom.
* So it should overwrite 10 bytes and create space for another 10
* bytes and write data. Third fragment 5 bytes overwritten and space
* for 5 bytes created.
*/
pkt = net_pkt_get_reserve_rx(0, K_FOREVER);
net_pkt_set_ll_reserve(pkt, LL_RESERVE);
/* First fragment make it fully occupied. */
frag = net_pkt_get_reserve_rx_data(net_pkt_ll_reserve(pkt),
K_FOREVER);
net_pkt_frag_add(pkt, frag);
len = net_buf_tailroom(frag);
net_buf_add(frag, len);
/* 2nd fragment last 10 bytes tailroom, rest occupied */
frag = net_pkt_get_reserve_rx_data(net_pkt_ll_reserve(pkt),
K_FOREVER);
net_pkt_frag_add(pkt, frag);
len = net_buf_tailroom(frag);
net_buf_add(frag, len - 10);
read_frag = temp_frag = frag;
read_pos = frag->len - 10;
/* 3rd fragment, only 5 bytes occupied */
frag = net_pkt_get_reserve_rx_data(net_pkt_ll_reserve(pkt),
K_FOREVER);
net_pkt_frag_add(pkt, frag);
net_buf_add(frag, 5);
temp_frag = net_pkt_write(pkt, temp_frag, temp_frag->len - 10, &pos,
30, (u8_t *) sample_data, K_FOREVER);
zassert_not_null(temp_frag, "Use case 6: Write failed");
read_frag = net_frag_read(read_frag, read_pos, &read_pos, 30,
read_data);
zassert_false(!read_frag && read_pos == 0xffff,
"Usecase 6: Read failed");
zassert_false(memcmp(read_data, sample_data, 30),
"Usecase 6: Read data mismatch");
net_pkt_unref(pkt);
/* 7) Offset is with in input fragment.
* Write app data after IPv6 and UDP header. (If the offset is after
* IPv6 + UDP header size, api will create empty space till offset
* and write data). Insert some app data after IPv6 + UDP header
* before first set of app data.
*/
pkt = net_pkt_get_reserve_rx(0, K_FOREVER);
net_pkt_set_ll_reserve(pkt, LL_RESERVE);
/* First fragment make it fully occupied. */
frag = net_pkt_get_reserve_rx_data(net_pkt_ll_reserve(pkt),
K_FOREVER);
net_pkt_frag_add(pkt, frag);
frag = net_pkt_write(pkt, frag, NET_IPV6UDPH_LEN, &pos, 10,
(u8_t *)sample_data + 10, K_FOREVER);
zassert_false(!frag || pos != 58, "Usecase 7: Write failed");
read_frag = net_frag_read(frag, NET_IPV6UDPH_LEN, &read_pos, 10,
read_data);
zassert_false(!read_frag && read_pos == 0xffff,
"Usecase 7: Read failed");
zassert_false(memcmp(read_data, sample_data + 10, 10),
"Usecase 7: Read data mismatch");
zassert_true(net_pkt_insert(pkt, frag, NET_IPV6UDPH_LEN, 10,
(u8_t *)sample_data, K_FOREVER),
"Usecase 7: Insert failed");
read_frag = net_frag_read(frag, NET_IPV6UDPH_LEN, &read_pos, 20,
read_data);
zassert_false(!read_frag && read_pos == 0xffff,
"Usecase 7: Read after failed");
zassert_false(memcmp(read_data, sample_data, 20),
"Usecase 7: Read data mismatch after insertion");
/* Insert data outside input fragment length, error case. */
zassert_false(net_pkt_insert(pkt, frag, 70, 10, (u8_t *)sample_data,
K_FOREVER),
"Usecase 7: False insert failed");
net_pkt_unref(pkt);
/* 8) Offset is with in input fragment.
* Write app data after IPv6 and UDP header. (If the offset is after
* IPv6 + UDP header size, api will create empty space till offset
* and write data). Insert some app data after IPv6 + UDP header
* before first set of app data. Insertion data is long which will
* take two fragments.
*/
pkt = net_pkt_get_reserve_rx(0, K_FOREVER);
net_pkt_set_ll_reserve(pkt, LL_RESERVE);
/* First fragment make it fully occupied. */
frag = net_pkt_get_reserve_rx_data(net_pkt_ll_reserve(pkt),
K_FOREVER);
net_pkt_frag_add(pkt, frag);
frag = net_pkt_write(pkt, frag, NET_IPV6UDPH_LEN, &pos, 10,
(u8_t *)sample_data + 60, K_FOREVER);
zassert_false(!frag || pos != 58, "Usecase 8: Write failed");
read_frag = net_frag_read(frag, NET_IPV6UDPH_LEN, &read_pos, 10,
read_data);
zassert_false(!read_frag && read_pos == 0xffff,
"Usecase 8: Read failed");
zassert_false(memcmp(read_data, sample_data + 60, 10),
"Usecase 8: Read data mismatch");
zassert_true(net_pkt_insert(pkt, frag, NET_IPV6UDPH_LEN, 60,
(u8_t *)sample_data, K_FOREVER),
"Usecase 8: Insert failed");
read_frag = net_frag_read(frag, NET_IPV6UDPH_LEN, &read_pos, 70,
read_data);
zassert_false(!read_frag && read_pos == 0xffff,
"Usecase 8: Read after failed");
zassert_false(memcmp(read_data, sample_data, 70),
"Usecase 8: Read data mismatch after insertion");
net_pkt_unref(pkt);
DBG("test_pkt_read_write_insert passed\n");
}
static int calc_fragments(struct net_pkt *pkt)
{
struct net_buf *frag = pkt->frags;
int count = 0;
while (frag) {
frag = frag->frags;
count++;
}
return count;
}
static bool net_pkt_is_compact(struct net_pkt *pkt)
{
struct net_buf *frag, *last;
size_t total = 0, calc;
int count = 0;
last = NULL;
frag = pkt->frags;
while (frag) {
total += frag->len;
count++;
last = frag;
frag = frag->frags;
}
NET_ASSERT(last);
if (!last) {
return false;
}
calc = count * (last->size) - net_buf_tailroom(last) -
count * (net_buf_headroom(last));
if (total == calc) {
return true;
}
NET_DBG("Not compacted total %zu real %zu", total, calc);
return false;
}
static void test_fragment_compact(void)
{
struct net_pkt *pkt;
struct net_buf *frags[FRAG_COUNT], *frag;
int i, bytes, total, count;
pkt = net_pkt_get_reserve_rx(0, K_FOREVER);
frag = NULL;
for (i = 0, total = 0; i < FRAG_COUNT; i++) {
frags[i] = net_pkt_get_reserve_rx_data(12, K_FOREVER);
if (frag) {
net_buf_frag_add(frag, frags[i]);
}
frag = frags[i];
/* Copy character test data in front of the fragment */
memcpy(net_buf_add(frags[i], sizeof(test_data)),
test_data, sizeof(test_data));
/* Followed by bytes of zeroes */
memset(net_buf_add(frags[i], sizeof(test_data)), 0,
sizeof(test_data));
total++;
}
if (total != FRAG_COUNT) {
printk("There should be %d fragments but was %d\n",
FRAG_COUNT, total);
zassert_true(false, "Invalid fragment count");
}
DBG("step 1\n");
pkt->frags = net_buf_frag_add(pkt->frags, frags[0]);
bytes = net_pkt_get_len(pkt);
if (bytes != FRAG_COUNT * sizeof(test_data) * 2) {
printk("Compact test failed, fragments had %d bytes but "
"should have had %zd\n", bytes,
FRAG_COUNT * sizeof(test_data) * 2);
zassert_true(false, "Invalid fragment bytes");
}
zassert_false(net_pkt_is_compact(pkt),
"The pkt is definitely not compact");
DBG("step 2\n");
net_pkt_compact(pkt);
zassert_true(net_pkt_is_compact(pkt),
"The pkt should be in compact form");
DBG("step 3\n");
/* Try compacting again, nothing should happen */
net_pkt_compact(pkt);
zassert_true(net_pkt_is_compact(pkt),
"The pkt should be compacted now");
total = calc_fragments(pkt);
/* Add empty fragment at the end and compact, the last fragment
* should be removed.
*/
frag = net_pkt_get_reserve_rx_data(0, K_FOREVER);
net_pkt_frag_add(pkt, frag);
count = calc_fragments(pkt);
DBG("step 4\n");
net_pkt_compact(pkt);
i = calc_fragments(pkt);
if (count != (i + 1)) {
printk("Last fragment removal failed, chain should have %d "
"fragments but had %d\n", i-1, i);
zassert_true(false, "Last frag rm fails");
}
if (i != total) {
printk("Fragments missing, expecting %d but got %d\n",
total, i);
zassert_true(false, "Frags missing");
}
/* Add two empty fragments at the end and compact, the last two
* fragment should be removed.
*/
frag = net_pkt_get_reserve_rx_data(0, K_FOREVER);
net_pkt_frag_add(pkt, frag);
frag = net_pkt_get_reserve_rx_data(0, K_FOREVER);
net_pkt_frag_add(pkt, frag);
count = calc_fragments(pkt);
DBG("step 5\n");
net_pkt_compact(pkt);
i = calc_fragments(pkt);
if (count != (i + 2)) {
printk("Last two fragment removal failed, chain should have "
"%d fragments but had %d\n", i-2, i);
zassert_true(false, "Last two frag rm fails");
}
if (i != total) {
printk("Fragments missing, expecting %d but got %d\n",
total, i);
zassert_true(false, "Frags missing");
}
/* Add empty fragment at the beginning and at the end, and then
* compact, the two fragment should be removed.
*/
frag = net_pkt_get_reserve_rx_data(0, K_FOREVER);
net_pkt_frag_insert(pkt, frag);
frag = net_pkt_get_reserve_rx_data(0, K_FOREVER);
net_pkt_frag_add(pkt, frag);
count = calc_fragments(pkt);
DBG("step 6\n");
net_pkt_compact(pkt);
i = calc_fragments(pkt);
if (count != (i + 2)) {
printk("Two fragment removal failed, chain should have "
"%d fragments but had %d\n", i-2, i);
zassert_true(false, "Two frag rm fails");
}
if (i != total) {
printk("Fragments missing, expecting %d but got %d\n",
total, i);
zassert_true(false, "Frags missing");
}
DBG("test_fragment_compact passed\n");
}
static const char frag_data[CONFIG_NET_BUF_DATA_SIZE] = { 42 };
static void test_fragment_split(void)
{
#define TEST_FRAG_COUNT (FRAG_COUNT - 2)
#define FRAGA (FRAG_COUNT - 2)
#define FRAGB (FRAG_COUNT - 1)
struct net_pkt *pkt;
struct net_buf *frags[FRAG_COUNT], *frag, *frag_a, *frag_b;
int i, total, split_a, split_b;
int ret, frag_size;
memset(frags, 0, FRAG_COUNT * sizeof(void *));
pkt = net_pkt_get_reserve_rx(0, K_FOREVER);
frag = NULL;
for (i = 0, total = 0; i < TEST_FRAG_COUNT; i++) {
frags[i] = net_pkt_get_reserve_rx_data(12, K_FOREVER);
if (frag) {
net_buf_frag_add(frag, frags[i]);
}
frag = frags[i];
/* Copy some test data in front of the fragment */
memcpy(net_buf_add(frags[i], sizeof(frag_data)),
frag_data, sizeof(frag_data));
total++;
}
if (total != TEST_FRAG_COUNT) {
printk("There should be %d fragments but was %d\n",
TEST_FRAG_COUNT, total);
zassert_true(false, "Frags missing");
}
frag_size = frags[0]->size;
zassert_true(frag_size > 0, "Invalid frag size");
net_pkt_frag_add(pkt, frags[0]);
frag_a = frags[FRAGA];
frag_b = frags[FRAGB];
zassert_is_null(frag_a, "frag_a is not NULL");
zassert_is_null(frag_b, "frag_b is not NULL");
split_a = frag_size * 2 / 3;
split_b = frag_size - split_a;
zassert_true(split_a > 0, "A size is 0");
zassert_true(split_a > split_b, "A is smaller than B");
/* Test some error cases first */
ret = net_pkt_split(NULL, NULL, 1024, &frag_a, &frag_b, K_NO_WAIT);
zassert_equal(ret, -EINVAL, "Invalid buf pointers");
ret = net_pkt_split(pkt, pkt->frags, CONFIG_NET_BUF_DATA_SIZE + 1,
&frag_a, &frag_b, K_NO_WAIT);
zassert_equal(ret, 0, "Split failed");
ret = net_pkt_split(pkt, pkt->frags, split_a,
&frag_a, &frag_b, K_NO_WAIT);
zassert_equal(ret, 0, "Cannot split frag");
if (frag_a->len != split_a) {
printk("Frag_a len %d not %d\n", frag_a->len, split_a);
zassert_equal(frag_a->len, split_a, "Frag_a len wrong");
}
if (frag_b->len != split_b) {
printk("Frag_b len %d not %d\n", frag_b->len, split_b);
zassert_true(false, "Frag_b len wrong");
}
zassert_false(memcmp(pkt->frags->data, frag_a->data, split_a),
"Frag_a data mismatch");
zassert_false(memcmp(pkt->frags->data + split_a, frag_b->data, split_b),
"Frag_b data mismatch");
}
void test_main(void)
{
ztest_test_suite(net_pkt_tests,
ztest_unit_test(test_ipv6_multi_frags),
ztest_unit_test(test_fragment_copy),
ztest_unit_test(test_pkt_read_append),
ztest_unit_test(test_pkt_read_write_insert),
ztest_unit_test(test_fragment_compact),
ztest_unit_test(test_fragment_split)
);
ztest_run_test_suite(net_pkt_tests);
}