blob: c6bd0f7a020a3e1796414abb7c35cdacf647a629 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * NET3 IP device support routines.
4 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Derived from the IP parts of dev.c 1.0.19
Jesper Juhl02c30a82005-05-05 16:16:16 -07006 * Authors: Ross Biro
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
8 * Mark Evans, <evansmp@uhura.aston.ac.uk>
9 *
10 * Additional Authors:
11 * Alan Cox, <gw4pts@gw4pts.ampr.org>
12 * Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
13 *
14 * Changes:
15 * Alexey Kuznetsov: pa_* fields are replaced with ifaddr
16 * lists.
17 * Cyrus Durgin: updated for kmod
18 * Matthias Andree: in devinet_ioctl, compare label and
19 * address (4.4BSD alias style support),
20 * fall back to comparing just the label
21 * if no match found.
22 */
23
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080025#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/bitops.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080027#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/module.h>
29#include <linux/types.h>
30#include <linux/kernel.h>
Ingo Molnar174cd4b2017-02-02 19:15:33 +010031#include <linux/sched/signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/string.h>
33#include <linux/mm.h>
34#include <linux/socket.h>
35#include <linux/sockios.h>
36#include <linux/in.h>
37#include <linux/errno.h>
38#include <linux/interrupt.h>
Thomas Graf18237302006-08-04 23:04:54 -070039#include <linux/if_addr.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/if_ether.h>
41#include <linux/inet.h>
42#include <linux/netdevice.h>
43#include <linux/etherdevice.h>
44#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include <linux/init.h>
46#include <linux/notifier.h>
47#include <linux/inetdevice.h>
48#include <linux/igmp.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090049#include <linux/slab.h>
David S. Millerfd23c3b2011-02-18 12:42:28 -080050#include <linux/hash.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#ifdef CONFIG_SYSCTL
52#include <linux/sysctl.h>
53#endif
54#include <linux/kmod.h>
Nicolas Dichteledc9e742012-10-25 22:28:52 +000055#include <linux/netconf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020057#include <net/arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#include <net/ip.h>
59#include <net/route.h>
60#include <net/ip_fib.h>
Thomas Graf63f34442007-03-22 11:55:17 -070061#include <net/rtnetlink.h>
Pavel Emelyanov752d14d2007-12-16 13:31:47 -080062#include <net/net_namespace.h>
Jiri Pirko5c766d62013-01-24 09:41:41 +000063#include <net/addrconf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Adrian Bunk0027ba82008-01-31 17:17:31 -080065static struct ipv4_devconf ipv4_devconf = {
Herbert Xu42f811b2007-06-04 23:34:44 -070066 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000067 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
68 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
69 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
70 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
William Manley26900482013-08-06 19:03:15 +010071 [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
72 [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
Herbert Xu42f811b2007-06-04 23:34:44 -070073 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070074};
75
76static struct ipv4_devconf ipv4_devconf_dflt = {
Herbert Xu42f811b2007-06-04 23:34:44 -070077 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000078 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
79 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
80 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
81 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
82 [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
William Manley26900482013-08-06 19:03:15 +010083 [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
84 [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
Herbert Xu42f811b2007-06-04 23:34:44 -070085 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070086};
87
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -080088#define IPV4_DEVCONF_DFLT(net, attr) \
89 IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr)
Herbert Xu42f811b2007-06-04 23:34:44 -070090
Patrick McHardyef7c79e2007-06-05 12:38:30 -070091static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
Thomas Graf5c753972006-08-04 23:03:53 -070092 [IFA_LOCAL] = { .type = NLA_U32 },
93 [IFA_ADDRESS] = { .type = NLA_U32 },
94 [IFA_BROADCAST] = { .type = NLA_U32 },
Thomas Graf5176f912006-08-26 20:13:18 -070095 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
Jiri Pirko5c766d62013-01-24 09:41:41 +000096 [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
Jiri Pirkoad6c8132013-12-08 12:16:10 +010097 [IFA_FLAGS] = { .type = NLA_U32 },
David Ahernaf4d7682018-05-27 08:09:57 -070098 [IFA_RT_PRIORITY] = { .type = NLA_U32 },
Christian Braunerd3807142018-09-04 21:53:49 +020099 [IFA_TARGET_NETNSID] = { .type = NLA_S32 },
Thomas Graf5c753972006-08-04 23:03:53 -0700100};
101
Christian Brauner978a46f2018-09-04 21:53:54 +0200102struct inet_fill_args {
103 u32 portid;
104 u32 seq;
105 int event;
106 unsigned int flags;
107 int netnsid;
David Ahern5fcd2662018-10-19 12:45:29 -0700108 int ifindex;
Christian Brauner978a46f2018-09-04 21:53:54 +0200109};
110
Eric Dumazet40384992012-08-03 21:06:50 +0000111#define IN4_ADDR_HSIZE_SHIFT 8
112#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT)
113
David S. Millerfd23c3b2011-02-18 12:42:28 -0800114static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
David S. Millerfd23c3b2011-02-18 12:42:28 -0800115
Eric Dumazet6eada012015-03-18 14:05:33 -0700116static u32 inet_addr_hash(const struct net *net, __be32 addr)
David S. Millerfd23c3b2011-02-18 12:42:28 -0800117{
Eric Dumazet40384992012-08-03 21:06:50 +0000118 u32 val = (__force u32) addr ^ net_hash_mix(net);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800119
Eric Dumazet40384992012-08-03 21:06:50 +0000120 return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800121}
122
123static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
124{
Eric Dumazet40384992012-08-03 21:06:50 +0000125 u32 hash = inet_addr_hash(net, ifa->ifa_local);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800126
WANG Cong32a4be42014-05-06 11:15:56 -0700127 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800128 hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800129}
130
131static void inet_hash_remove(struct in_ifaddr *ifa)
132{
WANG Cong32a4be42014-05-06 11:15:56 -0700133 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800134 hlist_del_init_rcu(&ifa->hash);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800135}
136
David S. Miller9435eb12011-02-18 12:43:09 -0800137/**
138 * __ip_dev_find - find the first device with a given source address.
139 * @net: the net namespace
140 * @addr: the source address
141 * @devref: if true, take a reference on the found device
142 *
143 * If a caller uses devref=false, it should be protected by RCU, or RTNL
144 */
145struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
146{
David S. Miller9435eb12011-02-18 12:43:09 -0800147 struct net_device *result = NULL;
148 struct in_ifaddr *ifa;
David S. Miller9435eb12011-02-18 12:43:09 -0800149
150 rcu_read_lock();
Paolo Abeni6e617de2017-09-20 18:26:53 +0200151 ifa = inet_lookup_ifaddr_rcu(net, addr);
152 if (!ifa) {
David S. Miller406b6f92011-03-22 21:56:23 -0700153 struct flowi4 fl4 = { .daddr = addr };
154 struct fib_result res = { 0 };
155 struct fib_table *local;
156
157 /* Fallback to FIB local table so that communication
158 * over loopback subnets work.
159 */
160 local = fib_get_table(net, RT_TABLE_LOCAL);
161 if (local &&
162 !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
163 res.type == RTN_LOCAL)
164 result = FIB_RES_DEV(res);
Paolo Abeni6e617de2017-09-20 18:26:53 +0200165 } else {
166 result = ifa->ifa_dev->dev;
David S. Miller406b6f92011-03-22 21:56:23 -0700167 }
David S. Miller9435eb12011-02-18 12:43:09 -0800168 if (result && devref)
169 dev_hold(result);
170 rcu_read_unlock();
171 return result;
172}
173EXPORT_SYMBOL(__ip_dev_find);
174
Paolo Abeni6e617de2017-09-20 18:26:53 +0200175/* called under RCU lock */
176struct in_ifaddr *inet_lookup_ifaddr_rcu(struct net *net, __be32 addr)
177{
178 u32 hash = inet_addr_hash(net, addr);
179 struct in_ifaddr *ifa;
180
181 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash)
182 if (ifa->ifa_local == addr &&
183 net_eq(dev_net(ifa->ifa_dev->dev), net))
184 return ifa;
185
186 return NULL;
187}
188
Thomas Grafd6062cb2006-08-15 00:33:59 -0700189static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
Alan Sterne041c682006-03-27 01:16:30 -0800191static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Krister Johansen3ad7d242017-06-08 13:12:14 -0700192static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
194 int destroy);
195#ifdef CONFIG_SYSCTL
WANG Cong20e61da2014-07-25 15:25:08 -0700196static int devinet_sysctl_register(struct in_device *idev);
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800197static void devinet_sysctl_unregister(struct in_device *idev);
198#else
WANG Cong20e61da2014-07-25 15:25:08 -0700199static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800200{
WANG Cong20e61da2014-07-25 15:25:08 -0700201 return 0;
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800202}
Eric Dumazet40384992012-08-03 21:06:50 +0000203static void devinet_sysctl_unregister(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800204{
205}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206#endif
207
208/* Locks all the inet devices. */
209
210static struct in_ifaddr *inet_alloc_ifa(void)
211{
Alexey Dobriyan93adcc82008-10-28 13:25:09 -0700212 return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213}
214
215static void inet_rcu_free_ifa(struct rcu_head *head)
216{
217 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
218 if (ifa->ifa_dev)
219 in_dev_put(ifa->ifa_dev);
220 kfree(ifa);
221}
222
Eric Dumazet40384992012-08-03 21:06:50 +0000223static void inet_free_ifa(struct in_ifaddr *ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224{
225 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
226}
227
228void in_dev_finish_destroy(struct in_device *idev)
229{
230 struct net_device *dev = idev->dev;
231
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700232 WARN_ON(idev->ifa_list);
233 WARN_ON(idev->mc_list);
Eric Dumazete9897072013-06-07 08:48:57 -0700234 kfree(rcu_dereference_protected(idev->mc_hash, 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235#ifdef NET_REFCNT_DEBUG
Joe Perches91df42b2012-05-15 14:11:54 +0000236 pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237#endif
238 dev_put(dev);
239 if (!idev->dead)
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800240 pr_err("Freeing alive in_device %p\n", idev);
241 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 kfree(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800244EXPORT_SYMBOL(in_dev_finish_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Herbert Xu71e27da2007-06-04 23:36:06 -0700246static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247{
248 struct in_device *in_dev;
WANG Cong20e61da2014-07-25 15:25:08 -0700249 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
251 ASSERT_RTNL();
252
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700253 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 if (!in_dev)
255 goto out;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900256 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -0800257 sizeof(in_dev->cnf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 in_dev->cnf.sysctl = NULL;
259 in_dev->dev = dev;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800260 in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
261 if (!in_dev->arp_parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 goto out_kfree;
Ben Hutchings0187bdf2008-06-19 16:15:47 -0700263 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
264 dev_disable_lro(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 /* Reference in_dev->dev */
266 dev_hold(dev);
David L Stevens30c4cf52007-01-04 12:31:14 -0800267 /* Account for reference dev->ip_ptr (below) */
Reshetova, Elena7658b362017-06-30 13:08:03 +0300268 refcount_set(&in_dev->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
WANG Cong20e61da2014-07-25 15:25:08 -0700270 err = devinet_sysctl_register(in_dev);
271 if (err) {
272 in_dev->dead = 1;
273 in_dev_put(in_dev);
274 in_dev = NULL;
275 goto out;
276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 ip_mc_init_dev(in_dev);
278 if (dev->flags & IFF_UP)
279 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800280
David L Stevens30c4cf52007-01-04 12:31:14 -0800281 /* we can receive as soon as ip_ptr is set -- do this last */
Eric Dumazetcf778b02012-01-12 04:41:32 +0000282 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800283out:
WANG Cong20e61da2014-07-25 15:25:08 -0700284 return in_dev ?: ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285out_kfree:
286 kfree(in_dev);
287 in_dev = NULL;
288 goto out;
289}
290
291static void in_dev_rcu_put(struct rcu_head *head)
292{
293 struct in_device *idev = container_of(head, struct in_device, rcu_head);
294 in_dev_put(idev);
295}
296
297static void inetdev_destroy(struct in_device *in_dev)
298{
299 struct in_ifaddr *ifa;
300 struct net_device *dev;
301
302 ASSERT_RTNL();
303
304 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
306 in_dev->dead = 1;
307
308 ip_mc_destroy_dev(in_dev);
309
310 while ((ifa = in_dev->ifa_list) != NULL) {
311 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
312 inet_free_ifa(ifa);
313 }
314
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000315 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800317 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
319 arp_ifdown(dev);
320
321 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
322}
323
Al Viroff428d72006-09-26 22:13:35 -0700324int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325{
326 rcu_read_lock();
327 for_primary_ifa(in_dev) {
328 if (inet_ifa_match(a, ifa)) {
329 if (!b || inet_ifa_match(b, ifa)) {
330 rcu_read_unlock();
331 return 1;
332 }
333 }
334 } endfor_ifa(in_dev);
335 rcu_read_unlock();
336 return 0;
337}
338
Thomas Grafd6062cb2006-08-15 00:33:59 -0700339static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000340 int destroy, struct nlmsghdr *nlh, u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
Harald Welte8f937c62005-05-29 20:23:46 -0700342 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800343 struct in_ifaddr *ifa, *ifa1 = *ifap;
344 struct in_ifaddr *last_prim = in_dev->ifa_list;
345 struct in_ifaddr *prev_prom = NULL;
346 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
348 ASSERT_RTNL();
349
David S. Millerfbd40ea2016-03-13 23:28:00 -0400350 if (in_dev->dead)
351 goto no_promotions;
352
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900353 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700354 * unless alias promotion is set
355 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
357 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
359
360 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900361 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800362 ifa1->ifa_scope <= ifa->ifa_scope)
363 last_prim = ifa;
364
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
366 ifa1->ifa_mask != ifa->ifa_mask ||
367 !inet_ifa_match(ifa1->ifa_address, ifa)) {
368 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800369 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 continue;
371 }
372
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800373 if (!do_promote) {
David S. Millerfd23c3b2011-02-18 12:42:28 -0800374 inet_hash_remove(ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700375 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
Eric W. Biederman15e47302012-09-07 20:12:54 +0000377 rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800378 blocking_notifier_call_chain(&inetaddr_chain,
379 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700380 inet_free_ifa(ifa);
381 } else {
382 promote = ifa;
383 break;
384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 }
386 }
387
Julian Anastasov2d230e22011-03-19 12:13:52 +0000388 /* On promotion all secondaries from subnet are changing
389 * the primary IP, we must remove all their routes silently
390 * and later to add them back with new prefsrc. Do this
391 * while all addresses are on the device list.
392 */
393 for (ifa = promote; ifa; ifa = ifa->ifa_next) {
394 if (ifa1->ifa_mask == ifa->ifa_mask &&
395 inet_ifa_match(ifa1->ifa_address, ifa))
396 fib_del_ifaddr(ifa, ifa1);
397 }
398
David S. Millerfbd40ea2016-03-13 23:28:00 -0400399no_promotions:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 /* 2. Unlink it */
401
402 *ifap = ifa1->ifa_next;
David S. Millerfd23c3b2011-02-18 12:42:28 -0800403 inet_hash_remove(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
405 /* 3. Announce address deletion */
406
407 /* Send message first, then call notifier.
408 At first sight, FIB update triggered by notifier
409 will refer to already deleted ifaddr, that could confuse
410 netlink listeners. It is not true: look, gated sees
411 that route deleted and if it still thinks that ifaddr
412 is valid, it will try to restore deleted routes... Grr.
413 So that, this order is correct.
414 */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000415 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800416 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800417
418 if (promote) {
Julian Anastasov04024b92011-03-19 12:13:54 +0000419 struct in_ifaddr *next_sec = promote->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800420
421 if (prev_prom) {
422 prev_prom->ifa_next = promote->ifa_next;
423 promote->ifa_next = last_prim->ifa_next;
424 last_prim->ifa_next = promote;
425 }
426
427 promote->ifa_flags &= ~IFA_F_SECONDARY;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000428 rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800429 blocking_notifier_call_chain(&inetaddr_chain,
430 NETDEV_UP, promote);
Julian Anastasov04024b92011-03-19 12:13:54 +0000431 for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800432 if (ifa1->ifa_mask != ifa->ifa_mask ||
433 !inet_ifa_match(ifa1->ifa_address, ifa))
434 continue;
435 fib_add_ifaddr(ifa);
436 }
437
438 }
Herbert Xu63630972007-06-07 18:35:38 -0700439 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441}
442
Thomas Grafd6062cb2006-08-15 00:33:59 -0700443static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
444 int destroy)
445{
446 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
447}
448
Jiri Pirko5c766d62013-01-24 09:41:41 +0000449static void check_lifetime(struct work_struct *work);
450
451static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
452
Thomas Grafd6062cb2006-08-15 00:33:59 -0700453static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
David Ahernde95e042017-10-18 09:56:54 -0700454 u32 portid, struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455{
456 struct in_device *in_dev = ifa->ifa_dev;
457 struct in_ifaddr *ifa1, **ifap, **last_primary;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700458 struct in_validator_info ivi;
459 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
461 ASSERT_RTNL();
462
463 if (!ifa->ifa_local) {
464 inet_free_ifa(ifa);
465 return 0;
466 }
467
468 ifa->ifa_flags &= ~IFA_F_SECONDARY;
469 last_primary = &in_dev->ifa_list;
470
471 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
472 ifap = &ifa1->ifa_next) {
473 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
474 ifa->ifa_scope <= ifa1->ifa_scope)
475 last_primary = &ifa1->ifa_next;
476 if (ifa1->ifa_mask == ifa->ifa_mask &&
477 inet_ifa_match(ifa1->ifa_address, ifa)) {
478 if (ifa1->ifa_local == ifa->ifa_local) {
479 inet_free_ifa(ifa);
480 return -EEXIST;
481 }
482 if (ifa1->ifa_scope != ifa->ifa_scope) {
483 inet_free_ifa(ifa);
484 return -EINVAL;
485 }
486 ifa->ifa_flags |= IFA_F_SECONDARY;
487 }
488 }
489
Krister Johansen3ad7d242017-06-08 13:12:14 -0700490 /* Allow any devices that wish to register ifaddr validtors to weigh
491 * in now, before changes are committed. The rntl lock is serializing
492 * access here, so the state should not change between a validator call
493 * and a final notify on commit. This isn't invoked on promotion under
494 * the assumption that validators are checking the address itself, and
495 * not the flags.
496 */
497 ivi.ivi_addr = ifa->ifa_address;
498 ivi.ivi_dev = ifa->ifa_dev;
David Ahernde95e042017-10-18 09:56:54 -0700499 ivi.extack = extack;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700500 ret = blocking_notifier_call_chain(&inetaddr_validator_chain,
501 NETDEV_UP, &ivi);
502 ret = notifier_to_errno(ret);
503 if (ret) {
504 inet_free_ifa(ifa);
505 return ret;
506 }
507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500509 prandom_seed((__force u32) ifa->ifa_local);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 ifap = last_primary;
511 }
512
513 ifa->ifa_next = *ifap;
514 *ifap = ifa;
515
David S. Millerfd23c3b2011-02-18 12:42:28 -0800516 inet_hash_insert(dev_net(in_dev->dev), ifa);
517
Jiri Pirko5c766d62013-01-24 09:41:41 +0000518 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530519 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000520
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 /* Send message first, then call notifier.
522 Notifier will trigger FIB update, so that
523 listeners of netlink will know about new ifaddr */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000524 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800525 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
527 return 0;
528}
529
Thomas Grafd6062cb2006-08-15 00:33:59 -0700530static int inet_insert_ifa(struct in_ifaddr *ifa)
531{
David Ahernde95e042017-10-18 09:56:54 -0700532 return __inet_insert_ifa(ifa, NULL, 0, NULL);
Thomas Grafd6062cb2006-08-15 00:33:59 -0700533}
534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
536{
Herbert Xue5ed6392005-10-03 14:35:55 -0700537 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
539 ASSERT_RTNL();
540
541 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700542 inet_free_ifa(ifa);
543 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700545 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100546 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700548 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 in_dev_hold(in_dev);
550 ifa->ifa_dev = in_dev;
551 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800552 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 ifa->ifa_scope = RT_SCOPE_HOST;
554 return inet_insert_ifa(ifa);
555}
556
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000557/* Caller must hold RCU or RTNL :
558 * We dont take a reference on found in_device
559 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800560struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561{
562 struct net_device *dev;
563 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000564
565 rcu_read_lock();
566 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000568 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000569 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 return in_dev;
571}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800572EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573
574/* Called only from RTNL semaphored context. No locks. */
575
Al Viro60cad5d2006-09-26 22:17:09 -0700576struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
577 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578{
579 ASSERT_RTNL();
580
581 for_primary_ifa(in_dev) {
582 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
583 return ifa;
584 } endfor_ifa(in_dev);
585 return NULL;
586}
587
Madhu Challa93a714d2015-02-25 09:58:35 -0800588static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa)
589{
590 struct ip_mreqn mreq = {
591 .imr_multiaddr.s_addr = ifa->ifa_address,
592 .imr_ifindex = ifa->ifa_dev->dev->ifindex,
593 };
594 int ret;
595
596 ASSERT_RTNL();
597
598 lock_sock(sk);
599 if (join)
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300600 ret = ip_mc_join_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800601 else
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300602 ret = ip_mc_leave_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800603 release_sock(sk);
604
605 return ret;
606}
607
David Ahernc21ef3e2017-04-16 09:48:24 -0700608static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
609 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900611 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700612 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700614 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700616 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618 ASSERT_RTNL();
619
Johannes Berg8cb08172019-04-26 14:07:28 +0200620 err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX,
621 ifa_ipv4_policy, extack);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700622 if (err < 0)
623 goto errout;
624
625 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800626 in_dev = inetdev_by_index(net, ifm->ifa_index);
Ian Morris51456b22015-04-03 09:17:26 +0100627 if (!in_dev) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700628 err = -ENODEV;
629 goto errout;
630 }
631
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
633 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700634 if (tb[IFA_LOCAL] &&
Jiri Benc67b61f62015-03-29 16:59:26 +0200635 ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700637
638 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
639 continue;
640
641 if (tb[IFA_ADDRESS] &&
642 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Jiri Benc67b61f62015-03-29 16:59:26 +0200643 !inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700644 continue;
645
Madhu Challa93a714d2015-02-25 09:58:35 -0800646 if (ipv4_is_multicast(ifa->ifa_address))
647 ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000648 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 return 0;
650 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700651
652 err = -EADDRNOTAVAIL;
653errout:
654 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655}
656
Jiri Pirko5c766d62013-01-24 09:41:41 +0000657#define INFINITY_LIFE_TIME 0xFFFFFFFF
658
659static void check_lifetime(struct work_struct *work)
660{
661 unsigned long now, next, next_sec, next_sched;
662 struct in_ifaddr *ifa;
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000663 struct hlist_node *n;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000664 int i;
665
666 now = jiffies;
667 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
668
Jiri Pirko5c766d62013-01-24 09:41:41 +0000669 for (i = 0; i < IN4_ADDR_HSIZE; i++) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000670 bool change_needed = false;
671
672 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800673 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
Jiri Pirko5c766d62013-01-24 09:41:41 +0000674 unsigned long age;
675
676 if (ifa->ifa_flags & IFA_F_PERMANENT)
677 continue;
678
679 /* We try to batch several events at once. */
680 age = (now - ifa->ifa_tstamp +
681 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
682
683 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
684 age >= ifa->ifa_valid_lft) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000685 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000686 } else if (ifa->ifa_preferred_lft ==
687 INFINITY_LIFE_TIME) {
688 continue;
689 } else if (age >= ifa->ifa_preferred_lft) {
690 if (time_before(ifa->ifa_tstamp +
691 ifa->ifa_valid_lft * HZ, next))
692 next = ifa->ifa_tstamp +
693 ifa->ifa_valid_lft * HZ;
694
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000695 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
696 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000697 } else if (time_before(ifa->ifa_tstamp +
698 ifa->ifa_preferred_lft * HZ,
699 next)) {
700 next = ifa->ifa_tstamp +
701 ifa->ifa_preferred_lft * HZ;
702 }
703 }
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000704 rcu_read_unlock();
705 if (!change_needed)
706 continue;
707 rtnl_lock();
708 hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
709 unsigned long age;
710
711 if (ifa->ifa_flags & IFA_F_PERMANENT)
712 continue;
713
714 /* We try to batch several events at once. */
715 age = (now - ifa->ifa_tstamp +
716 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
717
718 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
719 age >= ifa->ifa_valid_lft) {
720 struct in_ifaddr **ifap;
721
722 for (ifap = &ifa->ifa_dev->ifa_list;
723 *ifap != NULL; ifap = &(*ifap)->ifa_next) {
724 if (*ifap == ifa) {
725 inet_del_ifa(ifa->ifa_dev,
726 ifap, 1);
727 break;
728 }
729 }
730 } else if (ifa->ifa_preferred_lft !=
731 INFINITY_LIFE_TIME &&
732 age >= ifa->ifa_preferred_lft &&
733 !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
734 ifa->ifa_flags |= IFA_F_DEPRECATED;
735 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
736 }
737 }
738 rtnl_unlock();
Jiri Pirko5c766d62013-01-24 09:41:41 +0000739 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000740
741 next_sec = round_jiffies_up(next);
742 next_sched = next;
743
744 /* If rounded timeout is accurate enough, accept it. */
745 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
746 next_sched = next_sec;
747
748 now = jiffies;
749 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
750 if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
751 next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
752
viresh kumar906e0732014-01-22 12:23:32 +0530753 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work,
754 next_sched - now);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000755}
756
757static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
758 __u32 prefered_lft)
759{
760 unsigned long timeout;
761
762 ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
763
764 timeout = addrconf_timeout_fixup(valid_lft, HZ);
765 if (addrconf_finite_timeout(timeout))
766 ifa->ifa_valid_lft = timeout;
767 else
768 ifa->ifa_flags |= IFA_F_PERMANENT;
769
770 timeout = addrconf_timeout_fixup(prefered_lft, HZ);
771 if (addrconf_finite_timeout(timeout)) {
772 if (timeout == 0)
773 ifa->ifa_flags |= IFA_F_DEPRECATED;
774 ifa->ifa_preferred_lft = timeout;
775 }
776 ifa->ifa_tstamp = jiffies;
777 if (!ifa->ifa_cstamp)
778 ifa->ifa_cstamp = ifa->ifa_tstamp;
779}
780
781static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
David Aherndac9c972018-10-07 20:16:24 -0700782 __u32 *pvalid_lft, __u32 *pprefered_lft,
783 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784{
Thomas Graf5c753972006-08-04 23:03:53 -0700785 struct nlattr *tb[IFA_MAX+1];
786 struct in_ifaddr *ifa;
787 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 struct net_device *dev;
789 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800790 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
Johannes Berg8cb08172019-04-26 14:07:28 +0200792 err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX,
793 ifa_ipv4_policy, extack);
Thomas Graf5c753972006-08-04 23:03:53 -0700794 if (err < 0)
795 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
Thomas Graf5c753972006-08-04 23:03:53 -0700797 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800798 err = -EINVAL;
Ian Morris51456b22015-04-03 09:17:26 +0100799 if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL])
Thomas Graf5c753972006-08-04 23:03:53 -0700800 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800802 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800803 err = -ENODEV;
Ian Morris51456b22015-04-03 09:17:26 +0100804 if (!dev)
Thomas Graf5c753972006-08-04 23:03:53 -0700805 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
Thomas Graf5c753972006-08-04 23:03:53 -0700807 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800808 err = -ENOBUFS;
Ian Morris51456b22015-04-03 09:17:26 +0100809 if (!in_dev)
Herbert Xu71e27da2007-06-04 23:36:06 -0700810 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
Thomas Graf5c753972006-08-04 23:03:53 -0700812 ifa = inet_alloc_ifa();
Ian Morris51456b22015-04-03 09:17:26 +0100813 if (!ifa)
Thomas Graf5c753972006-08-04 23:03:53 -0700814 /*
815 * A potential indev allocation can be left alive, it stays
816 * assigned to its device and is destroy with it.
817 */
Thomas Graf5c753972006-08-04 23:03:53 -0700818 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700819
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800820 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100821 neigh_parms_data_state_setall(in_dev->arp_parms);
Thomas Graf5c753972006-08-04 23:03:53 -0700822 in_dev_hold(in_dev);
823
Ian Morris51456b22015-04-03 09:17:26 +0100824 if (!tb[IFA_ADDRESS])
Thomas Graf5c753972006-08-04 23:03:53 -0700825 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
826
David S. Millerfd23c3b2011-02-18 12:42:28 -0800827 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
829 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100830 ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
831 ifm->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700833 ifa->ifa_dev = in_dev;
834
Jiri Benc67b61f62015-03-29 16:59:26 +0200835 ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]);
836 ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700837
838 if (tb[IFA_BROADCAST])
Jiri Benc67b61f62015-03-29 16:59:26 +0200839 ifa->ifa_broadcast = nla_get_in_addr(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700840
Thomas Graf5c753972006-08-04 23:03:53 -0700841 if (tb[IFA_LABEL])
842 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 else
844 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
845
David Ahernaf4d7682018-05-27 08:09:57 -0700846 if (tb[IFA_RT_PRIORITY])
847 ifa->ifa_rt_priority = nla_get_u32(tb[IFA_RT_PRIORITY]);
848
Jiri Pirko5c766d62013-01-24 09:41:41 +0000849 if (tb[IFA_CACHEINFO]) {
850 struct ifa_cacheinfo *ci;
851
852 ci = nla_data(tb[IFA_CACHEINFO]);
853 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
854 err = -EINVAL;
Daniel Borkmann446266b2013-08-02 11:32:43 +0200855 goto errout_free;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000856 }
857 *pvalid_lft = ci->ifa_valid;
858 *pprefered_lft = ci->ifa_prefered;
859 }
860
Thomas Graf5c753972006-08-04 23:03:53 -0700861 return ifa;
862
Daniel Borkmann446266b2013-08-02 11:32:43 +0200863errout_free:
864 inet_free_ifa(ifa);
Thomas Graf5c753972006-08-04 23:03:53 -0700865errout:
866 return ERR_PTR(err);
867}
868
Jiri Pirko5c766d62013-01-24 09:41:41 +0000869static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
870{
871 struct in_device *in_dev = ifa->ifa_dev;
872 struct in_ifaddr *ifa1, **ifap;
873
874 if (!ifa->ifa_local)
875 return NULL;
876
877 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
878 ifap = &ifa1->ifa_next) {
879 if (ifa1->ifa_mask == ifa->ifa_mask &&
880 inet_ifa_match(ifa1->ifa_address, ifa) &&
881 ifa1->ifa_local == ifa->ifa_local)
882 return ifa1;
883 }
884 return NULL;
885}
886
David Ahernc21ef3e2017-04-16 09:48:24 -0700887static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
888 struct netlink_ext_ack *extack)
Thomas Graf5c753972006-08-04 23:03:53 -0700889{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900890 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700891 struct in_ifaddr *ifa;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000892 struct in_ifaddr *ifa_existing;
893 __u32 valid_lft = INFINITY_LIFE_TIME;
894 __u32 prefered_lft = INFINITY_LIFE_TIME;
Thomas Graf5c753972006-08-04 23:03:53 -0700895
896 ASSERT_RTNL();
897
David Aherndac9c972018-10-07 20:16:24 -0700898 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft, extack);
Thomas Graf5c753972006-08-04 23:03:53 -0700899 if (IS_ERR(ifa))
900 return PTR_ERR(ifa);
901
Jiri Pirko5c766d62013-01-24 09:41:41 +0000902 ifa_existing = find_matching_ifa(ifa);
903 if (!ifa_existing) {
904 /* It would be best to check for !NLM_F_CREATE here but
stephen hemminger614d0562014-05-16 20:46:58 -0700905 * userspace already relies on not having to provide this.
Jiri Pirko5c766d62013-01-24 09:41:41 +0000906 */
907 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Madhu Challa93a714d2015-02-25 09:58:35 -0800908 if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
909 int ret = ip_mc_config(net->ipv4.mc_autojoin_sk,
910 true, ifa);
911
912 if (ret < 0) {
913 inet_free_ifa(ifa);
914 return ret;
915 }
916 }
David Ahernde95e042017-10-18 09:56:54 -0700917 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid,
918 extack);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000919 } else {
David Ahernaf4d7682018-05-27 08:09:57 -0700920 u32 new_metric = ifa->ifa_rt_priority;
921
Jiri Pirko5c766d62013-01-24 09:41:41 +0000922 inet_free_ifa(ifa);
923
924 if (nlh->nlmsg_flags & NLM_F_EXCL ||
925 !(nlh->nlmsg_flags & NLM_F_REPLACE))
926 return -EEXIST;
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000927 ifa = ifa_existing;
David Ahernaf4d7682018-05-27 08:09:57 -0700928
929 if (ifa->ifa_rt_priority != new_metric) {
930 fib_modify_prefix_metric(ifa, new_metric);
931 ifa->ifa_rt_priority = new_metric;
932 }
933
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000934 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Jiri Pirko05a324b2013-04-04 23:39:38 +0000935 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530936 queue_delayed_work(system_power_efficient_wq,
937 &check_lifetime_work, 0);
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000938 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000939 }
940 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941}
942
943/*
944 * Determine a default network mask, based on the IP address.
945 */
946
Eric Dumazet40384992012-08-03 21:06:50 +0000947static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948{
949 int rc = -1; /* Something else, probably a multicast. */
950
Dave Taht65cab852018-12-11 15:30:34 -0800951 if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900952 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 else {
Al Viro714e85b2006-11-14 20:51:49 -0800954 __u32 haddr = ntohl(addr);
Al Viro714e85b2006-11-14 20:51:49 -0800955 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800957 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800959 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 rc = 24;
Dave Taht65cab852018-12-11 15:30:34 -0800961 else if (IN_CLASSE(haddr))
962 rc = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 }
964
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900965 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966}
967
968
Al Viro03aef172017-07-01 07:53:12 -0400969int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 struct sockaddr_in sin_orig;
Al Viro03aef172017-07-01 07:53:12 -0400972 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 struct in_device *in_dev;
974 struct in_ifaddr **ifap = NULL;
975 struct in_ifaddr *ifa = NULL;
976 struct net_device *dev;
977 char *colon;
978 int ret = -EFAULT;
979 int tryaddrmatch = 0;
980
Al Viro03aef172017-07-01 07:53:12 -0400981 ifr->ifr_name[IFNAMSIZ - 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
983 /* save original address for comparison */
984 memcpy(&sin_orig, sin, sizeof(*sin));
985
Al Viro03aef172017-07-01 07:53:12 -0400986 colon = strchr(ifr->ifr_name, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 if (colon)
988 *colon = 0;
989
Al Viro03aef172017-07-01 07:53:12 -0400990 dev_load(net, ifr->ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
Stephen Hemminger132adf52007-03-08 20:44:43 -0800992 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 case SIOCGIFADDR: /* Get interface address */
994 case SIOCGIFBRDADDR: /* Get the broadcast address */
995 case SIOCGIFDSTADDR: /* Get the destination address */
996 case SIOCGIFNETMASK: /* Get the netmask for the interface */
997 /* Note that these ioctls will not sleep,
998 so that we do not impose a lock.
999 One day we will be forced to put shlock here (I mean SMP)
1000 */
1001 tryaddrmatch = (sin_orig.sin_family == AF_INET);
1002 memset(sin, 0, sizeof(*sin));
1003 sin->sin_family = AF_INET;
1004 break;
1005
1006 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +00001007 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +00001008 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 goto out;
1010 break;
1011 case SIOCSIFADDR: /* Set interface address (and family) */
1012 case SIOCSIFBRDADDR: /* Set the broadcast address */
1013 case SIOCSIFDSTADDR: /* Set the destination address */
1014 case SIOCSIFNETMASK: /* Set the netmask for the interface */
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +00001015 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +00001016 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 goto out;
1018 ret = -EINVAL;
1019 if (sin->sin_family != AF_INET)
1020 goto out;
1021 break;
1022 default:
1023 ret = -EINVAL;
1024 goto out;
1025 }
1026
1027 rtnl_lock();
1028
1029 ret = -ENODEV;
Al Viro03aef172017-07-01 07:53:12 -04001030 dev = __dev_get_by_name(net, ifr->ifr_name);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001031 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 goto done;
1033
1034 if (colon)
1035 *colon = ':';
1036
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001037 in_dev = __in_dev_get_rtnl(dev);
1038 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 if (tryaddrmatch) {
1040 /* Matthias Andree */
1041 /* compare label and address (4.4BSD style) */
1042 /* note: we only do this for a limited set of ioctls
1043 and only if the original address family was AF_INET.
1044 This is checked above. */
1045 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1046 ifap = &ifa->ifa_next) {
Al Viro03aef172017-07-01 07:53:12 -04001047 if (!strcmp(ifr->ifr_name, ifa->ifa_label) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -08001049 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 break; /* found */
1051 }
1052 }
1053 }
1054 /* we didn't get a match, maybe the application is
1055 4.3BSD-style and passed in junk so we fall back to
1056 comparing just the label */
1057 if (!ifa) {
1058 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1059 ifap = &ifa->ifa_next)
Al Viro03aef172017-07-01 07:53:12 -04001060 if (!strcmp(ifr->ifr_name, ifa->ifa_label))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 break;
1062 }
1063 }
1064
1065 ret = -EADDRNOTAVAIL;
1066 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
1067 goto done;
1068
Stephen Hemminger132adf52007-03-08 20:44:43 -08001069 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 case SIOCGIFADDR: /* Get interface address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001071 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 sin->sin_addr.s_addr = ifa->ifa_local;
Al Viro03aef172017-07-01 07:53:12 -04001073 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
1075 case SIOCGIFBRDADDR: /* Get the broadcast address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001076 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 sin->sin_addr.s_addr = ifa->ifa_broadcast;
Al Viro03aef172017-07-01 07:53:12 -04001078 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
1080 case SIOCGIFDSTADDR: /* Get the destination address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001081 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 sin->sin_addr.s_addr = ifa->ifa_address;
Al Viro03aef172017-07-01 07:53:12 -04001083 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
1085 case SIOCGIFNETMASK: /* Get the netmask for the interface */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001086 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 sin->sin_addr.s_addr = ifa->ifa_mask;
Al Viro03aef172017-07-01 07:53:12 -04001088 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
1090 case SIOCSIFFLAGS:
1091 if (colon) {
1092 ret = -EADDRNOTAVAIL;
1093 if (!ifa)
1094 break;
1095 ret = 0;
Al Viro03aef172017-07-01 07:53:12 -04001096 if (!(ifr->ifr_flags & IFF_UP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 inet_del_ifa(in_dev, ifap, 1);
1098 break;
1099 }
Petr Machata567c5e12018-12-06 17:05:42 +00001100 ret = dev_change_flags(dev, ifr->ifr_flags, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 break;
1102
1103 case SIOCSIFADDR: /* Set interface address (and family) */
1104 ret = -EINVAL;
1105 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1106 break;
1107
1108 if (!ifa) {
1109 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001110 ifa = inet_alloc_ifa();
1111 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 break;
Xi Wangc7e2e1d2013-01-05 11:19:24 +00001113 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 if (colon)
Al Viro03aef172017-07-01 07:53:12 -04001115 memcpy(ifa->ifa_label, ifr->ifr_name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 else
1117 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1118 } else {
1119 ret = 0;
1120 if (ifa->ifa_local == sin->sin_addr.s_addr)
1121 break;
1122 inet_del_ifa(in_dev, ifap, 0);
1123 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -08001124 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 }
1126
1127 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
1128
1129 if (!(dev->flags & IFF_POINTOPOINT)) {
1130 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
1131 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
1132 if ((dev->flags & IFF_BROADCAST) &&
1133 ifa->ifa_prefixlen < 31)
1134 ifa->ifa_broadcast = ifa->ifa_address |
1135 ~ifa->ifa_mask;
1136 } else {
1137 ifa->ifa_prefixlen = 32;
1138 ifa->ifa_mask = inet_make_mask(32);
1139 }
Jiri Pirko5c766d62013-01-24 09:41:41 +00001140 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 ret = inet_set_ifa(dev, ifa);
1142 break;
1143
1144 case SIOCSIFBRDADDR: /* Set the broadcast address */
1145 ret = 0;
1146 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
1147 inet_del_ifa(in_dev, ifap, 0);
1148 ifa->ifa_broadcast = sin->sin_addr.s_addr;
1149 inet_insert_ifa(ifa);
1150 }
1151 break;
1152
1153 case SIOCSIFDSTADDR: /* Set the destination address */
1154 ret = 0;
1155 if (ifa->ifa_address == sin->sin_addr.s_addr)
1156 break;
1157 ret = -EINVAL;
1158 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1159 break;
1160 ret = 0;
1161 inet_del_ifa(in_dev, ifap, 0);
1162 ifa->ifa_address = sin->sin_addr.s_addr;
1163 inet_insert_ifa(ifa);
1164 break;
1165
1166 case SIOCSIFNETMASK: /* Set the netmask for the interface */
1167
1168 /*
1169 * The mask we set must be legal.
1170 */
1171 ret = -EINVAL;
1172 if (bad_mask(sin->sin_addr.s_addr, 0))
1173 break;
1174 ret = 0;
1175 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -07001176 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 inet_del_ifa(in_dev, ifap, 0);
1178 ifa->ifa_mask = sin->sin_addr.s_addr;
1179 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
1180
1181 /* See if current broadcast address matches
1182 * with current netmask, then recalculate
1183 * the broadcast address. Otherwise it's a
1184 * funny address, so don't touch it since
1185 * the user seems to know what (s)he's doing...
1186 */
1187 if ((dev->flags & IFF_BROADCAST) &&
1188 (ifa->ifa_prefixlen < 31) &&
1189 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -05001190 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 ifa->ifa_broadcast = (ifa->ifa_local |
1192 ~sin->sin_addr.s_addr);
1193 }
1194 inet_insert_ifa(ifa);
1195 }
1196 break;
1197 }
1198done:
1199 rtnl_unlock();
1200out:
1201 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202}
1203
Al Viro36fd6332017-06-26 13:19:16 -04001204static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205{
Herbert Xue5ed6392005-10-03 14:35:55 -07001206 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 struct in_ifaddr *ifa;
1208 struct ifreq ifr;
1209 int done = 0;
1210
Al Viro36fd6332017-06-26 13:19:16 -04001211 if (WARN_ON(size > sizeof(struct ifreq)))
1212 goto out;
1213
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001214 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 goto out;
1216
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001217 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 if (!buf) {
Al Viro36fd6332017-06-26 13:19:16 -04001219 done += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 continue;
1221 }
Al Viro36fd6332017-06-26 13:19:16 -04001222 if (len < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 break;
1224 memset(&ifr, 0, sizeof(struct ifreq));
Dan Carpenter4299c8a2013-07-29 22:15:19 +03001225 strcpy(ifr.ifr_name, ifa->ifa_label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
1227 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
1228 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1229 ifa->ifa_local;
1230
Al Viro36fd6332017-06-26 13:19:16 -04001231 if (copy_to_user(buf + done, &ifr, size)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 done = -EFAULT;
1233 break;
1234 }
Al Viro36fd6332017-06-26 13:19:16 -04001235 len -= size;
1236 done += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 }
1238out:
1239 return done;
1240}
1241
Gao Feng8b57fd12017-03-10 12:38:47 +08001242static __be32 in_dev_select_addr(const struct in_device *in_dev,
1243 int scope)
1244{
1245 for_primary_ifa(in_dev) {
1246 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1247 ifa->ifa_scope <= scope)
1248 return ifa->ifa_local;
1249 } endfor_ifa(in_dev);
1250
1251 return 0;
1252}
1253
Al Viroa61ced52006-09-26 21:27:54 -07001254__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255{
Al Viroa61ced52006-09-26 21:27:54 -07001256 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001258 struct net *net = dev_net(dev);
David Ahern3f2fb9a2016-02-24 11:47:02 -08001259 int master_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
1261 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001262 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 if (!in_dev)
1264 goto no_in_dev;
1265
1266 for_primary_ifa(in_dev) {
1267 if (ifa->ifa_scope > scope)
1268 continue;
1269 if (!dst || inet_ifa_match(dst, ifa)) {
1270 addr = ifa->ifa_local;
1271 break;
1272 }
1273 if (!addr)
1274 addr = ifa->ifa_local;
1275 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276
1277 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001278 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001279no_in_dev:
David Ahern3f2fb9a2016-02-24 11:47:02 -08001280 master_idx = l3mdev_master_ifindex_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281
David Lamparter17b693c2016-02-24 11:47:03 -08001282 /* For VRFs, the VRF device takes the place of the loopback device,
1283 * with addresses on it being preferred. Note in such cases the
1284 * loopback device will be among the devices that fail the master_idx
1285 * equality check in the loop below.
1286 */
1287 if (master_idx &&
1288 (dev = dev_get_by_index_rcu(net, master_idx)) &&
1289 (in_dev = __in_dev_get_rcu(dev))) {
Gao Feng8b57fd12017-03-10 12:38:47 +08001290 addr = in_dev_select_addr(in_dev, scope);
1291 if (addr)
1292 goto out_unlock;
David Lamparter17b693c2016-02-24 11:47:03 -08001293 }
1294
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 /* Not loopback addresses on loopback should be preferred
Stephen Hemmingerca9f1fd2015-02-14 13:47:54 -05001296 in this case. It is important that lo is the first interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 in dev_base list.
1298 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001299 for_each_netdev_rcu(net, dev) {
David Ahern3f2fb9a2016-02-24 11:47:02 -08001300 if (l3mdev_master_ifindex_rcu(dev) != master_idx)
1301 continue;
1302
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001303 in_dev = __in_dev_get_rcu(dev);
1304 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 continue;
1306
Gao Feng8b57fd12017-03-10 12:38:47 +08001307 addr = in_dev_select_addr(in_dev, scope);
1308 if (addr)
1309 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001311out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 return addr;
1314}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001315EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316
Al Viro60cad5d2006-09-26 22:17:09 -07001317static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1318 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319{
1320 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001321 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322
1323 for_ifa(in_dev) {
1324 if (!addr &&
1325 (local == ifa->ifa_local || !local) &&
1326 ifa->ifa_scope <= scope) {
1327 addr = ifa->ifa_local;
1328 if (same)
1329 break;
1330 }
1331 if (!same) {
1332 same = (!local || inet_ifa_match(local, ifa)) &&
1333 (!dst || inet_ifa_match(dst, ifa));
1334 if (same && addr) {
1335 if (local || !dst)
1336 break;
1337 /* Is the selected addr into dst subnet? */
1338 if (inet_ifa_match(addr, ifa))
1339 break;
1340 /* No, then can we use new local src? */
1341 if (ifa->ifa_scope <= scope) {
1342 addr = ifa->ifa_local;
1343 break;
1344 }
1345 /* search for large dst subnet for addr */
1346 same = 0;
1347 }
1348 }
1349 } endfor_ifa(in_dev);
1350
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001351 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352}
1353
1354/*
1355 * Confirm that local IP address exists using wildcards:
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001356 * - net: netns to check, cannot be NULL
1357 * - in_dev: only on this interface, NULL=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 * - dst: only in the same subnet as dst, 0=any dst
1359 * - local: address, 0=autoselect the local address
1360 * - scope: maximum allowed scope value for the local address
1361 */
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001362__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001363 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364{
Al Viro60cad5d2006-09-26 22:17:09 -07001365 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001366 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
Ian Morris00db4122015-04-03 09:17:27 +01001368 if (in_dev)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001369 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001372 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001373 in_dev = __in_dev_get_rcu(dev);
1374 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 addr = confirm_addr_indev(in_dev, dst, local, scope);
1376 if (addr)
1377 break;
1378 }
1379 }
1380 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381
1382 return addr;
1383}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001384EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385
1386/*
1387 * Device notifier
1388 */
1389
1390int register_inetaddr_notifier(struct notifier_block *nb)
1391{
Alan Sterne041c682006-03-27 01:16:30 -08001392 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001394EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
1396int unregister_inetaddr_notifier(struct notifier_block *nb)
1397{
Alan Sterne041c682006-03-27 01:16:30 -08001398 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001400EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
Krister Johansen3ad7d242017-06-08 13:12:14 -07001402int register_inetaddr_validator_notifier(struct notifier_block *nb)
1403{
1404 return blocking_notifier_chain_register(&inetaddr_validator_chain, nb);
1405}
1406EXPORT_SYMBOL(register_inetaddr_validator_notifier);
1407
1408int unregister_inetaddr_validator_notifier(struct notifier_block *nb)
1409{
1410 return blocking_notifier_chain_unregister(&inetaddr_validator_chain,
1411 nb);
1412}
1413EXPORT_SYMBOL(unregister_inetaddr_validator_notifier);
1414
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001415/* Rename ifa_labels for a device name change. Make some effort to preserve
1416 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417*/
1418static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001419{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 struct in_ifaddr *ifa;
1421 int named = 0;
1422
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001423 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1424 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
1426 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001427 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001429 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001430 dot = strchr(old, ':');
Ian Morris51456b22015-04-03 09:17:26 +01001431 if (!dot) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001432 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 dot = old;
1434 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001435 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001436 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001437 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001438 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001439skip:
1440 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001441 }
1442}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443
Eric Dumazet40384992012-08-03 21:06:50 +00001444static bool inetdev_valid_mtu(unsigned int mtu)
Breno Leitao06770842008-09-02 17:28:58 -07001445{
Eric Dumazetb5476022017-12-11 07:17:39 -08001446 return mtu >= IPV4_MIN_MTU;
Breno Leitao06770842008-09-02 17:28:58 -07001447}
1448
Ian Campbelld11327ad2011-02-11 07:44:16 +00001449static void inetdev_send_gratuitous_arp(struct net_device *dev,
1450 struct in_device *in_dev)
1451
1452{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001453 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001454
Zoltan Kissb76d0782011-07-24 13:09:30 +00001455 for (ifa = in_dev->ifa_list; ifa;
1456 ifa = ifa->ifa_next) {
1457 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1458 ifa->ifa_local, dev,
1459 ifa->ifa_local, NULL,
1460 dev->dev_addr, NULL);
1461 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001462}
1463
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464/* Called only under RTNL semaphore */
1465
1466static int inetdev_event(struct notifier_block *this, unsigned long event,
1467 void *ptr)
1468{
Jiri Pirko351638e2013-05-28 01:30:21 +00001469 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazet748e2d92012-08-22 21:50:59 +00001470 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471
1472 ASSERT_RTNL();
1473
1474 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001475 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 in_dev = inetdev_init(dev);
WANG Cong20e61da2014-07-25 15:25:08 -07001477 if (IS_ERR(in_dev))
1478 return notifier_from_errno(PTR_ERR(in_dev));
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001479 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001480 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1481 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001482 }
Breno Leitao06770842008-09-02 17:28:58 -07001483 } else if (event == NETDEV_CHANGEMTU) {
1484 /* Re-enabling IP */
1485 if (inetdev_valid_mtu(dev->mtu))
1486 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 }
1488 goto out;
1489 }
1490
1491 switch (event) {
1492 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001493 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001494 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 break;
1496 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001497 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001499 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001500 struct in_ifaddr *ifa = inet_alloc_ifa();
1501
1502 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001503 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 ifa->ifa_local =
1505 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1506 ifa->ifa_prefixlen = 8;
1507 ifa->ifa_mask = inet_make_mask(8);
1508 in_dev_hold(in_dev);
1509 ifa->ifa_dev = in_dev;
1510 ifa->ifa_scope = RT_SCOPE_HOST;
1511 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Jiri Pirko5c766d62013-01-24 09:41:41 +00001512 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1513 INFINITY_LIFE_TIME);
Jiri Pirkodfd15822014-01-07 15:55:45 +01001514 ipv4_devconf_setall(in_dev);
1515 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 inet_insert_ifa(ifa);
1517 }
1518 }
1519 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001520 /* fall through */
1521 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001522 if (!IN_DEV_ARP_NOTIFY(in_dev))
1523 break;
1524 /* fall through */
1525 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001526 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001527 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 break;
1529 case NETDEV_DOWN:
1530 ip_mc_down(in_dev);
1531 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001532 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001533 ip_mc_unmap(in_dev);
1534 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001535 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001536 ip_mc_remap(in_dev);
1537 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001539 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 break;
Breno Leitao06770842008-09-02 17:28:58 -07001541 /* disable IP when MTU is not enough */
Gustavo A. R. Silvafcfd6df2017-10-16 15:48:55 -05001542 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 case NETDEV_UNREGISTER:
1544 inetdev_destroy(in_dev);
1545 break;
1546 case NETDEV_CHANGENAME:
1547 /* Do not notify about label change, this event is
1548 * not interesting to applications using netlink.
1549 */
1550 inetdev_changename(dev, in_dev);
1551
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001552 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001553 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 break;
1555 }
1556out:
1557 return NOTIFY_DONE;
1558}
1559
1560static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001561 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562};
1563
Eric Dumazet40384992012-08-03 21:06:50 +00001564static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001565{
1566 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1567 + nla_total_size(4) /* IFA_ADDRESS */
1568 + nla_total_size(4) /* IFA_LOCAL */
1569 + nla_total_size(4) /* IFA_BROADCAST */
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001570 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001571 + nla_total_size(4) /* IFA_FLAGS */
David Ahernaf4d7682018-05-27 08:09:57 -07001572 + nla_total_size(4) /* IFA_RT_PRIORITY */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001573 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
Thomas Graf339bf982006-11-10 14:10:15 -08001574}
1575
Jiri Pirko5c766d62013-01-24 09:41:41 +00001576static inline u32 cstamp_delta(unsigned long cstamp)
1577{
1578 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1579}
1580
1581static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1582 unsigned long tstamp, u32 preferred, u32 valid)
1583{
1584 struct ifa_cacheinfo ci;
1585
1586 ci.cstamp = cstamp_delta(cstamp);
1587 ci.tstamp = cstamp_delta(tstamp);
1588 ci.ifa_prefered = preferred;
1589 ci.ifa_valid = valid;
1590
1591 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1592}
1593
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Christian Brauner978a46f2018-09-04 21:53:54 +02001595 struct inet_fill_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596{
1597 struct ifaddrmsg *ifm;
1598 struct nlmsghdr *nlh;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001599 u32 preferred, valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600
Christian Brauner978a46f2018-09-04 21:53:54 +02001601 nlh = nlmsg_put(skb, args->portid, args->seq, args->event, sizeof(*ifm),
1602 args->flags);
Ian Morris51456b22015-04-03 09:17:26 +01001603 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08001604 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001605
1606 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 ifm->ifa_family = AF_INET;
1608 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001609 ifm->ifa_flags = ifa->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 ifm->ifa_scope = ifa->ifa_scope;
1611 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612
Christian Brauner978a46f2018-09-04 21:53:54 +02001613 if (args->netnsid >= 0 &&
1614 nla_put_s32(skb, IFA_TARGET_NETNSID, args->netnsid))
Christian Braunerd3807142018-09-04 21:53:49 +02001615 goto nla_put_failure;
1616
Jiri Pirko5c766d62013-01-24 09:41:41 +00001617 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1618 preferred = ifa->ifa_preferred_lft;
1619 valid = ifa->ifa_valid_lft;
1620 if (preferred != INFINITY_LIFE_TIME) {
1621 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1622
1623 if (preferred > tval)
1624 preferred -= tval;
1625 else
1626 preferred = 0;
1627 if (valid != INFINITY_LIFE_TIME) {
1628 if (valid > tval)
1629 valid -= tval;
1630 else
1631 valid = 0;
1632 }
1633 }
1634 } else {
1635 preferred = INFINITY_LIFE_TIME;
1636 valid = INFINITY_LIFE_TIME;
1637 }
David S. Millerf3756b72012-04-01 20:39:02 -04001638 if ((ifa->ifa_address &&
Jiri Benc930345e2015-03-29 16:59:25 +02001639 nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001640 (ifa->ifa_local &&
Jiri Benc930345e2015-03-29 16:59:25 +02001641 nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001642 (ifa->ifa_broadcast &&
Jiri Benc930345e2015-03-29 16:59:25 +02001643 nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001644 (ifa->ifa_label[0] &&
Jiri Pirko5c766d62013-01-24 09:41:41 +00001645 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001646 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
David Ahernaf4d7682018-05-27 08:09:57 -07001647 (ifa->ifa_rt_priority &&
1648 nla_put_u32(skb, IFA_RT_PRIORITY, ifa->ifa_rt_priority)) ||
Jiri Pirko5c766d62013-01-24 09:41:41 +00001649 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1650 preferred, valid))
David S. Millerf3756b72012-04-01 20:39:02 -04001651 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001652
Johannes Berg053c0952015-01-16 22:09:00 +01001653 nlmsg_end(skb, nlh);
1654 return 0;
Thomas Graf47f68512006-08-04 23:04:36 -07001655
1656nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001657 nlmsg_cancel(skb, nlh);
1658 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659}
1660
David Ahernc33078e2018-10-07 20:16:28 -07001661static int inet_valid_dump_ifaddr_req(const struct nlmsghdr *nlh,
1662 struct inet_fill_args *fillargs,
1663 struct net **tgt_net, struct sock *sk,
David Ahern5fcd2662018-10-19 12:45:29 -07001664 struct netlink_callback *cb)
David Ahernc33078e2018-10-07 20:16:28 -07001665{
David Ahern5fcd2662018-10-19 12:45:29 -07001666 struct netlink_ext_ack *extack = cb->extack;
David Ahernc33078e2018-10-07 20:16:28 -07001667 struct nlattr *tb[IFA_MAX+1];
1668 struct ifaddrmsg *ifm;
1669 int err, i;
1670
1671 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) {
1672 NL_SET_ERR_MSG(extack, "ipv4: Invalid header for address dump request");
1673 return -EINVAL;
1674 }
1675
1676 ifm = nlmsg_data(nlh);
1677 if (ifm->ifa_prefixlen || ifm->ifa_flags || ifm->ifa_scope) {
1678 NL_SET_ERR_MSG(extack, "ipv4: Invalid values in header for address dump request");
1679 return -EINVAL;
1680 }
David Ahern5fcd2662018-10-19 12:45:29 -07001681
1682 fillargs->ifindex = ifm->ifa_index;
1683 if (fillargs->ifindex) {
1684 cb->answer_flags |= NLM_F_DUMP_FILTERED;
1685 fillargs->flags |= NLM_F_DUMP_FILTERED;
David Ahernc33078e2018-10-07 20:16:28 -07001686 }
1687
Johannes Berg8cb08172019-04-26 14:07:28 +02001688 err = nlmsg_parse_deprecated_strict(nlh, sizeof(*ifm), tb, IFA_MAX,
1689 ifa_ipv4_policy, extack);
David Ahernc33078e2018-10-07 20:16:28 -07001690 if (err < 0)
1691 return err;
1692
1693 for (i = 0; i <= IFA_MAX; ++i) {
1694 if (!tb[i])
1695 continue;
1696
1697 if (i == IFA_TARGET_NETNSID) {
1698 struct net *net;
1699
1700 fillargs->netnsid = nla_get_s32(tb[i]);
1701
1702 net = rtnl_get_net_ns_capable(sk, fillargs->netnsid);
1703 if (IS_ERR(net)) {
Bjørn Morkbf4cc402018-10-25 21:18:25 +02001704 fillargs->netnsid = -1;
David Ahernc33078e2018-10-07 20:16:28 -07001705 NL_SET_ERR_MSG(extack, "ipv4: Invalid target network namespace id");
1706 return PTR_ERR(net);
1707 }
1708 *tgt_net = net;
1709 } else {
1710 NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in dump request");
1711 return -EINVAL;
1712 }
1713 }
1714
1715 return 0;
1716}
1717
David Ahern1c98eca2018-10-19 12:45:27 -07001718static int in_dev_dump_addr(struct in_device *in_dev, struct sk_buff *skb,
1719 struct netlink_callback *cb, int s_ip_idx,
1720 struct inet_fill_args *fillargs)
1721{
1722 struct in_ifaddr *ifa;
1723 int ip_idx = 0;
1724 int err;
1725
1726 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next, ip_idx++) {
1727 if (ip_idx < s_ip_idx)
1728 continue;
1729
1730 err = inet_fill_ifaddr(skb, ifa, fillargs);
1731 if (err < 0)
1732 goto done;
1733
1734 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
1735 }
1736 err = 0;
1737
1738done:
1739 cb->args[2] = ip_idx;
1740
1741 return err;
1742}
1743
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1745{
David Ahernc33078e2018-10-07 20:16:28 -07001746 const struct nlmsghdr *nlh = cb->nlh;
Christian Brauner978a46f2018-09-04 21:53:54 +02001747 struct inet_fill_args fillargs = {
1748 .portid = NETLINK_CB(cb->skb).portid,
David Ahernc33078e2018-10-07 20:16:28 -07001749 .seq = nlh->nlmsg_seq,
Christian Brauner978a46f2018-09-04 21:53:54 +02001750 .event = RTM_NEWADDR,
1751 .flags = NLM_F_MULTI,
1752 .netnsid = -1,
1753 };
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001754 struct net *net = sock_net(skb->sk);
Christian Braunerd3807142018-09-04 21:53:49 +02001755 struct net *tgt_net = net;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001756 int h, s_h;
1757 int idx, s_idx;
David Ahern1c98eca2018-10-19 12:45:27 -07001758 int s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 struct net_device *dev;
1760 struct in_device *in_dev;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001761 struct hlist_head *head;
David Ahernd7e38612018-10-24 12:58:59 -07001762 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763
Eric Dumazeteec4df92009-11-12 07:44:25 +00001764 s_h = cb->args[0];
1765 s_idx = idx = cb->args[1];
David Ahern1c98eca2018-10-19 12:45:27 -07001766 s_ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
David Ahernc33078e2018-10-07 20:16:28 -07001768 if (cb->strict_check) {
David Ahernc33078e2018-10-07 20:16:28 -07001769 err = inet_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net,
David Ahern5fcd2662018-10-19 12:45:29 -07001770 skb->sk, cb);
David Ahernc33078e2018-10-07 20:16:28 -07001771 if (err < 0)
David Ahernd7e38612018-10-24 12:58:59 -07001772 goto put_tgt_net;
David Ahern5fcd2662018-10-19 12:45:29 -07001773
David Ahernd7e38612018-10-24 12:58:59 -07001774 err = 0;
David Ahern5fcd2662018-10-19 12:45:29 -07001775 if (fillargs.ifindex) {
1776 dev = __dev_get_by_index(tgt_net, fillargs.ifindex);
David Ahernd7e38612018-10-24 12:58:59 -07001777 if (!dev) {
1778 err = -ENODEV;
1779 goto put_tgt_net;
1780 }
David Ahern5fcd2662018-10-19 12:45:29 -07001781
1782 in_dev = __in_dev_get_rtnl(dev);
1783 if (in_dev) {
1784 err = in_dev_dump_addr(in_dev, skb, cb, s_ip_idx,
1785 &fillargs);
1786 }
1787 goto put_tgt_net;
1788 }
Christian Braunerd3807142018-09-04 21:53:49 +02001789 }
1790
Eric Dumazeteec4df92009-11-12 07:44:25 +00001791 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1792 idx = 0;
Christian Braunerd3807142018-09-04 21:53:49 +02001793 head = &tgt_net->dev_index_head[h];
Eric Dumazeteec4df92009-11-12 07:44:25 +00001794 rcu_read_lock();
Christian Braunerd3807142018-09-04 21:53:49 +02001795 cb->seq = atomic_read(&tgt_net->ipv4.dev_addr_genid) ^
1796 tgt_net->dev_base_seq;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001797 hlist_for_each_entry_rcu(dev, head, index_hlist) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001798 if (idx < s_idx)
1799 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001800 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001801 s_ip_idx = 0;
1802 in_dev = __in_dev_get_rcu(dev);
1803 if (!in_dev)
1804 goto cont;
1805
David Ahern1c98eca2018-10-19 12:45:27 -07001806 err = in_dev_dump_addr(in_dev, skb, cb, s_ip_idx,
1807 &fillargs);
1808 if (err < 0) {
1809 rcu_read_unlock();
1810 goto done;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001811 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001812cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001813 idx++;
1814 }
1815 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 }
1817
1818done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001819 cb->args[0] = h;
1820 cb->args[1] = idx;
David Ahern5fcd2662018-10-19 12:45:29 -07001821put_tgt_net:
Christian Brauner978a46f2018-09-04 21:53:54 +02001822 if (fillargs.netnsid >= 0)
Christian Braunerd3807142018-09-04 21:53:49 +02001823 put_net(tgt_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824
Arthur Gautier7c1e8a32018-12-31 02:10:58 +00001825 return skb->len ? : err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826}
1827
Jianjun Kong539afed2008-11-03 02:48:48 -08001828static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001829 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830{
Christian Brauner978a46f2018-09-04 21:53:54 +02001831 struct inet_fill_args fillargs = {
1832 .portid = portid,
1833 .seq = nlh ? nlh->nlmsg_seq : 0,
1834 .event = event,
1835 .flags = 0,
1836 .netnsid = -1,
1837 };
Thomas Graf47f68512006-08-04 23:04:36 -07001838 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001839 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001840 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001842 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001843 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001844 if (!skb)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001845 goto errout;
1846
Christian Brauner978a46f2018-09-04 21:53:54 +02001847 err = inet_fill_ifaddr(skb, ifa, &fillargs);
Patrick McHardy26932562007-01-31 23:16:40 -08001848 if (err < 0) {
1849 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1850 WARN_ON(err == -EMSGSIZE);
1851 kfree_skb(skb);
1852 goto errout;
1853 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001854 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001855 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001856errout:
1857 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001858 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859}
1860
Arad, Ronenb1974ed2015-10-19 09:23:28 -07001861static size_t inet_get_link_af_size(const struct net_device *dev,
1862 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001863{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001864 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001865
1866 if (!in_dev)
1867 return 0;
1868
1869 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1870}
1871
Sowmini Varadhand5566fd2015-09-11 16:48:48 -04001872static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
1873 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001874{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001875 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001876 struct nlattr *nla;
1877 int i;
1878
1879 if (!in_dev)
1880 return -ENODATA;
1881
1882 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
Ian Morris51456b22015-04-03 09:17:26 +01001883 if (!nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001884 return -EMSGSIZE;
1885
1886 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1887 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1888
1889 return 0;
1890}
1891
1892static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1893 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1894};
1895
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001896static int inet_validate_link_af(const struct net_device *dev,
1897 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001898{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001899 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1900 int err, rem;
1901
Florian Westphal5fa85a02017-10-16 15:44:36 +02001902 if (dev && !__in_dev_get_rcu(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001903 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001904
Johannes Berg8cb08172019-04-26 14:07:28 +02001905 err = nla_parse_nested_deprecated(tb, IFLA_INET_MAX, nla,
1906 inet_af_policy, NULL);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001907 if (err < 0)
1908 return err;
1909
1910 if (tb[IFLA_INET_CONF]) {
1911 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1912 int cfgid = nla_type(a);
1913
1914 if (nla_len(a) < 4)
1915 return -EINVAL;
1916
1917 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1918 return -EINVAL;
1919 }
1920 }
1921
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001922 return 0;
1923}
1924
1925static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1926{
Florian Westphal5fa85a02017-10-16 15:44:36 +02001927 struct in_device *in_dev = __in_dev_get_rcu(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001928 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1929 int rem;
1930
1931 if (!in_dev)
1932 return -EAFNOSUPPORT;
1933
Johannes Berg8cb08172019-04-26 14:07:28 +02001934 if (nla_parse_nested_deprecated(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0)
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001935 BUG();
1936
Thomas Graf9f0f7272010-11-16 04:32:48 +00001937 if (tb[IFLA_INET_CONF]) {
1938 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1939 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1940 }
1941
1942 return 0;
1943}
1944
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001945static int inet_netconf_msgsize_devconf(int type)
1946{
1947 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1948 + nla_total_size(4); /* NETCONFA_IFINDEX */
Zhang Shengju136ba622016-03-10 08:55:50 +00001949 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001950
Zhang Shengju136ba622016-03-10 08:55:50 +00001951 if (type == NETCONFA_ALL)
1952 all = true;
1953
1954 if (all || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001955 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001956 if (all || type == NETCONFA_RP_FILTER)
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001957 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001958 if (all || type == NETCONFA_MC_FORWARDING)
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001959 size += nla_total_size(4);
Xin Long5cbf7772018-07-27 16:37:28 +08001960 if (all || type == NETCONFA_BC_FORWARDING)
1961 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001962 if (all || type == NETCONFA_PROXY_NEIGH)
stephen hemmingerf085ff12013-12-12 13:06:50 -08001963 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001964 if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001965 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001966
1967 return size;
1968}
1969
1970static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1971 struct ipv4_devconf *devconf, u32 portid,
1972 u32 seq, int event, unsigned int flags,
1973 int type)
1974{
1975 struct nlmsghdr *nlh;
1976 struct netconfmsg *ncm;
Zhang Shengju136ba622016-03-10 08:55:50 +00001977 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001978
1979 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1980 flags);
Ian Morris51456b22015-04-03 09:17:26 +01001981 if (!nlh)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001982 return -EMSGSIZE;
1983
Zhang Shengju136ba622016-03-10 08:55:50 +00001984 if (type == NETCONFA_ALL)
1985 all = true;
1986
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001987 ncm = nlmsg_data(nlh);
1988 ncm->ncm_family = AF_INET;
1989
1990 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1991 goto nla_put_failure;
1992
David Ahernb5c96412017-03-28 14:28:03 -07001993 if (!devconf)
1994 goto out;
1995
Zhang Shengju136ba622016-03-10 08:55:50 +00001996 if ((all || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001997 nla_put_s32(skb, NETCONFA_FORWARDING,
1998 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1999 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00002000 if ((all || type == NETCONFA_RP_FILTER) &&
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002001 nla_put_s32(skb, NETCONFA_RP_FILTER,
2002 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
2003 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00002004 if ((all || type == NETCONFA_MC_FORWARDING) &&
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00002005 nla_put_s32(skb, NETCONFA_MC_FORWARDING,
2006 IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
2007 goto nla_put_failure;
Xin Long5cbf7772018-07-27 16:37:28 +08002008 if ((all || type == NETCONFA_BC_FORWARDING) &&
2009 nla_put_s32(skb, NETCONFA_BC_FORWARDING,
2010 IPV4_DEVCONF(*devconf, BC_FORWARDING)) < 0)
2011 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00002012 if ((all || type == NETCONFA_PROXY_NEIGH) &&
stephen hemminger09aea5d2013-12-17 22:35:52 -08002013 nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002014 IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
2015 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00002016 if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002017 nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
2018 IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
2019 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002020
David Ahernb5c96412017-03-28 14:28:03 -07002021out:
Johannes Berg053c0952015-01-16 22:09:00 +01002022 nlmsg_end(skb, nlh);
2023 return 0;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002024
2025nla_put_failure:
2026 nlmsg_cancel(skb, nlh);
2027 return -EMSGSIZE;
2028}
2029
David Ahern3b022862017-03-28 14:28:02 -07002030void inet_netconf_notify_devconf(struct net *net, int event, int type,
2031 int ifindex, struct ipv4_devconf *devconf)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002032{
2033 struct sk_buff *skb;
2034 int err = -ENOBUFS;
2035
Eric Dumazetfa178062016-07-08 05:18:24 +02002036 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002037 if (!skb)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002038 goto errout;
2039
2040 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
David Ahern3b022862017-03-28 14:28:02 -07002041 event, 0, type);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002042 if (err < 0) {
2043 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
2044 WARN_ON(err == -EMSGSIZE);
2045 kfree_skb(skb);
2046 goto errout;
2047 }
Eric Dumazetfa178062016-07-08 05:18:24 +02002048 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002049 return;
2050errout:
2051 if (err < 0)
2052 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
2053}
2054
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002055static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
2056 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
2057 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002058 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
stephen hemminger09aea5d2013-12-17 22:35:52 -08002059 [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) },
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002060 [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002061};
2062
Jakub Kicinskieede3702019-01-18 10:46:18 -08002063static int inet_netconf_valid_get_req(struct sk_buff *skb,
2064 const struct nlmsghdr *nlh,
2065 struct nlattr **tb,
2066 struct netlink_ext_ack *extack)
2067{
2068 int i, err;
2069
2070 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(struct netconfmsg))) {
2071 NL_SET_ERR_MSG(extack, "ipv4: Invalid header for netconf get request");
2072 return -EINVAL;
2073 }
2074
2075 if (!netlink_strict_get_check(skb))
Johannes Berg8cb08172019-04-26 14:07:28 +02002076 return nlmsg_parse_deprecated(nlh, sizeof(struct netconfmsg),
2077 tb, NETCONFA_MAX,
2078 devconf_ipv4_policy, extack);
Jakub Kicinskieede3702019-01-18 10:46:18 -08002079
Johannes Berg8cb08172019-04-26 14:07:28 +02002080 err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct netconfmsg),
2081 tb, NETCONFA_MAX,
2082 devconf_ipv4_policy, extack);
Jakub Kicinskieede3702019-01-18 10:46:18 -08002083 if (err)
2084 return err;
2085
2086 for (i = 0; i <= NETCONFA_MAX; i++) {
2087 if (!tb[i])
2088 continue;
2089
2090 switch (i) {
2091 case NETCONFA_IFINDEX:
2092 break;
2093 default:
2094 NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in netconf get request");
2095 return -EINVAL;
2096 }
2097 }
2098
2099 return 0;
2100}
2101
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002102static int inet_netconf_get_devconf(struct sk_buff *in_skb,
David Ahernc21ef3e2017-04-16 09:48:24 -07002103 struct nlmsghdr *nlh,
2104 struct netlink_ext_ack *extack)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002105{
2106 struct net *net = sock_net(in_skb->sk);
2107 struct nlattr *tb[NETCONFA_MAX+1];
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002108 struct sk_buff *skb;
2109 struct ipv4_devconf *devconf;
2110 struct in_device *in_dev;
2111 struct net_device *dev;
2112 int ifindex;
2113 int err;
2114
Jakub Kicinskieede3702019-01-18 10:46:18 -08002115 err = inet_netconf_valid_get_req(in_skb, nlh, tb, extack);
2116 if (err)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002117 goto errout;
2118
Anton Protopopova97eb332016-02-16 21:43:16 -05002119 err = -EINVAL;
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002120 if (!tb[NETCONFA_IFINDEX])
2121 goto errout;
2122
2123 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
2124 switch (ifindex) {
2125 case NETCONFA_IFINDEX_ALL:
2126 devconf = net->ipv4.devconf_all;
2127 break;
2128 case NETCONFA_IFINDEX_DEFAULT:
2129 devconf = net->ipv4.devconf_dflt;
2130 break;
2131 default:
2132 dev = __dev_get_by_index(net, ifindex);
Ian Morris51456b22015-04-03 09:17:26 +01002133 if (!dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002134 goto errout;
2135 in_dev = __in_dev_get_rtnl(dev);
Ian Morris51456b22015-04-03 09:17:26 +01002136 if (!in_dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002137 goto errout;
2138 devconf = &in_dev->cnf;
2139 break;
2140 }
2141
2142 err = -ENOBUFS;
Eric Dumazetfa178062016-07-08 05:18:24 +02002143 skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002144 if (!skb)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002145 goto errout;
2146
2147 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
2148 NETLINK_CB(in_skb).portid,
2149 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
Zhang Shengju136ba622016-03-10 08:55:50 +00002150 NETCONFA_ALL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002151 if (err < 0) {
2152 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
2153 WARN_ON(err == -EMSGSIZE);
2154 kfree_skb(skb);
2155 goto errout;
2156 }
2157 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
2158errout:
2159 return err;
2160}
2161
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002162static int inet_netconf_dump_devconf(struct sk_buff *skb,
2163 struct netlink_callback *cb)
2164{
David Ahernaddd3832018-10-07 20:16:41 -07002165 const struct nlmsghdr *nlh = cb->nlh;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002166 struct net *net = sock_net(skb->sk);
2167 int h, s_h;
2168 int idx, s_idx;
2169 struct net_device *dev;
2170 struct in_device *in_dev;
2171 struct hlist_head *head;
2172
David Ahernaddd3832018-10-07 20:16:41 -07002173 if (cb->strict_check) {
2174 struct netlink_ext_ack *extack = cb->extack;
2175 struct netconfmsg *ncm;
2176
2177 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ncm))) {
2178 NL_SET_ERR_MSG(extack, "ipv4: Invalid header for netconf dump request");
2179 return -EINVAL;
2180 }
2181
2182 if (nlmsg_attrlen(nlh, sizeof(*ncm))) {
2183 NL_SET_ERR_MSG(extack, "ipv4: Invalid data after header in netconf dump request");
2184 return -EINVAL;
2185 }
2186 }
2187
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002188 s_h = cb->args[0];
2189 s_idx = idx = cb->args[1];
2190
2191 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
2192 idx = 0;
2193 head = &net->dev_index_head[h];
2194 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00002195 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
2196 net->dev_base_seq;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002197 hlist_for_each_entry_rcu(dev, head, index_hlist) {
2198 if (idx < s_idx)
2199 goto cont;
2200 in_dev = __in_dev_get_rcu(dev);
2201 if (!in_dev)
2202 goto cont;
2203
2204 if (inet_netconf_fill_devconf(skb, dev->ifindex,
2205 &in_dev->cnf,
2206 NETLINK_CB(cb->skb).portid,
David Ahernaddd3832018-10-07 20:16:41 -07002207 nlh->nlmsg_seq,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002208 RTM_NEWNETCONF,
2209 NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002210 NETCONFA_ALL) < 0) {
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002211 rcu_read_unlock();
2212 goto done;
2213 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00002214 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002215cont:
2216 idx++;
2217 }
2218 rcu_read_unlock();
2219 }
2220 if (h == NETDEV_HASHENTRIES) {
2221 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
2222 net->ipv4.devconf_all,
2223 NETLINK_CB(cb->skb).portid,
David Ahernaddd3832018-10-07 20:16:41 -07002224 nlh->nlmsg_seq,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002225 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002226 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002227 goto done;
2228 else
2229 h++;
2230 }
2231 if (h == NETDEV_HASHENTRIES + 1) {
2232 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
2233 net->ipv4.devconf_dflt,
2234 NETLINK_CB(cb->skb).portid,
David Ahernaddd3832018-10-07 20:16:41 -07002235 nlh->nlmsg_seq,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002236 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002237 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002238 goto done;
2239 else
2240 h++;
2241 }
2242done:
2243 cb->args[0] = h;
2244 cb->args[1] = idx;
2245
2246 return skb->len;
2247}
2248
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249#ifdef CONFIG_SYSCTL
2250
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002251static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07002252{
2253 struct net_device *dev;
2254
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002255 rcu_read_lock();
2256 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07002257 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002258
Herbert Xu31be3082007-06-04 23:35:37 -07002259 in_dev = __in_dev_get_rcu(dev);
2260 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002261 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07002262 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002263 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07002264}
2265
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002266/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002267static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002268{
2269 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002270 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002271
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002272 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002273 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
David Ahern3b022862017-03-28 14:28:02 -07002274 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2275 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002276 NETCONFA_IFINDEX_ALL,
2277 net->ipv4.devconf_all);
David Ahern3b022862017-03-28 14:28:02 -07002278 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2279 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002280 NETCONFA_IFINDEX_DEFAULT,
2281 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002282
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002283 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002284 struct in_device *in_dev;
Eric Dumazetfa178062016-07-08 05:18:24 +02002285
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002286 if (on)
2287 dev_disable_lro(dev);
Eric Dumazetfa178062016-07-08 05:18:24 +02002288
2289 in_dev = __in_dev_get_rtnl(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002290 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002291 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
David Ahern3b022862017-03-28 14:28:02 -07002292 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2293 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002294 dev->ifindex, &in_dev->cnf);
2295 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002296 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002297}
2298
stephen hemmingerf085ff12013-12-12 13:06:50 -08002299static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf)
2300{
2301 if (cnf == net->ipv4.devconf_dflt)
2302 return NETCONFA_IFINDEX_DEFAULT;
2303 else if (cnf == net->ipv4.devconf_all)
2304 return NETCONFA_IFINDEX_ALL;
2305 else {
2306 struct in_device *idev
2307 = container_of(cnf, struct in_device, cnf);
2308 return idev->dev->ifindex;
2309 }
2310}
2311
Joe Perchesfe2c6332013-06-11 23:04:25 -07002312static int devinet_conf_proc(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002313 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07002314 size_t *lenp, loff_t *ppos)
2315{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002316 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002317 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002318 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07002319
2320 if (write) {
2321 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002322 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07002323 int i = (int *)ctl->data - cnf->data;
stephen hemmingerf085ff12013-12-12 13:06:50 -08002324 int ifindex;
Herbert Xu31be3082007-06-04 23:35:37 -07002325
2326 set_bit(i, cnf->state);
2327
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002328 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002329 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00002330 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
2331 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002332 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002333 rt_cache_flush(net);
stephen hemmingerf085ff12013-12-12 13:06:50 -08002334
Xin Long5cbf7772018-07-27 16:37:28 +08002335 if (i == IPV4_DEVCONF_BC_FORWARDING - 1 &&
2336 new_value != old_value)
2337 rt_cache_flush(net);
2338
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002339 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
2340 new_value != old_value) {
stephen hemmingerf085ff12013-12-12 13:06:50 -08002341 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002342 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2343 NETCONFA_RP_FILTER,
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002344 ifindex, cnf);
2345 }
stephen hemmingerf085ff12013-12-12 13:06:50 -08002346 if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
2347 new_value != old_value) {
2348 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002349 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2350 NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002351 ifindex, cnf);
2352 }
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002353 if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
2354 new_value != old_value) {
2355 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002356 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2357 NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002358 ifindex, cnf);
2359 }
Herbert Xu31be3082007-06-04 23:35:37 -07002360 }
2361
2362 return ret;
2363}
2364
Joe Perchesfe2c6332013-06-11 23:04:25 -07002365static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002366 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 size_t *lenp, loff_t *ppos)
2368{
2369 int *valp = ctl->data;
2370 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00002371 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002372 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373
2374 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002375 struct net *net = ctl->extra2;
2376
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002377 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00002378 if (!rtnl_trylock()) {
2379 /* Restore the original values before restarting */
2380 *valp = val;
2381 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00002382 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00002383 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002384 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2385 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002386 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002387 struct ipv4_devconf *cnf = ctl->extra1;
2388 struct in_device *idev =
2389 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002390 if (*valp)
2391 dev_disable_lro(idev->dev);
David Ahern3b022862017-03-28 14:28:02 -07002392 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002393 NETCONFA_FORWARDING,
2394 idev->dev->ifindex,
2395 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002396 }
2397 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002398 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002399 } else
David Ahern3b022862017-03-28 14:28:02 -07002400 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2401 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002402 NETCONFA_IFINDEX_DEFAULT,
2403 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 }
2405
2406 return ret;
2407}
2408
Joe Perchesfe2c6332013-06-11 23:04:25 -07002409static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
David S. Miller323e1262010-12-12 21:55:08 -08002410 void __user *buffer,
2411 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412{
2413 int *valp = ctl->data;
2414 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002415 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07002416 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417
2418 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002419 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
2421 return ret;
2422}
2423
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002424#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07002425 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07002426 .procname = name, \
2427 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00002428 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002429 .maxlen = sizeof(int), \
2430 .mode = mval, \
2431 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07002432 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002433 }
2434
2435#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002436 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002437
2438#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002439 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002440
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002441#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2442 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002443
2444#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002445 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07002446
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447static struct devinet_sysctl_table {
2448 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00002449 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450} devinet_sysctl = {
2451 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07002452 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002453 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07002454 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
Xin Long5cbf7772018-07-27 16:37:28 +08002455 DEVINET_SYSCTL_RW_ENTRY(BC_FORWARDING, "bc_forwarding"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002456
2457 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
2458 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
2459 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
2460 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
2461 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
2462 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
2463 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00002464 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08002465 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002466 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
2467 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
2468 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
2469 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
2470 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
2471 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
2472 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
2473 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
2474 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08002475 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00002476 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
William Manley5c6fe012013-08-06 19:03:14 +01002477 DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
2478 "force_igmp_version"),
William Manley26900482013-08-06 19:03:15 +01002479 DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
2480 "igmpv2_unsolicited_report_interval"),
2481 DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
2482 "igmpv3_unsolicited_report_interval"),
Andy Gospodarek0eeb0752015-06-23 13:45:37 -04002483 DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
2484 "ignore_routes_with_linkdown"),
Johannes Berg97daf332016-02-04 13:31:18 +01002485 DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
2486 "drop_gratuitous_arp"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002487
2488 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2489 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002490 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
2491 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00002492 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2493 "route_localnet"),
Johannes Berg12b74df2016-02-04 13:31:17 +01002494 DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
2495 "drop_unicast_in_l2_multicast"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497};
2498
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002499static int __devinet_sysctl_register(struct net *net, char *dev_name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002500 int ifindex, struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501{
2502 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002503 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002504 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11002505
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002506 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002508 goto out;
2509
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
2511 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07002512 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002513 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 }
2515
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002516 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002518 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002520 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521
2522 p->sysctl = t;
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002523
David Ahern3b022862017-03-28 14:28:02 -07002524 inet_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_ALL,
2525 ifindex, p);
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002526 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002528free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002530out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002531 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532}
2533
David Ahernb5c96412017-03-28 14:28:03 -07002534static void __devinet_sysctl_unregister(struct net *net,
2535 struct ipv4_devconf *cnf, int ifindex)
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002536{
2537 struct devinet_sysctl_table *t = cnf->sysctl;
2538
David Ahernb5c96412017-03-28 14:28:03 -07002539 if (t) {
2540 cnf->sysctl = NULL;
2541 unregister_net_sysctl_table(t->sysctl_header);
2542 kfree(t);
2543 }
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002544
David Ahernb5c96412017-03-28 14:28:03 -07002545 inet_netconf_notify_devconf(net, RTM_DELNETCONF, 0, ifindex, NULL);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002546}
2547
WANG Cong20e61da2014-07-25 15:25:08 -07002548static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002549{
WANG Cong20e61da2014-07-25 15:25:08 -07002550 int err;
2551
2552 if (!sysctl_dev_name_is_allowed(idev->dev->name))
2553 return -EINVAL;
2554
2555 err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
2556 if (err)
2557 return err;
2558 err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002559 idev->dev->ifindex, &idev->cnf);
WANG Cong20e61da2014-07-25 15:25:08 -07002560 if (err)
2561 neigh_sysctl_unregister(idev->arp_parms);
2562 return err;
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002563}
2564
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002565static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566{
David Ahernb5c96412017-03-28 14:28:03 -07002567 struct net *net = dev_net(idev->dev);
2568
2569 __devinet_sysctl_unregister(net, &idev->cnf, idev->dev->ifindex);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002570 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002573static struct ctl_table ctl_forward_entry[] = {
2574 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002575 .procname = "ip_forward",
2576 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00002577 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002578 .maxlen = sizeof(int),
2579 .mode = 0644,
2580 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002581 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002582 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002583 },
2584 { },
2585};
Eric Dumazet2a75de02008-01-05 23:08:49 -08002586#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002587
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002588static __net_init int devinet_init_net(struct net *net)
2589{
2590 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002591 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002592#ifdef CONFIG_SYSCTL
Cong Wang856c3952019-01-17 23:27:11 -08002593 struct ctl_table *tbl;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002594 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002595#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002596
2597 err = -ENOMEM;
Cong Wang856c3952019-01-17 23:27:11 -08002598 all = kmemdup(&ipv4_devconf, sizeof(ipv4_devconf), GFP_KERNEL);
2599 if (!all)
2600 goto err_alloc_all;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002601
Cong Wang856c3952019-01-17 23:27:11 -08002602 dflt = kmemdup(&ipv4_devconf_dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
2603 if (!dflt)
2604 goto err_alloc_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002605
Eric Dumazet2a75de02008-01-05 23:08:49 -08002606#ifdef CONFIG_SYSCTL
Cong Wang856c3952019-01-17 23:27:11 -08002607 tbl = kmemdup(ctl_forward_entry, sizeof(ctl_forward_entry), GFP_KERNEL);
2608 if (!tbl)
2609 goto err_alloc_ctl;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002610
Cong Wang856c3952019-01-17 23:27:11 -08002611 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
2612 tbl[0].extra1 = all;
2613 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002614#endif
Cong Wang856c3952019-01-17 23:27:11 -08002615
Arnd Bergmanna154d5d2019-03-04 21:38:03 +01002616 if ((!IS_ENABLED(CONFIG_SYSCTL) ||
2617 sysctl_devconf_inherit_init_net != 2) &&
2618 !net_eq(net, &init_net)) {
Cong Wang856c3952019-01-17 23:27:11 -08002619 memcpy(all, init_net.ipv4.devconf_all, sizeof(ipv4_devconf));
2620 memcpy(dflt, init_net.ipv4.devconf_dflt, sizeof(ipv4_devconf_dflt));
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002621 }
2622
2623#ifdef CONFIG_SYSCTL
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002624 err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002625 if (err < 0)
2626 goto err_reg_all;
2627
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002628 err = __devinet_sysctl_register(net, "default",
2629 NETCONFA_IFINDEX_DEFAULT, dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002630 if (err < 0)
2631 goto err_reg_dflt;
2632
2633 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002634 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Ian Morris51456b22015-04-03 09:17:26 +01002635 if (!forw_hdr)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002636 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002637 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002638#endif
2639
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002640 net->ipv4.devconf_all = all;
2641 net->ipv4.devconf_dflt = dflt;
2642 return 0;
2643
2644#ifdef CONFIG_SYSCTL
2645err_reg_ctl:
David Ahernb5c96412017-03-28 14:28:03 -07002646 __devinet_sysctl_unregister(net, dflt, NETCONFA_IFINDEX_DEFAULT);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002647err_reg_dflt:
David Ahernb5c96412017-03-28 14:28:03 -07002648 __devinet_sysctl_unregister(net, all, NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002649err_reg_all:
Cong Wang856c3952019-01-17 23:27:11 -08002650 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002651err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08002652#endif
Cong Wang856c3952019-01-17 23:27:11 -08002653 kfree(dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002654err_alloc_dflt:
Cong Wang856c3952019-01-17 23:27:11 -08002655 kfree(all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002656err_alloc_all:
2657 return err;
2658}
2659
2660static __net_exit void devinet_exit_net(struct net *net)
2661{
Eric Dumazet2a75de02008-01-05 23:08:49 -08002662#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002663 struct ctl_table *tbl;
2664
2665 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002666 unregister_net_sysctl_table(net->ipv4.forw_hdr);
David Ahernb5c96412017-03-28 14:28:03 -07002667 __devinet_sysctl_unregister(net, net->ipv4.devconf_dflt,
2668 NETCONFA_IFINDEX_DEFAULT);
2669 __devinet_sysctl_unregister(net, net->ipv4.devconf_all,
2670 NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002671 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08002672#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002673 kfree(net->ipv4.devconf_dflt);
2674 kfree(net->ipv4.devconf_all);
2675}
2676
2677static __net_initdata struct pernet_operations devinet_ops = {
2678 .init = devinet_init_net,
2679 .exit = devinet_exit_net,
2680};
2681
Daniel Borkmann207895fd32015-01-29 12:15:03 +01002682static struct rtnl_af_ops inet_af_ops __read_mostly = {
Thomas Graf9f0f7272010-11-16 04:32:48 +00002683 .family = AF_INET,
2684 .fill_link_af = inet_fill_link_af,
2685 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00002686 .validate_link_af = inet_validate_link_af,
2687 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00002688};
2689
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690void __init devinet_init(void)
2691{
David S. Millerfd23c3b2011-02-18 12:42:28 -08002692 int i;
2693
2694 for (i = 0; i < IN4_ADDR_HSIZE; i++)
2695 INIT_HLIST_HEAD(&inet_addr_lst[i]);
2696
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002697 register_pernet_subsys(&devinet_ops);
2698
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 register_gifconf(PF_INET, inet_gifconf);
2700 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07002701
viresh kumar906e0732014-01-22 12:23:32 +05302702 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +00002703
Thomas Graf9f0f7272010-11-16 04:32:48 +00002704 rtnl_af_register(&inet_af_ops);
2705
Florian Westphalb97bac62017-08-09 20:41:48 +02002706 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, 0);
2707 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, 0);
2708 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, 0);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002709 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
Florian Westphalb97bac62017-08-09 20:41:48 +02002710 inet_netconf_dump_devconf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711}