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.c140
1 files changed, 24 insertions, 116 deletions
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 14be0b9b77a5..c82d4d49f71f 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -42,7 +42,7 @@
42#include <net/ndisc.h> 42#include <net/ndisc.h>
43#include <net/ip6_route.h> 43#include <net/ip6_route.h>
44#include <net/addrconf.h> 44#include <net/addrconf.h>
45#ifdef CONFIG_IPV6_MIP6 45#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
46#include <net/xfrm.h> 46#include <net/xfrm.h>
47#endif 47#endif
48 48
@@ -90,6 +90,7 @@ int ipv6_find_tlv(struct sk_buff *skb, int offset, int type)
90 bad: 90 bad:
91 return -1; 91 return -1;
92} 92}
93EXPORT_SYMBOL_GPL(ipv6_find_tlv);
93 94
94/* 95/*
95 * Parsing tlv encoded headers. 96 * Parsing tlv encoded headers.
@@ -196,7 +197,7 @@ bad:
196 Destination options header. 197 Destination options header.
197 *****************************/ 198 *****************************/
198 199
199#ifdef CONFIG_IPV6_MIP6 200#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
200static int ipv6_dest_hao(struct sk_buff **skbp, int optoff) 201static int ipv6_dest_hao(struct sk_buff **skbp, int optoff)
201{ 202{
202 struct sk_buff *skb = *skbp; 203 struct sk_buff *skb = *skbp;
@@ -270,7 +271,7 @@ static int ipv6_dest_hao(struct sk_buff **skbp, int optoff)
270#endif 271#endif
271 272
272static struct tlvtype_proc tlvprocdestopt_lst[] = { 273static struct tlvtype_proc tlvprocdestopt_lst[] = {
273#ifdef CONFIG_IPV6_MIP6 274#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
274 { 275 {
275 .type = IPV6_TLV_HAO, 276 .type = IPV6_TLV_HAO,
276 .func = ipv6_dest_hao, 277 .func = ipv6_dest_hao,
@@ -283,7 +284,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp)
283{ 284{
284 struct sk_buff *skb = *skbp; 285 struct sk_buff *skb = *skbp;
285 struct inet6_skb_parm *opt = IP6CB(skb); 286 struct inet6_skb_parm *opt = IP6CB(skb);
286#ifdef CONFIG_IPV6_MIP6 287#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
287 __u16 dstbuf; 288 __u16 dstbuf;
288#endif 289#endif
289 struct dst_entry *dst; 290 struct dst_entry *dst;
@@ -298,7 +299,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp)
298 } 299 }
299 300
300 opt->lastopt = opt->dst1 = skb_network_header_len(skb); 301 opt->lastopt = opt->dst1 = skb_network_header_len(skb);
301#ifdef CONFIG_IPV6_MIP6 302#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
302 dstbuf = opt->dst1; 303 dstbuf = opt->dst1;
303#endif 304#endif
304 305
@@ -308,7 +309,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp)
308 skb = *skbp; 309 skb = *skbp;
309 skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3; 310 skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
310 opt = IP6CB(skb); 311 opt = IP6CB(skb);
311#ifdef CONFIG_IPV6_MIP6 312#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
312 opt->nhoff = dstbuf; 313 opt->nhoff = dstbuf;
313#else 314#else
314 opt->nhoff = opt->dst1; 315 opt->nhoff = opt->dst1;
@@ -371,22 +372,13 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
371 struct rt0_hdr *rthdr; 372 struct rt0_hdr *rthdr;
372 int accept_source_route = ipv6_devconf.accept_source_route; 373 int accept_source_route = ipv6_devconf.accept_source_route;
373 374
374 if (accept_source_route < 0 || 375 idev = in6_dev_get(skb->dev);
375 ((idev = in6_dev_get(skb->dev)) == NULL)) { 376 if (idev) {
376 kfree_skb(skb); 377 if (accept_source_route > idev->cnf.accept_source_route)
377 return -1; 378 accept_source_route = idev->cnf.accept_source_route;
378 }
379 if (idev->cnf.accept_source_route < 0) {
380 in6_dev_put(idev); 379 in6_dev_put(idev);
381 kfree_skb(skb);
382 return -1;
383 } 380 }
384 381
385 if (accept_source_route > idev->cnf.accept_source_route)
386 accept_source_route = idev->cnf.accept_source_route;
387
388 in6_dev_put(idev);
389
390 if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) || 382 if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
391 !pskb_may_pull(skb, (skb_transport_offset(skb) + 383 !pskb_may_pull(skb, (skb_transport_offset(skb) +
392 ((skb_transport_header(skb)[1] + 1) << 3)))) { 384 ((skb_transport_header(skb)[1] + 1) << 3)))) {
@@ -398,24 +390,6 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
398 390
399 hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb); 391 hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);
400 392
401 switch (hdr->type) {
402#ifdef CONFIG_IPV6_MIP6
403 case IPV6_SRCRT_TYPE_2:
404 break;
405#endif
406 case IPV6_SRCRT_TYPE_0:
407 if (accept_source_route > 0)
408 break;
409 kfree_skb(skb);
410 return -1;
411 default:
412 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
413 IPSTATS_MIB_INHDRERRORS);
414 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
415 (&hdr->type) - skb_network_header(skb));
416 return -1;
417 }
418
419 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) || 393 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ||
420 skb->pkt_type != PACKET_HOST) { 394 skb->pkt_type != PACKET_HOST) {
421 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), 395 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
@@ -427,7 +401,7 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
427looped_back: 401looped_back:
428 if (hdr->segments_left == 0) { 402 if (hdr->segments_left == 0) {
429 switch (hdr->type) { 403 switch (hdr->type) {
430#ifdef CONFIG_IPV6_MIP6 404#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
431 case IPV6_SRCRT_TYPE_2: 405 case IPV6_SRCRT_TYPE_2:
432 /* Silently discard type 2 header unless it was 406 /* Silently discard type 2 header unless it was
433 * processed by own 407 * processed by own
@@ -453,18 +427,10 @@ looped_back:
453 } 427 }
454 428
455 switch (hdr->type) { 429 switch (hdr->type) {
456 case IPV6_SRCRT_TYPE_0: 430#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
457 if (hdr->hdrlen & 0x01) {
458 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
459 IPSTATS_MIB_INHDRERRORS);
460 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
461 ((&hdr->hdrlen) -
462 skb_network_header(skb)));
463 return -1;
464 }
465 break;
466#ifdef CONFIG_IPV6_MIP6
467 case IPV6_SRCRT_TYPE_2: 431 case IPV6_SRCRT_TYPE_2:
432 if (accept_source_route < 0)
433 goto unknown_rh;
468 /* Silently discard invalid RTH type 2 */ 434 /* Silently discard invalid RTH type 2 */
469 if (hdr->hdrlen != 2 || hdr->segments_left != 1) { 435 if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
470 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), 436 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
@@ -474,6 +440,8 @@ looped_back:
474 } 440 }
475 break; 441 break;
476#endif 442#endif
443 default:
444 goto unknown_rh;
477 } 445 }
478 446
479 /* 447 /*
@@ -520,7 +488,7 @@ looped_back:
520 addr += i - 1; 488 addr += i - 1;
521 489
522 switch (hdr->type) { 490 switch (hdr->type) {
523#ifdef CONFIG_IPV6_MIP6 491#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
524 case IPV6_SRCRT_TYPE_2: 492 case IPV6_SRCRT_TYPE_2:
525 if (xfrm6_input_addr(skb, (xfrm_address_t *)addr, 493 if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
526 (xfrm_address_t *)&ipv6_hdr(skb)->saddr, 494 (xfrm_address_t *)&ipv6_hdr(skb)->saddr,
@@ -577,6 +545,12 @@ looped_back:
577 skb_push(skb, skb->data - skb_network_header(skb)); 545 skb_push(skb, skb->data - skb_network_header(skb));
578 dst_input(skb); 546 dst_input(skb);
579 return -1; 547 return -1;
548
549unknown_rh:
550 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
551 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
552 (&hdr->type) - skb_network_header(skb));
553 return -1;
580} 554}
581 555
582static struct inet6_protocol rthdr_protocol = { 556static struct inet6_protocol rthdr_protocol = {
@@ -590,72 +564,6 @@ void __init ipv6_rthdr_init(void)
590 printk(KERN_ERR "ipv6_rthdr_init: Could not register protocol\n"); 564 printk(KERN_ERR "ipv6_rthdr_init: Could not register protocol\n");
591}; 565};
592 566
593/*
594 This function inverts received rthdr.
595 NOTE: specs allow to make it automatically only if
596 packet authenticated.
597
598 I will not discuss it here (though, I am really pissed off at
599 this stupid requirement making rthdr idea useless)
600
601 Actually, it creates severe problems for us.
602 Embryonic requests has no associated sockets,
603 so that user have no control over it and
604 cannot not only to set reply options, but
605 even to know, that someone wants to connect
606 without success. :-(
607
608 For now we need to test the engine, so that I created
609 temporary (or permanent) backdoor.
610 If listening socket set IPV6_RTHDR to 2, then we invert header.
611 --ANK (980729)
612 */
613
614struct ipv6_txoptions *
615ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
616{
617 /* Received rthdr:
618
619 [ H1 -> H2 -> ... H_prev ] daddr=ME
620
621 Inverted result:
622 [ H_prev -> ... -> H1 ] daddr =sender
623
624 Note, that IP output engine will rewrite this rthdr
625 by rotating it left by one addr.
626 */
627
628 int n, i;
629 struct rt0_hdr *rthdr = (struct rt0_hdr*)hdr;
630 struct rt0_hdr *irthdr;
631 struct ipv6_txoptions *opt;
632 int hdrlen = ipv6_optlen(hdr);
633
634 if (hdr->segments_left ||
635 hdr->type != IPV6_SRCRT_TYPE_0 ||
636 hdr->hdrlen & 0x01)
637 return NULL;
638
639 n = hdr->hdrlen >> 1;
640 opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
641 if (opt == NULL)
642 return NULL;
643 memset(opt, 0, sizeof(*opt));
644 opt->tot_len = sizeof(*opt) + hdrlen;
645 opt->srcrt = (void*)(opt+1);
646 opt->opt_nflen = hdrlen;
647
648 memcpy(opt->srcrt, hdr, sizeof(*hdr));
649 irthdr = (struct rt0_hdr*)opt->srcrt;
650 irthdr->reserved = 0;
651 opt->srcrt->segments_left = n;
652 for (i=0; i<n; i++)
653 memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16);
654 return opt;
655}
656
657EXPORT_SYMBOL_GPL(ipv6_invert_rthdr);
658
659/********************************** 567/**********************************
660 Hop-by-hop options. 568 Hop-by-hop options.
661 **********************************/ 569 **********************************/