can: Unify droping of invalid tx skbs and netdev stats
authorOliver Hartkopp <oliver@hartkopp.net>
Tue, 12 Jan 2010 10:00:46 +0000 (02:00 -0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 12 Jan 2010 10:00:46 +0000 (02:00 -0800)
To prevent the CAN drivers to operate on invalid socketbuffers the skbs are
now checked and silently dropped at the xmit-function consistently.

Also the netdev stats are consistently using the CAN data length code (dlc)
for [rx|tx]_bytes now.

Signed-off-by: Oliver Hartkopp <oliver@hartkopp.net>
Acked-by: Wolfgang Grandegger <wg@grandegger.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/can/at91_can.c
drivers/net/can/bfin_can.c
drivers/net/can/mcp251x.c
drivers/net/can/mscan/mscan.c
drivers/net/can/sja1000/sja1000.c
drivers/net/can/ti_hecc.c
drivers/net/can/usb/ems_usb.c
drivers/net/can/vcan.c
include/linux/can/dev.h

index 166cc7e579c0a8c1eaadc9193dffdfedac0a6b82..f7287497ba6e70a4b57074151bcccaa8e38c5e10 100644 (file)
@@ -342,6 +342,9 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
        unsigned int mb, prio;
        u32 reg_mid, reg_mcr;
 
+       if (can_dropped_invalid_skb(dev, skb))
+               return NETDEV_TX_OK;
+
        mb = get_tx_next_mb(priv);
        prio = get_tx_next_prio(priv);
 
index 0ec1524523ccaa939988d3d0c1f55bcd3450114f..7e1926e79e9805fa2dbc38b8e7b43dfad92906f3 100644 (file)
@@ -318,6 +318,9 @@ static int bfin_can_start_xmit(struct sk_buff *skb, struct net_device *dev)
        u16 val;
        int i;
 
+       if (can_dropped_invalid_skb(dev, skb))
+               return NETDEV_TX_OK;
+
        netif_stop_queue(dev);
 
        /* fill id */
index 1a72ca066a17fa013a3453dcaacf694a32431fed..afa2fa45fed97c41fbee4b1ce96fed01d7099016 100644 (file)
@@ -494,12 +494,8 @@ static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
                return NETDEV_TX_BUSY;
        }
 
-       if (skb->len != sizeof(struct can_frame)) {
-               dev_err(&spi->dev, "dropping packet - bad length\n");
-               dev_kfree_skb(skb);
-               net->stats.tx_dropped++;
+       if (can_dropped_invalid_skb(net, skb))
                return NETDEV_TX_OK;
-       }
 
        netif_stop_queue(net);
        priv->tx_skb = skb;
index 500d18918bd574205fe822d3ead94a20f6771f46..40827c128b65ba108ff16aa94576ef31c98cccb8 100644 (file)
@@ -204,11 +204,8 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
        int i, rtr, buf_id;
        u32 can_id;
 
-       if (skb->len != sizeof(*frame) || frame->can_dlc > 8) {
-               kfree_skb(skb);
-               dev->stats.tx_dropped++;
+       if (can_dropped_invalid_skb(dev, skb))
                return NETDEV_TX_OK;
-       }
 
        out_8(&regs->cantier, 0);
 
index 542a4f7255b4f5db367ef755abb623aed752c9b1..345304d779b927361abb8d62633b61a25c0a7876 100644 (file)
@@ -249,6 +249,9 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb,
        uint8_t dreg;
        int i;
 
+       if (can_dropped_invalid_skb(dev, skb))
+               return NETDEV_TX_OK;
+
        netif_stop_queue(dev);
 
        fi = dlc = cf->can_dlc;
index 5c993c2da5281b24c74434ad54ccb0862fa9bc72..7d370e32a7a8c995f155aa41f43fbaa75c3bf471 100644 (file)
@@ -477,6 +477,9 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
        u32 mbxno, mbx_mask, data;
        unsigned long flags;
 
