blob: 5cb849300b816d2938ee2add7dd6cc8e735595ce [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
Eric Dumazet40384992012-08-03 21:06:50 +0000106#define IN4_ADDR_HSIZE_SHIFT 8
107#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT)
108
David S. Millerfd23c3b2011-02-18 12:42:28 -0800109static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
David S. Millerfd23c3b2011-02-18 12:42:28 -0800110
Eric Dumazet6eada012015-03-18 14:05:33 -0700111static u32 inet_addr_hash(const struct net *net, __be32 addr)
David S. Millerfd23c3b2011-02-18 12:42:28 -0800112{
Eric Dumazet40384992012-08-03 21:06:50 +0000113 u32 val = (__force u32) addr ^ net_hash_mix(net);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800114
Eric Dumazet40384992012-08-03 21:06:50 +0000115 return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800116}
117
118static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
119{
Eric Dumazet40384992012-08-03 21:06:50 +0000120 u32 hash = inet_addr_hash(net, ifa->ifa_local);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800121
WANG Cong32a4be42014-05-06 11:15:56 -0700122 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800123 hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800124}
125
126static void inet_hash_remove(struct in_ifaddr *ifa)
127{
WANG Cong32a4be42014-05-06 11:15:56 -0700128 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800129 hlist_del_init_rcu(&ifa->hash);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800130}
131
David S. Miller9435eb12011-02-18 12:43:09 -0800132/**
133 * __ip_dev_find - find the first device with a given source address.
134 * @net: the net namespace
135 * @addr: the source address
136 * @devref: if true, take a reference on the found device
137 *
138 * If a caller uses devref=false, it should be protected by RCU, or RTNL
139 */
140struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
141{
David S. Miller9435eb12011-02-18 12:43:09 -0800142 struct net_device *result = NULL;
143 struct in_ifaddr *ifa;
David S. Miller9435eb12011-02-18 12:43:09 -0800144
145 rcu_read_lock();
Paolo Abeni6e617de2017-09-20 18:26:53 +0200146 ifa = inet_lookup_ifaddr_rcu(net, addr);
147 if (!ifa) {
David S. Miller406b6f92011-03-22 21:56:23 -0700148 struct flowi4 fl4 = { .daddr = addr };
149 struct fib_result res = { 0 };
150 struct fib_table *local;
151
152 /* Fallback to FIB local table so that communication
153 * over loopback subnets work.
154 */
155 local = fib_get_table(net, RT_TABLE_LOCAL);
156 if (local &&
157 !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
158 res.type == RTN_LOCAL)
159 result = FIB_RES_DEV(res);
Paolo Abeni6e617de2017-09-20 18:26:53 +0200160 } else {
161 result = ifa->ifa_dev->dev;
David S. Miller406b6f92011-03-22 21:56:23 -0700162 }
David S. Miller9435eb12011-02-18 12:43:09 -0800163 if (result && devref)
164 dev_hold(result);
165 rcu_read_unlock();
166 return result;
167}
168EXPORT_SYMBOL(__ip_dev_find);
169
Paolo Abeni6e617de2017-09-20 18:26:53 +0200170/* called under RCU lock */
171struct in_ifaddr *inet_lookup_ifaddr_rcu(struct net *net, __be32 addr)
172{
173 u32 hash = inet_addr_hash(net, addr);
174 struct in_ifaddr *ifa;
175
176 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash)
177 if (ifa->ifa_local == addr &&
178 net_eq(dev_net(ifa->ifa_dev->dev), net))
179 return ifa;
180
181 return NULL;
182}
183
Thomas Grafd6062cb2006-08-15 00:33:59 -0700184static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
Alan Sterne041c682006-03-27 01:16:30 -0800186static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Krister Johansen3ad7d242017-06-08 13:12:14 -0700187static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
189 int destroy);
190#ifdef CONFIG_SYSCTL
WANG Cong20e61da2014-07-25 15:25:08 -0700191static int devinet_sysctl_register(struct in_device *idev);
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800192static void devinet_sysctl_unregister(struct in_device *idev);
193#else
WANG Cong20e61da2014-07-25 15:25:08 -0700194static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800195{
WANG Cong20e61da2014-07-25 15:25:08 -0700196 return 0;
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800197}
Eric Dumazet40384992012-08-03 21:06:50 +0000198static void devinet_sysctl_unregister(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800199{
200}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201#endif
202
203/* Locks all the inet devices. */
204
205static struct in_ifaddr *inet_alloc_ifa(void)
206{
Alexey Dobriyan93adcc82008-10-28 13:25:09 -0700207 return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208}
209
210static void inet_rcu_free_ifa(struct rcu_head *head)
211{
212 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
213 if (ifa->ifa_dev)
214 in_dev_put(ifa->ifa_dev);
215 kfree(ifa);
216}
217
Eric Dumazet40384992012-08-03 21:06:50 +0000218static void inet_free_ifa(struct in_ifaddr *ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219{
220 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
221}
222
223void in_dev_finish_destroy(struct in_device *idev)
224{
225 struct net_device *dev = idev->dev;
226
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700227 WARN_ON(idev->ifa_list);
228 WARN_ON(idev->mc_list);
Eric Dumazete9897072013-06-07 08:48:57 -0700229 kfree(rcu_dereference_protected(idev->mc_hash, 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230#ifdef NET_REFCNT_DEBUG
Joe Perches91df42b2012-05-15 14:11:54 +0000231 pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232#endif
233 dev_put(dev);
234 if (!idev->dead)
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800235 pr_err("Freeing alive in_device %p\n", idev);
236 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 kfree(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800239EXPORT_SYMBOL(in_dev_finish_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
Herbert Xu71e27da2007-06-04 23:36:06 -0700241static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242{
243 struct in_device *in_dev;
WANG Cong20e61da2014-07-25 15:25:08 -0700244 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
246 ASSERT_RTNL();
247
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700248 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 if (!in_dev)
250 goto out;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900251 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -0800252 sizeof(in_dev->cnf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 in_dev->cnf.sysctl = NULL;
254 in_dev->dev = dev;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800255 in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
256 if (!in_dev->arp_parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 goto out_kfree;
Ben Hutchings0187bdf2008-06-19 16:15:47 -0700258 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
259 dev_disable_lro(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 /* Reference in_dev->dev */
261 dev_hold(dev);
David L Stevens30c4cf52007-01-04 12:31:14 -0800262 /* Account for reference dev->ip_ptr (below) */
Reshetova, Elena7658b362017-06-30 13:08:03 +0300263 refcount_set(&in_dev->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
WANG Cong20e61da2014-07-25 15:25:08 -0700265 err = devinet_sysctl_register(in_dev);
266 if (err) {
267 in_dev->dead = 1;
268 in_dev_put(in_dev);
269 in_dev = NULL;
270 goto out;
271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 ip_mc_init_dev(in_dev);
273 if (dev->flags & IFF_UP)
274 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800275
David L Stevens30c4cf52007-01-04 12:31:14 -0800276 /* we can receive as soon as ip_ptr is set -- do this last */
Eric Dumazetcf778b02012-01-12 04:41:32 +0000277 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800278out:
WANG Cong20e61da2014-07-25 15:25:08 -0700279 return in_dev ?: ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280out_kfree:
281 kfree(in_dev);
282 in_dev = NULL;
283 goto out;
284}
285
286static void in_dev_rcu_put(struct rcu_head *head)
287{
288 struct in_device *idev = container_of(head, struct in_device, rcu_head);
289 in_dev_put(idev);
290}
291
292static void inetdev_destroy(struct in_device *in_dev)
293{
294 struct in_ifaddr *ifa;
295 struct net_device *dev;
296
297 ASSERT_RTNL();
298
299 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
301 in_dev->dead = 1;
302
303 ip_mc_destroy_dev(in_dev);
304
305 while ((ifa = in_dev->ifa_list) != NULL) {
306 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
307 inet_free_ifa(ifa);
308 }
309
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000310 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800312 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
314 arp_ifdown(dev);
315
316 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
317}
318
Al Viroff428d72006-09-26 22:13:35 -0700319int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
321 rcu_read_lock();
322 for_primary_ifa(in_dev) {
323 if (inet_ifa_match(a, ifa)) {
324 if (!b || inet_ifa_match(b, ifa)) {
325 rcu_read_unlock();
326 return 1;
327 }
328 }
329 } endfor_ifa(in_dev);
330 rcu_read_unlock();
331 return 0;
332}
333
Thomas Grafd6062cb2006-08-15 00:33:59 -0700334static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000335 int destroy, struct nlmsghdr *nlh, u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336{
Harald Welte8f937c62005-05-29 20:23:46 -0700337 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800338 struct in_ifaddr *ifa, *ifa1 = *ifap;
339 struct in_ifaddr *last_prim = in_dev->ifa_list;
340 struct in_ifaddr *prev_prom = NULL;
341 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
343 ASSERT_RTNL();
344
David S. Millerfbd40ea2016-03-13 23:28:00 -0400345 if (in_dev->dead)
346 goto no_promotions;
347
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900348 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700349 * unless alias promotion is set
350 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
352 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
354
355 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900356 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800357 ifa1->ifa_scope <= ifa->ifa_scope)
358 last_prim = ifa;
359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
361 ifa1->ifa_mask != ifa->ifa_mask ||
362 !inet_ifa_match(ifa1->ifa_address, ifa)) {
363 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800364 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 continue;
366 }
367
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800368 if (!do_promote) {
David S. Millerfd23c3b2011-02-18 12:42:28 -0800369 inet_hash_remove(ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700370 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Eric W. Biederman15e47302012-09-07 20:12:54 +0000372 rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800373 blocking_notifier_call_chain(&inetaddr_chain,
374 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700375 inet_free_ifa(ifa);
376 } else {
377 promote = ifa;
378 break;
379 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 }
381 }
382
Julian Anastasov2d230e22011-03-19 12:13:52 +0000383 /* On promotion all secondaries from subnet are changing
384 * the primary IP, we must remove all their routes silently
385 * and later to add them back with new prefsrc. Do this
386 * while all addresses are on the device list.
387 */
388 for (ifa = promote; ifa; ifa = ifa->ifa_next) {
389 if (ifa1->ifa_mask == ifa->ifa_mask &&
390 inet_ifa_match(ifa1->ifa_address, ifa))
391 fib_del_ifaddr(ifa, ifa1);
392 }
393
David S. Millerfbd40ea2016-03-13 23:28:00 -0400394no_promotions:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 /* 2. Unlink it */
396
397 *ifap = ifa1->ifa_next;
David S. Millerfd23c3b2011-02-18 12:42:28 -0800398 inet_hash_remove(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
400 /* 3. Announce address deletion */
401
402 /* Send message first, then call notifier.
403 At first sight, FIB update triggered by notifier
404 will refer to already deleted ifaddr, that could confuse
405 netlink listeners. It is not true: look, gated sees
406 that route deleted and if it still thinks that ifaddr
407 is valid, it will try to restore deleted routes... Grr.
408 So that, this order is correct.
409 */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000410 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800411 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800412
413 if (promote) {
Julian Anastasov04024b92011-03-19 12:13:54 +0000414 struct in_ifaddr *next_sec = promote->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800415
416 if (prev_prom) {
417 prev_prom->ifa_next = promote->ifa_next;
418 promote->ifa_next = last_prim->ifa_next;
419 last_prim->ifa_next = promote;
420 }
421
422 promote->ifa_flags &= ~IFA_F_SECONDARY;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000423 rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800424 blocking_notifier_call_chain(&inetaddr_chain,
425 NETDEV_UP, promote);
Julian Anastasov04024b92011-03-19 12:13:54 +0000426 for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800427 if (ifa1->ifa_mask != ifa->ifa_mask ||
428 !inet_ifa_match(ifa1->ifa_address, ifa))
429 continue;
430 fib_add_ifaddr(ifa);
431 }
432
433 }
Herbert Xu63630972007-06-07 18:35:38 -0700434 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436}
437
Thomas Grafd6062cb2006-08-15 00:33:59 -0700438static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
439 int destroy)
440{
441 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
442}
443
Jiri Pirko5c766d62013-01-24 09:41:41 +0000444static void check_lifetime(struct work_struct *work);
445
446static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
447
Thomas Grafd6062cb2006-08-15 00:33:59 -0700448static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
David Ahernde95e042017-10-18 09:56:54 -0700449 u32 portid, struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450{
451 struct in_device *in_dev = ifa->ifa_dev;
452 struct in_ifaddr *ifa1, **ifap, **last_primary;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700453 struct in_validator_info ivi;
454 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
456 ASSERT_RTNL();
457
458 if (!ifa->ifa_local) {
459 inet_free_ifa(ifa);
460 return 0;
461 }
462
463 ifa->ifa_flags &= ~IFA_F_SECONDARY;
464 last_primary = &in_dev->ifa_list;
465
466 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
467 ifap = &ifa1->ifa_next) {
468 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
469 ifa->ifa_scope <= ifa1->ifa_scope)
470 last_primary = &ifa1->ifa_next;
471 if (ifa1->ifa_mask == ifa->ifa_mask &&
472 inet_ifa_match(ifa1->ifa_address, ifa)) {
473 if (ifa1->ifa_local == ifa->ifa_local) {
474 inet_free_ifa(ifa);
475 return -EEXIST;
476 }
477 if (ifa1->ifa_scope != ifa->ifa_scope) {
478 inet_free_ifa(ifa);
479 return -EINVAL;
480 }
481 ifa->ifa_flags |= IFA_F_SECONDARY;
482 }
483 }
484
Krister Johansen3ad7d242017-06-08 13:12:14 -0700485 /* Allow any devices that wish to register ifaddr validtors to weigh
486 * in now, before changes are committed. The rntl lock is serializing
487 * access here, so the state should not change between a validator call
488 * and a final notify on commit. This isn't invoked on promotion under
489 * the assumption that validators are checking the address itself, and
490 * not the flags.
491 */
492 ivi.ivi_addr = ifa->ifa_address;
493 ivi.ivi_dev = ifa->ifa_dev;
David Ahernde95e042017-10-18 09:56:54 -0700494 ivi.extack = extack;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700495 ret = blocking_notifier_call_chain(&inetaddr_validator_chain,
496 NETDEV_UP, &ivi);
497 ret = notifier_to_errno(ret);
498 if (ret) {
499 inet_free_ifa(ifa);
500 return ret;
501 }
502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500504 prandom_seed((__force u32) ifa->ifa_local);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 ifap = last_primary;
506 }
507
508 ifa->ifa_next = *ifap;
509 *ifap = ifa;
510
David S. Millerfd23c3b2011-02-18 12:42:28 -0800511 inet_hash_insert(dev_net(in_dev->dev), ifa);
512
Jiri Pirko5c766d62013-01-24 09:41:41 +0000513 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530514 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000515
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 /* Send message first, then call notifier.
517 Notifier will trigger FIB update, so that
518 listeners of netlink will know about new ifaddr */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000519 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800520 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
522 return 0;
523}
524
Thomas Grafd6062cb2006-08-15 00:33:59 -0700525static int inet_insert_ifa(struct in_ifaddr *ifa)
526{
David Ahernde95e042017-10-18 09:56:54 -0700527 return __inet_insert_ifa(ifa, NULL, 0, NULL);
Thomas Grafd6062cb2006-08-15 00:33:59 -0700528}
529
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
531{
Herbert Xue5ed6392005-10-03 14:35:55 -0700532 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
534 ASSERT_RTNL();
535
536 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700537 inet_free_ifa(ifa);
538 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700540 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100541 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700543 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 in_dev_hold(in_dev);
545 ifa->ifa_dev = in_dev;
546 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800547 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 ifa->ifa_scope = RT_SCOPE_HOST;
549 return inet_insert_ifa(ifa);
550}
551
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000552/* Caller must hold RCU or RTNL :
553 * We dont take a reference on found in_device
554 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800555struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556{
557 struct net_device *dev;
558 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000559
560 rcu_read_lock();
561 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000563 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000564 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 return in_dev;
566}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800567EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
569/* Called only from RTNL semaphored context. No locks. */
570
Al Viro60cad5d2006-09-26 22:17:09 -0700571struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
572 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573{
574 ASSERT_RTNL();
575
576 for_primary_ifa(in_dev) {
577 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
578 return ifa;
579 } endfor_ifa(in_dev);
580 return NULL;
581}
582
Madhu Challa93a714d2015-02-25 09:58:35 -0800583static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa)
584{
585 struct ip_mreqn mreq = {
586 .imr_multiaddr.s_addr = ifa->ifa_address,
587 .imr_ifindex = ifa->ifa_dev->dev->ifindex,
588 };
589 int ret;
590
591 ASSERT_RTNL();
592
593 lock_sock(sk);
594 if (join)
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300595 ret = ip_mc_join_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800596 else
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300597 ret = ip_mc_leave_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800598 release_sock(sk);
599
600 return ret;
601}
602
David Ahernc21ef3e2017-04-16 09:48:24 -0700603static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
604 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900606 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700607 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700609 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700611 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
613 ASSERT_RTNL();
614
Johannes Bergfceb6432017-04-12 14:34:07 +0200615 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -0700616 extack);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700617 if (err < 0)
618 goto errout;
619
620 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800621 in_dev = inetdev_by_index(net, ifm->ifa_index);
Ian Morris51456b22015-04-03 09:17:26 +0100622 if (!in_dev) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700623 err = -ENODEV;
624 goto errout;
625 }
626
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
628 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700629 if (tb[IFA_LOCAL] &&
Jiri Benc67b61f62015-03-29 16:59:26 +0200630 ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700632
633 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
634 continue;
635
636 if (tb[IFA_ADDRESS] &&
637 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Jiri Benc67b61f62015-03-29 16:59:26 +0200638 !inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700639 continue;
640
Madhu Challa93a714d2015-02-25 09:58:35 -0800641 if (ipv4_is_multicast(ifa->ifa_address))
642 ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000643 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 return 0;
645 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700646
647 err = -EADDRNOTAVAIL;
648errout:
649 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650}
651
Jiri Pirko5c766d62013-01-24 09:41:41 +0000652#define INFINITY_LIFE_TIME 0xFFFFFFFF
653
654static void check_lifetime(struct work_struct *work)
655{
656 unsigned long now, next, next_sec, next_sched;
657 struct in_ifaddr *ifa;
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000658 struct hlist_node *n;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000659 int i;
660
661 now = jiffies;
662 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
663
Jiri Pirko5c766d62013-01-24 09:41:41 +0000664 for (i = 0; i < IN4_ADDR_HSIZE; i++) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000665 bool change_needed = false;
666
667 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800668 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
Jiri Pirko5c766d62013-01-24 09:41:41 +0000669 unsigned long age;
670
671 if (ifa->ifa_flags & IFA_F_PERMANENT)
672 continue;
673
674 /* We try to batch several events at once. */
675 age = (now - ifa->ifa_tstamp +
676 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
677
678 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
679 age >= ifa->ifa_valid_lft) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000680 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000681 } else if (ifa->ifa_preferred_lft ==
682 INFINITY_LIFE_TIME) {
683 continue;
684 } else if (age >= ifa->ifa_preferred_lft) {
685 if (time_before(ifa->ifa_tstamp +
686 ifa->ifa_valid_lft * HZ, next))
687 next = ifa->ifa_tstamp +
688 ifa->ifa_valid_lft * HZ;
689
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000690 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
691 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000692 } else if (time_before(ifa->ifa_tstamp +
693 ifa->ifa_preferred_lft * HZ,
694 next)) {
695 next = ifa->ifa_tstamp +
696 ifa->ifa_preferred_lft * HZ;
697 }
698 }
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000699 rcu_read_unlock();
700 if (!change_needed)
701 continue;
702 rtnl_lock();
703 hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
704 unsigned long age;
705
706 if (ifa->ifa_flags & IFA_F_PERMANENT)
707 continue;
708
709 /* We try to batch several events at once. */
710 age = (now - ifa->ifa_tstamp +
711 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
712
713 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
714 age >= ifa->ifa_valid_lft) {
715 struct in_ifaddr **ifap;
716
717 for (ifap = &ifa->ifa_dev->ifa_list;
718 *ifap != NULL; ifap = &(*ifap)->ifa_next) {
719 if (*ifap == ifa) {
720 inet_del_ifa(ifa->ifa_dev,
721 ifap, 1);
722 break;
723 }
724 }
725 } else if (ifa->ifa_preferred_lft !=
726 INFINITY_LIFE_TIME &&
727 age >= ifa->ifa_preferred_lft &&
728 !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
729 ifa->ifa_flags |= IFA_F_DEPRECATED;
730 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
731 }
732 }
733 rtnl_unlock();
Jiri Pirko5c766d62013-01-24 09:41:41 +0000734 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000735
736 next_sec = round_jiffies_up(next);
737 next_sched = next;
738
739 /* If rounded timeout is accurate enough, accept it. */
740 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
741 next_sched = next_sec;
742
743 now = jiffies;
744 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
745 if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
746 next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
747
viresh kumar906e0732014-01-22 12:23:32 +0530748 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work,
749 next_sched - now);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000750}
751
752static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
753 __u32 prefered_lft)
754{
755 unsigned long timeout;
756
757 ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
758
759 timeout = addrconf_timeout_fixup(valid_lft, HZ);
760 if (addrconf_finite_timeout(timeout))
761 ifa->ifa_valid_lft = timeout;
762 else
763 ifa->ifa_flags |= IFA_F_PERMANENT;
764
765 timeout = addrconf_timeout_fixup(prefered_lft, HZ);
766 if (addrconf_finite_timeout(timeout)) {
767 if (timeout == 0)
768 ifa->ifa_flags |= IFA_F_DEPRECATED;
769 ifa->ifa_preferred_lft = timeout;
770 }
771 ifa->ifa_tstamp = jiffies;
772 if (!ifa->ifa_cstamp)
773 ifa->ifa_cstamp = ifa->ifa_tstamp;
774}
775
776static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
777 __u32 *pvalid_lft, __u32 *pprefered_lft)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778{
Thomas Graf5c753972006-08-04 23:03:53 -0700779 struct nlattr *tb[IFA_MAX+1];
780 struct in_ifaddr *ifa;
781 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 struct net_device *dev;
783 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800784 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
Johannes Bergfceb6432017-04-12 14:34:07 +0200786 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
787 NULL);
Thomas Graf5c753972006-08-04 23:03:53 -0700788 if (err < 0)
789 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
Thomas Graf5c753972006-08-04 23:03:53 -0700791 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800792 err = -EINVAL;
Ian Morris51456b22015-04-03 09:17:26 +0100793 if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL])
Thomas Graf5c753972006-08-04 23:03:53 -0700794 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800796 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800797 err = -ENODEV;
Ian Morris51456b22015-04-03 09:17:26 +0100798 if (!dev)
Thomas Graf5c753972006-08-04 23:03:53 -0700799 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
Thomas Graf5c753972006-08-04 23:03:53 -0700801 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800802 err = -ENOBUFS;
Ian Morris51456b22015-04-03 09:17:26 +0100803 if (!in_dev)
Herbert Xu71e27da2007-06-04 23:36:06 -0700804 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
Thomas Graf5c753972006-08-04 23:03:53 -0700806 ifa = inet_alloc_ifa();
Ian Morris51456b22015-04-03 09:17:26 +0100807 if (!ifa)
Thomas Graf5c753972006-08-04 23:03:53 -0700808 /*
809 * A potential indev allocation can be left alive, it stays
810 * assigned to its device and is destroy with it.
811 */
Thomas Graf5c753972006-08-04 23:03:53 -0700812 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700813
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800814 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100815 neigh_parms_data_state_setall(in_dev->arp_parms);
Thomas Graf5c753972006-08-04 23:03:53 -0700816 in_dev_hold(in_dev);
817
Ian Morris51456b22015-04-03 09:17:26 +0100818 if (!tb[IFA_ADDRESS])
Thomas Graf5c753972006-08-04 23:03:53 -0700819 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
820
David S. Millerfd23c3b2011-02-18 12:42:28 -0800821 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
823 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100824 ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
825 ifm->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700827 ifa->ifa_dev = in_dev;
828
Jiri Benc67b61f62015-03-29 16:59:26 +0200829 ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]);
830 ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700831
832 if (tb[IFA_BROADCAST])
Jiri Benc67b61f62015-03-29 16:59:26 +0200833 ifa->ifa_broadcast = nla_get_in_addr(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700834
Thomas Graf5c753972006-08-04 23:03:53 -0700835 if (tb[IFA_LABEL])
836 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 else
838 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
839
David Ahernaf4d7682018-05-27 08:09:57 -0700840 if (tb[IFA_RT_PRIORITY])
841 ifa->ifa_rt_priority = nla_get_u32(tb[IFA_RT_PRIORITY]);
842
Jiri Pirko5c766d62013-01-24 09:41:41 +0000843 if (tb[IFA_CACHEINFO]) {
844 struct ifa_cacheinfo *ci;
845
846 ci = nla_data(tb[IFA_CACHEINFO]);
847 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
848 err = -EINVAL;
Daniel Borkmann446266b2013-08-02 11:32:43 +0200849 goto errout_free;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000850 }
851 *pvalid_lft = ci->ifa_valid;
852 *pprefered_lft = ci->ifa_prefered;
853 }
854
Thomas Graf5c753972006-08-04 23:03:53 -0700855 return ifa;
856
Daniel Borkmann446266b2013-08-02 11:32:43 +0200857errout_free:
858 inet_free_ifa(ifa);
Thomas Graf5c753972006-08-04 23:03:53 -0700859errout:
860 return ERR_PTR(err);
861}
862
Jiri Pirko5c766d62013-01-24 09:41:41 +0000863static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
864{
865 struct in_device *in_dev = ifa->ifa_dev;
866 struct in_ifaddr *ifa1, **ifap;
867
868 if (!ifa->ifa_local)
869 return NULL;
870
871 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
872 ifap = &ifa1->ifa_next) {
873 if (ifa1->ifa_mask == ifa->ifa_mask &&
874 inet_ifa_match(ifa1->ifa_address, ifa) &&
875 ifa1->ifa_local == ifa->ifa_local)
876 return ifa1;
877 }
878 return NULL;
879}
880
David Ahernc21ef3e2017-04-16 09:48:24 -0700881static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
882 struct netlink_ext_ack *extack)
Thomas Graf5c753972006-08-04 23:03:53 -0700883{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900884 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700885 struct in_ifaddr *ifa;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000886 struct in_ifaddr *ifa_existing;
887 __u32 valid_lft = INFINITY_LIFE_TIME;
888 __u32 prefered_lft = INFINITY_LIFE_TIME;
Thomas Graf5c753972006-08-04 23:03:53 -0700889
890 ASSERT_RTNL();
891
Jiri Pirko5c766d62013-01-24 09:41:41 +0000892 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft);
Thomas Graf5c753972006-08-04 23:03:53 -0700893 if (IS_ERR(ifa))
894 return PTR_ERR(ifa);
895
Jiri Pirko5c766d62013-01-24 09:41:41 +0000896 ifa_existing = find_matching_ifa(ifa);
897 if (!ifa_existing) {
898 /* It would be best to check for !NLM_F_CREATE here but
stephen hemminger614d0562014-05-16 20:46:58 -0700899 * userspace already relies on not having to provide this.
Jiri Pirko5c766d62013-01-24 09:41:41 +0000900 */
901 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Madhu Challa93a714d2015-02-25 09:58:35 -0800902 if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
903 int ret = ip_mc_config(net->ipv4.mc_autojoin_sk,
904 true, ifa);
905
906 if (ret < 0) {
907 inet_free_ifa(ifa);
908 return ret;
909 }
910 }
David Ahernde95e042017-10-18 09:56:54 -0700911 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid,
912 extack);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000913 } else {
David Ahernaf4d7682018-05-27 08:09:57 -0700914 u32 new_metric = ifa->ifa_rt_priority;
915
Jiri Pirko5c766d62013-01-24 09:41:41 +0000916 inet_free_ifa(ifa);
917
918 if (nlh->nlmsg_flags & NLM_F_EXCL ||
919 !(nlh->nlmsg_flags & NLM_F_REPLACE))
920 return -EEXIST;
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000921 ifa = ifa_existing;
David Ahernaf4d7682018-05-27 08:09:57 -0700922
923 if (ifa->ifa_rt_priority != new_metric) {
924 fib_modify_prefix_metric(ifa, new_metric);
925 ifa->ifa_rt_priority = new_metric;
926 }
927
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000928 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Jiri Pirko05a324b2013-04-04 23:39:38 +0000929 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530930 queue_delayed_work(system_power_efficient_wq,
931 &check_lifetime_work, 0);
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000932 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000933 }
934 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935}
936
937/*
938 * Determine a default network mask, based on the IP address.
939 */
940
Eric Dumazet40384992012-08-03 21:06:50 +0000941static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942{
943 int rc = -1; /* Something else, probably a multicast. */
944
Joe Perchesf97c1e02007-12-16 13:45:43 -0800945 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900946 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 else {
Al Viro714e85b2006-11-14 20:51:49 -0800948 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
Al Viro714e85b2006-11-14 20:51:49 -0800950 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800952 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800954 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 rc = 24;
956 }
957
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900958 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959}
960
961
Al Viro03aef172017-07-01 07:53:12 -0400962int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 struct sockaddr_in sin_orig;
Al Viro03aef172017-07-01 07:53:12 -0400965 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 struct in_device *in_dev;
967 struct in_ifaddr **ifap = NULL;
968 struct in_ifaddr *ifa = NULL;
969 struct net_device *dev;
970 char *colon;
971 int ret = -EFAULT;
972 int tryaddrmatch = 0;
973
Al Viro03aef172017-07-01 07:53:12 -0400974 ifr->ifr_name[IFNAMSIZ - 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
976 /* save original address for comparison */
977 memcpy(&sin_orig, sin, sizeof(*sin));
978
Al Viro03aef172017-07-01 07:53:12 -0400979 colon = strchr(ifr->ifr_name, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 if (colon)
981 *colon = 0;
982
Al Viro03aef172017-07-01 07:53:12 -0400983 dev_load(net, ifr->ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Stephen Hemminger132adf52007-03-08 20:44:43 -0800985 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 case SIOCGIFADDR: /* Get interface address */
987 case SIOCGIFBRDADDR: /* Get the broadcast address */
988 case SIOCGIFDSTADDR: /* Get the destination address */
989 case SIOCGIFNETMASK: /* Get the netmask for the interface */
990 /* Note that these ioctls will not sleep,
991 so that we do not impose a lock.
992 One day we will be forced to put shlock here (I mean SMP)
993 */
994 tryaddrmatch = (sin_orig.sin_family == AF_INET);
995 memset(sin, 0, sizeof(*sin));
996 sin->sin_family = AF_INET;
997 break;
998
999 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +00001000 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +00001001 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 goto out;
1003 break;
1004 case SIOCSIFADDR: /* Set interface address (and family) */
1005 case SIOCSIFBRDADDR: /* Set the broadcast address */
1006 case SIOCSIFDSTADDR: /* Set the destination address */
1007 case SIOCSIFNETMASK: /* Set the netmask for the interface */
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +00001008 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +00001009 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 goto out;
1011 ret = -EINVAL;
1012 if (sin->sin_family != AF_INET)
1013 goto out;
1014 break;
1015 default:
1016 ret = -EINVAL;
1017 goto out;
1018 }
1019
1020 rtnl_lock();
1021
1022 ret = -ENODEV;
Al Viro03aef172017-07-01 07:53:12 -04001023 dev = __dev_get_by_name(net, ifr->ifr_name);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001024 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 goto done;
1026
1027 if (colon)
1028 *colon = ':';
1029
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001030 in_dev = __in_dev_get_rtnl(dev);
1031 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 if (tryaddrmatch) {
1033 /* Matthias Andree */
1034 /* compare label and address (4.4BSD style) */
1035 /* note: we only do this for a limited set of ioctls
1036 and only if the original address family was AF_INET.
1037 This is checked above. */
1038 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1039 ifap = &ifa->ifa_next) {
Al Viro03aef172017-07-01 07:53:12 -04001040 if (!strcmp(ifr->ifr_name, ifa->ifa_label) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -08001042 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 break; /* found */
1044 }
1045 }
1046 }
1047 /* we didn't get a match, maybe the application is
1048 4.3BSD-style and passed in junk so we fall back to
1049 comparing just the label */
1050 if (!ifa) {
1051 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1052 ifap = &ifa->ifa_next)
Al Viro03aef172017-07-01 07:53:12 -04001053 if (!strcmp(ifr->ifr_name, ifa->ifa_label))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 break;
1055 }
1056 }
1057
1058 ret = -EADDRNOTAVAIL;
1059 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
1060 goto done;
1061
Stephen Hemminger132adf52007-03-08 20:44:43 -08001062 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 case SIOCGIFADDR: /* Get interface address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001064 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 sin->sin_addr.s_addr = ifa->ifa_local;
Al Viro03aef172017-07-01 07:53:12 -04001066 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067
1068 case SIOCGIFBRDADDR: /* Get the broadcast address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001069 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 sin->sin_addr.s_addr = ifa->ifa_broadcast;
Al Viro03aef172017-07-01 07:53:12 -04001071 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
1073 case SIOCGIFDSTADDR: /* Get the destination 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_address;
Al Viro03aef172017-07-01 07:53:12 -04001076 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
1078 case SIOCGIFNETMASK: /* Get the netmask for the interface */
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_mask;
Al Viro03aef172017-07-01 07:53:12 -04001081 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
1083 case SIOCSIFFLAGS:
1084 if (colon) {
1085 ret = -EADDRNOTAVAIL;
1086 if (!ifa)
1087 break;
1088 ret = 0;
Al Viro03aef172017-07-01 07:53:12 -04001089 if (!(ifr->ifr_flags & IFF_UP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 inet_del_ifa(in_dev, ifap, 1);
1091 break;
1092 }
Al Viro03aef172017-07-01 07:53:12 -04001093 ret = dev_change_flags(dev, ifr->ifr_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 break;
1095
1096 case SIOCSIFADDR: /* Set interface address (and family) */
1097 ret = -EINVAL;
1098 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1099 break;
1100
1101 if (!ifa) {
1102 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001103 ifa = inet_alloc_ifa();
1104 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 break;
Xi Wangc7e2e1d2013-01-05 11:19:24 +00001106 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 if (colon)
Al Viro03aef172017-07-01 07:53:12 -04001108 memcpy(ifa->ifa_label, ifr->ifr_name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 else
1110 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1111 } else {
1112 ret = 0;
1113 if (ifa->ifa_local == sin->sin_addr.s_addr)
1114 break;
1115 inet_del_ifa(in_dev, ifap, 0);
1116 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -08001117 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 }
1119
1120 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
1121
1122 if (!(dev->flags & IFF_POINTOPOINT)) {
1123 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
1124 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
1125 if ((dev->flags & IFF_BROADCAST) &&
1126 ifa->ifa_prefixlen < 31)
1127 ifa->ifa_broadcast = ifa->ifa_address |
1128 ~ifa->ifa_mask;
1129 } else {
1130 ifa->ifa_prefixlen = 32;
1131 ifa->ifa_mask = inet_make_mask(32);
1132 }
Jiri Pirko5c766d62013-01-24 09:41:41 +00001133 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 ret = inet_set_ifa(dev, ifa);
1135 break;
1136
1137 case SIOCSIFBRDADDR: /* Set the broadcast address */
1138 ret = 0;
1139 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
1140 inet_del_ifa(in_dev, ifap, 0);
1141 ifa->ifa_broadcast = sin->sin_addr.s_addr;
1142 inet_insert_ifa(ifa);
1143 }
1144 break;
1145
1146 case SIOCSIFDSTADDR: /* Set the destination address */
1147 ret = 0;
1148 if (ifa->ifa_address == sin->sin_addr.s_addr)
1149 break;
1150 ret = -EINVAL;
1151 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1152 break;
1153 ret = 0;
1154 inet_del_ifa(in_dev, ifap, 0);
1155 ifa->ifa_address = sin->sin_addr.s_addr;
1156 inet_insert_ifa(ifa);
1157 break;
1158
1159 case SIOCSIFNETMASK: /* Set the netmask for the interface */
1160
1161 /*
1162 * The mask we set must be legal.
1163 */
1164 ret = -EINVAL;
1165 if (bad_mask(sin->sin_addr.s_addr, 0))
1166 break;
1167 ret = 0;
1168 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -07001169 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 inet_del_ifa(in_dev, ifap, 0);
1171 ifa->ifa_mask = sin->sin_addr.s_addr;
1172 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
1173
1174 /* See if current broadcast address matches
1175 * with current netmask, then recalculate
1176 * the broadcast address. Otherwise it's a
1177 * funny address, so don't touch it since
1178 * the user seems to know what (s)he's doing...
1179 */
1180 if ((dev->flags & IFF_BROADCAST) &&
1181 (ifa->ifa_prefixlen < 31) &&
1182 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -05001183 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 ifa->ifa_broadcast = (ifa->ifa_local |
1185 ~sin->sin_addr.s_addr);
1186 }
1187 inet_insert_ifa(ifa);
1188 }
1189 break;
1190 }
1191done:
1192 rtnl_unlock();
1193out:
1194 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195}
1196
Al Viro36fd6332017-06-26 13:19:16 -04001197static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198{
Herbert Xue5ed6392005-10-03 14:35:55 -07001199 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 struct in_ifaddr *ifa;
1201 struct ifreq ifr;
1202 int done = 0;
1203
Al Viro36fd6332017-06-26 13:19:16 -04001204 if (WARN_ON(size > sizeof(struct ifreq)))
1205 goto out;
1206
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001207 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 goto out;
1209
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001210 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 if (!buf) {
Al Viro36fd6332017-06-26 13:19:16 -04001212 done += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 continue;
1214 }
Al Viro36fd6332017-06-26 13:19:16 -04001215 if (len < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 break;
1217 memset(&ifr, 0, sizeof(struct ifreq));
Dan Carpenter4299c8a2013-07-29 22:15:19 +03001218 strcpy(ifr.ifr_name, ifa->ifa_label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219
1220 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
1221 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1222 ifa->ifa_local;
1223
Al Viro36fd6332017-06-26 13:19:16 -04001224 if (copy_to_user(buf + done, &ifr, size)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 done = -EFAULT;
1226 break;
1227 }
Al Viro36fd6332017-06-26 13:19:16 -04001228 len -= size;
1229 done += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 }
1231out:
1232 return done;
1233}
1234
Gao Feng8b57fd12017-03-10 12:38:47 +08001235static __be32 in_dev_select_addr(const struct in_device *in_dev,
1236 int scope)
1237{
1238 for_primary_ifa(in_dev) {
1239 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1240 ifa->ifa_scope <= scope)
1241 return ifa->ifa_local;
1242 } endfor_ifa(in_dev);
1243
1244 return 0;
1245}
1246
Al Viroa61ced52006-09-26 21:27:54 -07001247__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248{
Al Viroa61ced52006-09-26 21:27:54 -07001249 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001251 struct net *net = dev_net(dev);
David Ahern3f2fb9a2016-02-24 11:47:02 -08001252 int master_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
1254 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001255 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 if (!in_dev)
1257 goto no_in_dev;
1258
1259 for_primary_ifa(in_dev) {
1260 if (ifa->ifa_scope > scope)
1261 continue;
1262 if (!dst || inet_ifa_match(dst, ifa)) {
1263 addr = ifa->ifa_local;
1264 break;
1265 }
1266 if (!addr)
1267 addr = ifa->ifa_local;
1268 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
1270 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001271 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001272no_in_dev:
David Ahern3f2fb9a2016-02-24 11:47:02 -08001273 master_idx = l3mdev_master_ifindex_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274
David Lamparter17b693c2016-02-24 11:47:03 -08001275 /* For VRFs, the VRF device takes the place of the loopback device,
1276 * with addresses on it being preferred. Note in such cases the
1277 * loopback device will be among the devices that fail the master_idx
1278 * equality check in the loop below.
1279 */
1280 if (master_idx &&
1281 (dev = dev_get_by_index_rcu(net, master_idx)) &&
1282 (in_dev = __in_dev_get_rcu(dev))) {
Gao Feng8b57fd12017-03-10 12:38:47 +08001283 addr = in_dev_select_addr(in_dev, scope);
1284 if (addr)
1285 goto out_unlock;
David Lamparter17b693c2016-02-24 11:47:03 -08001286 }
1287
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 /* Not loopback addresses on loopback should be preferred
Stephen Hemmingerca9f1fd2015-02-14 13:47:54 -05001289 in this case. It is important that lo is the first interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 in dev_base list.
1291 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001292 for_each_netdev_rcu(net, dev) {
David Ahern3f2fb9a2016-02-24 11:47:02 -08001293 if (l3mdev_master_ifindex_rcu(dev) != master_idx)
1294 continue;
1295
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001296 in_dev = __in_dev_get_rcu(dev);
1297 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 continue;
1299
Gao Feng8b57fd12017-03-10 12:38:47 +08001300 addr = in_dev_select_addr(in_dev, scope);
1301 if (addr)
1302 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001304out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 return addr;
1307}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001308EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309
Al Viro60cad5d2006-09-26 22:17:09 -07001310static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1311 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312{
1313 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001314 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315
1316 for_ifa(in_dev) {
1317 if (!addr &&
1318 (local == ifa->ifa_local || !local) &&
1319 ifa->ifa_scope <= scope) {
1320 addr = ifa->ifa_local;
1321 if (same)
1322 break;
1323 }
1324 if (!same) {
1325 same = (!local || inet_ifa_match(local, ifa)) &&
1326 (!dst || inet_ifa_match(dst, ifa));
1327 if (same && addr) {
1328 if (local || !dst)
1329 break;
1330 /* Is the selected addr into dst subnet? */
1331 if (inet_ifa_match(addr, ifa))
1332 break;
1333 /* No, then can we use new local src? */
1334 if (ifa->ifa_scope <= scope) {
1335 addr = ifa->ifa_local;
1336 break;
1337 }
1338 /* search for large dst subnet for addr */
1339 same = 0;
1340 }
1341 }
1342 } endfor_ifa(in_dev);
1343
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001344 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345}
1346
1347/*
1348 * Confirm that local IP address exists using wildcards:
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001349 * - net: netns to check, cannot be NULL
1350 * - in_dev: only on this interface, NULL=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 * - dst: only in the same subnet as dst, 0=any dst
1352 * - local: address, 0=autoselect the local address
1353 * - scope: maximum allowed scope value for the local address
1354 */
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001355__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001356 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357{
Al Viro60cad5d2006-09-26 22:17:09 -07001358 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001359 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
Ian Morris00db4122015-04-03 09:17:27 +01001361 if (in_dev)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001362 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001365 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001366 in_dev = __in_dev_get_rcu(dev);
1367 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 addr = confirm_addr_indev(in_dev, dst, local, scope);
1369 if (addr)
1370 break;
1371 }
1372 }
1373 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
1375 return addr;
1376}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001377EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
1379/*
1380 * Device notifier
1381 */
1382
1383int register_inetaddr_notifier(struct notifier_block *nb)
1384{
Alan Sterne041c682006-03-27 01:16:30 -08001385 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001387EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388
1389int unregister_inetaddr_notifier(struct notifier_block *nb)
1390{
Alan Sterne041c682006-03-27 01:16:30 -08001391 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001393EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
Krister Johansen3ad7d242017-06-08 13:12:14 -07001395int register_inetaddr_validator_notifier(struct notifier_block *nb)
1396{
1397 return blocking_notifier_chain_register(&inetaddr_validator_chain, nb);
1398}
1399EXPORT_SYMBOL(register_inetaddr_validator_notifier);
1400
1401int unregister_inetaddr_validator_notifier(struct notifier_block *nb)
1402{
1403 return blocking_notifier_chain_unregister(&inetaddr_validator_chain,
1404 nb);
1405}
1406EXPORT_SYMBOL(unregister_inetaddr_validator_notifier);
1407
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001408/* Rename ifa_labels for a device name change. Make some effort to preserve
1409 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410*/
1411static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001412{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 struct in_ifaddr *ifa;
1414 int named = 0;
1415
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001416 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1417 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418
1419 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001420 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001422 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001423 dot = strchr(old, ':');
Ian Morris51456b22015-04-03 09:17:26 +01001424 if (!dot) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001425 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 dot = old;
1427 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001428 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001429 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001430 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001431 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001432skip:
1433 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001434 }
1435}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436
Eric Dumazet40384992012-08-03 21:06:50 +00001437static bool inetdev_valid_mtu(unsigned int mtu)
Breno Leitao06770842008-09-02 17:28:58 -07001438{
Eric Dumazetb5476022017-12-11 07:17:39 -08001439 return mtu >= IPV4_MIN_MTU;
Breno Leitao06770842008-09-02 17:28:58 -07001440}
1441
Ian Campbelld11327ad2011-02-11 07:44:16 +00001442static void inetdev_send_gratuitous_arp(struct net_device *dev,
1443 struct in_device *in_dev)
1444
1445{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001446 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001447
Zoltan Kissb76d0782011-07-24 13:09:30 +00001448 for (ifa = in_dev->ifa_list; ifa;
1449 ifa = ifa->ifa_next) {
1450 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1451 ifa->ifa_local, dev,
1452 ifa->ifa_local, NULL,
1453 dev->dev_addr, NULL);
1454 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001455}
1456
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457/* Called only under RTNL semaphore */
1458
1459static int inetdev_event(struct notifier_block *this, unsigned long event,
1460 void *ptr)
1461{
Jiri Pirko351638e2013-05-28 01:30:21 +00001462 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazet748e2d92012-08-22 21:50:59 +00001463 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
1465 ASSERT_RTNL();
1466
1467 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001468 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 in_dev = inetdev_init(dev);
WANG Cong20e61da2014-07-25 15:25:08 -07001470 if (IS_ERR(in_dev))
1471 return notifier_from_errno(PTR_ERR(in_dev));
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001472 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001473 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1474 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001475 }
Breno Leitao06770842008-09-02 17:28:58 -07001476 } else if (event == NETDEV_CHANGEMTU) {
1477 /* Re-enabling IP */
1478 if (inetdev_valid_mtu(dev->mtu))
1479 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 }
1481 goto out;
1482 }
1483
1484 switch (event) {
1485 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001486 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001487 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 break;
1489 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001490 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001492 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001493 struct in_ifaddr *ifa = inet_alloc_ifa();
1494
1495 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001496 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 ifa->ifa_local =
1498 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1499 ifa->ifa_prefixlen = 8;
1500 ifa->ifa_mask = inet_make_mask(8);
1501 in_dev_hold(in_dev);
1502 ifa->ifa_dev = in_dev;
1503 ifa->ifa_scope = RT_SCOPE_HOST;
1504 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Jiri Pirko5c766d62013-01-24 09:41:41 +00001505 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1506 INFINITY_LIFE_TIME);
Jiri Pirkodfd15822014-01-07 15:55:45 +01001507 ipv4_devconf_setall(in_dev);
1508 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 inet_insert_ifa(ifa);
1510 }
1511 }
1512 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001513 /* fall through */
1514 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001515 if (!IN_DEV_ARP_NOTIFY(in_dev))
1516 break;
1517 /* fall through */
1518 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001519 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001520 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 break;
1522 case NETDEV_DOWN:
1523 ip_mc_down(in_dev);
1524 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001525 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001526 ip_mc_unmap(in_dev);
1527 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001528 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001529 ip_mc_remap(in_dev);
1530 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001532 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 break;
Breno Leitao06770842008-09-02 17:28:58 -07001534 /* disable IP when MTU is not enough */
Gustavo A. R. Silvafcfd6df2017-10-16 15:48:55 -05001535 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 case NETDEV_UNREGISTER:
1537 inetdev_destroy(in_dev);
1538 break;
1539 case NETDEV_CHANGENAME:
1540 /* Do not notify about label change, this event is
1541 * not interesting to applications using netlink.
1542 */
1543 inetdev_changename(dev, in_dev);
1544
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001545 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001546 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 break;
1548 }
1549out:
1550 return NOTIFY_DONE;
1551}
1552
1553static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001554 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555};
1556
Eric Dumazet40384992012-08-03 21:06:50 +00001557static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001558{
1559 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1560 + nla_total_size(4) /* IFA_ADDRESS */
1561 + nla_total_size(4) /* IFA_LOCAL */
1562 + nla_total_size(4) /* IFA_BROADCAST */
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001563 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001564 + nla_total_size(4) /* IFA_FLAGS */
David Ahernaf4d7682018-05-27 08:09:57 -07001565 + nla_total_size(4) /* IFA_RT_PRIORITY */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001566 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
Thomas Graf339bf982006-11-10 14:10:15 -08001567}
1568
Jiri Pirko5c766d62013-01-24 09:41:41 +00001569static inline u32 cstamp_delta(unsigned long cstamp)
1570{
1571 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1572}
1573
1574static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1575 unsigned long tstamp, u32 preferred, u32 valid)
1576{
1577 struct ifa_cacheinfo ci;
1578
1579 ci.cstamp = cstamp_delta(cstamp);
1580 ci.tstamp = cstamp_delta(tstamp);
1581 ci.ifa_prefered = preferred;
1582 ci.ifa_valid = valid;
1583
1584 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1585}
1586
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Christian Braunerd3807142018-09-04 21:53:49 +02001588 u32 portid, u32 seq, int event, unsigned int flags,
1589 int netnsid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590{
1591 struct ifaddrmsg *ifm;
1592 struct nlmsghdr *nlh;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001593 u32 preferred, valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594
Eric W. Biederman15e47302012-09-07 20:12:54 +00001595 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
Ian Morris51456b22015-04-03 09:17:26 +01001596 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08001597 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001598
1599 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 ifm->ifa_family = AF_INET;
1601 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001602 ifm->ifa_flags = ifa->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 ifm->ifa_scope = ifa->ifa_scope;
1604 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605
Christian Braunerd3807142018-09-04 21:53:49 +02001606 if (netnsid >= 0 && nla_put_s32(skb, IFA_TARGET_NETNSID, netnsid))
1607 goto nla_put_failure;
1608
Jiri Pirko5c766d62013-01-24 09:41:41 +00001609 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1610 preferred = ifa->ifa_preferred_lft;
1611 valid = ifa->ifa_valid_lft;
1612 if (preferred != INFINITY_LIFE_TIME) {
1613 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1614
1615 if (preferred > tval)
1616 preferred -= tval;
1617 else
1618 preferred = 0;
1619 if (valid != INFINITY_LIFE_TIME) {
1620 if (valid > tval)
1621 valid -= tval;
1622 else
1623 valid = 0;
1624 }
1625 }
1626 } else {
1627 preferred = INFINITY_LIFE_TIME;
1628 valid = INFINITY_LIFE_TIME;
1629 }
David S. Millerf3756b72012-04-01 20:39:02 -04001630 if ((ifa->ifa_address &&
Jiri Benc930345e2015-03-29 16:59:25 +02001631 nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001632 (ifa->ifa_local &&
Jiri Benc930345e2015-03-29 16:59:25 +02001633 nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001634 (ifa->ifa_broadcast &&
Jiri Benc930345e2015-03-29 16:59:25 +02001635 nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001636 (ifa->ifa_label[0] &&
Jiri Pirko5c766d62013-01-24 09:41:41 +00001637 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001638 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
David Ahernaf4d7682018-05-27 08:09:57 -07001639 (ifa->ifa_rt_priority &&
1640 nla_put_u32(skb, IFA_RT_PRIORITY, ifa->ifa_rt_priority)) ||
Jiri Pirko5c766d62013-01-24 09:41:41 +00001641 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1642 preferred, valid))
David S. Millerf3756b72012-04-01 20:39:02 -04001643 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001644
Johannes Berg053c0952015-01-16 22:09:00 +01001645 nlmsg_end(skb, nlh);
1646 return 0;
Thomas Graf47f68512006-08-04 23:04:36 -07001647
1648nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001649 nlmsg_cancel(skb, nlh);
1650 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651}
1652
1653static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1654{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001655 struct net *net = sock_net(skb->sk);
Christian Braunerd3807142018-09-04 21:53:49 +02001656 struct nlattr *tb[IFA_MAX+1];
1657 struct net *tgt_net = net;
1658 int netnsid = -1;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001659 int h, s_h;
1660 int idx, s_idx;
1661 int ip_idx, s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 struct net_device *dev;
1663 struct in_device *in_dev;
1664 struct in_ifaddr *ifa;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001665 struct hlist_head *head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666
Eric Dumazeteec4df92009-11-12 07:44:25 +00001667 s_h = cb->args[0];
1668 s_idx = idx = cb->args[1];
1669 s_ip_idx = ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
Christian Braunerd3807142018-09-04 21:53:49 +02001671 if (nlmsg_parse(cb->nlh, sizeof(struct ifaddrmsg), tb, IFA_MAX,
1672 ifa_ipv4_policy, NULL) >= 0) {
1673 if (tb[IFA_TARGET_NETNSID]) {
1674 netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]);
1675
1676 tgt_net = rtnl_get_net_ns_capable(skb->sk, netnsid);
1677 if (IS_ERR(tgt_net))
1678 return PTR_ERR(tgt_net);
1679 }
1680 }
1681
Eric Dumazeteec4df92009-11-12 07:44:25 +00001682 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1683 idx = 0;
Christian Braunerd3807142018-09-04 21:53:49 +02001684 head = &tgt_net->dev_index_head[h];
Eric Dumazeteec4df92009-11-12 07:44:25 +00001685 rcu_read_lock();
Christian Braunerd3807142018-09-04 21:53:49 +02001686 cb->seq = atomic_read(&tgt_net->ipv4.dev_addr_genid) ^
1687 tgt_net->dev_base_seq;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001688 hlist_for_each_entry_rcu(dev, head, index_hlist) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001689 if (idx < s_idx)
1690 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001691 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001692 s_ip_idx = 0;
1693 in_dev = __in_dev_get_rcu(dev);
1694 if (!in_dev)
1695 goto cont;
1696
1697 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1698 ifa = ifa->ifa_next, ip_idx++) {
1699 if (ip_idx < s_ip_idx)
1700 continue;
1701 if (inet_fill_ifaddr(skb, ifa,
Christian Braunerd3807142018-09-04 21:53:49 +02001702 NETLINK_CB(cb->skb).portid,
1703 cb->nlh->nlmsg_seq,
1704 RTM_NEWADDR, NLM_F_MULTI,
1705 netnsid) < 0) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001706 rcu_read_unlock();
1707 goto done;
1708 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001709 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Eric Dumazeteec4df92009-11-12 07:44:25 +00001710 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001711cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001712 idx++;
1713 }
1714 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 }
1716
1717done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001718 cb->args[0] = h;
1719 cb->args[1] = idx;
1720 cb->args[2] = ip_idx;
Christian Braunerd3807142018-09-04 21:53:49 +02001721 if (netnsid >= 0)
1722 put_net(tgt_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723
1724 return skb->len;
1725}
1726
Jianjun Kong539afed2008-11-03 02:48:48 -08001727static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001728 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729{
Thomas Graf47f68512006-08-04 23:04:36 -07001730 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001731 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1732 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001733 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001735 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001736 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001737 if (!skb)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001738 goto errout;
1739
Christian Braunerd3807142018-09-04 21:53:49 +02001740 err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0, -1);
Patrick McHardy26932562007-01-31 23:16:40 -08001741 if (err < 0) {
1742 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1743 WARN_ON(err == -EMSGSIZE);
1744 kfree_skb(skb);
1745 goto errout;
1746 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001747 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001748 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001749errout:
1750 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001751 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752}
1753
Arad, Ronenb1974ed2015-10-19 09:23:28 -07001754static size_t inet_get_link_af_size(const struct net_device *dev,
1755 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001756{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001757 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001758
1759 if (!in_dev)
1760 return 0;
1761
1762 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1763}
1764
Sowmini Varadhand5566fd2015-09-11 16:48:48 -04001765static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
1766 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001767{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001768 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001769 struct nlattr *nla;
1770 int i;
1771
1772 if (!in_dev)
1773 return -ENODATA;
1774
1775 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
Ian Morris51456b22015-04-03 09:17:26 +01001776 if (!nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001777 return -EMSGSIZE;
1778
1779 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1780 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1781
1782 return 0;
1783}
1784
1785static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1786 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1787};
1788
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001789static int inet_validate_link_af(const struct net_device *dev,
1790 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001791{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001792 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1793 int err, rem;
1794
Florian Westphal5fa85a02017-10-16 15:44:36 +02001795 if (dev && !__in_dev_get_rcu(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001796 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001797
Johannes Bergfceb6432017-04-12 14:34:07 +02001798 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy, NULL);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001799 if (err < 0)
1800 return err;
1801
1802 if (tb[IFLA_INET_CONF]) {
1803 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1804 int cfgid = nla_type(a);
1805
1806 if (nla_len(a) < 4)
1807 return -EINVAL;
1808
1809 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1810 return -EINVAL;
1811 }
1812 }
1813
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001814 return 0;
1815}
1816
1817static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1818{
Florian Westphal5fa85a02017-10-16 15:44:36 +02001819 struct in_device *in_dev = __in_dev_get_rcu(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001820 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1821 int rem;
1822
1823 if (!in_dev)
1824 return -EAFNOSUPPORT;
1825
Johannes Bergfceb6432017-04-12 14:34:07 +02001826 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0)
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001827 BUG();
1828
Thomas Graf9f0f7272010-11-16 04:32:48 +00001829 if (tb[IFLA_INET_CONF]) {
1830 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1831 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1832 }
1833
1834 return 0;
1835}
1836
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001837static int inet_netconf_msgsize_devconf(int type)
1838{
1839 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1840 + nla_total_size(4); /* NETCONFA_IFINDEX */
Zhang Shengju136ba622016-03-10 08:55:50 +00001841 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001842
Zhang Shengju136ba622016-03-10 08:55:50 +00001843 if (type == NETCONFA_ALL)
1844 all = true;
1845
1846 if (all || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001847 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001848 if (all || type == NETCONFA_RP_FILTER)
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001849 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001850 if (all || type == NETCONFA_MC_FORWARDING)
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001851 size += nla_total_size(4);
Xin Long5cbf7772018-07-27 16:37:28 +08001852 if (all || type == NETCONFA_BC_FORWARDING)
1853 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001854 if (all || type == NETCONFA_PROXY_NEIGH)
stephen hemmingerf085ff12013-12-12 13:06:50 -08001855 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001856 if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001857 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001858
1859 return size;
1860}
1861
1862static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1863 struct ipv4_devconf *devconf, u32 portid,
1864 u32 seq, int event, unsigned int flags,
1865 int type)
1866{
1867 struct nlmsghdr *nlh;
1868 struct netconfmsg *ncm;
Zhang Shengju136ba622016-03-10 08:55:50 +00001869 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001870
1871 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1872 flags);
Ian Morris51456b22015-04-03 09:17:26 +01001873 if (!nlh)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001874 return -EMSGSIZE;
1875
Zhang Shengju136ba622016-03-10 08:55:50 +00001876 if (type == NETCONFA_ALL)
1877 all = true;
1878
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001879 ncm = nlmsg_data(nlh);
1880 ncm->ncm_family = AF_INET;
1881
1882 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1883 goto nla_put_failure;
1884
David Ahernb5c96412017-03-28 14:28:03 -07001885 if (!devconf)
1886 goto out;
1887
Zhang Shengju136ba622016-03-10 08:55:50 +00001888 if ((all || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001889 nla_put_s32(skb, NETCONFA_FORWARDING,
1890 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1891 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001892 if ((all || type == NETCONFA_RP_FILTER) &&
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001893 nla_put_s32(skb, NETCONFA_RP_FILTER,
1894 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
1895 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001896 if ((all || type == NETCONFA_MC_FORWARDING) &&
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001897 nla_put_s32(skb, NETCONFA_MC_FORWARDING,
1898 IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
1899 goto nla_put_failure;
Xin Long5cbf7772018-07-27 16:37:28 +08001900 if ((all || type == NETCONFA_BC_FORWARDING) &&
1901 nla_put_s32(skb, NETCONFA_BC_FORWARDING,
1902 IPV4_DEVCONF(*devconf, BC_FORWARDING)) < 0)
1903 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001904 if ((all || type == NETCONFA_PROXY_NEIGH) &&
stephen hemminger09aea5d2013-12-17 22:35:52 -08001905 nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08001906 IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
1907 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001908 if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001909 nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
1910 IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
1911 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001912
David Ahernb5c96412017-03-28 14:28:03 -07001913out:
Johannes Berg053c0952015-01-16 22:09:00 +01001914 nlmsg_end(skb, nlh);
1915 return 0;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001916
1917nla_put_failure:
1918 nlmsg_cancel(skb, nlh);
1919 return -EMSGSIZE;
1920}
1921
David Ahern3b022862017-03-28 14:28:02 -07001922void inet_netconf_notify_devconf(struct net *net, int event, int type,
1923 int ifindex, struct ipv4_devconf *devconf)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001924{
1925 struct sk_buff *skb;
1926 int err = -ENOBUFS;
1927
Eric Dumazetfa178062016-07-08 05:18:24 +02001928 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001929 if (!skb)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001930 goto errout;
1931
1932 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
David Ahern3b022862017-03-28 14:28:02 -07001933 event, 0, type);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001934 if (err < 0) {
1935 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1936 WARN_ON(err == -EMSGSIZE);
1937 kfree_skb(skb);
1938 goto errout;
1939 }
Eric Dumazetfa178062016-07-08 05:18:24 +02001940 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001941 return;
1942errout:
1943 if (err < 0)
1944 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
1945}
1946
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001947static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
1948 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
1949 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001950 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
stephen hemminger09aea5d2013-12-17 22:35:52 -08001951 [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) },
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001952 [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001953};
1954
1955static int inet_netconf_get_devconf(struct sk_buff *in_skb,
David Ahernc21ef3e2017-04-16 09:48:24 -07001956 struct nlmsghdr *nlh,
1957 struct netlink_ext_ack *extack)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001958{
1959 struct net *net = sock_net(in_skb->sk);
1960 struct nlattr *tb[NETCONFA_MAX+1];
1961 struct netconfmsg *ncm;
1962 struct sk_buff *skb;
1963 struct ipv4_devconf *devconf;
1964 struct in_device *in_dev;
1965 struct net_device *dev;
1966 int ifindex;
1967 int err;
1968
1969 err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
David Ahernc21ef3e2017-04-16 09:48:24 -07001970 devconf_ipv4_policy, extack);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001971 if (err < 0)
1972 goto errout;
1973
Anton Protopopova97eb332016-02-16 21:43:16 -05001974 err = -EINVAL;
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001975 if (!tb[NETCONFA_IFINDEX])
1976 goto errout;
1977
1978 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
1979 switch (ifindex) {
1980 case NETCONFA_IFINDEX_ALL:
1981 devconf = net->ipv4.devconf_all;
1982 break;
1983 case NETCONFA_IFINDEX_DEFAULT:
1984 devconf = net->ipv4.devconf_dflt;
1985 break;
1986 default:
1987 dev = __dev_get_by_index(net, ifindex);
Ian Morris51456b22015-04-03 09:17:26 +01001988 if (!dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001989 goto errout;
1990 in_dev = __in_dev_get_rtnl(dev);
Ian Morris51456b22015-04-03 09:17:26 +01001991 if (!in_dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001992 goto errout;
1993 devconf = &in_dev->cnf;
1994 break;
1995 }
1996
1997 err = -ENOBUFS;
Eric Dumazetfa178062016-07-08 05:18:24 +02001998 skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001999 if (!skb)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002000 goto errout;
2001
2002 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
2003 NETLINK_CB(in_skb).portid,
2004 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
Zhang Shengju136ba622016-03-10 08:55:50 +00002005 NETCONFA_ALL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002006 if (err < 0) {
2007 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
2008 WARN_ON(err == -EMSGSIZE);
2009 kfree_skb(skb);
2010 goto errout;
2011 }
2012 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
2013errout:
2014 return err;
2015}
2016
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002017static int inet_netconf_dump_devconf(struct sk_buff *skb,
2018 struct netlink_callback *cb)
2019{
2020 struct net *net = sock_net(skb->sk);
2021 int h, s_h;
2022 int idx, s_idx;
2023 struct net_device *dev;
2024 struct in_device *in_dev;
2025 struct hlist_head *head;
2026
2027 s_h = cb->args[0];
2028 s_idx = idx = cb->args[1];
2029
2030 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
2031 idx = 0;
2032 head = &net->dev_index_head[h];
2033 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00002034 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
2035 net->dev_base_seq;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002036 hlist_for_each_entry_rcu(dev, head, index_hlist) {
2037 if (idx < s_idx)
2038 goto cont;
2039 in_dev = __in_dev_get_rcu(dev);
2040 if (!in_dev)
2041 goto cont;
2042
2043 if (inet_netconf_fill_devconf(skb, dev->ifindex,
2044 &in_dev->cnf,
2045 NETLINK_CB(cb->skb).portid,
2046 cb->nlh->nlmsg_seq,
2047 RTM_NEWNETCONF,
2048 NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002049 NETCONFA_ALL) < 0) {
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002050 rcu_read_unlock();
2051 goto done;
2052 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00002053 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002054cont:
2055 idx++;
2056 }
2057 rcu_read_unlock();
2058 }
2059 if (h == NETDEV_HASHENTRIES) {
2060 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
2061 net->ipv4.devconf_all,
2062 NETLINK_CB(cb->skb).portid,
2063 cb->nlh->nlmsg_seq,
2064 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002065 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002066 goto done;
2067 else
2068 h++;
2069 }
2070 if (h == NETDEV_HASHENTRIES + 1) {
2071 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
2072 net->ipv4.devconf_dflt,
2073 NETLINK_CB(cb->skb).portid,
2074 cb->nlh->nlmsg_seq,
2075 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002076 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002077 goto done;
2078 else
2079 h++;
2080 }
2081done:
2082 cb->args[0] = h;
2083 cb->args[1] = idx;
2084
2085 return skb->len;
2086}
2087
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088#ifdef CONFIG_SYSCTL
2089
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002090static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07002091{
2092 struct net_device *dev;
2093
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002094 rcu_read_lock();
2095 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07002096 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002097
Herbert Xu31be3082007-06-04 23:35:37 -07002098 in_dev = __in_dev_get_rcu(dev);
2099 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002100 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07002101 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002102 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07002103}
2104
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002105/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002106static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002107{
2108 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002109 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002110
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002111 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002112 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
David Ahern3b022862017-03-28 14:28:02 -07002113 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2114 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002115 NETCONFA_IFINDEX_ALL,
2116 net->ipv4.devconf_all);
David Ahern3b022862017-03-28 14:28:02 -07002117 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2118 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002119 NETCONFA_IFINDEX_DEFAULT,
2120 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002121
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002122 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002123 struct in_device *in_dev;
Eric Dumazetfa178062016-07-08 05:18:24 +02002124
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002125 if (on)
2126 dev_disable_lro(dev);
Eric Dumazetfa178062016-07-08 05:18:24 +02002127
2128 in_dev = __in_dev_get_rtnl(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002129 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002130 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
David Ahern3b022862017-03-28 14:28:02 -07002131 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2132 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002133 dev->ifindex, &in_dev->cnf);
2134 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002135 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002136}
2137
stephen hemmingerf085ff12013-12-12 13:06:50 -08002138static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf)
2139{
2140 if (cnf == net->ipv4.devconf_dflt)
2141 return NETCONFA_IFINDEX_DEFAULT;
2142 else if (cnf == net->ipv4.devconf_all)
2143 return NETCONFA_IFINDEX_ALL;
2144 else {
2145 struct in_device *idev
2146 = container_of(cnf, struct in_device, cnf);
2147 return idev->dev->ifindex;
2148 }
2149}
2150
Joe Perchesfe2c6332013-06-11 23:04:25 -07002151static int devinet_conf_proc(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002152 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07002153 size_t *lenp, loff_t *ppos)
2154{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002155 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002156 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002157 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07002158
2159 if (write) {
2160 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002161 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07002162 int i = (int *)ctl->data - cnf->data;
stephen hemmingerf085ff12013-12-12 13:06:50 -08002163 int ifindex;
Herbert Xu31be3082007-06-04 23:35:37 -07002164
2165 set_bit(i, cnf->state);
2166
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002167 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002168 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00002169 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
2170 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002171 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002172 rt_cache_flush(net);
stephen hemmingerf085ff12013-12-12 13:06:50 -08002173
Xin Long5cbf7772018-07-27 16:37:28 +08002174 if (i == IPV4_DEVCONF_BC_FORWARDING - 1 &&
2175 new_value != old_value)
2176 rt_cache_flush(net);
2177
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002178 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
2179 new_value != old_value) {
stephen hemmingerf085ff12013-12-12 13:06:50 -08002180 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002181 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2182 NETCONFA_RP_FILTER,
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002183 ifindex, cnf);
2184 }
stephen hemmingerf085ff12013-12-12 13:06:50 -08002185 if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
2186 new_value != old_value) {
2187 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002188 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2189 NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002190 ifindex, cnf);
2191 }
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002192 if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
2193 new_value != old_value) {
2194 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002195 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2196 NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002197 ifindex, cnf);
2198 }
Herbert Xu31be3082007-06-04 23:35:37 -07002199 }
2200
2201 return ret;
2202}
2203
Joe Perchesfe2c6332013-06-11 23:04:25 -07002204static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002205 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 size_t *lenp, loff_t *ppos)
2207{
2208 int *valp = ctl->data;
2209 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00002210 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002211 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212
2213 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002214 struct net *net = ctl->extra2;
2215
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002216 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00002217 if (!rtnl_trylock()) {
2218 /* Restore the original values before restarting */
2219 *valp = val;
2220 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00002221 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00002222 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002223 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2224 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002225 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002226 struct ipv4_devconf *cnf = ctl->extra1;
2227 struct in_device *idev =
2228 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002229 if (*valp)
2230 dev_disable_lro(idev->dev);
David Ahern3b022862017-03-28 14:28:02 -07002231 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002232 NETCONFA_FORWARDING,
2233 idev->dev->ifindex,
2234 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002235 }
2236 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002237 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002238 } else
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_DEFAULT,
2242 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 }
2244
2245 return ret;
2246}
2247
Joe Perchesfe2c6332013-06-11 23:04:25 -07002248static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
David S. Miller323e1262010-12-12 21:55:08 -08002249 void __user *buffer,
2250 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251{
2252 int *valp = ctl->data;
2253 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002254 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07002255 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256
2257 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002258 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259
2260 return ret;
2261}
2262
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002263#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07002264 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07002265 .procname = name, \
2266 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00002267 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002268 .maxlen = sizeof(int), \
2269 .mode = mval, \
2270 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07002271 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002272 }
2273
2274#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002275 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002276
2277#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002278 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002279
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002280#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2281 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002282
2283#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002284 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07002285
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286static struct devinet_sysctl_table {
2287 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00002288 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289} devinet_sysctl = {
2290 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07002291 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002292 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07002293 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
Xin Long5cbf7772018-07-27 16:37:28 +08002294 DEVINET_SYSCTL_RW_ENTRY(BC_FORWARDING, "bc_forwarding"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002295
2296 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
2297 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
2298 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
2299 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
2300 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
2301 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
2302 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00002303 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08002304 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002305 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
2306 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
2307 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
2308 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
2309 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
2310 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
2311 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
2312 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
2313 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08002314 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00002315 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
William Manley5c6fe012013-08-06 19:03:14 +01002316 DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
2317 "force_igmp_version"),
William Manley26900482013-08-06 19:03:15 +01002318 DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
2319 "igmpv2_unsolicited_report_interval"),
2320 DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
2321 "igmpv3_unsolicited_report_interval"),
Andy Gospodarek0eeb0752015-06-23 13:45:37 -04002322 DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
2323 "ignore_routes_with_linkdown"),
Johannes Berg97daf332016-02-04 13:31:18 +01002324 DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
2325 "drop_gratuitous_arp"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002326
2327 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2328 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002329 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
2330 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00002331 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2332 "route_localnet"),
Johannes Berg12b74df2016-02-04 13:31:17 +01002333 DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
2334 "drop_unicast_in_l2_multicast"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336};
2337
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002338static int __devinet_sysctl_register(struct net *net, char *dev_name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002339 int ifindex, struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340{
2341 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002342 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002343 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11002344
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002345 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002347 goto out;
2348
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
2350 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07002351 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002352 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 }
2354
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002355 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002357 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002359 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
2361 p->sysctl = t;
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002362
David Ahern3b022862017-03-28 14:28:02 -07002363 inet_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_ALL,
2364 ifindex, p);
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002365 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002367free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002369out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002370 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371}
2372
David Ahernb5c96412017-03-28 14:28:03 -07002373static void __devinet_sysctl_unregister(struct net *net,
2374 struct ipv4_devconf *cnf, int ifindex)
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002375{
2376 struct devinet_sysctl_table *t = cnf->sysctl;
2377
David Ahernb5c96412017-03-28 14:28:03 -07002378 if (t) {
2379 cnf->sysctl = NULL;
2380 unregister_net_sysctl_table(t->sysctl_header);
2381 kfree(t);
2382 }
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002383
David Ahernb5c96412017-03-28 14:28:03 -07002384 inet_netconf_notify_devconf(net, RTM_DELNETCONF, 0, ifindex, NULL);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002385}
2386
WANG Cong20e61da2014-07-25 15:25:08 -07002387static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002388{
WANG Cong20e61da2014-07-25 15:25:08 -07002389 int err;
2390
2391 if (!sysctl_dev_name_is_allowed(idev->dev->name))
2392 return -EINVAL;
2393
2394 err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
2395 if (err)
2396 return err;
2397 err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002398 idev->dev->ifindex, &idev->cnf);
WANG Cong20e61da2014-07-25 15:25:08 -07002399 if (err)
2400 neigh_sysctl_unregister(idev->arp_parms);
2401 return err;
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002402}
2403
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002404static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405{
David Ahernb5c96412017-03-28 14:28:03 -07002406 struct net *net = dev_net(idev->dev);
2407
2408 __devinet_sysctl_unregister(net, &idev->cnf, idev->dev->ifindex);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002409 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002412static struct ctl_table ctl_forward_entry[] = {
2413 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002414 .procname = "ip_forward",
2415 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00002416 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002417 .maxlen = sizeof(int),
2418 .mode = 0644,
2419 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002420 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002421 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002422 },
2423 { },
2424};
Eric Dumazet2a75de02008-01-05 23:08:49 -08002425#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002426
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002427static __net_init int devinet_init_net(struct net *net)
2428{
2429 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002430 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002431#ifdef CONFIG_SYSCTL
2432 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002433 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002434#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002435
2436 err = -ENOMEM;
2437 all = &ipv4_devconf;
2438 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002439
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002440 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002441 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002442 if (!all)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002443 goto err_alloc_all;
2444
2445 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002446 if (!dflt)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002447 goto err_alloc_dflt;
2448
Eric Dumazet2a75de02008-01-05 23:08:49 -08002449#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002450 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002451 if (!tbl)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002452 goto err_alloc_ctl;
2453
Eric W. Biederman02291682010-02-14 03:25:51 +00002454 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002455 tbl[0].extra1 = all;
2456 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002457#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002458 }
2459
2460#ifdef CONFIG_SYSCTL
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002461 err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002462 if (err < 0)
2463 goto err_reg_all;
2464
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002465 err = __devinet_sysctl_register(net, "default",
2466 NETCONFA_IFINDEX_DEFAULT, dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002467 if (err < 0)
2468 goto err_reg_dflt;
2469
2470 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002471 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Ian Morris51456b22015-04-03 09:17:26 +01002472 if (!forw_hdr)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002473 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002474 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002475#endif
2476
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002477 net->ipv4.devconf_all = all;
2478 net->ipv4.devconf_dflt = dflt;
2479 return 0;
2480
2481#ifdef CONFIG_SYSCTL
2482err_reg_ctl:
David Ahernb5c96412017-03-28 14:28:03 -07002483 __devinet_sysctl_unregister(net, dflt, NETCONFA_IFINDEX_DEFAULT);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002484err_reg_dflt:
David Ahernb5c96412017-03-28 14:28:03 -07002485 __devinet_sysctl_unregister(net, all, NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002486err_reg_all:
2487 if (tbl != ctl_forward_entry)
2488 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002489err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08002490#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002491 if (dflt != &ipv4_devconf_dflt)
2492 kfree(dflt);
2493err_alloc_dflt:
2494 if (all != &ipv4_devconf)
2495 kfree(all);
2496err_alloc_all:
2497 return err;
2498}
2499
2500static __net_exit void devinet_exit_net(struct net *net)
2501{
Eric Dumazet2a75de02008-01-05 23:08:49 -08002502#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002503 struct ctl_table *tbl;
2504
2505 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002506 unregister_net_sysctl_table(net->ipv4.forw_hdr);
David Ahernb5c96412017-03-28 14:28:03 -07002507 __devinet_sysctl_unregister(net, net->ipv4.devconf_dflt,
2508 NETCONFA_IFINDEX_DEFAULT);
2509 __devinet_sysctl_unregister(net, net->ipv4.devconf_all,
2510 NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002511 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08002512#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002513 kfree(net->ipv4.devconf_dflt);
2514 kfree(net->ipv4.devconf_all);
2515}
2516
2517static __net_initdata struct pernet_operations devinet_ops = {
2518 .init = devinet_init_net,
2519 .exit = devinet_exit_net,
2520};
2521
Daniel Borkmann207895fd32015-01-29 12:15:03 +01002522static struct rtnl_af_ops inet_af_ops __read_mostly = {
Thomas Graf9f0f7272010-11-16 04:32:48 +00002523 .family = AF_INET,
2524 .fill_link_af = inet_fill_link_af,
2525 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00002526 .validate_link_af = inet_validate_link_af,
2527 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00002528};
2529
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530void __init devinet_init(void)
2531{
David S. Millerfd23c3b2011-02-18 12:42:28 -08002532 int i;
2533
2534 for (i = 0; i < IN4_ADDR_HSIZE; i++)
2535 INIT_HLIST_HEAD(&inet_addr_lst[i]);
2536
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002537 register_pernet_subsys(&devinet_ops);
2538
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 register_gifconf(PF_INET, inet_gifconf);
2540 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07002541
viresh kumar906e0732014-01-22 12:23:32 +05302542 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +00002543
Thomas Graf9f0f7272010-11-16 04:32:48 +00002544 rtnl_af_register(&inet_af_ops);
2545
Florian Westphalb97bac62017-08-09 20:41:48 +02002546 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, 0);
2547 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, 0);
2548 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, 0);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002549 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
Florian Westphalb97bac62017-08-09 20:41:48 +02002550 inet_netconf_dump_devconf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551}