blob: fba2bffd65f7967f390dcaf5183994af1ae5493b [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
Matteo Croce2e605462019-07-01 19:01:55 +020065#define IPV6ONLY_FLAGS \
66 (IFA_F_NODAD | IFA_F_OPTIMISTIC | IFA_F_DADFAILED | \
67 IFA_F_HOMEADDRESS | IFA_F_TENTATIVE | \
68 IFA_F_MANAGETEMPADDR | IFA_F_STABLE_PRIVACY)
69
Adrian Bunk0027ba82008-01-31 17:17:31 -080070static struct ipv4_devconf ipv4_devconf = {
Herbert Xu42f811b2007-06-04 23:34:44 -070071 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000072 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
73 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
74 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
75 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
William Manley26900482013-08-06 19:03:15 +010076 [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
77 [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
James Prestwoodfcdb44d2021-11-01 10:36:28 -070078 [IPV4_DEVCONF_ARP_EVICT_NOCARRIER - 1] = 1,
Herbert Xu42f811b2007-06-04 23:34:44 -070079 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070080};
81
82static struct ipv4_devconf ipv4_devconf_dflt = {
Herbert Xu42f811b2007-06-04 23:34:44 -070083 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000084 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
85 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
86 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
87 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
88 [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
William Manley26900482013-08-06 19:03:15 +010089 [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
90 [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
James Prestwoodfcdb44d2021-11-01 10:36:28 -070091 [IPV4_DEVCONF_ARP_EVICT_NOCARRIER - 1] = 1,
Herbert Xu42f811b2007-06-04 23:34:44 -070092 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070093};
94
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -080095#define IPV4_DEVCONF_DFLT(net, attr) \
96 IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr)
Herbert Xu42f811b2007-06-04 23:34:44 -070097
Patrick McHardyef7c79e2007-06-05 12:38:30 -070098static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
Thomas Graf5c753972006-08-04 23:03:53 -070099 [IFA_LOCAL] = { .type = NLA_U32 },
100 [IFA_ADDRESS] = { .type = NLA_U32 },
101 [IFA_BROADCAST] = { .type = NLA_U32 },
Thomas Graf5176f912006-08-26 20:13:18 -0700102 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
Jiri Pirko5c766d62013-01-24 09:41:41 +0000103 [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100104 [IFA_FLAGS] = { .type = NLA_U32 },
David Ahernaf4d7682018-05-27 08:09:57 -0700105 [IFA_RT_PRIORITY] = { .type = NLA_U32 },
Christian Braunerd3807142018-09-04 21:53:49 +0200106 [IFA_TARGET_NETNSID] = { .type = NLA_S32 },
Thomas Graf5c753972006-08-04 23:03:53 -0700107};
108
Christian Brauner978a46f2018-09-04 21:53:54 +0200109struct inet_fill_args {
110 u32 portid;
111 u32 seq;
112 int event;
113 unsigned int flags;
114 int netnsid;
David Ahern5fcd2662018-10-19 12:45:29 -0700115 int ifindex;
Christian Brauner978a46f2018-09-04 21:53:54 +0200116};
117
Eric Dumazet40384992012-08-03 21:06:50 +0000118#define IN4_ADDR_HSIZE_SHIFT 8
119#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT)
120
David S. Millerfd23c3b2011-02-18 12:42:28 -0800121static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
David S. Millerfd23c3b2011-02-18 12:42:28 -0800122
Eric Dumazet6eada012015-03-18 14:05:33 -0700123static u32 inet_addr_hash(const struct net *net, __be32 addr)
David S. Millerfd23c3b2011-02-18 12:42:28 -0800124{
Eric Dumazet40384992012-08-03 21:06:50 +0000125 u32 val = (__force u32) addr ^ net_hash_mix(net);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800126
Eric Dumazet40384992012-08-03 21:06:50 +0000127 return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800128}
129
130static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
131{
Eric Dumazet40384992012-08-03 21:06:50 +0000132 u32 hash = inet_addr_hash(net, ifa->ifa_local);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800133
WANG Cong32a4be42014-05-06 11:15:56 -0700134 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800135 hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800136}
137
138static void inet_hash_remove(struct in_ifaddr *ifa)
139{
WANG Cong32a4be42014-05-06 11:15:56 -0700140 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800141 hlist_del_init_rcu(&ifa->hash);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800142}
143
David S. Miller9435eb12011-02-18 12:43:09 -0800144/**
145 * __ip_dev_find - find the first device with a given source address.
146 * @net: the net namespace
147 * @addr: the source address
148 * @devref: if true, take a reference on the found device
149 *
150 * If a caller uses devref=false, it should be protected by RCU, or RTNL
151 */
152struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
153{
David S. Miller9435eb12011-02-18 12:43:09 -0800154 struct net_device *result = NULL;
155 struct in_ifaddr *ifa;
David S. Miller9435eb12011-02-18 12:43:09 -0800156
157 rcu_read_lock();
Paolo Abeni6e617de2017-09-20 18:26:53 +0200158 ifa = inet_lookup_ifaddr_rcu(net, addr);
159 if (!ifa) {
David S. Miller406b6f92011-03-22 21:56:23 -0700160 struct flowi4 fl4 = { .daddr = addr };
161 struct fib_result res = { 0 };
162 struct fib_table *local;
163
164 /* Fallback to FIB local table so that communication
165 * over loopback subnets work.
166 */
167 local = fib_get_table(net, RT_TABLE_LOCAL);
168 if (local &&
169 !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
170 res.type == RTN_LOCAL)
171 result = FIB_RES_DEV(res);
Paolo Abeni6e617de2017-09-20 18:26:53 +0200172 } else {
173 result = ifa->ifa_dev->dev;
David S. Miller406b6f92011-03-22 21:56:23 -0700174 }
David S. Miller9435eb12011-02-18 12:43:09 -0800175 if (result && devref)
176 dev_hold(result);
177 rcu_read_unlock();
178 return result;
179}
180EXPORT_SYMBOL(__ip_dev_find);
181
Paolo Abeni6e617de2017-09-20 18:26:53 +0200182/* called under RCU lock */
183struct in_ifaddr *inet_lookup_ifaddr_rcu(struct net *net, __be32 addr)
184{
185 u32 hash = inet_addr_hash(net, addr);
186 struct in_ifaddr *ifa;
187
188 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash)
189 if (ifa->ifa_local == addr &&
190 net_eq(dev_net(ifa->ifa_dev->dev), net))
191 return ifa;
192
193 return NULL;
194}
195
Thomas Grafd6062cb2006-08-15 00:33:59 -0700196static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
Alan Sterne041c682006-03-27 01:16:30 -0800198static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Krister Johansen3ad7d242017-06-08 13:12:14 -0700199static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain);
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200200static void inet_del_ifa(struct in_device *in_dev,
201 struct in_ifaddr __rcu **ifap,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 int destroy);
203#ifdef CONFIG_SYSCTL
WANG Cong20e61da2014-07-25 15:25:08 -0700204static int devinet_sysctl_register(struct in_device *idev);
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800205static void devinet_sysctl_unregister(struct in_device *idev);
206#else
WANG Cong20e61da2014-07-25 15:25:08 -0700207static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800208{
WANG Cong20e61da2014-07-25 15:25:08 -0700209 return 0;
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800210}
Eric Dumazet40384992012-08-03 21:06:50 +0000211static void devinet_sysctl_unregister(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800212{
213}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214#endif
215
216/* Locks all the inet devices. */
217
218static struct in_ifaddr *inet_alloc_ifa(void)
219{
Vasily Averin61268912021-07-19 13:44:31 +0300220 return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL_ACCOUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221}
222
223static void inet_rcu_free_ifa(struct rcu_head *head)
224{
225 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
226 if (ifa->ifa_dev)
227 in_dev_put(ifa->ifa_dev);
228 kfree(ifa);
229}
230
Eric Dumazet40384992012-08-03 21:06:50 +0000231static void inet_free_ifa(struct in_ifaddr *ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232{
233 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
234}
235
236void in_dev_finish_destroy(struct in_device *idev)
237{
238 struct net_device *dev = idev->dev;
239
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700240 WARN_ON(idev->ifa_list);
241 WARN_ON(idev->mc_list);
Eric Dumazete9897072013-06-07 08:48:57 -0700242 kfree(rcu_dereference_protected(idev->mc_hash, 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243#ifdef NET_REFCNT_DEBUG
Joe Perches91df42b2012-05-15 14:11:54 +0000244 pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245#endif
Eric Dumazetc04438f2021-12-04 20:22:12 -0800246 dev_put_track(dev, &idev->dev_tracker);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 if (!idev->dead)
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800248 pr_err("Freeing alive in_device %p\n", idev);
249 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 kfree(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800252EXPORT_SYMBOL(in_dev_finish_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
Herbert Xu71e27da2007-06-04 23:36:06 -0700254static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255{
256 struct in_device *in_dev;
WANG Cong20e61da2014-07-25 15:25:08 -0700257 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
259 ASSERT_RTNL();
260
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700261 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 if (!in_dev)
263 goto out;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900264 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -0800265 sizeof(in_dev->cnf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 in_dev->cnf.sysctl = NULL;
267 in_dev->dev = dev;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800268 in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
269 if (!in_dev->arp_parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 goto out_kfree;
Ben Hutchings0187bdf2008-06-19 16:15:47 -0700271 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
272 dev_disable_lro(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 /* Reference in_dev->dev */
Eric Dumazetc04438f2021-12-04 20:22:12 -0800274 dev_hold_track(dev, &in_dev->dev_tracker, GFP_KERNEL);
David L Stevens30c4cf52007-01-04 12:31:14 -0800275 /* Account for reference dev->ip_ptr (below) */
Reshetova, Elena7658b362017-06-30 13:08:03 +0300276 refcount_set(&in_dev->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
WANG Cong20e61da2014-07-25 15:25:08 -0700278 err = devinet_sysctl_register(in_dev);
279 if (err) {
280 in_dev->dead = 1;
Yang Yingliang1b49cd72020-05-30 11:34:33 +0800281 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
WANG Cong20e61da2014-07-25 15:25:08 -0700282 in_dev_put(in_dev);
283 in_dev = NULL;
284 goto out;
285 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 ip_mc_init_dev(in_dev);
287 if (dev->flags & IFF_UP)
288 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800289
David L Stevens30c4cf52007-01-04 12:31:14 -0800290 /* we can receive as soon as ip_ptr is set -- do this last */
Eric Dumazetcf778b02012-01-12 04:41:32 +0000291 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800292out:
WANG Cong20e61da2014-07-25 15:25:08 -0700293 return in_dev ?: ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294out_kfree:
295 kfree(in_dev);
296 in_dev = NULL;
297 goto out;
298}
299
300static void in_dev_rcu_put(struct rcu_head *head)
301{
302 struct in_device *idev = container_of(head, struct in_device, rcu_head);
303 in_dev_put(idev);
304}
305
306static void inetdev_destroy(struct in_device *in_dev)
307{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 struct net_device *dev;
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200309 struct in_ifaddr *ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
311 ASSERT_RTNL();
312
313 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
315 in_dev->dead = 1;
316
317 ip_mc_destroy_dev(in_dev);
318
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200319 while ((ifa = rtnl_dereference(in_dev->ifa_list)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
321 inet_free_ifa(ifa);
322 }
323
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000324 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800326 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
328 arp_ifdown(dev);
329
330 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
331}
332
Al Viroff428d72006-09-26 22:13:35 -0700333int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
Florian Westphald519e872019-05-31 18:27:05 +0200335 const struct in_ifaddr *ifa;
336
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 rcu_read_lock();
Florian Westphald519e872019-05-31 18:27:05 +0200338 in_dev_for_each_ifa_rcu(ifa, in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 if (inet_ifa_match(a, ifa)) {
340 if (!b || inet_ifa_match(b, ifa)) {
341 rcu_read_unlock();
342 return 1;
343 }
344 }
Florian Westphald519e872019-05-31 18:27:05 +0200345 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 rcu_read_unlock();
347 return 0;
348}
349
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200350static void __inet_del_ifa(struct in_device *in_dev,
351 struct in_ifaddr __rcu **ifap,
352 int destroy, struct nlmsghdr *nlh, u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
Harald Welte8f937c62005-05-29 20:23:46 -0700354 struct in_ifaddr *promote = NULL;
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200355 struct in_ifaddr *ifa, *ifa1;
356 struct in_ifaddr *last_prim;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800357 struct in_ifaddr *prev_prom = NULL;
358 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
360 ASSERT_RTNL();
361
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200362 ifa1 = rtnl_dereference(*ifap);
363 last_prim = rtnl_dereference(in_dev->ifa_list);
David S. Millerfbd40ea2016-03-13 23:28:00 -0400364 if (in_dev->dead)
365 goto no_promotions;
366
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900367 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700368 * unless alias promotion is set
369 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200372 struct in_ifaddr __rcu **ifap1 = &ifa1->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200374 while ((ifa = rtnl_dereference(*ifap1)) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900375 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800376 ifa1->ifa_scope <= ifa->ifa_scope)
377 last_prim = ifa;
378
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
380 ifa1->ifa_mask != ifa->ifa_mask ||
381 !inet_ifa_match(ifa1->ifa_address, ifa)) {
382 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800383 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 continue;
385 }
386
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800387 if (!do_promote) {
David S. Millerfd23c3b2011-02-18 12:42:28 -0800388 inet_hash_remove(ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700389 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Eric W. Biederman15e47302012-09-07 20:12:54 +0000391 rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800392 blocking_notifier_call_chain(&inetaddr_chain,
393 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700394 inet_free_ifa(ifa);
395 } else {
396 promote = ifa;
397 break;
398 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 }
400 }
401
Julian Anastasov2d230e22011-03-19 12:13:52 +0000402 /* On promotion all secondaries from subnet are changing
403 * the primary IP, we must remove all their routes silently
404 * and later to add them back with new prefsrc. Do this
405 * while all addresses are on the device list.
406 */
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200407 for (ifa = promote; ifa; ifa = rtnl_dereference(ifa->ifa_next)) {
Julian Anastasov2d230e22011-03-19 12:13:52 +0000408 if (ifa1->ifa_mask == ifa->ifa_mask &&
409 inet_ifa_match(ifa1->ifa_address, ifa))
410 fib_del_ifaddr(ifa, ifa1);
411 }
412
David S. Millerfbd40ea2016-03-13 23:28:00 -0400413no_promotions:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 /* 2. Unlink it */
415
416 *ifap = ifa1->ifa_next;
David S. Millerfd23c3b2011-02-18 12:42:28 -0800417 inet_hash_remove(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 /* 3. Announce address deletion */
420
421 /* Send message first, then call notifier.
422 At first sight, FIB update triggered by notifier
423 will refer to already deleted ifaddr, that could confuse
424 netlink listeners. It is not true: look, gated sees
425 that route deleted and if it still thinks that ifaddr
426 is valid, it will try to restore deleted routes... Grr.
427 So that, this order is correct.
428 */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000429 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800430 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800431
432 if (promote) {
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200433 struct in_ifaddr *next_sec;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800434
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200435 next_sec = rtnl_dereference(promote->ifa_next);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800436 if (prev_prom) {
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200437 struct in_ifaddr *last_sec;
438
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200439 rcu_assign_pointer(prev_prom->ifa_next, next_sec);
Florian Westphal6a9e9ce2019-06-27 14:03:32 +0200440
441 last_sec = rtnl_dereference(last_prim->ifa_next);
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200442 rcu_assign_pointer(promote->ifa_next, last_sec);
443 rcu_assign_pointer(last_prim->ifa_next, promote);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800444 }
445
446 promote->ifa_flags &= ~IFA_F_SECONDARY;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000447 rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800448 blocking_notifier_call_chain(&inetaddr_chain,
449 NETDEV_UP, promote);
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200450 for (ifa = next_sec; ifa;
451 ifa = rtnl_dereference(ifa->ifa_next)) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800452 if (ifa1->ifa_mask != ifa->ifa_mask ||
453 !inet_ifa_match(ifa1->ifa_address, ifa))
454 continue;
455 fib_add_ifaddr(ifa);
456 }
457
458 }
Herbert Xu63630972007-06-07 18:35:38 -0700459 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461}
462
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200463static void inet_del_ifa(struct in_device *in_dev,
464 struct in_ifaddr __rcu **ifap,
Thomas Grafd6062cb2006-08-15 00:33:59 -0700465 int destroy)
466{
467 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
468}
469
Jiri Pirko5c766d62013-01-24 09:41:41 +0000470static void check_lifetime(struct work_struct *work);
471
472static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
473
Thomas Grafd6062cb2006-08-15 00:33:59 -0700474static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
David Ahernde95e042017-10-18 09:56:54 -0700475 u32 portid, struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476{
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200477 struct in_ifaddr __rcu **last_primary, **ifap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 struct in_device *in_dev = ifa->ifa_dev;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700479 struct in_validator_info ivi;
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200480 struct in_ifaddr *ifa1;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700481 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
483 ASSERT_RTNL();
484
485 if (!ifa->ifa_local) {
486 inet_free_ifa(ifa);
487 return 0;
488 }
489
490 ifa->ifa_flags &= ~IFA_F_SECONDARY;
491 last_primary = &in_dev->ifa_list;
492
Matteo Croce2e605462019-07-01 19:01:55 +0200493 /* Don't set IPv6 only flags to IPv4 addresses */
494 ifa->ifa_flags &= ~IPV6ONLY_FLAGS;
495
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200496 ifap = &in_dev->ifa_list;
497 ifa1 = rtnl_dereference(*ifap);
498
499 while (ifa1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
501 ifa->ifa_scope <= ifa1->ifa_scope)
502 last_primary = &ifa1->ifa_next;
503 if (ifa1->ifa_mask == ifa->ifa_mask &&
504 inet_ifa_match(ifa1->ifa_address, ifa)) {
505 if (ifa1->ifa_local == ifa->ifa_local) {
506 inet_free_ifa(ifa);
507 return -EEXIST;
508 }
509 if (ifa1->ifa_scope != ifa->ifa_scope) {
510 inet_free_ifa(ifa);
511 return -EINVAL;
512 }
513 ifa->ifa_flags |= IFA_F_SECONDARY;
514 }
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200515
516 ifap = &ifa1->ifa_next;
517 ifa1 = rtnl_dereference(*ifap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 }
519
Krister Johansen3ad7d242017-06-08 13:12:14 -0700520 /* Allow any devices that wish to register ifaddr validtors to weigh
521 * in now, before changes are committed. The rntl lock is serializing
522 * access here, so the state should not change between a validator call
523 * and a final notify on commit. This isn't invoked on promotion under
524 * the assumption that validators are checking the address itself, and
525 * not the flags.
526 */
527 ivi.ivi_addr = ifa->ifa_address;
528 ivi.ivi_dev = ifa->ifa_dev;
David Ahernde95e042017-10-18 09:56:54 -0700529 ivi.extack = extack;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700530 ret = blocking_notifier_call_chain(&inetaddr_validator_chain,
531 NETDEV_UP, &ivi);
532 ret = notifier_to_errno(ret);
533 if (ret) {
534 inet_free_ifa(ifa);
535 return ret;
536 }
537
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500539 prandom_seed((__force u32) ifa->ifa_local);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 ifap = last_primary;
541 }
542
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200543 rcu_assign_pointer(ifa->ifa_next, *ifap);
544 rcu_assign_pointer(*ifap, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
David S. Millerfd23c3b2011-02-18 12:42:28 -0800546 inet_hash_insert(dev_net(in_dev->dev), ifa);
547
Jiri Pirko5c766d62013-01-24 09:41:41 +0000548 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530549 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000550
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 /* Send message first, then call notifier.
552 Notifier will trigger FIB update, so that
553 listeners of netlink will know about new ifaddr */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000554 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800555 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
557 return 0;
558}
559
Thomas Grafd6062cb2006-08-15 00:33:59 -0700560static int inet_insert_ifa(struct in_ifaddr *ifa)
561{
David Ahernde95e042017-10-18 09:56:54 -0700562 return __inet_insert_ifa(ifa, NULL, 0, NULL);
Thomas Grafd6062cb2006-08-15 00:33:59 -0700563}
564
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
566{
Herbert Xue5ed6392005-10-03 14:35:55 -0700567 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
569 ASSERT_RTNL();
570
571 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700572 inet_free_ifa(ifa);
573 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700575 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100576 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700578 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 in_dev_hold(in_dev);
580 ifa->ifa_dev = in_dev;
581 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800582 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 ifa->ifa_scope = RT_SCOPE_HOST;
584 return inet_insert_ifa(ifa);
585}
586
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000587/* Caller must hold RCU or RTNL :
588 * We dont take a reference on found in_device
589 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800590struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591{
592 struct net_device *dev;
593 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000594
595 rcu_read_lock();
596 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000598 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000599 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 return in_dev;
601}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800602EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
604/* Called only from RTNL semaphored context. No locks. */
605
Al Viro60cad5d2006-09-26 22:17:09 -0700606struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
607 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608{
Florian Westphald519e872019-05-31 18:27:05 +0200609 struct in_ifaddr *ifa;
610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 ASSERT_RTNL();
612
Florian Westphald519e872019-05-31 18:27:05 +0200613 in_dev_for_each_ifa_rtnl(ifa, in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
615 return ifa;
Florian Westphald519e872019-05-31 18:27:05 +0200616 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 return NULL;
618}
619
Taras Chornyi690cc862020-04-09 20:25:24 +0300620static int ip_mc_autojoin_config(struct net *net, bool join,
621 const struct in_ifaddr *ifa)
Madhu Challa93a714d2015-02-25 09:58:35 -0800622{
Taras Chornyi690cc862020-04-09 20:25:24 +0300623#if defined(CONFIG_IP_MULTICAST)
Madhu Challa93a714d2015-02-25 09:58:35 -0800624 struct ip_mreqn mreq = {
625 .imr_multiaddr.s_addr = ifa->ifa_address,
626 .imr_ifindex = ifa->ifa_dev->dev->ifindex,
627 };
Taras Chornyi690cc862020-04-09 20:25:24 +0300628 struct sock *sk = net->ipv4.mc_autojoin_sk;
Madhu Challa93a714d2015-02-25 09:58:35 -0800629 int ret;
630
631 ASSERT_RTNL();
632
633 lock_sock(sk);
634 if (join)
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300635 ret = ip_mc_join_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800636 else
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300637 ret = ip_mc_leave_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800638 release_sock(sk);
639
640 return ret;
Taras Chornyi690cc862020-04-09 20:25:24 +0300641#else
642 return -EOPNOTSUPP;
643#endif
Madhu Challa93a714d2015-02-25 09:58:35 -0800644}
645
David Ahernc21ef3e2017-04-16 09:48:24 -0700646static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
647 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900649 struct net *net = sock_net(skb->sk);
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200650 struct in_ifaddr __rcu **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700651 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700653 struct ifaddrmsg *ifm;
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200654 struct in_ifaddr *ifa;
Menglong Dong30e23792020-11-08 09:05:41 +0800655 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
657 ASSERT_RTNL();
658
Johannes Berg8cb08172019-04-26 14:07:28 +0200659 err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX,
660 ifa_ipv4_policy, extack);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700661 if (err < 0)
662 goto errout;
663
664 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800665 in_dev = inetdev_by_index(net, ifm->ifa_index);
Ian Morris51456b22015-04-03 09:17:26 +0100666 if (!in_dev) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700667 err = -ENODEV;
668 goto errout;
669 }
670
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200671 for (ifap = &in_dev->ifa_list; (ifa = rtnl_dereference(*ifap)) != NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700673 if (tb[IFA_LOCAL] &&
Jiri Benc67b61f62015-03-29 16:59:26 +0200674 ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700676
677 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
678 continue;
679
680 if (tb[IFA_ADDRESS] &&
681 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Jiri Benc67b61f62015-03-29 16:59:26 +0200682 !inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700683 continue;
684
Madhu Challa93a714d2015-02-25 09:58:35 -0800685 if (ipv4_is_multicast(ifa->ifa_address))
Taras Chornyi690cc862020-04-09 20:25:24 +0300686 ip_mc_autojoin_config(net, false, ifa);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000687 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 return 0;
689 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700690
691 err = -EADDRNOTAVAIL;
692errout:
693 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694}
695
Jiri Pirko5c766d62013-01-24 09:41:41 +0000696#define INFINITY_LIFE_TIME 0xFFFFFFFF
697
698static void check_lifetime(struct work_struct *work)
699{
700 unsigned long now, next, next_sec, next_sched;
701 struct in_ifaddr *ifa;
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000702 struct hlist_node *n;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000703 int i;
704
705 now = jiffies;
706 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
707
Jiri Pirko5c766d62013-01-24 09:41:41 +0000708 for (i = 0; i < IN4_ADDR_HSIZE; i++) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000709 bool change_needed = false;
710
711 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800712 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
Jiri Pirko5c766d62013-01-24 09:41:41 +0000713 unsigned long age;
714
715 if (ifa->ifa_flags & IFA_F_PERMANENT)
716 continue;
717
718 /* We try to batch several events at once. */
719 age = (now - ifa->ifa_tstamp +
720 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
721
722 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
723 age >= ifa->ifa_valid_lft) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000724 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000725 } else if (ifa->ifa_preferred_lft ==
726 INFINITY_LIFE_TIME) {
727 continue;
728 } else if (age >= ifa->ifa_preferred_lft) {
729 if (time_before(ifa->ifa_tstamp +
730 ifa->ifa_valid_lft * HZ, next))
731 next = ifa->ifa_tstamp +
732 ifa->ifa_valid_lft * HZ;
733
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000734 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
735 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000736 } else if (time_before(ifa->ifa_tstamp +
737 ifa->ifa_preferred_lft * HZ,
738 next)) {
739 next = ifa->ifa_tstamp +
740 ifa->ifa_preferred_lft * HZ;
741 }
742 }
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000743 rcu_read_unlock();
744 if (!change_needed)
745 continue;
746 rtnl_lock();
747 hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
748 unsigned long age;
749
750 if (ifa->ifa_flags & IFA_F_PERMANENT)
751 continue;
752
753 /* We try to batch several events at once. */
754 age = (now - ifa->ifa_tstamp +
755 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
756
757 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
758 age >= ifa->ifa_valid_lft) {
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200759 struct in_ifaddr __rcu **ifap;
760 struct in_ifaddr *tmp;
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000761
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200762 ifap = &ifa->ifa_dev->ifa_list;
763 tmp = rtnl_dereference(*ifap);
764 while (tmp) {
Florian Westphal40008e92019-06-17 16:02:27 +0200765 if (tmp == ifa) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000766 inet_del_ifa(ifa->ifa_dev,
767 ifap, 1);
768 break;
769 }
Florian Westphal2638eb8b2019-05-31 18:27:09 +0200770 ifap = &tmp->ifa_next;
771 tmp = rtnl_dereference(*ifap);
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000772 }
773 } else if (ifa->ifa_preferred_lft !=
774 INFINITY_LIFE_TIME &&
775 age >= ifa->ifa_preferred_lft &&
776 !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
777 ifa->ifa_flags |= IFA_F_DEPRECATED;
778 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
779 }
780 }
781 rtnl_unlock();
Jiri Pirko5c766d62013-01-24 09:41:41 +0000782 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000783
784 next_sec = round_jiffies_up(next);
785 next_sched = next;
786
787 /* If rounded timeout is accurate enough, accept it. */
788 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
789 next_sched = next_sec;
790
791 now = jiffies;
792 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
793 if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
794 next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
795
viresh kumar906e0732014-01-22 12:23:32 +0530796 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work,
797 next_sched - now);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000798}
799
800static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
801 __u32 prefered_lft)
802{
803 unsigned long timeout;
804
805 ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
806
807 timeout = addrconf_timeout_fixup(valid_lft, HZ);
808 if (addrconf_finite_timeout(timeout))
809 ifa->ifa_valid_lft = timeout;
810 else
811 ifa->ifa_flags |= IFA_F_PERMANENT;
812
813 timeout = addrconf_timeout_fixup(prefered_lft, HZ);
814 if (addrconf_finite_timeout(timeout)) {
815 if (timeout == 0)
816 ifa->ifa_flags |= IFA_F_DEPRECATED;
817 ifa->ifa_preferred_lft = timeout;
818 }
819 ifa->ifa_tstamp = jiffies;
820 if (!ifa->ifa_cstamp)
821 ifa->ifa_cstamp = ifa->ifa_tstamp;
822}
823
824static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
David Aherndac9c972018-10-07 20:16:24 -0700825 __u32 *pvalid_lft, __u32 *pprefered_lft,
826 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827{
Thomas Graf5c753972006-08-04 23:03:53 -0700828 struct nlattr *tb[IFA_MAX+1];
829 struct in_ifaddr *ifa;
830 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 struct net_device *dev;
832 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800833 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
Johannes Berg8cb08172019-04-26 14:07:28 +0200835 err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX,
836 ifa_ipv4_policy, extack);
Thomas Graf5c753972006-08-04 23:03:53 -0700837 if (err < 0)
838 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
Thomas Graf5c753972006-08-04 23:03:53 -0700840 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800841 err = -EINVAL;
Ian Morris51456b22015-04-03 09:17:26 +0100842 if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL])
Thomas Graf5c753972006-08-04 23:03:53 -0700843 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800845 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800846 err = -ENODEV;
Ian Morris51456b22015-04-03 09:17:26 +0100847 if (!dev)
Thomas Graf5c753972006-08-04 23:03:53 -0700848 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
Thomas Graf5c753972006-08-04 23:03:53 -0700850 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800851 err = -ENOBUFS;
Ian Morris51456b22015-04-03 09:17:26 +0100852 if (!in_dev)
Herbert Xu71e27da2007-06-04 23:36:06 -0700853 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854
Thomas Graf5c753972006-08-04 23:03:53 -0700855 ifa = inet_alloc_ifa();
Ian Morris51456b22015-04-03 09:17:26 +0100856 if (!ifa)
Thomas Graf5c753972006-08-04 23:03:53 -0700857 /*
858 * A potential indev allocation can be left alive, it stays
859 * assigned to its device and is destroy with it.
860 */
Thomas Graf5c753972006-08-04 23:03:53 -0700861 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700862
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800863 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100864 neigh_parms_data_state_setall(in_dev->arp_parms);
Thomas Graf5c753972006-08-04 23:03:53 -0700865 in_dev_hold(in_dev);
866
Ian Morris51456b22015-04-03 09:17:26 +0100867 if (!tb[IFA_ADDRESS])
Thomas Graf5c753972006-08-04 23:03:53 -0700868 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
869
David S. Millerfd23c3b2011-02-18 12:42:28 -0800870 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
872 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100873 ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
874 ifm->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700876 ifa->ifa_dev = in_dev;
877
Jiri Benc67b61f62015-03-29 16:59:26 +0200878 ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]);
879 ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700880
881 if (tb[IFA_BROADCAST])
Jiri Benc67b61f62015-03-29 16:59:26 +0200882 ifa->ifa_broadcast = nla_get_in_addr(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700883
Thomas Graf5c753972006-08-04 23:03:53 -0700884 if (tb[IFA_LABEL])
Francis Laniel872f6902020-11-15 18:08:06 +0100885 nla_strscpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 else
887 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
888
David Ahernaf4d7682018-05-27 08:09:57 -0700889 if (tb[IFA_RT_PRIORITY])
890 ifa->ifa_rt_priority = nla_get_u32(tb[IFA_RT_PRIORITY]);
891
Jiri Pirko5c766d62013-01-24 09:41:41 +0000892 if (tb[IFA_CACHEINFO]) {
893 struct ifa_cacheinfo *ci;
894
895 ci = nla_data(tb[IFA_CACHEINFO]);
896 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
897 err = -EINVAL;
Daniel Borkmann446266b2013-08-02 11:32:43 +0200898 goto errout_free;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000899 }
900 *pvalid_lft = ci->ifa_valid;
901 *pprefered_lft = ci->ifa_prefered;
902 }
903
Thomas Graf5c753972006-08-04 23:03:53 -0700904 return ifa;
905
Daniel Borkmann446266b2013-08-02 11:32:43 +0200906errout_free:
907 inet_free_ifa(ifa);
Thomas Graf5c753972006-08-04 23:03:53 -0700908errout:
909 return ERR_PTR(err);
910}
911
Jiri Pirko5c766d62013-01-24 09:41:41 +0000912static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
913{
914 struct in_device *in_dev = ifa->ifa_dev;
Florian Westphalef11db32019-05-31 18:27:04 +0200915 struct in_ifaddr *ifa1;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000916
917 if (!ifa->ifa_local)
918 return NULL;
919
Florian Westphalef11db32019-05-31 18:27:04 +0200920 in_dev_for_each_ifa_rtnl(ifa1, in_dev) {
Jiri Pirko5c766d62013-01-24 09:41:41 +0000921 if (ifa1->ifa_mask == ifa->ifa_mask &&
922 inet_ifa_match(ifa1->ifa_address, ifa) &&
923 ifa1->ifa_local == ifa->ifa_local)
924 return ifa1;
925 }
926 return NULL;
927}
928
David Ahernc21ef3e2017-04-16 09:48:24 -0700929static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
930 struct netlink_ext_ack *extack)
Thomas Graf5c753972006-08-04 23:03:53 -0700931{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900932 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700933 struct in_ifaddr *ifa;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000934 struct in_ifaddr *ifa_existing;
935 __u32 valid_lft = INFINITY_LIFE_TIME;
936 __u32 prefered_lft = INFINITY_LIFE_TIME;
Thomas Graf5c753972006-08-04 23:03:53 -0700937
938 ASSERT_RTNL();
939
David Aherndac9c972018-10-07 20:16:24 -0700940 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft, extack);
Thomas Graf5c753972006-08-04 23:03:53 -0700941 if (IS_ERR(ifa))
942 return PTR_ERR(ifa);
943
Jiri Pirko5c766d62013-01-24 09:41:41 +0000944 ifa_existing = find_matching_ifa(ifa);
945 if (!ifa_existing) {
946 /* It would be best to check for !NLM_F_CREATE here but
stephen hemminger614d0562014-05-16 20:46:58 -0700947 * userspace already relies on not having to provide this.
Jiri Pirko5c766d62013-01-24 09:41:41 +0000948 */
949 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Madhu Challa93a714d2015-02-25 09:58:35 -0800950 if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
Taras Chornyi690cc862020-04-09 20:25:24 +0300951 int ret = ip_mc_autojoin_config(net, true, ifa);
Madhu Challa93a714d2015-02-25 09:58:35 -0800952
953 if (ret < 0) {
954 inet_free_ifa(ifa);
955 return ret;
956 }
957 }
David Ahernde95e042017-10-18 09:56:54 -0700958 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid,
959 extack);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000960 } else {
David Ahernaf4d7682018-05-27 08:09:57 -0700961 u32 new_metric = ifa->ifa_rt_priority;
962
Jiri Pirko5c766d62013-01-24 09:41:41 +0000963 inet_free_ifa(ifa);
964
965 if (nlh->nlmsg_flags & NLM_F_EXCL ||
966 !(nlh->nlmsg_flags & NLM_F_REPLACE))
967 return -EEXIST;
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000968 ifa = ifa_existing;
David Ahernaf4d7682018-05-27 08:09:57 -0700969
970 if (ifa->ifa_rt_priority != new_metric) {
971 fib_modify_prefix_metric(ifa, new_metric);
972 ifa->ifa_rt_priority = new_metric;
973 }
974
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000975 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Jiri Pirko05a324b2013-04-04 23:39:38 +0000976 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530977 queue_delayed_work(system_power_efficient_wq,
978 &check_lifetime_work, 0);
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000979 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000980 }
981 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982}
983
984/*
985 * Determine a default network mask, based on the IP address.
986 */
987
Eric Dumazet40384992012-08-03 21:06:50 +0000988static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989{
990 int rc = -1; /* Something else, probably a multicast. */
991
Dave Taht65cab852018-12-11 15:30:34 -0800992 if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900993 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 else {
Al Viro714e85b2006-11-14 20:51:49 -0800995 __u32 haddr = ntohl(addr);
Al Viro714e85b2006-11-14 20:51:49 -0800996 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800998 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -08001000 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 rc = 24;
Dave Taht65cab852018-12-11 15:30:34 -08001002 else if (IN_CLASSE(haddr))
1003 rc = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 }
1005
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001006 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007}
1008
1009
Al Viro03aef172017-07-01 07:53:12 -04001010int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 struct sockaddr_in sin_orig;
Al Viro03aef172017-07-01 07:53:12 -04001013 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
Florian Westphal2638eb8b2019-05-31 18:27:09 +02001014 struct in_ifaddr __rcu **ifap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 struct in_device *in_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 struct in_ifaddr *ifa = NULL;
1017 struct net_device *dev;
1018 char *colon;
1019 int ret = -EFAULT;
1020 int tryaddrmatch = 0;
1021
Al Viro03aef172017-07-01 07:53:12 -04001022 ifr->ifr_name[IFNAMSIZ - 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
1024 /* save original address for comparison */
1025 memcpy(&sin_orig, sin, sizeof(*sin));
1026
Al Viro03aef172017-07-01 07:53:12 -04001027 colon = strchr(ifr->ifr_name, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 if (colon)
1029 *colon = 0;
1030
Al Viro03aef172017-07-01 07:53:12 -04001031 dev_load(net, ifr->ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
Stephen Hemminger132adf52007-03-08 20:44:43 -08001033 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 case SIOCGIFADDR: /* Get interface address */
1035 case SIOCGIFBRDADDR: /* Get the broadcast address */
1036 case SIOCGIFDSTADDR: /* Get the destination address */
1037 case SIOCGIFNETMASK: /* Get the netmask for the interface */
1038 /* Note that these ioctls will not sleep,
1039 so that we do not impose a lock.
1040 One day we will be forced to put shlock here (I mean SMP)
1041 */
1042 tryaddrmatch = (sin_orig.sin_family == AF_INET);
1043 memset(sin, 0, sizeof(*sin));
1044 sin->sin_family = AF_INET;
1045 break;
1046
1047 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +00001048 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +00001049 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 goto out;
1051 break;
1052 case SIOCSIFADDR: /* Set interface address (and family) */
1053 case SIOCSIFBRDADDR: /* Set the broadcast address */
1054 case SIOCSIFDSTADDR: /* Set the destination address */
1055 case SIOCSIFNETMASK: /* Set the netmask for the interface */
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +00001056 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +00001057 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 goto out;
1059 ret = -EINVAL;
1060 if (sin->sin_family != AF_INET)
1061 goto out;
1062 break;
1063 default:
1064 ret = -EINVAL;
1065 goto out;
1066 }
1067
1068 rtnl_lock();
1069
1070 ret = -ENODEV;
Al Viro03aef172017-07-01 07:53:12 -04001071 dev = __dev_get_by_name(net, ifr->ifr_name);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001072 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 goto done;
1074
1075 if (colon)
1076 *colon = ':';
1077
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001078 in_dev = __in_dev_get_rtnl(dev);
1079 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 if (tryaddrmatch) {
1081 /* Matthias Andree */
1082 /* compare label and address (4.4BSD style) */
1083 /* note: we only do this for a limited set of ioctls
1084 and only if the original address family was AF_INET.
1085 This is checked above. */
Florian Westphal2638eb8b2019-05-31 18:27:09 +02001086
1087 for (ifap = &in_dev->ifa_list;
1088 (ifa = rtnl_dereference(*ifap)) != NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 ifap = &ifa->ifa_next) {
Al Viro03aef172017-07-01 07:53:12 -04001090 if (!strcmp(ifr->ifr_name, ifa->ifa_label) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -08001092 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 break; /* found */
1094 }
1095 }
1096 }
1097 /* we didn't get a match, maybe the application is
1098 4.3BSD-style and passed in junk so we fall back to
1099 comparing just the label */
1100 if (!ifa) {
Florian Westphal2638eb8b2019-05-31 18:27:09 +02001101 for (ifap = &in_dev->ifa_list;
1102 (ifa = rtnl_dereference(*ifap)) != NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 ifap = &ifa->ifa_next)
Al Viro03aef172017-07-01 07:53:12 -04001104 if (!strcmp(ifr->ifr_name, ifa->ifa_label))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 break;
1106 }
1107 }
1108
1109 ret = -EADDRNOTAVAIL;
1110 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
1111 goto done;
1112
Stephen Hemminger132adf52007-03-08 20:44:43 -08001113 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 case SIOCGIFADDR: /* Get interface address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001115 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 sin->sin_addr.s_addr = ifa->ifa_local;
Al Viro03aef172017-07-01 07:53:12 -04001117 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
1119 case SIOCGIFBRDADDR: /* Get the broadcast address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001120 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 sin->sin_addr.s_addr = ifa->ifa_broadcast;
Al Viro03aef172017-07-01 07:53:12 -04001122 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
1124 case SIOCGIFDSTADDR: /* Get the destination address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001125 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 sin->sin_addr.s_addr = ifa->ifa_address;
Al Viro03aef172017-07-01 07:53:12 -04001127 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
1129 case SIOCGIFNETMASK: /* Get the netmask for the interface */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001130 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 sin->sin_addr.s_addr = ifa->ifa_mask;
Al Viro03aef172017-07-01 07:53:12 -04001132 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
1134 case SIOCSIFFLAGS:
1135 if (colon) {
1136 ret = -EADDRNOTAVAIL;
1137 if (!ifa)
1138 break;
1139 ret = 0;
Al Viro03aef172017-07-01 07:53:12 -04001140 if (!(ifr->ifr_flags & IFF_UP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 inet_del_ifa(in_dev, ifap, 1);
1142 break;
1143 }
Petr Machata567c5e12018-12-06 17:05:42 +00001144 ret = dev_change_flags(dev, ifr->ifr_flags, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 break;
1146
1147 case SIOCSIFADDR: /* Set interface address (and family) */
1148 ret = -EINVAL;
1149 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1150 break;
1151
1152 if (!ifa) {
1153 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001154 ifa = inet_alloc_ifa();
1155 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 break;
Xi Wangc7e2e1d2013-01-05 11:19:24 +00001157 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 if (colon)
Al Viro03aef172017-07-01 07:53:12 -04001159 memcpy(ifa->ifa_label, ifr->ifr_name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 else
1161 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1162 } else {
1163 ret = 0;
1164 if (ifa->ifa_local == sin->sin_addr.s_addr)
1165 break;
1166 inet_del_ifa(in_dev, ifap, 0);
1167 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -08001168 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 }
1170
1171 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
1172
1173 if (!(dev->flags & IFF_POINTOPOINT)) {
1174 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
1175 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
1176 if ((dev->flags & IFF_BROADCAST) &&
1177 ifa->ifa_prefixlen < 31)
1178 ifa->ifa_broadcast = ifa->ifa_address |
1179 ~ifa->ifa_mask;
1180 } else {
1181 ifa->ifa_prefixlen = 32;
1182 ifa->ifa_mask = inet_make_mask(32);
1183 }
Jiri Pirko5c766d62013-01-24 09:41:41 +00001184 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 ret = inet_set_ifa(dev, ifa);
1186 break;
1187
1188 case SIOCSIFBRDADDR: /* Set the broadcast address */
1189 ret = 0;
1190 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
1191 inet_del_ifa(in_dev, ifap, 0);
1192 ifa->ifa_broadcast = sin->sin_addr.s_addr;
1193 inet_insert_ifa(ifa);
1194 }
1195 break;
1196
1197 case SIOCSIFDSTADDR: /* Set the destination address */
1198 ret = 0;
1199 if (ifa->ifa_address == sin->sin_addr.s_addr)
1200 break;
1201 ret = -EINVAL;
1202 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1203 break;
1204 ret = 0;
1205 inet_del_ifa(in_dev, ifap, 0);
1206 ifa->ifa_address = sin->sin_addr.s_addr;
1207 inet_insert_ifa(ifa);
1208 break;
1209
1210 case SIOCSIFNETMASK: /* Set the netmask for the interface */
1211
1212 /*
1213 * The mask we set must be legal.
1214 */
1215 ret = -EINVAL;
1216 if (bad_mask(sin->sin_addr.s_addr, 0))
1217 break;
1218 ret = 0;
1219 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -07001220 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 inet_del_ifa(in_dev, ifap, 0);
1222 ifa->ifa_mask = sin->sin_addr.s_addr;
1223 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
1224
1225 /* See if current broadcast address matches
1226 * with current netmask, then recalculate
1227 * the broadcast address. Otherwise it's a
1228 * funny address, so don't touch it since
1229 * the user seems to know what (s)he's doing...
1230 */
1231 if ((dev->flags & IFF_BROADCAST) &&
1232 (ifa->ifa_prefixlen < 31) &&
1233 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -05001234 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 ifa->ifa_broadcast = (ifa->ifa_local |
1236 ~sin->sin_addr.s_addr);
1237 }
1238 inet_insert_ifa(ifa);
1239 }
1240 break;
1241 }
1242done:
1243 rtnl_unlock();
1244out:
1245 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246}
1247
Arnd Bergmannb0e99d02021-07-22 16:29:01 +02001248int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249{
Herbert Xue5ed6392005-10-03 14:35:55 -07001250 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Florian Westphalef11db32019-05-31 18:27:04 +02001251 const struct in_ifaddr *ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 struct ifreq ifr;
1253 int done = 0;
1254
Al Viro36fd6332017-06-26 13:19:16 -04001255 if (WARN_ON(size > sizeof(struct ifreq)))
1256 goto out;
1257
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001258 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 goto out;
1260
Florian Westphalef11db32019-05-31 18:27:04 +02001261 in_dev_for_each_ifa_rtnl(ifa, in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 if (!buf) {
Al Viro36fd6332017-06-26 13:19:16 -04001263 done += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 continue;
1265 }
Al Viro36fd6332017-06-26 13:19:16 -04001266 if (len < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 break;
1268 memset(&ifr, 0, sizeof(struct ifreq));
Dan Carpenter4299c8a2013-07-29 22:15:19 +03001269 strcpy(ifr.ifr_name, ifa->ifa_label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270
1271 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
1272 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1273 ifa->ifa_local;
1274
Al Viro36fd6332017-06-26 13:19:16 -04001275 if (copy_to_user(buf + done, &ifr, size)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 done = -EFAULT;
1277 break;
1278 }
Al Viro36fd6332017-06-26 13:19:16 -04001279 len -= size;
1280 done += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 }
1282out:
1283 return done;
1284}
1285
Gao Feng8b57fd12017-03-10 12:38:47 +08001286static __be32 in_dev_select_addr(const struct in_device *in_dev,
1287 int scope)
1288{
Florian Westphald519e872019-05-31 18:27:05 +02001289 const struct in_ifaddr *ifa;
1290
1291 in_dev_for_each_ifa_rcu(ifa, in_dev) {
1292 if (ifa->ifa_flags & IFA_F_SECONDARY)
1293 continue;
Gao Feng8b57fd12017-03-10 12:38:47 +08001294 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1295 ifa->ifa_scope <= scope)
1296 return ifa->ifa_local;
Florian Westphald519e872019-05-31 18:27:05 +02001297 }
Gao Feng8b57fd12017-03-10 12:38:47 +08001298
1299 return 0;
1300}
1301
Al Viroa61ced52006-09-26 21:27:54 -07001302__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303{
Florian Westphald519e872019-05-31 18:27:05 +02001304 const struct in_ifaddr *ifa;
Al Viroa61ced52006-09-26 21:27:54 -07001305 __be32 addr = 0;
Shijie Luod8c444d2019-06-18 15:14:03 +00001306 unsigned char localnet_scope = RT_SCOPE_HOST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001308 struct net *net = dev_net(dev);
David Ahern3f2fb9a2016-02-24 11:47:02 -08001309 int master_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310
1311 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001312 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 if (!in_dev)
1314 goto no_in_dev;
1315
Shijie Luod8c444d2019-06-18 15:14:03 +00001316 if (unlikely(IN_DEV_ROUTE_LOCALNET(in_dev)))
1317 localnet_scope = RT_SCOPE_LINK;
1318
Florian Westphald519e872019-05-31 18:27:05 +02001319 in_dev_for_each_ifa_rcu(ifa, in_dev) {
1320 if (ifa->ifa_flags & IFA_F_SECONDARY)
1321 continue;
Shijie Luod8c444d2019-06-18 15:14:03 +00001322 if (min(ifa->ifa_scope, localnet_scope) > scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 continue;
1324 if (!dst || inet_ifa_match(dst, ifa)) {
1325 addr = ifa->ifa_local;
1326 break;
1327 }
1328 if (!addr)
1329 addr = ifa->ifa_local;
Florian Westphald519e872019-05-31 18:27:05 +02001330 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331
1332 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001333 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001334no_in_dev:
David Ahern3f2fb9a2016-02-24 11:47:02 -08001335 master_idx = l3mdev_master_ifindex_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336
David Lamparter17b693c2016-02-24 11:47:03 -08001337 /* For VRFs, the VRF device takes the place of the loopback device,
1338 * with addresses on it being preferred. Note in such cases the
1339 * loopback device will be among the devices that fail the master_idx
1340 * equality check in the loop below.
1341 */
1342 if (master_idx &&
1343 (dev = dev_get_by_index_rcu(net, master_idx)) &&
1344 (in_dev = __in_dev_get_rcu(dev))) {
Gao Feng8b57fd12017-03-10 12:38:47 +08001345 addr = in_dev_select_addr(in_dev, scope);
1346 if (addr)
1347 goto out_unlock;
David Lamparter17b693c2016-02-24 11:47:03 -08001348 }
1349
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 /* Not loopback addresses on loopback should be preferred
Stephen Hemmingerca9f1fd2015-02-14 13:47:54 -05001351 in this case. It is important that lo is the first interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 in dev_base list.
1353 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001354 for_each_netdev_rcu(net, dev) {
David Ahern3f2fb9a2016-02-24 11:47:02 -08001355 if (l3mdev_master_ifindex_rcu(dev) != master_idx)
1356 continue;
1357
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001358 in_dev = __in_dev_get_rcu(dev);
1359 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 continue;
1361
Gao Feng8b57fd12017-03-10 12:38:47 +08001362 addr = in_dev_select_addr(in_dev, scope);
1363 if (addr)
1364 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001366out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 return addr;
1369}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001370EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
Al Viro60cad5d2006-09-26 22:17:09 -07001372static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1373 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374{
Shijie Luo650638a2019-06-18 15:14:04 +00001375 unsigned char localnet_scope = RT_SCOPE_HOST;
Florian Westphalef11db32019-05-31 18:27:04 +02001376 const struct in_ifaddr *ifa;
Al Viroa144ea42006-09-28 18:00:55 -07001377 __be32 addr = 0;
Florian Westphalef11db32019-05-31 18:27:04 +02001378 int same = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379
Shijie Luo650638a2019-06-18 15:14:04 +00001380 if (unlikely(IN_DEV_ROUTE_LOCALNET(in_dev)))
1381 localnet_scope = RT_SCOPE_LINK;
1382
Florian Westphalef11db32019-05-31 18:27:04 +02001383 in_dev_for_each_ifa_rcu(ifa, in_dev) {
Shijie Luo650638a2019-06-18 15:14:04 +00001384 unsigned char min_scope = min(ifa->ifa_scope, localnet_scope);
1385
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 if (!addr &&
1387 (local == ifa->ifa_local || !local) &&
Shijie Luo650638a2019-06-18 15:14:04 +00001388 min_scope <= scope) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 addr = ifa->ifa_local;
1390 if (same)
1391 break;
1392 }
1393 if (!same) {
1394 same = (!local || inet_ifa_match(local, ifa)) &&
1395 (!dst || inet_ifa_match(dst, ifa));
1396 if (same && addr) {
1397 if (local || !dst)
1398 break;
1399 /* Is the selected addr into dst subnet? */
1400 if (inet_ifa_match(addr, ifa))
1401 break;
1402 /* No, then can we use new local src? */
Shijie Luo650638a2019-06-18 15:14:04 +00001403 if (min_scope <= scope) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 addr = ifa->ifa_local;
1405 break;
1406 }
1407 /* search for large dst subnet for addr */
1408 same = 0;
1409 }
1410 }
Florian Westphalef11db32019-05-31 18:27:04 +02001411 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001413 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414}
1415
1416/*
1417 * Confirm that local IP address exists using wildcards:
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001418 * - net: netns to check, cannot be NULL
1419 * - in_dev: only on this interface, NULL=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 * - dst: only in the same subnet as dst, 0=any dst
1421 * - local: address, 0=autoselect the local address
1422 * - scope: maximum allowed scope value for the local address
1423 */
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001424__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001425 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426{
Al Viro60cad5d2006-09-26 22:17:09 -07001427 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001428 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429
Ian Morris00db4122015-04-03 09:17:27 +01001430 if (in_dev)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001431 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001434 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001435 in_dev = __in_dev_get_rcu(dev);
1436 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 addr = confirm_addr_indev(in_dev, dst, local, scope);
1438 if (addr)
1439 break;
1440 }
1441 }
1442 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443
1444 return addr;
1445}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001446EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447
1448/*
1449 * Device notifier
1450 */
1451
1452int register_inetaddr_notifier(struct notifier_block *nb)
1453{
Alan Sterne041c682006-03-27 01:16:30 -08001454 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001456EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457
1458int unregister_inetaddr_notifier(struct notifier_block *nb)
1459{
Alan Sterne041c682006-03-27 01:16:30 -08001460 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001462EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463
Krister Johansen3ad7d242017-06-08 13:12:14 -07001464int register_inetaddr_validator_notifier(struct notifier_block *nb)
1465{
1466 return blocking_notifier_chain_register(&inetaddr_validator_chain, nb);
1467}
1468EXPORT_SYMBOL(register_inetaddr_validator_notifier);
1469
1470int unregister_inetaddr_validator_notifier(struct notifier_block *nb)
1471{
1472 return blocking_notifier_chain_unregister(&inetaddr_validator_chain,
1473 nb);
1474}
1475EXPORT_SYMBOL(unregister_inetaddr_validator_notifier);
1476
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001477/* Rename ifa_labels for a device name change. Make some effort to preserve
1478 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479*/
1480static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001481{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 struct in_ifaddr *ifa;
1483 int named = 0;
1484
Florian Westphalef11db32019-05-31 18:27:04 +02001485 in_dev_for_each_ifa_rtnl(ifa, in_dev) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001486 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487
1488 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001489 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001491 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001492 dot = strchr(old, ':');
Ian Morris51456b22015-04-03 09:17:26 +01001493 if (!dot) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001494 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 dot = old;
1496 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001497 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001498 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001499 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001500 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001501skip:
1502 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001503 }
1504}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505
Ian Campbelld11327ad2011-02-11 07:44:16 +00001506static void inetdev_send_gratuitous_arp(struct net_device *dev,
1507 struct in_device *in_dev)
1508
1509{
Florian Westphalef11db32019-05-31 18:27:04 +02001510 const struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001511
Florian Westphalef11db32019-05-31 18:27:04 +02001512 in_dev_for_each_ifa_rtnl(ifa, in_dev) {
Zoltan Kissb76d0782011-07-24 13:09:30 +00001513 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1514 ifa->ifa_local, dev,
1515 ifa->ifa_local, NULL,
1516 dev->dev_addr, NULL);
1517 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001518}
1519
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520/* Called only under RTNL semaphore */
1521
1522static int inetdev_event(struct notifier_block *this, unsigned long event,
1523 void *ptr)
1524{
Jiri Pirko351638e2013-05-28 01:30:21 +00001525 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazet748e2d92012-08-22 21:50:59 +00001526 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527
1528 ASSERT_RTNL();
1529
1530 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001531 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 in_dev = inetdev_init(dev);
WANG Cong20e61da2014-07-25 15:25:08 -07001533 if (IS_ERR(in_dev))
1534 return notifier_from_errno(PTR_ERR(in_dev));
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001535 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001536 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1537 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001538 }
Breno Leitao06770842008-09-02 17:28:58 -07001539 } else if (event == NETDEV_CHANGEMTU) {
1540 /* Re-enabling IP */
1541 if (inetdev_valid_mtu(dev->mtu))
1542 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 }
1544 goto out;
1545 }
1546
1547 switch (event) {
1548 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001549 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001550 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 break;
1552 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001553 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001555 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001556 struct in_ifaddr *ifa = inet_alloc_ifa();
1557
1558 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001559 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 ifa->ifa_local =
1561 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1562 ifa->ifa_prefixlen = 8;
1563 ifa->ifa_mask = inet_make_mask(8);
1564 in_dev_hold(in_dev);
1565 ifa->ifa_dev = in_dev;
1566 ifa->ifa_scope = RT_SCOPE_HOST;
1567 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Jiri Pirko5c766d62013-01-24 09:41:41 +00001568 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1569 INFINITY_LIFE_TIME);
Jiri Pirkodfd15822014-01-07 15:55:45 +01001570 ipv4_devconf_setall(in_dev);
1571 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 inet_insert_ifa(ifa);
1573 }
1574 }
1575 ip_mc_up(in_dev);
Joe Perchesa8eceea2020-03-12 15:50:22 -07001576 fallthrough;
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001577 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001578 if (!IN_DEV_ARP_NOTIFY(in_dev))
1579 break;
Joe Perchesa8eceea2020-03-12 15:50:22 -07001580 fallthrough;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001581 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001582 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001583 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 break;
1585 case NETDEV_DOWN:
1586 ip_mc_down(in_dev);
1587 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001588 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001589 ip_mc_unmap(in_dev);
1590 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001591 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001592 ip_mc_remap(in_dev);
1593 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001595 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 break;
Breno Leitao06770842008-09-02 17:28:58 -07001597 /* disable IP when MTU is not enough */
Joe Perchesa8eceea2020-03-12 15:50:22 -07001598 fallthrough;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 case NETDEV_UNREGISTER:
1600 inetdev_destroy(in_dev);
1601 break;
1602 case NETDEV_CHANGENAME:
1603 /* Do not notify about label change, this event is
1604 * not interesting to applications using netlink.
1605 */
1606 inetdev_changename(dev, in_dev);
1607
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001608 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001609 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 break;
1611 }
1612out:
1613 return NOTIFY_DONE;
1614}
1615
1616static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001617 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618};
1619
Eric Dumazet40384992012-08-03 21:06:50 +00001620static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001621{
1622 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1623 + nla_total_size(4) /* IFA_ADDRESS */
1624 + nla_total_size(4) /* IFA_LOCAL */
1625 + nla_total_size(4) /* IFA_BROADCAST */
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001626 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001627 + nla_total_size(4) /* IFA_FLAGS */
David Ahernaf4d7682018-05-27 08:09:57 -07001628 + nla_total_size(4) /* IFA_RT_PRIORITY */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001629 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
Thomas Graf339bf982006-11-10 14:10:15 -08001630}
1631
Jiri Pirko5c766d62013-01-24 09:41:41 +00001632static inline u32 cstamp_delta(unsigned long cstamp)
1633{
1634 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1635}
1636
1637static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1638 unsigned long tstamp, u32 preferred, u32 valid)
1639{
1640 struct ifa_cacheinfo ci;
1641
1642 ci.cstamp = cstamp_delta(cstamp);
1643 ci.tstamp = cstamp_delta(tstamp);
1644 ci.ifa_prefered = preferred;
1645 ci.ifa_valid = valid;
1646
1647 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1648}
1649
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Christian Brauner978a46f2018-09-04 21:53:54 +02001651 struct inet_fill_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652{
1653 struct ifaddrmsg *ifm;
1654 struct nlmsghdr *nlh;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001655 u32 preferred, valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656
Christian Brauner978a46f2018-09-04 21:53:54 +02001657 nlh = nlmsg_put(skb, args->portid, args->seq, args->event, sizeof(*ifm),
1658 args->flags);
Ian Morris51456b22015-04-03 09:17:26 +01001659 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08001660 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001661
1662 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 ifm->ifa_family = AF_INET;
1664 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001665 ifm->ifa_flags = ifa->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 ifm->ifa_scope = ifa->ifa_scope;
1667 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668
Christian Brauner978a46f2018-09-04 21:53:54 +02001669 if (args->netnsid >= 0 &&
1670 nla_put_s32(skb, IFA_TARGET_NETNSID, args->netnsid))
Christian Braunerd3807142018-09-04 21:53:49 +02001671 goto nla_put_failure;
1672
Jiri Pirko5c766d62013-01-24 09:41:41 +00001673 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1674 preferred = ifa->ifa_preferred_lft;
1675 valid = ifa->ifa_valid_lft;
1676 if (preferred != INFINITY_LIFE_TIME) {
1677 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1678
1679 if (preferred > tval)
1680 preferred -= tval;
1681 else
1682 preferred = 0;
1683 if (valid != INFINITY_LIFE_TIME) {
1684 if (valid > tval)
1685 valid -= tval;
1686 else
1687 valid = 0;
1688 }
1689 }
1690 } else {
1691 preferred = INFINITY_LIFE_TIME;
1692 valid = INFINITY_LIFE_TIME;
1693 }
David S. Millerf3756b72012-04-01 20:39:02 -04001694 if ((ifa->ifa_address &&
Jiri Benc930345e2015-03-29 16:59:25 +02001695 nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001696 (ifa->ifa_local &&
Jiri Benc930345e2015-03-29 16:59:25 +02001697 nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001698 (ifa->ifa_broadcast &&
Jiri Benc930345e2015-03-29 16:59:25 +02001699 nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001700 (ifa->ifa_label[0] &&
Jiri Pirko5c766d62013-01-24 09:41:41 +00001701 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001702 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
David Ahernaf4d7682018-05-27 08:09:57 -07001703 (ifa->ifa_rt_priority &&
1704 nla_put_u32(skb, IFA_RT_PRIORITY, ifa->ifa_rt_priority)) ||
Jiri Pirko5c766d62013-01-24 09:41:41 +00001705 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1706 preferred, valid))
David S. Millerf3756b72012-04-01 20:39:02 -04001707 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001708
Johannes Berg053c0952015-01-16 22:09:00 +01001709 nlmsg_end(skb, nlh);
1710 return 0;
Thomas Graf47f68512006-08-04 23:04:36 -07001711
1712nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001713 nlmsg_cancel(skb, nlh);
1714 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715}
1716
David Ahernc33078e2018-10-07 20:16:28 -07001717static int inet_valid_dump_ifaddr_req(const struct nlmsghdr *nlh,
1718 struct inet_fill_args *fillargs,
1719 struct net **tgt_net, struct sock *sk,
David Ahern5fcd2662018-10-19 12:45:29 -07001720 struct netlink_callback *cb)
David Ahernc33078e2018-10-07 20:16:28 -07001721{
David Ahern5fcd2662018-10-19 12:45:29 -07001722 struct netlink_ext_ack *extack = cb->extack;
David Ahernc33078e2018-10-07 20:16:28 -07001723 struct nlattr *tb[IFA_MAX+1];
1724 struct ifaddrmsg *ifm;
1725 int err, i;
1726
1727 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) {
1728 NL_SET_ERR_MSG(extack, "ipv4: Invalid header for address dump request");
1729 return -EINVAL;
1730 }
1731
1732 ifm = nlmsg_data(nlh);
1733 if (ifm->ifa_prefixlen || ifm->ifa_flags || ifm->ifa_scope) {
1734 NL_SET_ERR_MSG(extack, "ipv4: Invalid values in header for address dump request");
1735 return -EINVAL;
1736 }
David Ahern5fcd2662018-10-19 12:45:29 -07001737
1738 fillargs->ifindex = ifm->ifa_index;
1739 if (fillargs->ifindex) {
1740 cb->answer_flags |= NLM_F_DUMP_FILTERED;
1741 fillargs->flags |= NLM_F_DUMP_FILTERED;
David Ahernc33078e2018-10-07 20:16:28 -07001742 }
1743
Johannes Berg8cb08172019-04-26 14:07:28 +02001744 err = nlmsg_parse_deprecated_strict(nlh, sizeof(*ifm), tb, IFA_MAX,
1745 ifa_ipv4_policy, extack);
David Ahernc33078e2018-10-07 20:16:28 -07001746 if (err < 0)
1747 return err;
1748
1749 for (i = 0; i <= IFA_MAX; ++i) {
1750 if (!tb[i])
1751 continue;
1752
1753 if (i == IFA_TARGET_NETNSID) {
1754 struct net *net;
1755
1756 fillargs->netnsid = nla_get_s32(tb[i]);
1757
1758 net = rtnl_get_net_ns_capable(sk, fillargs->netnsid);
1759 if (IS_ERR(net)) {
Bjørn Morkbf4cc402018-10-25 21:18:25 +02001760 fillargs->netnsid = -1;
David Ahernc33078e2018-10-07 20:16:28 -07001761 NL_SET_ERR_MSG(extack, "ipv4: Invalid target network namespace id");
1762 return PTR_ERR(net);
1763 }
1764 *tgt_net = net;
1765 } else {
1766 NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in dump request");
1767 return -EINVAL;
1768 }
1769 }
1770
1771 return 0;
1772}
1773
David Ahern1c98eca2018-10-19 12:45:27 -07001774static int in_dev_dump_addr(struct in_device *in_dev, struct sk_buff *skb,
1775 struct netlink_callback *cb, int s_ip_idx,
1776 struct inet_fill_args *fillargs)
1777{
1778 struct in_ifaddr *ifa;
1779 int ip_idx = 0;
1780 int err;
1781
Florian Westphald3e6e282019-06-03 22:41:44 +02001782 in_dev_for_each_ifa_rtnl(ifa, in_dev) {
Florian Westphalef11db32019-05-31 18:27:04 +02001783 if (ip_idx < s_ip_idx) {
1784 ip_idx++;
David Ahern1c98eca2018-10-19 12:45:27 -07001785 continue;
Florian Westphalef11db32019-05-31 18:27:04 +02001786 }
David Ahern1c98eca2018-10-19 12:45:27 -07001787 err = inet_fill_ifaddr(skb, ifa, fillargs);
1788 if (err < 0)
1789 goto done;
1790
1791 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Florian Westphalef11db32019-05-31 18:27:04 +02001792 ip_idx++;
David Ahern1c98eca2018-10-19 12:45:27 -07001793 }
1794 err = 0;
1795
1796done:
1797 cb->args[2] = ip_idx;
1798
1799 return err;
1800}
1801
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1803{
David Ahernc33078e2018-10-07 20:16:28 -07001804 const struct nlmsghdr *nlh = cb->nlh;
Christian Brauner978a46f2018-09-04 21:53:54 +02001805 struct inet_fill_args fillargs = {
1806 .portid = NETLINK_CB(cb->skb).portid,
David Ahernc33078e2018-10-07 20:16:28 -07001807 .seq = nlh->nlmsg_seq,
Christian Brauner978a46f2018-09-04 21:53:54 +02001808 .event = RTM_NEWADDR,
1809 .flags = NLM_F_MULTI,
1810 .netnsid = -1,
1811 };
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001812 struct net *net = sock_net(skb->sk);
Christian Braunerd3807142018-09-04 21:53:49 +02001813 struct net *tgt_net = net;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001814 int h, s_h;
1815 int idx, s_idx;
David Ahern1c98eca2018-10-19 12:45:27 -07001816 int s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 struct net_device *dev;
1818 struct in_device *in_dev;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001819 struct hlist_head *head;
David Ahernd7e38612018-10-24 12:58:59 -07001820 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821
Eric Dumazeteec4df92009-11-12 07:44:25 +00001822 s_h = cb->args[0];
1823 s_idx = idx = cb->args[1];
David Ahern1c98eca2018-10-19 12:45:27 -07001824 s_ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825
David Ahernc33078e2018-10-07 20:16:28 -07001826 if (cb->strict_check) {
David Ahernc33078e2018-10-07 20:16:28 -07001827 err = inet_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net,
David Ahern5fcd2662018-10-19 12:45:29 -07001828 skb->sk, cb);
David Ahernc33078e2018-10-07 20:16:28 -07001829 if (err < 0)
David Ahernd7e38612018-10-24 12:58:59 -07001830 goto put_tgt_net;
David Ahern5fcd2662018-10-19 12:45:29 -07001831
David Ahernd7e38612018-10-24 12:58:59 -07001832 err = 0;
David Ahern5fcd2662018-10-19 12:45:29 -07001833 if (fillargs.ifindex) {
1834 dev = __dev_get_by_index(tgt_net, fillargs.ifindex);
David Ahernd7e38612018-10-24 12:58:59 -07001835 if (!dev) {
1836 err = -ENODEV;
1837 goto put_tgt_net;
1838 }
David Ahern5fcd2662018-10-19 12:45:29 -07001839
1840 in_dev = __in_dev_get_rtnl(dev);
1841 if (in_dev) {
1842 err = in_dev_dump_addr(in_dev, skb, cb, s_ip_idx,
1843 &fillargs);
1844 }
1845 goto put_tgt_net;
1846 }
Christian Braunerd3807142018-09-04 21:53:49 +02001847 }
1848
Eric Dumazeteec4df92009-11-12 07:44:25 +00001849 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1850 idx = 0;
Christian Braunerd3807142018-09-04 21:53:49 +02001851 head = &tgt_net->dev_index_head[h];
Eric Dumazeteec4df92009-11-12 07:44:25 +00001852 rcu_read_lock();
Christian Braunerd3807142018-09-04 21:53:49 +02001853 cb->seq = atomic_read(&tgt_net->ipv4.dev_addr_genid) ^
1854 tgt_net->dev_base_seq;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001855 hlist_for_each_entry_rcu(dev, head, index_hlist) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001856 if (idx < s_idx)
1857 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001858 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001859 s_ip_idx = 0;
1860 in_dev = __in_dev_get_rcu(dev);
1861 if (!in_dev)
1862 goto cont;
1863
David Ahern1c98eca2018-10-19 12:45:27 -07001864 err = in_dev_dump_addr(in_dev, skb, cb, s_ip_idx,
1865 &fillargs);
1866 if (err < 0) {
1867 rcu_read_unlock();
1868 goto done;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001869 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001870cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001871 idx++;
1872 }
1873 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 }
1875
1876done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001877 cb->args[0] = h;
1878 cb->args[1] = idx;
David Ahern5fcd2662018-10-19 12:45:29 -07001879put_tgt_net:
Christian Brauner978a46f2018-09-04 21:53:54 +02001880 if (fillargs.netnsid >= 0)
Christian Braunerd3807142018-09-04 21:53:49 +02001881 put_net(tgt_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882
Arthur Gautier7c1e8a32018-12-31 02:10:58 +00001883 return skb->len ? : err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884}
1885
Jianjun Kong539afed2008-11-03 02:48:48 -08001886static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001887 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888{
Christian Brauner978a46f2018-09-04 21:53:54 +02001889 struct inet_fill_args fillargs = {
1890 .portid = portid,
1891 .seq = nlh ? nlh->nlmsg_seq : 0,
1892 .event = event,
1893 .flags = 0,
1894 .netnsid = -1,
1895 };
Thomas Graf47f68512006-08-04 23:04:36 -07001896 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001897 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001898 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001900 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001901 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001902 if (!skb)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001903 goto errout;
1904
Christian Brauner978a46f2018-09-04 21:53:54 +02001905 err = inet_fill_ifaddr(skb, ifa, &fillargs);
Patrick McHardy26932562007-01-31 23:16:40 -08001906 if (err < 0) {
1907 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1908 WARN_ON(err == -EMSGSIZE);
1909 kfree_skb(skb);
1910 goto errout;
1911 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001912 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001913 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001914errout:
1915 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001916 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917}
1918
Arad, Ronenb1974ed2015-10-19 09:23:28 -07001919static size_t inet_get_link_af_size(const struct net_device *dev,
1920 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001921{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001922 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001923
1924 if (!in_dev)
1925 return 0;
1926
1927 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1928}
1929
Sowmini Varadhand5566fd2015-09-11 16:48:48 -04001930static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
1931 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001932{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001933 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001934 struct nlattr *nla;
1935 int i;
1936
1937 if (!in_dev)
1938 return -ENODATA;
1939
1940 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
Ian Morris51456b22015-04-03 09:17:26 +01001941 if (!nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001942 return -EMSGSIZE;
1943
1944 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1945 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1946
1947 return 0;
1948}
1949
1950static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1951 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1952};
1953
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001954static int inet_validate_link_af(const struct net_device *dev,
Rocco Yue8679c312021-08-03 20:02:50 +08001955 const struct nlattr *nla,
1956 struct netlink_ext_ack *extack)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001957{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001958 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1959 int err, rem;
1960
Cong Wanga1002432021-05-08 11:00:33 -07001961 if (dev && !__in_dev_get_rtnl(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001962 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001963
Johannes Berg8cb08172019-04-26 14:07:28 +02001964 err = nla_parse_nested_deprecated(tb, IFLA_INET_MAX, nla,
Rocco Yue8679c312021-08-03 20:02:50 +08001965 inet_af_policy, extack);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001966 if (err < 0)
1967 return err;
1968
1969 if (tb[IFLA_INET_CONF]) {
1970 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1971 int cfgid = nla_type(a);
1972
1973 if (nla_len(a) < 4)
1974 return -EINVAL;
1975
1976 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1977 return -EINVAL;
1978 }
1979 }
1980
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001981 return 0;
1982}
1983
Stephen Hemminger3583a4e2021-04-07 08:59:12 -07001984static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla,
1985 struct netlink_ext_ack *extack)
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001986{
Cong Wanga1002432021-05-08 11:00:33 -07001987 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001988 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1989 int rem;
1990
1991 if (!in_dev)
1992 return -EAFNOSUPPORT;
1993
Johannes Berg8cb08172019-04-26 14:07:28 +02001994 if (nla_parse_nested_deprecated(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0)
Zheng Yongjun5ac6b192021-06-08 09:53:15 +08001995 return -EINVAL;
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001996
Thomas Graf9f0f7272010-11-16 04:32:48 +00001997 if (tb[IFLA_INET_CONF]) {
1998 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1999 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
2000 }
2001
2002 return 0;
2003}
2004
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002005static int inet_netconf_msgsize_devconf(int type)
2006{
2007 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
2008 + nla_total_size(4); /* NETCONFA_IFINDEX */
Zhang Shengju136ba622016-03-10 08:55:50 +00002009 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002010
Zhang Shengju136ba622016-03-10 08:55:50 +00002011 if (type == NETCONFA_ALL)
2012 all = true;
2013
2014 if (all || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002015 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00002016 if (all || type == NETCONFA_RP_FILTER)
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002017 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00002018 if (all || type == NETCONFA_MC_FORWARDING)
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00002019 size += nla_total_size(4);
Xin Long5cbf7772018-07-27 16:37:28 +08002020 if (all || type == NETCONFA_BC_FORWARDING)
2021 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00002022 if (all || type == NETCONFA_PROXY_NEIGH)
stephen hemmingerf085ff12013-12-12 13:06:50 -08002023 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00002024 if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002025 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002026
2027 return size;
2028}
2029
2030static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
2031 struct ipv4_devconf *devconf, u32 portid,
2032 u32 seq, int event, unsigned int flags,
2033 int type)
2034{
2035 struct nlmsghdr *nlh;
2036 struct netconfmsg *ncm;
Zhang Shengju136ba622016-03-10 08:55:50 +00002037 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002038
2039 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
2040 flags);
Ian Morris51456b22015-04-03 09:17:26 +01002041 if (!nlh)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002042 return -EMSGSIZE;
2043
Zhang Shengju136ba622016-03-10 08:55:50 +00002044 if (type == NETCONFA_ALL)
2045 all = true;
2046
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002047 ncm = nlmsg_data(nlh);
2048 ncm->ncm_family = AF_INET;
2049
2050 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
2051 goto nla_put_failure;
2052
David Ahernb5c96412017-03-28 14:28:03 -07002053 if (!devconf)
2054 goto out;
2055
Zhang Shengju136ba622016-03-10 08:55:50 +00002056 if ((all || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002057 nla_put_s32(skb, NETCONFA_FORWARDING,
2058 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
2059 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00002060 if ((all || type == NETCONFA_RP_FILTER) &&
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002061 nla_put_s32(skb, NETCONFA_RP_FILTER,
2062 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
2063 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00002064 if ((all || type == NETCONFA_MC_FORWARDING) &&
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00002065 nla_put_s32(skb, NETCONFA_MC_FORWARDING,
2066 IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
2067 goto nla_put_failure;
Xin Long5cbf7772018-07-27 16:37:28 +08002068 if ((all || type == NETCONFA_BC_FORWARDING) &&
2069 nla_put_s32(skb, NETCONFA_BC_FORWARDING,
2070 IPV4_DEVCONF(*devconf, BC_FORWARDING)) < 0)
2071 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00002072 if ((all || type == NETCONFA_PROXY_NEIGH) &&
stephen hemminger09aea5d2013-12-17 22:35:52 -08002073 nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002074 IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
2075 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00002076 if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002077 nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
2078 IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
2079 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002080
David Ahernb5c96412017-03-28 14:28:03 -07002081out:
Johannes Berg053c0952015-01-16 22:09:00 +01002082 nlmsg_end(skb, nlh);
2083 return 0;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002084
2085nla_put_failure:
2086 nlmsg_cancel(skb, nlh);
2087 return -EMSGSIZE;
2088}
2089
David Ahern3b022862017-03-28 14:28:02 -07002090void inet_netconf_notify_devconf(struct net *net, int event, int type,
2091 int ifindex, struct ipv4_devconf *devconf)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002092{
2093 struct sk_buff *skb;
2094 int err = -ENOBUFS;
2095
Eric Dumazetfa178062016-07-08 05:18:24 +02002096 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002097 if (!skb)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002098 goto errout;
2099
2100 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
David Ahern3b022862017-03-28 14:28:02 -07002101 event, 0, type);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002102 if (err < 0) {
2103 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
2104 WARN_ON(err == -EMSGSIZE);
2105 kfree_skb(skb);
2106 goto errout;
2107 }
Eric Dumazetfa178062016-07-08 05:18:24 +02002108 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002109 return;
2110errout:
2111 if (err < 0)
2112 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
2113}
2114
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002115static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
2116 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
2117 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002118 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
stephen hemminger09aea5d2013-12-17 22:35:52 -08002119 [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) },
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002120 [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002121};
2122
Jakub Kicinskieede3702019-01-18 10:46:18 -08002123static int inet_netconf_valid_get_req(struct sk_buff *skb,
2124 const struct nlmsghdr *nlh,
2125 struct nlattr **tb,
2126 struct netlink_ext_ack *extack)
2127{
2128 int i, err;
2129
2130 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(struct netconfmsg))) {
2131 NL_SET_ERR_MSG(extack, "ipv4: Invalid header for netconf get request");
2132 return -EINVAL;
2133 }
2134
2135 if (!netlink_strict_get_check(skb))
Johannes Berg8cb08172019-04-26 14:07:28 +02002136 return nlmsg_parse_deprecated(nlh, sizeof(struct netconfmsg),
2137 tb, NETCONFA_MAX,
2138 devconf_ipv4_policy, extack);
Jakub Kicinskieede3702019-01-18 10:46:18 -08002139
Johannes Berg8cb08172019-04-26 14:07:28 +02002140 err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct netconfmsg),
2141 tb, NETCONFA_MAX,
2142 devconf_ipv4_policy, extack);
Jakub Kicinskieede3702019-01-18 10:46:18 -08002143 if (err)
2144 return err;
2145
2146 for (i = 0; i <= NETCONFA_MAX; i++) {
2147 if (!tb[i])
2148 continue;
2149
2150 switch (i) {
2151 case NETCONFA_IFINDEX:
2152 break;
2153 default:
2154 NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in netconf get request");
2155 return -EINVAL;
2156 }
2157 }
2158
2159 return 0;
2160}
2161
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002162static int inet_netconf_get_devconf(struct sk_buff *in_skb,
David Ahernc21ef3e2017-04-16 09:48:24 -07002163 struct nlmsghdr *nlh,
2164 struct netlink_ext_ack *extack)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002165{
2166 struct net *net = sock_net(in_skb->sk);
2167 struct nlattr *tb[NETCONFA_MAX+1];
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002168 struct sk_buff *skb;
2169 struct ipv4_devconf *devconf;
2170 struct in_device *in_dev;
2171 struct net_device *dev;
2172 int ifindex;
2173 int err;
2174
Jakub Kicinskieede3702019-01-18 10:46:18 -08002175 err = inet_netconf_valid_get_req(in_skb, nlh, tb, extack);
2176 if (err)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002177 goto errout;
2178
Anton Protopopova97eb332016-02-16 21:43:16 -05002179 err = -EINVAL;
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002180 if (!tb[NETCONFA_IFINDEX])
2181 goto errout;
2182
2183 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
2184 switch (ifindex) {
2185 case NETCONFA_IFINDEX_ALL:
2186 devconf = net->ipv4.devconf_all;
2187 break;
2188 case NETCONFA_IFINDEX_DEFAULT:
2189 devconf = net->ipv4.devconf_dflt;
2190 break;
2191 default:
2192 dev = __dev_get_by_index(net, ifindex);
Ian Morris51456b22015-04-03 09:17:26 +01002193 if (!dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002194 goto errout;
2195 in_dev = __in_dev_get_rtnl(dev);
Ian Morris51456b22015-04-03 09:17:26 +01002196 if (!in_dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002197 goto errout;
2198 devconf = &in_dev->cnf;
2199 break;
2200 }
2201
2202 err = -ENOBUFS;
Eric Dumazetfa178062016-07-08 05:18:24 +02002203 skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002204 if (!skb)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002205 goto errout;
2206
2207 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
2208 NETLINK_CB(in_skb).portid,
2209 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
Zhang Shengju136ba622016-03-10 08:55:50 +00002210 NETCONFA_ALL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002211 if (err < 0) {
2212 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
2213 WARN_ON(err == -EMSGSIZE);
2214 kfree_skb(skb);
2215 goto errout;
2216 }
2217 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
2218errout:
2219 return err;
2220}
2221
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002222static int inet_netconf_dump_devconf(struct sk_buff *skb,
2223 struct netlink_callback *cb)
2224{
David Ahernaddd3832018-10-07 20:16:41 -07002225 const struct nlmsghdr *nlh = cb->nlh;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002226 struct net *net = sock_net(skb->sk);
2227 int h, s_h;
2228 int idx, s_idx;
2229 struct net_device *dev;
2230 struct in_device *in_dev;
2231 struct hlist_head *head;
2232
David Ahernaddd3832018-10-07 20:16:41 -07002233 if (cb->strict_check) {
2234 struct netlink_ext_ack *extack = cb->extack;
2235 struct netconfmsg *ncm;
2236
2237 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ncm))) {
2238 NL_SET_ERR_MSG(extack, "ipv4: Invalid header for netconf dump request");
2239 return -EINVAL;
2240 }
2241
2242 if (nlmsg_attrlen(nlh, sizeof(*ncm))) {
2243 NL_SET_ERR_MSG(extack, "ipv4: Invalid data after header in netconf dump request");
2244 return -EINVAL;
2245 }
2246 }
2247
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002248 s_h = cb->args[0];
2249 s_idx = idx = cb->args[1];
2250
2251 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
2252 idx = 0;
2253 head = &net->dev_index_head[h];
2254 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00002255 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
2256 net->dev_base_seq;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002257 hlist_for_each_entry_rcu(dev, head, index_hlist) {
2258 if (idx < s_idx)
2259 goto cont;
2260 in_dev = __in_dev_get_rcu(dev);
2261 if (!in_dev)
2262 goto cont;
2263
2264 if (inet_netconf_fill_devconf(skb, dev->ifindex,
2265 &in_dev->cnf,
2266 NETLINK_CB(cb->skb).portid,
David Ahernaddd3832018-10-07 20:16:41 -07002267 nlh->nlmsg_seq,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002268 RTM_NEWNETCONF,
2269 NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002270 NETCONFA_ALL) < 0) {
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002271 rcu_read_unlock();
2272 goto done;
2273 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00002274 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002275cont:
2276 idx++;
2277 }
2278 rcu_read_unlock();
2279 }
2280 if (h == NETDEV_HASHENTRIES) {
2281 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
2282 net->ipv4.devconf_all,
2283 NETLINK_CB(cb->skb).portid,
David Ahernaddd3832018-10-07 20:16:41 -07002284 nlh->nlmsg_seq,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002285 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002286 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002287 goto done;
2288 else
2289 h++;
2290 }
2291 if (h == NETDEV_HASHENTRIES + 1) {
2292 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
2293 net->ipv4.devconf_dflt,
2294 NETLINK_CB(cb->skb).portid,
David Ahernaddd3832018-10-07 20:16:41 -07002295 nlh->nlmsg_seq,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002296 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002297 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002298 goto done;
2299 else
2300 h++;
2301 }
2302done:
2303 cb->args[0] = h;
2304 cb->args[1] = idx;
2305
2306 return skb->len;
2307}
2308
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309#ifdef CONFIG_SYSCTL
2310
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002311static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07002312{
2313 struct net_device *dev;
2314
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002315 rcu_read_lock();
2316 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07002317 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002318
Herbert Xu31be3082007-06-04 23:35:37 -07002319 in_dev = __in_dev_get_rcu(dev);
2320 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002321 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07002322 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002323 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07002324}
2325
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002326/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002327static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002328{
2329 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002330 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002331
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002332 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002333 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
David Ahern3b022862017-03-28 14:28:02 -07002334 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2335 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002336 NETCONFA_IFINDEX_ALL,
2337 net->ipv4.devconf_all);
David Ahern3b022862017-03-28 14:28:02 -07002338 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2339 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002340 NETCONFA_IFINDEX_DEFAULT,
2341 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002342
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002343 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002344 struct in_device *in_dev;
Eric Dumazetfa178062016-07-08 05:18:24 +02002345
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002346 if (on)
2347 dev_disable_lro(dev);
Eric Dumazetfa178062016-07-08 05:18:24 +02002348
2349 in_dev = __in_dev_get_rtnl(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002350 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002351 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
David Ahern3b022862017-03-28 14:28:02 -07002352 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2353 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002354 dev->ifindex, &in_dev->cnf);
2355 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002356 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002357}
2358
stephen hemmingerf085ff12013-12-12 13:06:50 -08002359static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf)
2360{
2361 if (cnf == net->ipv4.devconf_dflt)
2362 return NETCONFA_IFINDEX_DEFAULT;
2363 else if (cnf == net->ipv4.devconf_all)
2364 return NETCONFA_IFINDEX_ALL;
2365 else {
2366 struct in_device *idev
2367 = container_of(cnf, struct in_device, cnf);
2368 return idev->dev->ifindex;
2369 }
2370}
2371
Joe Perchesfe2c6332013-06-11 23:04:25 -07002372static int devinet_conf_proc(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02002373 void *buffer, size_t *lenp, loff_t *ppos)
Herbert Xu31be3082007-06-04 23:35:37 -07002374{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002375 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002376 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002377 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07002378
2379 if (write) {
2380 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002381 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07002382 int i = (int *)ctl->data - cnf->data;
stephen hemmingerf085ff12013-12-12 13:06:50 -08002383 int ifindex;
Herbert Xu31be3082007-06-04 23:35:37 -07002384
2385 set_bit(i, cnf->state);
2386
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002387 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002388 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00002389 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
2390 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002391 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002392 rt_cache_flush(net);
stephen hemmingerf085ff12013-12-12 13:06:50 -08002393
Xin Long5cbf7772018-07-27 16:37:28 +08002394 if (i == IPV4_DEVCONF_BC_FORWARDING - 1 &&
2395 new_value != old_value)
2396 rt_cache_flush(net);
2397
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002398 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
2399 new_value != old_value) {
stephen hemmingerf085ff12013-12-12 13:06:50 -08002400 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002401 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2402 NETCONFA_RP_FILTER,
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002403 ifindex, cnf);
2404 }
stephen hemmingerf085ff12013-12-12 13:06:50 -08002405 if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
2406 new_value != old_value) {
2407 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002408 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2409 NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002410 ifindex, cnf);
2411 }
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002412 if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
2413 new_value != old_value) {
2414 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002415 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2416 NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002417 ifindex, cnf);
2418 }
Herbert Xu31be3082007-06-04 23:35:37 -07002419 }
2420
2421 return ret;
2422}
2423
Joe Perchesfe2c6332013-06-11 23:04:25 -07002424static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02002425 void *buffer, size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426{
2427 int *valp = ctl->data;
2428 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00002429 loff_t pos = *ppos;
Yang Yang8292d7f2021-07-19 18:43:28 -07002430 struct net *net = ctl->extra2;
2431 int ret;
2432
2433 if (write && !ns_capable(net->user_ns, CAP_NET_ADMIN))
2434 return -EPERM;
2435
2436 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
2438 if (write && *valp != val) {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002439 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00002440 if (!rtnl_trylock()) {
2441 /* Restore the original values before restarting */
2442 *valp = val;
2443 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00002444 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00002445 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002446 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2447 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002448 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002449 struct ipv4_devconf *cnf = ctl->extra1;
2450 struct in_device *idev =
2451 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002452 if (*valp)
2453 dev_disable_lro(idev->dev);
David Ahern3b022862017-03-28 14:28:02 -07002454 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002455 NETCONFA_FORWARDING,
2456 idev->dev->ifindex,
2457 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002458 }
2459 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002460 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002461 } else
David Ahern3b022862017-03-28 14:28:02 -07002462 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2463 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002464 NETCONFA_IFINDEX_DEFAULT,
2465 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 }
2467
2468 return ret;
2469}
2470
Joe Perchesfe2c6332013-06-11 23:04:25 -07002471static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02002472 void *buffer, size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473{
2474 int *valp = ctl->data;
2475 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002476 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07002477 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478
2479 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002480 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481
2482 return ret;
2483}
2484
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002485#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07002486 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07002487 .procname = name, \
2488 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00002489 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002490 .maxlen = sizeof(int), \
2491 .mode = mval, \
2492 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07002493 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002494 }
2495
2496#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002497 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002498
2499#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002500 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002501
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002502#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2503 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002504
2505#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002506 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07002507
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508static struct devinet_sysctl_table {
2509 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00002510 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511} devinet_sysctl = {
2512 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07002513 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002514 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07002515 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
Xin Long5cbf7772018-07-27 16:37:28 +08002516 DEVINET_SYSCTL_RW_ENTRY(BC_FORWARDING, "bc_forwarding"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002517
2518 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
2519 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
2520 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
2521 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
2522 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
2523 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
2524 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00002525 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08002526 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002527 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
2528 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
2529 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
2530 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
2531 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
2532 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
2533 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
2534 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
2535 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08002536 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
James Prestwoodfcdb44d2021-11-01 10:36:28 -07002537 DEVINET_SYSCTL_RW_ENTRY(ARP_EVICT_NOCARRIER,
2538 "arp_evict_nocarrier"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00002539 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
William Manley5c6fe012013-08-06 19:03:14 +01002540 DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
2541 "force_igmp_version"),
William Manley26900482013-08-06 19:03:15 +01002542 DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
2543 "igmpv2_unsolicited_report_interval"),
2544 DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
2545 "igmpv3_unsolicited_report_interval"),
Andy Gospodarek0eeb0752015-06-23 13:45:37 -04002546 DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
2547 "ignore_routes_with_linkdown"),
Johannes Berg97daf332016-02-04 13:31:18 +01002548 DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
2549 "drop_gratuitous_arp"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002550
2551 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2552 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002553 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
2554 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00002555 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2556 "route_localnet"),
Johannes Berg12b74df2016-02-04 13:31:17 +01002557 DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
2558 "drop_unicast_in_l2_multicast"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560};
2561
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002562static int __devinet_sysctl_register(struct net *net, char *dev_name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002563 int ifindex, struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564{
2565 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002566 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002567 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11002568
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002569 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002571 goto out;
2572
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
2574 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07002575 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002576 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 }
2578
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002579 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002581 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002583 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584
2585 p->sysctl = t;
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002586
David Ahern3b022862017-03-28 14:28:02 -07002587 inet_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_ALL,
2588 ifindex, p);
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002589 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002591free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002593out:
liuguoqiang6def4802021-11-15 16:14:48 +08002594 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595}
2596
David Ahernb5c96412017-03-28 14:28:03 -07002597static void __devinet_sysctl_unregister(struct net *net,
2598 struct ipv4_devconf *cnf, int ifindex)
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002599{
2600 struct devinet_sysctl_table *t = cnf->sysctl;
2601
David Ahernb5c96412017-03-28 14:28:03 -07002602 if (t) {
2603 cnf->sysctl = NULL;
2604 unregister_net_sysctl_table(t->sysctl_header);
2605 kfree(t);
2606 }
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002607
David Ahernb5c96412017-03-28 14:28:03 -07002608 inet_netconf_notify_devconf(net, RTM_DELNETCONF, 0, ifindex, NULL);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002609}
2610
WANG Cong20e61da2014-07-25 15:25:08 -07002611static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002612{
WANG Cong20e61da2014-07-25 15:25:08 -07002613 int err;
2614
2615 if (!sysctl_dev_name_is_allowed(idev->dev->name))
2616 return -EINVAL;
2617
2618 err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
2619 if (err)
2620 return err;
2621 err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002622 idev->dev->ifindex, &idev->cnf);
WANG Cong20e61da2014-07-25 15:25:08 -07002623 if (err)
2624 neigh_sysctl_unregister(idev->arp_parms);
2625 return err;
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002626}
2627
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002628static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629{
David Ahernb5c96412017-03-28 14:28:03 -07002630 struct net *net = dev_net(idev->dev);
2631
2632 __devinet_sysctl_unregister(net, &idev->cnf, idev->dev->ifindex);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002633 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002636static struct ctl_table ctl_forward_entry[] = {
2637 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002638 .procname = "ip_forward",
2639 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00002640 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002641 .maxlen = sizeof(int),
2642 .mode = 0644,
2643 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002644 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002645 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002646 },
2647 { },
2648};
Eric Dumazet2a75de02008-01-05 23:08:49 -08002649#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002650
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002651static __net_init int devinet_init_net(struct net *net)
2652{
2653 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002654 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002655#ifdef CONFIG_SYSCTL
Cong Wang856c3952019-01-17 23:27:11 -08002656 struct ctl_table *tbl;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002657 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002658#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002659
2660 err = -ENOMEM;
Cong Wang856c3952019-01-17 23:27:11 -08002661 all = kmemdup(&ipv4_devconf, sizeof(ipv4_devconf), GFP_KERNEL);
2662 if (!all)
2663 goto err_alloc_all;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002664
Cong Wang856c3952019-01-17 23:27:11 -08002665 dflt = kmemdup(&ipv4_devconf_dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
2666 if (!dflt)
2667 goto err_alloc_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002668
Eric Dumazet2a75de02008-01-05 23:08:49 -08002669#ifdef CONFIG_SYSCTL
Cong Wang856c3952019-01-17 23:27:11 -08002670 tbl = kmemdup(ctl_forward_entry, sizeof(ctl_forward_entry), GFP_KERNEL);
2671 if (!tbl)
2672 goto err_alloc_ctl;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002673
Cong Wang856c3952019-01-17 23:27:11 -08002674 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
2675 tbl[0].extra1 = all;
2676 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002677#endif
Cong Wang856c3952019-01-17 23:27:11 -08002678
Nicolas Dichtel9efd6a32020-05-13 15:58:43 +02002679 if (!net_eq(net, &init_net)) {
2680 if (IS_ENABLED(CONFIG_SYSCTL) &&
2681 sysctl_devconf_inherit_init_net == 3) {
2682 /* copy from the current netns */
2683 memcpy(all, current->nsproxy->net_ns->ipv4.devconf_all,
2684 sizeof(ipv4_devconf));
2685 memcpy(dflt,
2686 current->nsproxy->net_ns->ipv4.devconf_dflt,
2687 sizeof(ipv4_devconf_dflt));
2688 } else if (!IS_ENABLED(CONFIG_SYSCTL) ||
2689 sysctl_devconf_inherit_init_net != 2) {
2690 /* inherit == 0 or 1: copy from init_net */
2691 memcpy(all, init_net.ipv4.devconf_all,
2692 sizeof(ipv4_devconf));
2693 memcpy(dflt, init_net.ipv4.devconf_dflt,
2694 sizeof(ipv4_devconf_dflt));
2695 }
2696 /* else inherit == 2: use compiled values */
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002697 }
2698
2699#ifdef CONFIG_SYSCTL
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002700 err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002701 if (err < 0)
2702 goto err_reg_all;
2703
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002704 err = __devinet_sysctl_register(net, "default",
2705 NETCONFA_IFINDEX_DEFAULT, dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002706 if (err < 0)
2707 goto err_reg_dflt;
2708
2709 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002710 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Ian Morris51456b22015-04-03 09:17:26 +01002711 if (!forw_hdr)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002712 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002713 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002714#endif
2715
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002716 net->ipv4.devconf_all = all;
2717 net->ipv4.devconf_dflt = dflt;
2718 return 0;
2719
2720#ifdef CONFIG_SYSCTL
2721err_reg_ctl:
David Ahernb5c96412017-03-28 14:28:03 -07002722 __devinet_sysctl_unregister(net, dflt, NETCONFA_IFINDEX_DEFAULT);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002723err_reg_dflt:
David Ahernb5c96412017-03-28 14:28:03 -07002724 __devinet_sysctl_unregister(net, all, NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002725err_reg_all:
Cong Wang856c3952019-01-17 23:27:11 -08002726 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002727err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08002728#endif
Cong Wang856c3952019-01-17 23:27:11 -08002729 kfree(dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002730err_alloc_dflt:
Cong Wang856c3952019-01-17 23:27:11 -08002731 kfree(all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002732err_alloc_all:
2733 return err;
2734}
2735
2736static __net_exit void devinet_exit_net(struct net *net)
2737{
Eric Dumazet2a75de02008-01-05 23:08:49 -08002738#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002739 struct ctl_table *tbl;
2740
2741 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002742 unregister_net_sysctl_table(net->ipv4.forw_hdr);
David Ahernb5c96412017-03-28 14:28:03 -07002743 __devinet_sysctl_unregister(net, net->ipv4.devconf_dflt,
2744 NETCONFA_IFINDEX_DEFAULT);
2745 __devinet_sysctl_unregister(net, net->ipv4.devconf_all,
2746 NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002747 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08002748#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002749 kfree(net->ipv4.devconf_dflt);
2750 kfree(net->ipv4.devconf_all);
2751}
2752
2753static __net_initdata struct pernet_operations devinet_ops = {
2754 .init = devinet_init_net,
2755 .exit = devinet_exit_net,
2756};
2757
Daniel Borkmann207895fd32015-01-29 12:15:03 +01002758static struct rtnl_af_ops inet_af_ops __read_mostly = {
Thomas Graf9f0f7272010-11-16 04:32:48 +00002759 .family = AF_INET,
2760 .fill_link_af = inet_fill_link_af,
2761 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00002762 .validate_link_af = inet_validate_link_af,
2763 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00002764};
2765
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766void __init devinet_init(void)
2767{
David S. Millerfd23c3b2011-02-18 12:42:28 -08002768 int i;
2769
2770 for (i = 0; i < IN4_ADDR_HSIZE; i++)
2771 INIT_HLIST_HEAD(&inet_addr_lst[i]);
2772
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002773 register_pernet_subsys(&devinet_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07002775
viresh kumar906e0732014-01-22 12:23:32 +05302776 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +00002777
Thomas Graf9f0f7272010-11-16 04:32:48 +00002778 rtnl_af_register(&inet_af_ops);
2779
Florian Westphalb97bac62017-08-09 20:41:48 +02002780 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, 0);
2781 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, 0);
2782 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, 0);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002783 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
Florian Westphalb97bac62017-08-09 20:41:48 +02002784 inet_netconf_dump_devconf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785}