1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/net/gnrc/netif/ethernet/gnrc_netif_ethernet.c
Martine S. Lenders 1ca05f0c08 gnrc_netif_ethernet: fix debug output for received packet
A received packet is outputted in DEBUG _after_ it was already parsed,
but with a reference to the already parsed header. The result is that
there can be some garbage in the output and the packet is not dumped in
total. As without parsing we do not have access to the header yet, we
use the `gnrc_netif_addr_to_str()` helper function instead of parsing
the destination address by hand.
2019-09-16 14:01:16 +02:00

256 lines
7.2 KiB
C

/*
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
* Copyright (C) 2017 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
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#include <string.h>
#include "net/ethernet/hdr.h"
#include "net/gnrc.h"
#include "net/gnrc/netif/ethernet.h"
#ifdef MODULE_GNRC_IPV6
#include "net/ipv6/hdr.h"
#endif
#define ENABLE_DEBUG (0)
#include "debug.h"
#if defined(MODULE_OD) && ENABLE_DEBUG
#include "od.h"
#endif
static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt);
static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif);
static char addr_str[ETHERNET_ADDR_LEN * 3];
static const gnrc_netif_ops_t ethernet_ops = {
.send = _send,
.recv = _recv,
.get = gnrc_netif_get_from_netdev,
.set = gnrc_netif_set_from_netdev,
};
gnrc_netif_t *gnrc_netif_ethernet_create(char *stack, int stacksize,
char priority, char *name,
netdev_t *dev)
{
return gnrc_netif_create(stack, stacksize, priority, name, dev,
&ethernet_ops);
}
static inline void _addr_set_broadcast(uint8_t *dst)
{
memset(dst, 0xff, ETHERNET_ADDR_LEN);
}
static inline void _addr_set_multicast(uint8_t *dst, gnrc_pktsnip_t *payload)
{
switch (payload->type) {
#ifdef MODULE_GNRC_IPV6
case GNRC_NETTYPE_IPV6:
/* https://tools.ietf.org/html/rfc2464#section-7 */
dst[0] = 0x33;
dst[1] = 0x33;
ipv6_hdr_t *ipv6 = payload->data;
memcpy(dst + 2, ipv6->dst.u8 + 12, 4);
break;
#endif
default:
_addr_set_broadcast(dst);
break;
}
}
static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
{
ethernet_hdr_t hdr;
gnrc_netif_hdr_t *netif_hdr;
gnrc_pktsnip_t *payload;
int res;
netdev_t *dev = netif->dev;
if (pkt == NULL) {
DEBUG("gnrc_netif_ethernet: pkt was NULL\n");
return -EINVAL;
}
payload = pkt->next;
if (pkt->type != GNRC_NETTYPE_NETIF) {
DEBUG("gnrc_netif_ethernet: First header was not generic netif header\n");
return -EBADMSG;
}
if (payload) {
hdr.type = byteorder_htons(gnrc_nettype_to_ethertype(payload->type));
}
else {
hdr.type = byteorder_htons(ETHERTYPE_UNKNOWN);
}
netif_hdr = pkt->data;
/* set ethernet header */
if (netif_hdr->src_l2addr_len == ETHERNET_ADDR_LEN) {
memcpy(hdr.dst, gnrc_netif_hdr_get_src_addr(netif_hdr),
netif_hdr->src_l2addr_len);
}
else {
dev->driver->get(dev, NETOPT_ADDRESS, hdr.src, ETHERNET_ADDR_LEN);
}
if (netif_hdr->flags & GNRC_NETIF_HDR_FLAGS_BROADCAST) {
_addr_set_broadcast(hdr.dst);
}
else if (netif_hdr->flags & GNRC_NETIF_HDR_FLAGS_MULTICAST) {
if (payload == NULL) {
DEBUG("gnrc_netif_ethernet: empty multicast packets over Ethernet "
"are not yet supported\n");
return -ENOTSUP;
}
_addr_set_multicast(hdr.dst, payload);
}
else if (netif_hdr->dst_l2addr_len == ETHERNET_ADDR_LEN) {
memcpy(hdr.dst, gnrc_netif_hdr_get_dst_addr(netif_hdr),
ETHERNET_ADDR_LEN);
}
else {
DEBUG("gnrc_netif_ethernet: destination address had unexpected "
"format\n");
return -EBADMSG;
}
DEBUG("gnrc_netif_ethernet: send to %02x:%02x:%02x:%02x:%02x:%02x\n",
hdr.dst[0], hdr.dst[1], hdr.dst[2],
hdr.dst[3], hdr.dst[4], hdr.dst[5]);
iolist_t iolist = {
.iol_next = (iolist_t *)payload,
.iol_base = &hdr,
.iol_len = sizeof(ethernet_hdr_t)
};
#ifdef MODULE_NETSTATS_L2
if ((netif_hdr->flags & GNRC_NETIF_HDR_FLAGS_BROADCAST) ||
(netif_hdr->flags & GNRC_NETIF_HDR_FLAGS_MULTICAST)) {
netif->stats.tx_mcast_count++;
}
else {
netif->stats.tx_unicast_count++;
}
#endif
res = dev->driver->send(dev, &iolist);
gnrc_pktbuf_release(pkt);
return res;
}
static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif)
{
netdev_t *dev = netif->dev;
int bytes_expected = dev->driver->recv(dev, NULL, 0, NULL);
gnrc_pktsnip_t *pkt = NULL;
if (bytes_expected > 0) {
pkt = gnrc_pktbuf_add(NULL, NULL,
bytes_expected,
GNRC_NETTYPE_UNDEF);
if (!pkt) {
DEBUG("gnrc_netif_ethernet: cannot allocate pktsnip.\n");
/* drop the packet */
dev->driver->recv(dev, NULL, bytes_expected, NULL);
goto out;
}
int nread = dev->driver->recv(dev, pkt->data, bytes_expected, NULL);
if (nread <= 0) {
DEBUG("gnrc_netif_ethernet: read error.\n");
goto safe_out;
}
#ifdef MODULE_NETSTATS_L2
netif->stats.rx_count++;
netif->stats.rx_bytes += nread;
#endif
if (nread < bytes_expected) {
/* we've got less than the expected packet size,
* so free the unused space.*/
DEBUG("gnrc_netif_ethernet: reallocating.\n");
gnrc_pktbuf_realloc_data(pkt, nread);
}
DEBUG("gnrc_netif_ethernet: received packet from %s of length %d\n",
gnrc_netif_addr_to_str(pkt->data, ETHERNET_ADDR_LEN, addr_str),
nread);
#if defined(MODULE_OD) && ENABLE_DEBUG
od_hex_dump(pkt->data, nread, OD_WIDTH_DEFAULT);
#endif
/* mark ethernet header */
gnrc_pktsnip_t *eth_hdr = gnrc_pktbuf_mark(pkt, sizeof(ethernet_hdr_t), GNRC_NETTYPE_UNDEF);
if (!eth_hdr) {
DEBUG("gnrc_netif_ethernet: no space left in packet buffer\n");
goto safe_out;
}
ethernet_hdr_t *hdr = (ethernet_hdr_t *)eth_hdr->data;
#ifdef MODULE_L2FILTER
if (!l2filter_pass(dev->filter, hdr->src, ETHERNET_ADDR_LEN)) {
DEBUG("gnrc_netif_ethernet: incoming packet filtered by l2filter\n");
goto safe_out;
}
#endif
/* set payload type from ethertype */
pkt->type = gnrc_nettype_from_ethertype(byteorder_ntohs(hdr->type));
/* create netif header */
gnrc_pktsnip_t *netif_hdr;
netif_hdr = gnrc_pktbuf_add(NULL, NULL,
sizeof(gnrc_netif_hdr_t) + (2 * ETHERNET_ADDR_LEN),
GNRC_NETTYPE_NETIF);
if (netif_hdr == NULL) {
DEBUG("gnrc_netif_ethernet: no space left in packet buffer\n");
pkt = eth_hdr;
goto safe_out;
}
gnrc_netif_hdr_init(netif_hdr->data, ETHERNET_ADDR_LEN, ETHERNET_ADDR_LEN);
gnrc_netif_hdr_set_src_addr(netif_hdr->data, hdr->src, ETHERNET_ADDR_LEN);
gnrc_netif_hdr_set_dst_addr(netif_hdr->data, hdr->dst, ETHERNET_ADDR_LEN);
gnrc_netif_hdr_set_netif(netif_hdr->data, netif);
gnrc_pktbuf_remove_snip(pkt, eth_hdr);
LL_APPEND(pkt, netif_hdr);
}
out:
return pkt;
safe_out:
gnrc_pktbuf_release(pkt);
return NULL;
}
/** @} */