xref: /linux/net/ipv4/devinet.c (revision 32a4be48907b930606f8736caa15c812af802227)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *	NET3	IP device support routines.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *		This program is free software; you can redistribute it and/or
51da177e4SLinus Torvalds  *		modify it under the terms of the GNU General Public License
61da177e4SLinus Torvalds  *		as published by the Free Software Foundation; either version
71da177e4SLinus Torvalds  *		2 of the License, or (at your option) any later version.
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *	Derived from the IP parts of dev.c 1.0.19
1002c30a84SJesper Juhl  * 		Authors:	Ross Biro
111da177e4SLinus Torvalds  *				Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
121da177e4SLinus Torvalds  *				Mark Evans, <evansmp@uhura.aston.ac.uk>
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  *	Additional Authors:
151da177e4SLinus Torvalds  *		Alan Cox, <gw4pts@gw4pts.ampr.org>
161da177e4SLinus Torvalds  *		Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  *	Changes:
191da177e4SLinus Torvalds  *		Alexey Kuznetsov:	pa_* fields are replaced with ifaddr
201da177e4SLinus Torvalds  *					lists.
211da177e4SLinus Torvalds  *		Cyrus Durgin:		updated for kmod
221da177e4SLinus Torvalds  *		Matthias Andree:	in devinet_ioctl, compare label and
231da177e4SLinus Torvalds  *					address (4.4BSD alias style support),
241da177e4SLinus Torvalds  *					fall back to comparing just the label
251da177e4SLinus Torvalds  *					if no match found.
261da177e4SLinus Torvalds  */
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds #include <asm/uaccess.h>
301da177e4SLinus Torvalds #include <linux/bitops.h>
314fc268d2SRandy Dunlap #include <linux/capability.h>
321da177e4SLinus Torvalds #include <linux/module.h>
331da177e4SLinus Torvalds #include <linux/types.h>
341da177e4SLinus Torvalds #include <linux/kernel.h>
351da177e4SLinus Torvalds #include <linux/string.h>
361da177e4SLinus Torvalds #include <linux/mm.h>
371da177e4SLinus Torvalds #include <linux/socket.h>
381da177e4SLinus Torvalds #include <linux/sockios.h>
391da177e4SLinus Torvalds #include <linux/in.h>
401da177e4SLinus Torvalds #include <linux/errno.h>
411da177e4SLinus Torvalds #include <linux/interrupt.h>
421823730fSThomas Graf #include <linux/if_addr.h>
431da177e4SLinus Torvalds #include <linux/if_ether.h>
441da177e4SLinus Torvalds #include <linux/inet.h>
451da177e4SLinus Torvalds #include <linux/netdevice.h>
461da177e4SLinus Torvalds #include <linux/etherdevice.h>
471da177e4SLinus Torvalds #include <linux/skbuff.h>
481da177e4SLinus Torvalds #include <linux/init.h>
491da177e4SLinus Torvalds #include <linux/notifier.h>
501da177e4SLinus Torvalds #include <linux/inetdevice.h>
511da177e4SLinus Torvalds #include <linux/igmp.h>
525a0e3ad6STejun Heo #include <linux/slab.h>
53fd23c3b3SDavid S. Miller #include <linux/hash.h>
541da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL
551da177e4SLinus Torvalds #include <linux/sysctl.h>
561da177e4SLinus Torvalds #endif
571da177e4SLinus Torvalds #include <linux/kmod.h>
58edc9e748SNicolas Dichtel #include <linux/netconf.h>
591da177e4SLinus Torvalds 
6014c85021SArnaldo Carvalho de Melo #include <net/arp.h>
611da177e4SLinus Torvalds #include <net/ip.h>
621da177e4SLinus Torvalds #include <net/route.h>
631da177e4SLinus Torvalds #include <net/ip_fib.h>
6463f3444fSThomas Graf #include <net/rtnetlink.h>
65752d14dcSPavel Emelyanov #include <net/net_namespace.h>
665c766d64SJiri Pirko #include <net/addrconf.h>
671da177e4SLinus Torvalds 
68406b6f97SDavid S. Miller #include "fib_lookup.h"
69406b6f97SDavid S. Miller 
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*/,
7842f811b8SHerbert Xu 	},
791da177e4SLinus Torvalds };
801da177e4SLinus Torvalds 
811da177e4SLinus Torvalds static struct ipv4_devconf ipv4_devconf_dflt = {
8242f811b8SHerbert Xu 	.data = {
8302291680SEric W. Biederman 		[IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
8402291680SEric W. Biederman 		[IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
8502291680SEric W. Biederman 		[IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
8602291680SEric W. Biederman 		[IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
8702291680SEric W. Biederman 		[IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
882690048cSWilliam Manley 		[IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
892690048cSWilliam Manley 		[IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] =  1000 /*ms*/,
9042f811b8SHerbert Xu 	},
911da177e4SLinus Torvalds };
921da177e4SLinus Torvalds 
939355bbd6SPavel Emelyanov #define IPV4_DEVCONF_DFLT(net, attr) \
949355bbd6SPavel Emelyanov 	IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr)
9542f811b8SHerbert Xu 
96ef7c79edSPatrick McHardy static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
975c753978SThomas Graf 	[IFA_LOCAL]     	= { .type = NLA_U32 },
985c753978SThomas Graf 	[IFA_ADDRESS]   	= { .type = NLA_U32 },
995c753978SThomas Graf 	[IFA_BROADCAST] 	= { .type = NLA_U32 },
1005176f91eSThomas Graf 	[IFA_LABEL]     	= { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
1015c766d64SJiri Pirko 	[IFA_CACHEINFO]		= { .len = sizeof(struct ifa_cacheinfo) },
102ad6c8135SJiri Pirko 	[IFA_FLAGS]		= { .type = NLA_U32 },
1035c753978SThomas Graf };
1045c753978SThomas Graf 
10540384999SEric Dumazet #define IN4_ADDR_HSIZE_SHIFT	8
10640384999SEric Dumazet #define IN4_ADDR_HSIZE		(1U << IN4_ADDR_HSIZE_SHIFT)
10740384999SEric Dumazet 
108fd23c3b3SDavid S. Miller static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
109fd23c3b3SDavid S. Miller 
11040384999SEric Dumazet static u32 inet_addr_hash(struct net *net, __be32 addr)
111fd23c3b3SDavid S. Miller {
11240384999SEric Dumazet 	u32 val = (__force u32) addr ^ net_hash_mix(net);
113fd23c3b3SDavid S. Miller 
11440384999SEric Dumazet 	return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
115fd23c3b3SDavid S. Miller }
116fd23c3b3SDavid S. Miller 
117fd23c3b3SDavid S. Miller static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
118fd23c3b3SDavid S. Miller {
11940384999SEric Dumazet 	u32 hash = inet_addr_hash(net, ifa->ifa_local);
120fd23c3b3SDavid S. Miller 
121*32a4be48SWANG Cong 	ASSERT_RTNL();
122fd23c3b3SDavid S. Miller 	hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
123fd23c3b3SDavid S. Miller }
124fd23c3b3SDavid S. Miller 
125fd23c3b3SDavid S. Miller static void inet_hash_remove(struct in_ifaddr *ifa)
126fd23c3b3SDavid S. Miller {
127*32a4be48SWANG Cong 	ASSERT_RTNL();
128fd23c3b3SDavid S. Miller 	hlist_del_init_rcu(&ifa->hash);
129fd23c3b3SDavid S. Miller }
130fd23c3b3SDavid S. Miller 
1319435eb1cSDavid S. Miller /**
1329435eb1cSDavid S. Miller  * __ip_dev_find - find the first device with a given source address.
1339435eb1cSDavid S. Miller  * @net: the net namespace
1349435eb1cSDavid S. Miller  * @addr: the source address
1359435eb1cSDavid S. Miller  * @devref: if true, take a reference on the found device
1369435eb1cSDavid S. Miller  *
1379435eb1cSDavid S. Miller  * If a caller uses devref=false, it should be protected by RCU, or RTNL
1389435eb1cSDavid S. Miller  */
1399435eb1cSDavid S. Miller struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
1409435eb1cSDavid S. Miller {
14140384999SEric Dumazet 	u32 hash = inet_addr_hash(net, addr);
1429435eb1cSDavid S. Miller 	struct net_device *result = NULL;
1439435eb1cSDavid S. Miller 	struct in_ifaddr *ifa;
1449435eb1cSDavid S. Miller 
1459435eb1cSDavid S. Miller 	rcu_read_lock();
146b67bfe0dSSasha Levin 	hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash) {
14740384999SEric Dumazet 		if (ifa->ifa_local == addr) {
1489435eb1cSDavid S. Miller 			struct net_device *dev = ifa->ifa_dev->dev;
1499435eb1cSDavid S. Miller 
1509435eb1cSDavid S. Miller 			if (!net_eq(dev_net(dev), net))
1519435eb1cSDavid S. Miller 				continue;
1529435eb1cSDavid S. Miller 			result = dev;
1539435eb1cSDavid S. Miller 			break;
1549435eb1cSDavid S. Miller 		}
1559435eb1cSDavid S. Miller 	}
156406b6f97SDavid S. Miller 	if (!result) {
157406b6f97SDavid S. Miller 		struct flowi4 fl4 = { .daddr = addr };
158406b6f97SDavid S. Miller 		struct fib_result res = { 0 };
159406b6f97SDavid S. Miller 		struct fib_table *local;
160406b6f97SDavid S. Miller 
161406b6f97SDavid S. Miller 		/* Fallback to FIB local table so that communication
162406b6f97SDavid S. Miller 		 * over loopback subnets work.
163406b6f97SDavid S. Miller 		 */
164406b6f97SDavid S. Miller 		local = fib_get_table(net, RT_TABLE_LOCAL);
165406b6f97SDavid S. Miller 		if (local &&
166406b6f97SDavid S. Miller 		    !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
167406b6f97SDavid S. Miller 		    res.type == RTN_LOCAL)
168406b6f97SDavid S. Miller 			result = FIB_RES_DEV(res);
169406b6f97SDavid S. Miller 	}
1709435eb1cSDavid S. Miller 	if (result && devref)
1719435eb1cSDavid S. Miller 		dev_hold(result);
1729435eb1cSDavid S. Miller 	rcu_read_unlock();
1739435eb1cSDavid S. Miller 	return result;
1749435eb1cSDavid S. Miller }
1759435eb1cSDavid S. Miller EXPORT_SYMBOL(__ip_dev_find);
1769435eb1cSDavid S. Miller 
177d6062cbbSThomas Graf static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
1781da177e4SLinus Torvalds 
179e041c683SAlan Stern static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
1801da177e4SLinus Torvalds static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
1811da177e4SLinus Torvalds 			 int destroy);
1821da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL
18366f27a52SPavel Emelyanov static void devinet_sysctl_register(struct in_device *idev);
18451602b2aSPavel Emelyanov static void devinet_sysctl_unregister(struct in_device *idev);
18551602b2aSPavel Emelyanov #else
18640384999SEric Dumazet static void devinet_sysctl_register(struct in_device *idev)
18751602b2aSPavel Emelyanov {
18851602b2aSPavel Emelyanov }
18940384999SEric Dumazet static void devinet_sysctl_unregister(struct in_device *idev)
19051602b2aSPavel Emelyanov {
19151602b2aSPavel Emelyanov }
1921da177e4SLinus Torvalds #endif
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds /* Locks all the inet devices. */
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds static struct in_ifaddr *inet_alloc_ifa(void)
1971da177e4SLinus Torvalds {
19893adcc80SAlexey Dobriyan 	return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
1991da177e4SLinus Torvalds }
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds static void inet_rcu_free_ifa(struct rcu_head *head)
2021da177e4SLinus Torvalds {
2031da177e4SLinus Torvalds 	struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
2041da177e4SLinus Torvalds 	if (ifa->ifa_dev)
2051da177e4SLinus Torvalds 		in_dev_put(ifa->ifa_dev);
2061da177e4SLinus Torvalds 	kfree(ifa);
2071da177e4SLinus Torvalds }
2081da177e4SLinus Torvalds 
20940384999SEric Dumazet static void inet_free_ifa(struct in_ifaddr *ifa)
2101da177e4SLinus Torvalds {
2111da177e4SLinus Torvalds 	call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
2121da177e4SLinus Torvalds }
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds void in_dev_finish_destroy(struct in_device *idev)
2151da177e4SLinus Torvalds {
2161da177e4SLinus Torvalds 	struct net_device *dev = idev->dev;
2171da177e4SLinus Torvalds 
218547b792cSIlpo Järvinen 	WARN_ON(idev->ifa_list);
219547b792cSIlpo Järvinen 	WARN_ON(idev->mc_list);
220e9897071SEric Dumazet 	kfree(rcu_dereference_protected(idev->mc_hash, 1));
2211da177e4SLinus Torvalds #ifdef NET_REFCNT_DEBUG
22291df42beSJoe Perches 	pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
2231da177e4SLinus Torvalds #endif
2241da177e4SLinus Torvalds 	dev_put(dev);
2251da177e4SLinus Torvalds 	if (!idev->dead)
2269f9354b9SEric Dumazet 		pr_err("Freeing alive in_device %p\n", idev);
2279f9354b9SEric Dumazet 	else
2281da177e4SLinus Torvalds 		kfree(idev);
2291da177e4SLinus Torvalds }
2309f9354b9SEric Dumazet EXPORT_SYMBOL(in_dev_finish_destroy);
2311da177e4SLinus Torvalds 
23271e27da9SHerbert Xu static struct in_device *inetdev_init(struct net_device *dev)
2331da177e4SLinus Torvalds {
2341da177e4SLinus Torvalds 	struct in_device *in_dev;
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds 	ASSERT_RTNL();
2371da177e4SLinus Torvalds 
2380da974f4SPanagiotis Issaris 	in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
2391da177e4SLinus Torvalds 	if (!in_dev)
2401da177e4SLinus Torvalds 		goto out;
241c346dca1SYOSHIFUJI Hideaki 	memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
2429355bbd6SPavel Emelyanov 			sizeof(in_dev->cnf));
2431da177e4SLinus Torvalds 	in_dev->cnf.sysctl = NULL;
2441da177e4SLinus Torvalds 	in_dev->dev = dev;
2459f9354b9SEric Dumazet 	in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
2469f9354b9SEric Dumazet 	if (!in_dev->arp_parms)
2471da177e4SLinus Torvalds 		goto out_kfree;
2480187bdfbSBen Hutchings 	if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
2490187bdfbSBen Hutchings 		dev_disable_lro(dev);
2501da177e4SLinus Torvalds 	/* Reference in_dev->dev */
2511da177e4SLinus Torvalds 	dev_hold(dev);
25230c4cf57SDavid L Stevens 	/* Account for reference dev->ip_ptr (below) */
2531da177e4SLinus Torvalds 	in_dev_hold(in_dev);
2541da177e4SLinus Torvalds 
25566f27a52SPavel Emelyanov 	devinet_sysctl_register(in_dev);
2561da177e4SLinus Torvalds 	ip_mc_init_dev(in_dev);
2571da177e4SLinus Torvalds 	if (dev->flags & IFF_UP)
2581da177e4SLinus Torvalds 		ip_mc_up(in_dev);
259483479ecSJarek Poplawski 
26030c4cf57SDavid L Stevens 	/* we can receive as soon as ip_ptr is set -- do this last */
261cf778b00SEric Dumazet 	rcu_assign_pointer(dev->ip_ptr, in_dev);
262483479ecSJarek Poplawski out:
2631da177e4SLinus Torvalds 	return in_dev;
2641da177e4SLinus Torvalds out_kfree:
2651da177e4SLinus Torvalds 	kfree(in_dev);
2661da177e4SLinus Torvalds 	in_dev = NULL;
2671da177e4SLinus Torvalds 	goto out;
2681da177e4SLinus Torvalds }
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds static void in_dev_rcu_put(struct rcu_head *head)
2711da177e4SLinus Torvalds {
2721da177e4SLinus Torvalds 	struct in_device *idev = container_of(head, struct in_device, rcu_head);
2731da177e4SLinus Torvalds 	in_dev_put(idev);
2741da177e4SLinus Torvalds }
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds static void inetdev_destroy(struct in_device *in_dev)
2771da177e4SLinus Torvalds {
2781da177e4SLinus Torvalds 	struct in_ifaddr *ifa;
2791da177e4SLinus Torvalds 	struct net_device *dev;
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds 	ASSERT_RTNL();
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds 	dev = in_dev->dev;
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 	in_dev->dead = 1;
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 	ip_mc_destroy_dev(in_dev);
2881da177e4SLinus Torvalds 
2891da177e4SLinus Torvalds 	while ((ifa = in_dev->ifa_list) != NULL) {
2901da177e4SLinus Torvalds 		inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
2911da177e4SLinus Torvalds 		inet_free_ifa(ifa);
2921da177e4SLinus Torvalds 	}
2931da177e4SLinus Torvalds 
294a9b3cd7fSStephen Hemminger 	RCU_INIT_POINTER(dev->ip_ptr, NULL);
2951da177e4SLinus Torvalds 
29651602b2aSPavel Emelyanov 	devinet_sysctl_unregister(in_dev);
2971da177e4SLinus Torvalds 	neigh_parms_release(&arp_tbl, in_dev->arp_parms);
2981da177e4SLinus Torvalds 	arp_ifdown(dev);
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds 	call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
3011da177e4SLinus Torvalds }
3021da177e4SLinus Torvalds 
303ff428d72SAl Viro int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
3041da177e4SLinus Torvalds {
3051da177e4SLinus Torvalds 	rcu_read_lock();
3061da177e4SLinus Torvalds 	for_primary_ifa(in_dev) {
3071da177e4SLinus Torvalds 		if (inet_ifa_match(a, ifa)) {
3081da177e4SLinus Torvalds 			if (!b || inet_ifa_match(b, ifa)) {
3091da177e4SLinus Torvalds 				rcu_read_unlock();
3101da177e4SLinus Torvalds 				return 1;
3111da177e4SLinus Torvalds 			}
3121da177e4SLinus Torvalds 		}
3131da177e4SLinus Torvalds 	} endfor_ifa(in_dev);
3141da177e4SLinus Torvalds 	rcu_read_unlock();
3151da177e4SLinus Torvalds 	return 0;
3161da177e4SLinus Torvalds }
3171da177e4SLinus Torvalds 
318d6062cbbSThomas Graf static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
31915e47304SEric W. Biederman 			 int destroy, struct nlmsghdr *nlh, u32 portid)
3201da177e4SLinus Torvalds {
3218f937c60SHarald Welte 	struct in_ifaddr *promote = NULL;
3220ff60a45SJamal Hadi Salim 	struct in_ifaddr *ifa, *ifa1 = *ifap;
3230ff60a45SJamal Hadi Salim 	struct in_ifaddr *last_prim = in_dev->ifa_list;
3240ff60a45SJamal Hadi Salim 	struct in_ifaddr *prev_prom = NULL;
3250ff60a45SJamal Hadi Salim 	int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds 	ASSERT_RTNL();
3281da177e4SLinus Torvalds 
3298f937c60SHarald Welte 	/* 1. Deleting primary ifaddr forces deletion all secondaries
3308f937c60SHarald Welte 	 * unless alias promotion is set
3318f937c60SHarald Welte 	 **/
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
3341da177e4SLinus Torvalds 		struct in_ifaddr **ifap1 = &ifa1->ifa_next;
3351da177e4SLinus Torvalds 
3361da177e4SLinus Torvalds 		while ((ifa = *ifap1) != NULL) {
3370ff60a45SJamal Hadi Salim 			if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
3380ff60a45SJamal Hadi Salim 			    ifa1->ifa_scope <= ifa->ifa_scope)
3390ff60a45SJamal Hadi Salim 				last_prim = ifa;
3400ff60a45SJamal Hadi Salim 
3411da177e4SLinus Torvalds 			if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
3421da177e4SLinus Torvalds 			    ifa1->ifa_mask != ifa->ifa_mask ||
3431da177e4SLinus Torvalds 			    !inet_ifa_match(ifa1->ifa_address, ifa)) {
3441da177e4SLinus Torvalds 				ifap1 = &ifa->ifa_next;
3450ff60a45SJamal Hadi Salim 				prev_prom = ifa;
3461da177e4SLinus Torvalds 				continue;
3471da177e4SLinus Torvalds 			}
3481da177e4SLinus Torvalds 
3490ff60a45SJamal Hadi Salim 			if (!do_promote) {
350fd23c3b3SDavid S. Miller 				inet_hash_remove(ifa);
3511da177e4SLinus Torvalds 				*ifap1 = ifa->ifa_next;
3521da177e4SLinus Torvalds 
35315e47304SEric W. Biederman 				rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
354e041c683SAlan Stern 				blocking_notifier_call_chain(&inetaddr_chain,
355e041c683SAlan Stern 						NETDEV_DOWN, ifa);
3561da177e4SLinus Torvalds 				inet_free_ifa(ifa);
3578f937c60SHarald Welte 			} else {
3588f937c60SHarald Welte 				promote = ifa;
3598f937c60SHarald Welte 				break;
3608f937c60SHarald Welte 			}
3611da177e4SLinus Torvalds 		}
3621da177e4SLinus Torvalds 	}
3631da177e4SLinus Torvalds 
3642d230e2bSJulian Anastasov 	/* On promotion all secondaries from subnet are changing
3652d230e2bSJulian Anastasov 	 * the primary IP, we must remove all their routes silently
3662d230e2bSJulian Anastasov 	 * and later to add them back with new prefsrc. Do this
3672d230e2bSJulian Anastasov 	 * while all addresses are on the device list.
3682d230e2bSJulian Anastasov 	 */
3692d230e2bSJulian Anastasov 	for (ifa = promote; ifa; ifa = ifa->ifa_next) {
3702d230e2bSJulian Anastasov 		if (ifa1->ifa_mask == ifa->ifa_mask &&
3712d230e2bSJulian Anastasov 		    inet_ifa_match(ifa1->ifa_address, ifa))
3722d230e2bSJulian Anastasov 			fib_del_ifaddr(ifa, ifa1);
3732d230e2bSJulian Anastasov 	}
3742d230e2bSJulian Anastasov 
3751da177e4SLinus Torvalds 	/* 2. Unlink it */
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds 	*ifap = ifa1->ifa_next;
378fd23c3b3SDavid S. Miller 	inet_hash_remove(ifa1);
3791da177e4SLinus Torvalds 
3801da177e4SLinus Torvalds 	/* 3. Announce address deletion */
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 	/* Send message first, then call notifier.
3831da177e4SLinus Torvalds 	   At first sight, FIB update triggered by notifier
3841da177e4SLinus Torvalds 	   will refer to already deleted ifaddr, that could confuse
3851da177e4SLinus Torvalds 	   netlink listeners. It is not true: look, gated sees
3861da177e4SLinus Torvalds 	   that route deleted and if it still thinks that ifaddr
3871da177e4SLinus Torvalds 	   is valid, it will try to restore deleted routes... Grr.
3881da177e4SLinus Torvalds 	   So that, this order is correct.
3891da177e4SLinus Torvalds 	 */
39015e47304SEric W. Biederman 	rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
391e041c683SAlan Stern 	blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
3920ff60a45SJamal Hadi Salim 
3930ff60a45SJamal Hadi Salim 	if (promote) {
39404024b93SJulian Anastasov 		struct in_ifaddr *next_sec = promote->ifa_next;
3950ff60a45SJamal Hadi Salim 
3960ff60a45SJamal Hadi Salim 		if (prev_prom) {
3970ff60a45SJamal Hadi Salim 			prev_prom->ifa_next = promote->ifa_next;
3980ff60a45SJamal Hadi Salim 			promote->ifa_next = last_prim->ifa_next;
3990ff60a45SJamal Hadi Salim 			last_prim->ifa_next = promote;
4000ff60a45SJamal Hadi Salim 		}
4010ff60a45SJamal Hadi Salim 
4020ff60a45SJamal Hadi Salim 		promote->ifa_flags &= ~IFA_F_SECONDARY;
40315e47304SEric W. Biederman 		rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
404e041c683SAlan Stern 		blocking_notifier_call_chain(&inetaddr_chain,
405e041c683SAlan Stern 				NETDEV_UP, promote);
40604024b93SJulian Anastasov 		for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
4070ff60a45SJamal Hadi Salim 			if (ifa1->ifa_mask != ifa->ifa_mask ||
4080ff60a45SJamal Hadi Salim 			    !inet_ifa_match(ifa1->ifa_address, ifa))
4090ff60a45SJamal Hadi Salim 					continue;
4100ff60a45SJamal Hadi Salim 			fib_add_ifaddr(ifa);
4110ff60a45SJamal Hadi Salim 		}
4120ff60a45SJamal Hadi Salim 
4130ff60a45SJamal Hadi Salim 	}
4146363097cSHerbert Xu 	if (destroy)
4151da177e4SLinus Torvalds 		inet_free_ifa(ifa1);
4161da177e4SLinus Torvalds }
4171da177e4SLinus Torvalds 
418d6062cbbSThomas Graf static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
419d6062cbbSThomas Graf 			 int destroy)
420d6062cbbSThomas Graf {
421d6062cbbSThomas Graf 	__inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
422d6062cbbSThomas Graf }
423d6062cbbSThomas Graf 
4245c766d64SJiri Pirko static void check_lifetime(struct work_struct *work);
4255c766d64SJiri Pirko 
4265c766d64SJiri Pirko static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
4275c766d64SJiri Pirko 
428d6062cbbSThomas Graf static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
42915e47304SEric W. Biederman 			     u32 portid)
4301da177e4SLinus Torvalds {
4311da177e4SLinus Torvalds 	struct in_device *in_dev = ifa->ifa_dev;
4321da177e4SLinus Torvalds 	struct in_ifaddr *ifa1, **ifap, **last_primary;
4331da177e4SLinus Torvalds 
4341da177e4SLinus Torvalds 	ASSERT_RTNL();
4351da177e4SLinus Torvalds 
4361da177e4SLinus Torvalds 	if (!ifa->ifa_local) {
4371da177e4SLinus Torvalds 		inet_free_ifa(ifa);
4381da177e4SLinus Torvalds 		return 0;
4391da177e4SLinus Torvalds 	}
4401da177e4SLinus Torvalds 
4411da177e4SLinus Torvalds 	ifa->ifa_flags &= ~IFA_F_SECONDARY;
4421da177e4SLinus Torvalds 	last_primary = &in_dev->ifa_list;
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds 	for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
4451da177e4SLinus Torvalds 	     ifap = &ifa1->ifa_next) {
4461da177e4SLinus Torvalds 		if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
4471da177e4SLinus Torvalds 		    ifa->ifa_scope <= ifa1->ifa_scope)
4481da177e4SLinus Torvalds 			last_primary = &ifa1->ifa_next;
4491da177e4SLinus Torvalds 		if (ifa1->ifa_mask == ifa->ifa_mask &&
4501da177e4SLinus Torvalds 		    inet_ifa_match(ifa1->ifa_address, ifa)) {
4511da177e4SLinus Torvalds 			if (ifa1->ifa_local == ifa->ifa_local) {
4521da177e4SLinus Torvalds 				inet_free_ifa(ifa);
4531da177e4SLinus Torvalds 				return -EEXIST;
4541da177e4SLinus Torvalds 			}
4551da177e4SLinus Torvalds 			if (ifa1->ifa_scope != ifa->ifa_scope) {
4561da177e4SLinus Torvalds 				inet_free_ifa(ifa);
4571da177e4SLinus Torvalds 				return -EINVAL;
4581da177e4SLinus Torvalds 			}
4591da177e4SLinus Torvalds 			ifa->ifa_flags |= IFA_F_SECONDARY;
4601da177e4SLinus Torvalds 		}
4611da177e4SLinus Torvalds 	}
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds 	if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
46463862b5bSAruna-Hewapathirane 		prandom_seed((__force u32) ifa->ifa_local);
4651da177e4SLinus Torvalds 		ifap = last_primary;
4661da177e4SLinus Torvalds 	}
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds 	ifa->ifa_next = *ifap;
4691da177e4SLinus Torvalds 	*ifap = ifa;
4701da177e4SLinus Torvalds 
471fd23c3b3SDavid S. Miller 	inet_hash_insert(dev_net(in_dev->dev), ifa);
472fd23c3b3SDavid S. Miller 
4735c766d64SJiri Pirko 	cancel_delayed_work(&check_lifetime_work);
474906e073fSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
4755c766d64SJiri Pirko 
4761da177e4SLinus Torvalds 	/* Send message first, then call notifier.
4771da177e4SLinus Torvalds 	   Notifier will trigger FIB update, so that
4781da177e4SLinus Torvalds 	   listeners of netlink will know about new ifaddr */
47915e47304SEric W. Biederman 	rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
480e041c683SAlan Stern 	blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
4811da177e4SLinus Torvalds 
4821da177e4SLinus Torvalds 	return 0;
4831da177e4SLinus Torvalds }
4841da177e4SLinus Torvalds 
485d6062cbbSThomas Graf static int inet_insert_ifa(struct in_ifaddr *ifa)
486d6062cbbSThomas Graf {
487d6062cbbSThomas Graf 	return __inet_insert_ifa(ifa, NULL, 0);
488d6062cbbSThomas Graf }
489d6062cbbSThomas Graf 
4901da177e4SLinus Torvalds static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
4911da177e4SLinus Torvalds {
492e5ed6399SHerbert Xu 	struct in_device *in_dev = __in_dev_get_rtnl(dev);
4931da177e4SLinus Torvalds 
4941da177e4SLinus Torvalds 	ASSERT_RTNL();
4951da177e4SLinus Torvalds 
4961da177e4SLinus Torvalds 	if (!in_dev) {
4971da177e4SLinus Torvalds 		inet_free_ifa(ifa);
4981da177e4SLinus Torvalds 		return -ENOBUFS;
4991da177e4SLinus Torvalds 	}
50071e27da9SHerbert Xu 	ipv4_devconf_setall(in_dev);
5011d4c8c29SJiri Pirko 	neigh_parms_data_state_setall(in_dev->arp_parms);
5021da177e4SLinus Torvalds 	if (ifa->ifa_dev != in_dev) {
503547b792cSIlpo Järvinen 		WARN_ON(ifa->ifa_dev);
5041da177e4SLinus Torvalds 		in_dev_hold(in_dev);
5051da177e4SLinus Torvalds 		ifa->ifa_dev = in_dev;
5061da177e4SLinus Torvalds 	}
507f97c1e0cSJoe Perches 	if (ipv4_is_loopback(ifa->ifa_local))
5081da177e4SLinus Torvalds 		ifa->ifa_scope = RT_SCOPE_HOST;
5091da177e4SLinus Torvalds 	return inet_insert_ifa(ifa);
5101da177e4SLinus Torvalds }
5111da177e4SLinus Torvalds 
5128723e1b4SEric Dumazet /* Caller must hold RCU or RTNL :
5138723e1b4SEric Dumazet  * We dont take a reference on found in_device
5148723e1b4SEric Dumazet  */
5157fee0ca2SDenis V. Lunev struct in_device *inetdev_by_index(struct net *net, int ifindex)
5161da177e4SLinus Torvalds {
5171da177e4SLinus Torvalds 	struct net_device *dev;
5181da177e4SLinus Torvalds 	struct in_device *in_dev = NULL;
519c148fc2eSEric Dumazet 
520c148fc2eSEric Dumazet 	rcu_read_lock();
521c148fc2eSEric Dumazet 	dev = dev_get_by_index_rcu(net, ifindex);
5221da177e4SLinus Torvalds 	if (dev)
5238723e1b4SEric Dumazet 		in_dev = rcu_dereference_rtnl(dev->ip_ptr);
524c148fc2eSEric Dumazet 	rcu_read_unlock();
5251da177e4SLinus Torvalds 	return in_dev;
5261da177e4SLinus Torvalds }
5279f9354b9SEric Dumazet EXPORT_SYMBOL(inetdev_by_index);
5281da177e4SLinus Torvalds 
5291da177e4SLinus Torvalds /* Called only from RTNL semaphored context. No locks. */
5301da177e4SLinus Torvalds 
53160cad5daSAl Viro struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
53260cad5daSAl Viro 				    __be32 mask)
5331da177e4SLinus Torvalds {
5341da177e4SLinus Torvalds 	ASSERT_RTNL();
5351da177e4SLinus Torvalds 
5361da177e4SLinus Torvalds 	for_primary_ifa(in_dev) {
5371da177e4SLinus Torvalds 		if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
5381da177e4SLinus Torvalds 			return ifa;
5391da177e4SLinus Torvalds 	} endfor_ifa(in_dev);
5401da177e4SLinus Torvalds 	return NULL;
5411da177e4SLinus Torvalds }
5421da177e4SLinus Torvalds 
543661d2967SThomas Graf static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
5441da177e4SLinus Torvalds {
5453b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
546dfdd5fd4SThomas Graf 	struct nlattr *tb[IFA_MAX+1];
5471da177e4SLinus Torvalds 	struct in_device *in_dev;
548dfdd5fd4SThomas Graf 	struct ifaddrmsg *ifm;
5491da177e4SLinus Torvalds 	struct in_ifaddr *ifa, **ifap;
550dfdd5fd4SThomas Graf 	int err = -EINVAL;
5511da177e4SLinus Torvalds 
5521da177e4SLinus Torvalds 	ASSERT_RTNL();
5531da177e4SLinus Torvalds 
554dfdd5fd4SThomas Graf 	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
555dfdd5fd4SThomas Graf 	if (err < 0)
556dfdd5fd4SThomas Graf 		goto errout;
557dfdd5fd4SThomas Graf 
558dfdd5fd4SThomas Graf 	ifm = nlmsg_data(nlh);
5597fee0ca2SDenis V. Lunev 	in_dev = inetdev_by_index(net, ifm->ifa_index);
560dfdd5fd4SThomas Graf 	if (in_dev == NULL) {
561dfdd5fd4SThomas Graf 		err = -ENODEV;
562dfdd5fd4SThomas Graf 		goto errout;
563dfdd5fd4SThomas Graf 	}
564dfdd5fd4SThomas Graf 
5651da177e4SLinus Torvalds 	for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
5661da177e4SLinus Torvalds 	     ifap = &ifa->ifa_next) {
567dfdd5fd4SThomas Graf 		if (tb[IFA_LOCAL] &&
568a7a628c4SAl Viro 		    ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
5691da177e4SLinus Torvalds 			continue;
570dfdd5fd4SThomas Graf 
571dfdd5fd4SThomas Graf 		if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
572dfdd5fd4SThomas Graf 			continue;
573dfdd5fd4SThomas Graf 
574dfdd5fd4SThomas Graf 		if (tb[IFA_ADDRESS] &&
575dfdd5fd4SThomas Graf 		    (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
576a7a628c4SAl Viro 		    !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
577dfdd5fd4SThomas Graf 			continue;
578dfdd5fd4SThomas Graf 
57915e47304SEric W. Biederman 		__inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
5801da177e4SLinus Torvalds 		return 0;
5811da177e4SLinus Torvalds 	}
582dfdd5fd4SThomas Graf 
583dfdd5fd4SThomas Graf 	err = -EADDRNOTAVAIL;
584dfdd5fd4SThomas Graf errout:
585dfdd5fd4SThomas Graf 	return err;
5861da177e4SLinus Torvalds }
5871da177e4SLinus Torvalds 
5885c766d64SJiri Pirko #define INFINITY_LIFE_TIME	0xFFFFFFFF
5895c766d64SJiri Pirko 
5905c766d64SJiri Pirko static void check_lifetime(struct work_struct *work)
5915c766d64SJiri Pirko {
5925c766d64SJiri Pirko 	unsigned long now, next, next_sec, next_sched;
5935c766d64SJiri Pirko 	struct in_ifaddr *ifa;
594c988d1e8SJiri Pirko 	struct hlist_node *n;
5955c766d64SJiri Pirko 	int i;
5965c766d64SJiri Pirko 
5975c766d64SJiri Pirko 	now = jiffies;
5985c766d64SJiri Pirko 	next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
5995c766d64SJiri Pirko 
6005c766d64SJiri Pirko 	for (i = 0; i < IN4_ADDR_HSIZE; i++) {
601c988d1e8SJiri Pirko 		bool change_needed = false;
602c988d1e8SJiri Pirko 
603c988d1e8SJiri Pirko 		rcu_read_lock();
604b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
6055c766d64SJiri Pirko 			unsigned long age;
6065c766d64SJiri Pirko 
6075c766d64SJiri Pirko 			if (ifa->ifa_flags & IFA_F_PERMANENT)
6085c766d64SJiri Pirko 				continue;
6095c766d64SJiri Pirko 
6105c766d64SJiri Pirko 			/* We try to batch several events at once. */
6115c766d64SJiri Pirko 			age = (now - ifa->ifa_tstamp +
6125c766d64SJiri Pirko 			       ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
6135c766d64SJiri Pirko 
6145c766d64SJiri Pirko 			if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
6155c766d64SJiri Pirko 			    age >= ifa->ifa_valid_lft) {
616c988d1e8SJiri Pirko 				change_needed = true;
617c988d1e8SJiri Pirko 			} else if (ifa->ifa_preferred_lft ==
618c988d1e8SJiri Pirko 				   INFINITY_LIFE_TIME) {
619c988d1e8SJiri Pirko 				continue;
620c988d1e8SJiri Pirko 			} else if (age >= ifa->ifa_preferred_lft) {
621c988d1e8SJiri Pirko 				if (time_before(ifa->ifa_tstamp +
622c988d1e8SJiri Pirko 						ifa->ifa_valid_lft * HZ, next))
623c988d1e8SJiri Pirko 					next = ifa->ifa_tstamp +
624c988d1e8SJiri Pirko 					       ifa->ifa_valid_lft * HZ;
625c988d1e8SJiri Pirko 
626c988d1e8SJiri Pirko 				if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
627c988d1e8SJiri Pirko 					change_needed = true;
628c988d1e8SJiri Pirko 			} else if (time_before(ifa->ifa_tstamp +
629c988d1e8SJiri Pirko 					       ifa->ifa_preferred_lft * HZ,
630c988d1e8SJiri Pirko 					       next)) {
631c988d1e8SJiri Pirko 				next = ifa->ifa_tstamp +
632c988d1e8SJiri Pirko 				       ifa->ifa_preferred_lft * HZ;
633c988d1e8SJiri Pirko 			}
634c988d1e8SJiri Pirko 		}
635c988d1e8SJiri Pirko 		rcu_read_unlock();
636c988d1e8SJiri Pirko 		if (!change_needed)
637c988d1e8SJiri Pirko 			continue;
638c988d1e8SJiri Pirko 		rtnl_lock();
639c988d1e8SJiri Pirko 		hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
640c988d1e8SJiri Pirko 			unsigned long age;
641c988d1e8SJiri Pirko 
642c988d1e8SJiri Pirko 			if (ifa->ifa_flags & IFA_F_PERMANENT)
643c988d1e8SJiri Pirko 				continue;
644c988d1e8SJiri Pirko 
645c988d1e8SJiri Pirko 			/* We try to batch several events at once. */
646c988d1e8SJiri Pirko 			age = (now - ifa->ifa_tstamp +
647c988d1e8SJiri Pirko 			       ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
648c988d1e8SJiri Pirko 
649c988d1e8SJiri Pirko 			if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
650c988d1e8SJiri Pirko 			    age >= ifa->ifa_valid_lft) {
6515c766d64SJiri Pirko 				struct in_ifaddr **ifap;
6525c766d64SJiri Pirko 
6535c766d64SJiri Pirko 				for (ifap = &ifa->ifa_dev->ifa_list;
654c988d1e8SJiri Pirko 				     *ifap != NULL; ifap = &(*ifap)->ifa_next) {
655c988d1e8SJiri Pirko 					if (*ifap == ifa) {
6565c766d64SJiri Pirko 						inet_del_ifa(ifa->ifa_dev,
6575c766d64SJiri Pirko 							     ifap, 1);
658c988d1e8SJiri Pirko 						break;
6595c766d64SJiri Pirko 					}
660c988d1e8SJiri Pirko 				}
661c988d1e8SJiri Pirko 			} else if (ifa->ifa_preferred_lft !=
662c988d1e8SJiri Pirko 				   INFINITY_LIFE_TIME &&
663c988d1e8SJiri Pirko 				   age >= ifa->ifa_preferred_lft &&
664c988d1e8SJiri Pirko 				   !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
6655c766d64SJiri Pirko 				ifa->ifa_flags |= IFA_F_DEPRECATED;
6665c766d64SJiri Pirko 				rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
6675c766d64SJiri Pirko 			}
6685c766d64SJiri Pirko 		}
669c988d1e8SJiri Pirko 		rtnl_unlock();
6705c766d64SJiri Pirko 	}
6715c766d64SJiri Pirko 
6725c766d64SJiri Pirko 	next_sec = round_jiffies_up(next);
6735c766d64SJiri Pirko 	next_sched = next;
6745c766d64SJiri Pirko 
6755c766d64SJiri Pirko 	/* If rounded timeout is accurate enough, accept it. */
6765c766d64SJiri Pirko 	if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
6775c766d64SJiri Pirko 		next_sched = next_sec;
6785c766d64SJiri Pirko 
6795c766d64SJiri Pirko 	now = jiffies;
6805c766d64SJiri Pirko 	/* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
6815c766d64SJiri Pirko 	if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
6825c766d64SJiri Pirko 		next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
6835c766d64SJiri Pirko 
684906e073fSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &check_lifetime_work,
685906e073fSviresh kumar 			next_sched - now);
6865c766d64SJiri Pirko }
6875c766d64SJiri Pirko 
6885c766d64SJiri Pirko static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
6895c766d64SJiri Pirko 			     __u32 prefered_lft)
6905c766d64SJiri Pirko {
6915c766d64SJiri Pirko 	unsigned long timeout;
6925c766d64SJiri Pirko 
6935c766d64SJiri Pirko 	ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
6945c766d64SJiri Pirko 
6955c766d64SJiri Pirko 	timeout = addrconf_timeout_fixup(valid_lft, HZ);
6965c766d64SJiri Pirko 	if (addrconf_finite_timeout(timeout))
6975c766d64SJiri Pirko 		ifa->ifa_valid_lft = timeout;
6985c766d64SJiri Pirko 	else
6995c766d64SJiri Pirko 		ifa->ifa_flags |= IFA_F_PERMANENT;
7005c766d64SJiri Pirko 
7015c766d64SJiri Pirko 	timeout = addrconf_timeout_fixup(prefered_lft, HZ);
7025c766d64SJiri Pirko 	if (addrconf_finite_timeout(timeout)) {
7035c766d64SJiri Pirko 		if (timeout == 0)
7045c766d64SJiri Pirko 			ifa->ifa_flags |= IFA_F_DEPRECATED;
7055c766d64SJiri Pirko 		ifa->ifa_preferred_lft = timeout;
7065c766d64SJiri Pirko 	}
7075c766d64SJiri Pirko 	ifa->ifa_tstamp = jiffies;
7085c766d64SJiri Pirko 	if (!ifa->ifa_cstamp)
7095c766d64SJiri Pirko 		ifa->ifa_cstamp = ifa->ifa_tstamp;
7105c766d64SJiri Pirko }
7115c766d64SJiri Pirko 
7125c766d64SJiri Pirko static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
7135c766d64SJiri Pirko 				       __u32 *pvalid_lft, __u32 *pprefered_lft)
7141da177e4SLinus Torvalds {
7155c753978SThomas Graf 	struct nlattr *tb[IFA_MAX+1];
7165c753978SThomas Graf 	struct in_ifaddr *ifa;
7175c753978SThomas Graf 	struct ifaddrmsg *ifm;
7181da177e4SLinus Torvalds 	struct net_device *dev;
7191da177e4SLinus Torvalds 	struct in_device *in_dev;
7207b218574SDenis V. Lunev 	int err;
7211da177e4SLinus Torvalds 
7225c753978SThomas Graf 	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
7235c753978SThomas Graf 	if (err < 0)
7245c753978SThomas Graf 		goto errout;
7251da177e4SLinus Torvalds 
7265c753978SThomas Graf 	ifm = nlmsg_data(nlh);
727c4e38f41SEvgeniy Polyakov 	err = -EINVAL;
7287b218574SDenis V. Lunev 	if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL)
7295c753978SThomas Graf 		goto errout;
7301da177e4SLinus Torvalds 
7314b8aa9abSDenis V. Lunev 	dev = __dev_get_by_index(net, ifm->ifa_index);
7325c753978SThomas Graf 	err = -ENODEV;
7337b218574SDenis V. Lunev 	if (dev == NULL)
7345c753978SThomas Graf 		goto errout;
7351da177e4SLinus Torvalds 
7365c753978SThomas Graf 	in_dev = __in_dev_get_rtnl(dev);
7375c753978SThomas Graf 	err = -ENOBUFS;
7387b218574SDenis V. Lunev 	if (in_dev == NULL)
7395c753978SThomas Graf 		goto errout;
74071e27da9SHerbert Xu 
7415c753978SThomas Graf 	ifa = inet_alloc_ifa();
7427b218574SDenis V. Lunev 	if (ifa == NULL)
7435c753978SThomas Graf 		/*
7445c753978SThomas Graf 		 * A potential indev allocation can be left alive, it stays
7455c753978SThomas Graf 		 * assigned to its device and is destroy with it.
7465c753978SThomas Graf 		 */
7475c753978SThomas Graf 		goto errout;
7485c753978SThomas Graf 
749a4e65d36SPavel Emelyanov 	ipv4_devconf_setall(in_dev);
7501d4c8c29SJiri Pirko 	neigh_parms_data_state_setall(in_dev->arp_parms);
7515c753978SThomas Graf 	in_dev_hold(in_dev);
7525c753978SThomas Graf 
7535c753978SThomas Graf 	if (tb[IFA_ADDRESS] == NULL)
7545c753978SThomas Graf 		tb[IFA_ADDRESS] = tb[IFA_LOCAL];
7555c753978SThomas Graf 
756fd23c3b3SDavid S. Miller 	INIT_HLIST_NODE(&ifa->hash);
7571da177e4SLinus Torvalds 	ifa->ifa_prefixlen = ifm->ifa_prefixlen;
7581da177e4SLinus Torvalds 	ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
759ad6c8135SJiri Pirko 	ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
760ad6c8135SJiri Pirko 					 ifm->ifa_flags;
7611da177e4SLinus Torvalds 	ifa->ifa_scope = ifm->ifa_scope;
7621da177e4SLinus Torvalds 	ifa->ifa_dev = in_dev;
7635c753978SThomas Graf 
764a7a628c4SAl Viro 	ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]);
765a7a628c4SAl Viro 	ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]);
7665c753978SThomas Graf 
7675c753978SThomas Graf 	if (tb[IFA_BROADCAST])
768a7a628c4SAl Viro 		ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);
7695c753978SThomas Graf 
7705c753978SThomas Graf 	if (tb[IFA_LABEL])
7715c753978SThomas Graf 		nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
7721da177e4SLinus Torvalds 	else
7731da177e4SLinus Torvalds 		memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
7741da177e4SLinus Torvalds 
7755c766d64SJiri Pirko 	if (tb[IFA_CACHEINFO]) {
7765c766d64SJiri Pirko 		struct ifa_cacheinfo *ci;
7775c766d64SJiri Pirko 
7785c766d64SJiri Pirko 		ci = nla_data(tb[IFA_CACHEINFO]);
7795c766d64SJiri Pirko 		if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
7805c766d64SJiri Pirko 			err = -EINVAL;
781446266b0SDaniel Borkmann 			goto errout_free;
7825c766d64SJiri Pirko 		}
7835c766d64SJiri Pirko 		*pvalid_lft = ci->ifa_valid;
7845c766d64SJiri Pirko 		*pprefered_lft = ci->ifa_prefered;
7855c766d64SJiri Pirko 	}
7865c766d64SJiri Pirko 
7875c753978SThomas Graf 	return ifa;
7885c753978SThomas Graf 
789446266b0SDaniel Borkmann errout_free:
790446266b0SDaniel Borkmann 	inet_free_ifa(ifa);
7915c753978SThomas Graf errout:
7925c753978SThomas Graf 	return ERR_PTR(err);
7935c753978SThomas Graf }
7945c753978SThomas Graf 
7955c766d64SJiri Pirko static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
7965c766d64SJiri Pirko {
7975c766d64SJiri Pirko 	struct in_device *in_dev = ifa->ifa_dev;
7985c766d64SJiri Pirko 	struct in_ifaddr *ifa1, **ifap;
7995c766d64SJiri Pirko 
8005c766d64SJiri Pirko 	if (!ifa->ifa_local)
8015c766d64SJiri Pirko 		return NULL;
8025c766d64SJiri Pirko 
8035c766d64SJiri Pirko 	for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
8045c766d64SJiri Pirko 	     ifap = &ifa1->ifa_next) {
8055c766d64SJiri Pirko 		if (ifa1->ifa_mask == ifa->ifa_mask &&
8065c766d64SJiri Pirko 		    inet_ifa_match(ifa1->ifa_address, ifa) &&
8075c766d64SJiri Pirko 		    ifa1->ifa_local == ifa->ifa_local)
8085c766d64SJiri Pirko 			return ifa1;
8095c766d64SJiri Pirko 	}
8105c766d64SJiri Pirko 	return NULL;
8115c766d64SJiri Pirko }
8125c766d64SJiri Pirko 
813661d2967SThomas Graf static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
8145c753978SThomas Graf {
8153b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
8165c753978SThomas Graf 	struct in_ifaddr *ifa;
8175c766d64SJiri Pirko 	struct in_ifaddr *ifa_existing;
8185c766d64SJiri Pirko 	__u32 valid_lft = INFINITY_LIFE_TIME;
8195c766d64SJiri Pirko 	__u32 prefered_lft = INFINITY_LIFE_TIME;
8205c753978SThomas Graf 
8215c753978SThomas Graf 	ASSERT_RTNL();
8225c753978SThomas Graf 
8235c766d64SJiri Pirko 	ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft);
8245c753978SThomas Graf 	if (IS_ERR(ifa))
8255c753978SThomas Graf 		return PTR_ERR(ifa);
8265c753978SThomas Graf 
8275c766d64SJiri Pirko 	ifa_existing = find_matching_ifa(ifa);
8285c766d64SJiri Pirko 	if (!ifa_existing) {
8295c766d64SJiri Pirko 		/* It would be best to check for !NLM_F_CREATE here but
8305c766d64SJiri Pirko 		 * userspace alreay relies on not having to provide this.
8315c766d64SJiri Pirko 		 */
8325c766d64SJiri Pirko 		set_ifa_lifetime(ifa, valid_lft, prefered_lft);
83315e47304SEric W. Biederman 		return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
8345c766d64SJiri Pirko 	} else {
8355c766d64SJiri Pirko 		inet_free_ifa(ifa);
8365c766d64SJiri Pirko 
8375c766d64SJiri Pirko 		if (nlh->nlmsg_flags & NLM_F_EXCL ||
8385c766d64SJiri Pirko 		    !(nlh->nlmsg_flags & NLM_F_REPLACE))
8395c766d64SJiri Pirko 			return -EEXIST;
84034e2ed34SJiri Pirko 		ifa = ifa_existing;
84134e2ed34SJiri Pirko 		set_ifa_lifetime(ifa, valid_lft, prefered_lft);
84205a324b9SJiri Pirko 		cancel_delayed_work(&check_lifetime_work);
843906e073fSviresh kumar 		queue_delayed_work(system_power_efficient_wq,
844906e073fSviresh kumar 				&check_lifetime_work, 0);
84534e2ed34SJiri Pirko 		rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
84634e2ed34SJiri Pirko 		blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
8475c766d64SJiri Pirko 	}
8485c766d64SJiri Pirko 	return 0;
8491da177e4SLinus Torvalds }
8501da177e4SLinus Torvalds 
8511da177e4SLinus Torvalds /*
8521da177e4SLinus Torvalds  *	Determine a default network mask, based on the IP address.
8531da177e4SLinus Torvalds  */
8541da177e4SLinus Torvalds 
85540384999SEric Dumazet static int inet_abc_len(__be32 addr)
8561da177e4SLinus Torvalds {
8571da177e4SLinus Torvalds 	int rc = -1;	/* Something else, probably a multicast. */
8581da177e4SLinus Torvalds 
859f97c1e0cSJoe Perches 	if (ipv4_is_zeronet(addr))
8601da177e4SLinus Torvalds 		rc = 0;
8611da177e4SLinus Torvalds 	else {
862714e85beSAl Viro 		__u32 haddr = ntohl(addr);
8631da177e4SLinus Torvalds 
864714e85beSAl Viro 		if (IN_CLASSA(haddr))
8651da177e4SLinus Torvalds 			rc = 8;
866714e85beSAl Viro 		else if (IN_CLASSB(haddr))
8671da177e4SLinus Torvalds 			rc = 16;
868714e85beSAl Viro 		else if (IN_CLASSC(haddr))
8691da177e4SLinus Torvalds 			rc = 24;
8701da177e4SLinus Torvalds 	}
8711da177e4SLinus Torvalds 
8721da177e4SLinus Torvalds 	return rc;
8731da177e4SLinus Torvalds }
8741da177e4SLinus Torvalds 
8751da177e4SLinus Torvalds 
876e5b13cb1SDenis V. Lunev int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
8771da177e4SLinus Torvalds {
8781da177e4SLinus Torvalds 	struct ifreq ifr;
8791da177e4SLinus Torvalds 	struct sockaddr_in sin_orig;
8801da177e4SLinus Torvalds 	struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
8811da177e4SLinus Torvalds 	struct in_device *in_dev;
8821da177e4SLinus Torvalds 	struct in_ifaddr **ifap = NULL;
8831da177e4SLinus Torvalds 	struct in_ifaddr *ifa = NULL;
8841da177e4SLinus Torvalds 	struct net_device *dev;
8851da177e4SLinus Torvalds 	char *colon;
8861da177e4SLinus Torvalds 	int ret = -EFAULT;
8871da177e4SLinus Torvalds 	int tryaddrmatch = 0;
8881da177e4SLinus Torvalds 
8891da177e4SLinus Torvalds 	/*
8901da177e4SLinus Torvalds 	 *	Fetch the caller's info block into kernel space
8911da177e4SLinus Torvalds 	 */
8921da177e4SLinus Torvalds 
8931da177e4SLinus Torvalds 	if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
8941da177e4SLinus Torvalds 		goto out;
8951da177e4SLinus Torvalds 	ifr.ifr_name[IFNAMSIZ - 1] = 0;
8961da177e4SLinus Torvalds 
8971da177e4SLinus Torvalds 	/* save original address for comparison */
8981da177e4SLinus Torvalds 	memcpy(&sin_orig, sin, sizeof(*sin));
8991da177e4SLinus Torvalds 
9001da177e4SLinus Torvalds 	colon = strchr(ifr.ifr_name, ':');
9011da177e4SLinus Torvalds 	if (colon)
9021da177e4SLinus Torvalds 		*colon = 0;
9031da177e4SLinus Torvalds 
904e5b13cb1SDenis V. Lunev 	dev_load(net, ifr.ifr_name);
9051da177e4SLinus Torvalds 
9061da177e4SLinus Torvalds 	switch (cmd) {
9071da177e4SLinus Torvalds 	case SIOCGIFADDR:	/* Get interface address */
9081da177e4SLinus Torvalds 	case SIOCGIFBRDADDR:	/* Get the broadcast address */
9091da177e4SLinus Torvalds 	case SIOCGIFDSTADDR:	/* Get the destination address */
9101da177e4SLinus Torvalds 	case SIOCGIFNETMASK:	/* Get the netmask for the interface */
9111da177e4SLinus Torvalds 		/* Note that these ioctls will not sleep,
9121da177e4SLinus Torvalds 		   so that we do not impose a lock.
9131da177e4SLinus Torvalds 		   One day we will be forced to put shlock here (I mean SMP)
9141da177e4SLinus Torvalds 		 */
9151da177e4SLinus Torvalds 		tryaddrmatch = (sin_orig.sin_family == AF_INET);
9161da177e4SLinus Torvalds 		memset(sin, 0, sizeof(*sin));
9171da177e4SLinus Torvalds 		sin->sin_family = AF_INET;
9181da177e4SLinus Torvalds 		break;
9191da177e4SLinus Torvalds 
9201da177e4SLinus Torvalds 	case SIOCSIFFLAGS:
921bf5b30b8SZhao Hongjiang 		ret = -EPERM;
92252e804c6SEric W. Biederman 		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
9231da177e4SLinus Torvalds 			goto out;
9241da177e4SLinus Torvalds 		break;
9251da177e4SLinus Torvalds 	case SIOCSIFADDR:	/* Set interface address (and family) */
9261da177e4SLinus Torvalds 	case SIOCSIFBRDADDR:	/* Set the broadcast address */
9271da177e4SLinus Torvalds 	case SIOCSIFDSTADDR:	/* Set the destination address */
9281da177e4SLinus Torvalds 	case SIOCSIFNETMASK: 	/* Set the netmask for the interface */
929bf5b30b8SZhao Hongjiang 		ret = -EPERM;
93052e804c6SEric W. Biederman 		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
9311da177e4SLinus Torvalds 			goto out;
9321da177e4SLinus Torvalds 		ret = -EINVAL;
9331da177e4SLinus Torvalds 		if (sin->sin_family != AF_INET)
9341da177e4SLinus Torvalds 			goto out;
9351da177e4SLinus Torvalds 		break;
9361da177e4SLinus Torvalds 	default:
9371da177e4SLinus Torvalds 		ret = -EINVAL;
9381da177e4SLinus Torvalds 		goto out;
9391da177e4SLinus Torvalds 	}
9401da177e4SLinus Torvalds 
9411da177e4SLinus Torvalds 	rtnl_lock();
9421da177e4SLinus Torvalds 
9431da177e4SLinus Torvalds 	ret = -ENODEV;
9449f9354b9SEric Dumazet 	dev = __dev_get_by_name(net, ifr.ifr_name);
9459f9354b9SEric Dumazet 	if (!dev)
9461da177e4SLinus Torvalds 		goto done;
9471da177e4SLinus Torvalds 
9481da177e4SLinus Torvalds 	if (colon)
9491da177e4SLinus Torvalds 		*colon = ':';
9501da177e4SLinus Torvalds 
9519f9354b9SEric Dumazet 	in_dev = __in_dev_get_rtnl(dev);
9529f9354b9SEric Dumazet 	if (in_dev) {
9531da177e4SLinus Torvalds 		if (tryaddrmatch) {
9541da177e4SLinus Torvalds 			/* Matthias Andree */
9551da177e4SLinus Torvalds 			/* compare label and address (4.4BSD style) */
9561da177e4SLinus Torvalds 			/* note: we only do this for a limited set of ioctls
9571da177e4SLinus Torvalds 			   and only if the original address family was AF_INET.
9581da177e4SLinus Torvalds 			   This is checked above. */
9591da177e4SLinus Torvalds 			for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
9601da177e4SLinus Torvalds 			     ifap = &ifa->ifa_next) {
9611da177e4SLinus Torvalds 				if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
9621da177e4SLinus Torvalds 				    sin_orig.sin_addr.s_addr ==
9636c91afe1SDavid S. Miller 							ifa->ifa_local) {
9641da177e4SLinus Torvalds 					break; /* found */
9651da177e4SLinus Torvalds 				}
9661da177e4SLinus Torvalds 			}
9671da177e4SLinus Torvalds 		}
9681da177e4SLinus Torvalds 		/* we didn't get a match, maybe the application is
9691da177e4SLinus Torvalds 		   4.3BSD-style and passed in junk so we fall back to
9701da177e4SLinus Torvalds 		   comparing just the label */
9711da177e4SLinus Torvalds 		if (!ifa) {
9721da177e4SLinus Torvalds 			for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
9731da177e4SLinus Torvalds 			     ifap = &ifa->ifa_next)
9741da177e4SLinus Torvalds 				if (!strcmp(ifr.ifr_name, ifa->ifa_label))
9751da177e4SLinus Torvalds 					break;
9761da177e4SLinus Torvalds 		}
9771da177e4SLinus Torvalds 	}
9781da177e4SLinus Torvalds 
9791da177e4SLinus Torvalds 	ret = -EADDRNOTAVAIL;
9801da177e4SLinus Torvalds 	if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
9811da177e4SLinus Torvalds 		goto done;
9821da177e4SLinus Torvalds 
9831da177e4SLinus Torvalds 	switch (cmd) {
9841da177e4SLinus Torvalds 	case SIOCGIFADDR:	/* Get interface address */
9851da177e4SLinus Torvalds 		sin->sin_addr.s_addr = ifa->ifa_local;
9861da177e4SLinus Torvalds 		goto rarok;
9871da177e4SLinus Torvalds 
9881da177e4SLinus Torvalds 	case SIOCGIFBRDADDR:	/* Get the broadcast address */
9891da177e4SLinus Torvalds 		sin->sin_addr.s_addr = ifa->ifa_broadcast;
9901da177e4SLinus Torvalds 		goto rarok;
9911da177e4SLinus Torvalds 
9921da177e4SLinus Torvalds 	case SIOCGIFDSTADDR:	/* Get the destination address */
9931da177e4SLinus Torvalds 		sin->sin_addr.s_addr = ifa->ifa_address;
9941da177e4SLinus Torvalds 		goto rarok;
9951da177e4SLinus Torvalds 
9961da177e4SLinus Torvalds 	case SIOCGIFNETMASK:	/* Get the netmask for the interface */
9971da177e4SLinus Torvalds 		sin->sin_addr.s_addr = ifa->ifa_mask;
9981da177e4SLinus Torvalds 		goto rarok;
9991da177e4SLinus Torvalds 
10001da177e4SLinus Torvalds 	case SIOCSIFFLAGS:
10011da177e4SLinus Torvalds 		if (colon) {
10021da177e4SLinus Torvalds 			ret = -EADDRNOTAVAIL;
10031da177e4SLinus Torvalds 			if (!ifa)
10041da177e4SLinus Torvalds 				break;
10051da177e4SLinus Torvalds 			ret = 0;
10061da177e4SLinus Torvalds 			if (!(ifr.ifr_flags & IFF_UP))
10071da177e4SLinus Torvalds 				inet_del_ifa(in_dev, ifap, 1);
10081da177e4SLinus Torvalds 			break;
10091da177e4SLinus Torvalds 		}
10101da177e4SLinus Torvalds 		ret = dev_change_flags(dev, ifr.ifr_flags);
10111da177e4SLinus Torvalds 		break;
10121da177e4SLinus Torvalds 
10131da177e4SLinus Torvalds 	case SIOCSIFADDR:	/* Set interface address (and family) */
10141da177e4SLinus Torvalds 		ret = -EINVAL;
10151da177e4SLinus Torvalds 		if (inet_abc_len(sin->sin_addr.s_addr) < 0)
10161da177e4SLinus Torvalds 			break;
10171da177e4SLinus Torvalds 
10181da177e4SLinus Torvalds 		if (!ifa) {
10191da177e4SLinus Torvalds 			ret = -ENOBUFS;
10209f9354b9SEric Dumazet 			ifa = inet_alloc_ifa();
10219f9354b9SEric Dumazet 			if (!ifa)
10221da177e4SLinus Torvalds 				break;
1023c7e2e1d7SXi Wang 			INIT_HLIST_NODE(&ifa->hash);
10241da177e4SLinus Torvalds 			if (colon)
10251da177e4SLinus Torvalds 				memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
10261da177e4SLinus Torvalds 			else
10271da177e4SLinus Torvalds 				memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
10281da177e4SLinus Torvalds 		} else {
10291da177e4SLinus Torvalds 			ret = 0;
10301da177e4SLinus Torvalds 			if (ifa->ifa_local == sin->sin_addr.s_addr)
10311da177e4SLinus Torvalds 				break;
10321da177e4SLinus Torvalds 			inet_del_ifa(in_dev, ifap, 0);
10331da177e4SLinus Torvalds 			ifa->ifa_broadcast = 0;
1034148f9729SBjorn Mork 			ifa->ifa_scope = 0;
10351da177e4SLinus Torvalds 		}
10361da177e4SLinus Torvalds 
10371da177e4SLinus Torvalds 		ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
10381da177e4SLinus Torvalds 
10391da177e4SLinus Torvalds 		if (!(dev->flags & IFF_POINTOPOINT)) {
10401da177e4SLinus Torvalds 			ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
10411da177e4SLinus Torvalds 			ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
10421da177e4SLinus Torvalds 			if ((dev->flags & IFF_BROADCAST) &&
10431da177e4SLinus Torvalds 			    ifa->ifa_prefixlen < 31)
10441da177e4SLinus Torvalds 				ifa->ifa_broadcast = ifa->ifa_address |
10451da177e4SLinus Torvalds 						     ~ifa->ifa_mask;
10461da177e4SLinus Torvalds 		} else {
10471da177e4SLinus Torvalds 			ifa->ifa_prefixlen = 32;
10481da177e4SLinus Torvalds 			ifa->ifa_mask = inet_make_mask(32);
10491da177e4SLinus Torvalds 		}
10505c766d64SJiri Pirko 		set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
10511da177e4SLinus Torvalds 		ret = inet_set_ifa(dev, ifa);
10521da177e4SLinus Torvalds 		break;
10531da177e4SLinus Torvalds 
10541da177e4SLinus Torvalds 	case SIOCSIFBRDADDR:	/* Set the broadcast address */
10551da177e4SLinus Torvalds 		ret = 0;
10561da177e4SLinus Torvalds 		if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
10571da177e4SLinus Torvalds 			inet_del_ifa(in_dev, ifap, 0);
10581da177e4SLinus Torvalds 			ifa->ifa_broadcast = sin->sin_addr.s_addr;
10591da177e4SLinus Torvalds 			inet_insert_ifa(ifa);
10601da177e4SLinus Torvalds 		}
10611da177e4SLinus Torvalds 		break;
10621da177e4SLinus Torvalds 
10631da177e4SLinus Torvalds 	case SIOCSIFDSTADDR:	/* Set the destination address */
10641da177e4SLinus Torvalds 		ret = 0;
10651da177e4SLinus Torvalds 		if (ifa->ifa_address == sin->sin_addr.s_addr)
10661da177e4SLinus Torvalds 			break;
10671da177e4SLinus Torvalds 		ret = -EINVAL;
10681da177e4SLinus Torvalds 		if (inet_abc_len(sin->sin_addr.s_addr) < 0)
10691da177e4SLinus Torvalds 			break;
10701da177e4SLinus Torvalds 		ret = 0;
10711da177e4SLinus Torvalds 		inet_del_ifa(in_dev, ifap, 0);
10721da177e4SLinus Torvalds 		ifa->ifa_address = sin->sin_addr.s_addr;
10731da177e4SLinus Torvalds 		inet_insert_ifa(ifa);
10741da177e4SLinus Torvalds 		break;
10751da177e4SLinus Torvalds 
10761da177e4SLinus Torvalds 	case SIOCSIFNETMASK: 	/* Set the netmask for the interface */
10771da177e4SLinus Torvalds 
10781da177e4SLinus Torvalds 		/*
10791da177e4SLinus Torvalds 		 *	The mask we set must be legal.
10801da177e4SLinus Torvalds 		 */
10811da177e4SLinus Torvalds 		ret = -EINVAL;
10821da177e4SLinus Torvalds 		if (bad_mask(sin->sin_addr.s_addr, 0))
10831da177e4SLinus Torvalds 			break;
10841da177e4SLinus Torvalds 		ret = 0;
10851da177e4SLinus Torvalds 		if (ifa->ifa_mask != sin->sin_addr.s_addr) {
1086a144ea4bSAl Viro 			__be32 old_mask = ifa->ifa_mask;
10871da177e4SLinus Torvalds 			inet_del_ifa(in_dev, ifap, 0);
10881da177e4SLinus Torvalds 			ifa->ifa_mask = sin->sin_addr.s_addr;
10891da177e4SLinus Torvalds 			ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
10901da177e4SLinus Torvalds 
10911da177e4SLinus Torvalds 			/* See if current broadcast address matches
10921da177e4SLinus Torvalds 			 * with current netmask, then recalculate
10931da177e4SLinus Torvalds 			 * the broadcast address. Otherwise it's a
10941da177e4SLinus Torvalds 			 * funny address, so don't touch it since
10951da177e4SLinus Torvalds 			 * the user seems to know what (s)he's doing...
10961da177e4SLinus Torvalds 			 */
10971da177e4SLinus Torvalds 			if ((dev->flags & IFF_BROADCAST) &&
10981da177e4SLinus Torvalds 			    (ifa->ifa_prefixlen < 31) &&
10991da177e4SLinus Torvalds 			    (ifa->ifa_broadcast ==
1100dcab5e1eSDavid Engel 			     (ifa->ifa_local|~old_mask))) {
11011da177e4SLinus Torvalds 				ifa->ifa_broadcast = (ifa->ifa_local |
11021da177e4SLinus Torvalds 						      ~sin->sin_addr.s_addr);
11031da177e4SLinus Torvalds 			}
11041da177e4SLinus Torvalds 			inet_insert_ifa(ifa);
11051da177e4SLinus Torvalds 		}
11061da177e4SLinus Torvalds 		break;
11071da177e4SLinus Torvalds 	}
11081da177e4SLinus Torvalds done:
11091da177e4SLinus Torvalds 	rtnl_unlock();
11101da177e4SLinus Torvalds out:
11111da177e4SLinus Torvalds 	return ret;
11121da177e4SLinus Torvalds rarok:
11131da177e4SLinus Torvalds 	rtnl_unlock();
11141da177e4SLinus Torvalds 	ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
11151da177e4SLinus Torvalds 	goto out;
11161da177e4SLinus Torvalds }
11171da177e4SLinus Torvalds 
11181da177e4SLinus Torvalds static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
11191da177e4SLinus Torvalds {
1120e5ed6399SHerbert Xu 	struct in_device *in_dev = __in_dev_get_rtnl(dev);
11211da177e4SLinus Torvalds 	struct in_ifaddr *ifa;
11221da177e4SLinus Torvalds 	struct ifreq ifr;
11231da177e4SLinus Torvalds 	int done = 0;
11241da177e4SLinus Torvalds 
11259f9354b9SEric Dumazet 	if (!in_dev)
11261da177e4SLinus Torvalds 		goto out;
11271da177e4SLinus Torvalds 
11289f9354b9SEric Dumazet 	for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
11291da177e4SLinus Torvalds 		if (!buf) {
11301da177e4SLinus Torvalds 			done += sizeof(ifr);
11311da177e4SLinus Torvalds 			continue;
11321da177e4SLinus Torvalds 		}
11331da177e4SLinus Torvalds 		if (len < (int) sizeof(ifr))
11341da177e4SLinus Torvalds 			break;
11351da177e4SLinus Torvalds 		memset(&ifr, 0, sizeof(struct ifreq));
11361da177e4SLinus Torvalds 		strcpy(ifr.ifr_name, ifa->ifa_label);
11371da177e4SLinus Torvalds 
11381da177e4SLinus Torvalds 		(*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
11391da177e4SLinus Torvalds 		(*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
11401da177e4SLinus Torvalds 								ifa->ifa_local;
11411da177e4SLinus Torvalds 
11421da177e4SLinus Torvalds 		if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
11431da177e4SLinus Torvalds 			done = -EFAULT;
11441da177e4SLinus Torvalds 			break;
11451da177e4SLinus Torvalds 		}
11461da177e4SLinus Torvalds 		buf  += sizeof(struct ifreq);
11471da177e4SLinus Torvalds 		len  -= sizeof(struct ifreq);
11481da177e4SLinus Torvalds 		done += sizeof(struct ifreq);
11491da177e4SLinus Torvalds 	}
11501da177e4SLinus Torvalds out:
11511da177e4SLinus Torvalds 	return done;
11521da177e4SLinus Torvalds }
11531da177e4SLinus Torvalds 
1154a61ced5dSAl Viro __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
11551da177e4SLinus Torvalds {
1156a61ced5dSAl Viro 	__be32 addr = 0;
11571da177e4SLinus Torvalds 	struct in_device *in_dev;
1158c346dca1SYOSHIFUJI Hideaki 	struct net *net = dev_net(dev);
11591da177e4SLinus Torvalds 
11601da177e4SLinus Torvalds 	rcu_read_lock();
1161e5ed6399SHerbert Xu 	in_dev = __in_dev_get_rcu(dev);
11621da177e4SLinus Torvalds 	if (!in_dev)
11631da177e4SLinus Torvalds 		goto no_in_dev;
11641da177e4SLinus Torvalds 
11651da177e4SLinus Torvalds 	for_primary_ifa(in_dev) {
11661da177e4SLinus Torvalds 		if (ifa->ifa_scope > scope)
11671da177e4SLinus Torvalds 			continue;
11681da177e4SLinus Torvalds 		if (!dst || inet_ifa_match(dst, ifa)) {
11691da177e4SLinus Torvalds 			addr = ifa->ifa_local;
11701da177e4SLinus Torvalds 			break;
11711da177e4SLinus Torvalds 		}
11721da177e4SLinus Torvalds 		if (!addr)
11731da177e4SLinus Torvalds 			addr = ifa->ifa_local;
11741da177e4SLinus Torvalds 	} endfor_ifa(in_dev);
11751da177e4SLinus Torvalds 
11761da177e4SLinus Torvalds 	if (addr)
1177c6d14c84SEric Dumazet 		goto out_unlock;
11789f9354b9SEric Dumazet no_in_dev:
11791da177e4SLinus Torvalds 
11801da177e4SLinus Torvalds 	/* Not loopback addresses on loopback should be preferred
11811da177e4SLinus Torvalds 	   in this case. It is importnat that lo is the first interface
11821da177e4SLinus Torvalds 	   in dev_base list.
11831da177e4SLinus Torvalds 	 */
1184c6d14c84SEric Dumazet 	for_each_netdev_rcu(net, dev) {
11859f9354b9SEric Dumazet 		in_dev = __in_dev_get_rcu(dev);
11869f9354b9SEric Dumazet 		if (!in_dev)
11871da177e4SLinus Torvalds 			continue;
11881da177e4SLinus Torvalds 
11891da177e4SLinus Torvalds 		for_primary_ifa(in_dev) {
11901da177e4SLinus Torvalds 			if (ifa->ifa_scope != RT_SCOPE_LINK &&
11911da177e4SLinus Torvalds 			    ifa->ifa_scope <= scope) {
11921da177e4SLinus Torvalds 				addr = ifa->ifa_local;
1193c6d14c84SEric Dumazet 				goto out_unlock;
11941da177e4SLinus Torvalds 			}
11951da177e4SLinus Torvalds 		} endfor_ifa(in_dev);
11961da177e4SLinus Torvalds 	}
1197c6d14c84SEric Dumazet out_unlock:
11981da177e4SLinus Torvalds 	rcu_read_unlock();
11991da177e4SLinus Torvalds 	return addr;
12001da177e4SLinus Torvalds }
12019f9354b9SEric Dumazet EXPORT_SYMBOL(inet_select_addr);
12021da177e4SLinus Torvalds 
120360cad5daSAl Viro static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
120460cad5daSAl Viro 			      __be32 local, int scope)
12051da177e4SLinus Torvalds {
12061da177e4SLinus Torvalds 	int same = 0;
1207a144ea4bSAl Viro 	__be32 addr = 0;
12081da177e4SLinus Torvalds 
12091da177e4SLinus Torvalds 	for_ifa(in_dev) {
12101da177e4SLinus Torvalds 		if (!addr &&
12111da177e4SLinus Torvalds 		    (local == ifa->ifa_local || !local) &&
12121da177e4SLinus Torvalds 		    ifa->ifa_scope <= scope) {
12131da177e4SLinus Torvalds 			addr = ifa->ifa_local;
12141da177e4SLinus Torvalds 			if (same)
12151da177e4SLinus Torvalds 				break;
12161da177e4SLinus Torvalds 		}
12171da177e4SLinus Torvalds 		if (!same) {
12181da177e4SLinus Torvalds 			same = (!local || inet_ifa_match(local, ifa)) &&
12191da177e4SLinus Torvalds 				(!dst || inet_ifa_match(dst, ifa));
12201da177e4SLinus Torvalds 			if (same && addr) {
12211da177e4SLinus Torvalds 				if (local || !dst)
12221da177e4SLinus Torvalds 					break;
12231da177e4SLinus Torvalds 				/* Is the selected addr into dst subnet? */
12241da177e4SLinus Torvalds 				if (inet_ifa_match(addr, ifa))
12251da177e4SLinus Torvalds 					break;
12261da177e4SLinus Torvalds 				/* No, then can we use new local src? */
12271da177e4SLinus Torvalds 				if (ifa->ifa_scope <= scope) {
12281da177e4SLinus Torvalds 					addr = ifa->ifa_local;
12291da177e4SLinus Torvalds 					break;
12301da177e4SLinus Torvalds 				}
12311da177e4SLinus Torvalds 				/* search for large dst subnet for addr */
12321da177e4SLinus Torvalds 				same = 0;
12331da177e4SLinus Torvalds 			}
12341da177e4SLinus Torvalds 		}
12351da177e4SLinus Torvalds 	} endfor_ifa(in_dev);
12361da177e4SLinus Torvalds 
12371da177e4SLinus Torvalds 	return same ? addr : 0;
12381da177e4SLinus Torvalds }
12391da177e4SLinus Torvalds 
12401da177e4SLinus Torvalds /*
12411da177e4SLinus Torvalds  * Confirm that local IP address exists using wildcards:
1242b601fa19SNicolas Dichtel  * - net: netns to check, cannot be NULL
1243b601fa19SNicolas Dichtel  * - in_dev: only on this interface, NULL=any interface
12441da177e4SLinus Torvalds  * - dst: only in the same subnet as dst, 0=any dst
12451da177e4SLinus Torvalds  * - local: address, 0=autoselect the local address
12461da177e4SLinus Torvalds  * - scope: maximum allowed scope value for the local address
12471da177e4SLinus Torvalds  */
1248b601fa19SNicolas Dichtel __be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
12499bd85e32SDenis V. Lunev 			 __be32 dst, __be32 local, int scope)
12501da177e4SLinus Torvalds {
125160cad5daSAl Viro 	__be32 addr = 0;
12529bd85e32SDenis V. Lunev 	struct net_device *dev;
12531da177e4SLinus Torvalds 
1254b601fa19SNicolas Dichtel 	if (in_dev != NULL)
12559bd85e32SDenis V. Lunev 		return confirm_addr_indev(in_dev, dst, local, scope);
12561da177e4SLinus Torvalds 
12571da177e4SLinus Torvalds 	rcu_read_lock();
1258c6d14c84SEric Dumazet 	for_each_netdev_rcu(net, dev) {
12599f9354b9SEric Dumazet 		in_dev = __in_dev_get_rcu(dev);
12609f9354b9SEric Dumazet 		if (in_dev) {
12611da177e4SLinus Torvalds 			addr = confirm_addr_indev(in_dev, dst, local, scope);
12621da177e4SLinus Torvalds 			if (addr)
12631da177e4SLinus Torvalds 				break;
12641da177e4SLinus Torvalds 		}
12651da177e4SLinus Torvalds 	}
12661da177e4SLinus Torvalds 	rcu_read_unlock();
12671da177e4SLinus Torvalds 
12681da177e4SLinus Torvalds 	return addr;
12691da177e4SLinus Torvalds }
1270eaddcd76SAndy Gospodarek EXPORT_SYMBOL(inet_confirm_addr);
12711da177e4SLinus Torvalds 
12721da177e4SLinus Torvalds /*
12731da177e4SLinus Torvalds  *	Device notifier
12741da177e4SLinus Torvalds  */
12751da177e4SLinus Torvalds 
12761da177e4SLinus Torvalds int register_inetaddr_notifier(struct notifier_block *nb)
12771da177e4SLinus Torvalds {
1278e041c683SAlan Stern 	return blocking_notifier_chain_register(&inetaddr_chain, nb);
12791da177e4SLinus Torvalds }
12809f9354b9SEric Dumazet EXPORT_SYMBOL(register_inetaddr_notifier);
12811da177e4SLinus Torvalds 
12821da177e4SLinus Torvalds int unregister_inetaddr_notifier(struct notifier_block *nb)
12831da177e4SLinus Torvalds {
1284e041c683SAlan Stern 	return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
12851da177e4SLinus Torvalds }
12869f9354b9SEric Dumazet EXPORT_SYMBOL(unregister_inetaddr_notifier);
12871da177e4SLinus Torvalds 
12889f9354b9SEric Dumazet /* Rename ifa_labels for a device name change. Make some effort to preserve
12899f9354b9SEric Dumazet  * existing alias numbering and to create unique labels if possible.
12901da177e4SLinus Torvalds */
12911da177e4SLinus Torvalds static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
12921da177e4SLinus Torvalds {
12931da177e4SLinus Torvalds 	struct in_ifaddr *ifa;
12941da177e4SLinus Torvalds 	int named = 0;
12951da177e4SLinus Torvalds 
12961da177e4SLinus Torvalds 	for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
12971da177e4SLinus Torvalds 		char old[IFNAMSIZ], *dot;
12981da177e4SLinus Torvalds 
12991da177e4SLinus Torvalds 		memcpy(old, ifa->ifa_label, IFNAMSIZ);
13001da177e4SLinus Torvalds 		memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
13011da177e4SLinus Torvalds 		if (named++ == 0)
1302573bf470SThomas Graf 			goto skip;
130344344b2aSMark McLoughlin 		dot = strchr(old, ':');
13041da177e4SLinus Torvalds 		if (dot == NULL) {
13051da177e4SLinus Torvalds 			sprintf(old, ":%d", named);
13061da177e4SLinus Torvalds 			dot = old;
13071da177e4SLinus Torvalds 		}
13089f9354b9SEric Dumazet 		if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
13091da177e4SLinus Torvalds 			strcat(ifa->ifa_label, dot);
13109f9354b9SEric Dumazet 		else
13111da177e4SLinus Torvalds 			strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
1312573bf470SThomas Graf skip:
1313573bf470SThomas Graf 		rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
13141da177e4SLinus Torvalds 	}
13151da177e4SLinus Torvalds }
13161da177e4SLinus Torvalds 
131740384999SEric Dumazet static bool inetdev_valid_mtu(unsigned int mtu)
131806770843SBreno Leitao {
131906770843SBreno Leitao 	return mtu >= 68;
132006770843SBreno Leitao }
132106770843SBreno Leitao 
1322d11327adSIan Campbell static void inetdev_send_gratuitous_arp(struct net_device *dev,
1323d11327adSIan Campbell 					struct in_device *in_dev)
1324d11327adSIan Campbell 
1325d11327adSIan Campbell {
1326b76d0789SZoltan Kiss 	struct in_ifaddr *ifa;
1327d11327adSIan Campbell 
1328b76d0789SZoltan Kiss 	for (ifa = in_dev->ifa_list; ifa;
1329b76d0789SZoltan Kiss 	     ifa = ifa->ifa_next) {
1330d11327adSIan Campbell 		arp_send(ARPOP_REQUEST, ETH_P_ARP,
13316c91afe1SDavid S. Miller 			 ifa->ifa_local, dev,
13326c91afe1SDavid S. Miller 			 ifa->ifa_local, NULL,
1333d11327adSIan Campbell 			 dev->dev_addr, NULL);
1334d11327adSIan Campbell 	}
1335b76d0789SZoltan Kiss }
1336d11327adSIan Campbell 
13371da177e4SLinus Torvalds /* Called only under RTNL semaphore */
13381da177e4SLinus Torvalds 
13391da177e4SLinus Torvalds static int inetdev_event(struct notifier_block *this, unsigned long event,
13401da177e4SLinus Torvalds 			 void *ptr)
13411da177e4SLinus Torvalds {
1342351638e7SJiri Pirko 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
1343748e2d93SEric Dumazet 	struct in_device *in_dev = __in_dev_get_rtnl(dev);
13441da177e4SLinus Torvalds 
13451da177e4SLinus Torvalds 	ASSERT_RTNL();
13461da177e4SLinus Torvalds 
13471da177e4SLinus Torvalds 	if (!in_dev) {
13488030f544SHerbert Xu 		if (event == NETDEV_REGISTER) {
13491da177e4SLinus Torvalds 			in_dev = inetdev_init(dev);
13508d76527eSHerbert Xu 			if (!in_dev)
1351b217d616SHerbert Xu 				return notifier_from_errno(-ENOMEM);
13520cc217e1SEric W. Biederman 			if (dev->flags & IFF_LOOPBACK) {
135342f811b8SHerbert Xu 				IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
135442f811b8SHerbert Xu 				IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
13551da177e4SLinus Torvalds 			}
135606770843SBreno Leitao 		} else if (event == NETDEV_CHANGEMTU) {
135706770843SBreno Leitao 			/* Re-enabling IP */
135806770843SBreno Leitao 			if (inetdev_valid_mtu(dev->mtu))
135906770843SBreno Leitao 				in_dev = inetdev_init(dev);
13608030f544SHerbert Xu 		}
13611da177e4SLinus Torvalds 		goto out;
13621da177e4SLinus Torvalds 	}
13631da177e4SLinus Torvalds 
13641da177e4SLinus Torvalds 	switch (event) {
13651da177e4SLinus Torvalds 	case NETDEV_REGISTER:
136691df42beSJoe Perches 		pr_debug("%s: bug\n", __func__);
1367a9b3cd7fSStephen Hemminger 		RCU_INIT_POINTER(dev->ip_ptr, NULL);
13681da177e4SLinus Torvalds 		break;
13691da177e4SLinus Torvalds 	case NETDEV_UP:
137006770843SBreno Leitao 		if (!inetdev_valid_mtu(dev->mtu))
13711da177e4SLinus Torvalds 			break;
13720cc217e1SEric W. Biederman 		if (dev->flags & IFF_LOOPBACK) {
13739f9354b9SEric Dumazet 			struct in_ifaddr *ifa = inet_alloc_ifa();
13749f9354b9SEric Dumazet 
13759f9354b9SEric Dumazet 			if (ifa) {
1376fd23c3b3SDavid S. Miller 				INIT_HLIST_NODE(&ifa->hash);
13771da177e4SLinus Torvalds 				ifa->ifa_local =
13781da177e4SLinus Torvalds 				  ifa->ifa_address = htonl(INADDR_LOOPBACK);
13791da177e4SLinus Torvalds 				ifa->ifa_prefixlen = 8;
13801da177e4SLinus Torvalds 				ifa->ifa_mask = inet_make_mask(8);
13811da177e4SLinus Torvalds 				in_dev_hold(in_dev);
13821da177e4SLinus Torvalds 				ifa->ifa_dev = in_dev;
13831da177e4SLinus Torvalds 				ifa->ifa_scope = RT_SCOPE_HOST;
13841da177e4SLinus Torvalds 				memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
13855c766d64SJiri Pirko 				set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
13865c766d64SJiri Pirko 						 INFINITY_LIFE_TIME);
1387dfd1582dSJiri Pirko 				ipv4_devconf_setall(in_dev);
1388dfd1582dSJiri Pirko 				neigh_parms_data_state_setall(in_dev->arp_parms);
13891da177e4SLinus Torvalds 				inet_insert_ifa(ifa);
13901da177e4SLinus Torvalds 			}
13911da177e4SLinus Torvalds 		}
13921da177e4SLinus Torvalds 		ip_mc_up(in_dev);
1393eefef1cfSStephen Hemminger 		/* fall through */
1394eefef1cfSStephen Hemminger 	case NETDEV_CHANGEADDR:
1395d11327adSIan Campbell 		if (!IN_DEV_ARP_NOTIFY(in_dev))
1396d11327adSIan Campbell 			break;
1397d11327adSIan Campbell 		/* fall through */
1398d11327adSIan Campbell 	case NETDEV_NOTIFY_PEERS:
1399a21090cfSStephen Hemminger 		/* Send gratuitous ARP to notify of link change */
1400d11327adSIan Campbell 		inetdev_send_gratuitous_arp(dev, in_dev);
14011da177e4SLinus Torvalds 		break;
14021da177e4SLinus Torvalds 	case NETDEV_DOWN:
14031da177e4SLinus Torvalds 		ip_mc_down(in_dev);
14041da177e4SLinus Torvalds 		break;
140593d9b7d7SJiri Pirko 	case NETDEV_PRE_TYPE_CHANGE:
140675c78500SMoni Shoua 		ip_mc_unmap(in_dev);
140775c78500SMoni Shoua 		break;
140893d9b7d7SJiri Pirko 	case NETDEV_POST_TYPE_CHANGE:
140975c78500SMoni Shoua 		ip_mc_remap(in_dev);
141075c78500SMoni Shoua 		break;
14111da177e4SLinus Torvalds 	case NETDEV_CHANGEMTU:
141206770843SBreno Leitao 		if (inetdev_valid_mtu(dev->mtu))
14131da177e4SLinus Torvalds 			break;
141406770843SBreno Leitao 		/* disable IP when MTU is not enough */
14151da177e4SLinus Torvalds 	case NETDEV_UNREGISTER:
14161da177e4SLinus Torvalds 		inetdev_destroy(in_dev);
14171da177e4SLinus Torvalds 		break;
14181da177e4SLinus Torvalds 	case NETDEV_CHANGENAME:
14191da177e4SLinus Torvalds 		/* Do not notify about label change, this event is
14201da177e4SLinus Torvalds 		 * not interesting to applications using netlink.
14211da177e4SLinus Torvalds 		 */
14221da177e4SLinus Torvalds 		inetdev_changename(dev, in_dev);
14231da177e4SLinus Torvalds 
142451602b2aSPavel Emelyanov 		devinet_sysctl_unregister(in_dev);
142566f27a52SPavel Emelyanov 		devinet_sysctl_register(in_dev);
14261da177e4SLinus Torvalds 		break;
14271da177e4SLinus Torvalds 	}
14281da177e4SLinus Torvalds out:
14291da177e4SLinus Torvalds 	return NOTIFY_DONE;
14301da177e4SLinus Torvalds }
14311da177e4SLinus Torvalds 
14321da177e4SLinus Torvalds static struct notifier_block ip_netdev_notifier = {
14331da177e4SLinus Torvalds 	.notifier_call = inetdev_event,
14341da177e4SLinus Torvalds };
14351da177e4SLinus Torvalds 
143640384999SEric Dumazet static size_t inet_nlmsg_size(void)
1437339bf98fSThomas Graf {
1438339bf98fSThomas Graf 	return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1439339bf98fSThomas Graf 	       + nla_total_size(4) /* IFA_ADDRESS */
1440339bf98fSThomas Graf 	       + nla_total_size(4) /* IFA_LOCAL */
1441339bf98fSThomas Graf 	       + nla_total_size(4) /* IFA_BROADCAST */
1442ad6c8135SJiri Pirko 	       + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
144363b5f152SGeert Uytterhoeven 	       + nla_total_size(4)  /* IFA_FLAGS */
144463b5f152SGeert Uytterhoeven 	       + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
1445339bf98fSThomas Graf }
1446339bf98fSThomas Graf 
14475c766d64SJiri Pirko static inline u32 cstamp_delta(unsigned long cstamp)
14485c766d64SJiri Pirko {
14495c766d64SJiri Pirko 	return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
14505c766d64SJiri Pirko }
14515c766d64SJiri Pirko 
14525c766d64SJiri Pirko static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
14535c766d64SJiri Pirko 			 unsigned long tstamp, u32 preferred, u32 valid)
14545c766d64SJiri Pirko {
14555c766d64SJiri Pirko 	struct ifa_cacheinfo ci;
14565c766d64SJiri Pirko 
14575c766d64SJiri Pirko 	ci.cstamp = cstamp_delta(cstamp);
14585c766d64SJiri Pirko 	ci.tstamp = cstamp_delta(tstamp);
14595c766d64SJiri Pirko 	ci.ifa_prefered = preferred;
14605c766d64SJiri Pirko 	ci.ifa_valid = valid;
14615c766d64SJiri Pirko 
14625c766d64SJiri Pirko 	return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
14635c766d64SJiri Pirko }
14645c766d64SJiri Pirko 
14651da177e4SLinus Torvalds static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
146615e47304SEric W. Biederman 			    u32 portid, u32 seq, int event, unsigned int flags)
14671da177e4SLinus Torvalds {
14681da177e4SLinus Torvalds 	struct ifaddrmsg *ifm;
14691da177e4SLinus Torvalds 	struct nlmsghdr  *nlh;
14705c766d64SJiri Pirko 	u32 preferred, valid;
14711da177e4SLinus Torvalds 
147215e47304SEric W. Biederman 	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
147347f68512SThomas Graf 	if (nlh == NULL)
147426932566SPatrick McHardy 		return -EMSGSIZE;
147547f68512SThomas Graf 
147647f68512SThomas Graf 	ifm = nlmsg_data(nlh);
14771da177e4SLinus Torvalds 	ifm->ifa_family = AF_INET;
14781da177e4SLinus Torvalds 	ifm->ifa_prefixlen = ifa->ifa_prefixlen;
14795c766d64SJiri Pirko 	ifm->ifa_flags = ifa->ifa_flags;
14801da177e4SLinus Torvalds 	ifm->ifa_scope = ifa->ifa_scope;
14811da177e4SLinus Torvalds 	ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
14821da177e4SLinus Torvalds 
14835c766d64SJiri Pirko 	if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
14845c766d64SJiri Pirko 		preferred = ifa->ifa_preferred_lft;
14855c766d64SJiri Pirko 		valid = ifa->ifa_valid_lft;
14865c766d64SJiri Pirko 		if (preferred != INFINITY_LIFE_TIME) {
14875c766d64SJiri Pirko 			long tval = (jiffies - ifa->ifa_tstamp) / HZ;
14885c766d64SJiri Pirko 
14895c766d64SJiri Pirko 			if (preferred > tval)
14905c766d64SJiri Pirko 				preferred -= tval;
14915c766d64SJiri Pirko 			else
14925c766d64SJiri Pirko 				preferred = 0;
14935c766d64SJiri Pirko 			if (valid != INFINITY_LIFE_TIME) {
14945c766d64SJiri Pirko 				if (valid > tval)
14955c766d64SJiri Pirko 					valid -= tval;
14965c766d64SJiri Pirko 				else
14975c766d64SJiri Pirko 					valid = 0;
14985c766d64SJiri Pirko 			}
14995c766d64SJiri Pirko 		}
15005c766d64SJiri Pirko 	} else {
15015c766d64SJiri Pirko 		preferred = INFINITY_LIFE_TIME;
15025c766d64SJiri Pirko 		valid = INFINITY_LIFE_TIME;
15035c766d64SJiri Pirko 	}
1504f3756b79SDavid S. Miller 	if ((ifa->ifa_address &&
1505f3756b79SDavid S. Miller 	     nla_put_be32(skb, IFA_ADDRESS, ifa->ifa_address)) ||
1506f3756b79SDavid S. Miller 	    (ifa->ifa_local &&
1507f3756b79SDavid S. Miller 	     nla_put_be32(skb, IFA_LOCAL, ifa->ifa_local)) ||
1508f3756b79SDavid S. Miller 	    (ifa->ifa_broadcast &&
1509f3756b79SDavid S. Miller 	     nla_put_be32(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
1510f3756b79SDavid S. Miller 	    (ifa->ifa_label[0] &&
15115c766d64SJiri Pirko 	     nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
1512ad6c8135SJiri Pirko 	    nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
15135c766d64SJiri Pirko 	    put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
15145c766d64SJiri Pirko 			  preferred, valid))
1515f3756b79SDavid S. Miller 		goto nla_put_failure;
151647f68512SThomas Graf 
151747f68512SThomas Graf 	return nlmsg_end(skb, nlh);
151847f68512SThomas Graf 
151947f68512SThomas Graf nla_put_failure:
152026932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
152126932566SPatrick McHardy 	return -EMSGSIZE;
15221da177e4SLinus Torvalds }
15231da177e4SLinus Torvalds 
15241da177e4SLinus Torvalds static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
15251da177e4SLinus Torvalds {
15263b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
1527eec4df98SEric Dumazet 	int h, s_h;
1528eec4df98SEric Dumazet 	int idx, s_idx;
1529eec4df98SEric Dumazet 	int ip_idx, s_ip_idx;
15301da177e4SLinus Torvalds 	struct net_device *dev;
15311da177e4SLinus Torvalds 	struct in_device *in_dev;
15321da177e4SLinus Torvalds 	struct in_ifaddr *ifa;
1533eec4df98SEric Dumazet 	struct hlist_head *head;
15341da177e4SLinus Torvalds 
1535eec4df98SEric Dumazet 	s_h = cb->args[0];
1536eec4df98SEric Dumazet 	s_idx = idx = cb->args[1];
1537eec4df98SEric Dumazet 	s_ip_idx = ip_idx = cb->args[2];
1538eec4df98SEric Dumazet 
1539eec4df98SEric Dumazet 	for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
15407562f876SPavel Emelianov 		idx = 0;
1541eec4df98SEric Dumazet 		head = &net->dev_index_head[h];
1542eec4df98SEric Dumazet 		rcu_read_lock();
15430465277fSNicolas Dichtel 		cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
15440465277fSNicolas Dichtel 			  net->dev_base_seq;
1545b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(dev, head, index_hlist) {
15461da177e4SLinus Torvalds 			if (idx < s_idx)
15477562f876SPavel Emelianov 				goto cont;
15484b97efdfSPatrick McHardy 			if (h > s_h || idx > s_idx)
15491da177e4SLinus Torvalds 				s_ip_idx = 0;
1550eec4df98SEric Dumazet 			in_dev = __in_dev_get_rcu(dev);
15519f9354b9SEric Dumazet 			if (!in_dev)
15527562f876SPavel Emelianov 				goto cont;
15531da177e4SLinus Torvalds 
15541da177e4SLinus Torvalds 			for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
15551da177e4SLinus Torvalds 			     ifa = ifa->ifa_next, ip_idx++) {
15561da177e4SLinus Torvalds 				if (ip_idx < s_ip_idx)
1557596e4150SStephen Hemminger 					continue;
1558eec4df98SEric Dumazet 				if (inet_fill_ifaddr(skb, ifa,
155915e47304SEric W. Biederman 					     NETLINK_CB(cb->skb).portid,
15601da177e4SLinus Torvalds 					     cb->nlh->nlmsg_seq,
1561eec4df98SEric Dumazet 					     RTM_NEWADDR, NLM_F_MULTI) <= 0) {
1562eec4df98SEric Dumazet 					rcu_read_unlock();
15631da177e4SLinus Torvalds 					goto done;
15641da177e4SLinus Torvalds 				}
15650465277fSNicolas Dichtel 				nl_dump_check_consistent(cb, nlmsg_hdr(skb));
1566eec4df98SEric Dumazet 			}
15677562f876SPavel Emelianov cont:
15687562f876SPavel Emelianov 			idx++;
15691da177e4SLinus Torvalds 		}
1570eec4df98SEric Dumazet 		rcu_read_unlock();
1571eec4df98SEric Dumazet 	}
15721da177e4SLinus Torvalds 
15731da177e4SLinus Torvalds done:
1574eec4df98SEric Dumazet 	cb->args[0] = h;
1575eec4df98SEric Dumazet 	cb->args[1] = idx;
1576eec4df98SEric Dumazet 	cb->args[2] = ip_idx;
15771da177e4SLinus Torvalds 
15781da177e4SLinus Torvalds 	return skb->len;
15791da177e4SLinus Torvalds }
15801da177e4SLinus Torvalds 
1581d6062cbbSThomas Graf static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
158215e47304SEric W. Biederman 		      u32 portid)
15831da177e4SLinus Torvalds {
158447f68512SThomas Graf 	struct sk_buff *skb;
1585d6062cbbSThomas Graf 	u32 seq = nlh ? nlh->nlmsg_seq : 0;
1586d6062cbbSThomas Graf 	int err = -ENOBUFS;
15874b8aa9abSDenis V. Lunev 	struct net *net;
15881da177e4SLinus Torvalds 
1589c346dca1SYOSHIFUJI Hideaki 	net = dev_net(ifa->ifa_dev->dev);
1590339bf98fSThomas Graf 	skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
159147f68512SThomas Graf 	if (skb == NULL)
1592d6062cbbSThomas Graf 		goto errout;
1593d6062cbbSThomas Graf 
159415e47304SEric W. Biederman 	err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0);
159526932566SPatrick McHardy 	if (err < 0) {
159626932566SPatrick McHardy 		/* -EMSGSIZE implies BUG in inet_nlmsg_size() */
159726932566SPatrick McHardy 		WARN_ON(err == -EMSGSIZE);
159826932566SPatrick McHardy 		kfree_skb(skb);
159926932566SPatrick McHardy 		goto errout;
160026932566SPatrick McHardy 	}
160115e47304SEric W. Biederman 	rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
16021ce85fe4SPablo Neira Ayuso 	return;
1603d6062cbbSThomas Graf errout:
1604d6062cbbSThomas Graf 	if (err < 0)
16054b8aa9abSDenis V. Lunev 		rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
16061da177e4SLinus Torvalds }
16071da177e4SLinus Torvalds 
16089f0f7272SThomas Graf static size_t inet_get_link_af_size(const struct net_device *dev)
16099f0f7272SThomas Graf {
16101fc19affSEric Dumazet 	struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
16119f0f7272SThomas Graf 
16129f0f7272SThomas Graf 	if (!in_dev)
16139f0f7272SThomas Graf 		return 0;
16149f0f7272SThomas Graf 
16159f0f7272SThomas Graf 	return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
16169f0f7272SThomas Graf }
16179f0f7272SThomas Graf 
16189f0f7272SThomas Graf static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
16199f0f7272SThomas Graf {
16201fc19affSEric Dumazet 	struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
16219f0f7272SThomas Graf 	struct nlattr *nla;
16229f0f7272SThomas Graf 	int i;
16239f0f7272SThomas Graf 
16249f0f7272SThomas Graf 	if (!in_dev)
16259f0f7272SThomas Graf 		return -ENODATA;
16269f0f7272SThomas Graf 
16279f0f7272SThomas Graf 	nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
16289f0f7272SThomas Graf 	if (nla == NULL)
16299f0f7272SThomas Graf 		return -EMSGSIZE;
16309f0f7272SThomas Graf 
16319f0f7272SThomas Graf 	for (i = 0; i < IPV4_DEVCONF_MAX; i++)
16329f0f7272SThomas Graf 		((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
16339f0f7272SThomas Graf 
16349f0f7272SThomas Graf 	return 0;
16359f0f7272SThomas Graf }
16369f0f7272SThomas Graf 
16379f0f7272SThomas Graf static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
16389f0f7272SThomas Graf 	[IFLA_INET_CONF]	= { .type = NLA_NESTED },
16399f0f7272SThomas Graf };
16409f0f7272SThomas Graf 
1641cf7afbfeSThomas Graf static int inet_validate_link_af(const struct net_device *dev,
1642cf7afbfeSThomas Graf 				 const struct nlattr *nla)
16439f0f7272SThomas Graf {
16449f0f7272SThomas Graf 	struct nlattr *a, *tb[IFLA_INET_MAX+1];
16459f0f7272SThomas Graf 	int err, rem;
16469f0f7272SThomas Graf 
1647f7fce74eSEric Dumazet 	if (dev && !__in_dev_get_rtnl(dev))
1648cf7afbfeSThomas Graf 		return -EAFNOSUPPORT;
16499f0f7272SThomas Graf 
16509f0f7272SThomas Graf 	err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy);
16519f0f7272SThomas Graf 	if (err < 0)
16529f0f7272SThomas Graf 		return err;
16539f0f7272SThomas Graf 
16549f0f7272SThomas Graf 	if (tb[IFLA_INET_CONF]) {
16559f0f7272SThomas Graf 		nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
16569f0f7272SThomas Graf 			int cfgid = nla_type(a);
16579f0f7272SThomas Graf 
16589f0f7272SThomas Graf 			if (nla_len(a) < 4)
16599f0f7272SThomas Graf 				return -EINVAL;
16609f0f7272SThomas Graf 
16619f0f7272SThomas Graf 			if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
16629f0f7272SThomas Graf 				return -EINVAL;
16639f0f7272SThomas Graf 		}
16649f0f7272SThomas Graf 	}
16659f0f7272SThomas Graf 
1666cf7afbfeSThomas Graf 	return 0;
1667cf7afbfeSThomas Graf }
1668cf7afbfeSThomas Graf 
1669cf7afbfeSThomas Graf static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1670cf7afbfeSThomas Graf {
1671f7fce74eSEric Dumazet 	struct in_device *in_dev = __in_dev_get_rtnl(dev);
1672cf7afbfeSThomas Graf 	struct nlattr *a, *tb[IFLA_INET_MAX+1];
1673cf7afbfeSThomas Graf 	int rem;
1674cf7afbfeSThomas Graf 
1675cf7afbfeSThomas Graf 	if (!in_dev)
1676cf7afbfeSThomas Graf 		return -EAFNOSUPPORT;
1677cf7afbfeSThomas Graf 
1678cf7afbfeSThomas Graf 	if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL) < 0)
1679cf7afbfeSThomas Graf 		BUG();
1680cf7afbfeSThomas Graf 
16819f0f7272SThomas Graf 	if (tb[IFLA_INET_CONF]) {
16829f0f7272SThomas Graf 		nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
16839f0f7272SThomas Graf 			ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
16849f0f7272SThomas Graf 	}
16859f0f7272SThomas Graf 
16869f0f7272SThomas Graf 	return 0;
16879f0f7272SThomas Graf }
16889f0f7272SThomas Graf 
1689edc9e748SNicolas Dichtel static int inet_netconf_msgsize_devconf(int type)
1690edc9e748SNicolas Dichtel {
1691edc9e748SNicolas Dichtel 	int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1692edc9e748SNicolas Dichtel 		   + nla_total_size(4);	/* NETCONFA_IFINDEX */
1693edc9e748SNicolas Dichtel 
16949e551110SNicolas Dichtel 	/* type -1 is used for ALL */
16959e551110SNicolas Dichtel 	if (type == -1 || type == NETCONFA_FORWARDING)
1696edc9e748SNicolas Dichtel 		size += nla_total_size(4);
1697cc535dfbSNicolas Dichtel 	if (type == -1 || type == NETCONFA_RP_FILTER)
1698cc535dfbSNicolas Dichtel 		size += nla_total_size(4);
1699d67b8c61SNicolas Dichtel 	if (type == -1 || type == NETCONFA_MC_FORWARDING)
1700d67b8c61SNicolas Dichtel 		size += nla_total_size(4);
170109aea5dfSstephen hemminger 	if (type == -1 || type == NETCONFA_PROXY_NEIGH)
1702f085ff1cSstephen hemminger 		size += nla_total_size(4);
1703edc9e748SNicolas Dichtel 
1704edc9e748SNicolas Dichtel 	return size;
1705edc9e748SNicolas Dichtel }
1706edc9e748SNicolas Dichtel 
1707edc9e748SNicolas Dichtel static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1708edc9e748SNicolas Dichtel 				     struct ipv4_devconf *devconf, u32 portid,
1709edc9e748SNicolas Dichtel 				     u32 seq, int event, unsigned int flags,
1710edc9e748SNicolas Dichtel 				     int type)
1711edc9e748SNicolas Dichtel {
1712edc9e748SNicolas Dichtel 	struct nlmsghdr  *nlh;
1713edc9e748SNicolas Dichtel 	struct netconfmsg *ncm;
1714edc9e748SNicolas Dichtel 
1715edc9e748SNicolas Dichtel 	nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1716edc9e748SNicolas Dichtel 			flags);
1717edc9e748SNicolas Dichtel 	if (nlh == NULL)
1718edc9e748SNicolas Dichtel 		return -EMSGSIZE;
1719edc9e748SNicolas Dichtel 
1720edc9e748SNicolas Dichtel 	ncm = nlmsg_data(nlh);
1721edc9e748SNicolas Dichtel 	ncm->ncm_family = AF_INET;
1722edc9e748SNicolas Dichtel 
1723edc9e748SNicolas Dichtel 	if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1724edc9e748SNicolas Dichtel 		goto nla_put_failure;
1725edc9e748SNicolas Dichtel 
17269e551110SNicolas Dichtel 	/* type -1 is used for ALL */
17279e551110SNicolas Dichtel 	if ((type == -1 || type == NETCONFA_FORWARDING) &&
1728edc9e748SNicolas Dichtel 	    nla_put_s32(skb, NETCONFA_FORWARDING,
1729edc9e748SNicolas Dichtel 			IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1730edc9e748SNicolas Dichtel 		goto nla_put_failure;
1731cc535dfbSNicolas Dichtel 	if ((type == -1 || type == NETCONFA_RP_FILTER) &&
1732cc535dfbSNicolas Dichtel 	    nla_put_s32(skb, NETCONFA_RP_FILTER,
1733cc535dfbSNicolas Dichtel 			IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
1734cc535dfbSNicolas Dichtel 		goto nla_put_failure;
1735d67b8c61SNicolas Dichtel 	if ((type == -1 || type == NETCONFA_MC_FORWARDING) &&
1736d67b8c61SNicolas Dichtel 	    nla_put_s32(skb, NETCONFA_MC_FORWARDING,
1737d67b8c61SNicolas Dichtel 			IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
1738d67b8c61SNicolas Dichtel 		goto nla_put_failure;
173909aea5dfSstephen hemminger 	if ((type == -1 || type == NETCONFA_PROXY_NEIGH) &&
174009aea5dfSstephen hemminger 	    nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
1741f085ff1cSstephen hemminger 			IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
1742f085ff1cSstephen hemminger 		goto nla_put_failure;
1743edc9e748SNicolas Dichtel 
1744edc9e748SNicolas Dichtel 	return nlmsg_end(skb, nlh);
1745edc9e748SNicolas Dichtel 
1746edc9e748SNicolas Dichtel nla_put_failure:
1747edc9e748SNicolas Dichtel 	nlmsg_cancel(skb, nlh);
1748edc9e748SNicolas Dichtel 	return -EMSGSIZE;
1749edc9e748SNicolas Dichtel }
1750edc9e748SNicolas Dichtel 
1751d67b8c61SNicolas Dichtel void inet_netconf_notify_devconf(struct net *net, int type, int ifindex,
1752edc9e748SNicolas Dichtel 				 struct ipv4_devconf *devconf)
1753edc9e748SNicolas Dichtel {
1754edc9e748SNicolas Dichtel 	struct sk_buff *skb;
1755edc9e748SNicolas Dichtel 	int err = -ENOBUFS;
1756edc9e748SNicolas Dichtel 
1757edc9e748SNicolas Dichtel 	skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_ATOMIC);
1758edc9e748SNicolas Dichtel 	if (skb == NULL)
1759edc9e748SNicolas Dichtel 		goto errout;
1760edc9e748SNicolas Dichtel 
1761edc9e748SNicolas Dichtel 	err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
1762edc9e748SNicolas Dichtel 					RTM_NEWNETCONF, 0, type);
1763edc9e748SNicolas Dichtel 	if (err < 0) {
1764edc9e748SNicolas Dichtel 		/* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1765edc9e748SNicolas Dichtel 		WARN_ON(err == -EMSGSIZE);
1766edc9e748SNicolas Dichtel 		kfree_skb(skb);
1767edc9e748SNicolas Dichtel 		goto errout;
1768edc9e748SNicolas Dichtel 	}
1769edc9e748SNicolas Dichtel 	rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_ATOMIC);
1770edc9e748SNicolas Dichtel 	return;
1771edc9e748SNicolas Dichtel errout:
1772edc9e748SNicolas Dichtel 	if (err < 0)
1773edc9e748SNicolas Dichtel 		rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
1774edc9e748SNicolas Dichtel }
1775edc9e748SNicolas Dichtel 
17769e551110SNicolas Dichtel static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
17779e551110SNicolas Dichtel 	[NETCONFA_IFINDEX]	= { .len = sizeof(int) },
17789e551110SNicolas Dichtel 	[NETCONFA_FORWARDING]	= { .len = sizeof(int) },
1779cc535dfbSNicolas Dichtel 	[NETCONFA_RP_FILTER]	= { .len = sizeof(int) },
178009aea5dfSstephen hemminger 	[NETCONFA_PROXY_NEIGH]	= { .len = sizeof(int) },
17819e551110SNicolas Dichtel };
17829e551110SNicolas Dichtel 
17839e551110SNicolas Dichtel static int inet_netconf_get_devconf(struct sk_buff *in_skb,
1784661d2967SThomas Graf 				    struct nlmsghdr *nlh)
17859e551110SNicolas Dichtel {
17869e551110SNicolas Dichtel 	struct net *net = sock_net(in_skb->sk);
17879e551110SNicolas Dichtel 	struct nlattr *tb[NETCONFA_MAX+1];
17889e551110SNicolas Dichtel 	struct netconfmsg *ncm;
17899e551110SNicolas Dichtel 	struct sk_buff *skb;
17909e551110SNicolas Dichtel 	struct ipv4_devconf *devconf;
17919e551110SNicolas Dichtel 	struct in_device *in_dev;
17929e551110SNicolas Dichtel 	struct net_device *dev;
17939e551110SNicolas Dichtel 	int ifindex;
17949e551110SNicolas Dichtel 	int err;
17959e551110SNicolas Dichtel 
17969e551110SNicolas Dichtel 	err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
17979e551110SNicolas Dichtel 			  devconf_ipv4_policy);
17989e551110SNicolas Dichtel 	if (err < 0)
17999e551110SNicolas Dichtel 		goto errout;
18009e551110SNicolas Dichtel 
18019e551110SNicolas Dichtel 	err = EINVAL;
18029e551110SNicolas Dichtel 	if (!tb[NETCONFA_IFINDEX])
18039e551110SNicolas Dichtel 		goto errout;
18049e551110SNicolas Dichtel 
18059e551110SNicolas Dichtel 	ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
18069e551110SNicolas Dichtel 	switch (ifindex) {
18079e551110SNicolas Dichtel 	case NETCONFA_IFINDEX_ALL:
18089e551110SNicolas Dichtel 		devconf = net->ipv4.devconf_all;
18099e551110SNicolas Dichtel 		break;
18109e551110SNicolas Dichtel 	case NETCONFA_IFINDEX_DEFAULT:
18119e551110SNicolas Dichtel 		devconf = net->ipv4.devconf_dflt;
18129e551110SNicolas Dichtel 		break;
18139e551110SNicolas Dichtel 	default:
18149e551110SNicolas Dichtel 		dev = __dev_get_by_index(net, ifindex);
18159e551110SNicolas Dichtel 		if (dev == NULL)
18169e551110SNicolas Dichtel 			goto errout;
18179e551110SNicolas Dichtel 		in_dev = __in_dev_get_rtnl(dev);
18189e551110SNicolas Dichtel 		if (in_dev == NULL)
18199e551110SNicolas Dichtel 			goto errout;
18209e551110SNicolas Dichtel 		devconf = &in_dev->cnf;
18219e551110SNicolas Dichtel 		break;
18229e551110SNicolas Dichtel 	}
18239e551110SNicolas Dichtel 
18249e551110SNicolas Dichtel 	err = -ENOBUFS;
18259e551110SNicolas Dichtel 	skb = nlmsg_new(inet_netconf_msgsize_devconf(-1), GFP_ATOMIC);
18269e551110SNicolas Dichtel 	if (skb == NULL)
18279e551110SNicolas Dichtel 		goto errout;
18289e551110SNicolas Dichtel 
18299e551110SNicolas Dichtel 	err = inet_netconf_fill_devconf(skb, ifindex, devconf,
18309e551110SNicolas Dichtel 					NETLINK_CB(in_skb).portid,
18319e551110SNicolas Dichtel 					nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
18329e551110SNicolas Dichtel 					-1);
18339e551110SNicolas Dichtel 	if (err < 0) {
18349e551110SNicolas Dichtel 		/* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
18359e551110SNicolas Dichtel 		WARN_ON(err == -EMSGSIZE);
18369e551110SNicolas Dichtel 		kfree_skb(skb);
18379e551110SNicolas Dichtel 		goto errout;
18389e551110SNicolas Dichtel 	}
18399e551110SNicolas Dichtel 	err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
18409e551110SNicolas Dichtel errout:
18419e551110SNicolas Dichtel 	return err;
18429e551110SNicolas Dichtel }
18439e551110SNicolas Dichtel 
18447a674200SNicolas Dichtel static int inet_netconf_dump_devconf(struct sk_buff *skb,
18457a674200SNicolas Dichtel 				     struct netlink_callback *cb)
18467a674200SNicolas Dichtel {
18477a674200SNicolas Dichtel 	struct net *net = sock_net(skb->sk);
18487a674200SNicolas Dichtel 	int h, s_h;
18497a674200SNicolas Dichtel 	int idx, s_idx;
18507a674200SNicolas Dichtel 	struct net_device *dev;
18517a674200SNicolas Dichtel 	struct in_device *in_dev;
18527a674200SNicolas Dichtel 	struct hlist_head *head;
18537a674200SNicolas Dichtel 
18547a674200SNicolas Dichtel 	s_h = cb->args[0];
18557a674200SNicolas Dichtel 	s_idx = idx = cb->args[1];
18567a674200SNicolas Dichtel 
18577a674200SNicolas Dichtel 	for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
18587a674200SNicolas Dichtel 		idx = 0;
18597a674200SNicolas Dichtel 		head = &net->dev_index_head[h];
18607a674200SNicolas Dichtel 		rcu_read_lock();
18610465277fSNicolas Dichtel 		cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
18620465277fSNicolas Dichtel 			  net->dev_base_seq;
18637a674200SNicolas Dichtel 		hlist_for_each_entry_rcu(dev, head, index_hlist) {
18647a674200SNicolas Dichtel 			if (idx < s_idx)
18657a674200SNicolas Dichtel 				goto cont;
18667a674200SNicolas Dichtel 			in_dev = __in_dev_get_rcu(dev);
18677a674200SNicolas Dichtel 			if (!in_dev)
18687a674200SNicolas Dichtel 				goto cont;
18697a674200SNicolas Dichtel 
18707a674200SNicolas Dichtel 			if (inet_netconf_fill_devconf(skb, dev->ifindex,
18717a674200SNicolas Dichtel 						      &in_dev->cnf,
18727a674200SNicolas Dichtel 						      NETLINK_CB(cb->skb).portid,
18737a674200SNicolas Dichtel 						      cb->nlh->nlmsg_seq,
18747a674200SNicolas Dichtel 						      RTM_NEWNETCONF,
18757a674200SNicolas Dichtel 						      NLM_F_MULTI,
18767a674200SNicolas Dichtel 						      -1) <= 0) {
18777a674200SNicolas Dichtel 				rcu_read_unlock();
18787a674200SNicolas Dichtel 				goto done;
18797a674200SNicolas Dichtel 			}
18800465277fSNicolas Dichtel 			nl_dump_check_consistent(cb, nlmsg_hdr(skb));
18817a674200SNicolas Dichtel cont:
18827a674200SNicolas Dichtel 			idx++;
18837a674200SNicolas Dichtel 		}
18847a674200SNicolas Dichtel 		rcu_read_unlock();
18857a674200SNicolas Dichtel 	}
18867a674200SNicolas Dichtel 	if (h == NETDEV_HASHENTRIES) {
18877a674200SNicolas Dichtel 		if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
18887a674200SNicolas Dichtel 					      net->ipv4.devconf_all,
18897a674200SNicolas Dichtel 					      NETLINK_CB(cb->skb).portid,
18907a674200SNicolas Dichtel 					      cb->nlh->nlmsg_seq,
18917a674200SNicolas Dichtel 					      RTM_NEWNETCONF, NLM_F_MULTI,
18927a674200SNicolas Dichtel 					      -1) <= 0)
18937a674200SNicolas Dichtel 			goto done;
18947a674200SNicolas Dichtel 		else
18957a674200SNicolas Dichtel 			h++;
18967a674200SNicolas Dichtel 	}
18977a674200SNicolas Dichtel 	if (h == NETDEV_HASHENTRIES + 1) {
18987a674200SNicolas Dichtel 		if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
18997a674200SNicolas Dichtel 					      net->ipv4.devconf_dflt,
19007a674200SNicolas Dichtel 					      NETLINK_CB(cb->skb).portid,
19017a674200SNicolas Dichtel 					      cb->nlh->nlmsg_seq,
19027a674200SNicolas Dichtel 					      RTM_NEWNETCONF, NLM_F_MULTI,
19037a674200SNicolas Dichtel 					      -1) <= 0)
19047a674200SNicolas Dichtel 			goto done;
19057a674200SNicolas Dichtel 		else
19067a674200SNicolas Dichtel 			h++;
19077a674200SNicolas Dichtel 	}
19087a674200SNicolas Dichtel done:
19097a674200SNicolas Dichtel 	cb->args[0] = h;
19107a674200SNicolas Dichtel 	cb->args[1] = idx;
19117a674200SNicolas Dichtel 
19127a674200SNicolas Dichtel 	return skb->len;
19137a674200SNicolas Dichtel }
19147a674200SNicolas Dichtel 
19151da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL
19161da177e4SLinus Torvalds 
1917c0ce9fb3SPavel Emelyanov static void devinet_copy_dflt_conf(struct net *net, int i)
191831be3085SHerbert Xu {
191931be3085SHerbert Xu 	struct net_device *dev;
192031be3085SHerbert Xu 
192131be3085SHerbert Xu 	rcu_read_lock();
1922c6d14c84SEric Dumazet 	for_each_netdev_rcu(net, dev) {
1923c6d14c84SEric Dumazet 		struct in_device *in_dev;
1924c6d14c84SEric Dumazet 
192531be3085SHerbert Xu 		in_dev = __in_dev_get_rcu(dev);
192631be3085SHerbert Xu 		if (in_dev && !test_bit(i, in_dev->cnf.state))
19279355bbd6SPavel Emelyanov 			in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
1928c6d14c84SEric Dumazet 	}
192931be3085SHerbert Xu 	rcu_read_unlock();
193031be3085SHerbert Xu }
193131be3085SHerbert Xu 
1932c6d14c84SEric Dumazet /* called with RTNL locked */
1933c0ce9fb3SPavel Emelyanov static void inet_forward_change(struct net *net)
193468dd299bSPavel Emelyanov {
193568dd299bSPavel Emelyanov 	struct net_device *dev;
1936586f1211SPavel Emelyanov 	int on = IPV4_DEVCONF_ALL(net, FORWARDING);
193768dd299bSPavel Emelyanov 
1938586f1211SPavel Emelyanov 	IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
19399355bbd6SPavel Emelyanov 	IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
1940edc9e748SNicolas Dichtel 	inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1941edc9e748SNicolas Dichtel 				    NETCONFA_IFINDEX_ALL,
1942edc9e748SNicolas Dichtel 				    net->ipv4.devconf_all);
1943edc9e748SNicolas Dichtel 	inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1944edc9e748SNicolas Dichtel 				    NETCONFA_IFINDEX_DEFAULT,
1945edc9e748SNicolas Dichtel 				    net->ipv4.devconf_dflt);
194668dd299bSPavel Emelyanov 
1947c0ce9fb3SPavel Emelyanov 	for_each_netdev(net, dev) {
194868dd299bSPavel Emelyanov 		struct in_device *in_dev;
19490187bdfbSBen Hutchings 		if (on)
19500187bdfbSBen Hutchings 			dev_disable_lro(dev);
195168dd299bSPavel Emelyanov 		rcu_read_lock();
195268dd299bSPavel Emelyanov 		in_dev = __in_dev_get_rcu(dev);
1953edc9e748SNicolas Dichtel 		if (in_dev) {
195468dd299bSPavel Emelyanov 			IN_DEV_CONF_SET(in_dev, FORWARDING, on);
1955edc9e748SNicolas Dichtel 			inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1956edc9e748SNicolas Dichtel 						    dev->ifindex, &in_dev->cnf);
1957edc9e748SNicolas Dichtel 		}
195868dd299bSPavel Emelyanov 		rcu_read_unlock();
195968dd299bSPavel Emelyanov 	}
196068dd299bSPavel Emelyanov }
196168dd299bSPavel Emelyanov 
1962f085ff1cSstephen hemminger static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf)
1963f085ff1cSstephen hemminger {
1964f085ff1cSstephen hemminger 	if (cnf == net->ipv4.devconf_dflt)
1965f085ff1cSstephen hemminger 		return NETCONFA_IFINDEX_DEFAULT;
1966f085ff1cSstephen hemminger 	else if (cnf == net->ipv4.devconf_all)
1967f085ff1cSstephen hemminger 		return NETCONFA_IFINDEX_ALL;
1968f085ff1cSstephen hemminger 	else {
1969f085ff1cSstephen hemminger 		struct in_device *idev
1970f085ff1cSstephen hemminger 			= container_of(cnf, struct in_device, cnf);
1971f085ff1cSstephen hemminger 		return idev->dev->ifindex;
1972f085ff1cSstephen hemminger 	}
1973f085ff1cSstephen hemminger }
1974f085ff1cSstephen hemminger 
1975fe2c6338SJoe Perches static int devinet_conf_proc(struct ctl_table *ctl, int write,
19768d65af78SAlexey Dobriyan 			     void __user *buffer,
197731be3085SHerbert Xu 			     size_t *lenp, loff_t *ppos)
197831be3085SHerbert Xu {
1979d01ff0a0SPeter Pan(潘卫平) 	int old_value = *(int *)ctl->data;
19808d65af78SAlexey Dobriyan 	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
1981d01ff0a0SPeter Pan(潘卫平) 	int new_value = *(int *)ctl->data;
198231be3085SHerbert Xu 
198331be3085SHerbert Xu 	if (write) {
198431be3085SHerbert Xu 		struct ipv4_devconf *cnf = ctl->extra1;
1985c0ce9fb3SPavel Emelyanov 		struct net *net = ctl->extra2;
198631be3085SHerbert Xu 		int i = (int *)ctl->data - cnf->data;
1987f085ff1cSstephen hemminger 		int ifindex;
198831be3085SHerbert Xu 
198931be3085SHerbert Xu 		set_bit(i, cnf->state);
199031be3085SHerbert Xu 
19919355bbd6SPavel Emelyanov 		if (cnf == net->ipv4.devconf_dflt)
1992c0ce9fb3SPavel Emelyanov 			devinet_copy_dflt_conf(net, i);
1993d0daebc3SThomas Graf 		if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
1994d0daebc3SThomas Graf 		    i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
1995d01ff0a0SPeter Pan(潘卫平) 			if ((new_value == 0) && (old_value != 0))
19964ccfe6d4SNicolas Dichtel 				rt_cache_flush(net);
1997f085ff1cSstephen hemminger 
1998cc535dfbSNicolas Dichtel 		if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
1999cc535dfbSNicolas Dichtel 		    new_value != old_value) {
2000f085ff1cSstephen hemminger 			ifindex = devinet_conf_ifindex(net, cnf);
2001cc535dfbSNicolas Dichtel 			inet_netconf_notify_devconf(net, NETCONFA_RP_FILTER,
2002cc535dfbSNicolas Dichtel 						    ifindex, cnf);
2003cc535dfbSNicolas Dichtel 		}
2004f085ff1cSstephen hemminger 		if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
2005f085ff1cSstephen hemminger 		    new_value != old_value) {
2006f085ff1cSstephen hemminger 			ifindex = devinet_conf_ifindex(net, cnf);
200709aea5dfSstephen hemminger 			inet_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH,
2008f085ff1cSstephen hemminger 						    ifindex, cnf);
2009f085ff1cSstephen hemminger 		}
201031be3085SHerbert Xu 	}
201131be3085SHerbert Xu 
201231be3085SHerbert Xu 	return ret;
201331be3085SHerbert Xu }
201431be3085SHerbert Xu 
2015fe2c6338SJoe Perches static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
20168d65af78SAlexey Dobriyan 				  void __user *buffer,
20171da177e4SLinus Torvalds 				  size_t *lenp, loff_t *ppos)
20181da177e4SLinus Torvalds {
20191da177e4SLinus Torvalds 	int *valp = ctl->data;
20201da177e4SLinus Torvalds 	int val = *valp;
202188af182eSEric W. Biederman 	loff_t pos = *ppos;
20228d65af78SAlexey Dobriyan 	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
20231da177e4SLinus Torvalds 
20241da177e4SLinus Torvalds 	if (write && *valp != val) {
2025c0ce9fb3SPavel Emelyanov 		struct net *net = ctl->extra2;
2026c0ce9fb3SPavel Emelyanov 
20270187bdfbSBen Hutchings 		if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
202888af182eSEric W. Biederman 			if (!rtnl_trylock()) {
202988af182eSEric W. Biederman 				/* Restore the original values before restarting */
203088af182eSEric W. Biederman 				*valp = val;
203188af182eSEric W. Biederman 				*ppos = pos;
20329b8adb5eSEric W. Biederman 				return restart_syscall();
203388af182eSEric W. Biederman 			}
20340187bdfbSBen Hutchings 			if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2035c0ce9fb3SPavel Emelyanov 				inet_forward_change(net);
2036edc9e748SNicolas Dichtel 			} else {
20370187bdfbSBen Hutchings 				struct ipv4_devconf *cnf = ctl->extra1;
20380187bdfbSBen Hutchings 				struct in_device *idev =
20390187bdfbSBen Hutchings 					container_of(cnf, struct in_device, cnf);
2040edc9e748SNicolas Dichtel 				if (*valp)
20410187bdfbSBen Hutchings 					dev_disable_lro(idev->dev);
2042edc9e748SNicolas Dichtel 				inet_netconf_notify_devconf(net,
2043edc9e748SNicolas Dichtel 							    NETCONFA_FORWARDING,
2044edc9e748SNicolas Dichtel 							    idev->dev->ifindex,
2045edc9e748SNicolas Dichtel 							    cnf);
20460187bdfbSBen Hutchings 			}
20470187bdfbSBen Hutchings 			rtnl_unlock();
20484ccfe6d4SNicolas Dichtel 			rt_cache_flush(net);
2049edc9e748SNicolas Dichtel 		} else
2050edc9e748SNicolas Dichtel 			inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
2051edc9e748SNicolas Dichtel 						    NETCONFA_IFINDEX_DEFAULT,
2052edc9e748SNicolas Dichtel 						    net->ipv4.devconf_dflt);
20530187bdfbSBen Hutchings 	}
20541da177e4SLinus Torvalds 
20551da177e4SLinus Torvalds 	return ret;
20561da177e4SLinus Torvalds }
20571da177e4SLinus Torvalds 
2058fe2c6338SJoe Perches static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
20598d65af78SAlexey Dobriyan 				void __user *buffer,
20601da177e4SLinus Torvalds 				size_t *lenp, loff_t *ppos)
20611da177e4SLinus Torvalds {
20621da177e4SLinus Torvalds 	int *valp = ctl->data;
20631da177e4SLinus Torvalds 	int val = *valp;
20648d65af78SAlexey Dobriyan 	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
206576e6ebfbSDenis V. Lunev 	struct net *net = ctl->extra2;
20661da177e4SLinus Torvalds 
20671da177e4SLinus Torvalds 	if (write && *valp != val)
20684ccfe6d4SNicolas Dichtel 		rt_cache_flush(net);
20691da177e4SLinus Torvalds 
20701da177e4SLinus Torvalds 	return ret;
20711da177e4SLinus Torvalds }
20721da177e4SLinus Torvalds 
2073f8572d8fSEric W. Biederman #define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
207442f811b8SHerbert Xu 	{ \
207542f811b8SHerbert Xu 		.procname	= name, \
207642f811b8SHerbert Xu 		.data		= ipv4_devconf.data + \
207702291680SEric W. Biederman 				  IPV4_DEVCONF_ ## attr - 1, \
207842f811b8SHerbert Xu 		.maxlen		= sizeof(int), \
207942f811b8SHerbert Xu 		.mode		= mval, \
208042f811b8SHerbert Xu 		.proc_handler	= proc, \
208131be3085SHerbert Xu 		.extra1		= &ipv4_devconf, \
208242f811b8SHerbert Xu 	}
208342f811b8SHerbert Xu 
208442f811b8SHerbert Xu #define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
2085f8572d8fSEric W. Biederman 	DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
208642f811b8SHerbert Xu 
208742f811b8SHerbert Xu #define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
2088f8572d8fSEric W. Biederman 	DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
208942f811b8SHerbert Xu 
2090f8572d8fSEric W. Biederman #define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2091f8572d8fSEric W. Biederman 	DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
209242f811b8SHerbert Xu 
209342f811b8SHerbert Xu #define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
2094f8572d8fSEric W. Biederman 	DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
209542f811b8SHerbert Xu 
20961da177e4SLinus Torvalds static struct devinet_sysctl_table {
20971da177e4SLinus Torvalds 	struct ctl_table_header *sysctl_header;
209802291680SEric W. Biederman 	struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
20991da177e4SLinus Torvalds } devinet_sysctl = {
21001da177e4SLinus Torvalds 	.devinet_vars = {
210142f811b8SHerbert Xu 		DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
2102f8572d8fSEric W. Biederman 					     devinet_sysctl_forward),
210342f811b8SHerbert Xu 		DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
210442f811b8SHerbert Xu 
210542f811b8SHerbert Xu 		DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
210642f811b8SHerbert Xu 		DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
210742f811b8SHerbert Xu 		DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
210842f811b8SHerbert Xu 		DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
210942f811b8SHerbert Xu 		DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
211042f811b8SHerbert Xu 		DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
211142f811b8SHerbert Xu 					"accept_source_route"),
21128153a10cSPatrick McHardy 		DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
211328f6aeeaSJamal Hadi Salim 		DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
211442f811b8SHerbert Xu 		DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
211542f811b8SHerbert Xu 		DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
211642f811b8SHerbert Xu 		DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
211742f811b8SHerbert Xu 		DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
211842f811b8SHerbert Xu 		DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
211942f811b8SHerbert Xu 		DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
212042f811b8SHerbert Xu 		DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
212142f811b8SHerbert Xu 		DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
212242f811b8SHerbert Xu 		DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
2123eefef1cfSStephen Hemminger 		DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
212465324144SJesper Dangaard Brouer 		DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
21255c6fe01cSWilliam Manley 		DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
21265c6fe01cSWilliam Manley 					"force_igmp_version"),
21272690048cSWilliam Manley 		DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
21282690048cSWilliam Manley 					"igmpv2_unsolicited_report_interval"),
21292690048cSWilliam Manley 		DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
21302690048cSWilliam Manley 					"igmpv3_unsolicited_report_interval"),
213142f811b8SHerbert Xu 
213242f811b8SHerbert Xu 		DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
213342f811b8SHerbert Xu 		DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
213442f811b8SHerbert Xu 		DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
213542f811b8SHerbert Xu 					      "promote_secondaries"),
2136d0daebc3SThomas Graf 		DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2137d0daebc3SThomas Graf 					      "route_localnet"),
21381da177e4SLinus Torvalds 	},
21391da177e4SLinus Torvalds };
21401da177e4SLinus Torvalds 
2141ea40b324SPavel Emelyanov static int __devinet_sysctl_register(struct net *net, char *dev_name,
2142f8572d8fSEric W. Biederman 					struct ipv4_devconf *p)
21431da177e4SLinus Torvalds {
21441da177e4SLinus Torvalds 	int i;
21459fa89642SPavel Emelyanov 	struct devinet_sysctl_table *t;
21468607ddb8SEric W. Biederman 	char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
2147bfada697SPavel Emelyanov 
21489fa89642SPavel Emelyanov 	t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
21491da177e4SLinus Torvalds 	if (!t)
21509fa89642SPavel Emelyanov 		goto out;
21519fa89642SPavel Emelyanov 
21521da177e4SLinus Torvalds 	for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
21531da177e4SLinus Torvalds 		t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
215431be3085SHerbert Xu 		t->devinet_vars[i].extra1 = p;
2155c0ce9fb3SPavel Emelyanov 		t->devinet_vars[i].extra2 = net;
21561da177e4SLinus Torvalds 	}
21571da177e4SLinus Torvalds 
21588607ddb8SEric W. Biederman 	snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
21591da177e4SLinus Torvalds 
21608607ddb8SEric W. Biederman 	t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
21611da177e4SLinus Torvalds 	if (!t->sysctl_header)
21628607ddb8SEric W. Biederman 		goto free;
21631da177e4SLinus Torvalds 
21641da177e4SLinus Torvalds 	p->sysctl = t;
2165ea40b324SPavel Emelyanov 	return 0;
21661da177e4SLinus Torvalds 
21671da177e4SLinus Torvalds free:
21681da177e4SLinus Torvalds 	kfree(t);
21699fa89642SPavel Emelyanov out:
2170ea40b324SPavel Emelyanov 	return -ENOBUFS;
21711da177e4SLinus Torvalds }
21721da177e4SLinus Torvalds 
217351602b2aSPavel Emelyanov static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
217466f27a52SPavel Emelyanov {
217551602b2aSPavel Emelyanov 	struct devinet_sysctl_table *t = cnf->sysctl;
217666f27a52SPavel Emelyanov 
217751602b2aSPavel Emelyanov 	if (t == NULL)
217851602b2aSPavel Emelyanov 		return;
217951602b2aSPavel Emelyanov 
218051602b2aSPavel Emelyanov 	cnf->sysctl = NULL;
2181ff538818SLucian Adrian Grijincu 	unregister_net_sysctl_table(t->sysctl_header);
21821da177e4SLinus Torvalds 	kfree(t);
21831da177e4SLinus Torvalds }
218451602b2aSPavel Emelyanov 
218551602b2aSPavel Emelyanov static void devinet_sysctl_register(struct in_device *idev)
218651602b2aSPavel Emelyanov {
218773af614aSJiri Pirko 	neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
2188c346dca1SYOSHIFUJI Hideaki 	__devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
2189f8572d8fSEric W. Biederman 					&idev->cnf);
219051602b2aSPavel Emelyanov }
219151602b2aSPavel Emelyanov 
219251602b2aSPavel Emelyanov static void devinet_sysctl_unregister(struct in_device *idev)
219351602b2aSPavel Emelyanov {
219451602b2aSPavel Emelyanov 	__devinet_sysctl_unregister(&idev->cnf);
219551602b2aSPavel Emelyanov 	neigh_sysctl_unregister(idev->arp_parms);
21961da177e4SLinus Torvalds }
21971da177e4SLinus Torvalds 
219868dd299bSPavel Emelyanov static struct ctl_table ctl_forward_entry[] = {
219968dd299bSPavel Emelyanov 	{
220068dd299bSPavel Emelyanov 		.procname	= "ip_forward",
220168dd299bSPavel Emelyanov 		.data		= &ipv4_devconf.data[
220202291680SEric W. Biederman 					IPV4_DEVCONF_FORWARDING - 1],
220368dd299bSPavel Emelyanov 		.maxlen		= sizeof(int),
220468dd299bSPavel Emelyanov 		.mode		= 0644,
220568dd299bSPavel Emelyanov 		.proc_handler	= devinet_sysctl_forward,
220668dd299bSPavel Emelyanov 		.extra1		= &ipv4_devconf,
2207c0ce9fb3SPavel Emelyanov 		.extra2		= &init_net,
220868dd299bSPavel Emelyanov 	},
220968dd299bSPavel Emelyanov 	{ },
221068dd299bSPavel Emelyanov };
22112a75de0cSEric Dumazet #endif
221268dd299bSPavel Emelyanov 
2213752d14dcSPavel Emelyanov static __net_init int devinet_init_net(struct net *net)
2214752d14dcSPavel Emelyanov {
2215752d14dcSPavel Emelyanov 	int err;
2216752d14dcSPavel Emelyanov 	struct ipv4_devconf *all, *dflt;
22172a75de0cSEric Dumazet #ifdef CONFIG_SYSCTL
22182a75de0cSEric Dumazet 	struct ctl_table *tbl = ctl_forward_entry;
2219752d14dcSPavel Emelyanov 	struct ctl_table_header *forw_hdr;
22202a75de0cSEric Dumazet #endif
2221752d14dcSPavel Emelyanov 
2222752d14dcSPavel Emelyanov 	err = -ENOMEM;
2223752d14dcSPavel Emelyanov 	all = &ipv4_devconf;
2224752d14dcSPavel Emelyanov 	dflt = &ipv4_devconf_dflt;
2225752d14dcSPavel Emelyanov 
222609ad9bc7SOctavian Purdila 	if (!net_eq(net, &init_net)) {
2227752d14dcSPavel Emelyanov 		all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
2228752d14dcSPavel Emelyanov 		if (all == NULL)
2229752d14dcSPavel Emelyanov 			goto err_alloc_all;
2230752d14dcSPavel Emelyanov 
2231752d14dcSPavel Emelyanov 		dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
2232752d14dcSPavel Emelyanov 		if (dflt == NULL)
2233752d14dcSPavel Emelyanov 			goto err_alloc_dflt;
2234752d14dcSPavel Emelyanov 
22352a75de0cSEric Dumazet #ifdef CONFIG_SYSCTL
2236752d14dcSPavel Emelyanov 		tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
2237752d14dcSPavel Emelyanov 		if (tbl == NULL)
2238752d14dcSPavel Emelyanov 			goto err_alloc_ctl;
2239752d14dcSPavel Emelyanov 
224002291680SEric W. Biederman 		tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
2241752d14dcSPavel Emelyanov 		tbl[0].extra1 = all;
2242752d14dcSPavel Emelyanov 		tbl[0].extra2 = net;
22432a75de0cSEric Dumazet #endif
2244752d14dcSPavel Emelyanov 	}
2245752d14dcSPavel Emelyanov 
2246752d14dcSPavel Emelyanov #ifdef CONFIG_SYSCTL
2247f8572d8fSEric W. Biederman 	err = __devinet_sysctl_register(net, "all", all);
2248752d14dcSPavel Emelyanov 	if (err < 0)
2249752d14dcSPavel Emelyanov 		goto err_reg_all;
2250752d14dcSPavel Emelyanov 
2251f8572d8fSEric W. Biederman 	err = __devinet_sysctl_register(net, "default", dflt);
2252752d14dcSPavel Emelyanov 	if (err < 0)
2253752d14dcSPavel Emelyanov 		goto err_reg_dflt;
2254752d14dcSPavel Emelyanov 
2255752d14dcSPavel Emelyanov 	err = -ENOMEM;
22568607ddb8SEric W. Biederman 	forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
2257752d14dcSPavel Emelyanov 	if (forw_hdr == NULL)
2258752d14dcSPavel Emelyanov 		goto err_reg_ctl;
22592a75de0cSEric Dumazet 	net->ipv4.forw_hdr = forw_hdr;
2260752d14dcSPavel Emelyanov #endif
2261752d14dcSPavel Emelyanov 
2262752d14dcSPavel Emelyanov 	net->ipv4.devconf_all = all;
2263752d14dcSPavel Emelyanov 	net->ipv4.devconf_dflt = dflt;
2264752d14dcSPavel Emelyanov 	return 0;
2265752d14dcSPavel Emelyanov 
2266752d14dcSPavel Emelyanov #ifdef CONFIG_SYSCTL
2267752d14dcSPavel Emelyanov err_reg_ctl:
2268752d14dcSPavel Emelyanov 	__devinet_sysctl_unregister(dflt);
2269752d14dcSPavel Emelyanov err_reg_dflt:
2270752d14dcSPavel Emelyanov 	__devinet_sysctl_unregister(all);
2271752d14dcSPavel Emelyanov err_reg_all:
2272752d14dcSPavel Emelyanov 	if (tbl != ctl_forward_entry)
2273752d14dcSPavel Emelyanov 		kfree(tbl);
2274752d14dcSPavel Emelyanov err_alloc_ctl:
22752a75de0cSEric Dumazet #endif
2276752d14dcSPavel Emelyanov 	if (dflt != &ipv4_devconf_dflt)
2277752d14dcSPavel Emelyanov 		kfree(dflt);
2278752d14dcSPavel Emelyanov err_alloc_dflt:
2279752d14dcSPavel Emelyanov 	if (all != &ipv4_devconf)
2280752d14dcSPavel Emelyanov 		kfree(all);
2281752d14dcSPavel Emelyanov err_alloc_all:
2282752d14dcSPavel Emelyanov 	return err;
2283752d14dcSPavel Emelyanov }
2284752d14dcSPavel Emelyanov 
2285752d14dcSPavel Emelyanov static __net_exit void devinet_exit_net(struct net *net)
2286752d14dcSPavel Emelyanov {
22872a75de0cSEric Dumazet #ifdef CONFIG_SYSCTL
2288752d14dcSPavel Emelyanov 	struct ctl_table *tbl;
2289752d14dcSPavel Emelyanov 
2290752d14dcSPavel Emelyanov 	tbl = net->ipv4.forw_hdr->ctl_table_arg;
2291752d14dcSPavel Emelyanov 	unregister_net_sysctl_table(net->ipv4.forw_hdr);
2292752d14dcSPavel Emelyanov 	__devinet_sysctl_unregister(net->ipv4.devconf_dflt);
2293752d14dcSPavel Emelyanov 	__devinet_sysctl_unregister(net->ipv4.devconf_all);
2294752d14dcSPavel Emelyanov 	kfree(tbl);
22952a75de0cSEric Dumazet #endif
2296752d14dcSPavel Emelyanov 	kfree(net->ipv4.devconf_dflt);
2297752d14dcSPavel Emelyanov 	kfree(net->ipv4.devconf_all);
2298752d14dcSPavel Emelyanov }
2299752d14dcSPavel Emelyanov 
2300752d14dcSPavel Emelyanov static __net_initdata struct pernet_operations devinet_ops = {
2301752d14dcSPavel Emelyanov 	.init = devinet_init_net,
2302752d14dcSPavel Emelyanov 	.exit = devinet_exit_net,
2303752d14dcSPavel Emelyanov };
2304752d14dcSPavel Emelyanov 
23059f0f7272SThomas Graf static struct rtnl_af_ops inet_af_ops = {
23069f0f7272SThomas Graf 	.family		  = AF_INET,
23079f0f7272SThomas Graf 	.fill_link_af	  = inet_fill_link_af,
23089f0f7272SThomas Graf 	.get_link_af_size = inet_get_link_af_size,
2309cf7afbfeSThomas Graf 	.validate_link_af = inet_validate_link_af,
2310cf7afbfeSThomas Graf 	.set_link_af	  = inet_set_link_af,
23119f0f7272SThomas Graf };
23129f0f7272SThomas Graf 
23131da177e4SLinus Torvalds void __init devinet_init(void)
23141da177e4SLinus Torvalds {
2315fd23c3b3SDavid S. Miller 	int i;
2316fd23c3b3SDavid S. Miller 
2317fd23c3b3SDavid S. Miller 	for (i = 0; i < IN4_ADDR_HSIZE; i++)
2318fd23c3b3SDavid S. Miller 		INIT_HLIST_HEAD(&inet_addr_lst[i]);
2319fd23c3b3SDavid S. Miller 
2320752d14dcSPavel Emelyanov 	register_pernet_subsys(&devinet_ops);
2321752d14dcSPavel Emelyanov 
23221da177e4SLinus Torvalds 	register_gifconf(PF_INET, inet_gifconf);
23231da177e4SLinus Torvalds 	register_netdevice_notifier(&ip_netdev_notifier);
232463f3444fSThomas Graf 
2325906e073fSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
23265c766d64SJiri Pirko 
23279f0f7272SThomas Graf 	rtnl_af_register(&inet_af_ops);
23289f0f7272SThomas Graf 
2329c7ac8679SGreg Rose 	rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL);
2330c7ac8679SGreg Rose 	rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, NULL);
2331c7ac8679SGreg Rose 	rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, NULL);
23329e551110SNicolas Dichtel 	rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
23337a674200SNicolas Dichtel 		      inet_netconf_dump_devconf, NULL);
23341da177e4SLinus Torvalds }
23351da177e4SLinus Torvalds 
2336