diff options
author | Olof Johansson <olof@lixom.net> | 2012-03-08 09:27:07 -0800 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2012-03-08 09:27:07 -0800 |
commit | a58f67e70a6cad021ceebd1c8919b898dd5d5de3 (patch) | |
tree | 78cb630cb31a8cbec17463f9acc0f766707c232f /net/netfilter/nf_queue.c | |
parent | 4c6c826b22da9f6408b6bc6939a92aa0be838488 (diff) | |
parent | 46e446db4fb2cdb2f1bc69d3981fa23738a42835 (diff) |
Merge branch 'dt' of git://github.com/hzhuang1/linux into next/dt
* 'dt' of git://github.com/hzhuang1/linux: (6 commits)
Document: devicetree: add OF documents for arch-mmp
ARM: dts: append DTS file of pxa168
ARM: mmp: append OF support on pxa168
ARM: mmp: enable rtc clk in pxa168
i2c: pxa: add OF support
serial: pxa: add OF support
(plus update to v3.3-rc6)
Diffstat (limited to 'net/netfilter/nf_queue.c')
-rw-r--r-- | net/netfilter/nf_queue.c | 40 |
1 files changed, 32 insertions, 8 deletions
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index b3a7db678b8..ce60cf0f6c1 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -203,6 +203,27 @@ err: return status; } +#ifdef CONFIG_BRIDGE_NETFILTER +/* When called from bridge netfilter, skb->data must point to MAC header + * before calling skb_gso_segment(). Else, original MAC header is lost + * and segmented skbs will be sent to wrong destination. + */ +static void nf_bridge_adjust_skb_data(struct sk_buff *skb) +{ + if (skb->nf_bridge) + __skb_push(skb, skb->network_header - skb->mac_header); +} + +static void nf_bridge_adjust_segmented_data(struct sk_buff *skb) +{ + if (skb->nf_bridge) + __skb_pull(skb, skb->network_header - skb->mac_header); +} +#else +#define nf_bridge_adjust_skb_data(s) do {} while (0) +#define nf_bridge_adjust_segmented_data(s) do {} while (0) +#endif + int nf_queue(struct sk_buff *skb, struct list_head *elem, u_int8_t pf, unsigned int hook, @@ -212,7 +233,7 @@ int nf_queue(struct sk_buff *skb, unsigned int queuenum) { struct sk_buff *segs; - int err; + int err = -EINVAL; unsigned int queued; if (!skb_is_gso(skb)) @@ -228,23 +249,25 @@ int nf_queue(struct sk_buff *skb, break; } + nf_bridge_adjust_skb_data(skb); segs = skb_gso_segment(skb, 0); /* Does not use PTR_ERR to limit the number of error codes that can be * returned by nf_queue. For instance, callers rely on -ECANCELED to mean * 'ignore this hook'. */ if (IS_ERR(segs)) - return -EINVAL; - + goto out_err; queued = 0; err = 0; do { struct sk_buff *nskb = segs->next; segs->next = NULL; - if (err == 0) + if (err == 0) { + nf_bridge_adjust_segmented_data(segs); err = __nf_queue(segs, elem, pf, hook, indev, outdev, okfn, queuenum); + } if (err == 0) queued++; else @@ -252,11 +275,12 @@ int nf_queue(struct sk_buff *skb, segs = nskb; } while (segs); - /* also free orig skb if only some segments were queued */ - if (unlikely(err && queued)) - err = 0; - if (err == 0) + if (queued) { kfree_skb(skb); + return 0; + } + out_err: + nf_bridge_adjust_segmented_data(skb); return err; } |