diff --git a/cpu/native/netdev2_tap/netdev2_tap.c b/cpu/native/netdev2_tap/netdev2_tap.c index d7213cbc23..b12631af57 100644 --- a/cpu/native/netdev2_tap/netdev2_tap.c +++ b/cpu/native/netdev2_tap/netdev2_tap.c @@ -184,12 +184,58 @@ static inline bool _is_addr_multicast(uint8_t *addr) return (addr[0] & 0x01); } +static void _continue_reading(netdev2_tap_t *dev) +{ + /* work around lost signals */ + fd_set rfds; + struct timeval t; + memset(&t, 0, sizeof(t)); + FD_ZERO(&rfds); + FD_SET(dev->tap_fd, &rfds); + + _native_in_syscall++; /* no switching here */ + + if (real_select(dev->tap_fd + 1, &rfds, NULL, NULL, &t) == 1) { + int sig = SIGIO; + extern int _sig_pipefd[2]; + extern ssize_t (*real_write)(int fd, const void * buf, size_t count); + real_write(_sig_pipefd[1], &sig, sizeof(int)); + _native_sigpend++; + DEBUG("netdev2_tap: sigpend++\n"); + } + else { + DEBUG("netdev2_tap: native_async_read_continue\n"); + native_async_read_continue(dev->tap_fd); + } + + _native_in_syscall--; +} + static int _recv(netdev2_t *netdev2, char *buf, int len, void *info) { netdev2_tap_t *dev = (netdev2_tap_t*)netdev2; (void)info; if (!buf) { + if (len > 0) { + /* no memory available in pktbuf, discarding the frame */ + DEBUG("netdev2_tap: discarding the frame\n"); + + /* repeating `real_read` for small size on tap device results in + * freeze for some reason. Using a large buffer for now. */ + /* + uint8_t buf[4]; + while (real_read(dev->tap_fd, buf, sizeof(buf)) > 0) { + } + */ + + static uint8_t buf[ETHERNET_FRAME_LEN]; + + real_read(dev->tap_fd, buf, sizeof(buf)); + + _continue_reading(dev); + } + /* no way of figuring out packet size without racey buffering, * so we return the maximum possible size */ return ETHERNET_FRAME_LEN; @@ -212,28 +258,8 @@ static int _recv(netdev2_t *netdev2, char *buf, int len, void *info) return 0; } - /* work around lost signals */ - fd_set rfds; - struct timeval t; - memset(&t, 0, sizeof(t)); - FD_ZERO(&rfds); - FD_SET(dev->tap_fd, &rfds); - _native_in_syscall++; /* no switching here */ - - if (real_select(dev->tap_fd + 1, &rfds, NULL, NULL, &t) == 1) { - int sig = SIGIO; - extern int _sig_pipefd[2]; - extern ssize_t (*real_write)(int fd, const void * buf, size_t count); - real_write(_sig_pipefd[1], &sig, sizeof(int)); - _native_sigpend++; - DEBUG("netdev2_tap: sigpend++\n"); - } - else { - native_async_read_continue(dev->tap_fd); - } - - _native_in_syscall--; + _continue_reading(dev); #ifdef MODULE_NETSTATS_L2 netdev2->stats.rx_count++; @@ -317,7 +343,7 @@ static int _init(netdev2_t *netdev) /* initialize device descriptor */ dev->promiscous = 0; /* implicitly create the tap interface */ - if ((dev->tap_fd = real_open(clonedev , O_RDWR)) == -1) { + if ((dev->tap_fd = real_open(clonedev, O_RDWR | O_NONBLOCK)) == -1) { err(EXIT_FAILURE, "open(%s)", clonedev); } #if (defined(__MACH__) || defined(__FreeBSD__)) /* OSX/FreeBSD */ diff --git a/drivers/include/net/netdev2.h b/drivers/include/net/netdev2.h index 6b9238c8e8..18b6d3e56b 100644 --- a/drivers/include/net/netdev2.h +++ b/drivers/include/net/netdev2.h @@ -135,6 +135,9 @@ typedef struct netdev2_driver { * * Supposed to be called from netdev2_event_handler(). * + * If buf == NULL and len == 0, returns the packet size without dropping it. + * If buf == NULL and len > 0, drops the packet and returns the packet size. + * * @param[in] dev network device descriptor * @param[out] buf buffer to write into or NULL * @param[in] len maximum nr. of bytes to read diff --git a/sys/net/gnrc/link_layer/netdev2/gnrc_netdev2_eth.c b/sys/net/gnrc/link_layer/netdev2/gnrc_netdev2_eth.c index eab49221d9..bf7b0dd720 100644 --- a/sys/net/gnrc/link_layer/netdev2/gnrc_netdev2_eth.c +++ b/sys/net/gnrc/link_layer/netdev2/gnrc_netdev2_eth.c @@ -42,6 +42,10 @@ static gnrc_pktsnip_t *_recv(gnrc_netdev2_t *gnrc_netdev2) if(!pkt) { DEBUG("_recv_ethernet_packet: cannot allocate pktsnip.\n"); + + /* drop the packet */ + dev->driver->recv(dev, NULL, bytes_expected, NULL); + goto out; }