blob: d9bb3ae78560824e81624d2d73f58aeec65ba3f6 [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
Matteo Croce82a65c62019-07-01 19:01:55 +020069#define IPV6ONLY_FLAGS \
70 (IFA_F_NODAD | IFA_F_OPTIMISTIC | IFA_F_DADFAILED | \
71 IFA_F_HOMEADDRESS | IFA_F_TENTATIVE | \
72 IFA_F_MANAGETEMPADDR | IFA_F_STABLE_PRIVACY)
73
Adrian Bunk0027ba82008-01-31 17:17:31 -080074static struct ipv4_devconf ipv4_devconf = {
Herbert Xu42f811b2007-06-04 23:34:44 -070075 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000076 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
77 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
78 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
79 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
William Manley26900482013-08-06 19:03:15 +010080 [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
81 [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
Herbert Xu42f811b2007-06-04 23:34:44 -070082 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070083};
84
85static struct ipv4_devconf ipv4_devconf_dflt = {
Herbert Xu42f811b2007-06-04 23:34:44 -070086 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000087 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
88 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
89 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
90 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
91 [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
William Manley26900482013-08-06 19:03:15 +010092 [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
93 [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
Herbert Xu42f811b2007-06-04 23:34:44 -070094 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070095};
96
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -080097#define IPV4_DEVCONF_DFLT(net, attr) \
98 IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr)
Herbert Xu42f811b2007-06-04 23:34:44 -070099
Patrick McHardyef7c79e2007-06-05 12:38:30 -0700100static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
Thomas Graf5c753972006-08-04 23:03:53 -0700101 [IFA_LOCAL] = { .type = NLA_U32 },
102 [IFA_ADDRESS] = { .type = NLA_U32 },
103 [IFA_BROADCAST] = { .type = NLA_U32 },
Thomas Graf5176f912006-08-26 20:13:18 -0700104 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
Jiri Pirko5c766d62013-01-24 09:41:41 +0000105 [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100106 [IFA_FLAGS] = { .type = NLA_U32 },
Thomas Graf5c753972006-08-04 23:03:53 -0700107};
108
Eric Dumazet40384992012-08-03 21:06:50 +0000109#define IN4_ADDR_HSIZE_SHIFT 8
110#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT)
111
David S. Millerfd23c3b2011-02-18 12:42:28 -0800112static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
David S. Millerfd23c3b2011-02-18 12:42:28 -0800113
Eric Dumazet6eada012015-03-18 14:05:33 -0700114static u32 inet_addr_hash(const struct net *net, __be32 addr)
David S. Millerfd23c3b2011-02-18 12:42:28 -0800115{
Eric Dumazet40384992012-08-03 21:06:50 +0000116 u32 val = (__force u32) addr ^ net_hash_mix(net);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800117
Eric Dumazet40384992012-08-03 21:06:50 +0000118 return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800119}
120
121static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
122{
Eric Dumazet40384992012-08-03 21:06:50 +0000123 u32 hash = inet_addr_hash(net, ifa->ifa_local);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800124
WANG Cong32a4be42014-05-06 11:15:56 -0700125 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800126 hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800127}
128
129static void inet_hash_remove(struct in_ifaddr *ifa)
130{
WANG Cong32a4be42014-05-06 11:15:56 -0700131 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800132 hlist_del_init_rcu(&ifa->hash);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800133}
134
David S. Miller9435eb12011-02-18 12:43:09 -0800135/**
136 * __ip_dev_find - find the first device with a given source address.
137 * @net: the net namespace
138 * @addr: the source address
139 * @devref: if true, take a reference on the found device
140 *
141 * If a caller uses devref=false, it should be protected by RCU, or RTNL
142 */
143struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
144{
Eric Dumazet40384992012-08-03 21:06:50 +0000145 u32 hash = inet_addr_hash(net, addr);
David S. Miller9435eb12011-02-18 12:43:09 -0800146 struct net_device *result = NULL;
147 struct in_ifaddr *ifa;
David S. Miller9435eb12011-02-18 12:43:09 -0800148
149 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800150 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash) {
David S. Millere0660082011-03-03 11:24:19 -0800151 if (ifa->ifa_local == addr) {
Eric Dumazet40384992012-08-03 21:06:50 +0000152 struct net_device *dev = ifa->ifa_dev->dev;
153
154 if (!net_eq(dev_net(dev), net))
155 continue;
David S. Miller9435eb12011-02-18 12:43:09 -0800156 result = dev;
157 break;
158 }
159 }
David S. Miller406b6f92011-03-22 21:56:23 -0700160 if (!result) {
161 struct flowi4 fl4 = { .daddr = addr };
162 struct fib_result res = { 0 };
163 struct fib_table *local;
164
165 /* Fallback to FIB local table so that communication
166 * over loopback subnets work.
167 */
168 local = fib_get_table(net, RT_TABLE_LOCAL);
169 if (local &&
170 !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
171 res.type == RTN_LOCAL)
172 result = FIB_RES_DEV(res);
173 }
David S. Miller9435eb12011-02-18 12:43:09 -0800174 if (result && devref)
175 dev_hold(result);
176 rcu_read_unlock();
177 return result;
178}
179EXPORT_SYMBOL(__ip_dev_find);
180
Thomas Grafd6062cb2006-08-15 00:33:59 -0700181static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Alan Sterne041c682006-03-27 01:16:30 -0800183static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Krister Johansen3ad7d242017-06-08 13:12:14 -0700184static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
186 int destroy);
187#ifdef CONFIG_SYSCTL
WANG Cong20e61da2014-07-25 15:25:08 -0700188static int devinet_sysctl_register(struct in_device *idev);
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800189static void devinet_sysctl_unregister(struct in_device *idev);
190#else
WANG Cong20e61da2014-07-25 15:25:08 -0700191static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800192{
WANG Cong20e61da2014-07-25 15:25:08 -0700193 return 0;
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800194}
Eric Dumazet40384992012-08-03 21:06:50 +0000195static void devinet_sysctl_unregister(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800196{
197}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198#endif
199
200/* Locks all the inet devices. */
201
202static struct in_ifaddr *inet_alloc_ifa(void)
203{
Alexey Dobriyan93adcc82008-10-28 13:25:09 -0700204 return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205}
206
207static void inet_rcu_free_ifa(struct rcu_head *head)
208{
209 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
210 if (ifa->ifa_dev)
211 in_dev_put(ifa->ifa_dev);
212 kfree(ifa);
213}
214
Eric Dumazet40384992012-08-03 21:06:50 +0000215static void inet_free_ifa(struct in_ifaddr *ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216{
217 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
218}
219
220void in_dev_finish_destroy(struct in_device *idev)
221{
222 struct net_device *dev = idev->dev;
223
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700224 WARN_ON(idev->ifa_list);
225 WARN_ON(idev->mc_list);
Eric Dumazete9897072013-06-07 08:48:57 -0700226 kfree(rcu_dereference_protected(idev->mc_hash, 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227#ifdef NET_REFCNT_DEBUG
Joe Perches91df42b2012-05-15 14:11:54 +0000228 pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229#endif
230 dev_put(dev);
231 if (!idev->dead)
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800232 pr_err("Freeing alive in_device %p\n", idev);
233 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 kfree(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800236EXPORT_SYMBOL(in_dev_finish_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
Herbert Xu71e27da2007-06-04 23:36:06 -0700238static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239{
240 struct in_device *in_dev;
WANG Cong20e61da2014-07-25 15:25:08 -0700241 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
243 ASSERT_RTNL();
244
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700245 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 if (!in_dev)
247 goto out;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900248 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -0800249 sizeof(in_dev->cnf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 in_dev->cnf.sysctl = NULL;
251 in_dev->dev = dev;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800252 in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
253 if (!in_dev->arp_parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 goto out_kfree;
Ben Hutchings0187bdf2008-06-19 16:15:47 -0700255 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
256 dev_disable_lro(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 /* Reference in_dev->dev */
258 dev_hold(dev);
David L Stevens30c4cf52007-01-04 12:31:14 -0800259 /* Account for reference dev->ip_ptr (below) */
Reshetova, Elena7658b362017-06-30 13:08:03 +0300260 refcount_set(&in_dev->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
WANG Cong20e61da2014-07-25 15:25:08 -0700262 err = devinet_sysctl_register(in_dev);
263 if (err) {
264 in_dev->dead = 1;
Yang Yingliang3e246aa2020-05-30 11:34:33 +0800265 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
WANG Cong20e61da2014-07-25 15:25:08 -0700266 in_dev_put(in_dev);
267 in_dev = NULL;
268 goto out;
269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 ip_mc_init_dev(in_dev);
271 if (dev->flags & IFF_UP)
272 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800273
David L Stevens30c4cf52007-01-04 12:31:14 -0800274 /* we can receive as soon as ip_ptr is set -- do this last */
Eric Dumazetcf778b02012-01-12 04:41:32 +0000275 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800276out:
WANG Cong20e61da2014-07-25 15:25:08 -0700277 return in_dev ?: ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278out_kfree:
279 kfree(in_dev);
280 in_dev = NULL;
281 goto out;
282}
283
284static void in_dev_rcu_put(struct rcu_head *head)
285{
286 struct in_device *idev = container_of(head, struct in_device, rcu_head);
287 in_dev_put(idev);
288}
289
290static void inetdev_destroy(struct in_device *in_dev)
291{
292 struct in_ifaddr *ifa;
293 struct net_device *dev;
294
295 ASSERT_RTNL();
296
297 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
299 in_dev->dead = 1;
300
301 ip_mc_destroy_dev(in_dev);
302
303 while ((ifa = in_dev->ifa_list) != NULL) {
304 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
305 inet_free_ifa(ifa);
306 }
307
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000308 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800310 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
312 arp_ifdown(dev);
313
314 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
315}
316
Al Viroff428d72006-09-26 22:13:35 -0700317int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
319 rcu_read_lock();
320 for_primary_ifa(in_dev) {
321 if (inet_ifa_match(a, ifa)) {
322 if (!b || inet_ifa_match(b, ifa)) {
323 rcu_read_unlock();
324 return 1;
325 }
326 }
327 } endfor_ifa(in_dev);
328 rcu_read_unlock();
329 return 0;
330}
331
Thomas Grafd6062cb2006-08-15 00:33:59 -0700332static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000333 int destroy, struct nlmsghdr *nlh, u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
Harald Welte8f937c62005-05-29 20:23:46 -0700335 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800336 struct in_ifaddr *ifa, *ifa1 = *ifap;
337 struct in_ifaddr *last_prim = in_dev->ifa_list;
338 struct in_ifaddr *prev_prom = NULL;
339 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
341 ASSERT_RTNL();
342
David S. Millerfbd40ea2016-03-13 23:28:00 -0400343 if (in_dev->dead)
344 goto no_promotions;
345
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900346 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700347 * unless alias promotion is set
348 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
350 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
352
353 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900354 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800355 ifa1->ifa_scope <= ifa->ifa_scope)
356 last_prim = ifa;
357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
359 ifa1->ifa_mask != ifa->ifa_mask ||
360 !inet_ifa_match(ifa1->ifa_address, ifa)) {
361 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800362 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 continue;
364 }
365
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800366 if (!do_promote) {
David S. Millerfd23c3b2011-02-18 12:42:28 -0800367 inet_hash_remove(ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700368 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
Eric W. Biederman15e47302012-09-07 20:12:54 +0000370 rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800371 blocking_notifier_call_chain(&inetaddr_chain,
372 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700373 inet_free_ifa(ifa);
374 } else {
375 promote = ifa;
376 break;
377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 }
379 }
380
Julian Anastasov2d230e22011-03-19 12:13:52 +0000381 /* On promotion all secondaries from subnet are changing
382 * the primary IP, we must remove all their routes silently
383 * and later to add them back with new prefsrc. Do this
384 * while all addresses are on the device list.
385 */
386 for (ifa = promote; ifa; ifa = ifa->ifa_next) {
387 if (ifa1->ifa_mask == ifa->ifa_mask &&
388 inet_ifa_match(ifa1->ifa_address, ifa))
389 fib_del_ifaddr(ifa, ifa1);
390 }
391
David S. Millerfbd40ea2016-03-13 23:28:00 -0400392no_promotions:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 /* 2. Unlink it */
394
395 *ifap = ifa1->ifa_next;
David S. Millerfd23c3b2011-02-18 12:42:28 -0800396 inet_hash_remove(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
398 /* 3. Announce address deletion */
399
400 /* Send message first, then call notifier.
401 At first sight, FIB update triggered by notifier
402 will refer to already deleted ifaddr, that could confuse
403 netlink listeners. It is not true: look, gated sees
404 that route deleted and if it still thinks that ifaddr
405 is valid, it will try to restore deleted routes... Grr.
406 So that, this order is correct.
407 */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000408 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800409 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800410
411 if (promote) {
Julian Anastasov04024b92011-03-19 12:13:54 +0000412 struct in_ifaddr *next_sec = promote->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800413
414 if (prev_prom) {
415 prev_prom->ifa_next = promote->ifa_next;
416 promote->ifa_next = last_prim->ifa_next;
417 last_prim->ifa_next = promote;
418 }
419
420 promote->ifa_flags &= ~IFA_F_SECONDARY;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000421 rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800422 blocking_notifier_call_chain(&inetaddr_chain,
423 NETDEV_UP, promote);
Julian Anastasov04024b92011-03-19 12:13:54 +0000424 for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800425 if (ifa1->ifa_mask != ifa->ifa_mask ||
426 !inet_ifa_match(ifa1->ifa_address, ifa))
427 continue;
428 fib_add_ifaddr(ifa);
429 }
430
431 }
Herbert Xu63630972007-06-07 18:35:38 -0700432 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434}
435
Thomas Grafd6062cb2006-08-15 00:33:59 -0700436static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
437 int destroy)
438{
439 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
440}
441
Jiri Pirko5c766d62013-01-24 09:41:41 +0000442static void check_lifetime(struct work_struct *work);
443
444static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
445
Thomas Grafd6062cb2006-08-15 00:33:59 -0700446static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000447 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
449 struct in_device *in_dev = ifa->ifa_dev;
450 struct in_ifaddr *ifa1, **ifap, **last_primary;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700451 struct in_validator_info ivi;
452 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453
454 ASSERT_RTNL();
455
456 if (!ifa->ifa_local) {
457 inet_free_ifa(ifa);
458 return 0;
459 }
460
461 ifa->ifa_flags &= ~IFA_F_SECONDARY;
462 last_primary = &in_dev->ifa_list;
463
Matteo Croce82a65c62019-07-01 19:01:55 +0200464 /* Don't set IPv6 only flags to IPv4 addresses */
465 ifa->ifa_flags &= ~IPV6ONLY_FLAGS;
466
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
468 ifap = &ifa1->ifa_next) {
469 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
470 ifa->ifa_scope <= ifa1->ifa_scope)
471 last_primary = &ifa1->ifa_next;
472 if (ifa1->ifa_mask == ifa->ifa_mask &&
473 inet_ifa_match(ifa1->ifa_address, ifa)) {
474 if (ifa1->ifa_local == ifa->ifa_local) {
475 inet_free_ifa(ifa);
476 return -EEXIST;
477 }
478 if (ifa1->ifa_scope != ifa->ifa_scope) {
479 inet_free_ifa(ifa);
480 return -EINVAL;
481 }
482 ifa->ifa_flags |= IFA_F_SECONDARY;
483 }
484 }
485
Krister Johansen3ad7d242017-06-08 13:12:14 -0700486 /* Allow any devices that wish to register ifaddr validtors to weigh
487 * in now, before changes are committed. The rntl lock is serializing
488 * access here, so the state should not change between a validator call
489 * and a final notify on commit. This isn't invoked on promotion under
490 * the assumption that validators are checking the address itself, and
491 * not the flags.
492 */
493 ivi.ivi_addr = ifa->ifa_address;
494 ivi.ivi_dev = ifa->ifa_dev;
495 ret = blocking_notifier_call_chain(&inetaddr_validator_chain,
496 NETDEV_UP, &ivi);
497 ret = notifier_to_errno(ret);
498 if (ret) {
499 inet_free_ifa(ifa);
500 return ret;
501 }
502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500504 prandom_seed((__force u32) ifa->ifa_local);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 ifap = last_primary;
506 }
507
508 ifa->ifa_next = *ifap;
509 *ifap = ifa;
510
David S. Millerfd23c3b2011-02-18 12:42:28 -0800511 inet_hash_insert(dev_net(in_dev->dev), ifa);
512
Jiri Pirko5c766d62013-01-24 09:41:41 +0000513 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530514 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000515
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 /* Send message first, then call notifier.
517 Notifier will trigger FIB update, so that
518 listeners of netlink will know about new ifaddr */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000519 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800520 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
522 return 0;
523}
524
Thomas Grafd6062cb2006-08-15 00:33:59 -0700525static int inet_insert_ifa(struct in_ifaddr *ifa)
526{
527 return __inet_insert_ifa(ifa, NULL, 0);
528}
529
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
531{
Herbert Xue5ed6392005-10-03 14:35:55 -0700532 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
534 ASSERT_RTNL();
535
536 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700537 inet_free_ifa(ifa);
538 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700540 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100541 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700543 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 in_dev_hold(in_dev);
545 ifa->ifa_dev = in_dev;
546 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800547 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 ifa->ifa_scope = RT_SCOPE_HOST;
549 return inet_insert_ifa(ifa);
550}
551
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000552/* Caller must hold RCU or RTNL :
553 * We dont take a reference on found in_device
554 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800555struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556{
557 struct net_device *dev;
558 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000559
560 rcu_read_lock();
561 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000563 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000564 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 return in_dev;
566}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800567EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
569/* Called only from RTNL semaphored context. No locks. */
570
Al Viro60cad5d2006-09-26 22:17:09 -0700571struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
572 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573{
574 ASSERT_RTNL();
575
576 for_primary_ifa(in_dev) {
577 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
578 return ifa;
579 } endfor_ifa(in_dev);
580 return NULL;
581}
582
Taras Chornyicce0d1b2020-04-09 20:25:24 +0300583static int ip_mc_autojoin_config(struct net *net, bool join,
584 const struct in_ifaddr *ifa)
Madhu Challa93a714d2015-02-25 09:58:35 -0800585{
Taras Chornyicce0d1b2020-04-09 20:25:24 +0300586#if defined(CONFIG_IP_MULTICAST)
Madhu Challa93a714d2015-02-25 09:58:35 -0800587 struct ip_mreqn mreq = {
588 .imr_multiaddr.s_addr = ifa->ifa_address,
589 .imr_ifindex = ifa->ifa_dev->dev->ifindex,
590 };
Taras Chornyicce0d1b2020-04-09 20:25:24 +0300591 struct sock *sk = net->ipv4.mc_autojoin_sk;
Madhu Challa93a714d2015-02-25 09:58:35 -0800592 int ret;
593
594 ASSERT_RTNL();
595
596 lock_sock(sk);
597 if (join)
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300598 ret = ip_mc_join_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800599 else
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300600 ret = ip_mc_leave_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800601 release_sock(sk);
602
603 return ret;
Taras Chornyicce0d1b2020-04-09 20:25:24 +0300604#else
605 return -EOPNOTSUPP;
606#endif
Madhu Challa93a714d2015-02-25 09:58:35 -0800607}
608
David Ahernc21ef3e2017-04-16 09:48:24 -0700609static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
610 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900612 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700613 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700615 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700617 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
619 ASSERT_RTNL();
620
Johannes Bergfceb6432017-04-12 14:34:07 +0200621 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -0700622 extack);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700623 if (err < 0)
624 goto errout;
625
626 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800627 in_dev = inetdev_by_index(net, ifm->ifa_index);
Ian Morris51456b22015-04-03 09:17:26 +0100628 if (!in_dev) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700629 err = -ENODEV;
630 goto errout;
631 }
632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
634 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700635 if (tb[IFA_LOCAL] &&
Jiri Benc67b61f62015-03-29 16:59:26 +0200636 ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700638
639 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
640 continue;
641
642 if (tb[IFA_ADDRESS] &&
643 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Jiri Benc67b61f62015-03-29 16:59:26 +0200644 !inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700645 continue;
646
Madhu Challa93a714d2015-02-25 09:58:35 -0800647 if (ipv4_is_multicast(ifa->ifa_address))
Taras Chornyicce0d1b2020-04-09 20:25:24 +0300648 ip_mc_autojoin_config(net, false, ifa);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000649 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 return 0;
651 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700652
653 err = -EADDRNOTAVAIL;
654errout:
655 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656}
657
Jiri Pirko5c766d62013-01-24 09:41:41 +0000658#define INFINITY_LIFE_TIME 0xFFFFFFFF
659
660static void check_lifetime(struct work_struct *work)
661{
662 unsigned long now, next, next_sec, next_sched;
663 struct in_ifaddr *ifa;
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000664 struct hlist_node *n;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000665 int i;
666
667 now = jiffies;
668 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
669
Jiri Pirko5c766d62013-01-24 09:41:41 +0000670 for (i = 0; i < IN4_ADDR_HSIZE; i++) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000671 bool change_needed = false;
672
673 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800674 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
Jiri Pirko5c766d62013-01-24 09:41:41 +0000675 unsigned long age;
676
677 if (ifa->ifa_flags & IFA_F_PERMANENT)
678 continue;
679
680 /* We try to batch several events at once. */
681 age = (now - ifa->ifa_tstamp +
682 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
683
684 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
685 age >= ifa->ifa_valid_lft) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000686 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000687 } else if (ifa->ifa_preferred_lft ==
688 INFINITY_LIFE_TIME) {
689 continue;
690 } else if (age >= ifa->ifa_preferred_lft) {
691 if (time_before(ifa->ifa_tstamp +
692 ifa->ifa_valid_lft * HZ, next))
693 next = ifa->ifa_tstamp +
694 ifa->ifa_valid_lft * HZ;
695
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000696 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
697 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000698 } else if (time_before(ifa->ifa_tstamp +
699 ifa->ifa_preferred_lft * HZ,
700 next)) {
701 next = ifa->ifa_tstamp +
702 ifa->ifa_preferred_lft * HZ;
703 }
704 }
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000705 rcu_read_unlock();
706 if (!change_needed)
707 continue;
708 rtnl_lock();
709 hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
710 unsigned long age;
711
712 if (ifa->ifa_flags & IFA_F_PERMANENT)
713 continue;
714
715 /* We try to batch several events at once. */
716 age = (now - ifa->ifa_tstamp +
717 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
718
719 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
720 age >= ifa->ifa_valid_lft) {
721 struct in_ifaddr **ifap;
722
723 for (ifap = &ifa->ifa_dev->ifa_list;
724 *ifap != NULL; ifap = &(*ifap)->ifa_next) {
725 if (*ifap == ifa) {
726 inet_del_ifa(ifa->ifa_dev,
727 ifap, 1);
728 break;
729 }
730 }
731 } else if (ifa->ifa_preferred_lft !=
732 INFINITY_LIFE_TIME &&
733 age >= ifa->ifa_preferred_lft &&
734 !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
735 ifa->ifa_flags |= IFA_F_DEPRECATED;
736 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
737 }
738 }
739 rtnl_unlock();
Jiri Pirko5c766d62013-01-24 09:41:41 +0000740 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000741
742 next_sec = round_jiffies_up(next);
743 next_sched = next;
744
745 /* If rounded timeout is accurate enough, accept it. */
746 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
747 next_sched = next_sec;
748
749 now = jiffies;
750 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
751 if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
752 next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
753
viresh kumar906e0732014-01-22 12:23:32 +0530754 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work,
755 next_sched - now);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000756}
757
758static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
759 __u32 prefered_lft)
760{
761 unsigned long timeout;
762
763 ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
764
765 timeout = addrconf_timeout_fixup(valid_lft, HZ);
766 if (addrconf_finite_timeout(timeout))
767 ifa->ifa_valid_lft = timeout;
768 else
769 ifa->ifa_flags |= IFA_F_PERMANENT;
770
771 timeout = addrconf_timeout_fixup(prefered_lft, HZ);
772 if (addrconf_finite_timeout(timeout)) {
773 if (timeout == 0)
774 ifa->ifa_flags |= IFA_F_DEPRECATED;
775 ifa->ifa_preferred_lft = timeout;
776 }
777 ifa->ifa_tstamp = jiffies;
778 if (!ifa->ifa_cstamp)
779 ifa->ifa_cstamp = ifa->ifa_tstamp;
780}
781
782static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
783 __u32 *pvalid_lft, __u32 *pprefered_lft)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784{
Thomas Graf5c753972006-08-04 23:03:53 -0700785 struct nlattr *tb[IFA_MAX+1];
786 struct in_ifaddr *ifa;
787 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 struct net_device *dev;
789 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800790 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
Johannes Bergfceb6432017-04-12 14:34:07 +0200792 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
793 NULL);
Thomas Graf5c753972006-08-04 23:03:53 -0700794 if (err < 0)
795 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
Thomas Graf5c753972006-08-04 23:03:53 -0700797 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800798 err = -EINVAL;
Ian Morris51456b22015-04-03 09:17:26 +0100799 if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL])
Thomas Graf5c753972006-08-04 23:03:53 -0700800 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800802 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800803 err = -ENODEV;
Ian Morris51456b22015-04-03 09:17:26 +0100804 if (!dev)
Thomas Graf5c753972006-08-04 23:03:53 -0700805 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
Thomas Graf5c753972006-08-04 23:03:53 -0700807 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800808 err = -ENOBUFS;
Ian Morris51456b22015-04-03 09:17:26 +0100809 if (!in_dev)
Herbert Xu71e27da2007-06-04 23:36:06 -0700810 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
Thomas Graf5c753972006-08-04 23:03:53 -0700812 ifa = inet_alloc_ifa();
Ian Morris51456b22015-04-03 09:17:26 +0100813 if (!ifa)
Thomas Graf5c753972006-08-04 23:03:53 -0700814 /*
815 * A potential indev allocation can be left alive, it stays
816 * assigned to its device and is destroy with it.
817 */
Thomas Graf5c753972006-08-04 23:03:53 -0700818 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700819
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800820 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100821 neigh_parms_data_state_setall(in_dev->arp_parms);
Thomas Graf5c753972006-08-04 23:03:53 -0700822 in_dev_hold(in_dev);
823
Ian Morris51456b22015-04-03 09:17:26 +0100824 if (!tb[IFA_ADDRESS])
Thomas Graf5c753972006-08-04 23:03:53 -0700825 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
826
David S. Millerfd23c3b2011-02-18 12:42:28 -0800827 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
829 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100830 ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
831 ifm->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700833 ifa->ifa_dev = in_dev;
834
Jiri Benc67b61f62015-03-29 16:59:26 +0200835 ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]);
836 ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700837
838 if (tb[IFA_BROADCAST])
Jiri Benc67b61f62015-03-29 16:59:26 +0200839 ifa->ifa_broadcast = nla_get_in_addr(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700840
Thomas Graf5c753972006-08-04 23:03:53 -0700841 if (tb[IFA_LABEL])
842 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 else
844 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
845
Jiri Pirko5c766d62013-01-24 09:41:41 +0000846 if (tb[IFA_CACHEINFO]) {
847 struct ifa_cacheinfo *ci;
848
849 ci = nla_data(tb[IFA_CACHEINFO]);
850 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
851 err = -EINVAL;
Daniel Borkmann446266b2013-08-02 11:32:43 +0200852 goto errout_free;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000853 }
854 *pvalid_lft = ci->ifa_valid;
855 *pprefered_lft = ci->ifa_prefered;
856 }
857
Thomas Graf5c753972006-08-04 23:03:53 -0700858 return ifa;
859
Daniel Borkmann446266b2013-08-02 11:32:43 +0200860errout_free:
861 inet_free_ifa(ifa);
Thomas Graf5c753972006-08-04 23:03:53 -0700862errout:
863 return ERR_PTR(err);
864}
865
Jiri Pirko5c766d62013-01-24 09:41:41 +0000866static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
867{
868 struct in_device *in_dev = ifa->ifa_dev;
869 struct in_ifaddr *ifa1, **ifap;
870
871 if (!ifa->ifa_local)
872 return NULL;
873
874 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
875 ifap = &ifa1->ifa_next) {
876 if (ifa1->ifa_mask == ifa->ifa_mask &&
877 inet_ifa_match(ifa1->ifa_address, ifa) &&
878 ifa1->ifa_local == ifa->ifa_local)
879 return ifa1;
880 }
881 return NULL;
882}
883
David Ahernc21ef3e2017-04-16 09:48:24 -0700884static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
885 struct netlink_ext_ack *extack)
Thomas Graf5c753972006-08-04 23:03:53 -0700886{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900887 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700888 struct in_ifaddr *ifa;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000889 struct in_ifaddr *ifa_existing;
890 __u32 valid_lft = INFINITY_LIFE_TIME;
891 __u32 prefered_lft = INFINITY_LIFE_TIME;
Thomas Graf5c753972006-08-04 23:03:53 -0700892
893 ASSERT_RTNL();
894
Jiri Pirko5c766d62013-01-24 09:41:41 +0000895 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft);
Thomas Graf5c753972006-08-04 23:03:53 -0700896 if (IS_ERR(ifa))
897 return PTR_ERR(ifa);
898
Jiri Pirko5c766d62013-01-24 09:41:41 +0000899 ifa_existing = find_matching_ifa(ifa);
900 if (!ifa_existing) {
901 /* It would be best to check for !NLM_F_CREATE here but
stephen hemminger614d0562014-05-16 20:46:58 -0700902 * userspace already relies on not having to provide this.
Jiri Pirko5c766d62013-01-24 09:41:41 +0000903 */
904 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Madhu Challa93a714d2015-02-25 09:58:35 -0800905 if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
Taras Chornyicce0d1b2020-04-09 20:25:24 +0300906 int ret = ip_mc_autojoin_config(net, true, ifa);
Madhu Challa93a714d2015-02-25 09:58:35 -0800907
908 if (ret < 0) {
909 inet_free_ifa(ifa);
910 return ret;
911 }
912 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000913 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
914 } else {
915 inet_free_ifa(ifa);
916
917 if (nlh->nlmsg_flags & NLM_F_EXCL ||
918 !(nlh->nlmsg_flags & NLM_F_REPLACE))
919 return -EEXIST;
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000920 ifa = ifa_existing;
921 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Jiri Pirko05a324b2013-04-04 23:39:38 +0000922 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530923 queue_delayed_work(system_power_efficient_wq,
924 &check_lifetime_work, 0);
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000925 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000926 }
927 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928}
929
930/*
931 * Determine a default network mask, based on the IP address.
932 */
933
Eric Dumazet40384992012-08-03 21:06:50 +0000934static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935{
936 int rc = -1; /* Something else, probably a multicast. */
937
Joe Perchesf97c1e02007-12-16 13:45:43 -0800938 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900939 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 else {
Al Viro714e85b2006-11-14 20:51:49 -0800941 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
Al Viro714e85b2006-11-14 20:51:49 -0800943 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800945 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800947 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 rc = 24;
949 }
950
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900951 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952}
953
954
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800955int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956{
957 struct ifreq ifr;
958 struct sockaddr_in sin_orig;
959 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
960 struct in_device *in_dev;
961 struct in_ifaddr **ifap = NULL;
962 struct in_ifaddr *ifa = NULL;
963 struct net_device *dev;
964 char *colon;
965 int ret = -EFAULT;
966 int tryaddrmatch = 0;
967
968 /*
969 * Fetch the caller's info block into kernel space
970 */
971
972 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
973 goto out;
974 ifr.ifr_name[IFNAMSIZ - 1] = 0;
975
976 /* save original address for comparison */
977 memcpy(&sin_orig, sin, sizeof(*sin));
978
979 colon = strchr(ifr.ifr_name, ':');
980 if (colon)
981 *colon = 0;
982
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800983 dev_load(net, ifr.ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Stephen Hemminger132adf52007-03-08 20:44:43 -0800985 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 case SIOCGIFADDR: /* Get interface address */
987 case SIOCGIFBRDADDR: /* Get the broadcast address */
988 case SIOCGIFDSTADDR: /* Get the destination address */
989 case SIOCGIFNETMASK: /* Get the netmask for the interface */
990 /* Note that these ioctls will not sleep,
991 so that we do not impose a lock.
992 One day we will be forced to put shlock here (I mean SMP)
993 */
994 tryaddrmatch = (sin_orig.sin_family == AF_INET);
995 memset(sin, 0, sizeof(*sin));
996 sin->sin_family = AF_INET;
997 break;
998
999 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +00001000 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +00001001 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 goto out;
1003 break;
1004 case SIOCSIFADDR: /* Set interface address (and family) */
1005 case SIOCSIFBRDADDR: /* Set the broadcast address */
1006 case SIOCSIFDSTADDR: /* Set the destination address */
1007 case SIOCSIFNETMASK: /* Set the netmask for the interface */
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +00001008 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +00001009 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 goto out;
1011 ret = -EINVAL;
1012 if (sin->sin_family != AF_INET)
1013 goto out;
1014 break;
1015 default:
1016 ret = -EINVAL;
1017 goto out;
1018 }
1019
1020 rtnl_lock();
1021
1022 ret = -ENODEV;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001023 dev = __dev_get_by_name(net, ifr.ifr_name);
1024 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 goto done;
1026
1027 if (colon)
1028 *colon = ':';
1029
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001030 in_dev = __in_dev_get_rtnl(dev);
1031 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 if (tryaddrmatch) {
1033 /* Matthias Andree */
1034 /* compare label and address (4.4BSD style) */
1035 /* note: we only do this for a limited set of ioctls
1036 and only if the original address family was AF_INET.
1037 This is checked above. */
1038 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1039 ifap = &ifa->ifa_next) {
1040 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
1041 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -08001042 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 break; /* found */
1044 }
1045 }
1046 }
1047 /* we didn't get a match, maybe the application is
1048 4.3BSD-style and passed in junk so we fall back to
1049 comparing just the label */
1050 if (!ifa) {
1051 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1052 ifap = &ifa->ifa_next)
1053 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
1054 break;
1055 }
1056 }
1057
1058 ret = -EADDRNOTAVAIL;
1059 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
1060 goto done;
1061
Stephen Hemminger132adf52007-03-08 20:44:43 -08001062 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 case SIOCGIFADDR: /* Get interface address */
1064 sin->sin_addr.s_addr = ifa->ifa_local;
1065 goto rarok;
1066
1067 case SIOCGIFBRDADDR: /* Get the broadcast address */
1068 sin->sin_addr.s_addr = ifa->ifa_broadcast;
1069 goto rarok;
1070
1071 case SIOCGIFDSTADDR: /* Get the destination address */
1072 sin->sin_addr.s_addr = ifa->ifa_address;
1073 goto rarok;
1074
1075 case SIOCGIFNETMASK: /* Get the netmask for the interface */
1076 sin->sin_addr.s_addr = ifa->ifa_mask;
1077 goto rarok;
1078
1079 case SIOCSIFFLAGS:
1080 if (colon) {
1081 ret = -EADDRNOTAVAIL;
1082 if (!ifa)
1083 break;
1084 ret = 0;
1085 if (!(ifr.ifr_flags & IFF_UP))
1086 inet_del_ifa(in_dev, ifap, 1);
1087 break;
1088 }
1089 ret = dev_change_flags(dev, ifr.ifr_flags);
1090 break;
1091
1092 case SIOCSIFADDR: /* Set interface address (and family) */
1093 ret = -EINVAL;
1094 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1095 break;
1096
1097 if (!ifa) {
1098 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001099 ifa = inet_alloc_ifa();
1100 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 break;
Xi Wangc7e2e1d2013-01-05 11:19:24 +00001102 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 if (colon)
1104 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
1105 else
1106 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1107 } else {
1108 ret = 0;
1109 if (ifa->ifa_local == sin->sin_addr.s_addr)
1110 break;
1111 inet_del_ifa(in_dev, ifap, 0);
1112 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -08001113 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 }
1115
1116 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
1117
1118 if (!(dev->flags & IFF_POINTOPOINT)) {
1119 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
1120 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
1121 if ((dev->flags & IFF_BROADCAST) &&
1122 ifa->ifa_prefixlen < 31)
1123 ifa->ifa_broadcast = ifa->ifa_address |
1124 ~ifa->ifa_mask;
1125 } else {
1126 ifa->ifa_prefixlen = 32;
1127 ifa->ifa_mask = inet_make_mask(32);
1128 }
Jiri Pirko5c766d62013-01-24 09:41:41 +00001129 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 ret = inet_set_ifa(dev, ifa);
1131 break;
1132
1133 case SIOCSIFBRDADDR: /* Set the broadcast address */
1134 ret = 0;
1135 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
1136 inet_del_ifa(in_dev, ifap, 0);
1137 ifa->ifa_broadcast = sin->sin_addr.s_addr;
1138 inet_insert_ifa(ifa);
1139 }
1140 break;
1141
1142 case SIOCSIFDSTADDR: /* Set the destination address */
1143 ret = 0;
1144 if (ifa->ifa_address == sin->sin_addr.s_addr)
1145 break;
1146 ret = -EINVAL;
1147 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1148 break;
1149 ret = 0;
1150 inet_del_ifa(in_dev, ifap, 0);
1151 ifa->ifa_address = sin->sin_addr.s_addr;
1152 inet_insert_ifa(ifa);
1153 break;
1154
1155 case SIOCSIFNETMASK: /* Set the netmask for the interface */
1156
1157 /*
1158 * The mask we set must be legal.
1159 */
1160 ret = -EINVAL;
1161 if (bad_mask(sin->sin_addr.s_addr, 0))
1162 break;
1163 ret = 0;
1164 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -07001165 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 inet_del_ifa(in_dev, ifap, 0);
1167 ifa->ifa_mask = sin->sin_addr.s_addr;
1168 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
1169
1170 /* See if current broadcast address matches
1171 * with current netmask, then recalculate
1172 * the broadcast address. Otherwise it's a
1173 * funny address, so don't touch it since
1174 * the user seems to know what (s)he's doing...
1175 */
1176 if ((dev->flags & IFF_BROADCAST) &&
1177 (ifa->ifa_prefixlen < 31) &&
1178 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -05001179 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 ifa->ifa_broadcast = (ifa->ifa_local |
1181 ~sin->sin_addr.s_addr);
1182 }
1183 inet_insert_ifa(ifa);
1184 }
1185 break;
1186 }
1187done:
1188 rtnl_unlock();
1189out:
1190 return ret;
1191rarok:
1192 rtnl_unlock();
1193 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
1194 goto out;
1195}
1196
1197static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
1198{
Herbert Xue5ed6392005-10-03 14:35:55 -07001199 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 struct in_ifaddr *ifa;
1201 struct ifreq ifr;
1202 int done = 0;
1203
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001204 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 goto out;
1206
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001207 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 if (!buf) {
1209 done += sizeof(ifr);
1210 continue;
1211 }
1212 if (len < (int) sizeof(ifr))
1213 break;
1214 memset(&ifr, 0, sizeof(struct ifreq));
Dan Carpenter4299c8a2013-07-29 22:15:19 +03001215 strcpy(ifr.ifr_name, ifa->ifa_label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
1217 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
1218 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1219 ifa->ifa_local;
1220
1221 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
1222 done = -EFAULT;
1223 break;
1224 }
1225 buf += sizeof(struct ifreq);
1226 len -= sizeof(struct ifreq);
1227 done += sizeof(struct ifreq);
1228 }
1229out:
1230 return done;
1231}
1232
Gao Feng8b57fd12017-03-10 12:38:47 +08001233static __be32 in_dev_select_addr(const struct in_device *in_dev,
1234 int scope)
1235{
1236 for_primary_ifa(in_dev) {
1237 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1238 ifa->ifa_scope <= scope)
1239 return ifa->ifa_local;
1240 } endfor_ifa(in_dev);
1241
1242 return 0;
1243}
1244
Al Viroa61ced52006-09-26 21:27:54 -07001245__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246{
Al Viroa61ced52006-09-26 21:27:54 -07001247 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001249 struct net *net = dev_net(dev);
David Ahern3f2fb9a2016-02-24 11:47:02 -08001250 int master_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
1252 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001253 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 if (!in_dev)
1255 goto no_in_dev;
1256
1257 for_primary_ifa(in_dev) {
1258 if (ifa->ifa_scope > scope)
1259 continue;
1260 if (!dst || inet_ifa_match(dst, ifa)) {
1261 addr = ifa->ifa_local;
1262 break;
1263 }
1264 if (!addr)
1265 addr = ifa->ifa_local;
1266 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267
1268 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001269 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001270no_in_dev:
David Ahern3f2fb9a2016-02-24 11:47:02 -08001271 master_idx = l3mdev_master_ifindex_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
David Lamparter17b693c2016-02-24 11:47:03 -08001273 /* For VRFs, the VRF device takes the place of the loopback device,
1274 * with addresses on it being preferred. Note in such cases the
1275 * loopback device will be among the devices that fail the master_idx
1276 * equality check in the loop below.
1277 */
1278 if (master_idx &&
1279 (dev = dev_get_by_index_rcu(net, master_idx)) &&
1280 (in_dev = __in_dev_get_rcu(dev))) {
Gao Feng8b57fd12017-03-10 12:38:47 +08001281 addr = in_dev_select_addr(in_dev, scope);
1282 if (addr)
1283 goto out_unlock;
David Lamparter17b693c2016-02-24 11:47:03 -08001284 }
1285
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 /* Not loopback addresses on loopback should be preferred
Stephen Hemmingerca9f1fd2015-02-14 13:47:54 -05001287 in this case. It is important that lo is the first interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 in dev_base list.
1289 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001290 for_each_netdev_rcu(net, dev) {
David Ahern3f2fb9a2016-02-24 11:47:02 -08001291 if (l3mdev_master_ifindex_rcu(dev) != master_idx)
1292 continue;
1293
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001294 in_dev = __in_dev_get_rcu(dev);
1295 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 continue;
1297
Gao Feng8b57fd12017-03-10 12:38:47 +08001298 addr = in_dev_select_addr(in_dev, scope);
1299 if (addr)
1300 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001302out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 return addr;
1305}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001306EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307
Al Viro60cad5d2006-09-26 22:17:09 -07001308static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1309 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310{
1311 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001312 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313
1314 for_ifa(in_dev) {
1315 if (!addr &&
1316 (local == ifa->ifa_local || !local) &&
1317 ifa->ifa_scope <= scope) {
1318 addr = ifa->ifa_local;
1319 if (same)
1320 break;
1321 }
1322 if (!same) {
1323 same = (!local || inet_ifa_match(local, ifa)) &&
1324 (!dst || inet_ifa_match(dst, ifa));
1325 if (same && addr) {
1326 if (local || !dst)
1327 break;
1328 /* Is the selected addr into dst subnet? */
1329 if (inet_ifa_match(addr, ifa))
1330 break;
1331 /* No, then can we use new local src? */
1332 if (ifa->ifa_scope <= scope) {
1333 addr = ifa->ifa_local;
1334 break;
1335 }
1336 /* search for large dst subnet for addr */
1337 same = 0;
1338 }
1339 }
1340 } endfor_ifa(in_dev);
1341
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001342 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343}
1344
1345/*
1346 * Confirm that local IP address exists using wildcards:
Nicolas Dichtelb601fa12013-12-10 15:02:40 +01001347 * - net: netns to check, cannot be NULL
1348 * - in_dev: only on this interface, NULL=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 * - dst: only in the same subnet as dst, 0=any dst
1350 * - local: address, 0=autoselect the local address
1351 * - scope: maximum allowed scope value for the local address
1352 */
Nicolas Dichtelb601fa12013-12-10 15:02:40 +01001353__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001354 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355{
Al Viro60cad5d2006-09-26 22:17:09 -07001356 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001357 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
Ian Morris00db4122015-04-03 09:17:27 +01001359 if (in_dev)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001360 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001363 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001364 in_dev = __in_dev_get_rcu(dev);
1365 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 addr = confirm_addr_indev(in_dev, dst, local, scope);
1367 if (addr)
1368 break;
1369 }
1370 }
1371 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
1373 return addr;
1374}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001375EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
1377/*
1378 * Device notifier
1379 */
1380
1381int register_inetaddr_notifier(struct notifier_block *nb)
1382{
Alan Sterne041c682006-03-27 01:16:30 -08001383 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001385EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386
1387int unregister_inetaddr_notifier(struct notifier_block *nb)
1388{
Alan Sterne041c682006-03-27 01:16:30 -08001389 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001391EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
Krister Johansen3ad7d242017-06-08 13:12:14 -07001393int register_inetaddr_validator_notifier(struct notifier_block *nb)
1394{
1395 return blocking_notifier_chain_register(&inetaddr_validator_chain, nb);
1396}
1397EXPORT_SYMBOL(register_inetaddr_validator_notifier);
1398
1399int unregister_inetaddr_validator_notifier(struct notifier_block *nb)
1400{
1401 return blocking_notifier_chain_unregister(&inetaddr_validator_chain,
1402 nb);
1403}
1404EXPORT_SYMBOL(unregister_inetaddr_validator_notifier);
1405
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001406/* Rename ifa_labels for a device name change. Make some effort to preserve
1407 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408*/
1409static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001410{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 struct in_ifaddr *ifa;
1412 int named = 0;
1413
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001414 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1415 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
1417 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001418 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001420 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001421 dot = strchr(old, ':');
Ian Morris51456b22015-04-03 09:17:26 +01001422 if (!dot) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001423 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 dot = old;
1425 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001426 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001427 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001428 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001429 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001430skip:
1431 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001432 }
1433}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434
Ian Campbelld11327ad2011-02-11 07:44:16 +00001435static void inetdev_send_gratuitous_arp(struct net_device *dev,
1436 struct in_device *in_dev)
1437
1438{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001439 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001440
Zoltan Kissb76d0782011-07-24 13:09:30 +00001441 for (ifa = in_dev->ifa_list; ifa;
1442 ifa = ifa->ifa_next) {
1443 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1444 ifa->ifa_local, dev,
1445 ifa->ifa_local, NULL,
1446 dev->dev_addr, NULL);
1447 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001448}
1449
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450/* Called only under RTNL semaphore */
1451
1452static int inetdev_event(struct notifier_block *this, unsigned long event,
1453 void *ptr)
1454{
Jiri Pirko351638e2013-05-28 01:30:21 +00001455 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazet748e2d92012-08-22 21:50:59 +00001456 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457
1458 ASSERT_RTNL();
1459
1460 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001461 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 in_dev = inetdev_init(dev);
WANG Cong20e61da2014-07-25 15:25:08 -07001463 if (IS_ERR(in_dev))
1464 return notifier_from_errno(PTR_ERR(in_dev));
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001465 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001466 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1467 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001468 }
Breno Leitao06770842008-09-02 17:28:58 -07001469 } else if (event == NETDEV_CHANGEMTU) {
1470 /* Re-enabling IP */
1471 if (inetdev_valid_mtu(dev->mtu))
1472 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 }
1474 goto out;
1475 }
1476
1477 switch (event) {
1478 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001479 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001480 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 break;
1482 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001483 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001485 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001486 struct in_ifaddr *ifa = inet_alloc_ifa();
1487
1488 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001489 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 ifa->ifa_local =
1491 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1492 ifa->ifa_prefixlen = 8;
1493 ifa->ifa_mask = inet_make_mask(8);
1494 in_dev_hold(in_dev);
1495 ifa->ifa_dev = in_dev;
1496 ifa->ifa_scope = RT_SCOPE_HOST;
1497 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Jiri Pirko5c766d62013-01-24 09:41:41 +00001498 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1499 INFINITY_LIFE_TIME);
Jiri Pirkodfd15822014-01-07 15:55:45 +01001500 ipv4_devconf_setall(in_dev);
1501 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 inet_insert_ifa(ifa);
1503 }
1504 }
1505 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001506 /* fall through */
1507 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001508 if (!IN_DEV_ARP_NOTIFY(in_dev))
1509 break;
1510 /* fall through */
1511 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001512 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001513 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 break;
1515 case NETDEV_DOWN:
1516 ip_mc_down(in_dev);
1517 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001518 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001519 ip_mc_unmap(in_dev);
1520 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001521 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001522 ip_mc_remap(in_dev);
1523 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001525 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 break;
Breno Leitao06770842008-09-02 17:28:58 -07001527 /* disable IP when MTU is not enough */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 case NETDEV_UNREGISTER:
1529 inetdev_destroy(in_dev);
1530 break;
1531 case NETDEV_CHANGENAME:
1532 /* Do not notify about label change, this event is
1533 * not interesting to applications using netlink.
1534 */
1535 inetdev_changename(dev, in_dev);
1536
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001537 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001538 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 break;
1540 }
1541out:
1542 return NOTIFY_DONE;
1543}
1544
1545static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001546 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547};
1548
Eric Dumazet40384992012-08-03 21:06:50 +00001549static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001550{
1551 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1552 + nla_total_size(4) /* IFA_ADDRESS */
1553 + nla_total_size(4) /* IFA_LOCAL */
1554 + nla_total_size(4) /* IFA_BROADCAST */
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001555 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001556 + nla_total_size(4) /* IFA_FLAGS */
1557 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
Thomas Graf339bf982006-11-10 14:10:15 -08001558}
1559
Jiri Pirko5c766d62013-01-24 09:41:41 +00001560static inline u32 cstamp_delta(unsigned long cstamp)
1561{
1562 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1563}
1564
1565static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1566 unsigned long tstamp, u32 preferred, u32 valid)
1567{
1568 struct ifa_cacheinfo ci;
1569
1570 ci.cstamp = cstamp_delta(cstamp);
1571 ci.tstamp = cstamp_delta(tstamp);
1572 ci.ifa_prefered = preferred;
1573 ci.ifa_valid = valid;
1574
1575 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1576}
1577
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001579 u32 portid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580{
1581 struct ifaddrmsg *ifm;
1582 struct nlmsghdr *nlh;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001583 u32 preferred, valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
Eric W. Biederman15e47302012-09-07 20:12:54 +00001585 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
Ian Morris51456b22015-04-03 09:17:26 +01001586 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08001587 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001588
1589 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 ifm->ifa_family = AF_INET;
1591 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001592 ifm->ifa_flags = ifa->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 ifm->ifa_scope = ifa->ifa_scope;
1594 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
Jiri Pirko5c766d62013-01-24 09:41:41 +00001596 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1597 preferred = ifa->ifa_preferred_lft;
1598 valid = ifa->ifa_valid_lft;
1599 if (preferred != INFINITY_LIFE_TIME) {
1600 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1601
1602 if (preferred > tval)
1603 preferred -= tval;
1604 else
1605 preferred = 0;
1606 if (valid != INFINITY_LIFE_TIME) {
1607 if (valid > tval)
1608 valid -= tval;
1609 else
1610 valid = 0;
1611 }
1612 }
1613 } else {
1614 preferred = INFINITY_LIFE_TIME;
1615 valid = INFINITY_LIFE_TIME;
1616 }
David S. Millerf3756b72012-04-01 20:39:02 -04001617 if ((ifa->ifa_address &&
Jiri Benc930345e2015-03-29 16:59:25 +02001618 nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001619 (ifa->ifa_local &&
Jiri Benc930345e2015-03-29 16:59:25 +02001620 nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001621 (ifa->ifa_broadcast &&
Jiri Benc930345e2015-03-29 16:59:25 +02001622 nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001623 (ifa->ifa_label[0] &&
Jiri Pirko5c766d62013-01-24 09:41:41 +00001624 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001625 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
Jiri Pirko5c766d62013-01-24 09:41:41 +00001626 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1627 preferred, valid))
David S. Millerf3756b72012-04-01 20:39:02 -04001628 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001629
Johannes Berg053c0952015-01-16 22:09:00 +01001630 nlmsg_end(skb, nlh);
1631 return 0;
Thomas Graf47f68512006-08-04 23:04:36 -07001632
1633nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001634 nlmsg_cancel(skb, nlh);
1635 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636}
1637
1638static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1639{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001640 struct net *net = sock_net(skb->sk);
Eric Dumazeteec4df92009-11-12 07:44:25 +00001641 int h, s_h;
1642 int idx, s_idx;
1643 int ip_idx, s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 struct net_device *dev;
1645 struct in_device *in_dev;
1646 struct in_ifaddr *ifa;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001647 struct hlist_head *head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648
Eric Dumazeteec4df92009-11-12 07:44:25 +00001649 s_h = cb->args[0];
1650 s_idx = idx = cb->args[1];
1651 s_ip_idx = ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652
Eric Dumazeteec4df92009-11-12 07:44:25 +00001653 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1654 idx = 0;
1655 head = &net->dev_index_head[h];
1656 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001657 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1658 net->dev_base_seq;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001659 hlist_for_each_entry_rcu(dev, head, index_hlist) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001660 if (idx < s_idx)
1661 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001662 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001663 s_ip_idx = 0;
1664 in_dev = __in_dev_get_rcu(dev);
1665 if (!in_dev)
1666 goto cont;
1667
1668 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1669 ifa = ifa->ifa_next, ip_idx++) {
1670 if (ip_idx < s_ip_idx)
1671 continue;
1672 if (inet_fill_ifaddr(skb, ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001673 NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 cb->nlh->nlmsg_seq,
Johannes Berg053c0952015-01-16 22:09:00 +01001675 RTM_NEWADDR, NLM_F_MULTI) < 0) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001676 rcu_read_unlock();
1677 goto done;
1678 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001679 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Eric Dumazeteec4df92009-11-12 07:44:25 +00001680 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001681cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001682 idx++;
1683 }
1684 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 }
1686
1687done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001688 cb->args[0] = h;
1689 cb->args[1] = idx;
1690 cb->args[2] = ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691
1692 return skb->len;
1693}
1694
Jianjun Kong539afed2008-11-03 02:48:48 -08001695static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001696 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697{
Thomas Graf47f68512006-08-04 23:04:36 -07001698 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001699 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1700 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001701 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001703 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001704 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001705 if (!skb)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001706 goto errout;
1707
Eric W. Biederman15e47302012-09-07 20:12:54 +00001708 err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001709 if (err < 0) {
1710 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1711 WARN_ON(err == -EMSGSIZE);
1712 kfree_skb(skb);
1713 goto errout;
1714 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001715 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001716 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001717errout:
1718 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001719 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720}
1721
Arad, Ronenb1974ed2015-10-19 09:23:28 -07001722static size_t inet_get_link_af_size(const struct net_device *dev,
1723 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001724{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001725 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001726
1727 if (!in_dev)
1728 return 0;
1729
1730 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1731}
1732
Sowmini Varadhand5566fd2015-09-11 16:48:48 -04001733static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
1734 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001735{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001736 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001737 struct nlattr *nla;
1738 int i;
1739
1740 if (!in_dev)
1741 return -ENODATA;
1742
1743 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
Ian Morris51456b22015-04-03 09:17:26 +01001744 if (!nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001745 return -EMSGSIZE;
1746
1747 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1748 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1749
1750 return 0;
1751}
1752
1753static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1754 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1755};
1756
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001757static int inet_validate_link_af(const struct net_device *dev,
1758 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001759{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001760 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1761 int err, rem;
1762
Eric Dumazetf7fce742010-12-01 06:03:06 +00001763 if (dev && !__in_dev_get_rtnl(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001764 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001765
Johannes Bergfceb6432017-04-12 14:34:07 +02001766 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy, NULL);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001767 if (err < 0)
1768 return err;
1769
1770 if (tb[IFLA_INET_CONF]) {
1771 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1772 int cfgid = nla_type(a);
1773
1774 if (nla_len(a) < 4)
1775 return -EINVAL;
1776
1777 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1778 return -EINVAL;
1779 }
1780 }
1781
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001782 return 0;
1783}
1784
1785static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1786{
Eric Dumazetf7fce742010-12-01 06:03:06 +00001787 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001788 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1789 int rem;
1790
1791 if (!in_dev)
1792 return -EAFNOSUPPORT;
1793
Johannes Bergfceb6432017-04-12 14:34:07 +02001794 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0)
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001795 BUG();
1796
Thomas Graf9f0f7272010-11-16 04:32:48 +00001797 if (tb[IFLA_INET_CONF]) {
1798 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1799 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1800 }
1801
1802 return 0;
1803}
1804
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001805static int inet_netconf_msgsize_devconf(int type)
1806{
1807 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1808 + nla_total_size(4); /* NETCONFA_IFINDEX */
Zhang Shengju136ba622016-03-10 08:55:50 +00001809 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001810
Zhang Shengju136ba622016-03-10 08:55:50 +00001811 if (type == NETCONFA_ALL)
1812 all = true;
1813
1814 if (all || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001815 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001816 if (all || type == NETCONFA_RP_FILTER)
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001817 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001818 if (all || type == NETCONFA_MC_FORWARDING)
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001819 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001820 if (all || type == NETCONFA_PROXY_NEIGH)
stephen hemmingerf085ff12013-12-12 13:06:50 -08001821 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001822 if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001823 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001824
1825 return size;
1826}
1827
1828static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1829 struct ipv4_devconf *devconf, u32 portid,
1830 u32 seq, int event, unsigned int flags,
1831 int type)
1832{
1833 struct nlmsghdr *nlh;
1834 struct netconfmsg *ncm;
Zhang Shengju136ba622016-03-10 08:55:50 +00001835 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001836
1837 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1838 flags);
Ian Morris51456b22015-04-03 09:17:26 +01001839 if (!nlh)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001840 return -EMSGSIZE;
1841
Zhang Shengju136ba622016-03-10 08:55:50 +00001842 if (type == NETCONFA_ALL)
1843 all = true;
1844
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001845 ncm = nlmsg_data(nlh);
1846 ncm->ncm_family = AF_INET;
1847
1848 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1849 goto nla_put_failure;
1850
David Ahernb5c96412017-03-28 14:28:03 -07001851 if (!devconf)
1852 goto out;
1853
Zhang Shengju136ba622016-03-10 08:55:50 +00001854 if ((all || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001855 nla_put_s32(skb, NETCONFA_FORWARDING,
1856 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1857 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001858 if ((all || type == NETCONFA_RP_FILTER) &&
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001859 nla_put_s32(skb, NETCONFA_RP_FILTER,
1860 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
1861 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001862 if ((all || type == NETCONFA_MC_FORWARDING) &&
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001863 nla_put_s32(skb, NETCONFA_MC_FORWARDING,
1864 IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
1865 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001866 if ((all || type == NETCONFA_PROXY_NEIGH) &&
stephen hemminger09aea5d2013-12-17 22:35:52 -08001867 nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08001868 IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
1869 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001870 if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001871 nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
1872 IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
1873 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001874
David Ahernb5c96412017-03-28 14:28:03 -07001875out:
Johannes Berg053c0952015-01-16 22:09:00 +01001876 nlmsg_end(skb, nlh);
1877 return 0;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001878
1879nla_put_failure:
1880 nlmsg_cancel(skb, nlh);
1881 return -EMSGSIZE;
1882}
1883
David Ahern3b022862017-03-28 14:28:02 -07001884void inet_netconf_notify_devconf(struct net *net, int event, int type,
1885 int ifindex, struct ipv4_devconf *devconf)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001886{
1887 struct sk_buff *skb;
1888 int err = -ENOBUFS;
1889
Eric Dumazetfa178062016-07-08 05:18:24 +02001890 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001891 if (!skb)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001892 goto errout;
1893
1894 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
David Ahern3b022862017-03-28 14:28:02 -07001895 event, 0, type);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001896 if (err < 0) {
1897 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1898 WARN_ON(err == -EMSGSIZE);
1899 kfree_skb(skb);
1900 goto errout;
1901 }
Eric Dumazetfa178062016-07-08 05:18:24 +02001902 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001903 return;
1904errout:
1905 if (err < 0)
1906 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
1907}
1908
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001909static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
1910 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
1911 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001912 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
stephen hemminger09aea5d2013-12-17 22:35:52 -08001913 [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) },
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001914 [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001915};
1916
1917static int inet_netconf_get_devconf(struct sk_buff *in_skb,
David Ahernc21ef3e2017-04-16 09:48:24 -07001918 struct nlmsghdr *nlh,
1919 struct netlink_ext_ack *extack)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001920{
1921 struct net *net = sock_net(in_skb->sk);
1922 struct nlattr *tb[NETCONFA_MAX+1];
1923 struct netconfmsg *ncm;
1924 struct sk_buff *skb;
1925 struct ipv4_devconf *devconf;
1926 struct in_device *in_dev;
1927 struct net_device *dev;
1928 int ifindex;
1929 int err;
1930
1931 err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
David Ahernc21ef3e2017-04-16 09:48:24 -07001932 devconf_ipv4_policy, extack);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001933 if (err < 0)
1934 goto errout;
1935
Anton Protopopova97eb332016-02-16 21:43:16 -05001936 err = -EINVAL;
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001937 if (!tb[NETCONFA_IFINDEX])
1938 goto errout;
1939
1940 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
1941 switch (ifindex) {
1942 case NETCONFA_IFINDEX_ALL:
1943 devconf = net->ipv4.devconf_all;
1944 break;
1945 case NETCONFA_IFINDEX_DEFAULT:
1946 devconf = net->ipv4.devconf_dflt;
1947 break;
1948 default:
1949 dev = __dev_get_by_index(net, ifindex);
Ian Morris51456b22015-04-03 09:17:26 +01001950 if (!dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001951 goto errout;
1952 in_dev = __in_dev_get_rtnl(dev);
Ian Morris51456b22015-04-03 09:17:26 +01001953 if (!in_dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001954 goto errout;
1955 devconf = &in_dev->cnf;
1956 break;
1957 }
1958
1959 err = -ENOBUFS;
Eric Dumazetfa178062016-07-08 05:18:24 +02001960 skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001961 if (!skb)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001962 goto errout;
1963
1964 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
1965 NETLINK_CB(in_skb).portid,
1966 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
Zhang Shengju136ba622016-03-10 08:55:50 +00001967 NETCONFA_ALL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001968 if (err < 0) {
1969 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1970 WARN_ON(err == -EMSGSIZE);
1971 kfree_skb(skb);
1972 goto errout;
1973 }
1974 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
1975errout:
1976 return err;
1977}
1978
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001979static int inet_netconf_dump_devconf(struct sk_buff *skb,
1980 struct netlink_callback *cb)
1981{
1982 struct net *net = sock_net(skb->sk);
1983 int h, s_h;
1984 int idx, s_idx;
1985 struct net_device *dev;
1986 struct in_device *in_dev;
1987 struct hlist_head *head;
1988
1989 s_h = cb->args[0];
1990 s_idx = idx = cb->args[1];
1991
1992 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1993 idx = 0;
1994 head = &net->dev_index_head[h];
1995 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001996 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1997 net->dev_base_seq;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001998 hlist_for_each_entry_rcu(dev, head, index_hlist) {
1999 if (idx < s_idx)
2000 goto cont;
2001 in_dev = __in_dev_get_rcu(dev);
2002 if (!in_dev)
2003 goto cont;
2004
2005 if (inet_netconf_fill_devconf(skb, dev->ifindex,
2006 &in_dev->cnf,
2007 NETLINK_CB(cb->skb).portid,
2008 cb->nlh->nlmsg_seq,
2009 RTM_NEWNETCONF,
2010 NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002011 NETCONFA_ALL) < 0) {
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002012 rcu_read_unlock();
2013 goto done;
2014 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00002015 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002016cont:
2017 idx++;
2018 }
2019 rcu_read_unlock();
2020 }
2021 if (h == NETDEV_HASHENTRIES) {
2022 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
2023 net->ipv4.devconf_all,
2024 NETLINK_CB(cb->skb).portid,
2025 cb->nlh->nlmsg_seq,
2026 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002027 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002028 goto done;
2029 else
2030 h++;
2031 }
2032 if (h == NETDEV_HASHENTRIES + 1) {
2033 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
2034 net->ipv4.devconf_dflt,
2035 NETLINK_CB(cb->skb).portid,
2036 cb->nlh->nlmsg_seq,
2037 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002038 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002039 goto done;
2040 else
2041 h++;
2042 }
2043done:
2044 cb->args[0] = h;
2045 cb->args[1] = idx;
2046
2047 return skb->len;
2048}
2049
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050#ifdef CONFIG_SYSCTL
2051
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002052static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07002053{
2054 struct net_device *dev;
2055
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002056 rcu_read_lock();
2057 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07002058 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002059
Herbert Xu31be3082007-06-04 23:35:37 -07002060 in_dev = __in_dev_get_rcu(dev);
2061 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002062 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07002063 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002064 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07002065}
2066
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002067/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002068static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002069{
2070 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002071 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002072
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002073 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002074 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
David Ahern3b022862017-03-28 14:28:02 -07002075 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2076 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002077 NETCONFA_IFINDEX_ALL,
2078 net->ipv4.devconf_all);
David Ahern3b022862017-03-28 14:28:02 -07002079 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2080 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002081 NETCONFA_IFINDEX_DEFAULT,
2082 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002083
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002084 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002085 struct in_device *in_dev;
Eric Dumazetfa178062016-07-08 05:18:24 +02002086
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002087 if (on)
2088 dev_disable_lro(dev);
Eric Dumazetfa178062016-07-08 05:18:24 +02002089
2090 in_dev = __in_dev_get_rtnl(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002091 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002092 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
David Ahern3b022862017-03-28 14:28:02 -07002093 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2094 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002095 dev->ifindex, &in_dev->cnf);
2096 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002097 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002098}
2099
stephen hemmingerf085ff12013-12-12 13:06:50 -08002100static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf)
2101{
2102 if (cnf == net->ipv4.devconf_dflt)
2103 return NETCONFA_IFINDEX_DEFAULT;
2104 else if (cnf == net->ipv4.devconf_all)
2105 return NETCONFA_IFINDEX_ALL;
2106 else {
2107 struct in_device *idev
2108 = container_of(cnf, struct in_device, cnf);
2109 return idev->dev->ifindex;
2110 }
2111}
2112
Joe Perchesfe2c6332013-06-11 23:04:25 -07002113static int devinet_conf_proc(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002114 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07002115 size_t *lenp, loff_t *ppos)
2116{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002117 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002118 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002119 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07002120
2121 if (write) {
2122 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002123 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07002124 int i = (int *)ctl->data - cnf->data;
stephen hemmingerf085ff12013-12-12 13:06:50 -08002125 int ifindex;
Herbert Xu31be3082007-06-04 23:35:37 -07002126
2127 set_bit(i, cnf->state);
2128
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002129 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002130 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00002131 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
2132 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002133 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002134 rt_cache_flush(net);
stephen hemmingerf085ff12013-12-12 13:06:50 -08002135
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002136 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
2137 new_value != old_value) {
stephen hemmingerf085ff12013-12-12 13:06:50 -08002138 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002139 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2140 NETCONFA_RP_FILTER,
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002141 ifindex, cnf);
2142 }
stephen hemmingerf085ff12013-12-12 13:06:50 -08002143 if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
2144 new_value != old_value) {
2145 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002146 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2147 NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002148 ifindex, cnf);
2149 }
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002150 if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
2151 new_value != old_value) {
2152 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002153 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2154 NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002155 ifindex, cnf);
2156 }
Herbert Xu31be3082007-06-04 23:35:37 -07002157 }
2158
2159 return ret;
2160}
2161
Joe Perchesfe2c6332013-06-11 23:04:25 -07002162static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002163 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 size_t *lenp, loff_t *ppos)
2165{
2166 int *valp = ctl->data;
2167 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00002168 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002169 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170
2171 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002172 struct net *net = ctl->extra2;
2173
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002174 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00002175 if (!rtnl_trylock()) {
2176 /* Restore the original values before restarting */
2177 *valp = val;
2178 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00002179 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00002180 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002181 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2182 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002183 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002184 struct ipv4_devconf *cnf = ctl->extra1;
2185 struct in_device *idev =
2186 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002187 if (*valp)
2188 dev_disable_lro(idev->dev);
David Ahern3b022862017-03-28 14:28:02 -07002189 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002190 NETCONFA_FORWARDING,
2191 idev->dev->ifindex,
2192 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002193 }
2194 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002195 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002196 } else
David Ahern3b022862017-03-28 14:28:02 -07002197 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2198 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002199 NETCONFA_IFINDEX_DEFAULT,
2200 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 }
2202
2203 return ret;
2204}
2205
Joe Perchesfe2c6332013-06-11 23:04:25 -07002206static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
David S. Miller323e1262010-12-12 21:55:08 -08002207 void __user *buffer,
2208 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209{
2210 int *valp = ctl->data;
2211 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002212 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07002213 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214
2215 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002216 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
2218 return ret;
2219}
2220
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002221#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07002222 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07002223 .procname = name, \
2224 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00002225 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002226 .maxlen = sizeof(int), \
2227 .mode = mval, \
2228 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07002229 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002230 }
2231
2232#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002233 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002234
2235#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002236 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002237
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002238#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2239 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002240
2241#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002242 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07002243
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244static struct devinet_sysctl_table {
2245 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00002246 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247} devinet_sysctl = {
2248 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07002249 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002250 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07002251 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
2252
2253 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
2254 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
2255 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
2256 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
2257 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
2258 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
2259 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00002260 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08002261 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002262 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
2263 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
2264 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
2265 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
2266 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
2267 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
2268 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
2269 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
2270 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08002271 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00002272 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
William Manley5c6fe012013-08-06 19:03:14 +01002273 DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
2274 "force_igmp_version"),
William Manley26900482013-08-06 19:03:15 +01002275 DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
2276 "igmpv2_unsolicited_report_interval"),
2277 DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
2278 "igmpv3_unsolicited_report_interval"),
Andy Gospodarek0eeb0752015-06-23 13:45:37 -04002279 DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
2280 "ignore_routes_with_linkdown"),
Johannes Berg97daf332016-02-04 13:31:18 +01002281 DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
2282 "drop_gratuitous_arp"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002283
2284 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2285 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002286 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
2287 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00002288 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2289 "route_localnet"),
Johannes Berg12b74df2016-02-04 13:31:17 +01002290 DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
2291 "drop_unicast_in_l2_multicast"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293};
2294
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002295static int __devinet_sysctl_register(struct net *net, char *dev_name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002296 int ifindex, struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297{
2298 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002299 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002300 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11002301
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002302 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002304 goto out;
2305
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
2307 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07002308 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002309 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 }
2311
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002312 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002314 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002316 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317
2318 p->sysctl = t;
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002319
David Ahern3b022862017-03-28 14:28:02 -07002320 inet_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_ALL,
2321 ifindex, p);
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002322 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002324free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002326out:
liuguoqiang1ce4633f2021-11-15 16:14:48 +08002327 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328}
2329
David Ahernb5c96412017-03-28 14:28:03 -07002330static void __devinet_sysctl_unregister(struct net *net,
2331 struct ipv4_devconf *cnf, int ifindex)
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002332{
2333 struct devinet_sysctl_table *t = cnf->sysctl;
2334
David Ahernb5c96412017-03-28 14:28:03 -07002335 if (t) {
2336 cnf->sysctl = NULL;
2337 unregister_net_sysctl_table(t->sysctl_header);
2338 kfree(t);
2339 }
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002340
David Ahernb5c96412017-03-28 14:28:03 -07002341 inet_netconf_notify_devconf(net, RTM_DELNETCONF, 0, ifindex, NULL);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002342}
2343
WANG Cong20e61da2014-07-25 15:25:08 -07002344static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002345{
WANG Cong20e61da2014-07-25 15:25:08 -07002346 int err;
2347
2348 if (!sysctl_dev_name_is_allowed(idev->dev->name))
2349 return -EINVAL;
2350
2351 err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
2352 if (err)
2353 return err;
2354 err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002355 idev->dev->ifindex, &idev->cnf);
WANG Cong20e61da2014-07-25 15:25:08 -07002356 if (err)
2357 neigh_sysctl_unregister(idev->arp_parms);
2358 return err;
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002359}
2360
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002361static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362{
David Ahernb5c96412017-03-28 14:28:03 -07002363 struct net *net = dev_net(idev->dev);
2364
2365 __devinet_sysctl_unregister(net, &idev->cnf, idev->dev->ifindex);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002366 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002369static struct ctl_table ctl_forward_entry[] = {
2370 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002371 .procname = "ip_forward",
2372 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00002373 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002374 .maxlen = sizeof(int),
2375 .mode = 0644,
2376 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002377 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002378 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002379 },
2380 { },
2381};
Eric Dumazet2a75de02008-01-05 23:08:49 -08002382#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002383
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002384static __net_init int devinet_init_net(struct net *net)
2385{
2386 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002387 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002388#ifdef CONFIG_SYSCTL
2389 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002390 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002391#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002392
2393 err = -ENOMEM;
2394 all = &ipv4_devconf;
2395 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002396
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002397 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002398 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002399 if (!all)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002400 goto err_alloc_all;
2401
2402 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002403 if (!dflt)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002404 goto err_alloc_dflt;
2405
Eric Dumazet2a75de02008-01-05 23:08:49 -08002406#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002407 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002408 if (!tbl)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002409 goto err_alloc_ctl;
2410
Eric W. Biederman02291682010-02-14 03:25:51 +00002411 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002412 tbl[0].extra1 = all;
2413 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002414#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002415 }
2416
2417#ifdef CONFIG_SYSCTL
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002418 err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002419 if (err < 0)
2420 goto err_reg_all;
2421
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002422 err = __devinet_sysctl_register(net, "default",
2423 NETCONFA_IFINDEX_DEFAULT, dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002424 if (err < 0)
2425 goto err_reg_dflt;
2426
2427 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002428 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Ian Morris51456b22015-04-03 09:17:26 +01002429 if (!forw_hdr)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002430 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002431 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002432#endif
2433
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002434 net->ipv4.devconf_all = all;
2435 net->ipv4.devconf_dflt = dflt;
2436 return 0;
2437
2438#ifdef CONFIG_SYSCTL
2439err_reg_ctl:
David Ahernb5c96412017-03-28 14:28:03 -07002440 __devinet_sysctl_unregister(net, dflt, NETCONFA_IFINDEX_DEFAULT);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002441err_reg_dflt:
David Ahernb5c96412017-03-28 14:28:03 -07002442 __devinet_sysctl_unregister(net, all, NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002443err_reg_all:
2444 if (tbl != ctl_forward_entry)
2445 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002446err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08002447#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002448 if (dflt != &ipv4_devconf_dflt)
2449 kfree(dflt);
2450err_alloc_dflt:
2451 if (all != &ipv4_devconf)
2452 kfree(all);
2453err_alloc_all:
2454 return err;
2455}
2456
2457static __net_exit void devinet_exit_net(struct net *net)
2458{
Eric Dumazet2a75de02008-01-05 23:08:49 -08002459#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002460 struct ctl_table *tbl;
2461
2462 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002463 unregister_net_sysctl_table(net->ipv4.forw_hdr);
David Ahernb5c96412017-03-28 14:28:03 -07002464 __devinet_sysctl_unregister(net, net->ipv4.devconf_dflt,
2465 NETCONFA_IFINDEX_DEFAULT);
2466 __devinet_sysctl_unregister(net, net->ipv4.devconf_all,
2467 NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002468 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08002469#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002470 kfree(net->ipv4.devconf_dflt);
2471 kfree(net->ipv4.devconf_all);
2472}
2473
2474static __net_initdata struct pernet_operations devinet_ops = {
2475 .init = devinet_init_net,
2476 .exit = devinet_exit_net,
2477};
2478
Daniel Borkmann207895f2015-01-29 12:15:03 +01002479static struct rtnl_af_ops inet_af_ops __read_mostly = {
Thomas Graf9f0f7272010-11-16 04:32:48 +00002480 .family = AF_INET,
2481 .fill_link_af = inet_fill_link_af,
2482 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00002483 .validate_link_af = inet_validate_link_af,
2484 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00002485};
2486
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487void __init devinet_init(void)
2488{
David S. Millerfd23c3b2011-02-18 12:42:28 -08002489 int i;
2490
2491 for (i = 0; i < IN4_ADDR_HSIZE; i++)
2492 INIT_HLIST_HEAD(&inet_addr_lst[i]);
2493
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002494 register_pernet_subsys(&devinet_ops);
2495
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 register_gifconf(PF_INET, inet_gifconf);
2497 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07002498
viresh kumar906e0732014-01-22 12:23:32 +05302499 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +00002500
Thomas Graf9f0f7272010-11-16 04:32:48 +00002501 rtnl_af_register(&inet_af_ops);
2502
Florian Westphalb97bac62017-08-09 20:41:48 +02002503 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, 0);
2504 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, 0);
2505 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, 0);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002506 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
Florian Westphalb97bac62017-08-09 20:41:48 +02002507 inet_netconf_dump_devconf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508}