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 <zhanghongyu@xiaomi.com>
This commit is contained in:
zhanghongyu 2024-03-28 15:01:31 +08:00 committed by Xiang Xiao
parent 589bb56bcb
commit a9bff735e7
3 changed files with 133 additions and 37 deletions

View File

@ -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
*

View File

@ -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 */

View File

@ -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);
}
/****************************************************************************