blob: 38d9af9b917c08685deb3288baab84189ec9c9a0 [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 },
Thomas Graf5c753972006-08-04 23:03:53 -0700102};
103
Eric Dumazet40384992012-08-03 21:06:50 +0000104#define IN4_ADDR_HSIZE_SHIFT 8
105#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT)
106
David S. Millerfd23c3b2011-02-18 12:42:28 -0800107static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
David S. Millerfd23c3b2011-02-18 12:42:28 -0800108
Eric Dumazet6eada012015-03-18 14:05:33 -0700109static u32 inet_addr_hash(const struct net *net, __be32 addr)
David S. Millerfd23c3b2011-02-18 12:42:28 -0800110{
Eric Dumazet40384992012-08-03 21:06:50 +0000111 u32 val = (__force u32) addr ^ net_hash_mix(net);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800112
Eric Dumazet40384992012-08-03 21:06:50 +0000113 return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800114}
115
116static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
117{
Eric Dumazet40384992012-08-03 21:06:50 +0000118 u32 hash = inet_addr_hash(net, ifa->ifa_local);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800119
WANG Cong32a4be42014-05-06 11:15:56 -0700120 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800121 hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800122}
123
124static void inet_hash_remove(struct in_ifaddr *ifa)
125{
WANG Cong32a4be42014-05-06 11:15:56 -0700126 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800127 hlist_del_init_rcu(&ifa->hash);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800128}
129
David S. Miller9435eb12011-02-18 12:43:09 -0800130/**
131 * __ip_dev_find - find the first device with a given source address.
132 * @net: the net namespace
133 * @addr: the source address
134 * @devref: if true, take a reference on the found device
135 *
136 * If a caller uses devref=false, it should be protected by RCU, or RTNL
137 */
138struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
139{
Eric Dumazet40384992012-08-03 21:06:50 +0000140 u32 hash = inet_addr_hash(net, addr);
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();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800145 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash) {
David S. Millere0660082011-03-03 11:24:19 -0800146 if (ifa->ifa_local == addr) {
Eric Dumazet40384992012-08-03 21:06:50 +0000147 struct net_device *dev = ifa->ifa_dev->dev;
148
149 if (!net_eq(dev_net(dev), net))
150 continue;
David S. Miller9435eb12011-02-18 12:43:09 -0800151 result = dev;
152 break;
153 }
154 }
David S. Miller406b6f92011-03-22 21:56:23 -0700155 if (!result) {
156 struct flowi4 fl4 = { .daddr = addr };
157 struct fib_result res = { 0 };
158 struct fib_table *local;
159
160 /* Fallback to FIB local table so that communication
161 * over loopback subnets work.
162 */
163 local = fib_get_table(net, RT_TABLE_LOCAL);
164 if (local &&
165 !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
166 res.type == RTN_LOCAL)
167 result = FIB_RES_DEV(res);
168 }
David S. Miller9435eb12011-02-18 12:43:09 -0800169 if (result && devref)
170 dev_hold(result);
171 rcu_read_unlock();
172 return result;
173}
174EXPORT_SYMBOL(__ip_dev_find);
175
Thomas Grafd6062cb2006-08-15 00:33:59 -0700176static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
Alan Sterne041c682006-03-27 01:16:30 -0800178static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Krister Johansen3ad7d242017-06-08 13:12:14 -0700179static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
181 int destroy);
182#ifdef CONFIG_SYSCTL
WANG Cong20e61da2014-07-25 15:25:08 -0700183static int devinet_sysctl_register(struct in_device *idev);
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800184static void devinet_sysctl_unregister(struct in_device *idev);
185#else
WANG Cong20e61da2014-07-25 15:25:08 -0700186static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800187{
WANG Cong20e61da2014-07-25 15:25:08 -0700188 return 0;
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800189}
Eric Dumazet40384992012-08-03 21:06:50 +0000190static void devinet_sysctl_unregister(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800191{
192}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193#endif
194
195/* Locks all the inet devices. */
196
197static struct in_ifaddr *inet_alloc_ifa(void)
198{
Alexey Dobriyan93adcc82008-10-28 13:25:09 -0700199 return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200}
201
202static void inet_rcu_free_ifa(struct rcu_head *head)
203{
204 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
205 if (ifa->ifa_dev)
206 in_dev_put(ifa->ifa_dev);
207 kfree(ifa);
208}
209
Eric Dumazet40384992012-08-03 21:06:50 +0000210static void inet_free_ifa(struct in_ifaddr *ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211{
212 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
213}
214
215void in_dev_finish_destroy(struct in_device *idev)
216{
217 struct net_device *dev = idev->dev;
218
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700219 WARN_ON(idev->ifa_list);
220 WARN_ON(idev->mc_list);
Eric Dumazete9897072013-06-07 08:48:57 -0700221 kfree(rcu_dereference_protected(idev->mc_hash, 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222#ifdef NET_REFCNT_DEBUG
Joe Perches91df42b2012-05-15 14:11:54 +0000223 pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224#endif
225 dev_put(dev);
226 if (!idev->dead)
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800227 pr_err("Freeing alive in_device %p\n", idev);
228 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 kfree(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800231EXPORT_SYMBOL(in_dev_finish_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
Herbert Xu71e27da2007-06-04 23:36:06 -0700233static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234{
235 struct in_device *in_dev;
WANG Cong20e61da2014-07-25 15:25:08 -0700236 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
238 ASSERT_RTNL();
239
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700240 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 if (!in_dev)
242 goto out;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900243 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -0800244 sizeof(in_dev->cnf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 in_dev->cnf.sysctl = NULL;
246 in_dev->dev = dev;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800247 in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
248 if (!in_dev->arp_parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 goto out_kfree;
Ben Hutchings0187bdf2008-06-19 16:15:47 -0700250 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
251 dev_disable_lro(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 /* Reference in_dev->dev */
253 dev_hold(dev);
David L Stevens30c4cf52007-01-04 12:31:14 -0800254 /* Account for reference dev->ip_ptr (below) */
Reshetova, Elena7658b362017-06-30 13:08:03 +0300255 refcount_set(&in_dev->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
WANG Cong20e61da2014-07-25 15:25:08 -0700257 err = devinet_sysctl_register(in_dev);
258 if (err) {
259 in_dev->dead = 1;
260 in_dev_put(in_dev);
261 in_dev = NULL;
262 goto out;
263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 ip_mc_init_dev(in_dev);
265 if (dev->flags & IFF_UP)
266 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800267
David L Stevens30c4cf52007-01-04 12:31:14 -0800268 /* we can receive as soon as ip_ptr is set -- do this last */
Eric Dumazetcf778b02012-01-12 04:41:32 +0000269 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800270out:
WANG Cong20e61da2014-07-25 15:25:08 -0700271 return in_dev ?: ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272out_kfree:
273 kfree(in_dev);
274 in_dev = NULL;
275 goto out;
276}
277
278static void in_dev_rcu_put(struct rcu_head *head)
279{
280 struct in_device *idev = container_of(head, struct in_device, rcu_head);
281 in_dev_put(idev);
282}
283
284static void inetdev_destroy(struct in_device *in_dev)
285{
286 struct in_ifaddr *ifa;
287 struct net_device *dev;
288
289 ASSERT_RTNL();
290
291 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
293 in_dev->dead = 1;
294
295 ip_mc_destroy_dev(in_dev);
296
297 while ((ifa = in_dev->ifa_list) != NULL) {
298 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
299 inet_free_ifa(ifa);
300 }
301
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000302 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800304 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
306 arp_ifdown(dev);
307
308 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
309}
310
Al Viroff428d72006-09-26 22:13:35 -0700311int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312{
313 rcu_read_lock();
314 for_primary_ifa(in_dev) {
315 if (inet_ifa_match(a, ifa)) {
316 if (!b || inet_ifa_match(b, ifa)) {
317 rcu_read_unlock();
318 return 1;
319 }
320 }
321 } endfor_ifa(in_dev);
322 rcu_read_unlock();
323 return 0;
324}
325
Thomas Grafd6062cb2006-08-15 00:33:59 -0700326static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000327 int destroy, struct nlmsghdr *nlh, u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328{
Harald Welte8f937c62005-05-29 20:23:46 -0700329 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800330 struct in_ifaddr *ifa, *ifa1 = *ifap;
331 struct in_ifaddr *last_prim = in_dev->ifa_list;
332 struct in_ifaddr *prev_prom = NULL;
333 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
335 ASSERT_RTNL();
336
David S. Millerfbd40ea2016-03-13 23:28:00 -0400337 if (in_dev->dead)
338 goto no_promotions;
339
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900340 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700341 * unless alias promotion is set
342 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
344 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
346
347 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900348 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800349 ifa1->ifa_scope <= ifa->ifa_scope)
350 last_prim = ifa;
351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
353 ifa1->ifa_mask != ifa->ifa_mask ||
354 !inet_ifa_match(ifa1->ifa_address, ifa)) {
355 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800356 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 continue;
358 }
359
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800360 if (!do_promote) {
David S. Millerfd23c3b2011-02-18 12:42:28 -0800361 inet_hash_remove(ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700362 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
Eric W. Biederman15e47302012-09-07 20:12:54 +0000364 rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800365 blocking_notifier_call_chain(&inetaddr_chain,
366 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700367 inet_free_ifa(ifa);
368 } else {
369 promote = ifa;
370 break;
371 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 }
373 }
374
Julian Anastasov2d230e22011-03-19 12:13:52 +0000375 /* On promotion all secondaries from subnet are changing
376 * the primary IP, we must remove all their routes silently
377 * and later to add them back with new prefsrc. Do this
378 * while all addresses are on the device list.
379 */
380 for (ifa = promote; ifa; ifa = ifa->ifa_next) {
381 if (ifa1->ifa_mask == ifa->ifa_mask &&
382 inet_ifa_match(ifa1->ifa_address, ifa))
383 fib_del_ifaddr(ifa, ifa1);
384 }
385
David S. Millerfbd40ea2016-03-13 23:28:00 -0400386no_promotions:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 /* 2. Unlink it */
388
389 *ifap = ifa1->ifa_next;
David S. Millerfd23c3b2011-02-18 12:42:28 -0800390 inet_hash_remove(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
392 /* 3. Announce address deletion */
393
394 /* Send message first, then call notifier.
395 At first sight, FIB update triggered by notifier
396 will refer to already deleted ifaddr, that could confuse
397 netlink listeners. It is not true: look, gated sees
398 that route deleted and if it still thinks that ifaddr
399 is valid, it will try to restore deleted routes... Grr.
400 So that, this order is correct.
401 */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000402 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800403 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800404
405 if (promote) {
Julian Anastasov04024b92011-03-19 12:13:54 +0000406 struct in_ifaddr *next_sec = promote->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800407
408 if (prev_prom) {
409 prev_prom->ifa_next = promote->ifa_next;
410 promote->ifa_next = last_prim->ifa_next;
411 last_prim->ifa_next = promote;
412 }
413
414 promote->ifa_flags &= ~IFA_F_SECONDARY;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000415 rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800416 blocking_notifier_call_chain(&inetaddr_chain,
417 NETDEV_UP, promote);
Julian Anastasov04024b92011-03-19 12:13:54 +0000418 for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800419 if (ifa1->ifa_mask != ifa->ifa_mask ||
420 !inet_ifa_match(ifa1->ifa_address, ifa))
421 continue;
422 fib_add_ifaddr(ifa);
423 }
424
425 }
Herbert Xu63630972007-06-07 18:35:38 -0700426 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428}
429
Thomas Grafd6062cb2006-08-15 00:33:59 -0700430static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
431 int destroy)
432{
433 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
434}
435
Jiri Pirko5c766d62013-01-24 09:41:41 +0000436static void check_lifetime(struct work_struct *work);
437
438static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
439
Thomas Grafd6062cb2006-08-15 00:33:59 -0700440static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000441 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442{
443 struct in_device *in_dev = ifa->ifa_dev;
444 struct in_ifaddr *ifa1, **ifap, **last_primary;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700445 struct in_validator_info ivi;
446 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
448 ASSERT_RTNL();
449
450 if (!ifa->ifa_local) {
451 inet_free_ifa(ifa);
452 return 0;
453 }
454
455 ifa->ifa_flags &= ~IFA_F_SECONDARY;
456 last_primary = &in_dev->ifa_list;
457
458 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
459 ifap = &ifa1->ifa_next) {
460 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
461 ifa->ifa_scope <= ifa1->ifa_scope)
462 last_primary = &ifa1->ifa_next;
463 if (ifa1->ifa_mask == ifa->ifa_mask &&
464 inet_ifa_match(ifa1->ifa_address, ifa)) {
465 if (ifa1->ifa_local == ifa->ifa_local) {
466 inet_free_ifa(ifa);
467 return -EEXIST;
468 }
469 if (ifa1->ifa_scope != ifa->ifa_scope) {
470 inet_free_ifa(ifa);
471 return -EINVAL;
472 }
473 ifa->ifa_flags |= IFA_F_SECONDARY;
474 }
475 }
476
Krister Johansen3ad7d242017-06-08 13:12:14 -0700477 /* Allow any devices that wish to register ifaddr validtors to weigh
478 * in now, before changes are committed. The rntl lock is serializing
479 * access here, so the state should not change between a validator call
480 * and a final notify on commit. This isn't invoked on promotion under
481 * the assumption that validators are checking the address itself, and
482 * not the flags.
483 */
484 ivi.ivi_addr = ifa->ifa_address;
485 ivi.ivi_dev = ifa->ifa_dev;
486 ret = blocking_notifier_call_chain(&inetaddr_validator_chain,
487 NETDEV_UP, &ivi);
488 ret = notifier_to_errno(ret);
489 if (ret) {
490 inet_free_ifa(ifa);
491 return ret;
492 }
493
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500495 prandom_seed((__force u32) ifa->ifa_local);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 ifap = last_primary;
497 }
498
499 ifa->ifa_next = *ifap;
500 *ifap = ifa;
501
David S. Millerfd23c3b2011-02-18 12:42:28 -0800502 inet_hash_insert(dev_net(in_dev->dev), ifa);
503
Jiri Pirko5c766d62013-01-24 09:41:41 +0000504 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530505 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000506
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 /* Send message first, then call notifier.
508 Notifier will trigger FIB update, so that
509 listeners of netlink will know about new ifaddr */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000510 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800511 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513 return 0;
514}
515
Thomas Grafd6062cb2006-08-15 00:33:59 -0700516static int inet_insert_ifa(struct in_ifaddr *ifa)
517{
518 return __inet_insert_ifa(ifa, NULL, 0);
519}
520
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
522{
Herbert Xue5ed6392005-10-03 14:35:55 -0700523 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
525 ASSERT_RTNL();
526
527 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700528 inet_free_ifa(ifa);
529 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700531 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100532 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700534 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 in_dev_hold(in_dev);
536 ifa->ifa_dev = in_dev;
537 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800538 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 ifa->ifa_scope = RT_SCOPE_HOST;
540 return inet_insert_ifa(ifa);
541}
542
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000543/* Caller must hold RCU or RTNL :
544 * We dont take a reference on found in_device
545 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800546struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547{
548 struct net_device *dev;
549 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000550
551 rcu_read_lock();
552 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000554 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000555 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 return in_dev;
557}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800558EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559
560/* Called only from RTNL semaphored context. No locks. */
561
Al Viro60cad5d2006-09-26 22:17:09 -0700562struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
563 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564{
565 ASSERT_RTNL();
566
567 for_primary_ifa(in_dev) {
568 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
569 return ifa;
570 } endfor_ifa(in_dev);
571 return NULL;
572}
573
Madhu Challa93a714d2015-02-25 09:58:35 -0800574static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa)
575{
576 struct ip_mreqn mreq = {
577 .imr_multiaddr.s_addr = ifa->ifa_address,
578 .imr_ifindex = ifa->ifa_dev->dev->ifindex,
579 };
580 int ret;
581
582 ASSERT_RTNL();
583
584 lock_sock(sk);
585 if (join)
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300586 ret = ip_mc_join_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800587 else
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300588 ret = ip_mc_leave_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800589 release_sock(sk);
590
591 return ret;
592}
593
David Ahernc21ef3e2017-04-16 09:48:24 -0700594static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
595 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900597 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700598 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700600 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700602 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
604 ASSERT_RTNL();
605
Johannes Bergfceb6432017-04-12 14:34:07 +0200606 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -0700607 extack);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700608 if (err < 0)
609 goto errout;
610
611 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800612 in_dev = inetdev_by_index(net, ifm->ifa_index);
Ian Morris51456b22015-04-03 09:17:26 +0100613 if (!in_dev) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700614 err = -ENODEV;
615 goto errout;
616 }
617
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
619 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700620 if (tb[IFA_LOCAL] &&
Jiri Benc67b61f62015-03-29 16:59:26 +0200621 ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700623
624 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
625 continue;
626
627 if (tb[IFA_ADDRESS] &&
628 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Jiri Benc67b61f62015-03-29 16:59:26 +0200629 !inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700630 continue;
631
Madhu Challa93a714d2015-02-25 09:58:35 -0800632 if (ipv4_is_multicast(ifa->ifa_address))
633 ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000634 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 return 0;
636 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700637
638 err = -EADDRNOTAVAIL;
639errout:
640 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641}
642
Jiri Pirko5c766d62013-01-24 09:41:41 +0000643#define INFINITY_LIFE_TIME 0xFFFFFFFF
644
645static void check_lifetime(struct work_struct *work)
646{
647 unsigned long now, next, next_sec, next_sched;
648 struct in_ifaddr *ifa;
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000649 struct hlist_node *n;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000650 int i;
651
652 now = jiffies;
653 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
654
Jiri Pirko5c766d62013-01-24 09:41:41 +0000655 for (i = 0; i < IN4_ADDR_HSIZE; i++) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000656 bool change_needed = false;
657
658 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800659 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
Jiri Pirko5c766d62013-01-24 09:41:41 +0000660 unsigned long age;
661
662 if (ifa->ifa_flags & IFA_F_PERMANENT)
663 continue;
664
665 /* We try to batch several events at once. */
666 age = (now - ifa->ifa_tstamp +
667 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
668
669 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
670 age >= ifa->ifa_valid_lft) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000671 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000672 } else if (ifa->ifa_preferred_lft ==
673 INFINITY_LIFE_TIME) {
674 continue;
675 } else if (age >= ifa->ifa_preferred_lft) {
676 if (time_before(ifa->ifa_tstamp +
677 ifa->ifa_valid_lft * HZ, next))
678 next = ifa->ifa_tstamp +
679 ifa->ifa_valid_lft * HZ;
680
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000681 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
682 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000683 } else if (time_before(ifa->ifa_tstamp +
684 ifa->ifa_preferred_lft * HZ,
685 next)) {
686 next = ifa->ifa_tstamp +
687 ifa->ifa_preferred_lft * HZ;
688 }
689 }
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000690 rcu_read_unlock();
691 if (!change_needed)
692 continue;
693 rtnl_lock();
694 hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
695 unsigned long age;
696
697 if (ifa->ifa_flags & IFA_F_PERMANENT)
698 continue;
699
700 /* We try to batch several events at once. */
701 age = (now - ifa->ifa_tstamp +
702 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
703
704 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
705 age >= ifa->ifa_valid_lft) {
706 struct in_ifaddr **ifap;
707
708 for (ifap = &ifa->ifa_dev->ifa_list;
709 *ifap != NULL; ifap = &(*ifap)->ifa_next) {
710 if (*ifap == ifa) {
711 inet_del_ifa(ifa->ifa_dev,
712 ifap, 1);
713 break;
714 }
715 }
716 } else if (ifa->ifa_preferred_lft !=
717 INFINITY_LIFE_TIME &&
718 age >= ifa->ifa_preferred_lft &&
719 !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
720 ifa->ifa_flags |= IFA_F_DEPRECATED;
721 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
722 }
723 }
724 rtnl_unlock();
Jiri Pirko5c766d62013-01-24 09:41:41 +0000725 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000726
727 next_sec = round_jiffies_up(next);
728 next_sched = next;
729
730 /* If rounded timeout is accurate enough, accept it. */
731 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
732 next_sched = next_sec;
733
734 now = jiffies;
735 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
736 if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
737 next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
738
viresh kumar906e0732014-01-22 12:23:32 +0530739 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work,
740 next_sched - now);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000741}
742
743static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
744 __u32 prefered_lft)
745{
746 unsigned long timeout;
747
748 ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
749
750 timeout = addrconf_timeout_fixup(valid_lft, HZ);
751 if (addrconf_finite_timeout(timeout))
752 ifa->ifa_valid_lft = timeout;
753 else
754 ifa->ifa_flags |= IFA_F_PERMANENT;
755
756 timeout = addrconf_timeout_fixup(prefered_lft, HZ);
757 if (addrconf_finite_timeout(timeout)) {
758 if (timeout == 0)
759 ifa->ifa_flags |= IFA_F_DEPRECATED;
760 ifa->ifa_preferred_lft = timeout;
761 }
762 ifa->ifa_tstamp = jiffies;
763 if (!ifa->ifa_cstamp)
764 ifa->ifa_cstamp = ifa->ifa_tstamp;
765}
766
767static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
768 __u32 *pvalid_lft, __u32 *pprefered_lft)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769{
Thomas Graf5c753972006-08-04 23:03:53 -0700770 struct nlattr *tb[IFA_MAX+1];
771 struct in_ifaddr *ifa;
772 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 struct net_device *dev;
774 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800775 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
Johannes Bergfceb6432017-04-12 14:34:07 +0200777 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
778 NULL);
Thomas Graf5c753972006-08-04 23:03:53 -0700779 if (err < 0)
780 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
Thomas Graf5c753972006-08-04 23:03:53 -0700782 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800783 err = -EINVAL;
Ian Morris51456b22015-04-03 09:17:26 +0100784 if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL])
Thomas Graf5c753972006-08-04 23:03:53 -0700785 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800787 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800788 err = -ENODEV;
Ian Morris51456b22015-04-03 09:17:26 +0100789 if (!dev)
Thomas Graf5c753972006-08-04 23:03:53 -0700790 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
Thomas Graf5c753972006-08-04 23:03:53 -0700792 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800793 err = -ENOBUFS;
Ian Morris51456b22015-04-03 09:17:26 +0100794 if (!in_dev)
Herbert Xu71e27da2007-06-04 23:36:06 -0700795 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
Thomas Graf5c753972006-08-04 23:03:53 -0700797 ifa = inet_alloc_ifa();
Ian Morris51456b22015-04-03 09:17:26 +0100798 if (!ifa)
Thomas Graf5c753972006-08-04 23:03:53 -0700799 /*
800 * A potential indev allocation can be left alive, it stays
801 * assigned to its device and is destroy with it.
802 */
Thomas Graf5c753972006-08-04 23:03:53 -0700803 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700804
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800805 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100806 neigh_parms_data_state_setall(in_dev->arp_parms);
Thomas Graf5c753972006-08-04 23:03:53 -0700807 in_dev_hold(in_dev);
808
Ian Morris51456b22015-04-03 09:17:26 +0100809 if (!tb[IFA_ADDRESS])
Thomas Graf5c753972006-08-04 23:03:53 -0700810 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
811
David S. Millerfd23c3b2011-02-18 12:42:28 -0800812 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
814 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100815 ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
816 ifm->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700818 ifa->ifa_dev = in_dev;
819
Jiri Benc67b61f62015-03-29 16:59:26 +0200820 ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]);
821 ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700822
823 if (tb[IFA_BROADCAST])
Jiri Benc67b61f62015-03-29 16:59:26 +0200824 ifa->ifa_broadcast = nla_get_in_addr(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700825
Thomas Graf5c753972006-08-04 23:03:53 -0700826 if (tb[IFA_LABEL])
827 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 else
829 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
830
Jiri Pirko5c766d62013-01-24 09:41:41 +0000831 if (tb[IFA_CACHEINFO]) {
832 struct ifa_cacheinfo *ci;
833
834 ci = nla_data(tb[IFA_CACHEINFO]);
835 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
836 err = -EINVAL;
Daniel Borkmann446266b2013-08-02 11:32:43 +0200837 goto errout_free;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000838 }
839 *pvalid_lft = ci->ifa_valid;
840 *pprefered_lft = ci->ifa_prefered;
841 }
842
Thomas Graf5c753972006-08-04 23:03:53 -0700843 return ifa;
844
Daniel Borkmann446266b2013-08-02 11:32:43 +0200845errout_free:
846 inet_free_ifa(ifa);
Thomas Graf5c753972006-08-04 23:03:53 -0700847errout:
848 return ERR_PTR(err);
849}
850
Jiri Pirko5c766d62013-01-24 09:41:41 +0000851static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
852{
853 struct in_device *in_dev = ifa->ifa_dev;
854 struct in_ifaddr *ifa1, **ifap;
855
856 if (!ifa->ifa_local)
857 return NULL;
858
859 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
860 ifap = &ifa1->ifa_next) {
861 if (ifa1->ifa_mask == ifa->ifa_mask &&
862 inet_ifa_match(ifa1->ifa_address, ifa) &&
863 ifa1->ifa_local == ifa->ifa_local)
864 return ifa1;
865 }
866 return NULL;
867}
868
David Ahernc21ef3e2017-04-16 09:48:24 -0700869static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
870 struct netlink_ext_ack *extack)
Thomas Graf5c753972006-08-04 23:03:53 -0700871{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900872 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700873 struct in_ifaddr *ifa;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000874 struct in_ifaddr *ifa_existing;
875 __u32 valid_lft = INFINITY_LIFE_TIME;
876 __u32 prefered_lft = INFINITY_LIFE_TIME;
Thomas Graf5c753972006-08-04 23:03:53 -0700877
878 ASSERT_RTNL();
879
Jiri Pirko5c766d62013-01-24 09:41:41 +0000880 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft);
Thomas Graf5c753972006-08-04 23:03:53 -0700881 if (IS_ERR(ifa))
882 return PTR_ERR(ifa);
883
Jiri Pirko5c766d62013-01-24 09:41:41 +0000884 ifa_existing = find_matching_ifa(ifa);
885 if (!ifa_existing) {
886 /* It would be best to check for !NLM_F_CREATE here but
stephen hemminger614d0562014-05-16 20:46:58 -0700887 * userspace already relies on not having to provide this.
Jiri Pirko5c766d62013-01-24 09:41:41 +0000888 */
889 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Madhu Challa93a714d2015-02-25 09:58:35 -0800890 if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
891 int ret = ip_mc_config(net->ipv4.mc_autojoin_sk,
892 true, ifa);
893
894 if (ret < 0) {
895 inet_free_ifa(ifa);
896 return ret;
897 }
898 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000899 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
900 } else {
901 inet_free_ifa(ifa);
902
903 if (nlh->nlmsg_flags & NLM_F_EXCL ||
904 !(nlh->nlmsg_flags & NLM_F_REPLACE))
905 return -EEXIST;
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000906 ifa = ifa_existing;
907 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Jiri Pirko05a324b2013-04-04 23:39:38 +0000908 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530909 queue_delayed_work(system_power_efficient_wq,
910 &check_lifetime_work, 0);
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000911 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000912 }
913 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914}
915
916/*
917 * Determine a default network mask, based on the IP address.
918 */
919
Eric Dumazet40384992012-08-03 21:06:50 +0000920static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921{
922 int rc = -1; /* Something else, probably a multicast. */
923
Joe Perchesf97c1e02007-12-16 13:45:43 -0800924 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900925 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 else {
Al Viro714e85b2006-11-14 20:51:49 -0800927 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
Al Viro714e85b2006-11-14 20:51:49 -0800929 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800931 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800933 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 rc = 24;
935 }
936
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900937 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938}
939
940
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800941int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942{
943 struct ifreq ifr;
944 struct sockaddr_in sin_orig;
945 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
946 struct in_device *in_dev;
947 struct in_ifaddr **ifap = NULL;
948 struct in_ifaddr *ifa = NULL;
949 struct net_device *dev;
950 char *colon;
951 int ret = -EFAULT;
952 int tryaddrmatch = 0;
953
954 /*
955 * Fetch the caller's info block into kernel space
956 */
957
958 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
959 goto out;
960 ifr.ifr_name[IFNAMSIZ - 1] = 0;
961
962 /* save original address for comparison */
963 memcpy(&sin_orig, sin, sizeof(*sin));
964
965 colon = strchr(ifr.ifr_name, ':');
966 if (colon)
967 *colon = 0;
968
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800969 dev_load(net, ifr.ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Stephen Hemminger132adf52007-03-08 20:44:43 -0800971 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 case SIOCGIFADDR: /* Get interface address */
973 case SIOCGIFBRDADDR: /* Get the broadcast address */
974 case SIOCGIFDSTADDR: /* Get the destination address */
975 case SIOCGIFNETMASK: /* Get the netmask for the interface */
976 /* Note that these ioctls will not sleep,
977 so that we do not impose a lock.
978 One day we will be forced to put shlock here (I mean SMP)
979 */
980 tryaddrmatch = (sin_orig.sin_family == AF_INET);
981 memset(sin, 0, sizeof(*sin));
982 sin->sin_family = AF_INET;
983 break;
984
985 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000986 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000987 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 goto out;
989 break;
990 case SIOCSIFADDR: /* Set interface address (and family) */
991 case SIOCSIFBRDADDR: /* Set the broadcast address */
992 case SIOCSIFDSTADDR: /* Set the destination address */
993 case SIOCSIFNETMASK: /* Set the netmask for the interface */
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000994 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000995 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 goto out;
997 ret = -EINVAL;
998 if (sin->sin_family != AF_INET)
999 goto out;
1000 break;
1001 default:
1002 ret = -EINVAL;
1003 goto out;
1004 }
1005
1006 rtnl_lock();
1007
1008 ret = -ENODEV;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001009 dev = __dev_get_by_name(net, ifr.ifr_name);
1010 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 goto done;
1012
1013 if (colon)
1014 *colon = ':';
1015
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001016 in_dev = __in_dev_get_rtnl(dev);
1017 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 if (tryaddrmatch) {
1019 /* Matthias Andree */
1020 /* compare label and address (4.4BSD style) */
1021 /* note: we only do this for a limited set of ioctls
1022 and only if the original address family was AF_INET.
1023 This is checked above. */
1024 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1025 ifap = &ifa->ifa_next) {
1026 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
1027 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -08001028 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 break; /* found */
1030 }
1031 }
1032 }
1033 /* we didn't get a match, maybe the application is
1034 4.3BSD-style and passed in junk so we fall back to
1035 comparing just the label */
1036 if (!ifa) {
1037 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1038 ifap = &ifa->ifa_next)
1039 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
1040 break;
1041 }
1042 }
1043
1044 ret = -EADDRNOTAVAIL;
1045 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
1046 goto done;
1047
Stephen Hemminger132adf52007-03-08 20:44:43 -08001048 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 case SIOCGIFADDR: /* Get interface address */
1050 sin->sin_addr.s_addr = ifa->ifa_local;
1051 goto rarok;
1052
1053 case SIOCGIFBRDADDR: /* Get the broadcast address */
1054 sin->sin_addr.s_addr = ifa->ifa_broadcast;
1055 goto rarok;
1056
1057 case SIOCGIFDSTADDR: /* Get the destination address */
1058 sin->sin_addr.s_addr = ifa->ifa_address;
1059 goto rarok;
1060
1061 case SIOCGIFNETMASK: /* Get the netmask for the interface */
1062 sin->sin_addr.s_addr = ifa->ifa_mask;
1063 goto rarok;
1064
1065 case SIOCSIFFLAGS:
1066 if (colon) {
1067 ret = -EADDRNOTAVAIL;
1068 if (!ifa)
1069 break;
1070 ret = 0;
1071 if (!(ifr.ifr_flags & IFF_UP))
1072 inet_del_ifa(in_dev, ifap, 1);
1073 break;
1074 }
1075 ret = dev_change_flags(dev, ifr.ifr_flags);
1076 break;
1077
1078 case SIOCSIFADDR: /* Set interface address (and family) */
1079 ret = -EINVAL;
1080 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1081 break;
1082
1083 if (!ifa) {
1084 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001085 ifa = inet_alloc_ifa();
1086 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 break;
Xi Wangc7e2e1d2013-01-05 11:19:24 +00001088 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 if (colon)
1090 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
1091 else
1092 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1093 } else {
1094 ret = 0;
1095 if (ifa->ifa_local == sin->sin_addr.s_addr)
1096 break;
1097 inet_del_ifa(in_dev, ifap, 0);
1098 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -08001099 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 }
1101
1102 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
1103
1104 if (!(dev->flags & IFF_POINTOPOINT)) {
1105 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
1106 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
1107 if ((dev->flags & IFF_BROADCAST) &&
1108 ifa->ifa_prefixlen < 31)
1109 ifa->ifa_broadcast = ifa->ifa_address |
1110 ~ifa->ifa_mask;
1111 } else {
1112 ifa->ifa_prefixlen = 32;
1113 ifa->ifa_mask = inet_make_mask(32);
1114 }
Jiri Pirko5c766d62013-01-24 09:41:41 +00001115 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 ret = inet_set_ifa(dev, ifa);
1117 break;
1118
1119 case SIOCSIFBRDADDR: /* Set the broadcast address */
1120 ret = 0;
1121 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
1122 inet_del_ifa(in_dev, ifap, 0);
1123 ifa->ifa_broadcast = sin->sin_addr.s_addr;
1124 inet_insert_ifa(ifa);
1125 }
1126 break;
1127
1128 case SIOCSIFDSTADDR: /* Set the destination address */
1129 ret = 0;
1130 if (ifa->ifa_address == sin->sin_addr.s_addr)
1131 break;
1132 ret = -EINVAL;
1133 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1134 break;
1135 ret = 0;
1136 inet_del_ifa(in_dev, ifap, 0);
1137 ifa->ifa_address = sin->sin_addr.s_addr;
1138 inet_insert_ifa(ifa);
1139 break;
1140
1141 case SIOCSIFNETMASK: /* Set the netmask for the interface */
1142
1143 /*
1144 * The mask we set must be legal.
1145 */
1146 ret = -EINVAL;
1147 if (bad_mask(sin->sin_addr.s_addr, 0))
1148 break;
1149 ret = 0;
1150 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -07001151 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 inet_del_ifa(in_dev, ifap, 0);
1153 ifa->ifa_mask = sin->sin_addr.s_addr;
1154 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
1155
1156 /* See if current broadcast address matches
1157 * with current netmask, then recalculate
1158 * the broadcast address. Otherwise it's a
1159 * funny address, so don't touch it since
1160 * the user seems to know what (s)he's doing...
1161 */
1162 if ((dev->flags & IFF_BROADCAST) &&
1163 (ifa->ifa_prefixlen < 31) &&
1164 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -05001165 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 ifa->ifa_broadcast = (ifa->ifa_local |
1167 ~sin->sin_addr.s_addr);
1168 }
1169 inet_insert_ifa(ifa);
1170 }
1171 break;
1172 }
1173done:
1174 rtnl_unlock();
1175out:
1176 return ret;
1177rarok:
1178 rtnl_unlock();
1179 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
1180 goto out;
1181}
1182
1183static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
1184{
Herbert Xue5ed6392005-10-03 14:35:55 -07001185 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 struct in_ifaddr *ifa;
1187 struct ifreq ifr;
1188 int done = 0;
1189
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001190 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 goto out;
1192
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001193 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 if (!buf) {
1195 done += sizeof(ifr);
1196 continue;
1197 }
1198 if (len < (int) sizeof(ifr))
1199 break;
1200 memset(&ifr, 0, sizeof(struct ifreq));
Dan Carpenter4299c8a2013-07-29 22:15:19 +03001201 strcpy(ifr.ifr_name, ifa->ifa_label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202
1203 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
1204 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1205 ifa->ifa_local;
1206
1207 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
1208 done = -EFAULT;
1209 break;
1210 }
1211 buf += sizeof(struct ifreq);
1212 len -= sizeof(struct ifreq);
1213 done += sizeof(struct ifreq);
1214 }
1215out:
1216 return done;
1217}
1218
Gao Feng8b57fd12017-03-10 12:38:47 +08001219static __be32 in_dev_select_addr(const struct in_device *in_dev,
1220 int scope)
1221{
1222 for_primary_ifa(in_dev) {
1223 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1224 ifa->ifa_scope <= scope)
1225 return ifa->ifa_local;
1226 } endfor_ifa(in_dev);
1227
1228 return 0;
1229}
1230
Al Viroa61ced52006-09-26 21:27:54 -07001231__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232{
Al Viroa61ced52006-09-26 21:27:54 -07001233 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001235 struct net *net = dev_net(dev);
David Ahern3f2fb9a2016-02-24 11:47:02 -08001236 int master_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237
1238 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001239 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 if (!in_dev)
1241 goto no_in_dev;
1242
1243 for_primary_ifa(in_dev) {
1244 if (ifa->ifa_scope > scope)
1245 continue;
1246 if (!dst || inet_ifa_match(dst, ifa)) {
1247 addr = ifa->ifa_local;
1248 break;
1249 }
1250 if (!addr)
1251 addr = ifa->ifa_local;
1252 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
1254 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001255 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001256no_in_dev:
David Ahern3f2fb9a2016-02-24 11:47:02 -08001257 master_idx = l3mdev_master_ifindex_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258
David Lamparter17b693c2016-02-24 11:47:03 -08001259 /* For VRFs, the VRF device takes the place of the loopback device,
1260 * with addresses on it being preferred. Note in such cases the
1261 * loopback device will be among the devices that fail the master_idx
1262 * equality check in the loop below.
1263 */
1264 if (master_idx &&
1265 (dev = dev_get_by_index_rcu(net, master_idx)) &&
1266 (in_dev = __in_dev_get_rcu(dev))) {
Gao Feng8b57fd12017-03-10 12:38:47 +08001267 addr = in_dev_select_addr(in_dev, scope);
1268 if (addr)
1269 goto out_unlock;
David Lamparter17b693c2016-02-24 11:47:03 -08001270 }
1271
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 /* Not loopback addresses on loopback should be preferred
Stephen Hemmingerca9f1fd2015-02-14 13:47:54 -05001273 in this case. It is important that lo is the first interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 in dev_base list.
1275 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001276 for_each_netdev_rcu(net, dev) {
David Ahern3f2fb9a2016-02-24 11:47:02 -08001277 if (l3mdev_master_ifindex_rcu(dev) != master_idx)
1278 continue;
1279
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001280 in_dev = __in_dev_get_rcu(dev);
1281 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 continue;
1283
Gao Feng8b57fd12017-03-10 12:38:47 +08001284 addr = in_dev_select_addr(in_dev, scope);
1285 if (addr)
1286 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001288out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 return addr;
1291}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001292EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
Al Viro60cad5d2006-09-26 22:17:09 -07001294static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1295 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296{
1297 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001298 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
1300 for_ifa(in_dev) {
1301 if (!addr &&
1302 (local == ifa->ifa_local || !local) &&
1303 ifa->ifa_scope <= scope) {
1304 addr = ifa->ifa_local;
1305 if (same)
1306 break;
1307 }
1308 if (!same) {
1309 same = (!local || inet_ifa_match(local, ifa)) &&
1310 (!dst || inet_ifa_match(dst, ifa));
1311 if (same && addr) {
1312 if (local || !dst)
1313 break;
1314 /* Is the selected addr into dst subnet? */
1315 if (inet_ifa_match(addr, ifa))
1316 break;
1317 /* No, then can we use new local src? */
1318 if (ifa->ifa_scope <= scope) {
1319 addr = ifa->ifa_local;
1320 break;
1321 }
1322 /* search for large dst subnet for addr */
1323 same = 0;
1324 }
1325 }
1326 } endfor_ifa(in_dev);
1327
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001328 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329}
1330
1331/*
1332 * Confirm that local IP address exists using wildcards:
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001333 * - net: netns to check, cannot be NULL
1334 * - in_dev: only on this interface, NULL=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 * - dst: only in the same subnet as dst, 0=any dst
1336 * - local: address, 0=autoselect the local address
1337 * - scope: maximum allowed scope value for the local address
1338 */
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001339__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001340 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341{
Al Viro60cad5d2006-09-26 22:17:09 -07001342 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001343 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344
Ian Morris00db4122015-04-03 09:17:27 +01001345 if (in_dev)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001346 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001349 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001350 in_dev = __in_dev_get_rcu(dev);
1351 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 addr = confirm_addr_indev(in_dev, dst, local, scope);
1353 if (addr)
1354 break;
1355 }
1356 }
1357 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
1359 return addr;
1360}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001361EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362
1363/*
1364 * Device notifier
1365 */
1366
1367int register_inetaddr_notifier(struct notifier_block *nb)
1368{
Alan Sterne041c682006-03-27 01:16:30 -08001369 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001371EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
1373int unregister_inetaddr_notifier(struct notifier_block *nb)
1374{
Alan Sterne041c682006-03-27 01:16:30 -08001375 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001377EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
Krister Johansen3ad7d242017-06-08 13:12:14 -07001379int register_inetaddr_validator_notifier(struct notifier_block *nb)
1380{
1381 return blocking_notifier_chain_register(&inetaddr_validator_chain, nb);
1382}
1383EXPORT_SYMBOL(register_inetaddr_validator_notifier);
1384
1385int unregister_inetaddr_validator_notifier(struct notifier_block *nb)
1386{
1387 return blocking_notifier_chain_unregister(&inetaddr_validator_chain,
1388 nb);
1389}
1390EXPORT_SYMBOL(unregister_inetaddr_validator_notifier);
1391
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001392/* Rename ifa_labels for a device name change. Make some effort to preserve
1393 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394*/
1395static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001396{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 struct in_ifaddr *ifa;
1398 int named = 0;
1399
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001400 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1401 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
1403 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001404 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001406 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001407 dot = strchr(old, ':');
Ian Morris51456b22015-04-03 09:17:26 +01001408 if (!dot) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001409 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 dot = old;
1411 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001412 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001413 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001414 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001415 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001416skip:
1417 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001418 }
1419}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420
Eric Dumazet40384992012-08-03 21:06:50 +00001421static bool inetdev_valid_mtu(unsigned int mtu)
Breno Leitao06770842008-09-02 17:28:58 -07001422{
1423 return mtu >= 68;
1424}
1425
Ian Campbelld11327ad2011-02-11 07:44:16 +00001426static void inetdev_send_gratuitous_arp(struct net_device *dev,
1427 struct in_device *in_dev)
1428
1429{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001430 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001431
Zoltan Kissb76d0782011-07-24 13:09:30 +00001432 for (ifa = in_dev->ifa_list; ifa;
1433 ifa = ifa->ifa_next) {
1434 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1435 ifa->ifa_local, dev,
1436 ifa->ifa_local, NULL,
1437 dev->dev_addr, NULL);
1438 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001439}
1440
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441/* Called only under RTNL semaphore */
1442
1443static int inetdev_event(struct notifier_block *this, unsigned long event,
1444 void *ptr)
1445{
Jiri Pirko351638e2013-05-28 01:30:21 +00001446 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazet748e2d92012-08-22 21:50:59 +00001447 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
1449 ASSERT_RTNL();
1450
1451 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001452 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 in_dev = inetdev_init(dev);
WANG Cong20e61da2014-07-25 15:25:08 -07001454 if (IS_ERR(in_dev))
1455 return notifier_from_errno(PTR_ERR(in_dev));
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001456 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001457 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1458 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001459 }
Breno Leitao06770842008-09-02 17:28:58 -07001460 } else if (event == NETDEV_CHANGEMTU) {
1461 /* Re-enabling IP */
1462 if (inetdev_valid_mtu(dev->mtu))
1463 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 }
1465 goto out;
1466 }
1467
1468 switch (event) {
1469 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001470 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001471 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 break;
1473 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001474 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001476 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001477 struct in_ifaddr *ifa = inet_alloc_ifa();
1478
1479 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001480 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 ifa->ifa_local =
1482 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1483 ifa->ifa_prefixlen = 8;
1484 ifa->ifa_mask = inet_make_mask(8);
1485 in_dev_hold(in_dev);
1486 ifa->ifa_dev = in_dev;
1487 ifa->ifa_scope = RT_SCOPE_HOST;
1488 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Jiri Pirko5c766d62013-01-24 09:41:41 +00001489 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1490 INFINITY_LIFE_TIME);
Jiri Pirkodfd15822014-01-07 15:55:45 +01001491 ipv4_devconf_setall(in_dev);
1492 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 inet_insert_ifa(ifa);
1494 }
1495 }
1496 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001497 /* fall through */
1498 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001499 if (!IN_DEV_ARP_NOTIFY(in_dev))
1500 break;
1501 /* fall through */
1502 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001503 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001504 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 break;
1506 case NETDEV_DOWN:
1507 ip_mc_down(in_dev);
1508 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001509 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001510 ip_mc_unmap(in_dev);
1511 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001512 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001513 ip_mc_remap(in_dev);
1514 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001516 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 break;
Breno Leitao06770842008-09-02 17:28:58 -07001518 /* disable IP when MTU is not enough */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 case NETDEV_UNREGISTER:
1520 inetdev_destroy(in_dev);
1521 break;
1522 case NETDEV_CHANGENAME:
1523 /* Do not notify about label change, this event is
1524 * not interesting to applications using netlink.
1525 */
1526 inetdev_changename(dev, in_dev);
1527
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001528 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001529 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 break;
1531 }
1532out:
1533 return NOTIFY_DONE;
1534}
1535
1536static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001537 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538};
1539
Eric Dumazet40384992012-08-03 21:06:50 +00001540static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001541{
1542 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1543 + nla_total_size(4) /* IFA_ADDRESS */
1544 + nla_total_size(4) /* IFA_LOCAL */
1545 + nla_total_size(4) /* IFA_BROADCAST */
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001546 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001547 + nla_total_size(4) /* IFA_FLAGS */
1548 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
Thomas Graf339bf982006-11-10 14:10:15 -08001549}
1550
Jiri Pirko5c766d62013-01-24 09:41:41 +00001551static inline u32 cstamp_delta(unsigned long cstamp)
1552{
1553 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1554}
1555
1556static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1557 unsigned long tstamp, u32 preferred, u32 valid)
1558{
1559 struct ifa_cacheinfo ci;
1560
1561 ci.cstamp = cstamp_delta(cstamp);
1562 ci.tstamp = cstamp_delta(tstamp);
1563 ci.ifa_prefered = preferred;
1564 ci.ifa_valid = valid;
1565
1566 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1567}
1568
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001570 u32 portid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571{
1572 struct ifaddrmsg *ifm;
1573 struct nlmsghdr *nlh;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001574 u32 preferred, valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
Eric W. Biederman15e47302012-09-07 20:12:54 +00001576 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
Ian Morris51456b22015-04-03 09:17:26 +01001577 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08001578 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001579
1580 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 ifm->ifa_family = AF_INET;
1582 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001583 ifm->ifa_flags = ifa->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 ifm->ifa_scope = ifa->ifa_scope;
1585 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
Jiri Pirko5c766d62013-01-24 09:41:41 +00001587 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1588 preferred = ifa->ifa_preferred_lft;
1589 valid = ifa->ifa_valid_lft;
1590 if (preferred != INFINITY_LIFE_TIME) {
1591 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1592
1593 if (preferred > tval)
1594 preferred -= tval;
1595 else
1596 preferred = 0;
1597 if (valid != INFINITY_LIFE_TIME) {
1598 if (valid > tval)
1599 valid -= tval;
1600 else
1601 valid = 0;
1602 }
1603 }
1604 } else {
1605 preferred = INFINITY_LIFE_TIME;
1606 valid = INFINITY_LIFE_TIME;
1607 }
David S. Millerf3756b72012-04-01 20:39:02 -04001608 if ((ifa->ifa_address &&
Jiri Benc930345e2015-03-29 16:59:25 +02001609 nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001610 (ifa->ifa_local &&
Jiri Benc930345e2015-03-29 16:59:25 +02001611 nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001612 (ifa->ifa_broadcast &&
Jiri Benc930345e2015-03-29 16:59:25 +02001613 nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001614 (ifa->ifa_label[0] &&
Jiri Pirko5c766d62013-01-24 09:41:41 +00001615 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001616 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
Jiri Pirko5c766d62013-01-24 09:41:41 +00001617 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1618 preferred, valid))
David S. Millerf3756b72012-04-01 20:39:02 -04001619 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001620
Johannes Berg053c0952015-01-16 22:09:00 +01001621 nlmsg_end(skb, nlh);
1622 return 0;
Thomas Graf47f68512006-08-04 23:04:36 -07001623
1624nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001625 nlmsg_cancel(skb, nlh);
1626 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627}
1628
1629static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1630{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001631 struct net *net = sock_net(skb->sk);
Eric Dumazeteec4df92009-11-12 07:44:25 +00001632 int h, s_h;
1633 int idx, s_idx;
1634 int ip_idx, s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 struct net_device *dev;
1636 struct in_device *in_dev;
1637 struct in_ifaddr *ifa;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001638 struct hlist_head *head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639
Eric Dumazeteec4df92009-11-12 07:44:25 +00001640 s_h = cb->args[0];
1641 s_idx = idx = cb->args[1];
1642 s_ip_idx = ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
Eric Dumazeteec4df92009-11-12 07:44:25 +00001644 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1645 idx = 0;
1646 head = &net->dev_index_head[h];
1647 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001648 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1649 net->dev_base_seq;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001650 hlist_for_each_entry_rcu(dev, head, index_hlist) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001651 if (idx < s_idx)
1652 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001653 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001654 s_ip_idx = 0;
1655 in_dev = __in_dev_get_rcu(dev);
1656 if (!in_dev)
1657 goto cont;
1658
1659 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1660 ifa = ifa->ifa_next, ip_idx++) {
1661 if (ip_idx < s_ip_idx)
1662 continue;
1663 if (inet_fill_ifaddr(skb, ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001664 NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 cb->nlh->nlmsg_seq,
Johannes Berg053c0952015-01-16 22:09:00 +01001666 RTM_NEWADDR, NLM_F_MULTI) < 0) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001667 rcu_read_unlock();
1668 goto done;
1669 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001670 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Eric Dumazeteec4df92009-11-12 07:44:25 +00001671 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001672cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001673 idx++;
1674 }
1675 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 }
1677
1678done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001679 cb->args[0] = h;
1680 cb->args[1] = idx;
1681 cb->args[2] = ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682
1683 return skb->len;
1684}
1685
Jianjun Kong539afed2008-11-03 02:48:48 -08001686static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001687 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688{
Thomas Graf47f68512006-08-04 23:04:36 -07001689 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001690 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1691 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001692 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001694 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001695 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001696 if (!skb)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001697 goto errout;
1698
Eric W. Biederman15e47302012-09-07 20:12:54 +00001699 err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001700 if (err < 0) {
1701 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1702 WARN_ON(err == -EMSGSIZE);
1703 kfree_skb(skb);
1704 goto errout;
1705 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001706 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001707 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001708errout:
1709 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001710 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711}
1712
Arad, Ronenb1974ed2015-10-19 09:23:28 -07001713static size_t inet_get_link_af_size(const struct net_device *dev,
1714 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001715{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001716 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001717
1718 if (!in_dev)
1719 return 0;
1720
1721 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1722}
1723
Sowmini Varadhand5566fd2015-09-11 16:48:48 -04001724static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
1725 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001726{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001727 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001728 struct nlattr *nla;
1729 int i;
1730
1731 if (!in_dev)
1732 return -ENODATA;
1733
1734 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
Ian Morris51456b22015-04-03 09:17:26 +01001735 if (!nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001736 return -EMSGSIZE;
1737
1738 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1739 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1740
1741 return 0;
1742}
1743
1744static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1745 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1746};
1747
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001748static int inet_validate_link_af(const struct net_device *dev,
1749 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001750{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001751 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1752 int err, rem;
1753
Eric Dumazetf7fce742010-12-01 06:03:06 +00001754 if (dev && !__in_dev_get_rtnl(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001755 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001756
Johannes Bergfceb6432017-04-12 14:34:07 +02001757 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy, NULL);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001758 if (err < 0)
1759 return err;
1760
1761 if (tb[IFLA_INET_CONF]) {
1762 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1763 int cfgid = nla_type(a);
1764
1765 if (nla_len(a) < 4)
1766 return -EINVAL;
1767
1768 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1769 return -EINVAL;
1770 }
1771 }
1772
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001773 return 0;
1774}
1775
1776static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1777{
Eric Dumazetf7fce742010-12-01 06:03:06 +00001778 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001779 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1780 int rem;
1781
1782 if (!in_dev)
1783 return -EAFNOSUPPORT;
1784
Johannes Bergfceb6432017-04-12 14:34:07 +02001785 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0)
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001786 BUG();
1787
Thomas Graf9f0f7272010-11-16 04:32:48 +00001788 if (tb[IFLA_INET_CONF]) {
1789 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1790 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1791 }
1792
1793 return 0;
1794}
1795
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001796static int inet_netconf_msgsize_devconf(int type)
1797{
1798 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1799 + nla_total_size(4); /* NETCONFA_IFINDEX */
Zhang Shengju136ba622016-03-10 08:55:50 +00001800 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001801
Zhang Shengju136ba622016-03-10 08:55:50 +00001802 if (type == NETCONFA_ALL)
1803 all = true;
1804
1805 if (all || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001806 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001807 if (all || type == NETCONFA_RP_FILTER)
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001808 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001809 if (all || type == NETCONFA_MC_FORWARDING)
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001810 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001811 if (all || type == NETCONFA_PROXY_NEIGH)
stephen hemmingerf085ff12013-12-12 13:06:50 -08001812 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001813 if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001814 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001815
1816 return size;
1817}
1818
1819static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1820 struct ipv4_devconf *devconf, u32 portid,
1821 u32 seq, int event, unsigned int flags,
1822 int type)
1823{
1824 struct nlmsghdr *nlh;
1825 struct netconfmsg *ncm;
Zhang Shengju136ba622016-03-10 08:55:50 +00001826 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001827
1828 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1829 flags);
Ian Morris51456b22015-04-03 09:17:26 +01001830 if (!nlh)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001831 return -EMSGSIZE;
1832
Zhang Shengju136ba622016-03-10 08:55:50 +00001833 if (type == NETCONFA_ALL)
1834 all = true;
1835
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001836 ncm = nlmsg_data(nlh);
1837 ncm->ncm_family = AF_INET;
1838
1839 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1840 goto nla_put_failure;
1841
David Ahernb5c96412017-03-28 14:28:03 -07001842 if (!devconf)
1843 goto out;
1844
Zhang Shengju136ba622016-03-10 08:55:50 +00001845 if ((all || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001846 nla_put_s32(skb, NETCONFA_FORWARDING,
1847 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1848 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001849 if ((all || type == NETCONFA_RP_FILTER) &&
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001850 nla_put_s32(skb, NETCONFA_RP_FILTER,
1851 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
1852 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001853 if ((all || type == NETCONFA_MC_FORWARDING) &&
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001854 nla_put_s32(skb, NETCONFA_MC_FORWARDING,
1855 IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
1856 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001857 if ((all || type == NETCONFA_PROXY_NEIGH) &&
stephen hemminger09aea5d2013-12-17 22:35:52 -08001858 nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08001859 IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
1860 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001861 if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001862 nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
1863 IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
1864 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001865
David Ahernb5c96412017-03-28 14:28:03 -07001866out:
Johannes Berg053c0952015-01-16 22:09:00 +01001867 nlmsg_end(skb, nlh);
1868 return 0;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001869
1870nla_put_failure:
1871 nlmsg_cancel(skb, nlh);
1872 return -EMSGSIZE;
1873}
1874
David Ahern3b022862017-03-28 14:28:02 -07001875void inet_netconf_notify_devconf(struct net *net, int event, int type,
1876 int ifindex, struct ipv4_devconf *devconf)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001877{
1878 struct sk_buff *skb;
1879 int err = -ENOBUFS;
1880
Eric Dumazetfa178062016-07-08 05:18:24 +02001881 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001882 if (!skb)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001883 goto errout;
1884
1885 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
David Ahern3b022862017-03-28 14:28:02 -07001886 event, 0, type);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001887 if (err < 0) {
1888 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1889 WARN_ON(err == -EMSGSIZE);
1890 kfree_skb(skb);
1891 goto errout;
1892 }
Eric Dumazetfa178062016-07-08 05:18:24 +02001893 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001894 return;
1895errout:
1896 if (err < 0)
1897 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
1898}
1899
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001900static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
1901 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
1902 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001903 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
stephen hemminger09aea5d2013-12-17 22:35:52 -08001904 [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) },
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001905 [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001906};
1907
1908static int inet_netconf_get_devconf(struct sk_buff *in_skb,
David Ahernc21ef3e2017-04-16 09:48:24 -07001909 struct nlmsghdr *nlh,
1910 struct netlink_ext_ack *extack)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001911{
1912 struct net *net = sock_net(in_skb->sk);
1913 struct nlattr *tb[NETCONFA_MAX+1];
1914 struct netconfmsg *ncm;
1915 struct sk_buff *skb;
1916 struct ipv4_devconf *devconf;
1917 struct in_device *in_dev;
1918 struct net_device *dev;
1919 int ifindex;
1920 int err;
1921
1922 err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
David Ahernc21ef3e2017-04-16 09:48:24 -07001923 devconf_ipv4_policy, extack);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001924 if (err < 0)
1925 goto errout;
1926
Anton Protopopova97eb332016-02-16 21:43:16 -05001927 err = -EINVAL;
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001928 if (!tb[NETCONFA_IFINDEX])
1929 goto errout;
1930
1931 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
1932 switch (ifindex) {
1933 case NETCONFA_IFINDEX_ALL:
1934 devconf = net->ipv4.devconf_all;
1935 break;
1936 case NETCONFA_IFINDEX_DEFAULT:
1937 devconf = net->ipv4.devconf_dflt;
1938 break;
1939 default:
1940 dev = __dev_get_by_index(net, ifindex);
Ian Morris51456b22015-04-03 09:17:26 +01001941 if (!dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001942 goto errout;
1943 in_dev = __in_dev_get_rtnl(dev);
Ian Morris51456b22015-04-03 09:17:26 +01001944 if (!in_dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001945 goto errout;
1946 devconf = &in_dev->cnf;
1947 break;
1948 }
1949
1950 err = -ENOBUFS;
Eric Dumazetfa178062016-07-08 05:18:24 +02001951 skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001952 if (!skb)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001953 goto errout;
1954
1955 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
1956 NETLINK_CB(in_skb).portid,
1957 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
Zhang Shengju136ba622016-03-10 08:55:50 +00001958 NETCONFA_ALL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001959 if (err < 0) {
1960 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1961 WARN_ON(err == -EMSGSIZE);
1962 kfree_skb(skb);
1963 goto errout;
1964 }
1965 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
1966errout:
1967 return err;
1968}
1969
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001970static int inet_netconf_dump_devconf(struct sk_buff *skb,
1971 struct netlink_callback *cb)
1972{
1973 struct net *net = sock_net(skb->sk);
1974 int h, s_h;
1975 int idx, s_idx;
1976 struct net_device *dev;
1977 struct in_device *in_dev;
1978 struct hlist_head *head;
1979
1980 s_h = cb->args[0];
1981 s_idx = idx = cb->args[1];
1982
1983 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1984 idx = 0;
1985 head = &net->dev_index_head[h];
1986 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001987 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1988 net->dev_base_seq;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001989 hlist_for_each_entry_rcu(dev, head, index_hlist) {
1990 if (idx < s_idx)
1991 goto cont;
1992 in_dev = __in_dev_get_rcu(dev);
1993 if (!in_dev)
1994 goto cont;
1995
1996 if (inet_netconf_fill_devconf(skb, dev->ifindex,
1997 &in_dev->cnf,
1998 NETLINK_CB(cb->skb).portid,
1999 cb->nlh->nlmsg_seq,
2000 RTM_NEWNETCONF,
2001 NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002002 NETCONFA_ALL) < 0) {
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002003 rcu_read_unlock();
2004 goto done;
2005 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00002006 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002007cont:
2008 idx++;
2009 }
2010 rcu_read_unlock();
2011 }
2012 if (h == NETDEV_HASHENTRIES) {
2013 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
2014 net->ipv4.devconf_all,
2015 NETLINK_CB(cb->skb).portid,
2016 cb->nlh->nlmsg_seq,
2017 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002018 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002019 goto done;
2020 else
2021 h++;
2022 }
2023 if (h == NETDEV_HASHENTRIES + 1) {
2024 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
2025 net->ipv4.devconf_dflt,
2026 NETLINK_CB(cb->skb).portid,
2027 cb->nlh->nlmsg_seq,
2028 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002029 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002030 goto done;
2031 else
2032 h++;
2033 }
2034done:
2035 cb->args[0] = h;
2036 cb->args[1] = idx;
2037
2038 return skb->len;
2039}
2040
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041#ifdef CONFIG_SYSCTL
2042
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002043static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07002044{
2045 struct net_device *dev;
2046
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002047 rcu_read_lock();
2048 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07002049 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002050
Herbert Xu31be3082007-06-04 23:35:37 -07002051 in_dev = __in_dev_get_rcu(dev);
2052 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002053 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07002054 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002055 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07002056}
2057
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002058/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002059static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002060{
2061 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002062 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002063
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002064 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002065 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
David Ahern3b022862017-03-28 14:28:02 -07002066 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2067 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002068 NETCONFA_IFINDEX_ALL,
2069 net->ipv4.devconf_all);
David Ahern3b022862017-03-28 14:28:02 -07002070 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2071 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002072 NETCONFA_IFINDEX_DEFAULT,
2073 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002074
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002075 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002076 struct in_device *in_dev;
Eric Dumazetfa178062016-07-08 05:18:24 +02002077
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002078 if (on)
2079 dev_disable_lro(dev);
Eric Dumazetfa178062016-07-08 05:18:24 +02002080
2081 in_dev = __in_dev_get_rtnl(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002082 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002083 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
David Ahern3b022862017-03-28 14:28:02 -07002084 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2085 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002086 dev->ifindex, &in_dev->cnf);
2087 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002088 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002089}
2090
stephen hemmingerf085ff12013-12-12 13:06:50 -08002091static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf)
2092{
2093 if (cnf == net->ipv4.devconf_dflt)
2094 return NETCONFA_IFINDEX_DEFAULT;
2095 else if (cnf == net->ipv4.devconf_all)
2096 return NETCONFA_IFINDEX_ALL;
2097 else {
2098 struct in_device *idev
2099 = container_of(cnf, struct in_device, cnf);
2100 return idev->dev->ifindex;
2101 }
2102}
2103
Joe Perchesfe2c6332013-06-11 23:04:25 -07002104static int devinet_conf_proc(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002105 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07002106 size_t *lenp, loff_t *ppos)
2107{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002108 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002109 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002110 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07002111
2112 if (write) {
2113 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002114 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07002115 int i = (int *)ctl->data - cnf->data;
stephen hemmingerf085ff12013-12-12 13:06:50 -08002116 int ifindex;
Herbert Xu31be3082007-06-04 23:35:37 -07002117
2118 set_bit(i, cnf->state);
2119
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002120 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002121 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00002122 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
2123 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002124 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002125 rt_cache_flush(net);
stephen hemmingerf085ff12013-12-12 13:06:50 -08002126
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002127 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
2128 new_value != old_value) {
stephen hemmingerf085ff12013-12-12 13:06:50 -08002129 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002130 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2131 NETCONFA_RP_FILTER,
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002132 ifindex, cnf);
2133 }
stephen hemmingerf085ff12013-12-12 13:06:50 -08002134 if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
2135 new_value != old_value) {
2136 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002137 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2138 NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002139 ifindex, cnf);
2140 }
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002141 if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
2142 new_value != old_value) {
2143 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002144 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2145 NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002146 ifindex, cnf);
2147 }
Herbert Xu31be3082007-06-04 23:35:37 -07002148 }
2149
2150 return ret;
2151}
2152
Joe Perchesfe2c6332013-06-11 23:04:25 -07002153static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002154 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 size_t *lenp, loff_t *ppos)
2156{
2157 int *valp = ctl->data;
2158 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00002159 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002160 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161
2162 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002163 struct net *net = ctl->extra2;
2164
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002165 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00002166 if (!rtnl_trylock()) {
2167 /* Restore the original values before restarting */
2168 *valp = val;
2169 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00002170 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00002171 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002172 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2173 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002174 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002175 struct ipv4_devconf *cnf = ctl->extra1;
2176 struct in_device *idev =
2177 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002178 if (*valp)
2179 dev_disable_lro(idev->dev);
David Ahern3b022862017-03-28 14:28:02 -07002180 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002181 NETCONFA_FORWARDING,
2182 idev->dev->ifindex,
2183 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002184 }
2185 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002186 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002187 } else
David Ahern3b022862017-03-28 14:28:02 -07002188 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2189 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002190 NETCONFA_IFINDEX_DEFAULT,
2191 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 }
2193
2194 return ret;
2195}
2196
Joe Perchesfe2c6332013-06-11 23:04:25 -07002197static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
David S. Miller323e1262010-12-12 21:55:08 -08002198 void __user *buffer,
2199 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200{
2201 int *valp = ctl->data;
2202 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002203 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07002204 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205
2206 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002207 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208
2209 return ret;
2210}
2211
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002212#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07002213 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07002214 .procname = name, \
2215 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00002216 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002217 .maxlen = sizeof(int), \
2218 .mode = mval, \
2219 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07002220 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002221 }
2222
2223#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002224 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002225
2226#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002227 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002228
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002229#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2230 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002231
2232#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002233 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07002234
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235static struct devinet_sysctl_table {
2236 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00002237 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238} devinet_sysctl = {
2239 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07002240 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002241 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07002242 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
2243
2244 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
2245 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
2246 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
2247 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
2248 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
2249 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
2250 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00002251 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08002252 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002253 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
2254 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
2255 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
2256 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
2257 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
2258 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
2259 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
2260 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
2261 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08002262 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00002263 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
William Manley5c6fe012013-08-06 19:03:14 +01002264 DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
2265 "force_igmp_version"),
William Manley26900482013-08-06 19:03:15 +01002266 DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
2267 "igmpv2_unsolicited_report_interval"),
2268 DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
2269 "igmpv3_unsolicited_report_interval"),
Andy Gospodarek0eeb0752015-06-23 13:45:37 -04002270 DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
2271 "ignore_routes_with_linkdown"),
Johannes Berg97daf332016-02-04 13:31:18 +01002272 DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
2273 "drop_gratuitous_arp"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002274
2275 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2276 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002277 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
2278 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00002279 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2280 "route_localnet"),
Johannes Berg12b74df2016-02-04 13:31:17 +01002281 DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
2282 "drop_unicast_in_l2_multicast"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284};
2285
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002286static int __devinet_sysctl_register(struct net *net, char *dev_name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002287 int ifindex, struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288{
2289 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002290 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002291 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11002292
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002293 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002295 goto out;
2296
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
2298 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07002299 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002300 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 }
2302
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002303 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002305 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002307 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308
2309 p->sysctl = t;
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002310
David Ahern3b022862017-03-28 14:28:02 -07002311 inet_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_ALL,
2312 ifindex, p);
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002313 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002315free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002317out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002318 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319}
2320
David Ahernb5c96412017-03-28 14:28:03 -07002321static void __devinet_sysctl_unregister(struct net *net,
2322 struct ipv4_devconf *cnf, int ifindex)
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002323{
2324 struct devinet_sysctl_table *t = cnf->sysctl;
2325
David Ahernb5c96412017-03-28 14:28:03 -07002326 if (t) {
2327 cnf->sysctl = NULL;
2328 unregister_net_sysctl_table(t->sysctl_header);
2329 kfree(t);
2330 }
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002331
David Ahernb5c96412017-03-28 14:28:03 -07002332 inet_netconf_notify_devconf(net, RTM_DELNETCONF, 0, ifindex, NULL);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002333}
2334
WANG Cong20e61da2014-07-25 15:25:08 -07002335static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002336{
WANG Cong20e61da2014-07-25 15:25:08 -07002337 int err;
2338
2339 if (!sysctl_dev_name_is_allowed(idev->dev->name))
2340 return -EINVAL;
2341
2342 err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
2343 if (err)
2344 return err;
2345 err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002346 idev->dev->ifindex, &idev->cnf);
WANG Cong20e61da2014-07-25 15:25:08 -07002347 if (err)
2348 neigh_sysctl_unregister(idev->arp_parms);
2349 return err;
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002350}
2351
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002352static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353{
David Ahernb5c96412017-03-28 14:28:03 -07002354 struct net *net = dev_net(idev->dev);
2355
2356 __devinet_sysctl_unregister(net, &idev->cnf, idev->dev->ifindex);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002357 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002360static struct ctl_table ctl_forward_entry[] = {
2361 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002362 .procname = "ip_forward",
2363 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00002364 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002365 .maxlen = sizeof(int),
2366 .mode = 0644,
2367 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002368 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002369 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002370 },
2371 { },
2372};
Eric Dumazet2a75de02008-01-05 23:08:49 -08002373#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002374
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002375static __net_init int devinet_init_net(struct net *net)
2376{
2377 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002378 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002379#ifdef CONFIG_SYSCTL
2380 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002381 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002382#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002383
2384 err = -ENOMEM;
2385 all = &ipv4_devconf;
2386 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002387
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002388 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002389 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002390 if (!all)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002391 goto err_alloc_all;
2392
2393 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002394 if (!dflt)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002395 goto err_alloc_dflt;
2396
Eric Dumazet2a75de02008-01-05 23:08:49 -08002397#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002398 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002399 if (!tbl)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002400 goto err_alloc_ctl;
2401
Eric W. Biederman02291682010-02-14 03:25:51 +00002402 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002403 tbl[0].extra1 = all;
2404 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002405#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002406 }
2407
2408#ifdef CONFIG_SYSCTL
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002409 err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002410 if (err < 0)
2411 goto err_reg_all;
2412
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002413 err = __devinet_sysctl_register(net, "default",
2414 NETCONFA_IFINDEX_DEFAULT, dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002415 if (err < 0)
2416 goto err_reg_dflt;
2417
2418 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002419 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Ian Morris51456b22015-04-03 09:17:26 +01002420 if (!forw_hdr)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002421 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002422 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002423#endif
2424
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002425 net->ipv4.devconf_all = all;
2426 net->ipv4.devconf_dflt = dflt;
2427 return 0;
2428
2429#ifdef CONFIG_SYSCTL
2430err_reg_ctl:
David Ahernb5c96412017-03-28 14:28:03 -07002431 __devinet_sysctl_unregister(net, dflt, NETCONFA_IFINDEX_DEFAULT);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002432err_reg_dflt:
David Ahernb5c96412017-03-28 14:28:03 -07002433 __devinet_sysctl_unregister(net, all, NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002434err_reg_all:
2435 if (tbl != ctl_forward_entry)
2436 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002437err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08002438#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002439 if (dflt != &ipv4_devconf_dflt)
2440 kfree(dflt);
2441err_alloc_dflt:
2442 if (all != &ipv4_devconf)
2443 kfree(all);
2444err_alloc_all:
2445 return err;
2446}
2447
2448static __net_exit void devinet_exit_net(struct net *net)
2449{
Eric Dumazet2a75de02008-01-05 23:08:49 -08002450#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002451 struct ctl_table *tbl;
2452
2453 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002454 unregister_net_sysctl_table(net->ipv4.forw_hdr);
David Ahernb5c96412017-03-28 14:28:03 -07002455 __devinet_sysctl_unregister(net, net->ipv4.devconf_dflt,
2456 NETCONFA_IFINDEX_DEFAULT);
2457 __devinet_sysctl_unregister(net, net->ipv4.devconf_all,
2458 NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002459 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08002460#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002461 kfree(net->ipv4.devconf_dflt);
2462 kfree(net->ipv4.devconf_all);
2463}
2464
2465static __net_initdata struct pernet_operations devinet_ops = {
2466 .init = devinet_init_net,
2467 .exit = devinet_exit_net,
2468};
2469
Daniel Borkmann207895fd32015-01-29 12:15:03 +01002470static struct rtnl_af_ops inet_af_ops __read_mostly = {
Thomas Graf9f0f7272010-11-16 04:32:48 +00002471 .family = AF_INET,
2472 .fill_link_af = inet_fill_link_af,
2473 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00002474 .validate_link_af = inet_validate_link_af,
2475 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00002476};
2477
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478void __init devinet_init(void)
2479{
David S. Millerfd23c3b2011-02-18 12:42:28 -08002480 int i;
2481
2482 for (i = 0; i < IN4_ADDR_HSIZE; i++)
2483 INIT_HLIST_HEAD(&inet_addr_lst[i]);
2484
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002485 register_pernet_subsys(&devinet_ops);
2486
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 register_gifconf(PF_INET, inet_gifconf);
2488 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07002489
viresh kumar906e0732014-01-22 12:23:32 +05302490 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +00002491
Thomas Graf9f0f7272010-11-16 04:32:48 +00002492 rtnl_af_register(&inet_af_ops);
2493
Greg Rosec7ac8672011-06-10 01:27:09 +00002494 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL);
2495 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, NULL);
2496 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, NULL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002497 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002498 inet_netconf_dump_devconf, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499}