12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * NET3 IP device support routines. 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Derived from the IP parts of dev.c 1.0.19 602c30a84SJesper Juhl * Authors: Ross Biro 71da177e4SLinus Torvalds * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> 81da177e4SLinus Torvalds * Mark Evans, <evansmp@uhura.aston.ac.uk> 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * Additional Authors: 111da177e4SLinus Torvalds * Alan Cox, <gw4pts@gw4pts.ampr.org> 121da177e4SLinus Torvalds * Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * Changes: 151da177e4SLinus Torvalds * Alexey Kuznetsov: pa_* fields are replaced with ifaddr 161da177e4SLinus Torvalds * lists. 171da177e4SLinus Torvalds * Cyrus Durgin: updated for kmod 181da177e4SLinus Torvalds * Matthias Andree: in devinet_ioctl, compare label and 191da177e4SLinus Torvalds * address (4.4BSD alias style support), 201da177e4SLinus Torvalds * fall back to comparing just the label 211da177e4SLinus Torvalds * if no match found. 221da177e4SLinus Torvalds */ 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds 257c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 261da177e4SLinus Torvalds #include <linux/bitops.h> 274fc268d2SRandy Dunlap #include <linux/capability.h> 281da177e4SLinus Torvalds #include <linux/module.h> 291da177e4SLinus Torvalds #include <linux/types.h> 301da177e4SLinus Torvalds #include <linux/kernel.h> 31174cd4b1SIngo Molnar #include <linux/sched/signal.h> 321da177e4SLinus Torvalds #include <linux/string.h> 331da177e4SLinus Torvalds #include <linux/mm.h> 341da177e4SLinus Torvalds #include <linux/socket.h> 351da177e4SLinus Torvalds #include <linux/sockios.h> 361da177e4SLinus Torvalds #include <linux/in.h> 371da177e4SLinus Torvalds #include <linux/errno.h> 381da177e4SLinus Torvalds #include <linux/interrupt.h> 391823730fSThomas Graf #include <linux/if_addr.h> 401da177e4SLinus Torvalds #include <linux/if_ether.h> 411da177e4SLinus Torvalds #include <linux/inet.h> 421da177e4SLinus Torvalds #include <linux/netdevice.h> 431da177e4SLinus Torvalds #include <linux/etherdevice.h> 441da177e4SLinus Torvalds #include <linux/skbuff.h> 451da177e4SLinus Torvalds #include <linux/init.h> 461da177e4SLinus Torvalds #include <linux/notifier.h> 471da177e4SLinus Torvalds #include <linux/inetdevice.h> 481da177e4SLinus Torvalds #include <linux/igmp.h> 495a0e3ad6STejun Heo #include <linux/slab.h> 50fd23c3b3SDavid S. Miller #include <linux/hash.h> 511da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL 521da177e4SLinus Torvalds #include <linux/sysctl.h> 531da177e4SLinus Torvalds #endif 541da177e4SLinus Torvalds #include <linux/kmod.h> 55edc9e748SNicolas Dichtel #include <linux/netconf.h> 561da177e4SLinus Torvalds 5714c85021SArnaldo Carvalho de Melo #include <net/arp.h> 581da177e4SLinus Torvalds #include <net/ip.h> 591da177e4SLinus Torvalds #include <net/route.h> 601da177e4SLinus Torvalds #include <net/ip_fib.h> 6163f3444fSThomas Graf #include <net/rtnetlink.h> 62752d14dcSPavel Emelyanov #include <net/net_namespace.h> 635c766d64SJiri Pirko #include <net/addrconf.h> 641da177e4SLinus Torvalds 652e605463SMatteo Croce #define IPV6ONLY_FLAGS \ 662e605463SMatteo Croce (IFA_F_NODAD | IFA_F_OPTIMISTIC | IFA_F_DADFAILED | \ 672e605463SMatteo Croce IFA_F_HOMEADDRESS | IFA_F_TENTATIVE | \ 682e605463SMatteo Croce IFA_F_MANAGETEMPADDR | IFA_F_STABLE_PRIVACY) 692e605463SMatteo Croce 700027ba84SAdrian Bunk static struct ipv4_devconf ipv4_devconf = { 7142f811b8SHerbert Xu .data = { 7202291680SEric W. Biederman [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1, 7302291680SEric W. Biederman [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1, 7402291680SEric W. Biederman [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1, 7502291680SEric W. Biederman [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1, 762690048cSWilliam Manley [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/, 772690048cSWilliam Manley [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/, 78fcdb44d0SJames Prestwood [IPV4_DEVCONF_ARP_EVICT_NOCARRIER - 1] = 1, 7942f811b8SHerbert Xu }, 801da177e4SLinus Torvalds }; 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds static struct ipv4_devconf ipv4_devconf_dflt = { 8342f811b8SHerbert Xu .data = { 8402291680SEric W. Biederman [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1, 8502291680SEric W. Biederman [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1, 8602291680SEric W. Biederman [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1, 8702291680SEric W. Biederman [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1, 8802291680SEric W. Biederman [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1, 892690048cSWilliam Manley [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/, 902690048cSWilliam Manley [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/, 91fcdb44d0SJames Prestwood [IPV4_DEVCONF_ARP_EVICT_NOCARRIER - 1] = 1, 9242f811b8SHerbert Xu }, 931da177e4SLinus Torvalds }; 941da177e4SLinus Torvalds 959355bbd6SPavel Emelyanov #define IPV4_DEVCONF_DFLT(net, attr) \ 969355bbd6SPavel Emelyanov IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr) 9742f811b8SHerbert Xu 98ef7c79edSPatrick McHardy static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = { 995c753978SThomas Graf [IFA_LOCAL] = { .type = NLA_U32 }, 1005c753978SThomas Graf [IFA_ADDRESS] = { .type = NLA_U32 }, 1015c753978SThomas Graf [IFA_BROADCAST] = { .type = NLA_U32 }, 1025176f91eSThomas Graf [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, 1035c766d64SJiri Pirko [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, 104ad6c8135SJiri Pirko [IFA_FLAGS] = { .type = NLA_U32 }, 105af4d768aSDavid Ahern [IFA_RT_PRIORITY] = { .type = NLA_U32 }, 106d3807145SChristian Brauner [IFA_TARGET_NETNSID] = { .type = NLA_S32 }, 10747f0bd50SJacques de Laval [IFA_PROTO] = { .type = NLA_U8 }, 1085c753978SThomas Graf }; 1095c753978SThomas Graf 110978a46faSChristian Brauner struct inet_fill_args { 111978a46faSChristian Brauner u32 portid; 112978a46faSChristian Brauner u32 seq; 113978a46faSChristian Brauner int event; 114978a46faSChristian Brauner unsigned int flags; 115978a46faSChristian Brauner int netnsid; 1165fcd266aSDavid Ahern int ifindex; 117978a46faSChristian Brauner }; 118978a46faSChristian Brauner 11940384999SEric Dumazet #define IN4_ADDR_HSIZE_SHIFT 8 12040384999SEric Dumazet #define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT) 12140384999SEric Dumazet 122fd23c3b3SDavid S. Miller static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE]; 123fd23c3b3SDavid S. Miller 1246eada011SEric Dumazet static u32 inet_addr_hash(const struct net *net, __be32 addr) 125fd23c3b3SDavid S. Miller { 12640384999SEric Dumazet u32 val = (__force u32) addr ^ net_hash_mix(net); 127fd23c3b3SDavid S. Miller 12840384999SEric Dumazet return hash_32(val, IN4_ADDR_HSIZE_SHIFT); 129fd23c3b3SDavid S. Miller } 130fd23c3b3SDavid S. Miller 131fd23c3b3SDavid S. Miller static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa) 132fd23c3b3SDavid S. Miller { 13340384999SEric Dumazet u32 hash = inet_addr_hash(net, ifa->ifa_local); 134fd23c3b3SDavid S. Miller 13532a4be48SWANG Cong ASSERT_RTNL(); 136fd23c3b3SDavid S. Miller hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]); 137fd23c3b3SDavid S. Miller } 138fd23c3b3SDavid S. Miller 139fd23c3b3SDavid S. Miller static void inet_hash_remove(struct in_ifaddr *ifa) 140fd23c3b3SDavid S. Miller { 14132a4be48SWANG Cong ASSERT_RTNL(); 142fd23c3b3SDavid S. Miller hlist_del_init_rcu(&ifa->hash); 143fd23c3b3SDavid S. Miller } 144fd23c3b3SDavid S. Miller 1459435eb1cSDavid S. Miller /** 1469435eb1cSDavid S. Miller * __ip_dev_find - find the first device with a given source address. 1479435eb1cSDavid S. Miller * @net: the net namespace 1489435eb1cSDavid S. Miller * @addr: the source address 1499435eb1cSDavid S. Miller * @devref: if true, take a reference on the found device 1509435eb1cSDavid S. Miller * 1519435eb1cSDavid S. Miller * If a caller uses devref=false, it should be protected by RCU, or RTNL 1529435eb1cSDavid S. Miller */ 1539435eb1cSDavid S. Miller struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref) 1549435eb1cSDavid S. Miller { 1559435eb1cSDavid S. Miller struct net_device *result = NULL; 1569435eb1cSDavid S. Miller struct in_ifaddr *ifa; 1579435eb1cSDavid S. Miller 1589435eb1cSDavid S. Miller rcu_read_lock(); 1596e617de8SPaolo Abeni ifa = inet_lookup_ifaddr_rcu(net, addr); 1606e617de8SPaolo Abeni if (!ifa) { 161406b6f97SDavid S. Miller struct flowi4 fl4 = { .daddr = addr }; 162406b6f97SDavid S. Miller struct fib_result res = { 0 }; 163406b6f97SDavid S. Miller struct fib_table *local; 164406b6f97SDavid S. Miller 165406b6f97SDavid S. Miller /* Fallback to FIB local table so that communication 166406b6f97SDavid S. Miller * over loopback subnets work. 167406b6f97SDavid S. Miller */ 168406b6f97SDavid S. Miller local = fib_get_table(net, RT_TABLE_LOCAL); 169406b6f97SDavid S. Miller if (local && 170406b6f97SDavid S. Miller !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) && 171406b6f97SDavid S. Miller res.type == RTN_LOCAL) 172406b6f97SDavid S. Miller result = FIB_RES_DEV(res); 1736e617de8SPaolo Abeni } else { 1746e617de8SPaolo Abeni result = ifa->ifa_dev->dev; 175406b6f97SDavid S. Miller } 1769435eb1cSDavid S. Miller if (result && devref) 1779435eb1cSDavid S. Miller dev_hold(result); 1789435eb1cSDavid S. Miller rcu_read_unlock(); 1799435eb1cSDavid S. Miller return result; 1809435eb1cSDavid S. Miller } 1819435eb1cSDavid S. Miller EXPORT_SYMBOL(__ip_dev_find); 1829435eb1cSDavid S. Miller 1836e617de8SPaolo Abeni /* called under RCU lock */ 1846e617de8SPaolo Abeni struct in_ifaddr *inet_lookup_ifaddr_rcu(struct net *net, __be32 addr) 1856e617de8SPaolo Abeni { 1866e617de8SPaolo Abeni u32 hash = inet_addr_hash(net, addr); 1876e617de8SPaolo Abeni struct in_ifaddr *ifa; 1886e617de8SPaolo Abeni 1896e617de8SPaolo Abeni hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash) 1906e617de8SPaolo Abeni if (ifa->ifa_local == addr && 1916e617de8SPaolo Abeni net_eq(dev_net(ifa->ifa_dev->dev), net)) 1926e617de8SPaolo Abeni return ifa; 1936e617de8SPaolo Abeni 1946e617de8SPaolo Abeni return NULL; 1956e617de8SPaolo Abeni } 1966e617de8SPaolo Abeni 197d6062cbbSThomas Graf static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32); 1981da177e4SLinus Torvalds 199e041c683SAlan Stern static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); 2003ad7d246SKrister Johansen static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain); 2012638eb8bSFlorian Westphal static void inet_del_ifa(struct in_device *in_dev, 2022638eb8bSFlorian Westphal struct in_ifaddr __rcu **ifap, 2031da177e4SLinus Torvalds int destroy); 2041da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL 20520e61da7SWANG Cong static int devinet_sysctl_register(struct in_device *idev); 20651602b2aSPavel Emelyanov static void devinet_sysctl_unregister(struct in_device *idev); 20751602b2aSPavel Emelyanov #else 20820e61da7SWANG Cong static int devinet_sysctl_register(struct in_device *idev) 20951602b2aSPavel Emelyanov { 21020e61da7SWANG Cong return 0; 21151602b2aSPavel Emelyanov } 21240384999SEric Dumazet static void devinet_sysctl_unregister(struct in_device *idev) 21351602b2aSPavel Emelyanov { 21451602b2aSPavel Emelyanov } 2151da177e4SLinus Torvalds #endif 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds /* Locks all the inet devices. */ 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds static struct in_ifaddr *inet_alloc_ifa(void) 2201da177e4SLinus Torvalds { 2216126891cSVasily Averin return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL_ACCOUNT); 2221da177e4SLinus Torvalds } 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds static void inet_rcu_free_ifa(struct rcu_head *head) 2251da177e4SLinus Torvalds { 2261da177e4SLinus Torvalds struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head); 2271da177e4SLinus Torvalds if (ifa->ifa_dev) 2281da177e4SLinus Torvalds in_dev_put(ifa->ifa_dev); 2291da177e4SLinus Torvalds kfree(ifa); 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds 23240384999SEric Dumazet static void inet_free_ifa(struct in_ifaddr *ifa) 2331da177e4SLinus Torvalds { 2341da177e4SLinus Torvalds call_rcu(&ifa->rcu_head, inet_rcu_free_ifa); 2351da177e4SLinus Torvalds } 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds void in_dev_finish_destroy(struct in_device *idev) 2381da177e4SLinus Torvalds { 2391da177e4SLinus Torvalds struct net_device *dev = idev->dev; 2401da177e4SLinus Torvalds 241547b792cSIlpo Järvinen WARN_ON(idev->ifa_list); 242547b792cSIlpo Järvinen WARN_ON(idev->mc_list); 243e9897071SEric Dumazet kfree(rcu_dereference_protected(idev->mc_hash, 1)); 2441da177e4SLinus Torvalds #ifdef NET_REFCNT_DEBUG 24591df42beSJoe Perches pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL"); 2461da177e4SLinus Torvalds #endif 247c04438f5SEric Dumazet dev_put_track(dev, &idev->dev_tracker); 2481da177e4SLinus Torvalds if (!idev->dead) 2499f9354b9SEric Dumazet pr_err("Freeing alive in_device %p\n", idev); 2509f9354b9SEric Dumazet else 2511da177e4SLinus Torvalds kfree(idev); 2521da177e4SLinus Torvalds } 2539f9354b9SEric Dumazet EXPORT_SYMBOL(in_dev_finish_destroy); 2541da177e4SLinus Torvalds 25571e27da9SHerbert Xu static struct in_device *inetdev_init(struct net_device *dev) 2561da177e4SLinus Torvalds { 2571da177e4SLinus Torvalds struct in_device *in_dev; 25820e61da7SWANG Cong int err = -ENOMEM; 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds ASSERT_RTNL(); 2611da177e4SLinus Torvalds 2620da974f4SPanagiotis Issaris in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL); 2631da177e4SLinus Torvalds if (!in_dev) 2641da177e4SLinus Torvalds goto out; 265c346dca1SYOSHIFUJI Hideaki memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt, 2669355bbd6SPavel Emelyanov sizeof(in_dev->cnf)); 2671da177e4SLinus Torvalds in_dev->cnf.sysctl = NULL; 2681da177e4SLinus Torvalds in_dev->dev = dev; 2699f9354b9SEric Dumazet in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl); 2709f9354b9SEric Dumazet if (!in_dev->arp_parms) 2711da177e4SLinus Torvalds goto out_kfree; 2720187bdfbSBen Hutchings if (IPV4_DEVCONF(in_dev->cnf, FORWARDING)) 2730187bdfbSBen Hutchings dev_disable_lro(dev); 2741da177e4SLinus Torvalds /* Reference in_dev->dev */ 275c04438f5SEric Dumazet dev_hold_track(dev, &in_dev->dev_tracker, GFP_KERNEL); 27630c4cf57SDavid L Stevens /* Account for reference dev->ip_ptr (below) */ 2777658b36fSReshetova, Elena refcount_set(&in_dev->refcnt, 1); 2781da177e4SLinus Torvalds 27920e61da7SWANG Cong err = devinet_sysctl_register(in_dev); 28020e61da7SWANG Cong if (err) { 28120e61da7SWANG Cong in_dev->dead = 1; 2821b49cd71SYang Yingliang neigh_parms_release(&arp_tbl, in_dev->arp_parms); 28320e61da7SWANG Cong in_dev_put(in_dev); 28420e61da7SWANG Cong in_dev = NULL; 28520e61da7SWANG Cong goto out; 28620e61da7SWANG Cong } 2871da177e4SLinus Torvalds ip_mc_init_dev(in_dev); 2881da177e4SLinus Torvalds if (dev->flags & IFF_UP) 2891da177e4SLinus Torvalds ip_mc_up(in_dev); 290483479ecSJarek Poplawski 29130c4cf57SDavid L Stevens /* we can receive as soon as ip_ptr is set -- do this last */ 292cf778b00SEric Dumazet rcu_assign_pointer(dev->ip_ptr, in_dev); 293483479ecSJarek Poplawski out: 29420e61da7SWANG Cong return in_dev ?: ERR_PTR(err); 2951da177e4SLinus Torvalds out_kfree: 2961da177e4SLinus Torvalds kfree(in_dev); 2971da177e4SLinus Torvalds in_dev = NULL; 2981da177e4SLinus Torvalds goto out; 2991da177e4SLinus Torvalds } 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds static void in_dev_rcu_put(struct rcu_head *head) 3021da177e4SLinus Torvalds { 3031da177e4SLinus Torvalds struct in_device *idev = container_of(head, struct in_device, rcu_head); 3041da177e4SLinus Torvalds in_dev_put(idev); 3051da177e4SLinus Torvalds } 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds static void inetdev_destroy(struct in_device *in_dev) 3081da177e4SLinus Torvalds { 3091da177e4SLinus Torvalds struct net_device *dev; 3102638eb8bSFlorian Westphal struct in_ifaddr *ifa; 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds ASSERT_RTNL(); 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds dev = in_dev->dev; 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds in_dev->dead = 1; 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds ip_mc_destroy_dev(in_dev); 3191da177e4SLinus Torvalds 3202638eb8bSFlorian Westphal while ((ifa = rtnl_dereference(in_dev->ifa_list)) != NULL) { 3211da177e4SLinus Torvalds inet_del_ifa(in_dev, &in_dev->ifa_list, 0); 3221da177e4SLinus Torvalds inet_free_ifa(ifa); 3231da177e4SLinus Torvalds } 3241da177e4SLinus Torvalds 325a9b3cd7fSStephen Hemminger RCU_INIT_POINTER(dev->ip_ptr, NULL); 3261da177e4SLinus Torvalds 32751602b2aSPavel Emelyanov devinet_sysctl_unregister(in_dev); 3281da177e4SLinus Torvalds neigh_parms_release(&arp_tbl, in_dev->arp_parms); 3291da177e4SLinus Torvalds arp_ifdown(dev); 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds call_rcu(&in_dev->rcu_head, in_dev_rcu_put); 3321da177e4SLinus Torvalds } 3331da177e4SLinus Torvalds 334ff428d72SAl Viro int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b) 3351da177e4SLinus Torvalds { 336d519e870SFlorian Westphal const struct in_ifaddr *ifa; 337d519e870SFlorian Westphal 3381da177e4SLinus Torvalds rcu_read_lock(); 339d519e870SFlorian Westphal in_dev_for_each_ifa_rcu(ifa, in_dev) { 3401da177e4SLinus Torvalds if (inet_ifa_match(a, ifa)) { 3411da177e4SLinus Torvalds if (!b || inet_ifa_match(b, ifa)) { 3421da177e4SLinus Torvalds rcu_read_unlock(); 3431da177e4SLinus Torvalds return 1; 3441da177e4SLinus Torvalds } 3451da177e4SLinus Torvalds } 346d519e870SFlorian Westphal } 3471da177e4SLinus Torvalds rcu_read_unlock(); 3481da177e4SLinus Torvalds return 0; 3491da177e4SLinus Torvalds } 3501da177e4SLinus Torvalds 3512638eb8bSFlorian Westphal static void __inet_del_ifa(struct in_device *in_dev, 3522638eb8bSFlorian Westphal struct in_ifaddr __rcu **ifap, 35315e47304SEric W. Biederman int destroy, struct nlmsghdr *nlh, u32 portid) 3541da177e4SLinus Torvalds { 3558f937c60SHarald Welte struct in_ifaddr *promote = NULL; 3562638eb8bSFlorian Westphal struct in_ifaddr *ifa, *ifa1; 3572638eb8bSFlorian Westphal struct in_ifaddr *last_prim; 3580ff60a45SJamal Hadi Salim struct in_ifaddr *prev_prom = NULL; 3590ff60a45SJamal Hadi Salim int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev); 3601da177e4SLinus Torvalds 3611da177e4SLinus Torvalds ASSERT_RTNL(); 3621da177e4SLinus Torvalds 3632638eb8bSFlorian Westphal ifa1 = rtnl_dereference(*ifap); 3642638eb8bSFlorian Westphal last_prim = rtnl_dereference(in_dev->ifa_list); 365fbd40ea0SDavid S. Miller if (in_dev->dead) 366fbd40ea0SDavid S. Miller goto no_promotions; 367fbd40ea0SDavid S. Miller 3688f937c60SHarald Welte /* 1. Deleting primary ifaddr forces deletion all secondaries 3698f937c60SHarald Welte * unless alias promotion is set 3708f937c60SHarald Welte **/ 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) { 3732638eb8bSFlorian Westphal struct in_ifaddr __rcu **ifap1 = &ifa1->ifa_next; 3741da177e4SLinus Torvalds 3752638eb8bSFlorian Westphal while ((ifa = rtnl_dereference(*ifap1)) != NULL) { 3760ff60a45SJamal Hadi Salim if (!(ifa->ifa_flags & IFA_F_SECONDARY) && 3770ff60a45SJamal Hadi Salim ifa1->ifa_scope <= ifa->ifa_scope) 3780ff60a45SJamal Hadi Salim last_prim = ifa; 3790ff60a45SJamal Hadi Salim 3801da177e4SLinus Torvalds if (!(ifa->ifa_flags & IFA_F_SECONDARY) || 3811da177e4SLinus Torvalds ifa1->ifa_mask != ifa->ifa_mask || 3821da177e4SLinus Torvalds !inet_ifa_match(ifa1->ifa_address, ifa)) { 3831da177e4SLinus Torvalds ifap1 = &ifa->ifa_next; 3840ff60a45SJamal Hadi Salim prev_prom = ifa; 3851da177e4SLinus Torvalds continue; 3861da177e4SLinus Torvalds } 3871da177e4SLinus Torvalds 3880ff60a45SJamal Hadi Salim if (!do_promote) { 389fd23c3b3SDavid S. Miller inet_hash_remove(ifa); 3901da177e4SLinus Torvalds *ifap1 = ifa->ifa_next; 3911da177e4SLinus Torvalds 39215e47304SEric W. Biederman rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid); 393e041c683SAlan Stern blocking_notifier_call_chain(&inetaddr_chain, 394e041c683SAlan Stern NETDEV_DOWN, ifa); 3951da177e4SLinus Torvalds inet_free_ifa(ifa); 3968f937c60SHarald Welte } else { 3978f937c60SHarald Welte promote = ifa; 3988f937c60SHarald Welte break; 3998f937c60SHarald Welte } 4001da177e4SLinus Torvalds } 4011da177e4SLinus Torvalds } 4021da177e4SLinus Torvalds 4032d230e2bSJulian Anastasov /* On promotion all secondaries from subnet are changing 4042d230e2bSJulian Anastasov * the primary IP, we must remove all their routes silently 4052d230e2bSJulian Anastasov * and later to add them back with new prefsrc. Do this 4062d230e2bSJulian Anastasov * while all addresses are on the device list. 4072d230e2bSJulian Anastasov */ 4082638eb8bSFlorian Westphal for (ifa = promote; ifa; ifa = rtnl_dereference(ifa->ifa_next)) { 4092d230e2bSJulian Anastasov if (ifa1->ifa_mask == ifa->ifa_mask && 4102d230e2bSJulian Anastasov inet_ifa_match(ifa1->ifa_address, ifa)) 4112d230e2bSJulian Anastasov fib_del_ifaddr(ifa, ifa1); 4122d230e2bSJulian Anastasov } 4132d230e2bSJulian Anastasov 414fbd40ea0SDavid S. Miller no_promotions: 4151da177e4SLinus Torvalds /* 2. Unlink it */ 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds *ifap = ifa1->ifa_next; 418fd23c3b3SDavid S. Miller inet_hash_remove(ifa1); 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds /* 3. Announce address deletion */ 4211da177e4SLinus Torvalds 4221da177e4SLinus Torvalds /* Send message first, then call notifier. 4231da177e4SLinus Torvalds At first sight, FIB update triggered by notifier 4241da177e4SLinus Torvalds will refer to already deleted ifaddr, that could confuse 4251da177e4SLinus Torvalds netlink listeners. It is not true: look, gated sees 4261da177e4SLinus Torvalds that route deleted and if it still thinks that ifaddr 4271da177e4SLinus Torvalds is valid, it will try to restore deleted routes... Grr. 4281da177e4SLinus Torvalds So that, this order is correct. 4291da177e4SLinus Torvalds */ 43015e47304SEric W. Biederman rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid); 431e041c683SAlan Stern blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); 4320ff60a45SJamal Hadi Salim 4330ff60a45SJamal Hadi Salim if (promote) { 4342638eb8bSFlorian Westphal struct in_ifaddr *next_sec; 4350ff60a45SJamal Hadi Salim 4362638eb8bSFlorian Westphal next_sec = rtnl_dereference(promote->ifa_next); 4370ff60a45SJamal Hadi Salim if (prev_prom) { 4382638eb8bSFlorian Westphal struct in_ifaddr *last_sec; 4392638eb8bSFlorian Westphal 4402638eb8bSFlorian Westphal rcu_assign_pointer(prev_prom->ifa_next, next_sec); 4416a9e9ceaSFlorian Westphal 4426a9e9ceaSFlorian Westphal last_sec = rtnl_dereference(last_prim->ifa_next); 4432638eb8bSFlorian Westphal rcu_assign_pointer(promote->ifa_next, last_sec); 4442638eb8bSFlorian Westphal rcu_assign_pointer(last_prim->ifa_next, promote); 4450ff60a45SJamal Hadi Salim } 4460ff60a45SJamal Hadi Salim 4470ff60a45SJamal Hadi Salim promote->ifa_flags &= ~IFA_F_SECONDARY; 44815e47304SEric W. Biederman rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid); 449e041c683SAlan Stern blocking_notifier_call_chain(&inetaddr_chain, 450e041c683SAlan Stern NETDEV_UP, promote); 4512638eb8bSFlorian Westphal for (ifa = next_sec; ifa; 4522638eb8bSFlorian Westphal ifa = rtnl_dereference(ifa->ifa_next)) { 4530ff60a45SJamal Hadi Salim if (ifa1->ifa_mask != ifa->ifa_mask || 4540ff60a45SJamal Hadi Salim !inet_ifa_match(ifa1->ifa_address, ifa)) 4550ff60a45SJamal Hadi Salim continue; 4560ff60a45SJamal Hadi Salim fib_add_ifaddr(ifa); 4570ff60a45SJamal Hadi Salim } 4580ff60a45SJamal Hadi Salim 4590ff60a45SJamal Hadi Salim } 4606363097cSHerbert Xu if (destroy) 4611da177e4SLinus Torvalds inet_free_ifa(ifa1); 4621da177e4SLinus Torvalds } 4631da177e4SLinus Torvalds 4642638eb8bSFlorian Westphal static void inet_del_ifa(struct in_device *in_dev, 4652638eb8bSFlorian Westphal struct in_ifaddr __rcu **ifap, 466d6062cbbSThomas Graf int destroy) 467d6062cbbSThomas Graf { 468d6062cbbSThomas Graf __inet_del_ifa(in_dev, ifap, destroy, NULL, 0); 469d6062cbbSThomas Graf } 470d6062cbbSThomas Graf 4715c766d64SJiri Pirko static void check_lifetime(struct work_struct *work); 4725c766d64SJiri Pirko 4735c766d64SJiri Pirko static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime); 4745c766d64SJiri Pirko 475d6062cbbSThomas Graf static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, 476de95e047SDavid Ahern u32 portid, struct netlink_ext_ack *extack) 4771da177e4SLinus Torvalds { 4782638eb8bSFlorian Westphal struct in_ifaddr __rcu **last_primary, **ifap; 4791da177e4SLinus Torvalds struct in_device *in_dev = ifa->ifa_dev; 4803ad7d246SKrister Johansen struct in_validator_info ivi; 4812638eb8bSFlorian Westphal struct in_ifaddr *ifa1; 4823ad7d246SKrister Johansen int ret; 4831da177e4SLinus Torvalds 4841da177e4SLinus Torvalds ASSERT_RTNL(); 4851da177e4SLinus Torvalds 4861da177e4SLinus Torvalds if (!ifa->ifa_local) { 4871da177e4SLinus Torvalds inet_free_ifa(ifa); 4881da177e4SLinus Torvalds return 0; 4891da177e4SLinus Torvalds } 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds ifa->ifa_flags &= ~IFA_F_SECONDARY; 4921da177e4SLinus Torvalds last_primary = &in_dev->ifa_list; 4931da177e4SLinus Torvalds 4942e605463SMatteo Croce /* Don't set IPv6 only flags to IPv4 addresses */ 4952e605463SMatteo Croce ifa->ifa_flags &= ~IPV6ONLY_FLAGS; 4962e605463SMatteo Croce 4972638eb8bSFlorian Westphal ifap = &in_dev->ifa_list; 4982638eb8bSFlorian Westphal ifa1 = rtnl_dereference(*ifap); 4992638eb8bSFlorian Westphal 5002638eb8bSFlorian Westphal while (ifa1) { 5011da177e4SLinus Torvalds if (!(ifa1->ifa_flags & IFA_F_SECONDARY) && 5021da177e4SLinus Torvalds ifa->ifa_scope <= ifa1->ifa_scope) 5031da177e4SLinus Torvalds last_primary = &ifa1->ifa_next; 5041da177e4SLinus Torvalds if (ifa1->ifa_mask == ifa->ifa_mask && 5051da177e4SLinus Torvalds inet_ifa_match(ifa1->ifa_address, ifa)) { 5061da177e4SLinus Torvalds if (ifa1->ifa_local == ifa->ifa_local) { 5071da177e4SLinus Torvalds inet_free_ifa(ifa); 5081da177e4SLinus Torvalds return -EEXIST; 5091da177e4SLinus Torvalds } 5101da177e4SLinus Torvalds if (ifa1->ifa_scope != ifa->ifa_scope) { 5111da177e4SLinus Torvalds inet_free_ifa(ifa); 5121da177e4SLinus Torvalds return -EINVAL; 5131da177e4SLinus Torvalds } 5141da177e4SLinus Torvalds ifa->ifa_flags |= IFA_F_SECONDARY; 5151da177e4SLinus Torvalds } 5162638eb8bSFlorian Westphal 5172638eb8bSFlorian Westphal ifap = &ifa1->ifa_next; 5182638eb8bSFlorian Westphal ifa1 = rtnl_dereference(*ifap); 5191da177e4SLinus Torvalds } 5201da177e4SLinus Torvalds 5213ad7d246SKrister Johansen /* Allow any devices that wish to register ifaddr validtors to weigh 5223ad7d246SKrister Johansen * in now, before changes are committed. The rntl lock is serializing 5233ad7d246SKrister Johansen * access here, so the state should not change between a validator call 5243ad7d246SKrister Johansen * and a final notify on commit. This isn't invoked on promotion under 5253ad7d246SKrister Johansen * the assumption that validators are checking the address itself, and 5263ad7d246SKrister Johansen * not the flags. 5273ad7d246SKrister Johansen */ 5283ad7d246SKrister Johansen ivi.ivi_addr = ifa->ifa_address; 5293ad7d246SKrister Johansen ivi.ivi_dev = ifa->ifa_dev; 530de95e047SDavid Ahern ivi.extack = extack; 5313ad7d246SKrister Johansen ret = blocking_notifier_call_chain(&inetaddr_validator_chain, 5323ad7d246SKrister Johansen NETDEV_UP, &ivi); 5333ad7d246SKrister Johansen ret = notifier_to_errno(ret); 5343ad7d246SKrister Johansen if (ret) { 5353ad7d246SKrister Johansen inet_free_ifa(ifa); 5363ad7d246SKrister Johansen return ret; 5373ad7d246SKrister Johansen } 5383ad7d246SKrister Johansen 539*d4150779SJason A. Donenfeld if (!(ifa->ifa_flags & IFA_F_SECONDARY)) 5401da177e4SLinus Torvalds ifap = last_primary; 5411da177e4SLinus Torvalds 5422638eb8bSFlorian Westphal rcu_assign_pointer(ifa->ifa_next, *ifap); 5432638eb8bSFlorian Westphal rcu_assign_pointer(*ifap, ifa); 5441da177e4SLinus Torvalds 545fd23c3b3SDavid S. Miller inet_hash_insert(dev_net(in_dev->dev), ifa); 546fd23c3b3SDavid S. Miller 5475c766d64SJiri Pirko cancel_delayed_work(&check_lifetime_work); 548906e073fSviresh kumar queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0); 5495c766d64SJiri Pirko 5501da177e4SLinus Torvalds /* Send message first, then call notifier. 5511da177e4SLinus Torvalds Notifier will trigger FIB update, so that 5521da177e4SLinus Torvalds listeners of netlink will know about new ifaddr */ 55315e47304SEric W. Biederman rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid); 554e041c683SAlan Stern blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); 5551da177e4SLinus Torvalds 5561da177e4SLinus Torvalds return 0; 5571da177e4SLinus Torvalds } 5581da177e4SLinus Torvalds 559d6062cbbSThomas Graf static int inet_insert_ifa(struct in_ifaddr *ifa) 560d6062cbbSThomas Graf { 561de95e047SDavid Ahern return __inet_insert_ifa(ifa, NULL, 0, NULL); 562d6062cbbSThomas Graf } 563d6062cbbSThomas Graf 5641da177e4SLinus Torvalds static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa) 5651da177e4SLinus Torvalds { 566e5ed6399SHerbert Xu struct in_device *in_dev = __in_dev_get_rtnl(dev); 5671da177e4SLinus Torvalds 5681da177e4SLinus Torvalds ASSERT_RTNL(); 5691da177e4SLinus Torvalds 5701da177e4SLinus Torvalds if (!in_dev) { 5711da177e4SLinus Torvalds inet_free_ifa(ifa); 5721da177e4SLinus Torvalds return -ENOBUFS; 5731da177e4SLinus Torvalds } 57471e27da9SHerbert Xu ipv4_devconf_setall(in_dev); 5751d4c8c29SJiri Pirko neigh_parms_data_state_setall(in_dev->arp_parms); 5761da177e4SLinus Torvalds if (ifa->ifa_dev != in_dev) { 577547b792cSIlpo Järvinen WARN_ON(ifa->ifa_dev); 5781da177e4SLinus Torvalds in_dev_hold(in_dev); 5791da177e4SLinus Torvalds ifa->ifa_dev = in_dev; 5801da177e4SLinus Torvalds } 581f97c1e0cSJoe Perches if (ipv4_is_loopback(ifa->ifa_local)) 5821da177e4SLinus Torvalds ifa->ifa_scope = RT_SCOPE_HOST; 5831da177e4SLinus Torvalds return inet_insert_ifa(ifa); 5841da177e4SLinus Torvalds } 5851da177e4SLinus Torvalds 5868723e1b4SEric Dumazet /* Caller must hold RCU or RTNL : 5878723e1b4SEric Dumazet * We dont take a reference on found in_device 5888723e1b4SEric Dumazet */ 5897fee0ca2SDenis V. Lunev struct in_device *inetdev_by_index(struct net *net, int ifindex) 5901da177e4SLinus Torvalds { 5911da177e4SLinus Torvalds struct net_device *dev; 5921da177e4SLinus Torvalds struct in_device *in_dev = NULL; 593c148fc2eSEric Dumazet 594c148fc2eSEric Dumazet rcu_read_lock(); 595c148fc2eSEric Dumazet dev = dev_get_by_index_rcu(net, ifindex); 5961da177e4SLinus Torvalds if (dev) 5978723e1b4SEric Dumazet in_dev = rcu_dereference_rtnl(dev->ip_ptr); 598c148fc2eSEric Dumazet rcu_read_unlock(); 5991da177e4SLinus Torvalds return in_dev; 6001da177e4SLinus Torvalds } 6019f9354b9SEric Dumazet EXPORT_SYMBOL(inetdev_by_index); 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds /* Called only from RTNL semaphored context. No locks. */ 6041da177e4SLinus Torvalds 60560cad5daSAl Viro struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, 60660cad5daSAl Viro __be32 mask) 6071da177e4SLinus Torvalds { 608d519e870SFlorian Westphal struct in_ifaddr *ifa; 609d519e870SFlorian Westphal 6101da177e4SLinus Torvalds ASSERT_RTNL(); 6111da177e4SLinus Torvalds 612d519e870SFlorian Westphal in_dev_for_each_ifa_rtnl(ifa, in_dev) { 6131da177e4SLinus Torvalds if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa)) 6141da177e4SLinus Torvalds return ifa; 615d519e870SFlorian Westphal } 6161da177e4SLinus Torvalds return NULL; 6171da177e4SLinus Torvalds } 6181da177e4SLinus Torvalds 619690cc863STaras Chornyi static int ip_mc_autojoin_config(struct net *net, bool join, 620690cc863STaras Chornyi const struct in_ifaddr *ifa) 62193a714d6SMadhu Challa { 622690cc863STaras Chornyi #if defined(CONFIG_IP_MULTICAST) 62393a714d6SMadhu Challa struct ip_mreqn mreq = { 62493a714d6SMadhu Challa .imr_multiaddr.s_addr = ifa->ifa_address, 62593a714d6SMadhu Challa .imr_ifindex = ifa->ifa_dev->dev->ifindex, 62693a714d6SMadhu Challa }; 627690cc863STaras Chornyi struct sock *sk = net->ipv4.mc_autojoin_sk; 62893a714d6SMadhu Challa int ret; 62993a714d6SMadhu Challa 63093a714d6SMadhu Challa ASSERT_RTNL(); 63193a714d6SMadhu Challa 63293a714d6SMadhu Challa lock_sock(sk); 63393a714d6SMadhu Challa if (join) 63454ff9ef3SMarcelo Ricardo Leitner ret = ip_mc_join_group(sk, &mreq); 63593a714d6SMadhu Challa else 63654ff9ef3SMarcelo Ricardo Leitner ret = ip_mc_leave_group(sk, &mreq); 63793a714d6SMadhu Challa release_sock(sk); 63893a714d6SMadhu Challa 63993a714d6SMadhu Challa return ret; 640690cc863STaras Chornyi #else 641690cc863STaras Chornyi return -EOPNOTSUPP; 642690cc863STaras Chornyi #endif 64393a714d6SMadhu Challa } 64493a714d6SMadhu Challa 645c21ef3e3SDavid Ahern static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, 646c21ef3e3SDavid Ahern struct netlink_ext_ack *extack) 6471da177e4SLinus Torvalds { 6483b1e0a65SYOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 6492638eb8bSFlorian Westphal struct in_ifaddr __rcu **ifap; 650dfdd5fd4SThomas Graf struct nlattr *tb[IFA_MAX+1]; 6511da177e4SLinus Torvalds struct in_device *in_dev; 652dfdd5fd4SThomas Graf struct ifaddrmsg *ifm; 6532638eb8bSFlorian Westphal struct in_ifaddr *ifa; 65430e2379eSMenglong Dong int err; 6551da177e4SLinus Torvalds 6561da177e4SLinus Torvalds ASSERT_RTNL(); 6571da177e4SLinus Torvalds 6588cb08174SJohannes Berg err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX, 6598cb08174SJohannes Berg ifa_ipv4_policy, extack); 660dfdd5fd4SThomas Graf if (err < 0) 661dfdd5fd4SThomas Graf goto errout; 662dfdd5fd4SThomas Graf 663dfdd5fd4SThomas Graf ifm = nlmsg_data(nlh); 6647fee0ca2SDenis V. Lunev in_dev = inetdev_by_index(net, ifm->ifa_index); 66551456b29SIan Morris if (!in_dev) { 666dfdd5fd4SThomas Graf err = -ENODEV; 667dfdd5fd4SThomas Graf goto errout; 668dfdd5fd4SThomas Graf } 669dfdd5fd4SThomas Graf 6702638eb8bSFlorian Westphal for (ifap = &in_dev->ifa_list; (ifa = rtnl_dereference(*ifap)) != NULL; 6711da177e4SLinus Torvalds ifap = &ifa->ifa_next) { 672dfdd5fd4SThomas Graf if (tb[IFA_LOCAL] && 67367b61f6cSJiri Benc ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL])) 6741da177e4SLinus Torvalds continue; 675dfdd5fd4SThomas Graf 676dfdd5fd4SThomas Graf if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label)) 677dfdd5fd4SThomas Graf continue; 678dfdd5fd4SThomas Graf 679dfdd5fd4SThomas Graf if (tb[IFA_ADDRESS] && 680dfdd5fd4SThomas Graf (ifm->ifa_prefixlen != ifa->ifa_prefixlen || 68167b61f6cSJiri Benc !inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa))) 682dfdd5fd4SThomas Graf continue; 683dfdd5fd4SThomas Graf 68493a714d6SMadhu Challa if (ipv4_is_multicast(ifa->ifa_address)) 685690cc863STaras Chornyi ip_mc_autojoin_config(net, false, ifa); 68615e47304SEric W. Biederman __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid); 6871da177e4SLinus Torvalds return 0; 6881da177e4SLinus Torvalds } 689dfdd5fd4SThomas Graf 690dfdd5fd4SThomas Graf err = -EADDRNOTAVAIL; 691dfdd5fd4SThomas Graf errout: 692dfdd5fd4SThomas Graf return err; 6931da177e4SLinus Torvalds } 6941da177e4SLinus Torvalds 6955c766d64SJiri Pirko #define INFINITY_LIFE_TIME 0xFFFFFFFF 6965c766d64SJiri Pirko 6975c766d64SJiri Pirko static void check_lifetime(struct work_struct *work) 6985c766d64SJiri Pirko { 6995c766d64SJiri Pirko unsigned long now, next, next_sec, next_sched; 7005c766d64SJiri Pirko struct in_ifaddr *ifa; 701c988d1e8SJiri Pirko struct hlist_node *n; 7025c766d64SJiri Pirko int i; 7035c766d64SJiri Pirko 7045c766d64SJiri Pirko now = jiffies; 7055c766d64SJiri Pirko next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY); 7065c766d64SJiri Pirko 7075c766d64SJiri Pirko for (i = 0; i < IN4_ADDR_HSIZE; i++) { 708c988d1e8SJiri Pirko bool change_needed = false; 709c988d1e8SJiri Pirko 710c988d1e8SJiri Pirko rcu_read_lock(); 711b67bfe0dSSasha Levin hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) { 7125c766d64SJiri Pirko unsigned long age; 7135c766d64SJiri Pirko 7145c766d64SJiri Pirko if (ifa->ifa_flags & IFA_F_PERMANENT) 7155c766d64SJiri Pirko continue; 7165c766d64SJiri Pirko 7175c766d64SJiri Pirko /* We try to batch several events at once. */ 7185c766d64SJiri Pirko age = (now - ifa->ifa_tstamp + 7195c766d64SJiri Pirko ADDRCONF_TIMER_FUZZ_MINUS) / HZ; 7205c766d64SJiri Pirko 7215c766d64SJiri Pirko if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME && 7225c766d64SJiri Pirko age >= ifa->ifa_valid_lft) { 723c988d1e8SJiri Pirko change_needed = true; 724c988d1e8SJiri Pirko } else if (ifa->ifa_preferred_lft == 725c988d1e8SJiri Pirko INFINITY_LIFE_TIME) { 726c988d1e8SJiri Pirko continue; 727c988d1e8SJiri Pirko } else if (age >= ifa->ifa_preferred_lft) { 728c988d1e8SJiri Pirko if (time_before(ifa->ifa_tstamp + 729c988d1e8SJiri Pirko ifa->ifa_valid_lft * HZ, next)) 730c988d1e8SJiri Pirko next = ifa->ifa_tstamp + 731c988d1e8SJiri Pirko ifa->ifa_valid_lft * HZ; 732c988d1e8SJiri Pirko 733c988d1e8SJiri Pirko if (!(ifa->ifa_flags & IFA_F_DEPRECATED)) 734c988d1e8SJiri Pirko change_needed = true; 735c988d1e8SJiri Pirko } else if (time_before(ifa->ifa_tstamp + 736c988d1e8SJiri Pirko ifa->ifa_preferred_lft * HZ, 737c988d1e8SJiri Pirko next)) { 738c988d1e8SJiri Pirko next = ifa->ifa_tstamp + 739c988d1e8SJiri Pirko ifa->ifa_preferred_lft * HZ; 740c988d1e8SJiri Pirko } 741c988d1e8SJiri Pirko } 742c988d1e8SJiri Pirko rcu_read_unlock(); 743c988d1e8SJiri Pirko if (!change_needed) 744c988d1e8SJiri Pirko continue; 745c988d1e8SJiri Pirko rtnl_lock(); 746c988d1e8SJiri Pirko hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) { 747c988d1e8SJiri Pirko unsigned long age; 748c988d1e8SJiri Pirko 749c988d1e8SJiri Pirko if (ifa->ifa_flags & IFA_F_PERMANENT) 750c988d1e8SJiri Pirko continue; 751c988d1e8SJiri Pirko 752c988d1e8SJiri Pirko /* We try to batch several events at once. */ 753c988d1e8SJiri Pirko age = (now - ifa->ifa_tstamp + 754c988d1e8SJiri Pirko ADDRCONF_TIMER_FUZZ_MINUS) / HZ; 755c988d1e8SJiri Pirko 756c988d1e8SJiri Pirko if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME && 757c988d1e8SJiri Pirko age >= ifa->ifa_valid_lft) { 7582638eb8bSFlorian Westphal struct in_ifaddr __rcu **ifap; 7592638eb8bSFlorian Westphal struct in_ifaddr *tmp; 7605c766d64SJiri Pirko 7612638eb8bSFlorian Westphal ifap = &ifa->ifa_dev->ifa_list; 7622638eb8bSFlorian Westphal tmp = rtnl_dereference(*ifap); 7632638eb8bSFlorian Westphal while (tmp) { 76440008e92SFlorian Westphal if (tmp == ifa) { 7655c766d64SJiri Pirko inet_del_ifa(ifa->ifa_dev, 7665c766d64SJiri Pirko ifap, 1); 767c988d1e8SJiri Pirko break; 7685c766d64SJiri Pirko } 7692638eb8bSFlorian Westphal ifap = &tmp->ifa_next; 7702638eb8bSFlorian Westphal tmp = rtnl_dereference(*ifap); 771c988d1e8SJiri Pirko } 772c988d1e8SJiri Pirko } else if (ifa->ifa_preferred_lft != 773c988d1e8SJiri Pirko INFINITY_LIFE_TIME && 774c988d1e8SJiri Pirko age >= ifa->ifa_preferred_lft && 775c988d1e8SJiri Pirko !(ifa->ifa_flags & IFA_F_DEPRECATED)) { 7765c766d64SJiri Pirko ifa->ifa_flags |= IFA_F_DEPRECATED; 7775c766d64SJiri Pirko rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0); 7785c766d64SJiri Pirko } 7795c766d64SJiri Pirko } 780c988d1e8SJiri Pirko rtnl_unlock(); 7815c766d64SJiri Pirko } 7825c766d64SJiri Pirko 7835c766d64SJiri Pirko next_sec = round_jiffies_up(next); 7845c766d64SJiri Pirko next_sched = next; 7855c766d64SJiri Pirko 7865c766d64SJiri Pirko /* If rounded timeout is accurate enough, accept it. */ 7875c766d64SJiri Pirko if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ)) 7885c766d64SJiri Pirko next_sched = next_sec; 7895c766d64SJiri Pirko 7905c766d64SJiri Pirko now = jiffies; 7915c766d64SJiri Pirko /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */ 7925c766d64SJiri Pirko if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX)) 7935c766d64SJiri Pirko next_sched = now + ADDRCONF_TIMER_FUZZ_MAX; 7945c766d64SJiri Pirko 795906e073fSviresh kumar queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 796906e073fSviresh kumar next_sched - now); 7975c766d64SJiri Pirko } 7985c766d64SJiri Pirko 7995c766d64SJiri Pirko static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft, 8005c766d64SJiri Pirko __u32 prefered_lft) 8015c766d64SJiri Pirko { 8025c766d64SJiri Pirko unsigned long timeout; 8035c766d64SJiri Pirko 8045c766d64SJiri Pirko ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED); 8055c766d64SJiri Pirko 8065c766d64SJiri Pirko timeout = addrconf_timeout_fixup(valid_lft, HZ); 8075c766d64SJiri Pirko if (addrconf_finite_timeout(timeout)) 8085c766d64SJiri Pirko ifa->ifa_valid_lft = timeout; 8095c766d64SJiri Pirko else 8105c766d64SJiri Pirko ifa->ifa_flags |= IFA_F_PERMANENT; 8115c766d64SJiri Pirko 8125c766d64SJiri Pirko timeout = addrconf_timeout_fixup(prefered_lft, HZ); 8135c766d64SJiri Pirko if (addrconf_finite_timeout(timeout)) { 8145c766d64SJiri Pirko if (timeout == 0) 8155c766d64SJiri Pirko ifa->ifa_flags |= IFA_F_DEPRECATED; 8165c766d64SJiri Pirko ifa->ifa_preferred_lft = timeout; 8175c766d64SJiri Pirko } 8185c766d64SJiri Pirko ifa->ifa_tstamp = jiffies; 8195c766d64SJiri Pirko if (!ifa->ifa_cstamp) 8205c766d64SJiri Pirko ifa->ifa_cstamp = ifa->ifa_tstamp; 8215c766d64SJiri Pirko } 8225c766d64SJiri Pirko 8235c766d64SJiri Pirko static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, 824dac9c979SDavid Ahern __u32 *pvalid_lft, __u32 *pprefered_lft, 825dac9c979SDavid Ahern struct netlink_ext_ack *extack) 8261da177e4SLinus Torvalds { 8275c753978SThomas Graf struct nlattr *tb[IFA_MAX+1]; 8285c753978SThomas Graf struct in_ifaddr *ifa; 8295c753978SThomas Graf struct ifaddrmsg *ifm; 8301da177e4SLinus Torvalds struct net_device *dev; 8311da177e4SLinus Torvalds struct in_device *in_dev; 8327b218574SDenis V. Lunev int err; 8331da177e4SLinus Torvalds 8348cb08174SJohannes Berg err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX, 8358cb08174SJohannes Berg ifa_ipv4_policy, extack); 8365c753978SThomas Graf if (err < 0) 8375c753978SThomas Graf goto errout; 8381da177e4SLinus Torvalds 8395c753978SThomas Graf ifm = nlmsg_data(nlh); 840c4e38f41SEvgeniy Polyakov err = -EINVAL; 84151456b29SIan Morris if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL]) 8425c753978SThomas Graf goto errout; 8431da177e4SLinus Torvalds 8444b8aa9abSDenis V. Lunev dev = __dev_get_by_index(net, ifm->ifa_index); 8455c753978SThomas Graf err = -ENODEV; 84651456b29SIan Morris if (!dev) 8475c753978SThomas Graf goto errout; 8481da177e4SLinus Torvalds 8495c753978SThomas Graf in_dev = __in_dev_get_rtnl(dev); 8505c753978SThomas Graf err = -ENOBUFS; 85151456b29SIan Morris if (!in_dev) 8525c753978SThomas Graf goto errout; 85371e27da9SHerbert Xu 8545c753978SThomas Graf ifa = inet_alloc_ifa(); 85551456b29SIan Morris if (!ifa) 8565c753978SThomas Graf /* 8575c753978SThomas Graf * A potential indev allocation can be left alive, it stays 8585c753978SThomas Graf * assigned to its device and is destroy with it. 8595c753978SThomas Graf */ 8605c753978SThomas Graf goto errout; 8615c753978SThomas Graf 862a4e65d36SPavel Emelyanov ipv4_devconf_setall(in_dev); 8631d4c8c29SJiri Pirko neigh_parms_data_state_setall(in_dev->arp_parms); 8645c753978SThomas Graf in_dev_hold(in_dev); 8655c753978SThomas Graf 86651456b29SIan Morris if (!tb[IFA_ADDRESS]) 8675c753978SThomas Graf tb[IFA_ADDRESS] = tb[IFA_LOCAL]; 8685c753978SThomas Graf 869fd23c3b3SDavid S. Miller INIT_HLIST_NODE(&ifa->hash); 8701da177e4SLinus Torvalds ifa->ifa_prefixlen = ifm->ifa_prefixlen; 8711da177e4SLinus Torvalds ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen); 872ad6c8135SJiri Pirko ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : 873ad6c8135SJiri Pirko ifm->ifa_flags; 8741da177e4SLinus Torvalds ifa->ifa_scope = ifm->ifa_scope; 8751da177e4SLinus Torvalds ifa->ifa_dev = in_dev; 8765c753978SThomas Graf 87767b61f6cSJiri Benc ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]); 87867b61f6cSJiri Benc ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]); 8795c753978SThomas Graf 8805c753978SThomas Graf if (tb[IFA_BROADCAST]) 88167b61f6cSJiri Benc ifa->ifa_broadcast = nla_get_in_addr(tb[IFA_BROADCAST]); 8825c753978SThomas Graf 8835c753978SThomas Graf if (tb[IFA_LABEL]) 884872f6903SFrancis Laniel nla_strscpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ); 8851da177e4SLinus Torvalds else 8861da177e4SLinus Torvalds memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); 8871da177e4SLinus Torvalds 888af4d768aSDavid Ahern if (tb[IFA_RT_PRIORITY]) 889af4d768aSDavid Ahern ifa->ifa_rt_priority = nla_get_u32(tb[IFA_RT_PRIORITY]); 890af4d768aSDavid Ahern 89147f0bd50SJacques de Laval if (tb[IFA_PROTO]) 89247f0bd50SJacques de Laval ifa->ifa_proto = nla_get_u8(tb[IFA_PROTO]); 89347f0bd50SJacques de Laval 8945c766d64SJiri Pirko if (tb[IFA_CACHEINFO]) { 8955c766d64SJiri Pirko struct ifa_cacheinfo *ci; 8965c766d64SJiri Pirko 8975c766d64SJiri Pirko ci = nla_data(tb[IFA_CACHEINFO]); 8985c766d64SJiri Pirko if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) { 8995c766d64SJiri Pirko err = -EINVAL; 900446266b0SDaniel Borkmann goto errout_free; 9015c766d64SJiri Pirko } 9025c766d64SJiri Pirko *pvalid_lft = ci->ifa_valid; 9035c766d64SJiri Pirko *pprefered_lft = ci->ifa_prefered; 9045c766d64SJiri Pirko } 9055c766d64SJiri Pirko 9065c753978SThomas Graf return ifa; 9075c753978SThomas Graf 908446266b0SDaniel Borkmann errout_free: 909446266b0SDaniel Borkmann inet_free_ifa(ifa); 9105c753978SThomas Graf errout: 9115c753978SThomas Graf return ERR_PTR(err); 9125c753978SThomas Graf } 9135c753978SThomas Graf 9145c766d64SJiri Pirko static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa) 9155c766d64SJiri Pirko { 9165c766d64SJiri Pirko struct in_device *in_dev = ifa->ifa_dev; 917ef11db33SFlorian Westphal struct in_ifaddr *ifa1; 9185c766d64SJiri Pirko 9195c766d64SJiri Pirko if (!ifa->ifa_local) 9205c766d64SJiri Pirko return NULL; 9215c766d64SJiri Pirko 922ef11db33SFlorian Westphal in_dev_for_each_ifa_rtnl(ifa1, in_dev) { 9235c766d64SJiri Pirko if (ifa1->ifa_mask == ifa->ifa_mask && 9245c766d64SJiri Pirko inet_ifa_match(ifa1->ifa_address, ifa) && 9255c766d64SJiri Pirko ifa1->ifa_local == ifa->ifa_local) 9265c766d64SJiri Pirko return ifa1; 9275c766d64SJiri Pirko } 9285c766d64SJiri Pirko return NULL; 9295c766d64SJiri Pirko } 9305c766d64SJiri Pirko 931c21ef3e3SDavid Ahern static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, 932c21ef3e3SDavid Ahern struct netlink_ext_ack *extack) 9335c753978SThomas Graf { 9343b1e0a65SYOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 9355c753978SThomas Graf struct in_ifaddr *ifa; 9365c766d64SJiri Pirko struct in_ifaddr *ifa_existing; 9375c766d64SJiri Pirko __u32 valid_lft = INFINITY_LIFE_TIME; 9385c766d64SJiri Pirko __u32 prefered_lft = INFINITY_LIFE_TIME; 9395c753978SThomas Graf 9405c753978SThomas Graf ASSERT_RTNL(); 9415c753978SThomas Graf 942dac9c979SDavid Ahern ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft, extack); 9435c753978SThomas Graf if (IS_ERR(ifa)) 9445c753978SThomas Graf return PTR_ERR(ifa); 9455c753978SThomas Graf 9465c766d64SJiri Pirko ifa_existing = find_matching_ifa(ifa); 9475c766d64SJiri Pirko if (!ifa_existing) { 9485c766d64SJiri Pirko /* It would be best to check for !NLM_F_CREATE here but 949614d056cSstephen hemminger * userspace already relies on not having to provide this. 9505c766d64SJiri Pirko */ 9515c766d64SJiri Pirko set_ifa_lifetime(ifa, valid_lft, prefered_lft); 95293a714d6SMadhu Challa if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) { 953690cc863STaras Chornyi int ret = ip_mc_autojoin_config(net, true, ifa); 95493a714d6SMadhu Challa 95593a714d6SMadhu Challa if (ret < 0) { 95693a714d6SMadhu Challa inet_free_ifa(ifa); 95793a714d6SMadhu Challa return ret; 95893a714d6SMadhu Challa } 95993a714d6SMadhu Challa } 960de95e047SDavid Ahern return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid, 961de95e047SDavid Ahern extack); 9625c766d64SJiri Pirko } else { 963af4d768aSDavid Ahern u32 new_metric = ifa->ifa_rt_priority; 964af4d768aSDavid Ahern 9655c766d64SJiri Pirko inet_free_ifa(ifa); 9665c766d64SJiri Pirko 9675c766d64SJiri Pirko if (nlh->nlmsg_flags & NLM_F_EXCL || 9685c766d64SJiri Pirko !(nlh->nlmsg_flags & NLM_F_REPLACE)) 9695c766d64SJiri Pirko return -EEXIST; 97034e2ed34SJiri Pirko ifa = ifa_existing; 971af4d768aSDavid Ahern 972af4d768aSDavid Ahern if (ifa->ifa_rt_priority != new_metric) { 973af4d768aSDavid Ahern fib_modify_prefix_metric(ifa, new_metric); 974af4d768aSDavid Ahern ifa->ifa_rt_priority = new_metric; 975af4d768aSDavid Ahern } 976af4d768aSDavid Ahern 97734e2ed34SJiri Pirko set_ifa_lifetime(ifa, valid_lft, prefered_lft); 97805a324b9SJiri Pirko cancel_delayed_work(&check_lifetime_work); 979906e073fSviresh kumar queue_delayed_work(system_power_efficient_wq, 980906e073fSviresh kumar &check_lifetime_work, 0); 98134e2ed34SJiri Pirko rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid); 9825c766d64SJiri Pirko } 9835c766d64SJiri Pirko return 0; 9841da177e4SLinus Torvalds } 9851da177e4SLinus Torvalds 9861da177e4SLinus Torvalds /* 9871da177e4SLinus Torvalds * Determine a default network mask, based on the IP address. 9881da177e4SLinus Torvalds */ 9891da177e4SLinus Torvalds 99040384999SEric Dumazet static int inet_abc_len(__be32 addr) 9911da177e4SLinus Torvalds { 9921da177e4SLinus Torvalds int rc = -1; /* Something else, probably a multicast. */ 9931da177e4SLinus Torvalds 99465cab850SDave Taht if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr)) 9951da177e4SLinus Torvalds rc = 0; 9961da177e4SLinus Torvalds else { 997714e85beSAl Viro __u32 haddr = ntohl(addr); 998714e85beSAl Viro if (IN_CLASSA(haddr)) 9991da177e4SLinus Torvalds rc = 8; 1000714e85beSAl Viro else if (IN_CLASSB(haddr)) 10011da177e4SLinus Torvalds rc = 16; 1002714e85beSAl Viro else if (IN_CLASSC(haddr)) 10031da177e4SLinus Torvalds rc = 24; 100465cab850SDave Taht else if (IN_CLASSE(haddr)) 100565cab850SDave Taht rc = 32; 10061da177e4SLinus Torvalds } 10071da177e4SLinus Torvalds 10081da177e4SLinus Torvalds return rc; 10091da177e4SLinus Torvalds } 10101da177e4SLinus Torvalds 10111da177e4SLinus Torvalds 101203aef17bSAl Viro int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr) 10131da177e4SLinus Torvalds { 10141da177e4SLinus Torvalds struct sockaddr_in sin_orig; 101503aef17bSAl Viro struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr; 10162638eb8bSFlorian Westphal struct in_ifaddr __rcu **ifap = NULL; 10171da177e4SLinus Torvalds struct in_device *in_dev; 10181da177e4SLinus Torvalds struct in_ifaddr *ifa = NULL; 10191da177e4SLinus Torvalds struct net_device *dev; 10201da177e4SLinus Torvalds char *colon; 10211da177e4SLinus Torvalds int ret = -EFAULT; 10221da177e4SLinus Torvalds int tryaddrmatch = 0; 10231da177e4SLinus Torvalds 102403aef17bSAl Viro ifr->ifr_name[IFNAMSIZ - 1] = 0; 10251da177e4SLinus Torvalds 10261da177e4SLinus Torvalds /* save original address for comparison */ 10271da177e4SLinus Torvalds memcpy(&sin_orig, sin, sizeof(*sin)); 10281da177e4SLinus Torvalds 102903aef17bSAl Viro colon = strchr(ifr->ifr_name, ':'); 10301da177e4SLinus Torvalds if (colon) 10311da177e4SLinus Torvalds *colon = 0; 10321da177e4SLinus Torvalds 103303aef17bSAl Viro dev_load(net, ifr->ifr_name); 10341da177e4SLinus Torvalds 10351da177e4SLinus Torvalds switch (cmd) { 10361da177e4SLinus Torvalds case SIOCGIFADDR: /* Get interface address */ 10371da177e4SLinus Torvalds case SIOCGIFBRDADDR: /* Get the broadcast address */ 10381da177e4SLinus Torvalds case SIOCGIFDSTADDR: /* Get the destination address */ 10391da177e4SLinus Torvalds case SIOCGIFNETMASK: /* Get the netmask for the interface */ 10401da177e4SLinus Torvalds /* Note that these ioctls will not sleep, 10411da177e4SLinus Torvalds so that we do not impose a lock. 10421da177e4SLinus Torvalds One day we will be forced to put shlock here (I mean SMP) 10431da177e4SLinus Torvalds */ 10441da177e4SLinus Torvalds tryaddrmatch = (sin_orig.sin_family == AF_INET); 10451da177e4SLinus Torvalds memset(sin, 0, sizeof(*sin)); 10461da177e4SLinus Torvalds sin->sin_family = AF_INET; 10471da177e4SLinus Torvalds break; 10481da177e4SLinus Torvalds 10491da177e4SLinus Torvalds case SIOCSIFFLAGS: 1050bf5b30b8SZhao Hongjiang ret = -EPERM; 105152e804c6SEric W. Biederman if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 10521da177e4SLinus Torvalds goto out; 10531da177e4SLinus Torvalds break; 10541da177e4SLinus Torvalds case SIOCSIFADDR: /* Set interface address (and family) */ 10551da177e4SLinus Torvalds case SIOCSIFBRDADDR: /* Set the broadcast address */ 10561da177e4SLinus Torvalds case SIOCSIFDSTADDR: /* Set the destination address */ 10571da177e4SLinus Torvalds case SIOCSIFNETMASK: /* Set the netmask for the interface */ 1058bf5b30b8SZhao Hongjiang ret = -EPERM; 105952e804c6SEric W. Biederman if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 10601da177e4SLinus Torvalds goto out; 10611da177e4SLinus Torvalds ret = -EINVAL; 10621da177e4SLinus Torvalds if (sin->sin_family != AF_INET) 10631da177e4SLinus Torvalds goto out; 10641da177e4SLinus Torvalds break; 10651da177e4SLinus Torvalds default: 10661da177e4SLinus Torvalds ret = -EINVAL; 10671da177e4SLinus Torvalds goto out; 10681da177e4SLinus Torvalds } 10691da177e4SLinus Torvalds 10701da177e4SLinus Torvalds rtnl_lock(); 10711da177e4SLinus Torvalds 10721da177e4SLinus Torvalds ret = -ENODEV; 107303aef17bSAl Viro dev = __dev_get_by_name(net, ifr->ifr_name); 10749f9354b9SEric Dumazet if (!dev) 10751da177e4SLinus Torvalds goto done; 10761da177e4SLinus Torvalds 10771da177e4SLinus Torvalds if (colon) 10781da177e4SLinus Torvalds *colon = ':'; 10791da177e4SLinus Torvalds 10809f9354b9SEric Dumazet in_dev = __in_dev_get_rtnl(dev); 10819f9354b9SEric Dumazet if (in_dev) { 10821da177e4SLinus Torvalds if (tryaddrmatch) { 10831da177e4SLinus Torvalds /* Matthias Andree */ 10841da177e4SLinus Torvalds /* compare label and address (4.4BSD style) */ 10851da177e4SLinus Torvalds /* note: we only do this for a limited set of ioctls 10861da177e4SLinus Torvalds and only if the original address family was AF_INET. 10871da177e4SLinus Torvalds This is checked above. */ 10882638eb8bSFlorian Westphal 10892638eb8bSFlorian Westphal for (ifap = &in_dev->ifa_list; 10902638eb8bSFlorian Westphal (ifa = rtnl_dereference(*ifap)) != NULL; 10911da177e4SLinus Torvalds ifap = &ifa->ifa_next) { 109203aef17bSAl Viro if (!strcmp(ifr->ifr_name, ifa->ifa_label) && 10931da177e4SLinus Torvalds sin_orig.sin_addr.s_addr == 10946c91afe1SDavid S. Miller ifa->ifa_local) { 10951da177e4SLinus Torvalds break; /* found */ 10961da177e4SLinus Torvalds } 10971da177e4SLinus Torvalds } 10981da177e4SLinus Torvalds } 10991da177e4SLinus Torvalds /* we didn't get a match, maybe the application is 11001da177e4SLinus Torvalds 4.3BSD-style and passed in junk so we fall back to 11011da177e4SLinus Torvalds comparing just the label */ 11021da177e4SLinus Torvalds if (!ifa) { 11032638eb8bSFlorian Westphal for (ifap = &in_dev->ifa_list; 11042638eb8bSFlorian Westphal (ifa = rtnl_dereference(*ifap)) != NULL; 11051da177e4SLinus Torvalds ifap = &ifa->ifa_next) 110603aef17bSAl Viro if (!strcmp(ifr->ifr_name, ifa->ifa_label)) 11071da177e4SLinus Torvalds break; 11081da177e4SLinus Torvalds } 11091da177e4SLinus Torvalds } 11101da177e4SLinus Torvalds 11111da177e4SLinus Torvalds ret = -EADDRNOTAVAIL; 11121da177e4SLinus Torvalds if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS) 11131da177e4SLinus Torvalds goto done; 11141da177e4SLinus Torvalds 11151da177e4SLinus Torvalds switch (cmd) { 11161da177e4SLinus Torvalds case SIOCGIFADDR: /* Get interface address */ 111730e948a3STonghao Zhang ret = 0; 11181da177e4SLinus Torvalds sin->sin_addr.s_addr = ifa->ifa_local; 111903aef17bSAl Viro break; 11201da177e4SLinus Torvalds 11211da177e4SLinus Torvalds case SIOCGIFBRDADDR: /* Get the broadcast address */ 112230e948a3STonghao Zhang ret = 0; 11231da177e4SLinus Torvalds sin->sin_addr.s_addr = ifa->ifa_broadcast; 112403aef17bSAl Viro break; 11251da177e4SLinus Torvalds 11261da177e4SLinus Torvalds case SIOCGIFDSTADDR: /* Get the destination address */ 112730e948a3STonghao Zhang ret = 0; 11281da177e4SLinus Torvalds sin->sin_addr.s_addr = ifa->ifa_address; 112903aef17bSAl Viro break; 11301da177e4SLinus Torvalds 11311da177e4SLinus Torvalds case SIOCGIFNETMASK: /* Get the netmask for the interface */ 113230e948a3STonghao Zhang ret = 0; 11331da177e4SLinus Torvalds sin->sin_addr.s_addr = ifa->ifa_mask; 113403aef17bSAl Viro break; 11351da177e4SLinus Torvalds 11361da177e4SLinus Torvalds case SIOCSIFFLAGS: 11371da177e4SLinus Torvalds if (colon) { 11381da177e4SLinus Torvalds ret = -EADDRNOTAVAIL; 11391da177e4SLinus Torvalds if (!ifa) 11401da177e4SLinus Torvalds break; 11411da177e4SLinus Torvalds ret = 0; 114203aef17bSAl Viro if (!(ifr->ifr_flags & IFF_UP)) 11431da177e4SLinus Torvalds inet_del_ifa(in_dev, ifap, 1); 11441da177e4SLinus Torvalds break; 11451da177e4SLinus Torvalds } 1146567c5e13SPetr Machata ret = dev_change_flags(dev, ifr->ifr_flags, NULL); 11471da177e4SLinus Torvalds break; 11481da177e4SLinus Torvalds 11491da177e4SLinus Torvalds case SIOCSIFADDR: /* Set interface address (and family) */ 11501da177e4SLinus Torvalds ret = -EINVAL; 11511da177e4SLinus Torvalds if (inet_abc_len(sin->sin_addr.s_addr) < 0) 11521da177e4SLinus Torvalds break; 11531da177e4SLinus Torvalds 11541da177e4SLinus Torvalds if (!ifa) { 11551da177e4SLinus Torvalds ret = -ENOBUFS; 11569f9354b9SEric Dumazet ifa = inet_alloc_ifa(); 11579f9354b9SEric Dumazet if (!ifa) 11581da177e4SLinus Torvalds break; 1159c7e2e1d7SXi Wang INIT_HLIST_NODE(&ifa->hash); 11601da177e4SLinus Torvalds if (colon) 116103aef17bSAl Viro memcpy(ifa->ifa_label, ifr->ifr_name, IFNAMSIZ); 11621da177e4SLinus Torvalds else 11631da177e4SLinus Torvalds memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); 11641da177e4SLinus Torvalds } else { 11651da177e4SLinus Torvalds ret = 0; 11661da177e4SLinus Torvalds if (ifa->ifa_local == sin->sin_addr.s_addr) 11671da177e4SLinus Torvalds break; 11681da177e4SLinus Torvalds inet_del_ifa(in_dev, ifap, 0); 11691da177e4SLinus Torvalds ifa->ifa_broadcast = 0; 1170148f9729SBjorn Mork ifa->ifa_scope = 0; 11711da177e4SLinus Torvalds } 11721da177e4SLinus Torvalds 11731da177e4SLinus Torvalds ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr; 11741da177e4SLinus Torvalds 11751da177e4SLinus Torvalds if (!(dev->flags & IFF_POINTOPOINT)) { 11761da177e4SLinus Torvalds ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address); 11771da177e4SLinus Torvalds ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen); 11781da177e4SLinus Torvalds if ((dev->flags & IFF_BROADCAST) && 11791da177e4SLinus Torvalds ifa->ifa_prefixlen < 31) 11801da177e4SLinus Torvalds ifa->ifa_broadcast = ifa->ifa_address | 11811da177e4SLinus Torvalds ~ifa->ifa_mask; 11821da177e4SLinus Torvalds } else { 11831da177e4SLinus Torvalds ifa->ifa_prefixlen = 32; 11841da177e4SLinus Torvalds ifa->ifa_mask = inet_make_mask(32); 11851da177e4SLinus Torvalds } 11865c766d64SJiri Pirko set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); 11871da177e4SLinus Torvalds ret = inet_set_ifa(dev, ifa); 11881da177e4SLinus Torvalds break; 11891da177e4SLinus Torvalds 11901da177e4SLinus Torvalds case SIOCSIFBRDADDR: /* Set the broadcast address */ 11911da177e4SLinus Torvalds ret = 0; 11921da177e4SLinus Torvalds if (ifa->ifa_broadcast != sin->sin_addr.s_addr) { 11931da177e4SLinus Torvalds inet_del_ifa(in_dev, ifap, 0); 11941da177e4SLinus Torvalds ifa->ifa_broadcast = sin->sin_addr.s_addr; 11951da177e4SLinus Torvalds inet_insert_ifa(ifa); 11961da177e4SLinus Torvalds } 11971da177e4SLinus Torvalds break; 11981da177e4SLinus Torvalds 11991da177e4SLinus Torvalds case SIOCSIFDSTADDR: /* Set the destination address */ 12001da177e4SLinus Torvalds ret = 0; 12011da177e4SLinus Torvalds if (ifa->ifa_address == sin->sin_addr.s_addr) 12021da177e4SLinus Torvalds break; 12031da177e4SLinus Torvalds ret = -EINVAL; 12041da177e4SLinus Torvalds if (inet_abc_len(sin->sin_addr.s_addr) < 0) 12051da177e4SLinus Torvalds break; 12061da177e4SLinus Torvalds ret = 0; 12071da177e4SLinus Torvalds inet_del_ifa(in_dev, ifap, 0); 12081da177e4SLinus Torvalds ifa->ifa_address = sin->sin_addr.s_addr; 12091da177e4SLinus Torvalds inet_insert_ifa(ifa); 12101da177e4SLinus Torvalds break; 12111da177e4SLinus Torvalds 12121da177e4SLinus Torvalds case SIOCSIFNETMASK: /* Set the netmask for the interface */ 12131da177e4SLinus Torvalds 12141da177e4SLinus Torvalds /* 12151da177e4SLinus Torvalds * The mask we set must be legal. 12161da177e4SLinus Torvalds */ 12171da177e4SLinus Torvalds ret = -EINVAL; 12181da177e4SLinus Torvalds if (bad_mask(sin->sin_addr.s_addr, 0)) 12191da177e4SLinus Torvalds break; 12201da177e4SLinus Torvalds ret = 0; 12211da177e4SLinus Torvalds if (ifa->ifa_mask != sin->sin_addr.s_addr) { 1222a144ea4bSAl Viro __be32 old_mask = ifa->ifa_mask; 12231da177e4SLinus Torvalds inet_del_ifa(in_dev, ifap, 0); 12241da177e4SLinus Torvalds ifa->ifa_mask = sin->sin_addr.s_addr; 12251da177e4SLinus Torvalds ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask); 12261da177e4SLinus Torvalds 12271da177e4SLinus Torvalds /* See if current broadcast address matches 12281da177e4SLinus Torvalds * with current netmask, then recalculate 12291da177e4SLinus Torvalds * the broadcast address. Otherwise it's a 12301da177e4SLinus Torvalds * funny address, so don't touch it since 12311da177e4SLinus Torvalds * the user seems to know what (s)he's doing... 12321da177e4SLinus Torvalds */ 12331da177e4SLinus Torvalds if ((dev->flags & IFF_BROADCAST) && 12341da177e4SLinus Torvalds (ifa->ifa_prefixlen < 31) && 12351da177e4SLinus Torvalds (ifa->ifa_broadcast == 1236dcab5e1eSDavid Engel (ifa->ifa_local|~old_mask))) { 12371da177e4SLinus Torvalds ifa->ifa_broadcast = (ifa->ifa_local | 12381da177e4SLinus Torvalds ~sin->sin_addr.s_addr); 12391da177e4SLinus Torvalds } 12401da177e4SLinus Torvalds inet_insert_ifa(ifa); 12411da177e4SLinus Torvalds } 12421da177e4SLinus Torvalds break; 12431da177e4SLinus Torvalds } 12441da177e4SLinus Torvalds done: 12451da177e4SLinus Torvalds rtnl_unlock(); 12461da177e4SLinus Torvalds out: 12471da177e4SLinus Torvalds return ret; 12481da177e4SLinus Torvalds } 12491da177e4SLinus Torvalds 1250b0e99d03SArnd Bergmann int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size) 12511da177e4SLinus Torvalds { 1252e5ed6399SHerbert Xu struct in_device *in_dev = __in_dev_get_rtnl(dev); 1253ef11db33SFlorian Westphal const struct in_ifaddr *ifa; 12541da177e4SLinus Torvalds struct ifreq ifr; 12551da177e4SLinus Torvalds int done = 0; 12561da177e4SLinus Torvalds 125736fd633eSAl Viro if (WARN_ON(size > sizeof(struct ifreq))) 125836fd633eSAl Viro goto out; 125936fd633eSAl Viro 12609f9354b9SEric Dumazet if (!in_dev) 12611da177e4SLinus Torvalds goto out; 12621da177e4SLinus Torvalds 1263ef11db33SFlorian Westphal in_dev_for_each_ifa_rtnl(ifa, in_dev) { 12641da177e4SLinus Torvalds if (!buf) { 126536fd633eSAl Viro done += size; 12661da177e4SLinus Torvalds continue; 12671da177e4SLinus Torvalds } 126836fd633eSAl Viro if (len < size) 12691da177e4SLinus Torvalds break; 12701da177e4SLinus Torvalds memset(&ifr, 0, sizeof(struct ifreq)); 12711da177e4SLinus Torvalds strcpy(ifr.ifr_name, ifa->ifa_label); 12721da177e4SLinus Torvalds 12731da177e4SLinus Torvalds (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET; 12741da177e4SLinus Torvalds (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr = 12751da177e4SLinus Torvalds ifa->ifa_local; 12761da177e4SLinus Torvalds 127736fd633eSAl Viro if (copy_to_user(buf + done, &ifr, size)) { 12781da177e4SLinus Torvalds done = -EFAULT; 12791da177e4SLinus Torvalds break; 12801da177e4SLinus Torvalds } 128136fd633eSAl Viro len -= size; 128236fd633eSAl Viro done += size; 12831da177e4SLinus Torvalds } 12841da177e4SLinus Torvalds out: 12851da177e4SLinus Torvalds return done; 12861da177e4SLinus Torvalds } 12871da177e4SLinus Torvalds 12888b57fd1eSGao Feng static __be32 in_dev_select_addr(const struct in_device *in_dev, 12898b57fd1eSGao Feng int scope) 12908b57fd1eSGao Feng { 1291d519e870SFlorian Westphal const struct in_ifaddr *ifa; 1292d519e870SFlorian Westphal 1293d519e870SFlorian Westphal in_dev_for_each_ifa_rcu(ifa, in_dev) { 1294d519e870SFlorian Westphal if (ifa->ifa_flags & IFA_F_SECONDARY) 1295d519e870SFlorian Westphal continue; 12968b57fd1eSGao Feng if (ifa->ifa_scope != RT_SCOPE_LINK && 12978b57fd1eSGao Feng ifa->ifa_scope <= scope) 12988b57fd1eSGao Feng return ifa->ifa_local; 1299d519e870SFlorian Westphal } 13008b57fd1eSGao Feng 13018b57fd1eSGao Feng return 0; 13028b57fd1eSGao Feng } 13038b57fd1eSGao Feng 1304a61ced5dSAl Viro __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) 13051da177e4SLinus Torvalds { 1306d519e870SFlorian Westphal const struct in_ifaddr *ifa; 1307a61ced5dSAl Viro __be32 addr = 0; 1308d8c444d5SShijie Luo unsigned char localnet_scope = RT_SCOPE_HOST; 13091da177e4SLinus Torvalds struct in_device *in_dev; 1310c346dca1SYOSHIFUJI Hideaki struct net *net = dev_net(dev); 13113f2fb9a8SDavid Ahern int master_idx; 13121da177e4SLinus Torvalds 13131da177e4SLinus Torvalds rcu_read_lock(); 1314e5ed6399SHerbert Xu in_dev = __in_dev_get_rcu(dev); 13151da177e4SLinus Torvalds if (!in_dev) 13161da177e4SLinus Torvalds goto no_in_dev; 13171da177e4SLinus Torvalds 1318d8c444d5SShijie Luo if (unlikely(IN_DEV_ROUTE_LOCALNET(in_dev))) 1319d8c444d5SShijie Luo localnet_scope = RT_SCOPE_LINK; 1320d8c444d5SShijie Luo 1321d519e870SFlorian Westphal in_dev_for_each_ifa_rcu(ifa, in_dev) { 1322d519e870SFlorian Westphal if (ifa->ifa_flags & IFA_F_SECONDARY) 1323d519e870SFlorian Westphal continue; 1324d8c444d5SShijie Luo if (min(ifa->ifa_scope, localnet_scope) > scope) 13251da177e4SLinus Torvalds continue; 13261da177e4SLinus Torvalds if (!dst || inet_ifa_match(dst, ifa)) { 13271da177e4SLinus Torvalds addr = ifa->ifa_local; 13281da177e4SLinus Torvalds break; 13291da177e4SLinus Torvalds } 13301da177e4SLinus Torvalds if (!addr) 13311da177e4SLinus Torvalds addr = ifa->ifa_local; 1332d519e870SFlorian Westphal } 13331da177e4SLinus Torvalds 13341da177e4SLinus Torvalds if (addr) 1335c6d14c84SEric Dumazet goto out_unlock; 13369f9354b9SEric Dumazet no_in_dev: 13373f2fb9a8SDavid Ahern master_idx = l3mdev_master_ifindex_rcu(dev); 13381da177e4SLinus Torvalds 133917b693cdSDavid Lamparter /* For VRFs, the VRF device takes the place of the loopback device, 134017b693cdSDavid Lamparter * with addresses on it being preferred. Note in such cases the 134117b693cdSDavid Lamparter * loopback device will be among the devices that fail the master_idx 134217b693cdSDavid Lamparter * equality check in the loop below. 134317b693cdSDavid Lamparter */ 134417b693cdSDavid Lamparter if (master_idx && 134517b693cdSDavid Lamparter (dev = dev_get_by_index_rcu(net, master_idx)) && 134617b693cdSDavid Lamparter (in_dev = __in_dev_get_rcu(dev))) { 13478b57fd1eSGao Feng addr = in_dev_select_addr(in_dev, scope); 13488b57fd1eSGao Feng if (addr) 134917b693cdSDavid Lamparter goto out_unlock; 135017b693cdSDavid Lamparter } 135117b693cdSDavid Lamparter 13521da177e4SLinus Torvalds /* Not loopback addresses on loopback should be preferred 1353ca9f1fd2SStephen Hemminger in this case. It is important that lo is the first interface 13541da177e4SLinus Torvalds in dev_base list. 13551da177e4SLinus Torvalds */ 1356c6d14c84SEric Dumazet for_each_netdev_rcu(net, dev) { 13573f2fb9a8SDavid Ahern if (l3mdev_master_ifindex_rcu(dev) != master_idx) 13583f2fb9a8SDavid Ahern continue; 13593f2fb9a8SDavid Ahern 13609f9354b9SEric Dumazet in_dev = __in_dev_get_rcu(dev); 13619f9354b9SEric Dumazet if (!in_dev) 13621da177e4SLinus Torvalds continue; 13631da177e4SLinus Torvalds 13648b57fd1eSGao Feng addr = in_dev_select_addr(in_dev, scope); 13658b57fd1eSGao Feng if (addr) 1366c6d14c84SEric Dumazet goto out_unlock; 13671da177e4SLinus Torvalds } 1368c6d14c84SEric Dumazet out_unlock: 13691da177e4SLinus Torvalds rcu_read_unlock(); 13701da177e4SLinus Torvalds return addr; 13711da177e4SLinus Torvalds } 13729f9354b9SEric Dumazet EXPORT_SYMBOL(inet_select_addr); 13731da177e4SLinus Torvalds 137460cad5daSAl Viro static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst, 137560cad5daSAl Viro __be32 local, int scope) 13761da177e4SLinus Torvalds { 1377650638a7SShijie Luo unsigned char localnet_scope = RT_SCOPE_HOST; 1378ef11db33SFlorian Westphal const struct in_ifaddr *ifa; 1379a144ea4bSAl Viro __be32 addr = 0; 1380ef11db33SFlorian Westphal int same = 0; 13811da177e4SLinus Torvalds 1382650638a7SShijie Luo if (unlikely(IN_DEV_ROUTE_LOCALNET(in_dev))) 1383650638a7SShijie Luo localnet_scope = RT_SCOPE_LINK; 1384650638a7SShijie Luo 1385ef11db33SFlorian Westphal in_dev_for_each_ifa_rcu(ifa, in_dev) { 1386650638a7SShijie Luo unsigned char min_scope = min(ifa->ifa_scope, localnet_scope); 1387650638a7SShijie Luo 13881da177e4SLinus Torvalds if (!addr && 13891da177e4SLinus Torvalds (local == ifa->ifa_local || !local) && 1390650638a7SShijie Luo min_scope <= scope) { 13911da177e4SLinus Torvalds addr = ifa->ifa_local; 13921da177e4SLinus Torvalds if (same) 13931da177e4SLinus Torvalds break; 13941da177e4SLinus Torvalds } 13951da177e4SLinus Torvalds if (!same) { 13961da177e4SLinus Torvalds same = (!local || inet_ifa_match(local, ifa)) && 13971da177e4SLinus Torvalds (!dst || inet_ifa_match(dst, ifa)); 13981da177e4SLinus Torvalds if (same && addr) { 13991da177e4SLinus Torvalds if (local || !dst) 14001da177e4SLinus Torvalds break; 14011da177e4SLinus Torvalds /* Is the selected addr into dst subnet? */ 14021da177e4SLinus Torvalds if (inet_ifa_match(addr, ifa)) 14031da177e4SLinus Torvalds break; 14041da177e4SLinus Torvalds /* No, then can we use new local src? */ 1405650638a7SShijie Luo if (min_scope <= scope) { 14061da177e4SLinus Torvalds addr = ifa->ifa_local; 14071da177e4SLinus Torvalds break; 14081da177e4SLinus Torvalds } 14091da177e4SLinus Torvalds /* search for large dst subnet for addr */ 14101da177e4SLinus Torvalds same = 0; 14111da177e4SLinus Torvalds } 14121da177e4SLinus Torvalds } 1413ef11db33SFlorian Westphal } 14141da177e4SLinus Torvalds 14151da177e4SLinus Torvalds return same ? addr : 0; 14161da177e4SLinus Torvalds } 14171da177e4SLinus Torvalds 14181da177e4SLinus Torvalds /* 14191da177e4SLinus Torvalds * Confirm that local IP address exists using wildcards: 1420b601fa19SNicolas Dichtel * - net: netns to check, cannot be NULL 1421b601fa19SNicolas Dichtel * - in_dev: only on this interface, NULL=any interface 14221da177e4SLinus Torvalds * - dst: only in the same subnet as dst, 0=any dst 14231da177e4SLinus Torvalds * - local: address, 0=autoselect the local address 14241da177e4SLinus Torvalds * - scope: maximum allowed scope value for the local address 14251da177e4SLinus Torvalds */ 1426b601fa19SNicolas Dichtel __be32 inet_confirm_addr(struct net *net, struct in_device *in_dev, 14279bd85e32SDenis V. Lunev __be32 dst, __be32 local, int scope) 14281da177e4SLinus Torvalds { 142960cad5daSAl Viro __be32 addr = 0; 14309bd85e32SDenis V. Lunev struct net_device *dev; 14311da177e4SLinus Torvalds 143200db4124SIan Morris if (in_dev) 14339bd85e32SDenis V. Lunev return confirm_addr_indev(in_dev, dst, local, scope); 14341da177e4SLinus Torvalds 14351da177e4SLinus Torvalds rcu_read_lock(); 1436c6d14c84SEric Dumazet for_each_netdev_rcu(net, dev) { 14379f9354b9SEric Dumazet in_dev = __in_dev_get_rcu(dev); 14389f9354b9SEric Dumazet if (in_dev) { 14391da177e4SLinus Torvalds addr = confirm_addr_indev(in_dev, dst, local, scope); 14401da177e4SLinus Torvalds if (addr) 14411da177e4SLinus Torvalds break; 14421da177e4SLinus Torvalds } 14431da177e4SLinus Torvalds } 14441da177e4SLinus Torvalds rcu_read_unlock(); 14451da177e4SLinus Torvalds 14461da177e4SLinus Torvalds return addr; 14471da177e4SLinus Torvalds } 1448eaddcd76SAndy Gospodarek EXPORT_SYMBOL(inet_confirm_addr); 14491da177e4SLinus Torvalds 14501da177e4SLinus Torvalds /* 14511da177e4SLinus Torvalds * Device notifier 14521da177e4SLinus Torvalds */ 14531da177e4SLinus Torvalds 14541da177e4SLinus Torvalds int register_inetaddr_notifier(struct notifier_block *nb) 14551da177e4SLinus Torvalds { 1456e041c683SAlan Stern return blocking_notifier_chain_register(&inetaddr_chain, nb); 14571da177e4SLinus Torvalds } 14589f9354b9SEric Dumazet EXPORT_SYMBOL(register_inetaddr_notifier); 14591da177e4SLinus Torvalds 14601da177e4SLinus Torvalds int unregister_inetaddr_notifier(struct notifier_block *nb) 14611da177e4SLinus Torvalds { 1462e041c683SAlan Stern return blocking_notifier_chain_unregister(&inetaddr_chain, nb); 14631da177e4SLinus Torvalds } 14649f9354b9SEric Dumazet EXPORT_SYMBOL(unregister_inetaddr_notifier); 14651da177e4SLinus Torvalds 14663ad7d246SKrister Johansen int register_inetaddr_validator_notifier(struct notifier_block *nb) 14673ad7d246SKrister Johansen { 14683ad7d246SKrister Johansen return blocking_notifier_chain_register(&inetaddr_validator_chain, nb); 14693ad7d246SKrister Johansen } 14703ad7d246SKrister Johansen EXPORT_SYMBOL(register_inetaddr_validator_notifier); 14713ad7d246SKrister Johansen 14723ad7d246SKrister Johansen int unregister_inetaddr_validator_notifier(struct notifier_block *nb) 14733ad7d246SKrister Johansen { 14743ad7d246SKrister Johansen return blocking_notifier_chain_unregister(&inetaddr_validator_chain, 14753ad7d246SKrister Johansen nb); 14763ad7d246SKrister Johansen } 14773ad7d246SKrister Johansen EXPORT_SYMBOL(unregister_inetaddr_validator_notifier); 14783ad7d246SKrister Johansen 14799f9354b9SEric Dumazet /* Rename ifa_labels for a device name change. Make some effort to preserve 14809f9354b9SEric Dumazet * existing alias numbering and to create unique labels if possible. 14811da177e4SLinus Torvalds */ 14821da177e4SLinus Torvalds static void inetdev_changename(struct net_device *dev, struct in_device *in_dev) 14831da177e4SLinus Torvalds { 14841da177e4SLinus Torvalds struct in_ifaddr *ifa; 14851da177e4SLinus Torvalds int named = 0; 14861da177e4SLinus Torvalds 1487ef11db33SFlorian Westphal in_dev_for_each_ifa_rtnl(ifa, in_dev) { 14881da177e4SLinus Torvalds char old[IFNAMSIZ], *dot; 14891da177e4SLinus Torvalds 14901da177e4SLinus Torvalds memcpy(old, ifa->ifa_label, IFNAMSIZ); 14911da177e4SLinus Torvalds memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); 14921da177e4SLinus Torvalds if (named++ == 0) 1493573bf470SThomas Graf goto skip; 149444344b2aSMark McLoughlin dot = strchr(old, ':'); 149551456b29SIan Morris if (!dot) { 14961da177e4SLinus Torvalds sprintf(old, ":%d", named); 14971da177e4SLinus Torvalds dot = old; 14981da177e4SLinus Torvalds } 14999f9354b9SEric Dumazet if (strlen(dot) + strlen(dev->name) < IFNAMSIZ) 15001da177e4SLinus Torvalds strcat(ifa->ifa_label, dot); 15019f9354b9SEric Dumazet else 15021da177e4SLinus Torvalds strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot); 1503573bf470SThomas Graf skip: 1504573bf470SThomas Graf rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0); 15051da177e4SLinus Torvalds } 15061da177e4SLinus Torvalds } 15071da177e4SLinus Torvalds 1508d11327adSIan Campbell static void inetdev_send_gratuitous_arp(struct net_device *dev, 1509d11327adSIan Campbell struct in_device *in_dev) 1510d11327adSIan Campbell 1511d11327adSIan Campbell { 1512ef11db33SFlorian Westphal const struct in_ifaddr *ifa; 1513d11327adSIan Campbell 1514ef11db33SFlorian Westphal in_dev_for_each_ifa_rtnl(ifa, in_dev) { 1515d11327adSIan Campbell arp_send(ARPOP_REQUEST, ETH_P_ARP, 15166c91afe1SDavid S. Miller ifa->ifa_local, dev, 15176c91afe1SDavid S. Miller ifa->ifa_local, NULL, 1518d11327adSIan Campbell dev->dev_addr, NULL); 1519d11327adSIan Campbell } 1520b76d0789SZoltan Kiss } 1521d11327adSIan Campbell 15221da177e4SLinus Torvalds /* Called only under RTNL semaphore */ 15231da177e4SLinus Torvalds 15241da177e4SLinus Torvalds static int inetdev_event(struct notifier_block *this, unsigned long event, 15251da177e4SLinus Torvalds void *ptr) 15261da177e4SLinus Torvalds { 1527351638e7SJiri Pirko struct net_device *dev = netdev_notifier_info_to_dev(ptr); 1528748e2d93SEric Dumazet struct in_device *in_dev = __in_dev_get_rtnl(dev); 15291da177e4SLinus Torvalds 15301da177e4SLinus Torvalds ASSERT_RTNL(); 15311da177e4SLinus Torvalds 15321da177e4SLinus Torvalds if (!in_dev) { 15338030f544SHerbert Xu if (event == NETDEV_REGISTER) { 15341da177e4SLinus Torvalds in_dev = inetdev_init(dev); 153520e61da7SWANG Cong if (IS_ERR(in_dev)) 153620e61da7SWANG Cong return notifier_from_errno(PTR_ERR(in_dev)); 15370cc217e1SEric W. Biederman if (dev->flags & IFF_LOOPBACK) { 153842f811b8SHerbert Xu IN_DEV_CONF_SET(in_dev, NOXFRM, 1); 153942f811b8SHerbert Xu IN_DEV_CONF_SET(in_dev, NOPOLICY, 1); 15401da177e4SLinus Torvalds } 154106770843SBreno Leitao } else if (event == NETDEV_CHANGEMTU) { 154206770843SBreno Leitao /* Re-enabling IP */ 154306770843SBreno Leitao if (inetdev_valid_mtu(dev->mtu)) 154406770843SBreno Leitao in_dev = inetdev_init(dev); 15458030f544SHerbert Xu } 15461da177e4SLinus Torvalds goto out; 15471da177e4SLinus Torvalds } 15481da177e4SLinus Torvalds 15491da177e4SLinus Torvalds switch (event) { 15501da177e4SLinus Torvalds case NETDEV_REGISTER: 155191df42beSJoe Perches pr_debug("%s: bug\n", __func__); 1552a9b3cd7fSStephen Hemminger RCU_INIT_POINTER(dev->ip_ptr, NULL); 15531da177e4SLinus Torvalds break; 15541da177e4SLinus Torvalds case NETDEV_UP: 155506770843SBreno Leitao if (!inetdev_valid_mtu(dev->mtu)) 15561da177e4SLinus Torvalds break; 15570cc217e1SEric W. Biederman if (dev->flags & IFF_LOOPBACK) { 15589f9354b9SEric Dumazet struct in_ifaddr *ifa = inet_alloc_ifa(); 15599f9354b9SEric Dumazet 15609f9354b9SEric Dumazet if (ifa) { 1561fd23c3b3SDavid S. Miller INIT_HLIST_NODE(&ifa->hash); 15621da177e4SLinus Torvalds ifa->ifa_local = 15631da177e4SLinus Torvalds ifa->ifa_address = htonl(INADDR_LOOPBACK); 15641da177e4SLinus Torvalds ifa->ifa_prefixlen = 8; 15651da177e4SLinus Torvalds ifa->ifa_mask = inet_make_mask(8); 15661da177e4SLinus Torvalds in_dev_hold(in_dev); 15671da177e4SLinus Torvalds ifa->ifa_dev = in_dev; 15681da177e4SLinus Torvalds ifa->ifa_scope = RT_SCOPE_HOST; 15691da177e4SLinus Torvalds memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); 15705c766d64SJiri Pirko set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, 15715c766d64SJiri Pirko INFINITY_LIFE_TIME); 1572dfd1582dSJiri Pirko ipv4_devconf_setall(in_dev); 1573dfd1582dSJiri Pirko neigh_parms_data_state_setall(in_dev->arp_parms); 15741da177e4SLinus Torvalds inet_insert_ifa(ifa); 15751da177e4SLinus Torvalds } 15761da177e4SLinus Torvalds } 15771da177e4SLinus Torvalds ip_mc_up(in_dev); 1578a8eceea8SJoe Perches fallthrough; 1579eefef1cfSStephen Hemminger case NETDEV_CHANGEADDR: 1580d11327adSIan Campbell if (!IN_DEV_ARP_NOTIFY(in_dev)) 1581d11327adSIan Campbell break; 1582a8eceea8SJoe Perches fallthrough; 1583d11327adSIan Campbell case NETDEV_NOTIFY_PEERS: 1584a21090cfSStephen Hemminger /* Send gratuitous ARP to notify of link change */ 1585d11327adSIan Campbell inetdev_send_gratuitous_arp(dev, in_dev); 15861da177e4SLinus Torvalds break; 15871da177e4SLinus Torvalds case NETDEV_DOWN: 15881da177e4SLinus Torvalds ip_mc_down(in_dev); 15891da177e4SLinus Torvalds break; 159093d9b7d7SJiri Pirko case NETDEV_PRE_TYPE_CHANGE: 159175c78500SMoni Shoua ip_mc_unmap(in_dev); 159275c78500SMoni Shoua break; 159393d9b7d7SJiri Pirko case NETDEV_POST_TYPE_CHANGE: 159475c78500SMoni Shoua ip_mc_remap(in_dev); 159575c78500SMoni Shoua break; 15961da177e4SLinus Torvalds case NETDEV_CHANGEMTU: 159706770843SBreno Leitao if (inetdev_valid_mtu(dev->mtu)) 15981da177e4SLinus Torvalds break; 159906770843SBreno Leitao /* disable IP when MTU is not enough */ 1600a8eceea8SJoe Perches fallthrough; 16011da177e4SLinus Torvalds case NETDEV_UNREGISTER: 16021da177e4SLinus Torvalds inetdev_destroy(in_dev); 16031da177e4SLinus Torvalds break; 16041da177e4SLinus Torvalds case NETDEV_CHANGENAME: 16051da177e4SLinus Torvalds /* Do not notify about label change, this event is 16061da177e4SLinus Torvalds * not interesting to applications using netlink. 16071da177e4SLinus Torvalds */ 16081da177e4SLinus Torvalds inetdev_changename(dev, in_dev); 16091da177e4SLinus Torvalds 161051602b2aSPavel Emelyanov devinet_sysctl_unregister(in_dev); 161166f27a52SPavel Emelyanov devinet_sysctl_register(in_dev); 16121da177e4SLinus Torvalds break; 16131da177e4SLinus Torvalds } 16141da177e4SLinus Torvalds out: 16151da177e4SLinus Torvalds return NOTIFY_DONE; 16161da177e4SLinus Torvalds } 16171da177e4SLinus Torvalds 16181da177e4SLinus Torvalds static struct notifier_block ip_netdev_notifier = { 16191da177e4SLinus Torvalds .notifier_call = inetdev_event, 16201da177e4SLinus Torvalds }; 16211da177e4SLinus Torvalds 162240384999SEric Dumazet static size_t inet_nlmsg_size(void) 1623339bf98fSThomas Graf { 1624339bf98fSThomas Graf return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) 1625339bf98fSThomas Graf + nla_total_size(4) /* IFA_ADDRESS */ 1626339bf98fSThomas Graf + nla_total_size(4) /* IFA_LOCAL */ 1627339bf98fSThomas Graf + nla_total_size(4) /* IFA_BROADCAST */ 1628ad6c8135SJiri Pirko + nla_total_size(IFNAMSIZ) /* IFA_LABEL */ 162963b5f152SGeert Uytterhoeven + nla_total_size(4) /* IFA_FLAGS */ 163047f0bd50SJacques de Laval + nla_total_size(1) /* IFA_PROTO */ 1631af4d768aSDavid Ahern + nla_total_size(4) /* IFA_RT_PRIORITY */ 163263b5f152SGeert Uytterhoeven + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */ 1633339bf98fSThomas Graf } 1634339bf98fSThomas Graf 16355c766d64SJiri Pirko static inline u32 cstamp_delta(unsigned long cstamp) 16365c766d64SJiri Pirko { 16375c766d64SJiri Pirko return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; 16385c766d64SJiri Pirko } 16395c766d64SJiri Pirko 16405c766d64SJiri Pirko static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp, 16415c766d64SJiri Pirko unsigned long tstamp, u32 preferred, u32 valid) 16425c766d64SJiri Pirko { 16435c766d64SJiri Pirko struct ifa_cacheinfo ci; 16445c766d64SJiri Pirko 16455c766d64SJiri Pirko ci.cstamp = cstamp_delta(cstamp); 16465c766d64SJiri Pirko ci.tstamp = cstamp_delta(tstamp); 16475c766d64SJiri Pirko ci.ifa_prefered = preferred; 16485c766d64SJiri Pirko ci.ifa_valid = valid; 16495c766d64SJiri Pirko 16505c766d64SJiri Pirko return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci); 16515c766d64SJiri Pirko } 16525c766d64SJiri Pirko 16531da177e4SLinus Torvalds static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, 1654978a46faSChristian Brauner struct inet_fill_args *args) 16551da177e4SLinus Torvalds { 16561da177e4SLinus Torvalds struct ifaddrmsg *ifm; 16571da177e4SLinus Torvalds struct nlmsghdr *nlh; 16585c766d64SJiri Pirko u32 preferred, valid; 16591da177e4SLinus Torvalds 1660978a46faSChristian Brauner nlh = nlmsg_put(skb, args->portid, args->seq, args->event, sizeof(*ifm), 1661978a46faSChristian Brauner args->flags); 166251456b29SIan Morris if (!nlh) 166326932566SPatrick McHardy return -EMSGSIZE; 166447f68512SThomas Graf 166547f68512SThomas Graf ifm = nlmsg_data(nlh); 16661da177e4SLinus Torvalds ifm->ifa_family = AF_INET; 16671da177e4SLinus Torvalds ifm->ifa_prefixlen = ifa->ifa_prefixlen; 16685c766d64SJiri Pirko ifm->ifa_flags = ifa->ifa_flags; 16691da177e4SLinus Torvalds ifm->ifa_scope = ifa->ifa_scope; 16701da177e4SLinus Torvalds ifm->ifa_index = ifa->ifa_dev->dev->ifindex; 16711da177e4SLinus Torvalds 1672978a46faSChristian Brauner if (args->netnsid >= 0 && 1673978a46faSChristian Brauner nla_put_s32(skb, IFA_TARGET_NETNSID, args->netnsid)) 1674d3807145SChristian Brauner goto nla_put_failure; 1675d3807145SChristian Brauner 16765c766d64SJiri Pirko if (!(ifm->ifa_flags & IFA_F_PERMANENT)) { 16775c766d64SJiri Pirko preferred = ifa->ifa_preferred_lft; 16785c766d64SJiri Pirko valid = ifa->ifa_valid_lft; 16795c766d64SJiri Pirko if (preferred != INFINITY_LIFE_TIME) { 16805c766d64SJiri Pirko long tval = (jiffies - ifa->ifa_tstamp) / HZ; 16815c766d64SJiri Pirko 16825c766d64SJiri Pirko if (preferred > tval) 16835c766d64SJiri Pirko preferred -= tval; 16845c766d64SJiri Pirko else 16855c766d64SJiri Pirko preferred = 0; 16865c766d64SJiri Pirko if (valid != INFINITY_LIFE_TIME) { 16875c766d64SJiri Pirko if (valid > tval) 16885c766d64SJiri Pirko valid -= tval; 16895c766d64SJiri Pirko else 16905c766d64SJiri Pirko valid = 0; 16915c766d64SJiri Pirko } 16925c766d64SJiri Pirko } 16935c766d64SJiri Pirko } else { 16945c766d64SJiri Pirko preferred = INFINITY_LIFE_TIME; 16955c766d64SJiri Pirko valid = INFINITY_LIFE_TIME; 16965c766d64SJiri Pirko } 1697f3756b79SDavid S. Miller if ((ifa->ifa_address && 1698930345eaSJiri Benc nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) || 1699f3756b79SDavid S. Miller (ifa->ifa_local && 1700930345eaSJiri Benc nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) || 1701f3756b79SDavid S. Miller (ifa->ifa_broadcast && 1702930345eaSJiri Benc nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) || 1703f3756b79SDavid S. Miller (ifa->ifa_label[0] && 17045c766d64SJiri Pirko nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) || 170547f0bd50SJacques de Laval (ifa->ifa_proto && 170647f0bd50SJacques de Laval nla_put_u8(skb, IFA_PROTO, ifa->ifa_proto)) || 1707ad6c8135SJiri Pirko nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) || 1708af4d768aSDavid Ahern (ifa->ifa_rt_priority && 1709af4d768aSDavid Ahern nla_put_u32(skb, IFA_RT_PRIORITY, ifa->ifa_rt_priority)) || 17105c766d64SJiri Pirko put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp, 17115c766d64SJiri Pirko preferred, valid)) 1712f3756b79SDavid S. Miller goto nla_put_failure; 171347f68512SThomas Graf 1714053c095aSJohannes Berg nlmsg_end(skb, nlh); 1715053c095aSJohannes Berg return 0; 171647f68512SThomas Graf 171747f68512SThomas Graf nla_put_failure: 171826932566SPatrick McHardy nlmsg_cancel(skb, nlh); 171926932566SPatrick McHardy return -EMSGSIZE; 17201da177e4SLinus Torvalds } 17211da177e4SLinus Torvalds 1722c33078e3SDavid Ahern static int inet_valid_dump_ifaddr_req(const struct nlmsghdr *nlh, 1723c33078e3SDavid Ahern struct inet_fill_args *fillargs, 1724c33078e3SDavid Ahern struct net **tgt_net, struct sock *sk, 17255fcd266aSDavid Ahern struct netlink_callback *cb) 1726c33078e3SDavid Ahern { 17275fcd266aSDavid Ahern struct netlink_ext_ack *extack = cb->extack; 1728c33078e3SDavid Ahern struct nlattr *tb[IFA_MAX+1]; 1729c33078e3SDavid Ahern struct ifaddrmsg *ifm; 1730c33078e3SDavid Ahern int err, i; 1731c33078e3SDavid Ahern 1732c33078e3SDavid Ahern if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { 1733c33078e3SDavid Ahern NL_SET_ERR_MSG(extack, "ipv4: Invalid header for address dump request"); 1734c33078e3SDavid Ahern return -EINVAL; 1735c33078e3SDavid Ahern } 1736c33078e3SDavid Ahern 1737c33078e3SDavid Ahern ifm = nlmsg_data(nlh); 1738c33078e3SDavid Ahern if (ifm->ifa_prefixlen || ifm->ifa_flags || ifm->ifa_scope) { 1739c33078e3SDavid Ahern NL_SET_ERR_MSG(extack, "ipv4: Invalid values in header for address dump request"); 1740c33078e3SDavid Ahern return -EINVAL; 1741c33078e3SDavid Ahern } 17425fcd266aSDavid Ahern 17435fcd266aSDavid Ahern fillargs->ifindex = ifm->ifa_index; 17445fcd266aSDavid Ahern if (fillargs->ifindex) { 17455fcd266aSDavid Ahern cb->answer_flags |= NLM_F_DUMP_FILTERED; 17465fcd266aSDavid Ahern fillargs->flags |= NLM_F_DUMP_FILTERED; 1747c33078e3SDavid Ahern } 1748c33078e3SDavid Ahern 17498cb08174SJohannes Berg err = nlmsg_parse_deprecated_strict(nlh, sizeof(*ifm), tb, IFA_MAX, 1750c33078e3SDavid Ahern ifa_ipv4_policy, extack); 1751c33078e3SDavid Ahern if (err < 0) 1752c33078e3SDavid Ahern return err; 1753c33078e3SDavid Ahern 1754c33078e3SDavid Ahern for (i = 0; i <= IFA_MAX; ++i) { 1755c33078e3SDavid Ahern if (!tb[i]) 1756c33078e3SDavid Ahern continue; 1757c33078e3SDavid Ahern 1758c33078e3SDavid Ahern if (i == IFA_TARGET_NETNSID) { 1759c33078e3SDavid Ahern struct net *net; 1760c33078e3SDavid Ahern 1761c33078e3SDavid Ahern fillargs->netnsid = nla_get_s32(tb[i]); 1762c33078e3SDavid Ahern 1763c33078e3SDavid Ahern net = rtnl_get_net_ns_capable(sk, fillargs->netnsid); 1764c33078e3SDavid Ahern if (IS_ERR(net)) { 1765bf4cc40eSBjørn Mork fillargs->netnsid = -1; 1766c33078e3SDavid Ahern NL_SET_ERR_MSG(extack, "ipv4: Invalid target network namespace id"); 1767c33078e3SDavid Ahern return PTR_ERR(net); 1768c33078e3SDavid Ahern } 1769c33078e3SDavid Ahern *tgt_net = net; 1770c33078e3SDavid Ahern } else { 1771c33078e3SDavid Ahern NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in dump request"); 1772c33078e3SDavid Ahern return -EINVAL; 1773c33078e3SDavid Ahern } 1774c33078e3SDavid Ahern } 1775c33078e3SDavid Ahern 1776c33078e3SDavid Ahern return 0; 1777c33078e3SDavid Ahern } 1778c33078e3SDavid Ahern 17791c98eca4SDavid Ahern static int in_dev_dump_addr(struct in_device *in_dev, struct sk_buff *skb, 17801c98eca4SDavid Ahern struct netlink_callback *cb, int s_ip_idx, 17811c98eca4SDavid Ahern struct inet_fill_args *fillargs) 17821c98eca4SDavid Ahern { 17831c98eca4SDavid Ahern struct in_ifaddr *ifa; 17841c98eca4SDavid Ahern int ip_idx = 0; 17851c98eca4SDavid Ahern int err; 17861c98eca4SDavid Ahern 1787d3e6e285SFlorian Westphal in_dev_for_each_ifa_rtnl(ifa, in_dev) { 1788ef11db33SFlorian Westphal if (ip_idx < s_ip_idx) { 1789ef11db33SFlorian Westphal ip_idx++; 17901c98eca4SDavid Ahern continue; 1791ef11db33SFlorian Westphal } 17921c98eca4SDavid Ahern err = inet_fill_ifaddr(skb, ifa, fillargs); 17931c98eca4SDavid Ahern if (err < 0) 17941c98eca4SDavid Ahern goto done; 17951c98eca4SDavid Ahern 17961c98eca4SDavid Ahern nl_dump_check_consistent(cb, nlmsg_hdr(skb)); 1797ef11db33SFlorian Westphal ip_idx++; 17981c98eca4SDavid Ahern } 17991c98eca4SDavid Ahern err = 0; 18001c98eca4SDavid Ahern 18011c98eca4SDavid Ahern done: 18021c98eca4SDavid Ahern cb->args[2] = ip_idx; 18031c98eca4SDavid Ahern 18041c98eca4SDavid Ahern return err; 18051c98eca4SDavid Ahern } 18061c98eca4SDavid Ahern 18071da177e4SLinus Torvalds static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) 18081da177e4SLinus Torvalds { 1809c33078e3SDavid Ahern const struct nlmsghdr *nlh = cb->nlh; 1810978a46faSChristian Brauner struct inet_fill_args fillargs = { 1811978a46faSChristian Brauner .portid = NETLINK_CB(cb->skb).portid, 1812c33078e3SDavid Ahern .seq = nlh->nlmsg_seq, 1813978a46faSChristian Brauner .event = RTM_NEWADDR, 1814978a46faSChristian Brauner .flags = NLM_F_MULTI, 1815978a46faSChristian Brauner .netnsid = -1, 1816978a46faSChristian Brauner }; 18173b1e0a65SYOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 1818d3807145SChristian Brauner struct net *tgt_net = net; 1819eec4df98SEric Dumazet int h, s_h; 1820eec4df98SEric Dumazet int idx, s_idx; 18211c98eca4SDavid Ahern int s_ip_idx; 18221da177e4SLinus Torvalds struct net_device *dev; 18231da177e4SLinus Torvalds struct in_device *in_dev; 1824eec4df98SEric Dumazet struct hlist_head *head; 1825d7e38611SDavid Ahern int err = 0; 18261da177e4SLinus Torvalds 1827eec4df98SEric Dumazet s_h = cb->args[0]; 1828eec4df98SEric Dumazet s_idx = idx = cb->args[1]; 18291c98eca4SDavid Ahern s_ip_idx = cb->args[2]; 1830eec4df98SEric Dumazet 1831c33078e3SDavid Ahern if (cb->strict_check) { 1832c33078e3SDavid Ahern err = inet_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net, 18335fcd266aSDavid Ahern skb->sk, cb); 1834c33078e3SDavid Ahern if (err < 0) 1835d7e38611SDavid Ahern goto put_tgt_net; 18365fcd266aSDavid Ahern 1837d7e38611SDavid Ahern err = 0; 18385fcd266aSDavid Ahern if (fillargs.ifindex) { 18395fcd266aSDavid Ahern dev = __dev_get_by_index(tgt_net, fillargs.ifindex); 1840d7e38611SDavid Ahern if (!dev) { 1841d7e38611SDavid Ahern err = -ENODEV; 1842d7e38611SDavid Ahern goto put_tgt_net; 1843d7e38611SDavid Ahern } 18445fcd266aSDavid Ahern 18455fcd266aSDavid Ahern in_dev = __in_dev_get_rtnl(dev); 18465fcd266aSDavid Ahern if (in_dev) { 18475fcd266aSDavid Ahern err = in_dev_dump_addr(in_dev, skb, cb, s_ip_idx, 18485fcd266aSDavid Ahern &fillargs); 18495fcd266aSDavid Ahern } 18505fcd266aSDavid Ahern goto put_tgt_net; 18515fcd266aSDavid Ahern } 1852d3807145SChristian Brauner } 1853d3807145SChristian Brauner 1854eec4df98SEric Dumazet for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { 18557562f876SPavel Emelianov idx = 0; 1856d3807145SChristian Brauner head = &tgt_net->dev_index_head[h]; 1857eec4df98SEric Dumazet rcu_read_lock(); 1858d3807145SChristian Brauner cb->seq = atomic_read(&tgt_net->ipv4.dev_addr_genid) ^ 1859d3807145SChristian Brauner tgt_net->dev_base_seq; 1860b67bfe0dSSasha Levin hlist_for_each_entry_rcu(dev, head, index_hlist) { 18611da177e4SLinus Torvalds if (idx < s_idx) 18627562f876SPavel Emelianov goto cont; 18634b97efdfSPatrick McHardy if (h > s_h || idx > s_idx) 18641da177e4SLinus Torvalds s_ip_idx = 0; 1865eec4df98SEric Dumazet in_dev = __in_dev_get_rcu(dev); 18669f9354b9SEric Dumazet if (!in_dev) 18677562f876SPavel Emelianov goto cont; 18681da177e4SLinus Torvalds 18691c98eca4SDavid Ahern err = in_dev_dump_addr(in_dev, skb, cb, s_ip_idx, 18701c98eca4SDavid Ahern &fillargs); 18711c98eca4SDavid Ahern if (err < 0) { 1872eec4df98SEric Dumazet rcu_read_unlock(); 18731da177e4SLinus Torvalds goto done; 18741da177e4SLinus Torvalds } 18757562f876SPavel Emelianov cont: 18767562f876SPavel Emelianov idx++; 18771da177e4SLinus Torvalds } 1878eec4df98SEric Dumazet rcu_read_unlock(); 1879eec4df98SEric Dumazet } 18801da177e4SLinus Torvalds 18811da177e4SLinus Torvalds done: 1882eec4df98SEric Dumazet cb->args[0] = h; 1883eec4df98SEric Dumazet cb->args[1] = idx; 18845fcd266aSDavid Ahern put_tgt_net: 1885978a46faSChristian Brauner if (fillargs.netnsid >= 0) 1886d3807145SChristian Brauner put_net(tgt_net); 18871da177e4SLinus Torvalds 18887c1e8a38SArthur Gautier return skb->len ? : err; 18891da177e4SLinus Torvalds } 18901da177e4SLinus Torvalds 1891d6062cbbSThomas Graf static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh, 189215e47304SEric W. Biederman u32 portid) 18931da177e4SLinus Torvalds { 1894978a46faSChristian Brauner struct inet_fill_args fillargs = { 1895978a46faSChristian Brauner .portid = portid, 1896978a46faSChristian Brauner .seq = nlh ? nlh->nlmsg_seq : 0, 1897978a46faSChristian Brauner .event = event, 1898978a46faSChristian Brauner .flags = 0, 1899978a46faSChristian Brauner .netnsid = -1, 1900978a46faSChristian Brauner }; 190147f68512SThomas Graf struct sk_buff *skb; 1902d6062cbbSThomas Graf int err = -ENOBUFS; 19034b8aa9abSDenis V. Lunev struct net *net; 19041da177e4SLinus Torvalds 1905c346dca1SYOSHIFUJI Hideaki net = dev_net(ifa->ifa_dev->dev); 1906339bf98fSThomas Graf skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL); 190751456b29SIan Morris if (!skb) 1908d6062cbbSThomas Graf goto errout; 1909d6062cbbSThomas Graf 1910978a46faSChristian Brauner err = inet_fill_ifaddr(skb, ifa, &fillargs); 191126932566SPatrick McHardy if (err < 0) { 191226932566SPatrick McHardy /* -EMSGSIZE implies BUG in inet_nlmsg_size() */ 191326932566SPatrick McHardy WARN_ON(err == -EMSGSIZE); 191426932566SPatrick McHardy kfree_skb(skb); 191526932566SPatrick McHardy goto errout; 191626932566SPatrick McHardy } 191715e47304SEric W. Biederman rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL); 19181ce85fe4SPablo Neira Ayuso return; 1919d6062cbbSThomas Graf errout: 1920d6062cbbSThomas Graf if (err < 0) 19214b8aa9abSDenis V. Lunev rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err); 19221da177e4SLinus Torvalds } 19231da177e4SLinus Torvalds 1924b1974ed0SArad, Ronen static size_t inet_get_link_af_size(const struct net_device *dev, 1925b1974ed0SArad, Ronen u32 ext_filter_mask) 19269f0f7272SThomas Graf { 19271fc19affSEric Dumazet struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr); 19289f0f7272SThomas Graf 19299f0f7272SThomas Graf if (!in_dev) 19309f0f7272SThomas Graf return 0; 19319f0f7272SThomas Graf 19329f0f7272SThomas Graf return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */ 19339f0f7272SThomas Graf } 19349f0f7272SThomas Graf 1935d5566fd7SSowmini Varadhan static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev, 1936d5566fd7SSowmini Varadhan u32 ext_filter_mask) 19379f0f7272SThomas Graf { 19381fc19affSEric Dumazet struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr); 19399f0f7272SThomas Graf struct nlattr *nla; 19409f0f7272SThomas Graf int i; 19419f0f7272SThomas Graf 19429f0f7272SThomas Graf if (!in_dev) 19439f0f7272SThomas Graf return -ENODATA; 19449f0f7272SThomas Graf 19459f0f7272SThomas Graf nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4); 194651456b29SIan Morris if (!nla) 19479f0f7272SThomas Graf return -EMSGSIZE; 19489f0f7272SThomas Graf 19499f0f7272SThomas Graf for (i = 0; i < IPV4_DEVCONF_MAX; i++) 19509f0f7272SThomas Graf ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i]; 19519f0f7272SThomas Graf 19529f0f7272SThomas Graf return 0; 19539f0f7272SThomas Graf } 19549f0f7272SThomas Graf 19559f0f7272SThomas Graf static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = { 19569f0f7272SThomas Graf [IFLA_INET_CONF] = { .type = NLA_NESTED }, 19579f0f7272SThomas Graf }; 19589f0f7272SThomas Graf 1959cf7afbfeSThomas Graf static int inet_validate_link_af(const struct net_device *dev, 19608679c31eSRocco Yue const struct nlattr *nla, 19618679c31eSRocco Yue struct netlink_ext_ack *extack) 19629f0f7272SThomas Graf { 19639f0f7272SThomas Graf struct nlattr *a, *tb[IFLA_INET_MAX+1]; 19649f0f7272SThomas Graf int err, rem; 19659f0f7272SThomas Graf 1966a100243dSCong Wang if (dev && !__in_dev_get_rtnl(dev)) 1967cf7afbfeSThomas Graf return -EAFNOSUPPORT; 19689f0f7272SThomas Graf 19698cb08174SJohannes Berg err = nla_parse_nested_deprecated(tb, IFLA_INET_MAX, nla, 19708679c31eSRocco Yue inet_af_policy, extack); 19719f0f7272SThomas Graf if (err < 0) 19729f0f7272SThomas Graf return err; 19739f0f7272SThomas Graf 19749f0f7272SThomas Graf if (tb[IFLA_INET_CONF]) { 19759f0f7272SThomas Graf nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) { 19769f0f7272SThomas Graf int cfgid = nla_type(a); 19779f0f7272SThomas Graf 19789f0f7272SThomas Graf if (nla_len(a) < 4) 19799f0f7272SThomas Graf return -EINVAL; 19809f0f7272SThomas Graf 19819f0f7272SThomas Graf if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX) 19829f0f7272SThomas Graf return -EINVAL; 19839f0f7272SThomas Graf } 19849f0f7272SThomas Graf } 19859f0f7272SThomas Graf 1986cf7afbfeSThomas Graf return 0; 1987cf7afbfeSThomas Graf } 1988cf7afbfeSThomas Graf 19893583a4e8SStephen Hemminger static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla, 19903583a4e8SStephen Hemminger struct netlink_ext_ack *extack) 1991cf7afbfeSThomas Graf { 1992a100243dSCong Wang struct in_device *in_dev = __in_dev_get_rtnl(dev); 1993cf7afbfeSThomas Graf struct nlattr *a, *tb[IFLA_INET_MAX+1]; 1994cf7afbfeSThomas Graf int rem; 1995cf7afbfeSThomas Graf 1996cf7afbfeSThomas Graf if (!in_dev) 1997cf7afbfeSThomas Graf return -EAFNOSUPPORT; 1998cf7afbfeSThomas Graf 19998cb08174SJohannes Berg if (nla_parse_nested_deprecated(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0) 20005ac6b198SZheng Yongjun return -EINVAL; 2001cf7afbfeSThomas Graf 20029f0f7272SThomas Graf if (tb[IFLA_INET_CONF]) { 20039f0f7272SThomas Graf nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) 20049f0f7272SThomas Graf ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a)); 20059f0f7272SThomas Graf } 20069f0f7272SThomas Graf 20079f0f7272SThomas Graf return 0; 20089f0f7272SThomas Graf } 20099f0f7272SThomas Graf 2010edc9e748SNicolas Dichtel static int inet_netconf_msgsize_devconf(int type) 2011edc9e748SNicolas Dichtel { 2012edc9e748SNicolas Dichtel int size = NLMSG_ALIGN(sizeof(struct netconfmsg)) 2013edc9e748SNicolas Dichtel + nla_total_size(4); /* NETCONFA_IFINDEX */ 2014136ba622SZhang Shengju bool all = false; 2015edc9e748SNicolas Dichtel 2016136ba622SZhang Shengju if (type == NETCONFA_ALL) 2017136ba622SZhang Shengju all = true; 2018136ba622SZhang Shengju 2019136ba622SZhang Shengju if (all || type == NETCONFA_FORWARDING) 2020edc9e748SNicolas Dichtel size += nla_total_size(4); 2021136ba622SZhang Shengju if (all || type == NETCONFA_RP_FILTER) 2022cc535dfbSNicolas Dichtel size += nla_total_size(4); 2023136ba622SZhang Shengju if (all || type == NETCONFA_MC_FORWARDING) 2024d67b8c61SNicolas Dichtel size += nla_total_size(4); 20255cbf777cSXin Long if (all || type == NETCONFA_BC_FORWARDING) 20265cbf777cSXin Long size += nla_total_size(4); 2027136ba622SZhang Shengju if (all || type == NETCONFA_PROXY_NEIGH) 2028f085ff1cSstephen hemminger size += nla_total_size(4); 2029136ba622SZhang Shengju if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) 2030974d7af5SAndy Gospodarek size += nla_total_size(4); 2031edc9e748SNicolas Dichtel 2032edc9e748SNicolas Dichtel return size; 2033edc9e748SNicolas Dichtel } 2034edc9e748SNicolas Dichtel 2035edc9e748SNicolas Dichtel static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex, 2036edc9e748SNicolas Dichtel struct ipv4_devconf *devconf, u32 portid, 2037edc9e748SNicolas Dichtel u32 seq, int event, unsigned int flags, 2038edc9e748SNicolas Dichtel int type) 2039edc9e748SNicolas Dichtel { 2040edc9e748SNicolas Dichtel struct nlmsghdr *nlh; 2041edc9e748SNicolas Dichtel struct netconfmsg *ncm; 2042136ba622SZhang Shengju bool all = false; 2043edc9e748SNicolas Dichtel 2044edc9e748SNicolas Dichtel nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg), 2045edc9e748SNicolas Dichtel flags); 204651456b29SIan Morris if (!nlh) 2047edc9e748SNicolas Dichtel return -EMSGSIZE; 2048edc9e748SNicolas Dichtel 2049136ba622SZhang Shengju if (type == NETCONFA_ALL) 2050136ba622SZhang Shengju all = true; 2051136ba622SZhang Shengju 2052edc9e748SNicolas Dichtel ncm = nlmsg_data(nlh); 2053edc9e748SNicolas Dichtel ncm->ncm_family = AF_INET; 2054edc9e748SNicolas Dichtel 2055edc9e748SNicolas Dichtel if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0) 2056edc9e748SNicolas Dichtel goto nla_put_failure; 2057edc9e748SNicolas Dichtel 2058b5c9641dSDavid Ahern if (!devconf) 2059b5c9641dSDavid Ahern goto out; 2060b5c9641dSDavid Ahern 2061136ba622SZhang Shengju if ((all || type == NETCONFA_FORWARDING) && 2062edc9e748SNicolas Dichtel nla_put_s32(skb, NETCONFA_FORWARDING, 2063edc9e748SNicolas Dichtel IPV4_DEVCONF(*devconf, FORWARDING)) < 0) 2064edc9e748SNicolas Dichtel goto nla_put_failure; 2065136ba622SZhang Shengju if ((all || type == NETCONFA_RP_FILTER) && 2066cc535dfbSNicolas Dichtel nla_put_s32(skb, NETCONFA_RP_FILTER, 2067cc535dfbSNicolas Dichtel IPV4_DEVCONF(*devconf, RP_FILTER)) < 0) 2068cc535dfbSNicolas Dichtel goto nla_put_failure; 2069136ba622SZhang Shengju if ((all || type == NETCONFA_MC_FORWARDING) && 2070d67b8c61SNicolas Dichtel nla_put_s32(skb, NETCONFA_MC_FORWARDING, 2071d67b8c61SNicolas Dichtel IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0) 2072d67b8c61SNicolas Dichtel goto nla_put_failure; 20735cbf777cSXin Long if ((all || type == NETCONFA_BC_FORWARDING) && 20745cbf777cSXin Long nla_put_s32(skb, NETCONFA_BC_FORWARDING, 20755cbf777cSXin Long IPV4_DEVCONF(*devconf, BC_FORWARDING)) < 0) 20765cbf777cSXin Long goto nla_put_failure; 2077136ba622SZhang Shengju if ((all || type == NETCONFA_PROXY_NEIGH) && 207809aea5dfSstephen hemminger nla_put_s32(skb, NETCONFA_PROXY_NEIGH, 2079f085ff1cSstephen hemminger IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0) 2080f085ff1cSstephen hemminger goto nla_put_failure; 2081136ba622SZhang Shengju if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) && 2082974d7af5SAndy Gospodarek nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, 2083974d7af5SAndy Gospodarek IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0) 2084974d7af5SAndy Gospodarek goto nla_put_failure; 2085edc9e748SNicolas Dichtel 2086b5c9641dSDavid Ahern out: 2087053c095aSJohannes Berg nlmsg_end(skb, nlh); 2088053c095aSJohannes Berg return 0; 2089edc9e748SNicolas Dichtel 2090edc9e748SNicolas Dichtel nla_put_failure: 2091edc9e748SNicolas Dichtel nlmsg_cancel(skb, nlh); 2092edc9e748SNicolas Dichtel return -EMSGSIZE; 2093edc9e748SNicolas Dichtel } 2094edc9e748SNicolas Dichtel 20953b022865SDavid Ahern void inet_netconf_notify_devconf(struct net *net, int event, int type, 20963b022865SDavid Ahern int ifindex, struct ipv4_devconf *devconf) 2097edc9e748SNicolas Dichtel { 2098edc9e748SNicolas Dichtel struct sk_buff *skb; 2099edc9e748SNicolas Dichtel int err = -ENOBUFS; 2100edc9e748SNicolas Dichtel 2101fa17806cSEric Dumazet skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL); 210251456b29SIan Morris if (!skb) 2103edc9e748SNicolas Dichtel goto errout; 2104edc9e748SNicolas Dichtel 2105edc9e748SNicolas Dichtel err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0, 21063b022865SDavid Ahern event, 0, type); 2107edc9e748SNicolas Dichtel if (err < 0) { 2108edc9e748SNicolas Dichtel /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */ 2109edc9e748SNicolas Dichtel WARN_ON(err == -EMSGSIZE); 2110edc9e748SNicolas Dichtel kfree_skb(skb); 2111edc9e748SNicolas Dichtel goto errout; 2112edc9e748SNicolas Dichtel } 2113fa17806cSEric Dumazet rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL); 2114edc9e748SNicolas Dichtel return; 2115edc9e748SNicolas Dichtel errout: 2116edc9e748SNicolas Dichtel if (err < 0) 2117edc9e748SNicolas Dichtel rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err); 2118edc9e748SNicolas Dichtel } 2119edc9e748SNicolas Dichtel 21209e551110SNicolas Dichtel static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = { 21219e551110SNicolas Dichtel [NETCONFA_IFINDEX] = { .len = sizeof(int) }, 21229e551110SNicolas Dichtel [NETCONFA_FORWARDING] = { .len = sizeof(int) }, 2123cc535dfbSNicolas Dichtel [NETCONFA_RP_FILTER] = { .len = sizeof(int) }, 212409aea5dfSstephen hemminger [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) }, 2125974d7af5SAndy Gospodarek [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) }, 21269e551110SNicolas Dichtel }; 21279e551110SNicolas Dichtel 2128eede370dSJakub Kicinski static int inet_netconf_valid_get_req(struct sk_buff *skb, 2129eede370dSJakub Kicinski const struct nlmsghdr *nlh, 2130eede370dSJakub Kicinski struct nlattr **tb, 2131eede370dSJakub Kicinski struct netlink_ext_ack *extack) 2132eede370dSJakub Kicinski { 2133eede370dSJakub Kicinski int i, err; 2134eede370dSJakub Kicinski 2135eede370dSJakub Kicinski if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(struct netconfmsg))) { 2136eede370dSJakub Kicinski NL_SET_ERR_MSG(extack, "ipv4: Invalid header for netconf get request"); 2137eede370dSJakub Kicinski return -EINVAL; 2138eede370dSJakub Kicinski } 2139eede370dSJakub Kicinski 2140eede370dSJakub Kicinski if (!netlink_strict_get_check(skb)) 21418cb08174SJohannes Berg return nlmsg_parse_deprecated(nlh, sizeof(struct netconfmsg), 21428cb08174SJohannes Berg tb, NETCONFA_MAX, 21438cb08174SJohannes Berg devconf_ipv4_policy, extack); 2144eede370dSJakub Kicinski 21458cb08174SJohannes Berg err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct netconfmsg), 21468cb08174SJohannes Berg tb, NETCONFA_MAX, 21478cb08174SJohannes Berg devconf_ipv4_policy, extack); 2148eede370dSJakub Kicinski if (err) 2149eede370dSJakub Kicinski return err; 2150eede370dSJakub Kicinski 2151eede370dSJakub Kicinski for (i = 0; i <= NETCONFA_MAX; i++) { 2152eede370dSJakub Kicinski if (!tb[i]) 2153eede370dSJakub Kicinski continue; 2154eede370dSJakub Kicinski 2155eede370dSJakub Kicinski switch (i) { 2156eede370dSJakub Kicinski case NETCONFA_IFINDEX: 2157eede370dSJakub Kicinski break; 2158eede370dSJakub Kicinski default: 2159eede370dSJakub Kicinski NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in netconf get request"); 2160eede370dSJakub Kicinski return -EINVAL; 2161eede370dSJakub Kicinski } 2162eede370dSJakub Kicinski } 2163eede370dSJakub Kicinski 2164eede370dSJakub Kicinski return 0; 2165eede370dSJakub Kicinski } 2166eede370dSJakub Kicinski 21679e551110SNicolas Dichtel static int inet_netconf_get_devconf(struct sk_buff *in_skb, 2168c21ef3e3SDavid Ahern struct nlmsghdr *nlh, 2169c21ef3e3SDavid Ahern struct netlink_ext_ack *extack) 21709e551110SNicolas Dichtel { 21719e551110SNicolas Dichtel struct net *net = sock_net(in_skb->sk); 21729e551110SNicolas Dichtel struct nlattr *tb[NETCONFA_MAX+1]; 21739e551110SNicolas Dichtel struct sk_buff *skb; 21749e551110SNicolas Dichtel struct ipv4_devconf *devconf; 21759e551110SNicolas Dichtel struct in_device *in_dev; 21769e551110SNicolas Dichtel struct net_device *dev; 21779e551110SNicolas Dichtel int ifindex; 21789e551110SNicolas Dichtel int err; 21799e551110SNicolas Dichtel 2180eede370dSJakub Kicinski err = inet_netconf_valid_get_req(in_skb, nlh, tb, extack); 2181eede370dSJakub Kicinski if (err) 21829e551110SNicolas Dichtel goto errout; 21839e551110SNicolas Dichtel 2184a97eb33fSAnton Protopopov err = -EINVAL; 21859e551110SNicolas Dichtel if (!tb[NETCONFA_IFINDEX]) 21869e551110SNicolas Dichtel goto errout; 21879e551110SNicolas Dichtel 21889e551110SNicolas Dichtel ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]); 21899e551110SNicolas Dichtel switch (ifindex) { 21909e551110SNicolas Dichtel case NETCONFA_IFINDEX_ALL: 21919e551110SNicolas Dichtel devconf = net->ipv4.devconf_all; 21929e551110SNicolas Dichtel break; 21939e551110SNicolas Dichtel case NETCONFA_IFINDEX_DEFAULT: 21949e551110SNicolas Dichtel devconf = net->ipv4.devconf_dflt; 21959e551110SNicolas Dichtel break; 21969e551110SNicolas Dichtel default: 21979e551110SNicolas Dichtel dev = __dev_get_by_index(net, ifindex); 219851456b29SIan Morris if (!dev) 21999e551110SNicolas Dichtel goto errout; 22009e551110SNicolas Dichtel in_dev = __in_dev_get_rtnl(dev); 220151456b29SIan Morris if (!in_dev) 22029e551110SNicolas Dichtel goto errout; 22039e551110SNicolas Dichtel devconf = &in_dev->cnf; 22049e551110SNicolas Dichtel break; 22059e551110SNicolas Dichtel } 22069e551110SNicolas Dichtel 22079e551110SNicolas Dichtel err = -ENOBUFS; 2208fa17806cSEric Dumazet skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL); 220951456b29SIan Morris if (!skb) 22109e551110SNicolas Dichtel goto errout; 22119e551110SNicolas Dichtel 22129e551110SNicolas Dichtel err = inet_netconf_fill_devconf(skb, ifindex, devconf, 22139e551110SNicolas Dichtel NETLINK_CB(in_skb).portid, 22149e551110SNicolas Dichtel nlh->nlmsg_seq, RTM_NEWNETCONF, 0, 2215136ba622SZhang Shengju NETCONFA_ALL); 22169e551110SNicolas Dichtel if (err < 0) { 22179e551110SNicolas Dichtel /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */ 22189e551110SNicolas Dichtel WARN_ON(err == -EMSGSIZE); 22199e551110SNicolas Dichtel kfree_skb(skb); 22209e551110SNicolas Dichtel goto errout; 22219e551110SNicolas Dichtel } 22229e551110SNicolas Dichtel err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); 22239e551110SNicolas Dichtel errout: 22249e551110SNicolas Dichtel return err; 22259e551110SNicolas Dichtel } 22269e551110SNicolas Dichtel 22277a674200SNicolas Dichtel static int inet_netconf_dump_devconf(struct sk_buff *skb, 22287a674200SNicolas Dichtel struct netlink_callback *cb) 22297a674200SNicolas Dichtel { 2230addd383fSDavid Ahern const struct nlmsghdr *nlh = cb->nlh; 22317a674200SNicolas Dichtel struct net *net = sock_net(skb->sk); 22327a674200SNicolas Dichtel int h, s_h; 22337a674200SNicolas Dichtel int idx, s_idx; 22347a674200SNicolas Dichtel struct net_device *dev; 22357a674200SNicolas Dichtel struct in_device *in_dev; 22367a674200SNicolas Dichtel struct hlist_head *head; 22377a674200SNicolas Dichtel 2238addd383fSDavid Ahern if (cb->strict_check) { 2239addd383fSDavid Ahern struct netlink_ext_ack *extack = cb->extack; 2240addd383fSDavid Ahern struct netconfmsg *ncm; 2241addd383fSDavid Ahern 2242addd383fSDavid Ahern if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ncm))) { 2243addd383fSDavid Ahern NL_SET_ERR_MSG(extack, "ipv4: Invalid header for netconf dump request"); 2244addd383fSDavid Ahern return -EINVAL; 2245addd383fSDavid Ahern } 2246addd383fSDavid Ahern 2247addd383fSDavid Ahern if (nlmsg_attrlen(nlh, sizeof(*ncm))) { 2248addd383fSDavid Ahern NL_SET_ERR_MSG(extack, "ipv4: Invalid data after header in netconf dump request"); 2249addd383fSDavid Ahern return -EINVAL; 2250addd383fSDavid Ahern } 2251addd383fSDavid Ahern } 2252addd383fSDavid Ahern 22537a674200SNicolas Dichtel s_h = cb->args[0]; 22547a674200SNicolas Dichtel s_idx = idx = cb->args[1]; 22557a674200SNicolas Dichtel 22567a674200SNicolas Dichtel for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { 22577a674200SNicolas Dichtel idx = 0; 22587a674200SNicolas Dichtel head = &net->dev_index_head[h]; 22597a674200SNicolas Dichtel rcu_read_lock(); 22600465277fSNicolas Dichtel cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^ 22610465277fSNicolas Dichtel net->dev_base_seq; 22627a674200SNicolas Dichtel hlist_for_each_entry_rcu(dev, head, index_hlist) { 22637a674200SNicolas Dichtel if (idx < s_idx) 22647a674200SNicolas Dichtel goto cont; 22657a674200SNicolas Dichtel in_dev = __in_dev_get_rcu(dev); 22667a674200SNicolas Dichtel if (!in_dev) 22677a674200SNicolas Dichtel goto cont; 22687a674200SNicolas Dichtel 22697a674200SNicolas Dichtel if (inet_netconf_fill_devconf(skb, dev->ifindex, 22707a674200SNicolas Dichtel &in_dev->cnf, 22717a674200SNicolas Dichtel NETLINK_CB(cb->skb).portid, 2272addd383fSDavid Ahern nlh->nlmsg_seq, 22737a674200SNicolas Dichtel RTM_NEWNETCONF, 22747a674200SNicolas Dichtel NLM_F_MULTI, 2275136ba622SZhang Shengju NETCONFA_ALL) < 0) { 22767a674200SNicolas Dichtel rcu_read_unlock(); 22777a674200SNicolas Dichtel goto done; 22787a674200SNicolas Dichtel } 22790465277fSNicolas Dichtel nl_dump_check_consistent(cb, nlmsg_hdr(skb)); 22807a674200SNicolas Dichtel cont: 22817a674200SNicolas Dichtel idx++; 22827a674200SNicolas Dichtel } 22837a674200SNicolas Dichtel rcu_read_unlock(); 22847a674200SNicolas Dichtel } 22857a674200SNicolas Dichtel if (h == NETDEV_HASHENTRIES) { 22867a674200SNicolas Dichtel if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL, 22877a674200SNicolas Dichtel net->ipv4.devconf_all, 22887a674200SNicolas Dichtel NETLINK_CB(cb->skb).portid, 2289addd383fSDavid Ahern nlh->nlmsg_seq, 22907a674200SNicolas Dichtel RTM_NEWNETCONF, NLM_F_MULTI, 2291136ba622SZhang Shengju NETCONFA_ALL) < 0) 22927a674200SNicolas Dichtel goto done; 22937a674200SNicolas Dichtel else 22947a674200SNicolas Dichtel h++; 22957a674200SNicolas Dichtel } 22967a674200SNicolas Dichtel if (h == NETDEV_HASHENTRIES + 1) { 22977a674200SNicolas Dichtel if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT, 22987a674200SNicolas Dichtel net->ipv4.devconf_dflt, 22997a674200SNicolas Dichtel NETLINK_CB(cb->skb).portid, 2300addd383fSDavid Ahern nlh->nlmsg_seq, 23017a674200SNicolas Dichtel RTM_NEWNETCONF, NLM_F_MULTI, 2302136ba622SZhang Shengju NETCONFA_ALL) < 0) 23037a674200SNicolas Dichtel goto done; 23047a674200SNicolas Dichtel else 23057a674200SNicolas Dichtel h++; 23067a674200SNicolas Dichtel } 23077a674200SNicolas Dichtel done: 23087a674200SNicolas Dichtel cb->args[0] = h; 23097a674200SNicolas Dichtel cb->args[1] = idx; 23107a674200SNicolas Dichtel 23117a674200SNicolas Dichtel return skb->len; 23127a674200SNicolas Dichtel } 23137a674200SNicolas Dichtel 23141da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL 23151da177e4SLinus Torvalds 2316c0ce9fb3SPavel Emelyanov static void devinet_copy_dflt_conf(struct net *net, int i) 231731be3085SHerbert Xu { 231831be3085SHerbert Xu struct net_device *dev; 231931be3085SHerbert Xu 232031be3085SHerbert Xu rcu_read_lock(); 2321c6d14c84SEric Dumazet for_each_netdev_rcu(net, dev) { 2322c6d14c84SEric Dumazet struct in_device *in_dev; 2323c6d14c84SEric Dumazet 232431be3085SHerbert Xu in_dev = __in_dev_get_rcu(dev); 232531be3085SHerbert Xu if (in_dev && !test_bit(i, in_dev->cnf.state)) 23269355bbd6SPavel Emelyanov in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i]; 2327c6d14c84SEric Dumazet } 232831be3085SHerbert Xu rcu_read_unlock(); 232931be3085SHerbert Xu } 233031be3085SHerbert Xu 2331c6d14c84SEric Dumazet /* called with RTNL locked */ 2332c0ce9fb3SPavel Emelyanov static void inet_forward_change(struct net *net) 233368dd299bSPavel Emelyanov { 233468dd299bSPavel Emelyanov struct net_device *dev; 2335586f1211SPavel Emelyanov int on = IPV4_DEVCONF_ALL(net, FORWARDING); 233668dd299bSPavel Emelyanov 2337586f1211SPavel Emelyanov IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on; 23389355bbd6SPavel Emelyanov IPV4_DEVCONF_DFLT(net, FORWARDING) = on; 23393b022865SDavid Ahern inet_netconf_notify_devconf(net, RTM_NEWNETCONF, 23403b022865SDavid Ahern NETCONFA_FORWARDING, 2341edc9e748SNicolas Dichtel NETCONFA_IFINDEX_ALL, 2342edc9e748SNicolas Dichtel net->ipv4.devconf_all); 23433b022865SDavid Ahern inet_netconf_notify_devconf(net, RTM_NEWNETCONF, 23443b022865SDavid Ahern NETCONFA_FORWARDING, 2345edc9e748SNicolas Dichtel NETCONFA_IFINDEX_DEFAULT, 2346edc9e748SNicolas Dichtel net->ipv4.devconf_dflt); 234768dd299bSPavel Emelyanov 2348c0ce9fb3SPavel Emelyanov for_each_netdev(net, dev) { 234968dd299bSPavel Emelyanov struct in_device *in_dev; 2350fa17806cSEric Dumazet 23510187bdfbSBen Hutchings if (on) 23520187bdfbSBen Hutchings dev_disable_lro(dev); 2353fa17806cSEric Dumazet 2354fa17806cSEric Dumazet in_dev = __in_dev_get_rtnl(dev); 2355edc9e748SNicolas Dichtel if (in_dev) { 235668dd299bSPavel Emelyanov IN_DEV_CONF_SET(in_dev, FORWARDING, on); 23573b022865SDavid Ahern inet_netconf_notify_devconf(net, RTM_NEWNETCONF, 23583b022865SDavid Ahern NETCONFA_FORWARDING, 2359edc9e748SNicolas Dichtel dev->ifindex, &in_dev->cnf); 2360edc9e748SNicolas Dichtel } 236168dd299bSPavel Emelyanov } 236268dd299bSPavel Emelyanov } 236368dd299bSPavel Emelyanov 2364f085ff1cSstephen hemminger static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf) 2365f085ff1cSstephen hemminger { 2366f085ff1cSstephen hemminger if (cnf == net->ipv4.devconf_dflt) 2367f085ff1cSstephen hemminger return NETCONFA_IFINDEX_DEFAULT; 2368f085ff1cSstephen hemminger else if (cnf == net->ipv4.devconf_all) 2369f085ff1cSstephen hemminger return NETCONFA_IFINDEX_ALL; 2370f085ff1cSstephen hemminger else { 2371f085ff1cSstephen hemminger struct in_device *idev 2372f085ff1cSstephen hemminger = container_of(cnf, struct in_device, cnf); 2373f085ff1cSstephen hemminger return idev->dev->ifindex; 2374f085ff1cSstephen hemminger } 2375f085ff1cSstephen hemminger } 2376f085ff1cSstephen hemminger 2377fe2c6338SJoe Perches static int devinet_conf_proc(struct ctl_table *ctl, int write, 237832927393SChristoph Hellwig void *buffer, size_t *lenp, loff_t *ppos) 237931be3085SHerbert Xu { 2380d01ff0a0SPeter Pan(潘卫平) int old_value = *(int *)ctl->data; 23818d65af78SAlexey Dobriyan int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); 2382d01ff0a0SPeter Pan(潘卫平) int new_value = *(int *)ctl->data; 238331be3085SHerbert Xu 238431be3085SHerbert Xu if (write) { 238531be3085SHerbert Xu struct ipv4_devconf *cnf = ctl->extra1; 2386c0ce9fb3SPavel Emelyanov struct net *net = ctl->extra2; 238731be3085SHerbert Xu int i = (int *)ctl->data - cnf->data; 2388f085ff1cSstephen hemminger int ifindex; 238931be3085SHerbert Xu 239031be3085SHerbert Xu set_bit(i, cnf->state); 239131be3085SHerbert Xu 23929355bbd6SPavel Emelyanov if (cnf == net->ipv4.devconf_dflt) 2393c0ce9fb3SPavel Emelyanov devinet_copy_dflt_conf(net, i); 2394d0daebc3SThomas Graf if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 || 2395d0daebc3SThomas Graf i == IPV4_DEVCONF_ROUTE_LOCALNET - 1) 2396d01ff0a0SPeter Pan(潘卫平) if ((new_value == 0) && (old_value != 0)) 23974ccfe6d4SNicolas Dichtel rt_cache_flush(net); 2398f085ff1cSstephen hemminger 23995cbf777cSXin Long if (i == IPV4_DEVCONF_BC_FORWARDING - 1 && 24005cbf777cSXin Long new_value != old_value) 24015cbf777cSXin Long rt_cache_flush(net); 24025cbf777cSXin Long 2403cc535dfbSNicolas Dichtel if (i == IPV4_DEVCONF_RP_FILTER - 1 && 2404cc535dfbSNicolas Dichtel new_value != old_value) { 2405f085ff1cSstephen hemminger ifindex = devinet_conf_ifindex(net, cnf); 24063b022865SDavid Ahern inet_netconf_notify_devconf(net, RTM_NEWNETCONF, 24073b022865SDavid Ahern NETCONFA_RP_FILTER, 2408cc535dfbSNicolas Dichtel ifindex, cnf); 2409cc535dfbSNicolas Dichtel } 2410f085ff1cSstephen hemminger if (i == IPV4_DEVCONF_PROXY_ARP - 1 && 2411f085ff1cSstephen hemminger new_value != old_value) { 2412f085ff1cSstephen hemminger ifindex = devinet_conf_ifindex(net, cnf); 24133b022865SDavid Ahern inet_netconf_notify_devconf(net, RTM_NEWNETCONF, 24143b022865SDavid Ahern NETCONFA_PROXY_NEIGH, 2415f085ff1cSstephen hemminger ifindex, cnf); 2416f085ff1cSstephen hemminger } 2417974d7af5SAndy Gospodarek if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 && 2418974d7af5SAndy Gospodarek new_value != old_value) { 2419974d7af5SAndy Gospodarek ifindex = devinet_conf_ifindex(net, cnf); 24203b022865SDavid Ahern inet_netconf_notify_devconf(net, RTM_NEWNETCONF, 24213b022865SDavid Ahern NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, 2422974d7af5SAndy Gospodarek ifindex, cnf); 2423974d7af5SAndy Gospodarek } 242431be3085SHerbert Xu } 242531be3085SHerbert Xu 242631be3085SHerbert Xu return ret; 242731be3085SHerbert Xu } 242831be3085SHerbert Xu 2429fe2c6338SJoe Perches static int devinet_sysctl_forward(struct ctl_table *ctl, int write, 243032927393SChristoph Hellwig void *buffer, size_t *lenp, loff_t *ppos) 24311da177e4SLinus Torvalds { 24321da177e4SLinus Torvalds int *valp = ctl->data; 24331da177e4SLinus Torvalds int val = *valp; 243488af182eSEric W. Biederman loff_t pos = *ppos; 24358292d7f6SYang Yang struct net *net = ctl->extra2; 24368292d7f6SYang Yang int ret; 24378292d7f6SYang Yang 24388292d7f6SYang Yang if (write && !ns_capable(net->user_ns, CAP_NET_ADMIN)) 24398292d7f6SYang Yang return -EPERM; 24408292d7f6SYang Yang 24418292d7f6SYang Yang ret = proc_dointvec(ctl, write, buffer, lenp, ppos); 24421da177e4SLinus Torvalds 24431da177e4SLinus Torvalds if (write && *valp != val) { 24440187bdfbSBen Hutchings if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) { 244588af182eSEric W. Biederman if (!rtnl_trylock()) { 244688af182eSEric W. Biederman /* Restore the original values before restarting */ 244788af182eSEric W. Biederman *valp = val; 244888af182eSEric W. Biederman *ppos = pos; 24499b8adb5eSEric W. Biederman return restart_syscall(); 245088af182eSEric W. Biederman } 24510187bdfbSBen Hutchings if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) { 2452c0ce9fb3SPavel Emelyanov inet_forward_change(net); 2453edc9e748SNicolas Dichtel } else { 24540187bdfbSBen Hutchings struct ipv4_devconf *cnf = ctl->extra1; 24550187bdfbSBen Hutchings struct in_device *idev = 24560187bdfbSBen Hutchings container_of(cnf, struct in_device, cnf); 2457edc9e748SNicolas Dichtel if (*valp) 24580187bdfbSBen Hutchings dev_disable_lro(idev->dev); 24593b022865SDavid Ahern inet_netconf_notify_devconf(net, RTM_NEWNETCONF, 2460edc9e748SNicolas Dichtel NETCONFA_FORWARDING, 2461edc9e748SNicolas Dichtel idev->dev->ifindex, 2462edc9e748SNicolas Dichtel cnf); 24630187bdfbSBen Hutchings } 24640187bdfbSBen Hutchings rtnl_unlock(); 24654ccfe6d4SNicolas Dichtel rt_cache_flush(net); 2466edc9e748SNicolas Dichtel } else 24673b022865SDavid Ahern inet_netconf_notify_devconf(net, RTM_NEWNETCONF, 24683b022865SDavid Ahern NETCONFA_FORWARDING, 2469edc9e748SNicolas Dichtel NETCONFA_IFINDEX_DEFAULT, 2470edc9e748SNicolas Dichtel net->ipv4.devconf_dflt); 24710187bdfbSBen Hutchings } 24721da177e4SLinus Torvalds 24731da177e4SLinus Torvalds return ret; 24741da177e4SLinus Torvalds } 24751da177e4SLinus Torvalds 2476fe2c6338SJoe Perches static int ipv4_doint_and_flush(struct ctl_table *ctl, int write, 247732927393SChristoph Hellwig void *buffer, size_t *lenp, loff_t *ppos) 24781da177e4SLinus Torvalds { 24791da177e4SLinus Torvalds int *valp = ctl->data; 24801da177e4SLinus Torvalds int val = *valp; 24818d65af78SAlexey Dobriyan int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); 248276e6ebfbSDenis V. Lunev struct net *net = ctl->extra2; 24831da177e4SLinus Torvalds 24841da177e4SLinus Torvalds if (write && *valp != val) 24854ccfe6d4SNicolas Dichtel rt_cache_flush(net); 24861da177e4SLinus Torvalds 24871da177e4SLinus Torvalds return ret; 24881da177e4SLinus Torvalds } 24891da177e4SLinus Torvalds 2490f8572d8fSEric W. Biederman #define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \ 249142f811b8SHerbert Xu { \ 249242f811b8SHerbert Xu .procname = name, \ 249342f811b8SHerbert Xu .data = ipv4_devconf.data + \ 249402291680SEric W. Biederman IPV4_DEVCONF_ ## attr - 1, \ 249542f811b8SHerbert Xu .maxlen = sizeof(int), \ 249642f811b8SHerbert Xu .mode = mval, \ 249742f811b8SHerbert Xu .proc_handler = proc, \ 249831be3085SHerbert Xu .extra1 = &ipv4_devconf, \ 249942f811b8SHerbert Xu } 250042f811b8SHerbert Xu 250142f811b8SHerbert Xu #define DEVINET_SYSCTL_RW_ENTRY(attr, name) \ 2502f8572d8fSEric W. Biederman DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc) 250342f811b8SHerbert Xu 250442f811b8SHerbert Xu #define DEVINET_SYSCTL_RO_ENTRY(attr, name) \ 2505f8572d8fSEric W. Biederman DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc) 250642f811b8SHerbert Xu 2507f8572d8fSEric W. Biederman #define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \ 2508f8572d8fSEric W. Biederman DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc) 250942f811b8SHerbert Xu 251042f811b8SHerbert Xu #define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \ 2511f8572d8fSEric W. Biederman DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush) 251242f811b8SHerbert Xu 25131da177e4SLinus Torvalds static struct devinet_sysctl_table { 25141da177e4SLinus Torvalds struct ctl_table_header *sysctl_header; 251502291680SEric W. Biederman struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX]; 25161da177e4SLinus Torvalds } devinet_sysctl = { 25171da177e4SLinus Torvalds .devinet_vars = { 251842f811b8SHerbert Xu DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding", 2519f8572d8fSEric W. Biederman devinet_sysctl_forward), 252042f811b8SHerbert Xu DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"), 25215cbf777cSXin Long DEVINET_SYSCTL_RW_ENTRY(BC_FORWARDING, "bc_forwarding"), 252242f811b8SHerbert Xu 252342f811b8SHerbert Xu DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"), 252442f811b8SHerbert Xu DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"), 252542f811b8SHerbert Xu DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"), 252642f811b8SHerbert Xu DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"), 252742f811b8SHerbert Xu DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"), 252842f811b8SHerbert Xu DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE, 252942f811b8SHerbert Xu "accept_source_route"), 25308153a10cSPatrick McHardy DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"), 253128f6aeeaSJamal Hadi Salim DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"), 253242f811b8SHerbert Xu DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"), 253342f811b8SHerbert Xu DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"), 253442f811b8SHerbert Xu DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"), 253542f811b8SHerbert Xu DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"), 253642f811b8SHerbert Xu DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"), 253742f811b8SHerbert Xu DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"), 253842f811b8SHerbert Xu DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"), 253942f811b8SHerbert Xu DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"), 254042f811b8SHerbert Xu DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"), 2541eefef1cfSStephen Hemminger DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"), 2542fcdb44d0SJames Prestwood DEVINET_SYSCTL_RW_ENTRY(ARP_EVICT_NOCARRIER, 2543fcdb44d0SJames Prestwood "arp_evict_nocarrier"), 254465324144SJesper Dangaard Brouer DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"), 25455c6fe01cSWilliam Manley DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION, 25465c6fe01cSWilliam Manley "force_igmp_version"), 25472690048cSWilliam Manley DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL, 25482690048cSWilliam Manley "igmpv2_unsolicited_report_interval"), 25492690048cSWilliam Manley DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL, 25502690048cSWilliam Manley "igmpv3_unsolicited_report_interval"), 25510eeb075fSAndy Gospodarek DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN, 25520eeb075fSAndy Gospodarek "ignore_routes_with_linkdown"), 255397daf331SJohannes Berg DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP, 255497daf331SJohannes Berg "drop_gratuitous_arp"), 255542f811b8SHerbert Xu 255642f811b8SHerbert Xu DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"), 255742f811b8SHerbert Xu DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"), 255842f811b8SHerbert Xu DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES, 255942f811b8SHerbert Xu "promote_secondaries"), 2560d0daebc3SThomas Graf DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET, 2561d0daebc3SThomas Graf "route_localnet"), 256212b74dfaSJohannes Berg DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST, 256312b74dfaSJohannes Berg "drop_unicast_in_l2_multicast"), 25641da177e4SLinus Torvalds }, 25651da177e4SLinus Torvalds }; 25661da177e4SLinus Torvalds 2567ea40b324SPavel Emelyanov static int __devinet_sysctl_register(struct net *net, char *dev_name, 256829c994e3SNicolas Dichtel int ifindex, struct ipv4_devconf *p) 25691da177e4SLinus Torvalds { 25701da177e4SLinus Torvalds int i; 25719fa89642SPavel Emelyanov struct devinet_sysctl_table *t; 25728607ddb8SEric W. Biederman char path[sizeof("net/ipv4/conf/") + IFNAMSIZ]; 2573bfada697SPavel Emelyanov 25749fa89642SPavel Emelyanov t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL); 25751da177e4SLinus Torvalds if (!t) 25769fa89642SPavel Emelyanov goto out; 25779fa89642SPavel Emelyanov 25781da177e4SLinus Torvalds for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) { 25791da177e4SLinus Torvalds t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf; 258031be3085SHerbert Xu t->devinet_vars[i].extra1 = p; 2581c0ce9fb3SPavel Emelyanov t->devinet_vars[i].extra2 = net; 25821da177e4SLinus Torvalds } 25831da177e4SLinus Torvalds 25848607ddb8SEric W. Biederman snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name); 25851da177e4SLinus Torvalds 25868607ddb8SEric W. Biederman t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars); 25871da177e4SLinus Torvalds if (!t->sysctl_header) 25888607ddb8SEric W. Biederman goto free; 25891da177e4SLinus Torvalds 25901da177e4SLinus Torvalds p->sysctl = t; 259129c994e3SNicolas Dichtel 25923b022865SDavid Ahern inet_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_ALL, 25933b022865SDavid Ahern ifindex, p); 2594ea40b324SPavel Emelyanov return 0; 25951da177e4SLinus Torvalds 25961da177e4SLinus Torvalds free: 25971da177e4SLinus Torvalds kfree(t); 25989fa89642SPavel Emelyanov out: 25996def4801Sliuguoqiang return -ENOMEM; 26001da177e4SLinus Torvalds } 26011da177e4SLinus Torvalds 2602b5c9641dSDavid Ahern static void __devinet_sysctl_unregister(struct net *net, 2603b5c9641dSDavid Ahern struct ipv4_devconf *cnf, int ifindex) 260466f27a52SPavel Emelyanov { 260551602b2aSPavel Emelyanov struct devinet_sysctl_table *t = cnf->sysctl; 260666f27a52SPavel Emelyanov 2607b5c9641dSDavid Ahern if (t) { 260851602b2aSPavel Emelyanov cnf->sysctl = NULL; 2609ff538818SLucian Adrian Grijincu unregister_net_sysctl_table(t->sysctl_header); 26101da177e4SLinus Torvalds kfree(t); 26111da177e4SLinus Torvalds } 261251602b2aSPavel Emelyanov 2613b5c9641dSDavid Ahern inet_netconf_notify_devconf(net, RTM_DELNETCONF, 0, ifindex, NULL); 2614b5c9641dSDavid Ahern } 2615b5c9641dSDavid Ahern 261620e61da7SWANG Cong static int devinet_sysctl_register(struct in_device *idev) 261751602b2aSPavel Emelyanov { 261820e61da7SWANG Cong int err; 261920e61da7SWANG Cong 262020e61da7SWANG Cong if (!sysctl_dev_name_is_allowed(idev->dev->name)) 262120e61da7SWANG Cong return -EINVAL; 262220e61da7SWANG Cong 262320e61da7SWANG Cong err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL); 262420e61da7SWANG Cong if (err) 262520e61da7SWANG Cong return err; 262620e61da7SWANG Cong err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name, 262729c994e3SNicolas Dichtel idev->dev->ifindex, &idev->cnf); 262820e61da7SWANG Cong if (err) 262920e61da7SWANG Cong neigh_sysctl_unregister(idev->arp_parms); 263020e61da7SWANG Cong return err; 263151602b2aSPavel Emelyanov } 263251602b2aSPavel Emelyanov 263351602b2aSPavel Emelyanov static void devinet_sysctl_unregister(struct in_device *idev) 263451602b2aSPavel Emelyanov { 2635b5c9641dSDavid Ahern struct net *net = dev_net(idev->dev); 2636b5c9641dSDavid Ahern 2637b5c9641dSDavid Ahern __devinet_sysctl_unregister(net, &idev->cnf, idev->dev->ifindex); 263851602b2aSPavel Emelyanov neigh_sysctl_unregister(idev->arp_parms); 26391da177e4SLinus Torvalds } 26401da177e4SLinus Torvalds 264168dd299bSPavel Emelyanov static struct ctl_table ctl_forward_entry[] = { 264268dd299bSPavel Emelyanov { 264368dd299bSPavel Emelyanov .procname = "ip_forward", 264468dd299bSPavel Emelyanov .data = &ipv4_devconf.data[ 264502291680SEric W. Biederman IPV4_DEVCONF_FORWARDING - 1], 264668dd299bSPavel Emelyanov .maxlen = sizeof(int), 264768dd299bSPavel Emelyanov .mode = 0644, 264868dd299bSPavel Emelyanov .proc_handler = devinet_sysctl_forward, 264968dd299bSPavel Emelyanov .extra1 = &ipv4_devconf, 2650c0ce9fb3SPavel Emelyanov .extra2 = &init_net, 265168dd299bSPavel Emelyanov }, 265268dd299bSPavel Emelyanov { }, 265368dd299bSPavel Emelyanov }; 26542a75de0cSEric Dumazet #endif 265568dd299bSPavel Emelyanov 2656752d14dcSPavel Emelyanov static __net_init int devinet_init_net(struct net *net) 2657752d14dcSPavel Emelyanov { 2658752d14dcSPavel Emelyanov int err; 2659752d14dcSPavel Emelyanov struct ipv4_devconf *all, *dflt; 26602a75de0cSEric Dumazet #ifdef CONFIG_SYSCTL 2661856c395cSCong Wang struct ctl_table *tbl; 2662752d14dcSPavel Emelyanov struct ctl_table_header *forw_hdr; 26632a75de0cSEric Dumazet #endif 2664752d14dcSPavel Emelyanov 2665752d14dcSPavel Emelyanov err = -ENOMEM; 2666856c395cSCong Wang all = kmemdup(&ipv4_devconf, sizeof(ipv4_devconf), GFP_KERNEL); 266751456b29SIan Morris if (!all) 2668752d14dcSPavel Emelyanov goto err_alloc_all; 2669752d14dcSPavel Emelyanov 2670856c395cSCong Wang dflt = kmemdup(&ipv4_devconf_dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL); 267151456b29SIan Morris if (!dflt) 2672752d14dcSPavel Emelyanov goto err_alloc_dflt; 2673752d14dcSPavel Emelyanov 26742a75de0cSEric Dumazet #ifdef CONFIG_SYSCTL 2675856c395cSCong Wang tbl = kmemdup(ctl_forward_entry, sizeof(ctl_forward_entry), GFP_KERNEL); 267651456b29SIan Morris if (!tbl) 2677752d14dcSPavel Emelyanov goto err_alloc_ctl; 2678752d14dcSPavel Emelyanov 267902291680SEric W. Biederman tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1]; 2680752d14dcSPavel Emelyanov tbl[0].extra1 = all; 2681752d14dcSPavel Emelyanov tbl[0].extra2 = net; 26822a75de0cSEric Dumazet #endif 2683856c395cSCong Wang 26849efd6a3cSNicolas Dichtel if (!net_eq(net, &init_net)) { 26859efd6a3cSNicolas Dichtel if (IS_ENABLED(CONFIG_SYSCTL) && 26869efd6a3cSNicolas Dichtel sysctl_devconf_inherit_init_net == 3) { 26879efd6a3cSNicolas Dichtel /* copy from the current netns */ 26889efd6a3cSNicolas Dichtel memcpy(all, current->nsproxy->net_ns->ipv4.devconf_all, 26899efd6a3cSNicolas Dichtel sizeof(ipv4_devconf)); 26909efd6a3cSNicolas Dichtel memcpy(dflt, 26919efd6a3cSNicolas Dichtel current->nsproxy->net_ns->ipv4.devconf_dflt, 26929efd6a3cSNicolas Dichtel sizeof(ipv4_devconf_dflt)); 26939efd6a3cSNicolas Dichtel } else if (!IS_ENABLED(CONFIG_SYSCTL) || 26949efd6a3cSNicolas Dichtel sysctl_devconf_inherit_init_net != 2) { 26959efd6a3cSNicolas Dichtel /* inherit == 0 or 1: copy from init_net */ 26969efd6a3cSNicolas Dichtel memcpy(all, init_net.ipv4.devconf_all, 26979efd6a3cSNicolas Dichtel sizeof(ipv4_devconf)); 26989efd6a3cSNicolas Dichtel memcpy(dflt, init_net.ipv4.devconf_dflt, 26999efd6a3cSNicolas Dichtel sizeof(ipv4_devconf_dflt)); 27009efd6a3cSNicolas Dichtel } 27019efd6a3cSNicolas Dichtel /* else inherit == 2: use compiled values */ 2702752d14dcSPavel Emelyanov } 2703752d14dcSPavel Emelyanov 2704752d14dcSPavel Emelyanov #ifdef CONFIG_SYSCTL 270529c994e3SNicolas Dichtel err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all); 2706752d14dcSPavel Emelyanov if (err < 0) 2707752d14dcSPavel Emelyanov goto err_reg_all; 2708752d14dcSPavel Emelyanov 270929c994e3SNicolas Dichtel err = __devinet_sysctl_register(net, "default", 271029c994e3SNicolas Dichtel NETCONFA_IFINDEX_DEFAULT, dflt); 2711752d14dcSPavel Emelyanov if (err < 0) 2712752d14dcSPavel Emelyanov goto err_reg_dflt; 2713752d14dcSPavel Emelyanov 2714752d14dcSPavel Emelyanov err = -ENOMEM; 27158607ddb8SEric W. Biederman forw_hdr = register_net_sysctl(net, "net/ipv4", tbl); 271651456b29SIan Morris if (!forw_hdr) 2717752d14dcSPavel Emelyanov goto err_reg_ctl; 27182a75de0cSEric Dumazet net->ipv4.forw_hdr = forw_hdr; 2719752d14dcSPavel Emelyanov #endif 2720752d14dcSPavel Emelyanov 2721752d14dcSPavel Emelyanov net->ipv4.devconf_all = all; 2722752d14dcSPavel Emelyanov net->ipv4.devconf_dflt = dflt; 2723752d14dcSPavel Emelyanov return 0; 2724752d14dcSPavel Emelyanov 2725752d14dcSPavel Emelyanov #ifdef CONFIG_SYSCTL 2726752d14dcSPavel Emelyanov err_reg_ctl: 2727b5c9641dSDavid Ahern __devinet_sysctl_unregister(net, dflt, NETCONFA_IFINDEX_DEFAULT); 2728752d14dcSPavel Emelyanov err_reg_dflt: 2729b5c9641dSDavid Ahern __devinet_sysctl_unregister(net, all, NETCONFA_IFINDEX_ALL); 2730752d14dcSPavel Emelyanov err_reg_all: 2731752d14dcSPavel Emelyanov kfree(tbl); 2732752d14dcSPavel Emelyanov err_alloc_ctl: 27332a75de0cSEric Dumazet #endif 2734752d14dcSPavel Emelyanov kfree(dflt); 2735752d14dcSPavel Emelyanov err_alloc_dflt: 2736752d14dcSPavel Emelyanov kfree(all); 2737752d14dcSPavel Emelyanov err_alloc_all: 2738752d14dcSPavel Emelyanov return err; 2739752d14dcSPavel Emelyanov } 2740752d14dcSPavel Emelyanov 2741752d14dcSPavel Emelyanov static __net_exit void devinet_exit_net(struct net *net) 2742752d14dcSPavel Emelyanov { 27432a75de0cSEric Dumazet #ifdef CONFIG_SYSCTL 2744752d14dcSPavel Emelyanov struct ctl_table *tbl; 2745752d14dcSPavel Emelyanov 2746752d14dcSPavel Emelyanov tbl = net->ipv4.forw_hdr->ctl_table_arg; 2747752d14dcSPavel Emelyanov unregister_net_sysctl_table(net->ipv4.forw_hdr); 2748b5c9641dSDavid Ahern __devinet_sysctl_unregister(net, net->ipv4.devconf_dflt, 2749b5c9641dSDavid Ahern NETCONFA_IFINDEX_DEFAULT); 2750b5c9641dSDavid Ahern __devinet_sysctl_unregister(net, net->ipv4.devconf_all, 2751b5c9641dSDavid Ahern NETCONFA_IFINDEX_ALL); 2752752d14dcSPavel Emelyanov kfree(tbl); 27532a75de0cSEric Dumazet #endif 2754752d14dcSPavel Emelyanov kfree(net->ipv4.devconf_dflt); 2755752d14dcSPavel Emelyanov kfree(net->ipv4.devconf_all); 2756752d14dcSPavel Emelyanov } 2757752d14dcSPavel Emelyanov 2758752d14dcSPavel Emelyanov static __net_initdata struct pernet_operations devinet_ops = { 2759752d14dcSPavel Emelyanov .init = devinet_init_net, 2760752d14dcSPavel Emelyanov .exit = devinet_exit_net, 2761752d14dcSPavel Emelyanov }; 2762752d14dcSPavel Emelyanov 2763207895fdSDaniel Borkmann static struct rtnl_af_ops inet_af_ops __read_mostly = { 27649f0f7272SThomas Graf .family = AF_INET, 27659f0f7272SThomas Graf .fill_link_af = inet_fill_link_af, 27669f0f7272SThomas Graf .get_link_af_size = inet_get_link_af_size, 2767cf7afbfeSThomas Graf .validate_link_af = inet_validate_link_af, 2768cf7afbfeSThomas Graf .set_link_af = inet_set_link_af, 27699f0f7272SThomas Graf }; 27709f0f7272SThomas Graf 27711da177e4SLinus Torvalds void __init devinet_init(void) 27721da177e4SLinus Torvalds { 2773fd23c3b3SDavid S. Miller int i; 2774fd23c3b3SDavid S. Miller 2775fd23c3b3SDavid S. Miller for (i = 0; i < IN4_ADDR_HSIZE; i++) 2776fd23c3b3SDavid S. Miller INIT_HLIST_HEAD(&inet_addr_lst[i]); 2777fd23c3b3SDavid S. Miller 2778752d14dcSPavel Emelyanov register_pernet_subsys(&devinet_ops); 27791da177e4SLinus Torvalds register_netdevice_notifier(&ip_netdev_notifier); 278063f3444fSThomas Graf 2781906e073fSviresh kumar queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0); 27825c766d64SJiri Pirko 27839f0f7272SThomas Graf rtnl_af_register(&inet_af_ops); 27849f0f7272SThomas Graf 2785b97bac64SFlorian Westphal rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, 0); 2786b97bac64SFlorian Westphal rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, 0); 2787b97bac64SFlorian Westphal rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, 0); 27889e551110SNicolas Dichtel rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf, 2789b97bac64SFlorian Westphal inet_netconf_dump_devconf, 0); 27901da177e4SLinus Torvalds } 2791