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 | |
| 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>
| -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))) |