+       if (can_dropped_invalid_skb(ndev, skb))
+               return NETDEV_TX_OK;
+
        mbxno = get_tx_head_mb(priv);
        mbx_mask = BIT(mbxno);
        spin_lock_irqsave(&priv->mbx_lock, flags);
@@ -491,7 +494,6 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
        spin_unlock_irqrestore(&priv->mbx_lock, flags);
 
        /* Prepare mailbox for transmission */
-       data = min_t(u8, cf->can_dlc, 8);
        if (cf->can_id & CAN_RTR_FLAG) /* Remote transmission request */
                data |= HECC_CANMCF_RTR;
        data |= get_tx_head_prio(priv) << 8;
index efbb05c71bf47fdde6af69fb13d1a38fdd80f032..ddb17e256656172a89de71a22c6de100e98d0ef1 100644 (file)
@@ -767,6 +767,9 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
        size_t size = CPC_HEADER_SIZE + CPC_MSG_HEADER_LEN
                        + sizeof(struct cpc_can_msg);
 
+       if (can_dropped_invalid_skb(netdev, skb))
+               return NETDEV_TX_OK;
+
        /* create a URB, and a buffer for it, and copy the data to the URB */
        urb = usb_alloc_urb(0, GFP_ATOMIC);
        if (!urb) {
index 80ac56313981983063340adb95150fe40d76bea9..d124d837ae58c4c1c5de7ce1d6a90d3fc86c5d52 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/can.h>
+#include <linux/can/dev.h>
 #include <net/rtnetlink.h>
 
 static __initdata const char banner[] =
@@ -70,10 +71,11 @@ MODULE_PARM_DESC(echo, "Echo sent frames (for testing). Default: 0 (Off)");
 
 static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
 {
+       struct can_frame *cf = (struct can_frame *)skb->data;
        struct net_device_stats *stats = &dev->stats;
 
        stats->rx_packets++;
-       stats->rx_bytes += skb->len;
+       stats->rx_bytes += cf->can_dlc;
 
        skb->protocol  = htons(ETH_P_CAN);
        skb->pkt_type  = PACKET_BROADCAST;
@@ -85,11 +87,15 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
 
 static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
 {
+       struct can_frame *cf = (struct can_frame *)skb->data;
        struct net_device_stats *stats = &dev->stats;
        int loop;
 
+       if (can_dropped_invalid_skb(dev, skb))
+               return NETDEV_TX_OK;
+
        stats->tx_packets++;
-       stats->tx_bytes += skb->len;
+       stats->tx_bytes += cf->can_dlc;
 
        /* set flag whether this packet has to be looped back */
        loop = skb->pkt_type == PACKET_LOOPBACK;
@@ -103,7 +109,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
                         * CAN core already did the echo for us
                         */
                        stats->rx_packets++;
-                       stats->rx_bytes += skb->len;
+                       stats->rx_bytes += cf->can_dlc;
                }
                kfree_skb(skb);
                return NETDEV_TX_OK;
index 3db7767d2a175b9caf61ec4d98de415f7c24f6b6..7e7c98a3e908b833ebb250e989e64e5a9bd8535b 100644 (file)
@@ -60,6 +60,21 @@ struct can_priv {
  */
 #define get_can_dlc(i) (min_t(__u8, (i), 8))
 
+/* Drop a given socketbuffer if it does not contain a valid CAN frame. */
+static inline int can_dropped_invalid_skb(struct net_device *dev,
+                                         struct sk_buff *skb)
+{
+       const struct can_frame *cf = (struct can_frame *)skb->data;
+
+       if (unlikely(skb->len != sizeof(*cf) || cf->can_dlc > 8)) {
+               kfree_skb(skb);
+               dev->stats.tx_dropped++;
+               return 1;
+       }
+
+       return 0;
+}
+
 struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max);
 void free_candev(struct net_device *dev);