diff --git a/drivers/net/netdev_upperhalf.c b/drivers/net/netdev_upperhalf.c index a9f32cd93af..e2cede4d474 100644 --- a/drivers/net/netdev_upperhalf.c +++ b/drivers/net/netdev_upperhalf.c @@ -1290,12 +1290,17 @@ FAR uint8_t *netpkt_getbase(FAR netpkt_t *pkt) * pkt - The net packet * len - The length of data in netpkt * + * Returned Value: + * The new effective data length, or a negated errno value on error. + * ****************************************************************************/ -void netpkt_setdatalen(FAR struct netdev_lowerhalf_s *dev, - FAR netpkt_t *pkt, unsigned int len) +int netpkt_setdatalen(FAR struct netdev_lowerhalf_s *dev, + FAR netpkt_t *pkt, unsigned int len) { - iob_update_pktlen(pkt, len - NET_LL_HDRLEN(&dev->netdev)); + uint8_t llhdrlen = NET_LL_HDRLEN(&dev->netdev); + int ret = iob_update_pktlen(pkt, len - llhdrlen, false); + return ret >= 0 ? ret + llhdrlen : ret; } /**************************************************************************** diff --git a/include/nuttx/mm/iob.h b/include/nuttx/mm/iob.h index 326597753cc..704d9d7bc20 100644 --- a/include/nuttx/mm/iob.h +++ b/include/nuttx/mm/iob.h @@ -571,14 +571,16 @@ void iob_reserve(FAR struct iob_s *iob, unsigned int reserved); * * Description: * This function will update packet length of the iob, it will be - * trimmed if the length of the iob chain is greater than the current - * length. - * This function will not grow the iob link, any grow operation should - * be implemented through iob_copyin()/iob_trycopyin(). + * trimmed if the current length of the iob chain is greater than the + * new length, and will be grown if less than new length. + * + * Returned Value: + * The new effective iob packet length, or a negated errno value on error. * ****************************************************************************/ -void iob_update_pktlen(FAR struct iob_s *iob, unsigned int pktlen); +int iob_update_pktlen(FAR struct iob_s *iob, unsigned int pktlen, + bool throttled); /**************************************************************************** * Name: iob_count diff --git a/include/nuttx/net/netdev_lowerhalf.h b/include/nuttx/net/netdev_lowerhalf.h index 737da56a697..d47f3247398 100644 --- a/include/nuttx/net/netdev_lowerhalf.h +++ b/include/nuttx/net/netdev_lowerhalf.h @@ -422,10 +422,13 @@ FAR uint8_t *netpkt_getbase(FAR netpkt_t *pkt); * pkt - The net packet * len - The length of data in netpkt * + * Returned Value: + * The new effective data length, or a negated errno value on error. + * ****************************************************************************/ -void netpkt_setdatalen(FAR struct netdev_lowerhalf_s *dev, - FAR netpkt_t *pkt, unsigned int len); +int netpkt_setdatalen(FAR struct netdev_lowerhalf_s *dev, + FAR netpkt_t *pkt, unsigned int len); /**************************************************************************** * Name: netpkt_getdatalen diff --git a/mm/iob/iob_update_pktlen.c b/mm/iob/iob_update_pktlen.c index 3d1e9eafa9e..e6e1fd46e32 100644 --- a/mm/iob/iob_update_pktlen.c +++ b/mm/iob/iob_update_pktlen.c @@ -36,14 +36,16 @@ * * Description: * This function will update packet length of the iob, it will be - * trimmed if the length of the iob chain is greater than the current - * length. - * This function will not grow the iob link, any grow operation should - * be implemented through iob_copyin()/iob_trycopyin(). + * trimmed if the current length of the iob chain is greater than the + * new length, and will be grown if less than new length. + * + * Returned Value: + * The new effective iob packet length, or a negated errno value on error. * ****************************************************************************/ -void iob_update_pktlen(FAR struct iob_s *iob, unsigned int pktlen) +int iob_update_pktlen(FAR struct iob_s *iob, unsigned int pktlen, + bool throttled) { FAR struct iob_s *penultimate; FAR struct iob_s *next; @@ -56,7 +58,7 @@ void iob_update_pktlen(FAR struct iob_s *iob, unsigned int pktlen) if (iob == NULL) { - return; + return -EINVAL; } /* Calculate the total entries of the data in the I/O buffer chain */ @@ -66,7 +68,8 @@ void iob_update_pktlen(FAR struct iob_s *iob, unsigned int pktlen) { ninqueue++; offset += next->io_offset; - next = next->io_flink; + penultimate = next; + next = next->io_flink; } /* Trim inqueue entries if needed */ @@ -104,6 +107,21 @@ void iob_update_pktlen(FAR struct iob_s *iob, unsigned int pktlen) } } } + else if (nrequire > ninqueue) + { + /* Start from the last IOB */ + + next = penultimate; + + /* Loop to extend the link */ + + while (next != NULL && nrequire > ninqueue) + { + next->io_flink = iob_tryalloc(throttled); + next = next->io_flink; + ninqueue++; + } + } iob->io_pktlen = pktlen; @@ -125,4 +143,10 @@ void iob_update_pktlen(FAR struct iob_s *iob, unsigned int pktlen) pktlen -= len; next = next->io_flink; } + + /* Adjust final pktlen if it's not fully increased (e.g. alloc fail) */ + + iob->io_pktlen -= pktlen; + + return iob->io_pktlen; } diff --git a/net/arp/arp_format.c b/net/arp/arp_format.c index 2b5db120bb3..6623b033d8e 100644 --- a/net/arp/arp_format.c +++ b/net/arp/arp_format.c @@ -109,7 +109,7 @@ void arp_format(FAR struct net_driver_s *dev, in_addr_t ipaddr) /* Update device buffer length */ - iob_update_pktlen(dev->d_iob, sizeof(struct arp_hdr_s)); + iob_update_pktlen(dev->d_iob, sizeof(struct arp_hdr_s), false); } #endif /* CONFIG_NET_ARP */ diff --git a/net/devif/devif_filesend.c b/net/devif/devif_filesend.c index a3245794c07..b6b4198df0d 100644 --- a/net/devif/devif_filesend.c +++ b/net/devif/devif_filesend.c @@ -92,7 +92,7 @@ int devif_file_send(FAR struct net_driver_s *dev, FAR struct file *file, goto errout; } - iob_update_pktlen(dev->d_iob, target_offset); + iob_update_pktlen(dev->d_iob, target_offset, false); ret = file_seek(file, offset, SEEK_SET); if (ret < 0) @@ -142,7 +142,7 @@ int devif_file_send(FAR struct net_driver_s *dev, FAR struct file *file, } } - iob_update_pktlen(dev->d_iob, target_offset + len); + iob_update_pktlen(dev->d_iob, target_offset + len, false); dev->d_sndlen = len; return len; diff --git a/net/devif/devif_poll.c b/net/devif/devif_poll.c index 45b989add05..8be17bce970 100644 --- a/net/devif/devif_poll.c +++ b/net/devif/devif_poll.c @@ -704,7 +704,7 @@ static int devif_poll_ipfrag(FAR struct net_driver_s *dev, if (!bstop && reused) { - iob_update_pktlen(dev->d_iob, 0); + iob_update_pktlen(dev->d_iob, 0, false); netdev_iob_prepare(dev, true, 0); } diff --git a/net/devif/devif_send.c b/net/devif/devif_send.c index 7ba5fd114bb..943b737bbdb 100644 --- a/net/devif/devif_send.c +++ b/net/devif/devif_send.c @@ -102,7 +102,7 @@ int devif_send(FAR struct net_driver_s *dev, FAR const void *buf, /* Prepare device buffer before poll callback */ - iob_update_pktlen(dev->d_iob, offset); + iob_update_pktlen(dev->d_iob, offset, false); ret = iob_trycopyin(dev->d_iob, buf, len, offset, false); if (ret != len) diff --git a/net/devif/ipv4_input.c b/net/devif/ipv4_input.c index 7a04d96dc23..5b8f9fc7fcb 100644 --- a/net/devif/ipv4_input.c +++ b/net/devif/ipv4_input.c @@ -207,7 +207,7 @@ static int ipv4_in(FAR struct net_driver_s *dev) totlen = (ipv4->len[0] << 8) + ipv4->len[1]; if (totlen < dev->d_len) { - iob_update_pktlen(dev->d_iob, totlen); + iob_update_pktlen(dev->d_iob, totlen, false); dev->d_len = totlen; } else if (totlen > dev->d_len) diff --git a/net/devif/ipv6_input.c b/net/devif/ipv6_input.c index 943bbc5cb47..4565261c5d4 100644 --- a/net/devif/ipv6_input.c +++ b/net/devif/ipv6_input.c @@ -256,7 +256,7 @@ static int ipv6_in(FAR struct net_driver_s *dev) if (paylen < dev->d_len) { - iob_update_pktlen(dev->d_iob, paylen); + iob_update_pktlen(dev->d_iob, paylen, false); dev->d_len = paylen; } else if (paylen > dev->d_len) diff --git a/net/icmp/icmp_reply.c b/net/icmp/icmp_reply.c index a19f556497b..5a6ca575200 100644 --- a/net/icmp/icmp_reply.c +++ b/net/icmp/icmp_reply.c @@ -133,7 +133,7 @@ void icmp_reply(FAR struct net_driver_s *dev, int type, int code) /* Skip icmp header from iob */ - iob_update_pktlen(dev->d_iob, datalen + ipicmplen); + iob_update_pktlen(dev->d_iob, datalen + ipicmplen, false); } else { @@ -167,8 +167,9 @@ void icmp_reply(FAR struct net_driver_s *dev, int type, int code) /* Skip icmp header from iob */ - iob_update_pktlen(dev->d_iob, dev->d_iob->io_pktlen + - sizeof(struct icmp_hdr_s)); + iob_update_pktlen(dev->d_iob, + dev->d_iob->io_pktlen + sizeof(struct icmp_hdr_s), + false); /* Concat new icmp packet before original datagram */ diff --git a/net/icmpv6/icmpv6_advertise.c b/net/icmpv6/icmpv6_advertise.c index 0bc2c4c5f96..583522ac1b5 100644 --- a/net/icmpv6/icmpv6_advertise.c +++ b/net/icmpv6/icmpv6_advertise.c @@ -105,7 +105,7 @@ void icmpv6_advertise(FAR struct net_driver_s *dev, /* Update device buffer length */ - iob_update_pktlen(dev->d_iob, IPv6_HDRLEN + l3size); + iob_update_pktlen(dev->d_iob, IPv6_HDRLEN + l3size, false); /* Calculate the checksum over both the ICMP header and payload */ diff --git a/net/icmpv6/icmpv6_radvertise.c b/net/icmpv6/icmpv6_radvertise.c index c9a882a9739..5b83530f531 100644 --- a/net/icmpv6/icmpv6_radvertise.c +++ b/net/icmpv6/icmpv6_radvertise.c @@ -282,7 +282,7 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev) /* Update device buffer length */ - iob_update_pktlen(dev->d_iob, IPv6_HDRLEN + l3size); + iob_update_pktlen(dev->d_iob, IPv6_HDRLEN + l3size, false); /* Calculate the checksum over both the ICMP header and payload */ diff --git a/net/icmpv6/icmpv6_reply.c b/net/icmpv6/icmpv6_reply.c index 4f20d3b2632..9aa0745983e 100644 --- a/net/icmpv6/icmpv6_reply.c +++ b/net/icmpv6/icmpv6_reply.c @@ -122,7 +122,7 @@ void icmpv6_reply(FAR struct net_driver_s *dev, int type, int code, int data) /* Skip icmp header from iob */ - iob_update_pktlen(dev->d_iob, datalen + ipicmplen); + iob_update_pktlen(dev->d_iob, datalen + ipicmplen, false); } else { @@ -156,8 +156,9 @@ void icmpv6_reply(FAR struct net_driver_s *dev, int type, int code, int data) /* Skip icmp header from iob */ - iob_update_pktlen(dev->d_iob, dev->d_iob->io_pktlen + - sizeof(struct icmpv6_hdr_s)); + iob_update_pktlen(dev->d_iob, + dev->d_iob->io_pktlen + sizeof(struct icmpv6_hdr_s), + false); /* Concat new icmp packet before original datagram */ diff --git a/net/icmpv6/icmpv6_rsolicit.c b/net/icmpv6/icmpv6_rsolicit.c index efce18ef200..40f7f024b5f 100644 --- a/net/icmpv6/icmpv6_rsolicit.c +++ b/net/icmpv6/icmpv6_rsolicit.c @@ -99,7 +99,7 @@ void icmpv6_rsolicit(FAR struct net_driver_s *dev) /* Update device buffer length */ - iob_update_pktlen(dev->d_iob, IPv6_HDRLEN + l3size); + iob_update_pktlen(dev->d_iob, IPv6_HDRLEN + l3size, false); /* Calculate the checksum over both the ICMP header and payload */ diff --git a/net/icmpv6/icmpv6_solicit.c b/net/icmpv6/icmpv6_solicit.c index 07421c9cba1..8519abd9334 100644 --- a/net/icmpv6/icmpv6_solicit.c +++ b/net/icmpv6/icmpv6_solicit.c @@ -122,7 +122,7 @@ void icmpv6_solicit(FAR struct net_driver_s *dev, /* Update device buffer length */ - iob_update_pktlen(dev->d_iob, IPv6_HDRLEN + l3size); + iob_update_pktlen(dev->d_iob, IPv6_HDRLEN + l3size, false); /* Calculate the checksum over both the ICMP header and payload */ diff --git a/net/igmp/igmp_send.c b/net/igmp/igmp_send.c index 9f770909c20..378f3fbc44b 100644 --- a/net/igmp/igmp_send.c +++ b/net/igmp/igmp_send.c @@ -129,7 +129,7 @@ void igmp_send(FAR struct net_driver_s *dev, FAR struct igmp_group_s *group, /* Update device buffer length */ - iob_update_pktlen(dev->d_iob, dev->d_len); + iob_update_pktlen(dev->d_iob, dev->d_len, false); /* The total size of the data is the size of the IGMP header */ diff --git a/net/mld/mld_send.c b/net/mld/mld_send.c index 09d676f0750..07e8b76ed75 100644 --- a/net/mld/mld_send.c +++ b/net/mld/mld_send.c @@ -168,7 +168,7 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group, /* Update device buffer length */ - iob_update_pktlen(dev->d_iob, dev->d_len); + iob_update_pktlen(dev->d_iob, dev->d_len, false); /* Select the IPv6 destination address. * This varies with the type of message being sent: diff --git a/net/tcp/tcp_send.c b/net/tcp/tcp_send.c index 6c328c4c0dc..68cd1830fc2 100644 --- a/net/tcp/tcp_send.c +++ b/net/tcp/tcp_send.c @@ -170,7 +170,7 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev, /* Update device buffer length before setup the IP header */ - iob_update_pktlen(dev->d_iob, dev->d_len); + iob_update_pktlen(dev->d_iob, dev->d_len, false); /* Calculate chk & build L3 header */ @@ -464,7 +464,7 @@ void tcp_reset(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn) /* Update device buffer length before setup the IP header */ - iob_update_pktlen(dev->d_iob, dev->d_len); + iob_update_pktlen(dev->d_iob, dev->d_len, false); /* Calculate chk & build L3 header */ diff --git a/net/udp/udp_send.c b/net/udp/udp_send.c index f6377a59f5f..39e0ffe6651 100644 --- a/net/udp/udp_send.c +++ b/net/udp/udp_send.c @@ -174,7 +174,7 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn) /* Update the device buffer length */ - iob_update_pktlen(dev->d_iob, dev->d_len); + iob_update_pktlen(dev->d_iob, dev->d_len, false); #ifdef CONFIG_NET_UDP_CHECKSUMS /* Calculate UDP checksum. */ diff --git a/net/udp/udp_sendto_buffered.c b/net/udp/udp_sendto_buffered.c index 5e944b05cb6..1eff0e8a24f 100644 --- a/net/udp/udp_sendto_buffered.c +++ b/net/udp/udp_sendto_buffered.c @@ -790,7 +790,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, udpiplen = udpip_hdrsize(conn); iob_reserve(wrb->wb_iob, CONFIG_NET_LL_GUARDSIZE); - iob_update_pktlen(wrb->wb_iob, udpiplen); + iob_update_pktlen(wrb->wb_iob, udpiplen, false); /* Copy the user data into the write buffer. We cannot wait for * buffer space if the socket was opened non-blocking.