aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/addrconf.c2
-rw-r--r--net/ipv6/ip6_output.c8
-rw-r--r--net/ipv6/ndisc.c34
-rw-r--r--net/ipv6/netfilter/ip6_tables.c2
-rw-r--r--net/ipv6/netfilter/ip6table_mangle.c3
-rw-r--r--net/ipv6/route.c72
6 files changed, 108 insertions, 13 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 1493534116df..129d7e1f311c 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -825,6 +825,8 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
825 dst_release(&rt->dst); 825 dst_release(&rt->dst);
826 } 826 }
827 827
828 /* clean up prefsrc entries */
829 rt6_remove_prefsrc(ifp);
828out: 830out:
829 in6_ifa_put(ifp); 831 in6_ifa_put(ifp);
830} 832}
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 46cf7bea6769..c614d02bf429 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -930,10 +930,10 @@ static int ip6_dst_lookup_tail(struct sock *sk,
930 goto out_err_release; 930 goto out_err_release;
931 931
932 if (ipv6_addr_any(&fl6->saddr)) { 932 if (ipv6_addr_any(&fl6->saddr)) {
933 err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev, 933 struct rt6_info *rt = (struct rt6_info *) *dst;
934 &fl6->daddr, 934 err = ip6_route_get_saddr(net, rt, &fl6->daddr,
935 sk ? inet6_sk(sk)->srcprefs : 0, 935 sk ? inet6_sk(sk)->srcprefs : 0,
936 &fl6->saddr); 936 &fl6->saddr);
937 if (err) 937 if (err)
938 goto out_err_release; 938 goto out_err_release;
939 } 939 }
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 92f952d093db..01a0ffc7b402 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -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
614static 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
614void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, 637void 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)
@@ -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
@@ -1722,6 +1746,10 @@ 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 case NETDEV_BONDING_FAILOVER:
1751 ndisc_send_unsol_na(dev);
1752 break;
1725 default: 1753 default:
1726 break; 1754 break;
1727 } 1755 }
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 5a1c6f27ffaf..4c1492ff473c 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -1578,7 +1578,6 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
1578 struct xt_table_info *newinfo, unsigned char *base) 1578 struct xt_table_info *newinfo, unsigned char *base)
1579{ 1579{
1580 struct xt_entry_target *t; 1580 struct xt_entry_target *t;
1581 struct xt_target *target;
1582 struct ip6t_entry *de; 1581 struct ip6t_entry *de;
1583 unsigned int origsize; 1582 unsigned int origsize;
1584 int ret, h; 1583 int ret, h;
@@ -1600,7 +1599,6 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
1600 } 1599 }
1601 de->target_offset = e->target_offset - (origsize - *size); 1600 de->target_offset = e->target_offset - (origsize - *size);
1602 t = compat_ip6t_get_target(e); 1601 t = compat_ip6t_get_target(e);
1603 target = t->u.kernel.target;
1604 xt_compat_target_from_user(t, dstptr, size); 1602 xt_compat_target_from_user(t, dstptr, size);
1605 1603
1606 de->next_offset = e->next_offset - (origsize - *size); 1604 de->next_offset = e->next_offset - (origsize - *size);
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index 679a0a3b7b3c..00d19173db7e 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -64,7 +64,8 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out)
64 (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) || 64 (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) ||
65 memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) || 65 memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) ||
66 skb->mark != mark || 66 skb->mark != mark ||
67 ipv6_hdr(skb)->hop_limit != hop_limit)) 67 ipv6_hdr(skb)->hop_limit != hop_limit ||
68 flowlabel != *((u_int32_t *)ipv6_hdr(skb))))
68 return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP; 69 return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP;
69 70
70 return ret; 71 return ret;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 843406f14d7b..af26cc1073cb 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1325,6 +1325,16 @@ int ip6_route_add(struct fib6_config *cfg)
1325 if (dev == NULL) 1325 if (dev == NULL)
1326 goto out; 1326 goto out;
1327 1327
1328 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
1329 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
1330 err = -EINVAL;
1331 goto out;
1332 }
1333 ipv6_addr_copy(&rt->rt6i_prefsrc.addr, &cfg->fc_prefsrc);
1334 rt->rt6i_prefsrc.plen = 128;
1335 } else
1336 rt->rt6i_prefsrc.plen = 0;
1337
1328 if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { 1338 if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) {
1329 rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); 1339 rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev);
1330 if (IS_ERR(rt->rt6i_nexthop)) { 1340 if (IS_ERR(rt->rt6i_nexthop)) {
@@ -2037,6 +2047,55 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2037 return rt; 2047 return rt;
2038} 2048}
2039 2049
2050int ip6_route_get_saddr(struct net *net,
2051 struct rt6_info *rt,
2052 struct in6_addr *daddr,
2053 unsigned int prefs,
2054 struct in6_addr *saddr)
2055{
2056 struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt);
2057 int err = 0;
2058 if (rt->rt6i_prefsrc.plen)
2059 ipv6_addr_copy(saddr, &rt->rt6i_prefsrc.addr);
2060 else
2061 err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
2062 daddr, prefs, saddr);
2063 return err;
2064}
2065
2066/* remove deleted ip from prefsrc entries */
2067struct arg_dev_net_ip {
2068 struct net_device *dev;
2069 struct net *net;
2070 struct in6_addr *addr;
2071};
2072
2073static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2074{
2075 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2076 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2077 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2078
2079 if (((void *)rt->rt6i_dev == dev || dev == NULL) &&
2080 rt != net->ipv6.ip6_null_entry &&
2081 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2082 /* remove prefsrc entry */
2083 rt->rt6i_prefsrc.plen = 0;
2084 }
2085 return 0;
2086}
2087
2088void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2089{
2090 struct net *net = dev_net(ifp->idev->dev);
2091 struct arg_dev_net_ip adni = {
2092 .dev = ifp->idev->dev,
2093 .net = net,
2094 .addr = &ifp->addr,
2095 };
2096 fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni);
2097}
2098
2040struct arg_dev_net { 2099struct arg_dev_net {
2041 struct net_device *dev; 2100 struct net_device *dev;
2042 struct net *net; 2101 struct net *net;
@@ -2183,6 +2242,9 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2183 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen); 2242 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
2184 } 2243 }
2185 2244
2245 if (tb[RTA_PREFSRC])
2246 nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16);
2247
2186 if (tb[RTA_OIF]) 2248 if (tb[RTA_OIF])
2187 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]); 2249 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
2188 2250
@@ -2325,13 +2387,17 @@ static int rt6_fill_node(struct net *net,
2325#endif 2387#endif
2326 NLA_PUT_U32(skb, RTA_IIF, iif); 2388 NLA_PUT_U32(skb, RTA_IIF, iif);
2327 } else if (dst) { 2389 } else if (dst) {
2328 struct inet6_dev *idev = ip6_dst_idev(&rt->dst);
2329 struct in6_addr saddr_buf; 2390 struct in6_addr saddr_buf;
2330 if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, 2391 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0)
2331 dst, 0, &saddr_buf) == 0)
2332 NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); 2392 NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
2333 } 2393 }
2334 2394
2395 if (rt->rt6i_prefsrc.plen) {
2396 struct in6_addr saddr_buf;
2397 ipv6_addr_copy(&saddr_buf, &rt->rt6i_prefsrc.addr);
2398 NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
2399 }
2400
2335 if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) 2401 if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
2336 goto nla_put_failure; 2402 goto nla_put_failure;
2337 2403