Commit 3ccd4c61 authored by Oliver Hartkopp's avatar Oliver Hartkopp Committed by David S. Miller

can: Unify droping of invalid tx skbs and netdev stats

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: default avatarOliver Hartkopp <oliver@hartkopp.net>
Acked-by: default avatarWolfgang Grandegger <wg@grandegger.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d218d111
...@@ -342,6 +342,9 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -342,6 +342,9 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned int mb, prio; unsigned int mb, prio;
u32 reg_mid, reg_mcr; u32 reg_mid, reg_mcr;
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
mb = get_tx_next_mb(priv); mb = get_tx_next_mb(priv);
prio = get_tx_next_prio(priv); prio = get_tx_next_prio(priv);
......
...@@ -318,6 +318,9 @@ static int bfin_can_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -318,6 +318,9 @@ static int bfin_can_start_xmit(struct sk_buff *skb, struct net_device *dev)
u16 val; u16 val;
int i; int i;
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
netif_stop_queue(dev); netif_stop_queue(dev);
/* fill id */ /* fill id */
......
...@@ -494,12 +494,8 @@ static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb, ...@@ -494,12 +494,8 @@ static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
if (skb->len != sizeof(struct can_frame)) { if (can_dropped_invalid_skb(net, skb))
dev_err(&spi->dev, "dropping packet - bad length\n");
dev_kfree_skb(skb);
net->stats.tx_dropped++;
return NETDEV_TX_OK; return NETDEV_TX_OK;
}
netif_stop_queue(net); netif_stop_queue(net);
priv->tx_skb = skb; priv->tx_skb = skb;
......
...@@ -204,11 +204,8 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -204,11 +204,8 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
int i, rtr, buf_id; int i, rtr, buf_id;
u32 can_id; u32 can_id;
if (skb->len != sizeof(*frame) || frame->can_dlc > 8) { if (can_dropped_invalid_skb(dev, skb))
kfree_skb(skb);
dev->stats.tx_dropped++;
return NETDEV_TX_OK; return NETDEV_TX_OK;
}
out_8(&regs->cantier, 0); out_8(&regs->cantier, 0);
......
...@@ -249,6 +249,9 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb, ...@@ -249,6 +249,9 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb,
uint8_t dreg; uint8_t dreg;
int i; int i;
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
netif_stop_queue(dev); netif_stop_queue(dev);
fi = dlc = cf->can_dlc; fi = dlc = cf->can_dlc;
......
...@@ -477,6 +477,9 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -477,6 +477,9 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
u32 mbxno, mbx_mask, data; u32 mbxno, mbx_mask, data;
unsigned long flags; unsigned long flags;
if (can_dropped_invalid_skb(ndev, skb))
return NETDEV_TX_OK;
mbxno = get_tx_head_mb(priv); mbxno = get_tx_head_mb(priv);
mbx_mask = BIT(mbxno); mbx_mask = BIT(mbxno);
spin_lock_irqsave(&priv->mbx_lock, flags); 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) ...@@ -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); spin_unlock_irqrestore(&priv->mbx_lock, flags);
/* Prepare mailbox for transmission */ /* Prepare mailbox for transmission */
data = min_t(u8, cf->can_dlc, 8);
if (cf->can_id & CAN_RTR_FLAG) /* Remote transmission request */ if (cf->can_id & CAN_RTR_FLAG) /* Remote transmission request */
data |= HECC_CANMCF_RTR; data |= HECC_CANMCF_RTR;
data |= get_tx_head_prio(priv) << 8; data |= get_tx_head_prio(priv) << 8;
......
...@@ -767,6 +767,9 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne ...@@ -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 size_t size = CPC_HEADER_SIZE + CPC_MSG_HEADER_LEN
+ sizeof(struct cpc_can_msg); + 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 */ /* create a URB, and a buffer for it, and copy the data to the URB */
urb = usb_alloc_urb(0, GFP_ATOMIC); urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) { if (!urb) {
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/dev.h>
#include <net/rtnetlink.h> #include <net/rtnetlink.h>
static __initdata const char banner[] = static __initdata const char banner[] =
...@@ -70,10 +71,11 @@ MODULE_PARM_DESC(echo, "Echo sent frames (for testing). Default: 0 (Off)"); ...@@ -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) 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; struct net_device_stats *stats = &dev->stats;
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += skb->len; stats->rx_bytes += cf->can_dlc;
skb->protocol = htons(ETH_P_CAN); skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST; skb->pkt_type = PACKET_BROADCAST;
...@@ -85,11 +87,15 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev) ...@@ -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) 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; struct net_device_stats *stats = &dev->stats;
int loop; int loop;
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
stats->tx_packets++; stats->tx_packets++;
stats->tx_bytes += skb->len; stats->tx_bytes += cf->can_dlc;
/* set flag whether this packet has to be looped back */ /* set flag whether this packet has to be looped back */
loop = skb->pkt_type == PACKET_LOOPBACK; loop = skb->pkt_type == PACKET_LOOPBACK;
...@@ -103,7 +109,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -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 * CAN core already did the echo for us
*/ */
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += skb->len; stats->rx_bytes += cf->can_dlc;
} }
kfree_skb(skb); kfree_skb(skb);
return NETDEV_TX_OK; return NETDEV_TX_OK;
......
...@@ -60,6 +60,21 @@ struct can_priv { ...@@ -60,6 +60,21 @@ struct can_priv {
*/ */
#define get_can_dlc(i) (min_t(__u8, (i), 8)) #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); struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max);
void free_candev(struct net_device *dev); void free_candev(struct net_device *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment