blob: 67f382c560ba1453b7b73d77cf66fc98a3449b06 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * NET3 IP device support routines.
3 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Derived from the IP parts of dev.c 1.0.19
Jesper Juhl02c30a82005-05-05 16:16:16 -070010 * Authors: Ross Biro
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
12 * Mark Evans, <evansmp@uhura.aston.ac.uk>
13 *
14 * Additional Authors:
15 * Alan Cox, <gw4pts@gw4pts.ampr.org>
16 * Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
17 *
18 * Changes:
19 * Alexey Kuznetsov: pa_* fields are replaced with ifaddr
20 * lists.
21 * Cyrus Durgin: updated for kmod
22 * Matthias Andree: in devinet_ioctl, compare label and
23 * address (4.4BSD alias style support),
24 * fall back to comparing just the label
25 * if no match found.
26 */
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080029#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/bitops.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080031#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/module.h>
33#include <linux/types.h>
34#include <linux/kernel.h>
Ingo Molnar174cd4b2017-02-02 19:15:33 +010035#include <linux/sched/signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/string.h>
37#include <linux/mm.h>
38#include <linux/socket.h>
39#include <linux/sockios.h>
40#include <linux/in.h>
41#include <linux/errno.h>
42#include <linux/interrupt.h>
Thomas Graf18237302006-08-04 23:04:54 -070043#include <linux/if_addr.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/if_ether.h>
45#include <linux/inet.h>
46#include <linux/netdevice.h>
47#include <linux/etherdevice.h>
48#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/init.h>
50#include <linux/notifier.h>
51#include <linux/inetdevice.h>
52#include <linux/igmp.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090053#include <linux/slab.h>
David S. Millerfd23c3b2011-02-18 12:42:28 -080054#include <linux/hash.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#ifdef CONFIG_SYSCTL
56#include <linux/sysctl.h>
57#endif
58#include <linux/kmod.h>
Nicolas Dichteledc9e742012-10-25 22:28:52 +000059#include <linux/netconf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020061#include <net/arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <net/ip.h>
63#include <net/route.h>
64#include <net/ip_fib.h>
Thomas Graf63f34442007-03-22 11:55:17 -070065#include <net/rtnetlink.h>
Pavel Emelyanov752d14d2007-12-16 13:31:47 -080066#include <net/net_namespace.h>
Jiri Pirko5c766d62013-01-24 09:41:41 +000067#include <net/addrconf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Adrian Bunk0027ba82008-01-31 17:17:31 -080069static struct ipv4_devconf ipv4_devconf = {
Herbert Xu42f811b2007-06-04 23:34:44 -070070 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000071 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
72 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
73 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
74 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
William Manley26900482013-08-06 19:03:15 +010075 [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
76 [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
Herbert Xu42f811b2007-06-04 23:34:44 -070077 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070078};
79
80static struct ipv4_devconf ipv4_devconf_dflt = {
Herbert Xu42f811b2007-06-04 23:34:44 -070081 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000082 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
83 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
84 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
85 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
86 [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
William Manley26900482013-08-06 19:03:15 +010087 [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
88 [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
Herbert Xu42f811b2007-06-04 23:34:44 -070089 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070090};
91
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -080092#define IPV4_DEVCONF_DFLT(net, attr) \
93 IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr)
Herbert Xu42f811b2007-06-04 23:34:44 -070094
Patrick McHardyef7c79e2007-06-05 12:38:30 -070095static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
Thomas Graf5c753972006-08-04 23:03:53 -070096 [IFA_LOCAL] = { .type = NLA_U32 },
97 [IFA_ADDRESS] = { .type = NLA_U32 },
98 [IFA_BROADCAST] = { .type = NLA_U32 },
Thomas Graf5176f912006-08-26 20:13:18 -070099 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
Jiri Pirko5c766d62013-01-24 09:41:41 +0000100 [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100101 [IFA_FLAGS] = { .type = NLA_U32 },
David Ahernaf4d7682018-05-27 08:09:57 -0700102 [IFA_RT_PRIORITY] = { .type = NLA_U32 },
Christian Braunerd3807142018-09-04 21:53:49 +0200103 [IFA_TARGET_NETNSID] = { .type = NLA_S32 },
Thomas Graf5c753972006-08-04 23:03:53 -0700104};
105
Christian Brauner978a46f2018-09-04 21:53:54 +0200106struct inet_fill_args {
107 u32 portid;
108 u32 seq;
109 int event;
110 unsigned int flags;
111 int netnsid;
112};
113
Eric Dumazet40384992012-08-03 21:06:50 +0000114#define IN4_ADDR_HSIZE_SHIFT 8
115#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT)
116
David S. Millerfd23c3b2011-02-18 12:42:28 -0800117static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
David S. Millerfd23c3b2011-02-18 12:42:28 -0800118
Eric Dumazet6eada012015-03-18 14:05:33 -0700119static u32 inet_addr_hash(const struct net *net, __be32 addr)
David S. Millerfd23c3b2011-02-18 12:42:28 -0800120{
Eric Dumazet40384992012-08-03 21:06:50 +0000121 u32 val = (__force u32) addr ^ net_hash_mix(net);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800122
Eric Dumazet40384992012-08-03 21:06:50 +0000123 return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800124}
125
126static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
127{
Eric Dumazet40384992012-08-03 21:06:50 +0000128 u32 hash = inet_addr_hash(net, ifa->ifa_local);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800129
WANG Cong32a4be42014-05-06 11:15:56 -0700130 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800131 hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800132}
133
134static void inet_hash_remove(struct in_ifaddr *ifa)
135{
WANG Cong32a4be42014-05-06 11:15:56 -0700136 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800137 hlist_del_init_rcu(&ifa->hash);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800138}
139
David S. Miller9435eb12011-02-18 12:43:09 -0800140/**
141 * __ip_dev_find - find the first device with a given source address.
142 * @net: the net namespace
143 * @addr: the source address
144 * @devref: if true, take a reference on the found device
145 *
146 * If a caller uses devref=false, it should be protected by RCU, or RTNL
147 */
148struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
149{
David S. Miller9435eb12011-02-18 12:43:09 -0800150 struct net_device *result = NULL;
151 struct in_ifaddr *ifa;
David S. Miller9435eb12011-02-18 12:43:09 -0800152
153 rcu_read_lock();
Paolo Abeni6e617de2017-09-20 18:26:53 +0200154 ifa = inet_lookup_ifaddr_rcu(net, addr);
155 if (!ifa) {
David S. Miller406b6f92011-03-22 21:56:23 -0700156 struct flowi4 fl4 = { .daddr = addr };
157 struct fib_result res = { 0 };
158 struct fib_table *local;
159
160 /* Fallback to FIB local table so that communication
161 * over loopback subnets work.
162 */
163 local = fib_get_table(net, RT_TABLE_LOCAL);
164 if (local &&
165 !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
166 res.type == RTN_LOCAL)
167 result = FIB_RES_DEV(res);
Paolo Abeni6e617de2017-09-20 18:26:53 +0200168 } else {
169 result = ifa->ifa_dev->dev;
David S. Miller406b6f92011-03-22 21:56:23 -0700170 }
David S. Miller9435eb12011-02-18 12:43:09 -0800171 if (result && devref)
172 dev_hold(result);
173 rcu_read_unlock();
174 return result;
175}
176EXPORT_SYMBOL(__ip_dev_find);
177
Paolo Abeni6e617de2017-09-20 18:26:53 +0200178/* called under RCU lock */
179struct in_ifaddr *inet_lookup_ifaddr_rcu(struct net *net, __be32 addr)
180{
181 u32 hash = inet_addr_hash(net, addr);
182 struct in_ifaddr *ifa;
183
184 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash)
185 if (ifa->ifa_local == addr &&
186 net_eq(dev_net(ifa->ifa_dev->dev), net))
187 return ifa;
188
189 return NULL;
190}
191
Thomas Grafd6062cb2006-08-15 00:33:59 -0700192static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Alan Sterne041c682006-03-27 01:16:30 -0800194static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Krister Johansen3ad7d242017-06-08 13:12:14 -0700195static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
197 int destroy);
198#ifdef CONFIG_SYSCTL
WANG Cong20e61da2014-07-25 15:25:08 -0700199static int devinet_sysctl_register(struct in_device *idev);
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800200static void devinet_sysctl_unregister(struct in_device *idev);
201#else
WANG Cong20e61da2014-07-25 15:25:08 -0700202static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800203{
WANG Cong20e61da2014-07-25 15:25:08 -0700204 return 0;
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800205}
Eric Dumazet40384992012-08-03 21:06:50 +0000206static void devinet_sysctl_unregister(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800207{
208}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209#endif
210
211/* Locks all the inet devices. */
212
213static struct in_ifaddr *inet_alloc_ifa(void)
214{
Alexey Dobriyan93adcc82008-10-28 13:25:09 -0700215 return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216}
217
218static void inet_rcu_free_ifa(struct rcu_head *head)
219{
220 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
221 if (ifa->ifa_dev)
222 in_dev_put(ifa->ifa_dev);
223 kfree(ifa);
224}
225
Eric Dumazet40384992012-08-03 21:06:50 +0000226static void inet_free_ifa(struct in_ifaddr *ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227{
228 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
229}
230
231void in_dev_finish_destroy(struct in_device *idev)
232{
233 struct net_device *dev = idev->dev;
234
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700235 WARN_ON(idev->ifa_list);
236 WARN_ON(idev->mc_list);
Eric Dumazete9897072013-06-07 08:48:57 -0700237 kfree(rcu_dereference_protected(idev->mc_hash, 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238#ifdef NET_REFCNT_DEBUG
Joe Perches91df42b2012-05-15 14:11:54 +0000239 pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240#endif
241 dev_put(dev);
242 if (!idev->dead)
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800243 pr_err("Freeing alive in_device %p\n", idev);
244 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 kfree(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800247EXPORT_SYMBOL(in_dev_finish_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Herbert Xu71e27da2007-06-04 23:36:06 -0700249static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250{
251 struct in_device *in_dev;
WANG Cong20e61da2014-07-25 15:25:08 -0700252 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
254 ASSERT_RTNL();
255
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700256 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 if (!in_dev)
258 goto out;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900259 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -0800260 sizeof(in_dev->cnf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 in_dev->cnf.sysctl = NULL;
262 in_dev->dev = dev;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800263 in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
264 if (!in_dev->arp_parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 goto out_kfree;
Ben Hutchings0187bdf2008-06-19 16:15:47 -0700266 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
267 dev_disable_lro(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 /* Reference in_dev->dev */
269 dev_hold(dev);
David L Stevens30c4cf52007-01-04 12:31:14 -0800270 /* Account for reference dev->ip_ptr (below) */
Reshetova, Elena7658b362017-06-30 13:08:03 +0300271 refcount_set(&in_dev->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
WANG Cong20e61da2014-07-25 15:25:08 -0700273 err = devinet_sysctl_register(in_dev);
274 if (err) {
275 in_dev->dead = 1;
276 in_dev_put(in_dev);
277 in_dev = NULL;
278 goto out;
279 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 ip_mc_init_dev(in_dev);
281 if (dev->flags & IFF_UP)
282 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800283
David L Stevens30c4cf52007-01-04 12:31:14 -0800284 /* we can receive as soon as ip_ptr is set -- do this last */
Eric Dumazetcf778b02012-01-12 04:41:32 +0000285 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800286out:
WANG Cong20e61da2014-07-25 15:25:08 -0700287 return in_dev ?: ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288out_kfree:
289 kfree(in_dev);
290 in_dev = NULL;
291 goto out;
292}
293
294static void in_dev_rcu_put(struct rcu_head *head)
295{
296 struct in_device *idev = container_of(head, struct in_device, rcu_head);
297 in_dev_put(idev);
298}
299
300static void inetdev_destroy(struct in_device *in_dev)
301{
302 struct in_ifaddr *ifa;
303 struct net_device *dev;
304
305 ASSERT_RTNL();
306
307 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309 in_dev->dead = 1;
310
311 ip_mc_destroy_dev(in_dev);
312
313 while ((ifa = in_dev->ifa_list) != NULL) {
314 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
315 inet_free_ifa(ifa);
316 }
317
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000318 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800320 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
322 arp_ifdown(dev);
323
324 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
325}
326
Al Viroff428d72006-09-26 22:13:35 -0700327int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328{
329 rcu_read_lock();
330 for_primary_ifa(in_dev) {
331 if (inet_ifa_match(a, ifa)) {
332 if (!b || inet_ifa_match(b, ifa)) {
333 rcu_read_unlock();
334 return 1;
335 }
336 }
337 } endfor_ifa(in_dev);
338 rcu_read_unlock();
339 return 0;
340}
341
Thomas Grafd6062cb2006-08-15 00:33:59 -0700342static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000343 int destroy, struct nlmsghdr *nlh, u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
Harald Welte8f937c62005-05-29 20:23:46 -0700345 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800346 struct in_ifaddr *ifa, *ifa1 = *ifap;
347 struct in_ifaddr *last_prim = in_dev->ifa_list;
348 struct in_ifaddr *prev_prom = NULL;
349 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
351 ASSERT_RTNL();
352
David S. Millerfbd40ea2016-03-13 23:28:00 -0400353 if (in_dev->dead)
354 goto no_promotions;
355
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900356 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700357 * unless alias promotion is set
358 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
360 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
362
363 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900364 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800365 ifa1->ifa_scope <= ifa->ifa_scope)
366 last_prim = ifa;
367
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
369 ifa1->ifa_mask != ifa->ifa_mask ||
370 !inet_ifa_match(ifa1->ifa_address, ifa)) {
371 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800372 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 continue;
374 }
375
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800376 if (!do_promote) {
David S. Millerfd23c3b2011-02-18 12:42:28 -0800377 inet_hash_remove(ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700378 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
Eric W. Biederman15e47302012-09-07 20:12:54 +0000380 rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800381 blocking_notifier_call_chain(&inetaddr_chain,
382 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700383 inet_free_ifa(ifa);
384 } else {
385 promote = ifa;
386 break;
387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 }
389 }
390
Julian Anastasov2d230e22011-03-19 12:13:52 +0000391 /* On promotion all secondaries from subnet are changing
392 * the primary IP, we must remove all their routes silently
393 * and later to add them back with new prefsrc. Do this
394 * while all addresses are on the device list.
395 */
396 for (ifa = promote; ifa; ifa = ifa->ifa_next) {
397 if (ifa1->ifa_mask == ifa->ifa_mask &&
398 inet_ifa_match(ifa1->ifa_address, ifa))
399 fib_del_ifaddr(ifa, ifa1);
400 }
401
David S. Millerfbd40ea2016-03-13 23:28:00 -0400402no_promotions:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 /* 2. Unlink it */
404
405 *ifap = ifa1->ifa_next;
David S. Millerfd23c3b2011-02-18 12:42:28 -0800406 inet_hash_remove(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407
408 /* 3. Announce address deletion */
409
410 /* Send message first, then call notifier.
411 At first sight, FIB update triggered by notifier
412 will refer to already deleted ifaddr, that could confuse
413 netlink listeners. It is not true: look, gated sees
414 that route deleted and if it still thinks that ifaddr
415 is valid, it will try to restore deleted routes... Grr.
416 So that, this order is correct.
417 */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000418 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800419 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800420
421 if (promote) {
Julian Anastasov04024b92011-03-19 12:13:54 +0000422 struct in_ifaddr *next_sec = promote->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800423
424 if (prev_prom) {
425 prev_prom->ifa_next = promote->ifa_next;
426 promote->ifa_next = last_prim->ifa_next;
427 last_prim->ifa_next = promote;
428 }
429
430 promote->ifa_flags &= ~IFA_F_SECONDARY;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000431 rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800432 blocking_notifier_call_chain(&inetaddr_chain,
433 NETDEV_UP, promote);
Julian Anastasov04024b92011-03-19 12:13:54 +0000434 for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800435 if (ifa1->ifa_mask != ifa->ifa_mask ||
436 !inet_ifa_match(ifa1->ifa_address, ifa))
437 continue;
438 fib_add_ifaddr(ifa);
439 }
440
441 }
Herbert Xu63630972007-06-07 18:35:38 -0700442 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444}
445
Thomas Grafd6062cb2006-08-15 00:33:59 -0700446static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
447 int destroy)
448{
449 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
450}
451
Jiri Pirko5c766d62013-01-24 09:41:41 +0000452static void check_lifetime(struct work_struct *work);
453
454static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
455
Thomas Grafd6062cb2006-08-15 00:33:59 -0700456static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
David Ahernde95e042017-10-18 09:56:54 -0700457 u32 portid, struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458{
459 struct in_device *in_dev = ifa->ifa_dev;
460 struct in_ifaddr *ifa1, **ifap, **last_primary;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700461 struct in_validator_info ivi;
462 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464 ASSERT_RTNL();
465
466 if (!ifa->ifa_local) {
467 inet_free_ifa(ifa);
468 return 0;
469 }
470
471 ifa->ifa_flags &= ~IFA_F_SECONDARY;
472 last_primary = &in_dev->ifa_list;
473
474 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
475 ifap = &ifa1->ifa_next) {
476 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
477 ifa->ifa_scope <= ifa1->ifa_scope)
478 last_primary = &ifa1->ifa_next;
479 if (ifa1->ifa_mask == ifa->ifa_mask &&
480 inet_ifa_match(ifa1->ifa_address, ifa)) {
481 if (ifa1->ifa_local == ifa->ifa_local) {
482 inet_free_ifa(ifa);
483 return -EEXIST;
484 }
485 if (ifa1->ifa_scope != ifa->ifa_scope) {
486 inet_free_ifa(ifa);
487 return -EINVAL;
488 }
489 ifa->ifa_flags |= IFA_F_SECONDARY;
490 }
491 }
492
Krister Johansen3ad7d242017-06-08 13:12:14 -0700493 /* Allow any devices that wish to register ifaddr validtors to weigh
494 * in now, before changes are committed. The rntl lock is serializing
495 * access here, so the state should not change between a validator call
496 * and a final notify on commit. This isn't invoked on promotion under
497 * the assumption that validators are checking the address itself, and
498 * not the flags.
499 */
500 ivi.ivi_addr = ifa->ifa_address;
501 ivi.ivi_dev = ifa->ifa_dev;
David Ahernde95e042017-10-18 09:56:54 -0700502 ivi.extack = extack;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700503 ret = blocking_notifier_call_chain(&inetaddr_validator_chain,
504 NETDEV_UP, &ivi);
505 ret = notifier_to_errno(ret);
506 if (ret) {
507 inet_free_ifa(ifa);
508 return ret;
509 }
510
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500512 prandom_seed((__force u32) ifa->ifa_local);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 ifap = last_primary;
514 }
515
516 ifa->ifa_next = *ifap;
517 *ifap = ifa;
518
David S. Millerfd23c3b2011-02-18 12:42:28 -0800519 inet_hash_insert(dev_net(in_dev->dev), ifa);
520
Jiri Pirko5c766d62013-01-24 09:41:41 +0000521 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530522 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 /* Send message first, then call notifier.
525 Notifier will trigger FIB update, so that
526 listeners of netlink will know about new ifaddr */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000527 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800528 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529
530 return 0;
531}
532
Thomas Grafd6062cb2006-08-15 00:33:59 -0700533static int inet_insert_ifa(struct in_ifaddr *ifa)
534{
David Ahernde95e042017-10-18 09:56:54 -0700535 return __inet_insert_ifa(ifa, NULL, 0, NULL);
Thomas Grafd6062cb2006-08-15 00:33:59 -0700536}
537
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
539{
Herbert Xue5ed6392005-10-03 14:35:55 -0700540 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
542 ASSERT_RTNL();
543
544 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700545 inet_free_ifa(ifa);
546 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700548 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100549 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700551 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 in_dev_hold(in_dev);
553 ifa->ifa_dev = in_dev;
554 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800555 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 ifa->ifa_scope = RT_SCOPE_HOST;
557 return inet_insert_ifa(ifa);
558}
559
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000560/* Caller must hold RCU or RTNL :
561 * We dont take a reference on found in_device
562 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800563struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564{
565 struct net_device *dev;
566 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000567
568 rcu_read_lock();
569 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000571 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000572 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 return in_dev;
574}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800575EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
577/* Called only from RTNL semaphored context. No locks. */
578
Al Viro60cad5d2006-09-26 22:17:09 -0700579struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
580 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581{
582 ASSERT_RTNL();
583
584 for_primary_ifa(in_dev) {
585 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
586 return ifa;
587 } endfor_ifa(in_dev);
588 return NULL;
589}
590
Madhu Challa93a714d2015-02-25 09:58:35 -0800591static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa)
592{
593 struct ip_mreqn mreq = {
594 .imr_multiaddr.s_addr = ifa->ifa_address,
595 .imr_ifindex = ifa->ifa_dev->dev->ifindex,
596 };
597 int ret;
598
599 ASSERT_RTNL();
600
601 lock_sock(sk);
602 if (join)
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300603 ret = ip_mc_join_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800604 else
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300605 ret = ip_mc_leave_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800606 release_sock(sk);
607
608 return ret;
609}
610
David Ahernc21ef3e2017-04-16 09:48:24 -0700611static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
612 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900614 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700615 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700617 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700619 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
621 ASSERT_RTNL();
622
Johannes Bergfceb6432017-04-12 14:34:07 +0200623 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -0700624 extack);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700625 if (err < 0)
626 goto errout;
627
628 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800629 in_dev = inetdev_by_index(net, ifm->ifa_index);
Ian Morris51456b22015-04-03 09:17:26 +0100630 if (!in_dev) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700631 err = -ENODEV;
632 goto errout;
633 }
634
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
636 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700637 if (tb[IFA_LOCAL] &&
Jiri Benc67b61f62015-03-29 16:59:26 +0200638 ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700640
641 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
642 continue;
643
644 if (tb[IFA_ADDRESS] &&
645 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Jiri Benc67b61f62015-03-29 16:59:26 +0200646 !inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700647 continue;
648
Madhu Challa93a714d2015-02-25 09:58:35 -0800649 if (ipv4_is_multicast(ifa->ifa_address))
650 ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000651 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 return 0;
653 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700654
655 err = -EADDRNOTAVAIL;
656errout:
657 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658}
659
Jiri Pirko5c766d62013-01-24 09:41:41 +0000660#define INFINITY_LIFE_TIME 0xFFFFFFFF
661
662static void check_lifetime(struct work_struct *work)
663{
664 unsigned long now, next, next_sec, next_sched;
665 struct in_ifaddr *ifa;
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000666 struct hlist_node *n;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000667 int i;
668
669 now = jiffies;
670 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
671
Jiri Pirko5c766d62013-01-24 09:41:41 +0000672 for (i = 0; i < IN4_ADDR_HSIZE; i++) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000673 bool change_needed = false;
674
675 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800676 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
Jiri Pirko5c766d62013-01-24 09:41:41 +0000677 unsigned long age;
678
679 if (ifa->ifa_flags & IFA_F_PERMANENT)
680 continue;
681
682 /* We try to batch several events at once. */
683 age = (now - ifa->ifa_tstamp +
684 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
685
686 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
687 age >= ifa->ifa_valid_lft) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000688 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000689 } else if (ifa->ifa_preferred_lft ==
690 INFINITY_LIFE_TIME) {
691 continue;
692 } else if (age >= ifa->ifa_preferred_lft) {
693 if (time_before(ifa->ifa_tstamp +
694 ifa->ifa_valid_lft * HZ, next))
695 next = ifa->ifa_tstamp +
696 ifa->ifa_valid_lft * HZ;
697
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000698 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
699 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000700 } else if (time_before(ifa->ifa_tstamp +
701 ifa->ifa_preferred_lft * HZ,
702 next)) {
703 next = ifa->ifa_tstamp +
704 ifa->ifa_preferred_lft * HZ;
705 }
706 }
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000707 rcu_read_unlock();
708 if (!change_needed)
709 continue;
710 rtnl_lock();
711 hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
712 unsigned long age;
713
714 if (ifa->ifa_flags & IFA_F_PERMANENT)
715 continue;
716
717 /* We try to batch several events at once. */
718 age = (now - ifa->ifa_tstamp +
719 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
720
721 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
722 age >= ifa->ifa_valid_lft) {
723 struct in_ifaddr **ifap;
724
725 for (ifap = &ifa->ifa_dev->ifa_list;
726 *ifap != NULL; ifap = &(*ifap)->ifa_next) {
727 if (*ifap == ifa) {
728 inet_del_ifa(ifa->ifa_dev,
729 ifap, 1);
730 break;
731 }
732 }
733 } else if (ifa->ifa_preferred_lft !=
734 INFINITY_LIFE_TIME &&
735 age >= ifa->ifa_preferred_lft &&
736 !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
737 ifa->ifa_flags |= IFA_F_DEPRECATED;
738 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
739 }
740 }
741 rtnl_unlock();
Jiri Pirko5c766d62013-01-24 09:41:41 +0000742 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000743
744 next_sec = round_jiffies_up(next);
745 next_sched = next;
746
747 /* If rounded timeout is accurate enough, accept it. */
748 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
749 next_sched = next_sec;
750
751 now = jiffies;
752 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
753 if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
754 next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
755
viresh kumar906e0732014-01-22 12:23:32 +0530756 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work,
757 next_sched - now);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000758}
759
760static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
761 __u32 prefered_lft)
762{
763 unsigned long timeout;
764
765 ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
766
767 timeout = addrconf_timeout_fixup(valid_lft, HZ);
768 if (addrconf_finite_timeout(timeout))
769 ifa->ifa_valid_lft = timeout;
770 else
771 ifa->ifa_flags |= IFA_F_PERMANENT;
772
773 timeout = addrconf_timeout_fixup(prefered_lft, HZ);
774 if (addrconf_finite_timeout(timeout)) {
775 if (timeout == 0)
776 ifa->ifa_flags |= IFA_F_DEPRECATED;
777 ifa->ifa_preferred_lft = timeout;
778 }
779 ifa->ifa_tstamp = jiffies;
780 if (!ifa->ifa_cstamp)
781 ifa->ifa_cstamp = ifa->ifa_tstamp;
782}
783
784static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
David Aherndac9c972018-10-07 20:16:24 -0700785 __u32 *pvalid_lft, __u32 *pprefered_lft,
786 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787{
Thomas Graf5c753972006-08-04 23:03:53 -0700788 struct nlattr *tb[IFA_MAX+1];
789 struct in_ifaddr *ifa;
790 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 struct net_device *dev;
792 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800793 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
Johannes Bergfceb6432017-04-12 14:34:07 +0200795 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
David Aherndac9c972018-10-07 20:16:24 -0700796 extack);
Thomas Graf5c753972006-08-04 23:03:53 -0700797 if (err < 0)
798 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
Thomas Graf5c753972006-08-04 23:03:53 -0700800 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800801 err = -EINVAL;
Ian Morris51456b22015-04-03 09:17:26 +0100802 if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL])
Thomas Graf5c753972006-08-04 23:03:53 -0700803 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800805 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800806 err = -ENODEV;
Ian Morris51456b22015-04-03 09:17:26 +0100807 if (!dev)
Thomas Graf5c753972006-08-04 23:03:53 -0700808 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
Thomas Graf5c753972006-08-04 23:03:53 -0700810 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800811 err = -ENOBUFS;
Ian Morris51456b22015-04-03 09:17:26 +0100812 if (!in_dev)
Herbert Xu71e27da2007-06-04 23:36:06 -0700813 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
Thomas Graf5c753972006-08-04 23:03:53 -0700815 ifa = inet_alloc_ifa();
Ian Morris51456b22015-04-03 09:17:26 +0100816 if (!ifa)
Thomas Graf5c753972006-08-04 23:03:53 -0700817 /*
818 * A potential indev allocation can be left alive, it stays
819 * assigned to its device and is destroy with it.
820 */
Thomas Graf5c753972006-08-04 23:03:53 -0700821 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700822
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800823 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100824 neigh_parms_data_state_setall(in_dev->arp_parms);
Thomas Graf5c753972006-08-04 23:03:53 -0700825 in_dev_hold(in_dev);
826
Ian Morris51456b22015-04-03 09:17:26 +0100827 if (!tb[IFA_ADDRESS])
Thomas Graf5c753972006-08-04 23:03:53 -0700828 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
829
David S. Millerfd23c3b2011-02-18 12:42:28 -0800830 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
832 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100833 ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
834 ifm->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700836 ifa->ifa_dev = in_dev;
837
Jiri Benc67b61f62015-03-29 16:59:26 +0200838 ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]);
839 ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700840
841 if (tb[IFA_BROADCAST])
Jiri Benc67b61f62015-03-29 16:59:26 +0200842 ifa->ifa_broadcast = nla_get_in_addr(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700843
Thomas Graf5c753972006-08-04 23:03:53 -0700844 if (tb[IFA_LABEL])
845 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 else
847 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
848
David Ahernaf4d7682018-05-27 08:09:57 -0700849 if (tb[IFA_RT_PRIORITY])
850 ifa->ifa_rt_priority = nla_get_u32(tb[IFA_RT_PRIORITY]);
851
Jiri Pirko5c766d62013-01-24 09:41:41 +0000852 if (tb[IFA_CACHEINFO]) {
853 struct ifa_cacheinfo *ci;
854
855 ci = nla_data(tb[IFA_CACHEINFO]);
856 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
857 err = -EINVAL;
Daniel Borkmann446266b2013-08-02 11:32:43 +0200858 goto errout_free;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000859 }
860 *pvalid_lft = ci->ifa_valid;
861 *pprefered_lft = ci->ifa_prefered;
862 }
863
Thomas Graf5c753972006-08-04 23:03:53 -0700864 return ifa;
865
Daniel Borkmann446266b2013-08-02 11:32:43 +0200866errout_free:
867 inet_free_ifa(ifa);
Thomas Graf5c753972006-08-04 23:03:53 -0700868errout:
869 return ERR_PTR(err);
870}
871
Jiri Pirko5c766d62013-01-24 09:41:41 +0000872static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
873{
874 struct in_device *in_dev = ifa->ifa_dev;
875 struct in_ifaddr *ifa1, **ifap;
876
877 if (!ifa->ifa_local)
878 return NULL;
879
880 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
881 ifap = &ifa1->ifa_next) {
882 if (ifa1->ifa_mask == ifa->ifa_mask &&
883 inet_ifa_match(ifa1->ifa_address, ifa) &&
884 ifa1->ifa_local == ifa->ifa_local)
885 return ifa1;
886 }
887 return NULL;
888}
889
David Ahernc21ef3e2017-04-16 09:48:24 -0700890static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
891 struct netlink_ext_ack *extack)
Thomas Graf5c753972006-08-04 23:03:53 -0700892{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900893 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700894 struct in_ifaddr *ifa;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000895 struct in_ifaddr *ifa_existing;
896 __u32 valid_lft = INFINITY_LIFE_TIME;
897 __u32 prefered_lft = INFINITY_LIFE_TIME;
Thomas Graf5c753972006-08-04 23:03:53 -0700898
899 ASSERT_RTNL();
900
David Aherndac9c972018-10-07 20:16:24 -0700901 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft, extack);
Thomas Graf5c753972006-08-04 23:03:53 -0700902 if (IS_ERR(ifa))
903 return PTR_ERR(ifa);
904
Jiri Pirko5c766d62013-01-24 09:41:41 +0000905 ifa_existing = find_matching_ifa(ifa);
906 if (!ifa_existing) {
907 /* It would be best to check for !NLM_F_CREATE here but
stephen hemminger614d0562014-05-16 20:46:58 -0700908 * userspace already relies on not having to provide this.
Jiri Pirko5c766d62013-01-24 09:41:41 +0000909 */
910 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Madhu Challa93a714d2015-02-25 09:58:35 -0800911 if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
912 int ret = ip_mc_config(net->ipv4.mc_autojoin_sk,
913 true, ifa);
914
915 if (ret < 0) {
916 inet_free_ifa(ifa);
917 return ret;
918 }
919 }
David Ahernde95e042017-10-18 09:56:54 -0700920 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid,
921 extack);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000922 } else {
David Ahernaf4d7682018-05-27 08:09:57 -0700923 u32 new_metric = ifa->ifa_rt_priority;
924
Jiri Pirko5c766d62013-01-24 09:41:41 +0000925 inet_free_ifa(ifa);
926
927 if (nlh->nlmsg_flags & NLM_F_EXCL ||
928 !(nlh->nlmsg_flags & NLM_F_REPLACE))
929 return -EEXIST;
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000930 ifa = ifa_existing;
David Ahernaf4d7682018-05-27 08:09:57 -0700931
932 if (ifa->ifa_rt_priority != new_metric) {
933 fib_modify_prefix_metric(ifa, new_metric);
934 ifa->ifa_rt_priority = new_metric;
935 }
936
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000937 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Jiri Pirko05a324b2013-04-04 23:39:38 +0000938 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530939 queue_delayed_work(system_power_efficient_wq,
940 &check_lifetime_work, 0);
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000941 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000942 }
943 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944}
945
946/*
947 * Determine a default network mask, based on the IP address.
948 */
949
Eric Dumazet40384992012-08-03 21:06:50 +0000950static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951{
952 int rc = -1; /* Something else, probably a multicast. */
953
Joe Perchesf97c1e02007-12-16 13:45:43 -0800954 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900955 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 else {
Al Viro714e85b2006-11-14 20:51:49 -0800957 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
Al Viro714e85b2006-11-14 20:51:49 -0800959 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800961 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800963 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 rc = 24;
965 }
966
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900967 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968}
969
970
Al Viro03aef172017-07-01 07:53:12 -0400971int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 struct sockaddr_in sin_orig;
Al Viro03aef172017-07-01 07:53:12 -0400974 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 struct in_device *in_dev;
976 struct in_ifaddr **ifap = NULL;
977 struct in_ifaddr *ifa = NULL;
978 struct net_device *dev;
979 char *colon;
980 int ret = -EFAULT;
981 int tryaddrmatch = 0;
982
Al Viro03aef172017-07-01 07:53:12 -0400983 ifr->ifr_name[IFNAMSIZ - 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
985 /* save original address for comparison */
986 memcpy(&sin_orig, sin, sizeof(*sin));
987
Al Viro03aef172017-07-01 07:53:12 -0400988 colon = strchr(ifr->ifr_name, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 if (colon)
990 *colon = 0;
991
Al Viro03aef172017-07-01 07:53:12 -0400992 dev_load(net, ifr->ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
Stephen Hemminger132adf52007-03-08 20:44:43 -0800994 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 case SIOCGIFADDR: /* Get interface address */
996 case SIOCGIFBRDADDR: /* Get the broadcast address */
997 case SIOCGIFDSTADDR: /* Get the destination address */
998 case SIOCGIFNETMASK: /* Get the netmask for the interface */
999 /* Note that these ioctls will not sleep,
1000 so that we do not impose a lock.
1001 One day we will be forced to put shlock here (I mean SMP)
1002 */
1003 tryaddrmatch = (sin_orig.sin_family == AF_INET);
1004 memset(sin, 0, sizeof(*sin));
1005 sin->sin_family = AF_INET;
1006 break;
1007
1008 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +00001009 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +00001010 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 goto out;
1012 break;
1013 case SIOCSIFADDR: /* Set interface address (and family) */
1014 case SIOCSIFBRDADDR: /* Set the broadcast address */
1015 case SIOCSIFDSTADDR: /* Set the destination address */
1016 case SIOCSIFNETMASK: /* Set the netmask for the interface */
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +00001017 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +00001018 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 goto out;
1020 ret = -EINVAL;
1021 if (sin->sin_family != AF_INET)
1022 goto out;
1023 break;
1024 default:
1025 ret = -EINVAL;
1026 goto out;
1027 }
1028
1029 rtnl_lock();
1030
1031 ret = -ENODEV;
Al Viro03aef172017-07-01 07:53:12 -04001032 dev = __dev_get_by_name(net, ifr->ifr_name);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001033 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 goto done;
1035
1036 if (colon)
1037 *colon = ':';
1038
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001039 in_dev = __in_dev_get_rtnl(dev);
1040 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 if (tryaddrmatch) {
1042 /* Matthias Andree */
1043 /* compare label and address (4.4BSD style) */
1044 /* note: we only do this for a limited set of ioctls
1045 and only if the original address family was AF_INET.
1046 This is checked above. */
1047 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1048 ifap = &ifa->ifa_next) {
Al Viro03aef172017-07-01 07:53:12 -04001049 if (!strcmp(ifr->ifr_name, ifa->ifa_label) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -08001051 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 break; /* found */
1053 }
1054 }
1055 }
1056 /* we didn't get a match, maybe the application is
1057 4.3BSD-style and passed in junk so we fall back to
1058 comparing just the label */
1059 if (!ifa) {
1060 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1061 ifap = &ifa->ifa_next)
Al Viro03aef172017-07-01 07:53:12 -04001062 if (!strcmp(ifr->ifr_name, ifa->ifa_label))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 break;
1064 }
1065 }
1066
1067 ret = -EADDRNOTAVAIL;
1068 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
1069 goto done;
1070
Stephen Hemminger132adf52007-03-08 20:44:43 -08001071 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 case SIOCGIFADDR: /* Get interface address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001073 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 sin->sin_addr.s_addr = ifa->ifa_local;
Al Viro03aef172017-07-01 07:53:12 -04001075 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
1077 case SIOCGIFBRDADDR: /* Get the broadcast address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001078 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 sin->sin_addr.s_addr = ifa->ifa_broadcast;
Al Viro03aef172017-07-01 07:53:12 -04001080 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
1082 case SIOCGIFDSTADDR: /* Get the destination address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001083 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 sin->sin_addr.s_addr = ifa->ifa_address;
Al Viro03aef172017-07-01 07:53:12 -04001085 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086
1087 case SIOCGIFNETMASK: /* Get the netmask for the interface */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001088 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 sin->sin_addr.s_addr = ifa->ifa_mask;
Al Viro03aef172017-07-01 07:53:12 -04001090 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
1092 case SIOCSIFFLAGS:
1093 if (colon) {
1094 ret = -EADDRNOTAVAIL;
1095 if (!ifa)
1096 break;
1097 ret = 0;
Al Viro03aef172017-07-01 07:53:12 -04001098 if (!(ifr->ifr_flags & IFF_UP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 inet_del_ifa(in_dev, ifap, 1);
1100 break;
1101 }
Al Viro03aef172017-07-01 07:53:12 -04001102 ret = dev_change_flags(dev, ifr->ifr_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 break;
1104
1105 case SIOCSIFADDR: /* Set interface address (and family) */
1106 ret = -EINVAL;
1107 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1108 break;
1109
1110 if (!ifa) {
1111 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001112 ifa = inet_alloc_ifa();
1113 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 break;
Xi Wangc7e2e1d2013-01-05 11:19:24 +00001115 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 if (colon)
Al Viro03aef172017-07-01 07:53:12 -04001117 memcpy(ifa->ifa_label, ifr->ifr_name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 else
1119 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1120 } else {
1121 ret = 0;
1122 if (ifa->ifa_local == sin->sin_addr.s_addr)
1123 break;
1124 inet_del_ifa(in_dev, ifap, 0);
1125 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -08001126 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 }
1128
1129 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
1130
1131 if (!(dev->flags & IFF_POINTOPOINT)) {
1132 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
1133 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
1134 if ((dev->flags & IFF_BROADCAST) &&
1135 ifa->ifa_prefixlen < 31)
1136 ifa->ifa_broadcast = ifa->ifa_address |
1137 ~ifa->ifa_mask;
1138 } else {
1139 ifa->ifa_prefixlen = 32;
1140 ifa->ifa_mask = inet_make_mask(32);
1141 }
Jiri Pirko5c766d62013-01-24 09:41:41 +00001142 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 ret = inet_set_ifa(dev, ifa);
1144 break;
1145
1146 case SIOCSIFBRDADDR: /* Set the broadcast address */
1147 ret = 0;
1148 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
1149 inet_del_ifa(in_dev, ifap, 0);
1150 ifa->ifa_broadcast = sin->sin_addr.s_addr;
1151 inet_insert_ifa(ifa);
1152 }
1153 break;
1154
1155 case SIOCSIFDSTADDR: /* Set the destination address */
1156 ret = 0;
1157 if (ifa->ifa_address == sin->sin_addr.s_addr)
1158 break;
1159 ret = -EINVAL;
1160 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1161 break;
1162 ret = 0;
1163 inet_del_ifa(in_dev, ifap, 0);
1164 ifa->ifa_address = sin->sin_addr.s_addr;
1165 inet_insert_ifa(ifa);
1166 break;
1167
1168 case SIOCSIFNETMASK: /* Set the netmask for the interface */
1169
1170 /*
1171 * The mask we set must be legal.
1172 */
1173 ret = -EINVAL;
1174 if (bad_mask(sin->sin_addr.s_addr, 0))
1175 break;
1176 ret = 0;
1177 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -07001178 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 inet_del_ifa(in_dev, ifap, 0);
1180 ifa->ifa_mask = sin->sin_addr.s_addr;
1181 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
1182
1183 /* See if current broadcast address matches
1184 * with current netmask, then recalculate
1185 * the broadcast address. Otherwise it's a
1186 * funny address, so don't touch it since
1187 * the user seems to know what (s)he's doing...
1188 */
1189 if ((dev->flags & IFF_BROADCAST) &&
1190 (ifa->ifa_prefixlen < 31) &&
1191 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -05001192 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 ifa->ifa_broadcast = (ifa->ifa_local |
1194 ~sin->sin_addr.s_addr);
1195 }
1196 inet_insert_ifa(ifa);
1197 }
1198 break;
1199 }
1200done:
1201 rtnl_unlock();
1202out:
1203 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204}
1205
Al Viro36fd6332017-06-26 13:19:16 -04001206static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207{
Herbert Xue5ed6392005-10-03 14:35:55 -07001208 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 struct in_ifaddr *ifa;
1210 struct ifreq ifr;
1211 int done = 0;
1212
Al Viro36fd6332017-06-26 13:19:16 -04001213 if (WARN_ON(size > sizeof(struct ifreq)))
1214 goto out;
1215
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001216 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 goto out;
1218
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001219 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 if (!buf) {
Al Viro36fd6332017-06-26 13:19:16 -04001221 done += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 continue;
1223 }
Al Viro36fd6332017-06-26 13:19:16 -04001224 if (len < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 break;
1226 memset(&ifr, 0, sizeof(struct ifreq));
Dan Carpenter4299c8a2013-07-29 22:15:19 +03001227 strcpy(ifr.ifr_name, ifa->ifa_label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228
1229 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
1230 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1231 ifa->ifa_local;
1232
Al Viro36fd6332017-06-26 13:19:16 -04001233 if (copy_to_user(buf + done, &ifr, size)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 done = -EFAULT;
1235 break;
1236 }
Al Viro36fd6332017-06-26 13:19:16 -04001237 len -= size;
1238 done += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 }
1240out:
1241 return done;
1242}
1243
Gao Feng8b57fd12017-03-10 12:38:47 +08001244static __be32 in_dev_select_addr(const struct in_device *in_dev,
1245 int scope)
1246{
1247 for_primary_ifa(in_dev) {
1248 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1249 ifa->ifa_scope <= scope)
1250 return ifa->ifa_local;
1251 } endfor_ifa(in_dev);
1252
1253 return 0;
1254}
1255
Al Viroa61ced52006-09-26 21:27:54 -07001256__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257{
Al Viroa61ced52006-09-26 21:27:54 -07001258 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001260 struct net *net = dev_net(dev);
David Ahern3f2fb9a2016-02-24 11:47:02 -08001261 int master_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262
1263 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001264 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 if (!in_dev)
1266 goto no_in_dev;
1267
1268 for_primary_ifa(in_dev) {
1269 if (ifa->ifa_scope > scope)
1270 continue;
1271 if (!dst || inet_ifa_match(dst, ifa)) {
1272 addr = ifa->ifa_local;
1273 break;
1274 }
1275 if (!addr)
1276 addr = ifa->ifa_local;
1277 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278
1279 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001280 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001281no_in_dev:
David Ahern3f2fb9a2016-02-24 11:47:02 -08001282 master_idx = l3mdev_master_ifindex_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283
David Lamparter17b693c2016-02-24 11:47:03 -08001284 /* For VRFs, the VRF device takes the place of the loopback device,
1285 * with addresses on it being preferred. Note in such cases the
1286 * loopback device will be among the devices that fail the master_idx
1287 * equality check in the loop below.
1288 */
1289 if (master_idx &&
1290 (dev = dev_get_by_index_rcu(net, master_idx)) &&
1291 (in_dev = __in_dev_get_rcu(dev))) {
Gao Feng8b57fd12017-03-10 12:38:47 +08001292 addr = in_dev_select_addr(in_dev, scope);
1293 if (addr)
1294 goto out_unlock;
David Lamparter17b693c2016-02-24 11:47:03 -08001295 }
1296
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 /* Not loopback addresses on loopback should be preferred
Stephen Hemmingerca9f1fd2015-02-14 13:47:54 -05001298 in this case. It is important that lo is the first interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 in dev_base list.
1300 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001301 for_each_netdev_rcu(net, dev) {
David Ahern3f2fb9a2016-02-24 11:47:02 -08001302 if (l3mdev_master_ifindex_rcu(dev) != master_idx)
1303 continue;
1304
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001305 in_dev = __in_dev_get_rcu(dev);
1306 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 continue;
1308
Gao Feng8b57fd12017-03-10 12:38:47 +08001309 addr = in_dev_select_addr(in_dev, scope);
1310 if (addr)
1311 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001313out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 return addr;
1316}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001317EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318
Al Viro60cad5d2006-09-26 22:17:09 -07001319static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1320 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321{
1322 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001323 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
1325 for_ifa(in_dev) {
1326 if (!addr &&
1327 (local == ifa->ifa_local || !local) &&
1328 ifa->ifa_scope <= scope) {
1329 addr = ifa->ifa_local;
1330 if (same)
1331 break;
1332 }
1333 if (!same) {
1334 same = (!local || inet_ifa_match(local, ifa)) &&
1335 (!dst || inet_ifa_match(dst, ifa));
1336 if (same && addr) {
1337 if (local || !dst)
1338 break;
1339 /* Is the selected addr into dst subnet? */
1340 if (inet_ifa_match(addr, ifa))
1341 break;
1342 /* No, then can we use new local src? */
1343 if (ifa->ifa_scope <= scope) {
1344 addr = ifa->ifa_local;
1345 break;
1346 }
1347 /* search for large dst subnet for addr */
1348 same = 0;
1349 }
1350 }
1351 } endfor_ifa(in_dev);
1352
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001353 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354}
1355
1356/*
1357 * Confirm that local IP address exists using wildcards:
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001358 * - net: netns to check, cannot be NULL
1359 * - in_dev: only on this interface, NULL=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 * - dst: only in the same subnet as dst, 0=any dst
1361 * - local: address, 0=autoselect the local address
1362 * - scope: maximum allowed scope value for the local address
1363 */
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001364__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001365 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366{
Al Viro60cad5d2006-09-26 22:17:09 -07001367 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001368 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369
Ian Morris00db4122015-04-03 09:17:27 +01001370 if (in_dev)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001371 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001374 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001375 in_dev = __in_dev_get_rcu(dev);
1376 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 addr = confirm_addr_indev(in_dev, dst, local, scope);
1378 if (addr)
1379 break;
1380 }
1381 }
1382 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
1384 return addr;
1385}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001386EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
1388/*
1389 * Device notifier
1390 */
1391
1392int register_inetaddr_notifier(struct notifier_block *nb)
1393{
Alan Sterne041c682006-03-27 01:16:30 -08001394 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001396EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
1398int unregister_inetaddr_notifier(struct notifier_block *nb)
1399{
Alan Sterne041c682006-03-27 01:16:30 -08001400 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001402EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403
Krister Johansen3ad7d242017-06-08 13:12:14 -07001404int register_inetaddr_validator_notifier(struct notifier_block *nb)
1405{
1406 return blocking_notifier_chain_register(&inetaddr_validator_chain, nb);
1407}
1408EXPORT_SYMBOL(register_inetaddr_validator_notifier);
1409
1410int unregister_inetaddr_validator_notifier(struct notifier_block *nb)
1411{
1412 return blocking_notifier_chain_unregister(&inetaddr_validator_chain,
1413 nb);
1414}
1415EXPORT_SYMBOL(unregister_inetaddr_validator_notifier);
1416
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001417/* Rename ifa_labels for a device name change. Make some effort to preserve
1418 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419*/
1420static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001421{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 struct in_ifaddr *ifa;
1423 int named = 0;
1424
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001425 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1426 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
1428 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001429 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001431 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001432 dot = strchr(old, ':');
Ian Morris51456b22015-04-03 09:17:26 +01001433 if (!dot) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001434 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 dot = old;
1436 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001437 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001438 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001439 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001440 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001441skip:
1442 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001443 }
1444}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445
Eric Dumazet40384992012-08-03 21:06:50 +00001446static bool inetdev_valid_mtu(unsigned int mtu)
Breno Leitao06770842008-09-02 17:28:58 -07001447{
Eric Dumazetb5476022017-12-11 07:17:39 -08001448 return mtu >= IPV4_MIN_MTU;
Breno Leitao06770842008-09-02 17:28:58 -07001449}
1450
Ian Campbelld11327ad2011-02-11 07:44:16 +00001451static void inetdev_send_gratuitous_arp(struct net_device *dev,
1452 struct in_device *in_dev)
1453
1454{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001455 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001456
Zoltan Kissb76d0782011-07-24 13:09:30 +00001457 for (ifa = in_dev->ifa_list; ifa;
1458 ifa = ifa->ifa_next) {
1459 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1460 ifa->ifa_local, dev,
1461 ifa->ifa_local, NULL,
1462 dev->dev_addr, NULL);
1463 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001464}
1465
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466/* Called only under RTNL semaphore */
1467
1468static int inetdev_event(struct notifier_block *this, unsigned long event,
1469 void *ptr)
1470{
Jiri Pirko351638e2013-05-28 01:30:21 +00001471 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazet748e2d92012-08-22 21:50:59 +00001472 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473
1474 ASSERT_RTNL();
1475
1476 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001477 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 in_dev = inetdev_init(dev);
WANG Cong20e61da2014-07-25 15:25:08 -07001479 if (IS_ERR(in_dev))
1480 return notifier_from_errno(PTR_ERR(in_dev));
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001481 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001482 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1483 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001484 }
Breno Leitao06770842008-09-02 17:28:58 -07001485 } else if (event == NETDEV_CHANGEMTU) {
1486 /* Re-enabling IP */
1487 if (inetdev_valid_mtu(dev->mtu))
1488 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 }
1490 goto out;
1491 }
1492
1493 switch (event) {
1494 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001495 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001496 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 break;
1498 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001499 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001501 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001502 struct in_ifaddr *ifa = inet_alloc_ifa();
1503
1504 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001505 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 ifa->ifa_local =
1507 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1508 ifa->ifa_prefixlen = 8;
1509 ifa->ifa_mask = inet_make_mask(8);
1510 in_dev_hold(in_dev);
1511 ifa->ifa_dev = in_dev;
1512 ifa->ifa_scope = RT_SCOPE_HOST;
1513 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Jiri Pirko5c766d62013-01-24 09:41:41 +00001514 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1515 INFINITY_LIFE_TIME);
Jiri Pirkodfd15822014-01-07 15:55:45 +01001516 ipv4_devconf_setall(in_dev);
1517 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 inet_insert_ifa(ifa);
1519 }
1520 }
1521 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001522 /* fall through */
1523 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001524 if (!IN_DEV_ARP_NOTIFY(in_dev))
1525 break;
1526 /* fall through */
1527 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001528 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001529 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 break;
1531 case NETDEV_DOWN:
1532 ip_mc_down(in_dev);
1533 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001534 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001535 ip_mc_unmap(in_dev);
1536 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001537 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001538 ip_mc_remap(in_dev);
1539 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001541 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 break;
Breno Leitao06770842008-09-02 17:28:58 -07001543 /* disable IP when MTU is not enough */
Gustavo A. R. Silvafcfd6df2017-10-16 15:48:55 -05001544 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 case NETDEV_UNREGISTER:
1546 inetdev_destroy(in_dev);
1547 break;
1548 case NETDEV_CHANGENAME:
1549 /* Do not notify about label change, this event is
1550 * not interesting to applications using netlink.
1551 */
1552 inetdev_changename(dev, in_dev);
1553
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001554 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001555 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 break;
1557 }
1558out:
1559 return NOTIFY_DONE;
1560}
1561
1562static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001563 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564};
1565
Eric Dumazet40384992012-08-03 21:06:50 +00001566static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001567{
1568 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1569 + nla_total_size(4) /* IFA_ADDRESS */
1570 + nla_total_size(4) /* IFA_LOCAL */
1571 + nla_total_size(4) /* IFA_BROADCAST */
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001572 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001573 + nla_total_size(4) /* IFA_FLAGS */
David Ahernaf4d7682018-05-27 08:09:57 -07001574 + nla_total_size(4) /* IFA_RT_PRIORITY */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001575 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
Thomas Graf339bf982006-11-10 14:10:15 -08001576}
1577
Jiri Pirko5c766d62013-01-24 09:41:41 +00001578static inline u32 cstamp_delta(unsigned long cstamp)
1579{
1580 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1581}
1582
1583static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1584 unsigned long tstamp, u32 preferred, u32 valid)
1585{
1586 struct ifa_cacheinfo ci;
1587
1588 ci.cstamp = cstamp_delta(cstamp);
1589 ci.tstamp = cstamp_delta(tstamp);
1590 ci.ifa_prefered = preferred;
1591 ci.ifa_valid = valid;
1592
1593 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1594}
1595
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Christian Brauner978a46f2018-09-04 21:53:54 +02001597 struct inet_fill_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598{
1599 struct ifaddrmsg *ifm;
1600 struct nlmsghdr *nlh;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001601 u32 preferred, valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602
Christian Brauner978a46f2018-09-04 21:53:54 +02001603 nlh = nlmsg_put(skb, args->portid, args->seq, args->event, sizeof(*ifm),
1604 args->flags);
Ian Morris51456b22015-04-03 09:17:26 +01001605 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08001606 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001607
1608 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 ifm->ifa_family = AF_INET;
1610 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001611 ifm->ifa_flags = ifa->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 ifm->ifa_scope = ifa->ifa_scope;
1613 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614
Christian Brauner978a46f2018-09-04 21:53:54 +02001615 if (args->netnsid >= 0 &&
1616 nla_put_s32(skb, IFA_TARGET_NETNSID, args->netnsid))
Christian Braunerd3807142018-09-04 21:53:49 +02001617 goto nla_put_failure;
1618
Jiri Pirko5c766d62013-01-24 09:41:41 +00001619 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1620 preferred = ifa->ifa_preferred_lft;
1621 valid = ifa->ifa_valid_lft;
1622 if (preferred != INFINITY_LIFE_TIME) {
1623 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1624
1625 if (preferred > tval)
1626 preferred -= tval;
1627 else
1628 preferred = 0;
1629 if (valid != INFINITY_LIFE_TIME) {
1630 if (valid > tval)
1631 valid -= tval;
1632 else
1633 valid = 0;
1634 }
1635 }
1636 } else {
1637 preferred = INFINITY_LIFE_TIME;
1638 valid = INFINITY_LIFE_TIME;
1639 }
David S. Millerf3756b72012-04-01 20:39:02 -04001640 if ((ifa->ifa_address &&
Jiri Benc930345e2015-03-29 16:59:25 +02001641 nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001642 (ifa->ifa_local &&
Jiri Benc930345e2015-03-29 16:59:25 +02001643 nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001644 (ifa->ifa_broadcast &&
Jiri Benc930345e2015-03-29 16:59:25 +02001645 nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001646 (ifa->ifa_label[0] &&
Jiri Pirko5c766d62013-01-24 09:41:41 +00001647 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001648 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
David Ahernaf4d7682018-05-27 08:09:57 -07001649 (ifa->ifa_rt_priority &&
1650 nla_put_u32(skb, IFA_RT_PRIORITY, ifa->ifa_rt_priority)) ||
Jiri Pirko5c766d62013-01-24 09:41:41 +00001651 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1652 preferred, valid))
David S. Millerf3756b72012-04-01 20:39:02 -04001653 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001654
Johannes Berg053c0952015-01-16 22:09:00 +01001655 nlmsg_end(skb, nlh);
1656 return 0;
Thomas Graf47f68512006-08-04 23:04:36 -07001657
1658nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001659 nlmsg_cancel(skb, nlh);
1660 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661}
1662
David Ahernc33078e2018-10-07 20:16:28 -07001663static int inet_valid_dump_ifaddr_req(const struct nlmsghdr *nlh,
1664 struct inet_fill_args *fillargs,
1665 struct net **tgt_net, struct sock *sk,
1666 struct netlink_ext_ack *extack)
1667{
1668 struct nlattr *tb[IFA_MAX+1];
1669 struct ifaddrmsg *ifm;
1670 int err, i;
1671
1672 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) {
1673 NL_SET_ERR_MSG(extack, "ipv4: Invalid header for address dump request");
1674 return -EINVAL;
1675 }
1676
1677 ifm = nlmsg_data(nlh);
1678 if (ifm->ifa_prefixlen || ifm->ifa_flags || ifm->ifa_scope) {
1679 NL_SET_ERR_MSG(extack, "ipv4: Invalid values in header for address dump request");
1680 return -EINVAL;
1681 }
1682 if (ifm->ifa_index) {
1683 NL_SET_ERR_MSG(extack, "ipv4: Filter by device index not supported for address dump");
1684 return -EINVAL;
1685 }
1686
1687 err = nlmsg_parse_strict(nlh, sizeof(*ifm), tb, IFA_MAX,
1688 ifa_ipv4_policy, extack);
1689 if (err < 0)
1690 return err;
1691
1692 for (i = 0; i <= IFA_MAX; ++i) {
1693 if (!tb[i])
1694 continue;
1695
1696 if (i == IFA_TARGET_NETNSID) {
1697 struct net *net;
1698
1699 fillargs->netnsid = nla_get_s32(tb[i]);
1700
1701 net = rtnl_get_net_ns_capable(sk, fillargs->netnsid);
1702 if (IS_ERR(net)) {
1703 NL_SET_ERR_MSG(extack, "ipv4: Invalid target network namespace id");
1704 return PTR_ERR(net);
1705 }
1706 *tgt_net = net;
1707 } else {
1708 NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in dump request");
1709 return -EINVAL;
1710 }
1711 }
1712
1713 return 0;
1714}
1715
David Ahern1c98eca2018-10-19 12:45:27 -07001716static int in_dev_dump_addr(struct in_device *in_dev, struct sk_buff *skb,
1717 struct netlink_callback *cb, int s_ip_idx,
1718 struct inet_fill_args *fillargs)
1719{
1720 struct in_ifaddr *ifa;
1721 int ip_idx = 0;
1722 int err;
1723
1724 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next, ip_idx++) {
1725 if (ip_idx < s_ip_idx)
1726 continue;
1727
1728 err = inet_fill_ifaddr(skb, ifa, fillargs);
1729 if (err < 0)
1730 goto done;
1731
1732 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
1733 }
1734 err = 0;
1735
1736done:
1737 cb->args[2] = ip_idx;
1738
1739 return err;
1740}
1741
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1743{
David Ahernc33078e2018-10-07 20:16:28 -07001744 const struct nlmsghdr *nlh = cb->nlh;
Christian Brauner978a46f2018-09-04 21:53:54 +02001745 struct inet_fill_args fillargs = {
1746 .portid = NETLINK_CB(cb->skb).portid,
David Ahernc33078e2018-10-07 20:16:28 -07001747 .seq = nlh->nlmsg_seq,
Christian Brauner978a46f2018-09-04 21:53:54 +02001748 .event = RTM_NEWADDR,
1749 .flags = NLM_F_MULTI,
1750 .netnsid = -1,
1751 };
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001752 struct net *net = sock_net(skb->sk);
Christian Braunerd3807142018-09-04 21:53:49 +02001753 struct net *tgt_net = net;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001754 int h, s_h;
1755 int idx, s_idx;
David Ahern1c98eca2018-10-19 12:45:27 -07001756 int s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 struct net_device *dev;
1758 struct in_device *in_dev;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001759 struct hlist_head *head;
David Ahern1c98eca2018-10-19 12:45:27 -07001760 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761
Eric Dumazeteec4df92009-11-12 07:44:25 +00001762 s_h = cb->args[0];
1763 s_idx = idx = cb->args[1];
David Ahern1c98eca2018-10-19 12:45:27 -07001764 s_ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765
David Ahernc33078e2018-10-07 20:16:28 -07001766 if (cb->strict_check) {
David Ahernc33078e2018-10-07 20:16:28 -07001767 err = inet_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net,
1768 skb->sk, cb->extack);
1769 if (err < 0)
1770 return err;
Christian Braunerd3807142018-09-04 21:53:49 +02001771 }
1772
Eric Dumazeteec4df92009-11-12 07:44:25 +00001773 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1774 idx = 0;
Christian Braunerd3807142018-09-04 21:53:49 +02001775 head = &tgt_net->dev_index_head[h];
Eric Dumazeteec4df92009-11-12 07:44:25 +00001776 rcu_read_lock();
Christian Braunerd3807142018-09-04 21:53:49 +02001777 cb->seq = atomic_read(&tgt_net->ipv4.dev_addr_genid) ^
1778 tgt_net->dev_base_seq;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001779 hlist_for_each_entry_rcu(dev, head, index_hlist) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001780 if (idx < s_idx)
1781 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001782 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001783 s_ip_idx = 0;
1784 in_dev = __in_dev_get_rcu(dev);
1785 if (!in_dev)
1786 goto cont;
1787
David Ahern1c98eca2018-10-19 12:45:27 -07001788 err = in_dev_dump_addr(in_dev, skb, cb, s_ip_idx,
1789 &fillargs);
1790 if (err < 0) {
1791 rcu_read_unlock();
1792 goto done;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001793 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001794cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001795 idx++;
1796 }
1797 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 }
1799
1800done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001801 cb->args[0] = h;
1802 cb->args[1] = idx;
Christian Brauner978a46f2018-09-04 21:53:54 +02001803 if (fillargs.netnsid >= 0)
Christian Braunerd3807142018-09-04 21:53:49 +02001804 put_net(tgt_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805
1806 return skb->len;
1807}
1808
Jianjun Kong539afed2008-11-03 02:48:48 -08001809static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001810 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811{
Christian Brauner978a46f2018-09-04 21:53:54 +02001812 struct inet_fill_args fillargs = {
1813 .portid = portid,
1814 .seq = nlh ? nlh->nlmsg_seq : 0,
1815 .event = event,
1816 .flags = 0,
1817 .netnsid = -1,
1818 };
Thomas Graf47f68512006-08-04 23:04:36 -07001819 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001820 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001821 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001823 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001824 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001825 if (!skb)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001826 goto errout;
1827
Christian Brauner978a46f2018-09-04 21:53:54 +02001828 err = inet_fill_ifaddr(skb, ifa, &fillargs);
Patrick McHardy26932562007-01-31 23:16:40 -08001829 if (err < 0) {
1830 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1831 WARN_ON(err == -EMSGSIZE);
1832 kfree_skb(skb);
1833 goto errout;
1834 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001835 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001836 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001837errout:
1838 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001839 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840}
1841
Arad, Ronenb1974ed2015-10-19 09:23:28 -07001842static size_t inet_get_link_af_size(const struct net_device *dev,
1843 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001844{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001845 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001846
1847 if (!in_dev)
1848 return 0;
1849
1850 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1851}
1852
Sowmini Varadhand5566fd2015-09-11 16:48:48 -04001853static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
1854 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001855{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001856 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001857 struct nlattr *nla;
1858 int i;
1859
1860 if (!in_dev)
1861 return -ENODATA;
1862
1863 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
Ian Morris51456b22015-04-03 09:17:26 +01001864 if (!nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001865 return -EMSGSIZE;
1866
1867 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1868 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1869
1870 return 0;
1871}
1872
1873static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1874 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1875};
1876
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001877static int inet_validate_link_af(const struct net_device *dev,
1878 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001879{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001880 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1881 int err, rem;
1882
Florian Westphal5fa85a02017-10-16 15:44:36 +02001883 if (dev && !__in_dev_get_rcu(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001884 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001885
Johannes Bergfceb6432017-04-12 14:34:07 +02001886 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy, NULL);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001887 if (err < 0)
1888 return err;
1889
1890 if (tb[IFLA_INET_CONF]) {
1891 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1892 int cfgid = nla_type(a);
1893
1894 if (nla_len(a) < 4)
1895 return -EINVAL;
1896
1897 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1898 return -EINVAL;
1899 }
1900 }
1901
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001902 return 0;
1903}
1904
1905static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1906{
Florian Westphal5fa85a02017-10-16 15:44:36 +02001907 struct in_device *in_dev = __in_dev_get_rcu(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001908 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1909 int rem;
1910
1911 if (!in_dev)
1912 return -EAFNOSUPPORT;
1913
Johannes Bergfceb6432017-04-12 14:34:07 +02001914 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0)
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001915 BUG();
1916
Thomas Graf9f0f7272010-11-16 04:32:48 +00001917 if (tb[IFLA_INET_CONF]) {
1918 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1919 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1920 }
1921
1922 return 0;
1923}
1924
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001925static int inet_netconf_msgsize_devconf(int type)
1926{
1927 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1928 + nla_total_size(4); /* NETCONFA_IFINDEX */
Zhang Shengju136ba622016-03-10 08:55:50 +00001929 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001930
Zhang Shengju136ba622016-03-10 08:55:50 +00001931 if (type == NETCONFA_ALL)
1932 all = true;
1933
1934 if (all || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001935 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001936 if (all || type == NETCONFA_RP_FILTER)
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001937 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001938 if (all || type == NETCONFA_MC_FORWARDING)
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001939 size += nla_total_size(4);
Xin Long5cbf7772018-07-27 16:37:28 +08001940 if (all || type == NETCONFA_BC_FORWARDING)
1941 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001942 if (all || type == NETCONFA_PROXY_NEIGH)
stephen hemmingerf085ff12013-12-12 13:06:50 -08001943 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001944 if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001945 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001946
1947 return size;
1948}
1949
1950static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1951 struct ipv4_devconf *devconf, u32 portid,
1952 u32 seq, int event, unsigned int flags,
1953 int type)
1954{
1955 struct nlmsghdr *nlh;
1956 struct netconfmsg *ncm;
Zhang Shengju136ba622016-03-10 08:55:50 +00001957 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001958
1959 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1960 flags);
Ian Morris51456b22015-04-03 09:17:26 +01001961 if (!nlh)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001962 return -EMSGSIZE;
1963
Zhang Shengju136ba622016-03-10 08:55:50 +00001964 if (type == NETCONFA_ALL)
1965 all = true;
1966
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001967 ncm = nlmsg_data(nlh);
1968 ncm->ncm_family = AF_INET;
1969
1970 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1971 goto nla_put_failure;
1972
David Ahernb5c96412017-03-28 14:28:03 -07001973 if (!devconf)
1974 goto out;
1975
Zhang Shengju136ba622016-03-10 08:55:50 +00001976 if ((all || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001977 nla_put_s32(skb, NETCONFA_FORWARDING,
1978 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1979 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001980 if ((all || type == NETCONFA_RP_FILTER) &&
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001981 nla_put_s32(skb, NETCONFA_RP_FILTER,
1982 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
1983 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001984 if ((all || type == NETCONFA_MC_FORWARDING) &&
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001985 nla_put_s32(skb, NETCONFA_MC_FORWARDING,
1986 IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
1987 goto nla_put_failure;
Xin Long5cbf7772018-07-27 16:37:28 +08001988 if ((all || type == NETCONFA_BC_FORWARDING) &&
1989 nla_put_s32(skb, NETCONFA_BC_FORWARDING,
1990 IPV4_DEVCONF(*devconf, BC_FORWARDING)) < 0)
1991 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001992 if ((all || type == NETCONFA_PROXY_NEIGH) &&
stephen hemminger09aea5d2013-12-17 22:35:52 -08001993 nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08001994 IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
1995 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001996 if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001997 nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
1998 IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
1999 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002000
David Ahernb5c96412017-03-28 14:28:03 -07002001out:
Johannes Berg053c0952015-01-16 22:09:00 +01002002 nlmsg_end(skb, nlh);
2003 return 0;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002004
2005nla_put_failure:
2006 nlmsg_cancel(skb, nlh);
2007 return -EMSGSIZE;
2008}
2009
David Ahern3b022862017-03-28 14:28:02 -07002010void inet_netconf_notify_devconf(struct net *net, int event, int type,
2011 int ifindex, struct ipv4_devconf *devconf)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002012{
2013 struct sk_buff *skb;
2014 int err = -ENOBUFS;
2015
Eric Dumazetfa178062016-07-08 05:18:24 +02002016 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002017 if (!skb)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002018 goto errout;
2019
2020 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
David Ahern3b022862017-03-28 14:28:02 -07002021 event, 0, type);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002022 if (err < 0) {
2023 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
2024 WARN_ON(err == -EMSGSIZE);
2025 kfree_skb(skb);
2026 goto errout;
2027 }
Eric Dumazetfa178062016-07-08 05:18:24 +02002028 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002029 return;
2030errout:
2031 if (err < 0)
2032 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
2033}
2034
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002035static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
2036 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
2037 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002038 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
stephen hemminger09aea5d2013-12-17 22:35:52 -08002039 [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) },
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002040 [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002041};
2042
2043static int inet_netconf_get_devconf(struct sk_buff *in_skb,
David Ahernc21ef3e2017-04-16 09:48:24 -07002044 struct nlmsghdr *nlh,
2045 struct netlink_ext_ack *extack)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002046{
2047 struct net *net = sock_net(in_skb->sk);
2048 struct nlattr *tb[NETCONFA_MAX+1];
2049 struct netconfmsg *ncm;
2050 struct sk_buff *skb;
2051 struct ipv4_devconf *devconf;
2052 struct in_device *in_dev;
2053 struct net_device *dev;
2054 int ifindex;
2055 int err;
2056
2057 err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
David Ahernc21ef3e2017-04-16 09:48:24 -07002058 devconf_ipv4_policy, extack);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002059 if (err < 0)
2060 goto errout;
2061
Anton Protopopova97eb332016-02-16 21:43:16 -05002062 err = -EINVAL;
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002063 if (!tb[NETCONFA_IFINDEX])
2064 goto errout;
2065
2066 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
2067 switch (ifindex) {
2068 case NETCONFA_IFINDEX_ALL:
2069 devconf = net->ipv4.devconf_all;
2070 break;
2071 case NETCONFA_IFINDEX_DEFAULT:
2072 devconf = net->ipv4.devconf_dflt;
2073 break;
2074 default:
2075 dev = __dev_get_by_index(net, ifindex);
Ian Morris51456b22015-04-03 09:17:26 +01002076 if (!dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002077 goto errout;
2078 in_dev = __in_dev_get_rtnl(dev);
Ian Morris51456b22015-04-03 09:17:26 +01002079 if (!in_dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002080 goto errout;
2081 devconf = &in_dev->cnf;
2082 break;
2083 }
2084
2085 err = -ENOBUFS;
Eric Dumazetfa178062016-07-08 05:18:24 +02002086 skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002087 if (!skb)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002088 goto errout;
2089
2090 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
2091 NETLINK_CB(in_skb).portid,
2092 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
Zhang Shengju136ba622016-03-10 08:55:50 +00002093 NETCONFA_ALL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002094 if (err < 0) {
2095 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
2096 WARN_ON(err == -EMSGSIZE);
2097 kfree_skb(skb);
2098 goto errout;
2099 }
2100 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
2101errout:
2102 return err;
2103}
2104
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002105static int inet_netconf_dump_devconf(struct sk_buff *skb,
2106 struct netlink_callback *cb)
2107{
David Ahernaddd3832018-10-07 20:16:41 -07002108 const struct nlmsghdr *nlh = cb->nlh;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002109 struct net *net = sock_net(skb->sk);
2110 int h, s_h;
2111 int idx, s_idx;
2112 struct net_device *dev;
2113 struct in_device *in_dev;
2114 struct hlist_head *head;
2115
David Ahernaddd3832018-10-07 20:16:41 -07002116 if (cb->strict_check) {
2117 struct netlink_ext_ack *extack = cb->extack;
2118 struct netconfmsg *ncm;
2119
2120 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ncm))) {
2121 NL_SET_ERR_MSG(extack, "ipv4: Invalid header for netconf dump request");
2122 return -EINVAL;
2123 }
2124
2125 if (nlmsg_attrlen(nlh, sizeof(*ncm))) {
2126 NL_SET_ERR_MSG(extack, "ipv4: Invalid data after header in netconf dump request");
2127 return -EINVAL;
2128 }
2129 }
2130
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002131 s_h = cb->args[0];
2132 s_idx = idx = cb->args[1];
2133
2134 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
2135 idx = 0;
2136 head = &net->dev_index_head[h];
2137 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00002138 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
2139 net->dev_base_seq;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002140 hlist_for_each_entry_rcu(dev, head, index_hlist) {
2141 if (idx < s_idx)
2142 goto cont;
2143 in_dev = __in_dev_get_rcu(dev);
2144 if (!in_dev)
2145 goto cont;
2146
2147 if (inet_netconf_fill_devconf(skb, dev->ifindex,
2148 &in_dev->cnf,
2149 NETLINK_CB(cb->skb).portid,
David Ahernaddd3832018-10-07 20:16:41 -07002150 nlh->nlmsg_seq,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002151 RTM_NEWNETCONF,
2152 NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002153 NETCONFA_ALL) < 0) {
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002154 rcu_read_unlock();
2155 goto done;
2156 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00002157 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002158cont:
2159 idx++;
2160 }
2161 rcu_read_unlock();
2162 }
2163 if (h == NETDEV_HASHENTRIES) {
2164 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
2165 net->ipv4.devconf_all,
2166 NETLINK_CB(cb->skb).portid,
David Ahernaddd3832018-10-07 20:16:41 -07002167 nlh->nlmsg_seq,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002168 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002169 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002170 goto done;
2171 else
2172 h++;
2173 }
2174 if (h == NETDEV_HASHENTRIES + 1) {
2175 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
2176 net->ipv4.devconf_dflt,
2177 NETLINK_CB(cb->skb).portid,
David Ahernaddd3832018-10-07 20:16:41 -07002178 nlh->nlmsg_seq,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002179 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002180 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002181 goto done;
2182 else
2183 h++;
2184 }
2185done:
2186 cb->args[0] = h;
2187 cb->args[1] = idx;
2188
2189 return skb->len;
2190}
2191
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192#ifdef CONFIG_SYSCTL
2193
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002194static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07002195{
2196 struct net_device *dev;
2197
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002198 rcu_read_lock();
2199 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07002200 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002201
Herbert Xu31be3082007-06-04 23:35:37 -07002202 in_dev = __in_dev_get_rcu(dev);
2203 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002204 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07002205 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002206 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07002207}
2208
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002209/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002210static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002211{
2212 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002213 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002214
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002215 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002216 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
David Ahern3b022862017-03-28 14:28:02 -07002217 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2218 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002219 NETCONFA_IFINDEX_ALL,
2220 net->ipv4.devconf_all);
David Ahern3b022862017-03-28 14:28:02 -07002221 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2222 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002223 NETCONFA_IFINDEX_DEFAULT,
2224 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002225
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002226 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002227 struct in_device *in_dev;
Eric Dumazetfa178062016-07-08 05:18:24 +02002228
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002229 if (on)
2230 dev_disable_lro(dev);
Eric Dumazetfa178062016-07-08 05:18:24 +02002231
2232 in_dev = __in_dev_get_rtnl(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002233 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002234 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
David Ahern3b022862017-03-28 14:28:02 -07002235 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2236 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002237 dev->ifindex, &in_dev->cnf);
2238 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002239 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002240}
2241
stephen hemmingerf085ff12013-12-12 13:06:50 -08002242static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf)
2243{
2244 if (cnf == net->ipv4.devconf_dflt)
2245 return NETCONFA_IFINDEX_DEFAULT;
2246 else if (cnf == net->ipv4.devconf_all)
2247 return NETCONFA_IFINDEX_ALL;
2248 else {
2249 struct in_device *idev
2250 = container_of(cnf, struct in_device, cnf);
2251 return idev->dev->ifindex;
2252 }
2253}
2254
Joe Perchesfe2c6332013-06-11 23:04:25 -07002255static int devinet_conf_proc(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002256 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07002257 size_t *lenp, loff_t *ppos)
2258{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002259 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002260 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002261 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07002262
2263 if (write) {
2264 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002265 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07002266 int i = (int *)ctl->data - cnf->data;
stephen hemmingerf085ff12013-12-12 13:06:50 -08002267 int ifindex;
Herbert Xu31be3082007-06-04 23:35:37 -07002268
2269 set_bit(i, cnf->state);
2270
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002271 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002272 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00002273 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
2274 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002275 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002276 rt_cache_flush(net);
stephen hemmingerf085ff12013-12-12 13:06:50 -08002277
Xin Long5cbf7772018-07-27 16:37:28 +08002278 if (i == IPV4_DEVCONF_BC_FORWARDING - 1 &&
2279 new_value != old_value)
2280 rt_cache_flush(net);
2281
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002282 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
2283 new_value != old_value) {
stephen hemmingerf085ff12013-12-12 13:06:50 -08002284 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002285 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2286 NETCONFA_RP_FILTER,
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002287 ifindex, cnf);
2288 }
stephen hemmingerf085ff12013-12-12 13:06:50 -08002289 if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
2290 new_value != old_value) {
2291 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002292 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2293 NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002294 ifindex, cnf);
2295 }
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002296 if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
2297 new_value != old_value) {
2298 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002299 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2300 NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002301 ifindex, cnf);
2302 }
Herbert Xu31be3082007-06-04 23:35:37 -07002303 }
2304
2305 return ret;
2306}
2307
Joe Perchesfe2c6332013-06-11 23:04:25 -07002308static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002309 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 size_t *lenp, loff_t *ppos)
2311{
2312 int *valp = ctl->data;
2313 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00002314 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002315 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316
2317 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002318 struct net *net = ctl->extra2;
2319
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002320 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00002321 if (!rtnl_trylock()) {
2322 /* Restore the original values before restarting */
2323 *valp = val;
2324 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00002325 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00002326 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002327 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2328 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002329 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002330 struct ipv4_devconf *cnf = ctl->extra1;
2331 struct in_device *idev =
2332 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002333 if (*valp)
2334 dev_disable_lro(idev->dev);
David Ahern3b022862017-03-28 14:28:02 -07002335 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002336 NETCONFA_FORWARDING,
2337 idev->dev->ifindex,
2338 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002339 }
2340 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002341 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002342 } else
David Ahern3b022862017-03-28 14:28:02 -07002343 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2344 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002345 NETCONFA_IFINDEX_DEFAULT,
2346 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 }
2348
2349 return ret;
2350}
2351
Joe Perchesfe2c6332013-06-11 23:04:25 -07002352static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
David S. Miller323e1262010-12-12 21:55:08 -08002353 void __user *buffer,
2354 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355{
2356 int *valp = ctl->data;
2357 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002358 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07002359 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
2361 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002362 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363
2364 return ret;
2365}
2366
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002367#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07002368 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07002369 .procname = name, \
2370 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00002371 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002372 .maxlen = sizeof(int), \
2373 .mode = mval, \
2374 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07002375 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002376 }
2377
2378#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002379 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002380
2381#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002382 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002383
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002384#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2385 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002386
2387#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002388 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07002389
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390static struct devinet_sysctl_table {
2391 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00002392 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393} devinet_sysctl = {
2394 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07002395 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002396 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07002397 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
Xin Long5cbf7772018-07-27 16:37:28 +08002398 DEVINET_SYSCTL_RW_ENTRY(BC_FORWARDING, "bc_forwarding"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002399
2400 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
2401 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
2402 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
2403 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
2404 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
2405 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
2406 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00002407 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08002408 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002409 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
2410 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
2411 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
2412 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
2413 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
2414 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
2415 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
2416 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
2417 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08002418 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00002419 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
William Manley5c6fe012013-08-06 19:03:14 +01002420 DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
2421 "force_igmp_version"),
William Manley26900482013-08-06 19:03:15 +01002422 DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
2423 "igmpv2_unsolicited_report_interval"),
2424 DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
2425 "igmpv3_unsolicited_report_interval"),
Andy Gospodarek0eeb0752015-06-23 13:45:37 -04002426 DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
2427 "ignore_routes_with_linkdown"),
Johannes Berg97daf332016-02-04 13:31:18 +01002428 DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
2429 "drop_gratuitous_arp"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002430
2431 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2432 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002433 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
2434 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00002435 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2436 "route_localnet"),
Johannes Berg12b74df2016-02-04 13:31:17 +01002437 DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
2438 "drop_unicast_in_l2_multicast"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440};
2441
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002442static int __devinet_sysctl_register(struct net *net, char *dev_name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002443 int ifindex, struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444{
2445 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002446 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002447 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11002448
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002449 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002451 goto out;
2452
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
2454 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07002455 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002456 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 }
2458
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002459 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002461 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002463 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464
2465 p->sysctl = t;
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002466
David Ahern3b022862017-03-28 14:28:02 -07002467 inet_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_ALL,
2468 ifindex, p);
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002469 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002471free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002473out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002474 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475}
2476
David Ahernb5c96412017-03-28 14:28:03 -07002477static void __devinet_sysctl_unregister(struct net *net,
2478 struct ipv4_devconf *cnf, int ifindex)
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002479{
2480 struct devinet_sysctl_table *t = cnf->sysctl;
2481
David Ahernb5c96412017-03-28 14:28:03 -07002482 if (t) {
2483 cnf->sysctl = NULL;
2484 unregister_net_sysctl_table(t->sysctl_header);
2485 kfree(t);
2486 }
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002487
David Ahernb5c96412017-03-28 14:28:03 -07002488 inet_netconf_notify_devconf(net, RTM_DELNETCONF, 0, ifindex, NULL);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002489}
2490
WANG Cong20e61da2014-07-25 15:25:08 -07002491static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002492{
WANG Cong20e61da2014-07-25 15:25:08 -07002493 int err;
2494
2495 if (!sysctl_dev_name_is_allowed(idev->dev->name))
2496 return -EINVAL;
2497
2498 err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
2499 if (err)
2500 return err;
2501 err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002502 idev->dev->ifindex, &idev->cnf);
WANG Cong20e61da2014-07-25 15:25:08 -07002503 if (err)
2504 neigh_sysctl_unregister(idev->arp_parms);
2505 return err;
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002506}
2507
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002508static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509{
David Ahernb5c96412017-03-28 14:28:03 -07002510 struct net *net = dev_net(idev->dev);
2511
2512 __devinet_sysctl_unregister(net, &idev->cnf, idev->dev->ifindex);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002513 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002516static struct ctl_table ctl_forward_entry[] = {
2517 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002518 .procname = "ip_forward",
2519 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00002520 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002521 .maxlen = sizeof(int),
2522 .mode = 0644,
2523 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002524 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002525 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002526 },
2527 { },
2528};
Eric Dumazet2a75de02008-01-05 23:08:49 -08002529#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002530
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002531static __net_init int devinet_init_net(struct net *net)
2532{
2533 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002534 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002535#ifdef CONFIG_SYSCTL
2536 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002537 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002538#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002539
2540 err = -ENOMEM;
2541 all = &ipv4_devconf;
2542 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002543
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002544 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002545 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002546 if (!all)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002547 goto err_alloc_all;
2548
2549 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002550 if (!dflt)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002551 goto err_alloc_dflt;
2552
Eric Dumazet2a75de02008-01-05 23:08:49 -08002553#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002554 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002555 if (!tbl)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002556 goto err_alloc_ctl;
2557
Eric W. Biederman02291682010-02-14 03:25:51 +00002558 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002559 tbl[0].extra1 = all;
2560 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002561#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002562 }
2563
2564#ifdef CONFIG_SYSCTL
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002565 err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002566 if (err < 0)
2567 goto err_reg_all;
2568
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002569 err = __devinet_sysctl_register(net, "default",
2570 NETCONFA_IFINDEX_DEFAULT, dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002571 if (err < 0)
2572 goto err_reg_dflt;
2573
2574 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002575 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Ian Morris51456b22015-04-03 09:17:26 +01002576 if (!forw_hdr)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002577 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002578 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002579#endif
2580
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002581 net->ipv4.devconf_all = all;
2582 net->ipv4.devconf_dflt = dflt;
2583 return 0;
2584
2585#ifdef CONFIG_SYSCTL
2586err_reg_ctl:
David Ahernb5c96412017-03-28 14:28:03 -07002587 __devinet_sysctl_unregister(net, dflt, NETCONFA_IFINDEX_DEFAULT);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002588err_reg_dflt:
David Ahernb5c96412017-03-28 14:28:03 -07002589 __devinet_sysctl_unregister(net, all, NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002590err_reg_all:
2591 if (tbl != ctl_forward_entry)
2592 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002593err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08002594#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002595 if (dflt != &ipv4_devconf_dflt)
2596 kfree(dflt);
2597err_alloc_dflt:
2598 if (all != &ipv4_devconf)
2599 kfree(all);
2600err_alloc_all:
2601 return err;
2602}
2603
2604static __net_exit void devinet_exit_net(struct net *net)
2605{
Eric Dumazet2a75de02008-01-05 23:08:49 -08002606#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002607 struct ctl_table *tbl;
2608
2609 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002610 unregister_net_sysctl_table(net->ipv4.forw_hdr);
David Ahernb5c96412017-03-28 14:28:03 -07002611 __devinet_sysctl_unregister(net, net->ipv4.devconf_dflt,
2612 NETCONFA_IFINDEX_DEFAULT);
2613 __devinet_sysctl_unregister(net, net->ipv4.devconf_all,
2614 NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002615 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08002616#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002617 kfree(net->ipv4.devconf_dflt);
2618 kfree(net->ipv4.devconf_all);
2619}
2620
2621static __net_initdata struct pernet_operations devinet_ops = {
2622 .init = devinet_init_net,
2623 .exit = devinet_exit_net,
2624};
2625
Daniel Borkmann207895fd32015-01-29 12:15:03 +01002626static struct rtnl_af_ops inet_af_ops __read_mostly = {
Thomas Graf9f0f7272010-11-16 04:32:48 +00002627 .family = AF_INET,
2628 .fill_link_af = inet_fill_link_af,
2629 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00002630 .validate_link_af = inet_validate_link_af,
2631 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00002632};
2633
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634void __init devinet_init(void)
2635{
David S. Millerfd23c3b2011-02-18 12:42:28 -08002636 int i;
2637
2638 for (i = 0; i < IN4_ADDR_HSIZE; i++)
2639 INIT_HLIST_HEAD(&inet_addr_lst[i]);
2640
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002641 register_pernet_subsys(&devinet_ops);
2642
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 register_gifconf(PF_INET, inet_gifconf);
2644 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07002645
viresh kumar906e0732014-01-22 12:23:32 +05302646 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +00002647
Thomas Graf9f0f7272010-11-16 04:32:48 +00002648 rtnl_af_register(&inet_af_ops);
2649
Florian Westphalb97bac62017-08-09 20:41:48 +02002650 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, 0);
2651 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, 0);
2652 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, 0);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002653 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
Florian Westphalb97bac62017-08-09 20:41:48 +02002654 inet_netconf_dump_devconf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655}