aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_output.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-11-14 00:43:11 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:53:48 -0500
commit862b82c6f960cc61274d370aa78ce1112f92a83e (patch)
tree51e252e1525dd7d02a695d428890a4c37fae2442 /net/xfrm/xfrm_output.c
parentef76bc23ef2acf20c8f7f841a542d8ab74c827c6 (diff)
[IPSEC]: Merge most of the output path
As part of the work on asynchrnous cryptographic operations, we need to be able to resume from the spot where they occur. As such, it helps if we isolate them to one spot. This patch moves most of the remaining family-specific processing into the common output code. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/xfrm/xfrm_output.c')
-rw-r--r--net/xfrm/xfrm_output.c70
1 files changed, 67 insertions, 3 deletions
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index b1efdc8850a7..bcb3701c5cf3 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -12,6 +12,7 @@
12#include <linux/errno.h> 12#include <linux/errno.h>
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/netdevice.h> 14#include <linux/netdevice.h>
15#include <linux/netfilter.h>
15#include <linux/skbuff.h> 16#include <linux/skbuff.h>
16#include <linux/spinlock.h> 17#include <linux/spinlock.h>
17#include <net/dst.h> 18#include <net/dst.h>
@@ -40,7 +41,7 @@ err:
40 return err; 41 return err;
41} 42}
42 43
43int xfrm_output(struct sk_buff *skb) 44static int xfrm_output_one(struct sk_buff *skb)
44{ 45{
45 struct dst_entry *dst = skb->dst; 46 struct dst_entry *dst = skb->dst;
46 struct xfrm_state *x = dst->xfrm; 47 struct xfrm_state *x = dst->xfrm;
@@ -87,10 +88,73 @@ int xfrm_output(struct sk_buff *skb)
87 88
88 err = 0; 89 err = 0;
89 90
90error_nolock: 91out_exit:
91 return err; 92 return err;
92error: 93error:
93 spin_unlock_bh(&x->lock); 94 spin_unlock_bh(&x->lock);
94 goto error_nolock; 95error_nolock:
96 kfree_skb(skb);
97 goto out_exit;
98}
99
100static int xfrm_output2(struct sk_buff *skb)
101{
102 int err;
103
104 while (likely((err = xfrm_output_one(skb)) == 0)) {
105 struct xfrm_state *x;
106
107 nf_reset(skb);
108
109 err = skb->dst->ops->local_out(skb);
110 if (unlikely(err != 1))
111 break;
112
113 x = skb->dst->xfrm;
114 if (!x)
115 return dst_output(skb);
116
117 err = nf_hook(x->inner_mode->afinfo->family,
118 x->inner_mode->afinfo->nf_post_routing, skb,
119 NULL, skb->dst->dev, xfrm_output2);
120 if (unlikely(err != 1))
121 break;
122 }
123
124 return err;
125}
126
127int xfrm_output(struct sk_buff *skb)
128{
129 struct sk_buff *segs;
130
131 if (!skb_is_gso(skb))
132 return xfrm_output2(skb);
133
134 segs = skb_gso_segment(skb, 0);
135 kfree_skb(skb);
136 if (unlikely(IS_ERR(segs)))
137 return PTR_ERR(segs);
138
139 do {
140 struct sk_buff *nskb = segs->next;
141 int err;
142
143 segs->next = NULL;
144 err = xfrm_output2(segs);
145
146 if (unlikely(err)) {
147 while ((segs = nskb)) {
148 nskb = segs->next;
149 segs->next = NULL;
150 kfree_skb(segs);
151 }
152 return err;
153 }
154
155 segs = nskb;
156 } while (segs);
157
158 return 0;
95} 159}
96EXPORT_SYMBOL_GPL(xfrm_output); 160EXPORT_SYMBOL_GPL(xfrm_output);