blob: a3a7d301736e20768acb0af555446ef61c0e0230 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * NET3 IP device support routines.
3 *
4 * Version: $Id: devinet.c,v 1.44 2001/10/31 21:55:54 davem Exp $
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 * Derived from the IP parts of dev.c 1.0.19
Jesper Juhl02c30a82005-05-05 16:16:16 -070012 * Authors: Ross Biro
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
14 * Mark Evans, <evansmp@uhura.aston.ac.uk>
15 *
16 * Additional Authors:
17 * Alan Cox, <gw4pts@gw4pts.ampr.org>
18 * Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
19 *
20 * Changes:
21 * Alexey Kuznetsov: pa_* fields are replaced with ifaddr
22 * lists.
23 * Cyrus Durgin: updated for kmod
24 * Matthias Andree: in devinet_ioctl, compare label and
25 * address (4.4BSD alias style support),
26 * fall back to comparing just the label
27 * if no match found.
28 */
29
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
31#include <asm/uaccess.h>
32#include <asm/system.h>
33#include <linux/bitops.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080034#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/module.h>
36#include <linux/types.h>
37#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/string.h>
39#include <linux/mm.h>
40#include <linux/socket.h>
41#include <linux/sockios.h>
42#include <linux/in.h>
43#include <linux/errno.h>
44#include <linux/interrupt.h>
Thomas Graf18237302006-08-04 23:04:54 -070045#include <linux/if_addr.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <linux/if_ether.h>
47#include <linux/inet.h>
48#include <linux/netdevice.h>
49#include <linux/etherdevice.h>
50#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <linux/init.h>
52#include <linux/notifier.h>
53#include <linux/inetdevice.h>
54#include <linux/igmp.h>
55#ifdef CONFIG_SYSCTL
56#include <linux/sysctl.h>
57#endif
58#include <linux/kmod.h>
59
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020060#include <net/arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <net/ip.h>
62#include <net/route.h>
63#include <net/ip_fib.h>
Thomas Graf63f34442007-03-22 11:55:17 -070064#include <net/rtnetlink.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66struct ipv4_devconf ipv4_devconf = {
Herbert Xu42f811b2007-06-04 23:34:44 -070067 .data = {
68 [NET_IPV4_CONF_ACCEPT_REDIRECTS - 1] = 1,
69 [NET_IPV4_CONF_SEND_REDIRECTS - 1] = 1,
70 [NET_IPV4_CONF_SECURE_REDIRECTS - 1] = 1,
71 [NET_IPV4_CONF_SHARED_MEDIA - 1] = 1,
72 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070073};
74
75static struct ipv4_devconf ipv4_devconf_dflt = {
Herbert Xu42f811b2007-06-04 23:34:44 -070076 .data = {
77 [NET_IPV4_CONF_ACCEPT_REDIRECTS - 1] = 1,
78 [NET_IPV4_CONF_SEND_REDIRECTS - 1] = 1,
79 [NET_IPV4_CONF_SECURE_REDIRECTS - 1] = 1,
80 [NET_IPV4_CONF_SHARED_MEDIA - 1] = 1,
81 [NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
82 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070083};
84
Herbert Xu42f811b2007-06-04 23:34:44 -070085#define IPV4_DEVCONF_DFLT(attr) IPV4_DEVCONF(ipv4_devconf_dflt, attr)
86
Patrick McHardyef7c79e2007-06-05 12:38:30 -070087static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
Thomas Graf5c753972006-08-04 23:03:53 -070088 [IFA_LOCAL] = { .type = NLA_U32 },
89 [IFA_ADDRESS] = { .type = NLA_U32 },
90 [IFA_BROADCAST] = { .type = NLA_U32 },
91 [IFA_ANYCAST] = { .type = NLA_U32 },
Thomas Graf5176f912006-08-26 20:13:18 -070092 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
Thomas Graf5c753972006-08-04 23:03:53 -070093};
94
Thomas Grafd6062cb2006-08-15 00:33:59 -070095static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Alan Sterne041c682006-03-27 01:16:30 -080097static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
99 int destroy);
100#ifdef CONFIG_SYSCTL
Pavel Emelyanov66f27a52007-12-02 00:55:54 +1100101static void devinet_sysctl_register(struct in_device *idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102static void devinet_sysctl_unregister(struct ipv4_devconf *p);
103#endif
104
105/* Locks all the inet devices. */
106
107static struct in_ifaddr *inet_alloc_ifa(void)
108{
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700109 struct in_ifaddr *ifa = kzalloc(sizeof(*ifa), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
111 if (ifa) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 INIT_RCU_HEAD(&ifa->rcu_head);
113 }
114
115 return ifa;
116}
117
118static void inet_rcu_free_ifa(struct rcu_head *head)
119{
120 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
121 if (ifa->ifa_dev)
122 in_dev_put(ifa->ifa_dev);
123 kfree(ifa);
124}
125
126static inline void inet_free_ifa(struct in_ifaddr *ifa)
127{
128 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
129}
130
131void in_dev_finish_destroy(struct in_device *idev)
132{
133 struct net_device *dev = idev->dev;
134
135 BUG_TRAP(!idev->ifa_list);
136 BUG_TRAP(!idev->mc_list);
137#ifdef NET_REFCNT_DEBUG
138 printk(KERN_DEBUG "in_dev_finish_destroy: %p=%s\n",
139 idev, dev ? dev->name : "NIL");
140#endif
141 dev_put(dev);
142 if (!idev->dead)
143 printk("Freeing alive in_device %p\n", idev);
144 else {
145 kfree(idev);
146 }
147}
148
Herbert Xu71e27da2007-06-04 23:36:06 -0700149static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150{
151 struct in_device *in_dev;
152
153 ASSERT_RTNL();
154
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700155 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 if (!in_dev)
157 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 INIT_RCU_HEAD(&in_dev->rcu_head);
159 memcpy(&in_dev->cnf, &ipv4_devconf_dflt, sizeof(in_dev->cnf));
160 in_dev->cnf.sysctl = NULL;
161 in_dev->dev = dev;
162 if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL)
163 goto out_kfree;
164 /* Reference in_dev->dev */
165 dev_hold(dev);
166#ifdef CONFIG_SYSCTL
167 neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
168 NET_IPV4_NEIGH, "ipv4", NULL, NULL);
169#endif
170
David L Stevens30c4cf52007-01-04 12:31:14 -0800171 /* Account for reference dev->ip_ptr (below) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 in_dev_hold(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
174#ifdef CONFIG_SYSCTL
Pavel Emelyanov66f27a52007-12-02 00:55:54 +1100175 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176#endif
177 ip_mc_init_dev(in_dev);
178 if (dev->flags & IFF_UP)
179 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800180
David L Stevens30c4cf52007-01-04 12:31:14 -0800181 /* we can receive as soon as ip_ptr is set -- do this last */
182 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800183out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 return in_dev;
185out_kfree:
186 kfree(in_dev);
187 in_dev = NULL;
188 goto out;
189}
190
191static void in_dev_rcu_put(struct rcu_head *head)
192{
193 struct in_device *idev = container_of(head, struct in_device, rcu_head);
194 in_dev_put(idev);
195}
196
197static void inetdev_destroy(struct in_device *in_dev)
198{
199 struct in_ifaddr *ifa;
200 struct net_device *dev;
201
202 ASSERT_RTNL();
203
204 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
206 in_dev->dead = 1;
207
208 ip_mc_destroy_dev(in_dev);
209
210 while ((ifa = in_dev->ifa_list) != NULL) {
211 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
212 inet_free_ifa(ifa);
213 }
214
215#ifdef CONFIG_SYSCTL
216 devinet_sysctl_unregister(&in_dev->cnf);
217#endif
218
219 dev->ip_ptr = NULL;
220
221#ifdef CONFIG_SYSCTL
222 neigh_sysctl_unregister(in_dev->arp_parms);
223#endif
224 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
225 arp_ifdown(dev);
226
227 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
228}
229
Al Viroff428d72006-09-26 22:13:35 -0700230int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
232 rcu_read_lock();
233 for_primary_ifa(in_dev) {
234 if (inet_ifa_match(a, ifa)) {
235 if (!b || inet_ifa_match(b, ifa)) {
236 rcu_read_unlock();
237 return 1;
238 }
239 }
240 } endfor_ifa(in_dev);
241 rcu_read_unlock();
242 return 0;
243}
244
Thomas Grafd6062cb2006-08-15 00:33:59 -0700245static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
246 int destroy, struct nlmsghdr *nlh, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247{
Harald Welte8f937c62005-05-29 20:23:46 -0700248 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800249 struct in_ifaddr *ifa, *ifa1 = *ifap;
250 struct in_ifaddr *last_prim = in_dev->ifa_list;
251 struct in_ifaddr *prev_prom = NULL;
252 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
254 ASSERT_RTNL();
255
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900256 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700257 * unless alias promotion is set
258 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
260 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
262
263 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900264 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800265 ifa1->ifa_scope <= ifa->ifa_scope)
266 last_prim = ifa;
267
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
269 ifa1->ifa_mask != ifa->ifa_mask ||
270 !inet_ifa_match(ifa1->ifa_address, ifa)) {
271 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800272 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 continue;
274 }
275
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800276 if (!do_promote) {
Harald Welte8f937c62005-05-29 20:23:46 -0700277 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Thomas Grafd6062cb2006-08-15 00:33:59 -0700279 rtmsg_ifa(RTM_DELADDR, ifa, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800280 blocking_notifier_call_chain(&inetaddr_chain,
281 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700282 inet_free_ifa(ifa);
283 } else {
284 promote = ifa;
285 break;
286 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 }
288 }
289
290 /* 2. Unlink it */
291
292 *ifap = ifa1->ifa_next;
293
294 /* 3. Announce address deletion */
295
296 /* Send message first, then call notifier.
297 At first sight, FIB update triggered by notifier
298 will refer to already deleted ifaddr, that could confuse
299 netlink listeners. It is not true: look, gated sees
300 that route deleted and if it still thinks that ifaddr
301 is valid, it will try to restore deleted routes... Grr.
302 So that, this order is correct.
303 */
Thomas Grafd6062cb2006-08-15 00:33:59 -0700304 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800305 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800306
307 if (promote) {
308
309 if (prev_prom) {
310 prev_prom->ifa_next = promote->ifa_next;
311 promote->ifa_next = last_prim->ifa_next;
312 last_prim->ifa_next = promote;
313 }
314
315 promote->ifa_flags &= ~IFA_F_SECONDARY;
Thomas Grafd6062cb2006-08-15 00:33:59 -0700316 rtmsg_ifa(RTM_NEWADDR, promote, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800317 blocking_notifier_call_chain(&inetaddr_chain,
318 NETDEV_UP, promote);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800319 for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) {
320 if (ifa1->ifa_mask != ifa->ifa_mask ||
321 !inet_ifa_match(ifa1->ifa_address, ifa))
322 continue;
323 fib_add_ifaddr(ifa);
324 }
325
326 }
Herbert Xu63630972007-06-07 18:35:38 -0700327 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329}
330
Thomas Grafd6062cb2006-08-15 00:33:59 -0700331static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
332 int destroy)
333{
334 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
335}
336
337static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
338 u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
340 struct in_device *in_dev = ifa->ifa_dev;
341 struct in_ifaddr *ifa1, **ifap, **last_primary;
342
343 ASSERT_RTNL();
344
345 if (!ifa->ifa_local) {
346 inet_free_ifa(ifa);
347 return 0;
348 }
349
350 ifa->ifa_flags &= ~IFA_F_SECONDARY;
351 last_primary = &in_dev->ifa_list;
352
353 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
354 ifap = &ifa1->ifa_next) {
355 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
356 ifa->ifa_scope <= ifa1->ifa_scope)
357 last_primary = &ifa1->ifa_next;
358 if (ifa1->ifa_mask == ifa->ifa_mask &&
359 inet_ifa_match(ifa1->ifa_address, ifa)) {
360 if (ifa1->ifa_local == ifa->ifa_local) {
361 inet_free_ifa(ifa);
362 return -EEXIST;
363 }
364 if (ifa1->ifa_scope != ifa->ifa_scope) {
365 inet_free_ifa(ifa);
366 return -EINVAL;
367 }
368 ifa->ifa_flags |= IFA_F_SECONDARY;
369 }
370 }
371
372 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
373 net_srandom(ifa->ifa_local);
374 ifap = last_primary;
375 }
376
377 ifa->ifa_next = *ifap;
378 *ifap = ifa;
379
380 /* Send message first, then call notifier.
381 Notifier will trigger FIB update, so that
382 listeners of netlink will know about new ifaddr */
Thomas Grafd6062cb2006-08-15 00:33:59 -0700383 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800384 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
386 return 0;
387}
388
Thomas Grafd6062cb2006-08-15 00:33:59 -0700389static int inet_insert_ifa(struct in_ifaddr *ifa)
390{
391 return __inet_insert_ifa(ifa, NULL, 0);
392}
393
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
395{
Herbert Xue5ed6392005-10-03 14:35:55 -0700396 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
398 ASSERT_RTNL();
399
400 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700401 inet_free_ifa(ifa);
402 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700404 ipv4_devconf_setall(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 if (ifa->ifa_dev != in_dev) {
406 BUG_TRAP(!ifa->ifa_dev);
407 in_dev_hold(in_dev);
408 ifa->ifa_dev = in_dev;
409 }
410 if (LOOPBACK(ifa->ifa_local))
411 ifa->ifa_scope = RT_SCOPE_HOST;
412 return inet_insert_ifa(ifa);
413}
414
415struct in_device *inetdev_by_index(int ifindex)
416{
417 struct net_device *dev;
418 struct in_device *in_dev = NULL;
419 read_lock(&dev_base_lock);
Eric W. Biederman881d9662007-09-17 11:56:21 -0700420 dev = __dev_get_by_index(&init_net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 if (dev)
422 in_dev = in_dev_get(dev);
423 read_unlock(&dev_base_lock);
424 return in_dev;
425}
426
427/* Called only from RTNL semaphored context. No locks. */
428
Al Viro60cad5d2006-09-26 22:17:09 -0700429struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
430 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431{
432 ASSERT_RTNL();
433
434 for_primary_ifa(in_dev) {
435 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
436 return ifa;
437 } endfor_ifa(in_dev);
438 return NULL;
439}
440
441static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
442{
Denis V. Lunevb8542722007-12-01 00:21:31 +1100443 struct net *net = skb->sk->sk_net;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700444 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700446 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700448 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
450 ASSERT_RTNL();
451
Denis V. Lunevb8542722007-12-01 00:21:31 +1100452 if (net != &init_net)
453 return -EINVAL;
454
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700455 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
456 if (err < 0)
457 goto errout;
458
459 ifm = nlmsg_data(nlh);
460 in_dev = inetdev_by_index(ifm->ifa_index);
461 if (in_dev == NULL) {
462 err = -ENODEV;
463 goto errout;
464 }
465
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 __in_dev_put(in_dev);
467
468 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
469 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700470 if (tb[IFA_LOCAL] &&
Al Viroa7a628c2006-09-26 22:16:43 -0700471 ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700473
474 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
475 continue;
476
477 if (tb[IFA_ADDRESS] &&
478 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Al Viroa7a628c2006-09-26 22:16:43 -0700479 !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700480 continue;
481
Thomas Grafd6062cb2006-08-15 00:33:59 -0700482 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 return 0;
484 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700485
486 err = -EADDRNOTAVAIL;
487errout:
488 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489}
490
Thomas Graf5c753972006-08-04 23:03:53 -0700491static struct in_ifaddr *rtm_to_ifaddr(struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492{
Thomas Graf5c753972006-08-04 23:03:53 -0700493 struct nlattr *tb[IFA_MAX+1];
494 struct in_ifaddr *ifa;
495 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 struct net_device *dev;
497 struct in_device *in_dev;
Thomas Graf5c753972006-08-04 23:03:53 -0700498 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
Thomas Graf5c753972006-08-04 23:03:53 -0700500 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
501 if (err < 0)
502 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
Thomas Graf5c753972006-08-04 23:03:53 -0700504 ifm = nlmsg_data(nlh);
Evgeniy Polyakovc4e38f42007-03-09 13:43:24 -0800505 if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL) {
506 err = -EINVAL;
Thomas Graf5c753972006-08-04 23:03:53 -0700507 goto errout;
Evgeniy Polyakovc4e38f42007-03-09 13:43:24 -0800508 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
Eric W. Biederman881d9662007-09-17 11:56:21 -0700510 dev = __dev_get_by_index(&init_net, ifm->ifa_index);
Thomas Graf5c753972006-08-04 23:03:53 -0700511 if (dev == NULL) {
512 err = -ENODEV;
513 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 }
515
Thomas Graf5c753972006-08-04 23:03:53 -0700516 in_dev = __in_dev_get_rtnl(dev);
517 if (in_dev == NULL) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700518 err = -ENOBUFS;
519 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
Thomas Graf5c753972006-08-04 23:03:53 -0700522 ifa = inet_alloc_ifa();
523 if (ifa == NULL) {
524 /*
525 * A potential indev allocation can be left alive, it stays
526 * assigned to its device and is destroy with it.
527 */
528 err = -ENOBUFS;
529 goto errout;
530 }
531
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800532 ipv4_devconf_setall(in_dev);
Thomas Graf5c753972006-08-04 23:03:53 -0700533 in_dev_hold(in_dev);
534
535 if (tb[IFA_ADDRESS] == NULL)
536 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
537
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
539 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 ifa->ifa_flags = ifm->ifa_flags;
541 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700542 ifa->ifa_dev = in_dev;
543
Al Viroa7a628c2006-09-26 22:16:43 -0700544 ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]);
545 ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700546
547 if (tb[IFA_BROADCAST])
Al Viroa7a628c2006-09-26 22:16:43 -0700548 ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700549
550 if (tb[IFA_ANYCAST])
Al Viroa7a628c2006-09-26 22:16:43 -0700551 ifa->ifa_anycast = nla_get_be32(tb[IFA_ANYCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700552
553 if (tb[IFA_LABEL])
554 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 else
556 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
557
Thomas Graf5c753972006-08-04 23:03:53 -0700558 return ifa;
559
560errout:
561 return ERR_PTR(err);
562}
563
564static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
565{
Denis V. Lunevb8542722007-12-01 00:21:31 +1100566 struct net *net = skb->sk->sk_net;
Thomas Graf5c753972006-08-04 23:03:53 -0700567 struct in_ifaddr *ifa;
568
569 ASSERT_RTNL();
570
Denis V. Lunevb8542722007-12-01 00:21:31 +1100571 if (net != &init_net)
572 return -EINVAL;
573
Thomas Graf5c753972006-08-04 23:03:53 -0700574 ifa = rtm_to_ifaddr(nlh);
575 if (IS_ERR(ifa))
576 return PTR_ERR(ifa);
577
Thomas Grafd6062cb2006-08-15 00:33:59 -0700578 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579}
580
581/*
582 * Determine a default network mask, based on the IP address.
583 */
584
Al Viro714e85b2006-11-14 20:51:49 -0800585static __inline__ int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586{
587 int rc = -1; /* Something else, probably a multicast. */
588
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900589 if (ZERONET(addr))
590 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 else {
Al Viro714e85b2006-11-14 20:51:49 -0800592 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
Al Viro714e85b2006-11-14 20:51:49 -0800594 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800596 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800598 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 rc = 24;
600 }
601
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900602 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603}
604
605
606int devinet_ioctl(unsigned int cmd, void __user *arg)
607{
608 struct ifreq ifr;
609 struct sockaddr_in sin_orig;
610 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
611 struct in_device *in_dev;
612 struct in_ifaddr **ifap = NULL;
613 struct in_ifaddr *ifa = NULL;
614 struct net_device *dev;
615 char *colon;
616 int ret = -EFAULT;
617 int tryaddrmatch = 0;
618
619 /*
620 * Fetch the caller's info block into kernel space
621 */
622
623 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
624 goto out;
625 ifr.ifr_name[IFNAMSIZ - 1] = 0;
626
627 /* save original address for comparison */
628 memcpy(&sin_orig, sin, sizeof(*sin));
629
630 colon = strchr(ifr.ifr_name, ':');
631 if (colon)
632 *colon = 0;
633
634#ifdef CONFIG_KMOD
Eric W. Biederman881d9662007-09-17 11:56:21 -0700635 dev_load(&init_net, ifr.ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636#endif
637
Stephen Hemminger132adf52007-03-08 20:44:43 -0800638 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 case SIOCGIFADDR: /* Get interface address */
640 case SIOCGIFBRDADDR: /* Get the broadcast address */
641 case SIOCGIFDSTADDR: /* Get the destination address */
642 case SIOCGIFNETMASK: /* Get the netmask for the interface */
643 /* Note that these ioctls will not sleep,
644 so that we do not impose a lock.
645 One day we will be forced to put shlock here (I mean SMP)
646 */
647 tryaddrmatch = (sin_orig.sin_family == AF_INET);
648 memset(sin, 0, sizeof(*sin));
649 sin->sin_family = AF_INET;
650 break;
651
652 case SIOCSIFFLAGS:
653 ret = -EACCES;
654 if (!capable(CAP_NET_ADMIN))
655 goto out;
656 break;
657 case SIOCSIFADDR: /* Set interface address (and family) */
658 case SIOCSIFBRDADDR: /* Set the broadcast address */
659 case SIOCSIFDSTADDR: /* Set the destination address */
660 case SIOCSIFNETMASK: /* Set the netmask for the interface */
661 ret = -EACCES;
662 if (!capable(CAP_NET_ADMIN))
663 goto out;
664 ret = -EINVAL;
665 if (sin->sin_family != AF_INET)
666 goto out;
667 break;
668 default:
669 ret = -EINVAL;
670 goto out;
671 }
672
673 rtnl_lock();
674
675 ret = -ENODEV;
Eric W. Biederman881d9662007-09-17 11:56:21 -0700676 if ((dev = __dev_get_by_name(&init_net, ifr.ifr_name)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 goto done;
678
679 if (colon)
680 *colon = ':';
681
Herbert Xue5ed6392005-10-03 14:35:55 -0700682 if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 if (tryaddrmatch) {
684 /* Matthias Andree */
685 /* compare label and address (4.4BSD style) */
686 /* note: we only do this for a limited set of ioctls
687 and only if the original address family was AF_INET.
688 This is checked above. */
689 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
690 ifap = &ifa->ifa_next) {
691 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
692 sin_orig.sin_addr.s_addr ==
693 ifa->ifa_address) {
694 break; /* found */
695 }
696 }
697 }
698 /* we didn't get a match, maybe the application is
699 4.3BSD-style and passed in junk so we fall back to
700 comparing just the label */
701 if (!ifa) {
702 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
703 ifap = &ifa->ifa_next)
704 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
705 break;
706 }
707 }
708
709 ret = -EADDRNOTAVAIL;
710 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
711 goto done;
712
Stephen Hemminger132adf52007-03-08 20:44:43 -0800713 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 case SIOCGIFADDR: /* Get interface address */
715 sin->sin_addr.s_addr = ifa->ifa_local;
716 goto rarok;
717
718 case SIOCGIFBRDADDR: /* Get the broadcast address */
719 sin->sin_addr.s_addr = ifa->ifa_broadcast;
720 goto rarok;
721
722 case SIOCGIFDSTADDR: /* Get the destination address */
723 sin->sin_addr.s_addr = ifa->ifa_address;
724 goto rarok;
725
726 case SIOCGIFNETMASK: /* Get the netmask for the interface */
727 sin->sin_addr.s_addr = ifa->ifa_mask;
728 goto rarok;
729
730 case SIOCSIFFLAGS:
731 if (colon) {
732 ret = -EADDRNOTAVAIL;
733 if (!ifa)
734 break;
735 ret = 0;
736 if (!(ifr.ifr_flags & IFF_UP))
737 inet_del_ifa(in_dev, ifap, 1);
738 break;
739 }
740 ret = dev_change_flags(dev, ifr.ifr_flags);
741 break;
742
743 case SIOCSIFADDR: /* Set interface address (and family) */
744 ret = -EINVAL;
745 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
746 break;
747
748 if (!ifa) {
749 ret = -ENOBUFS;
750 if ((ifa = inet_alloc_ifa()) == NULL)
751 break;
752 if (colon)
753 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
754 else
755 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
756 } else {
757 ret = 0;
758 if (ifa->ifa_local == sin->sin_addr.s_addr)
759 break;
760 inet_del_ifa(in_dev, ifap, 0);
761 ifa->ifa_broadcast = 0;
762 ifa->ifa_anycast = 0;
763 }
764
765 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
766
767 if (!(dev->flags & IFF_POINTOPOINT)) {
768 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
769 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
770 if ((dev->flags & IFF_BROADCAST) &&
771 ifa->ifa_prefixlen < 31)
772 ifa->ifa_broadcast = ifa->ifa_address |
773 ~ifa->ifa_mask;
774 } else {
775 ifa->ifa_prefixlen = 32;
776 ifa->ifa_mask = inet_make_mask(32);
777 }
778 ret = inet_set_ifa(dev, ifa);
779 break;
780
781 case SIOCSIFBRDADDR: /* Set the broadcast address */
782 ret = 0;
783 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
784 inet_del_ifa(in_dev, ifap, 0);
785 ifa->ifa_broadcast = sin->sin_addr.s_addr;
786 inet_insert_ifa(ifa);
787 }
788 break;
789
790 case SIOCSIFDSTADDR: /* Set the destination address */
791 ret = 0;
792 if (ifa->ifa_address == sin->sin_addr.s_addr)
793 break;
794 ret = -EINVAL;
795 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
796 break;
797 ret = 0;
798 inet_del_ifa(in_dev, ifap, 0);
799 ifa->ifa_address = sin->sin_addr.s_addr;
800 inet_insert_ifa(ifa);
801 break;
802
803 case SIOCSIFNETMASK: /* Set the netmask for the interface */
804
805 /*
806 * The mask we set must be legal.
807 */
808 ret = -EINVAL;
809 if (bad_mask(sin->sin_addr.s_addr, 0))
810 break;
811 ret = 0;
812 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -0700813 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 inet_del_ifa(in_dev, ifap, 0);
815 ifa->ifa_mask = sin->sin_addr.s_addr;
816 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
817
818 /* See if current broadcast address matches
819 * with current netmask, then recalculate
820 * the broadcast address. Otherwise it's a
821 * funny address, so don't touch it since
822 * the user seems to know what (s)he's doing...
823 */
824 if ((dev->flags & IFF_BROADCAST) &&
825 (ifa->ifa_prefixlen < 31) &&
826 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -0500827 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 ifa->ifa_broadcast = (ifa->ifa_local |
829 ~sin->sin_addr.s_addr);
830 }
831 inet_insert_ifa(ifa);
832 }
833 break;
834 }
835done:
836 rtnl_unlock();
837out:
838 return ret;
839rarok:
840 rtnl_unlock();
841 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
842 goto out;
843}
844
845static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
846{
Herbert Xue5ed6392005-10-03 14:35:55 -0700847 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 struct in_ifaddr *ifa;
849 struct ifreq ifr;
850 int done = 0;
851
852 if (!in_dev || (ifa = in_dev->ifa_list) == NULL)
853 goto out;
854
855 for (; ifa; ifa = ifa->ifa_next) {
856 if (!buf) {
857 done += sizeof(ifr);
858 continue;
859 }
860 if (len < (int) sizeof(ifr))
861 break;
862 memset(&ifr, 0, sizeof(struct ifreq));
863 if (ifa->ifa_label)
864 strcpy(ifr.ifr_name, ifa->ifa_label);
865 else
866 strcpy(ifr.ifr_name, dev->name);
867
868 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
869 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
870 ifa->ifa_local;
871
872 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
873 done = -EFAULT;
874 break;
875 }
876 buf += sizeof(struct ifreq);
877 len -= sizeof(struct ifreq);
878 done += sizeof(struct ifreq);
879 }
880out:
881 return done;
882}
883
Al Viroa61ced52006-09-26 21:27:54 -0700884__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885{
Al Viroa61ced52006-09-26 21:27:54 -0700886 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 struct in_device *in_dev;
888
889 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -0700890 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 if (!in_dev)
892 goto no_in_dev;
893
894 for_primary_ifa(in_dev) {
895 if (ifa->ifa_scope > scope)
896 continue;
897 if (!dst || inet_ifa_match(dst, ifa)) {
898 addr = ifa->ifa_local;
899 break;
900 }
901 if (!addr)
902 addr = ifa->ifa_local;
903 } endfor_ifa(in_dev);
904no_in_dev:
905 rcu_read_unlock();
906
907 if (addr)
908 goto out;
909
910 /* Not loopback addresses on loopback should be preferred
911 in this case. It is importnat that lo is the first interface
912 in dev_base list.
913 */
914 read_lock(&dev_base_lock);
915 rcu_read_lock();
Eric W. Biederman881d9662007-09-17 11:56:21 -0700916 for_each_netdev(&init_net, dev) {
Herbert Xue5ed6392005-10-03 14:35:55 -0700917 if ((in_dev = __in_dev_get_rcu(dev)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 continue;
919
920 for_primary_ifa(in_dev) {
921 if (ifa->ifa_scope != RT_SCOPE_LINK &&
922 ifa->ifa_scope <= scope) {
923 addr = ifa->ifa_local;
924 goto out_unlock_both;
925 }
926 } endfor_ifa(in_dev);
927 }
928out_unlock_both:
929 read_unlock(&dev_base_lock);
930 rcu_read_unlock();
931out:
932 return addr;
933}
934
Al Viro60cad5d2006-09-26 22:17:09 -0700935static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
936 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937{
938 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -0700939 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
941 for_ifa(in_dev) {
942 if (!addr &&
943 (local == ifa->ifa_local || !local) &&
944 ifa->ifa_scope <= scope) {
945 addr = ifa->ifa_local;
946 if (same)
947 break;
948 }
949 if (!same) {
950 same = (!local || inet_ifa_match(local, ifa)) &&
951 (!dst || inet_ifa_match(dst, ifa));
952 if (same && addr) {
953 if (local || !dst)
954 break;
955 /* Is the selected addr into dst subnet? */
956 if (inet_ifa_match(addr, ifa))
957 break;
958 /* No, then can we use new local src? */
959 if (ifa->ifa_scope <= scope) {
960 addr = ifa->ifa_local;
961 break;
962 }
963 /* search for large dst subnet for addr */
964 same = 0;
965 }
966 }
967 } endfor_ifa(in_dev);
968
969 return same? addr : 0;
970}
971
972/*
973 * Confirm that local IP address exists using wildcards:
974 * - dev: only on this interface, 0=any interface
975 * - dst: only in the same subnet as dst, 0=any dst
976 * - local: address, 0=autoselect the local address
977 * - scope: maximum allowed scope value for the local address
978 */
Al Viro60cad5d2006-09-26 22:17:09 -0700979__be32 inet_confirm_addr(const struct net_device *dev, __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980{
Al Viro60cad5d2006-09-26 22:17:09 -0700981 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 struct in_device *in_dev;
983
984 if (dev) {
985 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -0700986 if ((in_dev = __in_dev_get_rcu(dev)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 addr = confirm_addr_indev(in_dev, dst, local, scope);
988 rcu_read_unlock();
989
990 return addr;
991 }
992
993 read_lock(&dev_base_lock);
994 rcu_read_lock();
Eric W. Biederman881d9662007-09-17 11:56:21 -0700995 for_each_netdev(&init_net, dev) {
Herbert Xue5ed6392005-10-03 14:35:55 -0700996 if ((in_dev = __in_dev_get_rcu(dev))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 addr = confirm_addr_indev(in_dev, dst, local, scope);
998 if (addr)
999 break;
1000 }
1001 }
1002 rcu_read_unlock();
1003 read_unlock(&dev_base_lock);
1004
1005 return addr;
1006}
1007
1008/*
1009 * Device notifier
1010 */
1011
1012int register_inetaddr_notifier(struct notifier_block *nb)
1013{
Alan Sterne041c682006-03-27 01:16:30 -08001014 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015}
1016
1017int unregister_inetaddr_notifier(struct notifier_block *nb)
1018{
Alan Sterne041c682006-03-27 01:16:30 -08001019 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020}
1021
1022/* Rename ifa_labels for a device name change. Make some effort to preserve existing
1023 * alias numbering and to create unique labels if possible.
1024*/
1025static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001026{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 struct in_ifaddr *ifa;
1028 int named = 0;
1029
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001030 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1031 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
1033 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001034 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 if (named++ == 0)
1036 continue;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001037 dot = strchr(old, ':');
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001038 if (dot == NULL) {
1039 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 dot = old;
1041 }
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001042 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ) {
1043 strcat(ifa->ifa_label, dot);
1044 } else {
1045 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
1046 }
1047 }
1048}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049
1050/* Called only under RTNL semaphore */
1051
1052static int inetdev_event(struct notifier_block *this, unsigned long event,
1053 void *ptr)
1054{
1055 struct net_device *dev = ptr;
Herbert Xue5ed6392005-10-03 14:35:55 -07001056 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001058 if (dev->nd_net != &init_net)
1059 return NOTIFY_DONE;
1060
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 ASSERT_RTNL();
1062
1063 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001064 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 in_dev = inetdev_init(dev);
Herbert Xub217d612007-07-30 17:04:52 -07001066 if (!in_dev)
1067 return notifier_from_errno(-ENOMEM);
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001068 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001069 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1070 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001071 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 }
1073 goto out;
1074 }
1075
1076 switch (event) {
1077 case NETDEV_REGISTER:
1078 printk(KERN_DEBUG "inetdev_event: bug\n");
1079 dev->ip_ptr = NULL;
1080 break;
1081 case NETDEV_UP:
1082 if (dev->mtu < 68)
1083 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001084 if (dev->flags & IFF_LOOPBACK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 struct in_ifaddr *ifa;
1086 if ((ifa = inet_alloc_ifa()) != NULL) {
1087 ifa->ifa_local =
1088 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1089 ifa->ifa_prefixlen = 8;
1090 ifa->ifa_mask = inet_make_mask(8);
1091 in_dev_hold(in_dev);
1092 ifa->ifa_dev = in_dev;
1093 ifa->ifa_scope = RT_SCOPE_HOST;
1094 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1095 inet_insert_ifa(ifa);
1096 }
1097 }
1098 ip_mc_up(in_dev);
1099 break;
1100 case NETDEV_DOWN:
1101 ip_mc_down(in_dev);
1102 break;
1103 case NETDEV_CHANGEMTU:
1104 if (dev->mtu >= 68)
1105 break;
1106 /* MTU falled under 68, disable IP */
1107 case NETDEV_UNREGISTER:
1108 inetdev_destroy(in_dev);
1109 break;
1110 case NETDEV_CHANGENAME:
1111 /* Do not notify about label change, this event is
1112 * not interesting to applications using netlink.
1113 */
1114 inetdev_changename(dev, in_dev);
1115
1116#ifdef CONFIG_SYSCTL
1117 devinet_sysctl_unregister(&in_dev->cnf);
1118 neigh_sysctl_unregister(in_dev->arp_parms);
1119 neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
1120 NET_IPV4_NEIGH, "ipv4", NULL, NULL);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001121 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122#endif
1123 break;
1124 }
1125out:
1126 return NOTIFY_DONE;
1127}
1128
1129static struct notifier_block ip_netdev_notifier = {
1130 .notifier_call =inetdev_event,
1131};
1132
Thomas Graf339bf982006-11-10 14:10:15 -08001133static inline size_t inet_nlmsg_size(void)
1134{
1135 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1136 + nla_total_size(4) /* IFA_ADDRESS */
1137 + nla_total_size(4) /* IFA_LOCAL */
1138 + nla_total_size(4) /* IFA_BROADCAST */
1139 + nla_total_size(4) /* IFA_ANYCAST */
1140 + nla_total_size(IFNAMSIZ); /* IFA_LABEL */
1141}
1142
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07001144 u32 pid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145{
1146 struct ifaddrmsg *ifm;
1147 struct nlmsghdr *nlh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
Thomas Graf47f68512006-08-04 23:04:36 -07001149 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);
1150 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001151 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001152
1153 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 ifm->ifa_family = AF_INET;
1155 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
1156 ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT;
1157 ifm->ifa_scope = ifa->ifa_scope;
1158 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
Thomas Graf47f68512006-08-04 23:04:36 -07001160 if (ifa->ifa_address)
Al Viroa7a628c2006-09-26 22:16:43 -07001161 NLA_PUT_BE32(skb, IFA_ADDRESS, ifa->ifa_address);
Thomas Graf47f68512006-08-04 23:04:36 -07001162
1163 if (ifa->ifa_local)
Al Viroa7a628c2006-09-26 22:16:43 -07001164 NLA_PUT_BE32(skb, IFA_LOCAL, ifa->ifa_local);
Thomas Graf47f68512006-08-04 23:04:36 -07001165
1166 if (ifa->ifa_broadcast)
Al Viroa7a628c2006-09-26 22:16:43 -07001167 NLA_PUT_BE32(skb, IFA_BROADCAST, ifa->ifa_broadcast);
Thomas Graf47f68512006-08-04 23:04:36 -07001168
1169 if (ifa->ifa_anycast)
Al Viroa7a628c2006-09-26 22:16:43 -07001170 NLA_PUT_BE32(skb, IFA_ANYCAST, ifa->ifa_anycast);
Thomas Graf47f68512006-08-04 23:04:36 -07001171
1172 if (ifa->ifa_label[0])
1173 NLA_PUT_STRING(skb, IFA_LABEL, ifa->ifa_label);
1174
1175 return nlmsg_end(skb, nlh);
1176
1177nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001178 nlmsg_cancel(skb, nlh);
1179 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180}
1181
1182static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1183{
Denis V. Lunevb8542722007-12-01 00:21:31 +11001184 struct net *net = skb->sk->sk_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 int idx, ip_idx;
1186 struct net_device *dev;
1187 struct in_device *in_dev;
1188 struct in_ifaddr *ifa;
1189 int s_ip_idx, s_idx = cb->args[0];
1190
Denis V. Lunevb8542722007-12-01 00:21:31 +11001191 if (net != &init_net)
1192 return 0;
1193
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 s_ip_idx = ip_idx = cb->args[1];
Pavel Emelianov7562f872007-05-03 15:13:45 -07001195 idx = 0;
Eric W. Biederman881d9662007-09-17 11:56:21 -07001196 for_each_netdev(&init_net, dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 if (idx < s_idx)
Pavel Emelianov7562f872007-05-03 15:13:45 -07001198 goto cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 if (idx > s_idx)
1200 s_ip_idx = 0;
Patrick McHardy6313c1e2007-04-16 17:00:53 -07001201 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL)
Pavel Emelianov7562f872007-05-03 15:13:45 -07001202 goto cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
1204 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1205 ifa = ifa->ifa_next, ip_idx++) {
1206 if (ip_idx < s_ip_idx)
Stephen Hemminger596e4152007-09-11 10:41:04 +02001207 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
1209 cb->nlh->nlmsg_seq,
Patrick McHardy6313c1e2007-04-16 17:00:53 -07001210 RTM_NEWADDR, NLM_F_MULTI) <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 goto done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001213cont:
1214 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 }
1216
1217done:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 cb->args[0] = idx;
1219 cb->args[1] = ip_idx;
1220
1221 return skb->len;
1222}
1223
Thomas Grafd6062cb2006-08-15 00:33:59 -07001224static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
1225 u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226{
Thomas Graf47f68512006-08-04 23:04:36 -07001227 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001228 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1229 int err = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
Thomas Graf339bf982006-11-10 14:10:15 -08001231 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Thomas Graf47f68512006-08-04 23:04:36 -07001232 if (skb == NULL)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001233 goto errout;
1234
1235 err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001236 if (err < 0) {
1237 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1238 WARN_ON(err == -EMSGSIZE);
1239 kfree_skb(skb);
1240 goto errout;
1241 }
Denis V. Lunev97c53ca2007-11-19 22:26:51 -08001242 err = rtnl_notify(skb, &init_net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Thomas Grafd6062cb2006-08-15 00:33:59 -07001243errout:
1244 if (err < 0)
Denis V. Lunev97c53ca2007-11-19 22:26:51 -08001245 rtnl_set_sk_err(&init_net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246}
1247
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248#ifdef CONFIG_SYSCTL
1249
Herbert Xu31be3082007-06-04 23:35:37 -07001250static void devinet_copy_dflt_conf(int i)
1251{
1252 struct net_device *dev;
1253
1254 read_lock(&dev_base_lock);
Eric W. Biederman881d9662007-09-17 11:56:21 -07001255 for_each_netdev(&init_net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07001256 struct in_device *in_dev;
1257 rcu_read_lock();
1258 in_dev = __in_dev_get_rcu(dev);
1259 if (in_dev && !test_bit(i, in_dev->cnf.state))
1260 in_dev->cnf.data[i] = ipv4_devconf_dflt.data[i];
1261 rcu_read_unlock();
1262 }
1263 read_unlock(&dev_base_lock);
1264}
1265
1266static int devinet_conf_proc(ctl_table *ctl, int write,
1267 struct file* filp, void __user *buffer,
1268 size_t *lenp, loff_t *ppos)
1269{
1270 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1271
1272 if (write) {
1273 struct ipv4_devconf *cnf = ctl->extra1;
1274 int i = (int *)ctl->data - cnf->data;
1275
1276 set_bit(i, cnf->state);
1277
1278 if (cnf == &ipv4_devconf_dflt)
1279 devinet_copy_dflt_conf(i);
1280 }
1281
1282 return ret;
1283}
1284
1285static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,
1286 void __user *oldval, size_t __user *oldlenp,
1287 void __user *newval, size_t newlen)
1288{
1289 struct ipv4_devconf *cnf;
1290 int *valp = table->data;
1291 int new;
1292 int i;
1293
1294 if (!newval || !newlen)
1295 return 0;
1296
1297 if (newlen != sizeof(int))
1298 return -EINVAL;
1299
1300 if (get_user(new, (int __user *)newval))
1301 return -EFAULT;
1302
1303 if (new == *valp)
1304 return 0;
1305
1306 if (oldval && oldlenp) {
1307 size_t len;
1308
1309 if (get_user(len, oldlenp))
1310 return -EFAULT;
1311
1312 if (len) {
1313 if (len > table->maxlen)
1314 len = table->maxlen;
1315 if (copy_to_user(oldval, valp, len))
1316 return -EFAULT;
1317 if (put_user(len, oldlenp))
1318 return -EFAULT;
1319 }
1320 }
1321
1322 *valp = new;
1323
1324 cnf = table->extra1;
1325 i = (int *)table->data - cnf->data;
1326
1327 set_bit(i, cnf->state);
1328
1329 if (cnf == &ipv4_devconf_dflt)
1330 devinet_copy_dflt_conf(i);
1331
1332 return 1;
1333}
1334
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335void inet_forward_change(void)
1336{
1337 struct net_device *dev;
Herbert Xu42f811b2007-06-04 23:34:44 -07001338 int on = IPV4_DEVCONF_ALL(FORWARDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339
Herbert Xu42f811b2007-06-04 23:34:44 -07001340 IPV4_DEVCONF_ALL(ACCEPT_REDIRECTS) = !on;
1341 IPV4_DEVCONF_DFLT(FORWARDING) = on;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342
1343 read_lock(&dev_base_lock);
Eric W. Biederman881d9662007-09-17 11:56:21 -07001344 for_each_netdev(&init_net, dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 struct in_device *in_dev;
1346 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001347 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 if (in_dev)
Herbert Xu42f811b2007-06-04 23:34:44 -07001349 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 rcu_read_unlock();
1351 }
1352 read_unlock(&dev_base_lock);
1353
1354 rt_cache_flush(0);
1355}
1356
1357static int devinet_sysctl_forward(ctl_table *ctl, int write,
1358 struct file* filp, void __user *buffer,
1359 size_t *lenp, loff_t *ppos)
1360{
1361 int *valp = ctl->data;
1362 int val = *valp;
1363 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1364
1365 if (write && *valp != val) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001366 if (valp == &IPV4_DEVCONF_ALL(FORWARDING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 inet_forward_change();
Herbert Xu42f811b2007-06-04 23:34:44 -07001368 else if (valp != &IPV4_DEVCONF_DFLT(FORWARDING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 rt_cache_flush(0);
1370 }
1371
1372 return ret;
1373}
1374
1375int ipv4_doint_and_flush(ctl_table *ctl, int write,
1376 struct file* filp, void __user *buffer,
1377 size_t *lenp, loff_t *ppos)
1378{
1379 int *valp = ctl->data;
1380 int val = *valp;
1381 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1382
1383 if (write && *valp != val)
1384 rt_cache_flush(0);
1385
1386 return ret;
1387}
1388
1389int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
1390 void __user *oldval, size_t __user *oldlenp,
Alexey Dobriyan1f29bcd2006-12-10 02:19:10 -08001391 void __user *newval, size_t newlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392{
Herbert Xu31be3082007-06-04 23:35:37 -07001393 int ret = devinet_conf_sysctl(table, name, nlen, oldval, oldlenp,
1394 newval, newlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
Herbert Xu31be3082007-06-04 23:35:37 -07001396 if (ret == 1)
1397 rt_cache_flush(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
Herbert Xu31be3082007-06-04 23:35:37 -07001399 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400}
1401
1402
Herbert Xu42f811b2007-06-04 23:34:44 -07001403#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc, sysctl) \
1404 { \
1405 .ctl_name = NET_IPV4_CONF_ ## attr, \
1406 .procname = name, \
1407 .data = ipv4_devconf.data + \
1408 NET_IPV4_CONF_ ## attr - 1, \
1409 .maxlen = sizeof(int), \
1410 .mode = mval, \
1411 .proc_handler = proc, \
1412 .strategy = sysctl, \
Herbert Xu31be3082007-06-04 23:35:37 -07001413 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07001414 }
1415
1416#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Herbert Xu31be3082007-06-04 23:35:37 -07001417 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc, \
1418 devinet_conf_sysctl)
Herbert Xu42f811b2007-06-04 23:34:44 -07001419
1420#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Herbert Xu31be3082007-06-04 23:35:37 -07001421 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc, \
1422 devinet_conf_sysctl)
Herbert Xu42f811b2007-06-04 23:34:44 -07001423
1424#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc, sysctl) \
1425 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc, sysctl)
1426
1427#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
1428 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush, \
1429 ipv4_doint_and_flush_strategy)
1430
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431static struct devinet_sysctl_table {
1432 struct ctl_table_header *sysctl_header;
1433 ctl_table devinet_vars[__NET_IPV4_CONF_MAX];
1434 ctl_table devinet_dev[2];
1435 ctl_table devinet_conf_dir[2];
1436 ctl_table devinet_proto_dir[2];
1437 ctl_table devinet_root_dir[2];
1438} devinet_sysctl = {
1439 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07001440 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Herbert Xu31be3082007-06-04 23:35:37 -07001441 devinet_sysctl_forward,
1442 devinet_conf_sysctl),
Herbert Xu42f811b2007-06-04 23:34:44 -07001443 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
1444
1445 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
1446 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
1447 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
1448 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
1449 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
1450 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
1451 "accept_source_route"),
1452 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
1453 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
1454 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
1455 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
1456 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
1457 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
1458 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
1459 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
1460 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
1461
1462 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
1463 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
1464 DEVINET_SYSCTL_FLUSHING_ENTRY(FORCE_IGMP_VERSION,
1465 "force_igmp_version"),
1466 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
1467 "promote_secondaries"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 },
1469 .devinet_dev = {
1470 {
1471 .ctl_name = NET_PROTO_CONF_ALL,
1472 .procname = "all",
1473 .mode = 0555,
1474 .child = devinet_sysctl.devinet_vars,
1475 },
1476 },
1477 .devinet_conf_dir = {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001478 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 .ctl_name = NET_IPV4_CONF,
1480 .procname = "conf",
1481 .mode = 0555,
1482 .child = devinet_sysctl.devinet_dev,
1483 },
1484 },
1485 .devinet_proto_dir = {
1486 {
1487 .ctl_name = NET_IPV4,
1488 .procname = "ipv4",
1489 .mode = 0555,
1490 .child = devinet_sysctl.devinet_conf_dir,
1491 },
1492 },
1493 .devinet_root_dir = {
1494 {
1495 .ctl_name = CTL_NET,
1496 .procname = "net",
1497 .mode = 0555,
1498 .child = devinet_sysctl.devinet_proto_dir,
1499 },
1500 },
1501};
1502
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001503static void __devinet_sysctl_register(char *dev_name, int ctl_name,
1504 struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505{
1506 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001507 struct devinet_sysctl_table *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001509 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001511 goto out;
1512
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
1514 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07001515 t->devinet_vars[i].extra1 = p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 }
1517
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001518 t->devinet_dev[0].ctl_name = ctl_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001520 /*
1521 * Make a copy of dev_name, because '.procname' is regarded as const
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 * by sysctl and we wouldn't want anyone to change it under our feet
1523 * (see SIOCSIFNAME).
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001524 */
Paulo Marques543537b2005-06-23 00:09:02 -07001525 dev_name = kstrdup(dev_name, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 if (!dev_name)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001527 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528
1529 t->devinet_dev[0].procname = dev_name;
1530 t->devinet_dev[0].child = t->devinet_vars;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 t->devinet_conf_dir[0].child = t->devinet_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 t->devinet_proto_dir[0].child = t->devinet_conf_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 t->devinet_root_dir[0].child = t->devinet_proto_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
Eric W. Biederman0b4d4142007-02-14 00:34:09 -08001535 t->sysctl_header = register_sysctl_table(t->devinet_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 if (!t->sysctl_header)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001537 goto free_procname;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538
1539 p->sysctl = t;
1540 return;
1541
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001542free_procname:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 kfree(dev_name);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001544free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001546out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 return;
1548}
1549
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001550static void devinet_sysctl_register(struct in_device *idev)
1551{
1552 return __devinet_sysctl_register(idev->dev->name, idev->dev->ifindex,
1553 &idev->cnf);
1554}
1555
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556static void devinet_sysctl_unregister(struct ipv4_devconf *p)
1557{
1558 if (p->sysctl) {
1559 struct devinet_sysctl_table *t = p->sysctl;
1560 p->sysctl = NULL;
1561 unregister_sysctl_table(t->sysctl_header);
1562 kfree(t->devinet_dev[0].procname);
1563 kfree(t);
1564 }
1565}
1566#endif
1567
1568void __init devinet_init(void)
1569{
1570 register_gifconf(PF_INET, inet_gifconf);
1571 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07001572
1573 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL);
1574 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL);
1575 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576#ifdef CONFIG_SYSCTL
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001577 __devinet_sysctl_register("all", NET_PROTO_CONF_ALL,
1578 &ipv4_devconf);
1579 __devinet_sysctl_register("default", NET_PROTO_CONF_DEFAULT,
1580 &ipv4_devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581#endif
1582}
1583
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584EXPORT_SYMBOL(in_dev_finish_destroy);
1585EXPORT_SYMBOL(inet_select_addr);
1586EXPORT_SYMBOL(inetdev_by_index);
1587EXPORT_SYMBOL(register_inetaddr_notifier);
1588EXPORT_SYMBOL(unregister_inetaddr_notifier);