From a9bff735e7a9ced72e7f1ea3228e29ea5530c9a5 Mon Sep 17 00:00:00 2001 From: zhanghongyu Date: Thu, 28 Mar 2024 15:01:31 +0800 Subject: [PATCH] net/can: deliver data into multiple CAN conn bound to same dev Because CAN is a broadcast protocol, each conn needs to be given independent data to avoid mutual interference. Signed-off-by: zhanghongyu --- net/can/can.h | 19 +++++++ net/can/can_conn.c | 30 +++++++++++ net/can/can_input.c | 121 ++++++++++++++++++++++++++++++-------------- 3 files changed, 133 insertions(+), 37 deletions(-) diff --git a/net/can/can.h b/net/can/can.h index 46de920dc8..1c0a78c006 100644 --- a/net/can/can.h +++ b/net/can/can.h @@ -184,6 +184,25 @@ void can_free(FAR struct can_conn_s *conn); FAR struct can_conn_s *can_nextconn(FAR struct can_conn_s *conn); +/**************************************************************************** + * Name: can_active() + * + * Description: + * Traverse the list of NetLink connections that match dev + * + * Input Parameters: + * dev - The device to search for. + * conn - The current connection; may be NULL to start the search at the + * beginning + * + * Assumptions: + * This function is called from NetLink device logic. + * + ****************************************************************************/ + +FAR struct can_conn_s *can_active(FAR struct net_driver_s *dev, + FAR struct can_conn_s *conn); + /**************************************************************************** * Name: can_callback * diff --git a/net/can/can_conn.c b/net/can/can_conn.c index d03d20ac0c..a6cd63bc20 100644 --- a/net/can/can_conn.c +++ b/net/can/can_conn.c @@ -225,4 +225,34 @@ FAR struct can_conn_s *can_nextconn(FAR struct can_conn_s *conn) } } +/**************************************************************************** + * Name: can_active() + * + * Description: + * Traverse the list of NetLink connections that match dev + * + * Input Parameters: + * dev - The device to search for. + * conn - The current connection; may be NULL to start the search at the + * beginning + * + * Assumptions: + * This function is called from NetLink device logic. + * + ****************************************************************************/ + +FAR struct can_conn_s *can_active(FAR struct net_driver_s *dev, + FAR struct can_conn_s *conn) +{ + while ((conn = can_nextconn(conn)) != NULL) + { + if (conn->dev == NULL || conn->dev == dev) + { + break; + } + } + + return conn; +} + #endif /* CONFIG_NET_CAN */ diff --git a/net/can/can_input.c b/net/can/can_input.c index 42ae6c86ff..35d4a73fd1 100644 --- a/net/can/can_input.c +++ b/net/can/can_input.c @@ -127,6 +127,67 @@ const uint8_t len_to_can_dlc[65] = 15, }; +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: can_input_conn + * + * Description: + * Handle incoming packet input + * + * Input Parameters: + * dev - The device driver structure containing the received packet + * conn - A pointer to the CAN connection structure + * + * Returned Value: + * OK The packet has been processed and can be deleted + * -EAGAIN There is a matching connection, but could not dispatch the packet + * yet. Useful when a packet arrives before a recv call is in + * place. + * + * Assumptions: + * This function can be called from an interrupt. + * + ****************************************************************************/ + +static int can_input_conn(FAR struct net_driver_s *dev, + FAR struct can_conn_s *conn) +{ + uint16_t flags; + uint16_t buflen = dev->d_len; + int ret = OK; + + /* Setup for the application callback */ + + dev->d_appdata = dev->d_buf; + dev->d_sndlen = 0; + dev->d_len = buflen; + + /* Perform the application callback */ + + flags = can_callback(dev, conn, CAN_NEWDATA); + + /* If the operation was successful, the CAN_NEWDATA flag is removed + * and thus the packet can be deleted (OK will be returned). + */ + + if ((flags & CAN_NEWDATA) != 0) + { + /* No.. the packet was not processed now. Return -EAGAIN so + * that the driver may retry again later. We still need to + * set d_len to zero so that the driver is aware that there + * is nothing to be sent. + */ + + nwarn("WARNING: Packet not processed\n"); + ret = -EAGAIN; + } + + return ret; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -151,50 +212,36 @@ const uint8_t len_to_can_dlc[65] = * ****************************************************************************/ -static int can_in(struct net_driver_s *dev) +static int can_in(FAR struct net_driver_s *dev) { - FAR struct can_conn_s *conn = NULL; - int ret = OK; - uint16_t buflen = dev->d_len; + FAR struct can_conn_s *conn = can_active(dev, NULL); + FAR struct can_conn_s *nextconn; - do + /* Do we have second connection that can hold this packet? */ + + while ((nextconn = can_active(dev, conn)) != NULL) { - conn = can_nextconn(conn); + /* Yes... There are multiple listeners on the same dev. + * We need to clone the packet and deliver it to each listener. + */ - if (conn && (conn->dev == NULL || dev == conn->dev)) + FAR struct iob_s *iob = netdev_iob_clone(dev, false); + + if (iob == NULL) { - uint16_t flags; - - /* Setup for the application callback */ - - dev->d_appdata = dev->d_buf; - dev->d_sndlen = 0; - dev->d_len = buflen; - - /* Perform the application callback */ - - flags = can_callback(dev, conn, CAN_NEWDATA); - - /* If the operation was successful, the CAN_NEWDATA flag is removed - * and thus the packet can be deleted (OK will be returned). - */ - - if ((flags & CAN_NEWDATA) != 0) - { - /* No.. the packet was not processed now. Return -EAGAIN so - * that the driver may retry again later. We still need to - * set d_len to zero so that the driver is aware that there - * is nothing to be sent. - */ - - nwarn("WARNING: Packet not processed\n"); - ret = -EAGAIN; - } + nerr("ERROR: IOB clone failed.\n"); + break; /* We can still process one time without clone. */ } - } - while (conn); - return ret; + can_input_conn(dev, conn); + + netdev_iob_replace(dev, iob); + conn = nextconn; + } + + /* We can deliver the packet directly to the last listener. */ + + return can_input_conn(dev, conn); } /****************************************************************************