Blame view

net/ipv4/devinet.c 57.5 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   *	NET3	IP device support routines.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
   *		This program is free software; you can redistribute it and/or
   *		modify it under the terms of the GNU General Public License
   *		as published by the Free Software Foundation; either version
   *		2 of the License, or (at your option) any later version.
   *
   *	Derived from the IP parts of dev.c 1.0.19
02c30a84e   Jesper Juhl   [PATCH] update Ro...
10
   * 		Authors:	Ross Biro
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
   *				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
27
28
  
  #include <asm/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  #include <linux/bitops.h>
4fc268d24   Randy Dunlap   [PATCH] capable/c...
30
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
38
39
40
  #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...
41
  #include <linux/if_addr.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
  #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
47
48
49
50
  #include <linux/init.h>
  #include <linux/notifier.h>
  #include <linux/inetdevice.h>
  #include <linux/igmp.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
51
  #include <linux/slab.h>
fd23c3b31   David S. Miller   ipv4: Add hash ta...
52
  #include <linux/hash.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
55
56
  #ifdef CONFIG_SYSCTL
  #include <linux/sysctl.h>
  #endif
  #include <linux/kmod.h>
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
57
  #include <linux/netconf.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58

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

406b6f974   David S. Miller   ipv4: Fallback to...
67
  #include "fib_lookup.h"
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 },
5c7539781   Thomas Graf   [IPV4]: Convert a...
100
  };
40384999d   Eric Dumazet   ipv4: change inet...
101
102
  #define IN4_ADDR_HSIZE_SHIFT	8
  #define IN4_ADDR_HSIZE		(1U << IN4_ADDR_HSIZE_SHIFT)
fd23c3b31   David S. Miller   ipv4: Add hash ta...
103
  static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
fd23c3b31   David S. Miller   ipv4: Add hash ta...
104

40384999d   Eric Dumazet   ipv4: change inet...
105
  static u32 inet_addr_hash(struct net *net, __be32 addr)
fd23c3b31   David S. Miller   ipv4: Add hash ta...
106
  {
40384999d   Eric Dumazet   ipv4: change inet...
107
  	u32 val = (__force u32) addr ^ net_hash_mix(net);
fd23c3b31   David S. Miller   ipv4: Add hash ta...
108

40384999d   Eric Dumazet   ipv4: change inet...
109
  	return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
fd23c3b31   David S. Miller   ipv4: Add hash ta...
110
111
112
113
  }
  
  static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
  {
40384999d   Eric Dumazet   ipv4: change inet...
114
  	u32 hash = inet_addr_hash(net, ifa->ifa_local);
fd23c3b31   David S. Miller   ipv4: Add hash ta...
115

32a4be489   WANG Cong   ipv4: remove inet...
116
  	ASSERT_RTNL();
fd23c3b31   David S. Miller   ipv4: Add hash ta...
117
  	hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
fd23c3b31   David S. Miller   ipv4: Add hash ta...
118
119
120
121
  }
  
  static void inet_hash_remove(struct in_ifaddr *ifa)
  {
32a4be489   WANG Cong   ipv4: remove inet...
122
  	ASSERT_RTNL();
fd23c3b31   David S. Miller   ipv4: Add hash ta...
123
  	hlist_del_init_rcu(&ifa->hash);
fd23c3b31   David S. Miller   ipv4: Add hash ta...
124
  }
9435eb1cf   David S. Miller   ipv4: Implement _...
125
126
127
128
129
130
131
132
133
134
  /**
   * __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)
  {
40384999d   Eric Dumazet   ipv4: change inet...
135
  	u32 hash = inet_addr_hash(net, addr);
9435eb1cf   David S. Miller   ipv4: Implement _...
136
137
  	struct net_device *result = NULL;
  	struct in_ifaddr *ifa;
9435eb1cf   David S. Miller   ipv4: Implement _...
138
139
  
  	rcu_read_lock();
b67bfe0d4   Sasha Levin   hlist: drop the n...
140
  	hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash) {
e066008b3   David S. Miller   ipv4: Fix __ip_de...
141
  		if (ifa->ifa_local == addr) {
40384999d   Eric Dumazet   ipv4: change inet...
142
143
144
145
  			struct net_device *dev = ifa->ifa_dev->dev;
  
  			if (!net_eq(dev_net(dev), net))
  				continue;
9435eb1cf   David S. Miller   ipv4: Implement _...
146
147
148
149
  			result = dev;
  			break;
  		}
  	}
406b6f974   David S. Miller   ipv4: Fallback to...
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  	if (!result) {
  		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);
  	}
9435eb1cf   David S. Miller   ipv4: Implement _...
164
165
166
167
168
169
  	if (result && devref)
  		dev_hold(result);
  	rcu_read_unlock();
  	return result;
  }
  EXPORT_SYMBOL(__ip_dev_find);
d6062cbbd   Thomas Graf   [IPv4] address: C...
170
  static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171

e041c6834   Alan Stern   [PATCH] Notifier ...
172
  static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
175
  static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
  			 int destroy);
  #ifdef CONFIG_SYSCTL
66f27a520   Pavel Emelyanov   [IPV4]: Unify and...
176
  static void devinet_sysctl_register(struct in_device *idev);
51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
177
178
  static void devinet_sysctl_unregister(struct in_device *idev);
  #else
40384999d   Eric Dumazet   ipv4: change inet...
179
  static void devinet_sysctl_register(struct in_device *idev)
51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
180
181
  {
  }
40384999d   Eric Dumazet   ipv4: change inet...
182
  static void devinet_sysctl_unregister(struct in_device *idev)
51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
183
184
  {
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
188
189
190
  #endif
  
  /* Locks all the inet devices. */
  
  static struct in_ifaddr *inet_alloc_ifa(void)
  {
93adcc80f   Alexey Dobriyan   net: don't use IN...
191
  	return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
195
196
197
198
199
200
  }
  
  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...
201
  static void inet_free_ifa(struct in_ifaddr *ifa)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
