blob: 44fdf1413e2c6e6eabda3b6c44dbb9e30881cd99 [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
30#include <linux/config.h>
31
32#include <asm/uaccess.h>
33#include <asm/system.h>
34#include <linux/bitops.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080035#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/module.h>
37#include <linux/types.h>
38#include <linux/kernel.h>
39#include <linux/sched.h>
40#include <linux/string.h>
41#include <linux/mm.h>
42#include <linux/socket.h>
43#include <linux/sockios.h>
44#include <linux/in.h>
45#include <linux/errno.h>
46#include <linux/interrupt.h>
47#include <linux/if_ether.h>
48#include <linux/inet.h>
49#include <linux/netdevice.h>
50#include <linux/etherdevice.h>
51#include <linux/skbuff.h>
52#include <linux/rtnetlink.h>
53#include <linux/init.h>
54#include <linux/notifier.h>
55#include <linux/inetdevice.h>
56#include <linux/igmp.h>
57#ifdef CONFIG_SYSCTL
58#include <linux/sysctl.h>
59#endif
60#include <linux/kmod.h>
61
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020062#include <net/arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#include <net/ip.h>
64#include <net/route.h>
65#include <net/ip_fib.h>
66
67struct ipv4_devconf ipv4_devconf = {
68 .accept_redirects = 1,
69 .send_redirects = 1,
70 .secure_redirects = 1,
71 .shared_media = 1,
72};
73
74static struct ipv4_devconf ipv4_devconf_dflt = {
75 .accept_redirects = 1,
76 .send_redirects = 1,
77 .secure_redirects = 1,
78 .shared_media = 1,
79 .accept_source_route = 1,
80};
81
82static void rtmsg_ifa(int event, struct in_ifaddr *);
83
84static struct notifier_block *inetaddr_chain;
85static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
86 int destroy);
87#ifdef CONFIG_SYSCTL
88static void devinet_sysctl_register(struct in_device *in_dev,
89 struct ipv4_devconf *p);
90static void devinet_sysctl_unregister(struct ipv4_devconf *p);
91#endif
92
93/* Locks all the inet devices. */
94
95static struct in_ifaddr *inet_alloc_ifa(void)
96{
97 struct in_ifaddr *ifa = kmalloc(sizeof(*ifa), GFP_KERNEL);
98
99 if (ifa) {
100 memset(ifa, 0, sizeof(*ifa));
101 INIT_RCU_HEAD(&ifa->rcu_head);
102 }
103
104 return ifa;
105}
106
107static void inet_rcu_free_ifa(struct rcu_head *head)
108{
109 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
110 if (ifa->ifa_dev)
111 in_dev_put(ifa->ifa_dev);
112 kfree(ifa);
113}
114
115static inline void inet_free_ifa(struct in_ifaddr *ifa)
116{
117 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
118}
119
120void in_dev_finish_destroy(struct in_device *idev)
121{
122 struct net_device *dev = idev->dev;
123
124 BUG_TRAP(!idev->ifa_list);
125 BUG_TRAP(!idev->mc_list);
126#ifdef NET_REFCNT_DEBUG
127 printk(KERN_DEBUG "in_dev_finish_destroy: %p=%s\n",
128 idev, dev ? dev->name : "NIL");
129#endif
130 dev_put(dev);
131 if (!idev->dead)
132 printk("Freeing alive in_device %p\n", idev);
133 else {
134 kfree(idev);
135 }
136}
137
138struct in_device *inetdev_init(struct net_device *dev)
139{
140 struct in_device *in_dev;
141
142 ASSERT_RTNL();
143
144 in_dev = kmalloc(sizeof(*in_dev), GFP_KERNEL);
145 if (!in_dev)
146 goto out;
147 memset(in_dev, 0, sizeof(*in_dev));
148 INIT_RCU_HEAD(&in_dev->rcu_head);
149 memcpy(&in_dev->cnf, &ipv4_devconf_dflt, sizeof(in_dev->cnf));
150 in_dev->cnf.sysctl = NULL;
151 in_dev->dev = dev;
152 if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL)
153 goto out_kfree;
154 /* Reference in_dev->dev */
155 dev_hold(dev);
156#ifdef CONFIG_SYSCTL
157 neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
158 NET_IPV4_NEIGH, "ipv4", NULL, NULL);
159#endif
160
161 /* Account for reference dev->ip_ptr */
162 in_dev_hold(in_dev);
163 rcu_assign_pointer(dev->ip_ptr, in_dev);
164
165#ifdef CONFIG_SYSCTL
166 devinet_sysctl_register(in_dev, &in_dev->cnf);
167#endif
168 ip_mc_init_dev(in_dev);
169 if (dev->flags & IFF_UP)
170 ip_mc_up(in_dev);
171out:
172 return in_dev;
173out_kfree:
174 kfree(in_dev);
175 in_dev = NULL;
176 goto out;
177}
178
179static void in_dev_rcu_put(struct rcu_head *head)
180{
181 struct in_device *idev = container_of(head, struct in_device, rcu_head);
182 in_dev_put(idev);
183}
184
185static void inetdev_destroy(struct in_device *in_dev)
186{
187 struct in_ifaddr *ifa;
188 struct net_device *dev;
189
190 ASSERT_RTNL();
191
192 dev = in_dev->dev;
193 if (dev == &loopback_dev)
194 return;
195
196 in_dev->dead = 1;
197
198 ip_mc_destroy_dev(in_dev);
199
200 while ((ifa = in_dev->ifa_list) != NULL) {
201 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
202 inet_free_ifa(ifa);
203 }
204
205#ifdef CONFIG_SYSCTL
206 devinet_sysctl_unregister(&in_dev->cnf);
207#endif
208
209 dev->ip_ptr = NULL;
210
211#ifdef CONFIG_SYSCTL
212 neigh_sysctl_unregister(in_dev->arp_parms);
213#endif
214 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
215 arp_ifdown(dev);
216
217 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
218}
219
220int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b)
221{
222 rcu_read_lock();
223 for_primary_ifa(in_dev) {
224 if (inet_ifa_match(a, ifa)) {
225 if (!b || inet_ifa_match(b, ifa)) {
226 rcu_read_unlock();
227 return 1;
228 }
229 }
230 } endfor_ifa(in_dev);
231 rcu_read_unlock();
232 return 0;
233}
234
235static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
236 int destroy)
237{
Harald Welte8f937c62005-05-29 20:23:46 -0700238 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800239 struct in_ifaddr *ifa, *ifa1 = *ifap;
240 struct in_ifaddr *last_prim = in_dev->ifa_list;
241 struct in_ifaddr *prev_prom = NULL;
242 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
244 ASSERT_RTNL();
245
Harald Welte8f937c62005-05-29 20:23:46 -0700246 /* 1. Deleting primary ifaddr forces deletion all secondaries
247 * unless alias promotion is set
248 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
252
253 while ((ifa = *ifap1) != NULL) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800254 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
255 ifa1->ifa_scope <= ifa->ifa_scope)
256 last_prim = ifa;
257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
259 ifa1->ifa_mask != ifa->ifa_mask ||
260 !inet_ifa_match(ifa1->ifa_address, ifa)) {
261 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800262 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 continue;
264 }
265
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800266 if (!do_promote) {
Harald Welte8f937c62005-05-29 20:23:46 -0700267 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268
Harald Welte8f937c62005-05-29 20:23:46 -0700269 rtmsg_ifa(RTM_DELADDR, ifa);
270 notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa);
271 inet_free_ifa(ifa);
272 } else {
273 promote = ifa;
274 break;
275 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 }
277 }
278
279 /* 2. Unlink it */
280
281 *ifap = ifa1->ifa_next;
282
283 /* 3. Announce address deletion */
284
285 /* Send message first, then call notifier.
286 At first sight, FIB update triggered by notifier
287 will refer to already deleted ifaddr, that could confuse
288 netlink listeners. It is not true: look, gated sees
289 that route deleted and if it still thinks that ifaddr
290 is valid, it will try to restore deleted routes... Grr.
291 So that, this order is correct.
292 */
293 rtmsg_ifa(RTM_DELADDR, ifa1);
294 notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800295
296 if (promote) {
297
298 if (prev_prom) {
299 prev_prom->ifa_next = promote->ifa_next;
300 promote->ifa_next = last_prim->ifa_next;
301 last_prim->ifa_next = promote;
302 }
303
304 promote->ifa_flags &= ~IFA_F_SECONDARY;
305 rtmsg_ifa(RTM_NEWADDR, promote);
306 notifier_call_chain(&inetaddr_chain, NETDEV_UP, promote);
307 for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) {
308 if (ifa1->ifa_mask != ifa->ifa_mask ||
309 !inet_ifa_match(ifa1->ifa_address, ifa))
310 continue;
311 fib_add_ifaddr(ifa);
312 }
313
314 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 if (destroy) {
316 inet_free_ifa(ifa1);
317
318 if (!in_dev->ifa_list)
319 inetdev_destroy(in_dev);
320 }
321}
322
323static int inet_insert_ifa(struct in_ifaddr *ifa)
324{
325 struct in_device *in_dev = ifa->ifa_dev;
326 struct in_ifaddr *ifa1, **ifap, **last_primary;
327
328 ASSERT_RTNL();
329
330 if (!ifa->ifa_local) {
331 inet_free_ifa(ifa);
332 return 0;
333 }
334
335 ifa->ifa_flags &= ~IFA_F_SECONDARY;
336 last_primary = &in_dev->ifa_list;
337
338 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
339 ifap = &ifa1->ifa_next) {
340 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
341 ifa->ifa_scope <= ifa1->ifa_scope)
342 last_primary = &ifa1->ifa_next;
343 if (ifa1->ifa_mask == ifa->ifa_mask &&
344 inet_ifa_match(ifa1->ifa_address, ifa)) {
345 if (ifa1->ifa_local == ifa->ifa_local) {
346 inet_free_ifa(ifa);
347 return -EEXIST;
348 }
349 if (ifa1->ifa_scope != ifa->ifa_scope) {
350 inet_free_ifa(ifa);
351 return -EINVAL;
352 }
353 ifa->ifa_flags |= IFA_F_SECONDARY;
354 }
355 }
356
357 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
358 net_srandom(ifa->ifa_local);
359 ifap = last_primary;
360 }
361
362 ifa->ifa_next = *ifap;
363 *ifap = ifa;
364
365 /* Send message first, then call notifier.
366 Notifier will trigger FIB update, so that
367 listeners of netlink will know about new ifaddr */
368 rtmsg_ifa(RTM_NEWADDR, ifa);
369 notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
370
371 return 0;
372}
373
374static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
375{
Herbert Xue5ed6392005-10-03 14:35:55 -0700376 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
378 ASSERT_RTNL();
379
380 if (!in_dev) {
381 in_dev = inetdev_init(dev);
382 if (!in_dev) {
383 inet_free_ifa(ifa);
384 return -ENOBUFS;
385 }
386 }
387 if (ifa->ifa_dev != in_dev) {
388 BUG_TRAP(!ifa->ifa_dev);
389 in_dev_hold(in_dev);
390 ifa->ifa_dev = in_dev;
391 }
392 if (LOOPBACK(ifa->ifa_local))
393 ifa->ifa_scope = RT_SCOPE_HOST;
394 return inet_insert_ifa(ifa);
395}
396
397struct in_device *inetdev_by_index(int ifindex)
398{
399 struct net_device *dev;
400 struct in_device *in_dev = NULL;
401 read_lock(&dev_base_lock);
402 dev = __dev_get_by_index(ifindex);
403 if (dev)
404 in_dev = in_dev_get(dev);
405 read_unlock(&dev_base_lock);
406 return in_dev;
407}
408
409/* Called only from RTNL semaphored context. No locks. */
410
411struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix,
412 u32 mask)
413{
414 ASSERT_RTNL();
415
416 for_primary_ifa(in_dev) {
417 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
418 return ifa;
419 } endfor_ifa(in_dev);
420 return NULL;
421}
422
423static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
424{
425 struct rtattr **rta = arg;
426 struct in_device *in_dev;
427 struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
428 struct in_ifaddr *ifa, **ifap;
429
430 ASSERT_RTNL();
431
432 if ((in_dev = inetdev_by_index(ifm->ifa_index)) == NULL)
433 goto out;
434 __in_dev_put(in_dev);
435
436 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
437 ifap = &ifa->ifa_next) {
438 if ((rta[IFA_LOCAL - 1] &&
439 memcmp(RTA_DATA(rta[IFA_LOCAL - 1]),
440 &ifa->ifa_local, 4)) ||
441 (rta[IFA_LABEL - 1] &&
442 rtattr_strcmp(rta[IFA_LABEL - 1], ifa->ifa_label)) ||
443 (rta[IFA_ADDRESS - 1] &&
444 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
445 !inet_ifa_match(*(u32*)RTA_DATA(rta[IFA_ADDRESS - 1]),
446 ifa))))
447 continue;
448 inet_del_ifa(in_dev, ifap, 1);
449 return 0;
450 }
451out:
452 return -EADDRNOTAVAIL;
453}
454
455static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
456{
457 struct rtattr **rta = arg;
458 struct net_device *dev;
459 struct in_device *in_dev;
460 struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
461 struct in_ifaddr *ifa;
462 int rc = -EINVAL;
463
464 ASSERT_RTNL();
465
466 if (ifm->ifa_prefixlen > 32 || !rta[IFA_LOCAL - 1])
467 goto out;
468
469 rc = -ENODEV;
470 if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL)
471 goto out;
472
473 rc = -ENOBUFS;
Herbert Xue5ed6392005-10-03 14:35:55 -0700474 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 in_dev = inetdev_init(dev);
476 if (!in_dev)
477 goto out;
478 }
479
480 if ((ifa = inet_alloc_ifa()) == NULL)
481 goto out;
482
483 if (!rta[IFA_ADDRESS - 1])
484 rta[IFA_ADDRESS - 1] = rta[IFA_LOCAL - 1];
485 memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL - 1]), 4);
486 memcpy(&ifa->ifa_address, RTA_DATA(rta[IFA_ADDRESS - 1]), 4);
487 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
488 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
489 if (rta[IFA_BROADCAST - 1])
490 memcpy(&ifa->ifa_broadcast,
491 RTA_DATA(rta[IFA_BROADCAST - 1]), 4);
492 if (rta[IFA_ANYCAST - 1])
493 memcpy(&ifa->ifa_anycast, RTA_DATA(rta[IFA_ANYCAST - 1]), 4);
494 ifa->ifa_flags = ifm->ifa_flags;
495 ifa->ifa_scope = ifm->ifa_scope;
496 in_dev_hold(in_dev);
497 ifa->ifa_dev = in_dev;
498 if (rta[IFA_LABEL - 1])
499 rtattr_strlcpy(ifa->ifa_label, rta[IFA_LABEL - 1], IFNAMSIZ);
500 else
501 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
502
503 rc = inet_insert_ifa(ifa);
504out:
505 return rc;
506}
507
508/*
509 * Determine a default network mask, based on the IP address.
510 */
511
512static __inline__ int inet_abc_len(u32 addr)
513{
514 int rc = -1; /* Something else, probably a multicast. */
515
516 if (ZERONET(addr))
517 rc = 0;
518 else {
519 addr = ntohl(addr);
520
521 if (IN_CLASSA(addr))
522 rc = 8;
523 else if (IN_CLASSB(addr))
524 rc = 16;
525 else if (IN_CLASSC(addr))
526 rc = 24;
527 }
528
529 return rc;
530}
531
532
533int devinet_ioctl(unsigned int cmd, void __user *arg)
534{
535 struct ifreq ifr;
536 struct sockaddr_in sin_orig;
537 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
538 struct in_device *in_dev;
539 struct in_ifaddr **ifap = NULL;
540 struct in_ifaddr *ifa = NULL;
541 struct net_device *dev;
542 char *colon;
543 int ret = -EFAULT;
544 int tryaddrmatch = 0;
545
546 /*
547 * Fetch the caller's info block into kernel space
548 */
549
550 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
551 goto out;
552 ifr.ifr_name[IFNAMSIZ - 1] = 0;
553
554 /* save original address for comparison */
555 memcpy(&sin_orig, sin, sizeof(*sin));
556
557 colon = strchr(ifr.ifr_name, ':');
558 if (colon)
559 *colon = 0;
560
561#ifdef CONFIG_KMOD
562 dev_load(ifr.ifr_name);
563#endif
564
565 switch(cmd) {
566 case SIOCGIFADDR: /* Get interface address */
567 case SIOCGIFBRDADDR: /* Get the broadcast address */
568 case SIOCGIFDSTADDR: /* Get the destination address */
569 case SIOCGIFNETMASK: /* Get the netmask for the interface */
570 /* Note that these ioctls will not sleep,
571 so that we do not impose a lock.
572 One day we will be forced to put shlock here (I mean SMP)
573 */
574 tryaddrmatch = (sin_orig.sin_family == AF_INET);
575 memset(sin, 0, sizeof(*sin));
576 sin->sin_family = AF_INET;
577 break;
578
579 case SIOCSIFFLAGS:
580 ret = -EACCES;
581 if (!capable(CAP_NET_ADMIN))
582 goto out;
583 break;
584 case SIOCSIFADDR: /* Set interface address (and family) */
585 case SIOCSIFBRDADDR: /* Set the broadcast address */
586 case SIOCSIFDSTADDR: /* Set the destination address */
587 case SIOCSIFNETMASK: /* Set the netmask for the interface */
588 ret = -EACCES;
589 if (!capable(CAP_NET_ADMIN))
590 goto out;
591 ret = -EINVAL;
592 if (sin->sin_family != AF_INET)
593 goto out;
594 break;
595 default:
596 ret = -EINVAL;
597 goto out;
598 }
599
600 rtnl_lock();
601
602 ret = -ENODEV;
603 if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL)
604 goto done;
605
606 if (colon)
607 *colon = ':';
608
Herbert Xue5ed6392005-10-03 14:35:55 -0700609 if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 if (tryaddrmatch) {
611 /* Matthias Andree */
612 /* compare label and address (4.4BSD style) */
613 /* note: we only do this for a limited set of ioctls
614 and only if the original address family was AF_INET.
615 This is checked above. */
616 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
617 ifap = &ifa->ifa_next) {
618 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
619 sin_orig.sin_addr.s_addr ==
620 ifa->ifa_address) {
621 break; /* found */
622 }
623 }
624 }
625 /* we didn't get a match, maybe the application is
626 4.3BSD-style and passed in junk so we fall back to
627 comparing just the label */
628 if (!ifa) {
629 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
630 ifap = &ifa->ifa_next)
631 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
632 break;
633 }
634 }
635
636 ret = -EADDRNOTAVAIL;
637 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
638 goto done;
639
640 switch(cmd) {
641 case SIOCGIFADDR: /* Get interface address */
642 sin->sin_addr.s_addr = ifa->ifa_local;
643 goto rarok;
644
645 case SIOCGIFBRDADDR: /* Get the broadcast address */
646 sin->sin_addr.s_addr = ifa->ifa_broadcast;
647 goto rarok;
648
649 case SIOCGIFDSTADDR: /* Get the destination address */
650 sin->sin_addr.s_addr = ifa->ifa_address;
651 goto rarok;
652
653 case SIOCGIFNETMASK: /* Get the netmask for the interface */
654 sin->sin_addr.s_addr = ifa->ifa_mask;
655 goto rarok;
656
657 case SIOCSIFFLAGS:
658 if (colon) {
659 ret = -EADDRNOTAVAIL;
660 if (!ifa)
661 break;
662 ret = 0;
663 if (!(ifr.ifr_flags & IFF_UP))
664 inet_del_ifa(in_dev, ifap, 1);
665 break;
666 }
667 ret = dev_change_flags(dev, ifr.ifr_flags);
668 break;
669
670 case SIOCSIFADDR: /* Set interface address (and family) */
671 ret = -EINVAL;
672 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
673 break;
674
675 if (!ifa) {
676 ret = -ENOBUFS;
677 if ((ifa = inet_alloc_ifa()) == NULL)
678 break;
679 if (colon)
680 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
681 else
682 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
683 } else {
684 ret = 0;
685 if (ifa->ifa_local == sin->sin_addr.s_addr)
686 break;
687 inet_del_ifa(in_dev, ifap, 0);
688 ifa->ifa_broadcast = 0;
689 ifa->ifa_anycast = 0;
690 }
691
692 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
693
694 if (!(dev->flags & IFF_POINTOPOINT)) {
695 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
696 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
697 if ((dev->flags & IFF_BROADCAST) &&
698 ifa->ifa_prefixlen < 31)
699 ifa->ifa_broadcast = ifa->ifa_address |
700 ~ifa->ifa_mask;
701 } else {
702 ifa->ifa_prefixlen = 32;
703 ifa->ifa_mask = inet_make_mask(32);
704 }
705 ret = inet_set_ifa(dev, ifa);
706 break;
707
708 case SIOCSIFBRDADDR: /* Set the broadcast address */
709 ret = 0;
710 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
711 inet_del_ifa(in_dev, ifap, 0);
712 ifa->ifa_broadcast = sin->sin_addr.s_addr;
713 inet_insert_ifa(ifa);
714 }
715 break;
716
717 case SIOCSIFDSTADDR: /* Set the destination address */
718 ret = 0;
719 if (ifa->ifa_address == sin->sin_addr.s_addr)
720 break;
721 ret = -EINVAL;
722 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
723 break;
724 ret = 0;
725 inet_del_ifa(in_dev, ifap, 0);
726 ifa->ifa_address = sin->sin_addr.s_addr;
727 inet_insert_ifa(ifa);
728 break;
729
730 case SIOCSIFNETMASK: /* Set the netmask for the interface */
731
732 /*
733 * The mask we set must be legal.
734 */
735 ret = -EINVAL;
736 if (bad_mask(sin->sin_addr.s_addr, 0))
737 break;
738 ret = 0;
739 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
David Engeldcab5e12005-10-21 22:09:16 -0500740 u32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 inet_del_ifa(in_dev, ifap, 0);
742 ifa->ifa_mask = sin->sin_addr.s_addr;
743 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
744
745 /* See if current broadcast address matches
746 * with current netmask, then recalculate
747 * the broadcast address. Otherwise it's a
748 * funny address, so don't touch it since
749 * the user seems to know what (s)he's doing...
750 */
751 if ((dev->flags & IFF_BROADCAST) &&
752 (ifa->ifa_prefixlen < 31) &&
753 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -0500754 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 ifa->ifa_broadcast = (ifa->ifa_local |
756 ~sin->sin_addr.s_addr);
757 }
758 inet_insert_ifa(ifa);
759 }
760 break;
761 }
762done:
763 rtnl_unlock();
764out:
765 return ret;
766rarok:
767 rtnl_unlock();
768 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
769 goto out;
770}
771
772static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
773{
Herbert Xue5ed6392005-10-03 14:35:55 -0700774 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 struct in_ifaddr *ifa;
776 struct ifreq ifr;
777 int done = 0;
778
779 if (!in_dev || (ifa = in_dev->ifa_list) == NULL)
780 goto out;
781
782 for (; ifa; ifa = ifa->ifa_next) {
783 if (!buf) {
784 done += sizeof(ifr);
785 continue;
786 }
787 if (len < (int) sizeof(ifr))
788 break;
789 memset(&ifr, 0, sizeof(struct ifreq));
790 if (ifa->ifa_label)
791 strcpy(ifr.ifr_name, ifa->ifa_label);
792 else
793 strcpy(ifr.ifr_name, dev->name);
794
795 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
796 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
797 ifa->ifa_local;
798
799 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
800 done = -EFAULT;
801 break;
802 }
803 buf += sizeof(struct ifreq);
804 len -= sizeof(struct ifreq);
805 done += sizeof(struct ifreq);
806 }
807out:
808 return done;
809}
810
811u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
812{
813 u32 addr = 0;
814 struct in_device *in_dev;
815
816 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -0700817 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 if (!in_dev)
819 goto no_in_dev;
820
821 for_primary_ifa(in_dev) {
822 if (ifa->ifa_scope > scope)
823 continue;
824 if (!dst || inet_ifa_match(dst, ifa)) {
825 addr = ifa->ifa_local;
826 break;
827 }
828 if (!addr)
829 addr = ifa->ifa_local;
830 } endfor_ifa(in_dev);
831no_in_dev:
832 rcu_read_unlock();
833
834 if (addr)
835 goto out;
836
837 /* Not loopback addresses on loopback should be preferred
838 in this case. It is importnat that lo is the first interface
839 in dev_base list.
840 */
841 read_lock(&dev_base_lock);
842 rcu_read_lock();
843 for (dev = dev_base; dev; dev = dev->next) {
Herbert Xue5ed6392005-10-03 14:35:55 -0700844 if ((in_dev = __in_dev_get_rcu(dev)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 continue;
846
847 for_primary_ifa(in_dev) {
848 if (ifa->ifa_scope != RT_SCOPE_LINK &&
849 ifa->ifa_scope <= scope) {
850 addr = ifa->ifa_local;
851 goto out_unlock_both;
852 }
853 } endfor_ifa(in_dev);
854 }
855out_unlock_both:
856 read_unlock(&dev_base_lock);
857 rcu_read_unlock();
858out:
859 return addr;
860}
861
862static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst,
863 u32 local, int scope)
864{
865 int same = 0;
866 u32 addr = 0;
867
868 for_ifa(in_dev) {
869 if (!addr &&
870 (local == ifa->ifa_local || !local) &&
871 ifa->ifa_scope <= scope) {
872 addr = ifa->ifa_local;
873 if (same)
874 break;
875 }
876 if (!same) {
877 same = (!local || inet_ifa_match(local, ifa)) &&
878 (!dst || inet_ifa_match(dst, ifa));
879 if (same && addr) {
880 if (local || !dst)
881 break;
882 /* Is the selected addr into dst subnet? */
883 if (inet_ifa_match(addr, ifa))
884 break;
885 /* No, then can we use new local src? */
886 if (ifa->ifa_scope <= scope) {
887 addr = ifa->ifa_local;
888 break;
889 }
890 /* search for large dst subnet for addr */
891 same = 0;
892 }
893 }
894 } endfor_ifa(in_dev);
895
896 return same? addr : 0;
897}
898
899/*
900 * Confirm that local IP address exists using wildcards:
901 * - dev: only on this interface, 0=any interface
902 * - dst: only in the same subnet as dst, 0=any dst
903 * - local: address, 0=autoselect the local address
904 * - scope: maximum allowed scope value for the local address
905 */
906u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope)
907{
908 u32 addr = 0;
909 struct in_device *in_dev;
910
911 if (dev) {
912 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -0700913 if ((in_dev = __in_dev_get_rcu(dev)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 addr = confirm_addr_indev(in_dev, dst, local, scope);
915 rcu_read_unlock();
916
917 return addr;
918 }
919
920 read_lock(&dev_base_lock);
921 rcu_read_lock();
922 for (dev = dev_base; dev; dev = dev->next) {
Herbert Xue5ed6392005-10-03 14:35:55 -0700923 if ((in_dev = __in_dev_get_rcu(dev))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 addr = confirm_addr_indev(in_dev, dst, local, scope);
925 if (addr)
926 break;
927 }
928 }
929 rcu_read_unlock();
930 read_unlock(&dev_base_lock);
931
932 return addr;
933}
934
935/*
936 * Device notifier
937 */
938
939int register_inetaddr_notifier(struct notifier_block *nb)
940{
941 return notifier_chain_register(&inetaddr_chain, nb);
942}
943
944int unregister_inetaddr_notifier(struct notifier_block *nb)
945{
946 return notifier_chain_unregister(&inetaddr_chain, nb);
947}
948
949/* Rename ifa_labels for a device name change. Make some effort to preserve existing
950 * alias numbering and to create unique labels if possible.
951*/
952static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
953{
954 struct in_ifaddr *ifa;
955 int named = 0;
956
957 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
958 char old[IFNAMSIZ], *dot;
959
960 memcpy(old, ifa->ifa_label, IFNAMSIZ);
961 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
962 if (named++ == 0)
963 continue;
964 dot = strchr(ifa->ifa_label, ':');
965 if (dot == NULL) {
966 sprintf(old, ":%d", named);
967 dot = old;
968 }
969 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ) {
970 strcat(ifa->ifa_label, dot);
971 } else {
972 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
973 }
974 }
975}
976
977/* Called only under RTNL semaphore */
978
979static int inetdev_event(struct notifier_block *this, unsigned long event,
980 void *ptr)
981{
982 struct net_device *dev = ptr;
Herbert Xue5ed6392005-10-03 14:35:55 -0700983 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
985 ASSERT_RTNL();
986
987 if (!in_dev) {
988 if (event == NETDEV_REGISTER && dev == &loopback_dev) {
989 in_dev = inetdev_init(dev);
990 if (!in_dev)
991 panic("devinet: Failed to create loopback\n");
992 in_dev->cnf.no_xfrm = 1;
993 in_dev->cnf.no_policy = 1;
994 }
995 goto out;
996 }
997
998 switch (event) {
999 case NETDEV_REGISTER:
1000 printk(KERN_DEBUG "inetdev_event: bug\n");
1001 dev->ip_ptr = NULL;
1002 break;
1003 case NETDEV_UP:
1004 if (dev->mtu < 68)
1005 break;
1006 if (dev == &loopback_dev) {
1007 struct in_ifaddr *ifa;
1008 if ((ifa = inet_alloc_ifa()) != NULL) {
1009 ifa->ifa_local =
1010 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1011 ifa->ifa_prefixlen = 8;
1012 ifa->ifa_mask = inet_make_mask(8);
1013 in_dev_hold(in_dev);
1014 ifa->ifa_dev = in_dev;
1015 ifa->ifa_scope = RT_SCOPE_HOST;
1016 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1017 inet_insert_ifa(ifa);
1018 }
1019 }
1020 ip_mc_up(in_dev);
1021 break;
1022 case NETDEV_DOWN:
1023 ip_mc_down(in_dev);
1024 break;
1025 case NETDEV_CHANGEMTU:
1026 if (dev->mtu >= 68)
1027 break;
1028 /* MTU falled under 68, disable IP */
1029 case NETDEV_UNREGISTER:
1030 inetdev_destroy(in_dev);
1031 break;
1032 case NETDEV_CHANGENAME:
1033 /* Do not notify about label change, this event is
1034 * not interesting to applications using netlink.
1035 */
1036 inetdev_changename(dev, in_dev);
1037
1038#ifdef CONFIG_SYSCTL
1039 devinet_sysctl_unregister(&in_dev->cnf);
1040 neigh_sysctl_unregister(in_dev->arp_parms);
1041 neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
1042 NET_IPV4_NEIGH, "ipv4", NULL, NULL);
1043 devinet_sysctl_register(in_dev, &in_dev->cnf);
1044#endif
1045 break;
1046 }
1047out:
1048 return NOTIFY_DONE;
1049}
1050
1051static struct notifier_block ip_netdev_notifier = {
1052 .notifier_call =inetdev_event,
1053};
1054
1055static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07001056 u32 pid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057{
1058 struct ifaddrmsg *ifm;
1059 struct nlmsghdr *nlh;
1060 unsigned char *b = skb->tail;
1061
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07001062 nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 ifm = NLMSG_DATA(nlh);
1064 ifm->ifa_family = AF_INET;
1065 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
1066 ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT;
1067 ifm->ifa_scope = ifa->ifa_scope;
1068 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
1069 if (ifa->ifa_address)
1070 RTA_PUT(skb, IFA_ADDRESS, 4, &ifa->ifa_address);
1071 if (ifa->ifa_local)
1072 RTA_PUT(skb, IFA_LOCAL, 4, &ifa->ifa_local);
1073 if (ifa->ifa_broadcast)
1074 RTA_PUT(skb, IFA_BROADCAST, 4, &ifa->ifa_broadcast);
1075 if (ifa->ifa_anycast)
1076 RTA_PUT(skb, IFA_ANYCAST, 4, &ifa->ifa_anycast);
1077 if (ifa->ifa_label[0])
1078 RTA_PUT(skb, IFA_LABEL, IFNAMSIZ, &ifa->ifa_label);
1079 nlh->nlmsg_len = skb->tail - b;
1080 return skb->len;
1081
1082nlmsg_failure:
1083rtattr_failure:
1084 skb_trim(skb, b - skb->data);
1085 return -1;
1086}
1087
1088static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1089{
1090 int idx, ip_idx;
1091 struct net_device *dev;
1092 struct in_device *in_dev;
1093 struct in_ifaddr *ifa;
1094 int s_ip_idx, s_idx = cb->args[0];
1095
1096 s_ip_idx = ip_idx = cb->args[1];
1097 read_lock(&dev_base_lock);
1098 for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
1099 if (idx < s_idx)
1100 continue;
1101 if (idx > s_idx)
1102 s_ip_idx = 0;
1103 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001104 if ((in_dev = __in_dev_get_rcu(dev)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 rcu_read_unlock();
1106 continue;
1107 }
1108
1109 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1110 ifa = ifa->ifa_next, ip_idx++) {
1111 if (ip_idx < s_ip_idx)
1112 continue;
1113 if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
1114 cb->nlh->nlmsg_seq,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07001115 RTM_NEWADDR, NLM_F_MULTI) <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 rcu_read_unlock();
1117 goto done;
1118 }
1119 }
1120 rcu_read_unlock();
1121 }
1122
1123done:
1124 read_unlock(&dev_base_lock);
1125 cb->args[0] = idx;
1126 cb->args[1] = ip_idx;
1127
1128 return skb->len;
1129}
1130
1131static void rtmsg_ifa(int event, struct in_ifaddr* ifa)
1132{
1133 int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + 128);
1134 struct sk_buff *skb = alloc_skb(size, GFP_KERNEL);
1135
1136 if (!skb)
Patrick McHardyac6d4392005-08-14 19:29:52 -07001137 netlink_set_err(rtnl, 0, RTNLGRP_IPV4_IFADDR, ENOBUFS);
Alexey Kuznetsov28633512006-02-09 16:40:58 -08001138 else if (inet_fill_ifaddr(skb, ifa, 0, 0, event, 0) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 kfree_skb(skb);
Patrick McHardyac6d4392005-08-14 19:29:52 -07001140 netlink_set_err(rtnl, 0, RTNLGRP_IPV4_IFADDR, EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 } else {
Patrick McHardyac6d4392005-08-14 19:29:52 -07001142 netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV4_IFADDR, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 }
1144}
1145
Thomas Grafdb46edc2005-05-03 14:29:39 -07001146static struct rtnetlink_link inet_rtnetlink_table[RTM_NR_MSGTYPES] = {
1147 [RTM_NEWADDR - RTM_BASE] = { .doit = inet_rtm_newaddr, },
1148 [RTM_DELADDR - RTM_BASE] = { .doit = inet_rtm_deladdr, },
1149 [RTM_GETADDR - RTM_BASE] = { .dumpit = inet_dump_ifaddr, },
1150 [RTM_NEWROUTE - RTM_BASE] = { .doit = inet_rtm_newroute, },
1151 [RTM_DELROUTE - RTM_BASE] = { .doit = inet_rtm_delroute, },
1152 [RTM_GETROUTE - RTM_BASE] = { .doit = inet_rtm_getroute,
1153 .dumpit = inet_dump_fib, },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154#ifdef CONFIG_IP_MULTIPLE_TABLES
Thomas Grafdb46edc2005-05-03 14:29:39 -07001155 [RTM_NEWRULE - RTM_BASE] = { .doit = inet_rtm_newrule, },
1156 [RTM_DELRULE - RTM_BASE] = { .doit = inet_rtm_delrule, },
1157 [RTM_GETRULE - RTM_BASE] = { .dumpit = inet_dump_rules, },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158#endif
1159};
1160
1161#ifdef CONFIG_SYSCTL
1162
1163void inet_forward_change(void)
1164{
1165 struct net_device *dev;
1166 int on = ipv4_devconf.forwarding;
1167
1168 ipv4_devconf.accept_redirects = !on;
1169 ipv4_devconf_dflt.forwarding = on;
1170
1171 read_lock(&dev_base_lock);
1172 for (dev = dev_base; dev; dev = dev->next) {
1173 struct in_device *in_dev;
1174 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001175 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 if (in_dev)
1177 in_dev->cnf.forwarding = on;
1178 rcu_read_unlock();
1179 }
1180 read_unlock(&dev_base_lock);
1181
1182 rt_cache_flush(0);
1183}
1184
1185static int devinet_sysctl_forward(ctl_table *ctl, int write,
1186 struct file* filp, void __user *buffer,
1187 size_t *lenp, loff_t *ppos)
1188{
1189 int *valp = ctl->data;
1190 int val = *valp;
1191 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1192
1193 if (write && *valp != val) {
1194 if (valp == &ipv4_devconf.forwarding)
1195 inet_forward_change();
1196 else if (valp != &ipv4_devconf_dflt.forwarding)
1197 rt_cache_flush(0);
1198 }
1199
1200 return ret;
1201}
1202
1203int ipv4_doint_and_flush(ctl_table *ctl, int write,
1204 struct file* filp, void __user *buffer,
1205 size_t *lenp, loff_t *ppos)
1206{
1207 int *valp = ctl->data;
1208 int val = *valp;
1209 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1210
1211 if (write && *valp != val)
1212 rt_cache_flush(0);
1213
1214 return ret;
1215}
1216
1217int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
1218 void __user *oldval, size_t __user *oldlenp,
1219 void __user *newval, size_t newlen,
1220 void **context)
1221{
1222 int *valp = table->data;
1223 int new;
1224
1225 if (!newval || !newlen)
1226 return 0;
1227
1228 if (newlen != sizeof(int))
1229 return -EINVAL;
1230
1231 if (get_user(new, (int __user *)newval))
1232 return -EFAULT;
1233
1234 if (new == *valp)
1235 return 0;
1236
1237 if (oldval && oldlenp) {
1238 size_t len;
1239
1240 if (get_user(len, oldlenp))
1241 return -EFAULT;
1242
1243 if (len) {
1244 if (len > table->maxlen)
1245 len = table->maxlen;
1246 if (copy_to_user(oldval, valp, len))
1247 return -EFAULT;
1248 if (put_user(len, oldlenp))
1249 return -EFAULT;
1250 }
1251 }
1252
1253 *valp = new;
1254 rt_cache_flush(0);
1255 return 1;
1256}
1257
1258
1259static struct devinet_sysctl_table {
1260 struct ctl_table_header *sysctl_header;
1261 ctl_table devinet_vars[__NET_IPV4_CONF_MAX];
1262 ctl_table devinet_dev[2];
1263 ctl_table devinet_conf_dir[2];
1264 ctl_table devinet_proto_dir[2];
1265 ctl_table devinet_root_dir[2];
1266} devinet_sysctl = {
1267 .devinet_vars = {
1268 {
1269 .ctl_name = NET_IPV4_CONF_FORWARDING,
1270 .procname = "forwarding",
1271 .data = &ipv4_devconf.forwarding,
1272 .maxlen = sizeof(int),
1273 .mode = 0644,
1274 .proc_handler = &devinet_sysctl_forward,
1275 },
1276 {
1277 .ctl_name = NET_IPV4_CONF_MC_FORWARDING,
1278 .procname = "mc_forwarding",
1279 .data = &ipv4_devconf.mc_forwarding,
1280 .maxlen = sizeof(int),
1281 .mode = 0444,
1282 .proc_handler = &proc_dointvec,
1283 },
1284 {
1285 .ctl_name = NET_IPV4_CONF_ACCEPT_REDIRECTS,
1286 .procname = "accept_redirects",
1287 .data = &ipv4_devconf.accept_redirects,
1288 .maxlen = sizeof(int),
1289 .mode = 0644,
1290 .proc_handler = &proc_dointvec,
1291 },
1292 {
1293 .ctl_name = NET_IPV4_CONF_SECURE_REDIRECTS,
1294 .procname = "secure_redirects",
1295 .data = &ipv4_devconf.secure_redirects,
1296 .maxlen = sizeof(int),
1297 .mode = 0644,
1298 .proc_handler = &proc_dointvec,
1299 },
1300 {
1301 .ctl_name = NET_IPV4_CONF_SHARED_MEDIA,
1302 .procname = "shared_media",
1303 .data = &ipv4_devconf.shared_media,
1304 .maxlen = sizeof(int),
1305 .mode = 0644,
1306 .proc_handler = &proc_dointvec,
1307 },
1308 {
1309 .ctl_name = NET_IPV4_CONF_RP_FILTER,
1310 .procname = "rp_filter",
1311 .data = &ipv4_devconf.rp_filter,
1312 .maxlen = sizeof(int),
1313 .mode = 0644,
1314 .proc_handler = &proc_dointvec,
1315 },
1316 {
1317 .ctl_name = NET_IPV4_CONF_SEND_REDIRECTS,
1318 .procname = "send_redirects",
1319 .data = &ipv4_devconf.send_redirects,
1320 .maxlen = sizeof(int),
1321 .mode = 0644,
1322 .proc_handler = &proc_dointvec,
1323 },
1324 {
1325 .ctl_name = NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE,
1326 .procname = "accept_source_route",
1327 .data = &ipv4_devconf.accept_source_route,
1328 .maxlen = sizeof(int),
1329 .mode = 0644,
1330 .proc_handler = &proc_dointvec,
1331 },
1332 {
1333 .ctl_name = NET_IPV4_CONF_PROXY_ARP,
1334 .procname = "proxy_arp",
1335 .data = &ipv4_devconf.proxy_arp,
1336 .maxlen = sizeof(int),
1337 .mode = 0644,
1338 .proc_handler = &proc_dointvec,
1339 },
1340 {
1341 .ctl_name = NET_IPV4_CONF_MEDIUM_ID,
1342 .procname = "medium_id",
1343 .data = &ipv4_devconf.medium_id,
1344 .maxlen = sizeof(int),
1345 .mode = 0644,
1346 .proc_handler = &proc_dointvec,
1347 },
1348 {
1349 .ctl_name = NET_IPV4_CONF_BOOTP_RELAY,
1350 .procname = "bootp_relay",
1351 .data = &ipv4_devconf.bootp_relay,
1352 .maxlen = sizeof(int),
1353 .mode = 0644,
1354 .proc_handler = &proc_dointvec,
1355 },
1356 {
1357 .ctl_name = NET_IPV4_CONF_LOG_MARTIANS,
1358 .procname = "log_martians",
1359 .data = &ipv4_devconf.log_martians,
1360 .maxlen = sizeof(int),
1361 .mode = 0644,
1362 .proc_handler = &proc_dointvec,
1363 },
1364 {
1365 .ctl_name = NET_IPV4_CONF_TAG,
1366 .procname = "tag",
1367 .data = &ipv4_devconf.tag,
1368 .maxlen = sizeof(int),
1369 .mode = 0644,
1370 .proc_handler = &proc_dointvec,
1371 },
1372 {
1373 .ctl_name = NET_IPV4_CONF_ARPFILTER,
1374 .procname = "arp_filter",
1375 .data = &ipv4_devconf.arp_filter,
1376 .maxlen = sizeof(int),
1377 .mode = 0644,
1378 .proc_handler = &proc_dointvec,
1379 },
1380 {
1381 .ctl_name = NET_IPV4_CONF_ARP_ANNOUNCE,
1382 .procname = "arp_announce",
1383 .data = &ipv4_devconf.arp_announce,
1384 .maxlen = sizeof(int),
1385 .mode = 0644,
1386 .proc_handler = &proc_dointvec,
1387 },
1388 {
1389 .ctl_name = NET_IPV4_CONF_ARP_IGNORE,
1390 .procname = "arp_ignore",
1391 .data = &ipv4_devconf.arp_ignore,
1392 .maxlen = sizeof(int),
1393 .mode = 0644,
1394 .proc_handler = &proc_dointvec,
1395 },
1396 {
Neil Hormanabd596a2006-03-20 22:39:47 -08001397 .ctl_name = NET_IPV4_CONF_ARP_ACCEPT,
1398 .procname = "arp_accept",
1399 .data = &ipv4_devconf.arp_accept,
1400 .maxlen = sizeof(int),
1401 .mode = 0644,
1402 .proc_handler = &proc_dointvec,
1403 },
1404 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 .ctl_name = NET_IPV4_CONF_NOXFRM,
1406 .procname = "disable_xfrm",
1407 .data = &ipv4_devconf.no_xfrm,
1408 .maxlen = sizeof(int),
1409 .mode = 0644,
1410 .proc_handler = &ipv4_doint_and_flush,
1411 .strategy = &ipv4_doint_and_flush_strategy,
1412 },
1413 {
1414 .ctl_name = NET_IPV4_CONF_NOPOLICY,
1415 .procname = "disable_policy",
1416 .data = &ipv4_devconf.no_policy,
1417 .maxlen = sizeof(int),
1418 .mode = 0644,
1419 .proc_handler = &ipv4_doint_and_flush,
1420 .strategy = &ipv4_doint_and_flush_strategy,
1421 },
1422 {
1423 .ctl_name = NET_IPV4_CONF_FORCE_IGMP_VERSION,
1424 .procname = "force_igmp_version",
1425 .data = &ipv4_devconf.force_igmp_version,
1426 .maxlen = sizeof(int),
1427 .mode = 0644,
1428 .proc_handler = &ipv4_doint_and_flush,
1429 .strategy = &ipv4_doint_and_flush_strategy,
1430 },
Harald Welte8f937c62005-05-29 20:23:46 -07001431 {
1432 .ctl_name = NET_IPV4_CONF_PROMOTE_SECONDARIES,
1433 .procname = "promote_secondaries",
1434 .data = &ipv4_devconf.promote_secondaries,
1435 .maxlen = sizeof(int),
1436 .mode = 0644,
1437 .proc_handler = &ipv4_doint_and_flush,
1438 .strategy = &ipv4_doint_and_flush_strategy,
1439 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 },
1441 .devinet_dev = {
1442 {
1443 .ctl_name = NET_PROTO_CONF_ALL,
1444 .procname = "all",
1445 .mode = 0555,
1446 .child = devinet_sysctl.devinet_vars,
1447 },
1448 },
1449 .devinet_conf_dir = {
1450 {
1451 .ctl_name = NET_IPV4_CONF,
1452 .procname = "conf",
1453 .mode = 0555,
1454 .child = devinet_sysctl.devinet_dev,
1455 },
1456 },
1457 .devinet_proto_dir = {
1458 {
1459 .ctl_name = NET_IPV4,
1460 .procname = "ipv4",
1461 .mode = 0555,
1462 .child = devinet_sysctl.devinet_conf_dir,
1463 },
1464 },
1465 .devinet_root_dir = {
1466 {
1467 .ctl_name = CTL_NET,
1468 .procname = "net",
1469 .mode = 0555,
1470 .child = devinet_sysctl.devinet_proto_dir,
1471 },
1472 },
1473};
1474
1475static void devinet_sysctl_register(struct in_device *in_dev,
1476 struct ipv4_devconf *p)
1477{
1478 int i;
1479 struct net_device *dev = in_dev ? in_dev->dev : NULL;
1480 struct devinet_sysctl_table *t = kmalloc(sizeof(*t), GFP_KERNEL);
1481 char *dev_name = NULL;
1482
1483 if (!t)
1484 return;
1485 memcpy(t, &devinet_sysctl, sizeof(*t));
1486 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
1487 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
1488 t->devinet_vars[i].de = NULL;
1489 }
1490
1491 if (dev) {
1492 dev_name = dev->name;
1493 t->devinet_dev[0].ctl_name = dev->ifindex;
1494 } else {
1495 dev_name = "default";
1496 t->devinet_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT;
1497 }
1498
1499 /*
1500 * Make a copy of dev_name, because '.procname' is regarded as const
1501 * by sysctl and we wouldn't want anyone to change it under our feet
1502 * (see SIOCSIFNAME).
1503 */
Paulo Marques543537b2005-06-23 00:09:02 -07001504 dev_name = kstrdup(dev_name, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 if (!dev_name)
1506 goto free;
1507
1508 t->devinet_dev[0].procname = dev_name;
1509 t->devinet_dev[0].child = t->devinet_vars;
1510 t->devinet_dev[0].de = NULL;
1511 t->devinet_conf_dir[0].child = t->devinet_dev;
1512 t->devinet_conf_dir[0].de = NULL;
1513 t->devinet_proto_dir[0].child = t->devinet_conf_dir;
1514 t->devinet_proto_dir[0].de = NULL;
1515 t->devinet_root_dir[0].child = t->devinet_proto_dir;
1516 t->devinet_root_dir[0].de = NULL;
1517
1518 t->sysctl_header = register_sysctl_table(t->devinet_root_dir, 0);
1519 if (!t->sysctl_header)
1520 goto free_procname;
1521
1522 p->sysctl = t;
1523 return;
1524
1525 /* error path */
1526 free_procname:
1527 kfree(dev_name);
1528 free:
1529 kfree(t);
1530 return;
1531}
1532
1533static void devinet_sysctl_unregister(struct ipv4_devconf *p)
1534{
1535 if (p->sysctl) {
1536 struct devinet_sysctl_table *t = p->sysctl;
1537 p->sysctl = NULL;
1538 unregister_sysctl_table(t->sysctl_header);
1539 kfree(t->devinet_dev[0].procname);
1540 kfree(t);
1541 }
1542}
1543#endif
1544
1545void __init devinet_init(void)
1546{
1547 register_gifconf(PF_INET, inet_gifconf);
1548 register_netdevice_notifier(&ip_netdev_notifier);
1549 rtnetlink_links[PF_INET] = inet_rtnetlink_table;
1550#ifdef CONFIG_SYSCTL
1551 devinet_sysctl.sysctl_header =
1552 register_sysctl_table(devinet_sysctl.devinet_root_dir, 0);
1553 devinet_sysctl_register(NULL, &ipv4_devconf_dflt);
1554#endif
1555}
1556
1557EXPORT_SYMBOL(devinet_ioctl);
1558EXPORT_SYMBOL(in_dev_finish_destroy);
1559EXPORT_SYMBOL(inet_select_addr);
1560EXPORT_SYMBOL(inetdev_by_index);
1561EXPORT_SYMBOL(register_inetaddr_notifier);
1562EXPORT_SYMBOL(unregister_inetaddr_notifier);