blob: fa97b96a3d89e629bb80a53a7337a772f3af45a2 [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
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
Herbert Xu71e27da2007-06-04 23:36:06 -0700150static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151{
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) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700408 inet_free_ifa(ifa);
409 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700411 ipv4_devconf_setall(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 if (ifa->ifa_dev != in_dev) {
413 BUG_TRAP(!ifa->ifa_dev);
414 in_dev_hold(in_dev);
415 ifa->ifa_dev = in_dev;
416 }
417 if (LOOPBACK(ifa->ifa_local))
418 ifa->ifa_scope = RT_SCOPE_HOST;
419 return inet_insert_ifa(ifa);
420}
421
422struct in_device *inetdev_by_index(int ifindex)
423{
424 struct net_device *dev;
425 struct in_device *in_dev = NULL;
426 read_lock(&dev_base_lock);
427 dev = __dev_get_by_index(ifindex);
428 if (dev)
429 in_dev = in_dev_get(dev);
430 read_unlock(&dev_base_lock);
431 return in_dev;
432}
433
434/* Called only from RTNL semaphored context. No locks. */
435
Al Viro60cad5d2006-09-26 22:17:09 -0700436struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
437 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438{
439 ASSERT_RTNL();
440
441 for_primary_ifa(in_dev) {
442 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
443 return ifa;
444 } endfor_ifa(in_dev);
445 return NULL;
446}
447
448static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
449{
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700450 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700452 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700454 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
456 ASSERT_RTNL();
457
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700458 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
459 if (err < 0)
460 goto errout;
461
462 ifm = nlmsg_data(nlh);
463 in_dev = inetdev_by_index(ifm->ifa_index);
464 if (in_dev == NULL) {
465 err = -ENODEV;
466 goto errout;
467 }
468
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 __in_dev_put(in_dev);
470
471 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
472 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700473 if (tb[IFA_LOCAL] &&
Al Viroa7a628c2006-09-26 22:16:43 -0700474 ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700476
477 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
478 continue;
479
480 if (tb[IFA_ADDRESS] &&
481 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Al Viroa7a628c2006-09-26 22:16:43 -0700482 !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700483 continue;
484
Thomas Grafd6062cb2006-08-15 00:33:59 -0700485 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 return 0;
487 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700488
489 err = -EADDRNOTAVAIL;
490errout:
491 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492}
493
Thomas Graf5c753972006-08-04 23:03:53 -0700494static struct in_ifaddr *rtm_to_ifaddr(struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495{
Thomas Graf5c753972006-08-04 23:03:53 -0700496 struct nlattr *tb[IFA_MAX+1];
497 struct in_ifaddr *ifa;
498 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 struct net_device *dev;
500 struct in_device *in_dev;
Thomas Graf5c753972006-08-04 23:03:53 -0700501 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Thomas Graf5c753972006-08-04 23:03:53 -0700503 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
504 if (err < 0)
505 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
Thomas Graf5c753972006-08-04 23:03:53 -0700507 ifm = nlmsg_data(nlh);
Evgeniy Polyakovc4e38f42007-03-09 13:43:24 -0800508 if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL) {
509 err = -EINVAL;
Thomas Graf5c753972006-08-04 23:03:53 -0700510 goto errout;
Evgeniy Polyakovc4e38f42007-03-09 13:43:24 -0800511 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
Thomas Graf5c753972006-08-04 23:03:53 -0700513 dev = __dev_get_by_index(ifm->ifa_index);
514 if (dev == NULL) {
515 err = -ENODEV;
516 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 }
518
Thomas Graf5c753972006-08-04 23:03:53 -0700519 in_dev = __in_dev_get_rtnl(dev);
520 if (in_dev == NULL) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700521 err = -ENOBUFS;
522 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700523 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
Herbert Xu71e27da2007-06-04 23:36:06 -0700525 ipv4_devconf_setall(in_dev);
526
Thomas Graf5c753972006-08-04 23:03:53 -0700527 ifa = inet_alloc_ifa();
528 if (ifa == NULL) {
529 /*
530 * A potential indev allocation can be left alive, it stays
531 * assigned to its device and is destroy with it.
532 */
533 err = -ENOBUFS;
534 goto errout;
535 }
536
537 in_dev_hold(in_dev);
538
539 if (tb[IFA_ADDRESS] == NULL)
540 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
541
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
543 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 ifa->ifa_flags = ifm->ifa_flags;
545 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700546 ifa->ifa_dev = in_dev;
547
Al Viroa7a628c2006-09-26 22:16:43 -0700548 ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]);
549 ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700550
551 if (tb[IFA_BROADCAST])
Al Viroa7a628c2006-09-26 22:16:43 -0700552 ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700553
554 if (tb[IFA_ANYCAST])
Al Viroa7a628c2006-09-26 22:16:43 -0700555 ifa->ifa_anycast = nla_get_be32(tb[IFA_ANYCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700556
557 if (tb[IFA_LABEL])
558 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 else
560 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
561
Thomas Graf5c753972006-08-04 23:03:53 -0700562 return ifa;
563
564errout:
565 return ERR_PTR(err);
566}
567
568static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
569{
570 struct in_ifaddr *ifa;
571
572 ASSERT_RTNL();
573
574 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
635 dev_load(ifr.ifr_name);
636#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;
676 if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL)
677 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();
Pavel Emelianov7562f872007-05-03 15:13:45 -0700916 for_each_netdev(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();
Pavel Emelianov7562f872007-05-03 15:13:45 -0700995 for_each_netdev(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;
1037 dot = strchr(ifa->ifa_label, ':');
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
1058 ASSERT_RTNL();
1059
1060 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001061 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 in_dev = inetdev_init(dev);
Herbert Xu8030f542007-02-22 01:53:47 +09001063 if (dev == &loopback_dev) {
Herbert Xu8d76527e2007-06-04 23:34:08 -07001064 if (!in_dev)
1065 panic("devinet: "
1066 "Failed to create loopback\n");
Herbert Xu42f811b2007-06-04 23:34:44 -07001067 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1068 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001069 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 }
1071 goto out;
1072 }
1073
1074 switch (event) {
1075 case NETDEV_REGISTER:
1076 printk(KERN_DEBUG "inetdev_event: bug\n");
1077 dev->ip_ptr = NULL;
1078 break;
1079 case NETDEV_UP:
1080 if (dev->mtu < 68)
1081 break;
1082 if (dev == &loopback_dev) {
1083 struct in_ifaddr *ifa;
1084 if ((ifa = inet_alloc_ifa()) != NULL) {
1085 ifa->ifa_local =
1086 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1087 ifa->ifa_prefixlen = 8;
1088 ifa->ifa_mask = inet_make_mask(8);
1089 in_dev_hold(in_dev);
1090 ifa->ifa_dev = in_dev;
1091 ifa->ifa_scope = RT_SCOPE_HOST;
1092 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1093 inet_insert_ifa(ifa);
1094 }
1095 }
1096 ip_mc_up(in_dev);
1097 break;
1098 case NETDEV_DOWN:
1099 ip_mc_down(in_dev);
1100 break;
1101 case NETDEV_CHANGEMTU:
1102 if (dev->mtu >= 68)
1103 break;
1104 /* MTU falled under 68, disable IP */
1105 case NETDEV_UNREGISTER:
1106 inetdev_destroy(in_dev);
1107 break;
1108 case NETDEV_CHANGENAME:
1109 /* Do not notify about label change, this event is
1110 * not interesting to applications using netlink.
1111 */
1112 inetdev_changename(dev, in_dev);
1113
1114#ifdef CONFIG_SYSCTL
1115 devinet_sysctl_unregister(&in_dev->cnf);
1116 neigh_sysctl_unregister(in_dev->arp_parms);
1117 neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
1118 NET_IPV4_NEIGH, "ipv4", NULL, NULL);
1119 devinet_sysctl_register(in_dev, &in_dev->cnf);
1120#endif
1121 break;
1122 }
1123out:
1124 return NOTIFY_DONE;
1125}
1126
1127static struct notifier_block ip_netdev_notifier = {
1128 .notifier_call =inetdev_event,
1129};
1130
Thomas Graf339bf982006-11-10 14:10:15 -08001131static inline size_t inet_nlmsg_size(void)
1132{
1133 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1134 + nla_total_size(4) /* IFA_ADDRESS */
1135 + nla_total_size(4) /* IFA_LOCAL */
1136 + nla_total_size(4) /* IFA_BROADCAST */
1137 + nla_total_size(4) /* IFA_ANYCAST */
1138 + nla_total_size(IFNAMSIZ); /* IFA_LABEL */
1139}
1140
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07001142 u32 pid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143{
1144 struct ifaddrmsg *ifm;
1145 struct nlmsghdr *nlh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
Thomas Graf47f68512006-08-04 23:04:36 -07001147 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);
1148 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001149 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001150
1151 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 ifm->ifa_family = AF_INET;
1153 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
1154 ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT;
1155 ifm->ifa_scope = ifa->ifa_scope;
1156 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157
Thomas Graf47f68512006-08-04 23:04:36 -07001158 if (ifa->ifa_address)
Al Viroa7a628c2006-09-26 22:16:43 -07001159 NLA_PUT_BE32(skb, IFA_ADDRESS, ifa->ifa_address);
Thomas Graf47f68512006-08-04 23:04:36 -07001160
1161 if (ifa->ifa_local)
Al Viroa7a628c2006-09-26 22:16:43 -07001162 NLA_PUT_BE32(skb, IFA_LOCAL, ifa->ifa_local);
Thomas Graf47f68512006-08-04 23:04:36 -07001163
1164 if (ifa->ifa_broadcast)
Al Viroa7a628c2006-09-26 22:16:43 -07001165 NLA_PUT_BE32(skb, IFA_BROADCAST, ifa->ifa_broadcast);
Thomas Graf47f68512006-08-04 23:04:36 -07001166
1167 if (ifa->ifa_anycast)
Al Viroa7a628c2006-09-26 22:16:43 -07001168 NLA_PUT_BE32(skb, IFA_ANYCAST, ifa->ifa_anycast);
Thomas Graf47f68512006-08-04 23:04:36 -07001169
1170 if (ifa->ifa_label[0])
1171 NLA_PUT_STRING(skb, IFA_LABEL, ifa->ifa_label);
1172
1173 return nlmsg_end(skb, nlh);
1174
1175nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001176 nlmsg_cancel(skb, nlh);
1177 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178}
1179
1180static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1181{
1182 int idx, ip_idx;
1183 struct net_device *dev;
1184 struct in_device *in_dev;
1185 struct in_ifaddr *ifa;
1186 int s_ip_idx, s_idx = cb->args[0];
1187
1188 s_ip_idx = ip_idx = cb->args[1];
Pavel Emelianov7562f872007-05-03 15:13:45 -07001189 idx = 0;
1190 for_each_netdev(dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 if (idx < s_idx)
Pavel Emelianov7562f872007-05-03 15:13:45 -07001192 goto cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 if (idx > s_idx)
1194 s_ip_idx = 0;
Patrick McHardy6313c1e2007-04-16 17:00:53 -07001195 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL)
Pavel Emelianov7562f872007-05-03 15:13:45 -07001196 goto cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197
1198 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1199 ifa = ifa->ifa_next, ip_idx++) {
1200 if (ip_idx < s_ip_idx)
Pavel Emelianov7562f872007-05-03 15:13:45 -07001201 goto cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
1203 cb->nlh->nlmsg_seq,
Patrick McHardy6313c1e2007-04-16 17:00:53 -07001204 RTM_NEWADDR, NLM_F_MULTI) <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 goto done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001207cont:
1208 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 }
1210
1211done:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 cb->args[0] = idx;
1213 cb->args[1] = ip_idx;
1214
1215 return skb->len;
1216}
1217
Thomas Grafd6062cb2006-08-15 00:33:59 -07001218static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
1219 u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220{
Thomas Graf47f68512006-08-04 23:04:36 -07001221 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001222 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1223 int err = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224
Thomas Graf339bf982006-11-10 14:10:15 -08001225 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Thomas Graf47f68512006-08-04 23:04:36 -07001226 if (skb == NULL)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001227 goto errout;
1228
1229 err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001230 if (err < 0) {
1231 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1232 WARN_ON(err == -EMSGSIZE);
1233 kfree_skb(skb);
1234 goto errout;
1235 }
Thomas Grafd6062cb2006-08-15 00:33:59 -07001236 err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
1237errout:
1238 if (err < 0)
1239 rtnl_set_sk_err(RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240}
1241
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242#ifdef CONFIG_SYSCTL
1243
Herbert Xu31be3082007-06-04 23:35:37 -07001244static void devinet_copy_dflt_conf(int i)
1245{
1246 struct net_device *dev;
1247
1248 read_lock(&dev_base_lock);
1249 for_each_netdev(dev) {
1250 struct in_device *in_dev;
1251 rcu_read_lock();
1252 in_dev = __in_dev_get_rcu(dev);
1253 if (in_dev && !test_bit(i, in_dev->cnf.state))
1254 in_dev->cnf.data[i] = ipv4_devconf_dflt.data[i];
1255 rcu_read_unlock();
1256 }
1257 read_unlock(&dev_base_lock);
1258}
1259
1260static int devinet_conf_proc(ctl_table *ctl, int write,
1261 struct file* filp, void __user *buffer,
1262 size_t *lenp, loff_t *ppos)
1263{
1264 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1265
1266 if (write) {
1267 struct ipv4_devconf *cnf = ctl->extra1;
1268 int i = (int *)ctl->data - cnf->data;
1269
1270 set_bit(i, cnf->state);
1271
1272 if (cnf == &ipv4_devconf_dflt)
1273 devinet_copy_dflt_conf(i);
1274 }
1275
1276 return ret;
1277}
1278
1279static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,
1280 void __user *oldval, size_t __user *oldlenp,
1281 void __user *newval, size_t newlen)
1282{
1283 struct ipv4_devconf *cnf;
1284 int *valp = table->data;
1285 int new;
1286 int i;
1287
1288 if (!newval || !newlen)
1289 return 0;
1290
1291 if (newlen != sizeof(int))
1292 return -EINVAL;
1293
1294 if (get_user(new, (int __user *)newval))
1295 return -EFAULT;
1296
1297 if (new == *valp)
1298 return 0;
1299
1300 if (oldval && oldlenp) {
1301 size_t len;
1302
1303 if (get_user(len, oldlenp))
1304 return -EFAULT;
1305
1306 if (len) {
1307 if (len > table->maxlen)
1308 len = table->maxlen;
1309 if (copy_to_user(oldval, valp, len))
1310 return -EFAULT;
1311 if (put_user(len, oldlenp))
1312 return -EFAULT;
1313 }
1314 }
1315
1316 *valp = new;
1317
1318 cnf = table->extra1;
1319 i = (int *)table->data - cnf->data;
1320
1321 set_bit(i, cnf->state);
1322
1323 if (cnf == &ipv4_devconf_dflt)
1324 devinet_copy_dflt_conf(i);
1325
1326 return 1;
1327}
1328
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329void inet_forward_change(void)
1330{
1331 struct net_device *dev;
Herbert Xu42f811b2007-06-04 23:34:44 -07001332 int on = IPV4_DEVCONF_ALL(FORWARDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
Herbert Xu42f811b2007-06-04 23:34:44 -07001334 IPV4_DEVCONF_ALL(ACCEPT_REDIRECTS) = !on;
1335 IPV4_DEVCONF_DFLT(FORWARDING) = on;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336
1337 read_lock(&dev_base_lock);
Pavel Emelianov7562f872007-05-03 15:13:45 -07001338 for_each_netdev(dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 struct in_device *in_dev;
1340 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001341 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 if (in_dev)
Herbert Xu42f811b2007-06-04 23:34:44 -07001343 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 rcu_read_unlock();
1345 }
1346 read_unlock(&dev_base_lock);
1347
1348 rt_cache_flush(0);
1349}
1350
1351static int devinet_sysctl_forward(ctl_table *ctl, int write,
1352 struct file* filp, void __user *buffer,
1353 size_t *lenp, loff_t *ppos)
1354{
1355 int *valp = ctl->data;
1356 int val = *valp;
1357 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1358
1359 if (write && *valp != val) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001360 if (valp == &IPV4_DEVCONF_ALL(FORWARDING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 inet_forward_change();
Herbert Xu42f811b2007-06-04 23:34:44 -07001362 else if (valp != &IPV4_DEVCONF_DFLT(FORWARDING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 rt_cache_flush(0);
1364 }
1365
1366 return ret;
1367}
1368
1369int ipv4_doint_and_flush(ctl_table *ctl, int write,
1370 struct file* filp, void __user *buffer,
1371 size_t *lenp, loff_t *ppos)
1372{
1373 int *valp = ctl->data;
1374 int val = *valp;
1375 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1376
1377 if (write && *valp != val)
1378 rt_cache_flush(0);
1379
1380 return ret;
1381}
1382
1383int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
1384 void __user *oldval, size_t __user *oldlenp,
Alexey Dobriyan1f29bcd2006-12-10 02:19:10 -08001385 void __user *newval, size_t newlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386{
Herbert Xu31be3082007-06-04 23:35:37 -07001387 int ret = devinet_conf_sysctl(table, name, nlen, oldval, oldlenp,
1388 newval, newlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
Herbert Xu31be3082007-06-04 23:35:37 -07001390 if (ret == 1)
1391 rt_cache_flush(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
Herbert Xu31be3082007-06-04 23:35:37 -07001393 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394}
1395
1396
Herbert Xu42f811b2007-06-04 23:34:44 -07001397#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc, sysctl) \
1398 { \
1399 .ctl_name = NET_IPV4_CONF_ ## attr, \
1400 .procname = name, \
1401 .data = ipv4_devconf.data + \
1402 NET_IPV4_CONF_ ## attr - 1, \
1403 .maxlen = sizeof(int), \
1404 .mode = mval, \
1405 .proc_handler = proc, \
1406 .strategy = sysctl, \
Herbert Xu31be3082007-06-04 23:35:37 -07001407 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07001408 }
1409
1410#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Herbert Xu31be3082007-06-04 23:35:37 -07001411 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc, \
1412 devinet_conf_sysctl)
Herbert Xu42f811b2007-06-04 23:34:44 -07001413
1414#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Herbert Xu31be3082007-06-04 23:35:37 -07001415 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc, \
1416 devinet_conf_sysctl)
Herbert Xu42f811b2007-06-04 23:34:44 -07001417
1418#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc, sysctl) \
1419 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc, sysctl)
1420
1421#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
1422 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush, \
1423 ipv4_doint_and_flush_strategy)
1424
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425static struct devinet_sysctl_table {
1426 struct ctl_table_header *sysctl_header;
1427 ctl_table devinet_vars[__NET_IPV4_CONF_MAX];
1428 ctl_table devinet_dev[2];
1429 ctl_table devinet_conf_dir[2];
1430 ctl_table devinet_proto_dir[2];
1431 ctl_table devinet_root_dir[2];
1432} devinet_sysctl = {
1433 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07001434 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Herbert Xu31be3082007-06-04 23:35:37 -07001435 devinet_sysctl_forward,
1436 devinet_conf_sysctl),
Herbert Xu42f811b2007-06-04 23:34:44 -07001437 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
1438
1439 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
1440 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
1441 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
1442 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
1443 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
1444 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
1445 "accept_source_route"),
1446 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
1447 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
1448 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
1449 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
1450 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
1451 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
1452 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
1453 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
1454 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
1455
1456 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
1457 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
1458 DEVINET_SYSCTL_FLUSHING_ENTRY(FORCE_IGMP_VERSION,
1459 "force_igmp_version"),
1460 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
1461 "promote_secondaries"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 },
1463 .devinet_dev = {
1464 {
1465 .ctl_name = NET_PROTO_CONF_ALL,
1466 .procname = "all",
1467 .mode = 0555,
1468 .child = devinet_sysctl.devinet_vars,
1469 },
1470 },
1471 .devinet_conf_dir = {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001472 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 .ctl_name = NET_IPV4_CONF,
1474 .procname = "conf",
1475 .mode = 0555,
1476 .child = devinet_sysctl.devinet_dev,
1477 },
1478 },
1479 .devinet_proto_dir = {
1480 {
1481 .ctl_name = NET_IPV4,
1482 .procname = "ipv4",
1483 .mode = 0555,
1484 .child = devinet_sysctl.devinet_conf_dir,
1485 },
1486 },
1487 .devinet_root_dir = {
1488 {
1489 .ctl_name = CTL_NET,
1490 .procname = "net",
1491 .mode = 0555,
1492 .child = devinet_sysctl.devinet_proto_dir,
1493 },
1494 },
1495};
1496
1497static void devinet_sysctl_register(struct in_device *in_dev,
1498 struct ipv4_devconf *p)
1499{
1500 int i;
1501 struct net_device *dev = in_dev ? in_dev->dev : NULL;
Arnaldo Carvalho de Melo42e5ea462006-11-17 11:18:20 -02001502 struct devinet_sysctl_table *t = kmemdup(&devinet_sysctl, sizeof(*t),
1503 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 char *dev_name = NULL;
1505
1506 if (!t)
1507 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
1509 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07001510 t->devinet_vars[i].extra1 = p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 }
1512
1513 if (dev) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001514 dev_name = dev->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 t->devinet_dev[0].ctl_name = dev->ifindex;
1516 } else {
1517 dev_name = "default";
1518 t->devinet_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT;
1519 }
1520
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001521 /*
1522 * Make a copy of dev_name, because '.procname' is regarded as const
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 * by sysctl and we wouldn't want anyone to change it under our feet
1524 * (see SIOCSIFNAME).
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001525 */
Paulo Marques543537b2005-06-23 00:09:02 -07001526 dev_name = kstrdup(dev_name, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 if (!dev_name)
1528 goto free;
1529
1530 t->devinet_dev[0].procname = dev_name;
1531 t->devinet_dev[0].child = t->devinet_vars;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 t->devinet_conf_dir[0].child = t->devinet_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 t->devinet_proto_dir[0].child = t->devinet_conf_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 t->devinet_root_dir[0].child = t->devinet_proto_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535
Eric W. Biederman0b4d4142007-02-14 00:34:09 -08001536 t->sysctl_header = register_sysctl_table(t->devinet_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 if (!t->sysctl_header)
1538 goto free_procname;
1539
1540 p->sysctl = t;
1541 return;
1542
1543 /* error path */
1544 free_procname:
1545 kfree(dev_name);
1546 free:
1547 kfree(t);
1548 return;
1549}
1550
1551static void devinet_sysctl_unregister(struct ipv4_devconf *p)
1552{
1553 if (p->sysctl) {
1554 struct devinet_sysctl_table *t = p->sysctl;
1555 p->sysctl = NULL;
1556 unregister_sysctl_table(t->sysctl_header);
1557 kfree(t->devinet_dev[0].procname);
1558 kfree(t);
1559 }
1560}
1561#endif
1562
1563void __init devinet_init(void)
1564{
1565 register_gifconf(PF_INET, inet_gifconf);
1566 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07001567
1568 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL);
1569 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL);
1570 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571#ifdef CONFIG_SYSCTL
1572 devinet_sysctl.sysctl_header =
Eric W. Biederman0b4d4142007-02-14 00:34:09 -08001573 register_sysctl_table(devinet_sysctl.devinet_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 devinet_sysctl_register(NULL, &ipv4_devconf_dflt);
1575#endif
1576}
1577
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578EXPORT_SYMBOL(in_dev_finish_destroy);
1579EXPORT_SYMBOL(inet_select_addr);
1580EXPORT_SYMBOL(inetdev_by_index);
1581EXPORT_SYMBOL(register_inetaddr_notifier);
1582EXPORT_SYMBOL(unregister_inetaddr_notifier);