Blame view

net/ipv4/devinet.c 68.6 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
  /*
   *	NET3	IP device support routines.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
   *	Derived from the IP parts of dev.c 1.0.19
02c30a84e   Jesper Juhl   [PATCH] update Ro...
6
   * 		Authors:	Ross Biro
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   *				Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
   *				Mark Evans, <evansmp@uhura.aston.ac.uk>
   *
   *	Additional Authors:
   *		Alan Cox, <gw4pts@gw4pts.ampr.org>
   *		Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
   *
   *	Changes:
   *		Alexey Kuznetsov:	pa_* fields are replaced with ifaddr
   *					lists.
   *		Cyrus Durgin:		updated for kmod
   *		Matthias Andree:	in devinet_ioctl, compare label and
   *					address (4.4BSD alias style support),
   *					fall back to comparing just the label
   *					if no match found.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23

7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
24
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  #include <linux/bitops.h>
4fc268d24   Randy Dunlap   [PATCH] capable/c...
26
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
174cd4b1e   Ingo Molnar   sched/headers: Pr...
30
  #include <linux/sched/signal.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
35
36
37
  #include <linux/string.h>
  #include <linux/mm.h>
  #include <linux/socket.h>
  #include <linux/sockios.h>
  #include <linux/in.h>
  #include <linux/errno.h>
  #include <linux/interrupt.h>
1823730fb   Thomas Graf   [IPv4]: Move inte...
38
  #include <linux/if_addr.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
42
43
  #include <linux/if_ether.h>
  #include <linux/inet.h>
  #include <linux/netdevice.h>
  #include <linux/etherdevice.h>
  #include <linux/skbuff.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
  #include <linux/init.h>
  #include <linux/notifier.h>
  #include <linux/inetdevice.h>
  #include <linux/igmp.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
48
  #include <linux/slab.h>
fd23c3b31   David S. Miller   ipv4: Add hash ta...
49
  #include <linux/hash.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
53
  #ifdef CONFIG_SYSCTL
  #include <linux/sysctl.h>
  #endif
  #include <linux/kmod.h>
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
54
  #include <linux/netconf.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55

14c850212   Arnaldo Carvalho de Melo   [INET_SOCK]: Move...
56
  #include <net/arp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
  #include <net/ip.h>
  #include <net/route.h>
  #include <net/ip_fib.h>
63f3444fb   Thomas Graf   [IPv4]: Use rtnl ...
60
  #include <net/rtnetlink.h>
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
61
  #include <net/net_namespace.h>
5c766d642   Jiri Pirko   ipv4: introduce a...
62
  #include <net/addrconf.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63

2e6054636   Matteo Croce   ipv4: don't set I...
64
65
66
67
  #define IPV6ONLY_FLAGS	\
  		(IFA_F_NODAD | IFA_F_OPTIMISTIC | IFA_F_DADFAILED | \
  		 IFA_F_HOMEADDRESS | IFA_F_TENTATIVE | \
  		 IFA_F_MANAGETEMPADDR | IFA_F_STABLE_PRIVACY)
0027ba843   Adrian Bunk   [IPV4]: Make stru...
68
  static struct ipv4_devconf ipv4_devconf = {
42f811b8b   Herbert Xu   [IPV4]: Convert I...
69
  	.data = {
02291680f   Eric W. Biederman   net ipv4: Decoupl...
70
71
72
73
  		[IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
  		[IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
  		[IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
  		[IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
2690048c0   William Manley   net: igmp: Allow ...
74
75
  		[IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
  		[IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] =  1000 /*ms*/,
