blob: b42f74617bacfffaaf3af90856cc014ecf239dd5 [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{
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700444 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700446 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700448 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
450 ASSERT_RTNL();
451
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700452 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
453 if (err < 0)
454 goto errout;
455
456 ifm = nlmsg_data(nlh);
457 in_dev = inetdev_by_index(ifm->ifa_index);
458 if (in_dev == NULL) {
459 err = -ENODEV;
460 goto errout;
461 }
462
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 __in_dev_put(in_dev);
464
465 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
466 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700467 if (tb[IFA_LOCAL] &&
Al Viroa7a628c2006-09-26 22:16:43 -0700468 ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700470
471 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
472 continue;
473
474 if (tb[IFA_ADDRESS] &&
475 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Al Viroa7a628c2006-09-26 22:16:43 -0700476 !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700477 continue;
478
Thomas Grafd6062cb2006-08-15 00:33:59 -0700479 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 return 0;
481 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700482
483 err = -EADDRNOTAVAIL;
484errout:
485 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486}
487
Thomas Graf5c753972006-08-04 23:03:53 -0700488static struct in_ifaddr *rtm_to_ifaddr(struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489{
Thomas Graf5c753972006-08-04 23:03:53 -0700490 struct nlattr *tb[IFA_MAX+1];
491 struct in_ifaddr *ifa;
492 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 struct net_device *dev;
494 struct in_device *in_dev;
Thomas Graf5c753972006-08-04 23:03:53 -0700495 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
Thomas Graf5c753972006-08-04 23:03:53 -0700497 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
498 if (err < 0)
499 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
Thomas Graf5c753972006-08-04 23:03:53 -0700501 ifm = nlmsg_data(nlh);
Evgeniy Polyakovc4e38f42007-03-09 13:43:24 -0800502 if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL) {
503 err = -EINVAL;
Thomas Graf5c753972006-08-04 23:03:53 -0700504 goto errout;
Evgeniy Polyakovc4e38f42007-03-09 13:43:24 -0800505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
Eric W. Biederman881d9662007-09-17 11:56:21 -0700507 dev = __dev_get_by_index(&init_net, ifm->ifa_index);
Thomas Graf5c753972006-08-04 23:03:53 -0700508 if (dev == NULL) {
509 err = -ENODEV;
510 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 }
512
Thomas Graf5c753972006-08-04 23:03:53 -0700513 in_dev = __in_dev_get_rtnl(dev);
514 if (in_dev == NULL) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700515 err = -ENOBUFS;
516 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700517 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
Thomas Graf5c753972006-08-04 23:03:53 -0700519 ifa = inet_alloc_ifa();
520 if (ifa == NULL) {
521 /*
522 * A potential indev allocation can be left alive, it stays
523 * assigned to its device and is destroy with it.
524 */
525 err = -ENOBUFS;
526 goto errout;
527 }
528
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800529 ipv4_devconf_setall(in_dev);
Thomas Graf5c753972006-08-04 23:03:53 -0700530 in_dev_hold(in_dev);
531
532 if (tb[IFA_ADDRESS] == NULL)
533 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
536 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 ifa->ifa_flags = ifm->ifa_flags;
538 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700539 ifa->ifa_dev = in_dev;
540
Al Viroa7a628c2006-09-26 22:16:43 -0700541 ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]);
542 ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700543
544 if (tb[IFA_BROADCAST])
Al Viroa7a628c2006-09-26 22:16:43 -0700545 ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700546
547 if (tb[IFA_ANYCAST])
Al Viroa7a628c2006-09-26 22:16:43 -0700548 ifa->ifa_anycast = nla_get_be32(tb[IFA_ANYCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700549
550 if (tb[IFA_LABEL])
551 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 else
553 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
554
Thomas Graf5c753972006-08-04 23:03:53 -0700555 return ifa;
556
557errout:
558 return ERR_PTR(err);
559}
560
561static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
562{
563 struct in_ifaddr *ifa;
564
565 ASSERT_RTNL();
566
567 ifa = rtm_to_ifaddr(nlh);
568 if (IS_ERR(ifa))
569 return PTR_ERR(ifa);
570
Thomas Grafd6062cb2006-08-15 00:33:59 -0700571 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572}
573
574/*
575 * Determine a default network mask, based on the IP address.
576 */
577
Al Viro714e85b2006-11-14 20:51:49 -0800578static __inline__ int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579{
580 int rc = -1; /* Something else, probably a multicast. */
581
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900582 if (ZERONET(addr))
583 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 else {
Al Viro714e85b2006-11-14 20:51:49 -0800585 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
Al Viro714e85b2006-11-14 20:51:49 -0800587 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800589 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800591 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 rc = 24;
593 }
594
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900595 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596}
597
598
599int devinet_ioctl(unsigned int cmd, void __user *arg)
600{
601 struct ifreq ifr;
602 struct sockaddr_in sin_orig;
603 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
604 struct in_device *in_dev;
605 struct in_ifaddr **ifap = NULL;
606 struct in_ifaddr *ifa = NULL;
607 struct net_device *dev;
608 char *colon;
609 int ret = -EFAULT;
610 int tryaddrmatch = 0;
611
612 /*
613 * Fetch the caller's info block into kernel space
614 */
615
616 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
617 goto out;
618 ifr.ifr_name[IFNAMSIZ - 1] = 0;
619
620 /* save original address for comparison */
621 memcpy(&sin_orig, sin, sizeof(*sin));
622
623 colon = strchr(ifr.ifr_name, ':');
624 if (colon)
625 *colon = 0;
626
627#ifdef CONFIG_KMOD
Eric W. Biederman881d9662007-09-17 11:56:21 -0700628 dev_load(&init_net, ifr.ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629#endif
630
Stephen Hemminger132adf52007-03-08 20:44:43 -0800631 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 case SIOCGIFADDR: /* Get interface address */
633 case SIOCGIFBRDADDR: /* Get the broadcast address */
634 case SIOCGIFDSTADDR: /* Get the destination address */
635 case SIOCGIFNETMASK: /* Get the netmask for the interface */
636 /* Note that these ioctls will not sleep,
637 so that we do not impose a lock.
638 One day we will be forced to put shlock here (I mean SMP)
639 */
640 tryaddrmatch = (sin_orig.sin_family == AF_INET);
641 memset(sin, 0, sizeof(*sin));
642 sin->sin_family = AF_INET;
643 break;
644
645 case SIOCSIFFLAGS:
646 ret = -EACCES;
647 if (!capable(CAP_NET_ADMIN))
648 goto out;
649 break;
650 case SIOCSIFADDR: /* Set interface address (and family) */
651 case SIOCSIFBRDADDR: /* Set the broadcast address */
652 case SIOCSIFDSTADDR: /* Set the destination address */
653 case SIOCSIFNETMASK: /* Set the netmask for the interface */
654 ret = -EACCES;
655 if (!capable(CAP_NET_ADMIN))
656 goto out;
657 ret = -EINVAL;
658 if (sin->sin_family != AF_INET)
659 goto out;
660 break;
661 default:
662 ret = -EINVAL;
663 goto out;
664 }
665
666 rtnl_lock();
667
668 ret = -ENODEV;
Eric W. Biederman881d9662007-09-17 11:56:21 -0700669 if ((dev = __dev_get_by_name(&init_net, ifr.ifr_name)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 goto done;
671
672 if (colon)
673 *colon = ':';
674
Herbert Xue5ed6392005-10-03 14:35:55 -0700675 if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 if (tryaddrmatch) {
677 /* Matthias Andree */
678 /* compare label and address (4.4BSD style) */
679 /* note: we only do this for a limited set of ioctls
680 and only if the original address family was AF_INET.
681 This is checked above. */
682 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
683 ifap = &ifa->ifa_next) {
684 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
685 sin_orig.sin_addr.s_addr ==
686 ifa->ifa_address) {
687 break; /* found */
688 }
689 }
690 }
691 /* we didn't get a match, maybe the application is
692 4.3BSD-style and passed in junk so we fall back to
693 comparing just the label */
694 if (!ifa) {
695 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
696 ifap = &ifa->ifa_next)
697 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
698 break;
699 }
700 }
701
702 ret = -EADDRNOTAVAIL;
703 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
704 goto done;
705
Stephen Hemminger132adf52007-03-08 20:44:43 -0800706 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 case SIOCGIFADDR: /* Get interface address */
708 sin->sin_addr.s_addr = ifa->ifa_local;
709 goto rarok;
710
711 case SIOCGIFBRDADDR: /* Get the broadcast address */
712 sin->sin_addr.s_addr = ifa->ifa_broadcast;
713 goto rarok;
714
715 case SIOCGIFDSTADDR: /* Get the destination address */
716 sin->sin_addr.s_addr = ifa->ifa_address;
717 goto rarok;
718
719 case SIOCGIFNETMASK: /* Get the netmask for the interface */
720 sin->sin_addr.s_addr = ifa->ifa_mask;
721 goto rarok;
722
723 case SIOCSIFFLAGS:
724 if (colon) {
725 ret = -EADDRNOTAVAIL;
726 if (!ifa)
727 break;
728 ret = 0;
729 if (!(ifr.ifr_flags & IFF_UP))
730 inet_del_ifa(in_dev, ifap, 1);
731 break;
732 }
733 ret = dev_change_flags(dev, ifr.ifr_flags);
734 break;
735
736 case SIOCSIFADDR: /* Set interface address (and family) */
737 ret = -EINVAL;
738 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
739 break;
740
741 if (!ifa) {
742 ret = -ENOBUFS;
743 if ((ifa = inet_alloc_ifa()) == NULL)
744 break;
745 if (colon)
746 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
747 else
748 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
749 } else {
750 ret = 0;
751 if (ifa->ifa_local == sin->sin_addr.s_addr)
752 break;
753 inet_del_ifa(in_dev, ifap, 0);
754 ifa->ifa_broadcast = 0;
755 ifa->ifa_anycast = 0;
756 }
757
758 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
759
760 if (!(dev->flags & IFF_POINTOPOINT)) {
761 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
762 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
763 if ((dev->flags & IFF_BROADCAST) &&
764 ifa->ifa_prefixlen < 31)
765 ifa->ifa_broadcast = ifa->ifa_address |
766 ~ifa->ifa_mask;
767 } else {
768 ifa->ifa_prefixlen = 32;
769 ifa->ifa_mask = inet_make_mask(32);
770 }
771 ret = inet_set_ifa(dev, ifa);
772 break;
773
774 case SIOCSIFBRDADDR: /* Set the broadcast address */
775 ret = 0;
776 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
777 inet_del_ifa(in_dev, ifap, 0);
778 ifa->ifa_broadcast = sin->sin_addr.s_addr;
779 inet_insert_ifa(ifa);
780 }
781 break;
782
783 case SIOCSIFDSTADDR: /* Set the destination address */
784 ret = 0;
785 if (ifa->ifa_address == sin->sin_addr.s_addr)
786 break;
787 ret = -EINVAL;
788 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
789 break;
790 ret = 0;
791 inet_del_ifa(in_dev, ifap, 0);
792 ifa->ifa_address = sin->sin_addr.s_addr;
793 inet_insert_ifa(ifa);
794 break;
795
796 case SIOCSIFNETMASK: /* Set the netmask for the interface */
797
798 /*
799 * The mask we set must be legal.
800 */
801 ret = -EINVAL;
802 if (bad_mask(sin->sin_addr.s_addr, 0))
803 break;
804 ret = 0;
805 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -0700806 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 inet_del_ifa(in_dev, ifap, 0);
808 ifa->ifa_mask = sin->sin_addr.s_addr;
809 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
810
811 /* See if current broadcast address matches
812 * with current netmask, then recalculate
813 * the broadcast address. Otherwise it's a
814 * funny address, so don't touch it since
815 * the user seems to know what (s)he's doing...
816 */
817 if ((dev->flags & IFF_BROADCAST) &&
818 (ifa->ifa_prefixlen < 31) &&
819 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -0500820 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 ifa->ifa_broadcast = (ifa->ifa_local |
822 ~sin->sin_addr.s_addr);
823 }
824 inet_insert_ifa(ifa);
825 }
826 break;
827 }
828done:
829 rtnl_unlock();
830out:
831 return ret;
832rarok:
833 rtnl_unlock();
834 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
835 goto out;
836}
837
838static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
839{
Herbert Xue5ed6392005-10-03 14:35:55 -0700840 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 struct in_ifaddr *ifa;
842 struct ifreq ifr;
843 int done = 0;
844
845 if (!in_dev || (ifa = in_dev->ifa_list) == NULL)
846 goto out;
847
848 for (; ifa; ifa = ifa->ifa_next) {
849 if (!buf) {
850 done += sizeof(ifr);
851 continue;
852 }
853 if (len < (int) sizeof(ifr))
854 break;
855 memset(&ifr, 0, sizeof(struct ifreq));
856 if (ifa->ifa_label)
857 strcpy(ifr.ifr_name, ifa->ifa_label);
858 else
859 strcpy(ifr.ifr_name, dev->name);
860
861 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
862 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
863 ifa->ifa_local;
864
865 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
866 done = -EFAULT;
867 break;
868 }
869 buf += sizeof(struct ifreq);
870 len -= sizeof(struct ifreq);
871 done += sizeof(struct ifreq);
872 }
873out:
874 return done;
875}
876
Al Viroa61ced52006-09-26 21:27:54 -0700877__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878{
Al Viroa61ced52006-09-26 21:27:54 -0700879 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 struct in_device *in_dev;
881
882 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -0700883 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 if (!in_dev)
885 goto no_in_dev;
886
887 for_primary_ifa(in_dev) {
888 if (ifa->ifa_scope > scope)
889 continue;
890 if (!dst || inet_ifa_match(dst, ifa)) {
891 addr = ifa->ifa_local;
892 break;
893 }
894 if (!addr)
895 addr = ifa->ifa_local;
896 } endfor_ifa(in_dev);
897no_in_dev:
898 rcu_read_unlock();
899
900 if (addr)
901 goto out;
902
903 /* Not loopback addresses on loopback should be preferred
904 in this case. It is importnat that lo is the first interface
905 in dev_base list.
906 */
907 read_lock(&dev_base_lock);
908 rcu_read_lock();
Eric W. Biederman881d9662007-09-17 11:56:21 -0700909 for_each_netdev(&init_net, dev) {
Herbert Xue5ed6392005-10-03 14:35:55 -0700910 if ((in_dev = __in_dev_get_rcu(dev)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 continue;
912
913 for_primary_ifa(in_dev) {
914 if (ifa->ifa_scope != RT_SCOPE_LINK &&
915 ifa->ifa_scope <= scope) {
916 addr = ifa->ifa_local;
917 goto out_unlock_both;
918 }
919 } endfor_ifa(in_dev);
920 }
921out_unlock_both:
922 read_unlock(&dev_base_lock);
923 rcu_read_unlock();
924out:
925 return addr;
926}
927
Al Viro60cad5d2006-09-26 22:17:09 -0700928static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
929 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930{
931 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -0700932 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
934 for_ifa(in_dev) {
935 if (!addr &&
936 (local == ifa->ifa_local || !local) &&
937 ifa->ifa_scope <= scope) {
938 addr = ifa->ifa_local;
939 if (same)
940 break;
941 }
942 if (!same) {
943 same = (!local || inet_ifa_match(local, ifa)) &&
944 (!dst || inet_ifa_match(dst, ifa));
945 if (same && addr) {
946 if (local || !dst)
947 break;
948 /* Is the selected addr into dst subnet? */
949 if (inet_ifa_match(addr, ifa))
950 break;
951 /* No, then can we use new local src? */
952 if (ifa->ifa_scope <= scope) {
953 addr = ifa->ifa_local;
954 break;
955 }
956 /* search for large dst subnet for addr */
957 same = 0;
958 }
959 }
960 } endfor_ifa(in_dev);
961
962 return same? addr : 0;
963}
964
965/*
966 * Confirm that local IP address exists using wildcards:
967 * - dev: only on this interface, 0=any interface
968 * - dst: only in the same subnet as dst, 0=any dst
969 * - local: address, 0=autoselect the local address
970 * - scope: maximum allowed scope value for the local address
971 */
Al Viro60cad5d2006-09-26 22:17:09 -0700972__be32 inet_confirm_addr(const struct net_device *dev, __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973{
Al Viro60cad5d2006-09-26 22:17:09 -0700974 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 struct in_device *in_dev;
976
977 if (dev) {
978 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -0700979 if ((in_dev = __in_dev_get_rcu(dev)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 addr = confirm_addr_indev(in_dev, dst, local, scope);
981 rcu_read_unlock();
982
983 return addr;
984 }
985
986 read_lock(&dev_base_lock);
987 rcu_read_lock();
Eric W. Biederman881d9662007-09-17 11:56:21 -0700988 for_each_netdev(&init_net, dev) {
Herbert Xue5ed6392005-10-03 14:35:55 -0700989 if ((in_dev = __in_dev_get_rcu(dev))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 addr = confirm_addr_indev(in_dev, dst, local, scope);
991 if (addr)
992 break;
993 }
994 }
995 rcu_read_unlock();
996 read_unlock(&dev_base_lock);
997
998 return addr;
999}
1000
1001/*
1002 * Device notifier
1003 */
1004
1005int register_inetaddr_notifier(struct notifier_block *nb)
1006{
Alan Sterne041c682006-03-27 01:16:30 -08001007 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008}
1009
1010int unregister_inetaddr_notifier(struct notifier_block *nb)
1011{
Alan Sterne041c682006-03-27 01:16:30 -08001012 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013}
1014
1015/* Rename ifa_labels for a device name change. Make some effort to preserve existing
1016 * alias numbering and to create unique labels if possible.
1017*/
1018static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001019{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 struct in_ifaddr *ifa;
1021 int named = 0;
1022
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001023 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1024 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
1026 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001027 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 if (named++ == 0)
1029 continue;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001030 dot = strchr(old, ':');
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001031 if (dot == NULL) {
1032 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 dot = old;
1034 }
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001035 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ) {
1036 strcat(ifa->ifa_label, dot);
1037 } else {
1038 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
1039 }
1040 }
1041}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
1043/* Called only under RTNL semaphore */
1044
1045static int inetdev_event(struct notifier_block *this, unsigned long event,
1046 void *ptr)
1047{
1048 struct net_device *dev = ptr;
Herbert Xue5ed6392005-10-03 14:35:55 -07001049 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001051 if (dev->nd_net != &init_net)
1052 return NOTIFY_DONE;
1053
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 ASSERT_RTNL();
1055
1056 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001057 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 in_dev = inetdev_init(dev);
Herbert Xub217d612007-07-30 17:04:52 -07001059 if (!in_dev)
1060 return notifier_from_errno(-ENOMEM);
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001061 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001062 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1063 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001064 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 }
1066 goto out;
1067 }
1068
1069 switch (event) {
1070 case NETDEV_REGISTER:
1071 printk(KERN_DEBUG "inetdev_event: bug\n");
1072 dev->ip_ptr = NULL;
1073 break;
1074 case NETDEV_UP:
1075 if (dev->mtu < 68)
1076 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001077 if (dev->flags & IFF_LOOPBACK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 struct in_ifaddr *ifa;
1079 if ((ifa = inet_alloc_ifa()) != NULL) {
1080 ifa->ifa_local =
1081 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1082 ifa->ifa_prefixlen = 8;
1083 ifa->ifa_mask = inet_make_mask(8);
1084 in_dev_hold(in_dev);
1085 ifa->ifa_dev = in_dev;
1086 ifa->ifa_scope = RT_SCOPE_HOST;
1087 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1088 inet_insert_ifa(ifa);
1089 }
1090 }
1091 ip_mc_up(in_dev);
1092 break;
1093 case NETDEV_DOWN:
1094 ip_mc_down(in_dev);
1095 break;
1096 case NETDEV_CHANGEMTU:
1097 if (dev->mtu >= 68)
1098 break;
1099 /* MTU falled under 68, disable IP */
1100 case NETDEV_UNREGISTER:
1101 inetdev_destroy(in_dev);
1102 break;
1103 case NETDEV_CHANGENAME:
1104 /* Do not notify about label change, this event is
1105 * not interesting to applications using netlink.
1106 */
1107 inetdev_changename(dev, in_dev);
1108
1109#ifdef CONFIG_SYSCTL
1110 devinet_sysctl_unregister(&in_dev->cnf);
1111 neigh_sysctl_unregister(in_dev->arp_parms);
1112 neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
1113 NET_IPV4_NEIGH, "ipv4", NULL, NULL);
1114 devinet_sysctl_register(in_dev, &in_dev->cnf);
1115#endif
1116 break;
1117 }
1118out:
1119 return NOTIFY_DONE;
1120}
1121
1122static struct notifier_block ip_netdev_notifier = {
1123 .notifier_call =inetdev_event,
1124};
1125
Thomas Graf339bf982006-11-10 14:10:15 -08001126static inline size_t inet_nlmsg_size(void)
1127{
1128 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1129 + nla_total_size(4) /* IFA_ADDRESS */
1130 + nla_total_size(4) /* IFA_LOCAL */
1131 + nla_total_size(4) /* IFA_BROADCAST */
1132 + nla_total_size(4) /* IFA_ANYCAST */
1133 + nla_total_size(IFNAMSIZ); /* IFA_LABEL */
1134}
1135
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07001137 u32 pid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138{
1139 struct ifaddrmsg *ifm;
1140 struct nlmsghdr *nlh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
Thomas Graf47f68512006-08-04 23:04:36 -07001142 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);
1143 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001144 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001145
1146 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 ifm->ifa_family = AF_INET;
1148 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
1149 ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT;
1150 ifm->ifa_scope = ifa->ifa_scope;
1151 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
Thomas Graf47f68512006-08-04 23:04:36 -07001153 if (ifa->ifa_address)
Al Viroa7a628c2006-09-26 22:16:43 -07001154 NLA_PUT_BE32(skb, IFA_ADDRESS, ifa->ifa_address);
Thomas Graf47f68512006-08-04 23:04:36 -07001155
1156 if (ifa->ifa_local)
Al Viroa7a628c2006-09-26 22:16:43 -07001157 NLA_PUT_BE32(skb, IFA_LOCAL, ifa->ifa_local);
Thomas Graf47f68512006-08-04 23:04:36 -07001158
1159 if (ifa->ifa_broadcast)
Al Viroa7a628c2006-09-26 22:16:43 -07001160 NLA_PUT_BE32(skb, IFA_BROADCAST, ifa->ifa_broadcast);
Thomas Graf47f68512006-08-04 23:04:36 -07001161
1162 if (ifa->ifa_anycast)
Al Viroa7a628c2006-09-26 22:16:43 -07001163 NLA_PUT_BE32(skb, IFA_ANYCAST, ifa->ifa_anycast);
Thomas Graf47f68512006-08-04 23:04:36 -07001164
1165 if (ifa->ifa_label[0])
1166 NLA_PUT_STRING(skb, IFA_LABEL, ifa->ifa_label);
1167
1168 return nlmsg_end(skb, nlh);
1169
1170nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001171 nlmsg_cancel(skb, nlh);
1172 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173}
1174
1175static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1176{
1177 int idx, ip_idx;
1178 struct net_device *dev;
1179 struct in_device *in_dev;
1180 struct in_ifaddr *ifa;
1181 int s_ip_idx, s_idx = cb->args[0];
1182
1183 s_ip_idx = ip_idx = cb->args[1];
Pavel Emelianov7562f872007-05-03 15:13:45 -07001184 idx = 0;
Eric W. Biederman881d9662007-09-17 11:56:21 -07001185 for_each_netdev(&init_net, dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 if (idx < s_idx)
Pavel Emelianov7562f872007-05-03 15:13:45 -07001187 goto cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 if (idx > s_idx)
1189 s_ip_idx = 0;
Patrick McHardy6313c1e2007-04-16 17:00:53 -07001190 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL)
Pavel Emelianov7562f872007-05-03 15:13:45 -07001191 goto cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
1193 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1194 ifa = ifa->ifa_next, ip_idx++) {
1195 if (ip_idx < s_ip_idx)
Stephen Hemminger596e4152007-09-11 10:41:04 +02001196 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
1198 cb->nlh->nlmsg_seq,
Patrick McHardy6313c1e2007-04-16 17:00:53 -07001199 RTM_NEWADDR, NLM_F_MULTI) <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 goto done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001202cont:
1203 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 }
1205
1206done:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 cb->args[0] = idx;
1208 cb->args[1] = ip_idx;
1209
1210 return skb->len;
1211}
1212
Thomas Grafd6062cb2006-08-15 00:33:59 -07001213static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
1214 u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215{
Thomas Graf47f68512006-08-04 23:04:36 -07001216 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001217 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1218 int err = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219
Thomas Graf339bf982006-11-10 14:10:15 -08001220 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Thomas Graf47f68512006-08-04 23:04:36 -07001221 if (skb == NULL)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001222 goto errout;
1223
1224 err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001225 if (err < 0) {
1226 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1227 WARN_ON(err == -EMSGSIZE);
1228 kfree_skb(skb);
1229 goto errout;
1230 }
Thomas Grafd6062cb2006-08-15 00:33:59 -07001231 err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
1232errout:
1233 if (err < 0)
1234 rtnl_set_sk_err(RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235}
1236
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237#ifdef CONFIG_SYSCTL
1238
Herbert Xu31be3082007-06-04 23:35:37 -07001239static void devinet_copy_dflt_conf(int i)
1240{
1241 struct net_device *dev;
1242
1243 read_lock(&dev_base_lock);
Eric W. Biederman881d9662007-09-17 11:56:21 -07001244 for_each_netdev(&init_net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07001245 struct in_device *in_dev;
1246 rcu_read_lock();
1247 in_dev = __in_dev_get_rcu(dev);
1248 if (in_dev && !test_bit(i, in_dev->cnf.state))
1249 in_dev->cnf.data[i] = ipv4_devconf_dflt.data[i];
1250 rcu_read_unlock();
1251 }
1252 read_unlock(&dev_base_lock);
1253}
1254
1255static int devinet_conf_proc(ctl_table *ctl, int write,
1256 struct file* filp, void __user *buffer,
1257 size_t *lenp, loff_t *ppos)
1258{
1259 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1260
1261 if (write) {
1262 struct ipv4_devconf *cnf = ctl->extra1;
1263 int i = (int *)ctl->data - cnf->data;
1264
1265 set_bit(i, cnf->state);
1266
1267 if (cnf == &ipv4_devconf_dflt)
1268 devinet_copy_dflt_conf(i);
1269 }
1270
1271 return ret;
1272}
1273
1274static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,
1275 void __user *oldval, size_t __user *oldlenp,
1276 void __user *newval, size_t newlen)
1277{
1278 struct ipv4_devconf *cnf;
1279 int *valp = table->data;
1280 int new;
1281 int i;
1282
1283 if (!newval || !newlen)
1284 return 0;
1285
1286 if (newlen != sizeof(int))
1287 return -EINVAL;
1288
1289 if (get_user(new, (int __user *)newval))
1290 return -EFAULT;
1291
1292 if (new == *valp)
1293 return 0;
1294
1295 if (oldval && oldlenp) {
1296 size_t len;
1297
1298 if (get_user(len, oldlenp))
1299 return -EFAULT;
1300
1301 if (len) {
1302 if (len > table->maxlen)
1303 len = table->maxlen;
1304 if (copy_to_user(oldval, valp, len))
1305 return -EFAULT;
1306 if (put_user(len, oldlenp))
1307 return -EFAULT;
1308 }
1309 }
1310
1311 *valp = new;
1312
1313 cnf = table->extra1;
1314 i = (int *)table->data - cnf->data;
1315
1316 set_bit(i, cnf->state);
1317
1318 if (cnf == &ipv4_devconf_dflt)
1319 devinet_copy_dflt_conf(i);
1320
1321 return 1;
1322}
1323
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324void inet_forward_change(void)
1325{
1326 struct net_device *dev;
Herbert Xu42f811b2007-06-04 23:34:44 -07001327 int on = IPV4_DEVCONF_ALL(FORWARDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
Herbert Xu42f811b2007-06-04 23:34:44 -07001329 IPV4_DEVCONF_ALL(ACCEPT_REDIRECTS) = !on;
1330 IPV4_DEVCONF_DFLT(FORWARDING) = on;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331
1332 read_lock(&dev_base_lock);
Eric W. Biederman881d9662007-09-17 11:56:21 -07001333 for_each_netdev(&init_net, dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 struct in_device *in_dev;
1335 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001336 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 if (in_dev)
Herbert Xu42f811b2007-06-04 23:34:44 -07001338 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 rcu_read_unlock();
1340 }
1341 read_unlock(&dev_base_lock);
1342
1343 rt_cache_flush(0);
1344}
1345
1346static int devinet_sysctl_forward(ctl_table *ctl, int write,
1347 struct file* filp, void __user *buffer,
1348 size_t *lenp, loff_t *ppos)
1349{
1350 int *valp = ctl->data;
1351 int val = *valp;
1352 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1353
1354 if (write && *valp != val) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001355 if (valp == &IPV4_DEVCONF_ALL(FORWARDING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 inet_forward_change();
Herbert Xu42f811b2007-06-04 23:34:44 -07001357 else if (valp != &IPV4_DEVCONF_DFLT(FORWARDING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 rt_cache_flush(0);
1359 }
1360
1361 return ret;
1362}
1363
1364int ipv4_doint_and_flush(ctl_table *ctl, int write,
1365 struct file* filp, void __user *buffer,
1366 size_t *lenp, loff_t *ppos)
1367{
1368 int *valp = ctl->data;
1369 int val = *valp;
1370 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1371
1372 if (write && *valp != val)
1373 rt_cache_flush(0);
1374
1375 return ret;
1376}
1377
1378int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
1379 void __user *oldval, size_t __user *oldlenp,
Alexey Dobriyan1f29bcd2006-12-10 02:19:10 -08001380 void __user *newval, size_t newlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381{
Herbert Xu31be3082007-06-04 23:35:37 -07001382 int ret = devinet_conf_sysctl(table, name, nlen, oldval, oldlenp,
1383 newval, newlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384
Herbert Xu31be3082007-06-04 23:35:37 -07001385 if (ret == 1)
1386 rt_cache_flush(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
Herbert Xu31be3082007-06-04 23:35:37 -07001388 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389}
1390
1391
Herbert Xu42f811b2007-06-04 23:34:44 -07001392#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc, sysctl) \
1393 { \
1394 .ctl_name = NET_IPV4_CONF_ ## attr, \
1395 .procname = name, \
1396 .data = ipv4_devconf.data + \
1397 NET_IPV4_CONF_ ## attr - 1, \
1398 .maxlen = sizeof(int), \
1399 .mode = mval, \
1400 .proc_handler = proc, \
1401 .strategy = sysctl, \
Herbert Xu31be3082007-06-04 23:35:37 -07001402 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07001403 }
1404
1405#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Herbert Xu31be3082007-06-04 23:35:37 -07001406 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc, \
1407 devinet_conf_sysctl)
Herbert Xu42f811b2007-06-04 23:34:44 -07001408
1409#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Herbert Xu31be3082007-06-04 23:35:37 -07001410 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc, \
1411 devinet_conf_sysctl)
Herbert Xu42f811b2007-06-04 23:34:44 -07001412
1413#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc, sysctl) \
1414 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc, sysctl)
1415
1416#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
1417 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush, \
1418 ipv4_doint_and_flush_strategy)
1419
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420static struct devinet_sysctl_table {
1421 struct ctl_table_header *sysctl_header;
1422 ctl_table devinet_vars[__NET_IPV4_CONF_MAX];
1423 ctl_table devinet_dev[2];
1424 ctl_table devinet_conf_dir[2];
1425 ctl_table devinet_proto_dir[2];
1426 ctl_table devinet_root_dir[2];
1427} devinet_sysctl = {
1428 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07001429 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Herbert Xu31be3082007-06-04 23:35:37 -07001430 devinet_sysctl_forward,
1431 devinet_conf_sysctl),
Herbert Xu42f811b2007-06-04 23:34:44 -07001432 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
1433
1434 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
1435 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
1436 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
1437 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
1438 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
1439 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
1440 "accept_source_route"),
1441 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
1442 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
1443 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
1444 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
1445 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
1446 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
1447 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
1448 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
1449 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
1450
1451 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
1452 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
1453 DEVINET_SYSCTL_FLUSHING_ENTRY(FORCE_IGMP_VERSION,
1454 "force_igmp_version"),
1455 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
1456 "promote_secondaries"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 },
1458 .devinet_dev = {
1459 {
1460 .ctl_name = NET_PROTO_CONF_ALL,
1461 .procname = "all",
1462 .mode = 0555,
1463 .child = devinet_sysctl.devinet_vars,
1464 },
1465 },
1466 .devinet_conf_dir = {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001467 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 .ctl_name = NET_IPV4_CONF,
1469 .procname = "conf",
1470 .mode = 0555,
1471 .child = devinet_sysctl.devinet_dev,
1472 },
1473 },
1474 .devinet_proto_dir = {
1475 {
1476 .ctl_name = NET_IPV4,
1477 .procname = "ipv4",
1478 .mode = 0555,
1479 .child = devinet_sysctl.devinet_conf_dir,
1480 },
1481 },
1482 .devinet_root_dir = {
1483 {
1484 .ctl_name = CTL_NET,
1485 .procname = "net",
1486 .mode = 0555,
1487 .child = devinet_sysctl.devinet_proto_dir,
1488 },
1489 },
1490};
1491
1492static void devinet_sysctl_register(struct in_device *in_dev,
1493 struct ipv4_devconf *p)
1494{
1495 int i;
1496 struct net_device *dev = in_dev ? in_dev->dev : NULL;
Arnaldo Carvalho de Melo42e5ea462006-11-17 11:18:20 -02001497 struct devinet_sysctl_table *t = kmemdup(&devinet_sysctl, sizeof(*t),
1498 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 char *dev_name = NULL;
1500
1501 if (!t)
1502 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
1504 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07001505 t->devinet_vars[i].extra1 = p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 }
1507
1508 if (dev) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001509 dev_name = dev->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 t->devinet_dev[0].ctl_name = dev->ifindex;
1511 } else {
1512 dev_name = "default";
1513 t->devinet_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT;
1514 }
1515
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001516 /*
1517 * Make a copy of dev_name, because '.procname' is regarded as const
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 * by sysctl and we wouldn't want anyone to change it under our feet
1519 * (see SIOCSIFNAME).
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001520 */
Paulo Marques543537b2005-06-23 00:09:02 -07001521 dev_name = kstrdup(dev_name, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 if (!dev_name)
1523 goto free;
1524
1525 t->devinet_dev[0].procname = dev_name;
1526 t->devinet_dev[0].child = t->devinet_vars;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 t->devinet_conf_dir[0].child = t->devinet_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 t->devinet_proto_dir[0].child = t->devinet_conf_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 t->devinet_root_dir[0].child = t->devinet_proto_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530
Eric W. Biederman0b4d4142007-02-14 00:34:09 -08001531 t->sysctl_header = register_sysctl_table(t->devinet_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 if (!t->sysctl_header)
1533 goto free_procname;
1534
1535 p->sysctl = t;
1536 return;
1537
1538 /* error path */
1539 free_procname:
1540 kfree(dev_name);
1541 free:
1542 kfree(t);
1543 return;
1544}
1545
1546static void devinet_sysctl_unregister(struct ipv4_devconf *p)
1547{
1548 if (p->sysctl) {
1549 struct devinet_sysctl_table *t = p->sysctl;
1550 p->sysctl = NULL;
1551 unregister_sysctl_table(t->sysctl_header);
1552 kfree(t->devinet_dev[0].procname);
1553 kfree(t);
1554 }
1555}
1556#endif
1557
1558void __init devinet_init(void)
1559{
1560 register_gifconf(PF_INET, inet_gifconf);
1561 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07001562
1563 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL);
1564 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL);
1565 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566#ifdef CONFIG_SYSCTL
1567 devinet_sysctl.sysctl_header =
Eric W. Biederman0b4d4142007-02-14 00:34:09 -08001568 register_sysctl_table(devinet_sysctl.devinet_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 devinet_sysctl_register(NULL, &ipv4_devconf_dflt);
1570#endif
1571}
1572
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573EXPORT_SYMBOL(in_dev_finish_destroy);
1574EXPORT_SYMBOL(inet_select_addr);
1575EXPORT_SYMBOL(inetdev_by_index);
1576EXPORT_SYMBOL(register_inetaddr_notifier);
1577EXPORT_SYMBOL(unregister_inetaddr_notifier);