.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * IPv6 Address [auto]configuration |
---|
3 | 4 | * Linux INET6 implementation |
---|
.. | .. |
---|
5 | 6 | * Authors: |
---|
6 | 7 | * Pedro Roque <roque@di.fc.ul.pt> |
---|
7 | 8 | * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> |
---|
8 | | - * |
---|
9 | | - * This program is free software; you can redistribute it and/or |
---|
10 | | - * modify it under the terms of the GNU General Public License |
---|
11 | | - * as published by the Free Software Foundation; either version |
---|
12 | | - * 2 of the License, or (at your option) any later version. |
---|
13 | 9 | */ |
---|
14 | 10 | |
---|
15 | 11 | /* |
---|
.. | .. |
---|
94 | 90 | #include <linux/seq_file.h> |
---|
95 | 91 | #include <linux/export.h> |
---|
96 | 92 | |
---|
| 93 | +#include <trace/hooks/ipv6.h> |
---|
| 94 | + |
---|
97 | 95 | #define INFINITY_LIFE_TIME 0xFFFFFFFF |
---|
98 | 96 | |
---|
99 | 97 | #define IPV6_MAX_STRLEN \ |
---|
.. | .. |
---|
139 | 137 | } |
---|
140 | 138 | #endif |
---|
141 | 139 | |
---|
142 | | -static void ipv6_regen_rndid(struct inet6_dev *idev); |
---|
143 | | -static void ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr); |
---|
| 140 | +static void ipv6_gen_rnd_iid(struct in6_addr *addr); |
---|
144 | 141 | |
---|
145 | 142 | static int ipv6_generate_eui64(u8 *eui, struct net_device *dev); |
---|
146 | 143 | static int ipv6_count_addresses(const struct inet6_dev *idev); |
---|
.. | .. |
---|
168 | 165 | |
---|
169 | 166 | static void addrconf_type_change(struct net_device *dev, |
---|
170 | 167 | unsigned long event); |
---|
171 | | -static int addrconf_ifdown(struct net_device *dev, int how); |
---|
| 168 | +static int addrconf_ifdown(struct net_device *dev, bool unregister); |
---|
172 | 169 | |
---|
173 | 170 | static struct fib6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, |
---|
174 | 171 | int plen, |
---|
175 | 172 | const struct net_device *dev, |
---|
176 | | - u32 flags, u32 noflags); |
---|
| 173 | + u32 flags, u32 noflags, |
---|
| 174 | + bool no_gw); |
---|
177 | 175 | |
---|
178 | 176 | static void addrconf_dad_start(struct inet6_ifaddr *ifp); |
---|
179 | 177 | static void addrconf_dad_work(struct work_struct *w); |
---|
.. | .. |
---|
240 | 238 | .enhanced_dad = 1, |
---|
241 | 239 | .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64, |
---|
242 | 240 | .disable_policy = 0, |
---|
| 241 | + .rpl_seg_enabled = 0, |
---|
243 | 242 | }; |
---|
244 | 243 | |
---|
245 | 244 | static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { |
---|
.. | .. |
---|
295 | 294 | .enhanced_dad = 1, |
---|
296 | 295 | .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64, |
---|
297 | 296 | .disable_policy = 0, |
---|
| 297 | + .rpl_seg_enabled = 0, |
---|
298 | 298 | }; |
---|
299 | 299 | |
---|
300 | 300 | /* Check if link is ready: is it up and is a valid qdisc available */ |
---|
.. | .. |
---|
318 | 318 | static void addrconf_mod_rs_timer(struct inet6_dev *idev, |
---|
319 | 319 | unsigned long when) |
---|
320 | 320 | { |
---|
321 | | - if (!timer_pending(&idev->rs_timer)) |
---|
| 321 | + if (!mod_timer(&idev->rs_timer, jiffies + when)) |
---|
322 | 322 | in6_dev_hold(idev); |
---|
323 | | - mod_timer(&idev->rs_timer, jiffies + when); |
---|
324 | 323 | } |
---|
325 | 324 | |
---|
326 | 325 | static void addrconf_mod_dad_work(struct inet6_ifaddr *ifp, |
---|
.. | .. |
---|
435 | 434 | dev->type == ARPHRD_SIT || |
---|
436 | 435 | dev->type == ARPHRD_NONE) { |
---|
437 | 436 | ndev->cnf.use_tempaddr = -1; |
---|
438 | | - } else |
---|
439 | | - ipv6_regen_rndid(ndev); |
---|
| 437 | + } |
---|
440 | 438 | |
---|
441 | 439 | ndev->token = in6addr_any; |
---|
442 | 440 | |
---|
.. | .. |
---|
483 | 481 | if (!idev) { |
---|
484 | 482 | idev = ipv6_add_dev(dev); |
---|
485 | 483 | if (IS_ERR(idev)) |
---|
486 | | - return NULL; |
---|
| 484 | + return idev; |
---|
487 | 485 | } |
---|
488 | 486 | |
---|
489 | 487 | if (dev->flags&IFF_UP) |
---|
.. | .. |
---|
547 | 545 | #ifdef CONFIG_IPV6_MROUTE |
---|
548 | 546 | if ((all || type == NETCONFA_MC_FORWARDING) && |
---|
549 | 547 | nla_put_s32(skb, NETCONFA_MC_FORWARDING, |
---|
550 | | - devconf->mc_forwarding) < 0) |
---|
| 548 | + atomic_read(&devconf->mc_forwarding)) < 0) |
---|
551 | 549 | goto nla_put_failure; |
---|
552 | 550 | #endif |
---|
553 | 551 | if ((all || type == NETCONFA_PROXY_NEIGH) && |
---|
.. | .. |
---|
599 | 597 | [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) }, |
---|
600 | 598 | }; |
---|
601 | 599 | |
---|
| 600 | +static int inet6_netconf_valid_get_req(struct sk_buff *skb, |
---|
| 601 | + const struct nlmsghdr *nlh, |
---|
| 602 | + struct nlattr **tb, |
---|
| 603 | + struct netlink_ext_ack *extack) |
---|
| 604 | +{ |
---|
| 605 | + int i, err; |
---|
| 606 | + |
---|
| 607 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(struct netconfmsg))) { |
---|
| 608 | + NL_SET_ERR_MSG_MOD(extack, "Invalid header for netconf get request"); |
---|
| 609 | + return -EINVAL; |
---|
| 610 | + } |
---|
| 611 | + |
---|
| 612 | + if (!netlink_strict_get_check(skb)) |
---|
| 613 | + return nlmsg_parse_deprecated(nlh, sizeof(struct netconfmsg), |
---|
| 614 | + tb, NETCONFA_MAX, |
---|
| 615 | + devconf_ipv6_policy, extack); |
---|
| 616 | + |
---|
| 617 | + err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct netconfmsg), |
---|
| 618 | + tb, NETCONFA_MAX, |
---|
| 619 | + devconf_ipv6_policy, extack); |
---|
| 620 | + if (err) |
---|
| 621 | + return err; |
---|
| 622 | + |
---|
| 623 | + for (i = 0; i <= NETCONFA_MAX; i++) { |
---|
| 624 | + if (!tb[i]) |
---|
| 625 | + continue; |
---|
| 626 | + |
---|
| 627 | + switch (i) { |
---|
| 628 | + case NETCONFA_IFINDEX: |
---|
| 629 | + break; |
---|
| 630 | + default: |
---|
| 631 | + NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in netconf get request"); |
---|
| 632 | + return -EINVAL; |
---|
| 633 | + } |
---|
| 634 | + } |
---|
| 635 | + |
---|
| 636 | + return 0; |
---|
| 637 | +} |
---|
| 638 | + |
---|
602 | 639 | static int inet6_netconf_get_devconf(struct sk_buff *in_skb, |
---|
603 | 640 | struct nlmsghdr *nlh, |
---|
604 | 641 | struct netlink_ext_ack *extack) |
---|
.. | .. |
---|
607 | 644 | struct nlattr *tb[NETCONFA_MAX+1]; |
---|
608 | 645 | struct inet6_dev *in6_dev = NULL; |
---|
609 | 646 | struct net_device *dev = NULL; |
---|
610 | | - struct netconfmsg *ncm; |
---|
611 | 647 | struct sk_buff *skb; |
---|
612 | 648 | struct ipv6_devconf *devconf; |
---|
613 | 649 | int ifindex; |
---|
614 | 650 | int err; |
---|
615 | 651 | |
---|
616 | | - err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX, |
---|
617 | | - devconf_ipv6_policy, extack); |
---|
| 652 | + err = inet6_netconf_valid_get_req(in_skb, nlh, tb, extack); |
---|
618 | 653 | if (err < 0) |
---|
619 | 654 | return err; |
---|
620 | 655 | |
---|
.. | .. |
---|
668 | 703 | static int inet6_netconf_dump_devconf(struct sk_buff *skb, |
---|
669 | 704 | struct netlink_callback *cb) |
---|
670 | 705 | { |
---|
| 706 | + const struct nlmsghdr *nlh = cb->nlh; |
---|
671 | 707 | struct net *net = sock_net(skb->sk); |
---|
672 | 708 | int h, s_h; |
---|
673 | 709 | int idx, s_idx; |
---|
674 | 710 | struct net_device *dev; |
---|
675 | 711 | struct inet6_dev *idev; |
---|
676 | 712 | struct hlist_head *head; |
---|
| 713 | + |
---|
| 714 | + if (cb->strict_check) { |
---|
| 715 | + struct netlink_ext_ack *extack = cb->extack; |
---|
| 716 | + struct netconfmsg *ncm; |
---|
| 717 | + |
---|
| 718 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ncm))) { |
---|
| 719 | + NL_SET_ERR_MSG_MOD(extack, "Invalid header for netconf dump request"); |
---|
| 720 | + return -EINVAL; |
---|
| 721 | + } |
---|
| 722 | + |
---|
| 723 | + if (nlmsg_attrlen(nlh, sizeof(*ncm))) { |
---|
| 724 | + NL_SET_ERR_MSG_MOD(extack, "Invalid data after header in netconf dump request"); |
---|
| 725 | + return -EINVAL; |
---|
| 726 | + } |
---|
| 727 | + } |
---|
677 | 728 | |
---|
678 | 729 | s_h = cb->args[0]; |
---|
679 | 730 | s_idx = idx = cb->args[1]; |
---|
.. | .. |
---|
694 | 745 | if (inet6_netconf_fill_devconf(skb, dev->ifindex, |
---|
695 | 746 | &idev->cnf, |
---|
696 | 747 | NETLINK_CB(cb->skb).portid, |
---|
697 | | - cb->nlh->nlmsg_seq, |
---|
| 748 | + nlh->nlmsg_seq, |
---|
698 | 749 | RTM_NEWNETCONF, |
---|
699 | 750 | NLM_F_MULTI, |
---|
700 | 751 | NETCONFA_ALL) < 0) { |
---|
.. | .. |
---|
711 | 762 | if (inet6_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL, |
---|
712 | 763 | net->ipv6.devconf_all, |
---|
713 | 764 | NETLINK_CB(cb->skb).portid, |
---|
714 | | - cb->nlh->nlmsg_seq, |
---|
| 765 | + nlh->nlmsg_seq, |
---|
715 | 766 | RTM_NEWNETCONF, NLM_F_MULTI, |
---|
716 | 767 | NETCONFA_ALL) < 0) |
---|
717 | 768 | goto done; |
---|
.. | .. |
---|
722 | 773 | if (inet6_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT, |
---|
723 | 774 | net->ipv6.devconf_dflt, |
---|
724 | 775 | NETLINK_CB(cb->skb).portid, |
---|
725 | | - cb->nlh->nlmsg_seq, |
---|
| 776 | + nlh->nlmsg_seq, |
---|
726 | 777 | RTM_NEWNETCONF, NLM_F_MULTI, |
---|
727 | 778 | NETCONFA_ALL) < 0) |
---|
728 | 779 | goto done; |
---|
.. | .. |
---|
741 | 792 | { |
---|
742 | 793 | struct net_device *dev; |
---|
743 | 794 | struct inet6_ifaddr *ifa; |
---|
| 795 | + LIST_HEAD(tmp_addr_list); |
---|
744 | 796 | |
---|
745 | 797 | if (!idev) |
---|
746 | 798 | return; |
---|
.. | .. |
---|
759 | 811 | } |
---|
760 | 812 | } |
---|
761 | 813 | |
---|
| 814 | + read_lock_bh(&idev->lock); |
---|
762 | 815 | list_for_each_entry(ifa, &idev->addr_list, if_list) { |
---|
763 | 816 | if (ifa->flags&IFA_F_TENTATIVE) |
---|
764 | 817 | continue; |
---|
| 818 | + list_add_tail(&ifa->if_list_aux, &tmp_addr_list); |
---|
| 819 | + } |
---|
| 820 | + read_unlock_bh(&idev->lock); |
---|
| 821 | + |
---|
| 822 | + while (!list_empty(&tmp_addr_list)) { |
---|
| 823 | + ifa = list_first_entry(&tmp_addr_list, |
---|
| 824 | + struct inet6_ifaddr, if_list_aux); |
---|
| 825 | + list_del(&ifa->if_list_aux); |
---|
765 | 826 | if (idev->cnf.forwarding) |
---|
766 | 827 | addrconf_join_anycast(ifa); |
---|
767 | 828 | else |
---|
768 | 829 | addrconf_leave_anycast(ifa); |
---|
769 | 830 | } |
---|
| 831 | + |
---|
770 | 832 | inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF, |
---|
771 | 833 | NETCONFA_FORWARDING, |
---|
772 | 834 | dev->ifindex, &idev->cnf); |
---|
.. | .. |
---|
1000 | 1062 | (addr_type & IPV6_ADDR_MULTICAST && |
---|
1001 | 1063 | !(cfg->ifa_flags & IFA_F_MCAUTOJOIN)) || |
---|
1002 | 1064 | (!(idev->dev->flags & IFF_LOOPBACK) && |
---|
| 1065 | + !netif_is_l3_master(idev->dev) && |
---|
1003 | 1066 | addr_type & IPV6_ADDR_LOOPBACK)) |
---|
1004 | 1067 | return ERR_PTR(-EADDRNOTAVAIL); |
---|
1005 | 1068 | |
---|
.. | .. |
---|
1041 | 1104 | f6i = NULL; |
---|
1042 | 1105 | goto out; |
---|
1043 | 1106 | } |
---|
1044 | | - |
---|
1045 | | - if (net->ipv6.devconf_all->disable_policy || |
---|
1046 | | - idev->cnf.disable_policy) |
---|
1047 | | - f6i->dst_nopolicy = true; |
---|
1048 | 1107 | |
---|
1049 | 1108 | neigh_parms_data_state_setall(idev->nd_parms); |
---|
1050 | 1109 | |
---|
.. | .. |
---|
1183 | 1242 | struct fib6_info *f6i; |
---|
1184 | 1243 | |
---|
1185 | 1244 | f6i = addrconf_get_prefix_route(del_peer ? &ifp->peer_addr : &ifp->addr, |
---|
1186 | | - ifp->prefix_len, |
---|
1187 | | - ifp->idev->dev, |
---|
1188 | | - 0, RTF_GATEWAY | RTF_DEFAULT); |
---|
| 1245 | + ifp->prefix_len, |
---|
| 1246 | + ifp->idev->dev, 0, RTF_DEFAULT, true); |
---|
1189 | 1247 | if (f6i) { |
---|
1190 | 1248 | if (del_rt) |
---|
1191 | | - ip6_del_rt(dev_net(ifp->idev->dev), f6i); |
---|
| 1249 | + ip6_del_rt(dev_net(ifp->idev->dev), f6i, false); |
---|
1192 | 1250 | else { |
---|
1193 | 1251 | if (!(f6i->fib6_flags & RTF_EXPIRES)) |
---|
1194 | 1252 | fib6_set_expires(f6i, expires); |
---|
.. | .. |
---|
1256 | 1314 | in6_ifa_put(ifp); |
---|
1257 | 1315 | } |
---|
1258 | 1316 | |
---|
1259 | | -static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, |
---|
1260 | | - struct inet6_ifaddr *ift, |
---|
1261 | | - bool block) |
---|
| 1317 | +static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block) |
---|
1262 | 1318 | { |
---|
1263 | 1319 | struct inet6_dev *idev = ifp->idev; |
---|
1264 | | - struct in6_addr addr, *tmpaddr; |
---|
1265 | 1320 | unsigned long tmp_tstamp, age; |
---|
1266 | 1321 | unsigned long regen_advance; |
---|
1267 | | - struct ifa6_config cfg; |
---|
1268 | | - int ret = 0; |
---|
1269 | 1322 | unsigned long now = jiffies; |
---|
1270 | | - long max_desync_factor; |
---|
1271 | 1323 | s32 cnf_temp_preferred_lft; |
---|
| 1324 | + struct inet6_ifaddr *ift; |
---|
| 1325 | + struct ifa6_config cfg; |
---|
| 1326 | + long max_desync_factor; |
---|
| 1327 | + struct in6_addr addr; |
---|
| 1328 | + int ret = 0; |
---|
1272 | 1329 | |
---|
1273 | 1330 | write_lock_bh(&idev->lock); |
---|
1274 | | - if (ift) { |
---|
1275 | | - spin_lock_bh(&ift->lock); |
---|
1276 | | - memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8); |
---|
1277 | | - spin_unlock_bh(&ift->lock); |
---|
1278 | | - tmpaddr = &addr; |
---|
1279 | | - } else { |
---|
1280 | | - tmpaddr = NULL; |
---|
1281 | | - } |
---|
| 1331 | + |
---|
1282 | 1332 | retry: |
---|
1283 | 1333 | in6_dev_hold(idev); |
---|
1284 | 1334 | if (idev->cnf.use_tempaddr <= 0) { |
---|
.. | .. |
---|
1301 | 1351 | } |
---|
1302 | 1352 | in6_ifa_hold(ifp); |
---|
1303 | 1353 | memcpy(addr.s6_addr, ifp->addr.s6_addr, 8); |
---|
1304 | | - ipv6_try_regen_rndid(idev, tmpaddr); |
---|
1305 | | - memcpy(&addr.s6_addr[8], idev->rndid, 8); |
---|
| 1354 | + ipv6_gen_rnd_iid(&addr); |
---|
| 1355 | + |
---|
1306 | 1356 | age = (now - ifp->tstamp) / HZ; |
---|
1307 | 1357 | |
---|
1308 | 1358 | regen_advance = idev->cnf.regen_max_retry * |
---|
1309 | 1359 | idev->cnf.dad_transmits * |
---|
1310 | | - NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ; |
---|
| 1360 | + max(NEIGH_VAR(idev->nd_parms, RETRANS_TIME), HZ/100) / HZ; |
---|
1311 | 1361 | |
---|
1312 | 1362 | /* recalculate max_desync_factor each time and update |
---|
1313 | 1363 | * idev->desync_factor if it's larger |
---|
1314 | 1364 | */ |
---|
1315 | 1365 | cnf_temp_preferred_lft = READ_ONCE(idev->cnf.temp_prefered_lft); |
---|
1316 | | - max_desync_factor = min_t(__u32, |
---|
| 1366 | + max_desync_factor = min_t(long, |
---|
1317 | 1367 | idev->cnf.max_desync_factor, |
---|
1318 | 1368 | cnf_temp_preferred_lft - regen_advance); |
---|
1319 | 1369 | |
---|
.. | .. |
---|
1367 | 1417 | in6_ifa_put(ifp); |
---|
1368 | 1418 | in6_dev_put(idev); |
---|
1369 | 1419 | pr_info("%s: retry temporary address regeneration\n", __func__); |
---|
1370 | | - tmpaddr = &addr; |
---|
1371 | 1420 | write_lock_bh(&idev->lock); |
---|
1372 | 1421 | goto retry; |
---|
1373 | 1422 | } |
---|
.. | .. |
---|
1854 | 1903 | * 2. does the address exist on the specific device |
---|
1855 | 1904 | * (skip_dev_check = false) |
---|
1856 | 1905 | */ |
---|
1857 | | -int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr, |
---|
1858 | | - const struct net_device *dev, bool skip_dev_check, |
---|
1859 | | - int strict, u32 banned_flags) |
---|
| 1906 | +static struct net_device * |
---|
| 1907 | +__ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr, |
---|
| 1908 | + const struct net_device *dev, bool skip_dev_check, |
---|
| 1909 | + int strict, u32 banned_flags) |
---|
1860 | 1910 | { |
---|
1861 | 1911 | unsigned int hash = inet6_addr_hash(net, addr); |
---|
1862 | | - const struct net_device *l3mdev; |
---|
| 1912 | + struct net_device *l3mdev, *ndev; |
---|
1863 | 1913 | struct inet6_ifaddr *ifp; |
---|
1864 | 1914 | u32 ifp_flags; |
---|
1865 | 1915 | |
---|
.. | .. |
---|
1870 | 1920 | dev = NULL; |
---|
1871 | 1921 | |
---|
1872 | 1922 | hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) { |
---|
1873 | | - if (!net_eq(dev_net(ifp->idev->dev), net)) |
---|
| 1923 | + ndev = ifp->idev->dev; |
---|
| 1924 | + if (!net_eq(dev_net(ndev), net)) |
---|
1874 | 1925 | continue; |
---|
1875 | 1926 | |
---|
1876 | | - if (l3mdev_master_dev_rcu(ifp->idev->dev) != l3mdev) |
---|
| 1927 | + if (l3mdev_master_dev_rcu(ndev) != l3mdev) |
---|
1877 | 1928 | continue; |
---|
1878 | 1929 | |
---|
1879 | 1930 | /* Decouple optimistic from tentative for evaluation here. |
---|
.. | .. |
---|
1884 | 1935 | : ifp->flags; |
---|
1885 | 1936 | if (ipv6_addr_equal(&ifp->addr, addr) && |
---|
1886 | 1937 | !(ifp_flags&banned_flags) && |
---|
1887 | | - (!dev || ifp->idev->dev == dev || |
---|
| 1938 | + (!dev || ndev == dev || |
---|
1888 | 1939 | !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) { |
---|
1889 | 1940 | rcu_read_unlock(); |
---|
1890 | | - return 1; |
---|
| 1941 | + return ndev; |
---|
1891 | 1942 | } |
---|
1892 | 1943 | } |
---|
1893 | 1944 | |
---|
1894 | 1945 | rcu_read_unlock(); |
---|
1895 | | - return 0; |
---|
| 1946 | + return NULL; |
---|
| 1947 | +} |
---|
| 1948 | + |
---|
| 1949 | +int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr, |
---|
| 1950 | + const struct net_device *dev, bool skip_dev_check, |
---|
| 1951 | + int strict, u32 banned_flags) |
---|
| 1952 | +{ |
---|
| 1953 | + return __ipv6_chk_addr_and_flags(net, addr, dev, skip_dev_check, |
---|
| 1954 | + strict, banned_flags) ? 1 : 0; |
---|
1896 | 1955 | } |
---|
1897 | 1956 | EXPORT_SYMBOL(ipv6_chk_addr_and_flags); |
---|
1898 | 1957 | |
---|
.. | .. |
---|
1944 | 2003 | } |
---|
1945 | 2004 | EXPORT_SYMBOL(ipv6_chk_prefix); |
---|
1946 | 2005 | |
---|
| 2006 | +/** |
---|
| 2007 | + * ipv6_dev_find - find the first device with a given source address. |
---|
| 2008 | + * @net: the net namespace |
---|
| 2009 | + * @addr: the source address |
---|
| 2010 | + * |
---|
| 2011 | + * The caller should be protected by RCU, or RTNL. |
---|
| 2012 | + */ |
---|
| 2013 | +struct net_device *ipv6_dev_find(struct net *net, const struct in6_addr *addr, |
---|
| 2014 | + struct net_device *dev) |
---|
| 2015 | +{ |
---|
| 2016 | + return __ipv6_chk_addr_and_flags(net, addr, dev, !dev, 1, |
---|
| 2017 | + IFA_F_TENTATIVE); |
---|
| 2018 | +} |
---|
| 2019 | +EXPORT_SYMBOL(ipv6_dev_find); |
---|
| 2020 | + |
---|
1947 | 2021 | struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *addr, |
---|
1948 | 2022 | struct net_device *dev, int strict) |
---|
1949 | 2023 | { |
---|
.. | .. |
---|
1982 | 2056 | if (ifpub) { |
---|
1983 | 2057 | in6_ifa_hold(ifpub); |
---|
1984 | 2058 | spin_unlock_bh(&ifp->lock); |
---|
1985 | | - ipv6_create_tempaddr(ifpub, ifp, true); |
---|
| 2059 | + ipv6_create_tempaddr(ifpub, true); |
---|
1986 | 2060 | in6_ifa_put(ifpub); |
---|
1987 | 2061 | } else { |
---|
1988 | 2062 | spin_unlock_bh(&ifp->lock); |
---|
.. | .. |
---|
2279 | 2353 | return err; |
---|
2280 | 2354 | } |
---|
2281 | 2355 | |
---|
2282 | | -/* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */ |
---|
2283 | | -static void ipv6_regen_rndid(struct inet6_dev *idev) |
---|
| 2356 | +/* Generation of a randomized Interface Identifier |
---|
| 2357 | + * draft-ietf-6man-rfc4941bis, Section 3.3.1 |
---|
| 2358 | + */ |
---|
| 2359 | + |
---|
| 2360 | +static void ipv6_gen_rnd_iid(struct in6_addr *addr) |
---|
2284 | 2361 | { |
---|
2285 | 2362 | regen: |
---|
2286 | | - get_random_bytes(idev->rndid, sizeof(idev->rndid)); |
---|
2287 | | - idev->rndid[0] &= ~0x02; |
---|
| 2363 | + get_random_bytes(&addr->s6_addr[8], 8); |
---|
2288 | 2364 | |
---|
2289 | | - /* |
---|
2290 | | - * <draft-ietf-ipngwg-temp-addresses-v2-00.txt>: |
---|
2291 | | - * check if generated address is not inappropriate |
---|
| 2365 | + /* <draft-ietf-6man-rfc4941bis-08.txt>, Section 3.3.1: |
---|
| 2366 | + * check if generated address is not inappropriate: |
---|
2292 | 2367 | * |
---|
2293 | | - * - Reserved subnet anycast (RFC 2526) |
---|
2294 | | - * 11111101 11....11 1xxxxxxx |
---|
2295 | | - * - ISATAP (RFC4214) 6.1 |
---|
2296 | | - * 00-00-5E-FE-xx-xx-xx-xx |
---|
2297 | | - * - value 0 |
---|
2298 | | - * - XXX: already assigned to an address on the device |
---|
| 2368 | + * - Reserved IPv6 Interface Identifers |
---|
| 2369 | + * - XXX: already assigned to an address on the device |
---|
2299 | 2370 | */ |
---|
2300 | | - if (idev->rndid[0] == 0xfd && |
---|
2301 | | - (idev->rndid[1]&idev->rndid[2]&idev->rndid[3]&idev->rndid[4]&idev->rndid[5]&idev->rndid[6]) == 0xff && |
---|
2302 | | - (idev->rndid[7]&0x80)) |
---|
2303 | | - goto regen; |
---|
2304 | | - if ((idev->rndid[0]|idev->rndid[1]) == 0) { |
---|
2305 | | - if (idev->rndid[2] == 0x5e && idev->rndid[3] == 0xfe) |
---|
2306 | | - goto regen; |
---|
2307 | | - if ((idev->rndid[2]|idev->rndid[3]|idev->rndid[4]|idev->rndid[5]|idev->rndid[6]|idev->rndid[7]) == 0x00) |
---|
2308 | | - goto regen; |
---|
2309 | | - } |
---|
2310 | | -} |
---|
2311 | 2371 | |
---|
2312 | | -static void ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr) |
---|
2313 | | -{ |
---|
2314 | | - if (tmpaddr && memcmp(idev->rndid, &tmpaddr->s6_addr[8], 8) == 0) |
---|
2315 | | - ipv6_regen_rndid(idev); |
---|
| 2372 | + /* Subnet-router anycast: 0000:0000:0000:0000 */ |
---|
| 2373 | + if (!(addr->s6_addr32[2] | addr->s6_addr32[3])) |
---|
| 2374 | + goto regen; |
---|
| 2375 | + |
---|
| 2376 | + /* IANA Ethernet block: 0200:5EFF:FE00:0000-0200:5EFF:FE00:5212 |
---|
| 2377 | + * Proxy Mobile IPv6: 0200:5EFF:FE00:5213 |
---|
| 2378 | + * IANA Ethernet block: 0200:5EFF:FE00:5214-0200:5EFF:FEFF:FFFF |
---|
| 2379 | + */ |
---|
| 2380 | + if (ntohl(addr->s6_addr32[2]) == 0x02005eff && |
---|
| 2381 | + (ntohl(addr->s6_addr32[3]) & 0Xff000000) == 0xfe000000) |
---|
| 2382 | + goto regen; |
---|
| 2383 | + |
---|
| 2384 | + /* Reserved subnet anycast addresses */ |
---|
| 2385 | + if (ntohl(addr->s6_addr32[2]) == 0xfdffffff && |
---|
| 2386 | + ntohl(addr->s6_addr32[3]) >= 0Xffffff80) |
---|
| 2387 | + goto regen; |
---|
2316 | 2388 | } |
---|
2317 | 2389 | |
---|
2318 | 2390 | u32 addrconf_rt_table(const struct net_device *dev, u32 default_table) |
---|
.. | .. |
---|
2374 | 2446 | static struct fib6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, |
---|
2375 | 2447 | int plen, |
---|
2376 | 2448 | const struct net_device *dev, |
---|
2377 | | - u32 flags, u32 noflags) |
---|
| 2449 | + u32 flags, u32 noflags, |
---|
| 2450 | + bool no_gw) |
---|
2378 | 2451 | { |
---|
2379 | 2452 | struct fib6_node *fn; |
---|
2380 | 2453 | struct fib6_info *rt = NULL; |
---|
.. | .. |
---|
2391 | 2464 | goto out; |
---|
2392 | 2465 | |
---|
2393 | 2466 | for_each_fib6_node_rt_rcu(fn) { |
---|
2394 | | - if (rt->fib6_nh.nh_dev->ifindex != dev->ifindex) |
---|
| 2467 | + /* prefix routes only use builtin fib6_nh */ |
---|
| 2468 | + if (rt->nh) |
---|
| 2469 | + continue; |
---|
| 2470 | + |
---|
| 2471 | + if (rt->fib6_nh->fib_nh_dev->ifindex != dev->ifindex) |
---|
| 2472 | + continue; |
---|
| 2473 | + if (no_gw && rt->fib6_nh->fib_nh_gw_family) |
---|
2395 | 2474 | continue; |
---|
2396 | 2475 | if ((rt->fib6_flags & flags) != flags) |
---|
2397 | 2476 | continue; |
---|
.. | .. |
---|
2434 | 2513 | ASSERT_RTNL(); |
---|
2435 | 2514 | |
---|
2436 | 2515 | idev = ipv6_find_idev(dev); |
---|
2437 | | - if (!idev) |
---|
2438 | | - return ERR_PTR(-ENOBUFS); |
---|
| 2516 | + if (IS_ERR(idev)) |
---|
| 2517 | + return idev; |
---|
2439 | 2518 | |
---|
2440 | 2519 | if (idev->cnf.disable_ipv6) |
---|
2441 | 2520 | return ERR_PTR(-EACCES); |
---|
.. | .. |
---|
2500 | 2579 | ipv6_ifa_notify(0, ift); |
---|
2501 | 2580 | } |
---|
2502 | 2581 | |
---|
2503 | | - if ((create || list_empty(&idev->tempaddr_list)) && |
---|
2504 | | - idev->cnf.use_tempaddr > 0) { |
---|
| 2582 | + /* Also create a temporary address if it's enabled but no temporary |
---|
| 2583 | + * address currently exists. |
---|
| 2584 | + * However, we get called with valid_lft == 0, prefered_lft == 0, create == false |
---|
| 2585 | + * as part of cleanup (ie. deleting the mngtmpaddr). |
---|
| 2586 | + * We don't want that to result in creating a new temporary ip address. |
---|
| 2587 | + */ |
---|
| 2588 | + if (list_empty(&idev->tempaddr_list) && (valid_lft || prefered_lft)) |
---|
| 2589 | + create = true; |
---|
| 2590 | + |
---|
| 2591 | + if (create && idev->cnf.use_tempaddr > 0) { |
---|
2505 | 2592 | /* When a new public address is created as described |
---|
2506 | 2593 | * in [ADDRCONF], also create a new temporary address. |
---|
2507 | | - * Also create a temporary address if it's enabled but |
---|
2508 | | - * no temporary address currently exists. |
---|
2509 | 2594 | */ |
---|
2510 | 2595 | read_unlock_bh(&idev->lock); |
---|
2511 | | - ipv6_create_tempaddr(ifp, NULL, false); |
---|
| 2596 | + ipv6_create_tempaddr(ifp, false); |
---|
2512 | 2597 | } else { |
---|
2513 | 2598 | read_unlock_bh(&idev->lock); |
---|
2514 | 2599 | } |
---|
.. | .. |
---|
2690 | 2775 | pinfo->prefix_len, |
---|
2691 | 2776 | dev, |
---|
2692 | 2777 | RTF_ADDRCONF | RTF_PREFIX_RT, |
---|
2693 | | - RTF_GATEWAY | RTF_DEFAULT); |
---|
| 2778 | + RTF_DEFAULT, true); |
---|
2694 | 2779 | |
---|
2695 | 2780 | if (rt) { |
---|
2696 | 2781 | /* Autoconf prefix route */ |
---|
2697 | 2782 | if (valid_lft == 0) { |
---|
2698 | | - ip6_del_rt(net, rt); |
---|
| 2783 | + ip6_del_rt(net, rt, false); |
---|
2699 | 2784 | rt = NULL; |
---|
2700 | 2785 | } else if (addrconf_finite_timeout(rt_expires)) { |
---|
2701 | 2786 | /* not infinity */ |
---|
.. | .. |
---|
2773 | 2858 | in6_dev_put(in6_dev); |
---|
2774 | 2859 | } |
---|
2775 | 2860 | |
---|
| 2861 | +static int addrconf_set_sit_dstaddr(struct net *net, struct net_device *dev, |
---|
| 2862 | + struct in6_ifreq *ireq) |
---|
| 2863 | +{ |
---|
| 2864 | + struct ip_tunnel_parm p = { }; |
---|
| 2865 | + int err; |
---|
| 2866 | + |
---|
| 2867 | + if (!(ipv6_addr_type(&ireq->ifr6_addr) & IPV6_ADDR_COMPATv4)) |
---|
| 2868 | + return -EADDRNOTAVAIL; |
---|
| 2869 | + |
---|
| 2870 | + p.iph.daddr = ireq->ifr6_addr.s6_addr32[3]; |
---|
| 2871 | + p.iph.version = 4; |
---|
| 2872 | + p.iph.ihl = 5; |
---|
| 2873 | + p.iph.protocol = IPPROTO_IPV6; |
---|
| 2874 | + p.iph.ttl = 64; |
---|
| 2875 | + |
---|
| 2876 | + if (!dev->netdev_ops->ndo_tunnel_ctl) |
---|
| 2877 | + return -EOPNOTSUPP; |
---|
| 2878 | + err = dev->netdev_ops->ndo_tunnel_ctl(dev, &p, SIOCADDTUNNEL); |
---|
| 2879 | + if (err) |
---|
| 2880 | + return err; |
---|
| 2881 | + |
---|
| 2882 | + dev = __dev_get_by_name(net, p.name); |
---|
| 2883 | + if (!dev) |
---|
| 2884 | + return -ENOBUFS; |
---|
| 2885 | + return dev_open(dev, NULL); |
---|
| 2886 | +} |
---|
| 2887 | + |
---|
2776 | 2888 | /* |
---|
2777 | 2889 | * Set destination address. |
---|
2778 | 2890 | * Special case for SIT interfaces where we create a new "virtual" |
---|
.. | .. |
---|
2780 | 2892 | */ |
---|
2781 | 2893 | int addrconf_set_dstaddr(struct net *net, void __user *arg) |
---|
2782 | 2894 | { |
---|
2783 | | - struct in6_ifreq ireq; |
---|
2784 | 2895 | struct net_device *dev; |
---|
2785 | | - int err = -EINVAL; |
---|
| 2896 | + struct in6_ifreq ireq; |
---|
| 2897 | + int err = -ENODEV; |
---|
| 2898 | + |
---|
| 2899 | + if (!IS_ENABLED(CONFIG_IPV6_SIT)) |
---|
| 2900 | + return -ENODEV; |
---|
| 2901 | + if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) |
---|
| 2902 | + return -EFAULT; |
---|
2786 | 2903 | |
---|
2787 | 2904 | rtnl_lock(); |
---|
2788 | | - |
---|
2789 | | - err = -EFAULT; |
---|
2790 | | - if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) |
---|
2791 | | - goto err_exit; |
---|
2792 | | - |
---|
2793 | 2905 | dev = __dev_get_by_index(net, ireq.ifr6_ifindex); |
---|
2794 | | - |
---|
2795 | | - err = -ENODEV; |
---|
2796 | | - if (!dev) |
---|
2797 | | - goto err_exit; |
---|
2798 | | - |
---|
2799 | | -#if IS_ENABLED(CONFIG_IPV6_SIT) |
---|
2800 | | - if (dev->type == ARPHRD_SIT) { |
---|
2801 | | - const struct net_device_ops *ops = dev->netdev_ops; |
---|
2802 | | - struct ifreq ifr; |
---|
2803 | | - struct ip_tunnel_parm p; |
---|
2804 | | - |
---|
2805 | | - err = -EADDRNOTAVAIL; |
---|
2806 | | - if (!(ipv6_addr_type(&ireq.ifr6_addr) & IPV6_ADDR_COMPATv4)) |
---|
2807 | | - goto err_exit; |
---|
2808 | | - |
---|
2809 | | - memset(&p, 0, sizeof(p)); |
---|
2810 | | - p.iph.daddr = ireq.ifr6_addr.s6_addr32[3]; |
---|
2811 | | - p.iph.saddr = 0; |
---|
2812 | | - p.iph.version = 4; |
---|
2813 | | - p.iph.ihl = 5; |
---|
2814 | | - p.iph.protocol = IPPROTO_IPV6; |
---|
2815 | | - p.iph.ttl = 64; |
---|
2816 | | - ifr.ifr_ifru.ifru_data = (__force void __user *)&p; |
---|
2817 | | - |
---|
2818 | | - if (ops->ndo_do_ioctl) { |
---|
2819 | | - mm_segment_t oldfs = get_fs(); |
---|
2820 | | - |
---|
2821 | | - set_fs(KERNEL_DS); |
---|
2822 | | - err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL); |
---|
2823 | | - set_fs(oldfs); |
---|
2824 | | - } else |
---|
2825 | | - err = -EOPNOTSUPP; |
---|
2826 | | - |
---|
2827 | | - if (err == 0) { |
---|
2828 | | - err = -ENOBUFS; |
---|
2829 | | - dev = __dev_get_by_name(net, p.name); |
---|
2830 | | - if (!dev) |
---|
2831 | | - goto err_exit; |
---|
2832 | | - err = dev_open(dev); |
---|
2833 | | - } |
---|
2834 | | - } |
---|
2835 | | -#endif |
---|
2836 | | - |
---|
2837 | | -err_exit: |
---|
| 2906 | + if (dev && dev->type == ARPHRD_SIT) |
---|
| 2907 | + err = addrconf_set_sit_dstaddr(net, dev, &ireq); |
---|
2838 | 2908 | rtnl_unlock(); |
---|
2839 | 2909 | return err; |
---|
2840 | 2910 | } |
---|
.. | .. |
---|
3099 | 3169 | struct in_device *in_dev = __in_dev_get_rtnl(dev); |
---|
3100 | 3170 | if (in_dev && (dev->flags & IFF_UP)) { |
---|
3101 | 3171 | struct in_ifaddr *ifa; |
---|
3102 | | - |
---|
3103 | 3172 | int flag = scope; |
---|
3104 | 3173 | |
---|
3105 | | - for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { |
---|
3106 | | - |
---|
| 3174 | + in_dev_for_each_ifa_rtnl(ifa, in_dev) { |
---|
3107 | 3175 | addr.s6_addr32[3] = ifa->ifa_local; |
---|
3108 | 3176 | |
---|
3109 | 3177 | if (ifa->ifa_scope == RT_SCOPE_LINK) |
---|
.. | .. |
---|
3132 | 3200 | ASSERT_RTNL(); |
---|
3133 | 3201 | |
---|
3134 | 3202 | idev = ipv6_find_idev(dev); |
---|
3135 | | - if (!idev) { |
---|
| 3203 | + if (IS_ERR(idev)) { |
---|
3136 | 3204 | pr_debug("%s: add_dev failed\n", __func__); |
---|
3137 | 3205 | return; |
---|
3138 | 3206 | } |
---|
.. | .. |
---|
3191 | 3259 | const struct inet6_dev *idev) |
---|
3192 | 3260 | { |
---|
3193 | 3261 | static DEFINE_SPINLOCK(lock); |
---|
3194 | | - static __u32 digest[SHA_DIGEST_WORDS]; |
---|
3195 | | - static __u32 workspace[SHA_WORKSPACE_WORDS]; |
---|
| 3262 | + static __u32 digest[SHA1_DIGEST_WORDS]; |
---|
| 3263 | + static __u32 workspace[SHA1_WORKSPACE_WORDS]; |
---|
3196 | 3264 | |
---|
3197 | 3265 | static union { |
---|
3198 | | - char __data[SHA_MESSAGE_BYTES]; |
---|
| 3266 | + char __data[SHA1_BLOCK_SIZE]; |
---|
3199 | 3267 | struct { |
---|
3200 | 3268 | struct in6_addr secret; |
---|
3201 | 3269 | __be32 prefix[2]; |
---|
.. | .. |
---|
3220 | 3288 | retry: |
---|
3221 | 3289 | spin_lock_bh(&lock); |
---|
3222 | 3290 | |
---|
3223 | | - sha_init(digest); |
---|
| 3291 | + sha1_init(digest); |
---|
3224 | 3292 | memset(&data, 0, sizeof(data)); |
---|
3225 | 3293 | memset(workspace, 0, sizeof(workspace)); |
---|
3226 | 3294 | memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len); |
---|
.. | .. |
---|
3229 | 3297 | data.secret = secret; |
---|
3230 | 3298 | data.dad_count = dad_count; |
---|
3231 | 3299 | |
---|
3232 | | - sha_transform(digest, data.__data, workspace); |
---|
| 3300 | + sha1_transform(digest, data.__data, workspace); |
---|
3233 | 3301 | |
---|
3234 | 3302 | temp = *address; |
---|
3235 | 3303 | temp.s6_addr32[2] = (__force __be32)digest[0]; |
---|
.. | .. |
---|
3276 | 3344 | switch (idev->cnf.addr_gen_mode) { |
---|
3277 | 3345 | case IN6_ADDR_GEN_MODE_RANDOM: |
---|
3278 | 3346 | ipv6_gen_mode_random_init(idev); |
---|
3279 | | - /* fallthrough */ |
---|
| 3347 | + fallthrough; |
---|
3280 | 3348 | case IN6_ADDR_GEN_MODE_STABLE_PRIVACY: |
---|
3281 | 3349 | if (!ipv6_generate_stable_address(&addr, 0, idev)) |
---|
3282 | 3350 | addrconf_add_linklocal(idev, &addr, |
---|
.. | .. |
---|
3306 | 3374 | static void addrconf_dev_config(struct net_device *dev) |
---|
3307 | 3375 | { |
---|
3308 | 3376 | struct inet6_dev *idev; |
---|
| 3377 | + bool ret = false; |
---|
3309 | 3378 | |
---|
3310 | 3379 | ASSERT_RTNL(); |
---|
3311 | 3380 | |
---|
.. | .. |
---|
3333 | 3402 | if (IS_ERR(idev)) |
---|
3334 | 3403 | return; |
---|
3335 | 3404 | |
---|
| 3405 | + trace_android_vh_ipv6_gen_linklocal_addr(dev, &ret); |
---|
| 3406 | + if (ret) |
---|
| 3407 | + return; |
---|
| 3408 | + |
---|
3336 | 3409 | /* this device type has no EUI support */ |
---|
3337 | 3410 | if (dev->type == ARPHRD_NONE && |
---|
3338 | 3411 | idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_EUI64) |
---|
.. | .. |
---|
3355 | 3428 | */ |
---|
3356 | 3429 | |
---|
3357 | 3430 | idev = ipv6_find_idev(dev); |
---|
3358 | | - if (!idev) { |
---|
| 3431 | + if (IS_ERR(idev)) { |
---|
3359 | 3432 | pr_debug("%s: add_dev failed\n", __func__); |
---|
3360 | 3433 | return; |
---|
3361 | 3434 | } |
---|
.. | .. |
---|
3380 | 3453 | ASSERT_RTNL(); |
---|
3381 | 3454 | |
---|
3382 | 3455 | idev = ipv6_find_idev(dev); |
---|
3383 | | - if (!idev) { |
---|
| 3456 | + if (IS_ERR(idev)) { |
---|
3384 | 3457 | pr_debug("%s: add_dev failed\n", __func__); |
---|
3385 | 3458 | return; |
---|
3386 | 3459 | } |
---|
.. | .. |
---|
3498 | 3571 | break; |
---|
3499 | 3572 | |
---|
3500 | 3573 | run_pending = 1; |
---|
3501 | | - |
---|
3502 | | - /* fall through */ |
---|
3503 | | - |
---|
| 3574 | + fallthrough; |
---|
3504 | 3575 | case NETDEV_UP: |
---|
3505 | 3576 | case NETDEV_CHANGE: |
---|
3506 | 3577 | if (dev->flags & IFF_SLAVE) |
---|
.. | .. |
---|
3515 | 3586 | |
---|
3516 | 3587 | if (!addrconf_link_ready(dev)) { |
---|
3517 | 3588 | /* device is not ready yet. */ |
---|
3518 | | - pr_info("ADDRCONF(NETDEV_UP): %s: link is not ready\n", |
---|
3519 | | - dev->name); |
---|
| 3589 | + pr_debug("ADDRCONF(NETDEV_UP): %s: link is not ready\n", |
---|
| 3590 | + dev->name); |
---|
3520 | 3591 | break; |
---|
3521 | 3592 | } |
---|
3522 | 3593 | |
---|
.. | .. |
---|
3642 | 3713 | * an L3 master device (e.g., VRF) |
---|
3643 | 3714 | */ |
---|
3644 | 3715 | if (info->upper_dev && netif_is_l3_master(info->upper_dev)) |
---|
3645 | | - addrconf_ifdown(dev, 0); |
---|
| 3716 | + addrconf_ifdown(dev, false); |
---|
3646 | 3717 | } |
---|
3647 | 3718 | |
---|
3648 | 3719 | return NOTIFY_OK; |
---|
.. | .. |
---|
3675 | 3746 | (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK); |
---|
3676 | 3747 | } |
---|
3677 | 3748 | |
---|
3678 | | -static int addrconf_ifdown(struct net_device *dev, int how) |
---|
| 3749 | +static int addrconf_ifdown(struct net_device *dev, bool unregister) |
---|
3679 | 3750 | { |
---|
3680 | | - unsigned long event = how ? NETDEV_UNREGISTER : NETDEV_DOWN; |
---|
| 3751 | + unsigned long event = unregister ? NETDEV_UNREGISTER : NETDEV_DOWN; |
---|
3681 | 3752 | struct net *net = dev_net(dev); |
---|
3682 | 3753 | struct inet6_dev *idev; |
---|
3683 | | - struct inet6_ifaddr *ifa, *tmp; |
---|
| 3754 | + struct inet6_ifaddr *ifa; |
---|
| 3755 | + LIST_HEAD(tmp_addr_list); |
---|
3684 | 3756 | bool keep_addr = false; |
---|
| 3757 | + bool was_ready; |
---|
3685 | 3758 | int state, i; |
---|
3686 | 3759 | |
---|
3687 | 3760 | ASSERT_RTNL(); |
---|
.. | .. |
---|
3696 | 3769 | * Step 1: remove reference to ipv6 device from parent device. |
---|
3697 | 3770 | * Do not dev_put! |
---|
3698 | 3771 | */ |
---|
3699 | | - if (how) { |
---|
| 3772 | + if (unregister) { |
---|
3700 | 3773 | idev->dead = 1; |
---|
3701 | 3774 | |
---|
3702 | 3775 | /* protected by rtnl_lock */ |
---|
.. | .. |
---|
3710 | 3783 | /* combine the user config with event to determine if permanent |
---|
3711 | 3784 | * addresses are to be removed from address hash table |
---|
3712 | 3785 | */ |
---|
3713 | | - if (!how && !idev->cnf.disable_ipv6) { |
---|
| 3786 | + if (!unregister && !idev->cnf.disable_ipv6) { |
---|
3714 | 3787 | /* aggregate the system setting and interface setting */ |
---|
3715 | 3788 | int _keep_addr = net->ipv6.devconf_all->keep_addr_on_down; |
---|
3716 | 3789 | |
---|
.. | .. |
---|
3747 | 3820 | |
---|
3748 | 3821 | addrconf_del_rs_timer(idev); |
---|
3749 | 3822 | |
---|
3750 | | - /* Step 2: clear flags for stateless addrconf */ |
---|
3751 | | - if (!how) |
---|
| 3823 | + /* Step 2: clear flags for stateless addrconf, repeated down |
---|
| 3824 | + * detection |
---|
| 3825 | + */ |
---|
| 3826 | + was_ready = idev->if_flags & IF_READY; |
---|
| 3827 | + if (!unregister) |
---|
3752 | 3828 | idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY); |
---|
3753 | 3829 | |
---|
3754 | 3830 | /* Step 3: clear tempaddr list */ |
---|
.. | .. |
---|
3768 | 3844 | write_lock_bh(&idev->lock); |
---|
3769 | 3845 | } |
---|
3770 | 3846 | |
---|
3771 | | - list_for_each_entry_safe(ifa, tmp, &idev->addr_list, if_list) { |
---|
| 3847 | + list_for_each_entry(ifa, &idev->addr_list, if_list) |
---|
| 3848 | + list_add_tail(&ifa->if_list_aux, &tmp_addr_list); |
---|
| 3849 | + write_unlock_bh(&idev->lock); |
---|
| 3850 | + |
---|
| 3851 | + while (!list_empty(&tmp_addr_list)) { |
---|
3772 | 3852 | struct fib6_info *rt = NULL; |
---|
3773 | 3853 | bool keep; |
---|
| 3854 | + |
---|
| 3855 | + ifa = list_first_entry(&tmp_addr_list, |
---|
| 3856 | + struct inet6_ifaddr, if_list_aux); |
---|
| 3857 | + list_del(&ifa->if_list_aux); |
---|
3774 | 3858 | |
---|
3775 | 3859 | addrconf_del_dad_work(ifa); |
---|
3776 | 3860 | |
---|
3777 | 3861 | keep = keep_addr && (ifa->flags & IFA_F_PERMANENT) && |
---|
3778 | 3862 | !addr_is_local(&ifa->addr); |
---|
3779 | 3863 | |
---|
3780 | | - write_unlock_bh(&idev->lock); |
---|
3781 | 3864 | spin_lock_bh(&ifa->lock); |
---|
3782 | 3865 | |
---|
3783 | 3866 | if (keep) { |
---|
.. | .. |
---|
3797 | 3880 | spin_unlock_bh(&ifa->lock); |
---|
3798 | 3881 | |
---|
3799 | 3882 | if (rt) |
---|
3800 | | - ip6_del_rt(net, rt); |
---|
| 3883 | + ip6_del_rt(net, rt, false); |
---|
3801 | 3884 | |
---|
3802 | 3885 | if (state != INET6_IFADDR_STATE_DEAD) { |
---|
3803 | 3886 | __ipv6_ifa_notify(RTM_DELADDR, ifa); |
---|
.. | .. |
---|
3808 | 3891 | addrconf_leave_solict(ifa->idev, &ifa->addr); |
---|
3809 | 3892 | } |
---|
3810 | 3893 | |
---|
3811 | | - write_lock_bh(&idev->lock); |
---|
3812 | 3894 | if (!keep) { |
---|
| 3895 | + write_lock_bh(&idev->lock); |
---|
3813 | 3896 | list_del_rcu(&ifa->if_list); |
---|
| 3897 | + write_unlock_bh(&idev->lock); |
---|
3814 | 3898 | in6_ifa_put(ifa); |
---|
3815 | 3899 | } |
---|
3816 | 3900 | } |
---|
3817 | 3901 | |
---|
3818 | | - write_unlock_bh(&idev->lock); |
---|
3819 | | - |
---|
3820 | 3902 | /* Step 5: Discard anycast and multicast list */ |
---|
3821 | | - if (how) { |
---|
| 3903 | + if (unregister) { |
---|
3822 | 3904 | ipv6_ac_destroy_dev(idev); |
---|
3823 | 3905 | ipv6_mc_destroy_dev(idev); |
---|
3824 | | - } else { |
---|
| 3906 | + } else if (was_ready) { |
---|
3825 | 3907 | ipv6_mc_down(idev); |
---|
3826 | 3908 | } |
---|
3827 | 3909 | |
---|
3828 | 3910 | idev->tstamp = jiffies; |
---|
3829 | 3911 | |
---|
3830 | 3912 | /* Last: Shot the device (if unregistered) */ |
---|
3831 | | - if (how) { |
---|
| 3913 | + if (unregister) { |
---|
3832 | 3914 | addrconf_sysctl_unregister(idev); |
---|
3833 | 3915 | neigh_parms_release(&nd_tbl, idev->nd_parms); |
---|
3834 | 3916 | neigh_ifdown(&nd_tbl, dev); |
---|
.. | .. |
---|
4050 | 4132 | in6_ifa_hold(ifp); |
---|
4051 | 4133 | addrconf_dad_stop(ifp, 1); |
---|
4052 | 4134 | if (disable_ipv6) |
---|
4053 | | - addrconf_ifdown(idev->dev, 0); |
---|
| 4135 | + addrconf_ifdown(idev->dev, false); |
---|
4054 | 4136 | goto out; |
---|
4055 | 4137 | } |
---|
4056 | 4138 | |
---|
.. | .. |
---|
4092 | 4174 | |
---|
4093 | 4175 | ifp->dad_probes--; |
---|
4094 | 4176 | addrconf_mod_dad_work(ifp, |
---|
4095 | | - NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME)); |
---|
| 4177 | + max(NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME), |
---|
| 4178 | + HZ/100)); |
---|
4096 | 4179 | spin_unlock(&ifp->lock); |
---|
4097 | 4180 | write_unlock_bh(&idev->lock); |
---|
4098 | 4181 | |
---|
.. | .. |
---|
4147 | 4230 | send_rs = send_mld && |
---|
4148 | 4231 | ipv6_accept_ra(ifp->idev) && |
---|
4149 | 4232 | ifp->idev->cnf.rtr_solicits != 0 && |
---|
4150 | | - (dev->flags&IFF_LOOPBACK) == 0; |
---|
| 4233 | + (dev->flags & IFF_LOOPBACK) == 0 && |
---|
| 4234 | + (dev->type != ARPHRD_TUNNEL); |
---|
4151 | 4235 | read_unlock_bh(&ifp->idev->lock); |
---|
4152 | 4236 | |
---|
4153 | 4237 | /* While dad is in progress mld report's source address is in6_addrany. |
---|
.. | .. |
---|
4375 | 4459 | } |
---|
4376 | 4460 | #endif |
---|
4377 | 4461 | |
---|
| 4462 | +/* RFC6554 has some algorithm to avoid loops in segment routing by |
---|
| 4463 | + * checking if the segments contains any of a local interface address. |
---|
| 4464 | + * |
---|
| 4465 | + * Quote: |
---|
| 4466 | + * |
---|
| 4467 | + * To detect loops in the SRH, a router MUST determine if the SRH |
---|
| 4468 | + * includes multiple addresses assigned to any interface on that router. |
---|
| 4469 | + * If such addresses appear more than once and are separated by at least |
---|
| 4470 | + * one address not assigned to that router. |
---|
| 4471 | + */ |
---|
| 4472 | +int ipv6_chk_rpl_srh_loop(struct net *net, const struct in6_addr *segs, |
---|
| 4473 | + unsigned char nsegs) |
---|
| 4474 | +{ |
---|
| 4475 | + const struct in6_addr *addr; |
---|
| 4476 | + int i, ret = 0, found = 0; |
---|
| 4477 | + struct inet6_ifaddr *ifp; |
---|
| 4478 | + bool separated = false; |
---|
| 4479 | + unsigned int hash; |
---|
| 4480 | + bool hash_found; |
---|
| 4481 | + |
---|
| 4482 | + rcu_read_lock(); |
---|
| 4483 | + for (i = 0; i < nsegs; i++) { |
---|
| 4484 | + addr = &segs[i]; |
---|
| 4485 | + hash = inet6_addr_hash(net, addr); |
---|
| 4486 | + |
---|
| 4487 | + hash_found = false; |
---|
| 4488 | + hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) { |
---|
| 4489 | + if (!net_eq(dev_net(ifp->idev->dev), net)) |
---|
| 4490 | + continue; |
---|
| 4491 | + |
---|
| 4492 | + if (ipv6_addr_equal(&ifp->addr, addr)) { |
---|
| 4493 | + hash_found = true; |
---|
| 4494 | + break; |
---|
| 4495 | + } |
---|
| 4496 | + } |
---|
| 4497 | + |
---|
| 4498 | + if (hash_found) { |
---|
| 4499 | + if (found > 1 && separated) { |
---|
| 4500 | + ret = 1; |
---|
| 4501 | + break; |
---|
| 4502 | + } |
---|
| 4503 | + |
---|
| 4504 | + separated = false; |
---|
| 4505 | + found++; |
---|
| 4506 | + } else { |
---|
| 4507 | + separated = true; |
---|
| 4508 | + } |
---|
| 4509 | + } |
---|
| 4510 | + rcu_read_unlock(); |
---|
| 4511 | + |
---|
| 4512 | + return ret; |
---|
| 4513 | +} |
---|
| 4514 | + |
---|
4378 | 4515 | /* |
---|
4379 | 4516 | * Periodic address status verification |
---|
4380 | 4517 | */ |
---|
.. | .. |
---|
4445 | 4582 | !(ifp->flags&IFA_F_TENTATIVE)) { |
---|
4446 | 4583 | unsigned long regen_advance = ifp->idev->cnf.regen_max_retry * |
---|
4447 | 4584 | ifp->idev->cnf.dad_transmits * |
---|
4448 | | - NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME) / HZ; |
---|
| 4585 | + max(NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME), HZ/100) / HZ; |
---|
4449 | 4586 | |
---|
4450 | 4587 | if (age >= ifp->prefered_lft - regen_advance) { |
---|
4451 | 4588 | struct inet6_ifaddr *ifpub = ifp->ifpub; |
---|
.. | .. |
---|
4461 | 4598 | ifpub->regen_count = 0; |
---|
4462 | 4599 | spin_unlock(&ifpub->lock); |
---|
4463 | 4600 | rcu_read_unlock_bh(); |
---|
4464 | | - ipv6_create_tempaddr(ifpub, ifp, true); |
---|
| 4601 | + ipv6_create_tempaddr(ifpub, true); |
---|
4465 | 4602 | in6_ifa_put(ifpub); |
---|
4466 | 4603 | in6_ifa_put(ifp); |
---|
4467 | 4604 | rcu_read_lock_bh(); |
---|
.. | .. |
---|
4533 | 4670 | [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, |
---|
4534 | 4671 | [IFA_FLAGS] = { .len = sizeof(u32) }, |
---|
4535 | 4672 | [IFA_RT_PRIORITY] = { .len = sizeof(u32) }, |
---|
| 4673 | + [IFA_TARGET_NETNSID] = { .type = NLA_S32 }, |
---|
4536 | 4674 | }; |
---|
4537 | 4675 | |
---|
4538 | 4676 | static int |
---|
.. | .. |
---|
4546 | 4684 | u32 ifa_flags; |
---|
4547 | 4685 | int err; |
---|
4548 | 4686 | |
---|
4549 | | - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy, |
---|
4550 | | - extack); |
---|
| 4687 | + err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX, |
---|
| 4688 | + ifa_ipv6_policy, extack); |
---|
4551 | 4689 | if (err < 0) |
---|
4552 | 4690 | return err; |
---|
4553 | 4691 | |
---|
.. | .. |
---|
4574 | 4712 | |
---|
4575 | 4713 | f6i = addrconf_get_prefix_route(modify_peer ? &ifp->peer_addr : &ifp->addr, |
---|
4576 | 4714 | ifp->prefix_len, |
---|
4577 | | - ifp->idev->dev, |
---|
4578 | | - 0, RTF_GATEWAY | RTF_DEFAULT); |
---|
| 4715 | + ifp->idev->dev, 0, RTF_DEFAULT, true); |
---|
4579 | 4716 | if (!f6i) |
---|
4580 | 4717 | return -ENOENT; |
---|
4581 | 4718 | |
---|
4582 | 4719 | prio = ifp->rt_priority ? : IP6_RT_PRIO_ADDRCONF; |
---|
4583 | 4720 | if (f6i->fib6_metric != prio) { |
---|
4584 | 4721 | /* delete old one */ |
---|
4585 | | - ip6_del_rt(dev_net(ifp->idev->dev), f6i); |
---|
| 4722 | + ip6_del_rt(dev_net(ifp->idev->dev), f6i, false); |
---|
4586 | 4723 | |
---|
4587 | 4724 | /* add new one */ |
---|
4588 | 4725 | addrconf_prefix_route(modify_peer ? &ifp->peer_addr : &ifp->addr, |
---|
.. | .. |
---|
4734 | 4871 | struct ifa6_config cfg; |
---|
4735 | 4872 | int err; |
---|
4736 | 4873 | |
---|
4737 | | - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy, |
---|
4738 | | - extack); |
---|
| 4874 | + err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX, |
---|
| 4875 | + ifa_ipv6_policy, extack); |
---|
4739 | 4876 | if (err < 0) |
---|
4740 | 4877 | return err; |
---|
4741 | 4878 | |
---|
.. | .. |
---|
4777 | 4914 | IFA_F_MCAUTOJOIN | IFA_F_OPTIMISTIC; |
---|
4778 | 4915 | |
---|
4779 | 4916 | idev = ipv6_find_idev(dev); |
---|
4780 | | - if (!idev) |
---|
4781 | | - return -ENOBUFS; |
---|
| 4917 | + if (IS_ERR(idev)) |
---|
| 4918 | + return PTR_ERR(idev); |
---|
4782 | 4919 | |
---|
4783 | 4920 | if (!ipv6_allow_optimistic_dad(net, idev)) |
---|
4784 | 4921 | cfg.ifa_flags &= ~IFA_F_OPTIMISTIC; |
---|
.. | .. |
---|
4857 | 4994 | + nla_total_size(4) /* IFA_RT_PRIORITY */; |
---|
4858 | 4995 | } |
---|
4859 | 4996 | |
---|
| 4997 | +enum addr_type_t { |
---|
| 4998 | + UNICAST_ADDR, |
---|
| 4999 | + MULTICAST_ADDR, |
---|
| 5000 | + ANYCAST_ADDR, |
---|
| 5001 | +}; |
---|
| 5002 | + |
---|
| 5003 | +struct inet6_fill_args { |
---|
| 5004 | + u32 portid; |
---|
| 5005 | + u32 seq; |
---|
| 5006 | + int event; |
---|
| 5007 | + unsigned int flags; |
---|
| 5008 | + int netnsid; |
---|
| 5009 | + int ifindex; |
---|
| 5010 | + enum addr_type_t type; |
---|
| 5011 | +}; |
---|
| 5012 | + |
---|
4860 | 5013 | static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, |
---|
4861 | | - u32 portid, u32 seq, int event, unsigned int flags) |
---|
| 5014 | + struct inet6_fill_args *args) |
---|
4862 | 5015 | { |
---|
4863 | 5016 | struct nlmsghdr *nlh; |
---|
4864 | 5017 | u32 preferred, valid; |
---|
4865 | 5018 | |
---|
4866 | | - nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct ifaddrmsg), flags); |
---|
| 5019 | + nlh = nlmsg_put(skb, args->portid, args->seq, args->event, |
---|
| 5020 | + sizeof(struct ifaddrmsg), args->flags); |
---|
4867 | 5021 | if (!nlh) |
---|
4868 | 5022 | return -EMSGSIZE; |
---|
4869 | 5023 | |
---|
4870 | 5024 | put_ifaddrmsg(nlh, ifa->prefix_len, ifa->flags, rt_scope(ifa->scope), |
---|
4871 | 5025 | ifa->idev->dev->ifindex); |
---|
4872 | 5026 | |
---|
| 5027 | + if (args->netnsid >= 0 && |
---|
| 5028 | + nla_put_s32(skb, IFA_TARGET_NETNSID, args->netnsid)) |
---|
| 5029 | + goto error; |
---|
| 5030 | + |
---|
| 5031 | + spin_lock_bh(&ifa->lock); |
---|
4873 | 5032 | if (!((ifa->flags&IFA_F_PERMANENT) && |
---|
4874 | 5033 | (ifa->prefered_lft == INFINITY_LIFE_TIME))) { |
---|
4875 | 5034 | preferred = ifa->prefered_lft; |
---|
.. | .. |
---|
4891 | 5050 | preferred = INFINITY_LIFE_TIME; |
---|
4892 | 5051 | valid = INFINITY_LIFE_TIME; |
---|
4893 | 5052 | } |
---|
| 5053 | + spin_unlock_bh(&ifa->lock); |
---|
4894 | 5054 | |
---|
4895 | 5055 | if (!ipv6_addr_any(&ifa->peer_addr)) { |
---|
4896 | 5056 | if (nla_put_in6_addr(skb, IFA_LOCAL, &ifa->addr) < 0 || |
---|
.. | .. |
---|
4919 | 5079 | } |
---|
4920 | 5080 | |
---|
4921 | 5081 | static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, |
---|
4922 | | - u32 portid, u32 seq, int event, u16 flags) |
---|
| 5082 | + struct inet6_fill_args *args) |
---|
4923 | 5083 | { |
---|
4924 | 5084 | struct nlmsghdr *nlh; |
---|
4925 | 5085 | u8 scope = RT_SCOPE_UNIVERSE; |
---|
.. | .. |
---|
4928 | 5088 | if (ipv6_addr_scope(&ifmca->mca_addr) & IFA_SITE) |
---|
4929 | 5089 | scope = RT_SCOPE_SITE; |
---|
4930 | 5090 | |
---|
4931 | | - nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct ifaddrmsg), flags); |
---|
| 5091 | + nlh = nlmsg_put(skb, args->portid, args->seq, args->event, |
---|
| 5092 | + sizeof(struct ifaddrmsg), args->flags); |
---|
4932 | 5093 | if (!nlh) |
---|
4933 | 5094 | return -EMSGSIZE; |
---|
| 5095 | + |
---|
| 5096 | + if (args->netnsid >= 0 && |
---|
| 5097 | + nla_put_s32(skb, IFA_TARGET_NETNSID, args->netnsid)) { |
---|
| 5098 | + nlmsg_cancel(skb, nlh); |
---|
| 5099 | + return -EMSGSIZE; |
---|
| 5100 | + } |
---|
4934 | 5101 | |
---|
4935 | 5102 | put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex); |
---|
4936 | 5103 | if (nla_put_in6_addr(skb, IFA_MULTICAST, &ifmca->mca_addr) < 0 || |
---|
.. | .. |
---|
4945 | 5112 | } |
---|
4946 | 5113 | |
---|
4947 | 5114 | static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, |
---|
4948 | | - u32 portid, u32 seq, int event, unsigned int flags) |
---|
| 5115 | + struct inet6_fill_args *args) |
---|
4949 | 5116 | { |
---|
4950 | 5117 | struct net_device *dev = fib6_info_nh_dev(ifaca->aca_rt); |
---|
4951 | 5118 | int ifindex = dev ? dev->ifindex : 1; |
---|
.. | .. |
---|
4955 | 5122 | if (ipv6_addr_scope(&ifaca->aca_addr) & IFA_SITE) |
---|
4956 | 5123 | scope = RT_SCOPE_SITE; |
---|
4957 | 5124 | |
---|
4958 | | - nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct ifaddrmsg), flags); |
---|
| 5125 | + nlh = nlmsg_put(skb, args->portid, args->seq, args->event, |
---|
| 5126 | + sizeof(struct ifaddrmsg), args->flags); |
---|
4959 | 5127 | if (!nlh) |
---|
4960 | 5128 | return -EMSGSIZE; |
---|
| 5129 | + |
---|
| 5130 | + if (args->netnsid >= 0 && |
---|
| 5131 | + nla_put_s32(skb, IFA_TARGET_NETNSID, args->netnsid)) { |
---|
| 5132 | + nlmsg_cancel(skb, nlh); |
---|
| 5133 | + return -EMSGSIZE; |
---|
| 5134 | + } |
---|
4961 | 5135 | |
---|
4962 | 5136 | put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex); |
---|
4963 | 5137 | if (nla_put_in6_addr(skb, IFA_ANYCAST, &ifaca->aca_addr) < 0 || |
---|
.. | .. |
---|
4971 | 5145 | return 0; |
---|
4972 | 5146 | } |
---|
4973 | 5147 | |
---|
4974 | | -enum addr_type_t { |
---|
4975 | | - UNICAST_ADDR, |
---|
4976 | | - MULTICAST_ADDR, |
---|
4977 | | - ANYCAST_ADDR, |
---|
4978 | | -}; |
---|
4979 | | - |
---|
4980 | 5148 | /* called with rcu_read_lock() */ |
---|
4981 | 5149 | static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, |
---|
4982 | | - struct netlink_callback *cb, enum addr_type_t type, |
---|
4983 | | - int s_ip_idx, int *p_ip_idx) |
---|
| 5150 | + struct netlink_callback *cb, int s_ip_idx, |
---|
| 5151 | + struct inet6_fill_args *fillargs) |
---|
4984 | 5152 | { |
---|
4985 | 5153 | struct ifmcaddr6 *ifmca; |
---|
4986 | 5154 | struct ifacaddr6 *ifaca; |
---|
| 5155 | + int ip_idx = 0; |
---|
4987 | 5156 | int err = 1; |
---|
4988 | | - int ip_idx = *p_ip_idx; |
---|
4989 | 5157 | |
---|
4990 | 5158 | read_lock_bh(&idev->lock); |
---|
4991 | | - switch (type) { |
---|
| 5159 | + switch (fillargs->type) { |
---|
4992 | 5160 | case UNICAST_ADDR: { |
---|
4993 | 5161 | struct inet6_ifaddr *ifa; |
---|
| 5162 | + fillargs->event = RTM_NEWADDR; |
---|
4994 | 5163 | |
---|
4995 | 5164 | /* unicast address incl. temp addr */ |
---|
4996 | 5165 | list_for_each_entry(ifa, &idev->addr_list, if_list) { |
---|
4997 | 5166 | if (ip_idx < s_ip_idx) |
---|
4998 | 5167 | goto next; |
---|
4999 | | - err = inet6_fill_ifaddr(skb, ifa, |
---|
5000 | | - NETLINK_CB(cb->skb).portid, |
---|
5001 | | - cb->nlh->nlmsg_seq, |
---|
5002 | | - RTM_NEWADDR, |
---|
5003 | | - NLM_F_MULTI); |
---|
| 5168 | + err = inet6_fill_ifaddr(skb, ifa, fillargs); |
---|
5004 | 5169 | if (err < 0) |
---|
5005 | 5170 | break; |
---|
5006 | 5171 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); |
---|
.. | .. |
---|
5010 | 5175 | break; |
---|
5011 | 5176 | } |
---|
5012 | 5177 | case MULTICAST_ADDR: |
---|
| 5178 | + fillargs->event = RTM_GETMULTICAST; |
---|
| 5179 | + |
---|
5013 | 5180 | /* multicast address */ |
---|
5014 | 5181 | for (ifmca = idev->mc_list; ifmca; |
---|
5015 | 5182 | ifmca = ifmca->next, ip_idx++) { |
---|
5016 | 5183 | if (ip_idx < s_ip_idx) |
---|
5017 | 5184 | continue; |
---|
5018 | | - err = inet6_fill_ifmcaddr(skb, ifmca, |
---|
5019 | | - NETLINK_CB(cb->skb).portid, |
---|
5020 | | - cb->nlh->nlmsg_seq, |
---|
5021 | | - RTM_GETMULTICAST, |
---|
5022 | | - NLM_F_MULTI); |
---|
| 5185 | + err = inet6_fill_ifmcaddr(skb, ifmca, fillargs); |
---|
5023 | 5186 | if (err < 0) |
---|
5024 | 5187 | break; |
---|
5025 | 5188 | } |
---|
5026 | 5189 | break; |
---|
5027 | 5190 | case ANYCAST_ADDR: |
---|
| 5191 | + fillargs->event = RTM_GETANYCAST; |
---|
5028 | 5192 | /* anycast address */ |
---|
5029 | 5193 | for (ifaca = idev->ac_list; ifaca; |
---|
5030 | 5194 | ifaca = ifaca->aca_next, ip_idx++) { |
---|
5031 | 5195 | if (ip_idx < s_ip_idx) |
---|
5032 | 5196 | continue; |
---|
5033 | | - err = inet6_fill_ifacaddr(skb, ifaca, |
---|
5034 | | - NETLINK_CB(cb->skb).portid, |
---|
5035 | | - cb->nlh->nlmsg_seq, |
---|
5036 | | - RTM_GETANYCAST, |
---|
5037 | | - NLM_F_MULTI); |
---|
| 5197 | + err = inet6_fill_ifacaddr(skb, ifaca, fillargs); |
---|
5038 | 5198 | if (err < 0) |
---|
5039 | 5199 | break; |
---|
5040 | 5200 | } |
---|
.. | .. |
---|
5043 | 5203 | break; |
---|
5044 | 5204 | } |
---|
5045 | 5205 | read_unlock_bh(&idev->lock); |
---|
5046 | | - *p_ip_idx = ip_idx; |
---|
| 5206 | + cb->args[2] = ip_idx; |
---|
5047 | 5207 | return err; |
---|
| 5208 | +} |
---|
| 5209 | + |
---|
| 5210 | +static int inet6_valid_dump_ifaddr_req(const struct nlmsghdr *nlh, |
---|
| 5211 | + struct inet6_fill_args *fillargs, |
---|
| 5212 | + struct net **tgt_net, struct sock *sk, |
---|
| 5213 | + struct netlink_callback *cb) |
---|
| 5214 | +{ |
---|
| 5215 | + struct netlink_ext_ack *extack = cb->extack; |
---|
| 5216 | + struct nlattr *tb[IFA_MAX+1]; |
---|
| 5217 | + struct ifaddrmsg *ifm; |
---|
| 5218 | + int err, i; |
---|
| 5219 | + |
---|
| 5220 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { |
---|
| 5221 | + NL_SET_ERR_MSG_MOD(extack, "Invalid header for address dump request"); |
---|
| 5222 | + return -EINVAL; |
---|
| 5223 | + } |
---|
| 5224 | + |
---|
| 5225 | + ifm = nlmsg_data(nlh); |
---|
| 5226 | + if (ifm->ifa_prefixlen || ifm->ifa_flags || ifm->ifa_scope) { |
---|
| 5227 | + NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for address dump request"); |
---|
| 5228 | + return -EINVAL; |
---|
| 5229 | + } |
---|
| 5230 | + |
---|
| 5231 | + fillargs->ifindex = ifm->ifa_index; |
---|
| 5232 | + if (fillargs->ifindex) { |
---|
| 5233 | + cb->answer_flags |= NLM_F_DUMP_FILTERED; |
---|
| 5234 | + fillargs->flags |= NLM_F_DUMP_FILTERED; |
---|
| 5235 | + } |
---|
| 5236 | + |
---|
| 5237 | + err = nlmsg_parse_deprecated_strict(nlh, sizeof(*ifm), tb, IFA_MAX, |
---|
| 5238 | + ifa_ipv6_policy, extack); |
---|
| 5239 | + if (err < 0) |
---|
| 5240 | + return err; |
---|
| 5241 | + |
---|
| 5242 | + for (i = 0; i <= IFA_MAX; ++i) { |
---|
| 5243 | + if (!tb[i]) |
---|
| 5244 | + continue; |
---|
| 5245 | + |
---|
| 5246 | + if (i == IFA_TARGET_NETNSID) { |
---|
| 5247 | + struct net *net; |
---|
| 5248 | + |
---|
| 5249 | + fillargs->netnsid = nla_get_s32(tb[i]); |
---|
| 5250 | + net = rtnl_get_net_ns_capable(sk, fillargs->netnsid); |
---|
| 5251 | + if (IS_ERR(net)) { |
---|
| 5252 | + fillargs->netnsid = -1; |
---|
| 5253 | + NL_SET_ERR_MSG_MOD(extack, "Invalid target network namespace id"); |
---|
| 5254 | + return PTR_ERR(net); |
---|
| 5255 | + } |
---|
| 5256 | + *tgt_net = net; |
---|
| 5257 | + } else { |
---|
| 5258 | + NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in dump request"); |
---|
| 5259 | + return -EINVAL; |
---|
| 5260 | + } |
---|
| 5261 | + } |
---|
| 5262 | + |
---|
| 5263 | + return 0; |
---|
5048 | 5264 | } |
---|
5049 | 5265 | |
---|
5050 | 5266 | static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, |
---|
5051 | 5267 | enum addr_type_t type) |
---|
5052 | 5268 | { |
---|
| 5269 | + const struct nlmsghdr *nlh = cb->nlh; |
---|
| 5270 | + struct inet6_fill_args fillargs = { |
---|
| 5271 | + .portid = NETLINK_CB(cb->skb).portid, |
---|
| 5272 | + .seq = cb->nlh->nlmsg_seq, |
---|
| 5273 | + .flags = NLM_F_MULTI, |
---|
| 5274 | + .netnsid = -1, |
---|
| 5275 | + .type = type, |
---|
| 5276 | + }; |
---|
5053 | 5277 | struct net *net = sock_net(skb->sk); |
---|
| 5278 | + struct net *tgt_net = net; |
---|
| 5279 | + int idx, s_idx, s_ip_idx; |
---|
5054 | 5280 | int h, s_h; |
---|
5055 | | - int idx, ip_idx; |
---|
5056 | | - int s_idx, s_ip_idx; |
---|
5057 | 5281 | struct net_device *dev; |
---|
5058 | 5282 | struct inet6_dev *idev; |
---|
5059 | 5283 | struct hlist_head *head; |
---|
| 5284 | + int err = 0; |
---|
5060 | 5285 | |
---|
5061 | 5286 | s_h = cb->args[0]; |
---|
5062 | 5287 | s_idx = idx = cb->args[1]; |
---|
5063 | | - s_ip_idx = ip_idx = cb->args[2]; |
---|
| 5288 | + s_ip_idx = cb->args[2]; |
---|
| 5289 | + |
---|
| 5290 | + if (cb->strict_check) { |
---|
| 5291 | + err = inet6_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net, |
---|
| 5292 | + skb->sk, cb); |
---|
| 5293 | + if (err < 0) |
---|
| 5294 | + goto put_tgt_net; |
---|
| 5295 | + |
---|
| 5296 | + err = 0; |
---|
| 5297 | + if (fillargs.ifindex) { |
---|
| 5298 | + dev = __dev_get_by_index(tgt_net, fillargs.ifindex); |
---|
| 5299 | + if (!dev) { |
---|
| 5300 | + err = -ENODEV; |
---|
| 5301 | + goto put_tgt_net; |
---|
| 5302 | + } |
---|
| 5303 | + idev = __in6_dev_get(dev); |
---|
| 5304 | + if (idev) { |
---|
| 5305 | + err = in6_dump_addrs(idev, skb, cb, s_ip_idx, |
---|
| 5306 | + &fillargs); |
---|
| 5307 | + if (err > 0) |
---|
| 5308 | + err = 0; |
---|
| 5309 | + } |
---|
| 5310 | + goto put_tgt_net; |
---|
| 5311 | + } |
---|
| 5312 | + } |
---|
5064 | 5313 | |
---|
5065 | 5314 | rcu_read_lock(); |
---|
5066 | | - cb->seq = atomic_read(&net->ipv6.dev_addr_genid) ^ net->dev_base_seq; |
---|
| 5315 | + cb->seq = atomic_read(&tgt_net->ipv6.dev_addr_genid) ^ tgt_net->dev_base_seq; |
---|
5067 | 5316 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
---|
5068 | 5317 | idx = 0; |
---|
5069 | | - head = &net->dev_index_head[h]; |
---|
| 5318 | + head = &tgt_net->dev_index_head[h]; |
---|
5070 | 5319 | hlist_for_each_entry_rcu(dev, head, index_hlist) { |
---|
5071 | 5320 | if (idx < s_idx) |
---|
5072 | 5321 | goto cont; |
---|
5073 | 5322 | if (h > s_h || idx > s_idx) |
---|
5074 | 5323 | s_ip_idx = 0; |
---|
5075 | | - ip_idx = 0; |
---|
5076 | 5324 | idev = __in6_dev_get(dev); |
---|
5077 | 5325 | if (!idev) |
---|
5078 | 5326 | goto cont; |
---|
5079 | 5327 | |
---|
5080 | | - if (in6_dump_addrs(idev, skb, cb, type, |
---|
5081 | | - s_ip_idx, &ip_idx) < 0) |
---|
| 5328 | + if (in6_dump_addrs(idev, skb, cb, s_ip_idx, |
---|
| 5329 | + &fillargs) < 0) |
---|
5082 | 5330 | goto done; |
---|
5083 | 5331 | cont: |
---|
5084 | 5332 | idx++; |
---|
.. | .. |
---|
5088 | 5336 | rcu_read_unlock(); |
---|
5089 | 5337 | cb->args[0] = h; |
---|
5090 | 5338 | cb->args[1] = idx; |
---|
5091 | | - cb->args[2] = ip_idx; |
---|
| 5339 | +put_tgt_net: |
---|
| 5340 | + if (fillargs.netnsid >= 0) |
---|
| 5341 | + put_net(tgt_net); |
---|
5092 | 5342 | |
---|
5093 | | - return skb->len; |
---|
| 5343 | + return skb->len ? : err; |
---|
5094 | 5344 | } |
---|
5095 | 5345 | |
---|
5096 | 5346 | static int inet6_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) |
---|
.. | .. |
---|
5115 | 5365 | return inet6_dump_addr(skb, cb, type); |
---|
5116 | 5366 | } |
---|
5117 | 5367 | |
---|
| 5368 | +static int inet6_rtm_valid_getaddr_req(struct sk_buff *skb, |
---|
| 5369 | + const struct nlmsghdr *nlh, |
---|
| 5370 | + struct nlattr **tb, |
---|
| 5371 | + struct netlink_ext_ack *extack) |
---|
| 5372 | +{ |
---|
| 5373 | + struct ifaddrmsg *ifm; |
---|
| 5374 | + int i, err; |
---|
| 5375 | + |
---|
| 5376 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { |
---|
| 5377 | + NL_SET_ERR_MSG_MOD(extack, "Invalid header for get address request"); |
---|
| 5378 | + return -EINVAL; |
---|
| 5379 | + } |
---|
| 5380 | + |
---|
| 5381 | + if (!netlink_strict_get_check(skb)) |
---|
| 5382 | + return nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX, |
---|
| 5383 | + ifa_ipv6_policy, extack); |
---|
| 5384 | + |
---|
| 5385 | + ifm = nlmsg_data(nlh); |
---|
| 5386 | + if (ifm->ifa_prefixlen || ifm->ifa_flags || ifm->ifa_scope) { |
---|
| 5387 | + NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for get address request"); |
---|
| 5388 | + return -EINVAL; |
---|
| 5389 | + } |
---|
| 5390 | + |
---|
| 5391 | + err = nlmsg_parse_deprecated_strict(nlh, sizeof(*ifm), tb, IFA_MAX, |
---|
| 5392 | + ifa_ipv6_policy, extack); |
---|
| 5393 | + if (err) |
---|
| 5394 | + return err; |
---|
| 5395 | + |
---|
| 5396 | + for (i = 0; i <= IFA_MAX; i++) { |
---|
| 5397 | + if (!tb[i]) |
---|
| 5398 | + continue; |
---|
| 5399 | + |
---|
| 5400 | + switch (i) { |
---|
| 5401 | + case IFA_TARGET_NETNSID: |
---|
| 5402 | + case IFA_ADDRESS: |
---|
| 5403 | + case IFA_LOCAL: |
---|
| 5404 | + break; |
---|
| 5405 | + default: |
---|
| 5406 | + NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in get address request"); |
---|
| 5407 | + return -EINVAL; |
---|
| 5408 | + } |
---|
| 5409 | + } |
---|
| 5410 | + |
---|
| 5411 | + return 0; |
---|
| 5412 | +} |
---|
| 5413 | + |
---|
5118 | 5414 | static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh, |
---|
5119 | 5415 | struct netlink_ext_ack *extack) |
---|
5120 | 5416 | { |
---|
5121 | 5417 | struct net *net = sock_net(in_skb->sk); |
---|
| 5418 | + struct inet6_fill_args fillargs = { |
---|
| 5419 | + .portid = NETLINK_CB(in_skb).portid, |
---|
| 5420 | + .seq = nlh->nlmsg_seq, |
---|
| 5421 | + .event = RTM_NEWADDR, |
---|
| 5422 | + .flags = 0, |
---|
| 5423 | + .netnsid = -1, |
---|
| 5424 | + }; |
---|
| 5425 | + struct net *tgt_net = net; |
---|
5122 | 5426 | struct ifaddrmsg *ifm; |
---|
5123 | 5427 | struct nlattr *tb[IFA_MAX+1]; |
---|
5124 | 5428 | struct in6_addr *addr = NULL, *peer; |
---|
.. | .. |
---|
5127 | 5431 | struct sk_buff *skb; |
---|
5128 | 5432 | int err; |
---|
5129 | 5433 | |
---|
5130 | | - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy, |
---|
5131 | | - extack); |
---|
| 5434 | + err = inet6_rtm_valid_getaddr_req(in_skb, nlh, tb, extack); |
---|
5132 | 5435 | if (err < 0) |
---|
5133 | 5436 | return err; |
---|
| 5437 | + |
---|
| 5438 | + if (tb[IFA_TARGET_NETNSID]) { |
---|
| 5439 | + fillargs.netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]); |
---|
| 5440 | + |
---|
| 5441 | + tgt_net = rtnl_get_net_ns_capable(NETLINK_CB(in_skb).sk, |
---|
| 5442 | + fillargs.netnsid); |
---|
| 5443 | + if (IS_ERR(tgt_net)) |
---|
| 5444 | + return PTR_ERR(tgt_net); |
---|
| 5445 | + } |
---|
5134 | 5446 | |
---|
5135 | 5447 | addr = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL], &peer); |
---|
5136 | 5448 | if (!addr) |
---|
.. | .. |
---|
5138 | 5450 | |
---|
5139 | 5451 | ifm = nlmsg_data(nlh); |
---|
5140 | 5452 | if (ifm->ifa_index) |
---|
5141 | | - dev = dev_get_by_index(net, ifm->ifa_index); |
---|
| 5453 | + dev = dev_get_by_index(tgt_net, ifm->ifa_index); |
---|
5142 | 5454 | |
---|
5143 | | - ifa = ipv6_get_ifaddr(net, addr, dev, 1); |
---|
| 5455 | + ifa = ipv6_get_ifaddr(tgt_net, addr, dev, 1); |
---|
5144 | 5456 | if (!ifa) { |
---|
5145 | 5457 | err = -EADDRNOTAVAIL; |
---|
5146 | 5458 | goto errout; |
---|
.. | .. |
---|
5152 | 5464 | goto errout_ifa; |
---|
5153 | 5465 | } |
---|
5154 | 5466 | |
---|
5155 | | - err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).portid, |
---|
5156 | | - nlh->nlmsg_seq, RTM_NEWADDR, 0); |
---|
| 5467 | + err = inet6_fill_ifaddr(skb, ifa, &fillargs); |
---|
5157 | 5468 | if (err < 0) { |
---|
5158 | 5469 | /* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */ |
---|
5159 | 5470 | WARN_ON(err == -EMSGSIZE); |
---|
5160 | 5471 | kfree_skb(skb); |
---|
5161 | 5472 | goto errout_ifa; |
---|
5162 | 5473 | } |
---|
5163 | | - err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); |
---|
| 5474 | + err = rtnl_unicast(skb, tgt_net, NETLINK_CB(in_skb).portid); |
---|
5164 | 5475 | errout_ifa: |
---|
5165 | 5476 | in6_ifa_put(ifa); |
---|
5166 | 5477 | errout: |
---|
5167 | 5478 | if (dev) |
---|
5168 | 5479 | dev_put(dev); |
---|
| 5480 | + if (fillargs.netnsid >= 0) |
---|
| 5481 | + put_net(tgt_net); |
---|
| 5482 | + |
---|
5169 | 5483 | return err; |
---|
5170 | 5484 | } |
---|
5171 | 5485 | |
---|
.. | .. |
---|
5173 | 5487 | { |
---|
5174 | 5488 | struct sk_buff *skb; |
---|
5175 | 5489 | struct net *net = dev_net(ifa->idev->dev); |
---|
| 5490 | + struct inet6_fill_args fillargs = { |
---|
| 5491 | + .portid = 0, |
---|
| 5492 | + .seq = 0, |
---|
| 5493 | + .event = event, |
---|
| 5494 | + .flags = 0, |
---|
| 5495 | + .netnsid = -1, |
---|
| 5496 | + }; |
---|
5176 | 5497 | int err = -ENOBUFS; |
---|
5177 | 5498 | |
---|
5178 | 5499 | skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_ATOMIC); |
---|
5179 | 5500 | if (!skb) |
---|
5180 | 5501 | goto errout; |
---|
5181 | 5502 | |
---|
5182 | | - err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0); |
---|
| 5503 | + err = inet6_fill_ifaddr(skb, ifa, &fillargs); |
---|
5183 | 5504 | if (err < 0) { |
---|
5184 | 5505 | /* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */ |
---|
5185 | 5506 | WARN_ON(err == -EMSGSIZE); |
---|
.. | .. |
---|
5243 | 5564 | array[DEVCONF_USE_OPTIMISTIC] = cnf->use_optimistic; |
---|
5244 | 5565 | #endif |
---|
5245 | 5566 | #ifdef CONFIG_IPV6_MROUTE |
---|
5246 | | - array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding; |
---|
| 5567 | + array[DEVCONF_MC_FORWARDING] = atomic_read(&cnf->mc_forwarding); |
---|
5247 | 5568 | #endif |
---|
5248 | 5569 | array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6; |
---|
5249 | 5570 | array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad; |
---|
.. | .. |
---|
5266 | 5587 | array[DEVCONF_ADDR_GEN_MODE] = cnf->addr_gen_mode; |
---|
5267 | 5588 | array[DEVCONF_DISABLE_POLICY] = cnf->disable_policy; |
---|
5268 | 5589 | array[DEVCONF_NDISC_TCLASS] = cnf->ndisc_tclass; |
---|
| 5590 | + array[DEVCONF_RPL_SEG_ENABLED] = cnf->rpl_seg_enabled; |
---|
5269 | 5591 | } |
---|
5270 | 5592 | |
---|
5271 | 5593 | static inline size_t inet6_ifla6_size(void) |
---|
.. | .. |
---|
5378 | 5700 | nla = nla_reserve(skb, IFLA_INET6_TOKEN, sizeof(struct in6_addr)); |
---|
5379 | 5701 | if (!nla) |
---|
5380 | 5702 | goto nla_put_failure; |
---|
5381 | | - |
---|
5382 | | - if (nla_put_u8(skb, IFLA_INET6_ADDR_GEN_MODE, idev->cnf.addr_gen_mode)) |
---|
5383 | | - goto nla_put_failure; |
---|
5384 | | - |
---|
5385 | 5703 | read_lock_bh(&idev->lock); |
---|
5386 | 5704 | memcpy(nla_data(nla), idev->token.s6_addr, nla_len(nla)); |
---|
5387 | 5705 | read_unlock_bh(&idev->lock); |
---|
| 5706 | + |
---|
| 5707 | + if (nla_put_u8(skb, IFLA_INET6_ADDR_GEN_MODE, idev->cnf.addr_gen_mode)) |
---|
| 5708 | + goto nla_put_failure; |
---|
5388 | 5709 | |
---|
5389 | 5710 | return 0; |
---|
5390 | 5711 | |
---|
.. | .. |
---|
5486 | 5807 | [IFLA_INET6_TOKEN] = { .len = sizeof(struct in6_addr) }, |
---|
5487 | 5808 | }; |
---|
5488 | 5809 | |
---|
5489 | | -static int inet6_validate_link_af(const struct net_device *dev, |
---|
5490 | | - const struct nlattr *nla) |
---|
5491 | | -{ |
---|
5492 | | - struct nlattr *tb[IFLA_INET6_MAX + 1]; |
---|
5493 | | - |
---|
5494 | | - if (dev && !__in6_dev_get(dev)) |
---|
5495 | | - return -EAFNOSUPPORT; |
---|
5496 | | - |
---|
5497 | | - return nla_parse_nested(tb, IFLA_INET6_MAX, nla, inet6_af_policy, |
---|
5498 | | - NULL); |
---|
5499 | | -} |
---|
5500 | | - |
---|
5501 | 5810 | static int check_addr_gen_mode(int mode) |
---|
5502 | 5811 | { |
---|
5503 | 5812 | if (mode != IN6_ADDR_GEN_MODE_EUI64 && |
---|
.. | .. |
---|
5518 | 5827 | return 1; |
---|
5519 | 5828 | } |
---|
5520 | 5829 | |
---|
| 5830 | +static int inet6_validate_link_af(const struct net_device *dev, |
---|
| 5831 | + const struct nlattr *nla) |
---|
| 5832 | +{ |
---|
| 5833 | + struct nlattr *tb[IFLA_INET6_MAX + 1]; |
---|
| 5834 | + struct inet6_dev *idev = NULL; |
---|
| 5835 | + int err; |
---|
| 5836 | + |
---|
| 5837 | + if (dev) { |
---|
| 5838 | + idev = __in6_dev_get(dev); |
---|
| 5839 | + if (!idev) |
---|
| 5840 | + return -EAFNOSUPPORT; |
---|
| 5841 | + } |
---|
| 5842 | + |
---|
| 5843 | + err = nla_parse_nested_deprecated(tb, IFLA_INET6_MAX, nla, |
---|
| 5844 | + inet6_af_policy, NULL); |
---|
| 5845 | + if (err) |
---|
| 5846 | + return err; |
---|
| 5847 | + |
---|
| 5848 | + if (!tb[IFLA_INET6_TOKEN] && !tb[IFLA_INET6_ADDR_GEN_MODE]) |
---|
| 5849 | + return -EINVAL; |
---|
| 5850 | + |
---|
| 5851 | + if (tb[IFLA_INET6_ADDR_GEN_MODE]) { |
---|
| 5852 | + u8 mode = nla_get_u8(tb[IFLA_INET6_ADDR_GEN_MODE]); |
---|
| 5853 | + |
---|
| 5854 | + if (check_addr_gen_mode(mode) < 0) |
---|
| 5855 | + return -EINVAL; |
---|
| 5856 | + if (dev && check_stable_privacy(idev, dev_net(dev), mode) < 0) |
---|
| 5857 | + return -EINVAL; |
---|
| 5858 | + } |
---|
| 5859 | + |
---|
| 5860 | + return 0; |
---|
| 5861 | +} |
---|
| 5862 | + |
---|
5521 | 5863 | static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla) |
---|
5522 | 5864 | { |
---|
5523 | | - int err = -EINVAL; |
---|
5524 | 5865 | struct inet6_dev *idev = __in6_dev_get(dev); |
---|
5525 | 5866 | struct nlattr *tb[IFLA_INET6_MAX + 1]; |
---|
| 5867 | + int err; |
---|
5526 | 5868 | |
---|
5527 | 5869 | if (!idev) |
---|
5528 | 5870 | return -EAFNOSUPPORT; |
---|
5529 | 5871 | |
---|
5530 | | - if (nla_parse_nested(tb, IFLA_INET6_MAX, nla, NULL, NULL) < 0) |
---|
5531 | | - BUG(); |
---|
| 5872 | + if (nla_parse_nested_deprecated(tb, IFLA_INET6_MAX, nla, NULL, NULL) < 0) |
---|
| 5873 | + return -EINVAL; |
---|
5532 | 5874 | |
---|
5533 | 5875 | if (tb[IFLA_INET6_TOKEN]) { |
---|
5534 | 5876 | err = inet6_set_iftoken(idev, nla_data(tb[IFLA_INET6_TOKEN])); |
---|
.. | .. |
---|
5539 | 5881 | if (tb[IFLA_INET6_ADDR_GEN_MODE]) { |
---|
5540 | 5882 | u8 mode = nla_get_u8(tb[IFLA_INET6_ADDR_GEN_MODE]); |
---|
5541 | 5883 | |
---|
5542 | | - if (check_addr_gen_mode(mode) < 0 || |
---|
5543 | | - check_stable_privacy(idev, dev_net(dev), mode) < 0) |
---|
5544 | | - return -EINVAL; |
---|
5545 | | - |
---|
5546 | 5884 | idev->cnf.addr_gen_mode = mode; |
---|
5547 | | - err = 0; |
---|
5548 | 5885 | } |
---|
5549 | 5886 | |
---|
5550 | | - return err; |
---|
| 5887 | + return 0; |
---|
5551 | 5888 | } |
---|
5552 | 5889 | |
---|
5553 | 5890 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, |
---|
.. | .. |
---|
5579 | 5916 | nla_put_u8(skb, IFLA_OPERSTATE, |
---|
5580 | 5917 | netif_running(dev) ? dev->operstate : IF_OPER_DOWN)) |
---|
5581 | 5918 | goto nla_put_failure; |
---|
5582 | | - protoinfo = nla_nest_start(skb, IFLA_PROTINFO); |
---|
| 5919 | + protoinfo = nla_nest_start_noflag(skb, IFLA_PROTINFO); |
---|
5583 | 5920 | if (!protoinfo) |
---|
5584 | 5921 | goto nla_put_failure; |
---|
5585 | 5922 | |
---|
.. | .. |
---|
5595 | 5932 | return -EMSGSIZE; |
---|
5596 | 5933 | } |
---|
5597 | 5934 | |
---|
| 5935 | +static int inet6_valid_dump_ifinfo(const struct nlmsghdr *nlh, |
---|
| 5936 | + struct netlink_ext_ack *extack) |
---|
| 5937 | +{ |
---|
| 5938 | + struct ifinfomsg *ifm; |
---|
| 5939 | + |
---|
| 5940 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { |
---|
| 5941 | + NL_SET_ERR_MSG_MOD(extack, "Invalid header for link dump request"); |
---|
| 5942 | + return -EINVAL; |
---|
| 5943 | + } |
---|
| 5944 | + |
---|
| 5945 | + if (nlmsg_attrlen(nlh, sizeof(*ifm))) { |
---|
| 5946 | + NL_SET_ERR_MSG_MOD(extack, "Invalid data after header"); |
---|
| 5947 | + return -EINVAL; |
---|
| 5948 | + } |
---|
| 5949 | + |
---|
| 5950 | + ifm = nlmsg_data(nlh); |
---|
| 5951 | + if (ifm->__ifi_pad || ifm->ifi_type || ifm->ifi_flags || |
---|
| 5952 | + ifm->ifi_change || ifm->ifi_index) { |
---|
| 5953 | + NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for dump request"); |
---|
| 5954 | + return -EINVAL; |
---|
| 5955 | + } |
---|
| 5956 | + |
---|
| 5957 | + return 0; |
---|
| 5958 | +} |
---|
| 5959 | + |
---|
5598 | 5960 | static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) |
---|
5599 | 5961 | { |
---|
5600 | 5962 | struct net *net = sock_net(skb->sk); |
---|
.. | .. |
---|
5603 | 5965 | struct net_device *dev; |
---|
5604 | 5966 | struct inet6_dev *idev; |
---|
5605 | 5967 | struct hlist_head *head; |
---|
| 5968 | + |
---|
| 5969 | + /* only requests using strict checking can pass data to |
---|
| 5970 | + * influence the dump |
---|
| 5971 | + */ |
---|
| 5972 | + if (cb->strict_check) { |
---|
| 5973 | + int err = inet6_valid_dump_ifinfo(cb->nlh, cb->extack); |
---|
| 5974 | + |
---|
| 5975 | + if (err < 0) |
---|
| 5976 | + return err; |
---|
| 5977 | + } |
---|
5606 | 5978 | |
---|
5607 | 5979 | s_h = cb->args[0]; |
---|
5608 | 5980 | s_idx = cb->args[1]; |
---|
.. | .. |
---|
5771 | 6143 | struct fib6_info *rt; |
---|
5772 | 6144 | |
---|
5773 | 6145 | rt = addrconf_get_prefix_route(&ifp->peer_addr, 128, |
---|
5774 | | - ifp->idev->dev, 0, 0); |
---|
| 6146 | + ifp->idev->dev, 0, 0, |
---|
| 6147 | + false); |
---|
5775 | 6148 | if (rt) |
---|
5776 | | - ip6_del_rt(net, rt); |
---|
| 6149 | + ip6_del_rt(net, rt, false); |
---|
5777 | 6150 | } |
---|
5778 | 6151 | if (ifp->rt) { |
---|
5779 | | - ip6_del_rt(net, ifp->rt); |
---|
| 6152 | + ip6_del_rt(net, ifp->rt, false); |
---|
5780 | 6153 | ifp->rt = NULL; |
---|
5781 | 6154 | } |
---|
5782 | 6155 | rt_genid_bump_ipv6(net); |
---|
.. | .. |
---|
5795 | 6168 | |
---|
5796 | 6169 | #ifdef CONFIG_SYSCTL |
---|
5797 | 6170 | |
---|
5798 | | -static |
---|
5799 | | -int addrconf_sysctl_forward(struct ctl_table *ctl, int write, |
---|
5800 | | - void __user *buffer, size_t *lenp, loff_t *ppos) |
---|
| 6171 | +static int addrconf_sysctl_forward(struct ctl_table *ctl, int write, |
---|
| 6172 | + void *buffer, size_t *lenp, loff_t *ppos) |
---|
5801 | 6173 | { |
---|
5802 | 6174 | int *valp = ctl->data; |
---|
5803 | 6175 | int val = *valp; |
---|
.. | .. |
---|
5821 | 6193 | return ret; |
---|
5822 | 6194 | } |
---|
5823 | 6195 | |
---|
5824 | | -static |
---|
5825 | | -int addrconf_sysctl_mtu(struct ctl_table *ctl, int write, |
---|
5826 | | - void __user *buffer, size_t *lenp, loff_t *ppos) |
---|
| 6196 | +static int addrconf_sysctl_mtu(struct ctl_table *ctl, int write, |
---|
| 6197 | + void *buffer, size_t *lenp, loff_t *ppos) |
---|
5827 | 6198 | { |
---|
5828 | 6199 | struct inet6_dev *idev = ctl->extra1; |
---|
5829 | 6200 | int min_mtu = IPV6_MIN_MTU; |
---|
.. | .. |
---|
5893 | 6264 | return 0; |
---|
5894 | 6265 | } |
---|
5895 | 6266 | |
---|
5896 | | -static |
---|
5897 | | -int addrconf_sysctl_disable(struct ctl_table *ctl, int write, |
---|
5898 | | - void __user *buffer, size_t *lenp, loff_t *ppos) |
---|
| 6267 | +static int addrconf_sysctl_disable(struct ctl_table *ctl, int write, |
---|
| 6268 | + void *buffer, size_t *lenp, loff_t *ppos) |
---|
5899 | 6269 | { |
---|
5900 | 6270 | int *valp = ctl->data; |
---|
5901 | 6271 | int val = *valp; |
---|
.. | .. |
---|
5919 | 6289 | return ret; |
---|
5920 | 6290 | } |
---|
5921 | 6291 | |
---|
5922 | | -static |
---|
5923 | | -int addrconf_sysctl_proxy_ndp(struct ctl_table *ctl, int write, |
---|
5924 | | - void __user *buffer, size_t *lenp, loff_t *ppos) |
---|
| 6292 | +static int addrconf_sysctl_proxy_ndp(struct ctl_table *ctl, int write, |
---|
| 6293 | + void *buffer, size_t *lenp, loff_t *ppos) |
---|
5925 | 6294 | { |
---|
5926 | 6295 | int *valp = ctl->data; |
---|
5927 | 6296 | int ret; |
---|
.. | .. |
---|
5962 | 6331 | } |
---|
5963 | 6332 | |
---|
5964 | 6333 | static int addrconf_sysctl_addr_gen_mode(struct ctl_table *ctl, int write, |
---|
5965 | | - void __user *buffer, size_t *lenp, |
---|
| 6334 | + void *buffer, size_t *lenp, |
---|
5966 | 6335 | loff_t *ppos) |
---|
5967 | 6336 | { |
---|
5968 | 6337 | int ret = 0; |
---|
.. | .. |
---|
6024 | 6393 | } |
---|
6025 | 6394 | |
---|
6026 | 6395 | static int addrconf_sysctl_stable_secret(struct ctl_table *ctl, int write, |
---|
6027 | | - void __user *buffer, size_t *lenp, |
---|
| 6396 | + void *buffer, size_t *lenp, |
---|
6028 | 6397 | loff_t *ppos) |
---|
6029 | 6398 | { |
---|
6030 | 6399 | int err; |
---|
.. | .. |
---|
6091 | 6460 | |
---|
6092 | 6461 | static |
---|
6093 | 6462 | int addrconf_sysctl_ignore_routes_with_linkdown(struct ctl_table *ctl, |
---|
6094 | | - int write, |
---|
6095 | | - void __user *buffer, |
---|
| 6463 | + int write, void *buffer, |
---|
6096 | 6464 | size_t *lenp, |
---|
6097 | 6465 | loff_t *ppos) |
---|
6098 | 6466 | { |
---|
.. | .. |
---|
6137 | 6505 | list_for_each_entry(ifa, &idev->addr_list, if_list) { |
---|
6138 | 6506 | spin_lock(&ifa->lock); |
---|
6139 | 6507 | if (ifa->rt) { |
---|
6140 | | - struct fib6_info *rt = ifa->rt; |
---|
| 6508 | + /* host routes only use builtin fib6_nh */ |
---|
| 6509 | + struct fib6_nh *nh = ifa->rt->fib6_nh; |
---|
6141 | 6510 | int cpu; |
---|
6142 | 6511 | |
---|
6143 | 6512 | rcu_read_lock(); |
---|
6144 | 6513 | ifa->rt->dst_nopolicy = val ? true : false; |
---|
6145 | | - if (rt->rt6i_pcpu) { |
---|
| 6514 | + if (nh->rt6i_pcpu) { |
---|
6146 | 6515 | for_each_possible_cpu(cpu) { |
---|
6147 | 6516 | struct rt6_info **rtp; |
---|
6148 | 6517 | |
---|
6149 | | - rtp = per_cpu_ptr(rt->rt6i_pcpu, cpu); |
---|
| 6518 | + rtp = per_cpu_ptr(nh->rt6i_pcpu, cpu); |
---|
6150 | 6519 | addrconf_set_nopolicy(*rtp, val); |
---|
6151 | 6520 | } |
---|
6152 | 6521 | } |
---|
.. | .. |
---|
6191 | 6560 | return 0; |
---|
6192 | 6561 | } |
---|
6193 | 6562 | |
---|
6194 | | -static |
---|
6195 | | -int addrconf_sysctl_disable_policy(struct ctl_table *ctl, int write, |
---|
6196 | | - void __user *buffer, size_t *lenp, |
---|
6197 | | - loff_t *ppos) |
---|
| 6563 | +static int addrconf_sysctl_disable_policy(struct ctl_table *ctl, int write, |
---|
| 6564 | + void *buffer, size_t *lenp, loff_t *ppos) |
---|
6198 | 6565 | { |
---|
6199 | 6566 | int *valp = ctl->data; |
---|
6200 | 6567 | int val = *valp; |
---|
.. | .. |
---|
6216 | 6583 | } |
---|
6217 | 6584 | |
---|
6218 | 6585 | static int minus_one = -1; |
---|
6219 | | -static const int zero = 0; |
---|
6220 | | -static const int one = 1; |
---|
6221 | 6586 | static const int two_five_five = 255; |
---|
6222 | 6587 | |
---|
6223 | 6588 | static const struct ctl_table addrconf_sysctl[] = { |
---|
.. | .. |
---|
6234 | 6599 | .maxlen = sizeof(int), |
---|
6235 | 6600 | .mode = 0644, |
---|
6236 | 6601 | .proc_handler = proc_dointvec_minmax, |
---|
6237 | | - .extra1 = (void *)&one, |
---|
| 6602 | + .extra1 = (void *)SYSCTL_ONE, |
---|
6238 | 6603 | .extra2 = (void *)&two_five_five, |
---|
6239 | 6604 | }, |
---|
6240 | 6605 | { |
---|
.. | .. |
---|
6600 | 6965 | .maxlen = sizeof(int), |
---|
6601 | 6966 | .mode = 0644, |
---|
6602 | 6967 | .proc_handler = proc_dointvec_minmax, |
---|
6603 | | - .extra1 = (void *)&zero, |
---|
| 6968 | + .extra1 = (void *)SYSCTL_ZERO, |
---|
6604 | 6969 | .extra2 = (void *)&two_five_five, |
---|
| 6970 | + }, |
---|
| 6971 | + { |
---|
| 6972 | + .procname = "rpl_seg_enabled", |
---|
| 6973 | + .data = &ipv6_devconf.rpl_seg_enabled, |
---|
| 6974 | + .maxlen = sizeof(int), |
---|
| 6975 | + .mode = 0644, |
---|
| 6976 | + .proc_handler = proc_dointvec, |
---|
6605 | 6977 | }, |
---|
6606 | 6978 | { |
---|
6607 | 6979 | /* sentinel */ |
---|
.. | .. |
---|
6710 | 7082 | dflt = kmemdup(&ipv6_devconf_dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL); |
---|
6711 | 7083 | if (!dflt) |
---|
6712 | 7084 | goto err_alloc_dflt; |
---|
| 7085 | + |
---|
| 7086 | + if (!net_eq(net, &init_net)) { |
---|
| 7087 | + switch (net_inherit_devconf()) { |
---|
| 7088 | + case 1: /* copy from init_net */ |
---|
| 7089 | + memcpy(all, init_net.ipv6.devconf_all, |
---|
| 7090 | + sizeof(ipv6_devconf)); |
---|
| 7091 | + memcpy(dflt, init_net.ipv6.devconf_dflt, |
---|
| 7092 | + sizeof(ipv6_devconf_dflt)); |
---|
| 7093 | + break; |
---|
| 7094 | + case 3: /* copy from the current netns */ |
---|
| 7095 | + memcpy(all, current->nsproxy->net_ns->ipv6.devconf_all, |
---|
| 7096 | + sizeof(ipv6_devconf)); |
---|
| 7097 | + memcpy(dflt, |
---|
| 7098 | + current->nsproxy->net_ns->ipv6.devconf_dflt, |
---|
| 7099 | + sizeof(ipv6_devconf_dflt)); |
---|
| 7100 | + break; |
---|
| 7101 | + case 0: |
---|
| 7102 | + case 2: |
---|
| 7103 | + /* use compiled values */ |
---|
| 7104 | + break; |
---|
| 7105 | + } |
---|
| 7106 | + } |
---|
6713 | 7107 | |
---|
6714 | 7108 | /* these will be inherited by all namespaces */ |
---|
6715 | 7109 | dflt->autoconf = ipv6_defaults.autoconf; |
---|
.. | .. |
---|
6900 | 7294 | for_each_netdev(&init_net, dev) { |
---|
6901 | 7295 | if (__in6_dev_get(dev) == NULL) |
---|
6902 | 7296 | continue; |
---|
6903 | | - addrconf_ifdown(dev, 1); |
---|
| 7297 | + addrconf_ifdown(dev, true); |
---|
6904 | 7298 | } |
---|
6905 | | - addrconf_ifdown(init_net.loopback_dev, 2); |
---|
| 7299 | + addrconf_ifdown(init_net.loopback_dev, true); |
---|
6906 | 7300 | |
---|
6907 | 7301 | /* |
---|
6908 | 7302 | * Check hash table. |
---|