blob: 00940660739fc8897c592289fedc8840f3394aa0 [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
Thomas Graf5c753972006-08-04 23:03:53 -070087static struct nla_policy ifa_ipv4_policy[IFA_MAX+1] __read_mostly = {
88 [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
101static void devinet_sysctl_register(struct in_device *in_dev,
102 struct ipv4_devconf *p);
103static void devinet_sysctl_unregister(struct ipv4_devconf *p);
104#endif
105
106/* Locks all the inet devices. */
107
108static struct in_ifaddr *inet_alloc_ifa(void)
109{
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700110 struct in_ifaddr *ifa = kzalloc(sizeof(*ifa), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
112 if (ifa) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 INIT_RCU_HEAD(&ifa->rcu_head);
114 }
115
116 return ifa;
117}
118
119static void inet_rcu_free_ifa(struct rcu_head *head)
120{
121 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
122 if (ifa->ifa_dev)
123 in_dev_put(ifa->ifa_dev);
124 kfree(ifa);
125}
126
127static inline void inet_free_ifa(struct in_ifaddr *ifa)
128{
129 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
130}
131
132void in_dev_finish_destroy(struct in_device *idev)
133{
134 struct net_device *dev = idev->dev;
135
136 BUG_TRAP(!idev->ifa_list);
137 BUG_TRAP(!idev->mc_list);
138#ifdef NET_REFCNT_DEBUG
139 printk(KERN_DEBUG "in_dev_finish_destroy: %p=%s\n",
140 idev, dev ? dev->name : "NIL");
141#endif
142 dev_put(dev);
143 if (!idev->dead)
144 printk("Freeing alive in_device %p\n", idev);
145 else {
146 kfree(idev);
147 }
148}
149
150struct in_device *inetdev_init(struct net_device *dev)
151{
152 struct in_device *in_dev;
153
154 ASSERT_RTNL();
155
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700156 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 if (!in_dev)
158 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 INIT_RCU_HEAD(&in_dev->rcu_head);
160 memcpy(&in_dev->cnf, &ipv4_devconf_dflt, sizeof(in_dev->cnf));
161 in_dev->cnf.sysctl = NULL;
162 in_dev->dev = dev;
163 if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL)
164 goto out_kfree;
165 /* Reference in_dev->dev */
166 dev_hold(dev);
167#ifdef CONFIG_SYSCTL
168 neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
169 NET_IPV4_NEIGH, "ipv4", NULL, NULL);
170#endif
171
David L Stevens30c4cf52007-01-04 12:31:14 -0800172 /* Account for reference dev->ip_ptr (below) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 in_dev_hold(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
175#ifdef CONFIG_SYSCTL
176 devinet_sysctl_register(in_dev, &in_dev->cnf);
177#endif
178 ip_mc_init_dev(in_dev);
179 if (dev->flags & IFF_UP)
180 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800181
David L Stevens30c4cf52007-01-04 12:31:14 -0800182 /* we can receive as soon as ip_ptr is set -- do this last */
183 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800184out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 return in_dev;
186out_kfree:
187 kfree(in_dev);
188 in_dev = NULL;
189 goto out;
190}
191
192static void in_dev_rcu_put(struct rcu_head *head)
193{
194 struct in_device *idev = container_of(head, struct in_device, rcu_head);
195 in_dev_put(idev);
196}
197
198static void inetdev_destroy(struct in_device *in_dev)
199{
200 struct in_ifaddr *ifa;
201 struct net_device *dev;
202
203 ASSERT_RTNL();
204
205 dev = in_dev->dev;
206 if (dev == &loopback_dev)
207 return;
208
209 in_dev->dead = 1;
210
211 ip_mc_destroy_dev(in_dev);
212
213 while ((ifa = in_dev->ifa_list) != NULL) {
214 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
215 inet_free_ifa(ifa);
216 }
217
218#ifdef CONFIG_SYSCTL
219 devinet_sysctl_unregister(&in_dev->cnf);
220#endif
221
222 dev->ip_ptr = NULL;
223
224#ifdef CONFIG_SYSCTL
225 neigh_sysctl_unregister(in_dev->arp_parms);
226#endif
227 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
228 arp_ifdown(dev);
229
230 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
231}
232
Al Viroff428d72006-09-26 22:13:35 -0700233int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234{
235 rcu_read_lock();
236 for_primary_ifa(in_dev) {
237 if (inet_ifa_match(a, ifa)) {
238 if (!b || inet_ifa_match(b, ifa)) {
239 rcu_read_unlock();
240 return 1;
241 }
242 }
243 } endfor_ifa(in_dev);
244 rcu_read_unlock();
245 return 0;
246}
247
Thomas Grafd6062cb2006-08-15 00:33:59 -0700248static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
249 int destroy, struct nlmsghdr *nlh, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250{
Harald Welte8f937c62005-05-29 20:23:46 -0700251 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800252 struct in_ifaddr *ifa, *ifa1 = *ifap;
253 struct in_ifaddr *last_prim = in_dev->ifa_list;
254 struct in_ifaddr *prev_prom = NULL;
255 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
257 ASSERT_RTNL();
258
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900259 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700260 * unless alias promotion is set
261 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
263 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
265
266 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900267 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800268 ifa1->ifa_scope <= ifa->ifa_scope)
269 last_prim = ifa;
270
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
272 ifa1->ifa_mask != ifa->ifa_mask ||
273 !inet_ifa_match(ifa1->ifa_address, ifa)) {
274 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800275 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 continue;
277 }
278
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800279 if (!do_promote) {
Harald Welte8f937c62005-05-29 20:23:46 -0700280 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Thomas Grafd6062cb2006-08-15 00:33:59 -0700282 rtmsg_ifa(RTM_DELADDR, ifa, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800283 blocking_notifier_call_chain(&inetaddr_chain,
284 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700285 inet_free_ifa(ifa);
286 } else {
287 promote = ifa;
288 break;
289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 }
291 }
292
293 /* 2. Unlink it */
294
295 *ifap = ifa1->ifa_next;
296
297 /* 3. Announce address deletion */
298
299 /* Send message first, then call notifier.
300 At first sight, FIB update triggered by notifier
301 will refer to already deleted ifaddr, that could confuse
302 netlink listeners. It is not true: look, gated sees
303 that route deleted and if it still thinks that ifaddr
304 is valid, it will try to restore deleted routes... Grr.
305 So that, this order is correct.
306 */
Thomas Grafd6062cb2006-08-15 00:33:59 -0700307 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800308 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800309
310 if (promote) {
311
312 if (prev_prom) {
313 prev_prom->ifa_next = promote->ifa_next;
314 promote->ifa_next = last_prim->ifa_next;
315 last_prim->ifa_next = promote;
316 }
317
318 promote->ifa_flags &= ~IFA_F_SECONDARY;
Thomas Grafd6062cb2006-08-15 00:33:59 -0700319 rtmsg_ifa(RTM_NEWADDR, promote, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800320 blocking_notifier_call_chain(&inetaddr_chain,
321 NETDEV_UP, promote);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800322 for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) {
323 if (ifa1->ifa_mask != ifa->ifa_mask ||
324 !inet_ifa_match(ifa1->ifa_address, ifa))
325 continue;
326 fib_add_ifaddr(ifa);
327 }
328
329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 if (destroy) {
331 inet_free_ifa(ifa1);
332
333 if (!in_dev->ifa_list)
334 inetdev_destroy(in_dev);
335 }
336}
337
Thomas Grafd6062cb2006-08-15 00:33:59 -0700338static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
339 int destroy)
340{
341 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
342}
343
344static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
345 u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346{
347 struct in_device *in_dev = ifa->ifa_dev;
348 struct in_ifaddr *ifa1, **ifap, **last_primary;
349
350 ASSERT_RTNL();
351
352 if (!ifa->ifa_local) {
353 inet_free_ifa(ifa);
354 return 0;
355 }
356
357 ifa->ifa_flags &= ~IFA_F_SECONDARY;
358 last_primary = &in_dev->ifa_list;
359
360 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
361 ifap = &ifa1->ifa_next) {
362 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
363 ifa->ifa_scope <= ifa1->ifa_scope)
364 last_primary = &ifa1->ifa_next;
365 if (ifa1->ifa_mask == ifa->ifa_mask &&
366 inet_ifa_match(ifa1->ifa_address, ifa)) {
367 if (ifa1->ifa_local == ifa->ifa_local) {
368 inet_free_ifa(ifa);
369 return -EEXIST;
370 }
371 if (ifa1->ifa_scope != ifa->ifa_scope) {
372 inet_free_ifa(ifa);
373 return -EINVAL;
374 }
375 ifa->ifa_flags |= IFA_F_SECONDARY;
376 }
377 }
378
379 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
380 net_srandom(ifa->ifa_local);
381 ifap = last_primary;
382 }
383
384 ifa->ifa_next = *ifap;
385 *ifap = ifa;
386
387 /* Send message first, then call notifier.
388 Notifier will trigger FIB update, so that
389 listeners of netlink will know about new ifaddr */
Thomas Grafd6062cb2006-08-15 00:33:59 -0700390 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800391 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
393 return 0;
394}
395
Thomas Grafd6062cb2006-08-15 00:33:59 -0700396static int inet_insert_ifa(struct in_ifaddr *ifa)
397{
398 return __inet_insert_ifa(ifa, NULL, 0);
399}
400
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
402{
Herbert Xue5ed6392005-10-03 14:35:55 -0700403 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
405 ASSERT_RTNL();
406
407 if (!in_dev) {
408 in_dev = inetdev_init(dev);
409 if (!in_dev) {
410 inet_free_ifa(ifa);
411 return -ENOBUFS;
412 }
413 }
414 if (ifa->ifa_dev != in_dev) {
415 BUG_TRAP(!ifa->ifa_dev);
416 in_dev_hold(in_dev);
417 ifa->ifa_dev = in_dev;
418 }
419 if (LOOPBACK(ifa->ifa_local))
420 ifa->ifa_scope = RT_SCOPE_HOST;
421 return inet_insert_ifa(ifa);
422}
423
424struct in_device *inetdev_by_index(int ifindex)
425{
426 struct net_device *dev;
427 struct in_device *in_dev = NULL;
428 read_lock(&dev_base_lock);
429 dev = __dev_get_by_index(ifindex);
430 if (dev)
431 in_dev = in_dev_get(dev);
432 read_unlock(&dev_base_lock);
433 return in_dev;
434}
435
436/* Called only from RTNL semaphored context. No locks. */
437
Al Viro60cad5d2006-09-26 22:17:09 -0700438struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
439 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440{
441 ASSERT_RTNL();
442
443 for_primary_ifa(in_dev) {
444 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
445 return ifa;
446 } endfor_ifa(in_dev);
447 return NULL;
448}
449
450static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
451{
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700452 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700454 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700456 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
458 ASSERT_RTNL();
459
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700460 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
461 if (err < 0)
462 goto errout;
463
464 ifm = nlmsg_data(nlh);
465 in_dev = inetdev_by_index(ifm->ifa_index);
466 if (in_dev == NULL) {
467 err = -ENODEV;
468 goto errout;
469 }
470
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 __in_dev_put(in_dev);
472
473 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
474 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700475 if (tb[IFA_LOCAL] &&
Al Viroa7a628c2006-09-26 22:16:43 -0700476 ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700478
479 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
480 continue;
481
482 if (tb[IFA_ADDRESS] &&
483 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Al Viroa7a628c2006-09-26 22:16:43 -0700484 !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700485 continue;
486
Thomas Grafd6062cb2006-08-15 00:33:59 -0700487 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 return 0;
489 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700490
491 err = -EADDRNOTAVAIL;
492errout:
493 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494}
495
Thomas Graf5c753972006-08-04 23:03:53 -0700496static struct in_ifaddr *rtm_to_ifaddr(struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497{
Thomas Graf5c753972006-08-04 23:03:53 -0700498 struct nlattr *tb[IFA_MAX+1];
499 struct in_ifaddr *ifa;
500 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 struct net_device *dev;
502 struct in_device *in_dev;
Thomas Graf5c753972006-08-04 23:03:53 -0700503 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
Thomas Graf5c753972006-08-04 23:03:53 -0700505 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
506 if (err < 0)
507 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
Thomas Graf5c753972006-08-04 23:03:53 -0700509 ifm = nlmsg_data(nlh);
Evgeniy Polyakovc4e38f42007-03-09 13:43:24 -0800510 if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL) {
511 err = -EINVAL;
Thomas Graf5c753972006-08-04 23:03:53 -0700512 goto errout;
Evgeniy Polyakovc4e38f42007-03-09 13:43:24 -0800513 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
Thomas Graf5c753972006-08-04 23:03:53 -0700515 dev = __dev_get_by_index(ifm->ifa_index);
516 if (dev == NULL) {
517 err = -ENODEV;
518 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 }
520
Thomas Graf5c753972006-08-04 23:03:53 -0700521 in_dev = __in_dev_get_rtnl(dev);
522 if (in_dev == NULL) {
523 in_dev = inetdev_init(dev);
524 if (in_dev == NULL) {
525 err = -ENOBUFS;
526 goto errout;
527 }
528 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529
Thomas Graf5c753972006-08-04 23:03:53 -0700530 ifa = inet_alloc_ifa();
531 if (ifa == NULL) {
532 /*
533 * A potential indev allocation can be left alive, it stays
534 * assigned to its device and is destroy with it.
535 */
536 err = -ENOBUFS;
537 goto errout;
538 }
539
540 in_dev_hold(in_dev);
541
542 if (tb[IFA_ADDRESS] == NULL)
543 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
544
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
546 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 ifa->ifa_flags = ifm->ifa_flags;
548 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700549 ifa->ifa_dev = in_dev;
550
Al Viroa7a628c2006-09-26 22:16:43 -0700551 ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]);
552 ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700553
554 if (tb[IFA_BROADCAST])
Al Viroa7a628c2006-09-26 22:16:43 -0700555 ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700556
557 if (tb[IFA_ANYCAST])
Al Viroa7a628c2006-09-26 22:16:43 -0700558 ifa->ifa_anycast = nla_get_be32(tb[IFA_ANYCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700559
560 if (tb[IFA_LABEL])
561 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 else
563 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
564
Thomas Graf5c753972006-08-04 23:03:53 -0700565 return ifa;
566
567errout:
568 return ERR_PTR(err);
569}
570
571static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
572{
573 struct in_ifaddr *ifa;
574
575 ASSERT_RTNL();
576
577 ifa = rtm_to_ifaddr(nlh);
578 if (IS_ERR(ifa))
579 return PTR_ERR(ifa);
580
Thomas Grafd6062cb2006-08-15 00:33:59 -0700581 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582}
583
584/*
585 * Determine a default network mask, based on the IP address.
586 */
587
Al Viro714e85b2006-11-14 20:51:49 -0800588static __inline__ int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589{
590 int rc = -1; /* Something else, probably a multicast. */
591
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900592 if (ZERONET(addr))
593 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 else {
Al Viro714e85b2006-11-14 20:51:49 -0800595 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
Al Viro714e85b2006-11-14 20:51:49 -0800597 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800599 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800601 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 rc = 24;
603 }
604
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900605 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606}
607
608
609int devinet_ioctl(unsigned int cmd, void __user *arg)
610{
611 struct ifreq ifr;
612 struct sockaddr_in sin_orig;
613 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
614 struct in_device *in_dev;
615 struct in_ifaddr **ifap = NULL;
616 struct in_ifaddr *ifa = NULL;
617 struct net_device *dev;
618 char *colon;
619 int ret = -EFAULT;
620 int tryaddrmatch = 0;
621
622 /*
623 * Fetch the caller's info block into kernel space
624 */
625
626 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
627 goto out;
628 ifr.ifr_name[IFNAMSIZ - 1] = 0;
629
630 /* save original address for comparison */
631 memcpy(&sin_orig, sin, sizeof(*sin));
632
633 colon = strchr(ifr.ifr_name, ':');
634 if (colon)
635 *colon = 0;
636
637#ifdef CONFIG_KMOD
638 dev_load(ifr.ifr_name);
639#endif
640
Stephen Hemminger132adf52007-03-08 20:44:43 -0800641 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 case SIOCGIFADDR: /* Get interface address */
643 case SIOCGIFBRDADDR: /* Get the broadcast address */
644 case SIOCGIFDSTADDR: /* Get the destination address */
645 case SIOCGIFNETMASK: /* Get the netmask for the interface */
646 /* Note that these ioctls will not sleep,
647 so that we do not impose a lock.
648 One day we will be forced to put shlock here (I mean SMP)
649 */
650 tryaddrmatch = (sin_orig.sin_family == AF_INET);
651 memset(sin, 0, sizeof(*sin));
652 sin->sin_family = AF_INET;
653 break;
654
655 case SIOCSIFFLAGS:
656 ret = -EACCES;
657 if (!capable(CAP_NET_ADMIN))
658 goto out;
659 break;
660 case SIOCSIFADDR: /* Set interface address (and family) */
661 case SIOCSIFBRDADDR: /* Set the broadcast address */
662 case SIOCSIFDSTADDR: /* Set the destination address */
663 case SIOCSIFNETMASK: /* Set the netmask for the interface */
664 ret = -EACCES;
665 if (!capable(CAP_NET_ADMIN))
666 goto out;
667 ret = -EINVAL;
668 if (sin->sin_family != AF_INET)
669 goto out;
670 break;
671 default:
672 ret = -EINVAL;
673 goto out;
674 }
675
676 rtnl_lock();
677
678 ret = -ENODEV;
679 if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL)
680 goto done;
681
682 if (colon)
683 *colon = ':';
684
Herbert Xue5ed6392005-10-03 14:35:55 -0700685 if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 if (tryaddrmatch) {
687 /* Matthias Andree */
688 /* compare label and address (4.4BSD style) */
689 /* note: we only do this for a limited set of ioctls
690 and only if the original address family was AF_INET.
691 This is checked above. */
692 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
693 ifap = &ifa->ifa_next) {
694 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
695 sin_orig.sin_addr.s_addr ==
696 ifa->ifa_address) {
697 break; /* found */
698 }
699 }
700 }
701 /* we didn't get a match, maybe the application is
702 4.3BSD-style and passed in junk so we fall back to
703 comparing just the label */
704 if (!ifa) {
705 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
706 ifap = &ifa->ifa_next)
707 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
708 break;
709 }
710 }
711
712 ret = -EADDRNOTAVAIL;
713 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
714 goto done;
715
Stephen Hemminger132adf52007-03-08 20:44:43 -0800716 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 case SIOCGIFADDR: /* Get interface address */
718 sin->sin_addr.s_addr = ifa->ifa_local;
719 goto rarok;
720
721 case SIOCGIFBRDADDR: /* Get the broadcast address */
722 sin->sin_addr.s_addr = ifa->ifa_broadcast;
723 goto rarok;
724
725 case SIOCGIFDSTADDR: /* Get the destination address */
726 sin->sin_addr.s_addr = ifa->ifa_address;
727 goto rarok;
728
729 case SIOCGIFNETMASK: /* Get the netmask for the interface */
730 sin->sin_addr.s_addr = ifa->ifa_mask;
731 goto rarok;
732
733 case SIOCSIFFLAGS:
734 if (colon) {
735 ret = -EADDRNOTAVAIL;
736 if (!ifa)
737 break;
738 ret = 0;
739 if (!(ifr.ifr_flags & IFF_UP))
740 inet_del_ifa(in_dev, ifap, 1);
741 break;
742 }
743 ret = dev_change_flags(dev, ifr.ifr_flags);
744 break;
745
746 case SIOCSIFADDR: /* Set interface address (and family) */
747 ret = -EINVAL;
748 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
749 break;
750
751 if (!ifa) {
752 ret = -ENOBUFS;
753 if ((ifa = inet_alloc_ifa()) == NULL)
754 break;
755 if (colon)
756 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
757 else
758 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
759 } else {
760 ret = 0;
761 if (ifa->ifa_local == sin->sin_addr.s_addr)
762 break;
763 inet_del_ifa(in_dev, ifap, 0);
764 ifa->ifa_broadcast = 0;
765 ifa->ifa_anycast = 0;
766 }
767
768 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
769
770 if (!(dev->flags & IFF_POINTOPOINT)) {
771 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
772 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
773 if ((dev->flags & IFF_BROADCAST) &&
774 ifa->ifa_prefixlen < 31)
775 ifa->ifa_broadcast = ifa->ifa_address |
776 ~ifa->ifa_mask;
777 } else {
778 ifa->ifa_prefixlen = 32;
779 ifa->ifa_mask = inet_make_mask(32);
780 }
781 ret = inet_set_ifa(dev, ifa);
782 break;
783
784 case SIOCSIFBRDADDR: /* Set the broadcast address */
785 ret = 0;
786 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
787 inet_del_ifa(in_dev, ifap, 0);
788 ifa->ifa_broadcast = sin->sin_addr.s_addr;
789 inet_insert_ifa(ifa);
790 }
791 break;
792
793 case SIOCSIFDSTADDR: /* Set the destination address */
794 ret = 0;
795 if (ifa->ifa_address == sin->sin_addr.s_addr)
796 break;
797 ret = -EINVAL;
798 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
799 break;
800 ret = 0;
801 inet_del_ifa(in_dev, ifap, 0);
802 ifa->ifa_address = sin->sin_addr.s_addr;
803 inet_insert_ifa(ifa);
804 break;
805
806 case SIOCSIFNETMASK: /* Set the netmask for the interface */
807
808 /*
809 * The mask we set must be legal.
810 */
811 ret = -EINVAL;
812 if (bad_mask(sin->sin_addr.s_addr, 0))
813 break;
814 ret = 0;
815 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -0700816 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 inet_del_ifa(in_dev, ifap, 0);
818 ifa->ifa_mask = sin->sin_addr.s_addr;
819 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
820
821 /* See if current broadcast address matches
822 * with current netmask, then recalculate
823 * the broadcast address. Otherwise it's a
824 * funny address, so don't touch it since
825 * the user seems to know what (s)he's doing...
826 */
827 if ((dev->flags & IFF_BROADCAST) &&
828 (ifa->ifa_prefixlen < 31) &&
829 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -0500830 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 ifa->ifa_broadcast = (ifa->ifa_local |
832 ~sin->sin_addr.s_addr);
833 }
834 inet_insert_ifa(ifa);
835 }
836 break;
837 }
838done:
839 rtnl_unlock();
840out:
841 return ret;
842rarok:
843 rtnl_unlock();
844 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
845 goto out;
846}
847
848static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
849{
Herbert Xue5ed6392005-10-03 14:35:55 -0700850 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 struct in_ifaddr *ifa;
852 struct ifreq ifr;
853 int done = 0;
854
855 if (!in_dev || (ifa = in_dev->ifa_list) == NULL)
856 goto out;
857
858 for (; ifa; ifa = ifa->ifa_next) {
859 if (!buf) {
860 done += sizeof(ifr);
861 continue;
862 }
863 if (len < (int) sizeof(ifr))
864 break;
865 memset(&ifr, 0, sizeof(struct ifreq));
866 if (ifa->ifa_label)
867 strcpy(ifr.ifr_name, ifa->ifa_label);
868 else
869 strcpy(ifr.ifr_name, dev->name);
870
871 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
872 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
873 ifa->ifa_local;
874
875 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
876 done = -EFAULT;
877 break;
878 }
879 buf += sizeof(struct ifreq);
880 len -= sizeof(struct ifreq);
881 done += sizeof(struct ifreq);
882 }
883out:
884 return done;
885}
886
Al Viroa61ced52006-09-26 21:27:54 -0700887__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888{
Al Viroa61ced52006-09-26 21:27:54 -0700889 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 struct in_device *in_dev;
891
892 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -0700893 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 if (!in_dev)
895 goto no_in_dev;
896
897 for_primary_ifa(in_dev) {
898 if (ifa->ifa_scope > scope)
899 continue;
900 if (!dst || inet_ifa_match(dst, ifa)) {
901 addr = ifa->ifa_local;
902 break;
903 }
904 if (!addr)
905 addr = ifa->ifa_local;
906 } endfor_ifa(in_dev);
907no_in_dev:
908 rcu_read_unlock();
909
910 if (addr)
911 goto out;
912
913 /* Not loopback addresses on loopback should be preferred
914 in this case. It is importnat that lo is the first interface
915 in dev_base list.
916 */
917 read_lock(&dev_base_lock);
918 rcu_read_lock();
Pavel Emelianov7562f872007-05-03 15:13:45 -0700919 for_each_netdev(dev) {
Herbert Xue5ed6392005-10-03 14:35:55 -0700920 if ((in_dev = __in_dev_get_rcu(dev)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 continue;
922
923 for_primary_ifa(in_dev) {
924 if (ifa->ifa_scope != RT_SCOPE_LINK &&
925 ifa->ifa_scope <= scope) {
926 addr = ifa->ifa_local;
927 goto out_unlock_both;
928 }
929 } endfor_ifa(in_dev);
930 }
931out_unlock_both:
932 read_unlock(&dev_base_lock);
933 rcu_read_unlock();
934out:
935 return addr;
936}
937
Al Viro60cad5d2006-09-26 22:17:09 -0700938static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
939 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940{
941 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -0700942 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
944 for_ifa(in_dev) {
945 if (!addr &&
946 (local == ifa->ifa_local || !local) &&
947 ifa->ifa_scope <= scope) {
948 addr = ifa->ifa_local;
949 if (same)
950 break;
951 }
952 if (!same) {
953 same = (!local || inet_ifa_match(local, ifa)) &&
954 (!dst || inet_ifa_match(dst, ifa));
955 if (same && addr) {
956 if (local || !dst)
957 break;
958 /* Is the selected addr into dst subnet? */
959 if (inet_ifa_match(addr, ifa))
960 break;
961 /* No, then can we use new local src? */
962 if (ifa->ifa_scope <= scope) {
963 addr = ifa->ifa_local;
964 break;
965 }
966 /* search for large dst subnet for addr */
967 same = 0;
968 }
969 }
970 } endfor_ifa(in_dev);
971
972 return same? addr : 0;
973}
974
975/*
976 * Confirm that local IP address exists using wildcards:
977 * - dev: only on this interface, 0=any interface
978 * - dst: only in the same subnet as dst, 0=any dst
979 * - local: address, 0=autoselect the local address
980 * - scope: maximum allowed scope value for the local address
981 */
Al Viro60cad5d2006-09-26 22:17:09 -0700982__be32 inet_confirm_addr(const struct net_device *dev, __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983{
Al Viro60cad5d2006-09-26 22:17:09 -0700984 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 struct in_device *in_dev;
986
987 if (dev) {
988 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -0700989 if ((in_dev = __in_dev_get_rcu(dev)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 addr = confirm_addr_indev(in_dev, dst, local, scope);
991 rcu_read_unlock();
992
993 return addr;
994 }
995
996 read_lock(&dev_base_lock);
997 rcu_read_lock();
Pavel Emelianov7562f872007-05-03 15:13:45 -0700998 for_each_netdev(dev) {
Herbert Xue5ed6392005-10-03 14:35:55 -0700999 if ((in_dev = __in_dev_get_rcu(dev))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 addr = confirm_addr_indev(in_dev, dst, local, scope);
1001 if (addr)
1002 break;
1003 }
1004 }
1005 rcu_read_unlock();
1006 read_unlock(&dev_base_lock);
1007
1008 return addr;
1009}
1010
1011/*
1012 * Device notifier
1013 */
1014
1015int register_inetaddr_notifier(struct notifier_block *nb)
1016{
Alan Sterne041c682006-03-27 01:16:30 -08001017 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018}
1019
1020int unregister_inetaddr_notifier(struct notifier_block *nb)
1021{
Alan Sterne041c682006-03-27 01:16:30 -08001022 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023}
1024
1025/* Rename ifa_labels for a device name change. Make some effort to preserve existing
1026 * alias numbering and to create unique labels if possible.
1027*/
1028static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001029{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 struct in_ifaddr *ifa;
1031 int named = 0;
1032
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001033 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1034 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
1036 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001037 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 if (named++ == 0)
1039 continue;
1040 dot = strchr(ifa->ifa_label, ':');
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001041 if (dot == NULL) {
1042 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 dot = old;
1044 }
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001045 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ) {
1046 strcat(ifa->ifa_label, dot);
1047 } else {
1048 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
1049 }
1050 }
1051}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
1053/* Called only under RTNL semaphore */
1054
1055static int inetdev_event(struct notifier_block *this, unsigned long event,
1056 void *ptr)
1057{
1058 struct net_device *dev = ptr;
Herbert Xue5ed6392005-10-03 14:35:55 -07001059 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
1061 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 Xu8030f542007-02-22 01:53:47 +09001066 if (dev == &loopback_dev) {
Herbert Xu8d765272007-06-04 23:34:08 -07001067 if (!in_dev)
1068 panic("devinet: "
1069 "Failed to create loopback\n");
Herbert Xu42f811b2007-06-04 23:34:44 -07001070 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1071 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001072 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 }
1074 goto out;
1075 }
1076
1077 switch (event) {
1078 case NETDEV_REGISTER:
1079 printk(KERN_DEBUG "inetdev_event: bug\n");
1080 dev->ip_ptr = NULL;
1081 break;
1082 case NETDEV_UP:
1083 if (dev->mtu < 68)
1084 break;
1085 if (dev == &loopback_dev) {
1086 struct in_ifaddr *ifa;
1087 if ((ifa = inet_alloc_ifa()) != NULL) {
1088 ifa->ifa_local =
1089 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1090 ifa->ifa_prefixlen = 8;
1091 ifa->ifa_mask = inet_make_mask(8);
1092 in_dev_hold(in_dev);
1093 ifa->ifa_dev = in_dev;
1094 ifa->ifa_scope = RT_SCOPE_HOST;
1095 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1096 inet_insert_ifa(ifa);
1097 }
1098 }
1099 ip_mc_up(in_dev);
1100 break;
1101 case NETDEV_DOWN:
1102 ip_mc_down(in_dev);
1103 break;
1104 case NETDEV_CHANGEMTU:
1105 if (dev->mtu >= 68)
1106 break;
1107 /* MTU falled under 68, disable IP */
1108 case NETDEV_UNREGISTER:
1109 inetdev_destroy(in_dev);
1110 break;
1111 case NETDEV_CHANGENAME:
1112 /* Do not notify about label change, this event is
1113 * not interesting to applications using netlink.
1114 */
1115 inetdev_changename(dev, in_dev);
1116
1117#ifdef CONFIG_SYSCTL
1118 devinet_sysctl_unregister(&in_dev->cnf);
1119 neigh_sysctl_unregister(in_dev->arp_parms);
1120 neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
1121 NET_IPV4_NEIGH, "ipv4", NULL, NULL);
1122 devinet_sysctl_register(in_dev, &in_dev->cnf);
1123#endif
1124 break;
1125 }
1126out:
1127 return NOTIFY_DONE;
1128}
1129
1130static struct notifier_block ip_netdev_notifier = {
1131 .notifier_call =inetdev_event,
1132};
1133
Thomas Graf339bf982006-11-10 14:10:15 -08001134static inline size_t inet_nlmsg_size(void)
1135{
1136 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1137 + nla_total_size(4) /* IFA_ADDRESS */
1138 + nla_total_size(4) /* IFA_LOCAL */
1139 + nla_total_size(4) /* IFA_BROADCAST */
1140 + nla_total_size(4) /* IFA_ANYCAST */
1141 + nla_total_size(IFNAMSIZ); /* IFA_LABEL */
1142}
1143
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07001145 u32 pid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146{
1147 struct ifaddrmsg *ifm;
1148 struct nlmsghdr *nlh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
Thomas Graf47f68512006-08-04 23:04:36 -07001150 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);
1151 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001152 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001153
1154 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 ifm->ifa_family = AF_INET;
1156 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
1157 ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT;
1158 ifm->ifa_scope = ifa->ifa_scope;
1159 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
Thomas Graf47f68512006-08-04 23:04:36 -07001161 if (ifa->ifa_address)
Al Viroa7a628c2006-09-26 22:16:43 -07001162 NLA_PUT_BE32(skb, IFA_ADDRESS, ifa->ifa_address);
Thomas Graf47f68512006-08-04 23:04:36 -07001163
1164 if (ifa->ifa_local)
Al Viroa7a628c2006-09-26 22:16:43 -07001165 NLA_PUT_BE32(skb, IFA_LOCAL, ifa->ifa_local);
Thomas Graf47f68512006-08-04 23:04:36 -07001166
1167 if (ifa->ifa_broadcast)
Al Viroa7a628c2006-09-26 22:16:43 -07001168 NLA_PUT_BE32(skb, IFA_BROADCAST, ifa->ifa_broadcast);
Thomas Graf47f68512006-08-04 23:04:36 -07001169
1170 if (ifa->ifa_anycast)
Al Viroa7a628c2006-09-26 22:16:43 -07001171 NLA_PUT_BE32(skb, IFA_ANYCAST, ifa->ifa_anycast);
Thomas Graf47f68512006-08-04 23:04:36 -07001172
1173 if (ifa->ifa_label[0])
1174 NLA_PUT_STRING(skb, IFA_LABEL, ifa->ifa_label);
1175
1176 return nlmsg_end(skb, nlh);
1177
1178nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001179 nlmsg_cancel(skb, nlh);
1180 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181}
1182
1183static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1184{
1185 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
1191 s_ip_idx = ip_idx = cb->args[1];
Pavel Emelianov7562f872007-05-03 15:13:45 -07001192 idx = 0;
1193 for_each_netdev(dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 if (idx < s_idx)
Pavel Emelianov7562f872007-05-03 15:13:45 -07001195 goto cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 if (idx > s_idx)
1197 s_ip_idx = 0;
Patrick McHardy6313c1e2007-04-16 17:00:53 -07001198 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL)
Pavel Emelianov7562f872007-05-03 15:13:45 -07001199 goto cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
1201 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1202 ifa = ifa->ifa_next, ip_idx++) {
1203 if (ip_idx < s_ip_idx)
Pavel Emelianov7562f872007-05-03 15:13:45 -07001204 goto cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
1206 cb->nlh->nlmsg_seq,
Patrick McHardy6313c1e2007-04-16 17:00:53 -07001207 RTM_NEWADDR, NLM_F_MULTI) <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 goto done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001210cont:
1211 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 }
1213
1214done:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 cb->args[0] = idx;
1216 cb->args[1] = ip_idx;
1217
1218 return skb->len;
1219}
1220
Thomas Grafd6062cb2006-08-15 00:33:59 -07001221static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
1222 u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223{
Thomas Graf47f68512006-08-04 23:04:36 -07001224 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001225 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1226 int err = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
Thomas Graf339bf982006-11-10 14:10:15 -08001228 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Thomas Graf47f68512006-08-04 23:04:36 -07001229 if (skb == NULL)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001230 goto errout;
1231
1232 err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001233 if (err < 0) {
1234 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1235 WARN_ON(err == -EMSGSIZE);
1236 kfree_skb(skb);
1237 goto errout;
1238 }
Thomas Grafd6062cb2006-08-15 00:33:59 -07001239 err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
1240errout:
1241 if (err < 0)
1242 rtnl_set_sk_err(RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243}
1244
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245#ifdef CONFIG_SYSCTL
1246
1247void inet_forward_change(void)
1248{
1249 struct net_device *dev;
Herbert Xu42f811b2007-06-04 23:34:44 -07001250 int on = IPV4_DEVCONF_ALL(FORWARDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
Herbert Xu42f811b2007-06-04 23:34:44 -07001252 IPV4_DEVCONF_ALL(ACCEPT_REDIRECTS) = !on;
1253 IPV4_DEVCONF_DFLT(FORWARDING) = on;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254
1255 read_lock(&dev_base_lock);
Pavel Emelianov7562f872007-05-03 15:13:45 -07001256 for_each_netdev(dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 struct in_device *in_dev;
1258 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001259 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 if (in_dev)
Herbert Xu42f811b2007-06-04 23:34:44 -07001261 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 rcu_read_unlock();
1263 }
1264 read_unlock(&dev_base_lock);
1265
1266 rt_cache_flush(0);
1267}
1268
1269static int devinet_sysctl_forward(ctl_table *ctl, int write,
1270 struct file* filp, void __user *buffer,
1271 size_t *lenp, loff_t *ppos)
1272{
1273 int *valp = ctl->data;
1274 int val = *valp;
1275 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1276
1277 if (write && *valp != val) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001278 if (valp == &IPV4_DEVCONF_ALL(FORWARDING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 inet_forward_change();
Herbert Xu42f811b2007-06-04 23:34:44 -07001280 else if (valp != &IPV4_DEVCONF_DFLT(FORWARDING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 rt_cache_flush(0);
1282 }
1283
1284 return ret;
1285}
1286
1287int ipv4_doint_and_flush(ctl_table *ctl, int write,
1288 struct file* filp, void __user *buffer,
1289 size_t *lenp, loff_t *ppos)
1290{
1291 int *valp = ctl->data;
1292 int val = *valp;
1293 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1294
1295 if (write && *valp != val)
1296 rt_cache_flush(0);
1297
1298 return ret;
1299}
1300
1301int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
1302 void __user *oldval, size_t __user *oldlenp,
Alexey Dobriyan1f29bcd2006-12-10 02:19:10 -08001303 void __user *newval, size_t newlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304{
1305 int *valp = table->data;
1306 int new;
1307
1308 if (!newval || !newlen)
1309 return 0;
1310
1311 if (newlen != sizeof(int))
1312 return -EINVAL;
1313
1314 if (get_user(new, (int __user *)newval))
1315 return -EFAULT;
1316
1317 if (new == *valp)
1318 return 0;
1319
1320 if (oldval && oldlenp) {
1321 size_t len;
1322
1323 if (get_user(len, oldlenp))
1324 return -EFAULT;
1325
1326 if (len) {
1327 if (len > table->maxlen)
1328 len = table->maxlen;
1329 if (copy_to_user(oldval, valp, len))
1330 return -EFAULT;
1331 if (put_user(len, oldlenp))
1332 return -EFAULT;
1333 }
1334 }
1335
1336 *valp = new;
1337 rt_cache_flush(0);
1338 return 1;
1339}
1340
1341
Herbert Xu42f811b2007-06-04 23:34:44 -07001342#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc, sysctl) \
1343 { \
1344 .ctl_name = NET_IPV4_CONF_ ## attr, \
1345 .procname = name, \
1346 .data = ipv4_devconf.data + \
1347 NET_IPV4_CONF_ ## attr - 1, \
1348 .maxlen = sizeof(int), \
1349 .mode = mval, \
1350 .proc_handler = proc, \
1351 .strategy = sysctl, \
1352 }
1353
1354#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
1355 DEVINET_SYSCTL_ENTRY(attr, name, 0644, &proc_dointvec, NULL)
1356
1357#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
1358 DEVINET_SYSCTL_ENTRY(attr, name, 0444, &proc_dointvec, NULL)
1359
1360#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc, sysctl) \
1361 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc, sysctl)
1362
1363#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
1364 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush, \
1365 ipv4_doint_and_flush_strategy)
1366
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367static struct devinet_sysctl_table {
1368 struct ctl_table_header *sysctl_header;
1369 ctl_table devinet_vars[__NET_IPV4_CONF_MAX];
1370 ctl_table devinet_dev[2];
1371 ctl_table devinet_conf_dir[2];
1372 ctl_table devinet_proto_dir[2];
1373 ctl_table devinet_root_dir[2];
1374} devinet_sysctl = {
1375 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07001376 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
1377 devinet_sysctl_forward, NULL),
1378 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
1379
1380 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
1381 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
1382 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
1383 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
1384 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
1385 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
1386 "accept_source_route"),
1387 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
1388 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
1389 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
1390 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
1391 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
1392 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
1393 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
1394 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
1395 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
1396
1397 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
1398 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
1399 DEVINET_SYSCTL_FLUSHING_ENTRY(FORCE_IGMP_VERSION,
1400 "force_igmp_version"),
1401 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
1402 "promote_secondaries"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 },
1404 .devinet_dev = {
1405 {
1406 .ctl_name = NET_PROTO_CONF_ALL,
1407 .procname = "all",
1408 .mode = 0555,
1409 .child = devinet_sysctl.devinet_vars,
1410 },
1411 },
1412 .devinet_conf_dir = {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001413 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 .ctl_name = NET_IPV4_CONF,
1415 .procname = "conf",
1416 .mode = 0555,
1417 .child = devinet_sysctl.devinet_dev,
1418 },
1419 },
1420 .devinet_proto_dir = {
1421 {
1422 .ctl_name = NET_IPV4,
1423 .procname = "ipv4",
1424 .mode = 0555,
1425 .child = devinet_sysctl.devinet_conf_dir,
1426 },
1427 },
1428 .devinet_root_dir = {
1429 {
1430 .ctl_name = CTL_NET,
1431 .procname = "net",
1432 .mode = 0555,
1433 .child = devinet_sysctl.devinet_proto_dir,
1434 },
1435 },
1436};
1437
1438static void devinet_sysctl_register(struct in_device *in_dev,
1439 struct ipv4_devconf *p)
1440{
1441 int i;
1442 struct net_device *dev = in_dev ? in_dev->dev : NULL;
Arnaldo Carvalho de Melo42e5ea462006-11-17 11:18:20 -02001443 struct devinet_sysctl_table *t = kmemdup(&devinet_sysctl, sizeof(*t),
1444 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 char *dev_name = NULL;
1446
1447 if (!t)
1448 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
1450 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 }
1452
1453 if (dev) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001454 dev_name = dev->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 t->devinet_dev[0].ctl_name = dev->ifindex;
1456 } else {
1457 dev_name = "default";
1458 t->devinet_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT;
1459 }
1460
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001461 /*
1462 * Make a copy of dev_name, because '.procname' is regarded as const
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 * by sysctl and we wouldn't want anyone to change it under our feet
1464 * (see SIOCSIFNAME).
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001465 */
Paulo Marques543537b2005-06-23 00:09:02 -07001466 dev_name = kstrdup(dev_name, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 if (!dev_name)
1468 goto free;
1469
1470 t->devinet_dev[0].procname = dev_name;
1471 t->devinet_dev[0].child = t->devinet_vars;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 t->devinet_conf_dir[0].child = t->devinet_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 t->devinet_proto_dir[0].child = t->devinet_conf_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 t->devinet_root_dir[0].child = t->devinet_proto_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475
Eric W. Biederman0b4d4142007-02-14 00:34:09 -08001476 t->sysctl_header = register_sysctl_table(t->devinet_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 if (!t->sysctl_header)
1478 goto free_procname;
1479
1480 p->sysctl = t;
1481 return;
1482
1483 /* error path */
1484 free_procname:
1485 kfree(dev_name);
1486 free:
1487 kfree(t);
1488 return;
1489}
1490
1491static void devinet_sysctl_unregister(struct ipv4_devconf *p)
1492{
1493 if (p->sysctl) {
1494 struct devinet_sysctl_table *t = p->sysctl;
1495 p->sysctl = NULL;
1496 unregister_sysctl_table(t->sysctl_header);
1497 kfree(t->devinet_dev[0].procname);
1498 kfree(t);
1499 }
1500}
1501#endif
1502
1503void __init devinet_init(void)
1504{
1505 register_gifconf(PF_INET, inet_gifconf);
1506 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07001507
1508 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL);
1509 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL);
1510 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511#ifdef CONFIG_SYSCTL
1512 devinet_sysctl.sysctl_header =
Eric W. Biederman0b4d4142007-02-14 00:34:09 -08001513 register_sysctl_table(devinet_sysctl.devinet_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 devinet_sysctl_register(NULL, &ipv4_devconf_dflt);
1515#endif
1516}
1517
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518EXPORT_SYMBOL(in_dev_finish_destroy);
1519EXPORT_SYMBOL(inet_select_addr);
1520EXPORT_SYMBOL(inetdev_by_index);
1521EXPORT_SYMBOL(register_inetaddr_notifier);
1522EXPORT_SYMBOL(unregister_inetaddr_notifier);