205
206
207
208
  {
  	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_...
209
210
  	WARN_ON(idev->ifa_list);
  	WARN_ON(idev->mc_list);
e98970713   Eric Dumazet   igmp: hash a hash...
211
  	kfree(rcu_dereference_protected(idev->mc_hash, 1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
  #ifdef NET_REFCNT_DEBUG
91df42bed   Joe Perches   net: ipv4 and ipv...
213
214
  	pr_debug("%s: %p=%s
  ", __func__, idev, dev ? dev->name : "NIL");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
217
  #endif
  	dev_put(dev);
  	if (!idev->dead)
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
218
219
220
  		pr_err("Freeing alive in_device %p
  ", idev);
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
  		kfree(idev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
  }
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
223
  EXPORT_SYMBOL(in_dev_finish_destroy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224

71e27da96   Herbert Xu   [IPV4]: Restore o...
225
  static struct in_device *inetdev_init(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
  {
  	struct in_device *in_dev;
  
  	ASSERT_RTNL();
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
230
  	in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
232
  	if (!in_dev)
  		goto out;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
233
  	memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
9355bbd68   Pavel Emelyanov   [IPV4]: Switch us...
234
  			sizeof(in_dev->cnf));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
  	in_dev->cnf.sysctl = NULL;
  	in_dev->dev = dev;
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
237
238
  	in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
  	if (!in_dev->arp_parms)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
  		goto out_kfree;
0187bdfb0   Ben Hutchings   net: Disable LRO ...
240
241
  	if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
  		dev_disable_lro(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
  	/* Reference in_dev->dev */
  	dev_hold(dev);
30c4cf577   David L Stevens   [IPV4/IPV6]: Fix ...
244
  	/* Account for reference dev->ip_ptr (below) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
  	in_dev_hold(in_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246

66f27a520   Pavel Emelyanov   [IPV4]: Unify and...
247
  	devinet_sysctl_register(in_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
249
250
  	ip_mc_init_dev(in_dev);
  	if (dev->flags & IFF_UP)
  		ip_mc_up(in_dev);
483479ecc   Jarek Poplawski   [IPV4] devinet: i...
251

30c4cf577   David L Stevens   [IPV4/IPV6]: Fix ...
252
  	/* we can receive as soon as ip_ptr is set -- do this last */
cf778b00e   Eric Dumazet   net: reintroduce ...
253
  	rcu_assign_pointer(dev->ip_ptr, in_dev);
483479ecc   Jarek Poplawski   [IPV4] devinet: i...
254
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
  	return in_dev;
  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)
  {
  	struct in_ifaddr *ifa;
  	struct net_device *dev;
  
  	ASSERT_RTNL();
  
  	dev = in_dev->dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
279
280
281
282
283
284
  
  	in_dev->dead = 1;
  
  	ip_mc_destroy_dev(in_dev);
  
  	while ((ifa = in_dev->ifa_list) != NULL) {
  		inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
  		inet_free_ifa(ifa);
  	}
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
285
  	RCU_INIT_POINTER(dev->ip_ptr, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286

51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
287
  	devinet_sysctl_unregister(in_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
290
291
292
  	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...
293
  int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
296
297
298
299
300
301
302
303
304
305
306
  {
  	rcu_read_lock();
  	for_primary_ifa(in_dev) {
  		if (inet_ifa_match(a, ifa)) {
  			if (!b || inet_ifa_match(b, ifa)) {
  				rcu_read_unlock();
  				return 1;
  			}
  		}
  	} endfor_ifa(in_dev);
  	rcu_read_unlock();
  	return 0;
  }
d6062cbbd   Thomas Graf   [IPv4] address: C...
307
  static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
15e473046   Eric W. Biederman   netlink: Rename p...
308
  			 int destroy, struct nlmsghdr *nlh, u32 portid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  {
8f937c609   Harald Welte   [IPV4]: Primary a...
310
  	struct in_ifaddr *promote = NULL;
0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
311
312
313
314
  	struct in_ifaddr *ifa, *ifa1 = *ifap;
  	struct in_ifaddr *last_prim = in_dev->ifa_list;
  	struct in_ifaddr *prev_prom = NULL;
  	int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
  
  	ASSERT_RTNL();
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
317
  	/* 1. Deleting primary ifaddr forces deletion all secondaries
8f937c609   Harald Welte   [IPV4]: Primary a...
318
319
  	 * unless alias promotion is set
  	 **/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
321
  
  	if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
324
  		struct in_ifaddr **ifap1 = &ifa1->ifa_next;
  
  		while ((ifa = *ifap1) != NULL) {
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
325
  			if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
326
327
  			    ifa1->ifa_scope <= ifa->ifa_scope)
  				last_prim = ifa;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
330
331
  			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...
332
  				prev_prom = ifa;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
  				continue;
  			}
0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
335
  			if (!do_promote) {
fd23c3b31   David S. Miller   ipv4: Add hash ta...
336
  				inet_hash_remove(ifa);
8f937c609   Harald Welte   [IPV4]: Primary a...
337
  				*ifap1 = ifa->ifa_next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338

15e473046   Eric W. Biederman   netlink: Rename p...
339
  				rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
e041c6834   Alan Stern   [PATCH] Notifier ...
340
341
  				blocking_notifier_call_chain(&inetaddr_chain,
  						NETDEV_DOWN, ifa);
8f937c609   Harald Welte   [IPV4]: Primary a...
342
343
344
345
346
  				inet_free_ifa(ifa);
  			} else {
  				promote = ifa;
  				break;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
348
  		}
  	}
2d230e2b2   Julian Anastasov   ipv4: remove the ...
349
350
351
352
353
354
355
356
357
358
  	/* 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.
  	 */
  	for (ifa = promote; ifa; ifa = ifa->ifa_next) {
  		if (ifa1->ifa_mask == ifa->ifa_mask &&
  		    inet_ifa_match(ifa1->ifa_address, ifa))
  			fib_del_ifaddr(ifa, ifa1);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
361
  	/* 2. Unlink it */
  
  	*ifap = ifa1->ifa_next;
fd23c3b31   David S. Miller   ipv4: Add hash ta...
362
  	inet_hash_remove(ifa1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
365
366
367
368
369
370
371
372
373
  
  	/* 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...
374
  	rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
e041c6834   Alan Stern   [PATCH] Notifier ...
375
  	blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376

0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
377
  	if (promote) {
04024b937   Julian Anastasov   ipv4: optimize ro...
378
  		struct in_ifaddr *next_sec = promote->ifa_next;
0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
379
380
381
382
383
384
  
  		if (prev_prom) {
  			prev_prom->ifa_next = promote->ifa_next;
  			promote->ifa_next = last_prim->ifa_next;
  			last_prim->ifa_next = promote;
  		}
8f937c609   Harald Welte   [IPV4]: Primary a...
385

8f937c609   Harald Welte   [IPV4]: Primary a...
386
  		promote->ifa_flags &= ~IFA_F_SECONDARY;
15e473046   Eric W. Biederman   netlink: Rename p...
387
  		rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
e041c6834   Alan Stern   [PATCH] Notifier ...
388
389
  		blocking_notifier_call_chain(&inetaddr_chain,
  				NETDEV_UP, promote);
04024b937   Julian Anastasov   ipv4: optimize ro...
390
  		for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
391
392
393
394
395
396
397
  			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...
398
  	if (destroy)
0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
399
  		inet_free_ifa(ifa1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
  }
d6062cbbd   Thomas Graf   [IPv4] address: C...
401
402
403
404
405
  static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
  			 int destroy)
  {
  	__inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
  }
5c766d642   Jiri Pirko   ipv4: introduce a...
406
407
408
  static void check_lifetime(struct work_struct *work);
  
  static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
d6062cbbd   Thomas Graf   [IPv4] address: C...
409
  static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
15e473046   Eric W. Biederman   netlink: Rename p...
410
  			     u32 portid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
  {
  	struct in_device *in_dev = ifa->ifa_dev;
  	struct in_ifaddr *ifa1, **ifap, **last_primary;
  
  	ASSERT_RTNL();
  
  	if (!ifa->ifa_local) {
  		inet_free_ifa(ifa);
  		return 0;
  	}
  
  	ifa->ifa_flags &= ~IFA_F_SECONDARY;
  	last_primary = &in_dev->ifa_list;
  
  	for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
  	     ifap = &ifa1->ifa_next) {
  		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;
  		}
  	}
  
  	if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
63862b5be   Aruna-Hewapathirane   net: replace macr...
445
  		prandom_seed((__force u32) ifa->ifa_local);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
447
448
449
450
  		ifap = last_primary;
  	}
  
  	ifa->ifa_next = *ifap;
  	*ifap = ifa;
fd23c3b31   David S. Miller   ipv4: Add hash ta...
451
  	inet_hash_insert(dev_net(in_dev->dev), ifa);
5c766d642   Jiri Pirko   ipv4: introduce a...
452
  	cancel_delayed_work(&check_lifetime_work);
906e073f3   viresh kumar   net/ipv4: queue w...
453
  	queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
5c766d642   Jiri Pirko   ipv4: introduce a...
454

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
457
  	/* 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...
458
  	rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
e041c6834   Alan Stern   [PATCH] Notifier ...
459
  	blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
461
462
  
  	return 0;
  }
d6062cbbd   Thomas Graf   [IPv4] address: C...
463
464
465
466
  static int inet_insert_ifa(struct in_ifaddr *ifa)
  {
  	return __inet_insert_ifa(ifa, NULL, 0);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
  static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
  {
e5ed63991   Herbert Xu   [IPV4]: Replace _...
469
  	struct in_device *in_dev = __in_dev_get_rtnl(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
473
  
  	ASSERT_RTNL();
  
  	if (!in_dev) {
71e27da96   Herbert Xu   [IPV4]: Restore o...
474
475
  		inet_free_ifa(ifa);
  		return -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
  	}
71e27da96   Herbert Xu   [IPV4]: Restore o...
477
  	ipv4_devconf_setall(in_dev);
1d4c8c298   Jiri Pirko   neigh: restore ol...
478
  	neigh_parms_data_state_setall(in_dev->arp_parms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
  	if (ifa->ifa_dev != in_dev) {
547b792ca   Ilpo Järvinen   net: convert BUG_...
480
  		WARN_ON(ifa->ifa_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
482
483
  		in_dev_hold(in_dev);
  		ifa->ifa_dev = in_dev;
  	}
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
484
  	if (ipv4_is_loopback(ifa->ifa_local))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
486
487
  		ifa->ifa_scope = RT_SCOPE_HOST;
  	return inet_insert_ifa(ifa);
  }
8723e1b4a   Eric Dumazet   inet: RCU changes...
488
489
490
  /* Caller must hold RCU or RTNL :
   * We dont take a reference on found in_device
   */
7fee0ca23   Denis V. Lunev   [NETNS]: Add netn...
491
  struct in_device *inetdev_by_index(struct net *net, int ifindex)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
493
494
  {
  	struct net_device *dev;
  	struct in_device *in_dev = NULL;
c148fc2e3   Eric Dumazet   ipv4: inetdev_by_...
495
496
497
  
  	rcu_read_lock();
  	dev = dev_get_by_index_rcu(net, ifindex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
  	if (dev)
8723e1b4a   Eric Dumazet   inet: RCU changes...
499
  		in_dev = rcu_dereference_rtnl(dev->ip_ptr);
c148fc2e3   Eric Dumazet   ipv4: inetdev_by_...
500
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
502
  	return in_dev;
  }
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
503
  EXPORT_SYMBOL(inetdev_by_index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
505
  
  /* Called only from RTNL semaphored context. No locks. */
60cad5da5   Al Viro   [IPV4]: annotate ...
506
507
  struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
  				    __be32 mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
510
511
512
513
514
515
516
  {
  	ASSERT_RTNL();
  
  	for_primary_ifa(in_dev) {
  		if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
  			return ifa;
  	} endfor_ifa(in_dev);
  	return NULL;
  }
661d2967b   Thomas Graf   rtnetlink: Remove...
517
  static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
519
  	struct net *net = sock_net(skb->sk);
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
520
  	struct nlattr *tb[IFA_MAX+1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
  	struct in_device *in_dev;
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
522
  	struct ifaddrmsg *ifm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
  	struct in_ifaddr *ifa, **ifap;
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
524
  	int err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
  
  	ASSERT_RTNL();
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
527
528
529
530
531
  	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
  	if (err < 0)
  		goto errout;
  
  	ifm = nlmsg_data(nlh);
7fee0ca23   Denis V. Lunev   [NETNS]: Add netn...
532
  	in_dev = inetdev_by_index(net, ifm->ifa_index);
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
533
534
535
536
  	if (in_dev == NULL) {
  		err = -ENODEV;
  		goto errout;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
  	for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
  	     ifap = &ifa->ifa_next) {
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
539
  		if (tb[IFA_LOCAL] &&
a7a628c44   Al Viro   [IPV4]: IFA_{LOCA...
540
  		    ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
541
542
543
  			continue;
  
  		if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
  			continue;
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
545
546
547
  
  		if (tb[IFA_ADDRESS] &&
  		    (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
a7a628c44   Al Viro   [IPV4]: IFA_{LOCA...
548
  		    !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
549
  			continue;
15e473046   Eric W. Biederman   netlink: Rename p...
550
  		__inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
  		return 0;
  	}
dfdd5fd4e   Thomas Graf   [IPV4]: Convert a...
553
554
555
556
  
  	err = -EADDRNOTAVAIL;
  errout:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  }
5c766d642   Jiri Pirko   ipv4: introduce a...
558
559
560
561
562
563
  #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...
564
  	struct hlist_node *n;
5c766d642   Jiri Pirko   ipv4: introduce a...
565
566
567
568
  	int i;
  
  	now = jiffies;
  	next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
5c766d642   Jiri Pirko   ipv4: introduce a...
569
  	for (i = 0; i < IN4_ADDR_HSIZE; i++) {
c988d1e8c   Jiri Pirko   net: ipv4: fix sc...
570
571
572
  		bool change_needed = false;
  
  		rcu_read_lock();
b67bfe0d4   Sasha Levin   hlist: drop the n...
573
  		hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
5c766d642   Jiri Pirko   ipv4: introduce a...
574
575
576
577
578
579
580
581
582
583
584
  			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...
585
  				change_needed = true;
5c766d642   Jiri Pirko   ipv4: introduce a...
586
587
588
589
590
591
592
593
  			} 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...
594
595
  				if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
  					change_needed = true;
5c766d642   Jiri Pirko   ipv4: introduce a...
596
597
598
599
600
601
602
  			} 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...
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
  		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) {
  				struct in_ifaddr **ifap;
  
  				for (ifap = &ifa->ifa_dev->ifa_list;
  				     *ifap != NULL; ifap = &(*ifap)->ifa_next) {
  					if (*ifap == ifa) {
  						inet_del_ifa(ifa->ifa_dev,
  							     ifap, 1);
  						break;
  					}
  				}
  			} 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...
638
  	}
5c766d642   Jiri Pirko   ipv4: introduce a...
639
640
641
642
643
644
645
646
647
648
649
650
  
  	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...
651
652
  	queue_delayed_work(system_power_efficient_wq, &check_lifetime_work,
  			next_sched - now);
5c766d642   Jiri Pirko   ipv4: introduce a...
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
  }
  
  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,
  				       __u32 *pvalid_lft, __u32 *pprefered_lft)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
  {
5c7539781   Thomas Graf   [IPV4]: Convert a...
682
683
684
  	struct nlattr *tb[IFA_MAX+1];
  	struct in_ifaddr *ifa;
  	struct ifaddrmsg *ifm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
  	struct net_device *dev;
  	struct in_device *in_dev;
7b2185747   Denis V. Lunev   [IPV4]: Small sty...
687
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688

5c7539781   Thomas Graf   [IPV4]: Convert a...
689
690
691
  	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
  	if (err < 0)
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692

5c7539781   Thomas Graf   [IPV4]: Convert a...
693
  	ifm = nlmsg_data(nlh);
7b2185747   Denis V. Lunev   [IPV4]: Small sty...
694
695
  	err = -EINVAL;
  	if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL)
5c7539781   Thomas Graf   [IPV4]: Convert a...
696
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697

4b8aa9abe   Denis V. Lunev   [NETNS]: Process ...
698
  	dev = __dev_get_by_index(net, ifm->ifa_index);
7b2185747   Denis V. Lunev   [IPV4]: Small sty...
699
700
  	err = -ENODEV;
  	if (dev == NULL)
5c7539781   Thomas Graf   [IPV4]: Convert a...
701
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702

5c7539781   Thomas Graf   [IPV4]: Convert a...
703
  	in_dev = __in_dev_get_rtnl(dev);
7b2185747   Denis V. Lunev   [IPV4]: Small sty...
704
705
  	err = -ENOBUFS;
  	if (in_dev == NULL)
71e27da96   Herbert Xu   [IPV4]: Restore o...
706
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707

5c7539781   Thomas Graf   [IPV4]: Convert a...
708
  	ifa = inet_alloc_ifa();
7b2185747   Denis V. Lunev   [IPV4]: Small sty...
709
  	if (ifa == NULL)
5c7539781   Thomas Graf   [IPV4]: Convert a...
710
711
712
713
  		/*
  		 * 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...
714
  		goto errout;
5c7539781   Thomas Graf   [IPV4]: Convert a...
715

a4e65d36a   Pavel Emelyanov   [IPV4]: Swap the ...
716
  	ipv4_devconf_setall(in_dev);
1d4c8c298   Jiri Pirko   neigh: restore ol...
717
  	neigh_parms_data_state_setall(in_dev->arp_parms);
5c7539781   Thomas Graf   [IPV4]: Convert a...
718
719
720
721
  	in_dev_hold(in_dev);
  
  	if (tb[IFA_ADDRESS] == NULL)
  		tb[IFA_ADDRESS] = tb[IFA_LOCAL];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722

fd23c3b31   David S. Miller   ipv4: Add hash ta...
723
  	INIT_HLIST_NODE(&ifa->hash);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
725
  	ifa->ifa_prefixlen = ifm->ifa_prefixlen;
  	ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
ad6c81359   Jiri Pirko   ipv4: add support...
726
727
  	ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
  					 ifm->ifa_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
  	ifa->ifa_scope = ifm->ifa_scope;
5c7539781   Thomas Graf   [IPV4]: Convert a...
729
  	ifa->ifa_dev = in_dev;
a7a628c44   Al Viro   [IPV4]: IFA_{LOCA...
730
731
  	ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]);
  	ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]);
5c7539781   Thomas Graf   [IPV4]: Convert a...
732
733
  
  	if (tb[IFA_BROADCAST])
a7a628c44   Al Viro   [IPV4]: IFA_{LOCA...
734
  		ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);
5c7539781   Thomas Graf   [IPV4]: Convert a...
735

5c7539781   Thomas Graf   [IPV4]: Convert a...
736
737
  	if (tb[IFA_LABEL])
  		nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738
739
  	else
  		memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
5c766d642   Jiri Pirko   ipv4: introduce a...
740
741
742
743
744
745
  	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...
746
  			goto errout_free;
5c766d642   Jiri Pirko   ipv4: introduce a...
747
748
749
750
  		}
  		*pvalid_lft = ci->ifa_valid;
  		*pprefered_lft = ci->ifa_prefered;
  	}
5c7539781   Thomas Graf   [IPV4]: Convert a...
751
  	return ifa;
446266b0c   Daniel Borkmann   net: rtm_to_ifadd...
752
753
  errout_free:
  	inet_free_ifa(ifa);
5c7539781   Thomas Graf   [IPV4]: Convert a...
754
755
756
  errout:
  	return ERR_PTR(err);
  }
5c766d642   Jiri Pirko   ipv4: introduce a...
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
  static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
  {
  	struct in_device *in_dev = ifa->ifa_dev;
  	struct in_ifaddr *ifa1, **ifap;
  
  	if (!ifa->ifa_local)
  		return NULL;
  
  	for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
  	     ifap = &ifa1->ifa_next) {
  		if (ifa1->ifa_mask == ifa->ifa_mask &&
  		    inet_ifa_match(ifa1->ifa_address, ifa) &&
  		    ifa1->ifa_local == ifa->ifa_local)
  			return ifa1;
  	}
  	return NULL;
  }
661d2967b   Thomas Graf   rtnetlink: Remove...
774
  static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
5c7539781   Thomas Graf   [IPV4]: Convert a...
775
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
776
  	struct net *net = sock_net(skb->sk);
5c7539781   Thomas Graf   [IPV4]: Convert a...
777
  	struct in_ifaddr *ifa;
5c766d642   Jiri Pirko   ipv4: introduce a...
778
779
780
  	struct in_ifaddr *ifa_existing;
  	__u32 valid_lft = INFINITY_LIFE_TIME;
  	__u32 prefered_lft = INFINITY_LIFE_TIME;
5c7539781   Thomas Graf   [IPV4]: Convert a...
781
782
  
  	ASSERT_RTNL();
5c766d642   Jiri Pirko   ipv4: introduce a...
783
  	ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft);
5c7539781   Thomas Graf   [IPV4]: Convert a...
784
785
  	if (IS_ERR(ifa))
  		return PTR_ERR(ifa);
5c766d642   Jiri Pirko   ipv4: introduce a...
786
787
788
  	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...
789
  		 * userspace already relies on not having to provide this.
5c766d642   Jiri Pirko   ipv4: introduce a...
790
791
792
793
794
795
796
797
798
  		 */
  		set_ifa_lifetime(ifa, valid_lft, prefered_lft);
  		return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
  	} else {
  		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...
799
800
  		ifa = ifa_existing;
  		set_ifa_lifetime(ifa, valid_lft, prefered_lft);
05a324b9c   Jiri Pirko   net: ipv4: reset ...
801
  		cancel_delayed_work(&check_lifetime_work);
906e073f3   viresh kumar   net/ipv4: queue w...
802
803
  		queue_delayed_work(system_power_efficient_wq,
  				&check_lifetime_work, 0);
34e2ed34a   Jiri Pirko   net: ipv4: notify...
804
805
  		rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
  		blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
5c766d642   Jiri Pirko   ipv4: introduce a...
806
807
  	}
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
809
810
811
812
  }
  
  /*
   *	Determine a default network mask, based on the IP address.
   */
40384999d   Eric Dumazet   ipv4: change inet...
813
  static int inet_abc_len(__be32 addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
815
  {
  	int rc = -1;	/* Something else, probably a multicast. */
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
816
  	if (ipv4_is_zeronet(addr))
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
817
  		rc = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
  	else {
714e85be3   Al Viro   [IPV6]: Assorted ...
819
  		__u32 haddr = ntohl(addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820

714e85be3   Al Viro   [IPV6]: Assorted ...
821
  		if (IN_CLASSA(haddr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
  			rc = 8;
714e85be3   Al Viro   [IPV6]: Assorted ...
823
  		else if (IN_CLASSB(haddr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
  			rc = 16;
714e85be3   Al Viro   [IPV6]: Assorted ...
825
  		else if (IN_CLASSC(haddr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
827
  			rc = 24;
  	}
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
828
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
  }
e5b13cb10   Denis V. Lunev   [NETNS]: Process ...
830
  int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
  {
  	struct ifreq ifr;
  	struct sockaddr_in sin_orig;
  	struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
  	struct in_device *in_dev;
  	struct in_ifaddr **ifap = NULL;
  	struct in_ifaddr *ifa = NULL;
  	struct net_device *dev;
  	char *colon;
  	int ret = -EFAULT;
  	int tryaddrmatch = 0;
  
  	/*
  	 *	Fetch the caller's info block into kernel space
  	 */
  
  	if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
  		goto out;
  	ifr.ifr_name[IFNAMSIZ - 1] = 0;
  
  	/* save original address for comparison */
  	memcpy(&sin_orig, sin, sizeof(*sin));
  
  	colon = strchr(ifr.ifr_name, ':');
  	if (colon)
  		*colon = 0;
e5b13cb10   Denis V. Lunev   [NETNS]: Process ...
857
  	dev_load(net, ifr.ifr_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858

132adf546   Stephen Hemminger   [IPV4]: cleanup
859
  	switch (cmd) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
861
862
863
864
865
866
867
868
869
870
871
872
873
  	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...
874
  		ret = -EPERM;
52e804c6d   Eric W. Biederman   net: Allow userns...
875
  		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
877
878
879
880
881
  			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...
882
  		ret = -EPERM;
52e804c6d   Eric W. Biederman   net: Allow userns...
883
  		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884
885
886
887
888
889
890
891
892
893
894
895
896
  			goto out;
  		ret = -EINVAL;
  		if (sin->sin_family != AF_INET)
  			goto out;
  		break;
  	default:
  		ret = -EINVAL;
  		goto out;
  	}
  
  	rtnl_lock();
  
  	ret = -ENODEV;
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
897
898
  	dev = __dev_get_by_name(net, ifr.ifr_name);
  	if (!dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899
900
901
902
  		goto done;
  
  	if (colon)
  		*colon = ':';
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
903
904
  	in_dev = __in_dev_get_rtnl(dev);
  	if (in_dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
906
907
908
909
910
911
912
913
914
  		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. */
  			for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
  			     ifap = &ifa->ifa_next) {
  				if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
  				    sin_orig.sin_addr.s_addr ==
6c91afe1a   David S. Miller   ipv4: Fix erroneo...
915
  							ifa->ifa_local) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
  					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) {
  			for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
  			     ifap = &ifa->ifa_next)
  				if (!strcmp(ifr.ifr_name, ifa->ifa_label))
  					break;
  		}
  	}
  
  	ret = -EADDRNOTAVAIL;
  	if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
  		goto done;
132adf546   Stephen Hemminger   [IPV4]: cleanup
934
  	switch (cmd) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
  	case SIOCGIFADDR:	/* Get interface address */
  		sin->sin_addr.s_addr = ifa->ifa_local;
  		goto rarok;
  
  	case SIOCGIFBRDADDR:	/* Get the broadcast address */
  		sin->sin_addr.s_addr = ifa->ifa_broadcast;
  		goto rarok;
  
  	case SIOCGIFDSTADDR:	/* Get the destination address */
  		sin->sin_addr.s_addr = ifa->ifa_address;
  		goto rarok;
  
  	case SIOCGIFNETMASK:	/* Get the netmask for the interface */
  		sin->sin_addr.s_addr = ifa->ifa_mask;
  		goto rarok;
  
  	case SIOCSIFFLAGS:
  		if (colon) {
  			ret = -EADDRNOTAVAIL;
  			if (!ifa)
  				break;
  			ret = 0;
  			if (!(ifr.ifr_flags & IFF_UP))
  				inet_del_ifa(in_dev, ifap, 1);
  			break;
  		}
  		ret = dev_change_flags(dev, ifr.ifr_flags);
  		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...
971
972
  			ifa = inet_alloc_ifa();
  			if (!ifa)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
973
  				break;
c7e2e1d72   Xi Wang   ipv4: fix NULL ch...
974
  			INIT_HLIST_NODE(&ifa->hash);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975
976
977
978
979
980
981
982
983
984
  			if (colon)
  				memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
  			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...
985
  			ifa->ifa_scope = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
  		}
  
  		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...
1001
  		set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
  		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 ...
1037
  			__be32 old_mask = ifa->ifa_mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
  			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...
1051
  			     (ifa->ifa_local|~old_mask))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
  				ifa->ifa_broadcast = (ifa->ifa_local |
  						      ~sin->sin_addr.s_addr);
  			}
  			inet_insert_ifa(ifa);
  		}
  		break;
  	}
  done:
  	rtnl_unlock();
  out:
  	return ret;
  rarok:
  	rtnl_unlock();
  	ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
  	goto out;
  }
  
  static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
  {
e5ed63991   Herbert Xu   [IPV4]: Replace _...
1071
  	struct in_device *in_dev = __in_dev_get_rtnl(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1072
1073
1074
  	struct in_ifaddr *ifa;
  	struct ifreq ifr;
  	int done = 0;
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1075
  	if (!in_dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076
  		goto out;
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1077
  	for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1078
1079
1080
1081
1082
1083
1084
  		if (!buf) {
  			done += sizeof(ifr);
  			continue;
  		}
  		if (len < (int) sizeof(ifr))
  			break;
  		memset(&ifr, 0, sizeof(struct ifreq));
4299c8a94   Dan Carpenter   net: remove an un...
1085
  		strcpy(ifr.ifr_name, ifa->ifa_label);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
  
  		(*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
  		(*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
  								ifa->ifa_local;
  
  		if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
  			done = -EFAULT;
  			break;
  		}
  		buf  += sizeof(struct ifreq);
  		len  -= sizeof(struct ifreq);
  		done += sizeof(struct ifreq);
  	}
  out:
  	return done;
  }
a61ced5d1   Al Viro   [IPV4]: inet_sele...
1102
  __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103
  {
a61ced5d1   Al Viro   [IPV4]: inet_sele...
1104
  	__be32 addr = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105
  	struct in_device *in_dev;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1106
  	struct net *net = dev_net(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1107
1108
  
  	rcu_read_lock();
e5ed63991   Herbert Xu   [IPV4]: Replace _...
1109
  	in_dev = __in_dev_get_rcu(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
  	if (!in_dev)
  		goto no_in_dev;
  
  	for_primary_ifa(in_dev) {
  		if (ifa->ifa_scope > scope)
  			continue;
  		if (!dst || inet_ifa_match(dst, ifa)) {
  			addr = ifa->ifa_local;
  			break;
  		}
  		if (!addr)
  			addr = ifa->ifa_local;
  	} endfor_ifa(in_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1123
1124
  
  	if (addr)
c6d14c845   Eric Dumazet   net: Introduce fo...
1125
  		goto out_unlock;
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1126
  no_in_dev:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1127
1128
1129
1130
1131
  
  	/* Not loopback addresses on loopback should be preferred
  	   in this case. It is importnat that lo is the first interface
  	   in dev_base list.
  	 */
c6d14c845   Eric Dumazet   net: Introduce fo...
1132
  	for_each_netdev_rcu(net, dev) {
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1133
1134
  		in_dev = __in_dev_get_rcu(dev);
  		if (!in_dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1135
1136
1137
1138
1139
1140
  			continue;
  
  		for_primary_ifa(in_dev) {
  			if (ifa->ifa_scope != RT_SCOPE_LINK &&
  			    ifa->ifa_scope <= scope) {
  				addr = ifa->ifa_local;
c6d14c845   Eric Dumazet   net: Introduce fo...
1141
  				goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
1143
1144
  			}
  		} endfor_ifa(in_dev);
  	}
c6d14c845   Eric Dumazet   net: Introduce fo...
1145
  out_unlock:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1146
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147
1148
  	return addr;
  }
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1149
  EXPORT_SYMBOL(inet_select_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150

60cad5da5   Al Viro   [IPV4]: annotate ...
1151
1152
  static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
  			      __be32 local, int scope)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1153
1154
  {
  	int same = 0;
a144ea4b7   Al Viro   [IPV4]: annotate ...
1155
  	__be32 addr = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
  
  	for_ifa(in_dev) {
  		if (!addr &&
  		    (local == ifa->ifa_local || !local) &&
  		    ifa->ifa_scope <= scope) {
  			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? */
  				if (ifa->ifa_scope <= scope) {
  					addr = ifa->ifa_local;
  					break;
  				}
  				/* search for large dst subnet for addr */
  				same = 0;
  			}
  		}
  	} endfor_ifa(in_dev);
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1184
  	return same ? addr : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1185
1186
1187
1188
  }
  
  /*
   * Confirm that local IP address exists using wildcards:
b601fa197   Nicolas Dichtel   ipv4: fix wildcar...
1189
1190
   * - net: netns to check, cannot be NULL
   * - in_dev: only on this interface, NULL=any interface
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1191
1192
1193
1194
   * - 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...
1195
  __be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
9bd85e326   Denis V. Lunev   [IPV4]: Remove ex...
1196
  			 __be32 dst, __be32 local, int scope)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1197
  {
60cad5da5   Al Viro   [IPV4]: annotate ...
1198
  	__be32 addr = 0;
9bd85e326   Denis V. Lunev   [IPV4]: Remove ex...
1199
  	struct net_device *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1200

b601fa197   Nicolas Dichtel   ipv4: fix wildcar...
1201
  	if (in_dev != NULL)
9bd85e326   Denis V. Lunev   [IPV4]: Remove ex...
1202
  		return confirm_addr_indev(in_dev, dst, local, scope);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1203

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204
  	rcu_read_lock();
c6d14c845   Eric Dumazet   net: Introduce fo...
1205
  	for_each_netdev_rcu(net, dev) {
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1206
1207
  		in_dev = __in_dev_get_rcu(dev);
  		if (in_dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208
1209
1210
1211
1212
1213
  			addr = confirm_addr_indev(in_dev, dst, local, scope);
  			if (addr)
  				break;
  		}
  	}
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214
1215
1216
  
  	return addr;
  }
eaddcd769   Andy Gospodarek   bonding: remove e...
1217
  EXPORT_SYMBOL(inet_confirm_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1218
1219
1220
1221
1222
1223
1224
  
  /*
   *	Device notifier
   */
  
  int register_inetaddr_notifier(struct notifier_block *nb)
  {
e041c6834   Alan Stern   [PATCH] Notifier ...
1225
  	return blocking_notifier_chain_register(&inetaddr_chain, nb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1226
  }
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1227
  EXPORT_SYMBOL(register_inetaddr_notifier);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1228
1229
1230
  
  int unregister_inetaddr_notifier(struct notifier_block *nb)
  {
e041c6834   Alan Stern   [PATCH] Notifier ...
1231
  	return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232
  }
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1233
  EXPORT_SYMBOL(unregister_inetaddr_notifier);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1234

9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1235
1236
  /* 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
1237
1238
  */
  static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1239
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1240
1241
  	struct in_ifaddr *ifa;
  	int named = 0;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1242
1243
  	for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
  		char old[IFNAMSIZ], *dot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244
1245
  
  		memcpy(old, ifa->ifa_label, IFNAMSIZ);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1246
  		memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1247
  		if (named++ == 0)
573bf470e   Thomas Graf   ipv4 addr: Send n...
1248
  			goto skip;
44344b2a8   Mark McLoughlin   [INET]: Fix netde...
1249
  		dot = strchr(old, ':');
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1250
1251
  		if (dot == NULL) {
  			sprintf(old, ":%d", named);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1252
1253
  			dot = old;
  		}
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1254
  		if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1255
  			strcat(ifa->ifa_label, dot);
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1256
  		else
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1257
  			strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
573bf470e   Thomas Graf   ipv4 addr: Send n...
1258
1259
  skip:
  		rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1260
1261
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1262

40384999d   Eric Dumazet   ipv4: change inet...
1263
  static bool inetdev_valid_mtu(unsigned int mtu)
06770843c   Breno Leitao   ipv: Re-enable IP...
1264
1265
1266
  {
  	return mtu >= 68;
  }
d11327ad6   Ian Campbell   arp_notify: uncon...
1267
1268
1269
1270
  static void inetdev_send_gratuitous_arp(struct net_device *dev,
  					struct in_device *in_dev)
  
  {
b76d0789c   Zoltan Kiss   IPv4: Send gratui...
1271
  	struct in_ifaddr *ifa;
d11327ad6   Ian Campbell   arp_notify: uncon...
1272

b76d0789c   Zoltan Kiss   IPv4: Send gratui...
1273
1274
1275
1276
1277
1278
1279
  	for (ifa = in_dev->ifa_list; ifa;
  	     ifa = ifa->ifa_next) {
  		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...
1280
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1281
1282
1283
1284
1285
  /* 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...
1286
  	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
748e2d939   Eric Dumazet   net: reinstate rt...
1287
  	struct in_device *in_dev = __in_dev_get_rtnl(dev);
0115e8e30   Eric Dumazet   net: remove delay...
1288

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1289
1290
1291
  	ASSERT_RTNL();
  
  	if (!in_dev) {
8030f5449   Herbert Xu   [IPV4] devinet: R...
1292
  		if (event == NETDEV_REGISTER) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1293
  			in_dev = inetdev_init(dev);
b217d616a   Herbert Xu   [IPV4/IPV6]: Fail...
1294
1295
  			if (!in_dev)
  				return notifier_from_errno(-ENOMEM);
0cc217e16   Eric W. Biederman   [IPV4]: When poss...
1296
  			if (dev->flags & IFF_LOOPBACK) {
42f811b8b   Herbert Xu   [IPV4]: Convert I...
1297
1298
  				IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
  				IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
8030f5449   Herbert Xu   [IPV4] devinet: R...
1299
  			}
06770843c   Breno Leitao   ipv: Re-enable IP...
1300
1301
1302
1303
  		} 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
1304
1305
1306
1307
1308
1309
  		}
  		goto out;
  	}
  
  	switch (event) {
  	case NETDEV_REGISTER:
91df42bed   Joe Perches   net: ipv4 and ipv...
1310
1311
  		pr_debug("%s: bug
  ", __func__);
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
1312
  		RCU_INIT_POINTER(dev->ip_ptr, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1313
1314
  		break;
  	case NETDEV_UP:
06770843c   Breno Leitao   ipv: Re-enable IP...
1315
  		if (!inetdev_valid_mtu(dev->mtu))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1316
  			break;
0cc217e16   Eric W. Biederman   [IPV4]: When poss...
1317
  		if (dev->flags & IFF_LOOPBACK) {
9f9354b92   Eric Dumazet   net: net/ipv4/dev...
1318
1319
1320
  			struct in_ifaddr *ifa = inet_alloc_ifa();
  
  			if (ifa) {
fd23c3b31   David S. Miller   ipv4: Add hash ta...
1321
  				INIT_HLIST_NODE(&ifa->hash);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1322
1323
1324
1325
1326
1327
1328
1329
  				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...
1330
1331
  				set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
  						 INFINITY_LIFE_TIME);
dfd1582d1   Jiri Pirko   ipv4: loopback de...
1332
1333
  				ipv4_devconf_setall(in_dev);
  				neigh_parms_data_state_setall(in_dev->arp_parms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1334
1335
1336
1337
  				inet_insert_ifa(ifa);
  			}
  		}
  		ip_mc_up(in_dev);
eefef1cf7   Stephen Hemminger   net: add ARP noti...
1338
1339
  		/* fall through */
  	case NETDEV_CHANGEADDR:
d11327ad6   Ian Campbell   arp_notify: uncon...
1340
1341
1342
1343
  		if (!IN_DEV_ARP_NOTIFY(in_dev))
  			break;
  		/* fall through */
  	case NETDEV_NOTIFY_PEERS:
a21090cff   Stephen Hemminger   ipv4: arp_notify ...
1344
  		/* Send gratuitous ARP to notify of link change */
d11327ad6   Ian Campbell   arp_notify: uncon...
1345
  		inetdev_send_gratuitous_arp(dev, in_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1346
1347
1348
1349
  		break;
  	case NETDEV_DOWN:
  		ip_mc_down(in_dev);
  		break;
93d9b7d7a   Jiri Pirko   net: rename notif...
1350
  	case NETDEV_PRE_TYPE_CHANGE:
75c78500d   Moni Shoua   bonding: remap mu...
1351
1352
  		ip_mc_unmap(in_dev);
  		break;
93d9b7d7a   Jiri Pirko   net: rename notif...
1353
  	case NETDEV_POST_TYPE_CHANGE:
75c78500d   Moni Shoua   bonding: remap mu...
1354
1355
  		ip_mc_remap(in_dev);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1356
  	case NETDEV_CHANGEMTU:
06770843c   Breno Leitao   ipv: Re-enable IP...
1357
  		if (inetdev_valid_mtu(dev->mtu))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1358
  			break;
06770843c   Breno Leitao   ipv: Re-enable IP...
1359
  		/* disable IP when MTU is not enough */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1360
1361
1362
1363
1364
1365
1366
1367
  	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...
1368
  		devinet_sysctl_unregister(in_dev);
66f27a520   Pavel Emelyanov   [IPV4]: Unify and...
1369
  		devinet_sysctl_register(in_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1370
1371
1372
1373
1374
1375
1376
  		break;
  	}
  out:
  	return NOTIFY_DONE;
  }
  
  static struct notifier_block ip_netdev_notifier = {
539afedfc   Jianjun Kong   net: clean up net...
1377
  	.notifier_call = inetdev_event,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1378
  };
40384999d   Eric Dumazet   ipv4: change inet...
1379
  static size_t inet_nlmsg_size(void)
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
1380
1381
1382
1383
1384
  {
  	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...
1385
  	       + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
63b5f152e   Geert Uytterhoeven   ipv4: Fix runtime...
1386
1387
  	       + nla_total_size(4)  /* IFA_FLAGS */
  	       + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
1388
  }
5c766d642   Jiri Pirko   ipv4: introduce a...
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
  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
1406
  static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
15e473046   Eric W. Biederman   netlink: Rename p...
1407
  			    u32 portid, u32 seq, int event, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1408
1409
1410
  {
  	struct ifaddrmsg *ifm;
  	struct nlmsghdr  *nlh;
5c766d642   Jiri Pirko   ipv4: introduce a...
1411
  	u32 preferred, valid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412

15e473046   Eric W. Biederman   netlink: Rename p...
1413
  	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
47f68512d   Thomas Graf   [IPV4]: Convert a...
1414
  	if (nlh == NULL)
26932566a   Patrick McHardy   [NETLINK]: Don't ...
1415
  		return -EMSGSIZE;
47f68512d   Thomas Graf   [IPV4]: Convert a...
1416
1417
  
  	ifm = nlmsg_data(nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1418
1419
  	ifm->ifa_family = AF_INET;
  	ifm->ifa_prefixlen = ifa->ifa_prefixlen;
5c766d642   Jiri Pirko   ipv4: introduce a...
1420
  	ifm->ifa_flags = ifa->ifa_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1421
1422
  	ifm->ifa_scope = ifa->ifa_scope;
  	ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
47f68512d   Thomas Graf   [IPV4]: Convert a...
1423

5c766d642   Jiri Pirko   ipv4: introduce a...
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
  	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 ...
1445
1446
1447
1448
1449
1450
1451
  	if ((ifa->ifa_address &&
  	     nla_put_be32(skb, IFA_ADDRESS, ifa->ifa_address)) ||
  	    (ifa->ifa_local &&
  	     nla_put_be32(skb, IFA_LOCAL, ifa->ifa_local)) ||
  	    (ifa->ifa_broadcast &&
  	     nla_put_be32(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
  	    (ifa->ifa_label[0] &&
5c766d642   Jiri Pirko   ipv4: introduce a...
1452
  	     nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
ad6c81359   Jiri Pirko   ipv4: add support...
1453
  	    nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
5c766d642   Jiri Pirko   ipv4: introduce a...
1454
1455
  	    put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
  			  preferred, valid))
f3756b79e   David S. Miller   ipv4: Stop using ...
1456
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1457

47f68512d   Thomas Graf   [IPV4]: Convert a...
1458
1459
1460
  	return nlmsg_end(skb, nlh);
  
  nla_put_failure:
26932566a   Patrick McHardy   [NETLINK]: Don't ...
1461
1462
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1463
1464
1465
1466
  }
  
  static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1467
  	struct net *net = sock_net(skb->sk);
eec4df988   Eric Dumazet   ipv4: speedup ine...
1468
1469
1470
  	int h, s_h;
  	int idx, s_idx;
  	int ip_idx, s_ip_idx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1471
1472
1473
  	struct net_device *dev;
  	struct in_device *in_dev;
  	struct in_ifaddr *ifa;
eec4df988   Eric Dumazet   ipv4: speedup ine...
1474
  	struct hlist_head *head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1475

eec4df988   Eric Dumazet   ipv4: speedup ine...
1476
1477
1478
1479
1480
1481
1482
1483
  	s_h = cb->args[0];
  	s_idx = idx = cb->args[1];
  	s_ip_idx = ip_idx = cb->args[2];
  
  	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...
1484
1485
  		cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
  			  net->dev_base_seq;
b67bfe0d4   Sasha Levin   hlist: drop the n...
1486
  		hlist_for_each_entry_rcu(dev, head, index_hlist) {
eec4df988   Eric Dumazet   ipv4: speedup ine...
1487
1488
  			if (idx < s_idx)
  				goto cont;
4b97efdf3   Patrick McHardy   net: fix netlink ...
1489
  			if (h > s_h || idx > s_idx)
eec4df988   Eric Dumazet   ipv4: speedup ine...
1490
1491
1492
1493
  				s_ip_idx = 0;
  			in_dev = __in_dev_get_rcu(dev);
  			if (!in_dev)
  				goto cont;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1494

eec4df988   Eric Dumazet   ipv4: speedup ine...
1495
1496
1497
1498
1499
  			for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
  			     ifa = ifa->ifa_next, ip_idx++) {
  				if (ip_idx < s_ip_idx)
  					continue;
  				if (inet_fill_ifaddr(skb, ifa,
15e473046   Eric W. Biederman   netlink: Rename p...
1500
  					     NETLINK_CB(cb->skb).portid,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1501
  					     cb->nlh->nlmsg_seq,
eec4df988   Eric Dumazet   ipv4: speedup ine...
1502
1503
1504
1505
  					     RTM_NEWADDR, NLM_F_MULTI) <= 0) {
  					rcu_read_unlock();
  					goto done;
  				}
0465277f6   Nicolas Dichtel   ipv4: provide add...
1506
  				nl_dump_check_consistent(cb, nlmsg_hdr(skb));
eec4df988   Eric Dumazet   ipv4: speedup ine...
1507
  			}
7562f876c   Pavel Emelianov   [NET]: Rework dev...
1508
  cont:
eec4df988   Eric Dumazet   ipv4: speedup ine...
1509
1510
1511
  			idx++;
  		}
  		rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1512
1513
1514
  	}
  
  done:
eec4df988   Eric Dumazet   ipv4: speedup ine...
1515
1516
1517
  	cb->args[0] = h;
  	cb->args[1] = idx;
  	cb->args[2] = ip_idx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1518
1519
1520
  
  	return skb->len;
  }
539afedfc   Jianjun Kong   net: clean up net...
1521
  static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
15e473046   Eric W. Biederman   netlink: Rename p...
1522
  		      u32 portid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1523
  {
47f68512d   Thomas Graf   [IPV4]: Convert a...
1524
  	struct sk_buff *skb;
d6062cbbd   Thomas Graf   [IPv4] address: C...
1525
1526
  	u32 seq = nlh ? nlh->nlmsg_seq : 0;
  	int err = -ENOBUFS;
4b8aa9abe   Denis V. Lunev   [NETNS]: Process ...
1527
  	struct net *net;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1528

c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1529
  	net = dev_net(ifa->ifa_dev->dev);
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
1530
  	skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
47f68512d   Thomas Graf   [IPV4]: Convert a...
1531
  	if (skb == NULL)
d6062cbbd   Thomas Graf   [IPv4] address: C...
1532
  		goto errout;
15e473046   Eric W. Biederman   netlink: Rename p...
1533
  	err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0);
26932566a   Patrick McHardy   [NETLINK]: Don't ...
1534
1535
1536
1537
1538
1539
  	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...
1540
  	rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
1ce85fe40   Pablo Neira Ayuso   netlink: change n...
1541
  	return;
d6062cbbd   Thomas Graf   [IPv4] address: C...
1542
1543
  errout:
  	if (err < 0)
4b8aa9abe   Denis V. Lunev   [NETNS]: Process ...
1544
  		rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1545
  }
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
1546
1547
  static size_t inet_get_link_af_size(const struct net_device *dev)
  {
1fc19aff8   Eric Dumazet   net: fix two lock...
1548
  	struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
1549
1550
1551
1552
1553
1554
1555
1556
1557
  
  	if (!in_dev)
  		return 0;
  
  	return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
  }
  
  static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
  {
1fc19aff8   Eric Dumazet   net: fix two lock...
1558
  	struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
  	struct nlattr *nla;
  	int i;
  
  	if (!in_dev)
  		return -ENODATA;
  
  	nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
  	if (nla == NULL)
  		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...
1578
1579
  static int inet_validate_link_af(const struct net_device *dev,
  				 const struct nlattr *nla)
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
1580
  {
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
1581
1582
  	struct nlattr *a, *tb[IFLA_INET_MAX+1];
  	int err, rem;
f7fce74e3   Eric Dumazet   net: kill an RCU ...
1583
  	if (dev && !__in_dev_get_rtnl(dev))
cf7afbfeb   Thomas Graf   rtnl: make link a...
1584
  		return -EAFNOSUPPORT;
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
  
  	err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy);
  	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...
1601
1602
1603
1604
1605
  	return 0;
  }
  
  static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
  {
f7fce74e3   Eric Dumazet   net: kill an RCU ...
1606
  	struct in_device *in_dev = __in_dev_get_rtnl(dev);
cf7afbfeb   Thomas Graf   rtnl: make link a...
1607
1608
1609
1610
1611
1612
1613
1614
  	struct nlattr *a, *tb[IFLA_INET_MAX+1];
  	int rem;
  
  	if (!in_dev)
  		return -EAFNOSUPPORT;
  
  	if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL) < 0)
  		BUG();
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
1615
1616
1617
1618
1619
1620
1621
  	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...
1622
1623
1624
1625
  static int inet_netconf_msgsize_devconf(int type)
  {
  	int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
  		   + nla_total_size(4);	/* NETCONFA_IFINDEX */
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
1626
1627
  	/* type -1 is used for ALL */
  	if (type == -1 || type == NETCONFA_FORWARDING)
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1628
  		size += nla_total_size(4);
cc535dfb6   Nicolas Dichtel   rtnl/ipv4: use ne...
1629
1630
  	if (type == -1 || type == NETCONFA_RP_FILTER)
  		size += nla_total_size(4);
d67b8c616   Nicolas Dichtel   netconf: advertis...
1631
1632
  	if (type == -1 || type == NETCONFA_MC_FORWARDING)
  		size += nla_total_size(4);
09aea5df7   stephen hemminger   netconf: rename P...
1633
  	if (type == -1 || type == NETCONFA_PROXY_NEIGH)
f085ff1c1   stephen hemminger   netconf: add prox...
1634
  		size += nla_total_size(4);
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
  
  	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;
  
  	nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
  			flags);
  	if (nlh == NULL)
  		return -EMSGSIZE;
  
  	ncm = nlmsg_data(nlh);
  	ncm->ncm_family = AF_INET;
  
  	if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
  		goto nla_put_failure;
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
1657
1658
  	/* type -1 is used for ALL */
  	if ((type == -1 || type == NETCONFA_FORWARDING) &&
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1659
1660
1661
  	    nla_put_s32(skb, NETCONFA_FORWARDING,
  			IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
  		goto nla_put_failure;
cc535dfb6   Nicolas Dichtel   rtnl/ipv4: use ne...
1662
1663
1664
1665
  	if ((type == -1 || type == NETCONFA_RP_FILTER) &&
  	    nla_put_s32(skb, NETCONFA_RP_FILTER,
  			IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
  		goto nla_put_failure;
d67b8c616   Nicolas Dichtel   netconf: advertis...
1666
1667
1668
1669
  	if ((type == -1 || type == NETCONFA_MC_FORWARDING) &&
  	    nla_put_s32(skb, NETCONFA_MC_FORWARDING,
  			IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
  		goto nla_put_failure;
09aea5df7   stephen hemminger   netconf: rename P...
1670
1671
  	if ((type == -1 || type == NETCONFA_PROXY_NEIGH) &&
  	    nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
f085ff1c1   stephen hemminger   netconf: add prox...
1672
1673
  			IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
  		goto nla_put_failure;
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1674
1675
1676
1677
1678
1679
1680
  
  	return nlmsg_end(skb, nlh);
  
  nla_put_failure:
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
  }
d67b8c616   Nicolas Dichtel   netconf: advertis...
1681
1682
  void inet_netconf_notify_devconf(struct net *net, int type, int ifindex,
  				 struct ipv4_devconf *devconf)
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
  {
  	struct sk_buff *skb;
  	int err = -ENOBUFS;
  
  	skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_ATOMIC);
  	if (skb == NULL)
  		goto errout;
  
  	err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
  					RTM_NEWNETCONF, 0, type);
  	if (err < 0) {
  		/* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
  		WARN_ON(err == -EMSGSIZE);
  		kfree_skb(skb);
  		goto errout;
  	}
  	rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_ATOMIC);
  	return;
  errout:
  	if (err < 0)
  		rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
  }
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
1705
1706
1707
  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...
1708
  	[NETCONFA_RP_FILTER]	= { .len = sizeof(int) },
09aea5df7   stephen hemminger   netconf: rename P...
1709
  	[NETCONFA_PROXY_NEIGH]	= { .len = sizeof(int) },
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
1710
1711
1712
  };
  
  static int inet_netconf_get_devconf(struct sk_buff *in_skb,
661d2967b   Thomas Graf   rtnetlink: Remove...
1713
  				    struct nlmsghdr *nlh)
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
  {
  	struct net *net = sock_net(in_skb->sk);
  	struct nlattr *tb[NETCONFA_MAX+1];
  	struct netconfmsg *ncm;
  	struct sk_buff *skb;
  	struct ipv4_devconf *devconf;
  	struct in_device *in_dev;
  	struct net_device *dev;
  	int ifindex;
  	int err;
  
  	err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
  			  devconf_ipv4_policy);
  	if (err < 0)
  		goto errout;
  
  	err = EINVAL;
  	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);
  		if (dev == NULL)
  			goto errout;
  		in_dev = __in_dev_get_rtnl(dev);
  		if (in_dev == NULL)
  			goto errout;
  		devconf = &in_dev->cnf;
  		break;
  	}
  
  	err = -ENOBUFS;
  	skb = nlmsg_new(inet_netconf_msgsize_devconf(-1), GFP_ATOMIC);
  	if (skb == NULL)
  		goto errout;
  
  	err = inet_netconf_fill_devconf(skb, ifindex, devconf,
  					NETLINK_CB(in_skb).portid,
  					nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
  					-1);
  	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 ...
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
  static int inet_netconf_dump_devconf(struct sk_buff *skb,
  				     struct netlink_callback *cb)
  {
  	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;
  
  	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...
1789
1790
  		cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
  			  net->dev_base_seq;
7a6742003   Nicolas Dichtel   netconf: add the ...
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
  		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,
  						      cb->nlh->nlmsg_seq,
  						      RTM_NEWNETCONF,
  						      NLM_F_MULTI,
  						      -1) <= 0) {
  				rcu_read_unlock();
  				goto done;
  			}
0465277f6   Nicolas Dichtel   ipv4: provide add...
1808
  			nl_dump_check_consistent(cb, nlmsg_hdr(skb));
7a6742003   Nicolas Dichtel   netconf: add the ...
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
  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,
  					      cb->nlh->nlmsg_seq,
  					      RTM_NEWNETCONF, NLM_F_MULTI,
  					      -1) <= 0)
  			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,
  					      cb->nlh->nlmsg_seq,
  					      RTM_NEWNETCONF, NLM_F_MULTI,
  					      -1) <= 0)
  			goto done;
  		else
  			h++;
  	}
  done:
  	cb->args[0] = h;
  	cb->args[1] = idx;
  
  	return skb->len;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1842
  #ifdef CONFIG_SYSCTL
c0ce9fb30   Pavel Emelyanov   [IPV4]: Store the...
1843
  static void devinet_copy_dflt_conf(struct net *net, int i)
31be30854   Herbert Xu   [IPV4]: Add defau...
1844
1845
  {
  	struct net_device *dev;
c6d14c845   Eric Dumazet   net: Introduce fo...
1846
1847
  	rcu_read_lock();
  	for_each_netdev_rcu(net, dev) {
31be30854   Herbert Xu   [IPV4]: Add defau...
1848
  		struct in_device *in_dev;
c6d14c845   Eric Dumazet   net: Introduce fo...
1849

31be30854   Herbert Xu   [IPV4]: Add defau...
1850
1851
  		in_dev = __in_dev_get_rcu(dev);
  		if (in_dev && !test_bit(i, in_dev->cnf.state))
9355bbd68   Pavel Emelyanov   [IPV4]: Switch us...
1852
  			in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
31be30854   Herbert Xu   [IPV4]: Add defau...
1853
  	}
c6d14c845   Eric Dumazet   net: Introduce fo...
1854
  	rcu_read_unlock();
31be30854   Herbert Xu   [IPV4]: Add defau...
1855
  }
c6d14c845   Eric Dumazet   net: Introduce fo...
1856
  /* called with RTNL locked */
c0ce9fb30   Pavel Emelyanov   [IPV4]: Store the...
1857
  static void inet_forward_change(struct net *net)
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
1858
1859
  {
  	struct net_device *dev;
586f12115   Pavel Emelyanov   [IPV4]: Switch us...
1860
  	int on = IPV4_DEVCONF_ALL(net, FORWARDING);
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
1861

586f12115   Pavel Emelyanov   [IPV4]: Switch us...
1862
  	IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
9355bbd68   Pavel Emelyanov   [IPV4]: Switch us...
1863
  	IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1864
1865
1866
1867
1868
1869
  	inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
  				    NETCONFA_IFINDEX_ALL,
  				    net->ipv4.devconf_all);
  	inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
  				    NETCONFA_IFINDEX_DEFAULT,
  				    net->ipv4.devconf_dflt);
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
1870

c0ce9fb30   Pavel Emelyanov   [IPV4]: Store the...
1871
  	for_each_netdev(net, dev) {
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
1872
  		struct in_device *in_dev;
0187bdfb0   Ben Hutchings   net: Disable LRO ...
1873
1874
  		if (on)
  			dev_disable_lro(dev);
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
1875
1876
  		rcu_read_lock();
  		in_dev = __in_dev_get_rcu(dev);
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1877
  		if (in_dev) {
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
1878
  			IN_DEV_CONF_SET(in_dev, FORWARDING, on);
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1879
1880
1881
  			inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
  						    dev->ifindex, &in_dev->cnf);
  		}
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
1882
1883
  		rcu_read_unlock();
  	}
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
1884
  }
f085ff1c1   stephen hemminger   netconf: add prox...
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
  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...
1897
  static int devinet_conf_proc(struct ctl_table *ctl, int write,
8d65af789   Alexey Dobriyan   sysctl: remove "s...
1898
  			     void __user *buffer,
31be30854   Herbert Xu   [IPV4]: Add defau...
1899
1900
  			     size_t *lenp, loff_t *ppos)
  {
d01ff0a04   Peter Pan(潘卫平)   ipv4: flush route...
1901
  	int old_value = *(int *)ctl->data;
8d65af789   Alexey Dobriyan   sysctl: remove "s...
1902
  	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
d01ff0a04   Peter Pan(潘卫平)   ipv4: flush route...
1903
  	int new_value = *(int *)ctl->data;
31be30854   Herbert Xu   [IPV4]: Add defau...
1904
1905
1906
  
  	if (write) {
  		struct ipv4_devconf *cnf = ctl->extra1;
c0ce9fb30   Pavel Emelyanov   [IPV4]: Store the...
1907
  		struct net *net = ctl->extra2;
31be30854   Herbert Xu   [IPV4]: Add defau...
1908
  		int i = (int *)ctl->data - cnf->data;
f085ff1c1   stephen hemminger   netconf: add prox...
1909
  		int ifindex;
31be30854   Herbert Xu   [IPV4]: Add defau...
1910
1911
  
  		set_bit(i, cnf->state);
9355bbd68   Pavel Emelyanov   [IPV4]: Switch us...
1912
  		if (cnf == net->ipv4.devconf_dflt)
c0ce9fb30   Pavel Emelyanov   [IPV4]: Store the...
1913
  			devinet_copy_dflt_conf(net, i);
d0daebc3d   Thomas Graf   ipv4: Add interfa...
1914
1915
  		if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
  		    i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
d01ff0a04   Peter Pan(潘卫平)   ipv4: flush route...
1916
  			if ((new_value == 0) && (old_value != 0))
4ccfe6d41   Nicolas Dichtel   ipv4/route: arg d...
1917
  				rt_cache_flush(net);
f085ff1c1   stephen hemminger   netconf: add prox...
1918

cc535dfb6   Nicolas Dichtel   rtnl/ipv4: use ne...
1919
1920
  		if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
  		    new_value != old_value) {
f085ff1c1   stephen hemminger   netconf: add prox...
1921
  			ifindex = devinet_conf_ifindex(net, cnf);
cc535dfb6   Nicolas Dichtel   rtnl/ipv4: use ne...
1922
1923
1924
  			inet_netconf_notify_devconf(net, NETCONFA_RP_FILTER,
  						    ifindex, cnf);
  		}
f085ff1c1   stephen hemminger   netconf: add prox...
1925
1926
1927
  		if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
  		    new_value != old_value) {
  			ifindex = devinet_conf_ifindex(net, cnf);
09aea5df7   stephen hemminger   netconf: rename P...
1928
  			inet_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH,
f085ff1c1   stephen hemminger   netconf: add prox...
1929
1930
  						    ifindex, cnf);
  		}
31be30854   Herbert Xu   [IPV4]: Add defau...
1931
1932
1933
1934
  	}
  
  	return ret;
  }
fe2c6338f   Joe Perches   net: Convert uses...
1935
  static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
8d65af789   Alexey Dobriyan   sysctl: remove "s...
1936
  				  void __user *buffer,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1937
1938
1939
1940
  				  size_t *lenp, loff_t *ppos)
  {
  	int *valp = ctl->data;
  	int val = *valp;
88af182e3   Eric W. Biederman   net: Fix sysctl r...
1941
  	loff_t pos = *ppos;
8d65af789   Alexey Dobriyan   sysctl: remove "s...
1942
  	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1943
1944
  
  	if (write && *valp != val) {
c0ce9fb30   Pavel Emelyanov   [IPV4]: Store the...
1945
  		struct net *net = ctl->extra2;
0187bdfb0   Ben Hutchings   net: Disable LRO ...
1946
  		if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
88af182e3   Eric W. Biederman   net: Fix sysctl r...
1947
1948
1949
1950
  			if (!rtnl_trylock()) {
  				/* Restore the original values before restarting */
  				*valp = val;
  				*ppos = pos;
9b8adb5ea   Eric W. Biederman   net: Fix devinet_...
1951
  				return restart_syscall();
88af182e3   Eric W. Biederman   net: Fix sysctl r...
1952
  			}
0187bdfb0   Ben Hutchings   net: Disable LRO ...
1953
1954
  			if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
  				inet_forward_change(net);
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1955
  			} else {
0187bdfb0   Ben Hutchings   net: Disable LRO ...
1956
1957
1958
  				struct ipv4_devconf *cnf = ctl->extra1;
  				struct in_device *idev =
  					container_of(cnf, struct in_device, cnf);
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1959
1960
1961
1962
1963
1964
  				if (*valp)
  					dev_disable_lro(idev->dev);
  				inet_netconf_notify_devconf(net,
  							    NETCONFA_FORWARDING,
  							    idev->dev->ifindex,
  							    cnf);
0187bdfb0   Ben Hutchings   net: Disable LRO ...
1965
1966
  			}
  			rtnl_unlock();
4ccfe6d41   Nicolas Dichtel   ipv4/route: arg d...
1967
  			rt_cache_flush(net);
edc9e7489   Nicolas Dichtel   rtnl/ipv4: use ne...
1968
1969
1970
1971
  		} else
  			inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
  						    NETCONFA_IFINDEX_DEFAULT,
  						    net->ipv4.devconf_dflt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1972
1973
1974
1975
  	}
  
  	return ret;
  }
fe2c6338f   Joe Perches   net: Convert uses...
1976
  static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
323e126f0   David S. Miller   ipv4: Don't pre-s...
1977
1978
  				void __user *buffer,
  				size_t *lenp, loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1979
1980
1981
  {
  	int *valp = ctl->data;
  	int val = *valp;
8d65af789   Alexey Dobriyan   sysctl: remove "s...
1982
  	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
76e6ebfb4   Denis V. Lunev   netns: add namesp...
1983
  	struct net *net = ctl->extra2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1984
1985
  
  	if (write && *valp != val)
4ccfe6d41   Nicolas Dichtel   ipv4/route: arg d...
1986
  		rt_cache_flush(net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1987
1988
1989
  
  	return ret;
  }
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
1990
  #define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
42f811b8b   Herbert Xu   [IPV4]: Convert I...
1991
  	{ \
42f811b8b   Herbert Xu   [IPV4]: Convert I...
1992
1993
  		.procname	= name, \
  		.data		= ipv4_devconf.data + \
02291680f   Eric W. Biederman   net ipv4: Decoupl...
1994
  				  IPV4_DEVCONF_ ## attr - 1, \
42f811b8b   Herbert Xu   [IPV4]: Convert I...
1995
1996
1997
  		.maxlen		= sizeof(int), \
  		.mode		= mval, \
  		.proc_handler	= proc, \
31be30854   Herbert Xu   [IPV4]: Add defau...
1998
  		.extra1		= &ipv4_devconf, \
42f811b8b   Herbert Xu   [IPV4]: Convert I...
1999
2000
2001
  	}
  
  #define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2002
  	DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2003
2004
  
  #define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2005
  	DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2006

f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2007
2008
  #define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
  	DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2009
2010
  
  #define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2011
  	DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2012

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2013
2014
  static struct devinet_sysctl_table {
  	struct ctl_table_header *sysctl_header;
02291680f   Eric W. Biederman   net ipv4: Decoupl...
2015
  	struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2016
2017
  } devinet_sysctl = {
  	.devinet_vars = {
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2018
  		DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2019
  					     devinet_sysctl_forward),
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2020
2021
2022
2023
2024
2025
2026
2027
2028
  		DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
  
  		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...
2029
  		DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
28f6aeea3   Jamal Hadi Salim   net: restore ip s...
2030
  		DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2031
2032
2033
2034
2035
2036
2037
2038
2039
  		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...
2040
  		DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
65324144b   Jesper Dangaard Brouer   net: RFC3069, pri...
2041
  		DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
5c6fe01c1   William Manley   net: igmp: Don't ...
2042
2043
  		DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
  					"force_igmp_version"),
2690048c0   William Manley   net: igmp: Allow ...
2044
2045
2046
2047
  		DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
  					"igmpv2_unsolicited_report_interval"),
  		DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
  					"igmpv3_unsolicited_report_interval"),
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2048
2049
2050
  
  		DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
  		DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2051
2052
  		DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
  					      "promote_secondaries"),
d0daebc3d   Thomas Graf   ipv4: Add interfa...
2053
2054
  		DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
  					      "route_localnet"),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2055
  	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2056
  };
ea40b324d   Pavel Emelyanov   [IPV4]: Make __de...
2057
  static int __devinet_sysctl_register(struct net *net, char *dev_name,
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2058
  					struct ipv4_devconf *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2059
2060
  {
  	int i;
9fa896429   Pavel Emelyanov   [IPV4]: Cleanup t...
2061
  	struct devinet_sysctl_table *t;
8607ddb86   Eric W. Biederman   net ipv4: Convert...
2062
  	char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
bfada697b   Pavel Emelyanov   [IPV4]: Use ctl p...
2063

9fa896429   Pavel Emelyanov   [IPV4]: Cleanup t...
2064
  	t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2065
  	if (!t)
9fa896429   Pavel Emelyanov   [IPV4]: Cleanup t...
2066
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2067
2068
  	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...
2069
  		t->devinet_vars[i].extra1 = p;
c0ce9fb30   Pavel Emelyanov   [IPV4]: Store the...
2070
  		t->devinet_vars[i].extra2 = net;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2071
  	}
8607ddb86   Eric W. Biederman   net ipv4: Convert...
2072
  	snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2073

8607ddb86   Eric W. Biederman   net ipv4: Convert...
2074
  	t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2075
  	if (!t->sysctl_header)
8607ddb86   Eric W. Biederman   net ipv4: Convert...
2076
  		goto free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2077
2078
  
  	p->sysctl = t;
ea40b324d   Pavel Emelyanov   [IPV4]: Make __de...
2079
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2080

9fa896429   Pavel Emelyanov   [IPV4]: Cleanup t...
2081
  free:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2082
  	kfree(t);
9fa896429   Pavel Emelyanov   [IPV4]: Cleanup t...
2083
  out:
ea40b324d   Pavel Emelyanov   [IPV4]: Make __de...
2084
  	return -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2085
  }
51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
2086
2087
2088
2089
2090
2091
2092
2093
  static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
  {
  	struct devinet_sysctl_table *t = cnf->sysctl;
  
  	if (t == NULL)
  		return;
  
  	cnf->sysctl = NULL;
ff538818f   Lucian Adrian Grijincu   sysctl: net: call...
2094
  	unregister_net_sysctl_table(t->sysctl_header);
51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
2095
2096
  	kfree(t);
  }
66f27a520   Pavel Emelyanov   [IPV4]: Unify and...
2097
2098
  static void devinet_sysctl_register(struct in_device *idev)
  {
73af614ae   Jiri Pirko   neigh: use tbl->f...
2099
  	neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2100
  	__devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2101
  					&idev->cnf);
66f27a520   Pavel Emelyanov   [IPV4]: Unify and...
2102
  }
51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
2103
  static void devinet_sysctl_unregister(struct in_device *idev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2104
  {
51602b2a5   Pavel Emelyanov   [IPV4]: Cleanup s...
2105
2106
  	__devinet_sysctl_unregister(&idev->cnf);
  	neigh_sysctl_unregister(idev->arp_parms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2107
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2108

68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2109
2110
  static struct ctl_table ctl_forward_entry[] = {
  	{
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2111
2112
  		.procname	= "ip_forward",
  		.data		= &ipv4_devconf.data[
02291680f   Eric W. Biederman   net ipv4: Decoupl...
2113
  					IPV4_DEVCONF_FORWARDING - 1],
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2114
2115
2116
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
  		.proc_handler	= devinet_sysctl_forward,
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2117
  		.extra1		= &ipv4_devconf,
c0ce9fb30   Pavel Emelyanov   [IPV4]: Store the...
2118
  		.extra2		= &init_net,
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2119
2120
2121
  	},
  	{ },
  };
2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2122
  #endif
68dd299bc   Pavel Emelyanov   [INET]: Merge sys...
2123

752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2124
2125
2126
  static __net_init int devinet_init_net(struct net *net)
  {
  	int err;
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2127
  	struct ipv4_devconf *all, *dflt;
2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2128
2129
  #ifdef CONFIG_SYSCTL
  	struct ctl_table *tbl = ctl_forward_entry;
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2130
  	struct ctl_table_header *forw_hdr;
2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2131
  #endif
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2132
2133
2134
2135
  
  	err = -ENOMEM;
  	all = &ipv4_devconf;
  	dflt = &ipv4_devconf_dflt;
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2136

09ad9bc75   Octavian Purdila   net: use net_eq t...
2137
  	if (!net_eq(net, &init_net)) {
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2138
2139
2140
2141
2142
2143
2144
  		all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
  		if (all == NULL)
  			goto err_alloc_all;
  
  		dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
  		if (dflt == NULL)
  			goto err_alloc_dflt;
2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2145
  #ifdef CONFIG_SYSCTL
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2146
2147
2148
  		tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
  		if (tbl == NULL)
  			goto err_alloc_ctl;
02291680f   Eric W. Biederman   net ipv4: Decoupl...
2149
  		tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2150
2151
  		tbl[0].extra1 = all;
  		tbl[0].extra2 = net;
2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2152
  #endif
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2153
2154
2155
  	}
  
  #ifdef CONFIG_SYSCTL
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2156
  	err = __devinet_sysctl_register(net, "all", all);
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2157
2158
  	if (err < 0)
  		goto err_reg_all;
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2159
  	err = __devinet_sysctl_register(net, "default", dflt);
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2160
2161
2162
2163
  	if (err < 0)
  		goto err_reg_dflt;
  
  	err = -ENOMEM;
8607ddb86   Eric W. Biederman   net ipv4: Convert...
2164
  	forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2165
2166
  	if (forw_hdr == NULL)
  		goto err_reg_ctl;
2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2167
  	net->ipv4.forw_hdr = forw_hdr;
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2168
  #endif
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
  	net->ipv4.devconf_all = all;
  	net->ipv4.devconf_dflt = dflt;
  	return 0;
  
  #ifdef CONFIG_SYSCTL
  err_reg_ctl:
  	__devinet_sysctl_unregister(dflt);
  err_reg_dflt:
  	__devinet_sysctl_unregister(all);
  err_reg_all:
  	if (tbl != ctl_forward_entry)
  		kfree(tbl);
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2181
  err_alloc_ctl:
2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2182
  #endif
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
  	if (dflt != &ipv4_devconf_dflt)
  		kfree(dflt);
  err_alloc_dflt:
  	if (all != &ipv4_devconf)
  		kfree(all);
  err_alloc_all:
  	return err;
  }
  
  static __net_exit void devinet_exit_net(struct net *net)
  {
2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2194
  #ifdef CONFIG_SYSCTL
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2195
2196
2197
  	struct ctl_table *tbl;
  
  	tbl = net->ipv4.forw_hdr->ctl_table_arg;
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2198
2199
2200
  	unregister_net_sysctl_table(net->ipv4.forw_hdr);
  	__devinet_sysctl_unregister(net->ipv4.devconf_dflt);
  	__devinet_sysctl_unregister(net->ipv4.devconf_all);
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2201
  	kfree(tbl);
2a75de0c1   Eric Dumazet   [NETNS]: Should b...
2202
  #endif
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2203
2204
2205
2206
2207
2208
2209
2210
  	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,
  };
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
2211
2212
2213
2214
  static struct rtnl_af_ops inet_af_ops = {
  	.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...
2215
2216
  	.validate_link_af = inet_validate_link_af,
  	.set_link_af	  = inet_set_link_af,
9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
2217
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2218
2219
  void __init devinet_init(void)
  {
fd23c3b31   David S. Miller   ipv4: Add hash ta...
2220
2221
2222
2223
  	int i;
  
  	for (i = 0; i < IN4_ADDR_HSIZE; i++)
  		INIT_HLIST_HEAD(&inet_addr_lst[i]);
752d14dc6   Pavel Emelyanov   [IPV4]: Move the ...
2224
  	register_pernet_subsys(&devinet_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2225
2226
  	register_gifconf(PF_INET, inet_gifconf);
  	register_netdevice_notifier(&ip_netdev_notifier);
63f3444fb   Thomas Graf   [IPv4]: Use rtnl ...
2227

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

9f0f7272a   Thomas Graf   ipv4: AF_INET lin...
2230
  	rtnl_af_register(&inet_af_ops);
c7ac8679b   Greg Rose   rtnetlink: Comput...
2231
2232
2233
  	rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL);
  	rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, NULL);
  	rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, NULL);
9e5511106   Nicolas Dichtel   rtnl/ipv4: add su...
2234
  	rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
7a6742003   Nicolas Dichtel   netconf: add the ...
2235
  		      inet_netconf_dump_devconf, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2236
  }