diff options
author | Oliver Hartkopp <oliver@hartkopp.net> | 2009-12-11 23:13:21 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-12-13 22:47:42 -0500 |
commit | c7cd606f60e7679c7f9eee7010f02a6f000209c1 (patch) | |
tree | 31c19fd7617ede807757b0ae5c29d218587dc43f /drivers/net/can/sja1000/sja1000.c | |
parent | d90a909e1f3e006a1d57fe11fd417173b6494701 (diff) |
can: Fix data length code handling in rx path
A valid CAN dataframe can have a data length code (DLC) of 0 .. 8 data bytes.
When reading the CAN controllers register the 4-bit value may contain values
from 0 .. 15 which may exceed the reserved space in the socket buffer!
The ISO 11898-1 Chapter 8.4.2.3 (DLC field) says that register values > 8
should be reduced to 8 without any error reporting or frame drop.
This patch introduces a new helper macro to cast a given 4-bit data length
code (dlc) to __u8 and ensure the DLC value to be max. 8 bytes.
The different handlings in the rx path of the CAN netdevice drivers are fixed.
Signed-off-by: Oliver Hartkopp <oliver@hartkopp.net>
Signed-off-by: Wolfgang Grandegger <wg@grandegger.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/can/sja1000/sja1000.c')
-rw-r--r-- | drivers/net/can/sja1000/sja1000.c | 18 |
1 files changed, 8 insertions, 10 deletions
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index b4ba88a31075..542a4f7255b4 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c | |||
@@ -293,15 +293,14 @@ static void sja1000_rx(struct net_device *dev) | |||
293 | uint8_t fi; | 293 | uint8_t fi; |
294 | uint8_t dreg; | 294 | uint8_t dreg; |
295 | canid_t id; | 295 | canid_t id; |
296 | uint8_t dlc; | ||
297 | int i; | 296 | int i; |
298 | 297 | ||
298 | /* create zero'ed CAN frame buffer */ | ||
299 | skb = alloc_can_skb(dev, &cf); | 299 | skb = alloc_can_skb(dev, &cf); |
300 | if (skb == NULL) | 300 | if (skb == NULL) |
301 | return; | 301 | return; |
302 | 302 | ||
303 | fi = priv->read_reg(priv, REG_FI); | 303 | fi = priv->read_reg(priv, REG_FI); |
304 | dlc = fi & 0x0F; | ||
305 | 304 | ||
306 | if (fi & FI_FF) { | 305 | if (fi & FI_FF) { |
307 | /* extended frame format (EFF) */ | 306 | /* extended frame format (EFF) */ |
@@ -318,16 +317,15 @@ static void sja1000_rx(struct net_device *dev) | |||
318 | | (priv->read_reg(priv, REG_ID2) >> 5); | 317 | | (priv->read_reg(priv, REG_ID2) >> 5); |
319 | } | 318 | } |
320 | 319 | ||
321 | if (fi & FI_RTR) | 320 | if (fi & FI_RTR) { |
322 | id |= CAN_RTR_FLAG; | 321 | id |= CAN_RTR_FLAG; |
322 | } else { | ||
323 | cf->can_dlc = get_can_dlc(fi & 0x0F); | ||
324 | for (i = 0; i < cf->can_dlc; i++) | ||
325 | cf->data[i] = priv->read_reg(priv, dreg++); | ||
326 | } | ||
323 | 327 | ||
324 | cf->can_id = id; | 328 | cf->can_id = id; |
325 | cf->can_dlc = dlc; | ||
326 | for (i = 0; i < dlc; i++) | ||
327 | cf->data[i] = priv->read_reg(priv, dreg++); | ||
328 | |||
329 | while (i < 8) | ||
330 | cf->data[i++] = 0; | ||
331 | 329 | ||
332 | /* release receive buffer */ | 330 | /* release receive buffer */ |
333 | priv->write_reg(priv, REG_CMR, CMD_RRB); | 331 | priv->write_reg(priv, REG_CMR, CMD_RRB); |
@@ -335,7 +333,7 @@ static void sja1000_rx(struct net_device *dev) | |||
335 | netif_rx(skb); | 333 | netif_rx(skb); |
336 | 334 | ||
337 | stats->rx_packets++; | 335 | stats->rx_packets++; |
338 | stats->rx_bytes += dlc; | 336 | stats->rx_bytes += cf->can_dlc; |
339 | } | 337 | } |
340 | 338 | ||
341 | static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) | 339 | static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) |