aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_input.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-01-29 06:54:01 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-01-29 06:54:01 -0500
commit0ba6c33bcddc64a54b5f1c25a696c4767dc76292 (patch)
tree62e616f97a4762d8e75bf732e4827af2d15d52c5 /net/xfrm/xfrm_input.c
parent21af0297c7e56024a5ccc4d8ad2a590f9ec371ba (diff)
parent85040bcb4643cba578839e953f25e2d1965d83d0 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.25
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.25: (1470 commits) [IPV6] ADDRLABEL: Fix double free on label deletion. [PPP]: Sparse warning fixes. [IPV4] fib_trie: remove unneeded NULL check [IPV4] fib_trie: More whitespace cleanup. [NET_SCHED]: Use nla_policy for attribute validation in ematches [NET_SCHED]: Use nla_policy for attribute validation in actions [NET_SCHED]: Use nla_policy for attribute validation in classifiers [NET_SCHED]: Use nla_policy for attribute validation in packet schedulers [NET_SCHED]: sch_api: introduce constant for rate table size [NET_SCHED]: Use typeful attribute parsing helpers [NET_SCHED]: Use typeful attribute construction helpers [NET_SCHED]: Use NLA_PUT_STRING for string dumping [NET_SCHED]: Use nla_nest_start/nla_nest_end [NET_SCHED]: Propagate nla_parse return value [NET_SCHED]: act_api: use PTR_ERR in tcf_action_init/tcf_action_get [NET_SCHED]: act_api: use nlmsg_parse [NET_SCHED]: act_api: fix netlink API conversion bug [NET_SCHED]: sch_netem: use nla_parse_nested_compat [NET_SCHED]: sch_atm: fix format string warning [NETNS]: Add namespace for ICMP replying code. ...
Diffstat (limited to 'net/xfrm/xfrm_input.c')
-rw-r--r--net/xfrm/xfrm_input.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index cb97fda1b6df..039e7019c48a 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
@@ -81,6 +83,180 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
81} 83}
82EXPORT_SYMBOL(xfrm_parse_spi); 84EXPORT_SYMBOL(xfrm_parse_spi);
83 85
86int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
87{
88 int err;
89
90 err = x->outer_mode->afinfo->extract_input(x, skb);
91 if (err)
92 return err;
93
94 skb->protocol = x->inner_mode->afinfo->eth_proto;
95 return x->inner_mode->input2(x, skb);
96}
97EXPORT_SYMBOL(xfrm_prepare_input);
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 *x;
104 xfrm_address_t *daddr;
105 unsigned int family;
106 int decaps = 0;
107 int async = 0;
108
109 /* A negative encap_type indicates async resumption. */
110 if (encap_type < 0) {
111 async = 1;
112 x = xfrm_input_state(skb);
113 seq = XFRM_SKB_CB(skb)->seq;
114 goto resume;
115 }
116
117 /* Allocate new secpath or COW existing one. */
118 if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
119 struct sec_path *sp;
120
121 sp = secpath_dup(skb->sp);
122 if (!sp) {
123 XFRM_INC_STATS(LINUX_MIB_XFRMINERROR);
124 goto drop;
125 }
126 if (skb->sp)
127 secpath_put(skb->sp);
128 skb->sp = sp;
129 }
130
131 daddr = (xfrm_address_t *)(skb_network_header(skb) +
132 XFRM_SPI_SKB_CB(skb)->daddroff);
133 family = XFRM_SPI_SKB_CB(skb)->family;
134
135 seq = 0;
136 if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) {
137 XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR);
138 goto drop;
139 }
140
141 do {
142 if (skb->sp->len == XFRM_MAX_DEPTH) {
143 XFRM_INC_STATS(LINUX_MIB_XFRMINBUFFERERROR);
144 goto drop;
145 }
146
147 x = xfrm_state_lookup(daddr, spi, nexthdr, family);
148 if (x == NULL) {
149 XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES);
150 xfrm_audit_state_notfound(skb, family, spi, seq);
151 goto drop;
152 }
153
154 skb->sp->xvec[skb->sp->len++] = x;
155
156 spin_lock(&x->lock);
157 if (unlikely(x->km.state != XFRM_STATE_VALID)) {
158 XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEINVALID);
159 goto drop_unlock;
160 }
161
162 if ((x->encap ? x->encap->encap_type : 0) != encap_type) {
163 XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEINVALID);
164 goto drop_unlock;
165 }
166
167 if (x->props.replay_window && xfrm_replay_check(x, skb, seq)) {
168 XFRM_INC_STATS(LINUX_MIB_XFRMINSEQOUTOFWINDOW);
169 goto drop_unlock;
170 }
171
172 if (xfrm_state_check_expire(x)) {
173 XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEEXPIRED);
174 goto drop_unlock;
175 }
176
177 spin_unlock(&x->lock);
178
179 XFRM_SKB_CB(skb)->seq = seq;
180
181 nexthdr = x->type->input(x, skb);
182
183 if (nexthdr == -EINPROGRESS)
184 return 0;
185
186resume:
187 spin_lock(&x->lock);
188 if (nexthdr <= 0) {
189 if (nexthdr == -EBADMSG) {
190 xfrm_audit_state_icvfail(x, skb,
191 x->type->proto);
192 x->stats.integrity_failed++;
193 }
194 XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEPROTOERROR);
195 goto drop_unlock;
196 }
197
198 /* only the first xfrm gets the encap type */
199 encap_type = 0;
200
201 if (x->props.replay_window)
202 xfrm_replay_advance(x, seq);
203
204 x->curlft.bytes += skb->len;
205 x->curlft.packets++;
206
207 spin_unlock(&x->lock);
208
209 XFRM_MODE_SKB_CB(skb)->protocol = nexthdr;
210
211 if (x->inner_mode->input(x, skb)) {
212 XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEMODEERROR);
213 goto drop;
214 }
215
216 if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) {
217 decaps = 1;
218 break;
219 }
220
221 /*
222 * We need the inner address. However, we only get here for
223 * transport mode so the outer address is identical.
224 */
225 daddr = &x->id.daddr;
226 family = x->outer_mode->afinfo->family;
227
228 err = xfrm_parse_spi(skb, nexthdr, &spi, &seq);
229 if (err < 0) {
230 XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR);
231 goto drop;
232 }
233 } while (!err);
234
235 nf_reset(skb);
236
237 if (decaps) {
238 dst_release(skb->dst);
239 skb->dst = NULL;
240 netif_rx(skb);
241 return 0;
242 } else {
243 return x->inner_mode->afinfo->transport_finish(skb, async);
244 }
245
246drop_unlock:
247 spin_unlock(&x->lock);
248drop:
249 kfree_skb(skb);
250 return 0;
251}
252EXPORT_SYMBOL(xfrm_input);
253
254int xfrm_input_resume(struct sk_buff *skb, int nexthdr)
255{
256 return xfrm_input(skb, nexthdr, 0, -1);
257}
258EXPORT_SYMBOL(xfrm_input_resume);
259
84void __init xfrm_input_init(void) 260void __init xfrm_input_init(void)
85{ 261{
86 secpath_cachep = kmem_cache_create("secpath_cache", 262 secpath_cachep = kmem_cache_create("secpath_cache",