aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-11-14 00:44:23 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:53:50 -0500
commit716062fd4c2f88a33ab409f62a1e7397ad0a7e33 (patch)
tree73f2618fe99bca3870a0dbdc35acf6466ab3b976 /net/xfrm
parentc6581a457e661b7070e484ad723bbf555b17aca2 (diff)
[IPSEC]: Merge most of the input path
As part of the work on asynchronous 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 input 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')
-rw-r--r--net/xfrm/xfrm_input.c113
1 files changed, 113 insertions, 0 deletions
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index 4c803f7e74e5..b980095be935 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -9,6 +9,8 @@
9 9
10#include <linux/slab.h> 10#include <linux/slab.h>
11#include <linux/module.h> 11#include <linux/module.h>
12#include <linux/netdevice.h>
13#include <net/dst.h>
12#include <net/ip.h> 14#include <net/ip.h>
13#include <net/xfrm.h> 15#include <net/xfrm.h>
14 16
@@ -94,6 +96,117 @@ int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
94} 96}
95EXPORT_SYMBOL(xfrm_prepare_input); 97EXPORT_SYMBOL(xfrm_prepare_input);
96 98
99int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
100{
101 int err;
102 __be32 seq;
103 struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
104 struct xfrm_state *x;
105 int xfrm_nr = 0;
106 int decaps = 0;
107 unsigned int nhoff = XFRM_SPI_SKB_CB(skb)->nhoff;
108 unsigned int daddroff = XFRM_SPI_SKB_CB(skb)->daddroff;
109
110 seq = 0;
111 if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0)
112 goto drop;
113
114 do {
115 if (xfrm_nr == XFRM_MAX_DEPTH)
116 goto drop;
117
118 x = xfrm_state_lookup((xfrm_address_t *)
119 (skb_network_header(skb) + daddroff),
120 spi, nexthdr, AF_INET);
121 if (x == NULL)
122 goto drop;
123
124 spin_lock(&x->lock);
125 if (unlikely(x->km.state != XFRM_STATE_VALID))
126 goto drop_unlock;
127
128 if ((x->encap ? x->encap->encap_type : 0) != encap_type)
129 goto drop_unlock;
130
131 if (x->props.replay_window && xfrm_replay_check(x, seq))
132 goto drop_unlock;
133
134 if (xfrm_state_check_expire(x))
135 goto drop_unlock;
136
137 nexthdr = x->type->input(x, skb);
138 if (nexthdr <= 0)
139 goto drop_unlock;
140
141 skb_network_header(skb)[nhoff] = nexthdr;
142
143 /* only the first xfrm gets the encap type */
144 encap_type = 0;
145
146 if (x->props.replay_window)
147 xfrm_replay_advance(x, seq);
148
149 x->curlft.bytes += skb->len;
150 x->curlft.packets++;
151
152 spin_unlock(&x->lock);
153
154 xfrm_vec[xfrm_nr++] = x;
155
156 if (x->inner_mode->input(x, skb))
157 goto drop;
158
159 if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) {
160 decaps = 1;
161 break;
162 }
163
164 err = xfrm_parse_spi(skb, nexthdr, &spi, &seq);
165 if (err < 0)
166 goto drop;
167 } while (!err);
168
169 /* Allocate new secpath or COW existing one. */
170
171 if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
172 struct sec_path *sp;
173 sp = secpath_dup(skb->sp);
174 if (!sp)
175 goto drop;
176 if (skb->sp)
177 secpath_put(skb->sp);
178 skb->sp = sp;
179 }
180 if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
181 goto drop;
182
183 memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec,
184 xfrm_nr * sizeof(xfrm_vec[0]));
185 skb->sp->len += xfrm_nr;
186
187 nf_reset(skb);
188
189 if (decaps) {
190 dst_release(skb->dst);
191 skb->dst = NULL;
192 netif_rx(skb);
193 return 0;
194 } else {
195 return x->inner_mode->afinfo->transport_finish(skb, 0);
196 }
197
198drop_unlock:
199 spin_unlock(&x->lock);
200 xfrm_state_put(x);
201drop:
202 while (--xfrm_nr >= 0)
203 xfrm_state_put(xfrm_vec[xfrm_nr]);
204
205 kfree_skb(skb);
206 return 0;
207}
208EXPORT_SYMBOL(xfrm_input);
209
97void __init xfrm_input_init(void) 210void __init xfrm_input_init(void)
98{ 211{
99 secpath_cachep = kmem_cache_create("secpath_cache", 212 secpath_cachep = kmem_cache_create("secpath_cache",