blob: f14eff5067439c675ad4d031306d322dd3c0c2b7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * NET3 IP device support routines.
3 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Derived from the IP parts of dev.c 1.0.19
Jesper Juhl02c30a82005-05-05 16:16:16 -070010 * Authors: Ross Biro
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
12 * Mark Evans, <evansmp@uhura.aston.ac.uk>
13 *
14 * Additional Authors:
15 * Alan Cox, <gw4pts@gw4pts.ampr.org>
16 * Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
17 *
18 * Changes:
19 * Alexey Kuznetsov: pa_* fields are replaced with ifaddr
20 * lists.
21 * Cyrus Durgin: updated for kmod
22 * Matthias Andree: in devinet_ioctl, compare label and
23 * address (4.4BSD alias style support),
24 * fall back to comparing just the label
25 * if no match found.
26 */
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
29#include <asm/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/bitops.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080031#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/module.h>
33#include <linux/types.h>
34#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/string.h>
36#include <linux/mm.h>
37#include <linux/socket.h>
38#include <linux/sockios.h>
39#include <linux/in.h>
40#include <linux/errno.h>
41#include <linux/interrupt.h>
Thomas Graf18237302006-08-04 23:04:54 -070042#include <linux/if_addr.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/if_ether.h>
44#include <linux/inet.h>
45#include <linux/netdevice.h>
46#include <linux/etherdevice.h>
47#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <linux/init.h>
49#include <linux/notifier.h>
50#include <linux/inetdevice.h>
51#include <linux/igmp.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090052#include <linux/slab.h>
David S. Millerfd23c3b2011-02-18 12:42:28 -080053#include <linux/hash.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#ifdef CONFIG_SYSCTL
55#include <linux/sysctl.h>
56#endif
57#include <linux/kmod.h>
58
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020059#include <net/arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#include <net/ip.h>
61#include <net/route.h>
62#include <net/ip_fib.h>
Thomas Graf63f34442007-03-22 11:55:17 -070063#include <net/rtnetlink.h>
Pavel Emelyanov752d14d2007-12-16 13:31:47 -080064#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
David S. Miller406b6f92011-03-22 21:56:23 -070066#include "fib_lookup.h"
67
Adrian Bunk0027ba82008-01-31 17:17:31 -080068static struct ipv4_devconf ipv4_devconf = {
Herbert Xu42f811b2007-06-04 23:34:44 -070069 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000070 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
71 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
72 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
73 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
Herbert Xu42f811b2007-06-04 23:34:44 -070074 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070075};
76
77static struct ipv4_devconf ipv4_devconf_dflt = {
Herbert Xu42f811b2007-06-04 23:34:44 -070078 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000079 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
80 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
81 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
82 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
83 [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
Herbert Xu42f811b2007-06-04 23:34:44 -070084 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070085};
86
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -080087#define IPV4_DEVCONF_DFLT(net, attr) \
88 IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr)
Herbert Xu42f811b2007-06-04 23:34:44 -070089
Patrick McHardyef7c79e2007-06-05 12:38:30 -070090static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
Thomas Graf5c753972006-08-04 23:03:53 -070091 [IFA_LOCAL] = { .type = NLA_U32 },
92 [IFA_ADDRESS] = { .type = NLA_U32 },
93 [IFA_BROADCAST] = { .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
Eric Dumazet40384992012-08-03 21:06:50 +000097#define IN4_ADDR_HSIZE_SHIFT 8
98#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT)
99
David S. Millerfd23c3b2011-02-18 12:42:28 -0800100static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
101static DEFINE_SPINLOCK(inet_addr_hash_lock);
102
Eric Dumazet40384992012-08-03 21:06:50 +0000103static u32 inet_addr_hash(struct net *net, __be32 addr)
David S. Millerfd23c3b2011-02-18 12:42:28 -0800104{
Eric Dumazet40384992012-08-03 21:06:50 +0000105 u32 val = (__force u32) addr ^ net_hash_mix(net);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800106
Eric Dumazet40384992012-08-03 21:06:50 +0000107 return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800108}
109
110static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
111{
Eric Dumazet40384992012-08-03 21:06:50 +0000112 u32 hash = inet_addr_hash(net, ifa->ifa_local);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800113
114 spin_lock(&inet_addr_hash_lock);
115 hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
116 spin_unlock(&inet_addr_hash_lock);
117}
118
119static void inet_hash_remove(struct in_ifaddr *ifa)
120{
121 spin_lock(&inet_addr_hash_lock);
122 hlist_del_init_rcu(&ifa->hash);
123 spin_unlock(&inet_addr_hash_lock);
124}
125
David S. Miller9435eb12011-02-18 12:43:09 -0800126/**
127 * __ip_dev_find - find the first device with a given source address.
128 * @net: the net namespace
129 * @addr: the source address
130 * @devref: if true, take a reference on the found device
131 *
132 * If a caller uses devref=false, it should be protected by RCU, or RTNL
133 */
134struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
135{
Eric Dumazet40384992012-08-03 21:06:50 +0000136 u32 hash = inet_addr_hash(net, addr);
David S. Miller9435eb12011-02-18 12:43:09 -0800137 struct net_device *result = NULL;
138 struct in_ifaddr *ifa;
139 struct hlist_node *node;
140
141 rcu_read_lock();
142 hlist_for_each_entry_rcu(ifa, node, &inet_addr_lst[hash], hash) {
David S. Millere0660082011-03-03 11:24:19 -0800143 if (ifa->ifa_local == addr) {
Eric Dumazet40384992012-08-03 21:06:50 +0000144 struct net_device *dev = ifa->ifa_dev->dev;
145
146 if (!net_eq(dev_net(dev), net))
147 continue;
David S. Miller9435eb12011-02-18 12:43:09 -0800148 result = dev;
149 break;
150 }
151 }
David S. Miller406b6f92011-03-22 21:56:23 -0700152 if (!result) {
153 struct flowi4 fl4 = { .daddr = addr };
154 struct fib_result res = { 0 };
155 struct fib_table *local;
156
157 /* Fallback to FIB local table so that communication
158 * over loopback subnets work.
159 */
160 local = fib_get_table(net, RT_TABLE_LOCAL);
161 if (local &&
162 !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
163 res.type == RTN_LOCAL)
164 result = FIB_RES_DEV(res);
165 }
David S. Miller9435eb12011-02-18 12:43:09 -0800166 if (result && devref)
167 dev_hold(result);
168 rcu_read_unlock();
169 return result;
170}
171EXPORT_SYMBOL(__ip_dev_find);
172
Thomas Grafd6062cb2006-08-15 00:33:59 -0700173static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
Alan Sterne041c682006-03-27 01:16:30 -0800175static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
177 int destroy);
178#ifdef CONFIG_SYSCTL
Pavel Emelyanov66f27a52007-12-02 00:55:54 +1100179static void devinet_sysctl_register(struct in_device *idev);
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800180static void devinet_sysctl_unregister(struct in_device *idev);
181#else
Eric Dumazet40384992012-08-03 21:06:50 +0000182static void devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800183{
184}
Eric Dumazet40384992012-08-03 21:06:50 +0000185static void devinet_sysctl_unregister(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800186{
187}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188#endif
189
190/* Locks all the inet devices. */
191
192static struct in_ifaddr *inet_alloc_ifa(void)
193{
Alexey Dobriyan93adcc82008-10-28 13:25:09 -0700194 return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195}
196
197static void inet_rcu_free_ifa(struct rcu_head *head)
198{
199 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
200 if (ifa->ifa_dev)
201 in_dev_put(ifa->ifa_dev);
202 kfree(ifa);
203}
204
Eric Dumazet40384992012-08-03 21:06:50 +0000205static void inet_free_ifa(struct in_ifaddr *ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206{
207 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
208}
209
210void in_dev_finish_destroy(struct in_device *idev)
211{
212 struct net_device *dev = idev->dev;
213
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700214 WARN_ON(idev->ifa_list);
215 WARN_ON(idev->mc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216#ifdef NET_REFCNT_DEBUG
Joe Perches91df42b2012-05-15 14:11:54 +0000217 pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218#endif
219 dev_put(dev);
220 if (!idev->dead)
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800221 pr_err("Freeing alive in_device %p\n", idev);
222 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 kfree(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800225EXPORT_SYMBOL(in_dev_finish_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226
Herbert Xu71e27da2007-06-04 23:36:06 -0700227static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228{
229 struct in_device *in_dev;
230
231 ASSERT_RTNL();
232
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700233 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 if (!in_dev)
235 goto out;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900236 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -0800237 sizeof(in_dev->cnf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 in_dev->cnf.sysctl = NULL;
239 in_dev->dev = dev;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800240 in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
241 if (!in_dev->arp_parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 goto out_kfree;
Ben Hutchings0187bdf2008-06-19 16:15:47 -0700243 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
244 dev_disable_lro(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 /* Reference in_dev->dev */
246 dev_hold(dev);
David L Stevens30c4cf52007-01-04 12:31:14 -0800247 /* Account for reference dev->ip_ptr (below) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 in_dev_hold(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
Pavel Emelyanov66f27a52007-12-02 00:55:54 +1100250 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 ip_mc_init_dev(in_dev);
252 if (dev->flags & IFF_UP)
253 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800254
David L Stevens30c4cf52007-01-04 12:31:14 -0800255 /* we can receive as soon as ip_ptr is set -- do this last */
Eric Dumazetcf778b02012-01-12 04:41:32 +0000256 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800257out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 return in_dev;
259out_kfree:
260 kfree(in_dev);
261 in_dev = NULL;
262 goto out;
263}
264
265static void in_dev_rcu_put(struct rcu_head *head)
266{
267 struct in_device *idev = container_of(head, struct in_device, rcu_head);
268 in_dev_put(idev);
269}
270
271static void inetdev_destroy(struct in_device *in_dev)
272{
273 struct in_ifaddr *ifa;
274 struct net_device *dev;
275
276 ASSERT_RTNL();
277
278 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
280 in_dev->dead = 1;
281
282 ip_mc_destroy_dev(in_dev);
283
284 while ((ifa = in_dev->ifa_list) != NULL) {
285 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
286 inet_free_ifa(ifa);
287 }
288
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000289 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800291 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
293 arp_ifdown(dev);
294
295 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
296}
297
Al Viroff428d72006-09-26 22:13:35 -0700298int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
300 rcu_read_lock();
301 for_primary_ifa(in_dev) {
302 if (inet_ifa_match(a, ifa)) {
303 if (!b || inet_ifa_match(b, ifa)) {
304 rcu_read_unlock();
305 return 1;
306 }
307 }
308 } endfor_ifa(in_dev);
309 rcu_read_unlock();
310 return 0;
311}
312
Thomas Grafd6062cb2006-08-15 00:33:59 -0700313static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
314 int destroy, struct nlmsghdr *nlh, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
Harald Welte8f937c62005-05-29 20:23:46 -0700316 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800317 struct in_ifaddr *ifa, *ifa1 = *ifap;
318 struct in_ifaddr *last_prim = in_dev->ifa_list;
319 struct in_ifaddr *prev_prom = NULL;
320 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
322 ASSERT_RTNL();
323
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900324 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700325 * unless alias promotion is set
326 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
330
331 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900332 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800333 ifa1->ifa_scope <= ifa->ifa_scope)
334 last_prim = ifa;
335
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
337 ifa1->ifa_mask != ifa->ifa_mask ||
338 !inet_ifa_match(ifa1->ifa_address, ifa)) {
339 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800340 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 continue;
342 }
343
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800344 if (!do_promote) {
David S. Millerfd23c3b2011-02-18 12:42:28 -0800345 inet_hash_remove(ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700346 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
Thomas Grafd6062cb2006-08-15 00:33:59 -0700348 rtmsg_ifa(RTM_DELADDR, ifa, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800349 blocking_notifier_call_chain(&inetaddr_chain,
350 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700351 inet_free_ifa(ifa);
352 } else {
353 promote = ifa;
354 break;
355 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 }
357 }
358
Julian Anastasov2d230e22011-03-19 12:13:52 +0000359 /* On promotion all secondaries from subnet are changing
360 * the primary IP, we must remove all their routes silently
361 * and later to add them back with new prefsrc. Do this
362 * while all addresses are on the device list.
363 */
364 for (ifa = promote; ifa; ifa = ifa->ifa_next) {
365 if (ifa1->ifa_mask == ifa->ifa_mask &&
366 inet_ifa_match(ifa1->ifa_address, ifa))
367 fib_del_ifaddr(ifa, ifa1);
368 }
369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 /* 2. Unlink it */
371
372 *ifap = ifa1->ifa_next;
David S. Millerfd23c3b2011-02-18 12:42:28 -0800373 inet_hash_remove(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
375 /* 3. Announce address deletion */
376
377 /* Send message first, then call notifier.
378 At first sight, FIB update triggered by notifier
379 will refer to already deleted ifaddr, that could confuse
380 netlink listeners. It is not true: look, gated sees
381 that route deleted and if it still thinks that ifaddr
382 is valid, it will try to restore deleted routes... Grr.
383 So that, this order is correct.
384 */
Thomas Grafd6062cb2006-08-15 00:33:59 -0700385 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800386 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800387
388 if (promote) {
Julian Anastasov04024b92011-03-19 12:13:54 +0000389 struct in_ifaddr *next_sec = promote->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800390
391 if (prev_prom) {
392 prev_prom->ifa_next = promote->ifa_next;
393 promote->ifa_next = last_prim->ifa_next;
394 last_prim->ifa_next = promote;
395 }
396
397 promote->ifa_flags &= ~IFA_F_SECONDARY;
Thomas Grafd6062cb2006-08-15 00:33:59 -0700398 rtmsg_ifa(RTM_NEWADDR, promote, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800399 blocking_notifier_call_chain(&inetaddr_chain,
400 NETDEV_UP, promote);
Julian Anastasov04024b92011-03-19 12:13:54 +0000401 for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800402 if (ifa1->ifa_mask != ifa->ifa_mask ||
403 !inet_ifa_match(ifa1->ifa_address, ifa))
404 continue;
405 fib_add_ifaddr(ifa);
406 }
407
408 }
Herbert Xu63630972007-06-07 18:35:38 -0700409 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411}
412
Thomas Grafd6062cb2006-08-15 00:33:59 -0700413static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
414 int destroy)
415{
416 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
417}
418
419static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
420 u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421{
422 struct in_device *in_dev = ifa->ifa_dev;
423 struct in_ifaddr *ifa1, **ifap, **last_primary;
424
425 ASSERT_RTNL();
426
427 if (!ifa->ifa_local) {
428 inet_free_ifa(ifa);
429 return 0;
430 }
431
432 ifa->ifa_flags &= ~IFA_F_SECONDARY;
433 last_primary = &in_dev->ifa_list;
434
435 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
436 ifap = &ifa1->ifa_next) {
437 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
438 ifa->ifa_scope <= ifa1->ifa_scope)
439 last_primary = &ifa1->ifa_next;
440 if (ifa1->ifa_mask == ifa->ifa_mask &&
441 inet_ifa_match(ifa1->ifa_address, ifa)) {
442 if (ifa1->ifa_local == ifa->ifa_local) {
443 inet_free_ifa(ifa);
444 return -EEXIST;
445 }
446 if (ifa1->ifa_scope != ifa->ifa_scope) {
447 inet_free_ifa(ifa);
448 return -EINVAL;
449 }
450 ifa->ifa_flags |= IFA_F_SECONDARY;
451 }
452 }
453
454 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
455 net_srandom(ifa->ifa_local);
456 ifap = last_primary;
457 }
458
459 ifa->ifa_next = *ifap;
460 *ifap = ifa;
461
David S. Millerfd23c3b2011-02-18 12:42:28 -0800462 inet_hash_insert(dev_net(in_dev->dev), ifa);
463
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 /* Send message first, then call notifier.
465 Notifier will trigger FIB update, so that
466 listeners of netlink will know about new ifaddr */
Thomas Grafd6062cb2006-08-15 00:33:59 -0700467 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, pid);
Alan Sterne041c682006-03-27 01:16:30 -0800468 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
470 return 0;
471}
472
Thomas Grafd6062cb2006-08-15 00:33:59 -0700473static int inet_insert_ifa(struct in_ifaddr *ifa)
474{
475 return __inet_insert_ifa(ifa, NULL, 0);
476}
477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
479{
Herbert Xue5ed6392005-10-03 14:35:55 -0700480 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
482 ASSERT_RTNL();
483
484 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700485 inet_free_ifa(ifa);
486 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700488 ipv4_devconf_setall(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700490 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 in_dev_hold(in_dev);
492 ifa->ifa_dev = in_dev;
493 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800494 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 ifa->ifa_scope = RT_SCOPE_HOST;
496 return inet_insert_ifa(ifa);
497}
498
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000499/* Caller must hold RCU or RTNL :
500 * We dont take a reference on found in_device
501 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800502struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503{
504 struct net_device *dev;
505 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000506
507 rcu_read_lock();
508 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000510 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000511 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 return in_dev;
513}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800514EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
516/* Called only from RTNL semaphored context. No locks. */
517
Al Viro60cad5d2006-09-26 22:17:09 -0700518struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
519 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520{
521 ASSERT_RTNL();
522
523 for_primary_ifa(in_dev) {
524 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
525 return ifa;
526 } endfor_ifa(in_dev);
527 return NULL;
528}
529
530static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
531{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900532 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700533 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700535 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700537 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
539 ASSERT_RTNL();
540
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700541 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
542 if (err < 0)
543 goto errout;
544
545 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800546 in_dev = inetdev_by_index(net, ifm->ifa_index);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700547 if (in_dev == NULL) {
548 err = -ENODEV;
549 goto errout;
550 }
551
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
553 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700554 if (tb[IFA_LOCAL] &&
Al Viroa7a628c2006-09-26 22:16:43 -0700555 ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700557
558 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
559 continue;
560
561 if (tb[IFA_ADDRESS] &&
562 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Al Viroa7a628c2006-09-26 22:16:43 -0700563 !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700564 continue;
565
Thomas Grafd6062cb2006-08-15 00:33:59 -0700566 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 return 0;
568 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700569
570 err = -EADDRNOTAVAIL;
571errout:
572 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573}
574
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800575static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576{
Thomas Graf5c753972006-08-04 23:03:53 -0700577 struct nlattr *tb[IFA_MAX+1];
578 struct in_ifaddr *ifa;
579 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 struct net_device *dev;
581 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800582 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
Thomas Graf5c753972006-08-04 23:03:53 -0700584 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
585 if (err < 0)
586 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
Thomas Graf5c753972006-08-04 23:03:53 -0700588 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800589 err = -EINVAL;
590 if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700591 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800593 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800594 err = -ENODEV;
595 if (dev == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700596 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597
Thomas Graf5c753972006-08-04 23:03:53 -0700598 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800599 err = -ENOBUFS;
600 if (in_dev == NULL)
Herbert Xu71e27da2007-06-04 23:36:06 -0700601 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
Thomas Graf5c753972006-08-04 23:03:53 -0700603 ifa = inet_alloc_ifa();
Denis V. Lunev7b218572008-01-31 18:47:00 -0800604 if (ifa == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700605 /*
606 * A potential indev allocation can be left alive, it stays
607 * assigned to its device and is destroy with it.
608 */
Thomas Graf5c753972006-08-04 23:03:53 -0700609 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700610
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800611 ipv4_devconf_setall(in_dev);
Thomas Graf5c753972006-08-04 23:03:53 -0700612 in_dev_hold(in_dev);
613
614 if (tb[IFA_ADDRESS] == NULL)
615 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
616
David S. Millerfd23c3b2011-02-18 12:42:28 -0800617 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
619 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 ifa->ifa_flags = ifm->ifa_flags;
621 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700622 ifa->ifa_dev = in_dev;
623
Al Viroa7a628c2006-09-26 22:16:43 -0700624 ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]);
625 ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700626
627 if (tb[IFA_BROADCAST])
Al Viroa7a628c2006-09-26 22:16:43 -0700628 ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700629
Thomas Graf5c753972006-08-04 23:03:53 -0700630 if (tb[IFA_LABEL])
631 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 else
633 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
634
Thomas Graf5c753972006-08-04 23:03:53 -0700635 return ifa;
636
637errout:
638 return ERR_PTR(err);
639}
640
641static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
642{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900643 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700644 struct in_ifaddr *ifa;
645
646 ASSERT_RTNL();
647
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800648 ifa = rtm_to_ifaddr(net, nlh);
Thomas Graf5c753972006-08-04 23:03:53 -0700649 if (IS_ERR(ifa))
650 return PTR_ERR(ifa);
651
Thomas Grafd6062cb2006-08-15 00:33:59 -0700652 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653}
654
655/*
656 * Determine a default network mask, based on the IP address.
657 */
658
Eric Dumazet40384992012-08-03 21:06:50 +0000659static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660{
661 int rc = -1; /* Something else, probably a multicast. */
662
Joe Perchesf97c1e02007-12-16 13:45:43 -0800663 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900664 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 else {
Al Viro714e85b2006-11-14 20:51:49 -0800666 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
Al Viro714e85b2006-11-14 20:51:49 -0800668 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800670 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800672 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 rc = 24;
674 }
675
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900676 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677}
678
679
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800680int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681{
682 struct ifreq ifr;
683 struct sockaddr_in sin_orig;
684 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
685 struct in_device *in_dev;
686 struct in_ifaddr **ifap = NULL;
687 struct in_ifaddr *ifa = NULL;
688 struct net_device *dev;
689 char *colon;
690 int ret = -EFAULT;
691 int tryaddrmatch = 0;
692
693 /*
694 * Fetch the caller's info block into kernel space
695 */
696
697 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
698 goto out;
699 ifr.ifr_name[IFNAMSIZ - 1] = 0;
700
701 /* save original address for comparison */
702 memcpy(&sin_orig, sin, sizeof(*sin));
703
704 colon = strchr(ifr.ifr_name, ':');
705 if (colon)
706 *colon = 0;
707
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800708 dev_load(net, ifr.ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
Stephen Hemminger132adf52007-03-08 20:44:43 -0800710 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 case SIOCGIFADDR: /* Get interface address */
712 case SIOCGIFBRDADDR: /* Get the broadcast address */
713 case SIOCGIFDSTADDR: /* Get the destination address */
714 case SIOCGIFNETMASK: /* Get the netmask for the interface */
715 /* Note that these ioctls will not sleep,
716 so that we do not impose a lock.
717 One day we will be forced to put shlock here (I mean SMP)
718 */
719 tryaddrmatch = (sin_orig.sin_family == AF_INET);
720 memset(sin, 0, sizeof(*sin));
721 sin->sin_family = AF_INET;
722 break;
723
724 case SIOCSIFFLAGS:
725 ret = -EACCES;
726 if (!capable(CAP_NET_ADMIN))
727 goto out;
728 break;
729 case SIOCSIFADDR: /* Set interface address (and family) */
730 case SIOCSIFBRDADDR: /* Set the broadcast address */
731 case SIOCSIFDSTADDR: /* Set the destination address */
732 case SIOCSIFNETMASK: /* Set the netmask for the interface */
733 ret = -EACCES;
734 if (!capable(CAP_NET_ADMIN))
735 goto out;
736 ret = -EINVAL;
737 if (sin->sin_family != AF_INET)
738 goto out;
739 break;
740 default:
741 ret = -EINVAL;
742 goto out;
743 }
744
745 rtnl_lock();
746
747 ret = -ENODEV;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800748 dev = __dev_get_by_name(net, ifr.ifr_name);
749 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 goto done;
751
752 if (colon)
753 *colon = ':';
754
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800755 in_dev = __in_dev_get_rtnl(dev);
756 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 if (tryaddrmatch) {
758 /* Matthias Andree */
759 /* compare label and address (4.4BSD style) */
760 /* note: we only do this for a limited set of ioctls
761 and only if the original address family was AF_INET.
762 This is checked above. */
763 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
764 ifap = &ifa->ifa_next) {
765 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
766 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -0800767 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 break; /* found */
769 }
770 }
771 }
772 /* we didn't get a match, maybe the application is
773 4.3BSD-style and passed in junk so we fall back to
774 comparing just the label */
775 if (!ifa) {
776 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
777 ifap = &ifa->ifa_next)
778 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
779 break;
780 }
781 }
782
783 ret = -EADDRNOTAVAIL;
784 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
785 goto done;
786
Stephen Hemminger132adf52007-03-08 20:44:43 -0800787 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 case SIOCGIFADDR: /* Get interface address */
789 sin->sin_addr.s_addr = ifa->ifa_local;
790 goto rarok;
791
792 case SIOCGIFBRDADDR: /* Get the broadcast address */
793 sin->sin_addr.s_addr = ifa->ifa_broadcast;
794 goto rarok;
795
796 case SIOCGIFDSTADDR: /* Get the destination address */
797 sin->sin_addr.s_addr = ifa->ifa_address;
798 goto rarok;
799
800 case SIOCGIFNETMASK: /* Get the netmask for the interface */
801 sin->sin_addr.s_addr = ifa->ifa_mask;
802 goto rarok;
803
804 case SIOCSIFFLAGS:
805 if (colon) {
806 ret = -EADDRNOTAVAIL;
807 if (!ifa)
808 break;
809 ret = 0;
810 if (!(ifr.ifr_flags & IFF_UP))
811 inet_del_ifa(in_dev, ifap, 1);
812 break;
813 }
814 ret = dev_change_flags(dev, ifr.ifr_flags);
815 break;
816
817 case SIOCSIFADDR: /* Set interface address (and family) */
818 ret = -EINVAL;
819 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
820 break;
821
822 if (!ifa) {
823 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800824 ifa = inet_alloc_ifa();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800825 INIT_HLIST_NODE(&ifa->hash);
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800826 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 break;
828 if (colon)
829 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
830 else
831 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
832 } else {
833 ret = 0;
834 if (ifa->ifa_local == sin->sin_addr.s_addr)
835 break;
836 inet_del_ifa(in_dev, ifap, 0);
837 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -0800838 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 }
840
841 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
842
843 if (!(dev->flags & IFF_POINTOPOINT)) {
844 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
845 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
846 if ((dev->flags & IFF_BROADCAST) &&
847 ifa->ifa_prefixlen < 31)
848 ifa->ifa_broadcast = ifa->ifa_address |
849 ~ifa->ifa_mask;
850 } else {
851 ifa->ifa_prefixlen = 32;
852 ifa->ifa_mask = inet_make_mask(32);
853 }
854 ret = inet_set_ifa(dev, ifa);
855 break;
856
857 case SIOCSIFBRDADDR: /* Set the broadcast address */
858 ret = 0;
859 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
860 inet_del_ifa(in_dev, ifap, 0);
861 ifa->ifa_broadcast = sin->sin_addr.s_addr;
862 inet_insert_ifa(ifa);
863 }
864 break;
865
866 case SIOCSIFDSTADDR: /* Set the destination address */
867 ret = 0;
868 if (ifa->ifa_address == sin->sin_addr.s_addr)
869 break;
870 ret = -EINVAL;
871 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
872 break;
873 ret = 0;
874 inet_del_ifa(in_dev, ifap, 0);
875 ifa->ifa_address = sin->sin_addr.s_addr;
876 inet_insert_ifa(ifa);
877 break;
878
879 case SIOCSIFNETMASK: /* Set the netmask for the interface */
880
881 /*
882 * The mask we set must be legal.
883 */
884 ret = -EINVAL;
885 if (bad_mask(sin->sin_addr.s_addr, 0))
886 break;
887 ret = 0;
888 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -0700889 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 inet_del_ifa(in_dev, ifap, 0);
891 ifa->ifa_mask = sin->sin_addr.s_addr;
892 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
893
894 /* See if current broadcast address matches
895 * with current netmask, then recalculate
896 * the broadcast address. Otherwise it's a
897 * funny address, so don't touch it since
898 * the user seems to know what (s)he's doing...
899 */
900 if ((dev->flags & IFF_BROADCAST) &&
901 (ifa->ifa_prefixlen < 31) &&
902 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -0500903 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 ifa->ifa_broadcast = (ifa->ifa_local |
905 ~sin->sin_addr.s_addr);
906 }
907 inet_insert_ifa(ifa);
908 }
909 break;
910 }
911done:
912 rtnl_unlock();
913out:
914 return ret;
915rarok:
916 rtnl_unlock();
917 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
918 goto out;
919}
920
921static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
922{
Herbert Xue5ed6392005-10-03 14:35:55 -0700923 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 struct in_ifaddr *ifa;
925 struct ifreq ifr;
926 int done = 0;
927
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800928 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 goto out;
930
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800931 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 if (!buf) {
933 done += sizeof(ifr);
934 continue;
935 }
936 if (len < (int) sizeof(ifr))
937 break;
938 memset(&ifr, 0, sizeof(struct ifreq));
939 if (ifa->ifa_label)
940 strcpy(ifr.ifr_name, ifa->ifa_label);
941 else
942 strcpy(ifr.ifr_name, dev->name);
943
944 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
945 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
946 ifa->ifa_local;
947
948 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
949 done = -EFAULT;
950 break;
951 }
952 buf += sizeof(struct ifreq);
953 len -= sizeof(struct ifreq);
954 done += sizeof(struct ifreq);
955 }
956out:
957 return done;
958}
959
Al Viroa61ced52006-09-26 21:27:54 -0700960__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961{
Al Viroa61ced52006-09-26 21:27:54 -0700962 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900964 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
966 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -0700967 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 if (!in_dev)
969 goto no_in_dev;
970
971 for_primary_ifa(in_dev) {
972 if (ifa->ifa_scope > scope)
973 continue;
974 if (!dst || inet_ifa_match(dst, ifa)) {
975 addr = ifa->ifa_local;
976 break;
977 }
978 if (!addr)
979 addr = ifa->ifa_local;
980 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
982 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800983 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800984no_in_dev:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
986 /* Not loopback addresses on loopback should be preferred
987 in this case. It is importnat that lo is the first interface
988 in dev_base list.
989 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800990 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800991 in_dev = __in_dev_get_rcu(dev);
992 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 continue;
994
995 for_primary_ifa(in_dev) {
996 if (ifa->ifa_scope != RT_SCOPE_LINK &&
997 ifa->ifa_scope <= scope) {
998 addr = ifa->ifa_local;
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800999 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 }
1001 } endfor_ifa(in_dev);
1002 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001003out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 return addr;
1006}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001007EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008
Al Viro60cad5d2006-09-26 22:17:09 -07001009static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1010 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011{
1012 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001013 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
1015 for_ifa(in_dev) {
1016 if (!addr &&
1017 (local == ifa->ifa_local || !local) &&
1018 ifa->ifa_scope <= scope) {
1019 addr = ifa->ifa_local;
1020 if (same)
1021 break;
1022 }
1023 if (!same) {
1024 same = (!local || inet_ifa_match(local, ifa)) &&
1025 (!dst || inet_ifa_match(dst, ifa));
1026 if (same && addr) {
1027 if (local || !dst)
1028 break;
1029 /* Is the selected addr into dst subnet? */
1030 if (inet_ifa_match(addr, ifa))
1031 break;
1032 /* No, then can we use new local src? */
1033 if (ifa->ifa_scope <= scope) {
1034 addr = ifa->ifa_local;
1035 break;
1036 }
1037 /* search for large dst subnet for addr */
1038 same = 0;
1039 }
1040 }
1041 } endfor_ifa(in_dev);
1042
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001043 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044}
1045
1046/*
1047 * Confirm that local IP address exists using wildcards:
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001048 * - in_dev: only on this interface, 0=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 * - dst: only in the same subnet as dst, 0=any dst
1050 * - local: address, 0=autoselect the local address
1051 * - scope: maximum allowed scope value for the local address
1052 */
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001053__be32 inet_confirm_addr(struct in_device *in_dev,
1054 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055{
Al Viro60cad5d2006-09-26 22:17:09 -07001056 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001057 struct net_device *dev;
Denis V. Lunev39a6d062008-01-14 23:06:19 -08001058 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
Denis V. Lunev39a6d062008-01-14 23:06:19 -08001060 if (scope != RT_SCOPE_LINK)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001061 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001063 net = dev_net(in_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001065 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001066 in_dev = __in_dev_get_rcu(dev);
1067 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 addr = confirm_addr_indev(in_dev, dst, local, scope);
1069 if (addr)
1070 break;
1071 }
1072 }
1073 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
1075 return addr;
1076}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001077EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
1079/*
1080 * Device notifier
1081 */
1082
1083int register_inetaddr_notifier(struct notifier_block *nb)
1084{
Alan Sterne041c682006-03-27 01:16:30 -08001085 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001087EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
1089int unregister_inetaddr_notifier(struct notifier_block *nb)
1090{
Alan Sterne041c682006-03-27 01:16:30 -08001091 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001093EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001095/* Rename ifa_labels for a device name change. Make some effort to preserve
1096 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097*/
1098static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001099{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 struct in_ifaddr *ifa;
1101 int named = 0;
1102
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001103 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1104 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
1106 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001107 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001109 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001110 dot = strchr(old, ':');
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001111 if (dot == NULL) {
1112 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 dot = old;
1114 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001115 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001116 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001117 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001118 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001119skip:
1120 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001121 }
1122}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
Eric Dumazet40384992012-08-03 21:06:50 +00001124static bool inetdev_valid_mtu(unsigned int mtu)
Breno Leitao06770842008-09-02 17:28:58 -07001125{
1126 return mtu >= 68;
1127}
1128
Ian Campbelld11327ad2011-02-11 07:44:16 +00001129static void inetdev_send_gratuitous_arp(struct net_device *dev,
1130 struct in_device *in_dev)
1131
1132{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001133 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001134
Zoltan Kissb76d0782011-07-24 13:09:30 +00001135 for (ifa = in_dev->ifa_list; ifa;
1136 ifa = ifa->ifa_next) {
1137 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1138 ifa->ifa_local, dev,
1139 ifa->ifa_local, NULL,
1140 dev->dev_addr, NULL);
1141 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001142}
1143
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144/* Called only under RTNL semaphore */
1145
1146static int inetdev_event(struct notifier_block *this, unsigned long event,
1147 void *ptr)
1148{
1149 struct net_device *dev = ptr;
Eric Dumazet748e2d92012-08-22 21:50:59 +00001150 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
1152 ASSERT_RTNL();
1153
1154 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001155 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 in_dev = inetdev_init(dev);
Herbert Xub217d612007-07-30 17:04:52 -07001157 if (!in_dev)
1158 return notifier_from_errno(-ENOMEM);
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001159 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001160 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1161 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001162 }
Breno Leitao06770842008-09-02 17:28:58 -07001163 } else if (event == NETDEV_CHANGEMTU) {
1164 /* Re-enabling IP */
1165 if (inetdev_valid_mtu(dev->mtu))
1166 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 }
1168 goto out;
1169 }
1170
1171 switch (event) {
1172 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001173 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001174 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 break;
1176 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001177 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001179 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001180 struct in_ifaddr *ifa = inet_alloc_ifa();
1181
1182 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001183 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 ifa->ifa_local =
1185 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1186 ifa->ifa_prefixlen = 8;
1187 ifa->ifa_mask = inet_make_mask(8);
1188 in_dev_hold(in_dev);
1189 ifa->ifa_dev = in_dev;
1190 ifa->ifa_scope = RT_SCOPE_HOST;
1191 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1192 inet_insert_ifa(ifa);
1193 }
1194 }
1195 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001196 /* fall through */
1197 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001198 if (!IN_DEV_ARP_NOTIFY(in_dev))
1199 break;
1200 /* fall through */
1201 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001202 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001203 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 break;
1205 case NETDEV_DOWN:
1206 ip_mc_down(in_dev);
1207 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001208 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001209 ip_mc_unmap(in_dev);
1210 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001211 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001212 ip_mc_remap(in_dev);
1213 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001215 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 break;
Breno Leitao06770842008-09-02 17:28:58 -07001217 /* disable IP when MTU is not enough */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 case NETDEV_UNREGISTER:
1219 inetdev_destroy(in_dev);
1220 break;
1221 case NETDEV_CHANGENAME:
1222 /* Do not notify about label change, this event is
1223 * not interesting to applications using netlink.
1224 */
1225 inetdev_changename(dev, in_dev);
1226
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001227 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001228 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 break;
1230 }
1231out:
1232 return NOTIFY_DONE;
1233}
1234
1235static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001236 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237};
1238
Eric Dumazet40384992012-08-03 21:06:50 +00001239static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001240{
1241 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1242 + nla_total_size(4) /* IFA_ADDRESS */
1243 + nla_total_size(4) /* IFA_LOCAL */
1244 + nla_total_size(4) /* IFA_BROADCAST */
Thomas Graf339bf982006-11-10 14:10:15 -08001245 + nla_total_size(IFNAMSIZ); /* IFA_LABEL */
1246}
1247
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07001249 u32 pid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250{
1251 struct ifaddrmsg *ifm;
1252 struct nlmsghdr *nlh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
Thomas Graf47f68512006-08-04 23:04:36 -07001254 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);
1255 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001256 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001257
1258 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 ifm->ifa_family = AF_INET;
1260 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
1261 ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT;
1262 ifm->ifa_scope = ifa->ifa_scope;
1263 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
David S. Millerf3756b72012-04-01 20:39:02 -04001265 if ((ifa->ifa_address &&
1266 nla_put_be32(skb, IFA_ADDRESS, ifa->ifa_address)) ||
1267 (ifa->ifa_local &&
1268 nla_put_be32(skb, IFA_LOCAL, ifa->ifa_local)) ||
1269 (ifa->ifa_broadcast &&
1270 nla_put_be32(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
1271 (ifa->ifa_label[0] &&
1272 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)))
1273 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001274
1275 return nlmsg_end(skb, nlh);
1276
1277nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001278 nlmsg_cancel(skb, nlh);
1279 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280}
1281
1282static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1283{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001284 struct net *net = sock_net(skb->sk);
Eric Dumazeteec4df92009-11-12 07:44:25 +00001285 int h, s_h;
1286 int idx, s_idx;
1287 int ip_idx, s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 struct net_device *dev;
1289 struct in_device *in_dev;
1290 struct in_ifaddr *ifa;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001291 struct hlist_head *head;
1292 struct hlist_node *node;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
Eric Dumazeteec4df92009-11-12 07:44:25 +00001294 s_h = cb->args[0];
1295 s_idx = idx = cb->args[1];
1296 s_ip_idx = ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297
Eric Dumazeteec4df92009-11-12 07:44:25 +00001298 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1299 idx = 0;
1300 head = &net->dev_index_head[h];
1301 rcu_read_lock();
1302 hlist_for_each_entry_rcu(dev, node, head, index_hlist) {
1303 if (idx < s_idx)
1304 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001305 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001306 s_ip_idx = 0;
1307 in_dev = __in_dev_get_rcu(dev);
1308 if (!in_dev)
1309 goto cont;
1310
1311 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1312 ifa = ifa->ifa_next, ip_idx++) {
1313 if (ip_idx < s_ip_idx)
1314 continue;
1315 if (inet_fill_ifaddr(skb, ifa,
1316 NETLINK_CB(cb->skb).pid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 cb->nlh->nlmsg_seq,
Eric Dumazeteec4df92009-11-12 07:44:25 +00001318 RTM_NEWADDR, NLM_F_MULTI) <= 0) {
1319 rcu_read_unlock();
1320 goto done;
1321 }
1322 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001323cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001324 idx++;
1325 }
1326 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 }
1328
1329done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001330 cb->args[0] = h;
1331 cb->args[1] = idx;
1332 cb->args[2] = ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
1334 return skb->len;
1335}
1336
Jianjun Kong539afed2008-11-03 02:48:48 -08001337static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Thomas Grafd6062cb2006-08-15 00:33:59 -07001338 u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339{
Thomas Graf47f68512006-08-04 23:04:36 -07001340 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001341 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1342 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001343 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001345 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001346 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Thomas Graf47f68512006-08-04 23:04:36 -07001347 if (skb == NULL)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001348 goto errout;
1349
1350 err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001351 if (err < 0) {
1352 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1353 WARN_ON(err == -EMSGSIZE);
1354 kfree_skb(skb);
1355 goto errout;
1356 }
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001357 rtnl_notify(skb, net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
1358 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001359errout:
1360 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001361 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362}
1363
Thomas Graf9f0f7272010-11-16 04:32:48 +00001364static size_t inet_get_link_af_size(const struct net_device *dev)
1365{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001366 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001367
1368 if (!in_dev)
1369 return 0;
1370
1371 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1372}
1373
1374static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
1375{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001376 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001377 struct nlattr *nla;
1378 int i;
1379
1380 if (!in_dev)
1381 return -ENODATA;
1382
1383 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
1384 if (nla == NULL)
1385 return -EMSGSIZE;
1386
1387 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1388 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1389
1390 return 0;
1391}
1392
1393static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1394 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1395};
1396
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001397static int inet_validate_link_af(const struct net_device *dev,
1398 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001399{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001400 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1401 int err, rem;
1402
Eric Dumazetf7fce742010-12-01 06:03:06 +00001403 if (dev && !__in_dev_get_rtnl(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001404 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001405
1406 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy);
1407 if (err < 0)
1408 return err;
1409
1410 if (tb[IFLA_INET_CONF]) {
1411 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1412 int cfgid = nla_type(a);
1413
1414 if (nla_len(a) < 4)
1415 return -EINVAL;
1416
1417 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1418 return -EINVAL;
1419 }
1420 }
1421
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001422 return 0;
1423}
1424
1425static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1426{
Eric Dumazetf7fce742010-12-01 06:03:06 +00001427 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001428 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1429 int rem;
1430
1431 if (!in_dev)
1432 return -EAFNOSUPPORT;
1433
1434 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL) < 0)
1435 BUG();
1436
Thomas Graf9f0f7272010-11-16 04:32:48 +00001437 if (tb[IFLA_INET_CONF]) {
1438 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1439 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1440 }
1441
1442 return 0;
1443}
1444
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445#ifdef CONFIG_SYSCTL
1446
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001447static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07001448{
1449 struct net_device *dev;
1450
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001451 rcu_read_lock();
1452 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07001453 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001454
Herbert Xu31be3082007-06-04 23:35:37 -07001455 in_dev = __in_dev_get_rcu(dev);
1456 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001457 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07001458 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001459 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07001460}
1461
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001462/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001463static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001464{
1465 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08001466 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001467
Pavel Emelyanov586f1212007-12-16 13:32:48 -08001468 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001469 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001470
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001471 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001472 struct in_device *in_dev;
Ben Hutchings0187bdf2008-06-19 16:15:47 -07001473 if (on)
1474 dev_disable_lro(dev);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001475 rcu_read_lock();
1476 in_dev = __in_dev_get_rcu(dev);
1477 if (in_dev)
1478 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
1479 rcu_read_unlock();
1480 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001481}
1482
Herbert Xu31be3082007-06-04 23:35:37 -07001483static int devinet_conf_proc(ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001484 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07001485 size_t *lenp, loff_t *ppos)
1486{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00001487 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001488 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00001489 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07001490
1491 if (write) {
1492 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001493 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07001494 int i = (int *)ctl->data - cnf->data;
1495
1496 set_bit(i, cnf->state);
1497
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001498 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001499 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00001500 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
1501 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00001502 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00001503 rt_cache_flush(net);
Herbert Xu31be3082007-06-04 23:35:37 -07001504 }
1505
1506 return ret;
1507}
1508
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509static int devinet_sysctl_forward(ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001510 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 size_t *lenp, loff_t *ppos)
1512{
1513 int *valp = ctl->data;
1514 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00001515 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001516 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517
1518 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001519 struct net *net = ctl->extra2;
1520
Ben Hutchings0187bdf2008-06-19 16:15:47 -07001521 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00001522 if (!rtnl_trylock()) {
1523 /* Restore the original values before restarting */
1524 *valp = val;
1525 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00001526 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00001527 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07001528 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
1529 inet_forward_change(net);
1530 } else if (*valp) {
1531 struct ipv4_devconf *cnf = ctl->extra1;
1532 struct in_device *idev =
1533 container_of(cnf, struct in_device, cnf);
1534 dev_disable_lro(idev->dev);
1535 }
1536 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00001537 rt_cache_flush(net);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07001538 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 }
1540
1541 return ret;
1542}
1543
David S. Miller323e1262010-12-12 21:55:08 -08001544static int ipv4_doint_and_flush(ctl_table *ctl, int write,
1545 void __user *buffer,
1546 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547{
1548 int *valp = ctl->data;
1549 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001550 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07001551 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552
1553 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00001554 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555
1556 return ret;
1557}
1558
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001559#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07001560 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07001561 .procname = name, \
1562 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00001563 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07001564 .maxlen = sizeof(int), \
1565 .mode = mval, \
1566 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07001567 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07001568 }
1569
1570#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001571 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07001572
1573#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001574 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07001575
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001576#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
1577 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07001578
1579#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001580 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07001581
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582static struct devinet_sysctl_table {
1583 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00001584 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585} devinet_sysctl = {
1586 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07001587 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001588 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07001589 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
1590
1591 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
1592 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
1593 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
1594 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
1595 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
1596 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
1597 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00001598 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08001599 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07001600 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
1601 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
1602 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
1603 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
1604 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
1605 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
1606 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
1607 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
1608 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001609 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00001610 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
Herbert Xu42f811b2007-06-04 23:34:44 -07001611
1612 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
1613 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
1614 DEVINET_SYSCTL_FLUSHING_ENTRY(FORCE_IGMP_VERSION,
1615 "force_igmp_version"),
1616 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
1617 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00001618 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
1619 "route_localnet"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621};
1622
Pavel Emelyanovea40b322007-12-16 13:30:07 -08001623static int __devinet_sysctl_register(struct net *net, char *dev_name,
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001624 struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625{
1626 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001627 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00001628 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11001629
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001630 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001632 goto out;
1633
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
1635 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07001636 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001637 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 }
1639
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00001640 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00001642 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00001644 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
1646 p->sysctl = t;
Pavel Emelyanovea40b322007-12-16 13:30:07 -08001647 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001649free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001651out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08001652 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653}
1654
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001655static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
1656{
1657 struct devinet_sysctl_table *t = cnf->sysctl;
1658
1659 if (t == NULL)
1660 return;
1661
1662 cnf->sysctl = NULL;
Lucian Adrian Grijincuff538812011-05-01 01:44:01 +00001663 unregister_net_sysctl_table(t->sysctl_header);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001664 kfree(t);
1665}
1666
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001667static void devinet_sysctl_register(struct in_device *idev)
1668{
Eric W. Biederman54716e32010-02-14 03:27:03 +00001669 neigh_sysctl_register(idev->dev, idev->arp_parms, "ipv4", NULL);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001670 __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001671 &idev->cnf);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001672}
1673
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001674static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675{
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001676 __devinet_sysctl_unregister(&idev->cnf);
1677 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001680static struct ctl_table ctl_forward_entry[] = {
1681 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001682 .procname = "ip_forward",
1683 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00001684 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001685 .maxlen = sizeof(int),
1686 .mode = 0644,
1687 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001688 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001689 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001690 },
1691 { },
1692};
Eric Dumazet2a75de02008-01-05 23:08:49 -08001693#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001694
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001695static __net_init int devinet_init_net(struct net *net)
1696{
1697 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001698 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08001699#ifdef CONFIG_SYSCTL
1700 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001701 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08001702#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001703
1704 err = -ENOMEM;
1705 all = &ipv4_devconf;
1706 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001707
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08001708 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001709 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
1710 if (all == NULL)
1711 goto err_alloc_all;
1712
1713 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
1714 if (dflt == NULL)
1715 goto err_alloc_dflt;
1716
Eric Dumazet2a75de02008-01-05 23:08:49 -08001717#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001718 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
1719 if (tbl == NULL)
1720 goto err_alloc_ctl;
1721
Eric W. Biederman02291682010-02-14 03:25:51 +00001722 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001723 tbl[0].extra1 = all;
1724 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08001725#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001726 }
1727
1728#ifdef CONFIG_SYSCTL
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001729 err = __devinet_sysctl_register(net, "all", all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001730 if (err < 0)
1731 goto err_reg_all;
1732
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001733 err = __devinet_sysctl_register(net, "default", dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001734 if (err < 0)
1735 goto err_reg_dflt;
1736
1737 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00001738 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001739 if (forw_hdr == NULL)
1740 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08001741 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001742#endif
1743
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001744 net->ipv4.devconf_all = all;
1745 net->ipv4.devconf_dflt = dflt;
1746 return 0;
1747
1748#ifdef CONFIG_SYSCTL
1749err_reg_ctl:
1750 __devinet_sysctl_unregister(dflt);
1751err_reg_dflt:
1752 __devinet_sysctl_unregister(all);
1753err_reg_all:
1754 if (tbl != ctl_forward_entry)
1755 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001756err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08001757#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001758 if (dflt != &ipv4_devconf_dflt)
1759 kfree(dflt);
1760err_alloc_dflt:
1761 if (all != &ipv4_devconf)
1762 kfree(all);
1763err_alloc_all:
1764 return err;
1765}
1766
1767static __net_exit void devinet_exit_net(struct net *net)
1768{
Eric Dumazet2a75de02008-01-05 23:08:49 -08001769#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001770 struct ctl_table *tbl;
1771
1772 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001773 unregister_net_sysctl_table(net->ipv4.forw_hdr);
1774 __devinet_sysctl_unregister(net->ipv4.devconf_dflt);
1775 __devinet_sysctl_unregister(net->ipv4.devconf_all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001776 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08001777#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001778 kfree(net->ipv4.devconf_dflt);
1779 kfree(net->ipv4.devconf_all);
1780}
1781
1782static __net_initdata struct pernet_operations devinet_ops = {
1783 .init = devinet_init_net,
1784 .exit = devinet_exit_net,
1785};
1786
Thomas Graf9f0f7272010-11-16 04:32:48 +00001787static struct rtnl_af_ops inet_af_ops = {
1788 .family = AF_INET,
1789 .fill_link_af = inet_fill_link_af,
1790 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001791 .validate_link_af = inet_validate_link_af,
1792 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00001793};
1794
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795void __init devinet_init(void)
1796{
David S. Millerfd23c3b2011-02-18 12:42:28 -08001797 int i;
1798
1799 for (i = 0; i < IN4_ADDR_HSIZE; i++)
1800 INIT_HLIST_HEAD(&inet_addr_lst[i]);
1801
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001802 register_pernet_subsys(&devinet_ops);
1803
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 register_gifconf(PF_INET, inet_gifconf);
1805 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07001806
Thomas Graf9f0f7272010-11-16 04:32:48 +00001807 rtnl_af_register(&inet_af_ops);
1808
Greg Rosec7ac8672011-06-10 01:27:09 +00001809 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL);
1810 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, NULL);
1811 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812}
1813