diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-29 06:54:01 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-29 06:54:01 -0500 |
commit | 0ba6c33bcddc64a54b5f1c25a696c4767dc76292 (patch) | |
tree | 62e616f97a4762d8e75bf732e4827af2d15d52c5 /net/xfrm/xfrm_input.c | |
parent | 21af0297c7e56024a5ccc4d8ad2a590f9ec371ba (diff) | |
parent | 85040bcb4643cba578839e953f25e2d1965d83d0 (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.c | 176 |
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 | } |
82 | EXPORT_SYMBOL(xfrm_parse_spi); | 84 | EXPORT_SYMBOL(xfrm_parse_spi); |
83 | 85 | ||
86 | int 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 | } | ||
97 | EXPORT_SYMBOL(xfrm_prepare_input); | ||
98 | |||
99 | int 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 | |||
186 | resume: | ||
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 | |||
246 | drop_unlock: | ||
247 | spin_unlock(&x->lock); | ||
248 | drop: | ||
249 | kfree_skb(skb); | ||
250 | return 0; | ||
251 | } | ||
252 | EXPORT_SYMBOL(xfrm_input); | ||
253 | |||
254 | int xfrm_input_resume(struct sk_buff *skb, int nexthdr) | ||
255 | { | ||
256 | return xfrm_input(skb, nexthdr, 0, -1); | ||
257 | } | ||
258 | EXPORT_SYMBOL(xfrm_input_resume); | ||
259 | |||
84 | void __init xfrm_input_init(void) | 260 | void __init xfrm_input_init(void) |
85 | { | 261 | { |
86 | secpath_cachep = kmem_cache_create("secpath_cache", | 262 | secpath_cachep = kmem_cache_create("secpath_cache", |