ndisc.c (712cba5d87a6c0e980ee5fad45734e189c4d7151) ndisc.c (adc176c5472214971d77c1a61c83db9b01e9cdc7)
1/*
2 * Neighbour Discovery for IPv6
3 * Linux INET6 implementation
4 *
5 * Authors:
6 * Pedro Roque <roque@di.fc.ul.pt>
7 * Mike Shaver <shaver@ingenia.com>
8 *

--- 219 unchanged lines hidden (view full) ---

228 if (opt_len < l || l == 0)
229 return NULL;
230 if (ndisc_ops_parse_options(dev, nd_opt, ndopts))
231 goto next_opt;
232 switch (nd_opt->nd_opt_type) {
233 case ND_OPT_SOURCE_LL_ADDR:
234 case ND_OPT_TARGET_LL_ADDR:
235 case ND_OPT_MTU:
1/*
2 * Neighbour Discovery for IPv6
3 * Linux INET6 implementation
4 *
5 * Authors:
6 * Pedro Roque <roque@di.fc.ul.pt>
7 * Mike Shaver <shaver@ingenia.com>
8 *

--- 219 unchanged lines hidden (view full) ---

228 if (opt_len < l || l == 0)
229 return NULL;
230 if (ndisc_ops_parse_options(dev, nd_opt, ndopts))
231 goto next_opt;
232 switch (nd_opt->nd_opt_type) {
233 case ND_OPT_SOURCE_LL_ADDR:
234 case ND_OPT_TARGET_LL_ADDR:
235 case ND_OPT_MTU:
236 case ND_OPT_NONCE:
236 case ND_OPT_REDIRECT_HDR:
237 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
238 ND_PRINTK(2, warn,
239 "%s: duplicated ND6 option found: type=%d\n",
240 __func__, nd_opt->nd_opt_type);
241 } else {
242 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
243 }

--- 319 unchanged lines hidden (view full) ---

563 /*inc_opt=*/ true);
564 }
565 read_unlock_bh(&idev->lock);
566
567 in6_dev_put(idev);
568}
569
570void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
237 case ND_OPT_REDIRECT_HDR:
238 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
239 ND_PRINTK(2, warn,
240 "%s: duplicated ND6 option found: type=%d\n",
241 __func__, nd_opt->nd_opt_type);
242 } else {
243 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
244 }

--- 319 unchanged lines hidden (view full) ---

