From ea3edef5c7f6704dcf1ca270aca87ccd503024f6 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Fri, 16 Nov 2018 12:40:10 +0100 Subject: [PATCH 1/2] drivers/w5100: Added missing drop implementation The netdev_driver_t::recv implementation of the w5100 does not provide the drop feature. This commit adds it. Fixes: https://github.com/RIOT-OS/RIOT/issues/10410 --- drivers/w5100/w5100.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/w5100/w5100.c b/drivers/w5100/w5100.c index aec5ec2598..2d29e9456e 100644 --- a/drivers/w5100/w5100.c +++ b/drivers/w5100/w5100.c @@ -261,7 +261,10 @@ static int recv(netdev_t *netdev, void *buf, size_t len, void *info) DEBUG("[w5100] recv: read %i byte from device (at 0x%04x)\n", n, (int)rp); + } + /* if frame received OR drop requested, remove frame from RX buffer */ + if (len > 0) { /* set the new read pointer address */ waddr(dev, S0_RX_RD0, S0_RX_RD1, rp += psize); wreg(dev, S0_CR, CR_RECV); From a81d39494fd527ae928e698348f1b666bdfa73d8 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Wed, 21 Nov 2018 10:33:23 +0100 Subject: [PATCH 2/2] drivers/w5100: Fix recv() with too small buffer If netdev_driver_t::recv() is called and the provided buffer is smaller than the frame then `-ENOBUFS` should be returned, the frame should be dropped, and no data of the frame should be returned. Addresses: https://github.com/RIOT-OS/RIOT/issues/10413 --- drivers/w5100/w5100.c | 44 +++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/drivers/w5100/w5100.c b/drivers/w5100/w5100.c index 2d29e9456e..ed27e94b3c 100644 --- a/drivers/w5100/w5100.c +++ b/drivers/w5100/w5100.c @@ -18,6 +18,7 @@ * @} */ +#include #include #include @@ -230,12 +231,24 @@ static int send(netdev_t *netdev, const iolist_t *iolist) return sum; } -static int recv(netdev_t *netdev, void *buf, size_t len, void *info) +static inline void drop(w5100_t *dev, uint16_t num, uint16_t rp, uint16_t psize) +{ + /* set the new read pointer address */ + waddr(dev, S0_RX_RD0, S0_RX_RD1, rp + psize); + wreg(dev, S0_CR, CR_RECV); + + /* if RX buffer now empty, clear RECV interrupt flag */ + if ((num - psize) == 0) { + wreg(dev, S0_IR, IR_RECV); + } +} + +static int recv(netdev_t *netdev, void *buf, size_t max_len, void *info) { (void)info; w5100_t *dev = (w5100_t *)netdev; uint8_t *in_buf = (uint8_t *)buf; - unsigned n = 0; + unsigned len = 0; /* get access to the SPI bus for the duration of this function */ spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk); @@ -247,39 +260,38 @@ static int recv(netdev_t *netdev, void *buf, size_t len, void *info) uint16_t rp = raddr(dev, S0_RX_RD0, S0_RX_RD1); uint16_t psize = raddr(dev, (S0_RX_BASE + (rp & S0_MASK)), (S0_RX_BASE + ((rp + 1) & S0_MASK))); - n = psize - 2; + len = psize - 2; - DEBUG("[w5100] recv: got packet of %i byte (at 0x%04x)\n", n, (int)rp); + DEBUG("[w5100] recv: got packet of %i byte (at 0x%04x)\n", len, (int)rp); /* read the actual data into the given buffer if wanted */ if (in_buf != NULL) { + /* Is provided buffer big enough? */ + if (len > max_len) { + drop(dev, num, rp, psize); + spi_release(dev->p.spi); + return -ENOBUFS; + } uint16_t pos = rp + 2; - len = (n <= len) ? n : len; + for (unsigned i = 0; i < len; i++) { in_buf[i] = rreg(dev, (S0_RX_BASE + ((pos++) & S0_MASK))); } DEBUG("[w5100] recv: read %i byte from device (at 0x%04x)\n", - n, (int)rp); + len, (int)rp); } /* if frame received OR drop requested, remove frame from RX buffer */ - if (len > 0) { - /* set the new read pointer address */ - waddr(dev, S0_RX_RD0, S0_RX_RD1, rp += psize); - wreg(dev, S0_CR, CR_RECV); - - /* if RX buffer now empty, clear RECV interrupt flag */ - if ((num - psize) == 0) { - wreg(dev, S0_IR, IR_RECV); - } + if (max_len > 0) { + drop(dev, num, rp, psize); } } /* release the SPI bus again */ spi_release(dev->p.spi); - return (int)n; + return (int)len; } static void isr(netdev_t *netdev)