blob: 6e75c884e1afdc87f47839904efce712be267d5c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * NET3 IP device support routines.
3 *
4 * Version: $Id: devinet.c,v 1.44 2001/10/31 21:55:54 davem Exp $
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 * Derived from the IP parts of dev.c 1.0.19
Jesper Juhl02c30a82005-05-05 16:16:16 -070012 * Authors: Ross Biro
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
14 * Mark Evans, <evansmp@uhura.aston.ac.uk>
15 *
16 * Additional Authors:
17 * Alan Cox, <gw4pts@gw4pts.ampr.org>
18 * Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
19 *
20 * Changes:
21 * Alexey Kuznetsov: pa_* fields are replaced with ifaddr
22 * lists.
23 * Cyrus Durgin: updated for kmod
24 * Matthias Andree: in devinet_ioctl, compare label and
25 * address (4.4BSD alias style support),
26 * fall back to comparing just the label
27 * if no match found.
28 */
29
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
31#include <asm/uaccess.h>
32#include <asm/system.h>
33#include <linux/bitops.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080034#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/module.h>
36#include <linux/types.h>
37#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/string.h>
39#include <linux/mm.h>
40#include <linux/socket.h>
41#include <linux/sockios.h>
42#include <linux/in.h>
43#include <linux/errno.h>
44#include <linux/interrupt.h>
Thomas Graf18237302006-08-04 23:04:54 -070045#include <linux/if_addr.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <linux/if_ether.h>
47#include <linux/inet.h>
48#include <linux/netdevice.h>
49#include <linux/etherdevice.h>
50#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <linux/init.h>
52#include <linux/notifier.h>
53#include <linux/inetdevice.h>
54#include <linux/igmp.h>
55#ifdef CONFIG_SYSCTL
56#include <linux/sysctl.h>
57#endif
58#include <linux/kmod.h>
59
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020060#include <net/arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <net/ip.h>
62#include <net/route.h>
63#include <net/ip_fib.h>
Thomas Graf63f34442007-03-22 11:55:17 -070064#include <net/rtnetlink.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66struct ipv4_devconf ipv4_devconf = {
Herbert Xu42f811b2007-06-04 23:34:44 -070067 .data = {
68 [NET_IPV4_CONF_ACCEPT_REDIRECTS - 1] = 1,
69 [NET_IPV4_CONF_SEND_REDIRECTS - 1] = 1,
70 [NET_IPV4_CONF_SECURE_REDIRECTS - 1] = 1,
71 [NET_IPV4_CONF_SHARED_MEDIA - 1] = 1,
72 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070073};
74
75static struct ipv4_devconf ipv4_devconf_dflt = {
Herbert Xu42f811b2007-06-04 23:34:44 -070076 .data = {
77 [NET_IPV4_CONF_ACCEPT_REDIRECTS - 1] = 1,
78 [NET_IPV4_CONF_SEND_REDIRECTS - 1] = 1,
79 [NET_IPV4_CONF_SECURE_REDIRECTS - 1] = 1,
80 [NET_IPV4_CONF_SHARED_MEDIA - 1] = 1,
81 [NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
82 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070083};
84
Herbert Xu42f811b2007-06-04 23:34:44 -070085#define IPV4_DEVCONF_DFLT(attr) IPV4_DEVCONF(ipv4_devconf_dflt, attr)
86
Patrick McHardyef7c79e2007-06-05 12:38:30 -070087static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
Thomas Graf5c753972006-08-04 23:03:53 -070088 [IFA_LOCAL] = { .type = NLA_U32 },
89 [IFA_ADDRESS] = { .type = NLA_U32 },
90 [IFA_BROADCAST] = { .type = NLA_U32 },
91 [IFA_ANYCAST] = { .type = NLA_U32 },
Thomas Graf5176f912006-08-26 20:13:18 -070092 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
Thomas Graf5c753972006-08-04 23:03:53 -070093};
94
Thomas Grafd6062cb2006-08-15 00:33:59 -070095static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Alan Sterne041c682006-03-27 01:16:30 -080097static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
99 int destroy);
100#ifdef CONFIG_SYSCTL
101static void devinet_sysctl_register(struct in_device *in_dev,
102 struct ipv4_devconf *p);
103static void devinet_sysctl_unregister(struct ipv4_devconf *p);
104#endif
105
106/* Locks all the inet devices. */
107
108static struct in_ifaddr *inet_alloc_ifa(void)
109{
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700110 struct in_ifaddr *ifa = kzalloc(sizeof(*ifa), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
112 if (ifa) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 INIT_RCU_HEAD(&ifa->rcu_head);
114 }
115
116 return ifa;
117}
118
119static void inet_rcu_free_ifa(struct rcu_head *head)
120{
121 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
122 if (ifa->ifa_dev)
123 in_dev_put(ifa->ifa_dev);
124 kfree(ifa);
125}
126
127static inline void inet_free_ifa(struct in_ifaddr *ifa)
128{
129 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
130}
131
132void in_dev_finish_destroy(struct in_device *idev)
133{
134 struct net_device *dev = idev->dev;
135
136 BUG_TRAP(!idev->ifa_list);
137 BUG_TRAP(!idev->mc_list);
138#ifdef NET_REFCNT_DEBUG
139 printk(KERN_DEBUG "in_dev_finish_destroy: %p=%s\n",
140 idev, dev ? dev->name : "NIL");
141#endif
142 dev_put(dev);
143 if (!idev->dead)
144 printk("Freeing alive in_device %p\n", idev);
145 else {
146 kfree(idev);
147 }
148}
149
Herbert Xu71e27da2007-06-04 23:36:06 -0700150static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151{
152 struct in_device *in_dev;
153
154 ASSERT_RTNL();
155
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700156 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 if (!in_dev)
158 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 INIT_RCU_HEAD(&in_dev->rcu_head);
160 memcpy(&in_dev->cnf, &ipv4_devconf_dflt, sizeof(in_dev->cnf));
161 in_dev->cnf.sysctl = NULL;
162 in_dev->dev = dev;
163 if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL)
164 goto out_kfree;
165 /* Reference in_dev->dev */
166 dev_hold(dev);
167#ifdef CONFIG_SYSCTL
168 neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
169 NET_IPV4_NEIGH, "ipv4", NULL, NULL);
170#endif
171
David L Stevens30c4cf52007-01-04 12:31:14 -0800172 /* Account for reference dev->ip_ptr (below) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 in_dev_hold(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
175#ifdef CONFIG_SYSCTL
176 devinet_sysctl_register(in_dev, &in_dev->cnf);
177#endif
178 ip_mc_init_dev(in_dev);
179 if (dev->flags & IFF_UP)
180 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800181
David L Stevens30c4cf52007-01-04 12:31:14 -0800182 /* we can receive as soon as ip_ptr is set -- do this last */
183 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800184out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 return in_dev;
186out_kfree:
187 kfree(in_dev);
188 in_dev = NULL;
189 goto out;
190}
191
192static void in_dev_rcu_put(struct rcu_head *head)
193{
194 struct in_device *idev = container_of(head, struct in_device, rcu_head);
195 in_dev_put(idev);
196}
197
198static void inetdev_destroy(struct in_device *in_dev)
199{
200 struct in_ifaddr *ifa;
201 struct net_device *dev;
202
203 ASSERT_RTNL();
204
205 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
207 in_dev->dead = 1;
208
209 ip_mc_destroy_dev(in_dev);
210
211 while ((ifa = in_dev->ifa_list) != NULL) {
212 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
213 inet_free_ifa(ifa);
214 }
215
216#ifdef CONFIG_SYSCTL
217 devinet_sysctl_unregister(&in_dev->cnf);
218#endif
219
220 dev->ip_ptr = NULL;
221
222#ifdef CONFIG_SYSCTL
223 neigh_sysctl_unregister(in_dev->arp_parms);
224#endif
225 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
226 arp_ifdown(dev);
227
228 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
229}
230
Al Viroff428d72006-09-26 22:13:35 -0700231int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232{
233 rcu_read_lock();
234 for_primary_ifa(in_dev) {
235 if (inet_ifa_match(a, ifa)) {
236 if (!b || inet_ifa_match(b, ifa)) {
237 rcu_read_unlock();
238 return 1;
239 }
240 }
241 } endfor_ifa(in_dev);
242 rcu_read_unlock();
243 return 0;
244}
245
Thomas Grafd6062cb2006-08-15 00:33:59 -0700246static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
247 int destroy, struct nlmsghdr *nlh, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248{
Harald Welte8f937c62005-05-29 20:23:46 -0700249 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800250 struct in_ifaddr *ifa, *ifa1 = *ifap;
251 struct in_ifaddr *last_prim = in_dev->ifa_list;
252 struct in_ifaddr *prev_prom = NULL;
253 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
255 ASSERT_RTNL();
256
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900257 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700258 * unless alias promotion is set
259 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
261 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
263
264 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900265 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800266 ifa1->ifa_scope <= ifa->ifa_scope)
267 last_prim = ifa;
268
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
270 ifa1->ifa_mask != ifa->ifa_mask ||
271 !inet_ifa_match(ifa1->ifa_address, ifa)) {
272 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800273 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 continue;
275 }
276
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800277 if (!do_promote) {
Harald Welte8f937c62005-05-29 20:23:46 -0700278 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
Thomas Grafd6062cb2006-08-15 00:33:59 -0700280 rtmsg_ifa(RTM_DELADDR, ifa, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800281 blocking_notifier_call_chain(&inetaddr_chain,
282 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700283 inet_free_ifa(ifa);
284 } else {
285 promote = ifa;
286 break;
287 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 }
289 }
290
291 /* 2. Unlink it */
292
293 *ifap = ifa1->ifa_next;
294
295 /* 3. Announce address deletion */
296
297 /* Send message first, then call notifier.
298 At first sight, FIB update triggered by notifier
299 will refer to already deleted ifaddr, that could confuse
300 netlink listeners. It is not true: look, gated sees
301 that route deleted and if it still thinks that ifaddr
302 is valid, it will try to restore deleted routes... Grr.
303 So that, this order is correct.
304 */
Thomas Grafd6062cb2006-08-15 00:33:59 -0700305 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800306 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800307
308 if (promote) {
309
310 if (prev_prom) {
311 prev_prom->ifa_next = promote->ifa_next;
312 promote->ifa_next = last_prim->ifa_next;
313 last_prim->ifa_next = promote;
314 }
315
316 promote->ifa_flags &= ~IFA_F_SECONDARY;
Thomas Grafd6062cb2006-08-15 00:33:59 -0700317 rtmsg_ifa(RTM_NEWADDR, promote, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800318 blocking_notifier_call_chain(&inetaddr_chain,
319 NETDEV_UP, promote);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800320 for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) {
321 if (ifa1->ifa_mask != ifa->ifa_mask ||
322 !inet_ifa_match(ifa1->ifa_address, ifa))
323 continue;
324 fib_add_ifaddr(ifa);
325 }
326
327 }
Herbert Xu63630972007-06-07 18:35:38 -0700328 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330}
331
Thomas Grafd6062cb2006-08-15 00:33:59 -0700332static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
333 int destroy)
334{
335 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
336}
337
338static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
339 u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340{
341 struct in_device *in_dev = ifa->ifa_dev;
342 struct in_ifaddr *ifa1, **ifap, **last_primary;
343
344 ASSERT_RTNL();
345
346 if (!ifa->ifa_local) {
347 inet_free_ifa(ifa);
348 return 0;
349 }
350
351 ifa->ifa_flags &= ~IFA_F_SECONDARY;
352 last_primary = &in_dev->ifa_list;
353
354 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
355 ifap = &ifa1->ifa_next) {
356 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
357 ifa->ifa_scope <= ifa1->ifa_scope)
358 last_primary = &ifa1->ifa_next;
359 if (ifa1->ifa_mask == ifa->ifa_mask &&
360 inet_ifa_match(ifa1->ifa_address, ifa)) {
361 if (ifa1->ifa_local == ifa->ifa_local) {
362 inet_free_ifa(ifa);
363 return -EEXIST;
364 }
365 if (ifa1->ifa_scope != ifa->ifa_scope) {
366 inet_free_ifa(ifa);
367 return -EINVAL;
368 }
369 ifa->ifa_flags |= IFA_F_SECONDARY;
370 }
371 }
372
373 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
374 net_srandom(ifa->ifa_local);
375 ifap = last_primary;
376 }
377
378 ifa->ifa_next = *ifap;
379 *ifap = ifa;
380
381 /* Send message first, then call notifier.
382 Notifier will trigger FIB update, so that
383 listeners of netlink will know about new ifaddr */
Thomas Grafd6062cb2006-08-15 00:33:59 -0700384 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800385 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
387 return 0;
388}
389
Thomas Grafd6062cb2006-08-15 00:33:59 -0700390static int inet_insert_ifa(struct in_ifaddr *ifa)
391{
392 return __inet_insert_ifa(ifa, NULL, 0);
393}
394
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
396{
Herbert Xue5ed6392005-10-03 14:35:55 -0700397 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
399 ASSERT_RTNL();
400
401 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700402 inet_free_ifa(ifa);
403 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700405 ipv4_devconf_setall(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 if (ifa->ifa_dev != in_dev) {
407 BUG_TRAP(!ifa->ifa_dev);
408 in_dev_hold(in_dev);
409 ifa->ifa_dev = in_dev;
410 }
411 if (LOOPBACK(ifa->ifa_local))
412 ifa->ifa_scope = RT_SCOPE_HOST;
413 return inet_insert_ifa(ifa);
414}
415
416struct in_device *inetdev_by_index(int ifindex)
417{
418 struct net_device *dev;
419 struct in_device *in_dev = NULL;
420 read_lock(&dev_base_lock);
Eric W. Biederman881d9662007-09-17 11:56:21 -0700421 dev = __dev_get_by_index(&init_net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 if (dev)
423 in_dev = in_dev_get(dev);
424 read_unlock(&dev_base_lock);
425 return in_dev;
426}
427
428/* Called only from RTNL semaphored context. No locks. */
429
Al Viro60cad5d2006-09-26 22:17:09 -0700430struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
431 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432{
433 ASSERT_RTNL();
434
435 for_primary_ifa(in_dev) {
436 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
437 return ifa;
438 } endfor_ifa(in_dev);
439 return NULL;
440}
441
442static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
443{
Denis V. Lunevb8542722007-12-01 00:21:31 +1100444 struct net *net = skb->sk->sk_net;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700445 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700447 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700449 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451 ASSERT_RTNL();
452
Denis V. Lunevb8542722007-12-01 00:21:31 +1100453 if (net != &init_net)
454 return -EINVAL;
455
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700456 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
457 if (err < 0)
458 goto errout;
459
460 ifm = nlmsg_data(nlh);
461 in_dev = inetdev_by_index(ifm->ifa_index);
462 if (in_dev == NULL) {
463 err = -ENODEV;
464 goto errout;
465 }
466
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 __in_dev_put(in_dev);
468
469 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
470 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700471 if (tb[IFA_LOCAL] &&
Al Viroa7a628c2006-09-26 22:16:43 -0700472 ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700474
475 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
476 continue;
477
478 if (tb[IFA_ADDRESS] &&
479 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Al Viroa7a628c2006-09-26 22:16:43 -0700480 !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700481 continue;
482
Thomas Grafd6062cb2006-08-15 00:33:59 -0700483 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 return 0;
485 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700486
487 err = -EADDRNOTAVAIL;
488errout:
489 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490}
491
Thomas Graf5c753972006-08-04 23:03:53 -0700492static struct in_ifaddr *rtm_to_ifaddr(struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493{
Thomas Graf5c753972006-08-04 23:03:53 -0700494 struct nlattr *tb[IFA_MAX+1];
495 struct in_ifaddr *ifa;
496 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 struct net_device *dev;
498 struct in_device *in_dev;
Thomas Graf5c753972006-08-04 23:03:53 -0700499 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
Thomas Graf5c753972006-08-04 23:03:53 -0700501 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
502 if (err < 0)
503 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
Thomas Graf5c753972006-08-04 23:03:53 -0700505 ifm = nlmsg_data(nlh);
Evgeniy Polyakovc4e38f42007-03-09 13:43:24 -0800506 if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL) {
507 err = -EINVAL;
Thomas Graf5c753972006-08-04 23:03:53 -0700508 goto errout;
Evgeniy Polyakovc4e38f42007-03-09 13:43:24 -0800509 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
Eric W. Biederman881d9662007-09-17 11:56:21 -0700511 dev = __dev_get_by_index(&init_net, ifm->ifa_index);
Thomas Graf5c753972006-08-04 23:03:53 -0700512 if (dev == NULL) {
513 err = -ENODEV;
514 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 }
516
Thomas Graf5c753972006-08-04 23:03:53 -0700517 in_dev = __in_dev_get_rtnl(dev);
518 if (in_dev == NULL) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700519 err = -ENOBUFS;
520 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700521 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
Thomas Graf5c753972006-08-04 23:03:53 -0700523 ifa = inet_alloc_ifa();
524 if (ifa == NULL) {
525 /*
526 * A potential indev allocation can be left alive, it stays
527 * assigned to its device and is destroy with it.
528 */
529 err = -ENOBUFS;
530 goto errout;
531 }
532
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800533 ipv4_devconf_setall(in_dev);
Thomas Graf5c753972006-08-04 23:03:53 -0700534 in_dev_hold(in_dev);
535
536 if (tb[IFA_ADDRESS] == NULL)
537 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
538
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
540 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 ifa->ifa_flags = ifm->ifa_flags;
542 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700543 ifa->ifa_dev = in_dev;
544
Al Viroa7a628c2006-09-26 22:16:43 -0700545 ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]);
546 ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700547
548 if (tb[IFA_BROADCAST])
Al Viroa7a628c2006-09-26 22:16:43 -0700549 ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700550
551 if (tb[IFA_ANYCAST])
Al Viroa7a628c2006-09-26 22:16:43 -0700552 ifa->ifa_anycast = nla_get_be32(tb[IFA_ANYCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700553
554 if (tb[IFA_LABEL])
555 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 else
557 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
558
Thomas Graf5c753972006-08-04 23:03:53 -0700559 return ifa;
560
561errout:
562 return ERR_PTR(err);
563}
564
565static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
566{
Denis V. Lunevb8542722007-12-01 00:21:31 +1100567 struct net *net = skb->sk->sk_net;
Thomas Graf5c753972006-08-04 23:03:53 -0700568 struct in_ifaddr *ifa;
569
570 ASSERT_RTNL();
571
Denis V. Lunevb8542722007-12-01 00:21:31 +1100572 if (net != &init_net)
573 return -EINVAL;
574
Thomas Graf5c753972006-08-04 23:03:53 -0700575 ifa = rtm_to_ifaddr(nlh);
576 if (IS_ERR(ifa))
577 return PTR_ERR(ifa);
578
Thomas Grafd6062cb2006-08-15 00:33:59 -0700579 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580}
581
582/*
583 * Determine a default network mask, based on the IP address.
584 */
585
Al Viro714e85b2006-11-14 20:51:49 -0800586static __inline__ int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587{
588 int rc = -1; /* Something else, probably a multicast. */
589
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900590 if (ZERONET(addr))
591 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 else {
Al Viro714e85b2006-11-14 20:51:49 -0800593 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Al Viro714e85b2006-11-14 20:51:49 -0800595 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800597 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800599 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 rc = 24;
601 }
602
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900603 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604}
605
606
607int devinet_ioctl(unsigned int cmd, void __user *arg)
608{
609 struct ifreq ifr;
610 struct sockaddr_in sin_orig;
611 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
612 struct in_device *in_dev;
613 struct in_ifaddr **ifap = NULL;
614 struct in_ifaddr *ifa = NULL;
615 struct net_device *dev;
616 char *colon;
617 int ret = -EFAULT;
618 int tryaddrmatch = 0;
619
620 /*
621 * Fetch the caller's info block into kernel space
622 */
623
624 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
625 goto out;
626 ifr.ifr_name[IFNAMSIZ - 1] = 0;
627
628 /* save original address for comparison */
629 memcpy(&sin_orig, sin, sizeof(*sin));
630
631 colon = strchr(ifr.ifr_name, ':');
632 if (colon)
633 *colon = 0;
634
635#ifdef CONFIG_KMOD
Eric W. Biederman881d9662007-09-17 11:56:21 -0700636 dev_load(&init_net, ifr.ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637#endif
638
Stephen Hemminger132adf52007-03-08 20:44:43 -0800639 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 case SIOCGIFADDR: /* Get interface address */
641 case SIOCGIFBRDADDR: /* Get the broadcast address */
642 case SIOCGIFDSTADDR: /* Get the destination address */
643 case SIOCGIFNETMASK: /* Get the netmask for the interface */
644 /* Note that these ioctls will not sleep,
645 so that we do not impose a lock.
646 One day we will be forced to put shlock here (I mean SMP)
647 */
648 tryaddrmatch = (sin_orig.sin_family == AF_INET);
649 memset(sin, 0, sizeof(*sin));
650 sin->sin_family = AF_INET;
651 break;
652
653 case SIOCSIFFLAGS:
654 ret = -EACCES;
655 if (!capable(CAP_NET_ADMIN))
656 goto out;
657 break;
658 case SIOCSIFADDR: /* Set interface address (and family) */
659 case SIOCSIFBRDADDR: /* Set the broadcast address */
660 case SIOCSIFDSTADDR: /* Set the destination address */
661 case SIOCSIFNETMASK: /* Set the netmask for the interface */
662 ret = -EACCES;
663 if (!capable(CAP_NET_ADMIN))
664 goto out;
665 ret = -EINVAL;
666 if (sin->sin_family != AF_INET)
667 goto out;
668 break;
669 default:
670 ret = -EINVAL;
671 goto out;
672 }
673
674 rtnl_lock();
675
676 ret = -ENODEV;
Eric W. Biederman881d9662007-09-17 11:56:21 -0700677 if ((dev = __dev_get_by_name(&init_net, ifr.ifr_name)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 goto done;
679
680 if (colon)
681 *colon = ':';
682
Herbert Xue5ed6392005-10-03 14:35:55 -0700683 if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 if (tryaddrmatch) {
685 /* Matthias Andree */
686 /* compare label and address (4.4BSD style) */
687 /* note: we only do this for a limited set of ioctls
688 and only if the original address family was AF_INET.
689 This is checked above. */
690 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
691 ifap = &ifa->ifa_next) {
692 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
693 sin_orig.sin_addr.s_addr ==
694 ifa->ifa_address) {
695 break; /* found */
696 }
697 }
698 }
699 /* we didn't get a match, maybe the application is
700 4.3BSD-style and passed in junk so we fall back to
701 comparing just the label */
702 if (!ifa) {
703 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
704 ifap = &ifa->ifa_next)
705 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
706 break;
707 }
708 }
709
710 ret = -EADDRNOTAVAIL;
711 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
712 goto done;
713
Stephen Hemminger132adf52007-03-08 20:44:43 -0800714 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 case SIOCGIFADDR: /* Get interface address */
716 sin->sin_addr.s_addr = ifa->ifa_local;
717 goto rarok;
718
719 case SIOCGIFBRDADDR: /* Get the broadcast address */
720 sin->sin_addr.s_addr = ifa->ifa_broadcast;
721 goto rarok;
722
723 case SIOCGIFDSTADDR: /* Get the destination address */
724 sin->sin_addr.s_addr = ifa->ifa_address;
725 goto rarok;
726
727 case SIOCGIFNETMASK: /* Get the netmask for the interface */
728 sin->sin_addr.s_addr = ifa->ifa_mask;
729 goto rarok;
730
731 case SIOCSIFFLAGS:
732 if (colon) {
733 ret = -EADDRNOTAVAIL;
734 if (!ifa)
735 break;
736 ret = 0;
737 if (!(ifr.ifr_flags & IFF_UP))
738 inet_del_ifa(in_dev, ifap, 1);
739 break;
740 }
741 ret = dev_change_flags(dev, ifr.ifr_flags);
742 break;
743
744 case SIOCSIFADDR: /* Set interface address (and family) */
745 ret = -EINVAL;
746 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
747 break;
748
749 if (!ifa) {
750 ret = -ENOBUFS;
751 if ((ifa = inet_alloc_ifa()) == NULL)
752 break;
753 if (colon)
754 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
755 else
756 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
757 } else {
758 ret = 0;
759 if (ifa->ifa_local == sin->sin_addr.s_addr)
760 break;
761 inet_del_ifa(in_dev, ifap, 0);
762 ifa->ifa_broadcast = 0;
763 ifa->ifa_anycast = 0;
764 }
765
766 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
767
768 if (!(dev->flags & IFF_POINTOPOINT)) {
769 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
770 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
771 if ((dev->flags & IFF_BROADCAST) &&
772 ifa->ifa_prefixlen < 31)
773 ifa->ifa_broadcast = ifa->ifa_address |
774 ~ifa->ifa_mask;
775 } else {
776 ifa->ifa_prefixlen = 32;
777 ifa->ifa_mask = inet_make_mask(32);
778 }
779 ret = inet_set_ifa(dev, ifa);
780 break;
781
782 case SIOCSIFBRDADDR: /* Set the broadcast address */
783 ret = 0;
784 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
785 inet_del_ifa(in_dev, ifap, 0);
786 ifa->ifa_broadcast = sin->sin_addr.s_addr;
787 inet_insert_ifa(ifa);
788 }
789 break;
790
791 case SIOCSIFDSTADDR: /* Set the destination address */
792 ret = 0;
793 if (ifa->ifa_address == sin->sin_addr.s_addr)
794 break;
795 ret = -EINVAL;
796 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
797 break;
798 ret = 0;
799 inet_del_ifa(in_dev, ifap, 0);
800 ifa->ifa_address = sin->sin_addr.s_addr;
801 inet_insert_ifa(ifa);
802 break;
803
804 case SIOCSIFNETMASK: /* Set the netmask for the interface */
805
806 /*
807 * The mask we set must be legal.
808 */
809 ret = -EINVAL;
810 if (bad_mask(sin->sin_addr.s_addr, 0))
811 break;
812 ret = 0;
813 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -0700814 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 inet_del_ifa(in_dev, ifap, 0);
816 ifa->ifa_mask = sin->sin_addr.s_addr;
817 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
818
819 /* See if current broadcast address matches
820 * with current netmask, then recalculate
821 * the broadcast address. Otherwise it's a
822 * funny address, so don't touch it since
823 * the user seems to know what (s)he's doing...
824 */
825 if ((dev->flags & IFF_BROADCAST) &&
826 (ifa->ifa_prefixlen < 31) &&
827 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -0500828 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 ifa->ifa_broadcast = (ifa->ifa_local |
830 ~sin->sin_addr.s_addr);
831 }
832 inet_insert_ifa(ifa);
833 }
834 break;
835 }
836done:
837 rtnl_unlock();
838out:
839 return ret;
840rarok:
841 rtnl_unlock();
842 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
843 goto out;
844}
845
846static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
847{
Herbert Xue5ed6392005-10-03 14:35:55 -0700848 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 struct in_ifaddr *ifa;
850 struct ifreq ifr;
851 int done = 0;
852
853 if (!in_dev || (ifa = in_dev->ifa_list) == NULL)
854 goto out;
855
856 for (; ifa; ifa = ifa->ifa_next) {
857 if (!buf) {
858 done += sizeof(ifr);
859 continue;
860 }
861 if (len < (int) sizeof(ifr))
862 break;
863 memset(&ifr, 0, sizeof(struct ifreq));
864 if (ifa->ifa_label)
865 strcpy(ifr.ifr_name, ifa->ifa_label);
866 else
867 strcpy(ifr.ifr_name, dev->name);
868
869 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
870 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
871 ifa->ifa_local;
872
873 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
874 done = -EFAULT;
875 break;
876 }
877 buf += sizeof(struct ifreq);
878 len -= sizeof(struct ifreq);
879 done += sizeof(struct ifreq);
880 }
881out:
882 return done;
883}
884
Al Viroa61ced52006-09-26 21:27:54 -0700885__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886{
Al Viroa61ced52006-09-26 21:27:54 -0700887 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 struct in_device *in_dev;
889
890 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -0700891 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 if (!in_dev)
893 goto no_in_dev;
894
895 for_primary_ifa(in_dev) {
896 if (ifa->ifa_scope > scope)
897 continue;
898 if (!dst || inet_ifa_match(dst, ifa)) {
899 addr = ifa->ifa_local;
900 break;
901 }
902 if (!addr)
903 addr = ifa->ifa_local;
904 } endfor_ifa(in_dev);
905no_in_dev:
906 rcu_read_unlock();
907
908 if (addr)
909 goto out;
910
911 /* Not loopback addresses on loopback should be preferred
912 in this case. It is importnat that lo is the first interface
913 in dev_base list.
914 */
915 read_lock(&dev_base_lock);
916 rcu_read_lock();
Eric W. Biederman881d9662007-09-17 11:56:21 -0700917 for_each_netdev(&init_net, dev) {
Herbert Xue5ed6392005-10-03 14:35:55 -0700918 if ((in_dev = __in_dev_get_rcu(dev)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 continue;
920
921 for_primary_ifa(in_dev) {
922 if (ifa->ifa_scope != RT_SCOPE_LINK &&
923 ifa->ifa_scope <= scope) {
924 addr = ifa->ifa_local;
925 goto out_unlock_both;
926 }
927 } endfor_ifa(in_dev);
928 }
929out_unlock_both:
930 read_unlock(&dev_base_lock);
931 rcu_read_unlock();
932out:
933 return addr;
934}
935
Al Viro60cad5d2006-09-26 22:17:09 -0700936static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
937 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938{
939 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -0700940 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
942 for_ifa(in_dev) {
943 if (!addr &&
944 (local == ifa->ifa_local || !local) &&
945 ifa->ifa_scope <= scope) {
946 addr = ifa->ifa_local;
947 if (same)
948 break;
949 }
950 if (!same) {
951 same = (!local || inet_ifa_match(local, ifa)) &&
952 (!dst || inet_ifa_match(dst, ifa));
953 if (same && addr) {
954 if (local || !dst)
955 break;
956 /* Is the selected addr into dst subnet? */
957 if (inet_ifa_match(addr, ifa))
958 break;
959 /* No, then can we use new local src? */
960 if (ifa->ifa_scope <= scope) {
961 addr = ifa->ifa_local;
962 break;
963 }
964 /* search for large dst subnet for addr */
965 same = 0;
966 }
967 }
968 } endfor_ifa(in_dev);
969
970 return same? addr : 0;
971}
972
973/*
974 * Confirm that local IP address exists using wildcards:
975 * - dev: only on this interface, 0=any interface
976 * - dst: only in the same subnet as dst, 0=any dst
977 * - local: address, 0=autoselect the local address
978 * - scope: maximum allowed scope value for the local address
979 */
Al Viro60cad5d2006-09-26 22:17:09 -0700980__be32 inet_confirm_addr(const struct net_device *dev, __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981{
Al Viro60cad5d2006-09-26 22:17:09 -0700982 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 struct in_device *in_dev;
984
985 if (dev) {
986 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -0700987 if ((in_dev = __in_dev_get_rcu(dev)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 addr = confirm_addr_indev(in_dev, dst, local, scope);
989 rcu_read_unlock();
990
991 return addr;
992 }
993
994 read_lock(&dev_base_lock);
995 rcu_read_lock();
Eric W. Biederman881d9662007-09-17 11:56:21 -0700996 for_each_netdev(&init_net, dev) {
Herbert Xue5ed6392005-10-03 14:35:55 -0700997 if ((in_dev = __in_dev_get_rcu(dev))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 addr = confirm_addr_indev(in_dev, dst, local, scope);
999 if (addr)
1000 break;
1001 }
1002 }
1003 rcu_read_unlock();
1004 read_unlock(&dev_base_lock);
1005
1006 return addr;
1007}
1008
1009/*
1010 * Device notifier
1011 */
1012
1013int register_inetaddr_notifier(struct notifier_block *nb)
1014{
Alan Sterne041c682006-03-27 01:16:30 -08001015 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016}
1017
1018int unregister_inetaddr_notifier(struct notifier_block *nb)
1019{
Alan Sterne041c682006-03-27 01:16:30 -08001020 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021}
1022
1023/* Rename ifa_labels for a device name change. Make some effort to preserve existing
1024 * alias numbering and to create unique labels if possible.
1025*/
1026static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001027{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 struct in_ifaddr *ifa;
1029 int named = 0;
1030
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001031 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1032 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001035 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 if (named++ == 0)
1037 continue;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001038 dot = strchr(old, ':');
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001039 if (dot == NULL) {
1040 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 dot = old;
1042 }
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001043 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ) {
1044 strcat(ifa->ifa_label, dot);
1045 } else {
1046 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
1047 }
1048 }
1049}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
1051/* Called only under RTNL semaphore */
1052
1053static int inetdev_event(struct notifier_block *this, unsigned long event,
1054 void *ptr)
1055{
1056 struct net_device *dev = ptr;
Herbert Xue5ed6392005-10-03 14:35:55 -07001057 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001059 if (dev->nd_net != &init_net)
1060 return NOTIFY_DONE;
1061
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 ASSERT_RTNL();
1063
1064 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001065 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 in_dev = inetdev_init(dev);
Herbert Xub217d612007-07-30 17:04:52 -07001067 if (!in_dev)
1068 return notifier_from_errno(-ENOMEM);
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001069 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001070 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1071 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001072 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 }
1074 goto out;
1075 }
1076
1077 switch (event) {
1078 case NETDEV_REGISTER:
1079 printk(KERN_DEBUG "inetdev_event: bug\n");
1080 dev->ip_ptr = NULL;
1081 break;
1082 case NETDEV_UP:
1083 if (dev->mtu < 68)
1084 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001085 if (dev->flags & IFF_LOOPBACK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 struct in_ifaddr *ifa;
1087 if ((ifa = inet_alloc_ifa()) != NULL) {
1088 ifa->ifa_local =
1089 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1090 ifa->ifa_prefixlen = 8;
1091 ifa->ifa_mask = inet_make_mask(8);
1092 in_dev_hold(in_dev);
1093 ifa->ifa_dev = in_dev;
1094 ifa->ifa_scope = RT_SCOPE_HOST;
1095 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1096 inet_insert_ifa(ifa);
1097 }
1098 }
1099 ip_mc_up(in_dev);
1100 break;
1101 case NETDEV_DOWN:
1102 ip_mc_down(in_dev);
1103 break;
1104 case NETDEV_CHANGEMTU:
1105 if (dev->mtu >= 68)
1106 break;
1107 /* MTU falled under 68, disable IP */
1108 case NETDEV_UNREGISTER:
1109 inetdev_destroy(in_dev);
1110 break;
1111 case NETDEV_CHANGENAME:
1112 /* Do not notify about label change, this event is
1113 * not interesting to applications using netlink.
1114 */
1115 inetdev_changename(dev, in_dev);
1116
1117#ifdef CONFIG_SYSCTL
1118 devinet_sysctl_unregister(&in_dev->cnf);
1119 neigh_sysctl_unregister(in_dev->arp_parms);
1120 neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
1121 NET_IPV4_NEIGH, "ipv4", NULL, NULL);
1122 devinet_sysctl_register(in_dev, &in_dev->cnf);
1123#endif
1124 break;
1125 }
1126out:
1127 return NOTIFY_DONE;
1128}
1129
1130static struct notifier_block ip_netdev_notifier = {
1131 .notifier_call =inetdev_event,
1132};
1133
Thomas Graf339bf982006-11-10 14:10:15 -08001134static inline size_t inet_nlmsg_size(void)
1135{
1136 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1137 + nla_total_size(4) /* IFA_ADDRESS */
1138 + nla_total_size(4) /* IFA_LOCAL */
1139 + nla_total_size(4) /* IFA_BROADCAST */
1140 + nla_total_size(4) /* IFA_ANYCAST */
1141 + nla_total_size(IFNAMSIZ); /* IFA_LABEL */
1142}
1143
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07001145 u32 pid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146{
1147 struct ifaddrmsg *ifm;
1148 struct nlmsghdr *nlh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
Thomas Graf47f68512006-08-04 23:04:36 -07001150 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);
1151 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001152 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001153
1154 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 ifm->ifa_family = AF_INET;
1156 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
1157 ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT;
1158 ifm->ifa_scope = ifa->ifa_scope;
1159 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
Thomas Graf47f68512006-08-04 23:04:36 -07001161 if (ifa->ifa_address)
Al Viroa7a628c2006-09-26 22:16:43 -07001162 NLA_PUT_BE32(skb, IFA_ADDRESS, ifa->ifa_address);
Thomas Graf47f68512006-08-04 23:04:36 -07001163
1164 if (ifa->ifa_local)
Al Viroa7a628c2006-09-26 22:16:43 -07001165 NLA_PUT_BE32(skb, IFA_LOCAL, ifa->ifa_local);
Thomas Graf47f68512006-08-04 23:04:36 -07001166
1167 if (ifa->ifa_broadcast)
Al Viroa7a628c2006-09-26 22:16:43 -07001168 NLA_PUT_BE32(skb, IFA_BROADCAST, ifa->ifa_broadcast);
Thomas Graf47f68512006-08-04 23:04:36 -07001169
1170 if (ifa->ifa_anycast)
Al Viroa7a628c2006-09-26 22:16:43 -07001171 NLA_PUT_BE32(skb, IFA_ANYCAST, ifa->ifa_anycast);
Thomas Graf47f68512006-08-04 23:04:36 -07001172
1173 if (ifa->ifa_label[0])
1174 NLA_PUT_STRING(skb, IFA_LABEL, ifa->ifa_label);
1175
1176 return nlmsg_end(skb, nlh);
1177
1178nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001179 nlmsg_cancel(skb, nlh);
1180 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181}
1182
1183static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1184{
Denis V. Lunevb8542722007-12-01 00:21:31 +11001185 struct net *net = skb->sk->sk_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 int idx, ip_idx;
1187 struct net_device *dev;
1188 struct in_device *in_dev;
1189 struct in_ifaddr *ifa;
1190 int s_ip_idx, s_idx = cb->args[0];
1191
Denis V. Lunevb8542722007-12-01 00:21:31 +11001192 if (net != &init_net)
1193 return 0;
1194
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 s_ip_idx = ip_idx = cb->args[1];
Pavel Emelianov7562f872007-05-03 15:13:45 -07001196 idx = 0;
Eric W. Biederman881d9662007-09-17 11:56:21 -07001197 for_each_netdev(&init_net, dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 if (idx < s_idx)
Pavel Emelianov7562f872007-05-03 15:13:45 -07001199 goto cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 if (idx > s_idx)
1201 s_ip_idx = 0;
Patrick McHardy6313c1e2007-04-16 17:00:53 -07001202 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL)
Pavel Emelianov7562f872007-05-03 15:13:45 -07001203 goto cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204
1205 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1206 ifa = ifa->ifa_next, ip_idx++) {
1207 if (ip_idx < s_ip_idx)
Stephen Hemminger596e4152007-09-11 10:41:04 +02001208 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
1210 cb->nlh->nlmsg_seq,
Patrick McHardy6313c1e2007-04-16 17:00:53 -07001211 RTM_NEWADDR, NLM_F_MULTI) <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 goto done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001214cont:
1215 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 }
1217
1218done:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 cb->args[0] = idx;
1220 cb->args[1] = ip_idx;
1221
1222 return skb->len;
1223}
1224
Thomas Grafd6062cb2006-08-15 00:33:59 -07001225static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
1226 u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227{
Thomas Graf47f68512006-08-04 23:04:36 -07001228 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001229 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1230 int err = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231
Thomas Graf339bf982006-11-10 14:10:15 -08001232 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Thomas Graf47f68512006-08-04 23:04:36 -07001233 if (skb == NULL)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001234 goto errout;
1235
1236 err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001237 if (err < 0) {
1238 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1239 WARN_ON(err == -EMSGSIZE);
1240 kfree_skb(skb);
1241 goto errout;
1242 }
Denis V. Lunev97c53ca2007-11-19 22:26:51 -08001243 err = rtnl_notify(skb, &init_net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Thomas Grafd6062cb2006-08-15 00:33:59 -07001244errout:
1245 if (err < 0)
Denis V. Lunev97c53ca2007-11-19 22:26:51 -08001246 rtnl_set_sk_err(&init_net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247}
1248
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249#ifdef CONFIG_SYSCTL
1250
Herbert Xu31be3082007-06-04 23:35:37 -07001251static void devinet_copy_dflt_conf(int i)
1252{
1253 struct net_device *dev;
1254
1255 read_lock(&dev_base_lock);
Eric W. Biederman881d9662007-09-17 11:56:21 -07001256 for_each_netdev(&init_net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07001257 struct in_device *in_dev;
1258 rcu_read_lock();
1259 in_dev = __in_dev_get_rcu(dev);
1260 if (in_dev && !test_bit(i, in_dev->cnf.state))
1261 in_dev->cnf.data[i] = ipv4_devconf_dflt.data[i];
1262 rcu_read_unlock();
1263 }
1264 read_unlock(&dev_base_lock);
1265}
1266
1267static int devinet_conf_proc(ctl_table *ctl, int write,
1268 struct file* filp, void __user *buffer,
1269 size_t *lenp, loff_t *ppos)
1270{
1271 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1272
1273 if (write) {
1274 struct ipv4_devconf *cnf = ctl->extra1;
1275 int i = (int *)ctl->data - cnf->data;
1276
1277 set_bit(i, cnf->state);
1278
1279 if (cnf == &ipv4_devconf_dflt)
1280 devinet_copy_dflt_conf(i);
1281 }
1282
1283 return ret;
1284}
1285
1286static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,
1287 void __user *oldval, size_t __user *oldlenp,
1288 void __user *newval, size_t newlen)
1289{
1290 struct ipv4_devconf *cnf;
1291 int *valp = table->data;
1292 int new;
1293 int i;
1294
1295 if (!newval || !newlen)
1296 return 0;
1297
1298 if (newlen != sizeof(int))
1299 return -EINVAL;
1300
1301 if (get_user(new, (int __user *)newval))
1302 return -EFAULT;
1303
1304 if (new == *valp)
1305 return 0;
1306
1307 if (oldval && oldlenp) {
1308 size_t len;
1309
1310 if (get_user(len, oldlenp))
1311 return -EFAULT;
1312
1313 if (len) {
1314 if (len > table->maxlen)
1315 len = table->maxlen;
1316 if (copy_to_user(oldval, valp, len))
1317 return -EFAULT;
1318 if (put_user(len, oldlenp))
1319 return -EFAULT;
1320 }
1321 }
1322
1323 *valp = new;
1324
1325 cnf = table->extra1;
1326 i = (int *)table->data - cnf->data;
1327
1328 set_bit(i, cnf->state);
1329
1330 if (cnf == &ipv4_devconf_dflt)
1331 devinet_copy_dflt_conf(i);
1332
1333 return 1;
1334}
1335
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336void inet_forward_change(void)
1337{
1338 struct net_device *dev;
Herbert Xu42f811b2007-06-04 23:34:44 -07001339 int on = IPV4_DEVCONF_ALL(FORWARDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340
Herbert Xu42f811b2007-06-04 23:34:44 -07001341 IPV4_DEVCONF_ALL(ACCEPT_REDIRECTS) = !on;
1342 IPV4_DEVCONF_DFLT(FORWARDING) = on;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
1344 read_lock(&dev_base_lock);
Eric W. Biederman881d9662007-09-17 11:56:21 -07001345 for_each_netdev(&init_net, dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 struct in_device *in_dev;
1347 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001348 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 if (in_dev)
Herbert Xu42f811b2007-06-04 23:34:44 -07001350 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 rcu_read_unlock();
1352 }
1353 read_unlock(&dev_base_lock);
1354
1355 rt_cache_flush(0);
1356}
1357
1358static int devinet_sysctl_forward(ctl_table *ctl, int write,
1359 struct file* filp, void __user *buffer,
1360 size_t *lenp, loff_t *ppos)
1361{
1362 int *valp = ctl->data;
1363 int val = *valp;
1364 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1365
1366 if (write && *valp != val) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001367 if (valp == &IPV4_DEVCONF_ALL(FORWARDING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 inet_forward_change();
Herbert Xu42f811b2007-06-04 23:34:44 -07001369 else if (valp != &IPV4_DEVCONF_DFLT(FORWARDING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 rt_cache_flush(0);
1371 }
1372
1373 return ret;
1374}
1375
1376int ipv4_doint_and_flush(ctl_table *ctl, int write,
1377 struct file* filp, void __user *buffer,
1378 size_t *lenp, loff_t *ppos)
1379{
1380 int *valp = ctl->data;
1381 int val = *valp;
1382 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1383
1384 if (write && *valp != val)
1385 rt_cache_flush(0);
1386
1387 return ret;
1388}
1389
1390int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
1391 void __user *oldval, size_t __user *oldlenp,
Alexey Dobriyan1f29bcd2006-12-10 02:19:10 -08001392 void __user *newval, size_t newlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393{
Herbert Xu31be3082007-06-04 23:35:37 -07001394 int ret = devinet_conf_sysctl(table, name, nlen, oldval, oldlenp,
1395 newval, newlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396
Herbert Xu31be3082007-06-04 23:35:37 -07001397 if (ret == 1)
1398 rt_cache_flush(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399
Herbert Xu31be3082007-06-04 23:35:37 -07001400 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401}
1402
1403
Herbert Xu42f811b2007-06-04 23:34:44 -07001404#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc, sysctl) \
1405 { \
1406 .ctl_name = NET_IPV4_CONF_ ## attr, \
1407 .procname = name, \
1408 .data = ipv4_devconf.data + \
1409 NET_IPV4_CONF_ ## attr - 1, \
1410 .maxlen = sizeof(int), \
1411 .mode = mval, \
1412 .proc_handler = proc, \
1413 .strategy = sysctl, \
Herbert Xu31be3082007-06-04 23:35:37 -07001414 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07001415 }
1416
1417#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Herbert Xu31be3082007-06-04 23:35:37 -07001418 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc, \
1419 devinet_conf_sysctl)
Herbert Xu42f811b2007-06-04 23:34:44 -07001420
1421#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Herbert Xu31be3082007-06-04 23:35:37 -07001422 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc, \
1423 devinet_conf_sysctl)
Herbert Xu42f811b2007-06-04 23:34:44 -07001424
1425#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc, sysctl) \
1426 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc, sysctl)
1427
1428#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
1429 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush, \
1430 ipv4_doint_and_flush_strategy)
1431
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432static struct devinet_sysctl_table {
1433 struct ctl_table_header *sysctl_header;
1434 ctl_table devinet_vars[__NET_IPV4_CONF_MAX];
1435 ctl_table devinet_dev[2];
1436 ctl_table devinet_conf_dir[2];
1437 ctl_table devinet_proto_dir[2];
1438 ctl_table devinet_root_dir[2];
1439} devinet_sysctl = {
1440 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07001441 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Herbert Xu31be3082007-06-04 23:35:37 -07001442 devinet_sysctl_forward,
1443 devinet_conf_sysctl),
Herbert Xu42f811b2007-06-04 23:34:44 -07001444 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
1445
1446 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
1447 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
1448 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
1449 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
1450 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
1451 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
1452 "accept_source_route"),
1453 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
1454 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
1455 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
1456 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
1457 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
1458 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
1459 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
1460 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
1461 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
1462
1463 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
1464 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
1465 DEVINET_SYSCTL_FLUSHING_ENTRY(FORCE_IGMP_VERSION,
1466 "force_igmp_version"),
1467 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
1468 "promote_secondaries"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 },
1470 .devinet_dev = {
1471 {
1472 .ctl_name = NET_PROTO_CONF_ALL,
1473 .procname = "all",
1474 .mode = 0555,
1475 .child = devinet_sysctl.devinet_vars,
1476 },
1477 },
1478 .devinet_conf_dir = {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001479 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 .ctl_name = NET_IPV4_CONF,
1481 .procname = "conf",
1482 .mode = 0555,
1483 .child = devinet_sysctl.devinet_dev,
1484 },
1485 },
1486 .devinet_proto_dir = {
1487 {
1488 .ctl_name = NET_IPV4,
1489 .procname = "ipv4",
1490 .mode = 0555,
1491 .child = devinet_sysctl.devinet_conf_dir,
1492 },
1493 },
1494 .devinet_root_dir = {
1495 {
1496 .ctl_name = CTL_NET,
1497 .procname = "net",
1498 .mode = 0555,
1499 .child = devinet_sysctl.devinet_proto_dir,
1500 },
1501 },
1502};
1503
1504static void devinet_sysctl_register(struct in_device *in_dev,
1505 struct ipv4_devconf *p)
1506{
1507 int i;
1508 struct net_device *dev = in_dev ? in_dev->dev : NULL;
Arnaldo Carvalho de Melo42e5ea462006-11-17 11:18:20 -02001509 struct devinet_sysctl_table *t = kmemdup(&devinet_sysctl, sizeof(*t),
1510 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 char *dev_name = NULL;
1512
1513 if (!t)
1514 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
1516 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07001517 t->devinet_vars[i].extra1 = p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 }
1519
1520 if (dev) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001521 dev_name = dev->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 t->devinet_dev[0].ctl_name = dev->ifindex;
1523 } else {
1524 dev_name = "default";
1525 t->devinet_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT;
1526 }
1527
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001528 /*
1529 * Make a copy of dev_name, because '.procname' is regarded as const
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 * by sysctl and we wouldn't want anyone to change it under our feet
1531 * (see SIOCSIFNAME).
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001532 */
Paulo Marques543537b2005-06-23 00:09:02 -07001533 dev_name = kstrdup(dev_name, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 if (!dev_name)
1535 goto free;
1536
1537 t->devinet_dev[0].procname = dev_name;
1538 t->devinet_dev[0].child = t->devinet_vars;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 t->devinet_conf_dir[0].child = t->devinet_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 t->devinet_proto_dir[0].child = t->devinet_conf_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 t->devinet_root_dir[0].child = t->devinet_proto_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542
Eric W. Biederman0b4d4142007-02-14 00:34:09 -08001543 t->sysctl_header = register_sysctl_table(t->devinet_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 if (!t->sysctl_header)
1545 goto free_procname;
1546
1547 p->sysctl = t;
1548 return;
1549
1550 /* error path */
1551 free_procname:
1552 kfree(dev_name);
1553 free:
1554 kfree(t);
1555 return;
1556}
1557
1558static void devinet_sysctl_unregister(struct ipv4_devconf *p)
1559{
1560 if (p->sysctl) {
1561 struct devinet_sysctl_table *t = p->sysctl;
1562 p->sysctl = NULL;
1563 unregister_sysctl_table(t->sysctl_header);
1564 kfree(t->devinet_dev[0].procname);
1565 kfree(t);
1566 }
1567}
1568#endif
1569
1570void __init devinet_init(void)
1571{
1572 register_gifconf(PF_INET, inet_gifconf);
1573 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07001574
1575 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL);
1576 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL);
1577 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578#ifdef CONFIG_SYSCTL
1579 devinet_sysctl.sysctl_header =
Eric W. Biederman0b4d4142007-02-14 00:34:09 -08001580 register_sysctl_table(devinet_sysctl.devinet_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 devinet_sysctl_register(NULL, &ipv4_devconf_dflt);
1582#endif
1583}
1584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585EXPORT_SYMBOL(in_dev_finish_destroy);
1586EXPORT_SYMBOL(inet_select_addr);
1587EXPORT_SYMBOL(inetdev_by_index);
1588EXPORT_SYMBOL(register_inetaddr_notifier);
1589EXPORT_SYMBOL(unregister_inetaddr_notifier);