diff options
Diffstat (limited to 'drivers/net/usb/asix.c')
-rw-r--r-- | drivers/net/usb/asix.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 3ae80eccd0ef..6564c32d3af0 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c | |||
@@ -358,14 +358,30 @@ static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | |||
358 | 358 | ||
359 | padlen = ((skb->len + 4) & (dev->maxpacket - 1)) ? 0 : 4; | 359 | padlen = ((skb->len + 4) & (dev->maxpacket - 1)) ? 0 : 4; |
360 | 360 | ||
361 | if ((!skb_cloned(skb)) && | 361 | /* We need to push 4 bytes in front of frame (packet_len) |
362 | ((headroom + tailroom) >= (4 + padlen))) { | 362 | * and maybe add 4 bytes after the end (if padlen is 4) |
363 | if ((headroom < 4) || (tailroom < padlen)) { | 363 | * |
364 | * Avoid skb_copy_expand() expensive call, using following rules : | ||
365 | * - We are allowed to push 4 bytes in headroom if skb_header_cloned() | ||
366 | * is false (and if we have 4 bytes of headroom) | ||
367 | * - We are allowed to put 4 bytes at tail if skb_cloned() | ||
368 | * is false (and if we have 4 bytes of tailroom) | ||
369 | * | ||
370 | * TCP packets for example are cloned, but skb_header_release() | ||
371 | * was called in tcp stack, allowing us to use headroom for our needs. | ||
372 | */ | ||
373 | if (!skb_header_cloned(skb) && | ||
374 | !(padlen && skb_cloned(skb)) && | ||
375 | headroom + tailroom >= 4 + padlen) { | ||
376 | /* following should not happen, but better be safe */ | ||
377 | if (headroom < 4 || | ||
378 | tailroom < padlen) { | ||
364 | skb->data = memmove(skb->head + 4, skb->data, skb->len); | 379 | skb->data = memmove(skb->head + 4, skb->data, skb->len); |
365 | skb_set_tail_pointer(skb, skb->len); | 380 | skb_set_tail_pointer(skb, skb->len); |
366 | } | 381 | } |
367 | } else { | 382 | } else { |
368 | struct sk_buff *skb2; | 383 | struct sk_buff *skb2; |
384 | |||
369 | skb2 = skb_copy_expand(skb, 4, padlen, flags); | 385 | skb2 = skb_copy_expand(skb, 4, padlen, flags); |
370 | dev_kfree_skb_any(skb); | 386 | dev_kfree_skb_any(skb); |
371 | skb = skb2; | 387 | skb = skb2; |
@@ -373,8 +389,8 @@ static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | |||
373 | return NULL; | 389 | return NULL; |
374 | } | 390 | } |
375 | 391 | ||
392 | packet_len = ((skb->len ^ 0x0000ffff) << 16) + skb->len; | ||
376 | skb_push(skb, 4); | 393 | skb_push(skb, 4); |
377 | packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); | ||
378 | cpu_to_le32s(&packet_len); | 394 | cpu_to_le32s(&packet_len); |
379 | skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); | 395 | skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); |
380 | 396 | ||
@@ -880,6 +896,8 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) | |||
880 | 896 | ||
881 | dev->net->netdev_ops = &ax88172_netdev_ops; | 897 | dev->net->netdev_ops = &ax88172_netdev_ops; |
882 | dev->net->ethtool_ops = &ax88172_ethtool_ops; | 898 | dev->net->ethtool_ops = &ax88172_ethtool_ops; |
899 | dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ | ||
900 | dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ | ||
883 | 901 | ||
884 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); | 902 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); |
885 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | 903 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
@@ -1075,6 +1093,8 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) | |||
1075 | 1093 | ||
1076 | dev->net->netdev_ops = &ax88772_netdev_ops; | 1094 | dev->net->netdev_ops = &ax88772_netdev_ops; |
1077 | dev->net->ethtool_ops = &ax88772_ethtool_ops; | 1095 | dev->net->ethtool_ops = &ax88772_ethtool_ops; |
1096 | dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ | ||
1097 | dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ | ||
1078 | 1098 | ||
1079 | embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); | 1099 | embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); |
1080 | 1100 | ||