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