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.c54
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
414static inline void ndisc_flow_init(struct flowi *fl, u8 type, 414static 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
425static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, 428static 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
966out: 992out:
@@ -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)