diff options
| -rw-r--r-- | include/linux/if_vlan.h | 18 | ||||
| -rw-r--r-- | net/8021q/vlan_dev.c | 34 |
2 files changed, 8 insertions, 44 deletions
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index d36515dae62f..93f5d9b0e9f9 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h | |||
| @@ -185,22 +185,10 @@ static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci) | |||
| 185 | { | 185 | { |
| 186 | struct vlan_ethhdr *veth; | 186 | struct vlan_ethhdr *veth; |
| 187 | 187 | ||
| 188 | if (skb_headroom(skb) < VLAN_HLEN) { | 188 | if (skb_cow_head(skb, VLAN_HLEN) < 0) { |
| 189 | struct sk_buff *sk_tmp = skb; | 189 | kfree_skb(skb); |
| 190 | skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN); | 190 | return NULL; |
| 191 | kfree_skb(sk_tmp); | ||
| 192 | if (!skb) { | ||
| 193 | printk(KERN_ERR "vlan: failed to realloc headroom\n"); | ||
| 194 | return NULL; | ||
| 195 | } | ||
| 196 | } else { | ||
| 197 | skb = skb_unshare(skb, GFP_ATOMIC); | ||
| 198 | if (!skb) { | ||
| 199 | printk(KERN_ERR "vlan: failed to unshare skbuff\n"); | ||
| 200 | return NULL; | ||
| 201 | } | ||
| 202 | } | 191 | } |
| 203 | |||
| 204 | veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN); | 192 | veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN); |
| 205 | 193 | ||
| 206 | /* Move the mac addresses to the beginning of the new header. */ | 194 | /* Move the mac addresses to the beginning of the new header. */ |
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 2ccac6bea57e..b6e52c025fd8 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
| @@ -74,11 +74,8 @@ static int vlan_dev_rebuild_header(struct sk_buff *skb) | |||
| 74 | static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb) | 74 | static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb) |
| 75 | { | 75 | { |
| 76 | if (vlan_dev_info(skb->dev)->flags & VLAN_FLAG_REORDER_HDR) { | 76 | if (vlan_dev_info(skb->dev)->flags & VLAN_FLAG_REORDER_HDR) { |
| 77 | if (skb_shared(skb) || skb_cloned(skb)) { | 77 | if (skb_cow(skb, skb_headroom(skb)) < 0) |
| 78 | struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); | 78 | skb = NULL; |
| 79 | kfree_skb(skb); | ||
| 80 | skb = nskb; | ||
| 81 | } | ||
| 82 | if (skb) { | 79 | if (skb) { |
| 83 | /* Lifted from Gleb's VLAN code... */ | 80 | /* Lifted from Gleb's VLAN code... */ |
| 84 | memmove(skb->data - ETH_HLEN, | 81 | memmove(skb->data - ETH_HLEN, |
| @@ -262,12 +259,14 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, | |||
| 262 | u16 vlan_tci = 0; | 259 | u16 vlan_tci = 0; |
| 263 | int rc = 0; | 260 | int rc = 0; |
| 264 | int build_vlan_header = 0; | 261 | int build_vlan_header = 0; |
| 265 | struct net_device *vdev = dev; | ||
| 266 | 262 | ||
| 267 | pr_debug("%s: skb: %p type: %hx len: %u vlan_id: %hx, daddr: %p\n", | 263 | pr_debug("%s: skb: %p type: %hx len: %u vlan_id: %hx, daddr: %p\n", |
| 268 | __func__, skb, type, len, vlan_dev_info(dev)->vlan_id, | 264 | __func__, skb, type, len, vlan_dev_info(dev)->vlan_id, |
| 269 | daddr); | 265 | daddr); |
| 270 | 266 | ||
| 267 | if (WARN_ON(skb_headroom(skb) < dev->hard_header_len)) | ||
| 268 | return -ENOSPC; | ||
| 269 | |||
| 271 | /* build vlan header only if re_order_header flag is NOT set. This | 270 | /* build vlan header only if re_order_header flag is NOT set. This |
| 272 | * fixes some programs that get confused when they see a VLAN device | 271 | * fixes some programs that get confused when they see a VLAN device |
| 273 | * sending a frame that is VLAN encoded (the consensus is that the VLAN | 272 | * sending a frame that is VLAN encoded (the consensus is that the VLAN |
| @@ -316,29 +315,6 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, | |||
| 316 | 315 | ||
| 317 | dev = vlan_dev_info(dev)->real_dev; | 316 | dev = vlan_dev_info(dev)->real_dev; |
| 318 | 317 | ||
| 319 | /* MPLS can send us skbuffs w/out enough space. This check will grow | ||
| 320 | * the skb if it doesn't have enough headroom. Not a beautiful solution, | ||
| 321 | * so I'll tick a counter so that users can know it's happening... | ||
| 322 | * If they care... | ||
| 323 | */ | ||
| 324 | |||
| 325 | /* NOTE: This may still break if the underlying device is not the final | ||
| 326 | * device (and thus there are more headers to add...) It should work for | ||
| 327 | * good-ole-ethernet though. | ||
| 328 | */ | ||
| 329 | if (skb_headroom(skb) < dev->hard_header_len) { | ||
| 330 | struct sk_buff *sk_tmp = skb; | ||
| 331 | skb = skb_realloc_headroom(sk_tmp, dev->hard_header_len); | ||
| 332 | kfree_skb(sk_tmp); | ||
| 333 | if (skb == NULL) { | ||
| 334 | struct net_device_stats *stats = &vdev->stats; | ||
| 335 | stats->tx_dropped++; | ||
| 336 | return -ENOMEM; | ||
| 337 | } | ||
| 338 | vlan_dev_info(vdev)->cnt_inc_headroom_on_tx++; | ||
| 339 | pr_debug("%s: %s: had to grow skb\n", __func__, vdev->name); | ||
| 340 | } | ||
| 341 | |||
| 342 | if (build_vlan_header) { | 318 | if (build_vlan_header) { |
| 343 | /* Now make the underlying real hard header */ | 319 | /* Now make the underlying real hard header */ |
| 344 | rc = dev_hard_header(skb, dev, ETH_P_8021Q, daddr, saddr, | 320 | rc = dev_hard_header(skb, dev, ETH_P_8021Q, daddr, saddr, |
