summaryrefslogtreecommitdiff
path: root/drivers/net/can/dev
diff options
context:
space:
mode:
authorMarc Kleine-Budde <mkl@pengutronix.de>2021-04-02 12:05:39 +0200
committerMarc Kleine-Budde <mkl@pengutronix.de>2021-04-07 09:31:19 +0200
commitc8129487441e11617fab9770d9f98d9ae8fc7b3a (patch)
tree34f515572be4bb25aceea53ef782790084fd8084 /drivers/net/can/dev
parent0b35e0deb5bee7d4882356d6663522c1562a8321 (diff)
can: skb: alloc_can{,fd}_skb(): set "cf" to NULL if skb allocation fails
The handling of CAN bus errors typically consist of allocating a CAN error SKB using alloc_can_err_skb() followed by stats handling and filling the error details in the newly allocated CAN error SKB. Even if the allocation of the SKB fails the stats handling should not be skipped. The common pattern in CAN drivers is to allocate the skb and work on the struct can_frame pointer "cf", if it has been assigned by alloc_can_err_skb(). | skb = alloc_can_err_skb(priv->ndev, &cf); | | /* RX errors */ | if (bdiag1 & (MCP251XFD_REG_BDIAG1_DCRCERR | | MCP251XFD_REG_BDIAG1_NCRCERR)) { | netdev_dbg(priv->ndev, "CRC error\n"); | | stats->rx_errors++; | if (cf) | cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; | } In case of an OOM alloc_can_err_skb() returns NULL, but doesn't set "cf" to NULL as well. For the above pattern to work the "cf" has to be initialized to NULL, which is easily forgotten. To solve this kind of problems, set "cf" to NULL if alloc_can_err_skb() returns NULL. Link: https://lore.kernel.org/r/20210402102245.1512583-1-mkl@pengutronix.de Suggested-by: Vincent MAILHOL <mailhol.vincent@wanadoo.fr> Reviewed-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'drivers/net/can/dev')
-rw-r--r--drivers/net/can/dev/skb.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c
index 387c0bc0fb9c..61660248c69e 100644
--- a/drivers/net/can/dev/skb.c
+++ b/drivers/net/can/dev/skb.c
@@ -183,8 +183,11 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
sizeof(struct can_frame));
- if (unlikely(!skb))
+ if (unlikely(!skb)) {
+ *cf = NULL;
+
return NULL;
+ }
skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;
@@ -211,8 +214,11 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
sizeof(struct canfd_frame));
- if (unlikely(!skb))
+ if (unlikely(!skb)) {
+ *cfd = NULL;
+
return NULL;
+ }
skb->protocol = htons(ETH_P_CANFD);
skb->pkt_type = PACKET_BROADCAST;