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