564 /*inc_opt=*/ true);
565 }
566 read_unlock_bh(&idev->lock);
567
568 in6_dev_put(idev);
569}
570
571void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
571 const struct in6_addr *daddr, const struct in6_addr *saddr)
572 const struct in6_addr *daddr, const struct in6_addr *saddr,
573 u64 nonce)
572{
573 struct sk_buff *skb;
574 struct in6_addr addr_buf;
575 int inc_opt = dev->addr_len;
576 int optlen = 0;
577 struct nd_msg *msg;
578
579 if (!saddr) {
580 if (ipv6_get_lladdr(dev, &addr_buf,
581 (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
582 return;
583 saddr = &addr_buf;
584 }
585
586 if (ipv6_addr_any(saddr))
587 inc_opt = false;
588 if (inc_opt)
589 optlen += ndisc_opt_addr_space(dev,
590 NDISC_NEIGHBOUR_SOLICITATION);
574{
575 struct sk_buff *skb;
576 struct in6_addr addr_buf;
577 int inc_opt = dev->addr_len;
578 int optlen = 0;
579 struct nd_msg *msg;
580
581 if (!saddr) {
582 if (ipv6_get_lladdr(dev, &addr_buf,
583 (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
584 return;
585 saddr = &addr_buf;
586 }
587
588 if (ipv6_addr_any(saddr))
589 inc_opt = false;
590 if (inc_opt)
591 optlen += ndisc_opt_addr_space(dev,
592 NDISC_NEIGHBOUR_SOLICITATION);
593 if (nonce != 0)
594 optlen += 8;
591
592 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
593 if (!skb)
594 return;
595
596 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
597 *msg = (struct nd_msg) {
598 .icmph = {
599 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
600 },
601 .target = *solicit,
602 };
603
604 if (inc_opt)
605 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
606 dev->dev_addr,
607 NDISC_NEIGHBOUR_SOLICITATION);
595
596 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
597 if (!skb)
598 return;
599
600 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
601 *msg = (struct nd_msg) {
602 .icmph = {
603 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
604 },
605 .target = *solicit,
606 };
607
608 if (inc_opt)
609 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
610 dev->dev_addr,
611 NDISC_NEIGHBOUR_SOLICITATION);
612 if (nonce != 0) {
613 u8 *opt = skb_put(skb, 8);
608
614
615 opt[0] = ND_OPT_NONCE;
616 opt[1] = 8 >> 3;
617 memcpy(opt + 2, &nonce, 6);
618 }
619
609 ndisc_send_skb(skb, daddr, saddr);
610}
611
612void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
613 const struct in6_addr *daddr)
614{
615 struct sk_buff *skb;
616 struct rs_msg *msg;

--- 71 unchanged lines hidden (view full) ---

688 saddr = &ipv6_hdr(skb)->saddr;
689 probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES);
690 if (probes < 0) {
691 if (!(neigh->nud_state & NUD_VALID)) {
692 ND_PRINTK(1, dbg,
693 "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
694 __func__, target);
695 }
620 ndisc_send_skb(skb, daddr, saddr);
621}
622
623void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
624 const struct in6_addr *daddr)
625{
626 struct sk_buff *skb;
627 struct rs_msg *msg;

--- 71 unchanged lines hidden (view full) ---

699 saddr = &ipv6_hdr(skb)->saddr;
700 probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES);
701 if (probes < 0) {
702 if (!(neigh->nud_state & NUD_VALID)) {
703 ND_PRINTK(1, dbg,
704 "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
705 __func__, target);
706 }
696 ndisc_send_ns(dev, target, target, saddr);
707 ndisc_send_ns(dev, target, target, saddr, 0);
697 } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
698 neigh_app_ns(neigh);
699 } else {
700 addrconf_addr_solict_mult(target, &mcaddr);
708 } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
709 neigh_app_ns(neigh);
710 } else {
711 addrconf_addr_solict_mult(target, &mcaddr);
701 ndisc_send_ns(dev, target, &mcaddr, saddr);
712 ndisc_send_ns(dev, target, &mcaddr, saddr, 0);
702 }
703}
704
705static int pndisc_is_router(const void *pkey,
706 struct net_device *dev)
707{
708 struct pneigh_entry *n;
709 int ret = -1;

--- 27 unchanged lines hidden (view full) ---

737 struct ndisc_options ndopts;
738 struct net_device *dev = skb->dev;
739 struct inet6_ifaddr *ifp;
740 struct inet6_dev *idev = NULL;
741 struct neighbour *neigh;
742 int dad = ipv6_addr_any(saddr);
743 bool inc;
744 int is_router = -1;
713 }
714}
715
716static int pndisc_is_router(const void *pkey,
717 struct net_device *dev)
718{
719 struct pneigh_entry *n;
720 int ret = -1;

--- 27 unchanged lines hidden (view full) ---

748 struct ndisc_options ndopts;
749 struct net_device *dev = skb->dev;
750 struct inet6_ifaddr *ifp;
751 struct inet6_dev *idev = NULL;
752 struct neighbour *neigh;
753 int dad = ipv6_addr_any(saddr);
754 bool inc;
755 int is_router = -1;
756 u64 nonce = 0;
745
746 if (skb->len < sizeof(struct nd_msg)) {
747 ND_PRINTK(2, warn, "NS: packet too short\n");
748 return;
749 }
750
751 if (ipv6_addr_is_multicast(&msg->target)) {
752 ND_PRINTK(2, warn, "NS: multicast target address\n");

--- 28 unchanged lines hidden (view full) ---

781 * in the message.
782 */
783 if (dad) {
784 ND_PRINTK(2, warn,
785 "NS: bad DAD packet (link-layer address option)\n");
786 return;
787 }
788 }
757
758 if (skb->len < sizeof(struct nd_msg)) {
759 ND_PRINTK(2, warn, "NS: packet too short\n");
760 return;
761 }
762
763 if (ipv6_addr_is_multicast(&msg->target)) {
764 ND_PRINTK(2, warn, "NS: multicast target address\n");

--- 28 unchanged lines hidden (view full) ---

793 * in the message.
794 */
795 if (dad) {
796 ND_PRINTK(2, warn,
797 "NS: bad DAD packet (link-layer address option)\n");
798 return;
799 }
800 }
801 if (ndopts.nd_opts_nonce)
802 memcpy(&nonce, (u8 *)(ndopts.nd_opts_nonce + 1), 6);
789
790 inc = ipv6_addr_is_multicast(daddr);
791
792 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
793 if (ifp) {
794have_ifp:
795 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
796 if (dad) {
803
804 inc = ipv6_addr_is_multicast(daddr);
805
806 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
807 if (ifp) {
808have_ifp:
809 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
810 if (dad) {
811 if (nonce != 0 && ifp->dad_nonce == nonce) {
812 u8 *np = (u8 *)&nonce;
813 /* Matching nonce if looped back */
814 ND_PRINTK(2, notice,
815 "%s: IPv6 DAD loopback for address %pI6c nonce %pM ignored\n",
816 ifp->idev->dev->name,
817 &ifp->addr, np);
818 goto out;
819 }
797 /*
798 * We are colliding with another node
799 * who is doing DAD
800 * so fail our DAD process
801 */
802 addrconf_dad_failure(ifp);
803 return;
804 } else {

--- 1086 unchanged lines hidden ---
820 /*
821 * We are colliding with another node
822 * who is doing DAD
823 * so fail our DAD process
824 */
825 addrconf_dad_failure(ifp);
826 return;
827 } else {

--- 1086 unchanged lines hidden ---