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