blob: 6848e4760f3454910de56008226a10b5335a22e7 [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>
Pavel Emelyanov752d14d2007-12-16 13:31:47 -080065#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Adrian Bunk0027ba82008-01-31 17:17:31 -080067static struct ipv4_devconf ipv4_devconf = {
Herbert Xu42f811b2007-06-04 23:34:44 -070068 .data = {
69 [NET_IPV4_CONF_ACCEPT_REDIRECTS - 1] = 1,
70 [NET_IPV4_CONF_SEND_REDIRECTS - 1] = 1,
71 [NET_IPV4_CONF_SECURE_REDIRECTS - 1] = 1,
72 [NET_IPV4_CONF_SHARED_MEDIA - 1] = 1,
73 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070074};
75
76static struct ipv4_devconf ipv4_devconf_dflt = {
Herbert Xu42f811b2007-06-04 23:34:44 -070077 .data = {
78 [NET_IPV4_CONF_ACCEPT_REDIRECTS - 1] = 1,
79 [NET_IPV4_CONF_SEND_REDIRECTS - 1] = 1,
80 [NET_IPV4_CONF_SECURE_REDIRECTS - 1] = 1,
81 [NET_IPV4_CONF_SHARED_MEDIA - 1] = 1,
82 [NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
83 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070084};
85
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -080086#define IPV4_DEVCONF_DFLT(net, attr) \
87 IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr)
Herbert Xu42f811b2007-06-04 23:34:44 -070088
Patrick McHardyef7c79e2007-06-05 12:38:30 -070089static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
Thomas Graf5c753972006-08-04 23:03:53 -070090 [IFA_LOCAL] = { .type = NLA_U32 },
91 [IFA_ADDRESS] = { .type = NLA_U32 },
92 [IFA_BROADCAST] = { .type = NLA_U32 },
93 [IFA_ANYCAST] = { .type = NLA_U32 },
Thomas Graf5176f912006-08-26 20:13:18 -070094 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
Thomas Graf5c753972006-08-04 23:03:53 -070095};
96
Thomas Grafd6062cb2006-08-15 00:33:59 -070097static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
Alan Sterne041c682006-03-27 01:16:30 -080099static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
101 int destroy);
102#ifdef CONFIG_SYSCTL
Pavel Emelyanov66f27a52007-12-02 00:55:54 +1100103static void devinet_sysctl_register(struct in_device *idev);
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800104static void devinet_sysctl_unregister(struct in_device *idev);
105#else
106static inline void devinet_sysctl_register(struct in_device *idev)
107{
108}
109static inline void devinet_sysctl_unregister(struct in_device *idev)
110{
111}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112#endif
113
114/* Locks all the inet devices. */
115
116static struct in_ifaddr *inet_alloc_ifa(void)
117{
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700118 struct in_ifaddr *ifa = kzalloc(sizeof(*ifa), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
120 if (ifa) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 INIT_RCU_HEAD(&ifa->rcu_head);
122 }
123
124 return ifa;
125}
126
127static void inet_rcu_free_ifa(struct rcu_head *head)
128{
129 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
130 if (ifa->ifa_dev)
131 in_dev_put(ifa->ifa_dev);
132 kfree(ifa);
133}
134
135static inline void inet_free_ifa(struct in_ifaddr *ifa)
136{
137 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
138}
139
140void in_dev_finish_destroy(struct in_device *idev)
141{
142 struct net_device *dev = idev->dev;
143
144 BUG_TRAP(!idev->ifa_list);
145 BUG_TRAP(!idev->mc_list);
146#ifdef NET_REFCNT_DEBUG
147 printk(KERN_DEBUG "in_dev_finish_destroy: %p=%s\n",
148 idev, dev ? dev->name : "NIL");
149#endif
150 dev_put(dev);
151 if (!idev->dead)
152 printk("Freeing alive in_device %p\n", idev);
153 else {
154 kfree(idev);
155 }
156}
157
Herbert Xu71e27da2007-06-04 23:36:06 -0700158static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159{
160 struct in_device *in_dev;
161
162 ASSERT_RTNL();
163
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700164 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 if (!in_dev)
166 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 INIT_RCU_HEAD(&in_dev->rcu_head);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900168 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -0800169 sizeof(in_dev->cnf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 in_dev->cnf.sysctl = NULL;
171 in_dev->dev = dev;
172 if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL)
173 goto out_kfree;
174 /* Reference in_dev->dev */
175 dev_hold(dev);
David L Stevens30c4cf52007-01-04 12:31:14 -0800176 /* Account for reference dev->ip_ptr (below) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 in_dev_hold(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Pavel Emelyanov66f27a52007-12-02 00:55:54 +1100179 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 ip_mc_init_dev(in_dev);
181 if (dev->flags & IFF_UP)
182 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800183
David L Stevens30c4cf52007-01-04 12:31:14 -0800184 /* we can receive as soon as ip_ptr is set -- do this last */
185 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800186out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 return in_dev;
188out_kfree:
189 kfree(in_dev);
190 in_dev = NULL;
191 goto out;
192}
193
194static void in_dev_rcu_put(struct rcu_head *head)
195{
196 struct in_device *idev = container_of(head, struct in_device, rcu_head);
197 in_dev_put(idev);
198}
199
200static void inetdev_destroy(struct in_device *in_dev)
201{
202 struct in_ifaddr *ifa;
203 struct net_device *dev;
204
205 ASSERT_RTNL();
206
207 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
209 in_dev->dead = 1;
210
211 ip_mc_destroy_dev(in_dev);
212
213 while ((ifa = in_dev->ifa_list) != NULL) {
214 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
215 inet_free_ifa(ifa);
216 }
217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 dev->ip_ptr = NULL;
219
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800220 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
222 arp_ifdown(dev);
223
224 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
225}
226
Al Viroff428d72006-09-26 22:13:35 -0700227int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228{
229 rcu_read_lock();
230 for_primary_ifa(in_dev) {
231 if (inet_ifa_match(a, ifa)) {
232 if (!b || inet_ifa_match(b, ifa)) {
233 rcu_read_unlock();
234 return 1;
235 }
236 }
237 } endfor_ifa(in_dev);
238 rcu_read_unlock();
239 return 0;
240}
241
Thomas Grafd6062cb2006-08-15 00:33:59 -0700242static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
243 int destroy, struct nlmsghdr *nlh, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244{
Harald Welte8f937c62005-05-29 20:23:46 -0700245 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800246 struct in_ifaddr *ifa, *ifa1 = *ifap;
247 struct in_ifaddr *last_prim = in_dev->ifa_list;
248 struct in_ifaddr *prev_prom = NULL;
249 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
251 ASSERT_RTNL();
252
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900253 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700254 * unless alias promotion is set
255 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
257 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
259
260 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900261 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800262 ifa1->ifa_scope <= ifa->ifa_scope)
263 last_prim = ifa;
264
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
266 ifa1->ifa_mask != ifa->ifa_mask ||
267 !inet_ifa_match(ifa1->ifa_address, ifa)) {
268 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800269 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 continue;
271 }
272
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800273 if (!do_promote) {
Harald Welte8f937c62005-05-29 20:23:46 -0700274 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
Thomas Grafd6062cb2006-08-15 00:33:59 -0700276 rtmsg_ifa(RTM_DELADDR, ifa, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800277 blocking_notifier_call_chain(&inetaddr_chain,
278 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700279 inet_free_ifa(ifa);
280 } else {
281 promote = ifa;
282 break;
283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 }
285 }
286
287 /* 2. Unlink it */
288
289 *ifap = ifa1->ifa_next;
290
291 /* 3. Announce address deletion */
292
293 /* Send message first, then call notifier.
294 At first sight, FIB update triggered by notifier
295 will refer to already deleted ifaddr, that could confuse
296 netlink listeners. It is not true: look, gated sees
297 that route deleted and if it still thinks that ifaddr
298 is valid, it will try to restore deleted routes... Grr.
299 So that, this order is correct.
300 */
Thomas Grafd6062cb2006-08-15 00:33:59 -0700301 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800302 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800303
304 if (promote) {
305
306 if (prev_prom) {
307 prev_prom->ifa_next = promote->ifa_next;
308 promote->ifa_next = last_prim->ifa_next;
309 last_prim->ifa_next = promote;
310 }
311
312 promote->ifa_flags &= ~IFA_F_SECONDARY;
Thomas Grafd6062cb2006-08-15 00:33:59 -0700313 rtmsg_ifa(RTM_NEWADDR, promote, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800314 blocking_notifier_call_chain(&inetaddr_chain,
315 NETDEV_UP, promote);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800316 for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) {
317 if (ifa1->ifa_mask != ifa->ifa_mask ||
318 !inet_ifa_match(ifa1->ifa_address, ifa))
319 continue;
320 fib_add_ifaddr(ifa);
321 }
322
323 }
Herbert Xu63630972007-06-07 18:35:38 -0700324 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326}
327
Thomas Grafd6062cb2006-08-15 00:33:59 -0700328static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
329 int destroy)
330{
331 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
332}
333
334static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
335 u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336{
337 struct in_device *in_dev = ifa->ifa_dev;
338 struct in_ifaddr *ifa1, **ifap, **last_primary;
339
340 ASSERT_RTNL();
341
342 if (!ifa->ifa_local) {
343 inet_free_ifa(ifa);
344 return 0;
345 }
346
347 ifa->ifa_flags &= ~IFA_F_SECONDARY;
348 last_primary = &in_dev->ifa_list;
349
350 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
351 ifap = &ifa1->ifa_next) {
352 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
353 ifa->ifa_scope <= ifa1->ifa_scope)
354 last_primary = &ifa1->ifa_next;
355 if (ifa1->ifa_mask == ifa->ifa_mask &&
356 inet_ifa_match(ifa1->ifa_address, ifa)) {
357 if (ifa1->ifa_local == ifa->ifa_local) {
358 inet_free_ifa(ifa);
359 return -EEXIST;
360 }
361 if (ifa1->ifa_scope != ifa->ifa_scope) {
362 inet_free_ifa(ifa);
363 return -EINVAL;
364 }
365 ifa->ifa_flags |= IFA_F_SECONDARY;
366 }
367 }
368
369 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
370 net_srandom(ifa->ifa_local);
371 ifap = last_primary;
372 }
373
374 ifa->ifa_next = *ifap;
375 *ifap = ifa;
376
377 /* Send message first, then call notifier.
378 Notifier will trigger FIB update, so that
379 listeners of netlink will know about new ifaddr */
Thomas Grafd6062cb2006-08-15 00:33:59 -0700380 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800381 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
383 return 0;
384}
385
Thomas Grafd6062cb2006-08-15 00:33:59 -0700386static int inet_insert_ifa(struct in_ifaddr *ifa)
387{
388 return __inet_insert_ifa(ifa, NULL, 0);
389}
390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
392{
Herbert Xue5ed6392005-10-03 14:35:55 -0700393 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
395 ASSERT_RTNL();
396
397 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700398 inet_free_ifa(ifa);
399 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700401 ipv4_devconf_setall(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 if (ifa->ifa_dev != in_dev) {
403 BUG_TRAP(!ifa->ifa_dev);
404 in_dev_hold(in_dev);
405 ifa->ifa_dev = in_dev;
406 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800407 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 ifa->ifa_scope = RT_SCOPE_HOST;
409 return inet_insert_ifa(ifa);
410}
411
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800412struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413{
414 struct net_device *dev;
415 struct in_device *in_dev = NULL;
416 read_lock(&dev_base_lock);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800417 dev = __dev_get_by_index(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 if (dev)
419 in_dev = in_dev_get(dev);
420 read_unlock(&dev_base_lock);
421 return in_dev;
422}
423
424/* Called only from RTNL semaphored context. No locks. */
425
Al Viro60cad5d2006-09-26 22:17:09 -0700426struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
427 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428{
429 ASSERT_RTNL();
430
431 for_primary_ifa(in_dev) {
432 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
433 return ifa;
434 } endfor_ifa(in_dev);
435 return NULL;
436}
437
438static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
439{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900440 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700441 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700443 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700445 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
447 ASSERT_RTNL();
448
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700449 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
450 if (err < 0)
451 goto errout;
452
453 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800454 in_dev = inetdev_by_index(net, ifm->ifa_index);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700455 if (in_dev == NULL) {
456 err = -ENODEV;
457 goto errout;
458 }
459
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 __in_dev_put(in_dev);
461
462 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
463 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700464 if (tb[IFA_LOCAL] &&
Al Viroa7a628c2006-09-26 22:16:43 -0700465 ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700467
468 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
469 continue;
470
471 if (tb[IFA_ADDRESS] &&
472 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Al Viroa7a628c2006-09-26 22:16:43 -0700473 !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700474 continue;
475
Thomas Grafd6062cb2006-08-15 00:33:59 -0700476 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 return 0;
478 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700479
480 err = -EADDRNOTAVAIL;
481errout:
482 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483}
484
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800485static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486{
Thomas Graf5c753972006-08-04 23:03:53 -0700487 struct nlattr *tb[IFA_MAX+1];
488 struct in_ifaddr *ifa;
489 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 struct net_device *dev;
491 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800492 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493
Thomas Graf5c753972006-08-04 23:03:53 -0700494 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
495 if (err < 0)
496 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
Thomas Graf5c753972006-08-04 23:03:53 -0700498 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800499 err = -EINVAL;
500 if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700501 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800503 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800504 err = -ENODEV;
505 if (dev == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700506 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
Thomas Graf5c753972006-08-04 23:03:53 -0700508 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800509 err = -ENOBUFS;
510 if (in_dev == NULL)
Herbert Xu71e27da2007-06-04 23:36:06 -0700511 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
Thomas Graf5c753972006-08-04 23:03:53 -0700513 ifa = inet_alloc_ifa();
Denis V. Lunev7b218572008-01-31 18:47:00 -0800514 if (ifa == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700515 /*
516 * A potential indev allocation can be left alive, it stays
517 * assigned to its device and is destroy with it.
518 */
Thomas Graf5c753972006-08-04 23:03:53 -0700519 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700520
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800521 ipv4_devconf_setall(in_dev);
Thomas Graf5c753972006-08-04 23:03:53 -0700522 in_dev_hold(in_dev);
523
524 if (tb[IFA_ADDRESS] == NULL)
525 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
528 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 ifa->ifa_flags = ifm->ifa_flags;
530 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700531 ifa->ifa_dev = in_dev;
532
Al Viroa7a628c2006-09-26 22:16:43 -0700533 ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]);
534 ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700535
536 if (tb[IFA_BROADCAST])
Al Viroa7a628c2006-09-26 22:16:43 -0700537 ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700538
539 if (tb[IFA_ANYCAST])
Al Viroa7a628c2006-09-26 22:16:43 -0700540 ifa->ifa_anycast = nla_get_be32(tb[IFA_ANYCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700541
542 if (tb[IFA_LABEL])
543 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 else
545 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
546
Thomas Graf5c753972006-08-04 23:03:53 -0700547 return ifa;
548
549errout:
550 return ERR_PTR(err);
551}
552
553static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
554{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900555 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700556 struct in_ifaddr *ifa;
557
558 ASSERT_RTNL();
559
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800560 ifa = rtm_to_ifaddr(net, nlh);
Thomas Graf5c753972006-08-04 23:03:53 -0700561 if (IS_ERR(ifa))
562 return PTR_ERR(ifa);
563
Thomas Grafd6062cb2006-08-15 00:33:59 -0700564 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565}
566
567/*
568 * Determine a default network mask, based on the IP address.
569 */
570
Al Viro714e85b2006-11-14 20:51:49 -0800571static __inline__ int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572{
573 int rc = -1; /* Something else, probably a multicast. */
574
Joe Perchesf97c1e02007-12-16 13:45:43 -0800575 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900576 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 else {
Al Viro714e85b2006-11-14 20:51:49 -0800578 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
Al Viro714e85b2006-11-14 20:51:49 -0800580 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800582 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800584 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 rc = 24;
586 }
587
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900588 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589}
590
591
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800592int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593{
594 struct ifreq ifr;
595 struct sockaddr_in sin_orig;
596 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
597 struct in_device *in_dev;
598 struct in_ifaddr **ifap = NULL;
599 struct in_ifaddr *ifa = NULL;
600 struct net_device *dev;
601 char *colon;
602 int ret = -EFAULT;
603 int tryaddrmatch = 0;
604
605 /*
606 * Fetch the caller's info block into kernel space
607 */
608
609 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
610 goto out;
611 ifr.ifr_name[IFNAMSIZ - 1] = 0;
612
613 /* save original address for comparison */
614 memcpy(&sin_orig, sin, sizeof(*sin));
615
616 colon = strchr(ifr.ifr_name, ':');
617 if (colon)
618 *colon = 0;
619
620#ifdef CONFIG_KMOD
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800621 dev_load(net, ifr.ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622#endif
623
Stephen Hemminger132adf52007-03-08 20:44:43 -0800624 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 case SIOCGIFADDR: /* Get interface address */
626 case SIOCGIFBRDADDR: /* Get the broadcast address */
627 case SIOCGIFDSTADDR: /* Get the destination address */
628 case SIOCGIFNETMASK: /* Get the netmask for the interface */
629 /* Note that these ioctls will not sleep,
630 so that we do not impose a lock.
631 One day we will be forced to put shlock here (I mean SMP)
632 */
633 tryaddrmatch = (sin_orig.sin_family == AF_INET);
634 memset(sin, 0, sizeof(*sin));
635 sin->sin_family = AF_INET;
636 break;
637
638 case SIOCSIFFLAGS:
639 ret = -EACCES;
640 if (!capable(CAP_NET_ADMIN))
641 goto out;
642 break;
643 case SIOCSIFADDR: /* Set interface address (and family) */
644 case SIOCSIFBRDADDR: /* Set the broadcast address */
645 case SIOCSIFDSTADDR: /* Set the destination address */
646 case SIOCSIFNETMASK: /* Set the netmask for the interface */
647 ret = -EACCES;
648 if (!capable(CAP_NET_ADMIN))
649 goto out;
650 ret = -EINVAL;
651 if (sin->sin_family != AF_INET)
652 goto out;
653 break;
654 default:
655 ret = -EINVAL;
656 goto out;
657 }
658
659 rtnl_lock();
660
661 ret = -ENODEV;
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800662 if ((dev = __dev_get_by_name(net, ifr.ifr_name)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 goto done;
664
665 if (colon)
666 *colon = ':';
667
Herbert Xue5ed6392005-10-03 14:35:55 -0700668 if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 if (tryaddrmatch) {
670 /* Matthias Andree */
671 /* compare label and address (4.4BSD style) */
672 /* note: we only do this for a limited set of ioctls
673 and only if the original address family was AF_INET.
674 This is checked above. */
675 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
676 ifap = &ifa->ifa_next) {
677 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
678 sin_orig.sin_addr.s_addr ==
679 ifa->ifa_address) {
680 break; /* found */
681 }
682 }
683 }
684 /* we didn't get a match, maybe the application is
685 4.3BSD-style and passed in junk so we fall back to
686 comparing just the label */
687 if (!ifa) {
688 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
689 ifap = &ifa->ifa_next)
690 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
691 break;
692 }
693 }
694
695 ret = -EADDRNOTAVAIL;
696 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
697 goto done;
698
Stephen Hemminger132adf52007-03-08 20:44:43 -0800699 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 case SIOCGIFADDR: /* Get interface address */
701 sin->sin_addr.s_addr = ifa->ifa_local;
702 goto rarok;
703
704 case SIOCGIFBRDADDR: /* Get the broadcast address */
705 sin->sin_addr.s_addr = ifa->ifa_broadcast;
706 goto rarok;
707
708 case SIOCGIFDSTADDR: /* Get the destination address */
709 sin->sin_addr.s_addr = ifa->ifa_address;
710 goto rarok;
711
712 case SIOCGIFNETMASK: /* Get the netmask for the interface */
713 sin->sin_addr.s_addr = ifa->ifa_mask;
714 goto rarok;
715
716 case SIOCSIFFLAGS:
717 if (colon) {
718 ret = -EADDRNOTAVAIL;
719 if (!ifa)
720 break;
721 ret = 0;
722 if (!(ifr.ifr_flags & IFF_UP))
723 inet_del_ifa(in_dev, ifap, 1);
724 break;
725 }
726 ret = dev_change_flags(dev, ifr.ifr_flags);
727 break;
728
729 case SIOCSIFADDR: /* Set interface address (and family) */
730 ret = -EINVAL;
731 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
732 break;
733
734 if (!ifa) {
735 ret = -ENOBUFS;
736 if ((ifa = inet_alloc_ifa()) == NULL)
737 break;
738 if (colon)
739 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
740 else
741 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
742 } else {
743 ret = 0;
744 if (ifa->ifa_local == sin->sin_addr.s_addr)
745 break;
746 inet_del_ifa(in_dev, ifap, 0);
747 ifa->ifa_broadcast = 0;
748 ifa->ifa_anycast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -0800749 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 }
751
752 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
753
754 if (!(dev->flags & IFF_POINTOPOINT)) {
755 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
756 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
757 if ((dev->flags & IFF_BROADCAST) &&
758 ifa->ifa_prefixlen < 31)
759 ifa->ifa_broadcast = ifa->ifa_address |
760 ~ifa->ifa_mask;
761 } else {
762 ifa->ifa_prefixlen = 32;
763 ifa->ifa_mask = inet_make_mask(32);
764 }
765 ret = inet_set_ifa(dev, ifa);
766 break;
767
768 case SIOCSIFBRDADDR: /* Set the broadcast address */
769 ret = 0;
770 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
771 inet_del_ifa(in_dev, ifap, 0);
772 ifa->ifa_broadcast = sin->sin_addr.s_addr;
773 inet_insert_ifa(ifa);
774 }
775 break;
776
777 case SIOCSIFDSTADDR: /* Set the destination address */
778 ret = 0;
779 if (ifa->ifa_address == sin->sin_addr.s_addr)
780 break;
781 ret = -EINVAL;
782 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
783 break;
784 ret = 0;
785 inet_del_ifa(in_dev, ifap, 0);
786 ifa->ifa_address = sin->sin_addr.s_addr;
787 inet_insert_ifa(ifa);
788 break;
789
790 case SIOCSIFNETMASK: /* Set the netmask for the interface */
791
792 /*
793 * The mask we set must be legal.
794 */
795 ret = -EINVAL;
796 if (bad_mask(sin->sin_addr.s_addr, 0))
797 break;
798 ret = 0;
799 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -0700800 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 inet_del_ifa(in_dev, ifap, 0);
802 ifa->ifa_mask = sin->sin_addr.s_addr;
803 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
804
805 /* See if current broadcast address matches
806 * with current netmask, then recalculate
807 * the broadcast address. Otherwise it's a
808 * funny address, so don't touch it since
809 * the user seems to know what (s)he's doing...
810 */
811 if ((dev->flags & IFF_BROADCAST) &&
812 (ifa->ifa_prefixlen < 31) &&
813 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -0500814 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 ifa->ifa_broadcast = (ifa->ifa_local |
816 ~sin->sin_addr.s_addr);
817 }
818 inet_insert_ifa(ifa);
819 }
820 break;
821 }
822done:
823 rtnl_unlock();
824out:
825 return ret;
826rarok:
827 rtnl_unlock();
828 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
829 goto out;
830}
831
832static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
833{
Herbert Xue5ed6392005-10-03 14:35:55 -0700834 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 struct in_ifaddr *ifa;
836 struct ifreq ifr;
837 int done = 0;
838
839 if (!in_dev || (ifa = in_dev->ifa_list) == NULL)
840 goto out;
841
842 for (; ifa; ifa = ifa->ifa_next) {
843 if (!buf) {
844 done += sizeof(ifr);
845 continue;
846 }
847 if (len < (int) sizeof(ifr))
848 break;
849 memset(&ifr, 0, sizeof(struct ifreq));
850 if (ifa->ifa_label)
851 strcpy(ifr.ifr_name, ifa->ifa_label);
852 else
853 strcpy(ifr.ifr_name, dev->name);
854
855 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
856 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
857 ifa->ifa_local;
858
859 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
860 done = -EFAULT;
861 break;
862 }
863 buf += sizeof(struct ifreq);
864 len -= sizeof(struct ifreq);
865 done += sizeof(struct ifreq);
866 }
867out:
868 return done;
869}
870
Al Viroa61ced52006-09-26 21:27:54 -0700871__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872{
Al Viroa61ced52006-09-26 21:27:54 -0700873 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900875 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876
877 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -0700878 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 if (!in_dev)
880 goto no_in_dev;
881
882 for_primary_ifa(in_dev) {
883 if (ifa->ifa_scope > scope)
884 continue;
885 if (!dst || inet_ifa_match(dst, ifa)) {
886 addr = ifa->ifa_local;
887 break;
888 }
889 if (!addr)
890 addr = ifa->ifa_local;
891 } endfor_ifa(in_dev);
892no_in_dev:
893 rcu_read_unlock();
894
895 if (addr)
896 goto out;
897
898 /* Not loopback addresses on loopback should be preferred
899 in this case. It is importnat that lo is the first interface
900 in dev_base list.
901 */
902 read_lock(&dev_base_lock);
903 rcu_read_lock();
Denis V. Lunevc4544c72008-02-28 20:52:54 -0800904 for_each_netdev(net, dev) {
Herbert Xue5ed6392005-10-03 14:35:55 -0700905 if ((in_dev = __in_dev_get_rcu(dev)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 continue;
907
908 for_primary_ifa(in_dev) {
909 if (ifa->ifa_scope != RT_SCOPE_LINK &&
910 ifa->ifa_scope <= scope) {
911 addr = ifa->ifa_local;
912 goto out_unlock_both;
913 }
914 } endfor_ifa(in_dev);
915 }
916out_unlock_both:
917 read_unlock(&dev_base_lock);
918 rcu_read_unlock();
919out:
920 return addr;
921}
922
Al Viro60cad5d2006-09-26 22:17:09 -0700923static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
924 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925{
926 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -0700927 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
929 for_ifa(in_dev) {
930 if (!addr &&
931 (local == ifa->ifa_local || !local) &&
932 ifa->ifa_scope <= scope) {
933 addr = ifa->ifa_local;
934 if (same)
935 break;
936 }
937 if (!same) {
938 same = (!local || inet_ifa_match(local, ifa)) &&
939 (!dst || inet_ifa_match(dst, ifa));
940 if (same && addr) {
941 if (local || !dst)
942 break;
943 /* Is the selected addr into dst subnet? */
944 if (inet_ifa_match(addr, ifa))
945 break;
946 /* No, then can we use new local src? */
947 if (ifa->ifa_scope <= scope) {
948 addr = ifa->ifa_local;
949 break;
950 }
951 /* search for large dst subnet for addr */
952 same = 0;
953 }
954 }
955 } endfor_ifa(in_dev);
956
957 return same? addr : 0;
958}
959
960/*
961 * Confirm that local IP address exists using wildcards:
Denis V. Lunev9bd85e32008-01-14 23:05:55 -0800962 * - in_dev: only on this interface, 0=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 * - dst: only in the same subnet as dst, 0=any dst
964 * - local: address, 0=autoselect the local address
965 * - scope: maximum allowed scope value for the local address
966 */
Denis V. Lunev9bd85e32008-01-14 23:05:55 -0800967__be32 inet_confirm_addr(struct in_device *in_dev,
968 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969{
Al Viro60cad5d2006-09-26 22:17:09 -0700970 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -0800971 struct net_device *dev;
Denis V. Lunev39a6d062008-01-14 23:06:19 -0800972 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
Denis V. Lunev39a6d062008-01-14 23:06:19 -0800974 if (scope != RT_SCOPE_LINK)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -0800975 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900977 net = dev_net(in_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 read_lock(&dev_base_lock);
979 rcu_read_lock();
Denis V. Lunev39a6d062008-01-14 23:06:19 -0800980 for_each_netdev(net, dev) {
Herbert Xue5ed6392005-10-03 14:35:55 -0700981 if ((in_dev = __in_dev_get_rcu(dev))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 addr = confirm_addr_indev(in_dev, dst, local, scope);
983 if (addr)
984 break;
985 }
986 }
987 rcu_read_unlock();
988 read_unlock(&dev_base_lock);
989
990 return addr;
991}
992
993/*
994 * Device notifier
995 */
996
997int register_inetaddr_notifier(struct notifier_block *nb)
998{
Alan Sterne041c682006-03-27 01:16:30 -0800999 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000}
1001
1002int unregister_inetaddr_notifier(struct notifier_block *nb)
1003{
Alan Sterne041c682006-03-27 01:16:30 -08001004 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005}
1006
1007/* Rename ifa_labels for a device name change. Make some effort to preserve existing
1008 * alias numbering and to create unique labels if possible.
1009*/
1010static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001011{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 struct in_ifaddr *ifa;
1013 int named = 0;
1014
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001015 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1016 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
1018 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001019 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 if (named++ == 0)
1021 continue;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001022 dot = strchr(old, ':');
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001023 if (dot == NULL) {
1024 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 dot = old;
1026 }
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001027 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ) {
1028 strcat(ifa->ifa_label, dot);
1029 } else {
1030 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
1031 }
1032 }
1033}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
1035/* Called only under RTNL semaphore */
1036
1037static int inetdev_event(struct notifier_block *this, unsigned long event,
1038 void *ptr)
1039{
1040 struct net_device *dev = ptr;
Herbert Xue5ed6392005-10-03 14:35:55 -07001041 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
1043 ASSERT_RTNL();
1044
1045 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001046 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 in_dev = inetdev_init(dev);
Herbert Xub217d612007-07-30 17:04:52 -07001048 if (!in_dev)
1049 return notifier_from_errno(-ENOMEM);
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001050 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001051 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1052 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 }
1055 goto out;
1056 }
1057
1058 switch (event) {
1059 case NETDEV_REGISTER:
1060 printk(KERN_DEBUG "inetdev_event: bug\n");
1061 dev->ip_ptr = NULL;
1062 break;
1063 case NETDEV_UP:
1064 if (dev->mtu < 68)
1065 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001066 if (dev->flags & IFF_LOOPBACK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 struct in_ifaddr *ifa;
1068 if ((ifa = inet_alloc_ifa()) != NULL) {
1069 ifa->ifa_local =
1070 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1071 ifa->ifa_prefixlen = 8;
1072 ifa->ifa_mask = inet_make_mask(8);
1073 in_dev_hold(in_dev);
1074 ifa->ifa_dev = in_dev;
1075 ifa->ifa_scope = RT_SCOPE_HOST;
1076 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1077 inet_insert_ifa(ifa);
1078 }
1079 }
1080 ip_mc_up(in_dev);
1081 break;
1082 case NETDEV_DOWN:
1083 ip_mc_down(in_dev);
1084 break;
1085 case NETDEV_CHANGEMTU:
1086 if (dev->mtu >= 68)
1087 break;
1088 /* MTU falled under 68, disable IP */
1089 case NETDEV_UNREGISTER:
1090 inetdev_destroy(in_dev);
1091 break;
1092 case NETDEV_CHANGENAME:
1093 /* Do not notify about label change, this event is
1094 * not interesting to applications using netlink.
1095 */
1096 inetdev_changename(dev, in_dev);
1097
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001098 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001099 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 break;
1101 }
1102out:
1103 return NOTIFY_DONE;
1104}
1105
1106static struct notifier_block ip_netdev_notifier = {
1107 .notifier_call =inetdev_event,
1108};
1109
Thomas Graf339bf982006-11-10 14:10:15 -08001110static inline size_t inet_nlmsg_size(void)
1111{
1112 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1113 + nla_total_size(4) /* IFA_ADDRESS */
1114 + nla_total_size(4) /* IFA_LOCAL */
1115 + nla_total_size(4) /* IFA_BROADCAST */
1116 + nla_total_size(4) /* IFA_ANYCAST */
1117 + nla_total_size(IFNAMSIZ); /* IFA_LABEL */
1118}
1119
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07001121 u32 pid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122{
1123 struct ifaddrmsg *ifm;
1124 struct nlmsghdr *nlh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
Thomas Graf47f68512006-08-04 23:04:36 -07001126 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);
1127 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001128 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001129
1130 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 ifm->ifa_family = AF_INET;
1132 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
1133 ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT;
1134 ifm->ifa_scope = ifa->ifa_scope;
1135 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
Thomas Graf47f68512006-08-04 23:04:36 -07001137 if (ifa->ifa_address)
Al Viroa7a628c2006-09-26 22:16:43 -07001138 NLA_PUT_BE32(skb, IFA_ADDRESS, ifa->ifa_address);
Thomas Graf47f68512006-08-04 23:04:36 -07001139
1140 if (ifa->ifa_local)
Al Viroa7a628c2006-09-26 22:16:43 -07001141 NLA_PUT_BE32(skb, IFA_LOCAL, ifa->ifa_local);
Thomas Graf47f68512006-08-04 23:04:36 -07001142
1143 if (ifa->ifa_broadcast)
Al Viroa7a628c2006-09-26 22:16:43 -07001144 NLA_PUT_BE32(skb, IFA_BROADCAST, ifa->ifa_broadcast);
Thomas Graf47f68512006-08-04 23:04:36 -07001145
1146 if (ifa->ifa_anycast)
Al Viroa7a628c2006-09-26 22:16:43 -07001147 NLA_PUT_BE32(skb, IFA_ANYCAST, ifa->ifa_anycast);
Thomas Graf47f68512006-08-04 23:04:36 -07001148
1149 if (ifa->ifa_label[0])
1150 NLA_PUT_STRING(skb, IFA_LABEL, ifa->ifa_label);
1151
1152 return nlmsg_end(skb, nlh);
1153
1154nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001155 nlmsg_cancel(skb, nlh);
1156 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157}
1158
1159static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1160{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001161 struct net *net = sock_net(skb->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 int idx, ip_idx;
1163 struct net_device *dev;
1164 struct in_device *in_dev;
1165 struct in_ifaddr *ifa;
1166 int s_ip_idx, s_idx = cb->args[0];
1167
1168 s_ip_idx = ip_idx = cb->args[1];
Pavel Emelianov7562f872007-05-03 15:13:45 -07001169 idx = 0;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001170 for_each_netdev(net, dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 if (idx < s_idx)
Pavel Emelianov7562f872007-05-03 15:13:45 -07001172 goto cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 if (idx > s_idx)
1174 s_ip_idx = 0;
Patrick McHardy6313c1e2007-04-16 17:00:53 -07001175 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL)
Pavel Emelianov7562f872007-05-03 15:13:45 -07001176 goto cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177
1178 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1179 ifa = ifa->ifa_next, ip_idx++) {
1180 if (ip_idx < s_ip_idx)
Stephen Hemminger596e4152007-09-11 10:41:04 +02001181 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
1183 cb->nlh->nlmsg_seq,
Patrick McHardy6313c1e2007-04-16 17:00:53 -07001184 RTM_NEWADDR, NLM_F_MULTI) <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 goto done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001187cont:
1188 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 }
1190
1191done:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 cb->args[0] = idx;
1193 cb->args[1] = ip_idx;
1194
1195 return skb->len;
1196}
1197
Thomas Grafd6062cb2006-08-15 00:33:59 -07001198static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
1199 u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200{
Thomas Graf47f68512006-08-04 23:04:36 -07001201 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001202 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1203 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001204 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001206 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001207 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Thomas Graf47f68512006-08-04 23:04:36 -07001208 if (skb == NULL)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001209 goto errout;
1210
1211 err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001212 if (err < 0) {
1213 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1214 WARN_ON(err == -EMSGSIZE);
1215 kfree_skb(skb);
1216 goto errout;
1217 }
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001218 err = rtnl_notify(skb, net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Thomas Grafd6062cb2006-08-15 00:33:59 -07001219errout:
1220 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001221 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222}
1223
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224#ifdef CONFIG_SYSCTL
1225
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001226static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07001227{
1228 struct net_device *dev;
1229
1230 read_lock(&dev_base_lock);
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001231 for_each_netdev(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07001232 struct in_device *in_dev;
1233 rcu_read_lock();
1234 in_dev = __in_dev_get_rcu(dev);
1235 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001236 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07001237 rcu_read_unlock();
1238 }
1239 read_unlock(&dev_base_lock);
1240}
1241
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001242static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001243{
1244 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08001245 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001246
Pavel Emelyanov586f1212007-12-16 13:32:48 -08001247 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001248 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001249
1250 read_lock(&dev_base_lock);
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001251 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001252 struct in_device *in_dev;
1253 rcu_read_lock();
1254 in_dev = __in_dev_get_rcu(dev);
1255 if (in_dev)
1256 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
1257 rcu_read_unlock();
1258 }
1259 read_unlock(&dev_base_lock);
1260
1261 rt_cache_flush(0);
1262}
1263
Herbert Xu31be3082007-06-04 23:35:37 -07001264static int devinet_conf_proc(ctl_table *ctl, int write,
1265 struct file* filp, void __user *buffer,
1266 size_t *lenp, loff_t *ppos)
1267{
1268 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1269
1270 if (write) {
1271 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001272 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07001273 int i = (int *)ctl->data - cnf->data;
1274
1275 set_bit(i, cnf->state);
1276
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001277 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001278 devinet_copy_dflt_conf(net, i);
Herbert Xu31be3082007-06-04 23:35:37 -07001279 }
1280
1281 return ret;
1282}
1283
1284static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,
1285 void __user *oldval, size_t __user *oldlenp,
1286 void __user *newval, size_t newlen)
1287{
1288 struct ipv4_devconf *cnf;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001289 struct net *net;
Herbert Xu31be3082007-06-04 23:35:37 -07001290 int *valp = table->data;
1291 int new;
1292 int i;
1293
1294 if (!newval || !newlen)
1295 return 0;
1296
1297 if (newlen != sizeof(int))
1298 return -EINVAL;
1299
1300 if (get_user(new, (int __user *)newval))
1301 return -EFAULT;
1302
1303 if (new == *valp)
1304 return 0;
1305
1306 if (oldval && oldlenp) {
1307 size_t len;
1308
1309 if (get_user(len, oldlenp))
1310 return -EFAULT;
1311
1312 if (len) {
1313 if (len > table->maxlen)
1314 len = table->maxlen;
1315 if (copy_to_user(oldval, valp, len))
1316 return -EFAULT;
1317 if (put_user(len, oldlenp))
1318 return -EFAULT;
1319 }
1320 }
1321
1322 *valp = new;
1323
1324 cnf = table->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001325 net = table->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07001326 i = (int *)table->data - cnf->data;
1327
1328 set_bit(i, cnf->state);
1329
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001330 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001331 devinet_copy_dflt_conf(net, i);
Herbert Xu31be3082007-06-04 23:35:37 -07001332
1333 return 1;
1334}
1335
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336static int devinet_sysctl_forward(ctl_table *ctl, int write,
1337 struct file* filp, void __user *buffer,
1338 size_t *lenp, loff_t *ppos)
1339{
1340 int *valp = ctl->data;
1341 int val = *valp;
1342 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1343
1344 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001345 struct net *net = ctl->extra2;
1346
Pavel Emelyanov586f1212007-12-16 13:32:48 -08001347 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING))
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001348 inet_forward_change(net);
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001349 else if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 rt_cache_flush(0);
1351 }
1352
1353 return ret;
1354}
1355
1356int ipv4_doint_and_flush(ctl_table *ctl, int write,
1357 struct file* filp, void __user *buffer,
1358 size_t *lenp, loff_t *ppos)
1359{
1360 int *valp = ctl->data;
1361 int val = *valp;
1362 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1363
1364 if (write && *valp != val)
1365 rt_cache_flush(0);
1366
1367 return ret;
1368}
1369
1370int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
1371 void __user *oldval, size_t __user *oldlenp,
Alexey Dobriyan1f29bcd2006-12-10 02:19:10 -08001372 void __user *newval, size_t newlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373{
Herbert Xu31be3082007-06-04 23:35:37 -07001374 int ret = devinet_conf_sysctl(table, name, nlen, oldval, oldlenp,
1375 newval, newlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
Herbert Xu31be3082007-06-04 23:35:37 -07001377 if (ret == 1)
1378 rt_cache_flush(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379
Herbert Xu31be3082007-06-04 23:35:37 -07001380 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381}
1382
1383
Herbert Xu42f811b2007-06-04 23:34:44 -07001384#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc, sysctl) \
1385 { \
1386 .ctl_name = NET_IPV4_CONF_ ## attr, \
1387 .procname = name, \
1388 .data = ipv4_devconf.data + \
1389 NET_IPV4_CONF_ ## attr - 1, \
1390 .maxlen = sizeof(int), \
1391 .mode = mval, \
1392 .proc_handler = proc, \
1393 .strategy = sysctl, \
Herbert Xu31be3082007-06-04 23:35:37 -07001394 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07001395 }
1396
1397#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Herbert Xu31be3082007-06-04 23:35:37 -07001398 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc, \
1399 devinet_conf_sysctl)
Herbert Xu42f811b2007-06-04 23:34:44 -07001400
1401#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Herbert Xu31be3082007-06-04 23:35:37 -07001402 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc, \
1403 devinet_conf_sysctl)
Herbert Xu42f811b2007-06-04 23:34:44 -07001404
1405#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc, sysctl) \
1406 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc, sysctl)
1407
1408#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
1409 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush, \
1410 ipv4_doint_and_flush_strategy)
1411
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412static struct devinet_sysctl_table {
1413 struct ctl_table_header *sysctl_header;
Pavel Emelyanovbfada692007-12-02 00:57:08 +11001414 struct ctl_table devinet_vars[__NET_IPV4_CONF_MAX];
1415 char *dev_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416} devinet_sysctl = {
1417 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07001418 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Herbert Xu31be3082007-06-04 23:35:37 -07001419 devinet_sysctl_forward,
1420 devinet_conf_sysctl),
Herbert Xu42f811b2007-06-04 23:34:44 -07001421 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
1422
1423 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
1424 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
1425 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
1426 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
1427 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
1428 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
1429 "accept_source_route"),
1430 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
1431 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
1432 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
1433 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
1434 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
1435 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
1436 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
1437 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
1438 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
1439
1440 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
1441 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
1442 DEVINET_SYSCTL_FLUSHING_ENTRY(FORCE_IGMP_VERSION,
1443 "force_igmp_version"),
1444 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
1445 "promote_secondaries"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447};
1448
Pavel Emelyanovea40b322007-12-16 13:30:07 -08001449static int __devinet_sysctl_register(struct net *net, char *dev_name,
1450 int ctl_name, struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451{
1452 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001453 struct devinet_sysctl_table *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454
Pavel Emelyanovbfada692007-12-02 00:57:08 +11001455#define DEVINET_CTL_PATH_DEV 3
1456
1457 struct ctl_path devinet_ctl_path[] = {
1458 { .procname = "net", .ctl_name = CTL_NET, },
1459 { .procname = "ipv4", .ctl_name = NET_IPV4, },
1460 { .procname = "conf", .ctl_name = NET_IPV4_CONF, },
1461 { /* to be set */ },
1462 { },
1463 };
1464
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001465 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001467 goto out;
1468
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
1470 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07001471 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001472 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 }
1474
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001475 /*
1476 * Make a copy of dev_name, because '.procname' is regarded as const
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 * by sysctl and we wouldn't want anyone to change it under our feet
1478 * (see SIOCSIFNAME).
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001479 */
Pavel Emelyanovbfada692007-12-02 00:57:08 +11001480 t->dev_name = kstrdup(dev_name, GFP_KERNEL);
1481 if (!t->dev_name)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001482 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
Pavel Emelyanovbfada692007-12-02 00:57:08 +11001484 devinet_ctl_path[DEVINET_CTL_PATH_DEV].procname = t->dev_name;
1485 devinet_ctl_path[DEVINET_CTL_PATH_DEV].ctl_name = ctl_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001487 t->sysctl_header = register_net_sysctl_table(net, devinet_ctl_path,
Pavel Emelyanovbfada692007-12-02 00:57:08 +11001488 t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 if (!t->sysctl_header)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001490 goto free_procname;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491
1492 p->sysctl = t;
Pavel Emelyanovea40b322007-12-16 13:30:07 -08001493 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001495free_procname:
Pavel Emelyanovbfada692007-12-02 00:57:08 +11001496 kfree(t->dev_name);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001497free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001499out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08001500 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501}
1502
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001503static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
1504{
1505 struct devinet_sysctl_table *t = cnf->sysctl;
1506
1507 if (t == NULL)
1508 return;
1509
1510 cnf->sysctl = NULL;
1511 unregister_sysctl_table(t->sysctl_header);
1512 kfree(t->dev_name);
1513 kfree(t);
1514}
1515
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001516static void devinet_sysctl_register(struct in_device *idev)
1517{
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001518 neigh_sysctl_register(idev->dev, idev->arp_parms, NET_IPV4,
1519 NET_IPV4_NEIGH, "ipv4", NULL, NULL);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001520 __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001521 idev->dev->ifindex, &idev->cnf);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001522}
1523
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001524static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525{
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001526 __devinet_sysctl_unregister(&idev->cnf);
1527 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001530static struct ctl_table ctl_forward_entry[] = {
1531 {
1532 .ctl_name = NET_IPV4_FORWARD,
1533 .procname = "ip_forward",
1534 .data = &ipv4_devconf.data[
1535 NET_IPV4_CONF_FORWARDING - 1],
1536 .maxlen = sizeof(int),
1537 .mode = 0644,
1538 .proc_handler = devinet_sysctl_forward,
1539 .strategy = devinet_conf_sysctl,
1540 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001541 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001542 },
1543 { },
1544};
1545
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001546static __net_initdata struct ctl_path net_ipv4_path[] = {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001547 { .procname = "net", .ctl_name = CTL_NET, },
1548 { .procname = "ipv4", .ctl_name = NET_IPV4, },
1549 { },
1550};
Eric Dumazet2a75de02008-01-05 23:08:49 -08001551#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001552
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001553static __net_init int devinet_init_net(struct net *net)
1554{
1555 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001556 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08001557#ifdef CONFIG_SYSCTL
1558 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001559 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08001560#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001561
1562 err = -ENOMEM;
1563 all = &ipv4_devconf;
1564 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001565
1566 if (net != &init_net) {
1567 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
1568 if (all == NULL)
1569 goto err_alloc_all;
1570
1571 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
1572 if (dflt == NULL)
1573 goto err_alloc_dflt;
1574
Eric Dumazet2a75de02008-01-05 23:08:49 -08001575#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001576 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
1577 if (tbl == NULL)
1578 goto err_alloc_ctl;
1579
1580 tbl[0].data = &all->data[NET_IPV4_CONF_FORWARDING - 1];
1581 tbl[0].extra1 = all;
1582 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08001583#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001584 }
1585
1586#ifdef CONFIG_SYSCTL
1587 err = __devinet_sysctl_register(net, "all",
1588 NET_PROTO_CONF_ALL, all);
1589 if (err < 0)
1590 goto err_reg_all;
1591
1592 err = __devinet_sysctl_register(net, "default",
1593 NET_PROTO_CONF_DEFAULT, dflt);
1594 if (err < 0)
1595 goto err_reg_dflt;
1596
1597 err = -ENOMEM;
1598 forw_hdr = register_net_sysctl_table(net, net_ipv4_path, tbl);
1599 if (forw_hdr == NULL)
1600 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08001601 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001602#endif
1603
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001604 net->ipv4.devconf_all = all;
1605 net->ipv4.devconf_dflt = dflt;
1606 return 0;
1607
1608#ifdef CONFIG_SYSCTL
1609err_reg_ctl:
1610 __devinet_sysctl_unregister(dflt);
1611err_reg_dflt:
1612 __devinet_sysctl_unregister(all);
1613err_reg_all:
1614 if (tbl != ctl_forward_entry)
1615 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001616err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08001617#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001618 if (dflt != &ipv4_devconf_dflt)
1619 kfree(dflt);
1620err_alloc_dflt:
1621 if (all != &ipv4_devconf)
1622 kfree(all);
1623err_alloc_all:
1624 return err;
1625}
1626
1627static __net_exit void devinet_exit_net(struct net *net)
1628{
Eric Dumazet2a75de02008-01-05 23:08:49 -08001629#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001630 struct ctl_table *tbl;
1631
1632 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001633 unregister_net_sysctl_table(net->ipv4.forw_hdr);
1634 __devinet_sysctl_unregister(net->ipv4.devconf_dflt);
1635 __devinet_sysctl_unregister(net->ipv4.devconf_all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001636 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08001637#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001638 kfree(net->ipv4.devconf_dflt);
1639 kfree(net->ipv4.devconf_all);
1640}
1641
1642static __net_initdata struct pernet_operations devinet_ops = {
1643 .init = devinet_init_net,
1644 .exit = devinet_exit_net,
1645};
1646
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647void __init devinet_init(void)
1648{
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001649 register_pernet_subsys(&devinet_ops);
1650
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 register_gifconf(PF_INET, inet_gifconf);
1652 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07001653
1654 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL);
1655 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL);
1656 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657}
1658
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659EXPORT_SYMBOL(in_dev_finish_destroy);
1660EXPORT_SYMBOL(inet_select_addr);
1661EXPORT_SYMBOL(inetdev_by_index);
1662EXPORT_SYMBOL(register_inetaddr_notifier);
1663EXPORT_SYMBOL(unregister_inetaddr_notifier);