diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/addrconf.c | 2 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 8 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 34 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 2 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6table_mangle.c | 3 | ||||
-rw-r--r-- | net/ipv6/route.c | 72 |
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); | ||
828 | out: | 830 | out: |
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 | ||
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 | |||
614 | void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, | 637 | void 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 | ||
2050 | int 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 */ | ||
2067 | struct arg_dev_net_ip { | ||
2068 | struct net_device *dev; | ||
2069 | struct net *net; | ||
2070 | struct in6_addr *addr; | ||
2071 | }; | ||
2072 | |||
2073 | static 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 | |||
2088 | void 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 | |||
2040 | struct arg_dev_net { | 2099 | struct 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 | ||