diff options
Diffstat (limited to 'net/ipv6/exthdrs.c')
-rw-r--r-- | net/ipv6/exthdrs.c | 69 |
1 files changed, 61 insertions, 8 deletions
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 05afa6b1912b..8d3a0e17314d 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
@@ -43,6 +43,9 @@ | |||
43 | #include <net/ndisc.h> | 43 | #include <net/ndisc.h> |
44 | #include <net/ip6_route.h> | 44 | #include <net/ip6_route.h> |
45 | #include <net/addrconf.h> | 45 | #include <net/addrconf.h> |
46 | #ifdef CONFIG_IPV6_MIP6 | ||
47 | #include <net/xfrm.h> | ||
48 | #endif | ||
46 | 49 | ||
47 | #include <asm/uaccess.h> | 50 | #include <asm/uaccess.h> |
48 | 51 | ||
@@ -219,7 +222,7 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp) | |||
219 | { | 222 | { |
220 | struct sk_buff *skb = *skbp; | 223 | struct sk_buff *skb = *skbp; |
221 | struct inet6_skb_parm *opt = IP6CB(skb); | 224 | struct inet6_skb_parm *opt = IP6CB(skb); |
222 | struct in6_addr *addr; | 225 | struct in6_addr *addr = NULL; |
223 | struct in6_addr daddr; | 226 | struct in6_addr daddr; |
224 | int n, i; | 227 | int n, i; |
225 | 228 | ||
@@ -244,6 +247,23 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp) | |||
244 | 247 | ||
245 | looped_back: | 248 | looped_back: |
246 | if (hdr->segments_left == 0) { | 249 | if (hdr->segments_left == 0) { |
250 | switch (hdr->type) { | ||
251 | #ifdef CONFIG_IPV6_MIP6 | ||
252 | case IPV6_SRCRT_TYPE_2: | ||
253 | /* Silently discard type 2 header unless it was | ||
254 | * processed by own | ||
255 | */ | ||
256 | if (!addr) { | ||
257 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | ||
258 | kfree_skb(skb); | ||
259 | return -1; | ||
260 | } | ||
261 | break; | ||
262 | #endif | ||
263 | default: | ||
264 | break; | ||
265 | } | ||
266 | |||
247 | opt->lastopt = skb->h.raw - skb->nh.raw; | 267 | opt->lastopt = skb->h.raw - skb->nh.raw; |
248 | opt->srcrt = skb->h.raw - skb->nh.raw; | 268 | opt->srcrt = skb->h.raw - skb->nh.raw; |
249 | skb->h.raw += (hdr->hdrlen + 1) << 3; | 269 | skb->h.raw += (hdr->hdrlen + 1) << 3; |
@@ -253,17 +273,29 @@ looped_back: | |||
253 | return 1; | 273 | return 1; |
254 | } | 274 | } |
255 | 275 | ||
256 | if (hdr->type != IPV6_SRCRT_TYPE_0) { | 276 | switch (hdr->type) { |
277 | case IPV6_SRCRT_TYPE_0: | ||
278 | if (hdr->hdrlen & 0x01) { | ||
279 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | ||
280 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw); | ||
281 | return -1; | ||
282 | } | ||
283 | break; | ||
284 | #ifdef CONFIG_IPV6_MIP6 | ||
285 | case IPV6_SRCRT_TYPE_2: | ||
286 | /* Silently discard invalid RTH type 2 */ | ||
287 | if (hdr->hdrlen != 2 || hdr->segments_left != 1) { | ||
288 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | ||
289 | kfree_skb(skb); | ||
290 | return -1; | ||
291 | } | ||
292 | break; | ||
293 | #endif | ||
294 | default: | ||
257 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 295 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); |
258 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw); | 296 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw); |
259 | return -1; | 297 | return -1; |
260 | } | 298 | } |
261 | |||
262 | if (hdr->hdrlen & 0x01) { | ||
263 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | ||
264 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw); | ||
265 | return -1; | ||
266 | } | ||
267 | 299 | ||
268 | /* | 300 | /* |
269 | * This is the routing header forwarding algorithm from | 301 | * This is the routing header forwarding algorithm from |
@@ -303,6 +335,27 @@ looped_back: | |||
303 | addr = rthdr->addr; | 335 | addr = rthdr->addr; |
304 | addr += i - 1; | 336 | addr += i - 1; |
305 | 337 | ||
338 | switch (hdr->type) { | ||
339 | #ifdef CONFIG_IPV6_MIP6 | ||
340 | case IPV6_SRCRT_TYPE_2: | ||
341 | if (xfrm6_input_addr(skb, (xfrm_address_t *)addr, | ||
342 | (xfrm_address_t *)&skb->nh.ipv6h->saddr, | ||
343 | IPPROTO_ROUTING) < 0) { | ||
344 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | ||
345 | kfree_skb(skb); | ||
346 | return -1; | ||
347 | } | ||
348 | if (!ipv6_chk_home_addr(addr)) { | ||
349 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | ||
350 | kfree_skb(skb); | ||
351 | return -1; | ||
352 | } | ||
353 | break; | ||
354 | #endif | ||
355 | default: | ||
356 | break; | ||
357 | } | ||
358 | |||
306 | if (ipv6_addr_is_multicast(addr)) { | 359 | if (ipv6_addr_is_multicast(addr)) { |
307 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | 360 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); |
308 | kfree_skb(skb); | 361 | kfree_skb(skb); |