blob: cfaeb414b70e45eef38bc4d0365235745a27afa2 [file] [log] [blame]
/*
* Copyright (c) 2016 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <tc_util.h>
#include <net/net_ip.h>
#include <net/nbuf.h>
#include <ieee802154_frame.h>
#include <ipv6.h>
struct ieee802154_pkt_test {
char *name;
struct in6_addr src;
struct in6_addr dst;
uint8_t *pkt;
uint8_t length;
struct {
struct ieee802154_fcf_seq *fc_seq;
struct ieee802154_address_field *dst_addr;
struct ieee802154_address_field *src_addr;
} mhr_check;
};
uint8_t ns_pkt[] = {
0x41, 0xd8, 0x3e, 0xcd, 0xab, 0xff, 0xff, 0xc2, 0xa3, 0x9e, 0x00,
0x00, 0x4b, 0x12, 0x00, 0x7b, 0x09, 0x3a, 0x20, 0x01, 0x0d, 0xb8,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x02, 0x01, 0xff, 0x00, 0x00, 0x01, 0x87, 0x00, 0x2e, 0xad,
0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02,
0x00, 0x12, 0x4b, 0x00, 0x00, 0x9e, 0xa3, 0xc2, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3d, 0x74
};
struct ieee802154_pkt_test test_ns_pkt = {
.name = "NS frame",
.src = { { { 0x20, 0x01, 0xdb, 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
.dst = { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x01 } } },
.pkt = ns_pkt,
.length = sizeof(ns_pkt),
.mhr_check.fc_seq = (struct ieee802154_fcf_seq *)ns_pkt,
.mhr_check.dst_addr = (struct ieee802154_address_field *)(ns_pkt + 3),
.mhr_check.src_addr = (struct ieee802154_address_field *)(ns_pkt + 7),
};
uint8_t ack_pkt[] = { 0x02, 0x10, 0x16, 0xa2, 0x97 };
struct ieee802154_pkt_test test_ack_pkt = {
.name = "ACK frame",
.pkt = ack_pkt,
.length = sizeof(ack_pkt),
.mhr_check.fc_seq = (struct ieee802154_fcf_seq *)ack_pkt,
.mhr_check.dst_addr = NULL,
.mhr_check.src_addr = NULL,
};
uint8_t beacon_pkt[] = {
0x00, 0xd0, 0x11, 0xcd, 0xab, 0xc2, 0xa3, 0x9e, 0x00, 0x00, 0x4b,
0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
struct ieee802154_pkt_test test_beacon_pkt = {
.name = "Empty beacon frame",
.pkt = beacon_pkt,
.length = sizeof(beacon_pkt),
.mhr_check.fc_seq = (struct ieee802154_fcf_seq *)beacon_pkt,
.mhr_check.dst_addr = NULL,
.mhr_check.src_addr =
(struct ieee802154_address_field *) (beacon_pkt + 3),
};
struct net_buf *current_buf;
struct k_sem driver_lock;
struct net_if *iface;
static void pkt_hexdump(uint8_t *pkt, uint8_t length)
{
int i;
TC_PRINT(" -> Packet content:\n");
for (i = 0; i < length;) {
int j;
TC_PRINT("\t");
for (j = 0; j < 10 && i < length; j++, i++) {
TC_PRINT("%02x ", *pkt);
pkt++;
}
TC_PRINT("\n");
}
}
static void ieee_addr_hexdump(uint8_t *addr, uint8_t length)
{
int i;
TC_PRINT(" -> IEEE 802.15.4 Address: ");
for (i = 0; i < length-1; i++) {
TC_PRINT("%02x:", *addr);
addr++;
}
TC_PRINT("%02x\n", *addr);
}
static inline int test_packet_parsing(struct ieee802154_pkt_test *t)
{
struct ieee802154_mpdu mpdu;
TC_PRINT("- Parsing packet 0x%p of frame %s\n", t->pkt, t->name);
if (!ieee802154_validate_frame(t->pkt, t->length, &mpdu)) {
TC_ERROR("*** Could not validate frame %s\n", t->name);
return TC_FAIL;
}
if (mpdu.mhr.fs != t->mhr_check.fc_seq ||
mpdu.mhr.dst_addr != t->mhr_check.dst_addr ||
mpdu.mhr.src_addr != t->mhr_check.src_addr) {
TC_PRINT("d: %p vs %p -- s: %p vs %p\n",
mpdu.mhr.dst_addr, t->mhr_check.dst_addr,
mpdu.mhr.src_addr, t->mhr_check.src_addr);
TC_ERROR("*** Wrong MPDU information on frame %s\n",
t->name);
return TC_FAIL;
}
return TC_PASS;
}
static inline int test_ns_sending(struct ieee802154_pkt_test *t)
{
struct ieee802154_mpdu mpdu;
TC_PRINT("- Sending NS packet\n");
if (net_ipv6_send_ns(iface, NULL, &t->src, &t->dst, &t->dst, false)) {
TC_ERROR("*** Could not create IPv6 NS packet\n");
return TC_FAIL;
}
k_sem_take(&driver_lock, 10);
if (!current_buf->frags) {
TC_ERROR("*** Could not send IPv6 NS packet\n");
return TC_FAIL;
}
pkt_hexdump(net_nbuf_ll(current_buf), net_buf_frags_len(current_buf));
if (!ieee802154_validate_frame(net_nbuf_ll(current_buf),
net_buf_frags_len(current_buf), &mpdu)) {
TC_ERROR("*** Sent packet is not valid\n");
net_nbuf_unref(current_buf);
return TC_FAIL;
}
net_nbuf_unref(current_buf->frags);
current_buf->frags = NULL;
return TC_PASS;
}
static inline int test_ack_reply(struct ieee802154_pkt_test *t)
{
static uint8_t data_pkt[] = {
0x61, 0xdc, 0x16, 0xcd, 0xab, 0x26, 0x11, 0x32, 0x00, 0x00, 0x4b,
0x12, 0x00, 0x26, 0x18, 0x32, 0x00, 0x00, 0x4b, 0x12, 0x00, 0x7b,
0x00, 0x3a, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x01, 0x0d, 0xb8,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x87, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01,
0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x16, 0xf0, 0x02, 0xff, 0x16, 0xf0, 0x12, 0xff, 0x16, 0xf0, 0x32,
0xff, 0x16, 0xf0, 0x00, 0xff, 0x16, 0xf0, 0x00, 0xff, 0x16
};
struct ieee802154_mpdu mpdu;
struct net_buf *buf, *frag;
TC_PRINT("- Sending ACK reply to a data packet\n");
buf = net_nbuf_get_reserve_rx(0, K_FOREVER);
frag = net_nbuf_get_frag(buf, K_FOREVER);
memcpy(frag->data, data_pkt, sizeof(data_pkt));
frag->len = sizeof(data_pkt);
net_buf_frag_add(buf, frag);
net_recv_data(iface, buf);
k_sem_take(&driver_lock, 20);
/* an ACK packet should be in current_buf */
if (!current_buf->frags) {
TC_ERROR("*** No ACK reply sent\n");
return TC_FAIL;
}
pkt_hexdump(net_nbuf_ll(current_buf), net_buf_frags_len(current_buf));
if (!ieee802154_validate_frame(net_nbuf_ll(current_buf),
net_buf_frags_len(current_buf), &mpdu)) {
TC_ERROR("*** ACK Reply is invalid\n");
return TC_FAIL;
}
if (memcmp(mpdu.mhr.fs, t->mhr_check.fc_seq,
sizeof(struct ieee802154_fcf_seq))) {
TC_ERROR("*** ACK Reply does not compare\n");
return TC_FAIL;
}
net_nbuf_unref(current_buf->frags);
current_buf->frags = NULL;
return TC_PASS;
}
static inline int initialize_test_environment(void)
{
struct device *dev;
k_sem_init(&driver_lock, 0, UINT_MAX);
current_buf = net_nbuf_get_reserve_rx(0, K_FOREVER);
if (!current_buf) {
TC_ERROR("*** No buffer to allocate\n");
return TC_FAIL;
}
dev = device_get_binding("fake_ieee802154");
if (!dev) {
TC_ERROR("*** Could not get fake device\n");
return TC_FAIL;
}
iface = net_if_lookup_by_dev(dev);
if (!iface) {
TC_ERROR("*** Could not get fake iface\n");
return TC_FAIL;
}
TC_PRINT("Fake IEEE 802.15.4 network interface ready\n");
ieee_addr_hexdump(iface->link_addr.addr, 8);
return TC_PASS;
}
void main(void)
{
int status = TC_FAIL;
TC_PRINT("Starting ieee802154 stack test\n");
if (initialize_test_environment() != TC_PASS) {
goto end;
}
if (test_packet_parsing(&test_ns_pkt) != TC_PASS) {
goto end;
}
if (test_ns_sending(&test_ns_pkt) != TC_PASS) {
goto end;
}
if (test_packet_parsing(&test_ack_pkt) != TC_PASS) {
goto end;
}
if (test_ack_reply(&test_ack_pkt) != TC_PASS) {
goto end;
}
if (test_packet_parsing(&test_beacon_pkt) != TC_PASS) {
goto end;
}
status = TC_PASS;
end:
TC_END_RESULT(status);
TC_END_REPORT(status);
}