You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

358 lines
12 KiB

/*
* Copyright (C) 2016 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
*
* @file
* @brief Show case application for netdev_test
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*
* @}
*/
#include <stdio.h>
#include "msg.h"
#include "net/ethernet.h"
#include "net/gnrc.h"
#include "net/gnrc/netdev/eth.h"
#include "net/netdev_test.h"
#include "od.h"
#include "thread.h"
#include "utlist.h"
#define _EXP_LENGTH (64)
#define _MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT + THREAD_EXTRA_STACKSIZE_PRINTF)
#define _MAC_PRIO (THREAD_PRIORITY_MAIN - 4)
#define _MAIN_MSG_QUEUE_SIZE (2)
#define _TEST_PAYLOAD1 "gO3Xt,fP)6* MR161Auk?W^mTb\"LmY^Qc5w1h:C<+n(*/@4k("
#define _TEST_PAYLOAD2 "*b/'XKkraEBexaU\\O-X&<Bl'n%35Ll+nDy,jQ+[Oe4:9( 4cI"
#define EXECUTE(test) \
puts("Executing " # test "()"); \
if (!test()) { \
puts(" + failed."); \
return 1; \
} \
else { \
puts(" + succeeded."); \
}
static uint8_t _dev_addr[] = { 0x6c, 0x5d, 0xff, 0x73, 0x84, 0x6f };
static const uint8_t _test_dst[] = { 0xf5, 0x19, 0x9a, 0x1d, 0xd8, 0x8f };
static const uint8_t _test_src[] = { 0x41, 0x9b, 0x9f, 0x56, 0x36, 0x46 };
static char _mac_stack[_MAC_STACKSIZE];
static gnrc_netdev_t _gnrc_dev;
static netdev_test_t _dev;
static msg_t _main_msg_queue[_MAIN_MSG_QUEUE_SIZE];
static uint8_t _tmp[_EXP_LENGTH];
static kernel_pid_t _mac_pid;
static uint8_t _tmp_len = 0;
static void _dev_isr(netdev_t *dev);
static int _dev_recv(netdev_t *dev, char *buf, int len, void *info);
static int _dev_send(netdev_t *dev, const struct iovec *vector, int count);
static int _dev_get_addr(netdev_t *dev, void *value, size_t max_len);
static int _dev_set_addr(netdev_t *dev, void *value, size_t max_len);
/* tests getter */
static int test_get_addr(void)
{
uint8_t tmp[sizeof(_dev_addr)];
if (gnrc_netapi_get(_mac_pid, NETOPT_ADDRESS, 0, tmp, sizeof(tmp)) != sizeof(_dev_addr)) {
puts("Error getting device address");
return 0;
}
else if (memcmp(tmp, _dev_addr, sizeof(_dev_addr)) != 0) {
puts("Got wrong device address");
return 0;
}
return 1;
}
/* tests sending */
static int test_send(void)
{
ethernet_hdr_t *exp_mac = (ethernet_hdr_t *)_tmp;
uint8_t *exp_payload = _tmp + sizeof(ethernet_hdr_t);
gnrc_pktsnip_t *pkt, *hdr;
msg_t msg;
/* prepare packet for sending */
pkt = gnrc_pktbuf_add(NULL, _TEST_PAYLOAD1, sizeof(_TEST_PAYLOAD1) - 1,
GNRC_NETTYPE_UNDEF);
if (pkt == NULL) {
puts("Could not allocate send payload");
return 0;
}
hdr = gnrc_netif_hdr_build(NULL, 0, (uint8_t *)_test_dst, sizeof(_test_dst));
if (hdr == NULL) {
gnrc_pktbuf_release(pkt);
puts("Could not allocate send header");
return 0;
}
LL_PREPEND(pkt, hdr);
/* prepare expected data */
memcpy(exp_mac->dst, _test_dst, sizeof(_test_dst));
memcpy(exp_mac->src, _dev_addr, sizeof(_dev_addr));
exp_mac->type = byteorder_htons(ETHERTYPE_UNKNOWN);
memcpy(exp_payload, _TEST_PAYLOAD1, sizeof(_TEST_PAYLOAD1) - 1);
_tmp_len = sizeof(_TEST_PAYLOAD1) + sizeof(ethernet_hdr_t) - 1;
/* register for returned packet status */
if (gnrc_neterr_reg(pkt) != 0) {
puts("Can not register for error reporting");
return 0;
}
/* send packet to MAC layer */
gnrc_netapi_send(_mac_pid, pkt);
/* wait for packet status and check */
msg_receive(&msg);
if ((msg.type != GNRC_NETERR_MSG_TYPE) ||
(msg.content.value != GNRC_NETERR_SUCCESS)) {
puts("Error sending packet");
return 0;
}
return 1;
}
/* tests receiving */
static int test_receive(void)
{
ethernet_hdr_t *rcv_mac = (ethernet_hdr_t *)_tmp;
uint8_t *rcv_payload = _tmp + sizeof(ethernet_hdr_t);
gnrc_pktsnip_t *pkt, *hdr;
gnrc_netreg_entry_t me = GNRC_NETREG_ENTRY_INIT_PID(GNRC_NETREG_DEMUX_CTX_ALL,
sched_active_pid);
msg_t msg;
if (_dev.netdev.event_callback == NULL) {
puts("Device's event_callback not set");
return 0;
}
/* prepare receive buffer */
memcpy(rcv_mac->dst, _dev_addr, sizeof(_dev_addr));
memcpy(rcv_mac->src, _test_src, sizeof(_test_src));
/* no gnrc_ipv6 in compile unit => ETHERTYPE_IPV6 translates to
* GNRC_NETTYPE_UNDEF */
rcv_mac->type = byteorder_htons(ETHERTYPE_IPV6);
memcpy(rcv_payload, _TEST_PAYLOAD2, sizeof(_TEST_PAYLOAD2) - 1);
_tmp_len = sizeof(_TEST_PAYLOAD2) + sizeof(ethernet_hdr_t) - 1;
/* register for GNRC_NETTYPE_UNDEF */
gnrc_netreg_register(GNRC_NETTYPE_UNDEF, &me);
/* fire ISR event */
_dev.netdev.event_callback((netdev_t *)&_dev.netdev, NETDEV_EVENT_ISR);
/* wait for packet from MAC layer*/
msg_receive(&msg);
/* check message */
if (msg.sender_pid != _mac_pid) {
puts("Unexpected sender of netapi receive message");
return 0;
}
if (msg.type != GNRC_NETAPI_MSG_TYPE_RCV) {
puts("Expected netapi receive message");
return 0;
}
pkt = msg.content.ptr;
/* check payload */
if (pkt->size != _tmp_len - sizeof(ethernet_hdr_t)) {
puts("Payload of unexpected size");
}
if ((pkt->type != GNRC_NETTYPE_UNDEF) ||
(memcmp(pkt->data, _TEST_PAYLOAD2, pkt->size) != 0)) {
puts("Unexpected payload");
puts("===========================================================");
puts("expected");
puts("===========================================================");
od_hex_dump(_TEST_PAYLOAD2, pkt->size, OD_WIDTH_DEFAULT);
puts("===========================================================");
puts("send data");
puts("===========================================================");
od_hex_dump(pkt->data, pkt->size, OD_WIDTH_DEFAULT);
return 0;
}
hdr = pkt->next;
/* check netif header */
if ((hdr->type != GNRC_NETTYPE_NETIF) || (hdr->next != NULL) ||
(hdr->size) != (sizeof(gnrc_netif_hdr_t) + (2 * ETHERNET_ADDR_LEN))) {
puts("Malformed header received");
return 0;
}
if (memcmp(gnrc_netif_hdr_get_src_addr(hdr->data), _test_src,
ETHERNET_ADDR_LEN) != 0) {
char addr_str[ETHERNET_ADDR_LEN * 3];
puts("Unexpected source received");
puts("=================");
puts("expected");
puts("=================");
puts(gnrc_netif_addr_to_str(addr_str, sizeof(addr_str),
_test_src,
ETHERNET_ADDR_LEN));
puts("=================");
puts("received source");
puts("=================");
puts(gnrc_netif_addr_to_str(addr_str, sizeof(addr_str),
gnrc_netif_hdr_get_src_addr(hdr->data),
ETHERNET_ADDR_LEN));
return 0;
}
if (memcmp(gnrc_netif_hdr_get_dst_addr(hdr->data), _dev_addr,
ETHERNET_ADDR_LEN) != 0) {
char addr_str[ETHERNET_ADDR_LEN * 3];
puts("Unexpected destination received");
puts("=================");
puts("expected");
puts("=================");
puts(gnrc_netif_addr_to_str(addr_str, sizeof(addr_str),
_dev_addr,
ETHERNET_ADDR_LEN));
puts("====================");
puts("received destination");
puts("====================");
puts(gnrc_netif_addr_to_str(addr_str, sizeof(addr_str),
gnrc_netif_hdr_get_dst_addr(hdr->data),
ETHERNET_ADDR_LEN));
return 0;
}
gnrc_pktbuf_release(pkt);
gnrc_netreg_unregister(GNRC_NETTYPE_UNDEF, &me);
return 1;
}
static int test_set_addr(void)
{
static const uint8_t new_addr[] = { 0x71, 0x29, 0x5b, 0xc8, 0x52, 0x65 };
uint8_t tmp[sizeof(new_addr)];
if (gnrc_netapi_set(_mac_pid, NETOPT_ADDRESS, 0, (void *)new_addr,
sizeof(new_addr)) != sizeof(new_addr)) {
puts("Error setting device address");
return 0;
}
if (gnrc_netapi_get(_mac_pid, NETOPT_ADDRESS, 0, tmp,
sizeof(tmp)) != sizeof(tmp)) {
puts("Error setting device address");
return 0;
}
else if (memcmp(tmp, new_addr, sizeof(new_addr)) != 0) {
puts("Set to wrong device address");
return 0;
}
return 1;
}
int main(void)
{
/* initialization */
gnrc_pktbuf_init();
msg_init_queue(_main_msg_queue, _MAIN_MSG_QUEUE_SIZE);
netdev_test_setup(&_dev, NULL);
netdev_test_set_isr_cb(&_dev, _dev_isr);
netdev_test_set_recv_cb(&_dev, _dev_recv);
netdev_test_set_send_cb(&_dev, _dev_send);
netdev_test_set_get_cb(&_dev, NETOPT_ADDRESS, _dev_get_addr);
netdev_test_set_set_cb(&_dev, NETOPT_ADDRESS, _dev_set_addr);
gnrc_netdev_eth_init(&_gnrc_dev, (netdev_t *)(&_dev));
_mac_pid = gnrc_netdev_init(_mac_stack, _MAC_STACKSIZE, _MAC_PRIO,
"gnrc_netdev_eth_test", &_gnrc_dev);
if (_mac_pid <= KERNEL_PID_UNDEF) {
puts("Could not start MAC thread\n");
return 1;
}
/* test execution */
EXECUTE(test_get_addr);
EXECUTE(test_send);
EXECUTE(test_receive);
EXECUTE(test_set_addr);
puts("ALL TESTS SUCCESSFUL");
return 0;
}
/* netdev_test callbacks */
static void _dev_isr(netdev_t *dev)
{
(void)dev;
if (dev->event_callback) {
dev->event_callback(dev, NETDEV_EVENT_RX_COMPLETE);
}
}
static int _dev_recv(netdev_t *dev, char *buf, int len, void *info)
{
(void)dev;
(void)info;
if (buf == NULL) {
return _tmp_len;
}
else if (len < _tmp_len) {
return -ENOBUFS;
}
else {
memcpy(buf, _tmp, _tmp_len);
return _tmp_len;
}
}
static int _dev_send(netdev_t *dev, const struct iovec *vector, int count)
{
int idx = 0;
(void)dev;
/* check packet content with expected data */
for (int i = 0; i < count; i++) {
if (memcmp(&(_tmp[idx]), vector[i].iov_base, vector[i].iov_len) != 0) {
printf("Unexpected send data (vector index = %d)\n", i);
puts("===========================================================");
puts("expected");
puts("===========================================================");
od_hex_dump(&_tmp[idx], vector[i].iov_len, OD_WIDTH_DEFAULT);
puts("===========================================================");
puts("send data");
puts("===========================================================");
od_hex_dump(vector[i].iov_base, vector[i].iov_len, OD_WIDTH_DEFAULT);
return -EINVAL;
}
idx += vector[i].iov_len;
}
if (idx != _tmp_len) {
printf("Unexpected send length: %d (expected: %d)\n", idx, _tmp_len);
return -EINVAL;
}
return idx;
}
static int _dev_get_addr(netdev_t *dev, void *value, size_t max_len)
{
(void)dev;
if (max_len < sizeof(_dev_addr)) {
return -ENOBUFS;
}
memcpy(value, _dev_addr, sizeof(_dev_addr));
return sizeof(_dev_addr);
}
static int _dev_set_addr(netdev_t *dev, void *value, size_t value_len)
{
(void)dev;
if (value_len != sizeof(_dev_addr)) {
return -EOVERFLOW;
}
memcpy(_dev_addr, value, sizeof(_dev_addr));
return sizeof(_dev_addr);
}