blob: d7585ab1a77a0e9d0f942960811a7c61c70ae129 [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
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080029#include <linux/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>
Ingo Molnar174cd4b2017-02-02 19:15:33 +010035#include <linux/sched/signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/string.h>
37#include <linux/mm.h>
38#include <linux/socket.h>
39#include <linux/sockios.h>
40#include <linux/in.h>
41#include <linux/errno.h>
42#include <linux/interrupt.h>
Thomas Graf18237302006-08-04 23:04:54 -070043#include <linux/if_addr.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/if_ether.h>
45#include <linux/inet.h>
46#include <linux/netdevice.h>
47#include <linux/etherdevice.h>
48#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/init.h>
50#include <linux/notifier.h>
51#include <linux/inetdevice.h>
52#include <linux/igmp.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090053#include <linux/slab.h>
David S. Millerfd23c3b2011-02-18 12:42:28 -080054#include <linux/hash.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#ifdef CONFIG_SYSCTL
56#include <linux/sysctl.h>
57#endif
58#include <linux/kmod.h>
Nicolas Dichteledc9e742012-10-25 22:28:52 +000059#include <linux/netconf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020061#include <net/arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <net/ip.h>
63#include <net/route.h>
64#include <net/ip_fib.h>
Thomas Graf63f34442007-03-22 11:55:17 -070065#include <net/rtnetlink.h>
Pavel Emelyanov752d14d2007-12-16 13:31:47 -080066#include <net/net_namespace.h>
Jiri Pirko5c766d62013-01-24 09:41:41 +000067#include <net/addrconf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Adrian Bunk0027ba82008-01-31 17:17:31 -080069static struct ipv4_devconf ipv4_devconf = {
Herbert Xu42f811b2007-06-04 23:34:44 -070070 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000071 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
72 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
73 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
74 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
William Manley26900482013-08-06 19:03:15 +010075 [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
76 [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
Herbert Xu42f811b2007-06-04 23:34:44 -070077 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070078};
79
80static struct ipv4_devconf ipv4_devconf_dflt = {
Herbert Xu42f811b2007-06-04 23:34:44 -070081 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000082 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
83 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
84 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
85 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
86 [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
William Manley26900482013-08-06 19:03:15 +010087 [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
88 [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
Herbert Xu42f811b2007-06-04 23:34:44 -070089 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070090};
91
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -080092#define IPV4_DEVCONF_DFLT(net, attr) \
93 IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr)
Herbert Xu42f811b2007-06-04 23:34:44 -070094
Patrick McHardyef7c79e2007-06-05 12:38:30 -070095static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
Thomas Graf5c753972006-08-04 23:03:53 -070096 [IFA_LOCAL] = { .type = NLA_U32 },
97 [IFA_ADDRESS] = { .type = NLA_U32 },
98 [IFA_BROADCAST] = { .type = NLA_U32 },
Thomas Graf5176f912006-08-26 20:13:18 -070099 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
Jiri Pirko5c766d62013-01-24 09:41:41 +0000100 [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100101 [IFA_FLAGS] = { .type = NLA_U32 },
David Ahernaf4d7682018-05-27 08:09:57 -0700102 [IFA_RT_PRIORITY] = { .type = NLA_U32 },
Thomas Graf5c753972006-08-04 23:03:53 -0700103};
104
Eric Dumazet40384992012-08-03 21:06:50 +0000105#define IN4_ADDR_HSIZE_SHIFT 8
106#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT)
107
David S. Millerfd23c3b2011-02-18 12:42:28 -0800108static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
David S. Millerfd23c3b2011-02-18 12:42:28 -0800109
Eric Dumazet6eada012015-03-18 14:05:33 -0700110static u32 inet_addr_hash(const struct net *net, __be32 addr)
David S. Millerfd23c3b2011-02-18 12:42:28 -0800111{
Eric Dumazet40384992012-08-03 21:06:50 +0000112 u32 val = (__force u32) addr ^ net_hash_mix(net);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800113
Eric Dumazet40384992012-08-03 21:06:50 +0000114 return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800115}
116
117static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
118{
Eric Dumazet40384992012-08-03 21:06:50 +0000119 u32 hash = inet_addr_hash(net, ifa->ifa_local);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800120
WANG Cong32a4be42014-05-06 11:15:56 -0700121 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800122 hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800123}
124
125static void inet_hash_remove(struct in_ifaddr *ifa)
126{
WANG Cong32a4be42014-05-06 11:15:56 -0700127 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800128 hlist_del_init_rcu(&ifa->hash);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800129}
130
David S. Miller9435eb12011-02-18 12:43:09 -0800131/**
132 * __ip_dev_find - find the first device with a given source address.
133 * @net: the net namespace
134 * @addr: the source address
135 * @devref: if true, take a reference on the found device
136 *
137 * If a caller uses devref=false, it should be protected by RCU, or RTNL
138 */
139struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
140{
David S. Miller9435eb12011-02-18 12:43:09 -0800141 struct net_device *result = NULL;
142 struct in_ifaddr *ifa;
David S. Miller9435eb12011-02-18 12:43:09 -0800143
144 rcu_read_lock();
Paolo Abeni6e617de2017-09-20 18:26:53 +0200145 ifa = inet_lookup_ifaddr_rcu(net, addr);
146 if (!ifa) {
David S. Miller406b6f92011-03-22 21:56:23 -0700147 struct flowi4 fl4 = { .daddr = addr };
148 struct fib_result res = { 0 };
149 struct fib_table *local;
150
151 /* Fallback to FIB local table so that communication
152 * over loopback subnets work.
153 */
154 local = fib_get_table(net, RT_TABLE_LOCAL);
155 if (local &&
156 !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
157 res.type == RTN_LOCAL)
158 result = FIB_RES_DEV(res);
Paolo Abeni6e617de2017-09-20 18:26:53 +0200159 } else {
160 result = ifa->ifa_dev->dev;
David S. Miller406b6f92011-03-22 21:56:23 -0700161 }
David S. Miller9435eb12011-02-18 12:43:09 -0800162 if (result && devref)
163 dev_hold(result);
164 rcu_read_unlock();
165 return result;
166}
167EXPORT_SYMBOL(__ip_dev_find);
168
Paolo Abeni6e617de2017-09-20 18:26:53 +0200169/* called under RCU lock */
170struct in_ifaddr *inet_lookup_ifaddr_rcu(struct net *net, __be32 addr)
171{
172 u32 hash = inet_addr_hash(net, addr);
173 struct in_ifaddr *ifa;
174
175 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash)
176 if (ifa->ifa_local == addr &&
177 net_eq(dev_net(ifa->ifa_dev->dev), net))
178 return ifa;
179
180 return NULL;
181}
182
Thomas Grafd6062cb2006-08-15 00:33:59 -0700183static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Alan Sterne041c682006-03-27 01:16:30 -0800185static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Krister Johansen3ad7d242017-06-08 13:12:14 -0700186static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
188 int destroy);
189#ifdef CONFIG_SYSCTL
WANG Cong20e61da2014-07-25 15:25:08 -0700190static int devinet_sysctl_register(struct in_device *idev);
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800191static void devinet_sysctl_unregister(struct in_device *idev);
192#else
WANG Cong20e61da2014-07-25 15:25:08 -0700193static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800194{
WANG Cong20e61da2014-07-25 15:25:08 -0700195 return 0;
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800196}
Eric Dumazet40384992012-08-03 21:06:50 +0000197static void devinet_sysctl_unregister(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800198{
199}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200#endif
201
202/* Locks all the inet devices. */
203
204static struct in_ifaddr *inet_alloc_ifa(void)
205{
Alexey Dobriyan93adcc82008-10-28 13:25:09 -0700206 return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207}
208
209static void inet_rcu_free_ifa(struct rcu_head *head)
210{
211 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
212 if (ifa->ifa_dev)
213 in_dev_put(ifa->ifa_dev);
214 kfree(ifa);
215}
216
Eric Dumazet40384992012-08-03 21:06:50 +0000217static void inet_free_ifa(struct in_ifaddr *ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218{
219 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
220}
221
222void in_dev_finish_destroy(struct in_device *idev)
223{
224 struct net_device *dev = idev->dev;
225
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700226 WARN_ON(idev->ifa_list);
227 WARN_ON(idev->mc_list);
Eric Dumazete9897072013-06-07 08:48:57 -0700228 kfree(rcu_dereference_protected(idev->mc_hash, 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229#ifdef NET_REFCNT_DEBUG
Joe Perches91df42b2012-05-15 14:11:54 +0000230 pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231#endif
232 dev_put(dev);
233 if (!idev->dead)
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800234 pr_err("Freeing alive in_device %p\n", idev);
235 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 kfree(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800238EXPORT_SYMBOL(in_dev_finish_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
Herbert Xu71e27da2007-06-04 23:36:06 -0700240static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241{
242 struct in_device *in_dev;
WANG Cong20e61da2014-07-25 15:25:08 -0700243 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
245 ASSERT_RTNL();
246
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700247 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 if (!in_dev)
249 goto out;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900250 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -0800251 sizeof(in_dev->cnf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 in_dev->cnf.sysctl = NULL;
253 in_dev->dev = dev;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800254 in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
255 if (!in_dev->arp_parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 goto out_kfree;
Ben Hutchings0187bdf2008-06-19 16:15:47 -0700257 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
258 dev_disable_lro(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 /* Reference in_dev->dev */
260 dev_hold(dev);
David L Stevens30c4cf52007-01-04 12:31:14 -0800261 /* Account for reference dev->ip_ptr (below) */
Reshetova, Elena7658b362017-06-30 13:08:03 +0300262 refcount_set(&in_dev->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
WANG Cong20e61da2014-07-25 15:25:08 -0700264 err = devinet_sysctl_register(in_dev);
265 if (err) {
266 in_dev->dead = 1;
267 in_dev_put(in_dev);
268 in_dev = NULL;
269 goto out;
270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 ip_mc_init_dev(in_dev);
272 if (dev->flags & IFF_UP)
273 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800274
David L Stevens30c4cf52007-01-04 12:31:14 -0800275 /* we can receive as soon as ip_ptr is set -- do this last */
Eric Dumazetcf778b02012-01-12 04:41:32 +0000276 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800277out:
WANG Cong20e61da2014-07-25 15:25:08 -0700278 return in_dev ?: ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279out_kfree:
280 kfree(in_dev);
281 in_dev = NULL;
282 goto out;
283}
284
285static void in_dev_rcu_put(struct rcu_head *head)
286{
287 struct in_device *idev = container_of(head, struct in_device, rcu_head);
288 in_dev_put(idev);
289}
290
291static void inetdev_destroy(struct in_device *in_dev)
292{
293 struct in_ifaddr *ifa;
294 struct net_device *dev;
295
296 ASSERT_RTNL();
297
298 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
300 in_dev->dead = 1;
301
302 ip_mc_destroy_dev(in_dev);
303
304 while ((ifa = in_dev->ifa_list) != NULL) {
305 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
306 inet_free_ifa(ifa);
307 }
308
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000309 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800311 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
313 arp_ifdown(dev);
314
315 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
316}
317
Al Viroff428d72006-09-26 22:13:35 -0700318int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319{
320 rcu_read_lock();
321 for_primary_ifa(in_dev) {
322 if (inet_ifa_match(a, ifa)) {
323 if (!b || inet_ifa_match(b, ifa)) {
324 rcu_read_unlock();
325 return 1;
326 }
327 }
328 } endfor_ifa(in_dev);
329 rcu_read_unlock();
330 return 0;
331}
332
Thomas Grafd6062cb2006-08-15 00:33:59 -0700333static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000334 int destroy, struct nlmsghdr *nlh, u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
Harald Welte8f937c62005-05-29 20:23:46 -0700336 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800337 struct in_ifaddr *ifa, *ifa1 = *ifap;
338 struct in_ifaddr *last_prim = in_dev->ifa_list;
339 struct in_ifaddr *prev_prom = NULL;
340 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
342 ASSERT_RTNL();
343
David S. Millerfbd40ea2016-03-13 23:28:00 -0400344 if (in_dev->dead)
345 goto no_promotions;
346
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900347 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700348 * unless alias promotion is set
349 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
351 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
353
354 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900355 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800356 ifa1->ifa_scope <= ifa->ifa_scope)
357 last_prim = ifa;
358
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
360 ifa1->ifa_mask != ifa->ifa_mask ||
361 !inet_ifa_match(ifa1->ifa_address, ifa)) {
362 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800363 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 continue;
365 }
366
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800367 if (!do_promote) {
David S. Millerfd23c3b2011-02-18 12:42:28 -0800368 inet_hash_remove(ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700369 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
Eric W. Biederman15e47302012-09-07 20:12:54 +0000371 rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800372 blocking_notifier_call_chain(&inetaddr_chain,
373 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700374 inet_free_ifa(ifa);
375 } else {
376 promote = ifa;
377 break;
378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 }
380 }
381
Julian Anastasov2d230e22011-03-19 12:13:52 +0000382 /* On promotion all secondaries from subnet are changing
383 * the primary IP, we must remove all their routes silently
384 * and later to add them back with new prefsrc. Do this
385 * while all addresses are on the device list.
386 */
387 for (ifa = promote; ifa; ifa = ifa->ifa_next) {
388 if (ifa1->ifa_mask == ifa->ifa_mask &&
389 inet_ifa_match(ifa1->ifa_address, ifa))
390 fib_del_ifaddr(ifa, ifa1);
391 }
392
David S. Millerfbd40ea2016-03-13 23:28:00 -0400393no_promotions:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 /* 2. Unlink it */
395
396 *ifap = ifa1->ifa_next;
David S. Millerfd23c3b2011-02-18 12:42:28 -0800397 inet_hash_remove(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
399 /* 3. Announce address deletion */
400
401 /* Send message first, then call notifier.
402 At first sight, FIB update triggered by notifier
403 will refer to already deleted ifaddr, that could confuse
404 netlink listeners. It is not true: look, gated sees
405 that route deleted and if it still thinks that ifaddr
406 is valid, it will try to restore deleted routes... Grr.
407 So that, this order is correct.
408 */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000409 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800410 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800411
412 if (promote) {
Julian Anastasov04024b92011-03-19 12:13:54 +0000413 struct in_ifaddr *next_sec = promote->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800414
415 if (prev_prom) {
416 prev_prom->ifa_next = promote->ifa_next;
417 promote->ifa_next = last_prim->ifa_next;
418 last_prim->ifa_next = promote;
419 }
420
421 promote->ifa_flags &= ~IFA_F_SECONDARY;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000422 rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800423 blocking_notifier_call_chain(&inetaddr_chain,
424 NETDEV_UP, promote);
Julian Anastasov04024b92011-03-19 12:13:54 +0000425 for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800426 if (ifa1->ifa_mask != ifa->ifa_mask ||
427 !inet_ifa_match(ifa1->ifa_address, ifa))
428 continue;
429 fib_add_ifaddr(ifa);
430 }
431
432 }
Herbert Xu63630972007-06-07 18:35:38 -0700433 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435}
436
Thomas Grafd6062cb2006-08-15 00:33:59 -0700437static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
438 int destroy)
439{
440 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
441}
442
Jiri Pirko5c766d62013-01-24 09:41:41 +0000443static void check_lifetime(struct work_struct *work);
444
445static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
446
Thomas Grafd6062cb2006-08-15 00:33:59 -0700447static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
David Ahernde95e042017-10-18 09:56:54 -0700448 u32 portid, struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449{
450 struct in_device *in_dev = ifa->ifa_dev;
451 struct in_ifaddr *ifa1, **ifap, **last_primary;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700452 struct in_validator_info ivi;
453 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
455 ASSERT_RTNL();
456
457 if (!ifa->ifa_local) {
458 inet_free_ifa(ifa);
459 return 0;
460 }
461
462 ifa->ifa_flags &= ~IFA_F_SECONDARY;
463 last_primary = &in_dev->ifa_list;
464
465 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
466 ifap = &ifa1->ifa_next) {
467 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
468 ifa->ifa_scope <= ifa1->ifa_scope)
469 last_primary = &ifa1->ifa_next;
470 if (ifa1->ifa_mask == ifa->ifa_mask &&
471 inet_ifa_match(ifa1->ifa_address, ifa)) {
472 if (ifa1->ifa_local == ifa->ifa_local) {
473 inet_free_ifa(ifa);
474 return -EEXIST;
475 }
476 if (ifa1->ifa_scope != ifa->ifa_scope) {
477 inet_free_ifa(ifa);
478 return -EINVAL;
479 }
480 ifa->ifa_flags |= IFA_F_SECONDARY;
481 }
482 }
483
Krister Johansen3ad7d242017-06-08 13:12:14 -0700484 /* Allow any devices that wish to register ifaddr validtors to weigh
485 * in now, before changes are committed. The rntl lock is serializing
486 * access here, so the state should not change between a validator call
487 * and a final notify on commit. This isn't invoked on promotion under
488 * the assumption that validators are checking the address itself, and
489 * not the flags.
490 */
491 ivi.ivi_addr = ifa->ifa_address;
492 ivi.ivi_dev = ifa->ifa_dev;
David Ahernde95e042017-10-18 09:56:54 -0700493 ivi.extack = extack;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700494 ret = blocking_notifier_call_chain(&inetaddr_validator_chain,
495 NETDEV_UP, &ivi);
496 ret = notifier_to_errno(ret);
497 if (ret) {
498 inet_free_ifa(ifa);
499 return ret;
500 }
501
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500503 prandom_seed((__force u32) ifa->ifa_local);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 ifap = last_primary;
505 }
506
507 ifa->ifa_next = *ifap;
508 *ifap = ifa;
509
David S. Millerfd23c3b2011-02-18 12:42:28 -0800510 inet_hash_insert(dev_net(in_dev->dev), ifa);
511
Jiri Pirko5c766d62013-01-24 09:41:41 +0000512 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530513 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 /* Send message first, then call notifier.
516 Notifier will trigger FIB update, so that
517 listeners of netlink will know about new ifaddr */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000518 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800519 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
521 return 0;
522}
523
Thomas Grafd6062cb2006-08-15 00:33:59 -0700524static int inet_insert_ifa(struct in_ifaddr *ifa)
525{
David Ahernde95e042017-10-18 09:56:54 -0700526 return __inet_insert_ifa(ifa, NULL, 0, NULL);
Thomas Grafd6062cb2006-08-15 00:33:59 -0700527}
528
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
530{
Herbert Xue5ed6392005-10-03 14:35:55 -0700531 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532
533 ASSERT_RTNL();
534
535 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700536 inet_free_ifa(ifa);
537 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700539 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100540 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700542 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 in_dev_hold(in_dev);
544 ifa->ifa_dev = in_dev;
545 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800546 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 ifa->ifa_scope = RT_SCOPE_HOST;
548 return inet_insert_ifa(ifa);
549}
550
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000551/* Caller must hold RCU or RTNL :
552 * We dont take a reference on found in_device
553 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800554struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555{
556 struct net_device *dev;
557 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000558
559 rcu_read_lock();
560 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000562 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000563 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 return in_dev;
565}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800566EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
568/* Called only from RTNL semaphored context. No locks. */
569
Al Viro60cad5d2006-09-26 22:17:09 -0700570struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
571 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572{
573 ASSERT_RTNL();
574
575 for_primary_ifa(in_dev) {
576 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
577 return ifa;
578 } endfor_ifa(in_dev);
579 return NULL;
580}
581
Madhu Challa93a714d2015-02-25 09:58:35 -0800582static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa)
583{
584 struct ip_mreqn mreq = {
585 .imr_multiaddr.s_addr = ifa->ifa_address,
586 .imr_ifindex = ifa->ifa_dev->dev->ifindex,
587 };
588 int ret;
589
590 ASSERT_RTNL();
591
592 lock_sock(sk);
593 if (join)
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300594 ret = ip_mc_join_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800595 else
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300596 ret = ip_mc_leave_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800597 release_sock(sk);
598
599 return ret;
600}
601
David Ahernc21ef3e2017-04-16 09:48:24 -0700602static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
603 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900605 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700606 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700608 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700610 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611
612 ASSERT_RTNL();
613
Johannes Bergfceb6432017-04-12 14:34:07 +0200614 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -0700615 extack);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700616 if (err < 0)
617 goto errout;
618
619 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800620 in_dev = inetdev_by_index(net, ifm->ifa_index);
Ian Morris51456b22015-04-03 09:17:26 +0100621 if (!in_dev) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700622 err = -ENODEV;
623 goto errout;
624 }
625
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
627 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700628 if (tb[IFA_LOCAL] &&
Jiri Benc67b61f62015-03-29 16:59:26 +0200629 ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700631
632 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
633 continue;
634
635 if (tb[IFA_ADDRESS] &&
636 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Jiri Benc67b61f62015-03-29 16:59:26 +0200637 !inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700638 continue;
639
Madhu Challa93a714d2015-02-25 09:58:35 -0800640 if (ipv4_is_multicast(ifa->ifa_address))
641 ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000642 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 return 0;
644 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700645
646 err = -EADDRNOTAVAIL;
647errout:
648 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649}
650
Jiri Pirko5c766d62013-01-24 09:41:41 +0000651#define INFINITY_LIFE_TIME 0xFFFFFFFF
652
653static void check_lifetime(struct work_struct *work)
654{
655 unsigned long now, next, next_sec, next_sched;
656 struct in_ifaddr *ifa;
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000657 struct hlist_node *n;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000658 int i;
659
660 now = jiffies;
661 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
662
Jiri Pirko5c766d62013-01-24 09:41:41 +0000663 for (i = 0; i < IN4_ADDR_HSIZE; i++) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000664 bool change_needed = false;
665
666 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800667 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
Jiri Pirko5c766d62013-01-24 09:41:41 +0000668 unsigned long age;
669
670 if (ifa->ifa_flags & IFA_F_PERMANENT)
671 continue;
672
673 /* We try to batch several events at once. */
674 age = (now - ifa->ifa_tstamp +
675 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
676
677 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
678 age >= ifa->ifa_valid_lft) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000679 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000680 } else if (ifa->ifa_preferred_lft ==
681 INFINITY_LIFE_TIME) {
682 continue;
683 } else if (age >= ifa->ifa_preferred_lft) {
684 if (time_before(ifa->ifa_tstamp +
685 ifa->ifa_valid_lft * HZ, next))
686 next = ifa->ifa_tstamp +
687 ifa->ifa_valid_lft * HZ;
688
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000689 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
690 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000691 } else if (time_before(ifa->ifa_tstamp +
692 ifa->ifa_preferred_lft * HZ,
693 next)) {
694 next = ifa->ifa_tstamp +
695 ifa->ifa_preferred_lft * HZ;
696 }
697 }
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000698 rcu_read_unlock();
699 if (!change_needed)
700 continue;
701 rtnl_lock();
702 hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
703 unsigned long age;
704
705 if (ifa->ifa_flags & IFA_F_PERMANENT)
706 continue;
707
708 /* We try to batch several events at once. */
709 age = (now - ifa->ifa_tstamp +
710 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
711
712 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
713 age >= ifa->ifa_valid_lft) {
714 struct in_ifaddr **ifap;
715
716 for (ifap = &ifa->ifa_dev->ifa_list;
717 *ifap != NULL; ifap = &(*ifap)->ifa_next) {
718 if (*ifap == ifa) {
719 inet_del_ifa(ifa->ifa_dev,
720 ifap, 1);
721 break;
722 }
723 }
724 } else if (ifa->ifa_preferred_lft !=
725 INFINITY_LIFE_TIME &&
726 age >= ifa->ifa_preferred_lft &&
727 !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
728 ifa->ifa_flags |= IFA_F_DEPRECATED;
729 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
730 }
731 }
732 rtnl_unlock();
Jiri Pirko5c766d62013-01-24 09:41:41 +0000733 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000734
735 next_sec = round_jiffies_up(next);
736 next_sched = next;
737
738 /* If rounded timeout is accurate enough, accept it. */
739 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
740 next_sched = next_sec;
741
742 now = jiffies;
743 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
744 if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
745 next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
746
viresh kumar906e0732014-01-22 12:23:32 +0530747 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work,
748 next_sched - now);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000749}
750
751static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
752 __u32 prefered_lft)
753{
754 unsigned long timeout;
755
756 ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
757
758 timeout = addrconf_timeout_fixup(valid_lft, HZ);
759 if (addrconf_finite_timeout(timeout))
760 ifa->ifa_valid_lft = timeout;
761 else
762 ifa->ifa_flags |= IFA_F_PERMANENT;
763
764 timeout = addrconf_timeout_fixup(prefered_lft, HZ);
765 if (addrconf_finite_timeout(timeout)) {
766 if (timeout == 0)
767 ifa->ifa_flags |= IFA_F_DEPRECATED;
768 ifa->ifa_preferred_lft = timeout;
769 }
770 ifa->ifa_tstamp = jiffies;
771 if (!ifa->ifa_cstamp)
772 ifa->ifa_cstamp = ifa->ifa_tstamp;
773}
774
775static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
776 __u32 *pvalid_lft, __u32 *pprefered_lft)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777{
Thomas Graf5c753972006-08-04 23:03:53 -0700778 struct nlattr *tb[IFA_MAX+1];
779 struct in_ifaddr *ifa;
780 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 struct net_device *dev;
782 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800783 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
Johannes Bergfceb6432017-04-12 14:34:07 +0200785 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
786 NULL);
Thomas Graf5c753972006-08-04 23:03:53 -0700787 if (err < 0)
788 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
Thomas Graf5c753972006-08-04 23:03:53 -0700790 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800791 err = -EINVAL;
Ian Morris51456b22015-04-03 09:17:26 +0100792 if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL])
Thomas Graf5c753972006-08-04 23:03:53 -0700793 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800795 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800796 err = -ENODEV;
Ian Morris51456b22015-04-03 09:17:26 +0100797 if (!dev)
Thomas Graf5c753972006-08-04 23:03:53 -0700798 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
Thomas Graf5c753972006-08-04 23:03:53 -0700800 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800801 err = -ENOBUFS;
Ian Morris51456b22015-04-03 09:17:26 +0100802 if (!in_dev)
Herbert Xu71e27da2007-06-04 23:36:06 -0700803 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Thomas Graf5c753972006-08-04 23:03:53 -0700805 ifa = inet_alloc_ifa();
Ian Morris51456b22015-04-03 09:17:26 +0100806 if (!ifa)
Thomas Graf5c753972006-08-04 23:03:53 -0700807 /*
808 * A potential indev allocation can be left alive, it stays
809 * assigned to its device and is destroy with it.
810 */
Thomas Graf5c753972006-08-04 23:03:53 -0700811 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700812
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800813 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100814 neigh_parms_data_state_setall(in_dev->arp_parms);
Thomas Graf5c753972006-08-04 23:03:53 -0700815 in_dev_hold(in_dev);
816
Ian Morris51456b22015-04-03 09:17:26 +0100817 if (!tb[IFA_ADDRESS])
Thomas Graf5c753972006-08-04 23:03:53 -0700818 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
819
David S. Millerfd23c3b2011-02-18 12:42:28 -0800820 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
822 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100823 ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
824 ifm->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700826 ifa->ifa_dev = in_dev;
827
Jiri Benc67b61f62015-03-29 16:59:26 +0200828 ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]);
829 ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700830
831 if (tb[IFA_BROADCAST])
Jiri Benc67b61f62015-03-29 16:59:26 +0200832 ifa->ifa_broadcast = nla_get_in_addr(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700833
Thomas Graf5c753972006-08-04 23:03:53 -0700834 if (tb[IFA_LABEL])
835 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 else
837 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
838
David Ahernaf4d7682018-05-27 08:09:57 -0700839 if (tb[IFA_RT_PRIORITY])
840 ifa->ifa_rt_priority = nla_get_u32(tb[IFA_RT_PRIORITY]);
841
Jiri Pirko5c766d62013-01-24 09:41:41 +0000842 if (tb[IFA_CACHEINFO]) {
843 struct ifa_cacheinfo *ci;
844
845 ci = nla_data(tb[IFA_CACHEINFO]);
846 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
847 err = -EINVAL;
Daniel Borkmann446266b2013-08-02 11:32:43 +0200848 goto errout_free;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000849 }
850 *pvalid_lft = ci->ifa_valid;
851 *pprefered_lft = ci->ifa_prefered;
852 }
853
Thomas Graf5c753972006-08-04 23:03:53 -0700854 return ifa;
855
Daniel Borkmann446266b2013-08-02 11:32:43 +0200856errout_free:
857 inet_free_ifa(ifa);
Thomas Graf5c753972006-08-04 23:03:53 -0700858errout:
859 return ERR_PTR(err);
860}
861
Jiri Pirko5c766d62013-01-24 09:41:41 +0000862static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
863{
864 struct in_device *in_dev = ifa->ifa_dev;
865 struct in_ifaddr *ifa1, **ifap;
866
867 if (!ifa->ifa_local)
868 return NULL;
869
870 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
871 ifap = &ifa1->ifa_next) {
872 if (ifa1->ifa_mask == ifa->ifa_mask &&
873 inet_ifa_match(ifa1->ifa_address, ifa) &&
874 ifa1->ifa_local == ifa->ifa_local)
875 return ifa1;
876 }
877 return NULL;
878}
879
David Ahernc21ef3e2017-04-16 09:48:24 -0700880static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
881 struct netlink_ext_ack *extack)
Thomas Graf5c753972006-08-04 23:03:53 -0700882{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900883 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700884 struct in_ifaddr *ifa;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000885 struct in_ifaddr *ifa_existing;
886 __u32 valid_lft = INFINITY_LIFE_TIME;
887 __u32 prefered_lft = INFINITY_LIFE_TIME;
Thomas Graf5c753972006-08-04 23:03:53 -0700888
889 ASSERT_RTNL();
890
Jiri Pirko5c766d62013-01-24 09:41:41 +0000891 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft);
Thomas Graf5c753972006-08-04 23:03:53 -0700892 if (IS_ERR(ifa))
893 return PTR_ERR(ifa);
894
Jiri Pirko5c766d62013-01-24 09:41:41 +0000895 ifa_existing = find_matching_ifa(ifa);
896 if (!ifa_existing) {
897 /* It would be best to check for !NLM_F_CREATE here but
stephen hemminger614d0562014-05-16 20:46:58 -0700898 * userspace already relies on not having to provide this.
Jiri Pirko5c766d62013-01-24 09:41:41 +0000899 */
900 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Madhu Challa93a714d2015-02-25 09:58:35 -0800901 if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
902 int ret = ip_mc_config(net->ipv4.mc_autojoin_sk,
903 true, ifa);
904
905 if (ret < 0) {
906 inet_free_ifa(ifa);
907 return ret;
908 }
909 }
David Ahernde95e042017-10-18 09:56:54 -0700910 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid,
911 extack);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000912 } else {
David Ahernaf4d7682018-05-27 08:09:57 -0700913 u32 new_metric = ifa->ifa_rt_priority;
914
Jiri Pirko5c766d62013-01-24 09:41:41 +0000915 inet_free_ifa(ifa);
916
917 if (nlh->nlmsg_flags & NLM_F_EXCL ||
918 !(nlh->nlmsg_flags & NLM_F_REPLACE))
919 return -EEXIST;
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000920 ifa = ifa_existing;
David Ahernaf4d7682018-05-27 08:09:57 -0700921
922 if (ifa->ifa_rt_priority != new_metric) {
923 fib_modify_prefix_metric(ifa, new_metric);
924 ifa->ifa_rt_priority = new_metric;
925 }
926
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000927 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Jiri Pirko05a324b2013-04-04 23:39:38 +0000928 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530929 queue_delayed_work(system_power_efficient_wq,
930 &check_lifetime_work, 0);
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000931 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000932 }
933 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934}
935
936/*
937 * Determine a default network mask, based on the IP address.
938 */
939
Eric Dumazet40384992012-08-03 21:06:50 +0000940static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941{
942 int rc = -1; /* Something else, probably a multicast. */
943
Joe Perchesf97c1e02007-12-16 13:45:43 -0800944 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900945 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 else {
Al Viro714e85b2006-11-14 20:51:49 -0800947 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Al Viro714e85b2006-11-14 20:51:49 -0800949 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800951 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800953 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 rc = 24;
955 }
956
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900957 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958}
959
960
Al Viro03aef172017-07-01 07:53:12 -0400961int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 struct sockaddr_in sin_orig;
Al Viro03aef172017-07-01 07:53:12 -0400964 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 struct in_device *in_dev;
966 struct in_ifaddr **ifap = NULL;
967 struct in_ifaddr *ifa = NULL;
968 struct net_device *dev;
969 char *colon;
970 int ret = -EFAULT;
971 int tryaddrmatch = 0;
972
Al Viro03aef172017-07-01 07:53:12 -0400973 ifr->ifr_name[IFNAMSIZ - 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
975 /* save original address for comparison */
976 memcpy(&sin_orig, sin, sizeof(*sin));
977
Al Viro03aef172017-07-01 07:53:12 -0400978 colon = strchr(ifr->ifr_name, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 if (colon)
980 *colon = 0;
981
Al Viro03aef172017-07-01 07:53:12 -0400982 dev_load(net, ifr->ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
Stephen Hemminger132adf52007-03-08 20:44:43 -0800984 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 case SIOCGIFADDR: /* Get interface address */
986 case SIOCGIFBRDADDR: /* Get the broadcast address */
987 case SIOCGIFDSTADDR: /* Get the destination address */
988 case SIOCGIFNETMASK: /* Get the netmask for the interface */
989 /* Note that these ioctls will not sleep,
990 so that we do not impose a lock.
991 One day we will be forced to put shlock here (I mean SMP)
992 */
993 tryaddrmatch = (sin_orig.sin_family == AF_INET);
994 memset(sin, 0, sizeof(*sin));
995 sin->sin_family = AF_INET;
996 break;
997
998 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000999 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +00001000 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 goto out;
1002 break;
1003 case SIOCSIFADDR: /* Set interface address (and family) */
1004 case SIOCSIFBRDADDR: /* Set the broadcast address */
1005 case SIOCSIFDSTADDR: /* Set the destination address */
1006 case SIOCSIFNETMASK: /* Set the netmask for the interface */
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +00001007 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +00001008 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 goto out;
1010 ret = -EINVAL;
1011 if (sin->sin_family != AF_INET)
1012 goto out;
1013 break;
1014 default:
1015 ret = -EINVAL;
1016 goto out;
1017 }
1018
1019 rtnl_lock();
1020
1021 ret = -ENODEV;
Al Viro03aef172017-07-01 07:53:12 -04001022 dev = __dev_get_by_name(net, ifr->ifr_name);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001023 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 goto done;
1025
1026 if (colon)
1027 *colon = ':';
1028
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001029 in_dev = __in_dev_get_rtnl(dev);
1030 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 if (tryaddrmatch) {
1032 /* Matthias Andree */
1033 /* compare label and address (4.4BSD style) */
1034 /* note: we only do this for a limited set of ioctls
1035 and only if the original address family was AF_INET.
1036 This is checked above. */
1037 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1038 ifap = &ifa->ifa_next) {
Al Viro03aef172017-07-01 07:53:12 -04001039 if (!strcmp(ifr->ifr_name, ifa->ifa_label) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -08001041 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 break; /* found */
1043 }
1044 }
1045 }
1046 /* we didn't get a match, maybe the application is
1047 4.3BSD-style and passed in junk so we fall back to
1048 comparing just the label */
1049 if (!ifa) {
1050 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1051 ifap = &ifa->ifa_next)
Al Viro03aef172017-07-01 07:53:12 -04001052 if (!strcmp(ifr->ifr_name, ifa->ifa_label))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 break;
1054 }
1055 }
1056
1057 ret = -EADDRNOTAVAIL;
1058 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
1059 goto done;
1060
Stephen Hemminger132adf52007-03-08 20:44:43 -08001061 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 case SIOCGIFADDR: /* Get interface address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001063 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 sin->sin_addr.s_addr = ifa->ifa_local;
Al Viro03aef172017-07-01 07:53:12 -04001065 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
1067 case SIOCGIFBRDADDR: /* Get the broadcast address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001068 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 sin->sin_addr.s_addr = ifa->ifa_broadcast;
Al Viro03aef172017-07-01 07:53:12 -04001070 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
1072 case SIOCGIFDSTADDR: /* Get the destination address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001073 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 sin->sin_addr.s_addr = ifa->ifa_address;
Al Viro03aef172017-07-01 07:53:12 -04001075 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
1077 case SIOCGIFNETMASK: /* Get the netmask for the interface */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001078 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 sin->sin_addr.s_addr = ifa->ifa_mask;
Al Viro03aef172017-07-01 07:53:12 -04001080 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
1082 case SIOCSIFFLAGS:
1083 if (colon) {
1084 ret = -EADDRNOTAVAIL;
1085 if (!ifa)
1086 break;
1087 ret = 0;
Al Viro03aef172017-07-01 07:53:12 -04001088 if (!(ifr->ifr_flags & IFF_UP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 inet_del_ifa(in_dev, ifap, 1);
1090 break;
1091 }
Al Viro03aef172017-07-01 07:53:12 -04001092 ret = dev_change_flags(dev, ifr->ifr_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 break;
1094
1095 case SIOCSIFADDR: /* Set interface address (and family) */
1096 ret = -EINVAL;
1097 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1098 break;
1099
1100 if (!ifa) {
1101 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001102 ifa = inet_alloc_ifa();
1103 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 break;
Xi Wangc7e2e1d2013-01-05 11:19:24 +00001105 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 if (colon)
Al Viro03aef172017-07-01 07:53:12 -04001107 memcpy(ifa->ifa_label, ifr->ifr_name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 else
1109 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1110 } else {
1111 ret = 0;
1112 if (ifa->ifa_local == sin->sin_addr.s_addr)
1113 break;
1114 inet_del_ifa(in_dev, ifap, 0);
1115 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -08001116 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 }
1118
1119 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
1120
1121 if (!(dev->flags & IFF_POINTOPOINT)) {
1122 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
1123 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
1124 if ((dev->flags & IFF_BROADCAST) &&
1125 ifa->ifa_prefixlen < 31)
1126 ifa->ifa_broadcast = ifa->ifa_address |
1127 ~ifa->ifa_mask;
1128 } else {
1129 ifa->ifa_prefixlen = 32;
1130 ifa->ifa_mask = inet_make_mask(32);
1131 }
Jiri Pirko5c766d62013-01-24 09:41:41 +00001132 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 ret = inet_set_ifa(dev, ifa);
1134 break;
1135
1136 case SIOCSIFBRDADDR: /* Set the broadcast address */
1137 ret = 0;
1138 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
1139 inet_del_ifa(in_dev, ifap, 0);
1140 ifa->ifa_broadcast = sin->sin_addr.s_addr;
1141 inet_insert_ifa(ifa);
1142 }
1143 break;
1144
1145 case SIOCSIFDSTADDR: /* Set the destination address */
1146 ret = 0;
1147 if (ifa->ifa_address == sin->sin_addr.s_addr)
1148 break;
1149 ret = -EINVAL;
1150 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1151 break;
1152 ret = 0;
1153 inet_del_ifa(in_dev, ifap, 0);
1154 ifa->ifa_address = sin->sin_addr.s_addr;
1155 inet_insert_ifa(ifa);
1156 break;
1157
1158 case SIOCSIFNETMASK: /* Set the netmask for the interface */
1159
1160 /*
1161 * The mask we set must be legal.
1162 */
1163 ret = -EINVAL;
1164 if (bad_mask(sin->sin_addr.s_addr, 0))
1165 break;
1166 ret = 0;
1167 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -07001168 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 inet_del_ifa(in_dev, ifap, 0);
1170 ifa->ifa_mask = sin->sin_addr.s_addr;
1171 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
1172
1173 /* See if current broadcast address matches
1174 * with current netmask, then recalculate
1175 * the broadcast address. Otherwise it's a
1176 * funny address, so don't touch it since
1177 * the user seems to know what (s)he's doing...
1178 */
1179 if ((dev->flags & IFF_BROADCAST) &&
1180 (ifa->ifa_prefixlen < 31) &&
1181 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -05001182 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 ifa->ifa_broadcast = (ifa->ifa_local |
1184 ~sin->sin_addr.s_addr);
1185 }
1186 inet_insert_ifa(ifa);
1187 }
1188 break;
1189 }
1190done:
1191 rtnl_unlock();
1192out:
1193 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194}
1195
Al Viro36fd6332017-06-26 13:19:16 -04001196static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197{
Herbert Xue5ed6392005-10-03 14:35:55 -07001198 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 struct in_ifaddr *ifa;
1200 struct ifreq ifr;
1201 int done = 0;
1202
Al Viro36fd6332017-06-26 13:19:16 -04001203 if (WARN_ON(size > sizeof(struct ifreq)))
1204 goto out;
1205
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001206 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 goto out;
1208
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001209 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 if (!buf) {
Al Viro36fd6332017-06-26 13:19:16 -04001211 done += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 continue;
1213 }
Al Viro36fd6332017-06-26 13:19:16 -04001214 if (len < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 break;
1216 memset(&ifr, 0, sizeof(struct ifreq));
Dan Carpenter4299c8a2013-07-29 22:15:19 +03001217 strcpy(ifr.ifr_name, ifa->ifa_label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
1219 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
1220 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1221 ifa->ifa_local;
1222
Al Viro36fd6332017-06-26 13:19:16 -04001223 if (copy_to_user(buf + done, &ifr, size)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 done = -EFAULT;
1225 break;
1226 }
Al Viro36fd6332017-06-26 13:19:16 -04001227 len -= size;
1228 done += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 }
1230out:
1231 return done;
1232}
1233
Gao Feng8b57fd12017-03-10 12:38:47 +08001234static __be32 in_dev_select_addr(const struct in_device *in_dev,
1235 int scope)
1236{
1237 for_primary_ifa(in_dev) {
1238 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1239 ifa->ifa_scope <= scope)
1240 return ifa->ifa_local;
1241 } endfor_ifa(in_dev);
1242
1243 return 0;
1244}
1245
Al Viroa61ced52006-09-26 21:27:54 -07001246__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247{
Al Viroa61ced52006-09-26 21:27:54 -07001248 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001250 struct net *net = dev_net(dev);
David Ahern3f2fb9a2016-02-24 11:47:02 -08001251 int master_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252
1253 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001254 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 if (!in_dev)
1256 goto no_in_dev;
1257
1258 for_primary_ifa(in_dev) {
1259 if (ifa->ifa_scope > scope)
1260 continue;
1261 if (!dst || inet_ifa_match(dst, ifa)) {
1262 addr = ifa->ifa_local;
1263 break;
1264 }
1265 if (!addr)
1266 addr = ifa->ifa_local;
1267 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
1269 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001270 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001271no_in_dev:
David Ahern3f2fb9a2016-02-24 11:47:02 -08001272 master_idx = l3mdev_master_ifindex_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
David Lamparter17b693c2016-02-24 11:47:03 -08001274 /* For VRFs, the VRF device takes the place of the loopback device,
1275 * with addresses on it being preferred. Note in such cases the
1276 * loopback device will be among the devices that fail the master_idx
1277 * equality check in the loop below.
1278 */
1279 if (master_idx &&
1280 (dev = dev_get_by_index_rcu(net, master_idx)) &&
1281 (in_dev = __in_dev_get_rcu(dev))) {
Gao Feng8b57fd12017-03-10 12:38:47 +08001282 addr = in_dev_select_addr(in_dev, scope);
1283 if (addr)
1284 goto out_unlock;
David Lamparter17b693c2016-02-24 11:47:03 -08001285 }
1286
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 /* Not loopback addresses on loopback should be preferred
Stephen Hemmingerca9f1fd2015-02-14 13:47:54 -05001288 in this case. It is important that lo is the first interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 in dev_base list.
1290 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001291 for_each_netdev_rcu(net, dev) {
David Ahern3f2fb9a2016-02-24 11:47:02 -08001292 if (l3mdev_master_ifindex_rcu(dev) != master_idx)
1293 continue;
1294
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001295 in_dev = __in_dev_get_rcu(dev);
1296 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 continue;
1298
Gao Feng8b57fd12017-03-10 12:38:47 +08001299 addr = in_dev_select_addr(in_dev, scope);
1300 if (addr)
1301 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001303out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 return addr;
1306}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001307EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
Al Viro60cad5d2006-09-26 22:17:09 -07001309static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1310 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311{
1312 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001313 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314
1315 for_ifa(in_dev) {
1316 if (!addr &&
1317 (local == ifa->ifa_local || !local) &&
1318 ifa->ifa_scope <= scope) {
1319 addr = ifa->ifa_local;
1320 if (same)
1321 break;
1322 }
1323 if (!same) {
1324 same = (!local || inet_ifa_match(local, ifa)) &&
1325 (!dst || inet_ifa_match(dst, ifa));
1326 if (same && addr) {
1327 if (local || !dst)
1328 break;
1329 /* Is the selected addr into dst subnet? */
1330 if (inet_ifa_match(addr, ifa))
1331 break;
1332 /* No, then can we use new local src? */
1333 if (ifa->ifa_scope <= scope) {
1334 addr = ifa->ifa_local;
1335 break;
1336 }
1337 /* search for large dst subnet for addr */
1338 same = 0;
1339 }
1340 }
1341 } endfor_ifa(in_dev);
1342
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001343 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344}
1345
1346/*
1347 * Confirm that local IP address exists using wildcards:
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001348 * - net: netns to check, cannot be NULL
1349 * - in_dev: only on this interface, NULL=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 * - dst: only in the same subnet as dst, 0=any dst
1351 * - local: address, 0=autoselect the local address
1352 * - scope: maximum allowed scope value for the local address
1353 */
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001354__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001355 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356{
Al Viro60cad5d2006-09-26 22:17:09 -07001357 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001358 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
Ian Morris00db4122015-04-03 09:17:27 +01001360 if (in_dev)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001361 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001364 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001365 in_dev = __in_dev_get_rcu(dev);
1366 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 addr = confirm_addr_indev(in_dev, dst, local, scope);
1368 if (addr)
1369 break;
1370 }
1371 }
1372 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
1374 return addr;
1375}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001376EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
1378/*
1379 * Device notifier
1380 */
1381
1382int register_inetaddr_notifier(struct notifier_block *nb)
1383{
Alan Sterne041c682006-03-27 01:16:30 -08001384 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001386EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
1388int unregister_inetaddr_notifier(struct notifier_block *nb)
1389{
Alan Sterne041c682006-03-27 01:16:30 -08001390 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001392EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
Krister Johansen3ad7d242017-06-08 13:12:14 -07001394int register_inetaddr_validator_notifier(struct notifier_block *nb)
1395{
1396 return blocking_notifier_chain_register(&inetaddr_validator_chain, nb);
1397}
1398EXPORT_SYMBOL(register_inetaddr_validator_notifier);
1399
1400int unregister_inetaddr_validator_notifier(struct notifier_block *nb)
1401{
1402 return blocking_notifier_chain_unregister(&inetaddr_validator_chain,
1403 nb);
1404}
1405EXPORT_SYMBOL(unregister_inetaddr_validator_notifier);
1406
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001407/* Rename ifa_labels for a device name change. Make some effort to preserve
1408 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409*/
1410static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001411{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 struct in_ifaddr *ifa;
1413 int named = 0;
1414
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001415 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1416 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417
1418 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001419 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001421 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001422 dot = strchr(old, ':');
Ian Morris51456b22015-04-03 09:17:26 +01001423 if (!dot) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001424 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 dot = old;
1426 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001427 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001428 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001429 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001430 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001431skip:
1432 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001433 }
1434}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435
Eric Dumazet40384992012-08-03 21:06:50 +00001436static bool inetdev_valid_mtu(unsigned int mtu)
Breno Leitao06770842008-09-02 17:28:58 -07001437{
Eric Dumazetb5476022017-12-11 07:17:39 -08001438 return mtu >= IPV4_MIN_MTU;
Breno Leitao06770842008-09-02 17:28:58 -07001439}
1440
Ian Campbelld11327ad2011-02-11 07:44:16 +00001441static void inetdev_send_gratuitous_arp(struct net_device *dev,
1442 struct in_device *in_dev)
1443
1444{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001445 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001446
Zoltan Kissb76d0782011-07-24 13:09:30 +00001447 for (ifa = in_dev->ifa_list; ifa;
1448 ifa = ifa->ifa_next) {
1449 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1450 ifa->ifa_local, dev,
1451 ifa->ifa_local, NULL,
1452 dev->dev_addr, NULL);
1453 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001454}
1455
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456/* Called only under RTNL semaphore */
1457
1458static int inetdev_event(struct notifier_block *this, unsigned long event,
1459 void *ptr)
1460{
Jiri Pirko351638e2013-05-28 01:30:21 +00001461 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazet748e2d92012-08-22 21:50:59 +00001462 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463
1464 ASSERT_RTNL();
1465
1466 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001467 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 in_dev = inetdev_init(dev);
WANG Cong20e61da2014-07-25 15:25:08 -07001469 if (IS_ERR(in_dev))
1470 return notifier_from_errno(PTR_ERR(in_dev));
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001471 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001472 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1473 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001474 }
Breno Leitao06770842008-09-02 17:28:58 -07001475 } else if (event == NETDEV_CHANGEMTU) {
1476 /* Re-enabling IP */
1477 if (inetdev_valid_mtu(dev->mtu))
1478 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 }
1480 goto out;
1481 }
1482
1483 switch (event) {
1484 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001485 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001486 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 break;
1488 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001489 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001491 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001492 struct in_ifaddr *ifa = inet_alloc_ifa();
1493
1494 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001495 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 ifa->ifa_local =
1497 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1498 ifa->ifa_prefixlen = 8;
1499 ifa->ifa_mask = inet_make_mask(8);
1500 in_dev_hold(in_dev);
1501 ifa->ifa_dev = in_dev;
1502 ifa->ifa_scope = RT_SCOPE_HOST;
1503 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Jiri Pirko5c766d62013-01-24 09:41:41 +00001504 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1505 INFINITY_LIFE_TIME);
Jiri Pirkodfd15822014-01-07 15:55:45 +01001506 ipv4_devconf_setall(in_dev);
1507 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 inet_insert_ifa(ifa);
1509 }
1510 }
1511 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001512 /* fall through */
1513 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001514 if (!IN_DEV_ARP_NOTIFY(in_dev))
1515 break;
1516 /* fall through */
1517 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001518 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001519 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 break;
1521 case NETDEV_DOWN:
1522 ip_mc_down(in_dev);
1523 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001524 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001525 ip_mc_unmap(in_dev);
1526 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001527 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001528 ip_mc_remap(in_dev);
1529 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001531 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 break;
Breno Leitao06770842008-09-02 17:28:58 -07001533 /* disable IP when MTU is not enough */
Gustavo A. R. Silvafcfd6df2017-10-16 15:48:55 -05001534 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 case NETDEV_UNREGISTER:
1536 inetdev_destroy(in_dev);
1537 break;
1538 case NETDEV_CHANGENAME:
1539 /* Do not notify about label change, this event is
1540 * not interesting to applications using netlink.
1541 */
1542 inetdev_changename(dev, in_dev);
1543
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001544 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001545 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 break;
1547 }
1548out:
1549 return NOTIFY_DONE;
1550}
1551
1552static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001553 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554};
1555
Eric Dumazet40384992012-08-03 21:06:50 +00001556static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001557{
1558 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1559 + nla_total_size(4) /* IFA_ADDRESS */
1560 + nla_total_size(4) /* IFA_LOCAL */
1561 + nla_total_size(4) /* IFA_BROADCAST */
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001562 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001563 + nla_total_size(4) /* IFA_FLAGS */
David Ahernaf4d7682018-05-27 08:09:57 -07001564 + nla_total_size(4) /* IFA_RT_PRIORITY */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001565 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
Thomas Graf339bf982006-11-10 14:10:15 -08001566}
1567
Jiri Pirko5c766d62013-01-24 09:41:41 +00001568static inline u32 cstamp_delta(unsigned long cstamp)
1569{
1570 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1571}
1572
1573static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1574 unsigned long tstamp, u32 preferred, u32 valid)
1575{
1576 struct ifa_cacheinfo ci;
1577
1578 ci.cstamp = cstamp_delta(cstamp);
1579 ci.tstamp = cstamp_delta(tstamp);
1580 ci.ifa_prefered = preferred;
1581 ci.ifa_valid = valid;
1582
1583 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1584}
1585
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001587 u32 portid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588{
1589 struct ifaddrmsg *ifm;
1590 struct nlmsghdr *nlh;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001591 u32 preferred, valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
Eric W. Biederman15e47302012-09-07 20:12:54 +00001593 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
Ian Morris51456b22015-04-03 09:17:26 +01001594 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08001595 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001596
1597 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 ifm->ifa_family = AF_INET;
1599 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001600 ifm->ifa_flags = ifa->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 ifm->ifa_scope = ifa->ifa_scope;
1602 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603
Jiri Pirko5c766d62013-01-24 09:41:41 +00001604 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1605 preferred = ifa->ifa_preferred_lft;
1606 valid = ifa->ifa_valid_lft;
1607 if (preferred != INFINITY_LIFE_TIME) {
1608 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1609
1610 if (preferred > tval)
1611 preferred -= tval;
1612 else
1613 preferred = 0;
1614 if (valid != INFINITY_LIFE_TIME) {
1615 if (valid > tval)
1616 valid -= tval;
1617 else
1618 valid = 0;
1619 }
1620 }
1621 } else {
1622 preferred = INFINITY_LIFE_TIME;
1623 valid = INFINITY_LIFE_TIME;
1624 }
David S. Millerf3756b72012-04-01 20:39:02 -04001625 if ((ifa->ifa_address &&
Jiri Benc930345e2015-03-29 16:59:25 +02001626 nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001627 (ifa->ifa_local &&
Jiri Benc930345e2015-03-29 16:59:25 +02001628 nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001629 (ifa->ifa_broadcast &&
Jiri Benc930345e2015-03-29 16:59:25 +02001630 nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001631 (ifa->ifa_label[0] &&
Jiri Pirko5c766d62013-01-24 09:41:41 +00001632 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001633 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
David Ahernaf4d7682018-05-27 08:09:57 -07001634 (ifa->ifa_rt_priority &&
1635 nla_put_u32(skb, IFA_RT_PRIORITY, ifa->ifa_rt_priority)) ||
Jiri Pirko5c766d62013-01-24 09:41:41 +00001636 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1637 preferred, valid))
David S. Millerf3756b72012-04-01 20:39:02 -04001638 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001639
Johannes Berg053c0952015-01-16 22:09:00 +01001640 nlmsg_end(skb, nlh);
1641 return 0;
Thomas Graf47f68512006-08-04 23:04:36 -07001642
1643nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001644 nlmsg_cancel(skb, nlh);
1645 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646}
1647
1648static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1649{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001650 struct net *net = sock_net(skb->sk);
Eric Dumazeteec4df92009-11-12 07:44:25 +00001651 int h, s_h;
1652 int idx, s_idx;
1653 int ip_idx, s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 struct net_device *dev;
1655 struct in_device *in_dev;
1656 struct in_ifaddr *ifa;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001657 struct hlist_head *head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658
Eric Dumazeteec4df92009-11-12 07:44:25 +00001659 s_h = cb->args[0];
1660 s_idx = idx = cb->args[1];
1661 s_ip_idx = ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662
Eric Dumazeteec4df92009-11-12 07:44:25 +00001663 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1664 idx = 0;
1665 head = &net->dev_index_head[h];
1666 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001667 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1668 net->dev_base_seq;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001669 hlist_for_each_entry_rcu(dev, head, index_hlist) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001670 if (idx < s_idx)
1671 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001672 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001673 s_ip_idx = 0;
1674 in_dev = __in_dev_get_rcu(dev);
1675 if (!in_dev)
1676 goto cont;
1677
1678 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1679 ifa = ifa->ifa_next, ip_idx++) {
1680 if (ip_idx < s_ip_idx)
1681 continue;
1682 if (inet_fill_ifaddr(skb, ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001683 NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 cb->nlh->nlmsg_seq,
Johannes Berg053c0952015-01-16 22:09:00 +01001685 RTM_NEWADDR, NLM_F_MULTI) < 0) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001686 rcu_read_unlock();
1687 goto done;
1688 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001689 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Eric Dumazeteec4df92009-11-12 07:44:25 +00001690 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001691cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001692 idx++;
1693 }
1694 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 }
1696
1697done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001698 cb->args[0] = h;
1699 cb->args[1] = idx;
1700 cb->args[2] = ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701
1702 return skb->len;
1703}
1704
Jianjun Kong539afed2008-11-03 02:48:48 -08001705static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001706 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707{
Thomas Graf47f68512006-08-04 23:04:36 -07001708 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001709 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1710 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001711 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001713 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001714 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001715 if (!skb)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001716 goto errout;
1717
Eric W. Biederman15e47302012-09-07 20:12:54 +00001718 err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001719 if (err < 0) {
1720 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1721 WARN_ON(err == -EMSGSIZE);
1722 kfree_skb(skb);
1723 goto errout;
1724 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001725 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001726 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001727errout:
1728 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001729 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730}
1731
Arad, Ronenb1974ed2015-10-19 09:23:28 -07001732static size_t inet_get_link_af_size(const struct net_device *dev,
1733 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001734{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001735 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001736
1737 if (!in_dev)
1738 return 0;
1739
1740 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1741}
1742
Sowmini Varadhand5566fd2015-09-11 16:48:48 -04001743static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
1744 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001745{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001746 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001747 struct nlattr *nla;
1748 int i;
1749
1750 if (!in_dev)
1751 return -ENODATA;
1752
1753 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
Ian Morris51456b22015-04-03 09:17:26 +01001754 if (!nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001755 return -EMSGSIZE;
1756
1757 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1758 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1759
1760 return 0;
1761}
1762
1763static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1764 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1765};
1766
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001767static int inet_validate_link_af(const struct net_device *dev,
1768 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001769{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001770 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1771 int err, rem;
1772
Florian Westphal5fa85a02017-10-16 15:44:36 +02001773 if (dev && !__in_dev_get_rcu(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001774 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001775
Johannes Bergfceb6432017-04-12 14:34:07 +02001776 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy, NULL);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001777 if (err < 0)
1778 return err;
1779
1780 if (tb[IFLA_INET_CONF]) {
1781 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1782 int cfgid = nla_type(a);
1783
1784 if (nla_len(a) < 4)
1785 return -EINVAL;
1786
1787 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1788 return -EINVAL;
1789 }
1790 }
1791
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001792 return 0;
1793}
1794
1795static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1796{
Florian Westphal5fa85a02017-10-16 15:44:36 +02001797 struct in_device *in_dev = __in_dev_get_rcu(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001798 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1799 int rem;
1800
1801 if (!in_dev)
1802 return -EAFNOSUPPORT;
1803
Johannes Bergfceb6432017-04-12 14:34:07 +02001804 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0)
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001805 BUG();
1806
Thomas Graf9f0f7272010-11-16 04:32:48 +00001807 if (tb[IFLA_INET_CONF]) {
1808 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1809 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1810 }
1811
1812 return 0;
1813}
1814
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001815static int inet_netconf_msgsize_devconf(int type)
1816{
1817 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1818 + nla_total_size(4); /* NETCONFA_IFINDEX */
Zhang Shengju136ba622016-03-10 08:55:50 +00001819 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001820
Zhang Shengju136ba622016-03-10 08:55:50 +00001821 if (type == NETCONFA_ALL)
1822 all = true;
1823
1824 if (all || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001825 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001826 if (all || type == NETCONFA_RP_FILTER)
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001827 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001828 if (all || type == NETCONFA_MC_FORWARDING)
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001829 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001830 if (all || type == NETCONFA_PROXY_NEIGH)
stephen hemmingerf085ff12013-12-12 13:06:50 -08001831 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001832 if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001833 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001834
1835 return size;
1836}
1837
1838static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1839 struct ipv4_devconf *devconf, u32 portid,
1840 u32 seq, int event, unsigned int flags,
1841 int type)
1842{
1843 struct nlmsghdr *nlh;
1844 struct netconfmsg *ncm;
Zhang Shengju136ba622016-03-10 08:55:50 +00001845 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001846
1847 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1848 flags);
Ian Morris51456b22015-04-03 09:17:26 +01001849 if (!nlh)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001850 return -EMSGSIZE;
1851
Zhang Shengju136ba622016-03-10 08:55:50 +00001852 if (type == NETCONFA_ALL)
1853 all = true;
1854
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001855 ncm = nlmsg_data(nlh);
1856 ncm->ncm_family = AF_INET;
1857
1858 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1859 goto nla_put_failure;
1860
David Ahernb5c96412017-03-28 14:28:03 -07001861 if (!devconf)
1862 goto out;
1863
Zhang Shengju136ba622016-03-10 08:55:50 +00001864 if ((all || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001865 nla_put_s32(skb, NETCONFA_FORWARDING,
1866 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1867 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001868 if ((all || type == NETCONFA_RP_FILTER) &&
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001869 nla_put_s32(skb, NETCONFA_RP_FILTER,
1870 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
1871 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001872 if ((all || type == NETCONFA_MC_FORWARDING) &&
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001873 nla_put_s32(skb, NETCONFA_MC_FORWARDING,
1874 IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
1875 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001876 if ((all || type == NETCONFA_PROXY_NEIGH) &&
stephen hemminger09aea5d2013-12-17 22:35:52 -08001877 nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08001878 IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
1879 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001880 if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001881 nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
1882 IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
1883 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001884
David Ahernb5c96412017-03-28 14:28:03 -07001885out:
Johannes Berg053c0952015-01-16 22:09:00 +01001886 nlmsg_end(skb, nlh);
1887 return 0;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001888
1889nla_put_failure:
1890 nlmsg_cancel(skb, nlh);
1891 return -EMSGSIZE;
1892}
1893
David Ahern3b022862017-03-28 14:28:02 -07001894void inet_netconf_notify_devconf(struct net *net, int event, int type,
1895 int ifindex, struct ipv4_devconf *devconf)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001896{
1897 struct sk_buff *skb;
1898 int err = -ENOBUFS;
1899
Eric Dumazetfa178062016-07-08 05:18:24 +02001900 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001901 if (!skb)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001902 goto errout;
1903
1904 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
David Ahern3b022862017-03-28 14:28:02 -07001905 event, 0, type);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001906 if (err < 0) {
1907 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1908 WARN_ON(err == -EMSGSIZE);
1909 kfree_skb(skb);
1910 goto errout;
1911 }
Eric Dumazetfa178062016-07-08 05:18:24 +02001912 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001913 return;
1914errout:
1915 if (err < 0)
1916 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
1917}
1918
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001919static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
1920 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
1921 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001922 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
stephen hemminger09aea5d2013-12-17 22:35:52 -08001923 [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) },
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001924 [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001925};
1926
1927static int inet_netconf_get_devconf(struct sk_buff *in_skb,
David Ahernc21ef3e2017-04-16 09:48:24 -07001928 struct nlmsghdr *nlh,
1929 struct netlink_ext_ack *extack)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001930{
1931 struct net *net = sock_net(in_skb->sk);
1932 struct nlattr *tb[NETCONFA_MAX+1];
1933 struct netconfmsg *ncm;
1934 struct sk_buff *skb;
1935 struct ipv4_devconf *devconf;
1936 struct in_device *in_dev;
1937 struct net_device *dev;
1938 int ifindex;
1939 int err;
1940
1941 err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
David Ahernc21ef3e2017-04-16 09:48:24 -07001942 devconf_ipv4_policy, extack);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001943 if (err < 0)
1944 goto errout;
1945
Anton Protopopova97eb332016-02-16 21:43:16 -05001946 err = -EINVAL;
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001947 if (!tb[NETCONFA_IFINDEX])
1948 goto errout;
1949
1950 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
1951 switch (ifindex) {
1952 case NETCONFA_IFINDEX_ALL:
1953 devconf = net->ipv4.devconf_all;
1954 break;
1955 case NETCONFA_IFINDEX_DEFAULT:
1956 devconf = net->ipv4.devconf_dflt;
1957 break;
1958 default:
1959 dev = __dev_get_by_index(net, ifindex);
Ian Morris51456b22015-04-03 09:17:26 +01001960 if (!dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001961 goto errout;
1962 in_dev = __in_dev_get_rtnl(dev);
Ian Morris51456b22015-04-03 09:17:26 +01001963 if (!in_dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001964 goto errout;
1965 devconf = &in_dev->cnf;
1966 break;
1967 }
1968
1969 err = -ENOBUFS;
Eric Dumazetfa178062016-07-08 05:18:24 +02001970 skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001971 if (!skb)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001972 goto errout;
1973
1974 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
1975 NETLINK_CB(in_skb).portid,
1976 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
Zhang Shengju136ba622016-03-10 08:55:50 +00001977 NETCONFA_ALL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001978 if (err < 0) {
1979 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1980 WARN_ON(err == -EMSGSIZE);
1981 kfree_skb(skb);
1982 goto errout;
1983 }
1984 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
1985errout:
1986 return err;
1987}
1988
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001989static int inet_netconf_dump_devconf(struct sk_buff *skb,
1990 struct netlink_callback *cb)
1991{
1992 struct net *net = sock_net(skb->sk);
1993 int h, s_h;
1994 int idx, s_idx;
1995 struct net_device *dev;
1996 struct in_device *in_dev;
1997 struct hlist_head *head;
1998
1999 s_h = cb->args[0];
2000 s_idx = idx = cb->args[1];
2001
2002 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
2003 idx = 0;
2004 head = &net->dev_index_head[h];
2005 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00002006 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
2007 net->dev_base_seq;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002008 hlist_for_each_entry_rcu(dev, head, index_hlist) {
2009 if (idx < s_idx)
2010 goto cont;
2011 in_dev = __in_dev_get_rcu(dev);
2012 if (!in_dev)
2013 goto cont;
2014
2015 if (inet_netconf_fill_devconf(skb, dev->ifindex,
2016 &in_dev->cnf,
2017 NETLINK_CB(cb->skb).portid,
2018 cb->nlh->nlmsg_seq,
2019 RTM_NEWNETCONF,
2020 NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002021 NETCONFA_ALL) < 0) {
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002022 rcu_read_unlock();
2023 goto done;
2024 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00002025 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002026cont:
2027 idx++;
2028 }
2029 rcu_read_unlock();
2030 }
2031 if (h == NETDEV_HASHENTRIES) {
2032 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
2033 net->ipv4.devconf_all,
2034 NETLINK_CB(cb->skb).portid,
2035 cb->nlh->nlmsg_seq,
2036 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002037 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002038 goto done;
2039 else
2040 h++;
2041 }
2042 if (h == NETDEV_HASHENTRIES + 1) {
2043 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
2044 net->ipv4.devconf_dflt,
2045 NETLINK_CB(cb->skb).portid,
2046 cb->nlh->nlmsg_seq,
2047 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002048 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002049 goto done;
2050 else
2051 h++;
2052 }
2053done:
2054 cb->args[0] = h;
2055 cb->args[1] = idx;
2056
2057 return skb->len;
2058}
2059
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060#ifdef CONFIG_SYSCTL
2061
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002062static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07002063{
2064 struct net_device *dev;
2065
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002066 rcu_read_lock();
2067 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07002068 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002069
Herbert Xu31be3082007-06-04 23:35:37 -07002070 in_dev = __in_dev_get_rcu(dev);
2071 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002072 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07002073 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002074 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07002075}
2076
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002077/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002078static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002079{
2080 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002081 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002082
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002083 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002084 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
David Ahern3b022862017-03-28 14:28:02 -07002085 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2086 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002087 NETCONFA_IFINDEX_ALL,
2088 net->ipv4.devconf_all);
David Ahern3b022862017-03-28 14:28:02 -07002089 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2090 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002091 NETCONFA_IFINDEX_DEFAULT,
2092 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002093
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002094 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002095 struct in_device *in_dev;
Eric Dumazetfa178062016-07-08 05:18:24 +02002096
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002097 if (on)
2098 dev_disable_lro(dev);
Eric Dumazetfa178062016-07-08 05:18:24 +02002099
2100 in_dev = __in_dev_get_rtnl(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002101 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002102 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
David Ahern3b022862017-03-28 14:28:02 -07002103 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2104 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002105 dev->ifindex, &in_dev->cnf);
2106 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002107 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002108}
2109
stephen hemmingerf085ff12013-12-12 13:06:50 -08002110static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf)
2111{
2112 if (cnf == net->ipv4.devconf_dflt)
2113 return NETCONFA_IFINDEX_DEFAULT;
2114 else if (cnf == net->ipv4.devconf_all)
2115 return NETCONFA_IFINDEX_ALL;
2116 else {
2117 struct in_device *idev
2118 = container_of(cnf, struct in_device, cnf);
2119 return idev->dev->ifindex;
2120 }
2121}
2122
Joe Perchesfe2c6332013-06-11 23:04:25 -07002123static int devinet_conf_proc(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002124 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07002125 size_t *lenp, loff_t *ppos)
2126{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002127 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002128 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002129 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07002130
2131 if (write) {
2132 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002133 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07002134 int i = (int *)ctl->data - cnf->data;
stephen hemmingerf085ff12013-12-12 13:06:50 -08002135 int ifindex;
Herbert Xu31be3082007-06-04 23:35:37 -07002136
2137 set_bit(i, cnf->state);
2138
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002139 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002140 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00002141 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
2142 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002143 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002144 rt_cache_flush(net);
stephen hemmingerf085ff12013-12-12 13:06:50 -08002145
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002146 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
2147 new_value != old_value) {
stephen hemmingerf085ff12013-12-12 13:06:50 -08002148 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002149 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2150 NETCONFA_RP_FILTER,
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002151 ifindex, cnf);
2152 }
stephen hemmingerf085ff12013-12-12 13:06:50 -08002153 if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
2154 new_value != old_value) {
2155 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002156 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2157 NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002158 ifindex, cnf);
2159 }
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002160 if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
2161 new_value != old_value) {
2162 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002163 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2164 NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002165 ifindex, cnf);
2166 }
Herbert Xu31be3082007-06-04 23:35:37 -07002167 }
2168
2169 return ret;
2170}
2171
Joe Perchesfe2c6332013-06-11 23:04:25 -07002172static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002173 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 size_t *lenp, loff_t *ppos)
2175{
2176 int *valp = ctl->data;
2177 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00002178 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002179 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180
2181 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002182 struct net *net = ctl->extra2;
2183
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002184 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00002185 if (!rtnl_trylock()) {
2186 /* Restore the original values before restarting */
2187 *valp = val;
2188 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00002189 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00002190 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002191 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2192 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002193 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002194 struct ipv4_devconf *cnf = ctl->extra1;
2195 struct in_device *idev =
2196 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002197 if (*valp)
2198 dev_disable_lro(idev->dev);
David Ahern3b022862017-03-28 14:28:02 -07002199 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002200 NETCONFA_FORWARDING,
2201 idev->dev->ifindex,
2202 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002203 }
2204 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002205 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002206 } else
David Ahern3b022862017-03-28 14:28:02 -07002207 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2208 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002209 NETCONFA_IFINDEX_DEFAULT,
2210 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 }
2212
2213 return ret;
2214}
2215
Joe Perchesfe2c6332013-06-11 23:04:25 -07002216static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
David S. Miller323e1262010-12-12 21:55:08 -08002217 void __user *buffer,
2218 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219{
2220 int *valp = ctl->data;
2221 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002222 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07002223 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224
2225 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002226 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227
2228 return ret;
2229}
2230
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002231#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07002232 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07002233 .procname = name, \
2234 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00002235 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002236 .maxlen = sizeof(int), \
2237 .mode = mval, \
2238 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07002239 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002240 }
2241
2242#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002243 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002244
2245#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002246 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002247
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002248#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2249 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002250
2251#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002252 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07002253
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254static struct devinet_sysctl_table {
2255 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00002256 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257} devinet_sysctl = {
2258 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07002259 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002260 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07002261 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
2262
2263 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
2264 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
2265 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
2266 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
2267 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
2268 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
2269 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00002270 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08002271 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002272 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
2273 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
2274 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
2275 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
2276 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
2277 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
2278 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
2279 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
2280 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08002281 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00002282 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
William Manley5c6fe012013-08-06 19:03:14 +01002283 DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
2284 "force_igmp_version"),
William Manley26900482013-08-06 19:03:15 +01002285 DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
2286 "igmpv2_unsolicited_report_interval"),
2287 DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
2288 "igmpv3_unsolicited_report_interval"),
Andy Gospodarek0eeb0752015-06-23 13:45:37 -04002289 DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
2290 "ignore_routes_with_linkdown"),
Johannes Berg97daf332016-02-04 13:31:18 +01002291 DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
2292 "drop_gratuitous_arp"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002293
2294 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2295 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002296 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
2297 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00002298 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2299 "route_localnet"),
Johannes Berg12b74df2016-02-04 13:31:17 +01002300 DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
2301 "drop_unicast_in_l2_multicast"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303};
2304
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002305static int __devinet_sysctl_register(struct net *net, char *dev_name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002306 int ifindex, struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307{
2308 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002309 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002310 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11002311
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002312 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002314 goto out;
2315
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
2317 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07002318 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002319 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 }
2321
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002322 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002324 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002326 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327
2328 p->sysctl = t;
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002329
David Ahern3b022862017-03-28 14:28:02 -07002330 inet_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_ALL,
2331 ifindex, p);
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002332 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002334free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002336out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002337 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338}
2339
David Ahernb5c96412017-03-28 14:28:03 -07002340static void __devinet_sysctl_unregister(struct net *net,
2341 struct ipv4_devconf *cnf, int ifindex)
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002342{
2343 struct devinet_sysctl_table *t = cnf->sysctl;
2344
David Ahernb5c96412017-03-28 14:28:03 -07002345 if (t) {
2346 cnf->sysctl = NULL;
2347 unregister_net_sysctl_table(t->sysctl_header);
2348 kfree(t);
2349 }
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002350
David Ahernb5c96412017-03-28 14:28:03 -07002351 inet_netconf_notify_devconf(net, RTM_DELNETCONF, 0, ifindex, NULL);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002352}
2353
WANG Cong20e61da2014-07-25 15:25:08 -07002354static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002355{
WANG Cong20e61da2014-07-25 15:25:08 -07002356 int err;
2357
2358 if (!sysctl_dev_name_is_allowed(idev->dev->name))
2359 return -EINVAL;
2360
2361 err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
2362 if (err)
2363 return err;
2364 err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002365 idev->dev->ifindex, &idev->cnf);
WANG Cong20e61da2014-07-25 15:25:08 -07002366 if (err)
2367 neigh_sysctl_unregister(idev->arp_parms);
2368 return err;
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002369}
2370
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002371static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372{
David Ahernb5c96412017-03-28 14:28:03 -07002373 struct net *net = dev_net(idev->dev);
2374
2375 __devinet_sysctl_unregister(net, &idev->cnf, idev->dev->ifindex);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002376 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002379static struct ctl_table ctl_forward_entry[] = {
2380 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002381 .procname = "ip_forward",
2382 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00002383 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002384 .maxlen = sizeof(int),
2385 .mode = 0644,
2386 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002387 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002388 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002389 },
2390 { },
2391};
Eric Dumazet2a75de02008-01-05 23:08:49 -08002392#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002393
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002394static __net_init int devinet_init_net(struct net *net)
2395{
2396 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002397 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002398#ifdef CONFIG_SYSCTL
2399 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002400 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002401#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002402
2403 err = -ENOMEM;
2404 all = &ipv4_devconf;
2405 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002406
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002407 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002408 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002409 if (!all)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002410 goto err_alloc_all;
2411
2412 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002413 if (!dflt)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002414 goto err_alloc_dflt;
2415
Eric Dumazet2a75de02008-01-05 23:08:49 -08002416#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002417 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002418 if (!tbl)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002419 goto err_alloc_ctl;
2420
Eric W. Biederman02291682010-02-14 03:25:51 +00002421 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002422 tbl[0].extra1 = all;
2423 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002424#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002425 }
2426
2427#ifdef CONFIG_SYSCTL
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002428 err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002429 if (err < 0)
2430 goto err_reg_all;
2431
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002432 err = __devinet_sysctl_register(net, "default",
2433 NETCONFA_IFINDEX_DEFAULT, dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002434 if (err < 0)
2435 goto err_reg_dflt;
2436
2437 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002438 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Ian Morris51456b22015-04-03 09:17:26 +01002439 if (!forw_hdr)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002440 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002441 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002442#endif
2443
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002444 net->ipv4.devconf_all = all;
2445 net->ipv4.devconf_dflt = dflt;
2446 return 0;
2447
2448#ifdef CONFIG_SYSCTL
2449err_reg_ctl:
David Ahernb5c96412017-03-28 14:28:03 -07002450 __devinet_sysctl_unregister(net, dflt, NETCONFA_IFINDEX_DEFAULT);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002451err_reg_dflt:
David Ahernb5c96412017-03-28 14:28:03 -07002452 __devinet_sysctl_unregister(net, all, NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002453err_reg_all:
2454 if (tbl != ctl_forward_entry)
2455 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002456err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08002457#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002458 if (dflt != &ipv4_devconf_dflt)
2459 kfree(dflt);
2460err_alloc_dflt:
2461 if (all != &ipv4_devconf)
2462 kfree(all);
2463err_alloc_all:
2464 return err;
2465}
2466
2467static __net_exit void devinet_exit_net(struct net *net)
2468{
Eric Dumazet2a75de02008-01-05 23:08:49 -08002469#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002470 struct ctl_table *tbl;
2471
2472 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002473 unregister_net_sysctl_table(net->ipv4.forw_hdr);
David Ahernb5c96412017-03-28 14:28:03 -07002474 __devinet_sysctl_unregister(net, net->ipv4.devconf_dflt,
2475 NETCONFA_IFINDEX_DEFAULT);
2476 __devinet_sysctl_unregister(net, net->ipv4.devconf_all,
2477 NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002478 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08002479#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002480 kfree(net->ipv4.devconf_dflt);
2481 kfree(net->ipv4.devconf_all);
2482}
2483
2484static __net_initdata struct pernet_operations devinet_ops = {
2485 .init = devinet_init_net,
2486 .exit = devinet_exit_net,
2487};
2488
Daniel Borkmann207895f2015-01-29 12:15:03 +01002489static struct rtnl_af_ops inet_af_ops __read_mostly = {
Thomas Graf9f0f7272010-11-16 04:32:48 +00002490 .family = AF_INET,
2491 .fill_link_af = inet_fill_link_af,
2492 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00002493 .validate_link_af = inet_validate_link_af,
2494 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00002495};
2496
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497void __init devinet_init(void)
2498{
David S. Millerfd23c3b2011-02-18 12:42:28 -08002499 int i;
2500
2501 for (i = 0; i < IN4_ADDR_HSIZE; i++)
2502 INIT_HLIST_HEAD(&inet_addr_lst[i]);
2503
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002504 register_pernet_subsys(&devinet_ops);
2505
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 register_gifconf(PF_INET, inet_gifconf);
2507 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07002508
viresh kumar906e0732014-01-22 12:23:32 +05302509 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +00002510
Thomas Graf9f0f7272010-11-16 04:32:48 +00002511 rtnl_af_register(&inet_af_ops);
2512
Florian Westphalb97bac62017-08-09 20:41:48 +02002513 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, 0);
2514 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, 0);
2515 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, 0);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002516 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
Florian Westphalb97bac62017-08-09 20:41:48 +02002517 inet_netconf_dump_devconf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518}