aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/exthdrs.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/exthdrs.c')
-rw-r--r--net/ipv6/exthdrs.c69
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
245looped_back: 248looped_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);