-
Notifications
You must be signed in to change notification settings - Fork 2k
/
gnrc_netif_raw.c
130 lines (111 loc) · 3.48 KB
/
gnrc_netif_raw.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
* 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 <m.lenders@fu-berlin.de>
*/
#include "net/gnrc/pktbuf.h"
#include "net/gnrc/netif/hdr.h"
#include "net/gnrc/netif/raw.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#define IP_VERSION_MASK (0xf0U)
#define IP_VERSION4 (0x40U)
#define IP_VERSION6 (0x60U)
static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt);
static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif);
static const gnrc_netif_ops_t raw_ops = {
.init = gnrc_netif_default_init,
.send = _send,
.recv = _recv,
.get = gnrc_netif_get_from_netdev,
.set = gnrc_netif_set_from_netdev,
};
int gnrc_netif_raw_create(gnrc_netif_t *netif, char *stack, int stacksize,
char priority, char *name, netdev_t *dev)
{
return gnrc_netif_create(netif, stack, stacksize, priority, name, dev,
&raw_ops);
}
static inline uint8_t _get_version(uint8_t *data)
{
return (data[0] & IP_VERSION_MASK);
}
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) {
gnrc_pktsnip_t *hdr;
int nread;
pkt = gnrc_pktbuf_add(NULL, NULL, bytes_expected, GNRC_NETTYPE_UNDEF);
if (!pkt) {
DEBUG("gnrc_netif_raw: cannot allocate pktsnip.\n");
/* drop packet */
dev->driver->recv(dev, NULL, bytes_expected, NULL);
return pkt;
}
nread = dev->driver->recv(dev, pkt->data, bytes_expected, NULL);
if (nread <= 1) { /* we need at least 1 byte to identify IP version */
DEBUG("gnrc_netif_raw: read error.\n");
gnrc_pktbuf_release(pkt);
return NULL;
}
hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
if (!hdr) {
DEBUG("gnrc_netif_raw: cannot allocate pktsnip.\n");
gnrc_pktbuf_release(pkt);
return NULL;
}
gnrc_netif_hdr_set_netif(hdr->data, netif);
LL_APPEND(pkt, hdr);
#ifdef MODULE_NETSTATS_L2
netif->stats.rx_count++;
netif->stats.rx_bytes += nread;
#endif
if (nread < bytes_expected) {
/* we've got less then the expected packet size,
* so free the unused space.*/
DEBUG("gnrc_netif_raw: reallocating.\n");
gnrc_pktbuf_realloc_data(pkt, nread);
}
switch (_get_version(pkt->data)) {
#ifdef MODULE_GNRC_IPV6
case IP_VERSION6:
pkt->type = GNRC_NETTYPE_IPV6;
break;
#endif
default:
/* leave UNDEF */
break;
}
}
return pkt;
}
static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
{
int res = -ENOBUFS;
if (pkt->type == GNRC_NETTYPE_NETIF) {
/* we don't need the netif snip: remove it */
pkt = gnrc_pktbuf_remove_snip(pkt, pkt);
}
netdev_t *dev = netif->dev;
#ifdef MODULE_NETSTATS_L2
netif->stats.tx_unicast_count++;
#endif
res = dev->driver->send(dev, (iolist_t *)pkt);
if (gnrc_netif_netdev_legacy_api(netif)) {
/* only for legacy drivers we need to release pkt here */
gnrc_pktbuf_release(pkt);
}
return res;
}
/** @} */