diff options
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r-- | net/ipv6/ndisc.c | 75 |
1 files changed, 53 insertions, 22 deletions
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 2342545a5ee9..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: |
@@ -341,6 +341,8 @@ int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int d | |||
341 | case ARPHRD_INFINIBAND: | 341 | case ARPHRD_INFINIBAND: |
342 | ipv6_ib_mc_map(addr, dev->broadcast, buf); | 342 | ipv6_ib_mc_map(addr, dev->broadcast, buf); |
343 | return 0; | 343 | return 0; |
344 | case ARPHRD_IPGRE: | ||
345 | return ipv6_ipgre_mc_map(addr, dev->broadcast, buf); | ||
344 | default: | 346 | default: |
345 | if (dir) { | 347 | if (dir) { |
346 | memcpy(buf, dev->broadcast, dev->addr_len); | 348 | memcpy(buf, dev->broadcast, dev->addr_len); |
@@ -511,7 +513,7 @@ void ndisc_send_skb(struct sk_buff *skb, | |||
511 | const struct in6_addr *saddr, | 513 | const struct in6_addr *saddr, |
512 | struct icmp6hdr *icmp6h) | 514 | struct icmp6hdr *icmp6h) |
513 | { | 515 | { |
514 | struct flowi fl; | 516 | struct flowi6 fl6; |
515 | struct dst_entry *dst; | 517 | struct dst_entry *dst; |
516 | struct net *net = dev_net(dev); | 518 | struct net *net = dev_net(dev); |
517 | struct sock *sk = net->ipv6.ndisc_sk; | 519 | struct sock *sk = net->ipv6.ndisc_sk; |
@@ -521,7 +523,7 @@ void ndisc_send_skb(struct sk_buff *skb, | |||
521 | 523 | ||
522 | type = icmp6h->icmp6_type; | 524 | type = icmp6h->icmp6_type; |
523 | 525 | ||
524 | icmpv6_flow_init(sk, &fl, type, saddr, daddr, dev->ifindex); | 526 | icmpv6_flow_init(sk, &fl6, type, saddr, daddr, dev->ifindex); |
525 | 527 | ||
526 | dst = icmp6_dst_alloc(dev, neigh, daddr); | 528 | dst = icmp6_dst_alloc(dev, neigh, daddr); |
527 | if (!dst) { | 529 | if (!dst) { |
@@ -529,8 +531,8 @@ void ndisc_send_skb(struct sk_buff *skb, | |||
529 | return; | 531 | return; |
530 | } | 532 | } |
531 | 533 | ||
532 | err = xfrm_lookup(net, &dst, &fl, NULL, 0); | 534 | dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); |
533 | if (err < 0) { | 535 | if (IS_ERR(dst)) { |
534 | kfree_skb(skb); | 536 | kfree_skb(skb); |
535 | return; | 537 | return; |
536 | } | 538 | } |
@@ -609,6 +611,29 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
609 | inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); | 611 | inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); |
610 | } | 612 | } |
611 | 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 | |||
612 | void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, | 637 | void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, |
613 | const struct in6_addr *solicit, | 638 | const struct in6_addr *solicit, |
614 | const struct in6_addr *daddr, const struct in6_addr *saddr) | 639 | const struct in6_addr *daddr, const struct in6_addr *saddr) |
@@ -723,8 +748,8 @@ static int pndisc_is_router(const void *pkey, | |||
723 | static void ndisc_recv_ns(struct sk_buff *skb) | 748 | static void ndisc_recv_ns(struct sk_buff *skb) |
724 | { | 749 | { |
725 | struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); | 750 | struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); |
726 | struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; | 751 | const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; |
727 | struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; | 752 | const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; |
728 | u8 *lladdr = NULL; | 753 | u8 *lladdr = NULL; |
729 | u32 ndoptlen = skb->tail - (skb->transport_header + | 754 | u32 ndoptlen = skb->tail - (skb->transport_header + |
730 | offsetof(struct nd_msg, opt)); | 755 | offsetof(struct nd_msg, opt)); |
@@ -899,8 +924,8 @@ out: | |||
899 | static void ndisc_recv_na(struct sk_buff *skb) | 924 | static void ndisc_recv_na(struct sk_buff *skb) |
900 | { | 925 | { |
901 | struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); | 926 | struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); |
902 | struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; | 927 | const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; |
903 | struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; | 928 | const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; |
904 | u8 *lladdr = NULL; | 929 | u8 *lladdr = NULL; |
905 | u32 ndoptlen = skb->tail - (skb->transport_header + | 930 | u32 ndoptlen = skb->tail - (skb->transport_header + |
906 | offsetof(struct nd_msg, opt)); | 931 | offsetof(struct nd_msg, opt)); |
@@ -943,9 +968,10 @@ static void ndisc_recv_na(struct sk_buff *skb) | |||
943 | } | 968 | } |
944 | ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); | 969 | ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); |
945 | if (ifp) { | 970 | if (ifp) { |
946 | if (ifp->flags & IFA_F_TENTATIVE) { | 971 | if (skb->pkt_type != PACKET_LOOPBACK |
947 | addrconf_dad_failure(ifp); | 972 | && (ifp->flags & IFA_F_TENTATIVE)) { |
948 | return; | 973 | addrconf_dad_failure(ifp); |
974 | return; | ||
949 | } | 975 | } |
950 | /* What should we make now? The advertisement | 976 | /* What should we make now? The advertisement |
951 | is invalid, but ndisc specs say nothing | 977 | is invalid, but ndisc specs say nothing |
@@ -1012,7 +1038,7 @@ static void ndisc_recv_rs(struct sk_buff *skb) | |||
1012 | unsigned long ndoptlen = skb->len - sizeof(*rs_msg); | 1038 | unsigned long ndoptlen = skb->len - sizeof(*rs_msg); |
1013 | struct neighbour *neigh; | 1039 | struct neighbour *neigh; |
1014 | struct inet6_dev *idev; | 1040 | struct inet6_dev *idev; |
1015 | struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; | 1041 | const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; |
1016 | struct ndisc_options ndopts; | 1042 | struct ndisc_options ndopts; |
1017 | u8 *lladdr = NULL; | 1043 | u8 *lladdr = NULL; |
1018 | 1044 | ||
@@ -1409,8 +1435,8 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1409 | { | 1435 | { |
1410 | struct inet6_dev *in6_dev; | 1436 | struct inet6_dev *in6_dev; |
1411 | struct icmp6hdr *icmph; | 1437 | struct icmp6hdr *icmph; |
1412 | struct in6_addr *dest; | 1438 | const struct in6_addr *dest; |
1413 | struct in6_addr *target; /* new first hop to destination */ | 1439 | const struct in6_addr *target; /* new first hop to destination */ |
1414 | struct neighbour *neigh; | 1440 | struct neighbour *neigh; |
1415 | int on_link = 0; | 1441 | int on_link = 0; |
1416 | struct ndisc_options ndopts; | 1442 | struct ndisc_options ndopts; |
@@ -1443,7 +1469,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1443 | } | 1469 | } |
1444 | 1470 | ||
1445 | icmph = icmp6_hdr(skb); | 1471 | icmph = icmp6_hdr(skb); |
1446 | target = (struct in6_addr *) (icmph + 1); | 1472 | target = (const struct in6_addr *) (icmph + 1); |
1447 | dest = target + 1; | 1473 | dest = target + 1; |
1448 | 1474 | ||
1449 | if (ipv6_addr_is_multicast(dest)) { | 1475 | if (ipv6_addr_is_multicast(dest)) { |
@@ -1515,7 +1541,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1515 | struct rt6_info *rt; | 1541 | struct rt6_info *rt; |
1516 | struct dst_entry *dst; | 1542 | struct dst_entry *dst; |
1517 | struct inet6_dev *idev; | 1543 | struct inet6_dev *idev; |
1518 | struct flowi fl; | 1544 | struct flowi6 fl6; |
1519 | u8 *opt; | 1545 | u8 *opt; |
1520 | int rd_len; | 1546 | int rd_len; |
1521 | int err; | 1547 | int err; |
@@ -1535,15 +1561,15 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1535 | return; | 1561 | return; |
1536 | } | 1562 | } |
1537 | 1563 | ||
1538 | icmpv6_flow_init(sk, &fl, NDISC_REDIRECT, | 1564 | icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT, |
1539 | &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex); | 1565 | &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex); |
1540 | 1566 | ||
1541 | dst = ip6_route_output(net, NULL, &fl); | 1567 | dst = ip6_route_output(net, NULL, &fl6); |
1542 | if (dst == NULL) | 1568 | if (dst == NULL) |
1543 | return; | 1569 | return; |
1544 | 1570 | ||
1545 | err = xfrm_lookup(net, &dst, &fl, NULL, 0); | 1571 | dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); |
1546 | if (err) | 1572 | if (IS_ERR(dst)) |
1547 | return; | 1573 | return; |
1548 | 1574 | ||
1549 | rt = (struct rt6_info *) dst; | 1575 | rt = (struct rt6_info *) dst; |
@@ -1553,7 +1579,9 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1553 | "ICMPv6 Redirect: destination is not a neighbour.\n"); | 1579 | "ICMPv6 Redirect: destination is not a neighbour.\n"); |
1554 | goto release; | 1580 | goto release; |
1555 | } | 1581 | } |
1556 | if (!xrlim_allow(dst, 1*HZ)) | 1582 | if (!rt->rt6i_peer) |
1583 | rt6_bind_peer(rt, 1); | ||
1584 | if (inet_peer_xrlim_allow(rt->rt6i_peer, 1*HZ)) | ||
1557 | goto release; | 1585 | goto release; |
1558 | 1586 | ||
1559 | if (dev->addr_len) { | 1587 | if (dev->addr_len) { |
@@ -1718,6 +1746,9 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, | |||
1718 | neigh_ifdown(&nd_tbl, dev); | 1746 | neigh_ifdown(&nd_tbl, dev); |
1719 | fib6_run_gc(~0UL, net); | 1747 | fib6_run_gc(~0UL, net); |
1720 | break; | 1748 | break; |
1749 | case NETDEV_NOTIFY_PEERS: | ||
1750 | ndisc_send_unsol_na(dev); | ||
1751 | break; | ||
1721 | default: | 1752 | default: |
1722 | break; | 1753 | break; |
1723 | } | 1754 | } |