Skip to content

Commit

Permalink
net/can, net/devif: fix CAN RX/TX iob free semcount runaway issue
Browse files Browse the repository at this point in the history
  • Loading branch information
haitomatic authored and jlaitine committed Feb 12, 2024
1 parent 9ba0690 commit ac2c321
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 21 deletions.
16 changes: 16 additions & 0 deletions net/can/can_callback.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ can_data_event(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn,
uint16_t flags)
{
int buflen = dev->d_len;
#ifdef CONFIG_NET_TIMESTAMP
buflen -= sizeof(struct timeval);
#endif
uint16_t recvlen;
uint16_t ret;

Expand Down Expand Up @@ -133,6 +136,19 @@ uint16_t can_callback(FAR struct net_driver_s *dev,

if ((flags & CAN_NEWDATA) != 0)
{
if (dev->d_iob->io_flink != NULL ||
dev->d_iob->io_pktlen == 0 ||
dev->d_iob->io_offset <= 0)
{
if (dev->d_iob->io_flink == NULL)
{
iob_free(dev->d_iob);
}

netdev_iob_clear(dev);
return flags;
}

#ifdef CONFIG_NET_TIMESTAMP
/* TIMESTAMP sockopt is activated,
* create timestamp and copy to iob
Expand Down
45 changes: 25 additions & 20 deletions net/can/can_recvmsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,19 @@ static inline int can_readahead(struct can_recvfrom_s *pstate)
if ((iob = iob_peek_queue(&conn->readahead)) != NULL &&
pstate->pr_buflen > 0)
{
if (iob->io_flink != NULL ||
iob->io_pktlen == 0 ||
iob->io_offset <= 0)
{
if (iob->io_pktlen == 0 || iob->io_offset <= 0)
{
iob_free(iob);
}

iob_remove_queue(&conn->readahead);
return 0;
}

DEBUGASSERT(iob->io_pktlen > 0);

#ifdef CONFIG_NET_CANPROTO_OPTIONS
Expand Down Expand Up @@ -283,31 +296,23 @@ static inline int can_readahead(struct can_recvfrom_s *pstate)
* beginning of the I/O buffer chain.
*/

if (recvlen >= iob->io_pktlen)
{
FAR struct iob_s *tmp;
/* No trimming needed since one CAN/CANFD frame can perfectly
* fit in one iob
*/

/* Remove the I/O buffer chain from the head of the read-ahead
* buffer queue.
*/
FAR struct iob_s *tmp;

tmp = iob_remove_queue(&conn->readahead);
DEBUGASSERT(tmp == iob);
UNUSED(tmp);
/* Remove the I/O buffer chain from the head of the read-ahead
* buffer queue.
*/

/* And free the I/O buffer chain */
tmp = iob_remove_queue(&conn->readahead);
DEBUGASSERT(tmp == iob);
UNUSED(tmp);

iob_free_chain(iob);
}
else
{
/* The bytes that we have received from the head of the I/O
* buffer chain (probably changing the head of the I/O
* buffer queue).
*/
/* And free the I/O buffer chain */

iob_trimhead_queue(&conn->readahead, recvlen);
}
iob_free_chain(iob);

/* do not pass frames with DLC > 8 to a legacy socket */
#if defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD)
Expand Down
7 changes: 6 additions & 1 deletion net/devif/devif_send.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,12 @@ 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, false);
/* if pktlen is 0, no need to update */

if (offset != 0)
{
iob_update_pktlen(dev->d_iob, offset, false);
}

ret = iob_trycopyin(dev->d_iob, buf, len, offset, false);
if (ret != len)
Expand Down

0 comments on commit ac2c321

Please sign in to comment.