42f811b8b   Herbert Xu   [IPV4]: Convert I...
76
  	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
  };
  
  static struct ipv4_devconf ipv4_devconf_dflt = {
42f811b8b   Herbert Xu   [IPV4]: Convert I...
80
  	.data = {
02291680f   Eric W. Biederman   net ipv4: Decoupl...
81
82
83
84
85
  		[IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
  		[IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
  		[IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
  		[IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
  		[IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
2690048c0   William Manley   net: igmp: Allow ...
86
87
  		[IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
  		[IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] =  1000 /*ms*/,
42f811b8b   Herbert Xu   [IPV4]: Convert I...
88
  	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
  };
9355bbd68   Pavel Emelyanov   [IPV4]: Switch us...
90
91
  #define IPV4_DEVCONF_DFLT(net, attr) \
  	IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr)
42f811b8b   Herbert Xu   [IPV4]: Convert I...
92

ef7c79ed6   Patrick McHardy   [NETLINK]: Mark n...
93
  static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
5c7539781   Thomas Graf   [IPV4]: Convert a...
94
95
96
  	[IFA_LOCAL]     	= { .type = NLA_U32 },
  	[IFA_ADDRESS]   	= { .type = NLA_U32 },
  	[IFA_BROADCAST] 	= { .type = NLA_U32 },
5176f91ea   Thomas Graf   [NETLINK]: Make u...
97
  	[IFA_LABEL]     	= { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
5c766d642   Jiri Pirko   ipv4: introduce a...
98
  	[IFA_CACHEINFO]		= { .len = sizeof(struct ifa_cacheinfo) },
ad6c81359   Jiri Pirko   ipv4: add support...
99
  	[IFA_FLAGS]		= { .type = NLA_U32 },
af4d768ad   David Ahern   net/ipv4: Add sup...
100
  	[IFA_RT_PRIORITY]	= { .type = NLA_U32 },
d38071455   Christian Brauner   ipv4: enable IFA_...
101
  	[IFA_TARGET_NETNSID]	= { .type = NLA_S32 },
5c7539781   Thomas Graf   [IPV4]: Convert a...
102
  };
978a46fa6   Christian Brauner   ipv4: add inet_fi...
103
104
105
106
107
108
  struct inet_fill_args {
  	u32 portid;
  	u32 seq;
  	int event;
  	unsigned int flags;
  	int netnsid;
5fcd266a9   David Ahern   net/ipv4: Add sup...
109
  	int ifindex;
978a46fa6   Christian Brauner   ipv4: add inet_fi...
110
  };
40384999d   Eric Dumazet   ipv4: change inet...
111
112
  #define IN4_ADDR_HSIZE_SHIFT	8
  #define IN4_ADDR_HSIZE		(1U << IN4_ADDR_HSIZE_SHIFT)
fd23c3b31   David S. Miller   ipv4: Add hash ta...
113
  static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
fd23c3b31   David S. Miller   ipv4: Add hash ta...
114

6eada0110   Eric Dumazet   netns: constify n...
115
  static u32 inet_addr_hash(const struct net *net, __be32 addr)
fd23c3b31   David S. Miller   ipv4: Add hash ta...
116
  {
40384999d   Eric Dumazet   ipv4: change inet...
117
  	u32 val = (__force u32) addr ^ net_hash_mix(net);
fd23c3b31   David S. Miller   ipv4: Add hash ta...
118

40384999d   Eric Dumazet   ipv4: change inet...
119
  	return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
fd23c3b31   David S. Miller   ipv4: Add hash ta...
120
121
122
123
  }
  
  static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
  {
40384999d   Eric Dumazet   ipv4: change inet...
124
  	u32 hash = inet_addr_hash(net, ifa->ifa_local);
fd23c3b31   David S. Miller   ipv4: Add hash ta...
125

32a4be489   WANG Cong   ipv4: remove inet...
126
  	ASSERT_RTNL();
fd23c3b31   David S. Miller   ipv4: Add hash ta...
127
  	hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
fd23c3b31   David S. Miller   ipv4: Add hash ta...
128
129
130
131
  }
  
  static void inet_hash_remove(struct in_ifaddr *ifa)
  {
32a4be489   WANG Cong   ipv4: remove inet...
132
  	ASSERT_RTNL();
fd23c3b31   David S. Miller   ipv4: Add hash ta...
133
  	hlist_del_init_rcu(&ifa->hash);
fd23c3b31   David S. Miller   ipv4: Add hash ta...
134
  }
9435eb1cf   David S. Miller   ipv4: Implement _...
135
136
137
138
139
140
141
142
143
144
  /**
   * __ip_dev_find - find the first device with a given source address.
   * @net: the net namespace
   * @addr: the source address
   * @devref: if true, take a reference on the found device
   *
   * If a caller uses devref=false, it should be protected by RCU, or RTNL
   */
  struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
  {
9435eb1cf   David S. Miller   ipv4: Implement _...
145
146
  	struct net_device *result = NULL;
  	struct in_ifaddr *ifa;
9435eb1cf   David S. Miller   ipv4: Implement _...
147
148
  
  	rcu_read_lock();
6e617de84   Paolo Abeni   net: avoid a full...
149
150
  	ifa = inet_lookup_ifaddr_rcu(net, addr);
  	if (!ifa) {
406b6f974   David S. Miller   ipv4: Fallback to...
151
152
153
154
155
156
157
158
159
160
161
162
  		struct flowi4 fl4 = { .daddr = addr };
  		struct fib_result res = { 0 };
  		struct fib_table *local;
  
  		/* Fallback to FIB local table so that communication
  		 * over loopback subnets work.
  		 */
  		local = fib_get_table(net, RT_TABLE_LOCAL);
  		if (local &&
  		    !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
  		    res.type == RTN_LOCAL)
  			result = FIB_RES_DEV(res);
6e617de84   Paolo Abeni   net: avoid a full...
163
164
  	} else {
  		result = ifa->ifa_dev->dev;
406b6f974   David S. Miller   ipv4: Fallback to...
165
  	}
9435eb1cf   David S. Miller   ipv4: Implement _...
166
167
168
169
170
171
  	if (result && devref)
  		dev_hold(result);
  	rcu_read_unlock();
  	return result;
  }
  EXPORT_SYMBOL(__ip_dev_find);
6e617de84   Paolo Abeni   net: avoid a full...
172
173
174
175
176
177
178
179
180
181
182
183
184
  /* called under RCU lock */
  struct in_ifaddr *inet_lookup_ifaddr_rcu(struct net *net, __be32 addr)
  {
  	u32 hash = inet_addr_hash(net, addr);
  	struct in_ifaddr *ifa;
  
  	hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash)
  		if (ifa->ifa_local == addr &&
  		    net_eq(dev_net(ifa->ifa_dev->dev), net))
  			return ifa;
  
  	return NULL;
  }
d6062cbbd   Thomas Graf   [IPv4] address: C...
185
  static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186

e041c6834   Alan Stern   [PATCH] Notifier ...
187
  static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
3ad7d2468   Krister Johansen   Ipvlan should ret...
188
  static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain);
2638eb8b5   Florian Westphal   net: ipv4: provid...
189
190
  static void inet_del_ifa(struct in_device *in_dev,
  			 struct in_ifaddr __rcu **ifap,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
  			 int destroy);
  #ifdef CONFIG_SYSCTL
20e61da7f   WANG Cong   ipv4: fail early ...
193
  static int devinet_sysctl_register(struct in_device *idev);
51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
194
195
  static void devinet_sysctl_unregister(struct in_device *idev);
  #else
20e61da7f   WANG Cong   ipv4: fail early ...
196
  static int devinet_sysctl_register(struct in_device *idev)
51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
197
  {
20e61da7f   WANG Cong   ipv4: fail early ...
198
  	return 0;
51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
199
  }
40384999d   Eric Dumazet   ipv4: change inet...
200
  static void devinet_sysctl_unregister(struct in_device *idev)
51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
201
202
  {
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
205
206
207
208
  #endif
  
  /* Locks all the inet devices. */
  
  static struct in_ifaddr *inet_alloc_ifa(void)
  {
93adcc80f   Alexey Dobriyan   net: don't use IN...
209
  	return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
212
213
214
215
216
217
218
  }
  
  static void inet_rcu_free_ifa(struct rcu_head *head)
  {
  	struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
  	if (ifa->ifa_dev)
  		in_dev_put(ifa->ifa_dev);
  	kfree(ifa);
  }
40384999d   Eric Dumazet   ipv4: change inet...
219
  static void inet_free_ifa(struct in_ifaddr *ifa)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
222
223
224
225
226
  {
  	call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
  }
  
  void in_dev_finish_destroy(struct in_device *idev)
  {
  	struct net_device *dev = idev->dev;
547b792ca   Ilpo Järvinen   net: convert BUG_...
227
228
  	WARN_ON(idev->ifa_list);
  	WARN_ON(idev->mc_list);
e98970713   Eric Dumazet   igmp: hash a hash...
229
  	kfree(rcu_dereference_protected(idev->mc_hash, 1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
  #ifdef NET_REFCNT_DEBUG
91df42bed   Joe Perches   net: ipv4 and ipv...
231
232
  	pr_debug("%s: %p=%s
  ", __func__, idev, dev ? dev->name : "NIL");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
234
235
  #endif
  	dev_put(dev);
  	if (!idev->dead)
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
236
237
238
  		pr_err("Freeing alive in_device %p
  ", idev);
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
  		kfree(idev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  }
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
241
  EXPORT_SYMBOL(in_dev_finish_destroy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242

71e27da96   Herbert Xu   [IPV4]: Restore o...
243
  static struct in_device *inetdev_init(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
  {
  	struct in_device *in_dev;
20e61da7f   WANG Cong   ipv4: fail early ...
246
  	int err = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
  
  	ASSERT_RTNL();
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
249
  	in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
  	if (!in_dev)
  		goto out;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
252
  	memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
9355bbd68   Pavel Emelyanov   [IPV4]: Switch us...
253
  			sizeof(in_dev->cnf));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
255
  	in_dev->cnf.sysctl = NULL;
  	in_dev->dev = dev;
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
256
257
  	in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
  	if (!in_dev->arp_parms)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
  		goto out_kfree;
0187bdfb0   Ben Hutchings   net: Disable LRO ...
259
260
  	if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
  		dev_disable_lro(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
  	/* Reference in_dev->dev */
  	dev_hold(dev);
30c4cf577   David L Stevens   [IPV4/IPV6]: Fix ...
263
  	/* Account for reference dev->ip_ptr (below) */
7658b36f1   Reshetova, Elena   net: convert in_d...
264
  	refcount_set(&in_dev->refcnt, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265

20e61da7f   WANG Cong   ipv4: fail early ...
266
267
268
  	err = devinet_sysctl_register(in_dev);
  	if (err) {
  		in_dev->dead = 1;
1b49cd71b   Yang Yingliang   devinet: fix meml...
269
  		neigh_parms_release(&arp_tbl, in_dev->arp_parms);
20e61da7f   WANG Cong   ipv4: fail early ...
270
271
272
273
  		in_dev_put(in_dev);
  		in_dev = NULL;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
276
  	ip_mc_init_dev(in_dev);
  	if (dev->flags & IFF_UP)
  		ip_mc_up(in_dev);
483479ecc   Jarek Poplawski   [IPV4] devinet: i...
277

30c4cf577   David L Stevens   [IPV4/IPV6]: Fix ...
278
  	/* we can receive as soon as ip_ptr is set -- do this last */
cf778b00e   Eric Dumazet   net: reintroduce ...
279
  	rcu_assign_pointer(dev->ip_ptr, in_dev);
483479ecc   Jarek Poplawski   [IPV4] devinet: i...
280
  out:
20e61da7f   WANG Cong   ipv4: fail early ...
281
  	return in_dev ?: ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  out_kfree:
  	kfree(in_dev);
  	in_dev = NULL;
  	goto out;
  }
  
  static void in_dev_rcu_put(struct rcu_head *head)
  {
  	struct in_device *idev = container_of(head, struct in_device, rcu_head);
  	in_dev_put(idev);
  }
  
  static void inetdev_destroy(struct in_device *in_dev)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
  	struct net_device *dev;
2638eb8b5   Florian Westphal   net: ipv4: provid...
297
  	struct in_ifaddr *ifa;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
300
301
  
  	ASSERT_RTNL();
  
  	dev = in_dev->dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
305
  
  	in_dev->dead = 1;
  
  	ip_mc_destroy_dev(in_dev);
2638eb8b5   Florian Westphal   net: ipv4: provid...
306
  	while ((ifa = rtnl_dereference(in_dev->ifa_list)) != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
309
  		inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
  		inet_free_ifa(ifa);
  	}
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
310
  	RCU_INIT_POINTER(dev->ip_ptr, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311

51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
312
  	devinet_sysctl_unregister(in_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
314
315
316
317
  	neigh_parms_release(&arp_tbl, in_dev->arp_parms);
  	arp_ifdown(dev);
  
  	call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
  }
ff428d72c   Al Viro   [IPV4]: inet_addr...
318
  int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  {
d519e8708   Florian Westphal   devinet: use in_d...
320
  	const struct in_ifaddr *ifa;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
  	rcu_read_lock();
d519e8708   Florian Westphal   devinet: use in_d...
322
  	in_dev_for_each_ifa_rcu(ifa, in_dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
326
327
328
  		if (inet_ifa_match(a, ifa)) {
  			if (!b || inet_ifa_match(b, ifa)) {
  				rcu_read_unlock();
  				return 1;
  			}
  		}
d519e8708   Florian Westphal   devinet: use in_d...
329
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
332
  	rcu_read_unlock();
  	return 0;
  }
2638eb8b5   Florian Westphal   net: ipv4: provid...
333
334
335
  static void __inet_del_ifa(struct in_device *in_dev,
  			   struct in_ifaddr __rcu **ifap,
  			   int destroy, struct nlmsghdr *nlh, u32 portid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
  {
8f937c609   Harald Welte   [IPV4]: Primary a...
337
  	struct in_ifaddr *promote = NULL;
2638eb8b5   Florian Westphal   net: ipv4: provid...
338
339
  	struct in_ifaddr *ifa, *ifa1;
  	struct in_ifaddr *last_prim;
0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
340
341
  	struct in_ifaddr *prev_prom = NULL;
  	int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
  
  	ASSERT_RTNL();
2638eb8b5   Florian Westphal   net: ipv4: provid...
344
345
  	ifa1 = rtnl_dereference(*ifap);
  	last_prim = rtnl_dereference(in_dev->ifa_list);
fbd40ea01   David S. Miller   ipv4: Don't do ex...
346
347
  	if (in_dev->dead)
  		goto no_promotions;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
348
  	/* 1. Deleting primary ifaddr forces deletion all secondaries
8f937c609   Harald Welte   [IPV4]: Primary a...
349
350
  	 * unless alias promotion is set
  	 **/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
  
  	if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
2638eb8b5   Florian Westphal   net: ipv4: provid...
353
  		struct in_ifaddr __rcu **ifap1 = &ifa1->ifa_next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354

2638eb8b5   Florian Westphal   net: ipv4: provid...
355
  		while ((ifa = rtnl_dereference(*ifap1)) != NULL) {
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
356
  			if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
357
358
  			    ifa1->ifa_scope <= ifa->ifa_scope)
  				last_prim = ifa;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
361
362
  			if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
  			    ifa1->ifa_mask != ifa->ifa_mask ||
  			    !inet_ifa_match(ifa1->ifa_address, ifa)) {
  				ifap1 = &ifa->ifa_next;
0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
363
  				prev_prom = ifa;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
  				continue;
  			}
0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
366
  			if (!do_promote) {
fd23c3b31   David S. Miller   ipv4: Add hash ta...
367
  				inet_hash_remove(ifa);
8f937c609   Harald Welte   [IPV4]: Primary a...
368
  				*ifap1 = ifa->ifa_next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369

15e473046   Eric W. Biederman   netlink: Rename p...
370
  				rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
e041c6834   Alan Stern   [PATCH] Notifier ...
371
372
  				blocking_notifier_call_chain(&inetaddr_chain,
  						NETDEV_DOWN, ifa);
8f937c609   Harald Welte   [IPV4]: Primary a...
373
374
375
376
377
  				inet_free_ifa(ifa);
  			} else {
  				promote = ifa;
  				break;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
  		}
  	}
2d230e2b2   Julian Anastasov   ipv4: remove the ...
380
381
382
383
384
  	/* On promotion all secondaries from subnet are changing
  	 * the primary IP, we must remove all their routes silently
  	 * and later to add them back with new prefsrc. Do this
  	 * while all addresses are on the device list.
  	 */
2638eb8b5   Florian Westphal   net: ipv4: provid...
385
  	for (ifa = promote; ifa; ifa = rtnl_dereference(ifa->ifa_next)) {
2d230e2b2   Julian Anastasov   ipv4: remove the ...
386
387
388
389
  		if (ifa1->ifa_mask == ifa->ifa_mask &&
  		    inet_ifa_match(ifa1->ifa_address, ifa))
  			fib_del_ifaddr(ifa, ifa1);
  	}
fbd40ea01   David S. Miller   ipv4: Don't do ex...
390
  no_promotions:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
392
393
  	/* 2. Unlink it */
  
  	*ifap = ifa1->ifa_next;
fd23c3b31   David S. Miller   ipv4: Add hash ta...
394
  	inet_hash_remove(ifa1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
398
399
400
401
402
403
404
405
  
  	/* 3. Announce address deletion */
  
  	/* Send message first, then call notifier.
  	   At first sight, FIB update triggered by notifier
  	   will refer to already deleted ifaddr, that could confuse
  	   netlink listeners. It is not true: look, gated sees
  	   that route deleted and if it still thinks that ifaddr
  	   is valid, it will try to restore deleted routes... Grr.
  	   So that, this order is correct.
  	 */
15e473046   Eric W. Biederman   netlink: Rename p...
406
  	rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
e041c6834   Alan Stern   [PATCH] Notifier ...
407
  	blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408

0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
409
  	if (promote) {
2638eb8b5   Florian Westphal   net: ipv4: provid...
410
  		struct in_ifaddr *next_sec;
0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
411

2638eb8b5   Florian Westphal   net: ipv4: provid...
412
  		next_sec = rtnl_dereference(promote->ifa_next);
0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
413
  		if (prev_prom) {
2638eb8b5   Florian Westphal   net: ipv4: provid...
414
  			struct in_ifaddr *last_sec;
2638eb8b5   Florian Westphal   net: ipv4: provid...
415
  			rcu_assign_pointer(prev_prom->ifa_next, next_sec);
6a9e9cea4   Florian Westphal   net: ipv4: fix in...
416
417
  
  			last_sec = rtnl_dereference(last_prim->ifa_next);
2638eb8b5   Florian Westphal   net: ipv4: provid...
418
419
  			rcu_assign_pointer(promote->ifa_next, last_sec);
  			rcu_assign_pointer(last_prim->ifa_next, promote);
0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
420
  		}
8f937c609   Harald Welte   [IPV4]: Primary a...
421

8f937c609   Harald Welte   [IPV4]: Primary a...
422
  		promote->ifa_flags &= ~IFA_F_SECONDARY;
15e473046   Eric W. Biederman   netlink: Rename p...
423
  		rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
e041c6834   Alan Stern   [PATCH] Notifier ...
424
425
  		blocking_notifier_call_chain(&inetaddr_chain,
  				NETDEV_UP, promote);
2638eb8b5   Florian Westphal   net: ipv4: provid...
426
427
  		for (ifa = next_sec; ifa;
  		     ifa = rtnl_dereference(ifa->ifa_next)) {
0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
428
429
430
431
432
433
434
  			if (ifa1->ifa_mask != ifa->ifa_mask ||
  			    !inet_ifa_match(ifa1->ifa_address, ifa))
  					continue;
  			fib_add_ifaddr(ifa);
  		}
  
  	}
6363097cc   Herbert Xu   [IPV4]: Do not re...
435
  	if (destroy)
0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
436
  		inet_free_ifa(ifa1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
  }
2638eb8b5   Florian Westphal   net: ipv4: provid...
438
439
  static void inet_del_ifa(struct in_device *in_dev,
  			 struct in_ifaddr __rcu **ifap,
d6062cbbd   Thomas Graf   [IPv4] address: C...
440
441
442
443
  			 int destroy)
  {
  	__inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
  }
5c766d642   Jiri Pirko   ipv4: introduce a...
444
445
446
  static void check_lifetime(struct work_struct *work);
  
  static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
d6062cbbd   Thomas Graf   [IPv4] address: C...
447
  static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
de95e0479   David Ahern   net: Add extack t...
448
  			     u32 portid, struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
  {
2638eb8b5   Florian Westphal   net: ipv4: provid...
450
  	struct in_ifaddr __rcu **last_primary, **ifap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
  	struct in_device *in_dev = ifa->ifa_dev;
3ad7d2468   Krister Johansen   Ipvlan should ret...
452
  	struct in_validator_info ivi;
2638eb8b5   Florian Westphal   net: ipv4: provid...
453
  	struct in_ifaddr *ifa1;
3ad7d2468   Krister Johansen   Ipvlan should ret...
454
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
457
458
459
460
461
462
463
464
  
  	ASSERT_RTNL();
  
  	if (!ifa->ifa_local) {
  		inet_free_ifa(ifa);
  		return 0;
  	}
  
  	ifa->ifa_flags &= ~IFA_F_SECONDARY;
  	last_primary = &in_dev->ifa_list;
2e6054636   Matteo Croce   ipv4: don't set I...
465
466
  	/* Don't set IPv6 only flags to IPv4 addresses */
  	ifa->ifa_flags &= ~IPV6ONLY_FLAGS;
2638eb8b5   Florian Westphal   net: ipv4: provid...
467
468
469
470
  	ifap = &in_dev->ifa_list;
  	ifa1 = rtnl_dereference(*ifap);
  
  	while (ifa1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
  		if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
  		    ifa->ifa_scope <= ifa1->ifa_scope)
  			last_primary = &ifa1->ifa_next;
  		if (ifa1->ifa_mask == ifa->ifa_mask &&
  		    inet_ifa_match(ifa1->ifa_address, ifa)) {
  			if (ifa1->ifa_local == ifa->ifa_local) {
  				inet_free_ifa(ifa);
  				return -EEXIST;
  			}
  			if (ifa1->ifa_scope != ifa->ifa_scope) {
  				inet_free_ifa(ifa);
  				return -EINVAL;
  			}
  			ifa->ifa_flags |= IFA_F_SECONDARY;
  		}
2638eb8b5   Florian Westphal   net: ipv4: provid...
486
487
488
  
  		ifap = &ifa1->ifa_next;
  		ifa1 = rtnl_dereference(*ifap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  	}
3ad7d2468   Krister Johansen   Ipvlan should ret...
490
491
492
493
494
495
496
497
498
  	/* Allow any devices that wish to register ifaddr validtors to weigh
  	 * in now, before changes are committed.  The rntl lock is serializing
  	 * access here, so the state should not change between a validator call
  	 * and a final notify on commit.  This isn't invoked on promotion under
  	 * the assumption that validators are checking the address itself, and
  	 * not the flags.
  	 */
  	ivi.ivi_addr = ifa->ifa_address;
  	ivi.ivi_dev = ifa->ifa_dev;
de95e0479   David Ahern   net: Add extack t...
499
  	ivi.extack = extack;
3ad7d2468   Krister Johansen   Ipvlan should ret...
500
501
502
503
504
505
506
  	ret = blocking_notifier_call_chain(&inetaddr_validator_chain,
  					   NETDEV_UP, &ivi);
  	ret = notifier_to_errno(ret);
  	if (ret) {
  		inet_free_ifa(ifa);
  		return ret;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
  	if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
63862b5be   Aruna-Hewapathirane   net: replace macr...
508
  		prandom_seed((__force u32) ifa->ifa_local);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
  		ifap = last_primary;
  	}
2638eb8b5   Florian Westphal   net: ipv4: provid...
511
512
  	rcu_assign_pointer(ifa->ifa_next, *ifap);
  	rcu_assign_pointer(*ifap, ifa);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513

fd23c3b31   David S. Miller   ipv4: Add hash ta...
514
  	inet_hash_insert(dev_net(in_dev->dev), ifa);
5c766d642   Jiri Pirko   ipv4: introduce a...
515
  	cancel_delayed_work(&check_lifetime_work);
906e073f3   viresh kumar   net/ipv4: queue w...
516
  	queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
5c766d642   Jiri Pirko   ipv4: introduce a...
517

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
519
520
  	/* Send message first, then call notifier.
  	   Notifier will trigger FIB update, so that
  	   listeners of netlink will know about new ifaddr */
15e473046   Eric W. Biederman   netlink: Rename p...
521
  	rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
e041c6834   Alan Stern   [PATCH] Notifier ...
522
  	blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
525
  
  	return 0;
  }
d6062cbbd   Thomas Graf   [IPv4] address: C...
526
527
  static int inet_insert_ifa(struct in_ifaddr *ifa)
  {
de95e0479   David Ahern   net: Add extack t...
528
  	return __inet_insert_ifa(ifa, NULL, 0, NULL);
d6062cbbd   Thomas Graf   [IPv4] address: C...
529
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
531
  static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
  {
e5ed63991   Herbert Xu   [IPV4]: Replace _...
532
  	struct in_device *in_dev = __in_dev_get_rtnl(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
535
536
  
  	ASSERT_RTNL();
  
  	if (!in_dev) {
71e27da96   Herbert Xu   [IPV4]: Restore o...
537
538
  		inet_free_ifa(ifa);
  		return -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  	}
71e27da96   Herbert Xu   [IPV4]: Restore o...
540
  	ipv4_devconf_setall(in_dev);
1d4c8c298   Jiri Pirko   neigh: restore ol...
541
  	neigh_parms_data_state_setall(in_dev->arp_parms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
  	if (ifa->ifa_dev != in_dev) {
547b792ca   Ilpo Järvinen   net: convert BUG_...
543
  		WARN_ON(ifa->ifa_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
546
  		in_dev_hold(in_dev);
  		ifa->ifa_dev = in_dev;
  	}
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
547
  	if (ipv4_is_loopback(ifa->ifa_local))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
549
550
  		ifa->ifa_scope = RT_SCOPE_HOST;
  	return inet_insert_ifa(ifa);
  }
8723e1b4a   Eric Dumazet   inet: RCU changes...
551
552
553
  /* Caller must hold RCU or RTNL :
   * We dont take a reference on found in_device
   */
7fee0ca23   Denis V. Lunev   [NETNS]: Add netn...
554
  struct in_device *inetdev_by_index(struct net *net, int ifindex)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
557
  {
  	struct net_device *dev;
  	struct in_device *in_dev = NULL;
c148fc2e3   Eric Dumazet   ipv4: inetdev_by_...
558
559
560
  
  	rcu_read_lock();
  	dev = dev_get_by_index_rcu(net, ifindex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
  	if (dev)
8723e1b4a   Eric Dumazet   inet: RCU changes...
562
  		in_dev = rcu_dereference_rtnl(dev->ip_ptr);
c148fc2e3   Eric Dumazet   ipv4: inetdev_by_...
563
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
565
  	return in_dev;
  }
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
566
  EXPORT_SYMBOL(inetdev_by_index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
568
  
  /* Called only from RTNL semaphored context. No locks. */
60cad5da5   Al Viro   [IPV4]: annotate ...
569
570
  struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
  				    __be32 mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
  {
d519e8708   Florian Westphal   devinet: use in_d...
572
  	struct in_ifaddr *ifa;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
  	ASSERT_RTNL();
d519e8708   Florian Westphal   devinet: use in_d...
574
  	in_dev_for_each_ifa_rtnl(ifa, in_dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
  		if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
  			return ifa;
d519e8708   Florian Westphal   devinet: use in_d...
577
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
579
  	return NULL;
  }
690cc8632   Taras Chornyi   net: ipv4: devine...
580
581
  static int ip_mc_autojoin_config(struct net *net, bool join,
  				 const struct in_ifaddr *ifa)
93a714d6b   Madhu Challa   multicast: Extend...
582
  {
690cc8632   Taras Chornyi   net: ipv4: devine...
583
  #if defined(CONFIG_IP_MULTICAST)
93a714d6b   Madhu Challa   multicast: Extend...
584
585
586
587
  	struct ip_mreqn mreq = {
  		.imr_multiaddr.s_addr = ifa->ifa_address,
  		.imr_ifindex = ifa->ifa_dev->dev->ifindex,
  	};
690cc8632   Taras Chornyi   net: ipv4: devine...
588
  	struct sock *sk = net->ipv4.mc_autojoin_sk;
93a714d6b   Madhu Challa   multicast: Extend...
589
590
591
592
593
594
  	int ret;
  
  	ASSERT_RTNL();
  
  	lock_sock(sk);
  	if (join)
54ff9ef36   Marcelo Ricardo Leitner   ipv4, ipv6: kill ...
595
  		ret = ip_mc_join_group(sk, &mreq);
93a714d6b   Madhu Challa   multicast: Extend...
596
  	else
54ff9ef36   Marcelo Ricardo Leitner   ipv4, ipv6: kill ...
597
  		ret = ip_mc_leave_group(sk, &mreq);
93a714d6b   Madhu Challa   multicast: Extend...
598
599
600
  	release_sock(sk);
  
  	return ret;
690cc8632   Taras Chornyi   net: ipv4: devine...
601
602
603
  #else
  	return -EOPNOTSUPP;
  #endif
93a714d6b   Madhu Challa   multicast: Extend...
604
  }
c21ef3e34   David Ahern   net: rtnetlink: p...
605
606
  static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
  			    struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
608
  	struct net *net = sock_net(skb->sk);
2638eb8b5   Florian Westphal   net: ipv4: provid...
609
  	struct in_ifaddr __rcu **ifap;
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
610
  	struct nlattr *tb[IFA_MAX+1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
  	struct in_device *in_dev;
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
612
  	struct ifaddrmsg *ifm;
2638eb8b5   Florian Westphal   net: ipv4: provid...
613
  	struct in_ifaddr *ifa;
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
614
  	int err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
616
  
  	ASSERT_RTNL();
8cb081746   Johannes Berg   netlink: make val...
617
618
  	err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX,
  				     ifa_ipv4_policy, extack);
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
619
620
621
622
  	if (err < 0)
  		goto errout;
  
  	ifm = nlmsg_data(nlh);
7fee0ca23   Denis V. Lunev   [NETNS]: Add netn...
623
  	in_dev = inetdev_by_index(net, ifm->ifa_index);
51456b291   Ian Morris   ipv4: coding styl...
624
  	if (!in_dev) {
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
625
626
627
  		err = -ENODEV;
  		goto errout;
  	}
2638eb8b5   Florian Westphal   net: ipv4: provid...
628
  	for (ifap = &in_dev->ifa_list; (ifa = rtnl_dereference(*ifap)) != NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
  	     ifap = &ifa->ifa_next) {
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
630
  		if (tb[IFA_LOCAL] &&
67b61f6c1   Jiri Benc   netlink: implemen...
631
  		    ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
632
633
634
  			continue;
  
  		if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
  			continue;
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
636
637
638
  
  		if (tb[IFA_ADDRESS] &&
  		    (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
67b61f6c1   Jiri Benc   netlink: implemen...
639
  		    !inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa)))
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
640
  			continue;
93a714d6b   Madhu Challa   multicast: Extend...
641
  		if (ipv4_is_multicast(ifa->ifa_address))
690cc8632   Taras Chornyi   net: ipv4: devine...
642
  			ip_mc_autojoin_config(net, false, ifa);
15e473046   Eric W. Biederman   netlink: Rename p...
643
  		__inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
  		return 0;
  	}
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
646
647
648
649
  
  	err = -EADDRNOTAVAIL;
  errout:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  }
5c766d642   Jiri Pirko   ipv4: introduce a...
651
652
653
654
655
656
  #define INFINITY_LIFE_TIME	0xFFFFFFFF
  
  static void check_lifetime(struct work_struct *work)
  {
  	unsigned long now, next, next_sec, next_sched;
  	struct in_ifaddr *ifa;
c988d1e8c   Jiri Pirko   net: ipv4: fix sc...
657
  	struct hlist_node *n;
5c766d642   Jiri Pirko   ipv4: introduce a...
658
659
660
661
  	int i;
  
  	now = jiffies;
  	next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
5c766d642   Jiri Pirko   ipv4: introduce a...
662
  	for (i = 0; i < IN4_ADDR_HSIZE; i++) {
c988d1e8c   Jiri Pirko   net: ipv4: fix sc...
663
664
665
  		bool change_needed = false;
  
  		rcu_read_lock();
b67bfe0d4   Sasha Levin   hlist: drop the n...
666
  		hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
5c766d642   Jiri Pirko   ipv4: introduce a...
667
668
669
670
671
672
673
674
675
676
677
  			unsigned long age;
  
  			if (ifa->ifa_flags & IFA_F_PERMANENT)
  				continue;
  
  			/* We try to batch several events at once. */
  			age = (now - ifa->ifa_tstamp +
  			       ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
  
  			if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
  			    age >= ifa->ifa_valid_lft) {
c988d1e8c   Jiri Pirko   net: ipv4: fix sc...
678
  				change_needed = true;
5c766d642   Jiri Pirko   ipv4: introduce a...
679
680
681
682
683
684
685
686
  			} else if (ifa->ifa_preferred_lft ==
  				   INFINITY_LIFE_TIME) {
  				continue;
  			} else if (age >= ifa->ifa_preferred_lft) {
  				if (time_before(ifa->ifa_tstamp +
  						ifa->ifa_valid_lft * HZ, next))
  					next = ifa->ifa_tstamp +
  					       ifa->ifa_valid_lft * HZ;
c988d1e8c   Jiri Pirko   net: ipv4: fix sc...
687
688
  				if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
  					change_needed = true;
5c766d642   Jiri Pirko   ipv4: introduce a...
689
690
691
692
693
694
695
  			} else if (time_before(ifa->ifa_tstamp +
  					       ifa->ifa_preferred_lft * HZ,
  					       next)) {
  				next = ifa->ifa_tstamp +
  				       ifa->ifa_preferred_lft * HZ;
  			}
  		}
c988d1e8c   Jiri Pirko   net: ipv4: fix sc...
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
  		rcu_read_unlock();
  		if (!change_needed)
  			continue;
  		rtnl_lock();
  		hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
  			unsigned long age;
  
  			if (ifa->ifa_flags & IFA_F_PERMANENT)
  				continue;
  
  			/* We try to batch several events at once. */
  			age = (now - ifa->ifa_tstamp +
  			       ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
  
  			if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
  			    age >= ifa->ifa_valid_lft) {
2638eb8b5   Florian Westphal   net: ipv4: provid...
712
713
714
715
716
717
  				struct in_ifaddr __rcu **ifap;
  				struct in_ifaddr *tmp;
  
  				ifap = &ifa->ifa_dev->ifa_list;
  				tmp = rtnl_dereference(*ifap);
  				while (tmp) {
40008e921   Florian Westphal   net: ipv4: remove...
718
  					if (tmp == ifa) {
c988d1e8c   Jiri Pirko   net: ipv4: fix sc...
719
720
721
722
  						inet_del_ifa(ifa->ifa_dev,
  							     ifap, 1);
  						break;
  					}
2638eb8b5   Florian Westphal   net: ipv4: provid...
723
724
  					ifap = &tmp->ifa_next;
  					tmp = rtnl_dereference(*ifap);
c988d1e8c   Jiri Pirko   net: ipv4: fix sc...
725
726
727
728
729
730
731
732
733
734
  				}
  			} else if (ifa->ifa_preferred_lft !=
  				   INFINITY_LIFE_TIME &&
  				   age >= ifa->ifa_preferred_lft &&
  				   !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
  				ifa->ifa_flags |= IFA_F_DEPRECATED;
  				rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
  			}
  		}
  		rtnl_unlock();
5c766d642   Jiri Pirko   ipv4: introduce a...
735
  	}
5c766d642   Jiri Pirko   ipv4: introduce a...
736
737
738
739
740
741
742
743
744
745
746
747
  
  	next_sec = round_jiffies_up(next);
  	next_sched = next;
  
  	/* If rounded timeout is accurate enough, accept it. */
  	if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
  		next_sched = next_sec;
  
  	now = jiffies;
  	/* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
  	if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
  		next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
906e073f3   viresh kumar   net/ipv4: queue w...
748
749
  	queue_delayed_work(system_power_efficient_wq, &check_lifetime_work,
  			next_sched - now);
5c766d642   Jiri Pirko   ipv4: introduce a...
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
  }
  
  static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
  			     __u32 prefered_lft)
  {
  	unsigned long timeout;
  
  	ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
  
  	timeout = addrconf_timeout_fixup(valid_lft, HZ);
  	if (addrconf_finite_timeout(timeout))
  		ifa->ifa_valid_lft = timeout;
  	else
  		ifa->ifa_flags |= IFA_F_PERMANENT;
  
  	timeout = addrconf_timeout_fixup(prefered_lft, HZ);
  	if (addrconf_finite_timeout(timeout)) {
  		if (timeout == 0)
  			ifa->ifa_flags |= IFA_F_DEPRECATED;
  		ifa->ifa_preferred_lft = timeout;
  	}
  	ifa->ifa_tstamp = jiffies;
  	if (!ifa->ifa_cstamp)
  		ifa->ifa_cstamp = ifa->ifa_tstamp;
  }
  
  static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
dac9c9790   David Ahern   net: Add extack t...
777
778
  				       __u32 *pvalid_lft, __u32 *pprefered_lft,
  				       struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
  {
5c7539781   Thomas Graf   [IPV4]: Convert a...
780
781
782
  	struct nlattr *tb[IFA_MAX+1];
  	struct in_ifaddr *ifa;
  	struct ifaddrmsg *ifm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
784
  	struct net_device *dev;
  	struct in_device *in_dev;
7b2185747   Denis V. Lunev   [IPV4]: Small sty...
785
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786

8cb081746   Johannes Berg   netlink: make val...
787
788
  	err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX,
  				     ifa_ipv4_policy, extack);
5c7539781   Thomas Graf   [IPV4]: Convert a...
789
790
  	if (err < 0)
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791

5c7539781   Thomas Graf   [IPV4]: Convert a...
792
  	ifm = nlmsg_data(nlh);
7b2185747   Denis V. Lunev   [IPV4]: Small sty...
793
  	err = -EINVAL;
51456b291   Ian Morris   ipv4: coding styl...
794
  	if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL])
5c7539781   Thomas Graf   [IPV4]: Convert a...
795
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796

4b8aa9abe   Denis V. Lunev   [NETNS]: Process ...
797
  	dev = __dev_get_by_index(net, ifm->ifa_index);
7b2185747   Denis V. Lunev   [IPV4]: Small sty...
798
  	err = -ENODEV;
51456b291   Ian Morris   ipv4: coding styl...
799
  	if (!dev)
5c7539781   Thomas Graf   [IPV4]: Convert a...
800
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801

5c7539781   Thomas Graf   [IPV4]: Convert a...
802
  	in_dev = __in_dev_get_rtnl(dev);
7b2185747   Denis V. Lunev   [IPV4]: Small sty...
803
  	err = -ENOBUFS;
51456b291   Ian Morris   ipv4: coding styl...
804
  	if (!in_dev)
71e27da96   Herbert Xu   [IPV4]: Restore o...
805
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806

5c7539781   Thomas Graf   [IPV4]: Convert a...
807
  	ifa = inet_alloc_ifa();
51456b291   Ian Morris   ipv4: coding styl...
808
  	if (!ifa)
5c7539781   Thomas Graf   [IPV4]: Convert a...
809
810
811
812
  		/*
  		 * A potential indev allocation can be left alive, it stays
  		 * assigned to its device and is destroy with it.
  		 */
5c7539781   Thomas Graf   [IPV4]: Convert a...
813
  		goto errout;
5c7539781   Thomas Graf   [IPV4]: Convert a...
814

a4e65d36a   Pavel Emelyanov   [IPV4]: Swap the ...
815
  	ipv4_devconf_setall(in_dev);
1d4c8c298   Jiri Pirko   neigh: restore ol...
816
  	neigh_parms_data_state_setall(in_dev->arp_parms);
5c7539781   Thomas Graf   [IPV4]: Convert a...
817
  	in_dev_hold(in_dev);
51456b291   Ian Morris   ipv4: coding styl...
818
  	if (!tb[IFA_ADDRESS])
5c7539781   Thomas Graf   [IPV4]: Convert a...
819
  		tb[IFA_ADDRESS] = tb[IFA_LOCAL];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820

fd23c3b31   David S. Miller   ipv4: Add hash ta...
821
  	INIT_HLIST_NODE(&ifa->hash);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
823
  	ifa->ifa_prefixlen = ifm->ifa_prefixlen;
  	ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
ad6c81359   Jiri Pirko   ipv4: add support...
824
825
  	ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
  					 ifm->ifa_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
  	ifa->ifa_scope = ifm->ifa_scope;
5c7539781   Thomas Graf   [IPV4]: Convert a...
827
  	ifa->ifa_dev = in_dev;
67b61f6c1   Jiri Benc   netlink: implemen...
828
829
  	ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]);
  	ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]);
5c7539781   Thomas Graf   [IPV4]: Convert a...
830
831
  
  	if (tb[IFA_BROADCAST])
67b61f6c1   Jiri Benc   netlink: implemen...
832
  		ifa->ifa_broadcast = nla_get_in_addr(tb[IFA_BROADCAST]);
5c7539781   Thomas Graf   [IPV4]: Convert a...
833

5c7539781   Thomas Graf   [IPV4]: Convert a...
834
835
  	if (tb[IFA_LABEL])
  		nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
837
  	else
  		memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
af4d768ad   David Ahern   net/ipv4: Add sup...
838
839
  	if (tb[IFA_RT_PRIORITY])
  		ifa->ifa_rt_priority = nla_get_u32(tb[IFA_RT_PRIORITY]);
5c766d642   Jiri Pirko   ipv4: introduce a...
840
841
842
843
844
845
  	if (tb[IFA_CACHEINFO]) {
  		struct ifa_cacheinfo *ci;
  
  		ci = nla_data(tb[IFA_CACHEINFO]);
  		if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
  			err = -EINVAL;
446266b0c   Daniel Borkmann   net: rtm_to_ifadd...
846
  			goto errout_free;
5c766d642   Jiri Pirko   ipv4: introduce a...
847
848
849
850
  		}
  		*pvalid_lft = ci->ifa_valid;
  		*pprefered_lft = ci->ifa_prefered;
  	}
5c7539781   Thomas Graf   [IPV4]: Convert a...
851
  	return ifa;
446266b0c   Daniel Borkmann   net: rtm_to_ifadd...
852
853
  errout_free:
  	inet_free_ifa(ifa);
5c7539781   Thomas Graf   [IPV4]: Convert a...
854
855
856
  errout:
  	return ERR_PTR(err);
  }
5c766d642   Jiri Pirko   ipv4: introduce a...
857
858
859
  static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
  {
  	struct in_device *in_dev = ifa->ifa_dev;
ef11db331   Florian Westphal   net: inetdevice: ...
860
  	struct in_ifaddr *ifa1;
5c766d642   Jiri Pirko   ipv4: introduce a...
861
862
863
  
  	if (!ifa->ifa_local)
  		return NULL;
ef11db331   Florian Westphal   net: inetdevice: ...
864
  	in_dev_for_each_ifa_rtnl(ifa1, in_dev) {
5c766d642   Jiri Pirko   ipv4: introduce a...
865
866
867
868
869
870
871
  		if (ifa1->ifa_mask == ifa->ifa_mask &&
  		    inet_ifa_match(ifa1->ifa_address, ifa) &&
  		    ifa1->ifa_local == ifa->ifa_local)
  			return ifa1;
  	}
  	return NULL;
  }
c21ef3e34   David Ahern   net: rtnetlink: p...
872
873
  static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
  			    struct netlink_ext_ack *extack)
5c7539781   Thomas Graf   [IPV4]: Convert a...
874
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
875
  	struct net *net = sock_net(skb->sk);
5c7539781   Thomas Graf   [IPV4]: Convert a...
876
  	struct in_ifaddr *ifa;
5c766d642   Jiri Pirko   ipv4: introduce a...
877
878
879
  	struct in_ifaddr *ifa_existing;
  	__u32 valid_lft = INFINITY_LIFE_TIME;
  	__u32 prefered_lft = INFINITY_LIFE_TIME;
5c7539781   Thomas Graf   [IPV4]: Convert a...
880
881
  
  	ASSERT_RTNL();
dac9c9790   David Ahern   net: Add extack t...
882
  	ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft, extack);
5c7539781   Thomas Graf   [IPV4]: Convert a...
883
884
  	if (IS_ERR(ifa))
  		return PTR_ERR(ifa);
5c766d642   Jiri Pirko   ipv4: introduce a...
885
886
887
  	ifa_existing = find_matching_ifa(ifa);
  	if (!ifa_existing) {
  		/* It would be best to check for !NLM_F_CREATE here but
614d056c8   stephen hemminger   ipv4: minor spell...
888
  		 * userspace already relies on not having to provide this.
5c766d642   Jiri Pirko   ipv4: introduce a...
889
890
  		 */
  		set_ifa_lifetime(ifa, valid_lft, prefered_lft);
93a714d6b   Madhu Challa   multicast: Extend...
891
  		if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
690cc8632   Taras Chornyi   net: ipv4: devine...
892
  			int ret = ip_mc_autojoin_config(net, true, ifa);
93a714d6b   Madhu Challa   multicast: Extend...
893
894
895
896
897
898
  
  			if (ret < 0) {
  				inet_free_ifa(ifa);
  				return ret;
  			}
  		}
de95e0479   David Ahern   net: Add extack t...
899
900
  		return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid,
  					 extack);
5c766d642   Jiri Pirko   ipv4: introduce a...
901
  	} else {
af4d768ad   David Ahern   net/ipv4: Add sup...
902
  		u32 new_metric = ifa->ifa_rt_priority;
5c766d642   Jiri Pirko   ipv4: introduce a...
903
904
905
906
907
  		inet_free_ifa(ifa);
  
  		if (nlh->nlmsg_flags & NLM_F_EXCL ||
  		    !(nlh->nlmsg_flags & NLM_F_REPLACE))
  			return -EEXIST;
34e2ed34a   Jiri Pirko   net: ipv4: notify...
908
  		ifa = ifa_existing;
af4d768ad   David Ahern   net/ipv4: Add sup...
909
910
911
912
913
  
  		if (ifa->ifa_rt_priority != new_metric) {
  			fib_modify_prefix_metric(ifa, new_metric);
  			ifa->ifa_rt_priority = new_metric;
  		}
34e2ed34a   Jiri Pirko   net: ipv4: notify...
914
  		set_ifa_lifetime(ifa, valid_lft, prefered_lft);
05a324b9c   Jiri Pirko   net: ipv4: reset ...
915
  		cancel_delayed_work(&check_lifetime_work);
906e073f3   viresh kumar   net/ipv4: queue w...
916
917
  		queue_delayed_work(system_power_efficient_wq,
  				&check_lifetime_work, 0);
34e2ed34a   Jiri Pirko   net: ipv4: notify...
918
  		rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
5c766d642   Jiri Pirko   ipv4: introduce a...
919
920
  	}
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
922
923
924
925
  }
  
  /*
   *	Determine a default network mask, based on the IP address.
   */
40384999d   Eric Dumazet   ipv4: change inet...
926
  static int inet_abc_len(__be32 addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
928
  {
  	int rc = -1;	/* Something else, probably a multicast. */
65cab850f   Dave Taht   net: Allow class-...
929
  	if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr))
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
930
  		rc = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
931
  	else {
714e85be3   Al Viro   [IPV6]: Assorted ...
932
  		__u32 haddr = ntohl(addr);
714e85be3   Al Viro   [IPV6]: Assorted ...
933
  		if (IN_CLASSA(haddr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934
  			rc = 8;
714e85be3   Al Viro   [IPV6]: Assorted ...
935
  		else if (IN_CLASSB(haddr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
  			rc = 16;
714e85be3   Al Viro   [IPV6]: Assorted ...
937
  		else if (IN_CLASSC(haddr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
938
  			rc = 24;
65cab850f   Dave Taht   net: Allow class-...
939
940
  		else if (IN_CLASSE(haddr))
  			rc = 32;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
941
  	}
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
942
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943
  }
03aef17bb   Al Viro   devinet_ioctl(): ...
944
  int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
  	struct sockaddr_in sin_orig;
03aef17bb   Al Viro   devinet_ioctl(): ...
947
  	struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
2638eb8b5   Florian Westphal   net: ipv4: provid...
948
  	struct in_ifaddr __rcu **ifap = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
  	struct in_device *in_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
951
952
953
954
  	struct in_ifaddr *ifa = NULL;
  	struct net_device *dev;
  	char *colon;
  	int ret = -EFAULT;
  	int tryaddrmatch = 0;
03aef17bb   Al Viro   devinet_ioctl(): ...
955
  	ifr->ifr_name[IFNAMSIZ - 1] = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956
957
958
  
  	/* save original address for comparison */
  	memcpy(&sin_orig, sin, sizeof(*sin));
03aef17bb   Al Viro   devinet_ioctl(): ...
959
  	colon = strchr(ifr->ifr_name, ':');
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
  	if (colon)
  		*colon = 0;
03aef17bb   Al Viro   devinet_ioctl(): ...
962
  	dev_load(net, ifr->ifr_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
963

132adf546   Stephen Hemminger   [IPV4]: cleanup
964
  	switch (cmd) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
966
967
968
969
970
971
972
973
974
975
976
977
978
  	case SIOCGIFADDR:	/* Get interface address */
  	case SIOCGIFBRDADDR:	/* Get the broadcast address */
  	case SIOCGIFDSTADDR:	/* Get the destination address */
  	case SIOCGIFNETMASK:	/* Get the netmask for the interface */
  		/* Note that these ioctls will not sleep,
  		   so that we do not impose a lock.
  		   One day we will be forced to put shlock here (I mean SMP)
  		 */
  		tryaddrmatch = (sin_orig.sin_family == AF_INET);
  		memset(sin, 0, sizeof(*sin));
  		sin->sin_family = AF_INET;
  		break;
  
  	case SIOCSIFFLAGS:
bf5b30b8a   Zhao Hongjiang   net: change retur...
979
  		ret = -EPERM;
52e804c6d   Eric W. Biederman   net: Allow userns...
980
  		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
981
982
983
984
985
986
  			goto out;
  		break;
  	case SIOCSIFADDR:	/* Set interface address (and family) */
  	case SIOCSIFBRDADDR:	/* Set the broadcast address */
  	case SIOCSIFDSTADDR:	/* Set the destination address */
  	case SIOCSIFNETMASK: 	/* Set the netmask for the interface */
bf5b30b8a   Zhao Hongjiang   net: change retur...
987
  		ret = -EPERM;
52e804c6d   Eric W. Biederman   net: Allow userns...
988
  		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
989
990
991
992
993
994
995
996
997
998
999
1000
1001
  			goto out;
  		ret = -EINVAL;
  		if (sin->sin_family != AF_INET)
  			goto out;
  		break;
  	default:
  		ret = -EINVAL;
  		goto out;
  	}
  
  	rtnl_lock();
  
  	ret = -ENODEV;
03aef17bb   Al Viro   devinet_ioctl(): ...
1002
  	dev = __dev_get_by_name(net, ifr->ifr_name);
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1003
  	if (!dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1004
1005
1006
1007
  		goto done;
  
  	if (colon)
  		*colon = ':';
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1008
1009
  	in_dev = __in_dev_get_rtnl(dev);
  	if (in_dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
1011
1012
1013
1014
1015
  		if (tryaddrmatch) {
  			/* Matthias Andree */
  			/* compare label and address (4.4BSD style) */
  			/* note: we only do this for a limited set of ioctls
  			   and only if the original address family was AF_INET.
  			   This is checked above. */
2638eb8b5   Florian Westphal   net: ipv4: provid...
1016
1017
1018
  
  			for (ifap = &in_dev->ifa_list;
  			     (ifa = rtnl_dereference(*ifap)) != NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1019
  			     ifap = &ifa->ifa_next) {
03aef17bb   Al Viro   devinet_ioctl(): ...
1020
  				if (!strcmp(ifr->ifr_name, ifa->ifa_label) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1021
  				    sin_orig.sin_addr.s_addr ==
6c91afe1a   David S. Miller   ipv4: Fix erroneo...
1022
  							ifa->ifa_local) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1023
1024
1025
1026
1027
1028
1029
1030
  					break; /* found */
  				}
  			}
  		}
  		/* we didn't get a match, maybe the application is
  		   4.3BSD-style and passed in junk so we fall back to
  		   comparing just the label */
  		if (!ifa) {
2638eb8b5   Florian Westphal   net: ipv4: provid...
1031
1032
  			for (ifap = &in_dev->ifa_list;
  			     (ifa = rtnl_dereference(*ifap)) != NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
  			     ifap = &ifa->ifa_next)
03aef17bb   Al Viro   devinet_ioctl(): ...
1034
  				if (!strcmp(ifr->ifr_name, ifa->ifa_label))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1035
1036
1037
1038
1039
1040
1041
  					break;
  		}
  	}
  
  	ret = -EADDRNOTAVAIL;
  	if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
  		goto done;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1042
  	switch (cmd) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1043
  	case SIOCGIFADDR:	/* Get interface address */
30e948a37   Tonghao Zhang   ipv4: Get the add...
1044
  		ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045
  		sin->sin_addr.s_addr = ifa->ifa_local;
03aef17bb   Al Viro   devinet_ioctl(): ...
1046
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1047
1048
  
  	case SIOCGIFBRDADDR:	/* Get the broadcast address */
30e948a37   Tonghao Zhang   ipv4: Get the add...
1049
  		ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1050
  		sin->sin_addr.s_addr = ifa->ifa_broadcast;
03aef17bb   Al Viro   devinet_ioctl(): ...
1051
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052
1053
  
  	case SIOCGIFDSTADDR:	/* Get the destination address */
30e948a37   Tonghao Zhang   ipv4: Get the add...
1054
  		ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1055
  		sin->sin_addr.s_addr = ifa->ifa_address;
03aef17bb   Al Viro   devinet_ioctl(): ...
1056
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1057
1058
  
  	case SIOCGIFNETMASK:	/* Get the netmask for the interface */
30e948a37   Tonghao Zhang   ipv4: Get the add...
1059
  		ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
  		sin->sin_addr.s_addr = ifa->ifa_mask;
03aef17bb   Al Viro   devinet_ioctl(): ...
1061
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062
1063
1064
1065
1066
1067
1068
  
  	case SIOCSIFFLAGS:
  		if (colon) {
  			ret = -EADDRNOTAVAIL;
  			if (!ifa)
  				break;
  			ret = 0;
03aef17bb   Al Viro   devinet_ioctl(): ...
1069
  			if (!(ifr->ifr_flags & IFF_UP))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1070
1071
1072
  				inet_del_ifa(in_dev, ifap, 1);
  			break;
  		}
567c5e13b   Petr Machata   net: core: dev: A...
1073
  		ret = dev_change_flags(dev, ifr->ifr_flags, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1074
1075
1076
1077
1078
1079
1080
1081
1082
  		break;
  
  	case SIOCSIFADDR:	/* Set interface address (and family) */
  		ret = -EINVAL;
  		if (inet_abc_len(sin->sin_addr.s_addr) < 0)
  			break;
  
  		if (!ifa) {
  			ret = -ENOBUFS;
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1083
1084
  			ifa = inet_alloc_ifa();
  			if (!ifa)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1085
  				break;
c7e2e1d72   Xi Wang   ipv4: fix NULL ch...
1086
  			INIT_HLIST_NODE(&ifa->hash);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1087
  			if (colon)
03aef17bb   Al Viro   devinet_ioctl(): ...
1088
  				memcpy(ifa->ifa_label, ifr->ifr_name, IFNAMSIZ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1089
1090
1091
1092
1093
1094
1095
1096
  			else
  				memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
  		} else {
  			ret = 0;
  			if (ifa->ifa_local == sin->sin_addr.s_addr)
  				break;
  			inet_del_ifa(in_dev, ifap, 0);
  			ifa->ifa_broadcast = 0;
148f97292   Bjorn Mork   [IPV4]: Reset sco...
1097
  			ifa->ifa_scope = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
  		}
  
  		ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
  
  		if (!(dev->flags & IFF_POINTOPOINT)) {
  			ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
  			ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
  			if ((dev->flags & IFF_BROADCAST) &&
  			    ifa->ifa_prefixlen < 31)
  				ifa->ifa_broadcast = ifa->ifa_address |
  						     ~ifa->ifa_mask;
  		} else {
  			ifa->ifa_prefixlen = 32;
  			ifa->ifa_mask = inet_make_mask(32);
  		}
5c766d642   Jiri Pirko   ipv4: introduce a...
1113
  		set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
  		ret = inet_set_ifa(dev, ifa);
  		break;
  
  	case SIOCSIFBRDADDR:	/* Set the broadcast address */
  		ret = 0;
  		if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
  			inet_del_ifa(in_dev, ifap, 0);
  			ifa->ifa_broadcast = sin->sin_addr.s_addr;
  			inet_insert_ifa(ifa);
  		}
  		break;
  
  	case SIOCSIFDSTADDR:	/* Set the destination address */
  		ret = 0;
  		if (ifa->ifa_address == sin->sin_addr.s_addr)
  			break;
  		ret = -EINVAL;
  		if (inet_abc_len(sin->sin_addr.s_addr) < 0)
  			break;
  		ret = 0;
  		inet_del_ifa(in_dev, ifap, 0);
  		ifa->ifa_address = sin->sin_addr.s_addr;
  		inet_insert_ifa(ifa);
  		break;
  
  	case SIOCSIFNETMASK: 	/* Set the netmask for the interface */
  
  		/*
  		 *	The mask we set must be legal.
  		 */
  		ret = -EINVAL;
  		if (bad_mask(sin->sin_addr.s_addr, 0))
  			break;
  		ret = 0;
  		if (ifa->ifa_mask != sin->sin_addr.s_addr) {
a144ea4b7   Al Viro   [IPV4]: annotate ...
1149
  			__be32 old_mask = ifa->ifa_mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
  			inet_del_ifa(in_dev, ifap, 0);
  			ifa->ifa_mask = sin->sin_addr.s_addr;
  			ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
  
  			/* See if current broadcast address matches
  			 * with current netmask, then recalculate
  			 * the broadcast address. Otherwise it's a
  			 * funny address, so don't touch it since
  			 * the user seems to know what (s)he's doing...
  			 */
  			if ((dev->flags & IFF_BROADCAST) &&
  			    (ifa->ifa_prefixlen < 31) &&
  			    (ifa->ifa_broadcast ==
dcab5e1ee   David Engel   [IPV4]: Fix setti...
1163
  			     (ifa->ifa_local|~old_mask))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
  				ifa->ifa_broadcast = (ifa->ifa_local |
  						      ~sin->sin_addr.s_addr);
  			}
  			inet_insert_ifa(ifa);
  		}
  		break;
  	}
  done:
  	rtnl_unlock();
  out:
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1175
  }
36fd633ec   Al Viro   net: separate SIO...
1176
  static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1177
  {
e5ed63991   Herbert Xu   [IPV4]: Replace _...
1178
  	struct in_device *in_dev = __in_dev_get_rtnl(dev);
ef11db331   Florian Westphal   net: inetdevice: ...
1179
  	const struct in_ifaddr *ifa;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180
1181
  	struct ifreq ifr;
  	int done = 0;
36fd633ec   Al Viro   net: separate SIO...
1182
1183
  	if (WARN_ON(size > sizeof(struct ifreq)))
  		goto out;
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1184
  	if (!in_dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1185
  		goto out;
ef11db331   Florian Westphal   net: inetdevice: ...
1186
  	in_dev_for_each_ifa_rtnl(ifa, in_dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
  		if (!buf) {
36fd633ec   Al Viro   net: separate SIO...
1188
  			done += size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1189
1190
  			continue;
  		}
36fd633ec   Al Viro   net: separate SIO...
1191
  		if (len < size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192
1193
  			break;
  		memset(&ifr, 0, sizeof(struct ifreq));
4299c8a94   Dan Carpenter   net: remove an un...
1194
  		strcpy(ifr.ifr_name, ifa->ifa_label);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1195
1196
1197
1198
  
  		(*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
  		(*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
  								ifa->ifa_local;
36fd633ec   Al Viro   net: separate SIO...
1199
  		if (copy_to_user(buf + done, &ifr, size)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1200
1201
1202
  			done = -EFAULT;
  			break;
  		}
36fd633ec   Al Viro   net: separate SIO...
1203
1204
  		len  -= size;
  		done += size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1205
1206
1207
1208
  	}
  out:
  	return done;
  }
8b57fd1ec   Gao Feng   net: Eliminate du...
1209
1210
1211
  static __be32 in_dev_select_addr(const struct in_device *in_dev,
  				 int scope)
  {
d519e8708   Florian Westphal   devinet: use in_d...
1212
1213
1214
1215
1216
  	const struct in_ifaddr *ifa;
  
  	in_dev_for_each_ifa_rcu(ifa, in_dev) {
  		if (ifa->ifa_flags & IFA_F_SECONDARY)
  			continue;
8b57fd1ec   Gao Feng   net: Eliminate du...
1217
1218
1219
  		if (ifa->ifa_scope != RT_SCOPE_LINK &&
  		    ifa->ifa_scope <= scope)
  			return ifa->ifa_local;
d519e8708   Florian Westphal   devinet: use in_d...
1220
  	}
8b57fd1ec   Gao Feng   net: Eliminate du...
1221
1222
1223
  
  	return 0;
  }
a61ced5d1   Al Viro   [IPV4]: inet_sele...
1224
  __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1225
  {
d519e8708   Florian Westphal   devinet: use in_d...
1226
  	const struct in_ifaddr *ifa;
a61ced5d1   Al Viro   [IPV4]: inet_sele...
1227
  	__be32 addr = 0;
d8c444d54   Shijie Luo   ipv4: fix inet_se...
1228
  	unsigned char localnet_scope = RT_SCOPE_HOST;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1229
  	struct in_device *in_dev;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1230
  	struct net *net = dev_net(dev);
3f2fb9a83   David Ahern   net: l3mdev: addr...
1231
  	int master_idx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232
1233
  
  	rcu_read_lock();
e5ed63991   Herbert Xu   [IPV4]: Replace _...
1234
  	in_dev = __in_dev_get_rcu(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1235
1236
  	if (!in_dev)
  		goto no_in_dev;
d8c444d54   Shijie Luo   ipv4: fix inet_se...
1237
1238
  	if (unlikely(IN_DEV_ROUTE_LOCALNET(in_dev)))
  		localnet_scope = RT_SCOPE_LINK;
d519e8708   Florian Westphal   devinet: use in_d...
1239
1240
1241
  	in_dev_for_each_ifa_rcu(ifa, in_dev) {
  		if (ifa->ifa_flags & IFA_F_SECONDARY)
  			continue;
d8c444d54   Shijie Luo   ipv4: fix inet_se...
1242
  		if (min(ifa->ifa_scope, localnet_scope) > scope)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1243
1244
1245
1246
1247
1248
1249
  			continue;
  		if (!dst || inet_ifa_match(dst, ifa)) {
  			addr = ifa->ifa_local;
  			break;
  		}
  		if (!addr)
  			addr = ifa->ifa_local;
d519e8708   Florian Westphal   devinet: use in_d...
1250
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1251
1252
  
  	if (addr)
c6d14c845   Eric Dumazet   net: Introduce fo...
1253
  		goto out_unlock;
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1254
  no_in_dev:
3f2fb9a83   David Ahern   net: l3mdev: addr...
1255
  	master_idx = l3mdev_master_ifindex_rcu(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1256

17b693cdd   David Lamparter   net: l3mdev: pref...
1257
1258
1259
1260
1261
1262
1263
1264
  	/* For VRFs, the VRF device takes the place of the loopback device,
  	 * with addresses on it being preferred.  Note in such cases the
  	 * loopback device will be among the devices that fail the master_idx
  	 * equality check in the loop below.
  	 */
  	if (master_idx &&
  	    (dev = dev_get_by_index_rcu(net, master_idx)) &&
  	    (in_dev = __in_dev_get_rcu(dev))) {
8b57fd1ec   Gao Feng   net: Eliminate du...
1265
1266
1267
  		addr = in_dev_select_addr(in_dev, scope);
  		if (addr)
  			goto out_unlock;
17b693cdd   David Lamparter   net: l3mdev: pref...
1268
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1269
  	/* Not loopback addresses on loopback should be preferred
ca9f1fd26   Stephen Hemminger   net: spelling fixes
1270
  	   in this case. It is important that lo is the first interface
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1271
1272
  	   in dev_base list.
  	 */
c6d14c845   Eric Dumazet   net: Introduce fo...
1273
  	for_each_netdev_rcu(net, dev) {
3f2fb9a83   David Ahern   net: l3mdev: addr...
1274
1275
  		if (l3mdev_master_ifindex_rcu(dev) != master_idx)
  			continue;
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1276
1277
  		in_dev = __in_dev_get_rcu(dev);
  		if (!in_dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1278
  			continue;
8b57fd1ec   Gao Feng   net: Eliminate du...
1279
1280
1281
  		addr = in_dev_select_addr(in_dev, scope);
  		if (addr)
  			goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1282
  	}
c6d14c845   Eric Dumazet   net: Introduce fo...
1283
  out_unlock:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1284
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285
1286
  	return addr;
  }
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1287
  EXPORT_SYMBOL(inet_select_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1288

60cad5da5   Al Viro   [IPV4]: annotate ...
1289
1290
  static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
  			      __be32 local, int scope)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1291
  {
650638a7c   Shijie Luo   ipv4: fix confirm...
1292
  	unsigned char localnet_scope = RT_SCOPE_HOST;
ef11db331   Florian Westphal   net: inetdevice: ...
1293
  	const struct in_ifaddr *ifa;
a144ea4b7   Al Viro   [IPV4]: annotate ...
1294
  	__be32 addr = 0;
ef11db331   Florian Westphal   net: inetdevice: ...
1295
  	int same = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1296

650638a7c   Shijie Luo   ipv4: fix confirm...
1297
1298
  	if (unlikely(IN_DEV_ROUTE_LOCALNET(in_dev)))
  		localnet_scope = RT_SCOPE_LINK;
ef11db331   Florian Westphal   net: inetdevice: ...
1299
  	in_dev_for_each_ifa_rcu(ifa, in_dev) {
650638a7c   Shijie Luo   ipv4: fix confirm...
1300
  		unsigned char min_scope = min(ifa->ifa_scope, localnet_scope);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1301
1302
  		if (!addr &&
  		    (local == ifa->ifa_local || !local) &&
650638a7c   Shijie Luo   ipv4: fix confirm...
1303
  		    min_scope <= scope) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
  			addr = ifa->ifa_local;
  			if (same)
  				break;
  		}
  		if (!same) {
  			same = (!local || inet_ifa_match(local, ifa)) &&
  				(!dst || inet_ifa_match(dst, ifa));
  			if (same && addr) {
  				if (local || !dst)
  					break;
  				/* Is the selected addr into dst subnet? */
  				if (inet_ifa_match(addr, ifa))
  					break;
  				/* No, then can we use new local src? */
650638a7c   Shijie Luo   ipv4: fix confirm...
1318
  				if (min_scope <= scope) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1319
1320
1321
1322
1323
1324
1325
  					addr = ifa->ifa_local;
  					break;
  				}
  				/* search for large dst subnet for addr */
  				same = 0;
  			}
  		}
ef11db331   Florian Westphal   net: inetdevice: ...
1326
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1327

9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1328
  	return same ? addr : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1329
1330
1331
1332
  }
  
  /*
   * Confirm that local IP address exists using wildcards:
b601fa197   Nicolas Dichtel   ipv4: fix wildcar...
1333
1334
   * - net: netns to check, cannot be NULL
   * - in_dev: only on this interface, NULL=any interface
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1335
1336
1337
1338
   * - dst: only in the same subnet as dst, 0=any dst
   * - local: address, 0=autoselect the local address
   * - scope: maximum allowed scope value for the local address
   */
b601fa197   Nicolas Dichtel   ipv4: fix wildcar...
1339
  __be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
9bd85e326   Denis V. Lunev   [IPV4]: Remove ex...
1340
  			 __be32 dst, __be32 local, int scope)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1341
  {
60cad5da5   Al Viro   [IPV4]: annotate ...
1342
  	__be32 addr = 0;
9bd85e326   Denis V. Lunev   [IPV4]: Remove ex...
1343
  	struct net_device *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1344

00db41243   Ian Morris   ipv4: coding styl...
1345
  	if (in_dev)
9bd85e326   Denis V. Lunev   [IPV4]: Remove ex...
1346
  		return confirm_addr_indev(in_dev, dst, local, scope);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1347

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1348
  	rcu_read_lock();
c6d14c845   Eric Dumazet   net: Introduce fo...
1349
  	for_each_netdev_rcu(net, dev) {
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1350
1351
  		in_dev = __in_dev_get_rcu(dev);
  		if (in_dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1352
1353
1354
1355
1356
1357
  			addr = confirm_addr_indev(in_dev, dst, local, scope);
  			if (addr)
  				break;
  		}
  	}
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1358
1359
1360
  
  	return addr;
  }
eaddcd769   Andy Gospodarek   bonding: remove e...
1361
  EXPORT_SYMBOL(inet_confirm_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1362
1363
1364
1365
1366
1367
1368
  
  /*
   *	Device notifier
   */
  
  int register_inetaddr_notifier(struct notifier_block *nb)
  {
e041c6834   Alan Stern   [PATCH] Notifier ...
1369
  	return blocking_notifier_chain_register(&inetaddr_chain, nb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1370
  }
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1371
  EXPORT_SYMBOL(register_inetaddr_notifier);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1372
1373
1374
  
  int unregister_inetaddr_notifier(struct notifier_block *nb)
  {
e041c6834   Alan Stern   [PATCH] Notifier ...
1375
  	return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1376
  }
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1377
  EXPORT_SYMBOL(unregister_inetaddr_notifier);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1378

3ad7d2468   Krister Johansen   Ipvlan should ret...
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
  int register_inetaddr_validator_notifier(struct notifier_block *nb)
  {
  	return blocking_notifier_chain_register(&inetaddr_validator_chain, nb);
  }
  EXPORT_SYMBOL(register_inetaddr_validator_notifier);
  
  int unregister_inetaddr_validator_notifier(struct notifier_block *nb)
  {
  	return blocking_notifier_chain_unregister(&inetaddr_validator_chain,
  	    nb);
  }
  EXPORT_SYMBOL(unregister_inetaddr_validator_notifier);
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1391
1392
  /* Rename ifa_labels for a device name change. Make some effort to preserve
   * existing alias numbering and to create unique labels if possible.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1393
1394
  */
  static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1395
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1396
1397
  	struct in_ifaddr *ifa;
  	int named = 0;
ef11db331   Florian Westphal   net: inetdevice: ...
1398
  	in_dev_for_each_ifa_rtnl(ifa, in_dev) {
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1399
  		char old[IFNAMSIZ], *dot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1400
1401
  
  		memcpy(old, ifa->ifa_label, IFNAMSIZ);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1402
  		memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1403
  		if (named++ == 0)
573bf470e   Thomas Graf   ipv4 addr: Send n...
1404
  			goto skip;
44344b2a8   Mark McLoughlin   [INET]: Fix netde...
1405
  		dot = strchr(old, ':');
51456b291   Ian Morris   ipv4: coding styl...
1406
  		if (!dot) {
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1407
  			sprintf(old, ":%d", named);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1408
1409
  			dot = old;
  		}
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1410
  		if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1411
  			strcat(ifa->ifa_label, dot);
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1412
  		else
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1413
  			strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
573bf470e   Thomas Graf   ipv4 addr: Send n...
1414
1415
  skip:
  		rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1416
1417
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1418

d11327ad6   Ian Campbell   arp_notify: uncon...
1419
1420
1421
1422
  static void inetdev_send_gratuitous_arp(struct net_device *dev,
  					struct in_device *in_dev)
  
  {
ef11db331   Florian Westphal   net: inetdevice: ...
1423
  	const struct in_ifaddr *ifa;
d11327ad6   Ian Campbell   arp_notify: uncon...
1424

ef11db331   Florian Westphal   net: inetdevice: ...
1425
  	in_dev_for_each_ifa_rtnl(ifa, in_dev) {
b76d0789c   Zoltan Kiss   IPv4: Send gratui...
1426
1427
1428
1429
1430
  		arp_send(ARPOP_REQUEST, ETH_P_ARP,
  			 ifa->ifa_local, dev,
  			 ifa->ifa_local, NULL,
  			 dev->dev_addr, NULL);
  	}
d11327ad6   Ian Campbell   arp_notify: uncon...
1431
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1432
1433
1434
1435
1436
  /* Called only under RTNL semaphore */
  
  static int inetdev_event(struct notifier_block *this, unsigned long event,
  			 void *ptr)
  {
351638e7d   Jiri Pirko   net: pass info st...
1437
  	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
748e2d939   Eric Dumazet   net: reinstate rt...
1438
  	struct in_device *in_dev = __in_dev_get_rtnl(dev);
0115e8e30   Eric Dumazet   net: remove delay...
1439

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1440
1441
1442
  	ASSERT_RTNL();
  
  	if (!in_dev) {
8030f5449   Herbert Xu   [IPV4] devinet: R...
1443
  		if (event == NETDEV_REGISTER) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1444
  			in_dev = inetdev_init(dev);
20e61da7f   WANG Cong   ipv4: fail early ...
1445
1446
  			if (IS_ERR(in_dev))
  				return notifier_from_errno(PTR_ERR(in_dev));
0cc217e16   Eric W. Biederman   [IPV4]: When poss...
1447
  			if (dev->flags & IFF_LOOPBACK) {
42f811b8b   Herbert Xu   [IPV4]: Convert I...
1448
1449
  				IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
  				IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
8030f5449   Herbert Xu   [IPV4] devinet: R...
1450
  			}
06770843c   Breno Leitao   ipv: Re-enable IP...
1451
1452
1453
1454
  		} else if (event == NETDEV_CHANGEMTU) {
  			/* Re-enabling IP */
  			if (inetdev_valid_mtu(dev->mtu))
  				in_dev = inetdev_init(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1455
1456
1457
1458
1459
1460
  		}
  		goto out;
  	}
  
  	switch (event) {
  	case NETDEV_REGISTER:
91df42bed   Joe Perches   net: ipv4 and ipv...
1461
1462
  		pr_debug("%s: bug
  ", __func__);
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
1463
  		RCU_INIT_POINTER(dev->ip_ptr, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1464
1465
  		break;
  	case NETDEV_UP:
06770843c   Breno Leitao   ipv: Re-enable IP...
1466
  		if (!inetdev_valid_mtu(dev->mtu))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1467
  			break;
0cc217e16   Eric W. Biederman   [IPV4]: When poss...
1468
  		if (dev->flags & IFF_LOOPBACK) {
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1469
1470
1471
  			struct in_ifaddr *ifa = inet_alloc_ifa();
  
  			if (ifa) {
fd23c3b31   David S. Miller   ipv4: Add hash ta...
1472
  				INIT_HLIST_NODE(&ifa->hash);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1473
1474
1475
1476
1477
1478
1479
1480
  				ifa->ifa_local =
  				  ifa->ifa_address = htonl(INADDR_LOOPBACK);
  				ifa->ifa_prefixlen = 8;
  				ifa->ifa_mask = inet_make_mask(8);
  				in_dev_hold(in_dev);
  				ifa->ifa_dev = in_dev;
  				ifa->ifa_scope = RT_SCOPE_HOST;
  				memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
5c766d642   Jiri Pirko   ipv4: introduce a...
1481
1482
  				set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
  						 INFINITY_LIFE_TIME);
dfd1582d1   Jiri Pirko   ipv4: loopback de...
1483
1484
  				ipv4_devconf_setall(in_dev);
  				neigh_parms_data_state_setall(in_dev->arp_parms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1485
1486
1487
1488
  				inet_insert_ifa(ifa);
  			}
  		}
  		ip_mc_up(in_dev);
a8eceea84   Joe Perches   inet: Use fallthr...
1489
  		fallthrough;
eefef1cf7   Stephen Hemminger   net: add ARP noti...
1490
  	case NETDEV_CHANGEADDR:
d11327ad6   Ian Campbell   arp_notify: uncon...
1491
1492
  		if (!IN_DEV_ARP_NOTIFY(in_dev))
  			break;
a8eceea84   Joe Perches   inet: Use fallthr...
1493
  		fallthrough;
d11327ad6   Ian Campbell   arp_notify: uncon...
1494
  	case NETDEV_NOTIFY_PEERS:
a21090cff   Stephen Hemminger   ipv4: arp_notify ...
1495
  		/* Send gratuitous ARP to notify of link change */
d11327ad6   Ian Campbell   arp_notify: uncon...
1496
  		inetdev_send_gratuitous_arp(dev, in_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1497
1498
1499
1500
  		break;
  	case NETDEV_DOWN:
  		ip_mc_down(in_dev);
  		break;
93d9b7d7a   Jiri Pirko   net: rename notif...
1501
  	case NETDEV_PRE_TYPE_CHANGE:
75c78500d   Moni Shoua   bonding: remap mu...
1502
1503
  		ip_mc_unmap(in_dev);
  		break;
93d9b7d7a   Jiri Pirko   net: rename notif...
1504
  	case NETDEV_POST_TYPE_CHANGE:
75c78500d   Moni Shoua   bonding: remap mu...
1505
1506
  		ip_mc_remap(in_dev);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1507
  	case NETDEV_CHANGEMTU:
06770843c   Breno Leitao   ipv: Re-enable IP...
1508
  		if (inetdev_valid_mtu(dev->mtu))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1509
  			break;
06770843c   Breno Leitao   ipv: Re-enable IP...
1510
  		/* disable IP when MTU is not enough */
a8eceea84   Joe Perches   inet: Use fallthr...
1511
  		fallthrough;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1512
1513
1514
1515
1516
1517
1518
1519
  	case NETDEV_UNREGISTER:
  		inetdev_destroy(in_dev);
  		break;
  	case NETDEV_CHANGENAME:
  		/* Do not notify about label change, this event is
  		 * not interesting to applications using netlink.
  		 */
  		inetdev_changename(dev, in_dev);
51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
1520
  		devinet_sysctl_unregister(in_dev);
66f27a520   Pavel Emelyanov   [IPV4]: Unify and...
1521
  		devinet_sysctl_register(in_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1522
1523
1524
1525
1526
1527
1528
  		break;
  	}
  out:
  	return NOTIFY_DONE;
  }
  
  static struct notifier_block ip_netdev_notifier = {
539afedfc   Jianjun Kong   net: clean up net...
1529
  	.notifier_call = inetdev_event,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1530
  };
40384999d   Eric Dumazet   ipv4: change inet...
1531
  static size_t inet_nlmsg_size(void)
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
1532
1533
1534
1535
1536
  {
  	return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
  	       + nla_total_size(4) /* IFA_ADDRESS */
  	       + nla_total_size(4) /* IFA_LOCAL */
  	       + nla_total_size(4) /* IFA_BROADCAST */
ad6c81359   Jiri Pirko   ipv4: add support...
1537
  	       + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
63b5f152e   Geert Uytterhoeven   ipv4: Fix runtime...
1538
  	       + nla_total_size(4)  /* IFA_FLAGS */
af4d768ad   David Ahern   net/ipv4: Add sup...
1539
  	       + nla_total_size(4)  /* IFA_RT_PRIORITY */
63b5f152e   Geert Uytterhoeven   ipv4: Fix runtime...
1540
  	       + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
1541
  }
5c766d642   Jiri Pirko   ipv4: introduce a...
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
  static inline u32 cstamp_delta(unsigned long cstamp)
  {
  	return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
  }
  
  static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
  			 unsigned long tstamp, u32 preferred, u32 valid)
  {
  	struct ifa_cacheinfo ci;
  
  	ci.cstamp = cstamp_delta(cstamp);
  	ci.tstamp = cstamp_delta(tstamp);
  	ci.ifa_prefered = preferred;
  	ci.ifa_valid = valid;
  
  	return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1559
  static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
978a46fa6   Christian Brauner   ipv4: add inet_fi...
1560
  			    struct inet_fill_args *args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1561
1562
1563
  {
  	struct ifaddrmsg *ifm;
  	struct nlmsghdr  *nlh;
5c766d642   Jiri Pirko   ipv4: introduce a...
1564
  	u32 preferred, valid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1565

978a46fa6   Christian Brauner   ipv4: add inet_fi...
1566
1567
  	nlh = nlmsg_put(skb, args->portid, args->seq, args->event, sizeof(*ifm),
  			args->flags);
51456b291   Ian Morris   ipv4: coding styl...
1568
  	if (!nlh)
26932566a   Patrick McHardy   [NETLINK]: Don't ...
1569
  		return -EMSGSIZE;
47f68512d   Thomas Graf   [IPV4]: Convert a...
1570
1571
  
  	ifm = nlmsg_data(nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1572
1573
  	ifm->ifa_family = AF_INET;
  	ifm->ifa_prefixlen = ifa->ifa_prefixlen;
5c766d642   Jiri Pirko   ipv4: introduce a...
1574
  	ifm->ifa_flags = ifa->ifa_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1575
1576
  	ifm->ifa_scope = ifa->ifa_scope;
  	ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
47f68512d   Thomas Graf   [IPV4]: Convert a...
1577

978a46fa6   Christian Brauner   ipv4: add inet_fi...
1578
1579
  	if (args->netnsid >= 0 &&
  	    nla_put_s32(skb, IFA_TARGET_NETNSID, args->netnsid))
d38071455   Christian Brauner   ipv4: enable IFA_...
1580
  		goto nla_put_failure;
5c766d642   Jiri Pirko   ipv4: introduce a...
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
  	if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
  		preferred = ifa->ifa_preferred_lft;
  		valid = ifa->ifa_valid_lft;
  		if (preferred != INFINITY_LIFE_TIME) {
  			long tval = (jiffies - ifa->ifa_tstamp) / HZ;
  
  			if (preferred > tval)
  				preferred -= tval;
  			else
  				preferred = 0;
  			if (valid != INFINITY_LIFE_TIME) {
  				if (valid > tval)
  					valid -= tval;
  				else
  					valid = 0;
  			}
  		}
  	} else {
  		preferred = INFINITY_LIFE_TIME;
  		valid = INFINITY_LIFE_TIME;
  	}
f3756b79e   David S. Miller   ipv4: Stop using ...
1602
  	if ((ifa->ifa_address &&
930345ea6   Jiri Benc   netlink: implemen...
1603
  	     nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) ||
f3756b79e   David S. Miller   ipv4: Stop using ...
1604
  	    (ifa->ifa_local &&
930345ea6   Jiri Benc   netlink: implemen...
1605
  	     nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) ||
f3756b79e   David S. Miller   ipv4: Stop using ...
1606
  	    (ifa->ifa_broadcast &&
930345ea6   Jiri Benc   netlink: implemen...
1607
  	     nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
f3756b79e   David S. Miller   ipv4: Stop using ...
1608
  	    (ifa->ifa_label[0] &&
5c766d642   Jiri Pirko   ipv4: introduce a...
1609
  	     nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
ad6c81359   Jiri Pirko   ipv4: add support...
1610
  	    nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
af4d768ad   David Ahern   net/ipv4: Add sup...
1611
1612
  	    (ifa->ifa_rt_priority &&
  	     nla_put_u32(skb, IFA_RT_PRIORITY, ifa->ifa_rt_priority)) ||
5c766d642   Jiri Pirko   ipv4: introduce a...
1613
1614
  	    put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
  			  preferred, valid))
f3756b79e   David S. Miller   ipv4: Stop using ...
1615
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1616

053c095a8   Johannes Berg   netlink: make nlm...
1617
1618
  	nlmsg_end(skb, nlh);
  	return 0;
47f68512d   Thomas Graf   [IPV4]: Convert a...
1619
1620
  
  nla_put_failure:
26932566a   Patrick McHardy   [NETLINK]: Don't ...
1621
1622
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1623
  }
c33078e3d   David Ahern   net/ipv4: Update ...
1624
1625
1626
  static int inet_valid_dump_ifaddr_req(const struct nlmsghdr *nlh,
  				      struct inet_fill_args *fillargs,
  				      struct net **tgt_net, struct sock *sk,
5fcd266a9   David Ahern   net/ipv4: Add sup...
1627
  				      struct netlink_callback *cb)
c33078e3d   David Ahern   net/ipv4: Update ...
1628
  {
5fcd266a9   David Ahern   net/ipv4: Add sup...
1629
  	struct netlink_ext_ack *extack = cb->extack;
c33078e3d   David Ahern   net/ipv4: Update ...
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
  	struct nlattr *tb[IFA_MAX+1];
  	struct ifaddrmsg *ifm;
  	int err, i;
  
  	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) {
  		NL_SET_ERR_MSG(extack, "ipv4: Invalid header for address dump request");
  		return -EINVAL;
  	}
  
  	ifm = nlmsg_data(nlh);
  	if (ifm->ifa_prefixlen || ifm->ifa_flags || ifm->ifa_scope) {
  		NL_SET_ERR_MSG(extack, "ipv4: Invalid values in header for address dump request");
  		return -EINVAL;
  	}
5fcd266a9   David Ahern   net/ipv4: Add sup...
1644
1645
1646
1647
1648
  
  	fillargs->ifindex = ifm->ifa_index;
  	if (fillargs->ifindex) {
  		cb->answer_flags |= NLM_F_DUMP_FILTERED;
  		fillargs->flags |= NLM_F_DUMP_FILTERED;
c33078e3d   David Ahern   net/ipv4: Update ...
1649
  	}
8cb081746   Johannes Berg   netlink: make val...
1650
1651
  	err = nlmsg_parse_deprecated_strict(nlh, sizeof(*ifm), tb, IFA_MAX,
  					    ifa_ipv4_policy, extack);
c33078e3d   David Ahern   net/ipv4: Update ...
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
  	if (err < 0)
  		return err;
  
  	for (i = 0; i <= IFA_MAX; ++i) {
  		if (!tb[i])
  			continue;
  
  		if (i == IFA_TARGET_NETNSID) {
  			struct net *net;
  
  			fillargs->netnsid = nla_get_s32(tb[i]);
  
  			net = rtnl_get_net_ns_capable(sk, fillargs->netnsid);
  			if (IS_ERR(net)) {
bf4cc40e9   Bjørn Mork   net/{ipv4,ipv6}: ...
1666
  				fillargs->netnsid = -1;
c33078e3d   David Ahern   net/ipv4: Update ...
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
  				NL_SET_ERR_MSG(extack, "ipv4: Invalid target network namespace id");
  				return PTR_ERR(net);
  			}
  			*tgt_net = net;
  		} else {
  			NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in dump request");
  			return -EINVAL;
  		}
  	}
  
  	return 0;
  }
1c98eca41   David Ahern   net/ipv4: Move lo...
1679
1680
1681
1682
1683
1684
1685
  static int in_dev_dump_addr(struct in_device *in_dev, struct sk_buff *skb,
  			    struct netlink_callback *cb, int s_ip_idx,
  			    struct inet_fill_args *fillargs)
  {
  	struct in_ifaddr *ifa;
  	int ip_idx = 0;
  	int err;
d3e6e285f   Florian Westphal   net: ipv4: fix rc...
1686
  	in_dev_for_each_ifa_rtnl(ifa, in_dev) {
ef11db331   Florian Westphal   net: inetdevice: ...
1687
1688
  		if (ip_idx < s_ip_idx) {
  			ip_idx++;
1c98eca41   David Ahern   net/ipv4: Move lo...
1689
  			continue;
ef11db331   Florian Westphal   net: inetdevice: ...
1690
  		}
1c98eca41   David Ahern   net/ipv4: Move lo...
1691
1692
1693
1694
1695
  		err = inet_fill_ifaddr(skb, ifa, fillargs);
  		if (err < 0)
  			goto done;
  
  		nl_dump_check_consistent(cb, nlmsg_hdr(skb));
ef11db331   Florian Westphal   net: inetdevice: ...
1696
  		ip_idx++;
1c98eca41   David Ahern   net/ipv4: Move lo...
1697
1698
1699
1700
1701
1702
1703
1704
  	}
  	err = 0;
  
  done:
  	cb->args[2] = ip_idx;
  
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1705
1706
  static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
  {
c33078e3d   David Ahern   net/ipv4: Update ...
1707
  	const struct nlmsghdr *nlh = cb->nlh;
978a46fa6   Christian Brauner   ipv4: add inet_fi...
1708
1709
  	struct inet_fill_args fillargs = {
  		.portid = NETLINK_CB(cb->skb).portid,
c33078e3d   David Ahern   net/ipv4: Update ...
1710
  		.seq = nlh->nlmsg_seq,
978a46fa6   Christian Brauner   ipv4: add inet_fi...
1711
1712
1713
1714
  		.event = RTM_NEWADDR,
  		.flags = NLM_F_MULTI,
  		.netnsid = -1,
  	};
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1715
  	struct net *net = sock_net(skb->sk);
d38071455   Christian Brauner   ipv4: enable IFA_...
1716
  	struct net *tgt_net = net;
eec4df988   Eric Dumazet   ipv4: speedup ine...
1717
1718
  	int h, s_h;
  	int idx, s_idx;
1c98eca41   David Ahern   net/ipv4: Move lo...
1719
  	int s_ip_idx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1720
1721
  	struct net_device *dev;
  	struct in_device *in_dev;
eec4df988   Eric Dumazet   ipv4: speedup ine...
1722
  	struct hlist_head *head;
d7e38611b   David Ahern   net/ipv4: Put tar...
1723
  	int err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1724

eec4df988   Eric Dumazet   ipv4: speedup ine...
1725
1726
  	s_h = cb->args[0];
  	s_idx = idx = cb->args[1];
1c98eca41   David Ahern   net/ipv4: Move lo...
1727
  	s_ip_idx = cb->args[2];
eec4df988   Eric Dumazet   ipv4: speedup ine...
1728

c33078e3d   David Ahern   net/ipv4: Update ...
1729
  	if (cb->strict_check) {
c33078e3d   David Ahern   net/ipv4: Update ...
1730
  		err = inet_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net,
5fcd266a9   David Ahern   net/ipv4: Add sup...
1731
  						 skb->sk, cb);
c33078e3d   David Ahern   net/ipv4: Update ...
1732
  		if (err < 0)
d7e38611b   David Ahern   net/ipv4: Put tar...
1733
  			goto put_tgt_net;
5fcd266a9   David Ahern   net/ipv4: Add sup...
1734

d7e38611b   David Ahern   net/ipv4: Put tar...
1735
  		err = 0;
5fcd266a9   David Ahern   net/ipv4: Add sup...
1736
1737
  		if (fillargs.ifindex) {
  			dev = __dev_get_by_index(tgt_net, fillargs.ifindex);
d7e38611b   David Ahern   net/ipv4: Put tar...
1738
1739
1740
1741
  			if (!dev) {
  				err = -ENODEV;
  				goto put_tgt_net;
  			}
5fcd266a9   David Ahern   net/ipv4: Add sup...
1742
1743
1744
1745
1746
1747
1748
1749
  
  			in_dev = __in_dev_get_rtnl(dev);
  			if (in_dev) {
  				err = in_dev_dump_addr(in_dev, skb, cb, s_ip_idx,
  						       &fillargs);
  			}
  			goto put_tgt_net;
  		}
d38071455   Christian Brauner   ipv4: enable IFA_...
1750
  	}
eec4df988   Eric Dumazet   ipv4: speedup ine...
1751
1752
  	for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
  		idx = 0;
d38071455   Christian Brauner   ipv4: enable IFA_...
1753
  		head = &tgt_net->dev_index_head[h];
eec4df988   Eric Dumazet   ipv4: speedup ine...
1754
  		rcu_read_lock();
d38071455   Christian Brauner   ipv4: enable IFA_...
1755
1756
  		cb->seq = atomic_read(&tgt_net->ipv4.dev_addr_genid) ^
  			  tgt_net->dev_base_seq;
b67bfe0d4   Sasha Levin   hlist: drop the n...
1757
  		hlist_for_each_entry_rcu(dev, head, index_hlist) {
eec4df988   Eric Dumazet   ipv4: speedup ine...
1758
1759
  			if (idx < s_idx)
  				goto cont;
4b97efdf3   Patrick McHardy   net: fix netlink ...
1760
  			if (h > s_h || idx > s_idx)
eec4df988   Eric Dumazet   ipv4: speedup ine...
1761
1762
1763
1764
  				s_ip_idx = 0;
  			in_dev = __in_dev_get_rcu(dev);
  			if (!in_dev)
  				goto cont;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1765

1c98eca41   David Ahern   net/ipv4: Move lo...
1766
1767
1768
1769
1770
  			err = in_dev_dump_addr(in_dev, skb, cb, s_ip_idx,
  					       &fillargs);
  			if (err < 0) {
  				rcu_read_unlock();
  				goto done;
eec4df988   Eric Dumazet   ipv4: speedup ine...
1771
  			}
7562f876c   Pavel Emelianov   [NET]: Rework dev...
1772
  cont:
eec4df988   Eric Dumazet   ipv4: speedup ine...
1773
1774
1775
  			idx++;
  		}
  		rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1776
1777
1778
  	}
  
  done:
eec4df988   Eric Dumazet   ipv4: speedup ine...
1779
1780
  	cb->args[0] = h;
  	cb->args[1] = idx;
5fcd266a9   David Ahern   net/ipv4: Add sup...
1781
  put_tgt_net:
978a46fa6   Christian Brauner   ipv4: add inet_fi...
1782
  	if (fillargs.netnsid >= 0)
d38071455   Christian Brauner   ipv4: enable IFA_...
1783
  		put_net(tgt_net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1784

7c1e8a381   Arthur Gautier   netlink: fixup re...
1785
  	return skb->len ? : err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1786
  }
539afedfc   Jianjun Kong   net: clean up net...
1787
  static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
15e473046   Eric W. Biederman   netlink: Rename p...
1788
  		      u32 portid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1789
  {
978a46fa6   Christian Brauner   ipv4: add inet_fi...
1790
1791
1792
1793
1794
1795
1796
  	struct inet_fill_args fillargs = {
  		.portid = portid,
  		.seq = nlh ? nlh->nlmsg_seq : 0,
  		.event = event,
  		.flags = 0,
  		.netnsid = -1,
  	};
47f68512d   Thomas Graf   [IPV4]: Convert a...
1797
  	struct sk_buff *skb;
d6062cbbd   Thomas Graf   [IPv4] address: C...
1798
  	int err = -ENOBUFS;
4b8aa9abe   Denis V. Lunev   [NETNS]: Process ...
1799
  	struct net *net;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1800

c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1801
  	net = dev_net(ifa->ifa_dev->dev);
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
1802
  	skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
51456b291   Ian Morris   ipv4: coding styl...
1803
  	if (!skb)
d6062cbbd   Thomas Graf   [IPv4] address: C...
1804
  		goto errout;
978a46fa6   Christian Brauner   ipv4: add inet_fi...
1805
  	err = inet_fill_ifaddr(skb, ifa, &fillargs);
26932566a   Patrick McHardy   [NETLINK]: Don't ...
1806
1807
1808
1809
1810
1811
  	if (err < 0) {
  		/* -EMSGSIZE implies BUG in inet_nlmsg_size() */
  		WARN_ON(err == -EMSGSIZE);
  		kfree_skb(skb);
  		goto errout;
  	}
15e473046   Eric W. Biederman   netlink: Rename p...
1812
  	rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
1ce85fe40   Pablo Neira Ayuso   netlink: change n...
1813
  	return;
d6062cbbd   Thomas Graf   [IPv4] address: C...
1814
1815
  errout:
  	if (err < 0)
4b8aa9abe   Denis V. Lunev   [NETNS]: Process ...
1816
  		rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1817
  }
b1974ed05   Arad, Ronen   netlink: Rightsiz...
1818
1819
  static size_t inet_get_link_af_size(const struct net_device *dev,
  				    u32 ext_filter_mask)
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
1820
  {
1fc19aff8   Eric Dumazet   net: fix two lock...
1821
  	struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
1822
1823
1824
1825
1826
1827
  
  	if (!in_dev)
  		return 0;
  
  	return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
  }
d5566fd72   Sowmini Varadhan   rtnetlink: RTEXT_...
1828
1829
  static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
  			     u32 ext_filter_mask)
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
1830
  {
1fc19aff8   Eric Dumazet   net: fix two lock...
1831
  	struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
1832
1833
1834
1835
1836
1837
1838
  	struct nlattr *nla;
  	int i;
  
  	if (!in_dev)
  		return -ENODATA;
  
  	nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
51456b291   Ian Morris   ipv4: coding styl...
1839
  	if (!nla)
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
  		return -EMSGSIZE;
  
  	for (i = 0; i < IPV4_DEVCONF_MAX; i++)
  		((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
  
  	return 0;
  }
  
  static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
  	[IFLA_INET_CONF]	= { .type = NLA_NESTED },
  };
cf7afbfeb   Thomas Graf   rtnl: make link a...
1851
1852
  static int inet_validate_link_af(const struct net_device *dev,
  				 const struct nlattr *nla)
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
1853
  {
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
1854
1855
  	struct nlattr *a, *tb[IFLA_INET_MAX+1];
  	int err, rem;
5fa85a093   Florian Westphal   net: core: rcu-if...
1856
  	if (dev && !__in_dev_get_rcu(dev))
cf7afbfeb   Thomas Graf   rtnl: make link a...
1857
  		return -EAFNOSUPPORT;
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
1858

8cb081746   Johannes Berg   netlink: make val...
1859
1860
  	err = nla_parse_nested_deprecated(tb, IFLA_INET_MAX, nla,
  					  inet_af_policy, NULL);
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
  	if (err < 0)
  		return err;
  
  	if (tb[IFLA_INET_CONF]) {
  		nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
  			int cfgid = nla_type(a);
  
  			if (nla_len(a) < 4)
  				return -EINVAL;
  
  			if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
  				return -EINVAL;
  		}
  	}
cf7afbfeb   Thomas Graf   rtnl: make link a...
1875
1876
1877
1878
1879
  	return 0;
  }
  
  static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
  {
5fa85a093   Florian Westphal   net: core: rcu-if...
1880
  	struct in_device *in_dev = __in_dev_get_rcu(dev);
cf7afbfeb   Thomas Graf   rtnl: make link a...
1881
1882
1883
1884
1885
  	struct nlattr *a, *tb[IFLA_INET_MAX+1];
  	int rem;
  
  	if (!in_dev)
  		return -EAFNOSUPPORT;
8cb081746   Johannes Berg   netlink: make val...
1886
  	if (nla_parse_nested_deprecated(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0)
cf7afbfeb   Thomas Graf   rtnl: make link a...
1887
  		BUG();
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
1888
1889
1890
1891
1892
1893
1894
  	if (tb[IFLA_INET_CONF]) {
  		nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
  			ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
  	}
  
  	return 0;
  }
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1895
1896
1897
1898
  static int inet_netconf_msgsize_devconf(int type)
  {
  	int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
  		   + nla_total_size(4);	/* NETCONFA_IFINDEX */
136ba622d   Zhang Shengju   netconf: add macr...
1899
  	bool all = false;
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1900

136ba622d   Zhang Shengju   netconf: add macr...
1901
1902
1903
1904
  	if (type == NETCONFA_ALL)
  		all = true;
  
  	if (all || type == NETCONFA_FORWARDING)
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1905
  		size += nla_total_size(4);
136ba622d   Zhang Shengju   netconf: add macr...
1906
  	if (all || type == NETCONFA_RP_FILTER)
cc535dfb6   Nicolas Dichtel   rtnl/ipv4: use ne...
1907
  		size += nla_total_size(4);
136ba622d   Zhang Shengju   netconf: add macr...
1908
  	if (all || type == NETCONFA_MC_FORWARDING)
d67b8c616   Nicolas Dichtel   netconf: advertis...
1909
  		size += nla_total_size(4);
5cbf777cf   Xin Long   route: add suppor...
1910
1911
  	if (all || type == NETCONFA_BC_FORWARDING)
  		size += nla_total_size(4);
136ba622d   Zhang Shengju   netconf: add macr...
1912
  	if (all || type == NETCONFA_PROXY_NEIGH)
f085ff1c1   stephen hemminger   netconf: add prox...
1913
  		size += nla_total_size(4);
136ba622d   Zhang Shengju   netconf: add macr...
1914
  	if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
974d7af5f   Andy Gospodarek   ipv4: add support...
1915
  		size += nla_total_size(4);
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
  
  	return size;
  }
  
  static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
  				     struct ipv4_devconf *devconf, u32 portid,
  				     u32 seq, int event, unsigned int flags,
  				     int type)
  {
  	struct nlmsghdr  *nlh;
  	struct netconfmsg *ncm;
136ba622d   Zhang Shengju   netconf: add macr...
1927
  	bool all = false;
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1928
1929
1930
  
  	nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
  			flags);
51456b291   Ian Morris   ipv4: coding styl...
1931
  	if (!nlh)
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1932
  		return -EMSGSIZE;
136ba622d   Zhang Shengju   netconf: add macr...
1933
1934
  	if (type == NETCONFA_ALL)
  		all = true;
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1935
1936
1937
1938
1939
  	ncm = nlmsg_data(nlh);
  	ncm->ncm_family = AF_INET;
  
  	if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
  		goto nla_put_failure;
b5c9641d3   David Ahern   net: devinet: Add...
1940
1941
  	if (!devconf)
  		goto out;
136ba622d   Zhang Shengju   netconf: add macr...
1942
  	if ((all || type == NETCONFA_FORWARDING) &&
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1943
1944
1945
  	    nla_put_s32(skb, NETCONFA_FORWARDING,
  			IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
  		goto nla_put_failure;
136ba622d   Zhang Shengju   netconf: add macr...
1946
  	if ((all || type == NETCONFA_RP_FILTER) &&
cc535dfb6   Nicolas Dichtel   rtnl/ipv4: use ne...
1947
1948
1949
  	    nla_put_s32(skb, NETCONFA_RP_FILTER,
  			IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
  		goto nla_put_failure;
136ba622d   Zhang Shengju   netconf: add macr...
1950
  	if ((all || type == NETCONFA_MC_FORWARDING) &&
d67b8c616   Nicolas Dichtel   netconf: advertis...
1951
1952
1953
  	    nla_put_s32(skb, NETCONFA_MC_FORWARDING,
  			IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
  		goto nla_put_failure;
5cbf777cf   Xin Long   route: add suppor...
1954
1955
1956
1957
  	if ((all || type == NETCONFA_BC_FORWARDING) &&
  	    nla_put_s32(skb, NETCONFA_BC_FORWARDING,
  			IPV4_DEVCONF(*devconf, BC_FORWARDING)) < 0)
  		goto nla_put_failure;
136ba622d   Zhang Shengju   netconf: add macr...
1958
  	if ((all || type == NETCONFA_PROXY_NEIGH) &&
09aea5df7   stephen hemminger   netconf: rename P...
1959
  	    nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
f085ff1c1   stephen hemminger   netconf: add prox...
1960
1961
  			IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
  		goto nla_put_failure;
136ba622d   Zhang Shengju   netconf: add macr...
1962
  	if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
974d7af5f   Andy Gospodarek   ipv4: add support...
1963
1964
1965
  	    nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
  			IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
  		goto nla_put_failure;
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1966

b5c9641d3   David Ahern   net: devinet: Add...
1967
  out:
053c095a8   Johannes Berg   netlink: make nlm...
1968
1969
  	nlmsg_end(skb, nlh);
  	return 0;
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1970
1971
1972
1973
1974
  
  nla_put_failure:
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
  }
3b0228656   David Ahern   net: devinet: Ref...
1975
1976
  void inet_netconf_notify_devconf(struct net *net, int event, int type,
  				 int ifindex, struct ipv4_devconf *devconf)
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1977
1978
1979
  {
  	struct sk_buff *skb;
  	int err = -ENOBUFS;
fa17806cd   Eric Dumazet   ipv4: do not abus...
1980
  	skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL);
51456b291   Ian Morris   ipv4: coding styl...
1981
  	if (!skb)
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1982
1983
1984
  		goto errout;
  
  	err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
3b0228656   David Ahern   net: devinet: Ref...
1985
  					event, 0, type);
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1986
1987
1988
1989
1990
1991
  	if (err < 0) {
  		/* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
  		WARN_ON(err == -EMSGSIZE);
  		kfree_skb(skb);
  		goto errout;
  	}
fa17806cd   Eric Dumazet   ipv4: do not abus...
1992
  	rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL);
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1993
1994
1995
1996
1997
  	return;
  errout:
  	if (err < 0)
  		rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
  }
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
1998
1999
2000
  static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
  	[NETCONFA_IFINDEX]	= { .len = sizeof(int) },
  	[NETCONFA_FORWARDING]	= { .len = sizeof(int) },
cc535dfb6   Nicolas Dichtel   rtnl/ipv4: use ne...
2001
  	[NETCONFA_RP_FILTER]	= { .len = sizeof(int) },
09aea5df7   stephen hemminger   netconf: rename P...
2002
  	[NETCONFA_PROXY_NEIGH]	= { .len = sizeof(int) },
974d7af5f   Andy Gospodarek   ipv4: add support...
2003
  	[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN]	= { .len = sizeof(int) },
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
2004
  };
eede370d6   Jakub Kicinski   net: ipv4: netcon...
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
  static int inet_netconf_valid_get_req(struct sk_buff *skb,
  				      const struct nlmsghdr *nlh,
  				      struct nlattr **tb,
  				      struct netlink_ext_ack *extack)
  {
  	int i, err;
  
  	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(struct netconfmsg))) {
  		NL_SET_ERR_MSG(extack, "ipv4: Invalid header for netconf get request");
  		return -EINVAL;
  	}
  
  	if (!netlink_strict_get_check(skb))
8cb081746   Johannes Berg   netlink: make val...
2018
2019
2020
  		return nlmsg_parse_deprecated(nlh, sizeof(struct netconfmsg),
  					      tb, NETCONFA_MAX,
  					      devconf_ipv4_policy, extack);
eede370d6   Jakub Kicinski   net: ipv4: netcon...
2021

8cb081746   Johannes Berg   netlink: make val...
2022
2023
2024
  	err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct netconfmsg),
  					    tb, NETCONFA_MAX,
  					    devconf_ipv4_policy, extack);
eede370d6   Jakub Kicinski   net: ipv4: netcon...
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
  	if (err)
  		return err;
  
  	for (i = 0; i <= NETCONFA_MAX; i++) {
  		if (!tb[i])
  			continue;
  
  		switch (i) {
  		case NETCONFA_IFINDEX:
  			break;
  		default:
  			NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in netconf get request");
  			return -EINVAL;
  		}
  	}
  
  	return 0;
  }
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
2043
  static int inet_netconf_get_devconf(struct sk_buff *in_skb,
c21ef3e34   David Ahern   net: rtnetlink: p...
2044
2045
  				    struct nlmsghdr *nlh,
  				    struct netlink_ext_ack *extack)
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
2046
2047
2048
  {
  	struct net *net = sock_net(in_skb->sk);
  	struct nlattr *tb[NETCONFA_MAX+1];
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
2049
2050
2051
2052
2053
2054
  	struct sk_buff *skb;
  	struct ipv4_devconf *devconf;
  	struct in_device *in_dev;
  	struct net_device *dev;
  	int ifindex;
  	int err;
eede370d6   Jakub Kicinski   net: ipv4: netcon...
2055
2056
  	err = inet_netconf_valid_get_req(in_skb, nlh, tb, extack);
  	if (err)
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
2057
  		goto errout;
a97eb33ff   Anton Protopopov   rtnl: RTM_GETNETC...
2058
  	err = -EINVAL;
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
  	if (!tb[NETCONFA_IFINDEX])
  		goto errout;
  
  	ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
  	switch (ifindex) {
  	case NETCONFA_IFINDEX_ALL:
  		devconf = net->ipv4.devconf_all;
  		break;
  	case NETCONFA_IFINDEX_DEFAULT:
  		devconf = net->ipv4.devconf_dflt;
  		break;
  	default:
  		dev = __dev_get_by_index(net, ifindex);
51456b291   Ian Morris   ipv4: coding styl...
2072
  		if (!dev)
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
2073
2074
  			goto errout;
  		in_dev = __in_dev_get_rtnl(dev);
51456b291   Ian Morris   ipv4: coding styl...
2075
  		if (!in_dev)
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
2076
2077
2078
2079
2080
2081
  			goto errout;
  		devconf = &in_dev->cnf;
  		break;
  	}
  
  	err = -ENOBUFS;
fa17806cd   Eric Dumazet   ipv4: do not abus...
2082
  	skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
51456b291   Ian Morris   ipv4: coding styl...
2083
  	if (!skb)
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
2084
2085
2086
2087
2088
  		goto errout;
  
  	err = inet_netconf_fill_devconf(skb, ifindex, devconf,
  					NETLINK_CB(in_skb).portid,
  					nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
136ba622d   Zhang Shengju   netconf: add macr...
2089
  					NETCONFA_ALL);
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
  	if (err < 0) {
  		/* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
  		WARN_ON(err == -EMSGSIZE);
  		kfree_skb(skb);
  		goto errout;
  	}
  	err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
  errout:
  	return err;
  }
7a6742003   Nicolas Dichtel   netconf: add the ...
2100
2101
2102
  static int inet_netconf_dump_devconf(struct sk_buff *skb,
  				     struct netlink_callback *cb)
  {
addd383f5   David Ahern   net: Update netco...
2103
  	const struct nlmsghdr *nlh = cb->nlh;
7a6742003   Nicolas Dichtel   netconf: add the ...
2104
2105
2106
2107
2108
2109
  	struct net *net = sock_net(skb->sk);
  	int h, s_h;
  	int idx, s_idx;
  	struct net_device *dev;
  	struct in_device *in_dev;
  	struct hlist_head *head;
addd383f5   David Ahern   net: Update netco...
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
  	if (cb->strict_check) {
  		struct netlink_ext_ack *extack = cb->extack;
  		struct netconfmsg *ncm;
  
  		if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ncm))) {
  			NL_SET_ERR_MSG(extack, "ipv4: Invalid header for netconf dump request");
  			return -EINVAL;
  		}
  
  		if (nlmsg_attrlen(nlh, sizeof(*ncm))) {
  			NL_SET_ERR_MSG(extack, "ipv4: Invalid data after header in netconf dump request");
  			return -EINVAL;
  		}
  	}
7a6742003   Nicolas Dichtel   netconf: add the ...
2124
2125
2126
2127
2128
2129
2130
  	s_h = cb->args[0];
  	s_idx = idx = cb->args[1];
  
  	for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
  		idx = 0;
  		head = &net->dev_index_head[h];
  		rcu_read_lock();
0465277f6   Nicolas Dichtel   ipv4: provide add...
2131
2132
  		cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
  			  net->dev_base_seq;
7a6742003   Nicolas Dichtel   netconf: add the ...
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
  		hlist_for_each_entry_rcu(dev, head, index_hlist) {
  			if (idx < s_idx)
  				goto cont;
  			in_dev = __in_dev_get_rcu(dev);
  			if (!in_dev)
  				goto cont;
  
  			if (inet_netconf_fill_devconf(skb, dev->ifindex,
  						      &in_dev->cnf,
  						      NETLINK_CB(cb->skb).portid,
addd383f5   David Ahern   net: Update netco...
2143
  						      nlh->nlmsg_seq,
7a6742003   Nicolas Dichtel   netconf: add the ...
2144
2145
  						      RTM_NEWNETCONF,
  						      NLM_F_MULTI,
136ba622d   Zhang Shengju   netconf: add macr...
2146
  						      NETCONFA_ALL) < 0) {
7a6742003   Nicolas Dichtel   netconf: add the ...
2147
2148
2149
  				rcu_read_unlock();
  				goto done;
  			}
0465277f6   Nicolas Dichtel   ipv4: provide add...
2150
  			nl_dump_check_consistent(cb, nlmsg_hdr(skb));
7a6742003   Nicolas Dichtel   netconf: add the ...
2151
2152
2153
2154
2155
2156
2157
2158
2159
  cont:
  			idx++;
  		}
  		rcu_read_unlock();
  	}
  	if (h == NETDEV_HASHENTRIES) {
  		if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
  					      net->ipv4.devconf_all,
  					      NETLINK_CB(cb->skb).portid,
addd383f5   David Ahern   net: Update netco...
2160
  					      nlh->nlmsg_seq,
7a6742003   Nicolas Dichtel   netconf: add the ...
2161
  					      RTM_NEWNETCONF, NLM_F_MULTI,
136ba622d   Zhang Shengju   netconf: add macr...
2162
  					      NETCONFA_ALL) < 0)
7a6742003   Nicolas Dichtel   netconf: add the ...
2163
2164
2165
2166
2167
2168
2169
2170
  			goto done;
  		else
  			h++;
  	}
  	if (h == NETDEV_HASHENTRIES + 1) {
  		if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
  					      net->ipv4.devconf_dflt,
  					      NETLINK_CB(cb->skb).portid,
addd383f5   David Ahern   net: Update netco...
2171
  					      nlh->nlmsg_seq,
7a6742003   Nicolas Dichtel   netconf: add the ...
2172
  					      RTM_NEWNETCONF, NLM_F_MULTI,
136ba622d   Zhang Shengju   netconf: add macr...
2173
  					      NETCONFA_ALL) < 0)
7a6742003   Nicolas Dichtel   netconf: add the ...
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
  			goto done;
  		else
  			h++;
  	}
  done:
  	cb->args[0] = h;
  	cb->args[1] = idx;
  
  	return skb->len;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2184
  #ifdef CONFIG_SYSCTL
c0ce9fb30   Pavel Emelyanov   [IPV4]: Store the...
2185
  static void devinet_copy_dflt_conf(struct net *net, int i)
31be30854   Herbert Xu   [IPV4]: Add defau...
2186
2187
  {
  	struct net_device *dev;
c6d14c845   Eric Dumazet   net: Introduce fo...
2188
2189
  	rcu_read_lock();
  	for_each_netdev_rcu(net, dev) {
31be30854   Herbert Xu   [IPV4]: Add defau...
2190
  		struct in_device *in_dev;
c6d14c845   Eric Dumazet   net: Introduce fo...
2191

31be30854   Herbert Xu   [IPV4]: Add defau...
2192
2193
  		in_dev = __in_dev_get_rcu(dev);
  		if (in_dev && !test_bit(i, in_dev->cnf.state))
9355bbd68   Pavel Emelyanov   [IPV4]: Switch us...
2194
  			in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
31be30854   Herbert Xu   [IPV4]: Add defau...
2195
  	}
c6d14c845   Eric Dumazet   net: Introduce fo...
2196
  	rcu_read_unlock();
31be30854   Herbert Xu   [IPV4]: Add defau...
2197
  }
c6d14c845   Eric Dumazet   net: Introduce fo...
2198
  /* called with RTNL locked */
c0ce9fb30   Pavel Emelyanov   [IPV4]: Store the...
2199
  static void inet_forward_change(struct net *net)
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2200
2201
  {
  	struct net_device *dev;
586f12115   Pavel Emelyanov   [IPV4]: Switch us...
2202
  	int on = IPV4_DEVCONF_ALL(net, FORWARDING);
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2203

586f12115   Pavel Emelyanov   [IPV4]: Switch us...
2204
  	IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
9355bbd68   Pavel Emelyanov   [IPV4]: Switch us...
2205
  	IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
3b0228656   David Ahern   net: devinet: Ref...
2206
2207
  	inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
  				    NETCONFA_FORWARDING,
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
2208
2209
  				    NETCONFA_IFINDEX_ALL,
  				    net->ipv4.devconf_all);
3b0228656   David Ahern   net: devinet: Ref...
2210
2211
  	inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
  				    NETCONFA_FORWARDING,
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
2212
2213
  				    NETCONFA_IFINDEX_DEFAULT,
  				    net->ipv4.devconf_dflt);
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2214

c0ce9fb30   Pavel Emelyanov   [IPV4]: Store the...
2215
  	for_each_netdev(net, dev) {
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2216
  		struct in_device *in_dev;
fa17806cd   Eric Dumazet   ipv4: do not abus...
2217

0187bdfb0   Ben Hutchings   net: Disable LRO ...
2218
2219
  		if (on)
  			dev_disable_lro(dev);
fa17806cd   Eric Dumazet   ipv4: do not abus...
2220
2221
  
  		in_dev = __in_dev_get_rtnl(dev);
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
2222
  		if (in_dev) {
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2223
  			IN_DEV_CONF_SET(in_dev, FORWARDING, on);
3b0228656   David Ahern   net: devinet: Ref...
2224
2225
  			inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
  						    NETCONFA_FORWARDING,
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
2226
2227
  						    dev->ifindex, &in_dev->cnf);
  		}
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2228
  	}
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2229
  }
f085ff1c1   stephen hemminger   netconf: add prox...
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
  static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf)
  {
  	if (cnf == net->ipv4.devconf_dflt)
  		return NETCONFA_IFINDEX_DEFAULT;
  	else if (cnf == net->ipv4.devconf_all)
  		return NETCONFA_IFINDEX_ALL;
  	else {
  		struct in_device *idev
  			= container_of(cnf, struct in_device, cnf);
  		return idev->dev->ifindex;
  	}
  }
fe2c6338f   Joe Perches   net: Convert uses...
2242
  static int devinet_conf_proc(struct ctl_table *ctl, int write,
32927393d   Christoph Hellwig   sysctl: pass kern...
2243
  			     void *buffer, size_t *lenp, loff_t *ppos)
31be30854   Herbert Xu   [IPV4]: Add defau...
2244
  {
d01ff0a04   Peter Pan(潘卫平)   ipv4: flush route...
2245
  	int old_value = *(int *)ctl->data;
8d65af789   Alexey Dobriyan   sysctl: remove "s...
2246
  	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
d01ff0a04   Peter Pan(潘卫平)   ipv4: flush route...
2247
  	int new_value = *(int *)ctl->data;
31be30854   Herbert Xu   [IPV4]: Add defau...
2248
2249
2250
  
  	if (write) {
  		struct ipv4_devconf *cnf = ctl->extra1;
c0ce9fb30   Pavel Emelyanov   [IPV4]: Store the...
2251
  		struct net *net = ctl->extra2;
31be30854   Herbert Xu   [IPV4]: Add defau...
2252
  		int i = (int *)ctl->data - cnf->data;
f085ff1c1   stephen hemminger   netconf: add prox...
2253
  		int ifindex;
31be30854   Herbert Xu   [IPV4]: Add defau...
2254
2255
  
  		set_bit(i, cnf->state);
9355bbd68   Pavel Emelyanov   [IPV4]: Switch us...
2256
  		if (cnf == net->ipv4.devconf_dflt)
c0ce9fb30   Pavel Emelyanov   [IPV4]: Store the...
2257
  			devinet_copy_dflt_conf(net, i);
d0daebc3d   Thomas Graf   ipv4: Add interfa...
2258
2259
  		if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
  		    i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
d01ff0a04   Peter Pan(潘卫平)   ipv4: flush route...
2260
  			if ((new_value == 0) && (old_value != 0))
4ccfe6d41   Nicolas Dichtel   ipv4/route: arg d...
2261
  				rt_cache_flush(net);
f085ff1c1   stephen hemminger   netconf: add prox...
2262

5cbf777cf   Xin Long   route: add suppor...
2263
2264
2265
  		if (i == IPV4_DEVCONF_BC_FORWARDING - 1 &&
  		    new_value != old_value)
  			rt_cache_flush(net);
cc535dfb6   Nicolas Dichtel   rtnl/ipv4: use ne...
2266
2267
  		if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
  		    new_value != old_value) {
f085ff1c1   stephen hemminger   netconf: add prox...
2268
  			ifindex = devinet_conf_ifindex(net, cnf);
3b0228656   David Ahern   net: devinet: Ref...
2269
2270
  			inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
  						    NETCONFA_RP_FILTER,
cc535dfb6   Nicolas Dichtel   rtnl/ipv4: use ne...
2271
2272
  						    ifindex, cnf);
  		}
f085ff1c1   stephen hemminger   netconf: add prox...
2273
2274
2275
  		if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
  		    new_value != old_value) {
  			ifindex = devinet_conf_ifindex(net, cnf);
3b0228656   David Ahern   net: devinet: Ref...
2276
2277
  			inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
  						    NETCONFA_PROXY_NEIGH,
f085ff1c1   stephen hemminger   netconf: add prox...
2278
2279
  						    ifindex, cnf);
  		}
974d7af5f   Andy Gospodarek   ipv4: add support...
2280
2281
2282
  		if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
  		    new_value != old_value) {
  			ifindex = devinet_conf_ifindex(net, cnf);
3b0228656   David Ahern   net: devinet: Ref...
2283
2284
  			inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
  						    NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
974d7af5f   Andy Gospodarek   ipv4: add support...
2285
2286
  						    ifindex, cnf);
  		}
31be30854   Herbert Xu   [IPV4]: Add defau...
2287
2288
2289
2290
  	}
  
  	return ret;
  }
fe2c6338f   Joe Perches   net: Convert uses...
2291
  static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
32927393d   Christoph Hellwig   sysctl: pass kern...
2292
  				  void *buffer, size_t *lenp, loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2293
2294
2295
  {
  	int *valp = ctl->data;
  	int val = *valp;
88af182e3   Eric W. Biederman   net: Fix sysctl r...
2296
  	loff_t pos = *ppos;
8d65af789   Alexey Dobriyan   sysctl: remove "s...
2297
  	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2298
2299
  
  	if (write && *valp != val) {
c0ce9fb30   Pavel Emelyanov   [IPV4]: Store the...
2300
  		struct net *net = ctl->extra2;
0187bdfb0   Ben Hutchings   net: Disable LRO ...
2301
  		if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
88af182e3   Eric W. Biederman   net: Fix sysctl r...
2302
2303
2304
2305
  			if (!rtnl_trylock()) {
  				/* Restore the original values before restarting */
  				*valp = val;
  				*ppos = pos;
9b8adb5ea   Eric W. Biederman   net: Fix devinet_...
2306
  				return restart_syscall();
88af182e3   Eric W. Biederman   net: Fix sysctl r...
2307
  			}
0187bdfb0   Ben Hutchings   net: Disable LRO ...
2308
2309
  			if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
  				inet_forward_change(net);
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
2310
  			} else {
0187bdfb0   Ben Hutchings   net: Disable LRO ...
2311
2312
2313
  				struct ipv4_devconf *cnf = ctl->extra1;
  				struct in_device *idev =
  					container_of(cnf, struct in_device, cnf);
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
2314
2315
  				if (*valp)
  					dev_disable_lro(idev->dev);
3b0228656   David Ahern   net: devinet: Ref...
2316
  				inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
2317
2318
2319
  							    NETCONFA_FORWARDING,
  							    idev->dev->ifindex,
  							    cnf);
0187bdfb0   Ben Hutchings   net: Disable LRO ...
2320
2321
  			}
  			rtnl_unlock();
4ccfe6d41   Nicolas Dichtel   ipv4/route: arg d...
2322
  			rt_cache_flush(net);
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
2323
  		} else
3b0228656   David Ahern   net: devinet: Ref...
2324
2325
  			inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
  						    NETCONFA_FORWARDING,
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
2326
2327
  						    NETCONFA_IFINDEX_DEFAULT,
  						    net->ipv4.devconf_dflt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2328
2329
2330
2331
  	}
  
  	return ret;
  }
fe2c6338f   Joe Perches   net: Convert uses...
2332
  static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
32927393d   Christoph Hellwig   sysctl: pass kern...
2333
  				void *buffer, size_t *lenp, loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2334
2335
2336
  {
  	int *valp = ctl->data;
  	int val = *valp;
8d65af789   Alexey Dobriyan   sysctl: remove "s...
2337
  	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
76e6ebfb4   Denis V. Lunev   netns: add namesp...
2338
  	struct net *net = ctl->extra2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2339
2340
  
  	if (write && *valp != val)
4ccfe6d41   Nicolas Dichtel   ipv4/route: arg d...
2341
  		rt_cache_flush(net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2342
2343
2344
  
  	return ret;
  }
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2345
  #define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2346
  	{ \
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2347
2348
  		.procname	= name, \
  		.data		= ipv4_devconf.data + \
02291680f   Eric W. Biederman   net ipv4: Decoupl...
2349
  				  IPV4_DEVCONF_ ## attr - 1, \
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2350
2351
2352
  		.maxlen		= sizeof(int), \
  		.mode		= mval, \
  		.proc_handler	= proc, \
31be30854   Herbert Xu   [IPV4]: Add defau...
2353
  		.extra1		= &ipv4_devconf, \
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2354
2355
2356
  	}
  
  #define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2357
  	DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2358
2359
  
  #define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2360
  	DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2361

f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2362
2363
  #define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
  	DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2364
2365
  
  #define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2366
  	DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2367

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2368
2369
  static struct devinet_sysctl_table {
  	struct ctl_table_header *sysctl_header;
02291680f   Eric W. Biederman   net ipv4: Decoupl...
2370
  	struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2371
2372
  } devinet_sysctl = {
  	.devinet_vars = {
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2373
  		DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2374
  					     devinet_sysctl_forward),
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2375
  		DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
5cbf777cf   Xin Long   route: add suppor...
2376
  		DEVINET_SYSCTL_RW_ENTRY(BC_FORWARDING, "bc_forwarding"),
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2377
2378
2379
2380
2381
2382
2383
2384
  
  		DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
  		DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
  		DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
  		DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
  		DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
  		DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
  					"accept_source_route"),
8153a10c0   Patrick McHardy   ipv4 05/05: add s...
2385
  		DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
28f6aeea3   Jamal Hadi Salim   net: restore ip s...
2386
  		DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2387
2388
2389
2390
2391
2392
2393
2394
2395
  		DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
  		DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
  		DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
  		DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
  		DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
  		DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
  		DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
  		DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
  		DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
eefef1cf7   Stephen Hemminger   net: add ARP noti...
2396
  		DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
65324144b   Jesper Dangaard Brouer   net: RFC3069, pri...
2397
  		DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
5c6fe01c1   William Manley   net: igmp: Don't ...
2398
2399
  		DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
  					"force_igmp_version"),
2690048c0   William Manley   net: igmp: Allow ...
2400
2401
2402
2403
  		DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
  					"igmpv2_unsolicited_report_interval"),
  		DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
  					"igmpv3_unsolicited_report_interval"),
0eeb075fa   Andy Gospodarek   net: ipv4 sysctl ...
2404
2405
  		DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
  					"ignore_routes_with_linkdown"),
97daf3314   Johannes Berg   ipv4: add option ...
2406
2407
  		DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
  					"drop_gratuitous_arp"),
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2408
2409
2410
  
  		DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
  		DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2411
2412
  		DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
  					      "promote_secondaries"),
d0daebc3d   Thomas Graf   ipv4: Add interfa...
2413
2414
  		DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
  					      "route_localnet"),
12b74dfad   Johannes Berg   ipv4: add option ...
2415
2416
  		DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
  					      "drop_unicast_in_l2_multicast"),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2417
  	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2418
  };
ea40b324d   Pavel Emelyanov   [IPV4]: Make __de...
2419
  static int __devinet_sysctl_register(struct net *net, char *dev_name,
29c994e36   Nicolas Dichtel   netconf: add a no...
2420
  				     int ifindex, struct ipv4_devconf *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2421
2422
  {
  	int i;
9fa896429   Pavel Emelyanov   [IPV4]: Cleanup t...
2423
  	struct devinet_sysctl_table *t;
8607ddb86   Eric W. Biederman   net ipv4: Convert...
2424
  	char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
bfada697b   Pavel Emelyanov   [IPV4]: Use ctl p...
2425

9fa896429   Pavel Emelyanov   [IPV4]: Cleanup t...
2426
  	t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2427
  	if (!t)
9fa896429   Pavel Emelyanov   [IPV4]: Cleanup t...
2428
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2429
2430
  	for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
  		t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
31be30854   Herbert Xu   [IPV4]: Add defau...
2431
  		t->devinet_vars[i].extra1 = p;
c0ce9fb30   Pavel Emelyanov   [IPV4]: Store the...
2432
  		t->devinet_vars[i].extra2 = net;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2433
  	}
8607ddb86   Eric W. Biederman   net ipv4: Convert...
2434
  	snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2435

8607ddb86   Eric W. Biederman   net ipv4: Convert...
2436
  	t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2437
  	if (!t->sysctl_header)
8607ddb86   Eric W. Biederman   net ipv4: Convert...
2438
  		goto free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2439
2440
  
  	p->sysctl = t;
29c994e36   Nicolas Dichtel   netconf: add a no...
2441

3b0228656   David Ahern   net: devinet: Ref...
2442
2443
  	inet_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_ALL,
  				    ifindex, p);
ea40b324d   Pavel Emelyanov   [IPV4]: Make __de...
2444
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2445

9fa896429   Pavel Emelyanov   [IPV4]: Cleanup t...
2446
  free:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2447
  	kfree(t);
9fa896429   Pavel Emelyanov   [IPV4]: Cleanup t...
2448
  out:
ea40b324d   Pavel Emelyanov   [IPV4]: Make __de...
2449
  	return -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2450
  }
b5c9641d3   David Ahern   net: devinet: Add...
2451
2452
  static void __devinet_sysctl_unregister(struct net *net,
  					struct ipv4_devconf *cnf, int ifindex)
51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
2453
2454
  {
  	struct devinet_sysctl_table *t = cnf->sysctl;
b5c9641d3   David Ahern   net: devinet: Add...
2455
2456
2457
2458
2459
  	if (t) {
  		cnf->sysctl = NULL;
  		unregister_net_sysctl_table(t->sysctl_header);
  		kfree(t);
  	}
51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
2460

b5c9641d3   David Ahern   net: devinet: Add...
2461
  	inet_netconf_notify_devconf(net, RTM_DELNETCONF, 0, ifindex, NULL);
51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
2462
  }
20e61da7f   WANG Cong   ipv4: fail early ...
2463
  static int devinet_sysctl_register(struct in_device *idev)
66f27a520   Pavel Emelyanov   [IPV4]: Unify and...
2464
  {
20e61da7f   WANG Cong   ipv4: fail early ...
2465
2466
2467
2468
2469
2470
2471
2472
2473
  	int err;
  
  	if (!sysctl_dev_name_is_allowed(idev->dev->name))
  		return -EINVAL;
  
  	err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
  	if (err)
  		return err;
  	err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
29c994e36   Nicolas Dichtel   netconf: add a no...
2474
  					idev->dev->ifindex, &idev->cnf);
20e61da7f   WANG Cong   ipv4: fail early ...
2475
2476
2477
  	if (err)
  		neigh_sysctl_unregister(idev->arp_parms);
  	return err;
66f27a520   Pavel Emelyanov   [IPV4]: Unify and...
2478
  }
51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
2479
  static void devinet_sysctl_unregister(struct in_device *idev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2480
  {
b5c9641d3   David Ahern   net: devinet: Add...
2481
2482
2483
  	struct net *net = dev_net(idev->dev);
  
  	__devinet_sysctl_unregister(net, &idev->cnf, idev->dev->ifindex);
51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
2484
  	neigh_sysctl_unregister(idev->arp_parms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2485
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2486

68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2487
2488
  static struct ctl_table ctl_forward_entry[] = {
  	{
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2489
2490
  		.procname	= "ip_forward",
  		.data		= &ipv4_devconf.data[
02291680f   Eric W. Biederman   net ipv4: Decoupl...
2491
  					IPV4_DEVCONF_FORWARDING - 1],
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2492
2493
2494
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
  		.proc_handler	= devinet_sysctl_forward,
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2495
  		.extra1		= &ipv4_devconf,
c0ce9fb30   Pavel Emelyanov   [IPV4]: Store the...
2496
  		.extra2		= &init_net,
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2497
2498
2499
  	},
  	{ },
  };
2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2500
  #endif
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2501

752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2502
2503
2504
  static __net_init int devinet_init_net(struct net *net)
  {
  	int err;
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2505
  	struct ipv4_devconf *all, *dflt;
2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2506
  #ifdef CONFIG_SYSCTL
856c395cf   Cong Wang   net: introduce a ...
2507
  	struct ctl_table *tbl;
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2508
  	struct ctl_table_header *forw_hdr;
2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2509
  #endif
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2510
2511
  
  	err = -ENOMEM;
856c395cf   Cong Wang   net: introduce a ...
2512
2513
2514
  	all = kmemdup(&ipv4_devconf, sizeof(ipv4_devconf), GFP_KERNEL);
  	if (!all)
  		goto err_alloc_all;
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2515

856c395cf   Cong Wang   net: introduce a ...
2516
2517
2518
  	dflt = kmemdup(&ipv4_devconf_dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
  	if (!dflt)
  		goto err_alloc_dflt;
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2519

2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2520
  #ifdef CONFIG_SYSCTL
856c395cf   Cong Wang   net: introduce a ...
2521
2522
2523
  	tbl = kmemdup(ctl_forward_entry, sizeof(ctl_forward_entry), GFP_KERNEL);
  	if (!tbl)
  		goto err_alloc_ctl;
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2524

856c395cf   Cong Wang   net: introduce a ...
2525
2526
2527
  	tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
  	tbl[0].extra1 = all;
  	tbl[0].extra2 = net;
2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2528
  #endif
856c395cf   Cong Wang   net: introduce a ...
2529

9efd6a3ce   Nicolas Dichtel   netns: enable to ...
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
  	if (!net_eq(net, &init_net)) {
  		if (IS_ENABLED(CONFIG_SYSCTL) &&
  		    sysctl_devconf_inherit_init_net == 3) {
  			/* copy from the current netns */
  			memcpy(all, current->nsproxy->net_ns->ipv4.devconf_all,
  			       sizeof(ipv4_devconf));
  			memcpy(dflt,
  			       current->nsproxy->net_ns->ipv4.devconf_dflt,
  			       sizeof(ipv4_devconf_dflt));
  		} else if (!IS_ENABLED(CONFIG_SYSCTL) ||
  			   sysctl_devconf_inherit_init_net != 2) {
  			/* inherit == 0 or 1: copy from init_net */
  			memcpy(all, init_net.ipv4.devconf_all,
  			       sizeof(ipv4_devconf));
  			memcpy(dflt, init_net.ipv4.devconf_dflt,
  			       sizeof(ipv4_devconf_dflt));
  		}
  		/* else inherit == 2: use compiled values */
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2548
2549
2550
  	}
  
  #ifdef CONFIG_SYSCTL
29c994e36   Nicolas Dichtel   netconf: add a no...
2551
  	err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all);
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2552
2553
  	if (err < 0)
  		goto err_reg_all;
29c994e36   Nicolas Dichtel   netconf: add a no...
2554
2555
  	err = __devinet_sysctl_register(net, "default",
  					NETCONFA_IFINDEX_DEFAULT, dflt);
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2556
2557
2558
2559
  	if (err < 0)
  		goto err_reg_dflt;
  
  	err = -ENOMEM;
8607ddb86   Eric W. Biederman   net ipv4: Convert...
2560
  	forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
51456b291   Ian Morris   ipv4: coding styl...
2561
  	if (!forw_hdr)
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2562
  		goto err_reg_ctl;
2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2563
  	net->ipv4.forw_hdr = forw_hdr;
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2564
  #endif
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2565
2566
2567
2568
2569
2570
  	net->ipv4.devconf_all = all;
  	net->ipv4.devconf_dflt = dflt;
  	return 0;
  
  #ifdef CONFIG_SYSCTL
  err_reg_ctl:
b5c9641d3   David Ahern   net: devinet: Add...
2571
  	__devinet_sysctl_unregister(net, dflt, NETCONFA_IFINDEX_DEFAULT);
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2572
  err_reg_dflt:
b5c9641d3   David Ahern   net: devinet: Add...
2573
  	__devinet_sysctl_unregister(net, all, NETCONFA_IFINDEX_ALL);
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2574
  err_reg_all:
856c395cf   Cong Wang   net: introduce a ...
2575
  	kfree(tbl);
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2576
  err_alloc_ctl:
2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2577
  #endif
856c395cf   Cong Wang   net: introduce a ...
2578
  	kfree(dflt);
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2579
  err_alloc_dflt:
856c395cf   Cong Wang   net: introduce a ...
2580
  	kfree(all);
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2581
2582
2583
2584
2585
2586
  err_alloc_all:
  	return err;
  }
  
  static __net_exit void devinet_exit_net(struct net *net)
  {
2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2587
  #ifdef CONFIG_SYSCTL
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2588
2589
2590
  	struct ctl_table *tbl;
  
  	tbl = net->ipv4.forw_hdr->ctl_table_arg;
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2591
  	unregister_net_sysctl_table(net->ipv4.forw_hdr);
b5c9641d3   David Ahern   net: devinet: Add...
2592
2593
2594
2595
  	__devinet_sysctl_unregister(net, net->ipv4.devconf_dflt,
  				    NETCONFA_IFINDEX_DEFAULT);
  	__devinet_sysctl_unregister(net, net->ipv4.devconf_all,
  				    NETCONFA_IFINDEX_ALL);
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2596
  	kfree(tbl);
2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2597
  #endif
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2598
2599
2600
2601
2602
2603
2604
2605
  	kfree(net->ipv4.devconf_dflt);
  	kfree(net->ipv4.devconf_all);
  }
  
  static __net_initdata struct pernet_operations devinet_ops = {
  	.init = devinet_init_net,
  	.exit = devinet_exit_net,
  };
207895fd3   Daniel Borkmann   net: mark some po...
2606
  static struct rtnl_af_ops inet_af_ops __read_mostly = {
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
2607
2608
2609
  	.family		  = AF_INET,
  	.fill_link_af	  = inet_fill_link_af,
  	.get_link_af_size = inet_get_link_af_size,
cf7afbfeb   Thomas Graf   rtnl: make link a...
2610
2611
  	.validate_link_af = inet_validate_link_af,
  	.set_link_af	  = inet_set_link_af,
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
2612
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2613
2614
  void __init devinet_init(void)
  {
fd23c3b31   David S. Miller   ipv4: Add hash ta...
2615
2616
2617
2618
  	int i;
  
  	for (i = 0; i < IN4_ADDR_HSIZE; i++)
  		INIT_HLIST_HEAD(&inet_addr_lst[i]);
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2619
  	register_pernet_subsys(&devinet_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2620
2621
  	register_gifconf(PF_INET, inet_gifconf);
  	register_netdevice_notifier(&ip_netdev_notifier);
63f3444fb   Thomas Graf   [IPv4]: Use rtnl ...
2622

906e073f3   viresh kumar   net/ipv4: queue w...
2623
  	queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
5c766d642   Jiri Pirko   ipv4: introduce a...
2624

9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
2625
  	rtnl_af_register(&inet_af_ops);
b97bac64a   Florian Westphal   rtnetlink: make r...
2626
2627
2628
  	rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, 0);
  	rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, 0);
  	rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, 0);
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
2629
  	rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
b97bac64a   Florian Westphal   rtnetlink: make r...
2630
  		      inet_netconf_dump_devconf, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2631
  }