diff options
author | Stephen Hemminger <shemminger@osdl.org> | 2006-01-06 16:13:29 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-01-06 16:13:29 -0500 |
commit | ee02b3a613a692a40e0f48a25d9d60cc751ebbe5 (patch) | |
tree | 51c034027c96a213ac53cd831dee4cb24fd0ed17 /net | |
parent | a20a8554796bc4e28879beabd0db4bf3ce77b686 (diff) |
[BRIDGE] netfilter: vlan + hw checksum = bug?
It looks like the bridge netfilter code does not correctly update
the hardware checksum after popping off the VLAN header.
This is by inspection, I have *not* tested this.
To test you would need to set up a filtering bridge with vlans
and a device the does hardware receive checksum (skge, or sungem)
Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/bridge/br_netfilter.c | 13 |
1 files changed, 9 insertions, 4 deletions
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 223f8270daee..7cac3fb9f809 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
@@ -394,8 +394,9 @@ inhdr_error: | |||
394 | * target in particular. Save the original destination IP | 394 | * target in particular. Save the original destination IP |
395 | * address to be able to detect DNAT afterwards. */ | 395 | * address to be able to detect DNAT afterwards. */ |
396 | static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, | 396 | static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, |
397 | const struct net_device *in, const struct net_device *out, | 397 | const struct net_device *in, |
398 | int (*okfn)(struct sk_buff *)) | 398 | const struct net_device *out, |
399 | int (*okfn)(struct sk_buff *)) | ||
399 | { | 400 | { |
400 | struct iphdr *iph; | 401 | struct iphdr *iph; |
401 | __u32 len; | 402 | __u32 len; |
@@ -412,8 +413,10 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, | |||
412 | goto out; | 413 | goto out; |
413 | 414 | ||
414 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { | 415 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { |
416 | u8 *vhdr = skb->data; | ||
415 | skb_pull(skb, VLAN_HLEN); | 417 | skb_pull(skb, VLAN_HLEN); |
416 | (skb)->nh.raw += VLAN_HLEN; | 418 | skb_postpull_rcsum(skb, vhdr, VLAN_HLEN); |
419 | skb->nh.raw += VLAN_HLEN; | ||
417 | } | 420 | } |
418 | return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn); | 421 | return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn); |
419 | } | 422 | } |
@@ -429,8 +432,10 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, | |||
429 | goto out; | 432 | goto out; |
430 | 433 | ||
431 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { | 434 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { |
435 | u8 *vhdr = skb->data; | ||
432 | skb_pull(skb, VLAN_HLEN); | 436 | skb_pull(skb, VLAN_HLEN); |
433 | (skb)->nh.raw += VLAN_HLEN; | 437 | skb_postpull_rcsum(skb, vhdr, VLAN_HLEN); |
438 | skb->nh.raw += VLAN_HLEN; | ||
434 | } | 439 | } |
435 | 440 | ||
436 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | 441 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) |