blob: 1b7f7ae8514a5a08ee10e94cfb234686bc3182a9 [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>
Nicolas Dichteledc9e742012-10-25 22:28:52 +000058#include <linux/netconf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
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>
Jiri Pirko5c766d62013-01-24 09:41:41 +000066#include <net/addrconf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
David S. Miller406b6f92011-03-22 21:56:23 -070068#include "fib_lookup.h"
69
Adrian Bunk0027ba82008-01-31 17:17:31 -080070static struct ipv4_devconf ipv4_devconf = {
Herbert Xu42f811b2007-06-04 23:34:44 -070071 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000072 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
73 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
74 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
75 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
Herbert Xu42f811b2007-06-04 23:34:44 -070076 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070077};
78
79static struct ipv4_devconf ipv4_devconf_dflt = {
Herbert Xu42f811b2007-06-04 23:34:44 -070080 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000081 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
82 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
83 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
84 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
85 [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
Herbert Xu42f811b2007-06-04 23:34:44 -070086 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070087};
88
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -080089#define IPV4_DEVCONF_DFLT(net, attr) \
90 IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr)
Herbert Xu42f811b2007-06-04 23:34:44 -070091
Patrick McHardyef7c79e2007-06-05 12:38:30 -070092static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
Thomas Graf5c753972006-08-04 23:03:53 -070093 [IFA_LOCAL] = { .type = NLA_U32 },
94 [IFA_ADDRESS] = { .type = NLA_U32 },
95 [IFA_BROADCAST] = { .type = NLA_U32 },
Thomas Graf5176f912006-08-26 20:13:18 -070096 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
Jiri Pirko5c766d62013-01-24 09:41:41 +000097 [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
Thomas Graf5c753972006-08-04 23:03:53 -070098};
99
Eric Dumazet40384992012-08-03 21:06:50 +0000100#define IN4_ADDR_HSIZE_SHIFT 8
101#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT)
102
David S. Millerfd23c3b2011-02-18 12:42:28 -0800103static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
104static DEFINE_SPINLOCK(inet_addr_hash_lock);
105
Eric Dumazet40384992012-08-03 21:06:50 +0000106static u32 inet_addr_hash(struct net *net, __be32 addr)
David S. Millerfd23c3b2011-02-18 12:42:28 -0800107{
Eric Dumazet40384992012-08-03 21:06:50 +0000108 u32 val = (__force u32) addr ^ net_hash_mix(net);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800109
Eric Dumazet40384992012-08-03 21:06:50 +0000110 return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800111}
112
113static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
114{
Eric Dumazet40384992012-08-03 21:06:50 +0000115 u32 hash = inet_addr_hash(net, ifa->ifa_local);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800116
117 spin_lock(&inet_addr_hash_lock);
118 hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
119 spin_unlock(&inet_addr_hash_lock);
120}
121
122static void inet_hash_remove(struct in_ifaddr *ifa)
123{
124 spin_lock(&inet_addr_hash_lock);
125 hlist_del_init_rcu(&ifa->hash);
126 spin_unlock(&inet_addr_hash_lock);
127}
128
David S. Miller9435eb12011-02-18 12:43:09 -0800129/**
130 * __ip_dev_find - find the first device with a given source address.
131 * @net: the net namespace
132 * @addr: the source address
133 * @devref: if true, take a reference on the found device
134 *
135 * If a caller uses devref=false, it should be protected by RCU, or RTNL
136 */
137struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
138{
Eric Dumazet40384992012-08-03 21:06:50 +0000139 u32 hash = inet_addr_hash(net, addr);
David S. Miller9435eb12011-02-18 12:43:09 -0800140 struct net_device *result = NULL;
141 struct in_ifaddr *ifa;
David S. Miller9435eb12011-02-18 12:43:09 -0800142
143 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800144 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash) {
David S. Millere0660082011-03-03 11:24:19 -0800145 if (ifa->ifa_local == addr) {
Eric Dumazet40384992012-08-03 21:06:50 +0000146 struct net_device *dev = ifa->ifa_dev->dev;
147
148 if (!net_eq(dev_net(dev), net))
149 continue;
David S. Miller9435eb12011-02-18 12:43:09 -0800150 result = dev;
151 break;
152 }
153 }
David S. Miller406b6f92011-03-22 21:56:23 -0700154 if (!result) {
155 struct flowi4 fl4 = { .daddr = addr };
156 struct fib_result res = { 0 };
157 struct fib_table *local;
158
159 /* Fallback to FIB local table so that communication
160 * over loopback subnets work.
161 */
162 local = fib_get_table(net, RT_TABLE_LOCAL);
163 if (local &&
164 !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
165 res.type == RTN_LOCAL)
166 result = FIB_RES_DEV(res);
167 }
David S. Miller9435eb12011-02-18 12:43:09 -0800168 if (result && devref)
169 dev_hold(result);
170 rcu_read_unlock();
171 return result;
172}
173EXPORT_SYMBOL(__ip_dev_find);
174
Thomas Grafd6062cb2006-08-15 00:33:59 -0700175static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
Alan Sterne041c682006-03-27 01:16:30 -0800177static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
179 int destroy);
180#ifdef CONFIG_SYSCTL
Pavel Emelyanov66f27a52007-12-02 00:55:54 +1100181static void devinet_sysctl_register(struct in_device *idev);
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800182static void devinet_sysctl_unregister(struct in_device *idev);
183#else
Eric Dumazet40384992012-08-03 21:06:50 +0000184static void devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800185{
186}
Eric Dumazet40384992012-08-03 21:06:50 +0000187static void devinet_sysctl_unregister(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800188{
189}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190#endif
191
192/* Locks all the inet devices. */
193
194static struct in_ifaddr *inet_alloc_ifa(void)
195{
Alexey Dobriyan93adcc82008-10-28 13:25:09 -0700196 return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197}
198
199static void inet_rcu_free_ifa(struct rcu_head *head)
200{
201 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
202 if (ifa->ifa_dev)
203 in_dev_put(ifa->ifa_dev);
204 kfree(ifa);
205}
206
Eric Dumazet40384992012-08-03 21:06:50 +0000207static void inet_free_ifa(struct in_ifaddr *ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
209 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
210}
211
212void in_dev_finish_destroy(struct in_device *idev)
213{
214 struct net_device *dev = idev->dev;
215
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700216 WARN_ON(idev->ifa_list);
217 WARN_ON(idev->mc_list);
Eric Dumazete9897072013-06-07 08:48:57 -0700218 kfree(rcu_dereference_protected(idev->mc_hash, 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219#ifdef NET_REFCNT_DEBUG
Joe Perches91df42b2012-05-15 14:11:54 +0000220 pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221#endif
222 dev_put(dev);
223 if (!idev->dead)
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800224 pr_err("Freeing alive in_device %p\n", idev);
225 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 kfree(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800228EXPORT_SYMBOL(in_dev_finish_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
Herbert Xu71e27da2007-06-04 23:36:06 -0700230static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
232 struct in_device *in_dev;
233
234 ASSERT_RTNL();
235
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700236 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 if (!in_dev)
238 goto out;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900239 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -0800240 sizeof(in_dev->cnf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 in_dev->cnf.sysctl = NULL;
242 in_dev->dev = dev;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800243 in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
244 if (!in_dev->arp_parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 goto out_kfree;
Ben Hutchings0187bdf2008-06-19 16:15:47 -0700246 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
247 dev_disable_lro(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 /* Reference in_dev->dev */
249 dev_hold(dev);
David L Stevens30c4cf52007-01-04 12:31:14 -0800250 /* Account for reference dev->ip_ptr (below) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 in_dev_hold(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
Pavel Emelyanov66f27a52007-12-02 00:55:54 +1100253 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 ip_mc_init_dev(in_dev);
255 if (dev->flags & IFF_UP)
256 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800257
David L Stevens30c4cf52007-01-04 12:31:14 -0800258 /* we can receive as soon as ip_ptr is set -- do this last */
Eric Dumazetcf778b02012-01-12 04:41:32 +0000259 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800260out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 return in_dev;
262out_kfree:
263 kfree(in_dev);
264 in_dev = NULL;
265 goto out;
266}
267
268static void in_dev_rcu_put(struct rcu_head *head)
269{
270 struct in_device *idev = container_of(head, struct in_device, rcu_head);
271 in_dev_put(idev);
272}
273
274static void inetdev_destroy(struct in_device *in_dev)
275{
276 struct in_ifaddr *ifa;
277 struct net_device *dev;
278
279 ASSERT_RTNL();
280
281 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
283 in_dev->dead = 1;
284
285 ip_mc_destroy_dev(in_dev);
286
287 while ((ifa = in_dev->ifa_list) != NULL) {
288 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
289 inet_free_ifa(ifa);
290 }
291
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000292 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800294 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
296 arp_ifdown(dev);
297
298 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
299}
300
Al Viroff428d72006-09-26 22:13:35 -0700301int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302{
303 rcu_read_lock();
304 for_primary_ifa(in_dev) {
305 if (inet_ifa_match(a, ifa)) {
306 if (!b || inet_ifa_match(b, ifa)) {
307 rcu_read_unlock();
308 return 1;
309 }
310 }
311 } endfor_ifa(in_dev);
312 rcu_read_unlock();
313 return 0;
314}
315
Thomas Grafd6062cb2006-08-15 00:33:59 -0700316static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000317 int destroy, struct nlmsghdr *nlh, u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
Harald Welte8f937c62005-05-29 20:23:46 -0700319 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800320 struct in_ifaddr *ifa, *ifa1 = *ifap;
321 struct in_ifaddr *last_prim = in_dev->ifa_list;
322 struct in_ifaddr *prev_prom = NULL;
323 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325 ASSERT_RTNL();
326
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900327 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700328 * unless alias promotion is set
329 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
333
334 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900335 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800336 ifa1->ifa_scope <= ifa->ifa_scope)
337 last_prim = ifa;
338
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
340 ifa1->ifa_mask != ifa->ifa_mask ||
341 !inet_ifa_match(ifa1->ifa_address, ifa)) {
342 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800343 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 continue;
345 }
346
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800347 if (!do_promote) {
David S. Millerfd23c3b2011-02-18 12:42:28 -0800348 inet_hash_remove(ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700349 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Eric W. Biederman15e47302012-09-07 20:12:54 +0000351 rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800352 blocking_notifier_call_chain(&inetaddr_chain,
353 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700354 inet_free_ifa(ifa);
355 } else {
356 promote = ifa;
357 break;
358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 }
360 }
361
Julian Anastasov2d230e22011-03-19 12:13:52 +0000362 /* On promotion all secondaries from subnet are changing
363 * the primary IP, we must remove all their routes silently
364 * and later to add them back with new prefsrc. Do this
365 * while all addresses are on the device list.
366 */
367 for (ifa = promote; ifa; ifa = ifa->ifa_next) {
368 if (ifa1->ifa_mask == ifa->ifa_mask &&
369 inet_ifa_match(ifa1->ifa_address, ifa))
370 fib_del_ifaddr(ifa, ifa1);
371 }
372
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 /* 2. Unlink it */
374
375 *ifap = ifa1->ifa_next;
David S. Millerfd23c3b2011-02-18 12:42:28 -0800376 inet_hash_remove(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
378 /* 3. Announce address deletion */
379
380 /* Send message first, then call notifier.
381 At first sight, FIB update triggered by notifier
382 will refer to already deleted ifaddr, that could confuse
383 netlink listeners. It is not true: look, gated sees
384 that route deleted and if it still thinks that ifaddr
385 is valid, it will try to restore deleted routes... Grr.
386 So that, this order is correct.
387 */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000388 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800389 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800390
391 if (promote) {
Julian Anastasov04024b92011-03-19 12:13:54 +0000392 struct in_ifaddr *next_sec = promote->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800393
394 if (prev_prom) {
395 prev_prom->ifa_next = promote->ifa_next;
396 promote->ifa_next = last_prim->ifa_next;
397 last_prim->ifa_next = promote;
398 }
399
400 promote->ifa_flags &= ~IFA_F_SECONDARY;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000401 rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800402 blocking_notifier_call_chain(&inetaddr_chain,
403 NETDEV_UP, promote);
Julian Anastasov04024b92011-03-19 12:13:54 +0000404 for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800405 if (ifa1->ifa_mask != ifa->ifa_mask ||
406 !inet_ifa_match(ifa1->ifa_address, ifa))
407 continue;
408 fib_add_ifaddr(ifa);
409 }
410
411 }
Herbert Xu63630972007-06-07 18:35:38 -0700412 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414}
415
Thomas Grafd6062cb2006-08-15 00:33:59 -0700416static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
417 int destroy)
418{
419 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
420}
421
Jiri Pirko5c766d62013-01-24 09:41:41 +0000422static void check_lifetime(struct work_struct *work);
423
424static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
425
Thomas Grafd6062cb2006-08-15 00:33:59 -0700426static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000427 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428{
429 struct in_device *in_dev = ifa->ifa_dev;
430 struct in_ifaddr *ifa1, **ifap, **last_primary;
431
432 ASSERT_RTNL();
433
434 if (!ifa->ifa_local) {
435 inet_free_ifa(ifa);
436 return 0;
437 }
438
439 ifa->ifa_flags &= ~IFA_F_SECONDARY;
440 last_primary = &in_dev->ifa_list;
441
442 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
443 ifap = &ifa1->ifa_next) {
444 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
445 ifa->ifa_scope <= ifa1->ifa_scope)
446 last_primary = &ifa1->ifa_next;
447 if (ifa1->ifa_mask == ifa->ifa_mask &&
448 inet_ifa_match(ifa1->ifa_address, ifa)) {
449 if (ifa1->ifa_local == ifa->ifa_local) {
450 inet_free_ifa(ifa);
451 return -EEXIST;
452 }
453 if (ifa1->ifa_scope != ifa->ifa_scope) {
454 inet_free_ifa(ifa);
455 return -EINVAL;
456 }
457 ifa->ifa_flags |= IFA_F_SECONDARY;
458 }
459 }
460
461 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
462 net_srandom(ifa->ifa_local);
463 ifap = last_primary;
464 }
465
466 ifa->ifa_next = *ifap;
467 *ifap = ifa;
468
David S. Millerfd23c3b2011-02-18 12:42:28 -0800469 inet_hash_insert(dev_net(in_dev->dev), ifa);
470
Jiri Pirko5c766d62013-01-24 09:41:41 +0000471 cancel_delayed_work(&check_lifetime_work);
472 schedule_delayed_work(&check_lifetime_work, 0);
473
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 /* Send message first, then call notifier.
475 Notifier will trigger FIB update, so that
476 listeners of netlink will know about new ifaddr */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000477 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800478 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
480 return 0;
481}
482
Thomas Grafd6062cb2006-08-15 00:33:59 -0700483static int inet_insert_ifa(struct in_ifaddr *ifa)
484{
485 return __inet_insert_ifa(ifa, NULL, 0);
486}
487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
489{
Herbert Xue5ed6392005-10-03 14:35:55 -0700490 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
492 ASSERT_RTNL();
493
494 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700495 inet_free_ifa(ifa);
496 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700498 ipv4_devconf_setall(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700500 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 in_dev_hold(in_dev);
502 ifa->ifa_dev = in_dev;
503 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800504 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 ifa->ifa_scope = RT_SCOPE_HOST;
506 return inet_insert_ifa(ifa);
507}
508
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000509/* Caller must hold RCU or RTNL :
510 * We dont take a reference on found in_device
511 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800512struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513{
514 struct net_device *dev;
515 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000516
517 rcu_read_lock();
518 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000520 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000521 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 return in_dev;
523}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800524EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
526/* Called only from RTNL semaphored context. No locks. */
527
Al Viro60cad5d2006-09-26 22:17:09 -0700528struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
529 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530{
531 ASSERT_RTNL();
532
533 for_primary_ifa(in_dev) {
534 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
535 return ifa;
536 } endfor_ifa(in_dev);
537 return NULL;
538}
539
Thomas Graf661d2962013-03-21 07:45:29 +0000540static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900542 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700543 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700545 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700547 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549 ASSERT_RTNL();
550
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700551 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
552 if (err < 0)
553 goto errout;
554
555 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800556 in_dev = inetdev_by_index(net, ifm->ifa_index);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700557 if (in_dev == NULL) {
558 err = -ENODEV;
559 goto errout;
560 }
561
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
563 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700564 if (tb[IFA_LOCAL] &&
Al Viroa7a628c2006-09-26 22:16:43 -0700565 ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700567
568 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
569 continue;
570
571 if (tb[IFA_ADDRESS] &&
572 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Al Viroa7a628c2006-09-26 22:16:43 -0700573 !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700574 continue;
575
Eric W. Biederman15e47302012-09-07 20:12:54 +0000576 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 return 0;
578 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700579
580 err = -EADDRNOTAVAIL;
581errout:
582 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583}
584
Jiri Pirko5c766d62013-01-24 09:41:41 +0000585#define INFINITY_LIFE_TIME 0xFFFFFFFF
586
587static void check_lifetime(struct work_struct *work)
588{
589 unsigned long now, next, next_sec, next_sched;
590 struct in_ifaddr *ifa;
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000591 struct hlist_node *n;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000592 int i;
593
594 now = jiffies;
595 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
596
Jiri Pirko5c766d62013-01-24 09:41:41 +0000597 for (i = 0; i < IN4_ADDR_HSIZE; i++) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000598 bool change_needed = false;
599
600 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800601 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
Jiri Pirko5c766d62013-01-24 09:41:41 +0000602 unsigned long age;
603
604 if (ifa->ifa_flags & IFA_F_PERMANENT)
605 continue;
606
607 /* We try to batch several events at once. */
608 age = (now - ifa->ifa_tstamp +
609 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
610
611 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
612 age >= ifa->ifa_valid_lft) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000613 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000614 } else if (ifa->ifa_preferred_lft ==
615 INFINITY_LIFE_TIME) {
616 continue;
617 } else if (age >= ifa->ifa_preferred_lft) {
618 if (time_before(ifa->ifa_tstamp +
619 ifa->ifa_valid_lft * HZ, next))
620 next = ifa->ifa_tstamp +
621 ifa->ifa_valid_lft * HZ;
622
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000623 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
624 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000625 } else if (time_before(ifa->ifa_tstamp +
626 ifa->ifa_preferred_lft * HZ,
627 next)) {
628 next = ifa->ifa_tstamp +
629 ifa->ifa_preferred_lft * HZ;
630 }
631 }
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000632 rcu_read_unlock();
633 if (!change_needed)
634 continue;
635 rtnl_lock();
636 hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
637 unsigned long age;
638
639 if (ifa->ifa_flags & IFA_F_PERMANENT)
640 continue;
641
642 /* We try to batch several events at once. */
643 age = (now - ifa->ifa_tstamp +
644 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
645
646 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
647 age >= ifa->ifa_valid_lft) {
648 struct in_ifaddr **ifap;
649
650 for (ifap = &ifa->ifa_dev->ifa_list;
651 *ifap != NULL; ifap = &(*ifap)->ifa_next) {
652 if (*ifap == ifa) {
653 inet_del_ifa(ifa->ifa_dev,
654 ifap, 1);
655 break;
656 }
657 }
658 } else if (ifa->ifa_preferred_lft !=
659 INFINITY_LIFE_TIME &&
660 age >= ifa->ifa_preferred_lft &&
661 !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
662 ifa->ifa_flags |= IFA_F_DEPRECATED;
663 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
664 }
665 }
666 rtnl_unlock();
Jiri Pirko5c766d62013-01-24 09:41:41 +0000667 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000668
669 next_sec = round_jiffies_up(next);
670 next_sched = next;
671
672 /* If rounded timeout is accurate enough, accept it. */
673 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
674 next_sched = next_sec;
675
676 now = jiffies;
677 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
678 if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
679 next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
680
681 schedule_delayed_work(&check_lifetime_work, next_sched - now);
682}
683
684static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
685 __u32 prefered_lft)
686{
687 unsigned long timeout;
688
689 ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
690
691 timeout = addrconf_timeout_fixup(valid_lft, HZ);
692 if (addrconf_finite_timeout(timeout))
693 ifa->ifa_valid_lft = timeout;
694 else
695 ifa->ifa_flags |= IFA_F_PERMANENT;
696
697 timeout = addrconf_timeout_fixup(prefered_lft, HZ);
698 if (addrconf_finite_timeout(timeout)) {
699 if (timeout == 0)
700 ifa->ifa_flags |= IFA_F_DEPRECATED;
701 ifa->ifa_preferred_lft = timeout;
702 }
703 ifa->ifa_tstamp = jiffies;
704 if (!ifa->ifa_cstamp)
705 ifa->ifa_cstamp = ifa->ifa_tstamp;
706}
707
708static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
709 __u32 *pvalid_lft, __u32 *pprefered_lft)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710{
Thomas Graf5c753972006-08-04 23:03:53 -0700711 struct nlattr *tb[IFA_MAX+1];
712 struct in_ifaddr *ifa;
713 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 struct net_device *dev;
715 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800716 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
Thomas Graf5c753972006-08-04 23:03:53 -0700718 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
719 if (err < 0)
720 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
Thomas Graf5c753972006-08-04 23:03:53 -0700722 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800723 err = -EINVAL;
724 if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700725 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800727 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800728 err = -ENODEV;
729 if (dev == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700730 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
Thomas Graf5c753972006-08-04 23:03:53 -0700732 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800733 err = -ENOBUFS;
734 if (in_dev == NULL)
Herbert Xu71e27da2007-06-04 23:36:06 -0700735 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
Thomas Graf5c753972006-08-04 23:03:53 -0700737 ifa = inet_alloc_ifa();
Denis V. Lunev7b218572008-01-31 18:47:00 -0800738 if (ifa == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700739 /*
740 * A potential indev allocation can be left alive, it stays
741 * assigned to its device and is destroy with it.
742 */
Thomas Graf5c753972006-08-04 23:03:53 -0700743 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700744
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800745 ipv4_devconf_setall(in_dev);
Thomas Graf5c753972006-08-04 23:03:53 -0700746 in_dev_hold(in_dev);
747
748 if (tb[IFA_ADDRESS] == NULL)
749 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
750
David S. Millerfd23c3b2011-02-18 12:42:28 -0800751 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
753 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 ifa->ifa_flags = ifm->ifa_flags;
755 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700756 ifa->ifa_dev = in_dev;
757
Al Viroa7a628c2006-09-26 22:16:43 -0700758 ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]);
759 ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700760
761 if (tb[IFA_BROADCAST])
Al Viroa7a628c2006-09-26 22:16:43 -0700762 ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700763
Thomas Graf5c753972006-08-04 23:03:53 -0700764 if (tb[IFA_LABEL])
765 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 else
767 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
768
Jiri Pirko5c766d62013-01-24 09:41:41 +0000769 if (tb[IFA_CACHEINFO]) {
770 struct ifa_cacheinfo *ci;
771
772 ci = nla_data(tb[IFA_CACHEINFO]);
773 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
774 err = -EINVAL;
775 goto errout;
776 }
777 *pvalid_lft = ci->ifa_valid;
778 *pprefered_lft = ci->ifa_prefered;
779 }
780
Thomas Graf5c753972006-08-04 23:03:53 -0700781 return ifa;
782
783errout:
784 return ERR_PTR(err);
785}
786
Jiri Pirko5c766d62013-01-24 09:41:41 +0000787static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
788{
789 struct in_device *in_dev = ifa->ifa_dev;
790 struct in_ifaddr *ifa1, **ifap;
791
792 if (!ifa->ifa_local)
793 return NULL;
794
795 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
796 ifap = &ifa1->ifa_next) {
797 if (ifa1->ifa_mask == ifa->ifa_mask &&
798 inet_ifa_match(ifa1->ifa_address, ifa) &&
799 ifa1->ifa_local == ifa->ifa_local)
800 return ifa1;
801 }
802 return NULL;
803}
804
Thomas Graf661d2962013-03-21 07:45:29 +0000805static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
Thomas Graf5c753972006-08-04 23:03:53 -0700806{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900807 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700808 struct in_ifaddr *ifa;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000809 struct in_ifaddr *ifa_existing;
810 __u32 valid_lft = INFINITY_LIFE_TIME;
811 __u32 prefered_lft = INFINITY_LIFE_TIME;
Thomas Graf5c753972006-08-04 23:03:53 -0700812
813 ASSERT_RTNL();
814
Jiri Pirko5c766d62013-01-24 09:41:41 +0000815 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft);
Thomas Graf5c753972006-08-04 23:03:53 -0700816 if (IS_ERR(ifa))
817 return PTR_ERR(ifa);
818
Jiri Pirko5c766d62013-01-24 09:41:41 +0000819 ifa_existing = find_matching_ifa(ifa);
820 if (!ifa_existing) {
821 /* It would be best to check for !NLM_F_CREATE here but
822 * userspace alreay relies on not having to provide this.
823 */
824 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
825 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
826 } else {
827 inet_free_ifa(ifa);
828
829 if (nlh->nlmsg_flags & NLM_F_EXCL ||
830 !(nlh->nlmsg_flags & NLM_F_REPLACE))
831 return -EEXIST;
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000832 ifa = ifa_existing;
833 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Jiri Pirko05a324b2013-04-04 23:39:38 +0000834 cancel_delayed_work(&check_lifetime_work);
835 schedule_delayed_work(&check_lifetime_work, 0);
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000836 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
837 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000838 }
839 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840}
841
842/*
843 * Determine a default network mask, based on the IP address.
844 */
845
Eric Dumazet40384992012-08-03 21:06:50 +0000846static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847{
848 int rc = -1; /* Something else, probably a multicast. */
849
Joe Perchesf97c1e02007-12-16 13:45:43 -0800850 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900851 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 else {
Al Viro714e85b2006-11-14 20:51:49 -0800853 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854
Al Viro714e85b2006-11-14 20:51:49 -0800855 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800857 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800859 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 rc = 24;
861 }
862
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900863 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864}
865
866
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800867int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868{
869 struct ifreq ifr;
870 struct sockaddr_in sin_orig;
871 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
872 struct in_device *in_dev;
873 struct in_ifaddr **ifap = NULL;
874 struct in_ifaddr *ifa = NULL;
875 struct net_device *dev;
876 char *colon;
877 int ret = -EFAULT;
878 int tryaddrmatch = 0;
879
880 /*
881 * Fetch the caller's info block into kernel space
882 */
883
884 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
885 goto out;
886 ifr.ifr_name[IFNAMSIZ - 1] = 0;
887
888 /* save original address for comparison */
889 memcpy(&sin_orig, sin, sizeof(*sin));
890
891 colon = strchr(ifr.ifr_name, ':');
892 if (colon)
893 *colon = 0;
894
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800895 dev_load(net, ifr.ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896
Stephen Hemminger132adf52007-03-08 20:44:43 -0800897 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 case SIOCGIFADDR: /* Get interface address */
899 case SIOCGIFBRDADDR: /* Get the broadcast address */
900 case SIOCGIFDSTADDR: /* Get the destination address */
901 case SIOCGIFNETMASK: /* Get the netmask for the interface */
902 /* Note that these ioctls will not sleep,
903 so that we do not impose a lock.
904 One day we will be forced to put shlock here (I mean SMP)
905 */
906 tryaddrmatch = (sin_orig.sin_family == AF_INET);
907 memset(sin, 0, sizeof(*sin));
908 sin->sin_family = AF_INET;
909 break;
910
911 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000912 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000913 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 goto out;
915 break;
916 case SIOCSIFADDR: /* Set interface address (and family) */
917 case SIOCSIFBRDADDR: /* Set the broadcast address */
918 case SIOCSIFDSTADDR: /* Set the destination address */
919 case SIOCSIFNETMASK: /* Set the netmask for the interface */
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000920 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000921 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 goto out;
923 ret = -EINVAL;
924 if (sin->sin_family != AF_INET)
925 goto out;
926 break;
927 default:
928 ret = -EINVAL;
929 goto out;
930 }
931
932 rtnl_lock();
933
934 ret = -ENODEV;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800935 dev = __dev_get_by_name(net, ifr.ifr_name);
936 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 goto done;
938
939 if (colon)
940 *colon = ':';
941
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800942 in_dev = __in_dev_get_rtnl(dev);
943 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 if (tryaddrmatch) {
945 /* Matthias Andree */
946 /* compare label and address (4.4BSD style) */
947 /* note: we only do this for a limited set of ioctls
948 and only if the original address family was AF_INET.
949 This is checked above. */
950 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
951 ifap = &ifa->ifa_next) {
952 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
953 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -0800954 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 break; /* found */
956 }
957 }
958 }
959 /* we didn't get a match, maybe the application is
960 4.3BSD-style and passed in junk so we fall back to
961 comparing just the label */
962 if (!ifa) {
963 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
964 ifap = &ifa->ifa_next)
965 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
966 break;
967 }
968 }
969
970 ret = -EADDRNOTAVAIL;
971 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
972 goto done;
973
Stephen Hemminger132adf52007-03-08 20:44:43 -0800974 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 case SIOCGIFADDR: /* Get interface address */
976 sin->sin_addr.s_addr = ifa->ifa_local;
977 goto rarok;
978
979 case SIOCGIFBRDADDR: /* Get the broadcast address */
980 sin->sin_addr.s_addr = ifa->ifa_broadcast;
981 goto rarok;
982
983 case SIOCGIFDSTADDR: /* Get the destination address */
984 sin->sin_addr.s_addr = ifa->ifa_address;
985 goto rarok;
986
987 case SIOCGIFNETMASK: /* Get the netmask for the interface */
988 sin->sin_addr.s_addr = ifa->ifa_mask;
989 goto rarok;
990
991 case SIOCSIFFLAGS:
992 if (colon) {
993 ret = -EADDRNOTAVAIL;
994 if (!ifa)
995 break;
996 ret = 0;
997 if (!(ifr.ifr_flags & IFF_UP))
998 inet_del_ifa(in_dev, ifap, 1);
999 break;
1000 }
1001 ret = dev_change_flags(dev, ifr.ifr_flags);
1002 break;
1003
1004 case SIOCSIFADDR: /* Set interface address (and family) */
1005 ret = -EINVAL;
1006 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1007 break;
1008
1009 if (!ifa) {
1010 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001011 ifa = inet_alloc_ifa();
1012 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 break;
Xi Wangc7e2e1d2013-01-05 11:19:24 +00001014 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 if (colon)
1016 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
1017 else
1018 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1019 } else {
1020 ret = 0;
1021 if (ifa->ifa_local == sin->sin_addr.s_addr)
1022 break;
1023 inet_del_ifa(in_dev, ifap, 0);
1024 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -08001025 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 }
1027
1028 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
1029
1030 if (!(dev->flags & IFF_POINTOPOINT)) {
1031 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
1032 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
1033 if ((dev->flags & IFF_BROADCAST) &&
1034 ifa->ifa_prefixlen < 31)
1035 ifa->ifa_broadcast = ifa->ifa_address |
1036 ~ifa->ifa_mask;
1037 } else {
1038 ifa->ifa_prefixlen = 32;
1039 ifa->ifa_mask = inet_make_mask(32);
1040 }
Jiri Pirko5c766d62013-01-24 09:41:41 +00001041 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 ret = inet_set_ifa(dev, ifa);
1043 break;
1044
1045 case SIOCSIFBRDADDR: /* Set the broadcast address */
1046 ret = 0;
1047 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
1048 inet_del_ifa(in_dev, ifap, 0);
1049 ifa->ifa_broadcast = sin->sin_addr.s_addr;
1050 inet_insert_ifa(ifa);
1051 }
1052 break;
1053
1054 case SIOCSIFDSTADDR: /* Set the destination address */
1055 ret = 0;
1056 if (ifa->ifa_address == sin->sin_addr.s_addr)
1057 break;
1058 ret = -EINVAL;
1059 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1060 break;
1061 ret = 0;
1062 inet_del_ifa(in_dev, ifap, 0);
1063 ifa->ifa_address = sin->sin_addr.s_addr;
1064 inet_insert_ifa(ifa);
1065 break;
1066
1067 case SIOCSIFNETMASK: /* Set the netmask for the interface */
1068
1069 /*
1070 * The mask we set must be legal.
1071 */
1072 ret = -EINVAL;
1073 if (bad_mask(sin->sin_addr.s_addr, 0))
1074 break;
1075 ret = 0;
1076 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -07001077 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 inet_del_ifa(in_dev, ifap, 0);
1079 ifa->ifa_mask = sin->sin_addr.s_addr;
1080 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
1081
1082 /* See if current broadcast address matches
1083 * with current netmask, then recalculate
1084 * the broadcast address. Otherwise it's a
1085 * funny address, so don't touch it since
1086 * the user seems to know what (s)he's doing...
1087 */
1088 if ((dev->flags & IFF_BROADCAST) &&
1089 (ifa->ifa_prefixlen < 31) &&
1090 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -05001091 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 ifa->ifa_broadcast = (ifa->ifa_local |
1093 ~sin->sin_addr.s_addr);
1094 }
1095 inet_insert_ifa(ifa);
1096 }
1097 break;
1098 }
1099done:
1100 rtnl_unlock();
1101out:
1102 return ret;
1103rarok:
1104 rtnl_unlock();
1105 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
1106 goto out;
1107}
1108
1109static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
1110{
Herbert Xue5ed6392005-10-03 14:35:55 -07001111 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 struct in_ifaddr *ifa;
1113 struct ifreq ifr;
1114 int done = 0;
1115
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001116 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 goto out;
1118
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001119 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 if (!buf) {
1121 done += sizeof(ifr);
1122 continue;
1123 }
1124 if (len < (int) sizeof(ifr))
1125 break;
1126 memset(&ifr, 0, sizeof(struct ifreq));
Dan Carpenter4299c8a2013-07-29 22:15:19 +03001127 strcpy(ifr.ifr_name, ifa->ifa_label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
1129 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
1130 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1131 ifa->ifa_local;
1132
1133 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
1134 done = -EFAULT;
1135 break;
1136 }
1137 buf += sizeof(struct ifreq);
1138 len -= sizeof(struct ifreq);
1139 done += sizeof(struct ifreq);
1140 }
1141out:
1142 return done;
1143}
1144
Al Viroa61ced52006-09-26 21:27:54 -07001145__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146{
Al Viroa61ced52006-09-26 21:27:54 -07001147 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001149 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
1151 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001152 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 if (!in_dev)
1154 goto no_in_dev;
1155
1156 for_primary_ifa(in_dev) {
1157 if (ifa->ifa_scope > scope)
1158 continue;
1159 if (!dst || inet_ifa_match(dst, ifa)) {
1160 addr = ifa->ifa_local;
1161 break;
1162 }
1163 if (!addr)
1164 addr = ifa->ifa_local;
1165 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
1167 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001168 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001169no_in_dev:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170
1171 /* Not loopback addresses on loopback should be preferred
1172 in this case. It is importnat that lo is the first interface
1173 in dev_base list.
1174 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001175 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001176 in_dev = __in_dev_get_rcu(dev);
1177 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 continue;
1179
1180 for_primary_ifa(in_dev) {
1181 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1182 ifa->ifa_scope <= scope) {
1183 addr = ifa->ifa_local;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001184 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 }
1186 } endfor_ifa(in_dev);
1187 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001188out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 return addr;
1191}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001192EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
Al Viro60cad5d2006-09-26 22:17:09 -07001194static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1195 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196{
1197 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001198 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199
1200 for_ifa(in_dev) {
1201 if (!addr &&
1202 (local == ifa->ifa_local || !local) &&
1203 ifa->ifa_scope <= scope) {
1204 addr = ifa->ifa_local;
1205 if (same)
1206 break;
1207 }
1208 if (!same) {
1209 same = (!local || inet_ifa_match(local, ifa)) &&
1210 (!dst || inet_ifa_match(dst, ifa));
1211 if (same && addr) {
1212 if (local || !dst)
1213 break;
1214 /* Is the selected addr into dst subnet? */
1215 if (inet_ifa_match(addr, ifa))
1216 break;
1217 /* No, then can we use new local src? */
1218 if (ifa->ifa_scope <= scope) {
1219 addr = ifa->ifa_local;
1220 break;
1221 }
1222 /* search for large dst subnet for addr */
1223 same = 0;
1224 }
1225 }
1226 } endfor_ifa(in_dev);
1227
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001228 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229}
1230
1231/*
1232 * Confirm that local IP address exists using wildcards:
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001233 * - in_dev: only on this interface, 0=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 * - dst: only in the same subnet as dst, 0=any dst
1235 * - local: address, 0=autoselect the local address
1236 * - scope: maximum allowed scope value for the local address
1237 */
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001238__be32 inet_confirm_addr(struct in_device *in_dev,
1239 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240{
Al Viro60cad5d2006-09-26 22:17:09 -07001241 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001242 struct net_device *dev;
Denis V. Lunev39a6d062008-01-14 23:06:19 -08001243 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
Denis V. Lunev39a6d062008-01-14 23:06:19 -08001245 if (scope != RT_SCOPE_LINK)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001246 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001248 net = dev_net(in_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001250 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001251 in_dev = __in_dev_get_rcu(dev);
1252 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 addr = confirm_addr_indev(in_dev, dst, local, scope);
1254 if (addr)
1255 break;
1256 }
1257 }
1258 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259
1260 return addr;
1261}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001262EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263
1264/*
1265 * Device notifier
1266 */
1267
1268int register_inetaddr_notifier(struct notifier_block *nb)
1269{
Alan Sterne041c682006-03-27 01:16:30 -08001270 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001272EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
1274int unregister_inetaddr_notifier(struct notifier_block *nb)
1275{
Alan Sterne041c682006-03-27 01:16:30 -08001276 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001278EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001280/* Rename ifa_labels for a device name change. Make some effort to preserve
1281 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282*/
1283static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001284{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 struct in_ifaddr *ifa;
1286 int named = 0;
1287
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001288 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1289 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
1291 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001292 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001294 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001295 dot = strchr(old, ':');
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001296 if (dot == NULL) {
1297 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 dot = old;
1299 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001300 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001301 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001302 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001303 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001304skip:
1305 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001306 }
1307}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
Eric Dumazet40384992012-08-03 21:06:50 +00001309static bool inetdev_valid_mtu(unsigned int mtu)
Breno Leitao06770842008-09-02 17:28:58 -07001310{
1311 return mtu >= 68;
1312}
1313
Ian Campbelld11327ad2011-02-11 07:44:16 +00001314static void inetdev_send_gratuitous_arp(struct net_device *dev,
1315 struct in_device *in_dev)
1316
1317{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001318 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001319
Zoltan Kissb76d0782011-07-24 13:09:30 +00001320 for (ifa = in_dev->ifa_list; ifa;
1321 ifa = ifa->ifa_next) {
1322 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1323 ifa->ifa_local, dev,
1324 ifa->ifa_local, NULL,
1325 dev->dev_addr, NULL);
1326 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001327}
1328
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329/* Called only under RTNL semaphore */
1330
1331static int inetdev_event(struct notifier_block *this, unsigned long event,
1332 void *ptr)
1333{
Jiri Pirko351638e2013-05-28 01:30:21 +00001334 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazet748e2d92012-08-22 21:50:59 +00001335 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336
1337 ASSERT_RTNL();
1338
1339 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001340 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 in_dev = inetdev_init(dev);
Herbert Xub217d612007-07-30 17:04:52 -07001342 if (!in_dev)
1343 return notifier_from_errno(-ENOMEM);
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001344 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001345 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1346 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001347 }
Breno Leitao06770842008-09-02 17:28:58 -07001348 } else if (event == NETDEV_CHANGEMTU) {
1349 /* Re-enabling IP */
1350 if (inetdev_valid_mtu(dev->mtu))
1351 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 }
1353 goto out;
1354 }
1355
1356 switch (event) {
1357 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001358 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001359 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 break;
1361 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001362 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001364 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001365 struct in_ifaddr *ifa = inet_alloc_ifa();
1366
1367 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001368 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 ifa->ifa_local =
1370 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1371 ifa->ifa_prefixlen = 8;
1372 ifa->ifa_mask = inet_make_mask(8);
1373 in_dev_hold(in_dev);
1374 ifa->ifa_dev = in_dev;
1375 ifa->ifa_scope = RT_SCOPE_HOST;
1376 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Jiri Pirko5c766d62013-01-24 09:41:41 +00001377 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1378 INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 inet_insert_ifa(ifa);
1380 }
1381 }
1382 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001383 /* fall through */
1384 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001385 if (!IN_DEV_ARP_NOTIFY(in_dev))
1386 break;
1387 /* fall through */
1388 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001389 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001390 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 break;
1392 case NETDEV_DOWN:
1393 ip_mc_down(in_dev);
1394 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001395 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001396 ip_mc_unmap(in_dev);
1397 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001398 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001399 ip_mc_remap(in_dev);
1400 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001402 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 break;
Breno Leitao06770842008-09-02 17:28:58 -07001404 /* disable IP when MTU is not enough */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 case NETDEV_UNREGISTER:
1406 inetdev_destroy(in_dev);
1407 break;
1408 case NETDEV_CHANGENAME:
1409 /* Do not notify about label change, this event is
1410 * not interesting to applications using netlink.
1411 */
1412 inetdev_changename(dev, in_dev);
1413
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001414 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001415 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 break;
1417 }
1418out:
1419 return NOTIFY_DONE;
1420}
1421
1422static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001423 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424};
1425
Eric Dumazet40384992012-08-03 21:06:50 +00001426static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001427{
1428 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1429 + nla_total_size(4) /* IFA_ADDRESS */
1430 + nla_total_size(4) /* IFA_LOCAL */
1431 + nla_total_size(4) /* IFA_BROADCAST */
Thomas Graf339bf982006-11-10 14:10:15 -08001432 + nla_total_size(IFNAMSIZ); /* IFA_LABEL */
1433}
1434
Jiri Pirko5c766d62013-01-24 09:41:41 +00001435static inline u32 cstamp_delta(unsigned long cstamp)
1436{
1437 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1438}
1439
1440static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1441 unsigned long tstamp, u32 preferred, u32 valid)
1442{
1443 struct ifa_cacheinfo ci;
1444
1445 ci.cstamp = cstamp_delta(cstamp);
1446 ci.tstamp = cstamp_delta(tstamp);
1447 ci.ifa_prefered = preferred;
1448 ci.ifa_valid = valid;
1449
1450 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1451}
1452
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001454 u32 portid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455{
1456 struct ifaddrmsg *ifm;
1457 struct nlmsghdr *nlh;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001458 u32 preferred, valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459
Eric W. Biederman15e47302012-09-07 20:12:54 +00001460 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
Thomas Graf47f68512006-08-04 23:04:36 -07001461 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001462 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001463
1464 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 ifm->ifa_family = AF_INET;
1466 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001467 ifm->ifa_flags = ifa->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 ifm->ifa_scope = ifa->ifa_scope;
1469 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470
Jiri Pirko5c766d62013-01-24 09:41:41 +00001471 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1472 preferred = ifa->ifa_preferred_lft;
1473 valid = ifa->ifa_valid_lft;
1474 if (preferred != INFINITY_LIFE_TIME) {
1475 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1476
1477 if (preferred > tval)
1478 preferred -= tval;
1479 else
1480 preferred = 0;
1481 if (valid != INFINITY_LIFE_TIME) {
1482 if (valid > tval)
1483 valid -= tval;
1484 else
1485 valid = 0;
1486 }
1487 }
1488 } else {
1489 preferred = INFINITY_LIFE_TIME;
1490 valid = INFINITY_LIFE_TIME;
1491 }
David S. Millerf3756b72012-04-01 20:39:02 -04001492 if ((ifa->ifa_address &&
1493 nla_put_be32(skb, IFA_ADDRESS, ifa->ifa_address)) ||
1494 (ifa->ifa_local &&
1495 nla_put_be32(skb, IFA_LOCAL, ifa->ifa_local)) ||
1496 (ifa->ifa_broadcast &&
1497 nla_put_be32(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
1498 (ifa->ifa_label[0] &&
Jiri Pirko5c766d62013-01-24 09:41:41 +00001499 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
1500 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1501 preferred, valid))
David S. Millerf3756b72012-04-01 20:39:02 -04001502 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001503
1504 return nlmsg_end(skb, nlh);
1505
1506nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001507 nlmsg_cancel(skb, nlh);
1508 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509}
1510
1511static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1512{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001513 struct net *net = sock_net(skb->sk);
Eric Dumazeteec4df92009-11-12 07:44:25 +00001514 int h, s_h;
1515 int idx, s_idx;
1516 int ip_idx, s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 struct net_device *dev;
1518 struct in_device *in_dev;
1519 struct in_ifaddr *ifa;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001520 struct hlist_head *head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521
Eric Dumazeteec4df92009-11-12 07:44:25 +00001522 s_h = cb->args[0];
1523 s_idx = idx = cb->args[1];
1524 s_ip_idx = ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525
Eric Dumazeteec4df92009-11-12 07:44:25 +00001526 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1527 idx = 0;
1528 head = &net->dev_index_head[h];
1529 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001530 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1531 net->dev_base_seq;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001532 hlist_for_each_entry_rcu(dev, head, index_hlist) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001533 if (idx < s_idx)
1534 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001535 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001536 s_ip_idx = 0;
1537 in_dev = __in_dev_get_rcu(dev);
1538 if (!in_dev)
1539 goto cont;
1540
1541 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1542 ifa = ifa->ifa_next, ip_idx++) {
1543 if (ip_idx < s_ip_idx)
1544 continue;
1545 if (inet_fill_ifaddr(skb, ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001546 NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 cb->nlh->nlmsg_seq,
Eric Dumazeteec4df92009-11-12 07:44:25 +00001548 RTM_NEWADDR, NLM_F_MULTI) <= 0) {
1549 rcu_read_unlock();
1550 goto done;
1551 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001552 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Eric Dumazeteec4df92009-11-12 07:44:25 +00001553 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001554cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001555 idx++;
1556 }
1557 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 }
1559
1560done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001561 cb->args[0] = h;
1562 cb->args[1] = idx;
1563 cb->args[2] = ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564
1565 return skb->len;
1566}
1567
Jianjun Kong539afed2008-11-03 02:48:48 -08001568static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001569 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570{
Thomas Graf47f68512006-08-04 23:04:36 -07001571 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001572 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1573 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001574 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001576 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001577 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Thomas Graf47f68512006-08-04 23:04:36 -07001578 if (skb == NULL)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001579 goto errout;
1580
Eric W. Biederman15e47302012-09-07 20:12:54 +00001581 err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001582 if (err < 0) {
1583 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1584 WARN_ON(err == -EMSGSIZE);
1585 kfree_skb(skb);
1586 goto errout;
1587 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001588 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001589 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001590errout:
1591 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001592 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593}
1594
Thomas Graf9f0f7272010-11-16 04:32:48 +00001595static size_t inet_get_link_af_size(const struct net_device *dev)
1596{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001597 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001598
1599 if (!in_dev)
1600 return 0;
1601
1602 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1603}
1604
1605static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
1606{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001607 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001608 struct nlattr *nla;
1609 int i;
1610
1611 if (!in_dev)
1612 return -ENODATA;
1613
1614 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
1615 if (nla == NULL)
1616 return -EMSGSIZE;
1617
1618 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1619 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1620
1621 return 0;
1622}
1623
1624static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1625 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1626};
1627
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001628static int inet_validate_link_af(const struct net_device *dev,
1629 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001630{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001631 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1632 int err, rem;
1633
Eric Dumazetf7fce742010-12-01 06:03:06 +00001634 if (dev && !__in_dev_get_rtnl(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001635 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001636
1637 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy);
1638 if (err < 0)
1639 return err;
1640
1641 if (tb[IFLA_INET_CONF]) {
1642 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1643 int cfgid = nla_type(a);
1644
1645 if (nla_len(a) < 4)
1646 return -EINVAL;
1647
1648 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1649 return -EINVAL;
1650 }
1651 }
1652
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001653 return 0;
1654}
1655
1656static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1657{
Eric Dumazetf7fce742010-12-01 06:03:06 +00001658 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001659 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1660 int rem;
1661
1662 if (!in_dev)
1663 return -EAFNOSUPPORT;
1664
1665 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL) < 0)
1666 BUG();
1667
Thomas Graf9f0f7272010-11-16 04:32:48 +00001668 if (tb[IFLA_INET_CONF]) {
1669 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1670 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1671 }
1672
1673 return 0;
1674}
1675
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001676static int inet_netconf_msgsize_devconf(int type)
1677{
1678 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1679 + nla_total_size(4); /* NETCONFA_IFINDEX */
1680
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001681 /* type -1 is used for ALL */
1682 if (type == -1 || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001683 size += nla_total_size(4);
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001684 if (type == -1 || type == NETCONFA_RP_FILTER)
1685 size += nla_total_size(4);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001686 if (type == -1 || type == NETCONFA_MC_FORWARDING)
1687 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001688
1689 return size;
1690}
1691
1692static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1693 struct ipv4_devconf *devconf, u32 portid,
1694 u32 seq, int event, unsigned int flags,
1695 int type)
1696{
1697 struct nlmsghdr *nlh;
1698 struct netconfmsg *ncm;
1699
1700 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1701 flags);
1702 if (nlh == NULL)
1703 return -EMSGSIZE;
1704
1705 ncm = nlmsg_data(nlh);
1706 ncm->ncm_family = AF_INET;
1707
1708 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1709 goto nla_put_failure;
1710
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001711 /* type -1 is used for ALL */
1712 if ((type == -1 || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001713 nla_put_s32(skb, NETCONFA_FORWARDING,
1714 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1715 goto nla_put_failure;
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001716 if ((type == -1 || type == NETCONFA_RP_FILTER) &&
1717 nla_put_s32(skb, NETCONFA_RP_FILTER,
1718 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
1719 goto nla_put_failure;
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001720 if ((type == -1 || type == NETCONFA_MC_FORWARDING) &&
1721 nla_put_s32(skb, NETCONFA_MC_FORWARDING,
1722 IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
1723 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001724
1725 return nlmsg_end(skb, nlh);
1726
1727nla_put_failure:
1728 nlmsg_cancel(skb, nlh);
1729 return -EMSGSIZE;
1730}
1731
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001732void inet_netconf_notify_devconf(struct net *net, int type, int ifindex,
1733 struct ipv4_devconf *devconf)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001734{
1735 struct sk_buff *skb;
1736 int err = -ENOBUFS;
1737
1738 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_ATOMIC);
1739 if (skb == NULL)
1740 goto errout;
1741
1742 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
1743 RTM_NEWNETCONF, 0, type);
1744 if (err < 0) {
1745 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1746 WARN_ON(err == -EMSGSIZE);
1747 kfree_skb(skb);
1748 goto errout;
1749 }
1750 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_ATOMIC);
1751 return;
1752errout:
1753 if (err < 0)
1754 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
1755}
1756
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001757static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
1758 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
1759 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001760 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001761};
1762
1763static int inet_netconf_get_devconf(struct sk_buff *in_skb,
Thomas Graf661d2962013-03-21 07:45:29 +00001764 struct nlmsghdr *nlh)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001765{
1766 struct net *net = sock_net(in_skb->sk);
1767 struct nlattr *tb[NETCONFA_MAX+1];
1768 struct netconfmsg *ncm;
1769 struct sk_buff *skb;
1770 struct ipv4_devconf *devconf;
1771 struct in_device *in_dev;
1772 struct net_device *dev;
1773 int ifindex;
1774 int err;
1775
1776 err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
1777 devconf_ipv4_policy);
1778 if (err < 0)
1779 goto errout;
1780
1781 err = EINVAL;
1782 if (!tb[NETCONFA_IFINDEX])
1783 goto errout;
1784
1785 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
1786 switch (ifindex) {
1787 case NETCONFA_IFINDEX_ALL:
1788 devconf = net->ipv4.devconf_all;
1789 break;
1790 case NETCONFA_IFINDEX_DEFAULT:
1791 devconf = net->ipv4.devconf_dflt;
1792 break;
1793 default:
1794 dev = __dev_get_by_index(net, ifindex);
1795 if (dev == NULL)
1796 goto errout;
1797 in_dev = __in_dev_get_rtnl(dev);
1798 if (in_dev == NULL)
1799 goto errout;
1800 devconf = &in_dev->cnf;
1801 break;
1802 }
1803
1804 err = -ENOBUFS;
1805 skb = nlmsg_new(inet_netconf_msgsize_devconf(-1), GFP_ATOMIC);
1806 if (skb == NULL)
1807 goto errout;
1808
1809 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
1810 NETLINK_CB(in_skb).portid,
1811 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
1812 -1);
1813 if (err < 0) {
1814 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1815 WARN_ON(err == -EMSGSIZE);
1816 kfree_skb(skb);
1817 goto errout;
1818 }
1819 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
1820errout:
1821 return err;
1822}
1823
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001824static int inet_netconf_dump_devconf(struct sk_buff *skb,
1825 struct netlink_callback *cb)
1826{
1827 struct net *net = sock_net(skb->sk);
1828 int h, s_h;
1829 int idx, s_idx;
1830 struct net_device *dev;
1831 struct in_device *in_dev;
1832 struct hlist_head *head;
1833
1834 s_h = cb->args[0];
1835 s_idx = idx = cb->args[1];
1836
1837 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1838 idx = 0;
1839 head = &net->dev_index_head[h];
1840 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001841 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1842 net->dev_base_seq;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001843 hlist_for_each_entry_rcu(dev, head, index_hlist) {
1844 if (idx < s_idx)
1845 goto cont;
1846 in_dev = __in_dev_get_rcu(dev);
1847 if (!in_dev)
1848 goto cont;
1849
1850 if (inet_netconf_fill_devconf(skb, dev->ifindex,
1851 &in_dev->cnf,
1852 NETLINK_CB(cb->skb).portid,
1853 cb->nlh->nlmsg_seq,
1854 RTM_NEWNETCONF,
1855 NLM_F_MULTI,
1856 -1) <= 0) {
1857 rcu_read_unlock();
1858 goto done;
1859 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001860 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001861cont:
1862 idx++;
1863 }
1864 rcu_read_unlock();
1865 }
1866 if (h == NETDEV_HASHENTRIES) {
1867 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
1868 net->ipv4.devconf_all,
1869 NETLINK_CB(cb->skb).portid,
1870 cb->nlh->nlmsg_seq,
1871 RTM_NEWNETCONF, NLM_F_MULTI,
1872 -1) <= 0)
1873 goto done;
1874 else
1875 h++;
1876 }
1877 if (h == NETDEV_HASHENTRIES + 1) {
1878 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
1879 net->ipv4.devconf_dflt,
1880 NETLINK_CB(cb->skb).portid,
1881 cb->nlh->nlmsg_seq,
1882 RTM_NEWNETCONF, NLM_F_MULTI,
1883 -1) <= 0)
1884 goto done;
1885 else
1886 h++;
1887 }
1888done:
1889 cb->args[0] = h;
1890 cb->args[1] = idx;
1891
1892 return skb->len;
1893}
1894
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895#ifdef CONFIG_SYSCTL
1896
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001897static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07001898{
1899 struct net_device *dev;
1900
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001901 rcu_read_lock();
1902 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07001903 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001904
Herbert Xu31be3082007-06-04 23:35:37 -07001905 in_dev = __in_dev_get_rcu(dev);
1906 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001907 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07001908 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001909 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07001910}
1911
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001912/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001913static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001914{
1915 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08001916 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001917
Pavel Emelyanov586f1212007-12-16 13:32:48 -08001918 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001919 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001920 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1921 NETCONFA_IFINDEX_ALL,
1922 net->ipv4.devconf_all);
1923 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1924 NETCONFA_IFINDEX_DEFAULT,
1925 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001926
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001927 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001928 struct in_device *in_dev;
Ben Hutchings0187bdf2008-06-19 16:15:47 -07001929 if (on)
1930 dev_disable_lro(dev);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001931 rcu_read_lock();
1932 in_dev = __in_dev_get_rcu(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001933 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001934 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001935 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1936 dev->ifindex, &in_dev->cnf);
1937 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001938 rcu_read_unlock();
1939 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001940}
1941
Joe Perchesfe2c6332013-06-11 23:04:25 -07001942static int devinet_conf_proc(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001943 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07001944 size_t *lenp, loff_t *ppos)
1945{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00001946 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001947 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00001948 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07001949
1950 if (write) {
1951 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001952 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07001953 int i = (int *)ctl->data - cnf->data;
1954
1955 set_bit(i, cnf->state);
1956
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001957 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001958 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00001959 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
1960 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00001961 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00001962 rt_cache_flush(net);
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001963 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
1964 new_value != old_value) {
1965 int ifindex;
1966
1967 if (cnf == net->ipv4.devconf_dflt)
1968 ifindex = NETCONFA_IFINDEX_DEFAULT;
1969 else if (cnf == net->ipv4.devconf_all)
1970 ifindex = NETCONFA_IFINDEX_ALL;
1971 else {
1972 struct in_device *idev =
1973 container_of(cnf, struct in_device,
1974 cnf);
1975 ifindex = idev->dev->ifindex;
1976 }
1977 inet_netconf_notify_devconf(net, NETCONFA_RP_FILTER,
1978 ifindex, cnf);
1979 }
Herbert Xu31be3082007-06-04 23:35:37 -07001980 }
1981
1982 return ret;
1983}
1984
Joe Perchesfe2c6332013-06-11 23:04:25 -07001985static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001986 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 size_t *lenp, loff_t *ppos)
1988{
1989 int *valp = ctl->data;
1990 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00001991 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001992 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993
1994 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001995 struct net *net = ctl->extra2;
1996
Ben Hutchings0187bdf2008-06-19 16:15:47 -07001997 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00001998 if (!rtnl_trylock()) {
1999 /* Restore the original values before restarting */
2000 *valp = val;
2001 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00002002 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00002003 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002004 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2005 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002006 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002007 struct ipv4_devconf *cnf = ctl->extra1;
2008 struct in_device *idev =
2009 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002010 if (*valp)
2011 dev_disable_lro(idev->dev);
2012 inet_netconf_notify_devconf(net,
2013 NETCONFA_FORWARDING,
2014 idev->dev->ifindex,
2015 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002016 }
2017 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002018 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002019 } else
2020 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
2021 NETCONFA_IFINDEX_DEFAULT,
2022 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 }
2024
2025 return ret;
2026}
2027
Joe Perchesfe2c6332013-06-11 23:04:25 -07002028static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
David S. Miller323e1262010-12-12 21:55:08 -08002029 void __user *buffer,
2030 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031{
2032 int *valp = ctl->data;
2033 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002034 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07002035 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036
2037 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002038 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039
2040 return ret;
2041}
2042
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002043#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07002044 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07002045 .procname = name, \
2046 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00002047 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002048 .maxlen = sizeof(int), \
2049 .mode = mval, \
2050 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07002051 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002052 }
2053
2054#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002055 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002056
2057#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002058 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002059
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002060#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2061 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002062
2063#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002064 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07002065
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066static struct devinet_sysctl_table {
2067 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00002068 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069} devinet_sysctl = {
2070 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07002071 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002072 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07002073 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
2074
2075 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
2076 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
2077 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
2078 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
2079 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
2080 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
2081 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00002082 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08002083 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002084 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
2085 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
2086 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
2087 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
2088 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
2089 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
2090 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
2091 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
2092 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08002093 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00002094 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002095
2096 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2097 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
2098 DEVINET_SYSCTL_FLUSHING_ENTRY(FORCE_IGMP_VERSION,
2099 "force_igmp_version"),
2100 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
2101 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00002102 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2103 "route_localnet"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105};
2106
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002107static int __devinet_sysctl_register(struct net *net, char *dev_name,
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002108 struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109{
2110 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002111 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002112 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11002113
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002114 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002116 goto out;
2117
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
2119 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07002120 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002121 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 }
2123
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002124 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002126 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002128 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129
2130 p->sysctl = t;
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002131 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002133free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002135out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002136 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137}
2138
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002139static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
2140{
2141 struct devinet_sysctl_table *t = cnf->sysctl;
2142
2143 if (t == NULL)
2144 return;
2145
2146 cnf->sysctl = NULL;
Lucian Adrian Grijincuff538812011-05-01 01:44:01 +00002147 unregister_net_sysctl_table(t->sysctl_header);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002148 kfree(t);
2149}
2150
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002151static void devinet_sysctl_register(struct in_device *idev)
2152{
Eric W. Biederman54716e32010-02-14 03:27:03 +00002153 neigh_sysctl_register(idev->dev, idev->arp_parms, "ipv4", NULL);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002154 __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002155 &idev->cnf);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002156}
2157
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002158static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159{
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002160 __devinet_sysctl_unregister(&idev->cnf);
2161 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002164static struct ctl_table ctl_forward_entry[] = {
2165 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002166 .procname = "ip_forward",
2167 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00002168 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002169 .maxlen = sizeof(int),
2170 .mode = 0644,
2171 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002172 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002173 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002174 },
2175 { },
2176};
Eric Dumazet2a75de02008-01-05 23:08:49 -08002177#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002178
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002179static __net_init int devinet_init_net(struct net *net)
2180{
2181 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002182 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002183#ifdef CONFIG_SYSCTL
2184 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002185 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002186#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002187
2188 err = -ENOMEM;
2189 all = &ipv4_devconf;
2190 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002191
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002192 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002193 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
2194 if (all == NULL)
2195 goto err_alloc_all;
2196
2197 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
2198 if (dflt == NULL)
2199 goto err_alloc_dflt;
2200
Eric Dumazet2a75de02008-01-05 23:08:49 -08002201#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002202 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
2203 if (tbl == NULL)
2204 goto err_alloc_ctl;
2205
Eric W. Biederman02291682010-02-14 03:25:51 +00002206 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002207 tbl[0].extra1 = all;
2208 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002209#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002210 }
2211
2212#ifdef CONFIG_SYSCTL
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002213 err = __devinet_sysctl_register(net, "all", all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002214 if (err < 0)
2215 goto err_reg_all;
2216
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002217 err = __devinet_sysctl_register(net, "default", dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002218 if (err < 0)
2219 goto err_reg_dflt;
2220
2221 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002222 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002223 if (forw_hdr == NULL)
2224 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002225 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002226#endif
2227
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002228 net->ipv4.devconf_all = all;
2229 net->ipv4.devconf_dflt = dflt;
2230 return 0;
2231
2232#ifdef CONFIG_SYSCTL
2233err_reg_ctl:
2234 __devinet_sysctl_unregister(dflt);
2235err_reg_dflt:
2236 __devinet_sysctl_unregister(all);
2237err_reg_all:
2238 if (tbl != ctl_forward_entry)
2239 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002240err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08002241#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002242 if (dflt != &ipv4_devconf_dflt)
2243 kfree(dflt);
2244err_alloc_dflt:
2245 if (all != &ipv4_devconf)
2246 kfree(all);
2247err_alloc_all:
2248 return err;
2249}
2250
2251static __net_exit void devinet_exit_net(struct net *net)
2252{
Eric Dumazet2a75de02008-01-05 23:08:49 -08002253#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002254 struct ctl_table *tbl;
2255
2256 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002257 unregister_net_sysctl_table(net->ipv4.forw_hdr);
2258 __devinet_sysctl_unregister(net->ipv4.devconf_dflt);
2259 __devinet_sysctl_unregister(net->ipv4.devconf_all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002260 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08002261#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002262 kfree(net->ipv4.devconf_dflt);
2263 kfree(net->ipv4.devconf_all);
2264}
2265
2266static __net_initdata struct pernet_operations devinet_ops = {
2267 .init = devinet_init_net,
2268 .exit = devinet_exit_net,
2269};
2270
Thomas Graf9f0f7272010-11-16 04:32:48 +00002271static struct rtnl_af_ops inet_af_ops = {
2272 .family = AF_INET,
2273 .fill_link_af = inet_fill_link_af,
2274 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00002275 .validate_link_af = inet_validate_link_af,
2276 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00002277};
2278
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279void __init devinet_init(void)
2280{
David S. Millerfd23c3b2011-02-18 12:42:28 -08002281 int i;
2282
2283 for (i = 0; i < IN4_ADDR_HSIZE; i++)
2284 INIT_HLIST_HEAD(&inet_addr_lst[i]);
2285
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002286 register_pernet_subsys(&devinet_ops);
2287
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 register_gifconf(PF_INET, inet_gifconf);
2289 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07002290
Jiri Pirko5c766d62013-01-24 09:41:41 +00002291 schedule_delayed_work(&check_lifetime_work, 0);
2292
Thomas Graf9f0f7272010-11-16 04:32:48 +00002293 rtnl_af_register(&inet_af_ops);
2294
Greg Rosec7ac8672011-06-10 01:27:09 +00002295 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL);
2296 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, NULL);
2297 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, NULL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002298 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002299 inet_netconf_dump_devconf, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300}
2301