diff options
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r-- | net/ipv6/ndisc.c | 237 |
1 files changed, 145 insertions, 92 deletions
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 452a2ac4eec8..2c74885f8355 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -84,13 +84,12 @@ | |||
84 | 84 | ||
85 | #include <net/flow.h> | 85 | #include <net/flow.h> |
86 | #include <net/ip6_checksum.h> | 86 | #include <net/ip6_checksum.h> |
87 | #include <net/inet_common.h> | ||
87 | #include <linux/proc_fs.h> | 88 | #include <linux/proc_fs.h> |
88 | 89 | ||
89 | #include <linux/netfilter.h> | 90 | #include <linux/netfilter.h> |
90 | #include <linux/netfilter_ipv6.h> | 91 | #include <linux/netfilter_ipv6.h> |
91 | 92 | ||
92 | static struct socket *ndisc_socket; | ||
93 | |||
94 | static u32 ndisc_hash(const void *pkey, const struct net_device *dev); | 93 | static u32 ndisc_hash(const void *pkey, const struct net_device *dev); |
95 | static int ndisc_constructor(struct neighbour *neigh); | 94 | static int ndisc_constructor(struct neighbour *neigh); |
96 | static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); | 95 | static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); |
@@ -270,7 +269,7 @@ static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, | |||
270 | if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { | 269 | if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { |
271 | ND_PRINTK2(KERN_WARNING | 270 | ND_PRINTK2(KERN_WARNING |
272 | "%s(): duplicated ND6 option found: type=%d\n", | 271 | "%s(): duplicated ND6 option found: type=%d\n", |
273 | __FUNCTION__, | 272 | __func__, |
274 | nd_opt->nd_opt_type); | 273 | nd_opt->nd_opt_type); |
275 | } else { | 274 | } else { |
276 | ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; | 275 | ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; |
@@ -301,7 +300,7 @@ static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, | |||
301 | */ | 300 | */ |
302 | ND_PRINTK2(KERN_NOTICE | 301 | ND_PRINTK2(KERN_NOTICE |
303 | "%s(): ignored unsupported option; type=%d, len=%d\n", | 302 | "%s(): ignored unsupported option; type=%d, len=%d\n", |
304 | __FUNCTION__, | 303 | __func__, |
305 | nd_opt->nd_opt_type, nd_opt->nd_opt_len); | 304 | nd_opt->nd_opt_type, nd_opt->nd_opt_len); |
306 | } | 305 | } |
307 | } | 306 | } |
@@ -441,30 +440,17 @@ static void pndisc_destructor(struct pneigh_entry *n) | |||
441 | /* | 440 | /* |
442 | * Send a Neighbour Advertisement | 441 | * Send a Neighbour Advertisement |
443 | */ | 442 | */ |
444 | |||
445 | static inline void ndisc_flow_init(struct flowi *fl, u8 type, | ||
446 | struct in6_addr *saddr, struct in6_addr *daddr, | ||
447 | int oif) | ||
448 | { | ||
449 | memset(fl, 0, sizeof(*fl)); | ||
450 | ipv6_addr_copy(&fl->fl6_src, saddr); | ||
451 | ipv6_addr_copy(&fl->fl6_dst, daddr); | ||
452 | fl->proto = IPPROTO_ICMPV6; | ||
453 | fl->fl_icmp_type = type; | ||
454 | fl->fl_icmp_code = 0; | ||
455 | fl->oif = oif; | ||
456 | security_sk_classify_flow(ndisc_socket->sk, fl); | ||
457 | } | ||
458 | |||
459 | static void __ndisc_send(struct net_device *dev, | 443 | static void __ndisc_send(struct net_device *dev, |
460 | struct neighbour *neigh, | 444 | struct neighbour *neigh, |
461 | struct in6_addr *daddr, struct in6_addr *saddr, | 445 | const struct in6_addr *daddr, |
462 | struct icmp6hdr *icmp6h, struct in6_addr *target, | 446 | const struct in6_addr *saddr, |
447 | struct icmp6hdr *icmp6h, const struct in6_addr *target, | ||
463 | int llinfo) | 448 | int llinfo) |
464 | { | 449 | { |
465 | struct flowi fl; | 450 | struct flowi fl; |
466 | struct dst_entry *dst; | 451 | struct dst_entry *dst; |
467 | struct sock *sk = ndisc_socket->sk; | 452 | struct net *net = dev_net(dev); |
453 | struct sock *sk = net->ipv6.ndisc_sk; | ||
468 | struct sk_buff *skb; | 454 | struct sk_buff *skb; |
469 | struct icmp6hdr *hdr; | 455 | struct icmp6hdr *hdr; |
470 | struct inet6_dev *idev; | 456 | struct inet6_dev *idev; |
@@ -474,10 +460,9 @@ static void __ndisc_send(struct net_device *dev, | |||
474 | 460 | ||
475 | type = icmp6h->icmp6_type; | 461 | type = icmp6h->icmp6_type; |
476 | 462 | ||
477 | ndisc_flow_init(&fl, type, saddr, daddr, | 463 | icmpv6_flow_init(sk, &fl, type, saddr, daddr, dev->ifindex); |
478 | dev->ifindex); | ||
479 | 464 | ||
480 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); | 465 | dst = icmp6_dst_alloc(dev, neigh, daddr); |
481 | if (!dst) | 466 | if (!dst) |
482 | return; | 467 | return; |
483 | 468 | ||
@@ -499,7 +484,7 @@ static void __ndisc_send(struct net_device *dev, | |||
499 | if (!skb) { | 484 | if (!skb) { |
500 | ND_PRINTK0(KERN_ERR | 485 | ND_PRINTK0(KERN_ERR |
501 | "ICMPv6 ND: %s() failed to allocate an skb.\n", | 486 | "ICMPv6 ND: %s() failed to allocate an skb.\n", |
502 | __FUNCTION__); | 487 | __func__); |
503 | dst_release(dst); | 488 | dst_release(dst); |
504 | return; | 489 | return; |
505 | } | 490 | } |
@@ -545,25 +530,28 @@ static void __ndisc_send(struct net_device *dev, | |||
545 | } | 530 | } |
546 | 531 | ||
547 | static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | 532 | static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, |
548 | struct in6_addr *daddr, struct in6_addr *solicited_addr, | 533 | const struct in6_addr *daddr, |
549 | int router, int solicited, int override, int inc_opt) | 534 | const struct in6_addr *solicited_addr, |
535 | int router, int solicited, int override, int inc_opt) | ||
550 | { | 536 | { |
551 | struct in6_addr tmpaddr; | 537 | struct in6_addr tmpaddr; |
552 | struct inet6_ifaddr *ifp; | 538 | struct inet6_ifaddr *ifp; |
553 | struct in6_addr *src_addr; | 539 | const struct in6_addr *src_addr; |
554 | struct icmp6hdr icmp6h = { | 540 | struct icmp6hdr icmp6h = { |
555 | .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, | 541 | .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, |
556 | }; | 542 | }; |
557 | 543 | ||
558 | /* for anycast or proxy, solicited_addr != src_addr */ | 544 | /* for anycast or proxy, solicited_addr != src_addr */ |
559 | ifp = ipv6_get_ifaddr(&init_net, solicited_addr, dev, 1); | 545 | ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1); |
560 | if (ifp) { | 546 | if (ifp) { |
561 | src_addr = solicited_addr; | 547 | src_addr = solicited_addr; |
562 | if (ifp->flags & IFA_F_OPTIMISTIC) | 548 | if (ifp->flags & IFA_F_OPTIMISTIC) |
563 | override = 0; | 549 | override = 0; |
564 | in6_ifa_put(ifp); | 550 | in6_ifa_put(ifp); |
565 | } else { | 551 | } else { |
566 | if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr)) | 552 | if (ipv6_dev_get_saddr(dev, daddr, |
553 | inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs, | ||
554 | &tmpaddr)) | ||
567 | return; | 555 | return; |
568 | src_addr = &tmpaddr; | 556 | src_addr = &tmpaddr; |
569 | } | 557 | } |
@@ -578,8 +566,8 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
578 | } | 566 | } |
579 | 567 | ||
580 | void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, | 568 | void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, |
581 | struct in6_addr *solicit, | 569 | const struct in6_addr *solicit, |
582 | struct in6_addr *daddr, struct in6_addr *saddr) | 570 | const struct in6_addr *daddr, const struct in6_addr *saddr) |
583 | { | 571 | { |
584 | struct in6_addr addr_buf; | 572 | struct in6_addr addr_buf; |
585 | struct icmp6hdr icmp6h = { | 573 | struct icmp6hdr icmp6h = { |
@@ -598,8 +586,8 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, | |||
598 | !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0); | 586 | !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0); |
599 | } | 587 | } |
600 | 588 | ||
601 | void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, | 589 | void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, |
602 | struct in6_addr *daddr) | 590 | const struct in6_addr *daddr) |
603 | { | 591 | { |
604 | struct icmp6hdr icmp6h = { | 592 | struct icmp6hdr icmp6h = { |
605 | .icmp6_type = NDISC_ROUTER_SOLICITATION, | 593 | .icmp6_type = NDISC_ROUTER_SOLICITATION, |
@@ -616,7 +604,7 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, | |||
616 | * suppress the inclusion of the sllao. | 604 | * suppress the inclusion of the sllao. |
617 | */ | 605 | */ |
618 | if (send_sllao) { | 606 | if (send_sllao) { |
619 | struct inet6_ifaddr *ifp = ipv6_get_ifaddr(&init_net, saddr, | 607 | struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr, |
620 | dev, 1); | 608 | dev, 1); |
621 | if (ifp) { | 609 | if (ifp) { |
622 | if (ifp->flags & IFA_F_OPTIMISTIC) { | 610 | if (ifp->flags & IFA_F_OPTIMISTIC) { |
@@ -654,7 +642,7 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) | |||
654 | struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; | 642 | struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; |
655 | int probes = atomic_read(&neigh->probes); | 643 | int probes = atomic_read(&neigh->probes); |
656 | 644 | ||
657 | if (skb && ipv6_chk_addr(&init_net, &ipv6_hdr(skb)->saddr, dev, 1)) | 645 | if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1)) |
658 | saddr = &ipv6_hdr(skb)->saddr; | 646 | saddr = &ipv6_hdr(skb)->saddr; |
659 | 647 | ||
660 | if ((probes -= neigh->parms->ucast_probes) < 0) { | 648 | if ((probes -= neigh->parms->ucast_probes) < 0) { |
@@ -662,7 +650,7 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) | |||
662 | ND_PRINTK1(KERN_DEBUG | 650 | ND_PRINTK1(KERN_DEBUG |
663 | "%s(): trying to ucast probe in NUD_INVALID: " | 651 | "%s(): trying to ucast probe in NUD_INVALID: " |
664 | NIP6_FMT "\n", | 652 | NIP6_FMT "\n", |
665 | __FUNCTION__, | 653 | __func__, |
666 | NIP6(*target)); | 654 | NIP6(*target)); |
667 | } | 655 | } |
668 | ndisc_send_ns(dev, neigh, target, target, saddr); | 656 | ndisc_send_ns(dev, neigh, target, target, saddr); |
@@ -676,18 +664,19 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) | |||
676 | } | 664 | } |
677 | } | 665 | } |
678 | 666 | ||
679 | static struct pneigh_entry *pndisc_check_router(struct net_device *dev, | 667 | static int pndisc_is_router(const void *pkey, |
680 | struct in6_addr *addr, int *is_router) | 668 | struct net_device *dev) |
681 | { | 669 | { |
682 | struct pneigh_entry *n; | 670 | struct pneigh_entry *n; |
671 | int ret = -1; | ||
683 | 672 | ||
684 | read_lock_bh(&nd_tbl.lock); | 673 | read_lock_bh(&nd_tbl.lock); |
685 | n = __pneigh_lookup(&nd_tbl, &init_net, addr, dev); | 674 | n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev); |
686 | if (n != NULL) | 675 | if (n) |
687 | *is_router = (n->flags & NTF_ROUTER); | 676 | ret = !!(n->flags & NTF_ROUTER); |
688 | read_unlock_bh(&nd_tbl.lock); | 677 | read_unlock_bh(&nd_tbl.lock); |
689 | 678 | ||
690 | return n; | 679 | return ret; |
691 | } | 680 | } |
692 | 681 | ||
693 | static void ndisc_recv_ns(struct sk_buff *skb) | 682 | static void ndisc_recv_ns(struct sk_buff *skb) |
@@ -703,10 +692,9 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
703 | struct inet6_ifaddr *ifp; | 692 | struct inet6_ifaddr *ifp; |
704 | struct inet6_dev *idev = NULL; | 693 | struct inet6_dev *idev = NULL; |
705 | struct neighbour *neigh; | 694 | struct neighbour *neigh; |
706 | struct pneigh_entry *pneigh = NULL; | ||
707 | int dad = ipv6_addr_any(saddr); | 695 | int dad = ipv6_addr_any(saddr); |
708 | int inc; | 696 | int inc; |
709 | int is_router = 0; | 697 | int is_router = -1; |
710 | 698 | ||
711 | if (ipv6_addr_is_multicast(&msg->target)) { | 699 | if (ipv6_addr_is_multicast(&msg->target)) { |
712 | ND_PRINTK2(KERN_WARNING | 700 | ND_PRINTK2(KERN_WARNING |
@@ -756,7 +744,8 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
756 | 744 | ||
757 | inc = ipv6_addr_is_multicast(daddr); | 745 | inc = ipv6_addr_is_multicast(daddr); |
758 | 746 | ||
759 | if ((ifp = ipv6_get_ifaddr(&init_net, &msg->target, dev, 1)) != NULL) { | 747 | ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); |
748 | if (ifp) { | ||
760 | 749 | ||
761 | if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) { | 750 | if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) { |
762 | if (dad) { | 751 | if (dad) { |
@@ -801,11 +790,10 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
801 | return; | 790 | return; |
802 | } | 791 | } |
803 | 792 | ||
804 | if (ipv6_chk_acast_addr(dev, &msg->target) || | 793 | if (ipv6_chk_acast_addr(dev_net(dev), dev, &msg->target) || |
805 | (idev->cnf.forwarding && | 794 | (idev->cnf.forwarding && |
806 | (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && | 795 | (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && |
807 | (pneigh = pndisc_check_router(dev, &msg->target, | 796 | (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) { |
808 | &is_router)) != NULL)) { | ||
809 | if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && | 797 | if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && |
810 | skb->pkt_type != PACKET_HOST && | 798 | skb->pkt_type != PACKET_HOST && |
811 | inc != 0 && | 799 | inc != 0 && |
@@ -826,13 +814,11 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
826 | goto out; | 814 | goto out; |
827 | } | 815 | } |
828 | 816 | ||
829 | is_router = !!(pneigh ? is_router : idev->cnf.forwarding); | 817 | if (is_router < 0) |
818 | is_router = !!idev->cnf.forwarding; | ||
830 | 819 | ||
831 | if (dad) { | 820 | if (dad) { |
832 | struct in6_addr maddr; | 821 | ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target, |
833 | |||
834 | ipv6_addr_all_nodes(&maddr); | ||
835 | ndisc_send_na(dev, NULL, &maddr, &msg->target, | ||
836 | is_router, 0, (ifp != NULL), 1); | 822 | is_router, 0, (ifp != NULL), 1); |
837 | goto out; | 823 | goto out; |
838 | } | 824 | } |
@@ -914,7 +900,8 @@ static void ndisc_recv_na(struct sk_buff *skb) | |||
914 | return; | 900 | return; |
915 | } | 901 | } |
916 | } | 902 | } |
917 | if ((ifp = ipv6_get_ifaddr(&init_net, &msg->target, dev, 1))) { | 903 | ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); |
904 | if (ifp) { | ||
918 | if (ifp->flags & IFA_F_TENTATIVE) { | 905 | if (ifp->flags & IFA_F_TENTATIVE) { |
919 | addrconf_dad_failure(ifp); | 906 | addrconf_dad_failure(ifp); |
920 | return; | 907 | return; |
@@ -945,7 +932,7 @@ static void ndisc_recv_na(struct sk_buff *skb) | |||
945 | */ | 932 | */ |
946 | if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && | 933 | if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && |
947 | ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp && | 934 | ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp && |
948 | pneigh_lookup(&nd_tbl, &init_net, &msg->target, dev, 0)) { | 935 | pneigh_lookup(&nd_tbl, dev_net(dev), &msg->target, dev, 0)) { |
949 | /* XXX: idev->cnf.prixy_ndp */ | 936 | /* XXX: idev->cnf.prixy_ndp */ |
950 | goto out; | 937 | goto out; |
951 | } | 938 | } |
@@ -1035,6 +1022,7 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt) | |||
1035 | struct sk_buff *skb; | 1022 | struct sk_buff *skb; |
1036 | struct nlmsghdr *nlh; | 1023 | struct nlmsghdr *nlh; |
1037 | struct nduseroptmsg *ndmsg; | 1024 | struct nduseroptmsg *ndmsg; |
1025 | struct net *net = dev_net(ra->dev); | ||
1038 | int err; | 1026 | int err; |
1039 | int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg) | 1027 | int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg) |
1040 | + (opt->nd_opt_len << 3)); | 1028 | + (opt->nd_opt_len << 3)); |
@@ -1064,7 +1052,7 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt) | |||
1064 | &ipv6_hdr(ra)->saddr); | 1052 | &ipv6_hdr(ra)->saddr); |
1065 | nlmsg_end(skb, nlh); | 1053 | nlmsg_end(skb, nlh); |
1066 | 1054 | ||
1067 | err = rtnl_notify(skb, &init_net, 0, RTNLGRP_ND_USEROPT, NULL, | 1055 | err = rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, |
1068 | GFP_ATOMIC); | 1056 | GFP_ATOMIC); |
1069 | if (err < 0) | 1057 | if (err < 0) |
1070 | goto errout; | 1058 | goto errout; |
@@ -1075,7 +1063,7 @@ nla_put_failure: | |||
1075 | nlmsg_free(skb); | 1063 | nlmsg_free(skb); |
1076 | err = -EMSGSIZE; | 1064 | err = -EMSGSIZE; |
1077 | errout: | 1065 | errout: |
1078 | rtnl_set_sk_err(&init_net, RTNLGRP_ND_USEROPT, err); | 1066 | rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err); |
1079 | } | 1067 | } |
1080 | 1068 | ||
1081 | static void ndisc_router_discovery(struct sk_buff *skb) | 1069 | static void ndisc_router_discovery(struct sk_buff *skb) |
@@ -1104,6 +1092,14 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1104 | return; | 1092 | return; |
1105 | } | 1093 | } |
1106 | 1094 | ||
1095 | #ifdef CONFIG_IPV6_NDISC_NODETYPE | ||
1096 | if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) { | ||
1097 | ND_PRINTK2(KERN_WARNING | ||
1098 | "ICMPv6 RA: from host or unauthorized router\n"); | ||
1099 | return; | ||
1100 | } | ||
1101 | #endif | ||
1102 | |||
1107 | /* | 1103 | /* |
1108 | * set the RA_RECV flag in the interface | 1104 | * set the RA_RECV flag in the interface |
1109 | */ | 1105 | */ |
@@ -1127,6 +1123,12 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1127 | return; | 1123 | return; |
1128 | } | 1124 | } |
1129 | 1125 | ||
1126 | #ifdef CONFIG_IPV6_NDISC_NODETYPE | ||
1127 | /* skip link-specific parameters from interior routers */ | ||
1128 | if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) | ||
1129 | goto skip_linkparms; | ||
1130 | #endif | ||
1131 | |||
1130 | if (in6_dev->if_flags & IF_RS_SENT) { | 1132 | if (in6_dev->if_flags & IF_RS_SENT) { |
1131 | /* | 1133 | /* |
1132 | * flag that an RA was received after an RS was sent | 1134 | * flag that an RA was received after an RS was sent |
@@ -1178,7 +1180,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1178 | if (rt == NULL) { | 1180 | if (rt == NULL) { |
1179 | ND_PRINTK0(KERN_ERR | 1181 | ND_PRINTK0(KERN_ERR |
1180 | "ICMPv6 RA: %s() failed to add default route.\n", | 1182 | "ICMPv6 RA: %s() failed to add default route.\n", |
1181 | __FUNCTION__); | 1183 | __func__); |
1182 | in6_dev_put(in6_dev); | 1184 | in6_dev_put(in6_dev); |
1183 | return; | 1185 | return; |
1184 | } | 1186 | } |
@@ -1187,7 +1189,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1187 | if (neigh == NULL) { | 1189 | if (neigh == NULL) { |
1188 | ND_PRINTK0(KERN_ERR | 1190 | ND_PRINTK0(KERN_ERR |
1189 | "ICMPv6 RA: %s() got default router without neighbour.\n", | 1191 | "ICMPv6 RA: %s() got default router without neighbour.\n", |
1190 | __FUNCTION__); | 1192 | __func__); |
1191 | dst_release(&rt->u.dst); | 1193 | dst_release(&rt->u.dst); |
1192 | in6_dev_put(in6_dev); | 1194 | in6_dev_put(in6_dev); |
1193 | return; | 1195 | return; |
@@ -1241,6 +1243,10 @@ skip_defrtr: | |||
1241 | } | 1243 | } |
1242 | } | 1244 | } |
1243 | 1245 | ||
1246 | #ifdef CONFIG_IPV6_NDISC_NODETYPE | ||
1247 | skip_linkparms: | ||
1248 | #endif | ||
1249 | |||
1244 | /* | 1250 | /* |
1245 | * Process options. | 1251 | * Process options. |
1246 | */ | 1252 | */ |
@@ -1272,7 +1278,13 @@ skip_defrtr: | |||
1272 | for (p = ndopts.nd_opts_ri; | 1278 | for (p = ndopts.nd_opts_ri; |
1273 | p; | 1279 | p; |
1274 | p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) { | 1280 | p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) { |
1275 | if (((struct route_info *)p)->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen) | 1281 | struct route_info *ri = (struct route_info *)p; |
1282 | #ifdef CONFIG_IPV6_NDISC_NODETYPE | ||
1283 | if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT && | ||
1284 | ri->prefix_len == 0) | ||
1285 | continue; | ||
1286 | #endif | ||
1287 | if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen) | ||
1276 | continue; | 1288 | continue; |
1277 | rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3, | 1289 | rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3, |
1278 | &ipv6_hdr(skb)->saddr); | 1290 | &ipv6_hdr(skb)->saddr); |
@@ -1280,6 +1292,12 @@ skip_defrtr: | |||
1280 | } | 1292 | } |
1281 | #endif | 1293 | #endif |
1282 | 1294 | ||
1295 | #ifdef CONFIG_IPV6_NDISC_NODETYPE | ||
1296 | /* skip link-specific ndopts from interior routers */ | ||
1297 | if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) | ||
1298 | goto out; | ||
1299 | #endif | ||
1300 | |||
1283 | if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) { | 1301 | if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) { |
1284 | struct nd_opt_hdr *p; | 1302 | struct nd_opt_hdr *p; |
1285 | for (p = ndopts.nd_opts_pi; | 1303 | for (p = ndopts.nd_opts_pi; |
@@ -1343,6 +1361,16 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1343 | int optlen; | 1361 | int optlen; |
1344 | u8 *lladdr = NULL; | 1362 | u8 *lladdr = NULL; |
1345 | 1363 | ||
1364 | #ifdef CONFIG_IPV6_NDISC_NODETYPE | ||
1365 | switch (skb->ndisc_nodetype) { | ||
1366 | case NDISC_NODETYPE_HOST: | ||
1367 | case NDISC_NODETYPE_NODEFAULT: | ||
1368 | ND_PRINTK2(KERN_WARNING | ||
1369 | "ICMPv6 Redirect: from host or unauthorized router\n"); | ||
1370 | return; | ||
1371 | } | ||
1372 | #endif | ||
1373 | |||
1346 | if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) { | 1374 | if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) { |
1347 | ND_PRINTK2(KERN_WARNING | 1375 | ND_PRINTK2(KERN_WARNING |
1348 | "ICMPv6 Redirect: source address is not link-local.\n"); | 1376 | "ICMPv6 Redirect: source address is not link-local.\n"); |
@@ -1418,15 +1446,16 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1418 | } | 1446 | } |
1419 | 1447 | ||
1420 | void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | 1448 | void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, |
1421 | struct in6_addr *target) | 1449 | const struct in6_addr *target) |
1422 | { | 1450 | { |
1423 | struct sock *sk = ndisc_socket->sk; | 1451 | struct net_device *dev = skb->dev; |
1452 | struct net *net = dev_net(dev); | ||
1453 | struct sock *sk = net->ipv6.ndisc_sk; | ||
1424 | int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); | 1454 | int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); |
1425 | struct sk_buff *buff; | 1455 | struct sk_buff *buff; |
1426 | struct icmp6hdr *icmph; | 1456 | struct icmp6hdr *icmph; |
1427 | struct in6_addr saddr_buf; | 1457 | struct in6_addr saddr_buf; |
1428 | struct in6_addr *addrp; | 1458 | struct in6_addr *addrp; |
1429 | struct net_device *dev; | ||
1430 | struct rt6_info *rt; | 1459 | struct rt6_info *rt; |
1431 | struct dst_entry *dst; | 1460 | struct dst_entry *dst; |
1432 | struct inet6_dev *idev; | 1461 | struct inet6_dev *idev; |
@@ -1436,8 +1465,6 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1436 | int err; | 1465 | int err; |
1437 | u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; | 1466 | u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; |
1438 | 1467 | ||
1439 | dev = skb->dev; | ||
1440 | |||
1441 | if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) { | 1468 | if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) { |
1442 | ND_PRINTK2(KERN_WARNING | 1469 | ND_PRINTK2(KERN_WARNING |
1443 | "ICMPv6 Redirect: no link-local address on %s\n", | 1470 | "ICMPv6 Redirect: no link-local address on %s\n", |
@@ -1452,10 +1479,10 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1452 | return; | 1479 | return; |
1453 | } | 1480 | } |
1454 | 1481 | ||
1455 | ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &ipv6_hdr(skb)->saddr, | 1482 | icmpv6_flow_init(sk, &fl, NDISC_REDIRECT, |
1456 | dev->ifindex); | 1483 | &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex); |
1457 | 1484 | ||
1458 | dst = ip6_route_output(NULL, &fl); | 1485 | dst = ip6_route_output(net, NULL, &fl); |
1459 | if (dst == NULL) | 1486 | if (dst == NULL) |
1460 | return; | 1487 | return; |
1461 | 1488 | ||
@@ -1499,12 +1526,11 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1499 | if (buff == NULL) { | 1526 | if (buff == NULL) { |
1500 | ND_PRINTK0(KERN_ERR | 1527 | ND_PRINTK0(KERN_ERR |
1501 | "ICMPv6 Redirect: %s() failed to allocate an skb.\n", | 1528 | "ICMPv6 Redirect: %s() failed to allocate an skb.\n", |
1502 | __FUNCTION__); | 1529 | __func__); |
1503 | dst_release(dst); | 1530 | dst_release(dst); |
1504 | return; | 1531 | return; |
1505 | } | 1532 | } |
1506 | 1533 | ||
1507 | |||
1508 | skb_reserve(buff, LL_RESERVED_SPACE(dev)); | 1534 | skb_reserve(buff, LL_RESERVED_SPACE(dev)); |
1509 | ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr, | 1535 | ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr, |
1510 | IPPROTO_ICMPV6, len); | 1536 | IPPROTO_ICMPV6, len); |
@@ -1625,18 +1651,16 @@ int ndisc_rcv(struct sk_buff *skb) | |||
1625 | static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) | 1651 | static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) |
1626 | { | 1652 | { |
1627 | struct net_device *dev = ptr; | 1653 | struct net_device *dev = ptr; |
1628 | 1654 | struct net *net = dev_net(dev); | |
1629 | if (dev->nd_net != &init_net) | ||
1630 | return NOTIFY_DONE; | ||
1631 | 1655 | ||
1632 | switch (event) { | 1656 | switch (event) { |
1633 | case NETDEV_CHANGEADDR: | 1657 | case NETDEV_CHANGEADDR: |
1634 | neigh_changeaddr(&nd_tbl, dev); | 1658 | neigh_changeaddr(&nd_tbl, dev); |
1635 | fib6_run_gc(~0UL); | 1659 | fib6_run_gc(~0UL, net); |
1636 | break; | 1660 | break; |
1637 | case NETDEV_DOWN: | 1661 | case NETDEV_DOWN: |
1638 | neigh_ifdown(&nd_tbl, dev); | 1662 | neigh_ifdown(&nd_tbl, dev); |
1639 | fib6_run_gc(~0UL); | 1663 | fib6_run_gc(~0UL, net); |
1640 | break; | 1664 | break; |
1641 | default: | 1665 | default: |
1642 | break; | 1666 | break; |
@@ -1745,44 +1769,74 @@ static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name, | |||
1745 | 1769 | ||
1746 | #endif | 1770 | #endif |
1747 | 1771 | ||
1748 | int __init ndisc_init(struct net_proto_family *ops) | 1772 | static int ndisc_net_init(struct net *net) |
1749 | { | 1773 | { |
1750 | struct ipv6_pinfo *np; | 1774 | struct ipv6_pinfo *np; |
1751 | struct sock *sk; | 1775 | struct sock *sk; |
1752 | int err; | 1776 | int err; |
1753 | 1777 | ||
1754 | err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &ndisc_socket); | 1778 | err = inet_ctl_sock_create(&sk, PF_INET6, |
1779 | SOCK_RAW, IPPROTO_ICMPV6, net); | ||
1755 | if (err < 0) { | 1780 | if (err < 0) { |
1756 | ND_PRINTK0(KERN_ERR | 1781 | ND_PRINTK0(KERN_ERR |
1757 | "ICMPv6 NDISC: Failed to initialize the control socket (err %d).\n", | 1782 | "ICMPv6 NDISC: Failed to initialize the control socket (err %d).\n", |
1758 | err); | 1783 | err); |
1759 | ndisc_socket = NULL; /* For safety. */ | ||
1760 | return err; | 1784 | return err; |
1761 | } | 1785 | } |
1762 | 1786 | ||
1763 | sk = ndisc_socket->sk; | 1787 | net->ipv6.ndisc_sk = sk; |
1788 | |||
1764 | np = inet6_sk(sk); | 1789 | np = inet6_sk(sk); |
1765 | sk->sk_allocation = GFP_ATOMIC; | ||
1766 | np->hop_limit = 255; | 1790 | np->hop_limit = 255; |
1767 | /* Do not loopback ndisc messages */ | 1791 | /* Do not loopback ndisc messages */ |
1768 | np->mc_loop = 0; | 1792 | np->mc_loop = 0; |
1769 | sk->sk_prot->unhash(sk); | ||
1770 | 1793 | ||
1794 | return 0; | ||
1795 | } | ||
1796 | |||
1797 | static void ndisc_net_exit(struct net *net) | ||
1798 | { | ||
1799 | inet_ctl_sock_destroy(net->ipv6.ndisc_sk); | ||
1800 | } | ||
1801 | |||
1802 | static struct pernet_operations ndisc_net_ops = { | ||
1803 | .init = ndisc_net_init, | ||
1804 | .exit = ndisc_net_exit, | ||
1805 | }; | ||
1806 | |||
1807 | int __init ndisc_init(void) | ||
1808 | { | ||
1809 | int err; | ||
1810 | |||
1811 | err = register_pernet_subsys(&ndisc_net_ops); | ||
1812 | if (err) | ||
1813 | return err; | ||
1771 | /* | 1814 | /* |
1772 | * Initialize the neighbour table | 1815 | * Initialize the neighbour table |
1773 | */ | 1816 | */ |
1774 | |||
1775 | neigh_table_init(&nd_tbl); | 1817 | neigh_table_init(&nd_tbl); |
1776 | 1818 | ||
1777 | #ifdef CONFIG_SYSCTL | 1819 | #ifdef CONFIG_SYSCTL |
1778 | neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, | 1820 | err = neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, |
1779 | "ipv6", | 1821 | NET_IPV6_NEIGH, "ipv6", |
1780 | &ndisc_ifinfo_sysctl_change, | 1822 | &ndisc_ifinfo_sysctl_change, |
1781 | &ndisc_ifinfo_sysctl_strategy); | 1823 | &ndisc_ifinfo_sysctl_strategy); |
1824 | if (err) | ||
1825 | goto out_unregister_pernet; | ||
1782 | #endif | 1826 | #endif |
1827 | err = register_netdevice_notifier(&ndisc_netdev_notifier); | ||
1828 | if (err) | ||
1829 | goto out_unregister_sysctl; | ||
1830 | out: | ||
1831 | return err; | ||
1783 | 1832 | ||
1784 | register_netdevice_notifier(&ndisc_netdev_notifier); | 1833 | out_unregister_sysctl: |
1785 | return 0; | 1834 | #ifdef CONFIG_SYSCTL |
1835 | neigh_sysctl_unregister(&nd_tbl.parms); | ||
1836 | out_unregister_pernet: | ||
1837 | #endif | ||
1838 | unregister_pernet_subsys(&ndisc_net_ops); | ||
1839 | goto out; | ||
1786 | } | 1840 | } |
1787 | 1841 | ||
1788 | void ndisc_cleanup(void) | 1842 | void ndisc_cleanup(void) |
@@ -1792,6 +1846,5 @@ void ndisc_cleanup(void) | |||
1792 | neigh_sysctl_unregister(&nd_tbl.parms); | 1846 | neigh_sysctl_unregister(&nd_tbl.parms); |
1793 | #endif | 1847 | #endif |
1794 | neigh_table_clear(&nd_tbl); | 1848 | neigh_table_clear(&nd_tbl); |
1795 | sock_release(ndisc_socket); | 1849 | unregister_pernet_subsys(&ndisc_net_ops); |
1796 | ndisc_socket = NULL; /* For safety. */ | ||
1797 | } | 1850 | } |