blob: a34602ae27dee2d3ff5d579172910c5f9f004292 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * NET3 IP device support routines.
3 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Derived from the IP parts of dev.c 1.0.19
Jesper Juhl02c30a82005-05-05 16:16:16 -070010 * Authors: Ross Biro
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
12 * Mark Evans, <evansmp@uhura.aston.ac.uk>
13 *
14 * Additional Authors:
15 * Alan Cox, <gw4pts@gw4pts.ampr.org>
16 * Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
17 *
18 * Changes:
19 * Alexey Kuznetsov: pa_* fields are replaced with ifaddr
20 * lists.
21 * Cyrus Durgin: updated for kmod
22 * Matthias Andree: in devinet_ioctl, compare label and
23 * address (4.4BSD alias style support),
24 * fall back to comparing just the label
25 * if no match found.
26 */
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080029#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/bitops.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080031#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/module.h>
33#include <linux/types.h>
34#include <linux/kernel.h>
Ingo Molnar174cd4b2017-02-02 19:15:33 +010035#include <linux/sched/signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/string.h>
37#include <linux/mm.h>
38#include <linux/socket.h>
39#include <linux/sockios.h>
40#include <linux/in.h>
41#include <linux/errno.h>
42#include <linux/interrupt.h>
Thomas Graf18237302006-08-04 23:04:54 -070043#include <linux/if_addr.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/if_ether.h>
45#include <linux/inet.h>
46#include <linux/netdevice.h>
47#include <linux/etherdevice.h>
48#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/init.h>
50#include <linux/notifier.h>
51#include <linux/inetdevice.h>
52#include <linux/igmp.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090053#include <linux/slab.h>
David S. Millerfd23c3b2011-02-18 12:42:28 -080054#include <linux/hash.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#ifdef CONFIG_SYSCTL
56#include <linux/sysctl.h>
57#endif
58#include <linux/kmod.h>
Nicolas Dichteledc9e742012-10-25 22:28:52 +000059#include <linux/netconf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020061#include <net/arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <net/ip.h>
63#include <net/route.h>
64#include <net/ip_fib.h>
Thomas Graf63f34442007-03-22 11:55:17 -070065#include <net/rtnetlink.h>
Pavel Emelyanov752d14d2007-12-16 13:31:47 -080066#include <net/net_namespace.h>
Jiri Pirko5c766d62013-01-24 09:41:41 +000067#include <net/addrconf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Adrian Bunk0027ba82008-01-31 17:17:31 -080069static struct ipv4_devconf ipv4_devconf = {
Herbert Xu42f811b2007-06-04 23:34:44 -070070 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000071 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
72 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
73 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
74 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
William Manley26900482013-08-06 19:03:15 +010075 [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
76 [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
Herbert Xu42f811b2007-06-04 23:34:44 -070077 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070078};
79
80static struct ipv4_devconf ipv4_devconf_dflt = {
Herbert Xu42f811b2007-06-04 23:34:44 -070081 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000082 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
83 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
84 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
85 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
86 [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
William Manley26900482013-08-06 19:03:15 +010087 [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
88 [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
Herbert Xu42f811b2007-06-04 23:34:44 -070089 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070090};
91
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -080092#define IPV4_DEVCONF_DFLT(net, attr) \
93 IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr)
Herbert Xu42f811b2007-06-04 23:34:44 -070094
Patrick McHardyef7c79e2007-06-05 12:38:30 -070095static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
Thomas Graf5c753972006-08-04 23:03:53 -070096 [IFA_LOCAL] = { .type = NLA_U32 },
97 [IFA_ADDRESS] = { .type = NLA_U32 },
98 [IFA_BROADCAST] = { .type = NLA_U32 },
Thomas Graf5176f912006-08-26 20:13:18 -070099 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
Jiri Pirko5c766d62013-01-24 09:41:41 +0000100 [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100101 [IFA_FLAGS] = { .type = NLA_U32 },
David Ahernaf4d7682018-05-27 08:09:57 -0700102 [IFA_RT_PRIORITY] = { .type = NLA_U32 },
Christian Braunerd3807142018-09-04 21:53:49 +0200103 [IFA_TARGET_NETNSID] = { .type = NLA_S32 },
Thomas Graf5c753972006-08-04 23:03:53 -0700104};
105
Christian Brauner978a46f2018-09-04 21:53:54 +0200106struct inet_fill_args {
107 u32 portid;
108 u32 seq;
109 int event;
110 unsigned int flags;
111 int netnsid;
David Ahern5fcd2662018-10-19 12:45:29 -0700112 int ifindex;
Christian Brauner978a46f2018-09-04 21:53:54 +0200113};
114
Eric Dumazet40384992012-08-03 21:06:50 +0000115#define IN4_ADDR_HSIZE_SHIFT 8
116#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT)
117
David S. Millerfd23c3b2011-02-18 12:42:28 -0800118static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
David S. Millerfd23c3b2011-02-18 12:42:28 -0800119
Eric Dumazet6eada012015-03-18 14:05:33 -0700120static u32 inet_addr_hash(const struct net *net, __be32 addr)
David S. Millerfd23c3b2011-02-18 12:42:28 -0800121{
Eric Dumazet40384992012-08-03 21:06:50 +0000122 u32 val = (__force u32) addr ^ net_hash_mix(net);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800123
Eric Dumazet40384992012-08-03 21:06:50 +0000124 return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800125}
126
127static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
128{
Eric Dumazet40384992012-08-03 21:06:50 +0000129 u32 hash = inet_addr_hash(net, ifa->ifa_local);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800130
WANG Cong32a4be42014-05-06 11:15:56 -0700131 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800132 hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800133}
134
135static void inet_hash_remove(struct in_ifaddr *ifa)
136{
WANG Cong32a4be42014-05-06 11:15:56 -0700137 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800138 hlist_del_init_rcu(&ifa->hash);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800139}
140
David S. Miller9435eb12011-02-18 12:43:09 -0800141/**
142 * __ip_dev_find - find the first device with a given source address.
143 * @net: the net namespace
144 * @addr: the source address
145 * @devref: if true, take a reference on the found device
146 *
147 * If a caller uses devref=false, it should be protected by RCU, or RTNL
148 */
149struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
150{
David S. Miller9435eb12011-02-18 12:43:09 -0800151 struct net_device *result = NULL;
152 struct in_ifaddr *ifa;
David S. Miller9435eb12011-02-18 12:43:09 -0800153
154 rcu_read_lock();
Paolo Abeni6e617de2017-09-20 18:26:53 +0200155 ifa = inet_lookup_ifaddr_rcu(net, addr);
156 if (!ifa) {
David S. Miller406b6f92011-03-22 21:56:23 -0700157 struct flowi4 fl4 = { .daddr = addr };
158 struct fib_result res = { 0 };
159 struct fib_table *local;
160
161 /* Fallback to FIB local table so that communication
162 * over loopback subnets work.
163 */
164 local = fib_get_table(net, RT_TABLE_LOCAL);
165 if (local &&
166 !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
167 res.type == RTN_LOCAL)
168 result = FIB_RES_DEV(res);
Paolo Abeni6e617de2017-09-20 18:26:53 +0200169 } else {
170 result = ifa->ifa_dev->dev;
David S. Miller406b6f92011-03-22 21:56:23 -0700171 }
David S. Miller9435eb12011-02-18 12:43:09 -0800172 if (result && devref)
173 dev_hold(result);
174 rcu_read_unlock();
175 return result;
176}
177EXPORT_SYMBOL(__ip_dev_find);
178
Paolo Abeni6e617de2017-09-20 18:26:53 +0200179/* called under RCU lock */
180struct in_ifaddr *inet_lookup_ifaddr_rcu(struct net *net, __be32 addr)
181{
182 u32 hash = inet_addr_hash(net, addr);
183 struct in_ifaddr *ifa;
184
185 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash)
186 if (ifa->ifa_local == addr &&
187 net_eq(dev_net(ifa->ifa_dev->dev), net))
188 return ifa;
189
190 return NULL;
191}
192
Thomas Grafd6062cb2006-08-15 00:33:59 -0700193static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Alan Sterne041c682006-03-27 01:16:30 -0800195static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Krister Johansen3ad7d242017-06-08 13:12:14 -0700196static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
198 int destroy);
199#ifdef CONFIG_SYSCTL
WANG Cong20e61da2014-07-25 15:25:08 -0700200static int devinet_sysctl_register(struct in_device *idev);
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800201static void devinet_sysctl_unregister(struct in_device *idev);
202#else
WANG Cong20e61da2014-07-25 15:25:08 -0700203static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800204{
WANG Cong20e61da2014-07-25 15:25:08 -0700205 return 0;
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800206}
Eric Dumazet40384992012-08-03 21:06:50 +0000207static void devinet_sysctl_unregister(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800208{
209}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210#endif
211
212/* Locks all the inet devices. */
213
214static struct in_ifaddr *inet_alloc_ifa(void)
215{
Alexey Dobriyan93adcc82008-10-28 13:25:09 -0700216 return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217}
218
219static void inet_rcu_free_ifa(struct rcu_head *head)
220{
221 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
222 if (ifa->ifa_dev)
223 in_dev_put(ifa->ifa_dev);
224 kfree(ifa);
225}
226
Eric Dumazet40384992012-08-03 21:06:50 +0000227static void inet_free_ifa(struct in_ifaddr *ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228{
229 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
230}
231
232void in_dev_finish_destroy(struct in_device *idev)
233{
234 struct net_device *dev = idev->dev;
235
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700236 WARN_ON(idev->ifa_list);
237 WARN_ON(idev->mc_list);
Eric Dumazete9897072013-06-07 08:48:57 -0700238 kfree(rcu_dereference_protected(idev->mc_hash, 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239#ifdef NET_REFCNT_DEBUG
Joe Perches91df42b2012-05-15 14:11:54 +0000240 pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241#endif
242 dev_put(dev);
243 if (!idev->dead)
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800244 pr_err("Freeing alive in_device %p\n", idev);
245 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 kfree(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800248EXPORT_SYMBOL(in_dev_finish_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
Herbert Xu71e27da2007-06-04 23:36:06 -0700250static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251{
252 struct in_device *in_dev;
WANG Cong20e61da2014-07-25 15:25:08 -0700253 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
255 ASSERT_RTNL();
256
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700257 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 if (!in_dev)
259 goto out;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900260 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -0800261 sizeof(in_dev->cnf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 in_dev->cnf.sysctl = NULL;
263 in_dev->dev = dev;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800264 in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
265 if (!in_dev->arp_parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 goto out_kfree;
Ben Hutchings0187bdf2008-06-19 16:15:47 -0700267 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
268 dev_disable_lro(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 /* Reference in_dev->dev */
270 dev_hold(dev);
David L Stevens30c4cf52007-01-04 12:31:14 -0800271 /* Account for reference dev->ip_ptr (below) */
Reshetova, Elena7658b362017-06-30 13:08:03 +0300272 refcount_set(&in_dev->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
WANG Cong20e61da2014-07-25 15:25:08 -0700274 err = devinet_sysctl_register(in_dev);
275 if (err) {
276 in_dev->dead = 1;
277 in_dev_put(in_dev);
278 in_dev = NULL;
279 goto out;
280 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 ip_mc_init_dev(in_dev);
282 if (dev->flags & IFF_UP)
283 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800284
David L Stevens30c4cf52007-01-04 12:31:14 -0800285 /* we can receive as soon as ip_ptr is set -- do this last */
Eric Dumazetcf778b02012-01-12 04:41:32 +0000286 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800287out:
WANG Cong20e61da2014-07-25 15:25:08 -0700288 return in_dev ?: ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289out_kfree:
290 kfree(in_dev);
291 in_dev = NULL;
292 goto out;
293}
294
295static void in_dev_rcu_put(struct rcu_head *head)
296{
297 struct in_device *idev = container_of(head, struct in_device, rcu_head);
298 in_dev_put(idev);
299}
300
301static void inetdev_destroy(struct in_device *in_dev)
302{
303 struct in_ifaddr *ifa;
304 struct net_device *dev;
305
306 ASSERT_RTNL();
307
308 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
310 in_dev->dead = 1;
311
312 ip_mc_destroy_dev(in_dev);
313
314 while ((ifa = in_dev->ifa_list) != NULL) {
315 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
316 inet_free_ifa(ifa);
317 }
318
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000319 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800321 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
323 arp_ifdown(dev);
324
325 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
326}
327
Al Viroff428d72006-09-26 22:13:35 -0700328int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
330 rcu_read_lock();
331 for_primary_ifa(in_dev) {
332 if (inet_ifa_match(a, ifa)) {
333 if (!b || inet_ifa_match(b, ifa)) {
334 rcu_read_unlock();
335 return 1;
336 }
337 }
338 } endfor_ifa(in_dev);
339 rcu_read_unlock();
340 return 0;
341}
342
Thomas Grafd6062cb2006-08-15 00:33:59 -0700343static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000344 int destroy, struct nlmsghdr *nlh, u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345{
Harald Welte8f937c62005-05-29 20:23:46 -0700346 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800347 struct in_ifaddr *ifa, *ifa1 = *ifap;
348 struct in_ifaddr *last_prim = in_dev->ifa_list;
349 struct in_ifaddr *prev_prom = NULL;
350 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
352 ASSERT_RTNL();
353
David S. Millerfbd40ea2016-03-13 23:28:00 -0400354 if (in_dev->dead)
355 goto no_promotions;
356
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900357 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700358 * unless alias promotion is set
359 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
361 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
363
364 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900365 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800366 ifa1->ifa_scope <= ifa->ifa_scope)
367 last_prim = ifa;
368
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
370 ifa1->ifa_mask != ifa->ifa_mask ||
371 !inet_ifa_match(ifa1->ifa_address, ifa)) {
372 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800373 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 continue;
375 }
376
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800377 if (!do_promote) {
David S. Millerfd23c3b2011-02-18 12:42:28 -0800378 inet_hash_remove(ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700379 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
Eric W. Biederman15e47302012-09-07 20:12:54 +0000381 rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800382 blocking_notifier_call_chain(&inetaddr_chain,
383 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700384 inet_free_ifa(ifa);
385 } else {
386 promote = ifa;
387 break;
388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 }
390 }
391
Julian Anastasov2d230e22011-03-19 12:13:52 +0000392 /* On promotion all secondaries from subnet are changing
393 * the primary IP, we must remove all their routes silently
394 * and later to add them back with new prefsrc. Do this
395 * while all addresses are on the device list.
396 */
397 for (ifa = promote; ifa; ifa = ifa->ifa_next) {
398 if (ifa1->ifa_mask == ifa->ifa_mask &&
399 inet_ifa_match(ifa1->ifa_address, ifa))
400 fib_del_ifaddr(ifa, ifa1);
401 }
402
David S. Millerfbd40ea2016-03-13 23:28:00 -0400403no_promotions:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 /* 2. Unlink it */
405
406 *ifap = ifa1->ifa_next;
David S. Millerfd23c3b2011-02-18 12:42:28 -0800407 inet_hash_remove(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
409 /* 3. Announce address deletion */
410
411 /* Send message first, then call notifier.
412 At first sight, FIB update triggered by notifier
413 will refer to already deleted ifaddr, that could confuse
414 netlink listeners. It is not true: look, gated sees
415 that route deleted and if it still thinks that ifaddr
416 is valid, it will try to restore deleted routes... Grr.
417 So that, this order is correct.
418 */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000419 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800420 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800421
422 if (promote) {
Julian Anastasov04024b92011-03-19 12:13:54 +0000423 struct in_ifaddr *next_sec = promote->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800424
425 if (prev_prom) {
426 prev_prom->ifa_next = promote->ifa_next;
427 promote->ifa_next = last_prim->ifa_next;
428 last_prim->ifa_next = promote;
429 }
430
431 promote->ifa_flags &= ~IFA_F_SECONDARY;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000432 rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800433 blocking_notifier_call_chain(&inetaddr_chain,
434 NETDEV_UP, promote);
Julian Anastasov04024b92011-03-19 12:13:54 +0000435 for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800436 if (ifa1->ifa_mask != ifa->ifa_mask ||
437 !inet_ifa_match(ifa1->ifa_address, ifa))
438 continue;
439 fib_add_ifaddr(ifa);
440 }
441
442 }
Herbert Xu63630972007-06-07 18:35:38 -0700443 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445}
446
Thomas Grafd6062cb2006-08-15 00:33:59 -0700447static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
448 int destroy)
449{
450 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
451}
452
Jiri Pirko5c766d62013-01-24 09:41:41 +0000453static void check_lifetime(struct work_struct *work);
454
455static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
456
Thomas Grafd6062cb2006-08-15 00:33:59 -0700457static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
David Ahernde95e042017-10-18 09:56:54 -0700458 u32 portid, struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459{
460 struct in_device *in_dev = ifa->ifa_dev;
461 struct in_ifaddr *ifa1, **ifap, **last_primary;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700462 struct in_validator_info ivi;
463 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
465 ASSERT_RTNL();
466
467 if (!ifa->ifa_local) {
468 inet_free_ifa(ifa);
469 return 0;
470 }
471
472 ifa->ifa_flags &= ~IFA_F_SECONDARY;
473 last_primary = &in_dev->ifa_list;
474
475 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
476 ifap = &ifa1->ifa_next) {
477 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
478 ifa->ifa_scope <= ifa1->ifa_scope)
479 last_primary = &ifa1->ifa_next;
480 if (ifa1->ifa_mask == ifa->ifa_mask &&
481 inet_ifa_match(ifa1->ifa_address, ifa)) {
482 if (ifa1->ifa_local == ifa->ifa_local) {
483 inet_free_ifa(ifa);
484 return -EEXIST;
485 }
486 if (ifa1->ifa_scope != ifa->ifa_scope) {
487 inet_free_ifa(ifa);
488 return -EINVAL;
489 }
490 ifa->ifa_flags |= IFA_F_SECONDARY;
491 }
492 }
493
Krister Johansen3ad7d242017-06-08 13:12:14 -0700494 /* Allow any devices that wish to register ifaddr validtors to weigh
495 * in now, before changes are committed. The rntl lock is serializing
496 * access here, so the state should not change between a validator call
497 * and a final notify on commit. This isn't invoked on promotion under
498 * the assumption that validators are checking the address itself, and
499 * not the flags.
500 */
501 ivi.ivi_addr = ifa->ifa_address;
502 ivi.ivi_dev = ifa->ifa_dev;
David Ahernde95e042017-10-18 09:56:54 -0700503 ivi.extack = extack;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700504 ret = blocking_notifier_call_chain(&inetaddr_validator_chain,
505 NETDEV_UP, &ivi);
506 ret = notifier_to_errno(ret);
507 if (ret) {
508 inet_free_ifa(ifa);
509 return ret;
510 }
511
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500513 prandom_seed((__force u32) ifa->ifa_local);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 ifap = last_primary;
515 }
516
517 ifa->ifa_next = *ifap;
518 *ifap = ifa;
519
David S. Millerfd23c3b2011-02-18 12:42:28 -0800520 inet_hash_insert(dev_net(in_dev->dev), ifa);
521
Jiri Pirko5c766d62013-01-24 09:41:41 +0000522 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530523 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000524
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 /* Send message first, then call notifier.
526 Notifier will trigger FIB update, so that
527 listeners of netlink will know about new ifaddr */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000528 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800529 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
531 return 0;
532}
533
Thomas Grafd6062cb2006-08-15 00:33:59 -0700534static int inet_insert_ifa(struct in_ifaddr *ifa)
535{
David Ahernde95e042017-10-18 09:56:54 -0700536 return __inet_insert_ifa(ifa, NULL, 0, NULL);
Thomas Grafd6062cb2006-08-15 00:33:59 -0700537}
538
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
540{
Herbert Xue5ed6392005-10-03 14:35:55 -0700541 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
543 ASSERT_RTNL();
544
545 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700546 inet_free_ifa(ifa);
547 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700549 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100550 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700552 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 in_dev_hold(in_dev);
554 ifa->ifa_dev = in_dev;
555 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800556 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 ifa->ifa_scope = RT_SCOPE_HOST;
558 return inet_insert_ifa(ifa);
559}
560
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000561/* Caller must hold RCU or RTNL :
562 * We dont take a reference on found in_device
563 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800564struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565{
566 struct net_device *dev;
567 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000568
569 rcu_read_lock();
570 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000572 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000573 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 return in_dev;
575}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800576EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
578/* Called only from RTNL semaphored context. No locks. */
579
Al Viro60cad5d2006-09-26 22:17:09 -0700580struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
581 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582{
583 ASSERT_RTNL();
584
585 for_primary_ifa(in_dev) {
586 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
587 return ifa;
588 } endfor_ifa(in_dev);
589 return NULL;
590}
591
Madhu Challa93a714d2015-02-25 09:58:35 -0800592static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa)
593{
594 struct ip_mreqn mreq = {
595 .imr_multiaddr.s_addr = ifa->ifa_address,
596 .imr_ifindex = ifa->ifa_dev->dev->ifindex,
597 };
598 int ret;
599
600 ASSERT_RTNL();
601
602 lock_sock(sk);
603 if (join)
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300604 ret = ip_mc_join_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800605 else
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300606 ret = ip_mc_leave_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800607 release_sock(sk);
608
609 return ret;
610}
611
David Ahernc21ef3e2017-04-16 09:48:24 -0700612static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
613 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900615 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700616 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700618 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700620 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
622 ASSERT_RTNL();
623
Johannes Bergfceb6432017-04-12 14:34:07 +0200624 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -0700625 extack);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700626 if (err < 0)
627 goto errout;
628
629 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800630 in_dev = inetdev_by_index(net, ifm->ifa_index);
Ian Morris51456b22015-04-03 09:17:26 +0100631 if (!in_dev) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700632 err = -ENODEV;
633 goto errout;
634 }
635
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
637 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700638 if (tb[IFA_LOCAL] &&
Jiri Benc67b61f62015-03-29 16:59:26 +0200639 ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700641
642 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
643 continue;
644
645 if (tb[IFA_ADDRESS] &&
646 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Jiri Benc67b61f62015-03-29 16:59:26 +0200647 !inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700648 continue;
649
Madhu Challa93a714d2015-02-25 09:58:35 -0800650 if (ipv4_is_multicast(ifa->ifa_address))
651 ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000652 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 return 0;
654 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700655
656 err = -EADDRNOTAVAIL;
657errout:
658 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659}
660
Jiri Pirko5c766d62013-01-24 09:41:41 +0000661#define INFINITY_LIFE_TIME 0xFFFFFFFF
662
663static void check_lifetime(struct work_struct *work)
664{
665 unsigned long now, next, next_sec, next_sched;
666 struct in_ifaddr *ifa;
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000667 struct hlist_node *n;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000668 int i;
669
670 now = jiffies;
671 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
672
Jiri Pirko5c766d62013-01-24 09:41:41 +0000673 for (i = 0; i < IN4_ADDR_HSIZE; i++) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000674 bool change_needed = false;
675
676 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800677 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
Jiri Pirko5c766d62013-01-24 09:41:41 +0000678 unsigned long age;
679
680 if (ifa->ifa_flags & IFA_F_PERMANENT)
681 continue;
682
683 /* We try to batch several events at once. */
684 age = (now - ifa->ifa_tstamp +
685 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
686
687 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
688 age >= ifa->ifa_valid_lft) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000689 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000690 } else if (ifa->ifa_preferred_lft ==
691 INFINITY_LIFE_TIME) {
692 continue;
693 } else if (age >= ifa->ifa_preferred_lft) {
694 if (time_before(ifa->ifa_tstamp +
695 ifa->ifa_valid_lft * HZ, next))
696 next = ifa->ifa_tstamp +
697 ifa->ifa_valid_lft * HZ;
698
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000699 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
700 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000701 } else if (time_before(ifa->ifa_tstamp +
702 ifa->ifa_preferred_lft * HZ,
703 next)) {
704 next = ifa->ifa_tstamp +
705 ifa->ifa_preferred_lft * HZ;
706 }
707 }
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000708 rcu_read_unlock();
709 if (!change_needed)
710 continue;
711 rtnl_lock();
712 hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
713 unsigned long age;
714
715 if (ifa->ifa_flags & IFA_F_PERMANENT)
716 continue;
717
718 /* We try to batch several events at once. */
719 age = (now - ifa->ifa_tstamp +
720 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
721
722 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
723 age >= ifa->ifa_valid_lft) {
724 struct in_ifaddr **ifap;
725
726 for (ifap = &ifa->ifa_dev->ifa_list;
727 *ifap != NULL; ifap = &(*ifap)->ifa_next) {
728 if (*ifap == ifa) {
729 inet_del_ifa(ifa->ifa_dev,
730 ifap, 1);
731 break;
732 }
733 }
734 } else if (ifa->ifa_preferred_lft !=
735 INFINITY_LIFE_TIME &&
736 age >= ifa->ifa_preferred_lft &&
737 !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
738 ifa->ifa_flags |= IFA_F_DEPRECATED;
739 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
740 }
741 }
742 rtnl_unlock();
Jiri Pirko5c766d62013-01-24 09:41:41 +0000743 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000744
745 next_sec = round_jiffies_up(next);
746 next_sched = next;
747
748 /* If rounded timeout is accurate enough, accept it. */
749 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
750 next_sched = next_sec;
751
752 now = jiffies;
753 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
754 if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
755 next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
756
viresh kumar906e0732014-01-22 12:23:32 +0530757 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work,
758 next_sched - now);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000759}
760
761static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
762 __u32 prefered_lft)
763{
764 unsigned long timeout;
765
766 ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
767
768 timeout = addrconf_timeout_fixup(valid_lft, HZ);
769 if (addrconf_finite_timeout(timeout))
770 ifa->ifa_valid_lft = timeout;
771 else
772 ifa->ifa_flags |= IFA_F_PERMANENT;
773
774 timeout = addrconf_timeout_fixup(prefered_lft, HZ);
775 if (addrconf_finite_timeout(timeout)) {
776 if (timeout == 0)
777 ifa->ifa_flags |= IFA_F_DEPRECATED;
778 ifa->ifa_preferred_lft = timeout;
779 }
780 ifa->ifa_tstamp = jiffies;
781 if (!ifa->ifa_cstamp)
782 ifa->ifa_cstamp = ifa->ifa_tstamp;
783}
784
785static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
David Aherndac9c972018-10-07 20:16:24 -0700786 __u32 *pvalid_lft, __u32 *pprefered_lft,
787 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788{
Thomas Graf5c753972006-08-04 23:03:53 -0700789 struct nlattr *tb[IFA_MAX+1];
790 struct in_ifaddr *ifa;
791 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 struct net_device *dev;
793 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800794 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
Johannes Bergfceb6432017-04-12 14:34:07 +0200796 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
David Aherndac9c972018-10-07 20:16:24 -0700797 extack);
Thomas Graf5c753972006-08-04 23:03:53 -0700798 if (err < 0)
799 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
Thomas Graf5c753972006-08-04 23:03:53 -0700801 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800802 err = -EINVAL;
Ian Morris51456b22015-04-03 09:17:26 +0100803 if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL])
Thomas Graf5c753972006-08-04 23:03:53 -0700804 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800806 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800807 err = -ENODEV;
Ian Morris51456b22015-04-03 09:17:26 +0100808 if (!dev)
Thomas Graf5c753972006-08-04 23:03:53 -0700809 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
Thomas Graf5c753972006-08-04 23:03:53 -0700811 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800812 err = -ENOBUFS;
Ian Morris51456b22015-04-03 09:17:26 +0100813 if (!in_dev)
Herbert Xu71e27da2007-06-04 23:36:06 -0700814 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
Thomas Graf5c753972006-08-04 23:03:53 -0700816 ifa = inet_alloc_ifa();
Ian Morris51456b22015-04-03 09:17:26 +0100817 if (!ifa)
Thomas Graf5c753972006-08-04 23:03:53 -0700818 /*
819 * A potential indev allocation can be left alive, it stays
820 * assigned to its device and is destroy with it.
821 */
Thomas Graf5c753972006-08-04 23:03:53 -0700822 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700823
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800824 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100825 neigh_parms_data_state_setall(in_dev->arp_parms);
Thomas Graf5c753972006-08-04 23:03:53 -0700826 in_dev_hold(in_dev);
827
Ian Morris51456b22015-04-03 09:17:26 +0100828 if (!tb[IFA_ADDRESS])
Thomas Graf5c753972006-08-04 23:03:53 -0700829 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
830
David S. Millerfd23c3b2011-02-18 12:42:28 -0800831 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
833 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100834 ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
835 ifm->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700837 ifa->ifa_dev = in_dev;
838
Jiri Benc67b61f62015-03-29 16:59:26 +0200839 ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]);
840 ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700841
842 if (tb[IFA_BROADCAST])
Jiri Benc67b61f62015-03-29 16:59:26 +0200843 ifa->ifa_broadcast = nla_get_in_addr(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700844
Thomas Graf5c753972006-08-04 23:03:53 -0700845 if (tb[IFA_LABEL])
846 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 else
848 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
849
David Ahernaf4d7682018-05-27 08:09:57 -0700850 if (tb[IFA_RT_PRIORITY])
851 ifa->ifa_rt_priority = nla_get_u32(tb[IFA_RT_PRIORITY]);
852
Jiri Pirko5c766d62013-01-24 09:41:41 +0000853 if (tb[IFA_CACHEINFO]) {
854 struct ifa_cacheinfo *ci;
855
856 ci = nla_data(tb[IFA_CACHEINFO]);
857 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
858 err = -EINVAL;
Daniel Borkmann446266b2013-08-02 11:32:43 +0200859 goto errout_free;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000860 }
861 *pvalid_lft = ci->ifa_valid;
862 *pprefered_lft = ci->ifa_prefered;
863 }
864
Thomas Graf5c753972006-08-04 23:03:53 -0700865 return ifa;
866
Daniel Borkmann446266b2013-08-02 11:32:43 +0200867errout_free:
868 inet_free_ifa(ifa);
Thomas Graf5c753972006-08-04 23:03:53 -0700869errout:
870 return ERR_PTR(err);
871}
872
Jiri Pirko5c766d62013-01-24 09:41:41 +0000873static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
874{
875 struct in_device *in_dev = ifa->ifa_dev;
876 struct in_ifaddr *ifa1, **ifap;
877
878 if (!ifa->ifa_local)
879 return NULL;
880
881 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
882 ifap = &ifa1->ifa_next) {
883 if (ifa1->ifa_mask == ifa->ifa_mask &&
884 inet_ifa_match(ifa1->ifa_address, ifa) &&
885 ifa1->ifa_local == ifa->ifa_local)
886 return ifa1;
887 }
888 return NULL;
889}
890
David Ahernc21ef3e2017-04-16 09:48:24 -0700891static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
892 struct netlink_ext_ack *extack)
Thomas Graf5c753972006-08-04 23:03:53 -0700893{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900894 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700895 struct in_ifaddr *ifa;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000896 struct in_ifaddr *ifa_existing;
897 __u32 valid_lft = INFINITY_LIFE_TIME;
898 __u32 prefered_lft = INFINITY_LIFE_TIME;
Thomas Graf5c753972006-08-04 23:03:53 -0700899
900 ASSERT_RTNL();
901
David Aherndac9c972018-10-07 20:16:24 -0700902 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft, extack);
Thomas Graf5c753972006-08-04 23:03:53 -0700903 if (IS_ERR(ifa))
904 return PTR_ERR(ifa);
905
Jiri Pirko5c766d62013-01-24 09:41:41 +0000906 ifa_existing = find_matching_ifa(ifa);
907 if (!ifa_existing) {
908 /* It would be best to check for !NLM_F_CREATE here but
stephen hemminger614d0562014-05-16 20:46:58 -0700909 * userspace already relies on not having to provide this.
Jiri Pirko5c766d62013-01-24 09:41:41 +0000910 */
911 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Madhu Challa93a714d2015-02-25 09:58:35 -0800912 if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
913 int ret = ip_mc_config(net->ipv4.mc_autojoin_sk,
914 true, ifa);
915
916 if (ret < 0) {
917 inet_free_ifa(ifa);
918 return ret;
919 }
920 }
David Ahernde95e042017-10-18 09:56:54 -0700921 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid,
922 extack);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000923 } else {
David Ahernaf4d7682018-05-27 08:09:57 -0700924 u32 new_metric = ifa->ifa_rt_priority;
925
Jiri Pirko5c766d62013-01-24 09:41:41 +0000926 inet_free_ifa(ifa);
927
928 if (nlh->nlmsg_flags & NLM_F_EXCL ||
929 !(nlh->nlmsg_flags & NLM_F_REPLACE))
930 return -EEXIST;
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000931 ifa = ifa_existing;
David Ahernaf4d7682018-05-27 08:09:57 -0700932
933 if (ifa->ifa_rt_priority != new_metric) {
934 fib_modify_prefix_metric(ifa, new_metric);
935 ifa->ifa_rt_priority = new_metric;
936 }
937
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000938 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Jiri Pirko05a324b2013-04-04 23:39:38 +0000939 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530940 queue_delayed_work(system_power_efficient_wq,
941 &check_lifetime_work, 0);
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000942 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000943 }
944 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945}
946
947/*
948 * Determine a default network mask, based on the IP address.
949 */
950
Eric Dumazet40384992012-08-03 21:06:50 +0000951static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952{
953 int rc = -1; /* Something else, probably a multicast. */
954
Joe Perchesf97c1e02007-12-16 13:45:43 -0800955 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900956 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 else {
Al Viro714e85b2006-11-14 20:51:49 -0800958 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
Al Viro714e85b2006-11-14 20:51:49 -0800960 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800962 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800964 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 rc = 24;
966 }
967
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900968 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969}
970
971
Al Viro03aef172017-07-01 07:53:12 -0400972int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 struct sockaddr_in sin_orig;
Al Viro03aef172017-07-01 07:53:12 -0400975 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 struct in_device *in_dev;
977 struct in_ifaddr **ifap = NULL;
978 struct in_ifaddr *ifa = NULL;
979 struct net_device *dev;
980 char *colon;
981 int ret = -EFAULT;
982 int tryaddrmatch = 0;
983
Al Viro03aef172017-07-01 07:53:12 -0400984 ifr->ifr_name[IFNAMSIZ - 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
986 /* save original address for comparison */
987 memcpy(&sin_orig, sin, sizeof(*sin));
988
Al Viro03aef172017-07-01 07:53:12 -0400989 colon = strchr(ifr->ifr_name, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 if (colon)
991 *colon = 0;
992
Al Viro03aef172017-07-01 07:53:12 -0400993 dev_load(net, ifr->ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
Stephen Hemminger132adf52007-03-08 20:44:43 -0800995 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 case SIOCGIFADDR: /* Get interface address */
997 case SIOCGIFBRDADDR: /* Get the broadcast address */
998 case SIOCGIFDSTADDR: /* Get the destination address */
999 case SIOCGIFNETMASK: /* Get the netmask for the interface */
1000 /* Note that these ioctls will not sleep,
1001 so that we do not impose a lock.
1002 One day we will be forced to put shlock here (I mean SMP)
1003 */
1004 tryaddrmatch = (sin_orig.sin_family == AF_INET);
1005 memset(sin, 0, sizeof(*sin));
1006 sin->sin_family = AF_INET;
1007 break;
1008
1009 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +00001010 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +00001011 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 goto out;
1013 break;
1014 case SIOCSIFADDR: /* Set interface address (and family) */
1015 case SIOCSIFBRDADDR: /* Set the broadcast address */
1016 case SIOCSIFDSTADDR: /* Set the destination address */
1017 case SIOCSIFNETMASK: /* Set the netmask for the interface */
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +00001018 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +00001019 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 goto out;
1021 ret = -EINVAL;
1022 if (sin->sin_family != AF_INET)
1023 goto out;
1024 break;
1025 default:
1026 ret = -EINVAL;
1027 goto out;
1028 }
1029
1030 rtnl_lock();
1031
1032 ret = -ENODEV;
Al Viro03aef172017-07-01 07:53:12 -04001033 dev = __dev_get_by_name(net, ifr->ifr_name);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001034 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 goto done;
1036
1037 if (colon)
1038 *colon = ':';
1039
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001040 in_dev = __in_dev_get_rtnl(dev);
1041 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 if (tryaddrmatch) {
1043 /* Matthias Andree */
1044 /* compare label and address (4.4BSD style) */
1045 /* note: we only do this for a limited set of ioctls
1046 and only if the original address family was AF_INET.
1047 This is checked above. */
1048 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1049 ifap = &ifa->ifa_next) {
Al Viro03aef172017-07-01 07:53:12 -04001050 if (!strcmp(ifr->ifr_name, ifa->ifa_label) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -08001052 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 break; /* found */
1054 }
1055 }
1056 }
1057 /* we didn't get a match, maybe the application is
1058 4.3BSD-style and passed in junk so we fall back to
1059 comparing just the label */
1060 if (!ifa) {
1061 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1062 ifap = &ifa->ifa_next)
Al Viro03aef172017-07-01 07:53:12 -04001063 if (!strcmp(ifr->ifr_name, ifa->ifa_label))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 break;
1065 }
1066 }
1067
1068 ret = -EADDRNOTAVAIL;
1069 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
1070 goto done;
1071
Stephen Hemminger132adf52007-03-08 20:44:43 -08001072 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 case SIOCGIFADDR: /* Get interface address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001074 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 sin->sin_addr.s_addr = ifa->ifa_local;
Al Viro03aef172017-07-01 07:53:12 -04001076 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
1078 case SIOCGIFBRDADDR: /* Get the broadcast address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001079 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 sin->sin_addr.s_addr = ifa->ifa_broadcast;
Al Viro03aef172017-07-01 07:53:12 -04001081 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
1083 case SIOCGIFDSTADDR: /* Get the destination address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001084 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 sin->sin_addr.s_addr = ifa->ifa_address;
Al Viro03aef172017-07-01 07:53:12 -04001086 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087
1088 case SIOCGIFNETMASK: /* Get the netmask for the interface */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001089 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 sin->sin_addr.s_addr = ifa->ifa_mask;
Al Viro03aef172017-07-01 07:53:12 -04001091 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092
1093 case SIOCSIFFLAGS:
1094 if (colon) {
1095 ret = -EADDRNOTAVAIL;
1096 if (!ifa)
1097 break;
1098 ret = 0;
Al Viro03aef172017-07-01 07:53:12 -04001099 if (!(ifr->ifr_flags & IFF_UP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 inet_del_ifa(in_dev, ifap, 1);
1101 break;
1102 }
Al Viro03aef172017-07-01 07:53:12 -04001103 ret = dev_change_flags(dev, ifr->ifr_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 break;
1105
1106 case SIOCSIFADDR: /* Set interface address (and family) */
1107 ret = -EINVAL;
1108 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1109 break;
1110
1111 if (!ifa) {
1112 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001113 ifa = inet_alloc_ifa();
1114 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 break;
Xi Wangc7e2e1d2013-01-05 11:19:24 +00001116 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 if (colon)
Al Viro03aef172017-07-01 07:53:12 -04001118 memcpy(ifa->ifa_label, ifr->ifr_name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 else
1120 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1121 } else {
1122 ret = 0;
1123 if (ifa->ifa_local == sin->sin_addr.s_addr)
1124 break;
1125 inet_del_ifa(in_dev, ifap, 0);
1126 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -08001127 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 }
1129
1130 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
1131
1132 if (!(dev->flags & IFF_POINTOPOINT)) {
1133 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
1134 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
1135 if ((dev->flags & IFF_BROADCAST) &&
1136 ifa->ifa_prefixlen < 31)
1137 ifa->ifa_broadcast = ifa->ifa_address |
1138 ~ifa->ifa_mask;
1139 } else {
1140 ifa->ifa_prefixlen = 32;
1141 ifa->ifa_mask = inet_make_mask(32);
1142 }
Jiri Pirko5c766d62013-01-24 09:41:41 +00001143 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 ret = inet_set_ifa(dev, ifa);
1145 break;
1146
1147 case SIOCSIFBRDADDR: /* Set the broadcast address */
1148 ret = 0;
1149 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
1150 inet_del_ifa(in_dev, ifap, 0);
1151 ifa->ifa_broadcast = sin->sin_addr.s_addr;
1152 inet_insert_ifa(ifa);
1153 }
1154 break;
1155
1156 case SIOCSIFDSTADDR: /* Set the destination address */
1157 ret = 0;
1158 if (ifa->ifa_address == sin->sin_addr.s_addr)
1159 break;
1160 ret = -EINVAL;
1161 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1162 break;
1163 ret = 0;
1164 inet_del_ifa(in_dev, ifap, 0);
1165 ifa->ifa_address = sin->sin_addr.s_addr;
1166 inet_insert_ifa(ifa);
1167 break;
1168
1169 case SIOCSIFNETMASK: /* Set the netmask for the interface */
1170
1171 /*
1172 * The mask we set must be legal.
1173 */
1174 ret = -EINVAL;
1175 if (bad_mask(sin->sin_addr.s_addr, 0))
1176 break;
1177 ret = 0;
1178 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -07001179 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 inet_del_ifa(in_dev, ifap, 0);
1181 ifa->ifa_mask = sin->sin_addr.s_addr;
1182 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
1183
1184 /* See if current broadcast address matches
1185 * with current netmask, then recalculate
1186 * the broadcast address. Otherwise it's a
1187 * funny address, so don't touch it since
1188 * the user seems to know what (s)he's doing...
1189 */
1190 if ((dev->flags & IFF_BROADCAST) &&
1191 (ifa->ifa_prefixlen < 31) &&
1192 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -05001193 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 ifa->ifa_broadcast = (ifa->ifa_local |
1195 ~sin->sin_addr.s_addr);
1196 }
1197 inet_insert_ifa(ifa);
1198 }
1199 break;
1200 }
1201done:
1202 rtnl_unlock();
1203out:
1204 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205}
1206
Al Viro36fd6332017-06-26 13:19:16 -04001207static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208{
Herbert Xue5ed6392005-10-03 14:35:55 -07001209 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 struct in_ifaddr *ifa;
1211 struct ifreq ifr;
1212 int done = 0;
1213
Al Viro36fd6332017-06-26 13:19:16 -04001214 if (WARN_ON(size > sizeof(struct ifreq)))
1215 goto out;
1216
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001217 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 goto out;
1219
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001220 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 if (!buf) {
Al Viro36fd6332017-06-26 13:19:16 -04001222 done += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 continue;
1224 }
Al Viro36fd6332017-06-26 13:19:16 -04001225 if (len < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 break;
1227 memset(&ifr, 0, sizeof(struct ifreq));
Dan Carpenter4299c8a2013-07-29 22:15:19 +03001228 strcpy(ifr.ifr_name, ifa->ifa_label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229
1230 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
1231 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1232 ifa->ifa_local;
1233
Al Viro36fd6332017-06-26 13:19:16 -04001234 if (copy_to_user(buf + done, &ifr, size)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 done = -EFAULT;
1236 break;
1237 }
Al Viro36fd6332017-06-26 13:19:16 -04001238 len -= size;
1239 done += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 }
1241out:
1242 return done;
1243}
1244
Gao Feng8b57fd12017-03-10 12:38:47 +08001245static __be32 in_dev_select_addr(const struct in_device *in_dev,
1246 int scope)
1247{
1248 for_primary_ifa(in_dev) {
1249 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1250 ifa->ifa_scope <= scope)
1251 return ifa->ifa_local;
1252 } endfor_ifa(in_dev);
1253
1254 return 0;
1255}
1256
Al Viroa61ced52006-09-26 21:27:54 -07001257__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258{
Al Viroa61ced52006-09-26 21:27:54 -07001259 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001261 struct net *net = dev_net(dev);
David Ahern3f2fb9a2016-02-24 11:47:02 -08001262 int master_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263
1264 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001265 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 if (!in_dev)
1267 goto no_in_dev;
1268
1269 for_primary_ifa(in_dev) {
1270 if (ifa->ifa_scope > scope)
1271 continue;
1272 if (!dst || inet_ifa_match(dst, ifa)) {
1273 addr = ifa->ifa_local;
1274 break;
1275 }
1276 if (!addr)
1277 addr = ifa->ifa_local;
1278 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
1280 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001281 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001282no_in_dev:
David Ahern3f2fb9a2016-02-24 11:47:02 -08001283 master_idx = l3mdev_master_ifindex_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
David Lamparter17b693c2016-02-24 11:47:03 -08001285 /* For VRFs, the VRF device takes the place of the loopback device,
1286 * with addresses on it being preferred. Note in such cases the
1287 * loopback device will be among the devices that fail the master_idx
1288 * equality check in the loop below.
1289 */
1290 if (master_idx &&
1291 (dev = dev_get_by_index_rcu(net, master_idx)) &&
1292 (in_dev = __in_dev_get_rcu(dev))) {
Gao Feng8b57fd12017-03-10 12:38:47 +08001293 addr = in_dev_select_addr(in_dev, scope);
1294 if (addr)
1295 goto out_unlock;
David Lamparter17b693c2016-02-24 11:47:03 -08001296 }
1297
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 /* Not loopback addresses on loopback should be preferred
Stephen Hemmingerca9f1fd2015-02-14 13:47:54 -05001299 in this case. It is important that lo is the first interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 in dev_base list.
1301 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001302 for_each_netdev_rcu(net, dev) {
David Ahern3f2fb9a2016-02-24 11:47:02 -08001303 if (l3mdev_master_ifindex_rcu(dev) != master_idx)
1304 continue;
1305
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001306 in_dev = __in_dev_get_rcu(dev);
1307 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 continue;
1309
Gao Feng8b57fd12017-03-10 12:38:47 +08001310 addr = in_dev_select_addr(in_dev, scope);
1311 if (addr)
1312 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001314out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 return addr;
1317}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001318EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
Al Viro60cad5d2006-09-26 22:17:09 -07001320static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1321 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322{
1323 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001324 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325
1326 for_ifa(in_dev) {
1327 if (!addr &&
1328 (local == ifa->ifa_local || !local) &&
1329 ifa->ifa_scope <= scope) {
1330 addr = ifa->ifa_local;
1331 if (same)
1332 break;
1333 }
1334 if (!same) {
1335 same = (!local || inet_ifa_match(local, ifa)) &&
1336 (!dst || inet_ifa_match(dst, ifa));
1337 if (same && addr) {
1338 if (local || !dst)
1339 break;
1340 /* Is the selected addr into dst subnet? */
1341 if (inet_ifa_match(addr, ifa))
1342 break;
1343 /* No, then can we use new local src? */
1344 if (ifa->ifa_scope <= scope) {
1345 addr = ifa->ifa_local;
1346 break;
1347 }
1348 /* search for large dst subnet for addr */
1349 same = 0;
1350 }
1351 }
1352 } endfor_ifa(in_dev);
1353
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001354 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355}
1356
1357/*
1358 * Confirm that local IP address exists using wildcards:
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001359 * - net: netns to check, cannot be NULL
1360 * - in_dev: only on this interface, NULL=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 * - dst: only in the same subnet as dst, 0=any dst
1362 * - local: address, 0=autoselect the local address
1363 * - scope: maximum allowed scope value for the local address
1364 */
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001365__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001366 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367{
Al Viro60cad5d2006-09-26 22:17:09 -07001368 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001369 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
Ian Morris00db4122015-04-03 09:17:27 +01001371 if (in_dev)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001372 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001375 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001376 in_dev = __in_dev_get_rcu(dev);
1377 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 addr = confirm_addr_indev(in_dev, dst, local, scope);
1379 if (addr)
1380 break;
1381 }
1382 }
1383 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384
1385 return addr;
1386}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001387EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388
1389/*
1390 * Device notifier
1391 */
1392
1393int register_inetaddr_notifier(struct notifier_block *nb)
1394{
Alan Sterne041c682006-03-27 01:16:30 -08001395 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001397EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
1399int unregister_inetaddr_notifier(struct notifier_block *nb)
1400{
Alan Sterne041c682006-03-27 01:16:30 -08001401 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001403EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
Krister Johansen3ad7d242017-06-08 13:12:14 -07001405int register_inetaddr_validator_notifier(struct notifier_block *nb)
1406{
1407 return blocking_notifier_chain_register(&inetaddr_validator_chain, nb);
1408}
1409EXPORT_SYMBOL(register_inetaddr_validator_notifier);
1410
1411int unregister_inetaddr_validator_notifier(struct notifier_block *nb)
1412{
1413 return blocking_notifier_chain_unregister(&inetaddr_validator_chain,
1414 nb);
1415}
1416EXPORT_SYMBOL(unregister_inetaddr_validator_notifier);
1417
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001418/* Rename ifa_labels for a device name change. Make some effort to preserve
1419 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420*/
1421static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001422{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 struct in_ifaddr *ifa;
1424 int named = 0;
1425
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001426 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1427 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428
1429 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001430 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001432 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001433 dot = strchr(old, ':');
Ian Morris51456b22015-04-03 09:17:26 +01001434 if (!dot) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001435 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 dot = old;
1437 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001438 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001439 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001440 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001441 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001442skip:
1443 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001444 }
1445}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446
Eric Dumazet40384992012-08-03 21:06:50 +00001447static bool inetdev_valid_mtu(unsigned int mtu)
Breno Leitao06770842008-09-02 17:28:58 -07001448{
Eric Dumazetb5476022017-12-11 07:17:39 -08001449 return mtu >= IPV4_MIN_MTU;
Breno Leitao06770842008-09-02 17:28:58 -07001450}
1451
Ian Campbelld11327ad2011-02-11 07:44:16 +00001452static void inetdev_send_gratuitous_arp(struct net_device *dev,
1453 struct in_device *in_dev)
1454
1455{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001456 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001457
Zoltan Kissb76d0782011-07-24 13:09:30 +00001458 for (ifa = in_dev->ifa_list; ifa;
1459 ifa = ifa->ifa_next) {
1460 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1461 ifa->ifa_local, dev,
1462 ifa->ifa_local, NULL,
1463 dev->dev_addr, NULL);
1464 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001465}
1466
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467/* Called only under RTNL semaphore */
1468
1469static int inetdev_event(struct notifier_block *this, unsigned long event,
1470 void *ptr)
1471{
Jiri Pirko351638e2013-05-28 01:30:21 +00001472 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazet748e2d92012-08-22 21:50:59 +00001473 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474
1475 ASSERT_RTNL();
1476
1477 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001478 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 in_dev = inetdev_init(dev);
WANG Cong20e61da2014-07-25 15:25:08 -07001480 if (IS_ERR(in_dev))
1481 return notifier_from_errno(PTR_ERR(in_dev));
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001482 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001483 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1484 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001485 }
Breno Leitao06770842008-09-02 17:28:58 -07001486 } else if (event == NETDEV_CHANGEMTU) {
1487 /* Re-enabling IP */
1488 if (inetdev_valid_mtu(dev->mtu))
1489 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 }
1491 goto out;
1492 }
1493
1494 switch (event) {
1495 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001496 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001497 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 break;
1499 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001500 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001502 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001503 struct in_ifaddr *ifa = inet_alloc_ifa();
1504
1505 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001506 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 ifa->ifa_local =
1508 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1509 ifa->ifa_prefixlen = 8;
1510 ifa->ifa_mask = inet_make_mask(8);
1511 in_dev_hold(in_dev);
1512 ifa->ifa_dev = in_dev;
1513 ifa->ifa_scope = RT_SCOPE_HOST;
1514 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Jiri Pirko5c766d62013-01-24 09:41:41 +00001515 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1516 INFINITY_LIFE_TIME);
Jiri Pirkodfd15822014-01-07 15:55:45 +01001517 ipv4_devconf_setall(in_dev);
1518 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 inet_insert_ifa(ifa);
1520 }
1521 }
1522 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001523 /* fall through */
1524 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001525 if (!IN_DEV_ARP_NOTIFY(in_dev))
1526 break;
1527 /* fall through */
1528 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001529 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001530 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 break;
1532 case NETDEV_DOWN:
1533 ip_mc_down(in_dev);
1534 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001535 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001536 ip_mc_unmap(in_dev);
1537 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001538 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001539 ip_mc_remap(in_dev);
1540 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001542 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 break;
Breno Leitao06770842008-09-02 17:28:58 -07001544 /* disable IP when MTU is not enough */
Gustavo A. R. Silvafcfd6df2017-10-16 15:48:55 -05001545 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 case NETDEV_UNREGISTER:
1547 inetdev_destroy(in_dev);
1548 break;
1549 case NETDEV_CHANGENAME:
1550 /* Do not notify about label change, this event is
1551 * not interesting to applications using netlink.
1552 */
1553 inetdev_changename(dev, in_dev);
1554
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001555 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001556 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 break;
1558 }
1559out:
1560 return NOTIFY_DONE;
1561}
1562
1563static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001564 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565};
1566
Eric Dumazet40384992012-08-03 21:06:50 +00001567static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001568{
1569 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1570 + nla_total_size(4) /* IFA_ADDRESS */
1571 + nla_total_size(4) /* IFA_LOCAL */
1572 + nla_total_size(4) /* IFA_BROADCAST */
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001573 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001574 + nla_total_size(4) /* IFA_FLAGS */
David Ahernaf4d7682018-05-27 08:09:57 -07001575 + nla_total_size(4) /* IFA_RT_PRIORITY */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001576 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
Thomas Graf339bf982006-11-10 14:10:15 -08001577}
1578
Jiri Pirko5c766d62013-01-24 09:41:41 +00001579static inline u32 cstamp_delta(unsigned long cstamp)
1580{
1581 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1582}
1583
1584static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1585 unsigned long tstamp, u32 preferred, u32 valid)
1586{
1587 struct ifa_cacheinfo ci;
1588
1589 ci.cstamp = cstamp_delta(cstamp);
1590 ci.tstamp = cstamp_delta(tstamp);
1591 ci.ifa_prefered = preferred;
1592 ci.ifa_valid = valid;
1593
1594 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1595}
1596
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Christian Brauner978a46f2018-09-04 21:53:54 +02001598 struct inet_fill_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599{
1600 struct ifaddrmsg *ifm;
1601 struct nlmsghdr *nlh;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001602 u32 preferred, valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603
Christian Brauner978a46f2018-09-04 21:53:54 +02001604 nlh = nlmsg_put(skb, args->portid, args->seq, args->event, sizeof(*ifm),
1605 args->flags);
Ian Morris51456b22015-04-03 09:17:26 +01001606 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08001607 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001608
1609 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 ifm->ifa_family = AF_INET;
1611 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001612 ifm->ifa_flags = ifa->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 ifm->ifa_scope = ifa->ifa_scope;
1614 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615
Christian Brauner978a46f2018-09-04 21:53:54 +02001616 if (args->netnsid >= 0 &&
1617 nla_put_s32(skb, IFA_TARGET_NETNSID, args->netnsid))
Christian Braunerd3807142018-09-04 21:53:49 +02001618 goto nla_put_failure;
1619
Jiri Pirko5c766d62013-01-24 09:41:41 +00001620 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1621 preferred = ifa->ifa_preferred_lft;
1622 valid = ifa->ifa_valid_lft;
1623 if (preferred != INFINITY_LIFE_TIME) {
1624 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1625
1626 if (preferred > tval)
1627 preferred -= tval;
1628 else
1629 preferred = 0;
1630 if (valid != INFINITY_LIFE_TIME) {
1631 if (valid > tval)
1632 valid -= tval;
1633 else
1634 valid = 0;
1635 }
1636 }
1637 } else {
1638 preferred = INFINITY_LIFE_TIME;
1639 valid = INFINITY_LIFE_TIME;
1640 }
David S. Millerf3756b72012-04-01 20:39:02 -04001641 if ((ifa->ifa_address &&
Jiri Benc930345e2015-03-29 16:59:25 +02001642 nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001643 (ifa->ifa_local &&
Jiri Benc930345e2015-03-29 16:59:25 +02001644 nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001645 (ifa->ifa_broadcast &&
Jiri Benc930345e2015-03-29 16:59:25 +02001646 nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001647 (ifa->ifa_label[0] &&
Jiri Pirko5c766d62013-01-24 09:41:41 +00001648 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001649 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
David Ahernaf4d7682018-05-27 08:09:57 -07001650 (ifa->ifa_rt_priority &&
1651 nla_put_u32(skb, IFA_RT_PRIORITY, ifa->ifa_rt_priority)) ||
Jiri Pirko5c766d62013-01-24 09:41:41 +00001652 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1653 preferred, valid))
David S. Millerf3756b72012-04-01 20:39:02 -04001654 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001655
Johannes Berg053c0952015-01-16 22:09:00 +01001656 nlmsg_end(skb, nlh);
1657 return 0;
Thomas Graf47f68512006-08-04 23:04:36 -07001658
1659nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001660 nlmsg_cancel(skb, nlh);
1661 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662}
1663
David Ahernc33078e2018-10-07 20:16:28 -07001664static int inet_valid_dump_ifaddr_req(const struct nlmsghdr *nlh,
1665 struct inet_fill_args *fillargs,
1666 struct net **tgt_net, struct sock *sk,
David Ahern5fcd2662018-10-19 12:45:29 -07001667 struct netlink_callback *cb)
David Ahernc33078e2018-10-07 20:16:28 -07001668{
David Ahern5fcd2662018-10-19 12:45:29 -07001669 struct netlink_ext_ack *extack = cb->extack;
David Ahernc33078e2018-10-07 20:16:28 -07001670 struct nlattr *tb[IFA_MAX+1];
1671 struct ifaddrmsg *ifm;
1672 int err, i;
1673
1674 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) {
1675 NL_SET_ERR_MSG(extack, "ipv4: Invalid header for address dump request");
1676 return -EINVAL;
1677 }
1678
1679 ifm = nlmsg_data(nlh);
1680 if (ifm->ifa_prefixlen || ifm->ifa_flags || ifm->ifa_scope) {
1681 NL_SET_ERR_MSG(extack, "ipv4: Invalid values in header for address dump request");
1682 return -EINVAL;
1683 }
David Ahern5fcd2662018-10-19 12:45:29 -07001684
1685 fillargs->ifindex = ifm->ifa_index;
1686 if (fillargs->ifindex) {
1687 cb->answer_flags |= NLM_F_DUMP_FILTERED;
1688 fillargs->flags |= NLM_F_DUMP_FILTERED;
David Ahernc33078e2018-10-07 20:16:28 -07001689 }
1690
1691 err = nlmsg_parse_strict(nlh, sizeof(*ifm), tb, IFA_MAX,
1692 ifa_ipv4_policy, extack);
1693 if (err < 0)
1694 return err;
1695
1696 for (i = 0; i <= IFA_MAX; ++i) {
1697 if (!tb[i])
1698 continue;
1699
1700 if (i == IFA_TARGET_NETNSID) {
1701 struct net *net;
1702
1703 fillargs->netnsid = nla_get_s32(tb[i]);
1704
1705 net = rtnl_get_net_ns_capable(sk, fillargs->netnsid);
1706 if (IS_ERR(net)) {
Bjørn Morkbf4cc402018-10-25 21:18:25 +02001707 fillargs->netnsid = -1;
David Ahernc33078e2018-10-07 20:16:28 -07001708 NL_SET_ERR_MSG(extack, "ipv4: Invalid target network namespace id");
1709 return PTR_ERR(net);
1710 }
1711 *tgt_net = net;
1712 } else {
1713 NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in dump request");
1714 return -EINVAL;
1715 }
1716 }
1717
1718 return 0;
1719}
1720
David Ahern1c98eca2018-10-19 12:45:27 -07001721static int in_dev_dump_addr(struct in_device *in_dev, struct sk_buff *skb,
1722 struct netlink_callback *cb, int s_ip_idx,
1723 struct inet_fill_args *fillargs)
1724{
1725 struct in_ifaddr *ifa;
1726 int ip_idx = 0;
1727 int err;
1728
1729 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next, ip_idx++) {
1730 if (ip_idx < s_ip_idx)
1731 continue;
1732
1733 err = inet_fill_ifaddr(skb, ifa, fillargs);
1734 if (err < 0)
1735 goto done;
1736
1737 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
1738 }
1739 err = 0;
1740
1741done:
1742 cb->args[2] = ip_idx;
1743
1744 return err;
1745}
1746
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1748{
David Ahernc33078e2018-10-07 20:16:28 -07001749 const struct nlmsghdr *nlh = cb->nlh;
Christian Brauner978a46f2018-09-04 21:53:54 +02001750 struct inet_fill_args fillargs = {
1751 .portid = NETLINK_CB(cb->skb).portid,
David Ahernc33078e2018-10-07 20:16:28 -07001752 .seq = nlh->nlmsg_seq,
Christian Brauner978a46f2018-09-04 21:53:54 +02001753 .event = RTM_NEWADDR,
1754 .flags = NLM_F_MULTI,
1755 .netnsid = -1,
1756 };
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001757 struct net *net = sock_net(skb->sk);
Christian Braunerd3807142018-09-04 21:53:49 +02001758 struct net *tgt_net = net;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001759 int h, s_h;
1760 int idx, s_idx;
David Ahern1c98eca2018-10-19 12:45:27 -07001761 int s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 struct net_device *dev;
1763 struct in_device *in_dev;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001764 struct hlist_head *head;
David Ahernd7e38612018-10-24 12:58:59 -07001765 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
Eric Dumazeteec4df92009-11-12 07:44:25 +00001767 s_h = cb->args[0];
1768 s_idx = idx = cb->args[1];
David Ahern1c98eca2018-10-19 12:45:27 -07001769 s_ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770
David Ahernc33078e2018-10-07 20:16:28 -07001771 if (cb->strict_check) {
David Ahernc33078e2018-10-07 20:16:28 -07001772 err = inet_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net,
David Ahern5fcd2662018-10-19 12:45:29 -07001773 skb->sk, cb);
David Ahernc33078e2018-10-07 20:16:28 -07001774 if (err < 0)
David Ahernd7e38612018-10-24 12:58:59 -07001775 goto put_tgt_net;
David Ahern5fcd2662018-10-19 12:45:29 -07001776
David Ahernd7e38612018-10-24 12:58:59 -07001777 err = 0;
David Ahern5fcd2662018-10-19 12:45:29 -07001778 if (fillargs.ifindex) {
1779 dev = __dev_get_by_index(tgt_net, fillargs.ifindex);
David Ahernd7e38612018-10-24 12:58:59 -07001780 if (!dev) {
1781 err = -ENODEV;
1782 goto put_tgt_net;
1783 }
David Ahern5fcd2662018-10-19 12:45:29 -07001784
1785 in_dev = __in_dev_get_rtnl(dev);
1786 if (in_dev) {
1787 err = in_dev_dump_addr(in_dev, skb, cb, s_ip_idx,
1788 &fillargs);
1789 }
1790 goto put_tgt_net;
1791 }
Christian Braunerd3807142018-09-04 21:53:49 +02001792 }
1793
Eric Dumazeteec4df92009-11-12 07:44:25 +00001794 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1795 idx = 0;
Christian Braunerd3807142018-09-04 21:53:49 +02001796 head = &tgt_net->dev_index_head[h];
Eric Dumazeteec4df92009-11-12 07:44:25 +00001797 rcu_read_lock();
Christian Braunerd3807142018-09-04 21:53:49 +02001798 cb->seq = atomic_read(&tgt_net->ipv4.dev_addr_genid) ^
1799 tgt_net->dev_base_seq;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001800 hlist_for_each_entry_rcu(dev, head, index_hlist) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001801 if (idx < s_idx)
1802 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001803 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001804 s_ip_idx = 0;
1805 in_dev = __in_dev_get_rcu(dev);
1806 if (!in_dev)
1807 goto cont;
1808
David Ahern1c98eca2018-10-19 12:45:27 -07001809 err = in_dev_dump_addr(in_dev, skb, cb, s_ip_idx,
1810 &fillargs);
1811 if (err < 0) {
1812 rcu_read_unlock();
1813 goto done;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001814 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001815cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001816 idx++;
1817 }
1818 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 }
1820
1821done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001822 cb->args[0] = h;
1823 cb->args[1] = idx;
David Ahern5fcd2662018-10-19 12:45:29 -07001824put_tgt_net:
Christian Brauner978a46f2018-09-04 21:53:54 +02001825 if (fillargs.netnsid >= 0)
Christian Braunerd3807142018-09-04 21:53:49 +02001826 put_net(tgt_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827
David Ahernd7e38612018-10-24 12:58:59 -07001828 return err < 0 ? err : skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829}
1830
Jianjun Kong539afed2008-11-03 02:48:48 -08001831static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001832 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833{
Christian Brauner978a46f2018-09-04 21:53:54 +02001834 struct inet_fill_args fillargs = {
1835 .portid = portid,
1836 .seq = nlh ? nlh->nlmsg_seq : 0,
1837 .event = event,
1838 .flags = 0,
1839 .netnsid = -1,
1840 };
Thomas Graf47f68512006-08-04 23:04:36 -07001841 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001842 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001843 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001845 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001846 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001847 if (!skb)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001848 goto errout;
1849
Christian Brauner978a46f2018-09-04 21:53:54 +02001850 err = inet_fill_ifaddr(skb, ifa, &fillargs);
Patrick McHardy26932562007-01-31 23:16:40 -08001851 if (err < 0) {
1852 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1853 WARN_ON(err == -EMSGSIZE);
1854 kfree_skb(skb);
1855 goto errout;
1856 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001857 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001858 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001859errout:
1860 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001861 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862}
1863
Arad, Ronenb1974ed2015-10-19 09:23:28 -07001864static size_t inet_get_link_af_size(const struct net_device *dev,
1865 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001866{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001867 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001868
1869 if (!in_dev)
1870 return 0;
1871
1872 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1873}
1874
Sowmini Varadhand5566fd2015-09-11 16:48:48 -04001875static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
1876 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001877{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001878 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001879 struct nlattr *nla;
1880 int i;
1881
1882 if (!in_dev)
1883 return -ENODATA;
1884
1885 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
Ian Morris51456b22015-04-03 09:17:26 +01001886 if (!nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001887 return -EMSGSIZE;
1888
1889 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1890 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1891
1892 return 0;
1893}
1894
1895static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1896 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1897};
1898
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001899static int inet_validate_link_af(const struct net_device *dev,
1900 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001901{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001902 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1903 int err, rem;
1904
Florian Westphal5fa85a02017-10-16 15:44:36 +02001905 if (dev && !__in_dev_get_rcu(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001906 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001907
Johannes Bergfceb6432017-04-12 14:34:07 +02001908 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy, NULL);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001909 if (err < 0)
1910 return err;
1911
1912 if (tb[IFLA_INET_CONF]) {
1913 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1914 int cfgid = nla_type(a);
1915
1916 if (nla_len(a) < 4)
1917 return -EINVAL;
1918
1919 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1920 return -EINVAL;
1921 }
1922 }
1923
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001924 return 0;
1925}
1926
1927static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1928{
Florian Westphal5fa85a02017-10-16 15:44:36 +02001929 struct in_device *in_dev = __in_dev_get_rcu(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001930 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1931 int rem;
1932
1933 if (!in_dev)
1934 return -EAFNOSUPPORT;
1935
Johannes Bergfceb6432017-04-12 14:34:07 +02001936 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0)
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001937 BUG();
1938
Thomas Graf9f0f7272010-11-16 04:32:48 +00001939 if (tb[IFLA_INET_CONF]) {
1940 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1941 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1942 }
1943
1944 return 0;
1945}
1946
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001947static int inet_netconf_msgsize_devconf(int type)
1948{
1949 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1950 + nla_total_size(4); /* NETCONFA_IFINDEX */
Zhang Shengju136ba622016-03-10 08:55:50 +00001951 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001952
Zhang Shengju136ba622016-03-10 08:55:50 +00001953 if (type == NETCONFA_ALL)
1954 all = true;
1955
1956 if (all || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001957 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001958 if (all || type == NETCONFA_RP_FILTER)
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001959 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001960 if (all || type == NETCONFA_MC_FORWARDING)
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001961 size += nla_total_size(4);
Xin Long5cbf7772018-07-27 16:37:28 +08001962 if (all || type == NETCONFA_BC_FORWARDING)
1963 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001964 if (all || type == NETCONFA_PROXY_NEIGH)
stephen hemmingerf085ff12013-12-12 13:06:50 -08001965 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001966 if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001967 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001968
1969 return size;
1970}
1971
1972static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1973 struct ipv4_devconf *devconf, u32 portid,
1974 u32 seq, int event, unsigned int flags,
1975 int type)
1976{
1977 struct nlmsghdr *nlh;
1978 struct netconfmsg *ncm;
Zhang Shengju136ba622016-03-10 08:55:50 +00001979 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001980
1981 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1982 flags);
Ian Morris51456b22015-04-03 09:17:26 +01001983 if (!nlh)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001984 return -EMSGSIZE;
1985
Zhang Shengju136ba622016-03-10 08:55:50 +00001986 if (type == NETCONFA_ALL)
1987 all = true;
1988
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001989 ncm = nlmsg_data(nlh);
1990 ncm->ncm_family = AF_INET;
1991
1992 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1993 goto nla_put_failure;
1994
David Ahernb5c96412017-03-28 14:28:03 -07001995 if (!devconf)
1996 goto out;
1997
Zhang Shengju136ba622016-03-10 08:55:50 +00001998 if ((all || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001999 nla_put_s32(skb, NETCONFA_FORWARDING,
2000 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
2001 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00002002 if ((all || type == NETCONFA_RP_FILTER) &&
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002003 nla_put_s32(skb, NETCONFA_RP_FILTER,
2004 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
2005 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00002006 if ((all || type == NETCONFA_MC_FORWARDING) &&
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00002007 nla_put_s32(skb, NETCONFA_MC_FORWARDING,
2008 IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
2009 goto nla_put_failure;
Xin Long5cbf7772018-07-27 16:37:28 +08002010 if ((all || type == NETCONFA_BC_FORWARDING) &&
2011 nla_put_s32(skb, NETCONFA_BC_FORWARDING,
2012 IPV4_DEVCONF(*devconf, BC_FORWARDING)) < 0)
2013 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00002014 if ((all || type == NETCONFA_PROXY_NEIGH) &&
stephen hemminger09aea5d2013-12-17 22:35:52 -08002015 nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002016 IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
2017 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00002018 if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002019 nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
2020 IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
2021 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002022
David Ahernb5c96412017-03-28 14:28:03 -07002023out:
Johannes Berg053c0952015-01-16 22:09:00 +01002024 nlmsg_end(skb, nlh);
2025 return 0;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002026
2027nla_put_failure:
2028 nlmsg_cancel(skb, nlh);
2029 return -EMSGSIZE;
2030}
2031
David Ahern3b022862017-03-28 14:28:02 -07002032void inet_netconf_notify_devconf(struct net *net, int event, int type,
2033 int ifindex, struct ipv4_devconf *devconf)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002034{
2035 struct sk_buff *skb;
2036 int err = -ENOBUFS;
2037
Eric Dumazetfa178062016-07-08 05:18:24 +02002038 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002039 if (!skb)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002040 goto errout;
2041
2042 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
David Ahern3b022862017-03-28 14:28:02 -07002043 event, 0, type);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002044 if (err < 0) {
2045 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
2046 WARN_ON(err == -EMSGSIZE);
2047 kfree_skb(skb);
2048 goto errout;
2049 }
Eric Dumazetfa178062016-07-08 05:18:24 +02002050 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002051 return;
2052errout:
2053 if (err < 0)
2054 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
2055}
2056
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002057static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
2058 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
2059 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002060 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
stephen hemminger09aea5d2013-12-17 22:35:52 -08002061 [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) },
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002062 [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002063};
2064
2065static int inet_netconf_get_devconf(struct sk_buff *in_skb,
David Ahernc21ef3e2017-04-16 09:48:24 -07002066 struct nlmsghdr *nlh,
2067 struct netlink_ext_ack *extack)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002068{
2069 struct net *net = sock_net(in_skb->sk);
2070 struct nlattr *tb[NETCONFA_MAX+1];
2071 struct netconfmsg *ncm;
2072 struct sk_buff *skb;
2073 struct ipv4_devconf *devconf;
2074 struct in_device *in_dev;
2075 struct net_device *dev;
2076 int ifindex;
2077 int err;
2078
2079 err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
David Ahernc21ef3e2017-04-16 09:48:24 -07002080 devconf_ipv4_policy, extack);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002081 if (err < 0)
2082 goto errout;
2083
Anton Protopopova97eb332016-02-16 21:43:16 -05002084 err = -EINVAL;
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002085 if (!tb[NETCONFA_IFINDEX])
2086 goto errout;
2087
2088 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
2089 switch (ifindex) {
2090 case NETCONFA_IFINDEX_ALL:
2091 devconf = net->ipv4.devconf_all;
2092 break;
2093 case NETCONFA_IFINDEX_DEFAULT:
2094 devconf = net->ipv4.devconf_dflt;
2095 break;
2096 default:
2097 dev = __dev_get_by_index(net, ifindex);
Ian Morris51456b22015-04-03 09:17:26 +01002098 if (!dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002099 goto errout;
2100 in_dev = __in_dev_get_rtnl(dev);
Ian Morris51456b22015-04-03 09:17:26 +01002101 if (!in_dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002102 goto errout;
2103 devconf = &in_dev->cnf;
2104 break;
2105 }
2106
2107 err = -ENOBUFS;
Eric Dumazetfa178062016-07-08 05:18:24 +02002108 skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002109 if (!skb)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002110 goto errout;
2111
2112 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
2113 NETLINK_CB(in_skb).portid,
2114 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
Zhang Shengju136ba622016-03-10 08:55:50 +00002115 NETCONFA_ALL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002116 if (err < 0) {
2117 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
2118 WARN_ON(err == -EMSGSIZE);
2119 kfree_skb(skb);
2120 goto errout;
2121 }
2122 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
2123errout:
2124 return err;
2125}
2126
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002127static int inet_netconf_dump_devconf(struct sk_buff *skb,
2128 struct netlink_callback *cb)
2129{
David Ahernaddd3832018-10-07 20:16:41 -07002130 const struct nlmsghdr *nlh = cb->nlh;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002131 struct net *net = sock_net(skb->sk);
2132 int h, s_h;
2133 int idx, s_idx;
2134 struct net_device *dev;
2135 struct in_device *in_dev;
2136 struct hlist_head *head;
2137
David Ahernaddd3832018-10-07 20:16:41 -07002138 if (cb->strict_check) {
2139 struct netlink_ext_ack *extack = cb->extack;
2140 struct netconfmsg *ncm;
2141
2142 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ncm))) {
2143 NL_SET_ERR_MSG(extack, "ipv4: Invalid header for netconf dump request");
2144 return -EINVAL;
2145 }
2146
2147 if (nlmsg_attrlen(nlh, sizeof(*ncm))) {
2148 NL_SET_ERR_MSG(extack, "ipv4: Invalid data after header in netconf dump request");
2149 return -EINVAL;
2150 }
2151 }
2152
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002153 s_h = cb->args[0];
2154 s_idx = idx = cb->args[1];
2155
2156 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
2157 idx = 0;
2158 head = &net->dev_index_head[h];
2159 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00002160 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
2161 net->dev_base_seq;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002162 hlist_for_each_entry_rcu(dev, head, index_hlist) {
2163 if (idx < s_idx)
2164 goto cont;
2165 in_dev = __in_dev_get_rcu(dev);
2166 if (!in_dev)
2167 goto cont;
2168
2169 if (inet_netconf_fill_devconf(skb, dev->ifindex,
2170 &in_dev->cnf,
2171 NETLINK_CB(cb->skb).portid,
David Ahernaddd3832018-10-07 20:16:41 -07002172 nlh->nlmsg_seq,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002173 RTM_NEWNETCONF,
2174 NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002175 NETCONFA_ALL) < 0) {
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002176 rcu_read_unlock();
2177 goto done;
2178 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00002179 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002180cont:
2181 idx++;
2182 }
2183 rcu_read_unlock();
2184 }
2185 if (h == NETDEV_HASHENTRIES) {
2186 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
2187 net->ipv4.devconf_all,
2188 NETLINK_CB(cb->skb).portid,
David Ahernaddd3832018-10-07 20:16:41 -07002189 nlh->nlmsg_seq,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002190 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002191 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002192 goto done;
2193 else
2194 h++;
2195 }
2196 if (h == NETDEV_HASHENTRIES + 1) {
2197 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
2198 net->ipv4.devconf_dflt,
2199 NETLINK_CB(cb->skb).portid,
David Ahernaddd3832018-10-07 20:16:41 -07002200 nlh->nlmsg_seq,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002201 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002202 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002203 goto done;
2204 else
2205 h++;
2206 }
2207done:
2208 cb->args[0] = h;
2209 cb->args[1] = idx;
2210
2211 return skb->len;
2212}
2213
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214#ifdef CONFIG_SYSCTL
2215
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002216static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07002217{
2218 struct net_device *dev;
2219
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002220 rcu_read_lock();
2221 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07002222 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002223
Herbert Xu31be3082007-06-04 23:35:37 -07002224 in_dev = __in_dev_get_rcu(dev);
2225 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002226 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07002227 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002228 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07002229}
2230
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002231/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002232static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002233{
2234 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002235 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002236
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002237 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002238 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
David Ahern3b022862017-03-28 14:28:02 -07002239 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2240 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002241 NETCONFA_IFINDEX_ALL,
2242 net->ipv4.devconf_all);
David Ahern3b022862017-03-28 14:28:02 -07002243 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2244 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002245 NETCONFA_IFINDEX_DEFAULT,
2246 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002247
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002248 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002249 struct in_device *in_dev;
Eric Dumazetfa178062016-07-08 05:18:24 +02002250
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002251 if (on)
2252 dev_disable_lro(dev);
Eric Dumazetfa178062016-07-08 05:18:24 +02002253
2254 in_dev = __in_dev_get_rtnl(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002255 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002256 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
David Ahern3b022862017-03-28 14:28:02 -07002257 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2258 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002259 dev->ifindex, &in_dev->cnf);
2260 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002261 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002262}
2263
stephen hemmingerf085ff12013-12-12 13:06:50 -08002264static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf)
2265{
2266 if (cnf == net->ipv4.devconf_dflt)
2267 return NETCONFA_IFINDEX_DEFAULT;
2268 else if (cnf == net->ipv4.devconf_all)
2269 return NETCONFA_IFINDEX_ALL;
2270 else {
2271 struct in_device *idev
2272 = container_of(cnf, struct in_device, cnf);
2273 return idev->dev->ifindex;
2274 }
2275}
2276
Joe Perchesfe2c6332013-06-11 23:04:25 -07002277static int devinet_conf_proc(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002278 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07002279 size_t *lenp, loff_t *ppos)
2280{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002281 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002282 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002283 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07002284
2285 if (write) {
2286 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002287 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07002288 int i = (int *)ctl->data - cnf->data;
stephen hemmingerf085ff12013-12-12 13:06:50 -08002289 int ifindex;
Herbert Xu31be3082007-06-04 23:35:37 -07002290
2291 set_bit(i, cnf->state);
2292
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002293 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002294 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00002295 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
2296 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002297 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002298 rt_cache_flush(net);
stephen hemmingerf085ff12013-12-12 13:06:50 -08002299
Xin Long5cbf7772018-07-27 16:37:28 +08002300 if (i == IPV4_DEVCONF_BC_FORWARDING - 1 &&
2301 new_value != old_value)
2302 rt_cache_flush(net);
2303
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002304 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
2305 new_value != old_value) {
stephen hemmingerf085ff12013-12-12 13:06:50 -08002306 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002307 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2308 NETCONFA_RP_FILTER,
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002309 ifindex, cnf);
2310 }
stephen hemmingerf085ff12013-12-12 13:06:50 -08002311 if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
2312 new_value != old_value) {
2313 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002314 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2315 NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002316 ifindex, cnf);
2317 }
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002318 if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
2319 new_value != old_value) {
2320 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002321 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2322 NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002323 ifindex, cnf);
2324 }
Herbert Xu31be3082007-06-04 23:35:37 -07002325 }
2326
2327 return ret;
2328}
2329
Joe Perchesfe2c6332013-06-11 23:04:25 -07002330static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002331 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 size_t *lenp, loff_t *ppos)
2333{
2334 int *valp = ctl->data;
2335 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00002336 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002337 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338
2339 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002340 struct net *net = ctl->extra2;
2341
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002342 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00002343 if (!rtnl_trylock()) {
2344 /* Restore the original values before restarting */
2345 *valp = val;
2346 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00002347 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00002348 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002349 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2350 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002351 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002352 struct ipv4_devconf *cnf = ctl->extra1;
2353 struct in_device *idev =
2354 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002355 if (*valp)
2356 dev_disable_lro(idev->dev);
David Ahern3b022862017-03-28 14:28:02 -07002357 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002358 NETCONFA_FORWARDING,
2359 idev->dev->ifindex,
2360 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002361 }
2362 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002363 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002364 } else
David Ahern3b022862017-03-28 14:28:02 -07002365 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2366 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002367 NETCONFA_IFINDEX_DEFAULT,
2368 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 }
2370
2371 return ret;
2372}
2373
Joe Perchesfe2c6332013-06-11 23:04:25 -07002374static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
David S. Miller323e1262010-12-12 21:55:08 -08002375 void __user *buffer,
2376 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377{
2378 int *valp = ctl->data;
2379 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002380 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07002381 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382
2383 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002384 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385
2386 return ret;
2387}
2388
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002389#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07002390 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07002391 .procname = name, \
2392 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00002393 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002394 .maxlen = sizeof(int), \
2395 .mode = mval, \
2396 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07002397 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002398 }
2399
2400#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002401 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002402
2403#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002404 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002405
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002406#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2407 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002408
2409#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002410 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07002411
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412static struct devinet_sysctl_table {
2413 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00002414 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415} devinet_sysctl = {
2416 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07002417 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002418 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07002419 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
Xin Long5cbf7772018-07-27 16:37:28 +08002420 DEVINET_SYSCTL_RW_ENTRY(BC_FORWARDING, "bc_forwarding"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002421
2422 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
2423 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
2424 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
2425 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
2426 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
2427 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
2428 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00002429 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08002430 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002431 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
2432 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
2433 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
2434 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
2435 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
2436 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
2437 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
2438 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
2439 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08002440 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00002441 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
William Manley5c6fe012013-08-06 19:03:14 +01002442 DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
2443 "force_igmp_version"),
William Manley26900482013-08-06 19:03:15 +01002444 DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
2445 "igmpv2_unsolicited_report_interval"),
2446 DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
2447 "igmpv3_unsolicited_report_interval"),
Andy Gospodarek0eeb0752015-06-23 13:45:37 -04002448 DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
2449 "ignore_routes_with_linkdown"),
Johannes Berg97daf332016-02-04 13:31:18 +01002450 DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
2451 "drop_gratuitous_arp"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002452
2453 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2454 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002455 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
2456 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00002457 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2458 "route_localnet"),
Johannes Berg12b74df2016-02-04 13:31:17 +01002459 DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
2460 "drop_unicast_in_l2_multicast"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462};
2463
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002464static int __devinet_sysctl_register(struct net *net, char *dev_name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002465 int ifindex, struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466{
2467 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002468 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002469 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11002470
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002471 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002473 goto out;
2474
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
2476 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07002477 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002478 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 }
2480
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002481 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002483 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002485 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486
2487 p->sysctl = t;
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002488
David Ahern3b022862017-03-28 14:28:02 -07002489 inet_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_ALL,
2490 ifindex, p);
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002491 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002493free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002495out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002496 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497}
2498
David Ahernb5c96412017-03-28 14:28:03 -07002499static void __devinet_sysctl_unregister(struct net *net,
2500 struct ipv4_devconf *cnf, int ifindex)
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002501{
2502 struct devinet_sysctl_table *t = cnf->sysctl;
2503
David Ahernb5c96412017-03-28 14:28:03 -07002504 if (t) {
2505 cnf->sysctl = NULL;
2506 unregister_net_sysctl_table(t->sysctl_header);
2507 kfree(t);
2508 }
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002509
David Ahernb5c96412017-03-28 14:28:03 -07002510 inet_netconf_notify_devconf(net, RTM_DELNETCONF, 0, ifindex, NULL);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002511}
2512
WANG Cong20e61da2014-07-25 15:25:08 -07002513static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002514{
WANG Cong20e61da2014-07-25 15:25:08 -07002515 int err;
2516
2517 if (!sysctl_dev_name_is_allowed(idev->dev->name))
2518 return -EINVAL;
2519
2520 err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
2521 if (err)
2522 return err;
2523 err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002524 idev->dev->ifindex, &idev->cnf);
WANG Cong20e61da2014-07-25 15:25:08 -07002525 if (err)
2526 neigh_sysctl_unregister(idev->arp_parms);
2527 return err;
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002528}
2529
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002530static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531{
David Ahernb5c96412017-03-28 14:28:03 -07002532 struct net *net = dev_net(idev->dev);
2533
2534 __devinet_sysctl_unregister(net, &idev->cnf, idev->dev->ifindex);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002535 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002538static struct ctl_table ctl_forward_entry[] = {
2539 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002540 .procname = "ip_forward",
2541 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00002542 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002543 .maxlen = sizeof(int),
2544 .mode = 0644,
2545 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002546 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002547 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002548 },
2549 { },
2550};
Eric Dumazet2a75de02008-01-05 23:08:49 -08002551#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002552
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002553static __net_init int devinet_init_net(struct net *net)
2554{
2555 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002556 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002557#ifdef CONFIG_SYSCTL
2558 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002559 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002560#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002561
2562 err = -ENOMEM;
2563 all = &ipv4_devconf;
2564 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002565
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002566 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002567 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002568 if (!all)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002569 goto err_alloc_all;
2570
2571 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002572 if (!dflt)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002573 goto err_alloc_dflt;
2574
Eric Dumazet2a75de02008-01-05 23:08:49 -08002575#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002576 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002577 if (!tbl)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002578 goto err_alloc_ctl;
2579
Eric W. Biederman02291682010-02-14 03:25:51 +00002580 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002581 tbl[0].extra1 = all;
2582 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002583#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002584 }
2585
2586#ifdef CONFIG_SYSCTL
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002587 err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002588 if (err < 0)
2589 goto err_reg_all;
2590
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002591 err = __devinet_sysctl_register(net, "default",
2592 NETCONFA_IFINDEX_DEFAULT, dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002593 if (err < 0)
2594 goto err_reg_dflt;
2595
2596 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002597 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Ian Morris51456b22015-04-03 09:17:26 +01002598 if (!forw_hdr)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002599 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002600 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002601#endif
2602
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002603 net->ipv4.devconf_all = all;
2604 net->ipv4.devconf_dflt = dflt;
2605 return 0;
2606
2607#ifdef CONFIG_SYSCTL
2608err_reg_ctl:
David Ahernb5c96412017-03-28 14:28:03 -07002609 __devinet_sysctl_unregister(net, dflt, NETCONFA_IFINDEX_DEFAULT);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002610err_reg_dflt:
David Ahernb5c96412017-03-28 14:28:03 -07002611 __devinet_sysctl_unregister(net, all, NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002612err_reg_all:
2613 if (tbl != ctl_forward_entry)
2614 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002615err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08002616#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002617 if (dflt != &ipv4_devconf_dflt)
2618 kfree(dflt);
2619err_alloc_dflt:
2620 if (all != &ipv4_devconf)
2621 kfree(all);
2622err_alloc_all:
2623 return err;
2624}
2625
2626static __net_exit void devinet_exit_net(struct net *net)
2627{
Eric Dumazet2a75de02008-01-05 23:08:49 -08002628#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002629 struct ctl_table *tbl;
2630
2631 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002632 unregister_net_sysctl_table(net->ipv4.forw_hdr);
David Ahernb5c96412017-03-28 14:28:03 -07002633 __devinet_sysctl_unregister(net, net->ipv4.devconf_dflt,
2634 NETCONFA_IFINDEX_DEFAULT);
2635 __devinet_sysctl_unregister(net, net->ipv4.devconf_all,
2636 NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002637 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08002638#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002639 kfree(net->ipv4.devconf_dflt);
2640 kfree(net->ipv4.devconf_all);
2641}
2642
2643static __net_initdata struct pernet_operations devinet_ops = {
2644 .init = devinet_init_net,
2645 .exit = devinet_exit_net,
2646};
2647
Daniel Borkmann207895fd32015-01-29 12:15:03 +01002648static struct rtnl_af_ops inet_af_ops __read_mostly = {
Thomas Graf9f0f7272010-11-16 04:32:48 +00002649 .family = AF_INET,
2650 .fill_link_af = inet_fill_link_af,
2651 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00002652 .validate_link_af = inet_validate_link_af,
2653 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00002654};
2655
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656void __init devinet_init(void)
2657{
David S. Millerfd23c3b2011-02-18 12:42:28 -08002658 int i;
2659
2660 for (i = 0; i < IN4_ADDR_HSIZE; i++)
2661 INIT_HLIST_HEAD(&inet_addr_lst[i]);
2662
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002663 register_pernet_subsys(&devinet_ops);
2664
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 register_gifconf(PF_INET, inet_gifconf);
2666 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07002667
viresh kumar906e0732014-01-22 12:23:32 +05302668 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +00002669
Thomas Graf9f0f7272010-11-16 04:32:48 +00002670 rtnl_af_register(&inet_af_ops);
2671
Florian Westphalb97bac62017-08-09 20:41:48 +02002672 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, 0);
2673 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, 0);
2674 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, 0);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002675 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
Florian Westphalb97bac62017-08-09 20:41:48 +02002676 inet_netconf_dump_devconf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677}