diff options
-rw-r--r-- | include/linux/xfrm.h | 1 | ||||
-rw-r--r-- | include/net/xfrm.h | 2 | ||||
-rw-r--r-- | net/ipv6/ipv6_syms.c | 1 | ||||
-rw-r--r-- | net/ipv6/xfrm6_input.c | 108 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 1 |
5 files changed, 113 insertions, 0 deletions
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 66343d3d4b91..a7c9e4cfb15b 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h | |||
@@ -256,6 +256,7 @@ struct xfrm_usersa_info { | |||
256 | #define XFRM_STATE_NOECN 1 | 256 | #define XFRM_STATE_NOECN 1 |
257 | #define XFRM_STATE_DECAP_DSCP 2 | 257 | #define XFRM_STATE_DECAP_DSCP 2 |
258 | #define XFRM_STATE_NOPMTUDISC 4 | 258 | #define XFRM_STATE_NOPMTUDISC 4 |
259 | #define XFRM_STATE_WILDRECV 8 | ||
259 | }; | 260 | }; |
260 | 261 | ||
261 | struct xfrm_usersa_id { | 262 | struct xfrm_usersa_id { |
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index eed48f832ce1..0d735a5aba61 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -955,6 +955,8 @@ extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler); | |||
955 | extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler); | 955 | extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler); |
956 | extern int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi); | 956 | extern int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi); |
957 | extern int xfrm6_rcv(struct sk_buff **pskb); | 957 | extern int xfrm6_rcv(struct sk_buff **pskb); |
958 | extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, | ||
959 | xfrm_address_t *saddr, u8 proto); | ||
958 | extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler); | 960 | extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler); |
959 | extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler); | 961 | extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler); |
960 | extern u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr); | 962 | extern u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr); |
diff --git a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c index e1a741612888..7b7b90d9c3d0 100644 --- a/net/ipv6/ipv6_syms.c +++ b/net/ipv6/ipv6_syms.c | |||
@@ -31,6 +31,7 @@ EXPORT_SYMBOL(ipv6_chk_addr); | |||
31 | EXPORT_SYMBOL(in6_dev_finish_destroy); | 31 | EXPORT_SYMBOL(in6_dev_finish_destroy); |
32 | #ifdef CONFIG_XFRM | 32 | #ifdef CONFIG_XFRM |
33 | EXPORT_SYMBOL(xfrm6_rcv); | 33 | EXPORT_SYMBOL(xfrm6_rcv); |
34 | EXPORT_SYMBOL(xfrm6_input_addr); | ||
34 | EXPORT_SYMBOL(xfrm6_find_1stfragopt); | 35 | EXPORT_SYMBOL(xfrm6_find_1stfragopt); |
35 | #endif | 36 | #endif |
36 | EXPORT_SYMBOL(rt6_lookup); | 37 | EXPORT_SYMBOL(rt6_lookup); |
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index ee2f6b3908b6..a40a05789013 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c | |||
@@ -138,3 +138,111 @@ int xfrm6_rcv(struct sk_buff **pskb) | |||
138 | { | 138 | { |
139 | return xfrm6_rcv_spi(*pskb, 0); | 139 | return xfrm6_rcv_spi(*pskb, 0); |
140 | } | 140 | } |
141 | |||
142 | int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, | ||
143 | xfrm_address_t *saddr, u8 proto) | ||
144 | { | ||
145 | struct xfrm_state *x = NULL; | ||
146 | int wildcard = 0; | ||
147 | struct in6_addr any; | ||
148 | xfrm_address_t *xany; | ||
149 | struct xfrm_state *xfrm_vec_one = NULL; | ||
150 | int nh = 0; | ||
151 | int i = 0; | ||
152 | |||
153 | ipv6_addr_set(&any, 0, 0, 0, 0); | ||
154 | xany = (xfrm_address_t *)&any; | ||
155 | |||
156 | for (i = 0; i < 3; i++) { | ||
157 | xfrm_address_t *dst, *src; | ||
158 | switch (i) { | ||
159 | case 0: | ||
160 | dst = daddr; | ||
161 | src = saddr; | ||
162 | break; | ||
163 | case 1: | ||
164 | /* lookup state with wild-card source address */ | ||
165 | wildcard = 1; | ||
166 | dst = daddr; | ||
167 | src = xany; | ||
168 | break; | ||
169 | case 2: | ||
170 | default: | ||
171 | /* lookup state with wild-card addresses */ | ||
172 | wildcard = 1; /* XXX */ | ||
173 | dst = xany; | ||
174 | src = xany; | ||
175 | break; | ||
176 | } | ||
177 | |||
178 | x = xfrm_state_lookup_byaddr(dst, src, proto, AF_INET6); | ||
179 | if (!x) | ||
180 | continue; | ||
181 | |||
182 | spin_lock(&x->lock); | ||
183 | |||
184 | if (wildcard) { | ||
185 | if ((x->props.flags & XFRM_STATE_WILDRECV) == 0) { | ||
186 | spin_unlock(&x->lock); | ||
187 | xfrm_state_put(x); | ||
188 | x = NULL; | ||
189 | continue; | ||
190 | } | ||
191 | } | ||
192 | |||
193 | if (unlikely(x->km.state != XFRM_STATE_VALID)) { | ||
194 | spin_unlock(&x->lock); | ||
195 | xfrm_state_put(x); | ||
196 | x = NULL; | ||
197 | continue; | ||
198 | } | ||
199 | if (xfrm_state_check_expire(x)) { | ||
200 | spin_unlock(&x->lock); | ||
201 | xfrm_state_put(x); | ||
202 | x = NULL; | ||
203 | continue; | ||
204 | } | ||
205 | |||
206 | nh = x->type->input(x, skb); | ||
207 | if (nh <= 0) { | ||
208 | spin_unlock(&x->lock); | ||
209 | xfrm_state_put(x); | ||
210 | x = NULL; | ||
211 | continue; | ||
212 | } | ||
213 | |||
214 | x->curlft.bytes += skb->len; | ||
215 | x->curlft.packets++; | ||
216 | |||
217 | spin_unlock(&x->lock); | ||
218 | |||
219 | xfrm_vec_one = x; | ||
220 | break; | ||
221 | } | ||
222 | |||
223 | if (!xfrm_vec_one) | ||
224 | goto drop; | ||
225 | |||
226 | /* Allocate new secpath or COW existing one. */ | ||
227 | if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { | ||
228 | struct sec_path *sp; | ||
229 | sp = secpath_dup(skb->sp); | ||
230 | if (!sp) | ||
231 | goto drop; | ||
232 | if (skb->sp) | ||
233 | secpath_put(skb->sp); | ||
234 | skb->sp = sp; | ||
235 | } | ||
236 | |||
237 | if (1 + skb->sp->len > XFRM_MAX_DEPTH) | ||
238 | goto drop; | ||
239 | |||
240 | skb->sp->xvec[skb->sp->len] = xfrm_vec_one; | ||
241 | skb->sp->len ++; | ||
242 | |||
243 | return 1; | ||
244 | drop: | ||
245 | if (xfrm_vec_one) | ||
246 | xfrm_state_put(xfrm_vec_one); | ||
247 | return -1; | ||
248 | } | ||
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 11f480b12952..f05371556cce 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -352,6 +352,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
352 | list_for_each_entry(x, xfrm_state_bydst+h, bydst) { | 352 | list_for_each_entry(x, xfrm_state_bydst+h, bydst) { |
353 | if (x->props.family == family && | 353 | if (x->props.family == family && |
354 | x->props.reqid == tmpl->reqid && | 354 | x->props.reqid == tmpl->reqid && |
355 | !(x->props.flags & XFRM_STATE_WILDRECV) && | ||
355 | xfrm_state_addr_check(x, daddr, saddr, family) && | 356 | xfrm_state_addr_check(x, daddr, saddr, family) && |
356 | tmpl->mode == x->props.mode && | 357 | tmpl->mode == x->props.mode && |
357 | tmpl->id.proto == x->id.proto && | 358 | tmpl->id.proto == x->id.proto && |