Skip to content

netdev: iolist not checked for empty elements on send #11163

@miri64

Description

@miri64

Description

It is not possible to send an UDP packet with an empty payload via an at86rf2xx-shipping board (considering #11161 is merged), as an assertion in the device driver is hit. I was able to find the same problem in cc2420 but did not check any more devices.

Edit: the discussion came to the conclusion that (3) should be implemented (see Tracking list)

I am raising this issue instead of fixing it, since I'm not sure where to fix it exactly, as I see three possible solutions. The assert (see "Actual results" section) itself is correct, so the deepest level to fix this would be to add a check for len in at86rf2xx_sram_write() (1).

void at86rf2xx_sram_write(const at86rf2xx_t *dev, uint8_t offset,
const uint8_t *data, size_t len)
{
uint8_t reg = (AT86RF2XX_ACCESS_SRAM | AT86RF2XX_ACCESS_WRITE);
getbus(dev);
spi_transfer_byte(SPIDEV, CSPIN, true, reg);
spi_transfer_byte(SPIDEV, CSPIN, true, offset);
spi_transfer_bytes(SPIDEV, CSPIN, false, data, NULL, len);
spi_release(SPIDEV);
}

or at86rf2xx_tx_load() (2) if we just want to solve this for sending specifically by checking there for len

size_t at86rf2xx_tx_load(at86rf2xx_t *dev, const uint8_t *data,
size_t len, size_t offset)
{
dev->tx_frame_len += (uint8_t)len;
at86rf2xx_sram_write(dev, offset + 1, data, len);
return offset + len;
}

However, one typically knows what they are doing when they are sending with the device driver directly, so maybe we rather want to fix the netdev interface handling of the device(s) by checking in this loop for iol->iol_len == 0 (3).

for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
/* current packet data + FCS too long */
if ((len + iol->iol_len + 2) > AT86RF2XX_MAX_PKT_LENGTH) {
DEBUG("[at86rf2xx] error: packet too large (%u byte) to be send\n",
(unsigned)len + 2);
return -EOVERFLOW;
}
len = at86rf2xx_tx_load(dev, iol->iol_base, iol->iol_len, len);
}

Lastly, we could just fix it in GNRC, which would be the least intrusive fix, as we only need to fix the gnrc_pktsnip_t to iolist_t conversion instead of checking all device drivers somewhere here (4)

/* prepare iolist for netdev / mac layer */
iolist_t iolist = {
.iol_next = (iolist_t *)pkt->next,
.iol_base = mhr,
.iol_len = (size_t)res
};
#ifdef MODULE_NETSTATS_L2
if (netif_hdr->flags &
(GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) {
netif->stats.tx_mcast_count++;
}
else {
netif->stats.tx_unicast_count++;
}
#endif
#ifdef MODULE_GNRC_MAC
if (netif->mac.mac_info & GNRC_NETIF_MAC_INFO_CSMA_ENABLED) {
res = csma_sender_csma_ca_send(dev, &iolist, &netif->mac.csma_conf);
}
else {
res = dev->driver->send(dev, &iolist);
}
#else
res = dev->driver->send(dev, &iolist);
#endif

(which would however remove the advantage of mapping the gnrc_pktsnip_t list directly to iolist_t).

Steps to reproduce the issue

Merge #11161 and (was merged) try to send a UDP packet with empty payload using gnrc_networking on samr21-xpro (with other boards the actual result might differ):

udp send ff02::1 1337 ""

Expected results

The packet is sent and can be received by another radio (or sniffed with a sniffer).

Actual results

The node aborts on a failed assertion in this line

assert(out || in);

Versions

Current master (4af3548) with #11161 merged.

Tracking

To implement (3) and close this issue the following tasks need to be completed:

Metadata

Metadata

Labels

Area: driversArea: Device driversArea: networkArea: NetworkingType: bugThe issue reports a bug / The PR fixes a bug (including spelling errors)Type: trackingThe issue tracks and organizes the sub-tasks of a larger effort

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions