diff options
Diffstat (limited to 'net/ipv6/ndisc.c')
| -rw-r--r-- | net/ipv6/ndisc.c | 54 |
1 files changed, 41 insertions, 13 deletions
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index dfa20d3be9b6..0304b5fe8d6a 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
| @@ -48,7 +48,6 @@ | |||
| 48 | #endif | 48 | #endif |
| 49 | 49 | ||
| 50 | #include <linux/module.h> | 50 | #include <linux/module.h> |
| 51 | #include <linux/config.h> | ||
| 52 | #include <linux/errno.h> | 51 | #include <linux/errno.h> |
| 53 | #include <linux/types.h> | 52 | #include <linux/types.h> |
| 54 | #include <linux/socket.h> | 53 | #include <linux/socket.h> |
| @@ -63,6 +62,7 @@ | |||
| 63 | #include <linux/sysctl.h> | 62 | #include <linux/sysctl.h> |
| 64 | #endif | 63 | #endif |
| 65 | 64 | ||
| 65 | #include <linux/if_addr.h> | ||
| 66 | #include <linux/if_arp.h> | 66 | #include <linux/if_arp.h> |
| 67 | #include <linux/ipv6.h> | 67 | #include <linux/ipv6.h> |
| 68 | #include <linux/icmpv6.h> | 68 | #include <linux/icmpv6.h> |
| @@ -412,7 +412,8 @@ static void pndisc_destructor(struct pneigh_entry *n) | |||
| 412 | */ | 412 | */ |
| 413 | 413 | ||
| 414 | static inline void ndisc_flow_init(struct flowi *fl, u8 type, | 414 | static inline void ndisc_flow_init(struct flowi *fl, u8 type, |
| 415 | struct in6_addr *saddr, struct in6_addr *daddr) | 415 | struct in6_addr *saddr, struct in6_addr *daddr, |
| 416 | int oif) | ||
| 416 | { | 417 | { |
| 417 | memset(fl, 0, sizeof(*fl)); | 418 | memset(fl, 0, sizeof(*fl)); |
| 418 | ipv6_addr_copy(&fl->fl6_src, saddr); | 419 | ipv6_addr_copy(&fl->fl6_src, saddr); |
| @@ -420,6 +421,8 @@ static inline void ndisc_flow_init(struct flowi *fl, u8 type, | |||
| 420 | fl->proto = IPPROTO_ICMPV6; | 421 | fl->proto = IPPROTO_ICMPV6; |
| 421 | fl->fl_icmp_type = type; | 422 | fl->fl_icmp_type = type; |
| 422 | fl->fl_icmp_code = 0; | 423 | fl->fl_icmp_code = 0; |
| 424 | fl->oif = oif; | ||
| 425 | security_sk_classify_flow(ndisc_socket->sk, fl); | ||
| 423 | } | 426 | } |
| 424 | 427 | ||
| 425 | static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | 428 | static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, |
| @@ -451,7 +454,8 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
| 451 | src_addr = &tmpaddr; | 454 | src_addr = &tmpaddr; |
| 452 | } | 455 | } |
| 453 | 456 | ||
| 454 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr); | 457 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr, |
| 458 | dev->ifindex); | ||
| 455 | 459 | ||
| 456 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); | 460 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); |
| 457 | if (!dst) | 461 | if (!dst) |
| @@ -492,7 +496,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
| 492 | msg->icmph.icmp6_unused = 0; | 496 | msg->icmph.icmp6_unused = 0; |
| 493 | msg->icmph.icmp6_router = router; | 497 | msg->icmph.icmp6_router = router; |
| 494 | msg->icmph.icmp6_solicited = solicited; | 498 | msg->icmph.icmp6_solicited = solicited; |
| 495 | msg->icmph.icmp6_override = !!override; | 499 | msg->icmph.icmp6_override = override; |
| 496 | 500 | ||
| 497 | /* Set the target address. */ | 501 | /* Set the target address. */ |
| 498 | ipv6_addr_copy(&msg->target, solicited_addr); | 502 | ipv6_addr_copy(&msg->target, solicited_addr); |
| @@ -541,7 +545,8 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, | |||
| 541 | saddr = &addr_buf; | 545 | saddr = &addr_buf; |
| 542 | } | 546 | } |
| 543 | 547 | ||
| 544 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr); | 548 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr, |
| 549 | dev->ifindex); | ||
| 545 | 550 | ||
| 546 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); | 551 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); |
| 547 | if (!dst) | 552 | if (!dst) |
| @@ -616,7 +621,8 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, | |||
| 616 | int len; | 621 | int len; |
| 617 | int err; | 622 | int err; |
| 618 | 623 | ||
| 619 | ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr); | 624 | ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr, |
| 625 | dev->ifindex); | ||
| 620 | 626 | ||
| 621 | dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output); | 627 | dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output); |
| 622 | if (!dst) | 628 | if (!dst) |
| @@ -730,8 +736,10 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
| 730 | struct inet6_ifaddr *ifp; | 736 | struct inet6_ifaddr *ifp; |
| 731 | struct inet6_dev *idev = NULL; | 737 | struct inet6_dev *idev = NULL; |
| 732 | struct neighbour *neigh; | 738 | struct neighbour *neigh; |
| 739 | struct pneigh_entry *pneigh = NULL; | ||
| 733 | int dad = ipv6_addr_any(saddr); | 740 | int dad = ipv6_addr_any(saddr); |
| 734 | int inc; | 741 | int inc; |
| 742 | int is_router; | ||
| 735 | 743 | ||
| 736 | if (ipv6_addr_is_multicast(&msg->target)) { | 744 | if (ipv6_addr_is_multicast(&msg->target)) { |
| 737 | ND_PRINTK2(KERN_WARNING | 745 | ND_PRINTK2(KERN_WARNING |
| @@ -816,7 +824,9 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
| 816 | 824 | ||
| 817 | if (ipv6_chk_acast_addr(dev, &msg->target) || | 825 | if (ipv6_chk_acast_addr(dev, &msg->target) || |
| 818 | (idev->cnf.forwarding && | 826 | (idev->cnf.forwarding && |
| 819 | pneigh_lookup(&nd_tbl, &msg->target, dev, 0))) { | 827 | (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && |
| 828 | (pneigh = pneigh_lookup(&nd_tbl, | ||
| 829 | &msg->target, dev, 0)) != NULL)) { | ||
| 820 | if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && | 830 | if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && |
| 821 | skb->pkt_type != PACKET_HOST && | 831 | skb->pkt_type != PACKET_HOST && |
| 822 | inc != 0 && | 832 | inc != 0 && |
| @@ -837,12 +847,14 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
| 837 | goto out; | 847 | goto out; |
| 838 | } | 848 | } |
| 839 | 849 | ||
| 850 | is_router = !!(pneigh ? pneigh->flags & NTF_ROUTER : idev->cnf.forwarding); | ||
| 851 | |||
| 840 | if (dad) { | 852 | if (dad) { |
| 841 | struct in6_addr maddr; | 853 | struct in6_addr maddr; |
| 842 | 854 | ||
| 843 | ipv6_addr_all_nodes(&maddr); | 855 | ipv6_addr_all_nodes(&maddr); |
| 844 | ndisc_send_na(dev, NULL, &maddr, &msg->target, | 856 | ndisc_send_na(dev, NULL, &maddr, &msg->target, |
| 845 | idev->cnf.forwarding, 0, (ifp != NULL), 1); | 857 | is_router, 0, (ifp != NULL), 1); |
| 846 | goto out; | 858 | goto out; |
| 847 | } | 859 | } |
| 848 | 860 | ||
| @@ -863,7 +875,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
| 863 | NEIGH_UPDATE_F_OVERRIDE); | 875 | NEIGH_UPDATE_F_OVERRIDE); |
| 864 | if (neigh || !dev->hard_header) { | 876 | if (neigh || !dev->hard_header) { |
| 865 | ndisc_send_na(dev, neigh, saddr, &msg->target, | 877 | ndisc_send_na(dev, neigh, saddr, &msg->target, |
| 866 | idev->cnf.forwarding, | 878 | is_router, |
| 867 | 1, (ifp != NULL && inc), inc); | 879 | 1, (ifp != NULL && inc), inc); |
| 868 | if (neigh) | 880 | if (neigh) |
| 869 | neigh_release(neigh); | 881 | neigh_release(neigh); |
| @@ -946,6 +958,20 @@ static void ndisc_recv_na(struct sk_buff *skb) | |||
| 946 | if (neigh->nud_state & NUD_FAILED) | 958 | if (neigh->nud_state & NUD_FAILED) |
| 947 | goto out; | 959 | goto out; |
| 948 | 960 | ||
| 961 | /* | ||
| 962 | * Don't update the neighbor cache entry on a proxy NA from | ||
| 963 | * ourselves because either the proxied node is off link or it | ||
| 964 | * has already sent a NA to us. | ||
| 965 | */ | ||
| 966 | if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && | ||
| 967 | ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp && | ||
| 968 | pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) { | ||
| 969 | /* XXX: idev->cnf.prixy_ndp */ | ||
| 970 | WARN_ON(skb->dst != NULL && | ||
| 971 | ((struct rt6_info *)skb->dst)->rt6i_idev); | ||
| 972 | goto out; | ||
| 973 | } | ||
| 974 | |||
| 949 | neigh_update(neigh, lladdr, | 975 | neigh_update(neigh, lladdr, |
| 950 | msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE, | 976 | msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE, |
| 951 | NEIGH_UPDATE_F_WEAK_OVERRIDE| | 977 | NEIGH_UPDATE_F_WEAK_OVERRIDE| |
| @@ -960,7 +986,7 @@ static void ndisc_recv_na(struct sk_buff *skb) | |||
| 960 | struct rt6_info *rt; | 986 | struct rt6_info *rt; |
| 961 | rt = rt6_get_dflt_router(saddr, dev); | 987 | rt = rt6_get_dflt_router(saddr, dev); |
| 962 | if (rt) | 988 | if (rt) |
| 963 | ip6_del_rt(rt, NULL, NULL, NULL); | 989 | ip6_del_rt(rt); |
| 964 | } | 990 | } |
| 965 | 991 | ||
| 966 | out: | 992 | out: |
| @@ -1113,7 +1139,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1113 | 1139 | ||
| 1114 | if (rt && lifetime == 0) { | 1140 | if (rt && lifetime == 0) { |
| 1115 | neigh_clone(neigh); | 1141 | neigh_clone(neigh); |
| 1116 | ip6_del_rt(rt, NULL, NULL, NULL); | 1142 | ip6_del_rt(rt); |
| 1117 | rt = NULL; | 1143 | rt = NULL; |
| 1118 | } | 1144 | } |
| 1119 | 1145 | ||
| @@ -1345,7 +1371,8 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
| 1345 | 1371 | ||
| 1346 | neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); | 1372 | neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); |
| 1347 | if (neigh) { | 1373 | if (neigh) { |
| 1348 | rt6_redirect(dest, &skb->nh.ipv6h->saddr, neigh, lladdr, | 1374 | rt6_redirect(dest, &skb->nh.ipv6h->daddr, |
| 1375 | &skb->nh.ipv6h->saddr, neigh, lladdr, | ||
| 1349 | on_link); | 1376 | on_link); |
| 1350 | neigh_release(neigh); | 1377 | neigh_release(neigh); |
| 1351 | } | 1378 | } |
| @@ -1381,7 +1408,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
| 1381 | return; | 1408 | return; |
| 1382 | } | 1409 | } |
| 1383 | 1410 | ||
| 1384 | ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &skb->nh.ipv6h->saddr); | 1411 | ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &skb->nh.ipv6h->saddr, |
| 1412 | dev->ifindex); | ||
| 1385 | 1413 | ||
| 1386 | dst = ip6_route_output(NULL, &fl); | 1414 | dst = ip6_route_output(NULL, &fl); |
| 1387 | if (dst == NULL) | 1415 | if (dst == NULL) |
