blob: e1e2ec0525e6bcf75c552c05843856dfda266d13 [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{
David S. Miller9435eb12011-02-18 12:43:09 -0800140 struct net_device *result = NULL;
141 struct in_ifaddr *ifa;
David S. Miller9435eb12011-02-18 12:43:09 -0800142
143 rcu_read_lock();
Paolo Abeni6e617de2017-09-20 18:26:53 +0200144 ifa = inet_lookup_ifaddr_rcu(net, addr);
145 if (!ifa) {
David S. Miller406b6f92011-03-22 21:56:23 -0700146 struct flowi4 fl4 = { .daddr = addr };
147 struct fib_result res = { 0 };
148 struct fib_table *local;
149
150 /* Fallback to FIB local table so that communication
151 * over loopback subnets work.
152 */
153 local = fib_get_table(net, RT_TABLE_LOCAL);
154 if (local &&
155 !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
156 res.type == RTN_LOCAL)
157 result = FIB_RES_DEV(res);
Paolo Abeni6e617de2017-09-20 18:26:53 +0200158 } else {
159 result = ifa->ifa_dev->dev;
David S. Miller406b6f92011-03-22 21:56:23 -0700160 }
David S. Miller9435eb12011-02-18 12:43:09 -0800161 if (result && devref)
162 dev_hold(result);
163 rcu_read_unlock();
164 return result;
165}
166EXPORT_SYMBOL(__ip_dev_find);
167
Paolo Abeni6e617de2017-09-20 18:26:53 +0200168/* called under RCU lock */
169struct in_ifaddr *inet_lookup_ifaddr_rcu(struct net *net, __be32 addr)
170{
171 u32 hash = inet_addr_hash(net, addr);
172 struct in_ifaddr *ifa;
173
174 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash)
175 if (ifa->ifa_local == addr &&
176 net_eq(dev_net(ifa->ifa_dev->dev), net))
177 return ifa;
178
179 return NULL;
180}
181
Thomas Grafd6062cb2006-08-15 00:33:59 -0700182static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Alan Sterne041c682006-03-27 01:16:30 -0800184static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Krister Johansen3ad7d242017-06-08 13:12:14 -0700185static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
187 int destroy);
188#ifdef CONFIG_SYSCTL
WANG Cong20e61da2014-07-25 15:25:08 -0700189static int devinet_sysctl_register(struct in_device *idev);
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800190static void devinet_sysctl_unregister(struct in_device *idev);
191#else
WANG Cong20e61da2014-07-25 15:25:08 -0700192static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800193{
WANG Cong20e61da2014-07-25 15:25:08 -0700194 return 0;
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800195}
Eric Dumazet40384992012-08-03 21:06:50 +0000196static void devinet_sysctl_unregister(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800197{
198}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199#endif
200
201/* Locks all the inet devices. */
202
203static struct in_ifaddr *inet_alloc_ifa(void)
204{
Alexey Dobriyan93adcc82008-10-28 13:25:09 -0700205 return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206}
207
208static void inet_rcu_free_ifa(struct rcu_head *head)
209{
210 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
211 if (ifa->ifa_dev)
212 in_dev_put(ifa->ifa_dev);
213 kfree(ifa);
214}
215
Eric Dumazet40384992012-08-03 21:06:50 +0000216static void inet_free_ifa(struct in_ifaddr *ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217{
218 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
219}
220
221void in_dev_finish_destroy(struct in_device *idev)
222{
223 struct net_device *dev = idev->dev;
224
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700225 WARN_ON(idev->ifa_list);
226 WARN_ON(idev->mc_list);
Eric Dumazete9897072013-06-07 08:48:57 -0700227 kfree(rcu_dereference_protected(idev->mc_hash, 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228#ifdef NET_REFCNT_DEBUG
Joe Perches91df42b2012-05-15 14:11:54 +0000229 pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230#endif
231 dev_put(dev);
232 if (!idev->dead)
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800233 pr_err("Freeing alive in_device %p\n", idev);
234 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 kfree(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800237EXPORT_SYMBOL(in_dev_finish_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
Herbert Xu71e27da2007-06-04 23:36:06 -0700239static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240{
241 struct in_device *in_dev;
WANG Cong20e61da2014-07-25 15:25:08 -0700242 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
244 ASSERT_RTNL();
245
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700246 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 if (!in_dev)
248 goto out;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900249 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -0800250 sizeof(in_dev->cnf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 in_dev->cnf.sysctl = NULL;
252 in_dev->dev = dev;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800253 in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
254 if (!in_dev->arp_parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 goto out_kfree;
Ben Hutchings0187bdf2008-06-19 16:15:47 -0700256 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
257 dev_disable_lro(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 /* Reference in_dev->dev */
259 dev_hold(dev);
David L Stevens30c4cf52007-01-04 12:31:14 -0800260 /* Account for reference dev->ip_ptr (below) */
Reshetova, Elena7658b362017-06-30 13:08:03 +0300261 refcount_set(&in_dev->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
WANG Cong20e61da2014-07-25 15:25:08 -0700263 err = devinet_sysctl_register(in_dev);
264 if (err) {
265 in_dev->dead = 1;
266 in_dev_put(in_dev);
267 in_dev = NULL;
268 goto out;
269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 ip_mc_init_dev(in_dev);
271 if (dev->flags & IFF_UP)
272 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800273
David L Stevens30c4cf52007-01-04 12:31:14 -0800274 /* we can receive as soon as ip_ptr is set -- do this last */
Eric Dumazetcf778b02012-01-12 04:41:32 +0000275 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800276out:
WANG Cong20e61da2014-07-25 15:25:08 -0700277 return in_dev ?: ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278out_kfree:
279 kfree(in_dev);
280 in_dev = NULL;
281 goto out;
282}
283
284static void in_dev_rcu_put(struct rcu_head *head)
285{
286 struct in_device *idev = container_of(head, struct in_device, rcu_head);
287 in_dev_put(idev);
288}
289
290static void inetdev_destroy(struct in_device *in_dev)
291{
292 struct in_ifaddr *ifa;
293 struct net_device *dev;
294
295 ASSERT_RTNL();
296
297 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
299 in_dev->dead = 1;
300
301 ip_mc_destroy_dev(in_dev);
302
303 while ((ifa = in_dev->ifa_list) != NULL) {
304 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
305 inet_free_ifa(ifa);
306 }
307
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000308 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800310 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
312 arp_ifdown(dev);
313
314 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
315}
316
Al Viroff428d72006-09-26 22:13:35 -0700317int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
319 rcu_read_lock();
320 for_primary_ifa(in_dev) {
321 if (inet_ifa_match(a, ifa)) {
322 if (!b || inet_ifa_match(b, ifa)) {
323 rcu_read_unlock();
324 return 1;
325 }
326 }
327 } endfor_ifa(in_dev);
328 rcu_read_unlock();
329 return 0;
330}
331
Thomas Grafd6062cb2006-08-15 00:33:59 -0700332static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000333 int destroy, struct nlmsghdr *nlh, u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
Harald Welte8f937c62005-05-29 20:23:46 -0700335 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800336 struct in_ifaddr *ifa, *ifa1 = *ifap;
337 struct in_ifaddr *last_prim = in_dev->ifa_list;
338 struct in_ifaddr *prev_prom = NULL;
339 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
341 ASSERT_RTNL();
342
David S. Millerfbd40ea2016-03-13 23:28:00 -0400343 if (in_dev->dead)
344 goto no_promotions;
345
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900346 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700347 * unless alias promotion is set
348 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
350 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
352
353 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900354 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800355 ifa1->ifa_scope <= ifa->ifa_scope)
356 last_prim = ifa;
357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
359 ifa1->ifa_mask != ifa->ifa_mask ||
360 !inet_ifa_match(ifa1->ifa_address, ifa)) {
361 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800362 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 continue;
364 }
365
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800366 if (!do_promote) {
David S. Millerfd23c3b2011-02-18 12:42:28 -0800367 inet_hash_remove(ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700368 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
Eric W. Biederman15e47302012-09-07 20:12:54 +0000370 rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800371 blocking_notifier_call_chain(&inetaddr_chain,
372 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700373 inet_free_ifa(ifa);
374 } else {
375 promote = ifa;
376 break;
377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 }
379 }
380
Julian Anastasov2d230e22011-03-19 12:13:52 +0000381 /* On promotion all secondaries from subnet are changing
382 * the primary IP, we must remove all their routes silently
383 * and later to add them back with new prefsrc. Do this
384 * while all addresses are on the device list.
385 */
386 for (ifa = promote; ifa; ifa = ifa->ifa_next) {
387 if (ifa1->ifa_mask == ifa->ifa_mask &&
388 inet_ifa_match(ifa1->ifa_address, ifa))
389 fib_del_ifaddr(ifa, ifa1);
390 }
391
David S. Millerfbd40ea2016-03-13 23:28:00 -0400392no_promotions:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 /* 2. Unlink it */
394
395 *ifap = ifa1->ifa_next;
David S. Millerfd23c3b2011-02-18 12:42:28 -0800396 inet_hash_remove(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
398 /* 3. Announce address deletion */
399
400 /* Send message first, then call notifier.
401 At first sight, FIB update triggered by notifier
402 will refer to already deleted ifaddr, that could confuse
403 netlink listeners. It is not true: look, gated sees
404 that route deleted and if it still thinks that ifaddr
405 is valid, it will try to restore deleted routes... Grr.
406 So that, this order is correct.
407 */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000408 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800409 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800410
411 if (promote) {
Julian Anastasov04024b92011-03-19 12:13:54 +0000412 struct in_ifaddr *next_sec = promote->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800413
414 if (prev_prom) {
415 prev_prom->ifa_next = promote->ifa_next;
416 promote->ifa_next = last_prim->ifa_next;
417 last_prim->ifa_next = promote;
418 }
419
420 promote->ifa_flags &= ~IFA_F_SECONDARY;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000421 rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800422 blocking_notifier_call_chain(&inetaddr_chain,
423 NETDEV_UP, promote);
Julian Anastasov04024b92011-03-19 12:13:54 +0000424 for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800425 if (ifa1->ifa_mask != ifa->ifa_mask ||
426 !inet_ifa_match(ifa1->ifa_address, ifa))
427 continue;
428 fib_add_ifaddr(ifa);
429 }
430
431 }
Herbert Xu63630972007-06-07 18:35:38 -0700432 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434}
435
Thomas Grafd6062cb2006-08-15 00:33:59 -0700436static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
437 int destroy)
438{
439 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
440}
441
Jiri Pirko5c766d62013-01-24 09:41:41 +0000442static void check_lifetime(struct work_struct *work);
443
444static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
445
Thomas Grafd6062cb2006-08-15 00:33:59 -0700446static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000447 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
449 struct in_device *in_dev = ifa->ifa_dev;
450 struct in_ifaddr *ifa1, **ifap, **last_primary;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700451 struct in_validator_info ivi;
452 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453
454 ASSERT_RTNL();
455
456 if (!ifa->ifa_local) {
457 inet_free_ifa(ifa);
458 return 0;
459 }
460
461 ifa->ifa_flags &= ~IFA_F_SECONDARY;
462 last_primary = &in_dev->ifa_list;
463
464 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
465 ifap = &ifa1->ifa_next) {
466 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
467 ifa->ifa_scope <= ifa1->ifa_scope)
468 last_primary = &ifa1->ifa_next;
469 if (ifa1->ifa_mask == ifa->ifa_mask &&
470 inet_ifa_match(ifa1->ifa_address, ifa)) {
471 if (ifa1->ifa_local == ifa->ifa_local) {
472 inet_free_ifa(ifa);
473 return -EEXIST;
474 }
475 if (ifa1->ifa_scope != ifa->ifa_scope) {
476 inet_free_ifa(ifa);
477 return -EINVAL;
478 }
479 ifa->ifa_flags |= IFA_F_SECONDARY;
480 }
481 }
482
Krister Johansen3ad7d242017-06-08 13:12:14 -0700483 /* Allow any devices that wish to register ifaddr validtors to weigh
484 * in now, before changes are committed. The rntl lock is serializing
485 * access here, so the state should not change between a validator call
486 * and a final notify on commit. This isn't invoked on promotion under
487 * the assumption that validators are checking the address itself, and
488 * not the flags.
489 */
490 ivi.ivi_addr = ifa->ifa_address;
491 ivi.ivi_dev = ifa->ifa_dev;
492 ret = blocking_notifier_call_chain(&inetaddr_validator_chain,
493 NETDEV_UP, &ivi);
494 ret = notifier_to_errno(ret);
495 if (ret) {
496 inet_free_ifa(ifa);
497 return ret;
498 }
499
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500501 prandom_seed((__force u32) ifa->ifa_local);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 ifap = last_primary;
503 }
504
505 ifa->ifa_next = *ifap;
506 *ifap = ifa;
507
David S. Millerfd23c3b2011-02-18 12:42:28 -0800508 inet_hash_insert(dev_net(in_dev->dev), ifa);
509
Jiri Pirko5c766d62013-01-24 09:41:41 +0000510 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530511 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000512
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 /* Send message first, then call notifier.
514 Notifier will trigger FIB update, so that
515 listeners of netlink will know about new ifaddr */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000516 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800517 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
519 return 0;
520}
521
Thomas Grafd6062cb2006-08-15 00:33:59 -0700522static int inet_insert_ifa(struct in_ifaddr *ifa)
523{
524 return __inet_insert_ifa(ifa, NULL, 0);
525}
526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
528{
Herbert Xue5ed6392005-10-03 14:35:55 -0700529 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
531 ASSERT_RTNL();
532
533 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700534 inet_free_ifa(ifa);
535 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700537 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100538 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700540 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 in_dev_hold(in_dev);
542 ifa->ifa_dev = in_dev;
543 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800544 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 ifa->ifa_scope = RT_SCOPE_HOST;
546 return inet_insert_ifa(ifa);
547}
548
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000549/* Caller must hold RCU or RTNL :
550 * We dont take a reference on found in_device
551 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800552struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553{
554 struct net_device *dev;
555 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000556
557 rcu_read_lock();
558 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000560 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000561 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 return in_dev;
563}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800564EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
566/* Called only from RTNL semaphored context. No locks. */
567
Al Viro60cad5d2006-09-26 22:17:09 -0700568struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
569 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570{
571 ASSERT_RTNL();
572
573 for_primary_ifa(in_dev) {
574 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
575 return ifa;
576 } endfor_ifa(in_dev);
577 return NULL;
578}
579
Madhu Challa93a714d2015-02-25 09:58:35 -0800580static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa)
581{
582 struct ip_mreqn mreq = {
583 .imr_multiaddr.s_addr = ifa->ifa_address,
584 .imr_ifindex = ifa->ifa_dev->dev->ifindex,
585 };
586 int ret;
587
588 ASSERT_RTNL();
589
590 lock_sock(sk);
591 if (join)
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300592 ret = ip_mc_join_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800593 else
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300594 ret = ip_mc_leave_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800595 release_sock(sk);
596
597 return ret;
598}
599
David Ahernc21ef3e2017-04-16 09:48:24 -0700600static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
601 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900603 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700604 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700606 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700608 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
610 ASSERT_RTNL();
611
Johannes Bergfceb6432017-04-12 14:34:07 +0200612 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -0700613 extack);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700614 if (err < 0)
615 goto errout;
616
617 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800618 in_dev = inetdev_by_index(net, ifm->ifa_index);
Ian Morris51456b22015-04-03 09:17:26 +0100619 if (!in_dev) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700620 err = -ENODEV;
621 goto errout;
622 }
623
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
625 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700626 if (tb[IFA_LOCAL] &&
Jiri Benc67b61f62015-03-29 16:59:26 +0200627 ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700629
630 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
631 continue;
632
633 if (tb[IFA_ADDRESS] &&
634 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Jiri Benc67b61f62015-03-29 16:59:26 +0200635 !inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700636 continue;
637
Madhu Challa93a714d2015-02-25 09:58:35 -0800638 if (ipv4_is_multicast(ifa->ifa_address))
639 ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000640 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 return 0;
642 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700643
644 err = -EADDRNOTAVAIL;
645errout:
646 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647}
648
Jiri Pirko5c766d62013-01-24 09:41:41 +0000649#define INFINITY_LIFE_TIME 0xFFFFFFFF
650
651static void check_lifetime(struct work_struct *work)
652{
653 unsigned long now, next, next_sec, next_sched;
654 struct in_ifaddr *ifa;
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000655 struct hlist_node *n;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000656 int i;
657
658 now = jiffies;
659 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
660
Jiri Pirko5c766d62013-01-24 09:41:41 +0000661 for (i = 0; i < IN4_ADDR_HSIZE; i++) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000662 bool change_needed = false;
663
664 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800665 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
Jiri Pirko5c766d62013-01-24 09:41:41 +0000666 unsigned long age;
667
668 if (ifa->ifa_flags & IFA_F_PERMANENT)
669 continue;
670
671 /* We try to batch several events at once. */
672 age = (now - ifa->ifa_tstamp +
673 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
674
675 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
676 age >= ifa->ifa_valid_lft) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000677 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000678 } else if (ifa->ifa_preferred_lft ==
679 INFINITY_LIFE_TIME) {
680 continue;
681 } else if (age >= ifa->ifa_preferred_lft) {
682 if (time_before(ifa->ifa_tstamp +
683 ifa->ifa_valid_lft * HZ, next))
684 next = ifa->ifa_tstamp +
685 ifa->ifa_valid_lft * HZ;
686
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000687 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
688 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000689 } else if (time_before(ifa->ifa_tstamp +
690 ifa->ifa_preferred_lft * HZ,
691 next)) {
692 next = ifa->ifa_tstamp +
693 ifa->ifa_preferred_lft * HZ;
694 }
695 }
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000696 rcu_read_unlock();
697 if (!change_needed)
698 continue;
699 rtnl_lock();
700 hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
701 unsigned long age;
702
703 if (ifa->ifa_flags & IFA_F_PERMANENT)
704 continue;
705
706 /* We try to batch several events at once. */
707 age = (now - ifa->ifa_tstamp +
708 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
709
710 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
711 age >= ifa->ifa_valid_lft) {
712 struct in_ifaddr **ifap;
713
714 for (ifap = &ifa->ifa_dev->ifa_list;
715 *ifap != NULL; ifap = &(*ifap)->ifa_next) {
716 if (*ifap == ifa) {
717 inet_del_ifa(ifa->ifa_dev,
718 ifap, 1);
719 break;
720 }
721 }
722 } else if (ifa->ifa_preferred_lft !=
723 INFINITY_LIFE_TIME &&
724 age >= ifa->ifa_preferred_lft &&
725 !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
726 ifa->ifa_flags |= IFA_F_DEPRECATED;
727 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
728 }
729 }
730 rtnl_unlock();
Jiri Pirko5c766d62013-01-24 09:41:41 +0000731 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000732
733 next_sec = round_jiffies_up(next);
734 next_sched = next;
735
736 /* If rounded timeout is accurate enough, accept it. */
737 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
738 next_sched = next_sec;
739
740 now = jiffies;
741 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
742 if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
743 next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
744
viresh kumar906e0732014-01-22 12:23:32 +0530745 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work,
746 next_sched - now);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000747}
748
749static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
750 __u32 prefered_lft)
751{
752 unsigned long timeout;
753
754 ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
755
756 timeout = addrconf_timeout_fixup(valid_lft, HZ);
757 if (addrconf_finite_timeout(timeout))
758 ifa->ifa_valid_lft = timeout;
759 else
760 ifa->ifa_flags |= IFA_F_PERMANENT;
761
762 timeout = addrconf_timeout_fixup(prefered_lft, HZ);
763 if (addrconf_finite_timeout(timeout)) {
764 if (timeout == 0)
765 ifa->ifa_flags |= IFA_F_DEPRECATED;
766 ifa->ifa_preferred_lft = timeout;
767 }
768 ifa->ifa_tstamp = jiffies;
769 if (!ifa->ifa_cstamp)
770 ifa->ifa_cstamp = ifa->ifa_tstamp;
771}
772
773static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
774 __u32 *pvalid_lft, __u32 *pprefered_lft)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
Thomas Graf5c753972006-08-04 23:03:53 -0700776 struct nlattr *tb[IFA_MAX+1];
777 struct in_ifaddr *ifa;
778 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 struct net_device *dev;
780 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800781 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
Johannes Bergfceb6432017-04-12 14:34:07 +0200783 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
784 NULL);
Thomas Graf5c753972006-08-04 23:03:53 -0700785 if (err < 0)
786 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
Thomas Graf5c753972006-08-04 23:03:53 -0700788 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800789 err = -EINVAL;
Ian Morris51456b22015-04-03 09:17:26 +0100790 if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL])
Thomas Graf5c753972006-08-04 23:03:53 -0700791 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800793 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800794 err = -ENODEV;
Ian Morris51456b22015-04-03 09:17:26 +0100795 if (!dev)
Thomas Graf5c753972006-08-04 23:03:53 -0700796 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
Thomas Graf5c753972006-08-04 23:03:53 -0700798 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800799 err = -ENOBUFS;
Ian Morris51456b22015-04-03 09:17:26 +0100800 if (!in_dev)
Herbert Xu71e27da2007-06-04 23:36:06 -0700801 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
Thomas Graf5c753972006-08-04 23:03:53 -0700803 ifa = inet_alloc_ifa();
Ian Morris51456b22015-04-03 09:17:26 +0100804 if (!ifa)
Thomas Graf5c753972006-08-04 23:03:53 -0700805 /*
806 * A potential indev allocation can be left alive, it stays
807 * assigned to its device and is destroy with it.
808 */
Thomas Graf5c753972006-08-04 23:03:53 -0700809 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700810
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800811 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100812 neigh_parms_data_state_setall(in_dev->arp_parms);
Thomas Graf5c753972006-08-04 23:03:53 -0700813 in_dev_hold(in_dev);
814
Ian Morris51456b22015-04-03 09:17:26 +0100815 if (!tb[IFA_ADDRESS])
Thomas Graf5c753972006-08-04 23:03:53 -0700816 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
817
David S. Millerfd23c3b2011-02-18 12:42:28 -0800818 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
820 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100821 ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
822 ifm->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700824 ifa->ifa_dev = in_dev;
825
Jiri Benc67b61f62015-03-29 16:59:26 +0200826 ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]);
827 ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700828
829 if (tb[IFA_BROADCAST])
Jiri Benc67b61f62015-03-29 16:59:26 +0200830 ifa->ifa_broadcast = nla_get_in_addr(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700831
Thomas Graf5c753972006-08-04 23:03:53 -0700832 if (tb[IFA_LABEL])
833 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 else
835 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
836
Jiri Pirko5c766d62013-01-24 09:41:41 +0000837 if (tb[IFA_CACHEINFO]) {
838 struct ifa_cacheinfo *ci;
839
840 ci = nla_data(tb[IFA_CACHEINFO]);
841 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
842 err = -EINVAL;
Daniel Borkmann446266b2013-08-02 11:32:43 +0200843 goto errout_free;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000844 }
845 *pvalid_lft = ci->ifa_valid;
846 *pprefered_lft = ci->ifa_prefered;
847 }
848
Thomas Graf5c753972006-08-04 23:03:53 -0700849 return ifa;
850
Daniel Borkmann446266b2013-08-02 11:32:43 +0200851errout_free:
852 inet_free_ifa(ifa);
Thomas Graf5c753972006-08-04 23:03:53 -0700853errout:
854 return ERR_PTR(err);
855}
856
Jiri Pirko5c766d62013-01-24 09:41:41 +0000857static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
858{
859 struct in_device *in_dev = ifa->ifa_dev;
860 struct in_ifaddr *ifa1, **ifap;
861
862 if (!ifa->ifa_local)
863 return NULL;
864
865 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
866 ifap = &ifa1->ifa_next) {
867 if (ifa1->ifa_mask == ifa->ifa_mask &&
868 inet_ifa_match(ifa1->ifa_address, ifa) &&
869 ifa1->ifa_local == ifa->ifa_local)
870 return ifa1;
871 }
872 return NULL;
873}
874
David Ahernc21ef3e2017-04-16 09:48:24 -0700875static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
876 struct netlink_ext_ack *extack)
Thomas Graf5c753972006-08-04 23:03:53 -0700877{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900878 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700879 struct in_ifaddr *ifa;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000880 struct in_ifaddr *ifa_existing;
881 __u32 valid_lft = INFINITY_LIFE_TIME;
882 __u32 prefered_lft = INFINITY_LIFE_TIME;
Thomas Graf5c753972006-08-04 23:03:53 -0700883
884 ASSERT_RTNL();
885
Jiri Pirko5c766d62013-01-24 09:41:41 +0000886 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft);
Thomas Graf5c753972006-08-04 23:03:53 -0700887 if (IS_ERR(ifa))
888 return PTR_ERR(ifa);
889
Jiri Pirko5c766d62013-01-24 09:41:41 +0000890 ifa_existing = find_matching_ifa(ifa);
891 if (!ifa_existing) {
892 /* It would be best to check for !NLM_F_CREATE here but
stephen hemminger614d0562014-05-16 20:46:58 -0700893 * userspace already relies on not having to provide this.
Jiri Pirko5c766d62013-01-24 09:41:41 +0000894 */
895 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Madhu Challa93a714d2015-02-25 09:58:35 -0800896 if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
897 int ret = ip_mc_config(net->ipv4.mc_autojoin_sk,
898 true, ifa);
899
900 if (ret < 0) {
901 inet_free_ifa(ifa);
902 return ret;
903 }
904 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000905 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
906 } else {
907 inet_free_ifa(ifa);
908
909 if (nlh->nlmsg_flags & NLM_F_EXCL ||
910 !(nlh->nlmsg_flags & NLM_F_REPLACE))
911 return -EEXIST;
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000912 ifa = ifa_existing;
913 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Jiri Pirko05a324b2013-04-04 23:39:38 +0000914 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530915 queue_delayed_work(system_power_efficient_wq,
916 &check_lifetime_work, 0);
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000917 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000918 }
919 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920}
921
922/*
923 * Determine a default network mask, based on the IP address.
924 */
925
Eric Dumazet40384992012-08-03 21:06:50 +0000926static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927{
928 int rc = -1; /* Something else, probably a multicast. */
929
Joe Perchesf97c1e02007-12-16 13:45:43 -0800930 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900931 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 else {
Al Viro714e85b2006-11-14 20:51:49 -0800933 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
Al Viro714e85b2006-11-14 20:51:49 -0800935 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800937 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800939 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 rc = 24;
941 }
942
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900943 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944}
945
946
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800947int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948{
949 struct ifreq ifr;
950 struct sockaddr_in sin_orig;
951 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
952 struct in_device *in_dev;
953 struct in_ifaddr **ifap = NULL;
954 struct in_ifaddr *ifa = NULL;
955 struct net_device *dev;
956 char *colon;
957 int ret = -EFAULT;
958 int tryaddrmatch = 0;
959
960 /*
961 * Fetch the caller's info block into kernel space
962 */
963
964 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
965 goto out;
966 ifr.ifr_name[IFNAMSIZ - 1] = 0;
967
968 /* save original address for comparison */
969 memcpy(&sin_orig, sin, sizeof(*sin));
970
971 colon = strchr(ifr.ifr_name, ':');
972 if (colon)
973 *colon = 0;
974
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800975 dev_load(net, ifr.ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Stephen Hemminger132adf52007-03-08 20:44:43 -0800977 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 case SIOCGIFADDR: /* Get interface address */
979 case SIOCGIFBRDADDR: /* Get the broadcast address */
980 case SIOCGIFDSTADDR: /* Get the destination address */
981 case SIOCGIFNETMASK: /* Get the netmask for the interface */
982 /* Note that these ioctls will not sleep,
983 so that we do not impose a lock.
984 One day we will be forced to put shlock here (I mean SMP)
985 */
986 tryaddrmatch = (sin_orig.sin_family == AF_INET);
987 memset(sin, 0, sizeof(*sin));
988 sin->sin_family = AF_INET;
989 break;
990
991 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000992 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000993 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 goto out;
995 break;
996 case SIOCSIFADDR: /* Set interface address (and family) */
997 case SIOCSIFBRDADDR: /* Set the broadcast address */
998 case SIOCSIFDSTADDR: /* Set the destination address */
999 case SIOCSIFNETMASK: /* Set the netmask for the interface */
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +00001000 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +00001001 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 goto out;
1003 ret = -EINVAL;
1004 if (sin->sin_family != AF_INET)
1005 goto out;
1006 break;
1007 default:
1008 ret = -EINVAL;
1009 goto out;
1010 }
1011
1012 rtnl_lock();
1013
1014 ret = -ENODEV;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001015 dev = __dev_get_by_name(net, ifr.ifr_name);
1016 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 goto done;
1018
1019 if (colon)
1020 *colon = ':';
1021
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001022 in_dev = __in_dev_get_rtnl(dev);
1023 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 if (tryaddrmatch) {
1025 /* Matthias Andree */
1026 /* compare label and address (4.4BSD style) */
1027 /* note: we only do this for a limited set of ioctls
1028 and only if the original address family was AF_INET.
1029 This is checked above. */
1030 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1031 ifap = &ifa->ifa_next) {
1032 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
1033 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -08001034 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 break; /* found */
1036 }
1037 }
1038 }
1039 /* we didn't get a match, maybe the application is
1040 4.3BSD-style and passed in junk so we fall back to
1041 comparing just the label */
1042 if (!ifa) {
1043 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1044 ifap = &ifa->ifa_next)
1045 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
1046 break;
1047 }
1048 }
1049
1050 ret = -EADDRNOTAVAIL;
1051 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
1052 goto done;
1053
Stephen Hemminger132adf52007-03-08 20:44:43 -08001054 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 case SIOCGIFADDR: /* Get interface address */
1056 sin->sin_addr.s_addr = ifa->ifa_local;
1057 goto rarok;
1058
1059 case SIOCGIFBRDADDR: /* Get the broadcast address */
1060 sin->sin_addr.s_addr = ifa->ifa_broadcast;
1061 goto rarok;
1062
1063 case SIOCGIFDSTADDR: /* Get the destination address */
1064 sin->sin_addr.s_addr = ifa->ifa_address;
1065 goto rarok;
1066
1067 case SIOCGIFNETMASK: /* Get the netmask for the interface */
1068 sin->sin_addr.s_addr = ifa->ifa_mask;
1069 goto rarok;
1070
1071 case SIOCSIFFLAGS:
1072 if (colon) {
1073 ret = -EADDRNOTAVAIL;
1074 if (!ifa)
1075 break;
1076 ret = 0;
1077 if (!(ifr.ifr_flags & IFF_UP))
1078 inet_del_ifa(in_dev, ifap, 1);
1079 break;
1080 }
1081 ret = dev_change_flags(dev, ifr.ifr_flags);
1082 break;
1083
1084 case SIOCSIFADDR: /* Set interface address (and family) */
1085 ret = -EINVAL;
1086 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1087 break;
1088
1089 if (!ifa) {
1090 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001091 ifa = inet_alloc_ifa();
1092 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 break;
Xi Wangc7e2e1d2013-01-05 11:19:24 +00001094 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 if (colon)
1096 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
1097 else
1098 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1099 } else {
1100 ret = 0;
1101 if (ifa->ifa_local == sin->sin_addr.s_addr)
1102 break;
1103 inet_del_ifa(in_dev, ifap, 0);
1104 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -08001105 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 }
1107
1108 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
1109
1110 if (!(dev->flags & IFF_POINTOPOINT)) {
1111 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
1112 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
1113 if ((dev->flags & IFF_BROADCAST) &&
1114 ifa->ifa_prefixlen < 31)
1115 ifa->ifa_broadcast = ifa->ifa_address |
1116 ~ifa->ifa_mask;
1117 } else {
1118 ifa->ifa_prefixlen = 32;
1119 ifa->ifa_mask = inet_make_mask(32);
1120 }
Jiri Pirko5c766d62013-01-24 09:41:41 +00001121 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 ret = inet_set_ifa(dev, ifa);
1123 break;
1124
1125 case SIOCSIFBRDADDR: /* Set the broadcast address */
1126 ret = 0;
1127 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
1128 inet_del_ifa(in_dev, ifap, 0);
1129 ifa->ifa_broadcast = sin->sin_addr.s_addr;
1130 inet_insert_ifa(ifa);
1131 }
1132 break;
1133
1134 case SIOCSIFDSTADDR: /* Set the destination address */
1135 ret = 0;
1136 if (ifa->ifa_address == sin->sin_addr.s_addr)
1137 break;
1138 ret = -EINVAL;
1139 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1140 break;
1141 ret = 0;
1142 inet_del_ifa(in_dev, ifap, 0);
1143 ifa->ifa_address = sin->sin_addr.s_addr;
1144 inet_insert_ifa(ifa);
1145 break;
1146
1147 case SIOCSIFNETMASK: /* Set the netmask for the interface */
1148
1149 /*
1150 * The mask we set must be legal.
1151 */
1152 ret = -EINVAL;
1153 if (bad_mask(sin->sin_addr.s_addr, 0))
1154 break;
1155 ret = 0;
1156 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -07001157 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 inet_del_ifa(in_dev, ifap, 0);
1159 ifa->ifa_mask = sin->sin_addr.s_addr;
1160 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
1161
1162 /* See if current broadcast address matches
1163 * with current netmask, then recalculate
1164 * the broadcast address. Otherwise it's a
1165 * funny address, so don't touch it since
1166 * the user seems to know what (s)he's doing...
1167 */
1168 if ((dev->flags & IFF_BROADCAST) &&
1169 (ifa->ifa_prefixlen < 31) &&
1170 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -05001171 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 ifa->ifa_broadcast = (ifa->ifa_local |
1173 ~sin->sin_addr.s_addr);
1174 }
1175 inet_insert_ifa(ifa);
1176 }
1177 break;
1178 }
1179done:
1180 rtnl_unlock();
1181out:
1182 return ret;
1183rarok:
1184 rtnl_unlock();
1185 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
1186 goto out;
1187}
1188
1189static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
1190{
Herbert Xue5ed6392005-10-03 14:35:55 -07001191 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 struct in_ifaddr *ifa;
1193 struct ifreq ifr;
1194 int done = 0;
1195
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001196 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 goto out;
1198
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001199 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 if (!buf) {
1201 done += sizeof(ifr);
1202 continue;
1203 }
1204 if (len < (int) sizeof(ifr))
1205 break;
1206 memset(&ifr, 0, sizeof(struct ifreq));
Dan Carpenter4299c8a2013-07-29 22:15:19 +03001207 strcpy(ifr.ifr_name, ifa->ifa_label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
1209 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
1210 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1211 ifa->ifa_local;
1212
1213 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
1214 done = -EFAULT;
1215 break;
1216 }
1217 buf += sizeof(struct ifreq);
1218 len -= sizeof(struct ifreq);
1219 done += sizeof(struct ifreq);
1220 }
1221out:
1222 return done;
1223}
1224
Gao Feng8b57fd12017-03-10 12:38:47 +08001225static __be32 in_dev_select_addr(const struct in_device *in_dev,
1226 int scope)
1227{
1228 for_primary_ifa(in_dev) {
1229 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1230 ifa->ifa_scope <= scope)
1231 return ifa->ifa_local;
1232 } endfor_ifa(in_dev);
1233
1234 return 0;
1235}
1236
Al Viroa61ced52006-09-26 21:27:54 -07001237__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238{
Al Viroa61ced52006-09-26 21:27:54 -07001239 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001241 struct net *net = dev_net(dev);
David Ahern3f2fb9a2016-02-24 11:47:02 -08001242 int master_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243
1244 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001245 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 if (!in_dev)
1247 goto no_in_dev;
1248
1249 for_primary_ifa(in_dev) {
1250 if (ifa->ifa_scope > scope)
1251 continue;
1252 if (!dst || inet_ifa_match(dst, ifa)) {
1253 addr = ifa->ifa_local;
1254 break;
1255 }
1256 if (!addr)
1257 addr = ifa->ifa_local;
1258 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259
1260 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001261 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001262no_in_dev:
David Ahern3f2fb9a2016-02-24 11:47:02 -08001263 master_idx = l3mdev_master_ifindex_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
David Lamparter17b693c2016-02-24 11:47:03 -08001265 /* For VRFs, the VRF device takes the place of the loopback device,
1266 * with addresses on it being preferred. Note in such cases the
1267 * loopback device will be among the devices that fail the master_idx
1268 * equality check in the loop below.
1269 */
1270 if (master_idx &&
1271 (dev = dev_get_by_index_rcu(net, master_idx)) &&
1272 (in_dev = __in_dev_get_rcu(dev))) {
Gao Feng8b57fd12017-03-10 12:38:47 +08001273 addr = in_dev_select_addr(in_dev, scope);
1274 if (addr)
1275 goto out_unlock;
David Lamparter17b693c2016-02-24 11:47:03 -08001276 }
1277
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 /* Not loopback addresses on loopback should be preferred
Stephen Hemmingerca9f1fd2015-02-14 13:47:54 -05001279 in this case. It is important that lo is the first interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 in dev_base list.
1281 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001282 for_each_netdev_rcu(net, dev) {
David Ahern3f2fb9a2016-02-24 11:47:02 -08001283 if (l3mdev_master_ifindex_rcu(dev) != master_idx)
1284 continue;
1285
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001286 in_dev = __in_dev_get_rcu(dev);
1287 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 continue;
1289
Gao Feng8b57fd12017-03-10 12:38:47 +08001290 addr = in_dev_select_addr(in_dev, scope);
1291 if (addr)
1292 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001294out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 return addr;
1297}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001298EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
Al Viro60cad5d2006-09-26 22:17:09 -07001300static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1301 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302{
1303 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001304 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305
1306 for_ifa(in_dev) {
1307 if (!addr &&
1308 (local == ifa->ifa_local || !local) &&
1309 ifa->ifa_scope <= scope) {
1310 addr = ifa->ifa_local;
1311 if (same)
1312 break;
1313 }
1314 if (!same) {
1315 same = (!local || inet_ifa_match(local, ifa)) &&
1316 (!dst || inet_ifa_match(dst, ifa));
1317 if (same && addr) {
1318 if (local || !dst)
1319 break;
1320 /* Is the selected addr into dst subnet? */
1321 if (inet_ifa_match(addr, ifa))
1322 break;
1323 /* No, then can we use new local src? */
1324 if (ifa->ifa_scope <= scope) {
1325 addr = ifa->ifa_local;
1326 break;
1327 }
1328 /* search for large dst subnet for addr */
1329 same = 0;
1330 }
1331 }
1332 } endfor_ifa(in_dev);
1333
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001334 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335}
1336
1337/*
1338 * Confirm that local IP address exists using wildcards:
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001339 * - net: netns to check, cannot be NULL
1340 * - in_dev: only on this interface, NULL=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 * - dst: only in the same subnet as dst, 0=any dst
1342 * - local: address, 0=autoselect the local address
1343 * - scope: maximum allowed scope value for the local address
1344 */
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001345__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001346 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347{
Al Viro60cad5d2006-09-26 22:17:09 -07001348 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001349 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
Ian Morris00db4122015-04-03 09:17:27 +01001351 if (in_dev)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001352 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001355 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001356 in_dev = __in_dev_get_rcu(dev);
1357 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 addr = confirm_addr_indev(in_dev, dst, local, scope);
1359 if (addr)
1360 break;
1361 }
1362 }
1363 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364
1365 return addr;
1366}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001367EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
1369/*
1370 * Device notifier
1371 */
1372
1373int register_inetaddr_notifier(struct notifier_block *nb)
1374{
Alan Sterne041c682006-03-27 01:16:30 -08001375 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001377EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
1379int unregister_inetaddr_notifier(struct notifier_block *nb)
1380{
Alan Sterne041c682006-03-27 01:16:30 -08001381 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001383EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384
Krister Johansen3ad7d242017-06-08 13:12:14 -07001385int register_inetaddr_validator_notifier(struct notifier_block *nb)
1386{
1387 return blocking_notifier_chain_register(&inetaddr_validator_chain, nb);
1388}
1389EXPORT_SYMBOL(register_inetaddr_validator_notifier);
1390
1391int unregister_inetaddr_validator_notifier(struct notifier_block *nb)
1392{
1393 return blocking_notifier_chain_unregister(&inetaddr_validator_chain,
1394 nb);
1395}
1396EXPORT_SYMBOL(unregister_inetaddr_validator_notifier);
1397
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001398/* Rename ifa_labels for a device name change. Make some effort to preserve
1399 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400*/
1401static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001402{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 struct in_ifaddr *ifa;
1404 int named = 0;
1405
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001406 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1407 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408
1409 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001410 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001412 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001413 dot = strchr(old, ':');
Ian Morris51456b22015-04-03 09:17:26 +01001414 if (!dot) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001415 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 dot = old;
1417 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001418 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001419 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001420 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001421 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001422skip:
1423 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001424 }
1425}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426
Eric Dumazet40384992012-08-03 21:06:50 +00001427static bool inetdev_valid_mtu(unsigned int mtu)
Breno Leitao06770842008-09-02 17:28:58 -07001428{
1429 return mtu >= 68;
1430}
1431
Ian Campbelld11327ad2011-02-11 07:44:16 +00001432static void inetdev_send_gratuitous_arp(struct net_device *dev,
1433 struct in_device *in_dev)
1434
1435{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001436 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001437
Zoltan Kissb76d0782011-07-24 13:09:30 +00001438 for (ifa = in_dev->ifa_list; ifa;
1439 ifa = ifa->ifa_next) {
1440 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1441 ifa->ifa_local, dev,
1442 ifa->ifa_local, NULL,
1443 dev->dev_addr, NULL);
1444 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001445}
1446
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447/* Called only under RTNL semaphore */
1448
1449static int inetdev_event(struct notifier_block *this, unsigned long event,
1450 void *ptr)
1451{
Jiri Pirko351638e2013-05-28 01:30:21 +00001452 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazet748e2d92012-08-22 21:50:59 +00001453 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454
1455 ASSERT_RTNL();
1456
1457 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001458 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 in_dev = inetdev_init(dev);
WANG Cong20e61da2014-07-25 15:25:08 -07001460 if (IS_ERR(in_dev))
1461 return notifier_from_errno(PTR_ERR(in_dev));
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001462 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001463 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1464 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001465 }
Breno Leitao06770842008-09-02 17:28:58 -07001466 } else if (event == NETDEV_CHANGEMTU) {
1467 /* Re-enabling IP */
1468 if (inetdev_valid_mtu(dev->mtu))
1469 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 }
1471 goto out;
1472 }
1473
1474 switch (event) {
1475 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001476 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001477 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 break;
1479 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001480 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001482 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001483 struct in_ifaddr *ifa = inet_alloc_ifa();
1484
1485 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001486 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 ifa->ifa_local =
1488 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1489 ifa->ifa_prefixlen = 8;
1490 ifa->ifa_mask = inet_make_mask(8);
1491 in_dev_hold(in_dev);
1492 ifa->ifa_dev = in_dev;
1493 ifa->ifa_scope = RT_SCOPE_HOST;
1494 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Jiri Pirko5c766d62013-01-24 09:41:41 +00001495 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1496 INFINITY_LIFE_TIME);
Jiri Pirkodfd15822014-01-07 15:55:45 +01001497 ipv4_devconf_setall(in_dev);
1498 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 inet_insert_ifa(ifa);
1500 }
1501 }
1502 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001503 /* fall through */
1504 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001505 if (!IN_DEV_ARP_NOTIFY(in_dev))
1506 break;
1507 /* fall through */
1508 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001509 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001510 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 break;
1512 case NETDEV_DOWN:
1513 ip_mc_down(in_dev);
1514 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001515 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001516 ip_mc_unmap(in_dev);
1517 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001518 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001519 ip_mc_remap(in_dev);
1520 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001522 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 break;
Breno Leitao06770842008-09-02 17:28:58 -07001524 /* disable IP when MTU is not enough */
Gustavo A. R. Silvafcfd6df2017-10-16 15:48:55 -05001525 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 case NETDEV_UNREGISTER:
1527 inetdev_destroy(in_dev);
1528 break;
1529 case NETDEV_CHANGENAME:
1530 /* Do not notify about label change, this event is
1531 * not interesting to applications using netlink.
1532 */
1533 inetdev_changename(dev, in_dev);
1534
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001535 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001536 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 break;
1538 }
1539out:
1540 return NOTIFY_DONE;
1541}
1542
1543static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001544 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545};
1546
Eric Dumazet40384992012-08-03 21:06:50 +00001547static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001548{
1549 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1550 + nla_total_size(4) /* IFA_ADDRESS */
1551 + nla_total_size(4) /* IFA_LOCAL */
1552 + nla_total_size(4) /* IFA_BROADCAST */
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001553 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001554 + nla_total_size(4) /* IFA_FLAGS */
1555 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
Thomas Graf339bf982006-11-10 14:10:15 -08001556}
1557
Jiri Pirko5c766d62013-01-24 09:41:41 +00001558static inline u32 cstamp_delta(unsigned long cstamp)
1559{
1560 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1561}
1562
1563static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1564 unsigned long tstamp, u32 preferred, u32 valid)
1565{
1566 struct ifa_cacheinfo ci;
1567
1568 ci.cstamp = cstamp_delta(cstamp);
1569 ci.tstamp = cstamp_delta(tstamp);
1570 ci.ifa_prefered = preferred;
1571 ci.ifa_valid = valid;
1572
1573 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1574}
1575
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001577 u32 portid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578{
1579 struct ifaddrmsg *ifm;
1580 struct nlmsghdr *nlh;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001581 u32 preferred, valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
Eric W. Biederman15e47302012-09-07 20:12:54 +00001583 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
Ian Morris51456b22015-04-03 09:17:26 +01001584 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08001585 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001586
1587 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 ifm->ifa_family = AF_INET;
1589 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001590 ifm->ifa_flags = ifa->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 ifm->ifa_scope = ifa->ifa_scope;
1592 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593
Jiri Pirko5c766d62013-01-24 09:41:41 +00001594 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1595 preferred = ifa->ifa_preferred_lft;
1596 valid = ifa->ifa_valid_lft;
1597 if (preferred != INFINITY_LIFE_TIME) {
1598 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1599
1600 if (preferred > tval)
1601 preferred -= tval;
1602 else
1603 preferred = 0;
1604 if (valid != INFINITY_LIFE_TIME) {
1605 if (valid > tval)
1606 valid -= tval;
1607 else
1608 valid = 0;
1609 }
1610 }
1611 } else {
1612 preferred = INFINITY_LIFE_TIME;
1613 valid = INFINITY_LIFE_TIME;
1614 }
David S. Millerf3756b72012-04-01 20:39:02 -04001615 if ((ifa->ifa_address &&
Jiri Benc930345e2015-03-29 16:59:25 +02001616 nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001617 (ifa->ifa_local &&
Jiri Benc930345e2015-03-29 16:59:25 +02001618 nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001619 (ifa->ifa_broadcast &&
Jiri Benc930345e2015-03-29 16:59:25 +02001620 nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001621 (ifa->ifa_label[0] &&
Jiri Pirko5c766d62013-01-24 09:41:41 +00001622 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001623 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
Jiri Pirko5c766d62013-01-24 09:41:41 +00001624 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1625 preferred, valid))
David S. Millerf3756b72012-04-01 20:39:02 -04001626 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001627
Johannes Berg053c0952015-01-16 22:09:00 +01001628 nlmsg_end(skb, nlh);
1629 return 0;
Thomas Graf47f68512006-08-04 23:04:36 -07001630
1631nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001632 nlmsg_cancel(skb, nlh);
1633 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634}
1635
1636static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1637{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001638 struct net *net = sock_net(skb->sk);
Eric Dumazeteec4df92009-11-12 07:44:25 +00001639 int h, s_h;
1640 int idx, s_idx;
1641 int ip_idx, s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 struct net_device *dev;
1643 struct in_device *in_dev;
1644 struct in_ifaddr *ifa;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001645 struct hlist_head *head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
Eric Dumazeteec4df92009-11-12 07:44:25 +00001647 s_h = cb->args[0];
1648 s_idx = idx = cb->args[1];
1649 s_ip_idx = ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650
Eric Dumazeteec4df92009-11-12 07:44:25 +00001651 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1652 idx = 0;
1653 head = &net->dev_index_head[h];
1654 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001655 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1656 net->dev_base_seq;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001657 hlist_for_each_entry_rcu(dev, head, index_hlist) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001658 if (idx < s_idx)
1659 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001660 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001661 s_ip_idx = 0;
1662 in_dev = __in_dev_get_rcu(dev);
1663 if (!in_dev)
1664 goto cont;
1665
1666 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1667 ifa = ifa->ifa_next, ip_idx++) {
1668 if (ip_idx < s_ip_idx)
1669 continue;
1670 if (inet_fill_ifaddr(skb, ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001671 NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 cb->nlh->nlmsg_seq,
Johannes Berg053c0952015-01-16 22:09:00 +01001673 RTM_NEWADDR, NLM_F_MULTI) < 0) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001674 rcu_read_unlock();
1675 goto done;
1676 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001677 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Eric Dumazeteec4df92009-11-12 07:44:25 +00001678 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001679cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001680 idx++;
1681 }
1682 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 }
1684
1685done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001686 cb->args[0] = h;
1687 cb->args[1] = idx;
1688 cb->args[2] = ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
1690 return skb->len;
1691}
1692
Jianjun Kong539afed2008-11-03 02:48:48 -08001693static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001694 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695{
Thomas Graf47f68512006-08-04 23:04:36 -07001696 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001697 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1698 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001699 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001701 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001702 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001703 if (!skb)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001704 goto errout;
1705
Eric W. Biederman15e47302012-09-07 20:12:54 +00001706 err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001707 if (err < 0) {
1708 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1709 WARN_ON(err == -EMSGSIZE);
1710 kfree_skb(skb);
1711 goto errout;
1712 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001713 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001714 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001715errout:
1716 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001717 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718}
1719
Arad, Ronenb1974ed2015-10-19 09:23:28 -07001720static size_t inet_get_link_af_size(const struct net_device *dev,
1721 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001722{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001723 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001724
1725 if (!in_dev)
1726 return 0;
1727
1728 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1729}
1730
Sowmini Varadhand5566fd2015-09-11 16:48:48 -04001731static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
1732 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001733{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001734 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001735 struct nlattr *nla;
1736 int i;
1737
1738 if (!in_dev)
1739 return -ENODATA;
1740
1741 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
Ian Morris51456b22015-04-03 09:17:26 +01001742 if (!nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001743 return -EMSGSIZE;
1744
1745 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1746 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1747
1748 return 0;
1749}
1750
1751static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1752 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1753};
1754
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001755static int inet_validate_link_af(const struct net_device *dev,
1756 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001757{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001758 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1759 int err, rem;
1760
Florian Westphal5fa85a02017-10-16 15:44:36 +02001761 if (dev && !__in_dev_get_rcu(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001762 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001763
Johannes Bergfceb6432017-04-12 14:34:07 +02001764 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy, NULL);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001765 if (err < 0)
1766 return err;
1767
1768 if (tb[IFLA_INET_CONF]) {
1769 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1770 int cfgid = nla_type(a);
1771
1772 if (nla_len(a) < 4)
1773 return -EINVAL;
1774
1775 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1776 return -EINVAL;
1777 }
1778 }
1779
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001780 return 0;
1781}
1782
1783static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1784{
Florian Westphal5fa85a02017-10-16 15:44:36 +02001785 struct in_device *in_dev = __in_dev_get_rcu(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001786 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1787 int rem;
1788
1789 if (!in_dev)
1790 return -EAFNOSUPPORT;
1791
Johannes Bergfceb6432017-04-12 14:34:07 +02001792 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0)
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001793 BUG();
1794
Thomas Graf9f0f7272010-11-16 04:32:48 +00001795 if (tb[IFLA_INET_CONF]) {
1796 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1797 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1798 }
1799
1800 return 0;
1801}
1802
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001803static int inet_netconf_msgsize_devconf(int type)
1804{
1805 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1806 + nla_total_size(4); /* NETCONFA_IFINDEX */
Zhang Shengju136ba622016-03-10 08:55:50 +00001807 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001808
Zhang Shengju136ba622016-03-10 08:55:50 +00001809 if (type == NETCONFA_ALL)
1810 all = true;
1811
1812 if (all || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001813 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001814 if (all || type == NETCONFA_RP_FILTER)
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001815 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001816 if (all || type == NETCONFA_MC_FORWARDING)
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001817 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001818 if (all || type == NETCONFA_PROXY_NEIGH)
stephen hemmingerf085ff12013-12-12 13:06:50 -08001819 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001820 if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001821 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001822
1823 return size;
1824}
1825
1826static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1827 struct ipv4_devconf *devconf, u32 portid,
1828 u32 seq, int event, unsigned int flags,
1829 int type)
1830{
1831 struct nlmsghdr *nlh;
1832 struct netconfmsg *ncm;
Zhang Shengju136ba622016-03-10 08:55:50 +00001833 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001834
1835 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1836 flags);
Ian Morris51456b22015-04-03 09:17:26 +01001837 if (!nlh)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001838 return -EMSGSIZE;
1839
Zhang Shengju136ba622016-03-10 08:55:50 +00001840 if (type == NETCONFA_ALL)
1841 all = true;
1842
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001843 ncm = nlmsg_data(nlh);
1844 ncm->ncm_family = AF_INET;
1845
1846 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1847 goto nla_put_failure;
1848
David Ahernb5c96412017-03-28 14:28:03 -07001849 if (!devconf)
1850 goto out;
1851
Zhang Shengju136ba622016-03-10 08:55:50 +00001852 if ((all || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001853 nla_put_s32(skb, NETCONFA_FORWARDING,
1854 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1855 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001856 if ((all || type == NETCONFA_RP_FILTER) &&
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001857 nla_put_s32(skb, NETCONFA_RP_FILTER,
1858 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
1859 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001860 if ((all || type == NETCONFA_MC_FORWARDING) &&
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001861 nla_put_s32(skb, NETCONFA_MC_FORWARDING,
1862 IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
1863 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001864 if ((all || type == NETCONFA_PROXY_NEIGH) &&
stephen hemminger09aea5d2013-12-17 22:35:52 -08001865 nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08001866 IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
1867 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001868 if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001869 nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
1870 IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
1871 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001872
David Ahernb5c96412017-03-28 14:28:03 -07001873out:
Johannes Berg053c0952015-01-16 22:09:00 +01001874 nlmsg_end(skb, nlh);
1875 return 0;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001876
1877nla_put_failure:
1878 nlmsg_cancel(skb, nlh);
1879 return -EMSGSIZE;
1880}
1881
David Ahern3b022862017-03-28 14:28:02 -07001882void inet_netconf_notify_devconf(struct net *net, int event, int type,
1883 int ifindex, struct ipv4_devconf *devconf)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001884{
1885 struct sk_buff *skb;
1886 int err = -ENOBUFS;
1887
Eric Dumazetfa178062016-07-08 05:18:24 +02001888 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001889 if (!skb)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001890 goto errout;
1891
1892 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
David Ahern3b022862017-03-28 14:28:02 -07001893 event, 0, type);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001894 if (err < 0) {
1895 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1896 WARN_ON(err == -EMSGSIZE);
1897 kfree_skb(skb);
1898 goto errout;
1899 }
Eric Dumazetfa178062016-07-08 05:18:24 +02001900 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001901 return;
1902errout:
1903 if (err < 0)
1904 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
1905}
1906
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001907static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
1908 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
1909 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001910 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
stephen hemminger09aea5d2013-12-17 22:35:52 -08001911 [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) },
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001912 [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001913};
1914
1915static int inet_netconf_get_devconf(struct sk_buff *in_skb,
David Ahernc21ef3e2017-04-16 09:48:24 -07001916 struct nlmsghdr *nlh,
1917 struct netlink_ext_ack *extack)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001918{
1919 struct net *net = sock_net(in_skb->sk);
1920 struct nlattr *tb[NETCONFA_MAX+1];
1921 struct netconfmsg *ncm;
1922 struct sk_buff *skb;
1923 struct ipv4_devconf *devconf;
1924 struct in_device *in_dev;
1925 struct net_device *dev;
1926 int ifindex;
1927 int err;
1928
1929 err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
David Ahernc21ef3e2017-04-16 09:48:24 -07001930 devconf_ipv4_policy, extack);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001931 if (err < 0)
1932 goto errout;
1933
Anton Protopopova97eb332016-02-16 21:43:16 -05001934 err = -EINVAL;
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001935 if (!tb[NETCONFA_IFINDEX])
1936 goto errout;
1937
1938 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
1939 switch (ifindex) {
1940 case NETCONFA_IFINDEX_ALL:
1941 devconf = net->ipv4.devconf_all;
1942 break;
1943 case NETCONFA_IFINDEX_DEFAULT:
1944 devconf = net->ipv4.devconf_dflt;
1945 break;
1946 default:
1947 dev = __dev_get_by_index(net, ifindex);
Ian Morris51456b22015-04-03 09:17:26 +01001948 if (!dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001949 goto errout;
1950 in_dev = __in_dev_get_rtnl(dev);
Ian Morris51456b22015-04-03 09:17:26 +01001951 if (!in_dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001952 goto errout;
1953 devconf = &in_dev->cnf;
1954 break;
1955 }
1956
1957 err = -ENOBUFS;
Eric Dumazetfa178062016-07-08 05:18:24 +02001958 skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001959 if (!skb)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001960 goto errout;
1961
1962 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
1963 NETLINK_CB(in_skb).portid,
1964 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
Zhang Shengju136ba622016-03-10 08:55:50 +00001965 NETCONFA_ALL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001966 if (err < 0) {
1967 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1968 WARN_ON(err == -EMSGSIZE);
1969 kfree_skb(skb);
1970 goto errout;
1971 }
1972 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
1973errout:
1974 return err;
1975}
1976
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001977static int inet_netconf_dump_devconf(struct sk_buff *skb,
1978 struct netlink_callback *cb)
1979{
1980 struct net *net = sock_net(skb->sk);
1981 int h, s_h;
1982 int idx, s_idx;
1983 struct net_device *dev;
1984 struct in_device *in_dev;
1985 struct hlist_head *head;
1986
1987 s_h = cb->args[0];
1988 s_idx = idx = cb->args[1];
1989
1990 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1991 idx = 0;
1992 head = &net->dev_index_head[h];
1993 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001994 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1995 net->dev_base_seq;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001996 hlist_for_each_entry_rcu(dev, head, index_hlist) {
1997 if (idx < s_idx)
1998 goto cont;
1999 in_dev = __in_dev_get_rcu(dev);
2000 if (!in_dev)
2001 goto cont;
2002
2003 if (inet_netconf_fill_devconf(skb, dev->ifindex,
2004 &in_dev->cnf,
2005 NETLINK_CB(cb->skb).portid,
2006 cb->nlh->nlmsg_seq,
2007 RTM_NEWNETCONF,
2008 NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002009 NETCONFA_ALL) < 0) {
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002010 rcu_read_unlock();
2011 goto done;
2012 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00002013 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002014cont:
2015 idx++;
2016 }
2017 rcu_read_unlock();
2018 }
2019 if (h == NETDEV_HASHENTRIES) {
2020 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
2021 net->ipv4.devconf_all,
2022 NETLINK_CB(cb->skb).portid,
2023 cb->nlh->nlmsg_seq,
2024 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002025 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002026 goto done;
2027 else
2028 h++;
2029 }
2030 if (h == NETDEV_HASHENTRIES + 1) {
2031 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
2032 net->ipv4.devconf_dflt,
2033 NETLINK_CB(cb->skb).portid,
2034 cb->nlh->nlmsg_seq,
2035 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002036 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002037 goto done;
2038 else
2039 h++;
2040 }
2041done:
2042 cb->args[0] = h;
2043 cb->args[1] = idx;
2044
2045 return skb->len;
2046}
2047
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048#ifdef CONFIG_SYSCTL
2049
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002050static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07002051{
2052 struct net_device *dev;
2053
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002054 rcu_read_lock();
2055 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07002056 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002057
Herbert Xu31be3082007-06-04 23:35:37 -07002058 in_dev = __in_dev_get_rcu(dev);
2059 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002060 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07002061 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002062 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07002063}
2064
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002065/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002066static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002067{
2068 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002069 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002070
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002071 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002072 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
David Ahern3b022862017-03-28 14:28:02 -07002073 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2074 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002075 NETCONFA_IFINDEX_ALL,
2076 net->ipv4.devconf_all);
David Ahern3b022862017-03-28 14:28:02 -07002077 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2078 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002079 NETCONFA_IFINDEX_DEFAULT,
2080 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002081
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002082 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002083 struct in_device *in_dev;
Eric Dumazetfa178062016-07-08 05:18:24 +02002084
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002085 if (on)
2086 dev_disable_lro(dev);
Eric Dumazetfa178062016-07-08 05:18:24 +02002087
2088 in_dev = __in_dev_get_rtnl(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002089 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002090 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
David Ahern3b022862017-03-28 14:28:02 -07002091 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2092 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002093 dev->ifindex, &in_dev->cnf);
2094 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002095 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002096}
2097
stephen hemmingerf085ff12013-12-12 13:06:50 -08002098static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf)
2099{
2100 if (cnf == net->ipv4.devconf_dflt)
2101 return NETCONFA_IFINDEX_DEFAULT;
2102 else if (cnf == net->ipv4.devconf_all)
2103 return NETCONFA_IFINDEX_ALL;
2104 else {
2105 struct in_device *idev
2106 = container_of(cnf, struct in_device, cnf);
2107 return idev->dev->ifindex;
2108 }
2109}
2110
Joe Perchesfe2c6332013-06-11 23:04:25 -07002111static int devinet_conf_proc(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002112 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07002113 size_t *lenp, loff_t *ppos)
2114{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002115 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002116 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002117 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07002118
2119 if (write) {
2120 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002121 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07002122 int i = (int *)ctl->data - cnf->data;
stephen hemmingerf085ff12013-12-12 13:06:50 -08002123 int ifindex;
Herbert Xu31be3082007-06-04 23:35:37 -07002124
2125 set_bit(i, cnf->state);
2126
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002127 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002128 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00002129 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
2130 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002131 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002132 rt_cache_flush(net);
stephen hemmingerf085ff12013-12-12 13:06:50 -08002133
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002134 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
2135 new_value != old_value) {
stephen hemmingerf085ff12013-12-12 13:06:50 -08002136 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002137 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2138 NETCONFA_RP_FILTER,
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002139 ifindex, cnf);
2140 }
stephen hemmingerf085ff12013-12-12 13:06:50 -08002141 if (i == IPV4_DEVCONF_PROXY_ARP - 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_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002146 ifindex, cnf);
2147 }
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002148 if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
2149 new_value != old_value) {
2150 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002151 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2152 NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002153 ifindex, cnf);
2154 }
Herbert Xu31be3082007-06-04 23:35:37 -07002155 }
2156
2157 return ret;
2158}
2159
Joe Perchesfe2c6332013-06-11 23:04:25 -07002160static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002161 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 size_t *lenp, loff_t *ppos)
2163{
2164 int *valp = ctl->data;
2165 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00002166 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002167 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168
2169 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002170 struct net *net = ctl->extra2;
2171
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002172 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00002173 if (!rtnl_trylock()) {
2174 /* Restore the original values before restarting */
2175 *valp = val;
2176 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00002177 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00002178 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002179 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2180 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002181 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002182 struct ipv4_devconf *cnf = ctl->extra1;
2183 struct in_device *idev =
2184 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002185 if (*valp)
2186 dev_disable_lro(idev->dev);
David Ahern3b022862017-03-28 14:28:02 -07002187 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002188 NETCONFA_FORWARDING,
2189 idev->dev->ifindex,
2190 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002191 }
2192 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002193 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002194 } else
David Ahern3b022862017-03-28 14:28:02 -07002195 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2196 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002197 NETCONFA_IFINDEX_DEFAULT,
2198 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 }
2200
2201 return ret;
2202}
2203
Joe Perchesfe2c6332013-06-11 23:04:25 -07002204static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
David S. Miller323e1262010-12-12 21:55:08 -08002205 void __user *buffer,
2206 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207{
2208 int *valp = ctl->data;
2209 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002210 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07002211 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212
2213 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002214 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215
2216 return ret;
2217}
2218
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002219#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07002220 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07002221 .procname = name, \
2222 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00002223 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002224 .maxlen = sizeof(int), \
2225 .mode = mval, \
2226 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07002227 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002228 }
2229
2230#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002231 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002232
2233#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002234 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002235
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002236#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2237 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002238
2239#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002240 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07002241
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242static struct devinet_sysctl_table {
2243 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00002244 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245} devinet_sysctl = {
2246 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07002247 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002248 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07002249 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
2250
2251 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
2252 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
2253 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
2254 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
2255 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
2256 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
2257 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00002258 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08002259 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002260 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
2261 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
2262 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
2263 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
2264 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
2265 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
2266 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
2267 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
2268 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08002269 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00002270 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
William Manley5c6fe012013-08-06 19:03:14 +01002271 DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
2272 "force_igmp_version"),
William Manley26900482013-08-06 19:03:15 +01002273 DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
2274 "igmpv2_unsolicited_report_interval"),
2275 DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
2276 "igmpv3_unsolicited_report_interval"),
Andy Gospodarek0eeb0752015-06-23 13:45:37 -04002277 DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
2278 "ignore_routes_with_linkdown"),
Johannes Berg97daf332016-02-04 13:31:18 +01002279 DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
2280 "drop_gratuitous_arp"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002281
2282 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2283 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002284 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
2285 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00002286 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2287 "route_localnet"),
Johannes Berg12b74df2016-02-04 13:31:17 +01002288 DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
2289 "drop_unicast_in_l2_multicast"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291};
2292
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002293static int __devinet_sysctl_register(struct net *net, char *dev_name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002294 int ifindex, struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295{
2296 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002297 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002298 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11002299
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002300 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002302 goto out;
2303
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
2305 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07002306 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002307 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 }
2309
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002310 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002312 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002314 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315
2316 p->sysctl = t;
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002317
David Ahern3b022862017-03-28 14:28:02 -07002318 inet_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_ALL,
2319 ifindex, p);
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002320 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002322free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002324out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002325 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326}
2327
David Ahernb5c96412017-03-28 14:28:03 -07002328static void __devinet_sysctl_unregister(struct net *net,
2329 struct ipv4_devconf *cnf, int ifindex)
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002330{
2331 struct devinet_sysctl_table *t = cnf->sysctl;
2332
David Ahernb5c96412017-03-28 14:28:03 -07002333 if (t) {
2334 cnf->sysctl = NULL;
2335 unregister_net_sysctl_table(t->sysctl_header);
2336 kfree(t);
2337 }
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002338
David Ahernb5c96412017-03-28 14:28:03 -07002339 inet_netconf_notify_devconf(net, RTM_DELNETCONF, 0, ifindex, NULL);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002340}
2341
WANG Cong20e61da2014-07-25 15:25:08 -07002342static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002343{
WANG Cong20e61da2014-07-25 15:25:08 -07002344 int err;
2345
2346 if (!sysctl_dev_name_is_allowed(idev->dev->name))
2347 return -EINVAL;
2348
2349 err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
2350 if (err)
2351 return err;
2352 err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002353 idev->dev->ifindex, &idev->cnf);
WANG Cong20e61da2014-07-25 15:25:08 -07002354 if (err)
2355 neigh_sysctl_unregister(idev->arp_parms);
2356 return err;
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002357}
2358
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002359static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360{
David Ahernb5c96412017-03-28 14:28:03 -07002361 struct net *net = dev_net(idev->dev);
2362
2363 __devinet_sysctl_unregister(net, &idev->cnf, idev->dev->ifindex);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002364 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002367static struct ctl_table ctl_forward_entry[] = {
2368 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002369 .procname = "ip_forward",
2370 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00002371 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002372 .maxlen = sizeof(int),
2373 .mode = 0644,
2374 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002375 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002376 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002377 },
2378 { },
2379};
Eric Dumazet2a75de02008-01-05 23:08:49 -08002380#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002381
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002382static __net_init int devinet_init_net(struct net *net)
2383{
2384 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002385 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002386#ifdef CONFIG_SYSCTL
2387 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002388 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002389#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002390
2391 err = -ENOMEM;
2392 all = &ipv4_devconf;
2393 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002394
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002395 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002396 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002397 if (!all)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002398 goto err_alloc_all;
2399
2400 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002401 if (!dflt)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002402 goto err_alloc_dflt;
2403
Eric Dumazet2a75de02008-01-05 23:08:49 -08002404#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002405 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002406 if (!tbl)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002407 goto err_alloc_ctl;
2408
Eric W. Biederman02291682010-02-14 03:25:51 +00002409 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002410 tbl[0].extra1 = all;
2411 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002412#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002413 }
2414
2415#ifdef CONFIG_SYSCTL
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002416 err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002417 if (err < 0)
2418 goto err_reg_all;
2419
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002420 err = __devinet_sysctl_register(net, "default",
2421 NETCONFA_IFINDEX_DEFAULT, dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002422 if (err < 0)
2423 goto err_reg_dflt;
2424
2425 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002426 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Ian Morris51456b22015-04-03 09:17:26 +01002427 if (!forw_hdr)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002428 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002429 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002430#endif
2431
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002432 net->ipv4.devconf_all = all;
2433 net->ipv4.devconf_dflt = dflt;
2434 return 0;
2435
2436#ifdef CONFIG_SYSCTL
2437err_reg_ctl:
David Ahernb5c96412017-03-28 14:28:03 -07002438 __devinet_sysctl_unregister(net, dflt, NETCONFA_IFINDEX_DEFAULT);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002439err_reg_dflt:
David Ahernb5c96412017-03-28 14:28:03 -07002440 __devinet_sysctl_unregister(net, all, NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002441err_reg_all:
2442 if (tbl != ctl_forward_entry)
2443 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002444err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08002445#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002446 if (dflt != &ipv4_devconf_dflt)
2447 kfree(dflt);
2448err_alloc_dflt:
2449 if (all != &ipv4_devconf)
2450 kfree(all);
2451err_alloc_all:
2452 return err;
2453}
2454
2455static __net_exit void devinet_exit_net(struct net *net)
2456{
Eric Dumazet2a75de02008-01-05 23:08:49 -08002457#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002458 struct ctl_table *tbl;
2459
2460 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002461 unregister_net_sysctl_table(net->ipv4.forw_hdr);
David Ahernb5c96412017-03-28 14:28:03 -07002462 __devinet_sysctl_unregister(net, net->ipv4.devconf_dflt,
2463 NETCONFA_IFINDEX_DEFAULT);
2464 __devinet_sysctl_unregister(net, net->ipv4.devconf_all,
2465 NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002466 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08002467#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002468 kfree(net->ipv4.devconf_dflt);
2469 kfree(net->ipv4.devconf_all);
2470}
2471
2472static __net_initdata struct pernet_operations devinet_ops = {
2473 .init = devinet_init_net,
2474 .exit = devinet_exit_net,
2475};
2476
Daniel Borkmann207895fd32015-01-29 12:15:03 +01002477static struct rtnl_af_ops inet_af_ops __read_mostly = {
Thomas Graf9f0f7272010-11-16 04:32:48 +00002478 .family = AF_INET,
2479 .fill_link_af = inet_fill_link_af,
2480 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00002481 .validate_link_af = inet_validate_link_af,
2482 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00002483};
2484
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485void __init devinet_init(void)
2486{
David S. Millerfd23c3b2011-02-18 12:42:28 -08002487 int i;
2488
2489 for (i = 0; i < IN4_ADDR_HSIZE; i++)
2490 INIT_HLIST_HEAD(&inet_addr_lst[i]);
2491
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002492 register_pernet_subsys(&devinet_ops);
2493
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 register_gifconf(PF_INET, inet_gifconf);
2495 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07002496
viresh kumar906e0732014-01-22 12:23:32 +05302497 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +00002498
Thomas Graf9f0f7272010-11-16 04:32:48 +00002499 rtnl_af_register(&inet_af_ops);
2500
Florian Westphalb97bac62017-08-09 20:41:48 +02002501 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, 0);
2502 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, 0);
2503 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, 0);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002504 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
Florian Westphalb97bac62017-08-09 20:41:48 +02002505 inet_netconf_dump_devconf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506}