diff options
Diffstat (limited to 'drivers/net/can/dev.c')
-rw-r--r-- | drivers/net/can/dev.c | 76 |
1 files changed, 62 insertions, 14 deletions
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 2868fe842a41..c1bb29f0322b 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c | |||
@@ -245,7 +245,7 @@ static void can_flush_echo_skb(struct net_device *dev) | |||
245 | struct net_device_stats *stats = &dev->stats; | 245 | struct net_device_stats *stats = &dev->stats; |
246 | int i; | 246 | int i; |
247 | 247 | ||
248 | for (i = 0; i < CAN_ECHO_SKB_MAX; i++) { | 248 | for (i = 0; i < priv->echo_skb_max; i++) { |
249 | if (priv->echo_skb[i]) { | 249 | if (priv->echo_skb[i]) { |
250 | kfree_skb(priv->echo_skb[i]); | 250 | kfree_skb(priv->echo_skb[i]); |
251 | priv->echo_skb[i] = NULL; | 251 | priv->echo_skb[i] = NULL; |
@@ -262,10 +262,13 @@ static void can_flush_echo_skb(struct net_device *dev) | |||
262 | * of the device driver. The driver must protect access to | 262 | * of the device driver. The driver must protect access to |
263 | * priv->echo_skb, if necessary. | 263 | * priv->echo_skb, if necessary. |
264 | */ | 264 | */ |
265 | void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, int idx) | 265 | void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, |
266 | unsigned int idx) | ||
266 | { | 267 | { |
267 | struct can_priv *priv = netdev_priv(dev); | 268 | struct can_priv *priv = netdev_priv(dev); |
268 | 269 | ||
270 | BUG_ON(idx >= priv->echo_skb_max); | ||
271 | |||
269 | /* check flag whether this packet has to be looped back */ | 272 | /* check flag whether this packet has to be looped back */ |
270 | if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK) { | 273 | if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK) { |
271 | kfree_skb(skb); | 274 | kfree_skb(skb); |
@@ -311,10 +314,12 @@ EXPORT_SYMBOL_GPL(can_put_echo_skb); | |||
311 | * is handled in the device driver. The driver must protect | 314 | * is handled in the device driver. The driver must protect |
312 | * access to priv->echo_skb, if necessary. | 315 | * access to priv->echo_skb, if necessary. |
313 | */ | 316 | */ |
314 | void can_get_echo_skb(struct net_device *dev, int idx) | 317 | void can_get_echo_skb(struct net_device *dev, unsigned int idx) |
315 | { | 318 | { |
316 | struct can_priv *priv = netdev_priv(dev); | 319 | struct can_priv *priv = netdev_priv(dev); |
317 | 320 | ||
321 | BUG_ON(idx >= priv->echo_skb_max); | ||
322 | |||
318 | if (priv->echo_skb[idx]) { | 323 | if (priv->echo_skb[idx]) { |
319 | netif_rx(priv->echo_skb[idx]); | 324 | netif_rx(priv->echo_skb[idx]); |
320 | priv->echo_skb[idx] = NULL; | 325 | priv->echo_skb[idx] = NULL; |
@@ -327,10 +332,12 @@ EXPORT_SYMBOL_GPL(can_get_echo_skb); | |||
327 | * | 332 | * |
328 | * The function is typically called when TX failed. | 333 | * The function is typically called when TX failed. |
329 | */ | 334 | */ |
330 | void can_free_echo_skb(struct net_device *dev, int idx) | 335 | void can_free_echo_skb(struct net_device *dev, unsigned int idx) |
331 | { | 336 | { |
332 | struct can_priv *priv = netdev_priv(dev); | 337 | struct can_priv *priv = netdev_priv(dev); |
333 | 338 | ||
339 | BUG_ON(idx >= priv->echo_skb_max); | ||
340 | |||
334 | if (priv->echo_skb[idx]) { | 341 | if (priv->echo_skb[idx]) { |
335 | kfree_skb(priv->echo_skb[idx]); | 342 | kfree_skb(priv->echo_skb[idx]); |
336 | priv->echo_skb[idx] = NULL; | 343 | priv->echo_skb[idx] = NULL; |
@@ -359,17 +366,12 @@ void can_restart(unsigned long data) | |||
359 | can_flush_echo_skb(dev); | 366 | can_flush_echo_skb(dev); |
360 | 367 | ||
361 | /* send restart message upstream */ | 368 | /* send restart message upstream */ |
362 | skb = dev_alloc_skb(sizeof(struct can_frame)); | 369 | skb = alloc_can_err_skb(dev, &cf); |
363 | if (skb == NULL) { | 370 | if (skb == NULL) { |
364 | err = -ENOMEM; | 371 | err = -ENOMEM; |
365 | goto restart; | 372 | goto restart; |
366 | } | 373 | } |
367 | skb->dev = dev; | 374 | cf->can_id |= CAN_ERR_RESTARTED; |
368 | skb->protocol = htons(ETH_P_CAN); | ||
369 | cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); | ||
370 | memset(cf, 0, sizeof(struct can_frame)); | ||
371 | cf->can_id = CAN_ERR_FLAG | CAN_ERR_RESTARTED; | ||
372 | cf->can_dlc = CAN_ERR_DLC; | ||
373 | 375 | ||
374 | netif_rx(skb); | 376 | netif_rx(skb); |
375 | 377 | ||
@@ -442,20 +444,66 @@ static void can_setup(struct net_device *dev) | |||
442 | dev->features = NETIF_F_NO_CSUM; | 444 | dev->features = NETIF_F_NO_CSUM; |
443 | } | 445 | } |
444 | 446 | ||
447 | struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) | ||
448 | { | ||
449 | struct sk_buff *skb; | ||
450 | |||
451 | skb = netdev_alloc_skb(dev, sizeof(struct can_frame)); | ||
452 | if (unlikely(!skb)) | ||
453 | return NULL; | ||
454 | |||
455 | skb->protocol = htons(ETH_P_CAN); | ||
456 | skb->pkt_type = PACKET_BROADCAST; | ||
457 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
458 | *cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); | ||
459 | memset(*cf, 0, sizeof(struct can_frame)); | ||
460 | |||
461 | return skb; | ||
462 | } | ||
463 | EXPORT_SYMBOL_GPL(alloc_can_skb); | ||
464 | |||
465 | struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf) | ||
466 | { | ||
467 | struct sk_buff *skb; | ||
468 | |||
469 | skb = alloc_can_skb(dev, cf); | ||
470 | if (unlikely(!skb)) | ||
471 | return NULL; | ||
472 | |||
473 | (*cf)->can_id = CAN_ERR_FLAG; | ||
474 | (*cf)->can_dlc = CAN_ERR_DLC; | ||
475 | |||
476 | return skb; | ||
477 | } | ||
478 | EXPORT_SYMBOL_GPL(alloc_can_err_skb); | ||
479 | |||
445 | /* | 480 | /* |
446 | * Allocate and setup space for the CAN network device | 481 | * Allocate and setup space for the CAN network device |
447 | */ | 482 | */ |
448 | struct net_device *alloc_candev(int sizeof_priv) | 483 | struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max) |
449 | { | 484 | { |
450 | struct net_device *dev; | 485 | struct net_device *dev; |
451 | struct can_priv *priv; | 486 | struct can_priv *priv; |
487 | int size; | ||
452 | 488 | ||
453 | dev = alloc_netdev(sizeof_priv, "can%d", can_setup); | 489 | if (echo_skb_max) |
490 | size = ALIGN(sizeof_priv, sizeof(struct sk_buff *)) + | ||
491 | echo_skb_max * sizeof(struct sk_buff *); | ||
492 | else | ||
493 | size = sizeof_priv; | ||
494 | |||
495 | dev = alloc_netdev(size, "can%d", can_setup); | ||
454 | if (!dev) | 496 | if (!dev) |
455 | return NULL; | 497 | return NULL; |
456 | 498 | ||
457 | priv = netdev_priv(dev); | 499 | priv = netdev_priv(dev); |
458 | 500 | ||
501 | if (echo_skb_max) { | ||
502 | priv->echo_skb_max = echo_skb_max; | ||
503 | priv->echo_skb = (void *)priv + | ||
504 | ALIGN(sizeof_priv, sizeof(struct sk_buff *)); | ||
505 | } | ||
506 | |||
459 | priv->state = CAN_STATE_STOPPED; | 507 | priv->state = CAN_STATE_STOPPED; |
460 | 508 | ||
461 | init_timer(&priv->restart_timer); | 509 | init_timer(&priv->restart_timer); |
@@ -647,7 +695,7 @@ nla_put_failure: | |||
647 | return -EMSGSIZE; | 695 | return -EMSGSIZE; |
648 | } | 696 | } |
649 | 697 | ||
650 | static int can_newlink(struct net_device *dev, | 698 | static int can_newlink(struct net *src_net, struct net_device *dev, |
651 | struct nlattr *tb[], struct nlattr *data[]) | 699 | struct nlattr *tb[], struct nlattr *data[]) |
652 | { | 700 | { |
653 | return -EOPNOTSUPP; | 701 | return -EOPNOTSUPP; |