diff options
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r-- | net/ipv6/ndisc.c | 51 |
1 files changed, 39 insertions, 12 deletions
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 92f952d093db..7596f071d308 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -324,7 +324,7 @@ static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p, | |||
324 | return lladdr + prepad; | 324 | return lladdr + prepad; |
325 | } | 325 | } |
326 | 326 | ||
327 | int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir) | 327 | int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir) |
328 | { | 328 | { |
329 | switch (dev->type) { | 329 | switch (dev->type) { |
330 | case ARPHRD_ETHER: | 330 | case ARPHRD_ETHER: |
@@ -611,6 +611,29 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
611 | inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); | 611 | inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); |
612 | } | 612 | } |
613 | 613 | ||
614 | static void ndisc_send_unsol_na(struct net_device *dev) | ||
615 | { | ||
616 | struct inet6_dev *idev; | ||
617 | struct inet6_ifaddr *ifa; | ||
618 | struct in6_addr mcaddr; | ||
619 | |||
620 | idev = in6_dev_get(dev); | ||
621 | if (!idev) | ||
622 | return; | ||
623 | |||
624 | read_lock_bh(&idev->lock); | ||
625 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | ||
626 | addrconf_addr_solict_mult(&ifa->addr, &mcaddr); | ||
627 | ndisc_send_na(dev, NULL, &mcaddr, &ifa->addr, | ||
628 | /*router=*/ !!idev->cnf.forwarding, | ||
629 | /*solicited=*/ false, /*override=*/ true, | ||
630 | /*inc_opt=*/ true); | ||
631 | } | ||
632 | read_unlock_bh(&idev->lock); | ||
633 | |||
634 | in6_dev_put(idev); | ||
635 | } | ||
636 | |||
614 | void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, | 637 | void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, |
615 | const struct in6_addr *solicit, | 638 | const struct in6_addr *solicit, |
616 | const struct in6_addr *daddr, const struct in6_addr *saddr) | 639 | const struct in6_addr *daddr, const struct in6_addr *saddr) |
@@ -725,8 +748,8 @@ static int pndisc_is_router(const void *pkey, | |||
725 | static void ndisc_recv_ns(struct sk_buff *skb) | 748 | static void ndisc_recv_ns(struct sk_buff *skb) |
726 | { | 749 | { |
727 | struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); | 750 | struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); |
728 | struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; | 751 | const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; |
729 | struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; | 752 | const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; |
730 | u8 *lladdr = NULL; | 753 | u8 *lladdr = NULL; |
731 | u32 ndoptlen = skb->tail - (skb->transport_header + | 754 | u32 ndoptlen = skb->tail - (skb->transport_header + |
732 | offsetof(struct nd_msg, opt)); | 755 | offsetof(struct nd_msg, opt)); |
@@ -901,8 +924,8 @@ out: | |||
901 | static void ndisc_recv_na(struct sk_buff *skb) | 924 | static void ndisc_recv_na(struct sk_buff *skb) |
902 | { | 925 | { |
903 | struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); | 926 | struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); |
904 | struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; | 927 | const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; |
905 | struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; | 928 | const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; |
906 | u8 *lladdr = NULL; | 929 | u8 *lladdr = NULL; |
907 | u32 ndoptlen = skb->tail - (skb->transport_header + | 930 | u32 ndoptlen = skb->tail - (skb->transport_header + |
908 | offsetof(struct nd_msg, opt)); | 931 | offsetof(struct nd_msg, opt)); |
@@ -945,9 +968,10 @@ static void ndisc_recv_na(struct sk_buff *skb) | |||
945 | } | 968 | } |
946 | ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); | 969 | ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); |
947 | if (ifp) { | 970 | if (ifp) { |
948 | if (ifp->flags & IFA_F_TENTATIVE) { | 971 | if (skb->pkt_type != PACKET_LOOPBACK |
949 | addrconf_dad_failure(ifp); | 972 | && (ifp->flags & IFA_F_TENTATIVE)) { |
950 | return; | 973 | addrconf_dad_failure(ifp); |
974 | return; | ||
951 | } | 975 | } |
952 | /* What should we make now? The advertisement | 976 | /* What should we make now? The advertisement |
953 | is invalid, but ndisc specs say nothing | 977 | is invalid, but ndisc specs say nothing |
@@ -1014,7 +1038,7 @@ static void ndisc_recv_rs(struct sk_buff *skb) | |||
1014 | unsigned long ndoptlen = skb->len - sizeof(*rs_msg); | 1038 | unsigned long ndoptlen = skb->len - sizeof(*rs_msg); |
1015 | struct neighbour *neigh; | 1039 | struct neighbour *neigh; |
1016 | struct inet6_dev *idev; | 1040 | struct inet6_dev *idev; |
1017 | struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; | 1041 | const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; |
1018 | struct ndisc_options ndopts; | 1042 | struct ndisc_options ndopts; |
1019 | u8 *lladdr = NULL; | 1043 | u8 *lladdr = NULL; |
1020 | 1044 | ||
@@ -1411,8 +1435,8 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1411 | { | 1435 | { |
1412 | struct inet6_dev *in6_dev; | 1436 | struct inet6_dev *in6_dev; |
1413 | struct icmp6hdr *icmph; | 1437 | struct icmp6hdr *icmph; |
1414 | struct in6_addr *dest; | 1438 | const struct in6_addr *dest; |
1415 | struct in6_addr *target; /* new first hop to destination */ | 1439 | const struct in6_addr *target; /* new first hop to destination */ |
1416 | struct neighbour *neigh; | 1440 | struct neighbour *neigh; |
1417 | int on_link = 0; | 1441 | int on_link = 0; |
1418 | struct ndisc_options ndopts; | 1442 | struct ndisc_options ndopts; |
@@ -1445,7 +1469,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1445 | } | 1469 | } |
1446 | 1470 | ||
1447 | icmph = icmp6_hdr(skb); | 1471 | icmph = icmp6_hdr(skb); |
1448 | target = (struct in6_addr *) (icmph + 1); | 1472 | target = (const struct in6_addr *) (icmph + 1); |
1449 | dest = target + 1; | 1473 | dest = target + 1; |
1450 | 1474 | ||
1451 | if (ipv6_addr_is_multicast(dest)) { | 1475 | if (ipv6_addr_is_multicast(dest)) { |
@@ -1722,6 +1746,9 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, | |||
1722 | neigh_ifdown(&nd_tbl, dev); | 1746 | neigh_ifdown(&nd_tbl, dev); |
1723 | fib6_run_gc(~0UL, net); | 1747 | fib6_run_gc(~0UL, net); |
1724 | break; | 1748 | break; |
1749 | case NETDEV_NOTIFY_PEERS: | ||
1750 | ndisc_send_unsol_na(dev); | ||
1751 | break; | ||
1725 | default: | 1752 | default: |
1726 | break; | 1753 | break; |
1727 | } | 1754 | } |