blob: 54419b27686f86f33e370c4241235ef5bc723034 [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
Alan Sterne041c682006-03-27 01:16:30 -080084static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085static 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);
Alan Sterne041c682006-03-27 01:16:30 -0800270 blocking_notifier_call_chain(&inetaddr_chain,
271 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700272 inet_free_ifa(ifa);
273 } else {
274 promote = ifa;
275 break;
276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 }
278 }
279
280 /* 2. Unlink it */
281
282 *ifap = ifa1->ifa_next;
283
284 /* 3. Announce address deletion */
285
286 /* Send message first, then call notifier.
287 At first sight, FIB update triggered by notifier
288 will refer to already deleted ifaddr, that could confuse
289 netlink listeners. It is not true: look, gated sees
290 that route deleted and if it still thinks that ifaddr
291 is valid, it will try to restore deleted routes... Grr.
292 So that, this order is correct.
293 */
294 rtmsg_ifa(RTM_DELADDR, ifa1);
Alan Sterne041c682006-03-27 01:16:30 -0800295 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800296
297 if (promote) {
298
299 if (prev_prom) {
300 prev_prom->ifa_next = promote->ifa_next;
301 promote->ifa_next = last_prim->ifa_next;
302 last_prim->ifa_next = promote;
303 }
304
305 promote->ifa_flags &= ~IFA_F_SECONDARY;
306 rtmsg_ifa(RTM_NEWADDR, promote);
Alan Sterne041c682006-03-27 01:16:30 -0800307 blocking_notifier_call_chain(&inetaddr_chain,
308 NETDEV_UP, promote);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800309 for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) {
310 if (ifa1->ifa_mask != ifa->ifa_mask ||
311 !inet_ifa_match(ifa1->ifa_address, ifa))
312 continue;
313 fib_add_ifaddr(ifa);
314 }
315
316 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 if (destroy) {
318 inet_free_ifa(ifa1);
319
320 if (!in_dev->ifa_list)
321 inetdev_destroy(in_dev);
322 }
323}
324
325static int inet_insert_ifa(struct in_ifaddr *ifa)
326{
327 struct in_device *in_dev = ifa->ifa_dev;
328 struct in_ifaddr *ifa1, **ifap, **last_primary;
329
330 ASSERT_RTNL();
331
332 if (!ifa->ifa_local) {
333 inet_free_ifa(ifa);
334 return 0;
335 }
336
337 ifa->ifa_flags &= ~IFA_F_SECONDARY;
338 last_primary = &in_dev->ifa_list;
339
340 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
341 ifap = &ifa1->ifa_next) {
342 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
343 ifa->ifa_scope <= ifa1->ifa_scope)
344 last_primary = &ifa1->ifa_next;
345 if (ifa1->ifa_mask == ifa->ifa_mask &&
346 inet_ifa_match(ifa1->ifa_address, ifa)) {
347 if (ifa1->ifa_local == ifa->ifa_local) {
348 inet_free_ifa(ifa);
349 return -EEXIST;
350 }
351 if (ifa1->ifa_scope != ifa->ifa_scope) {
352 inet_free_ifa(ifa);
353 return -EINVAL;
354 }
355 ifa->ifa_flags |= IFA_F_SECONDARY;
356 }
357 }
358
359 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
360 net_srandom(ifa->ifa_local);
361 ifap = last_primary;
362 }
363
364 ifa->ifa_next = *ifap;
365 *ifap = ifa;
366
367 /* Send message first, then call notifier.
368 Notifier will trigger FIB update, so that
369 listeners of netlink will know about new ifaddr */
370 rtmsg_ifa(RTM_NEWADDR, ifa);
Alan Sterne041c682006-03-27 01:16:30 -0800371 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
373 return 0;
374}
375
376static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
377{
Herbert Xue5ed6392005-10-03 14:35:55 -0700378 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380 ASSERT_RTNL();
381
382 if (!in_dev) {
383 in_dev = inetdev_init(dev);
384 if (!in_dev) {
385 inet_free_ifa(ifa);
386 return -ENOBUFS;
387 }
388 }
389 if (ifa->ifa_dev != in_dev) {
390 BUG_TRAP(!ifa->ifa_dev);
391 in_dev_hold(in_dev);
392 ifa->ifa_dev = in_dev;
393 }
394 if (LOOPBACK(ifa->ifa_local))
395 ifa->ifa_scope = RT_SCOPE_HOST;
396 return inet_insert_ifa(ifa);
397}
398
399struct in_device *inetdev_by_index(int ifindex)
400{
401 struct net_device *dev;
402 struct in_device *in_dev = NULL;
403 read_lock(&dev_base_lock);
404 dev = __dev_get_by_index(ifindex);
405 if (dev)
406 in_dev = in_dev_get(dev);
407 read_unlock(&dev_base_lock);
408 return in_dev;
409}
410
411/* Called only from RTNL semaphored context. No locks. */
412
413struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix,
414 u32 mask)
415{
416 ASSERT_RTNL();
417
418 for_primary_ifa(in_dev) {
419 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
420 return ifa;
421 } endfor_ifa(in_dev);
422 return NULL;
423}
424
425static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
426{
427 struct rtattr **rta = arg;
428 struct in_device *in_dev;
429 struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
430 struct in_ifaddr *ifa, **ifap;
431
432 ASSERT_RTNL();
433
434 if ((in_dev = inetdev_by_index(ifm->ifa_index)) == NULL)
435 goto out;
436 __in_dev_put(in_dev);
437
438 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
439 ifap = &ifa->ifa_next) {
440 if ((rta[IFA_LOCAL - 1] &&
441 memcmp(RTA_DATA(rta[IFA_LOCAL - 1]),
442 &ifa->ifa_local, 4)) ||
443 (rta[IFA_LABEL - 1] &&
444 rtattr_strcmp(rta[IFA_LABEL - 1], ifa->ifa_label)) ||
445 (rta[IFA_ADDRESS - 1] &&
446 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
447 !inet_ifa_match(*(u32*)RTA_DATA(rta[IFA_ADDRESS - 1]),
448 ifa))))
449 continue;
450 inet_del_ifa(in_dev, ifap, 1);
451 return 0;
452 }
453out:
454 return -EADDRNOTAVAIL;
455}
456
457static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
458{
459 struct rtattr **rta = arg;
460 struct net_device *dev;
461 struct in_device *in_dev;
462 struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
463 struct in_ifaddr *ifa;
464 int rc = -EINVAL;
465
466 ASSERT_RTNL();
467
468 if (ifm->ifa_prefixlen > 32 || !rta[IFA_LOCAL - 1])
469 goto out;
470
471 rc = -ENODEV;
472 if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL)
473 goto out;
474
475 rc = -ENOBUFS;
Herbert Xue5ed6392005-10-03 14:35:55 -0700476 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 in_dev = inetdev_init(dev);
478 if (!in_dev)
479 goto out;
480 }
481
482 if ((ifa = inet_alloc_ifa()) == NULL)
483 goto out;
484
485 if (!rta[IFA_ADDRESS - 1])
486 rta[IFA_ADDRESS - 1] = rta[IFA_LOCAL - 1];
487 memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL - 1]), 4);
488 memcpy(&ifa->ifa_address, RTA_DATA(rta[IFA_ADDRESS - 1]), 4);
489 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
490 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
491 if (rta[IFA_BROADCAST - 1])
492 memcpy(&ifa->ifa_broadcast,
493 RTA_DATA(rta[IFA_BROADCAST - 1]), 4);
494 if (rta[IFA_ANYCAST - 1])
495 memcpy(&ifa->ifa_anycast, RTA_DATA(rta[IFA_ANYCAST - 1]), 4);
496 ifa->ifa_flags = ifm->ifa_flags;
497 ifa->ifa_scope = ifm->ifa_scope;
498 in_dev_hold(in_dev);
499 ifa->ifa_dev = in_dev;
500 if (rta[IFA_LABEL - 1])
501 rtattr_strlcpy(ifa->ifa_label, rta[IFA_LABEL - 1], IFNAMSIZ);
502 else
503 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
504
505 rc = inet_insert_ifa(ifa);
506out:
507 return rc;
508}
509
510/*
511 * Determine a default network mask, based on the IP address.
512 */
513
514static __inline__ int inet_abc_len(u32 addr)
515{
516 int rc = -1; /* Something else, probably a multicast. */
517
518 if (ZERONET(addr))
519 rc = 0;
520 else {
521 addr = ntohl(addr);
522
523 if (IN_CLASSA(addr))
524 rc = 8;
525 else if (IN_CLASSB(addr))
526 rc = 16;
527 else if (IN_CLASSC(addr))
528 rc = 24;
529 }
530
531 return rc;
532}
533
534
535int devinet_ioctl(unsigned int cmd, void __user *arg)
536{
537 struct ifreq ifr;
538 struct sockaddr_in sin_orig;
539 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
540 struct in_device *in_dev;
541 struct in_ifaddr **ifap = NULL;
542 struct in_ifaddr *ifa = NULL;
543 struct net_device *dev;
544 char *colon;
545 int ret = -EFAULT;
546 int tryaddrmatch = 0;
547
548 /*
549 * Fetch the caller's info block into kernel space
550 */
551
552 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
553 goto out;
554 ifr.ifr_name[IFNAMSIZ - 1] = 0;
555
556 /* save original address for comparison */
557 memcpy(&sin_orig, sin, sizeof(*sin));
558
559 colon = strchr(ifr.ifr_name, ':');
560 if (colon)
561 *colon = 0;
562
563#ifdef CONFIG_KMOD
564 dev_load(ifr.ifr_name);
565#endif
566
567 switch(cmd) {
568 case SIOCGIFADDR: /* Get interface address */
569 case SIOCGIFBRDADDR: /* Get the broadcast address */
570 case SIOCGIFDSTADDR: /* Get the destination address */
571 case SIOCGIFNETMASK: /* Get the netmask for the interface */
572 /* Note that these ioctls will not sleep,
573 so that we do not impose a lock.
574 One day we will be forced to put shlock here (I mean SMP)
575 */
576 tryaddrmatch = (sin_orig.sin_family == AF_INET);
577 memset(sin, 0, sizeof(*sin));
578 sin->sin_family = AF_INET;
579 break;
580
581 case SIOCSIFFLAGS:
582 ret = -EACCES;
583 if (!capable(CAP_NET_ADMIN))
584 goto out;
585 break;
586 case SIOCSIFADDR: /* Set interface address (and family) */
587 case SIOCSIFBRDADDR: /* Set the broadcast address */
588 case SIOCSIFDSTADDR: /* Set the destination address */
589 case SIOCSIFNETMASK: /* Set the netmask for the interface */
590 ret = -EACCES;
591 if (!capable(CAP_NET_ADMIN))
592 goto out;
593 ret = -EINVAL;
594 if (sin->sin_family != AF_INET)
595 goto out;
596 break;
597 default:
598 ret = -EINVAL;
599 goto out;
600 }
601
602 rtnl_lock();
603
604 ret = -ENODEV;
605 if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL)
606 goto done;
607
608 if (colon)
609 *colon = ':';
610
Herbert Xue5ed6392005-10-03 14:35:55 -0700611 if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 if (tryaddrmatch) {
613 /* Matthias Andree */
614 /* compare label and address (4.4BSD style) */
615 /* note: we only do this for a limited set of ioctls
616 and only if the original address family was AF_INET.
617 This is checked above. */
618 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
619 ifap = &ifa->ifa_next) {
620 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
621 sin_orig.sin_addr.s_addr ==
622 ifa->ifa_address) {
623 break; /* found */
624 }
625 }
626 }
627 /* we didn't get a match, maybe the application is
628 4.3BSD-style and passed in junk so we fall back to
629 comparing just the label */
630 if (!ifa) {
631 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
632 ifap = &ifa->ifa_next)
633 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
634 break;
635 }
636 }
637
638 ret = -EADDRNOTAVAIL;
639 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
640 goto done;
641
642 switch(cmd) {
643 case SIOCGIFADDR: /* Get interface address */
644 sin->sin_addr.s_addr = ifa->ifa_local;
645 goto rarok;
646
647 case SIOCGIFBRDADDR: /* Get the broadcast address */
648 sin->sin_addr.s_addr = ifa->ifa_broadcast;
649 goto rarok;
650
651 case SIOCGIFDSTADDR: /* Get the destination address */
652 sin->sin_addr.s_addr = ifa->ifa_address;
653 goto rarok;
654
655 case SIOCGIFNETMASK: /* Get the netmask for the interface */
656 sin->sin_addr.s_addr = ifa->ifa_mask;
657 goto rarok;
658
659 case SIOCSIFFLAGS:
660 if (colon) {
661 ret = -EADDRNOTAVAIL;
662 if (!ifa)
663 break;
664 ret = 0;
665 if (!(ifr.ifr_flags & IFF_UP))
666 inet_del_ifa(in_dev, ifap, 1);
667 break;
668 }
669 ret = dev_change_flags(dev, ifr.ifr_flags);
670 break;
671
672 case SIOCSIFADDR: /* Set interface address (and family) */
673 ret = -EINVAL;
674 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
675 break;
676
677 if (!ifa) {
678 ret = -ENOBUFS;
679 if ((ifa = inet_alloc_ifa()) == NULL)
680 break;
681 if (colon)
682 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
683 else
684 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
685 } else {
686 ret = 0;
687 if (ifa->ifa_local == sin->sin_addr.s_addr)
688 break;
689 inet_del_ifa(in_dev, ifap, 0);
690 ifa->ifa_broadcast = 0;
691 ifa->ifa_anycast = 0;
692 }
693
694 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
695
696 if (!(dev->flags & IFF_POINTOPOINT)) {
697 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
698 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
699 if ((dev->flags & IFF_BROADCAST) &&
700 ifa->ifa_prefixlen < 31)
701 ifa->ifa_broadcast = ifa->ifa_address |
702 ~ifa->ifa_mask;
703 } else {
704 ifa->ifa_prefixlen = 32;
705 ifa->ifa_mask = inet_make_mask(32);
706 }
707 ret = inet_set_ifa(dev, ifa);
708 break;
709
710 case SIOCSIFBRDADDR: /* Set the broadcast address */
711 ret = 0;
712 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
713 inet_del_ifa(in_dev, ifap, 0);
714 ifa->ifa_broadcast = sin->sin_addr.s_addr;
715 inet_insert_ifa(ifa);
716 }
717 break;
718
719 case SIOCSIFDSTADDR: /* Set the destination address */
720 ret = 0;
721 if (ifa->ifa_address == sin->sin_addr.s_addr)
722 break;
723 ret = -EINVAL;
724 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
725 break;
726 ret = 0;
727 inet_del_ifa(in_dev, ifap, 0);
728 ifa->ifa_address = sin->sin_addr.s_addr;
729 inet_insert_ifa(ifa);
730 break;
731
732 case SIOCSIFNETMASK: /* Set the netmask for the interface */
733
734 /*
735 * The mask we set must be legal.
736 */
737 ret = -EINVAL;
738 if (bad_mask(sin->sin_addr.s_addr, 0))
739 break;
740 ret = 0;
741 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
David Engeldcab5e12005-10-21 22:09:16 -0500742 u32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 inet_del_ifa(in_dev, ifap, 0);
744 ifa->ifa_mask = sin->sin_addr.s_addr;
745 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
746
747 /* See if current broadcast address matches
748 * with current netmask, then recalculate
749 * the broadcast address. Otherwise it's a
750 * funny address, so don't touch it since
751 * the user seems to know what (s)he's doing...
752 */
753 if ((dev->flags & IFF_BROADCAST) &&
754 (ifa->ifa_prefixlen < 31) &&
755 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -0500756 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 ifa->ifa_broadcast = (ifa->ifa_local |
758 ~sin->sin_addr.s_addr);
759 }
760 inet_insert_ifa(ifa);
761 }
762 break;
763 }
764done:
765 rtnl_unlock();
766out:
767 return ret;
768rarok:
769 rtnl_unlock();
770 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
771 goto out;
772}
773
774static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
775{
Herbert Xue5ed6392005-10-03 14:35:55 -0700776 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 struct in_ifaddr *ifa;
778 struct ifreq ifr;
779 int done = 0;
780
781 if (!in_dev || (ifa = in_dev->ifa_list) == NULL)
782 goto out;
783
784 for (; ifa; ifa = ifa->ifa_next) {
785 if (!buf) {
786 done += sizeof(ifr);
787 continue;
788 }
789 if (len < (int) sizeof(ifr))
790 break;
791 memset(&ifr, 0, sizeof(struct ifreq));
792 if (ifa->ifa_label)
793 strcpy(ifr.ifr_name, ifa->ifa_label);
794 else
795 strcpy(ifr.ifr_name, dev->name);
796
797 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
798 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
799 ifa->ifa_local;
800
801 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
802 done = -EFAULT;
803 break;
804 }
805 buf += sizeof(struct ifreq);
806 len -= sizeof(struct ifreq);
807 done += sizeof(struct ifreq);
808 }
809out:
810 return done;
811}
812
813u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
814{
815 u32 addr = 0;
816 struct in_device *in_dev;
817
818 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -0700819 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 if (!in_dev)
821 goto no_in_dev;
822
823 for_primary_ifa(in_dev) {
824 if (ifa->ifa_scope > scope)
825 continue;
826 if (!dst || inet_ifa_match(dst, ifa)) {
827 addr = ifa->ifa_local;
828 break;
829 }
830 if (!addr)
831 addr = ifa->ifa_local;
832 } endfor_ifa(in_dev);
833no_in_dev:
834 rcu_read_unlock();
835
836 if (addr)
837 goto out;
838
839 /* Not loopback addresses on loopback should be preferred
840 in this case. It is importnat that lo is the first interface
841 in dev_base list.
842 */
843 read_lock(&dev_base_lock);
844 rcu_read_lock();
845 for (dev = dev_base; dev; dev = dev->next) {
Herbert Xue5ed6392005-10-03 14:35:55 -0700846 if ((in_dev = __in_dev_get_rcu(dev)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 continue;
848
849 for_primary_ifa(in_dev) {
850 if (ifa->ifa_scope != RT_SCOPE_LINK &&
851 ifa->ifa_scope <= scope) {
852 addr = ifa->ifa_local;
853 goto out_unlock_both;
854 }
855 } endfor_ifa(in_dev);
856 }
857out_unlock_both:
858 read_unlock(&dev_base_lock);
859 rcu_read_unlock();
860out:
861 return addr;
862}
863
864static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst,
865 u32 local, int scope)
866{
867 int same = 0;
868 u32 addr = 0;
869
870 for_ifa(in_dev) {
871 if (!addr &&
872 (local == ifa->ifa_local || !local) &&
873 ifa->ifa_scope <= scope) {
874 addr = ifa->ifa_local;
875 if (same)
876 break;
877 }
878 if (!same) {
879 same = (!local || inet_ifa_match(local, ifa)) &&
880 (!dst || inet_ifa_match(dst, ifa));
881 if (same && addr) {
882 if (local || !dst)
883 break;
884 /* Is the selected addr into dst subnet? */
885 if (inet_ifa_match(addr, ifa))
886 break;
887 /* No, then can we use new local src? */
888 if (ifa->ifa_scope <= scope) {
889 addr = ifa->ifa_local;
890 break;
891 }
892 /* search for large dst subnet for addr */
893 same = 0;
894 }
895 }
896 } endfor_ifa(in_dev);
897
898 return same? addr : 0;
899}
900
901/*
902 * Confirm that local IP address exists using wildcards:
903 * - dev: only on this interface, 0=any interface
904 * - dst: only in the same subnet as dst, 0=any dst
905 * - local: address, 0=autoselect the local address
906 * - scope: maximum allowed scope value for the local address
907 */
908u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope)
909{
910 u32 addr = 0;
911 struct in_device *in_dev;
912
913 if (dev) {
914 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -0700915 if ((in_dev = __in_dev_get_rcu(dev)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 addr = confirm_addr_indev(in_dev, dst, local, scope);
917 rcu_read_unlock();
918
919 return addr;
920 }
921
922 read_lock(&dev_base_lock);
923 rcu_read_lock();
924 for (dev = dev_base; dev; dev = dev->next) {
Herbert Xue5ed6392005-10-03 14:35:55 -0700925 if ((in_dev = __in_dev_get_rcu(dev))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 addr = confirm_addr_indev(in_dev, dst, local, scope);
927 if (addr)
928 break;
929 }
930 }
931 rcu_read_unlock();
932 read_unlock(&dev_base_lock);
933
934 return addr;
935}
936
937/*
938 * Device notifier
939 */
940
941int register_inetaddr_notifier(struct notifier_block *nb)
942{
Alan Sterne041c682006-03-27 01:16:30 -0800943 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944}
945
946int unregister_inetaddr_notifier(struct notifier_block *nb)
947{
Alan Sterne041c682006-03-27 01:16:30 -0800948 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949}
950
951/* Rename ifa_labels for a device name change. Make some effort to preserve existing
952 * alias numbering and to create unique labels if possible.
953*/
954static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
955{
956 struct in_ifaddr *ifa;
957 int named = 0;
958
959 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
960 char old[IFNAMSIZ], *dot;
961
962 memcpy(old, ifa->ifa_label, IFNAMSIZ);
963 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
964 if (named++ == 0)
965 continue;
966 dot = strchr(ifa->ifa_label, ':');
967 if (dot == NULL) {
968 sprintf(old, ":%d", named);
969 dot = old;
970 }
971 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ) {
972 strcat(ifa->ifa_label, dot);
973 } else {
974 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
975 }
976 }
977}
978
979/* Called only under RTNL semaphore */
980
981static int inetdev_event(struct notifier_block *this, unsigned long event,
982 void *ptr)
983{
984 struct net_device *dev = ptr;
Herbert Xue5ed6392005-10-03 14:35:55 -0700985 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
987 ASSERT_RTNL();
988
989 if (!in_dev) {
990 if (event == NETDEV_REGISTER && dev == &loopback_dev) {
991 in_dev = inetdev_init(dev);
992 if (!in_dev)
993 panic("devinet: Failed to create loopback\n");
994 in_dev->cnf.no_xfrm = 1;
995 in_dev->cnf.no_policy = 1;
996 }
997 goto out;
998 }
999
1000 switch (event) {
1001 case NETDEV_REGISTER:
1002 printk(KERN_DEBUG "inetdev_event: bug\n");
1003 dev->ip_ptr = NULL;
1004 break;
1005 case NETDEV_UP:
1006 if (dev->mtu < 68)
1007 break;
1008 if (dev == &loopback_dev) {
1009 struct in_ifaddr *ifa;
1010 if ((ifa = inet_alloc_ifa()) != NULL) {
1011 ifa->ifa_local =
1012 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1013 ifa->ifa_prefixlen = 8;
1014 ifa->ifa_mask = inet_make_mask(8);
1015 in_dev_hold(in_dev);
1016 ifa->ifa_dev = in_dev;
1017 ifa->ifa_scope = RT_SCOPE_HOST;
1018 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1019 inet_insert_ifa(ifa);
1020 }
1021 }
1022 ip_mc_up(in_dev);
1023 break;
1024 case NETDEV_DOWN:
1025 ip_mc_down(in_dev);
1026 break;
1027 case NETDEV_CHANGEMTU:
1028 if (dev->mtu >= 68)
1029 break;
1030 /* MTU falled under 68, disable IP */
1031 case NETDEV_UNREGISTER:
1032 inetdev_destroy(in_dev);
1033 break;
1034 case NETDEV_CHANGENAME:
1035 /* Do not notify about label change, this event is
1036 * not interesting to applications using netlink.
1037 */
1038 inetdev_changename(dev, in_dev);
1039
1040#ifdef CONFIG_SYSCTL
1041 devinet_sysctl_unregister(&in_dev->cnf);
1042 neigh_sysctl_unregister(in_dev->arp_parms);
1043 neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
1044 NET_IPV4_NEIGH, "ipv4", NULL, NULL);
1045 devinet_sysctl_register(in_dev, &in_dev->cnf);
1046#endif
1047 break;
1048 }
1049out:
1050 return NOTIFY_DONE;
1051}
1052
1053static struct notifier_block ip_netdev_notifier = {
1054 .notifier_call =inetdev_event,
1055};
1056
1057static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07001058 u32 pid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059{
1060 struct ifaddrmsg *ifm;
1061 struct nlmsghdr *nlh;
1062 unsigned char *b = skb->tail;
1063
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07001064 nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 ifm = NLMSG_DATA(nlh);
1066 ifm->ifa_family = AF_INET;
1067 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
1068 ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT;
1069 ifm->ifa_scope = ifa->ifa_scope;
1070 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
1071 if (ifa->ifa_address)
1072 RTA_PUT(skb, IFA_ADDRESS, 4, &ifa->ifa_address);
1073 if (ifa->ifa_local)
1074 RTA_PUT(skb, IFA_LOCAL, 4, &ifa->ifa_local);
1075 if (ifa->ifa_broadcast)
1076 RTA_PUT(skb, IFA_BROADCAST, 4, &ifa->ifa_broadcast);
1077 if (ifa->ifa_anycast)
1078 RTA_PUT(skb, IFA_ANYCAST, 4, &ifa->ifa_anycast);
1079 if (ifa->ifa_label[0])
1080 RTA_PUT(skb, IFA_LABEL, IFNAMSIZ, &ifa->ifa_label);
1081 nlh->nlmsg_len = skb->tail - b;
1082 return skb->len;
1083
1084nlmsg_failure:
1085rtattr_failure:
1086 skb_trim(skb, b - skb->data);
1087 return -1;
1088}
1089
1090static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1091{
1092 int idx, ip_idx;
1093 struct net_device *dev;
1094 struct in_device *in_dev;
1095 struct in_ifaddr *ifa;
1096 int s_ip_idx, s_idx = cb->args[0];
1097
1098 s_ip_idx = ip_idx = cb->args[1];
1099 read_lock(&dev_base_lock);
1100 for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
1101 if (idx < s_idx)
1102 continue;
1103 if (idx > s_idx)
1104 s_ip_idx = 0;
1105 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001106 if ((in_dev = __in_dev_get_rcu(dev)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 rcu_read_unlock();
1108 continue;
1109 }
1110
1111 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1112 ifa = ifa->ifa_next, ip_idx++) {
1113 if (ip_idx < s_ip_idx)
1114 continue;
1115 if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
1116 cb->nlh->nlmsg_seq,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07001117 RTM_NEWADDR, NLM_F_MULTI) <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 rcu_read_unlock();
1119 goto done;
1120 }
1121 }
1122 rcu_read_unlock();
1123 }
1124
1125done:
1126 read_unlock(&dev_base_lock);
1127 cb->args[0] = idx;
1128 cb->args[1] = ip_idx;
1129
1130 return skb->len;
1131}
1132
1133static void rtmsg_ifa(int event, struct in_ifaddr* ifa)
1134{
1135 int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + 128);
1136 struct sk_buff *skb = alloc_skb(size, GFP_KERNEL);
1137
1138 if (!skb)
Patrick McHardyac6d4392005-08-14 19:29:52 -07001139 netlink_set_err(rtnl, 0, RTNLGRP_IPV4_IFADDR, ENOBUFS);
Alexey Kuznetsov28633512006-02-09 16:40:58 -08001140 else if (inet_fill_ifaddr(skb, ifa, 0, 0, event, 0) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 kfree_skb(skb);
Patrick McHardyac6d4392005-08-14 19:29:52 -07001142 netlink_set_err(rtnl, 0, RTNLGRP_IPV4_IFADDR, EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 } else {
Patrick McHardyac6d4392005-08-14 19:29:52 -07001144 netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV4_IFADDR, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 }
1146}
1147
Thomas Grafdb46edc2005-05-03 14:29:39 -07001148static struct rtnetlink_link inet_rtnetlink_table[RTM_NR_MSGTYPES] = {
1149 [RTM_NEWADDR - RTM_BASE] = { .doit = inet_rtm_newaddr, },
1150 [RTM_DELADDR - RTM_BASE] = { .doit = inet_rtm_deladdr, },
1151 [RTM_GETADDR - RTM_BASE] = { .dumpit = inet_dump_ifaddr, },
1152 [RTM_NEWROUTE - RTM_BASE] = { .doit = inet_rtm_newroute, },
1153 [RTM_DELROUTE - RTM_BASE] = { .doit = inet_rtm_delroute, },
1154 [RTM_GETROUTE - RTM_BASE] = { .doit = inet_rtm_getroute,
1155 .dumpit = inet_dump_fib, },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156#ifdef CONFIG_IP_MULTIPLE_TABLES
Thomas Grafdb46edc2005-05-03 14:29:39 -07001157 [RTM_NEWRULE - RTM_BASE] = { .doit = inet_rtm_newrule, },
1158 [RTM_DELRULE - RTM_BASE] = { .doit = inet_rtm_delrule, },
1159 [RTM_GETRULE - RTM_BASE] = { .dumpit = inet_dump_rules, },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160#endif
1161};
1162
1163#ifdef CONFIG_SYSCTL
1164
1165void inet_forward_change(void)
1166{
1167 struct net_device *dev;
1168 int on = ipv4_devconf.forwarding;
1169
1170 ipv4_devconf.accept_redirects = !on;
1171 ipv4_devconf_dflt.forwarding = on;
1172
1173 read_lock(&dev_base_lock);
1174 for (dev = dev_base; dev; dev = dev->next) {
1175 struct in_device *in_dev;
1176 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001177 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 if (in_dev)
1179 in_dev->cnf.forwarding = on;
1180 rcu_read_unlock();
1181 }
1182 read_unlock(&dev_base_lock);
1183
1184 rt_cache_flush(0);
1185}
1186
1187static int devinet_sysctl_forward(ctl_table *ctl, int write,
1188 struct file* filp, void __user *buffer,
1189 size_t *lenp, loff_t *ppos)
1190{
1191 int *valp = ctl->data;
1192 int val = *valp;
1193 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1194
1195 if (write && *valp != val) {
1196 if (valp == &ipv4_devconf.forwarding)
1197 inet_forward_change();
1198 else if (valp != &ipv4_devconf_dflt.forwarding)
1199 rt_cache_flush(0);
1200 }
1201
1202 return ret;
1203}
1204
1205int ipv4_doint_and_flush(ctl_table *ctl, int write,
1206 struct file* filp, void __user *buffer,
1207 size_t *lenp, loff_t *ppos)
1208{
1209 int *valp = ctl->data;
1210 int val = *valp;
1211 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1212
1213 if (write && *valp != val)
1214 rt_cache_flush(0);
1215
1216 return ret;
1217}
1218
1219int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
1220 void __user *oldval, size_t __user *oldlenp,
1221 void __user *newval, size_t newlen,
1222 void **context)
1223{
1224 int *valp = table->data;
1225 int new;
1226
1227 if (!newval || !newlen)
1228 return 0;
1229
1230 if (newlen != sizeof(int))
1231 return -EINVAL;
1232
1233 if (get_user(new, (int __user *)newval))
1234 return -EFAULT;
1235
1236 if (new == *valp)
1237 return 0;
1238
1239 if (oldval && oldlenp) {
1240 size_t len;
1241
1242 if (get_user(len, oldlenp))
1243 return -EFAULT;
1244
1245 if (len) {
1246 if (len > table->maxlen)
1247 len = table->maxlen;
1248 if (copy_to_user(oldval, valp, len))
1249 return -EFAULT;
1250 if (put_user(len, oldlenp))
1251 return -EFAULT;
1252 }
1253 }
1254
1255 *valp = new;
1256 rt_cache_flush(0);
1257 return 1;
1258}
1259
1260
1261static struct devinet_sysctl_table {
1262 struct ctl_table_header *sysctl_header;
1263 ctl_table devinet_vars[__NET_IPV4_CONF_MAX];
1264 ctl_table devinet_dev[2];
1265 ctl_table devinet_conf_dir[2];
1266 ctl_table devinet_proto_dir[2];
1267 ctl_table devinet_root_dir[2];
1268} devinet_sysctl = {
1269 .devinet_vars = {
1270 {
1271 .ctl_name = NET_IPV4_CONF_FORWARDING,
1272 .procname = "forwarding",
1273 .data = &ipv4_devconf.forwarding,
1274 .maxlen = sizeof(int),
1275 .mode = 0644,
1276 .proc_handler = &devinet_sysctl_forward,
1277 },
1278 {
1279 .ctl_name = NET_IPV4_CONF_MC_FORWARDING,
1280 .procname = "mc_forwarding",
1281 .data = &ipv4_devconf.mc_forwarding,
1282 .maxlen = sizeof(int),
1283 .mode = 0444,
1284 .proc_handler = &proc_dointvec,
1285 },
1286 {
1287 .ctl_name = NET_IPV4_CONF_ACCEPT_REDIRECTS,
1288 .procname = "accept_redirects",
1289 .data = &ipv4_devconf.accept_redirects,
1290 .maxlen = sizeof(int),
1291 .mode = 0644,
1292 .proc_handler = &proc_dointvec,
1293 },
1294 {
1295 .ctl_name = NET_IPV4_CONF_SECURE_REDIRECTS,
1296 .procname = "secure_redirects",
1297 .data = &ipv4_devconf.secure_redirects,
1298 .maxlen = sizeof(int),
1299 .mode = 0644,
1300 .proc_handler = &proc_dointvec,
1301 },
1302 {
1303 .ctl_name = NET_IPV4_CONF_SHARED_MEDIA,
1304 .procname = "shared_media",
1305 .data = &ipv4_devconf.shared_media,
1306 .maxlen = sizeof(int),
1307 .mode = 0644,
1308 .proc_handler = &proc_dointvec,
1309 },
1310 {
1311 .ctl_name = NET_IPV4_CONF_RP_FILTER,
1312 .procname = "rp_filter",
1313 .data = &ipv4_devconf.rp_filter,
1314 .maxlen = sizeof(int),
1315 .mode = 0644,
1316 .proc_handler = &proc_dointvec,
1317 },
1318 {
1319 .ctl_name = NET_IPV4_CONF_SEND_REDIRECTS,
1320 .procname = "send_redirects",
1321 .data = &ipv4_devconf.send_redirects,
1322 .maxlen = sizeof(int),
1323 .mode = 0644,
1324 .proc_handler = &proc_dointvec,
1325 },
1326 {
1327 .ctl_name = NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE,
1328 .procname = "accept_source_route",
1329 .data = &ipv4_devconf.accept_source_route,
1330 .maxlen = sizeof(int),
1331 .mode = 0644,
1332 .proc_handler = &proc_dointvec,
1333 },
1334 {
1335 .ctl_name = NET_IPV4_CONF_PROXY_ARP,
1336 .procname = "proxy_arp",
1337 .data = &ipv4_devconf.proxy_arp,
1338 .maxlen = sizeof(int),
1339 .mode = 0644,
1340 .proc_handler = &proc_dointvec,
1341 },
1342 {
1343 .ctl_name = NET_IPV4_CONF_MEDIUM_ID,
1344 .procname = "medium_id",
1345 .data = &ipv4_devconf.medium_id,
1346 .maxlen = sizeof(int),
1347 .mode = 0644,
1348 .proc_handler = &proc_dointvec,
1349 },
1350 {
1351 .ctl_name = NET_IPV4_CONF_BOOTP_RELAY,
1352 .procname = "bootp_relay",
1353 .data = &ipv4_devconf.bootp_relay,
1354 .maxlen = sizeof(int),
1355 .mode = 0644,
1356 .proc_handler = &proc_dointvec,
1357 },
1358 {
1359 .ctl_name = NET_IPV4_CONF_LOG_MARTIANS,
1360 .procname = "log_martians",
1361 .data = &ipv4_devconf.log_martians,
1362 .maxlen = sizeof(int),
1363 .mode = 0644,
1364 .proc_handler = &proc_dointvec,
1365 },
1366 {
1367 .ctl_name = NET_IPV4_CONF_TAG,
1368 .procname = "tag",
1369 .data = &ipv4_devconf.tag,
1370 .maxlen = sizeof(int),
1371 .mode = 0644,
1372 .proc_handler = &proc_dointvec,
1373 },
1374 {
1375 .ctl_name = NET_IPV4_CONF_ARPFILTER,
1376 .procname = "arp_filter",
1377 .data = &ipv4_devconf.arp_filter,
1378 .maxlen = sizeof(int),
1379 .mode = 0644,
1380 .proc_handler = &proc_dointvec,
1381 },
1382 {
1383 .ctl_name = NET_IPV4_CONF_ARP_ANNOUNCE,
1384 .procname = "arp_announce",
1385 .data = &ipv4_devconf.arp_announce,
1386 .maxlen = sizeof(int),
1387 .mode = 0644,
1388 .proc_handler = &proc_dointvec,
1389 },
1390 {
1391 .ctl_name = NET_IPV4_CONF_ARP_IGNORE,
1392 .procname = "arp_ignore",
1393 .data = &ipv4_devconf.arp_ignore,
1394 .maxlen = sizeof(int),
1395 .mode = 0644,
1396 .proc_handler = &proc_dointvec,
1397 },
1398 {
Neil Hormanabd596a2006-03-20 22:39:47 -08001399 .ctl_name = NET_IPV4_CONF_ARP_ACCEPT,
1400 .procname = "arp_accept",
1401 .data = &ipv4_devconf.arp_accept,
1402 .maxlen = sizeof(int),
1403 .mode = 0644,
1404 .proc_handler = &proc_dointvec,
1405 },
1406 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 .ctl_name = NET_IPV4_CONF_NOXFRM,
1408 .procname = "disable_xfrm",
1409 .data = &ipv4_devconf.no_xfrm,
1410 .maxlen = sizeof(int),
1411 .mode = 0644,
1412 .proc_handler = &ipv4_doint_and_flush,
1413 .strategy = &ipv4_doint_and_flush_strategy,
1414 },
1415 {
1416 .ctl_name = NET_IPV4_CONF_NOPOLICY,
1417 .procname = "disable_policy",
1418 .data = &ipv4_devconf.no_policy,
1419 .maxlen = sizeof(int),
1420 .mode = 0644,
1421 .proc_handler = &ipv4_doint_and_flush,
1422 .strategy = &ipv4_doint_and_flush_strategy,
1423 },
1424 {
1425 .ctl_name = NET_IPV4_CONF_FORCE_IGMP_VERSION,
1426 .procname = "force_igmp_version",
1427 .data = &ipv4_devconf.force_igmp_version,
1428 .maxlen = sizeof(int),
1429 .mode = 0644,
1430 .proc_handler = &ipv4_doint_and_flush,
1431 .strategy = &ipv4_doint_and_flush_strategy,
1432 },
Harald Welte8f937c62005-05-29 20:23:46 -07001433 {
1434 .ctl_name = NET_IPV4_CONF_PROMOTE_SECONDARIES,
1435 .procname = "promote_secondaries",
1436 .data = &ipv4_devconf.promote_secondaries,
1437 .maxlen = sizeof(int),
1438 .mode = 0644,
1439 .proc_handler = &ipv4_doint_and_flush,
1440 .strategy = &ipv4_doint_and_flush_strategy,
1441 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 },
1443 .devinet_dev = {
1444 {
1445 .ctl_name = NET_PROTO_CONF_ALL,
1446 .procname = "all",
1447 .mode = 0555,
1448 .child = devinet_sysctl.devinet_vars,
1449 },
1450 },
1451 .devinet_conf_dir = {
1452 {
1453 .ctl_name = NET_IPV4_CONF,
1454 .procname = "conf",
1455 .mode = 0555,
1456 .child = devinet_sysctl.devinet_dev,
1457 },
1458 },
1459 .devinet_proto_dir = {
1460 {
1461 .ctl_name = NET_IPV4,
1462 .procname = "ipv4",
1463 .mode = 0555,
1464 .child = devinet_sysctl.devinet_conf_dir,
1465 },
1466 },
1467 .devinet_root_dir = {
1468 {
1469 .ctl_name = CTL_NET,
1470 .procname = "net",
1471 .mode = 0555,
1472 .child = devinet_sysctl.devinet_proto_dir,
1473 },
1474 },
1475};
1476
1477static void devinet_sysctl_register(struct in_device *in_dev,
1478 struct ipv4_devconf *p)
1479{
1480 int i;
1481 struct net_device *dev = in_dev ? in_dev->dev : NULL;
1482 struct devinet_sysctl_table *t = kmalloc(sizeof(*t), GFP_KERNEL);
1483 char *dev_name = NULL;
1484
1485 if (!t)
1486 return;
1487 memcpy(t, &devinet_sysctl, sizeof(*t));
1488 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
1489 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
1490 t->devinet_vars[i].de = NULL;
1491 }
1492
1493 if (dev) {
1494 dev_name = dev->name;
1495 t->devinet_dev[0].ctl_name = dev->ifindex;
1496 } else {
1497 dev_name = "default";
1498 t->devinet_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT;
1499 }
1500
1501 /*
1502 * Make a copy of dev_name, because '.procname' is regarded as const
1503 * by sysctl and we wouldn't want anyone to change it under our feet
1504 * (see SIOCSIFNAME).
1505 */
Paulo Marques543537b2005-06-23 00:09:02 -07001506 dev_name = kstrdup(dev_name, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 if (!dev_name)
1508 goto free;
1509
1510 t->devinet_dev[0].procname = dev_name;
1511 t->devinet_dev[0].child = t->devinet_vars;
1512 t->devinet_dev[0].de = NULL;
1513 t->devinet_conf_dir[0].child = t->devinet_dev;
1514 t->devinet_conf_dir[0].de = NULL;
1515 t->devinet_proto_dir[0].child = t->devinet_conf_dir;
1516 t->devinet_proto_dir[0].de = NULL;
1517 t->devinet_root_dir[0].child = t->devinet_proto_dir;
1518 t->devinet_root_dir[0].de = NULL;
1519
1520 t->sysctl_header = register_sysctl_table(t->devinet_root_dir, 0);
1521 if (!t->sysctl_header)
1522 goto free_procname;
1523
1524 p->sysctl = t;
1525 return;
1526
1527 /* error path */
1528 free_procname:
1529 kfree(dev_name);
1530 free:
1531 kfree(t);
1532 return;
1533}
1534
1535static void devinet_sysctl_unregister(struct ipv4_devconf *p)
1536{
1537 if (p->sysctl) {
1538 struct devinet_sysctl_table *t = p->sysctl;
1539 p->sysctl = NULL;
1540 unregister_sysctl_table(t->sysctl_header);
1541 kfree(t->devinet_dev[0].procname);
1542 kfree(t);
1543 }
1544}
1545#endif
1546
1547void __init devinet_init(void)
1548{
1549 register_gifconf(PF_INET, inet_gifconf);
1550 register_netdevice_notifier(&ip_netdev_notifier);
1551 rtnetlink_links[PF_INET] = inet_rtnetlink_table;
1552#ifdef CONFIG_SYSCTL
1553 devinet_sysctl.sysctl_header =
1554 register_sysctl_table(devinet_sysctl.devinet_root_dir, 0);
1555 devinet_sysctl_register(NULL, &ipv4_devconf_dflt);
1556#endif
1557}
1558
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559EXPORT_SYMBOL(in_dev_finish_destroy);
1560EXPORT_SYMBOL(inet_select_addr);
1561EXPORT_SYMBOL(inetdev_by_index);
1562EXPORT_SYMBOL(register_inetaddr_notifier);
1563EXPORT_SYMBOL(unregister_inetaddr_notifier);