blob: 7ce22a2c07ce07ac2cd4cafb5aff6ec8d074531f [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 },
Thomas Graf5c753972006-08-04 23:03:53 -0700102};
103
Eric Dumazet40384992012-08-03 21:06:50 +0000104#define IN4_ADDR_HSIZE_SHIFT 8
105#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT)
106
David S. Millerfd23c3b2011-02-18 12:42:28 -0800107static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
David S. Millerfd23c3b2011-02-18 12:42:28 -0800108
Eric Dumazet6eada012015-03-18 14:05:33 -0700109static u32 inet_addr_hash(const struct net *net, __be32 addr)
David S. Millerfd23c3b2011-02-18 12:42:28 -0800110{
Eric Dumazet40384992012-08-03 21:06:50 +0000111 u32 val = (__force u32) addr ^ net_hash_mix(net);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800112
Eric Dumazet40384992012-08-03 21:06:50 +0000113 return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800114}
115
116static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
117{
Eric Dumazet40384992012-08-03 21:06:50 +0000118 u32 hash = inet_addr_hash(net, ifa->ifa_local);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800119
WANG Cong32a4be42014-05-06 11:15:56 -0700120 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800121 hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800122}
123
124static void inet_hash_remove(struct in_ifaddr *ifa)
125{
WANG Cong32a4be42014-05-06 11:15:56 -0700126 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800127 hlist_del_init_rcu(&ifa->hash);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800128}
129
David S. Miller9435eb12011-02-18 12:43:09 -0800130/**
131 * __ip_dev_find - find the first device with a given source address.
132 * @net: the net namespace
133 * @addr: the source address
134 * @devref: if true, take a reference on the found device
135 *
136 * If a caller uses devref=false, it should be protected by RCU, or RTNL
137 */
138struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
139{
David S. Miller9435eb12011-02-18 12:43:09 -0800140 struct net_device *result = NULL;
141 struct in_ifaddr *ifa;
David S. Miller9435eb12011-02-18 12:43:09 -0800142
143 rcu_read_lock();
Paolo Abeni6e617de2017-09-20 18:26:53 +0200144 ifa = inet_lookup_ifaddr_rcu(net, addr);
145 if (!ifa) {
David S. Miller406b6f92011-03-22 21:56:23 -0700146 struct flowi4 fl4 = { .daddr = addr };
147 struct fib_result res = { 0 };
148 struct fib_table *local;
149
150 /* Fallback to FIB local table so that communication
151 * over loopback subnets work.
152 */
153 local = fib_get_table(net, RT_TABLE_LOCAL);
154 if (local &&
155 !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
156 res.type == RTN_LOCAL)
157 result = FIB_RES_DEV(res);
Paolo Abeni6e617de2017-09-20 18:26:53 +0200158 } else {
159 result = ifa->ifa_dev->dev;
David S. Miller406b6f92011-03-22 21:56:23 -0700160 }
David S. Miller9435eb12011-02-18 12:43:09 -0800161 if (result && devref)
162 dev_hold(result);
163 rcu_read_unlock();
164 return result;
165}
166EXPORT_SYMBOL(__ip_dev_find);
167
Paolo Abeni6e617de2017-09-20 18:26:53 +0200168/* called under RCU lock */
169struct in_ifaddr *inet_lookup_ifaddr_rcu(struct net *net, __be32 addr)
170{
171 u32 hash = inet_addr_hash(net, addr);
172 struct in_ifaddr *ifa;
173
174 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash)
175 if (ifa->ifa_local == addr &&
176 net_eq(dev_net(ifa->ifa_dev->dev), net))
177 return ifa;
178
179 return NULL;
180}
181
Thomas Grafd6062cb2006-08-15 00:33:59 -0700182static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Alan Sterne041c682006-03-27 01:16:30 -0800184static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Krister Johansen3ad7d242017-06-08 13:12:14 -0700185static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
187 int destroy);
188#ifdef CONFIG_SYSCTL
WANG Cong20e61da2014-07-25 15:25:08 -0700189static int devinet_sysctl_register(struct in_device *idev);
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800190static void devinet_sysctl_unregister(struct in_device *idev);
191#else
WANG Cong20e61da2014-07-25 15:25:08 -0700192static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800193{
WANG Cong20e61da2014-07-25 15:25:08 -0700194 return 0;
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800195}
Eric Dumazet40384992012-08-03 21:06:50 +0000196static void devinet_sysctl_unregister(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800197{
198}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199#endif
200
201/* Locks all the inet devices. */
202
203static struct in_ifaddr *inet_alloc_ifa(void)
204{
Alexey Dobriyan93adcc82008-10-28 13:25:09 -0700205 return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206}
207
208static void inet_rcu_free_ifa(struct rcu_head *head)
209{
210 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
211 if (ifa->ifa_dev)
212 in_dev_put(ifa->ifa_dev);
213 kfree(ifa);
214}
215
Eric Dumazet40384992012-08-03 21:06:50 +0000216static void inet_free_ifa(struct in_ifaddr *ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217{
218 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
219}
220
221void in_dev_finish_destroy(struct in_device *idev)
222{
223 struct net_device *dev = idev->dev;
224
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700225 WARN_ON(idev->ifa_list);
226 WARN_ON(idev->mc_list);
Eric Dumazete9897072013-06-07 08:48:57 -0700227 kfree(rcu_dereference_protected(idev->mc_hash, 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228#ifdef NET_REFCNT_DEBUG
Joe Perches91df42b2012-05-15 14:11:54 +0000229 pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230#endif
231 dev_put(dev);
232 if (!idev->dead)
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800233 pr_err("Freeing alive in_device %p\n", idev);
234 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 kfree(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800237EXPORT_SYMBOL(in_dev_finish_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
Herbert Xu71e27da2007-06-04 23:36:06 -0700239static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240{
241 struct in_device *in_dev;
WANG Cong20e61da2014-07-25 15:25:08 -0700242 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
244 ASSERT_RTNL();
245
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700246 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 if (!in_dev)
248 goto out;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900249 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -0800250 sizeof(in_dev->cnf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 in_dev->cnf.sysctl = NULL;
252 in_dev->dev = dev;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800253 in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
254 if (!in_dev->arp_parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 goto out_kfree;
Ben Hutchings0187bdf2008-06-19 16:15:47 -0700256 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
257 dev_disable_lro(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 /* Reference in_dev->dev */
259 dev_hold(dev);
David L Stevens30c4cf52007-01-04 12:31:14 -0800260 /* Account for reference dev->ip_ptr (below) */
Reshetova, Elena7658b362017-06-30 13:08:03 +0300261 refcount_set(&in_dev->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
WANG Cong20e61da2014-07-25 15:25:08 -0700263 err = devinet_sysctl_register(in_dev);
264 if (err) {
265 in_dev->dead = 1;
266 in_dev_put(in_dev);
267 in_dev = NULL;
268 goto out;
269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 ip_mc_init_dev(in_dev);
271 if (dev->flags & IFF_UP)
272 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800273
David L Stevens30c4cf52007-01-04 12:31:14 -0800274 /* we can receive as soon as ip_ptr is set -- do this last */
Eric Dumazetcf778b02012-01-12 04:41:32 +0000275 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800276out:
WANG Cong20e61da2014-07-25 15:25:08 -0700277 return in_dev ?: ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278out_kfree:
279 kfree(in_dev);
280 in_dev = NULL;
281 goto out;
282}
283
284static void in_dev_rcu_put(struct rcu_head *head)
285{
286 struct in_device *idev = container_of(head, struct in_device, rcu_head);
287 in_dev_put(idev);
288}
289
290static void inetdev_destroy(struct in_device *in_dev)
291{
292 struct in_ifaddr *ifa;
293 struct net_device *dev;
294
295 ASSERT_RTNL();
296
297 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
299 in_dev->dead = 1;
300
301 ip_mc_destroy_dev(in_dev);
302
303 while ((ifa = in_dev->ifa_list) != NULL) {
304 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
305 inet_free_ifa(ifa);
306 }
307
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000308 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800310 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
312 arp_ifdown(dev);
313
314 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
315}
316
Al Viroff428d72006-09-26 22:13:35 -0700317int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
319 rcu_read_lock();
320 for_primary_ifa(in_dev) {
321 if (inet_ifa_match(a, ifa)) {
322 if (!b || inet_ifa_match(b, ifa)) {
323 rcu_read_unlock();
324 return 1;
325 }
326 }
327 } endfor_ifa(in_dev);
328 rcu_read_unlock();
329 return 0;
330}
331
Thomas Grafd6062cb2006-08-15 00:33:59 -0700332static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000333 int destroy, struct nlmsghdr *nlh, u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
Harald Welte8f937c62005-05-29 20:23:46 -0700335 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800336 struct in_ifaddr *ifa, *ifa1 = *ifap;
337 struct in_ifaddr *last_prim = in_dev->ifa_list;
338 struct in_ifaddr *prev_prom = NULL;
339 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
341 ASSERT_RTNL();
342
David S. Millerfbd40ea2016-03-13 23:28:00 -0400343 if (in_dev->dead)
344 goto no_promotions;
345
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900346 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700347 * unless alias promotion is set
348 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
350 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
352
353 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900354 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800355 ifa1->ifa_scope <= ifa->ifa_scope)
356 last_prim = ifa;
357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
359 ifa1->ifa_mask != ifa->ifa_mask ||
360 !inet_ifa_match(ifa1->ifa_address, ifa)) {
361 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800362 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 continue;
364 }
365
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800366 if (!do_promote) {
David S. Millerfd23c3b2011-02-18 12:42:28 -0800367 inet_hash_remove(ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700368 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
Eric W. Biederman15e47302012-09-07 20:12:54 +0000370 rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800371 blocking_notifier_call_chain(&inetaddr_chain,
372 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700373 inet_free_ifa(ifa);
374 } else {
375 promote = ifa;
376 break;
377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 }
379 }
380
Julian Anastasov2d230e22011-03-19 12:13:52 +0000381 /* On promotion all secondaries from subnet are changing
382 * the primary IP, we must remove all their routes silently
383 * and later to add them back with new prefsrc. Do this
384 * while all addresses are on the device list.
385 */
386 for (ifa = promote; ifa; ifa = ifa->ifa_next) {
387 if (ifa1->ifa_mask == ifa->ifa_mask &&
388 inet_ifa_match(ifa1->ifa_address, ifa))
389 fib_del_ifaddr(ifa, ifa1);
390 }
391
David S. Millerfbd40ea2016-03-13 23:28:00 -0400392no_promotions:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 /* 2. Unlink it */
394
395 *ifap = ifa1->ifa_next;
David S. Millerfd23c3b2011-02-18 12:42:28 -0800396 inet_hash_remove(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
398 /* 3. Announce address deletion */
399
400 /* Send message first, then call notifier.
401 At first sight, FIB update triggered by notifier
402 will refer to already deleted ifaddr, that could confuse
403 netlink listeners. It is not true: look, gated sees
404 that route deleted and if it still thinks that ifaddr
405 is valid, it will try to restore deleted routes... Grr.
406 So that, this order is correct.
407 */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000408 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800409 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800410
411 if (promote) {
Julian Anastasov04024b92011-03-19 12:13:54 +0000412 struct in_ifaddr *next_sec = promote->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800413
414 if (prev_prom) {
415 prev_prom->ifa_next = promote->ifa_next;
416 promote->ifa_next = last_prim->ifa_next;
417 last_prim->ifa_next = promote;
418 }
419
420 promote->ifa_flags &= ~IFA_F_SECONDARY;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000421 rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800422 blocking_notifier_call_chain(&inetaddr_chain,
423 NETDEV_UP, promote);
Julian Anastasov04024b92011-03-19 12:13:54 +0000424 for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800425 if (ifa1->ifa_mask != ifa->ifa_mask ||
426 !inet_ifa_match(ifa1->ifa_address, ifa))
427 continue;
428 fib_add_ifaddr(ifa);
429 }
430
431 }
Herbert Xu63630972007-06-07 18:35:38 -0700432 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434}
435
Thomas Grafd6062cb2006-08-15 00:33:59 -0700436static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
437 int destroy)
438{
439 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
440}
441
Jiri Pirko5c766d62013-01-24 09:41:41 +0000442static void check_lifetime(struct work_struct *work);
443
444static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
445
Thomas Grafd6062cb2006-08-15 00:33:59 -0700446static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000447 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
449 struct in_device *in_dev = ifa->ifa_dev;
450 struct in_ifaddr *ifa1, **ifap, **last_primary;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700451 struct in_validator_info ivi;
452 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453
454 ASSERT_RTNL();
455
456 if (!ifa->ifa_local) {
457 inet_free_ifa(ifa);
458 return 0;
459 }
460
461 ifa->ifa_flags &= ~IFA_F_SECONDARY;
462 last_primary = &in_dev->ifa_list;
463
464 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
465 ifap = &ifa1->ifa_next) {
466 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
467 ifa->ifa_scope <= ifa1->ifa_scope)
468 last_primary = &ifa1->ifa_next;
469 if (ifa1->ifa_mask == ifa->ifa_mask &&
470 inet_ifa_match(ifa1->ifa_address, ifa)) {
471 if (ifa1->ifa_local == ifa->ifa_local) {
472 inet_free_ifa(ifa);
473 return -EEXIST;
474 }
475 if (ifa1->ifa_scope != ifa->ifa_scope) {
476 inet_free_ifa(ifa);
477 return -EINVAL;
478 }
479 ifa->ifa_flags |= IFA_F_SECONDARY;
480 }
481 }
482
Krister Johansen3ad7d242017-06-08 13:12:14 -0700483 /* Allow any devices that wish to register ifaddr validtors to weigh
484 * in now, before changes are committed. The rntl lock is serializing
485 * access here, so the state should not change between a validator call
486 * and a final notify on commit. This isn't invoked on promotion under
487 * the assumption that validators are checking the address itself, and
488 * not the flags.
489 */
490 ivi.ivi_addr = ifa->ifa_address;
491 ivi.ivi_dev = ifa->ifa_dev;
492 ret = blocking_notifier_call_chain(&inetaddr_validator_chain,
493 NETDEV_UP, &ivi);
494 ret = notifier_to_errno(ret);
495 if (ret) {
496 inet_free_ifa(ifa);
497 return ret;
498 }
499
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500501 prandom_seed((__force u32) ifa->ifa_local);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 ifap = last_primary;
503 }
504
505 ifa->ifa_next = *ifap;
506 *ifap = ifa;
507
David S. Millerfd23c3b2011-02-18 12:42:28 -0800508 inet_hash_insert(dev_net(in_dev->dev), ifa);
509
Jiri Pirko5c766d62013-01-24 09:41:41 +0000510 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530511 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000512
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 /* Send message first, then call notifier.
514 Notifier will trigger FIB update, so that
515 listeners of netlink will know about new ifaddr */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000516 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800517 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
519 return 0;
520}
521
Thomas Grafd6062cb2006-08-15 00:33:59 -0700522static int inet_insert_ifa(struct in_ifaddr *ifa)
523{
524 return __inet_insert_ifa(ifa, NULL, 0);
525}
526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
528{
Herbert Xue5ed6392005-10-03 14:35:55 -0700529 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
531 ASSERT_RTNL();
532
533 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700534 inet_free_ifa(ifa);
535 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700537 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100538 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700540 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 in_dev_hold(in_dev);
542 ifa->ifa_dev = in_dev;
543 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800544 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 ifa->ifa_scope = RT_SCOPE_HOST;
546 return inet_insert_ifa(ifa);
547}
548
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000549/* Caller must hold RCU or RTNL :
550 * We dont take a reference on found in_device
551 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800552struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553{
554 struct net_device *dev;
555 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000556
557 rcu_read_lock();
558 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000560 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000561 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 return in_dev;
563}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800564EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
566/* Called only from RTNL semaphored context. No locks. */
567
Al Viro60cad5d2006-09-26 22:17:09 -0700568struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
569 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570{
571 ASSERT_RTNL();
572
573 for_primary_ifa(in_dev) {
574 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
575 return ifa;
576 } endfor_ifa(in_dev);
577 return NULL;
578}
579
Madhu Challa93a714d2015-02-25 09:58:35 -0800580static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa)
581{
582 struct ip_mreqn mreq = {
583 .imr_multiaddr.s_addr = ifa->ifa_address,
584 .imr_ifindex = ifa->ifa_dev->dev->ifindex,
585 };
586 int ret;
587
588 ASSERT_RTNL();
589
590 lock_sock(sk);
591 if (join)
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300592 ret = ip_mc_join_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800593 else
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300594 ret = ip_mc_leave_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800595 release_sock(sk);
596
597 return ret;
598}
599
David Ahernc21ef3e2017-04-16 09:48:24 -0700600static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
601 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900603 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700604 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700606 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700608 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
610 ASSERT_RTNL();
611
Johannes Bergfceb6432017-04-12 14:34:07 +0200612 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -0700613 extack);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700614 if (err < 0)
615 goto errout;
616
617 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800618 in_dev = inetdev_by_index(net, ifm->ifa_index);
Ian Morris51456b22015-04-03 09:17:26 +0100619 if (!in_dev) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700620 err = -ENODEV;
621 goto errout;
622 }
623
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
625 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700626 if (tb[IFA_LOCAL] &&
Jiri Benc67b61f62015-03-29 16:59:26 +0200627 ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700629
630 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
631 continue;
632
633 if (tb[IFA_ADDRESS] &&
634 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Jiri Benc67b61f62015-03-29 16:59:26 +0200635 !inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700636 continue;
637
Madhu Challa93a714d2015-02-25 09:58:35 -0800638 if (ipv4_is_multicast(ifa->ifa_address))
639 ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000640 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 return 0;
642 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700643
644 err = -EADDRNOTAVAIL;
645errout:
646 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647}
648
Jiri Pirko5c766d62013-01-24 09:41:41 +0000649#define INFINITY_LIFE_TIME 0xFFFFFFFF
650
651static void check_lifetime(struct work_struct *work)
652{
653 unsigned long now, next, next_sec, next_sched;
654 struct in_ifaddr *ifa;
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000655 struct hlist_node *n;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000656 int i;
657
658 now = jiffies;
659 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
660
Jiri Pirko5c766d62013-01-24 09:41:41 +0000661 for (i = 0; i < IN4_ADDR_HSIZE; i++) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000662 bool change_needed = false;
663
664 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800665 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
Jiri Pirko5c766d62013-01-24 09:41:41 +0000666 unsigned long age;
667
668 if (ifa->ifa_flags & IFA_F_PERMANENT)
669 continue;
670
671 /* We try to batch several events at once. */
672 age = (now - ifa->ifa_tstamp +
673 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
674
675 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
676 age >= ifa->ifa_valid_lft) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000677 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000678 } else if (ifa->ifa_preferred_lft ==
679 INFINITY_LIFE_TIME) {
680 continue;
681 } else if (age >= ifa->ifa_preferred_lft) {
682 if (time_before(ifa->ifa_tstamp +
683 ifa->ifa_valid_lft * HZ, next))
684 next = ifa->ifa_tstamp +
685 ifa->ifa_valid_lft * HZ;
686
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000687 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
688 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000689 } else if (time_before(ifa->ifa_tstamp +
690 ifa->ifa_preferred_lft * HZ,
691 next)) {
692 next = ifa->ifa_tstamp +
693 ifa->ifa_preferred_lft * HZ;
694 }
695 }
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000696 rcu_read_unlock();
697 if (!change_needed)
698 continue;
699 rtnl_lock();
700 hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
701 unsigned long age;
702
703 if (ifa->ifa_flags & IFA_F_PERMANENT)
704 continue;
705
706 /* We try to batch several events at once. */
707 age = (now - ifa->ifa_tstamp +
708 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
709
710 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
711 age >= ifa->ifa_valid_lft) {
712 struct in_ifaddr **ifap;
713
714 for (ifap = &ifa->ifa_dev->ifa_list;
715 *ifap != NULL; ifap = &(*ifap)->ifa_next) {
716 if (*ifap == ifa) {
717 inet_del_ifa(ifa->ifa_dev,
718 ifap, 1);
719 break;
720 }
721 }
722 } else if (ifa->ifa_preferred_lft !=
723 INFINITY_LIFE_TIME &&
724 age >= ifa->ifa_preferred_lft &&
725 !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
726 ifa->ifa_flags |= IFA_F_DEPRECATED;
727 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
728 }
729 }
730 rtnl_unlock();
Jiri Pirko5c766d62013-01-24 09:41:41 +0000731 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000732
733 next_sec = round_jiffies_up(next);
734 next_sched = next;
735
736 /* If rounded timeout is accurate enough, accept it. */
737 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
738 next_sched = next_sec;
739
740 now = jiffies;
741 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
742 if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
743 next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
744
viresh kumar906e0732014-01-22 12:23:32 +0530745 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work,
746 next_sched - now);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000747}
748
749static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
750 __u32 prefered_lft)
751{
752 unsigned long timeout;
753
754 ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
755
756 timeout = addrconf_timeout_fixup(valid_lft, HZ);
757 if (addrconf_finite_timeout(timeout))
758 ifa->ifa_valid_lft = timeout;
759 else
760 ifa->ifa_flags |= IFA_F_PERMANENT;
761
762 timeout = addrconf_timeout_fixup(prefered_lft, HZ);
763 if (addrconf_finite_timeout(timeout)) {
764 if (timeout == 0)
765 ifa->ifa_flags |= IFA_F_DEPRECATED;
766 ifa->ifa_preferred_lft = timeout;
767 }
768 ifa->ifa_tstamp = jiffies;
769 if (!ifa->ifa_cstamp)
770 ifa->ifa_cstamp = ifa->ifa_tstamp;
771}
772
773static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
774 __u32 *pvalid_lft, __u32 *pprefered_lft)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
Thomas Graf5c753972006-08-04 23:03:53 -0700776 struct nlattr *tb[IFA_MAX+1];
777 struct in_ifaddr *ifa;
778 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 struct net_device *dev;
780 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800781 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
Johannes Bergfceb6432017-04-12 14:34:07 +0200783 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
784 NULL);
Thomas Graf5c753972006-08-04 23:03:53 -0700785 if (err < 0)
786 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
Thomas Graf5c753972006-08-04 23:03:53 -0700788 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800789 err = -EINVAL;
Ian Morris51456b22015-04-03 09:17:26 +0100790 if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL])
Thomas Graf5c753972006-08-04 23:03:53 -0700791 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800793 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800794 err = -ENODEV;
Ian Morris51456b22015-04-03 09:17:26 +0100795 if (!dev)
Thomas Graf5c753972006-08-04 23:03:53 -0700796 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
Thomas Graf5c753972006-08-04 23:03:53 -0700798 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800799 err = -ENOBUFS;
Ian Morris51456b22015-04-03 09:17:26 +0100800 if (!in_dev)
Herbert Xu71e27da2007-06-04 23:36:06 -0700801 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
Thomas Graf5c753972006-08-04 23:03:53 -0700803 ifa = inet_alloc_ifa();
Ian Morris51456b22015-04-03 09:17:26 +0100804 if (!ifa)
Thomas Graf5c753972006-08-04 23:03:53 -0700805 /*
806 * A potential indev allocation can be left alive, it stays
807 * assigned to its device and is destroy with it.
808 */
Thomas Graf5c753972006-08-04 23:03:53 -0700809 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700810
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800811 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100812 neigh_parms_data_state_setall(in_dev->arp_parms);
Thomas Graf5c753972006-08-04 23:03:53 -0700813 in_dev_hold(in_dev);
814
Ian Morris51456b22015-04-03 09:17:26 +0100815 if (!tb[IFA_ADDRESS])
Thomas Graf5c753972006-08-04 23:03:53 -0700816 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
817
David S. Millerfd23c3b2011-02-18 12:42:28 -0800818 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
820 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100821 ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
822 ifm->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700824 ifa->ifa_dev = in_dev;
825
Jiri Benc67b61f62015-03-29 16:59:26 +0200826 ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]);
827 ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700828
829 if (tb[IFA_BROADCAST])
Jiri Benc67b61f62015-03-29 16:59:26 +0200830 ifa->ifa_broadcast = nla_get_in_addr(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700831
Thomas Graf5c753972006-08-04 23:03:53 -0700832 if (tb[IFA_LABEL])
833 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 else
835 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
836
Jiri Pirko5c766d62013-01-24 09:41:41 +0000837 if (tb[IFA_CACHEINFO]) {
838 struct ifa_cacheinfo *ci;
839
840 ci = nla_data(tb[IFA_CACHEINFO]);
841 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
842 err = -EINVAL;
Daniel Borkmann446266b2013-08-02 11:32:43 +0200843 goto errout_free;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000844 }
845 *pvalid_lft = ci->ifa_valid;
846 *pprefered_lft = ci->ifa_prefered;
847 }
848
Thomas Graf5c753972006-08-04 23:03:53 -0700849 return ifa;
850
Daniel Borkmann446266b2013-08-02 11:32:43 +0200851errout_free:
852 inet_free_ifa(ifa);
Thomas Graf5c753972006-08-04 23:03:53 -0700853errout:
854 return ERR_PTR(err);
855}
856
Jiri Pirko5c766d62013-01-24 09:41:41 +0000857static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
858{
859 struct in_device *in_dev = ifa->ifa_dev;
860 struct in_ifaddr *ifa1, **ifap;
861
862 if (!ifa->ifa_local)
863 return NULL;
864
865 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
866 ifap = &ifa1->ifa_next) {
867 if (ifa1->ifa_mask == ifa->ifa_mask &&
868 inet_ifa_match(ifa1->ifa_address, ifa) &&
869 ifa1->ifa_local == ifa->ifa_local)
870 return ifa1;
871 }
872 return NULL;
873}
874
David Ahernc21ef3e2017-04-16 09:48:24 -0700875static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
876 struct netlink_ext_ack *extack)
Thomas Graf5c753972006-08-04 23:03:53 -0700877{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900878 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700879 struct in_ifaddr *ifa;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000880 struct in_ifaddr *ifa_existing;
881 __u32 valid_lft = INFINITY_LIFE_TIME;
882 __u32 prefered_lft = INFINITY_LIFE_TIME;
Thomas Graf5c753972006-08-04 23:03:53 -0700883
884 ASSERT_RTNL();
885
Jiri Pirko5c766d62013-01-24 09:41:41 +0000886 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft);
Thomas Graf5c753972006-08-04 23:03:53 -0700887 if (IS_ERR(ifa))
888 return PTR_ERR(ifa);
889
Jiri Pirko5c766d62013-01-24 09:41:41 +0000890 ifa_existing = find_matching_ifa(ifa);
891 if (!ifa_existing) {
892 /* It would be best to check for !NLM_F_CREATE here but
stephen hemminger614d0562014-05-16 20:46:58 -0700893 * userspace already relies on not having to provide this.
Jiri Pirko5c766d62013-01-24 09:41:41 +0000894 */
895 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Madhu Challa93a714d2015-02-25 09:58:35 -0800896 if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
897 int ret = ip_mc_config(net->ipv4.mc_autojoin_sk,
898 true, ifa);
899
900 if (ret < 0) {
901 inet_free_ifa(ifa);
902 return ret;
903 }
904 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000905 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
906 } else {
907 inet_free_ifa(ifa);
908
909 if (nlh->nlmsg_flags & NLM_F_EXCL ||
910 !(nlh->nlmsg_flags & NLM_F_REPLACE))
911 return -EEXIST;
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000912 ifa = ifa_existing;
913 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Jiri Pirko05a324b2013-04-04 23:39:38 +0000914 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530915 queue_delayed_work(system_power_efficient_wq,
916 &check_lifetime_work, 0);
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000917 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000918 }
919 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920}
921
922/*
923 * Determine a default network mask, based on the IP address.
924 */
925
Eric Dumazet40384992012-08-03 21:06:50 +0000926static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927{
928 int rc = -1; /* Something else, probably a multicast. */
929
Joe Perchesf97c1e02007-12-16 13:45:43 -0800930 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900931 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 else {
Al Viro714e85b2006-11-14 20:51:49 -0800933 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
Al Viro714e85b2006-11-14 20:51:49 -0800935 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800937 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800939 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 rc = 24;
941 }
942
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900943 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944}
945
946
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800947int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948{
949 struct ifreq ifr;
950 struct sockaddr_in sin_orig;
951 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
952 struct in_device *in_dev;
953 struct in_ifaddr **ifap = NULL;
954 struct in_ifaddr *ifa = NULL;
955 struct net_device *dev;
956 char *colon;
957 int ret = -EFAULT;
958 int tryaddrmatch = 0;
959
960 /*
961 * Fetch the caller's info block into kernel space
962 */
963
964 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
965 goto out;
966 ifr.ifr_name[IFNAMSIZ - 1] = 0;
967
968 /* save original address for comparison */
969 memcpy(&sin_orig, sin, sizeof(*sin));
970
971 colon = strchr(ifr.ifr_name, ':');
972 if (colon)
973 *colon = 0;
974
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800975 dev_load(net, ifr.ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Stephen Hemminger132adf52007-03-08 20:44:43 -0800977 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 case SIOCGIFADDR: /* Get interface address */
979 case SIOCGIFBRDADDR: /* Get the broadcast address */
980 case SIOCGIFDSTADDR: /* Get the destination address */
981 case SIOCGIFNETMASK: /* Get the netmask for the interface */
982 /* Note that these ioctls will not sleep,
983 so that we do not impose a lock.
984 One day we will be forced to put shlock here (I mean SMP)
985 */
986 tryaddrmatch = (sin_orig.sin_family == AF_INET);
987 memset(sin, 0, sizeof(*sin));
988 sin->sin_family = AF_INET;
989 break;
990
991 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000992 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000993 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 goto out;
995 break;
996 case SIOCSIFADDR: /* Set interface address (and family) */
997 case SIOCSIFBRDADDR: /* Set the broadcast address */
998 case SIOCSIFDSTADDR: /* Set the destination address */
999 case SIOCSIFNETMASK: /* Set the netmask for the interface */
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 ret = -EINVAL;
1004 if (sin->sin_family != AF_INET)
1005 goto out;
1006 break;
1007 default:
1008 ret = -EINVAL;
1009 goto out;
1010 }
1011
1012 rtnl_lock();
1013
1014 ret = -ENODEV;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001015 dev = __dev_get_by_name(net, ifr.ifr_name);
1016 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 goto done;
1018
1019 if (colon)
1020 *colon = ':';
1021
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001022 in_dev = __in_dev_get_rtnl(dev);
1023 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 if (tryaddrmatch) {
1025 /* Matthias Andree */
1026 /* compare label and address (4.4BSD style) */
1027 /* note: we only do this for a limited set of ioctls
1028 and only if the original address family was AF_INET.
1029 This is checked above. */
1030 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1031 ifap = &ifa->ifa_next) {
1032 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
1033 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -08001034 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 break; /* found */
1036 }
1037 }
1038 }
1039 /* we didn't get a match, maybe the application is
1040 4.3BSD-style and passed in junk so we fall back to
1041 comparing just the label */
1042 if (!ifa) {
1043 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1044 ifap = &ifa->ifa_next)
1045 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
1046 break;
1047 }
1048 }
1049
1050 ret = -EADDRNOTAVAIL;
1051 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
1052 goto done;
1053
Stephen Hemminger132adf52007-03-08 20:44:43 -08001054 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 case SIOCGIFADDR: /* Get interface address */
1056 sin->sin_addr.s_addr = ifa->ifa_local;
1057 goto rarok;
1058
1059 case SIOCGIFBRDADDR: /* Get the broadcast address */
1060 sin->sin_addr.s_addr = ifa->ifa_broadcast;
1061 goto rarok;
1062
1063 case SIOCGIFDSTADDR: /* Get the destination address */
1064 sin->sin_addr.s_addr = ifa->ifa_address;
1065 goto rarok;
1066
1067 case SIOCGIFNETMASK: /* Get the netmask for the interface */
1068 sin->sin_addr.s_addr = ifa->ifa_mask;
1069 goto rarok;
1070
1071 case SIOCSIFFLAGS:
1072 if (colon) {
1073 ret = -EADDRNOTAVAIL;
1074 if (!ifa)
1075 break;
1076 ret = 0;
1077 if (!(ifr.ifr_flags & IFF_UP))
1078 inet_del_ifa(in_dev, ifap, 1);
1079 break;
1080 }
1081 ret = dev_change_flags(dev, ifr.ifr_flags);
1082 break;
1083
1084 case SIOCSIFADDR: /* Set interface address (and family) */
1085 ret = -EINVAL;
1086 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1087 break;
1088
1089 if (!ifa) {
1090 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001091 ifa = inet_alloc_ifa();
1092 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 break;
Xi Wangc7e2e1d2013-01-05 11:19:24 +00001094 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 if (colon)
1096 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
1097 else
1098 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1099 } else {
1100 ret = 0;
1101 if (ifa->ifa_local == sin->sin_addr.s_addr)
1102 break;
1103 inet_del_ifa(in_dev, ifap, 0);
1104 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -08001105 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 }
1107
1108 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
1109
1110 if (!(dev->flags & IFF_POINTOPOINT)) {
1111 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
1112 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
1113 if ((dev->flags & IFF_BROADCAST) &&
1114 ifa->ifa_prefixlen < 31)
1115 ifa->ifa_broadcast = ifa->ifa_address |
1116 ~ifa->ifa_mask;
1117 } else {
1118 ifa->ifa_prefixlen = 32;
1119 ifa->ifa_mask = inet_make_mask(32);
1120 }
Jiri Pirko5c766d62013-01-24 09:41:41 +00001121 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 ret = inet_set_ifa(dev, ifa);
1123 break;
1124
1125 case SIOCSIFBRDADDR: /* Set the broadcast address */
1126 ret = 0;
1127 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
1128 inet_del_ifa(in_dev, ifap, 0);
1129 ifa->ifa_broadcast = sin->sin_addr.s_addr;
1130 inet_insert_ifa(ifa);
1131 }
1132 break;
1133
1134 case SIOCSIFDSTADDR: /* Set the destination address */
1135 ret = 0;
1136 if (ifa->ifa_address == sin->sin_addr.s_addr)
1137 break;
1138 ret = -EINVAL;
1139 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1140 break;
1141 ret = 0;
1142 inet_del_ifa(in_dev, ifap, 0);
1143 ifa->ifa_address = sin->sin_addr.s_addr;
1144 inet_insert_ifa(ifa);
1145 break;
1146
1147 case SIOCSIFNETMASK: /* Set the netmask for the interface */
1148
1149 /*
1150 * The mask we set must be legal.
1151 */
1152 ret = -EINVAL;
1153 if (bad_mask(sin->sin_addr.s_addr, 0))
1154 break;
1155 ret = 0;
1156 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -07001157 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 inet_del_ifa(in_dev, ifap, 0);
1159 ifa->ifa_mask = sin->sin_addr.s_addr;
1160 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
1161
1162 /* See if current broadcast address matches
1163 * with current netmask, then recalculate
1164 * the broadcast address. Otherwise it's a
1165 * funny address, so don't touch it since
1166 * the user seems to know what (s)he's doing...
1167 */
1168 if ((dev->flags & IFF_BROADCAST) &&
1169 (ifa->ifa_prefixlen < 31) &&
1170 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -05001171 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 ifa->ifa_broadcast = (ifa->ifa_local |
1173 ~sin->sin_addr.s_addr);
1174 }
1175 inet_insert_ifa(ifa);
1176 }
1177 break;
1178 }
1179done:
1180 rtnl_unlock();
1181out:
1182 return ret;
1183rarok:
1184 rtnl_unlock();
1185 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
1186 goto out;
1187}
1188
1189static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
1190{
Herbert Xue5ed6392005-10-03 14:35:55 -07001191 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 struct in_ifaddr *ifa;
1193 struct ifreq ifr;
1194 int done = 0;
1195
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001196 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 goto out;
1198
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001199 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 if (!buf) {
1201 done += sizeof(ifr);
1202 continue;
1203 }
1204 if (len < (int) sizeof(ifr))
1205 break;
1206 memset(&ifr, 0, sizeof(struct ifreq));
Dan Carpenter4299c8a2013-07-29 22:15:19 +03001207 strcpy(ifr.ifr_name, ifa->ifa_label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
1209 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
1210 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1211 ifa->ifa_local;
1212
1213 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
1214 done = -EFAULT;
1215 break;
1216 }
1217 buf += sizeof(struct ifreq);
1218 len -= sizeof(struct ifreq);
1219 done += sizeof(struct ifreq);
1220 }
1221out:
1222 return done;
1223}
1224
Gao Feng8b57fd12017-03-10 12:38:47 +08001225static __be32 in_dev_select_addr(const struct in_device *in_dev,
1226 int scope)
1227{
1228 for_primary_ifa(in_dev) {
1229 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1230 ifa->ifa_scope <= scope)
1231 return ifa->ifa_local;
1232 } endfor_ifa(in_dev);
1233
1234 return 0;
1235}
1236
Al Viroa61ced52006-09-26 21:27:54 -07001237__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238{
Al Viroa61ced52006-09-26 21:27:54 -07001239 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001241 struct net *net = dev_net(dev);
David Ahern3f2fb9a2016-02-24 11:47:02 -08001242 int master_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243
1244 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001245 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 if (!in_dev)
1247 goto no_in_dev;
1248
1249 for_primary_ifa(in_dev) {
1250 if (ifa->ifa_scope > scope)
1251 continue;
1252 if (!dst || inet_ifa_match(dst, ifa)) {
1253 addr = ifa->ifa_local;
1254 break;
1255 }
1256 if (!addr)
1257 addr = ifa->ifa_local;
1258 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259
1260 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001261 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001262no_in_dev:
David Ahern3f2fb9a2016-02-24 11:47:02 -08001263 master_idx = l3mdev_master_ifindex_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
David Lamparter17b693c2016-02-24 11:47:03 -08001265 /* For VRFs, the VRF device takes the place of the loopback device,
1266 * with addresses on it being preferred. Note in such cases the
1267 * loopback device will be among the devices that fail the master_idx
1268 * equality check in the loop below.
1269 */
1270 if (master_idx &&
1271 (dev = dev_get_by_index_rcu(net, master_idx)) &&
1272 (in_dev = __in_dev_get_rcu(dev))) {
Gao Feng8b57fd12017-03-10 12:38:47 +08001273 addr = in_dev_select_addr(in_dev, scope);
1274 if (addr)
1275 goto out_unlock;
David Lamparter17b693c2016-02-24 11:47:03 -08001276 }
1277
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 /* Not loopback addresses on loopback should be preferred
Stephen Hemmingerca9f1fd2015-02-14 13:47:54 -05001279 in this case. It is important that lo is the first interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 in dev_base list.
1281 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001282 for_each_netdev_rcu(net, dev) {
David Ahern3f2fb9a2016-02-24 11:47:02 -08001283 if (l3mdev_master_ifindex_rcu(dev) != master_idx)
1284 continue;
1285
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001286 in_dev = __in_dev_get_rcu(dev);
1287 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 continue;
1289
Gao Feng8b57fd12017-03-10 12:38:47 +08001290 addr = in_dev_select_addr(in_dev, scope);
1291 if (addr)
1292 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001294out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 return addr;
1297}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001298EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
Al Viro60cad5d2006-09-26 22:17:09 -07001300static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1301 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302{
1303 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001304 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305
1306 for_ifa(in_dev) {
1307 if (!addr &&
1308 (local == ifa->ifa_local || !local) &&
1309 ifa->ifa_scope <= scope) {
1310 addr = ifa->ifa_local;
1311 if (same)
1312 break;
1313 }
1314 if (!same) {
1315 same = (!local || inet_ifa_match(local, ifa)) &&
1316 (!dst || inet_ifa_match(dst, ifa));
1317 if (same && addr) {
1318 if (local || !dst)
1319 break;
1320 /* Is the selected addr into dst subnet? */
1321 if (inet_ifa_match(addr, ifa))
1322 break;
1323 /* No, then can we use new local src? */
1324 if (ifa->ifa_scope <= scope) {
1325 addr = ifa->ifa_local;
1326 break;
1327 }
1328 /* search for large dst subnet for addr */
1329 same = 0;
1330 }
1331 }
1332 } endfor_ifa(in_dev);
1333
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001334 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335}
1336
1337/*
1338 * Confirm that local IP address exists using wildcards:
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001339 * - net: netns to check, cannot be NULL
1340 * - in_dev: only on this interface, NULL=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 * - dst: only in the same subnet as dst, 0=any dst
1342 * - local: address, 0=autoselect the local address
1343 * - scope: maximum allowed scope value for the local address
1344 */
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001345__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001346 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347{
Al Viro60cad5d2006-09-26 22:17:09 -07001348 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001349 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
Ian Morris00db4122015-04-03 09:17:27 +01001351 if (in_dev)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001352 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001355 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001356 in_dev = __in_dev_get_rcu(dev);
1357 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 addr = confirm_addr_indev(in_dev, dst, local, scope);
1359 if (addr)
1360 break;
1361 }
1362 }
1363 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364
1365 return addr;
1366}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001367EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
1369/*
1370 * Device notifier
1371 */
1372
1373int register_inetaddr_notifier(struct notifier_block *nb)
1374{
Alan Sterne041c682006-03-27 01:16:30 -08001375 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001377EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
1379int unregister_inetaddr_notifier(struct notifier_block *nb)
1380{
Alan Sterne041c682006-03-27 01:16:30 -08001381 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001383EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384
Krister Johansen3ad7d242017-06-08 13:12:14 -07001385int register_inetaddr_validator_notifier(struct notifier_block *nb)
1386{
1387 return blocking_notifier_chain_register(&inetaddr_validator_chain, nb);
1388}
1389EXPORT_SYMBOL(register_inetaddr_validator_notifier);
1390
1391int unregister_inetaddr_validator_notifier(struct notifier_block *nb)
1392{
1393 return blocking_notifier_chain_unregister(&inetaddr_validator_chain,
1394 nb);
1395}
1396EXPORT_SYMBOL(unregister_inetaddr_validator_notifier);
1397
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001398/* Rename ifa_labels for a device name change. Make some effort to preserve
1399 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400*/
1401static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001402{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 struct in_ifaddr *ifa;
1404 int named = 0;
1405
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001406 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1407 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408
1409 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001410 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001412 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001413 dot = strchr(old, ':');
Ian Morris51456b22015-04-03 09:17:26 +01001414 if (!dot) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001415 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 dot = old;
1417 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001418 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001419 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001420 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001421 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001422skip:
1423 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001424 }
1425}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426
Eric Dumazet40384992012-08-03 21:06:50 +00001427static bool inetdev_valid_mtu(unsigned int mtu)
Breno Leitao06770842008-09-02 17:28:58 -07001428{
1429 return mtu >= 68;
1430}
1431
Ian Campbelld11327ad2011-02-11 07:44:16 +00001432static void inetdev_send_gratuitous_arp(struct net_device *dev,
1433 struct in_device *in_dev)
1434
1435{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001436 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001437
Zoltan Kissb76d0782011-07-24 13:09:30 +00001438 for (ifa = in_dev->ifa_list; ifa;
1439 ifa = ifa->ifa_next) {
1440 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1441 ifa->ifa_local, dev,
1442 ifa->ifa_local, NULL,
1443 dev->dev_addr, NULL);
1444 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001445}
1446
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447/* Called only under RTNL semaphore */
1448
1449static int inetdev_event(struct notifier_block *this, unsigned long event,
1450 void *ptr)
1451{
Jiri Pirko351638e2013-05-28 01:30:21 +00001452 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazet748e2d92012-08-22 21:50:59 +00001453 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454
1455 ASSERT_RTNL();
1456
1457 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001458 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 in_dev = inetdev_init(dev);
WANG Cong20e61da2014-07-25 15:25:08 -07001460 if (IS_ERR(in_dev))
1461 return notifier_from_errno(PTR_ERR(in_dev));
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001462 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001463 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1464 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001465 }
Breno Leitao06770842008-09-02 17:28:58 -07001466 } else if (event == NETDEV_CHANGEMTU) {
1467 /* Re-enabling IP */
1468 if (inetdev_valid_mtu(dev->mtu))
1469 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 }
1471 goto out;
1472 }
1473
1474 switch (event) {
1475 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001476 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001477 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 break;
1479 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001480 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001482 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001483 struct in_ifaddr *ifa = inet_alloc_ifa();
1484
1485 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001486 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 ifa->ifa_local =
1488 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1489 ifa->ifa_prefixlen = 8;
1490 ifa->ifa_mask = inet_make_mask(8);
1491 in_dev_hold(in_dev);
1492 ifa->ifa_dev = in_dev;
1493 ifa->ifa_scope = RT_SCOPE_HOST;
1494 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Jiri Pirko5c766d62013-01-24 09:41:41 +00001495 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1496 INFINITY_LIFE_TIME);
Jiri Pirkodfd15822014-01-07 15:55:45 +01001497 ipv4_devconf_setall(in_dev);
1498 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 inet_insert_ifa(ifa);
1500 }
1501 }
1502 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001503 /* fall through */
1504 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001505 if (!IN_DEV_ARP_NOTIFY(in_dev))
1506 break;
1507 /* fall through */
1508 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001509 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001510 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 break;
1512 case NETDEV_DOWN:
1513 ip_mc_down(in_dev);
1514 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001515 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001516 ip_mc_unmap(in_dev);
1517 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001518 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001519 ip_mc_remap(in_dev);
1520 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001522 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 break;
Breno Leitao06770842008-09-02 17:28:58 -07001524 /* disable IP when MTU is not enough */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 case NETDEV_UNREGISTER:
1526 inetdev_destroy(in_dev);
1527 break;
1528 case NETDEV_CHANGENAME:
1529 /* Do not notify about label change, this event is
1530 * not interesting to applications using netlink.
1531 */
1532 inetdev_changename(dev, in_dev);
1533
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001534 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001535 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 break;
1537 }
1538out:
1539 return NOTIFY_DONE;
1540}
1541
1542static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001543 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544};
1545
Eric Dumazet40384992012-08-03 21:06:50 +00001546static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001547{
1548 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1549 + nla_total_size(4) /* IFA_ADDRESS */
1550 + nla_total_size(4) /* IFA_LOCAL */
1551 + nla_total_size(4) /* IFA_BROADCAST */
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001552 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001553 + nla_total_size(4) /* IFA_FLAGS */
1554 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
Thomas Graf339bf982006-11-10 14:10:15 -08001555}
1556
Jiri Pirko5c766d62013-01-24 09:41:41 +00001557static inline u32 cstamp_delta(unsigned long cstamp)
1558{
1559 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1560}
1561
1562static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1563 unsigned long tstamp, u32 preferred, u32 valid)
1564{
1565 struct ifa_cacheinfo ci;
1566
1567 ci.cstamp = cstamp_delta(cstamp);
1568 ci.tstamp = cstamp_delta(tstamp);
1569 ci.ifa_prefered = preferred;
1570 ci.ifa_valid = valid;
1571
1572 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1573}
1574
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001576 u32 portid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577{
1578 struct ifaddrmsg *ifm;
1579 struct nlmsghdr *nlh;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001580 u32 preferred, valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
Eric W. Biederman15e47302012-09-07 20:12:54 +00001582 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
Ian Morris51456b22015-04-03 09:17:26 +01001583 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08001584 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001585
1586 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 ifm->ifa_family = AF_INET;
1588 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001589 ifm->ifa_flags = ifa->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 ifm->ifa_scope = ifa->ifa_scope;
1591 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
Jiri Pirko5c766d62013-01-24 09:41:41 +00001593 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1594 preferred = ifa->ifa_preferred_lft;
1595 valid = ifa->ifa_valid_lft;
1596 if (preferred != INFINITY_LIFE_TIME) {
1597 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1598
1599 if (preferred > tval)
1600 preferred -= tval;
1601 else
1602 preferred = 0;
1603 if (valid != INFINITY_LIFE_TIME) {
1604 if (valid > tval)
1605 valid -= tval;
1606 else
1607 valid = 0;
1608 }
1609 }
1610 } else {
1611 preferred = INFINITY_LIFE_TIME;
1612 valid = INFINITY_LIFE_TIME;
1613 }
David S. Millerf3756b72012-04-01 20:39:02 -04001614 if ((ifa->ifa_address &&
Jiri Benc930345e2015-03-29 16:59:25 +02001615 nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001616 (ifa->ifa_local &&
Jiri Benc930345e2015-03-29 16:59:25 +02001617 nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001618 (ifa->ifa_broadcast &&
Jiri Benc930345e2015-03-29 16:59:25 +02001619 nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001620 (ifa->ifa_label[0] &&
Jiri Pirko5c766d62013-01-24 09:41:41 +00001621 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001622 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
Jiri Pirko5c766d62013-01-24 09:41:41 +00001623 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1624 preferred, valid))
David S. Millerf3756b72012-04-01 20:39:02 -04001625 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001626
Johannes Berg053c0952015-01-16 22:09:00 +01001627 nlmsg_end(skb, nlh);
1628 return 0;
Thomas Graf47f68512006-08-04 23:04:36 -07001629
1630nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001631 nlmsg_cancel(skb, nlh);
1632 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633}
1634
1635static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1636{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001637 struct net *net = sock_net(skb->sk);
Eric Dumazeteec4df92009-11-12 07:44:25 +00001638 int h, s_h;
1639 int idx, s_idx;
1640 int ip_idx, s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 struct net_device *dev;
1642 struct in_device *in_dev;
1643 struct in_ifaddr *ifa;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001644 struct hlist_head *head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
Eric Dumazeteec4df92009-11-12 07:44:25 +00001646 s_h = cb->args[0];
1647 s_idx = idx = cb->args[1];
1648 s_ip_idx = ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649
Eric Dumazeteec4df92009-11-12 07:44:25 +00001650 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1651 idx = 0;
1652 head = &net->dev_index_head[h];
1653 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001654 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1655 net->dev_base_seq;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001656 hlist_for_each_entry_rcu(dev, head, index_hlist) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001657 if (idx < s_idx)
1658 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001659 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001660 s_ip_idx = 0;
1661 in_dev = __in_dev_get_rcu(dev);
1662 if (!in_dev)
1663 goto cont;
1664
1665 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1666 ifa = ifa->ifa_next, ip_idx++) {
1667 if (ip_idx < s_ip_idx)
1668 continue;
1669 if (inet_fill_ifaddr(skb, ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001670 NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 cb->nlh->nlmsg_seq,
Johannes Berg053c0952015-01-16 22:09:00 +01001672 RTM_NEWADDR, NLM_F_MULTI) < 0) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001673 rcu_read_unlock();
1674 goto done;
1675 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001676 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Eric Dumazeteec4df92009-11-12 07:44:25 +00001677 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001678cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001679 idx++;
1680 }
1681 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 }
1683
1684done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001685 cb->args[0] = h;
1686 cb->args[1] = idx;
1687 cb->args[2] = ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688
1689 return skb->len;
1690}
1691
Jianjun Kong539afed2008-11-03 02:48:48 -08001692static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001693 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694{
Thomas Graf47f68512006-08-04 23:04:36 -07001695 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001696 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1697 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001698 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001700 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001701 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001702 if (!skb)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001703 goto errout;
1704
Eric W. Biederman15e47302012-09-07 20:12:54 +00001705 err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001706 if (err < 0) {
1707 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1708 WARN_ON(err == -EMSGSIZE);
1709 kfree_skb(skb);
1710 goto errout;
1711 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001712 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001713 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001714errout:
1715 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001716 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717}
1718
Arad, Ronenb1974ed2015-10-19 09:23:28 -07001719static size_t inet_get_link_af_size(const struct net_device *dev,
1720 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001721{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001722 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001723
1724 if (!in_dev)
1725 return 0;
1726
1727 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1728}
1729
Sowmini Varadhand5566fd2015-09-11 16:48:48 -04001730static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
1731 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001732{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001733 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001734 struct nlattr *nla;
1735 int i;
1736
1737 if (!in_dev)
1738 return -ENODATA;
1739
1740 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
Ian Morris51456b22015-04-03 09:17:26 +01001741 if (!nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001742 return -EMSGSIZE;
1743
1744 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1745 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1746
1747 return 0;
1748}
1749
1750static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1751 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1752};
1753
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001754static int inet_validate_link_af(const struct net_device *dev,
1755 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001756{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001757 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1758 int err, rem;
1759
Eric Dumazetf7fce742010-12-01 06:03:06 +00001760 if (dev && !__in_dev_get_rtnl(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001761 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001762
Johannes Bergfceb6432017-04-12 14:34:07 +02001763 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy, NULL);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001764 if (err < 0)
1765 return err;
1766
1767 if (tb[IFLA_INET_CONF]) {
1768 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1769 int cfgid = nla_type(a);
1770
1771 if (nla_len(a) < 4)
1772 return -EINVAL;
1773
1774 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1775 return -EINVAL;
1776 }
1777 }
1778
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001779 return 0;
1780}
1781
1782static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1783{
Eric Dumazetf7fce742010-12-01 06:03:06 +00001784 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001785 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1786 int rem;
1787
1788 if (!in_dev)
1789 return -EAFNOSUPPORT;
1790
Johannes Bergfceb6432017-04-12 14:34:07 +02001791 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0)
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001792 BUG();
1793
Thomas Graf9f0f7272010-11-16 04:32:48 +00001794 if (tb[IFLA_INET_CONF]) {
1795 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1796 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1797 }
1798
1799 return 0;
1800}
1801
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001802static int inet_netconf_msgsize_devconf(int type)
1803{
1804 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1805 + nla_total_size(4); /* NETCONFA_IFINDEX */
Zhang Shengju136ba622016-03-10 08:55:50 +00001806 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001807
Zhang Shengju136ba622016-03-10 08:55:50 +00001808 if (type == NETCONFA_ALL)
1809 all = true;
1810
1811 if (all || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001812 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001813 if (all || type == NETCONFA_RP_FILTER)
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001814 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001815 if (all || type == NETCONFA_MC_FORWARDING)
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001816 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001817 if (all || type == NETCONFA_PROXY_NEIGH)
stephen hemmingerf085ff12013-12-12 13:06:50 -08001818 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001819 if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001820 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001821
1822 return size;
1823}
1824
1825static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1826 struct ipv4_devconf *devconf, u32 portid,
1827 u32 seq, int event, unsigned int flags,
1828 int type)
1829{
1830 struct nlmsghdr *nlh;
1831 struct netconfmsg *ncm;
Zhang Shengju136ba622016-03-10 08:55:50 +00001832 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001833
1834 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1835 flags);
Ian Morris51456b22015-04-03 09:17:26 +01001836 if (!nlh)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001837 return -EMSGSIZE;
1838
Zhang Shengju136ba622016-03-10 08:55:50 +00001839 if (type == NETCONFA_ALL)
1840 all = true;
1841
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001842 ncm = nlmsg_data(nlh);
1843 ncm->ncm_family = AF_INET;
1844
1845 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1846 goto nla_put_failure;
1847
David Ahernb5c96412017-03-28 14:28:03 -07001848 if (!devconf)
1849 goto out;
1850
Zhang Shengju136ba622016-03-10 08:55:50 +00001851 if ((all || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001852 nla_put_s32(skb, NETCONFA_FORWARDING,
1853 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1854 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001855 if ((all || type == NETCONFA_RP_FILTER) &&
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001856 nla_put_s32(skb, NETCONFA_RP_FILTER,
1857 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
1858 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001859 if ((all || type == NETCONFA_MC_FORWARDING) &&
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001860 nla_put_s32(skb, NETCONFA_MC_FORWARDING,
1861 IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
1862 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001863 if ((all || type == NETCONFA_PROXY_NEIGH) &&
stephen hemminger09aea5d2013-12-17 22:35:52 -08001864 nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08001865 IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
1866 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001867 if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001868 nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
1869 IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
1870 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001871
David Ahernb5c96412017-03-28 14:28:03 -07001872out:
Johannes Berg053c0952015-01-16 22:09:00 +01001873 nlmsg_end(skb, nlh);
1874 return 0;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001875
1876nla_put_failure:
1877 nlmsg_cancel(skb, nlh);
1878 return -EMSGSIZE;
1879}
1880
David Ahern3b022862017-03-28 14:28:02 -07001881void inet_netconf_notify_devconf(struct net *net, int event, int type,
1882 int ifindex, struct ipv4_devconf *devconf)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001883{
1884 struct sk_buff *skb;
1885 int err = -ENOBUFS;
1886
Eric Dumazetfa178062016-07-08 05:18:24 +02001887 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001888 if (!skb)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001889 goto errout;
1890
1891 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
David Ahern3b022862017-03-28 14:28:02 -07001892 event, 0, type);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001893 if (err < 0) {
1894 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1895 WARN_ON(err == -EMSGSIZE);
1896 kfree_skb(skb);
1897 goto errout;
1898 }
Eric Dumazetfa178062016-07-08 05:18:24 +02001899 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001900 return;
1901errout:
1902 if (err < 0)
1903 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
1904}
1905
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001906static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
1907 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
1908 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001909 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
stephen hemminger09aea5d2013-12-17 22:35:52 -08001910 [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) },
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001911 [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001912};
1913
1914static int inet_netconf_get_devconf(struct sk_buff *in_skb,
David Ahernc21ef3e2017-04-16 09:48:24 -07001915 struct nlmsghdr *nlh,
1916 struct netlink_ext_ack *extack)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001917{
1918 struct net *net = sock_net(in_skb->sk);
1919 struct nlattr *tb[NETCONFA_MAX+1];
1920 struct netconfmsg *ncm;
1921 struct sk_buff *skb;
1922 struct ipv4_devconf *devconf;
1923 struct in_device *in_dev;
1924 struct net_device *dev;
1925 int ifindex;
1926 int err;
1927
1928 err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
David Ahernc21ef3e2017-04-16 09:48:24 -07001929 devconf_ipv4_policy, extack);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001930 if (err < 0)
1931 goto errout;
1932
Anton Protopopova97eb332016-02-16 21:43:16 -05001933 err = -EINVAL;
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001934 if (!tb[NETCONFA_IFINDEX])
1935 goto errout;
1936
1937 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
1938 switch (ifindex) {
1939 case NETCONFA_IFINDEX_ALL:
1940 devconf = net->ipv4.devconf_all;
1941 break;
1942 case NETCONFA_IFINDEX_DEFAULT:
1943 devconf = net->ipv4.devconf_dflt;
1944 break;
1945 default:
1946 dev = __dev_get_by_index(net, ifindex);
Ian Morris51456b22015-04-03 09:17:26 +01001947 if (!dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001948 goto errout;
1949 in_dev = __in_dev_get_rtnl(dev);
Ian Morris51456b22015-04-03 09:17:26 +01001950 if (!in_dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001951 goto errout;
1952 devconf = &in_dev->cnf;
1953 break;
1954 }
1955
1956 err = -ENOBUFS;
Eric Dumazetfa178062016-07-08 05:18:24 +02001957 skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001958 if (!skb)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001959 goto errout;
1960
1961 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
1962 NETLINK_CB(in_skb).portid,
1963 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
Zhang Shengju136ba622016-03-10 08:55:50 +00001964 NETCONFA_ALL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001965 if (err < 0) {
1966 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1967 WARN_ON(err == -EMSGSIZE);
1968 kfree_skb(skb);
1969 goto errout;
1970 }
1971 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
1972errout:
1973 return err;
1974}
1975
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001976static int inet_netconf_dump_devconf(struct sk_buff *skb,
1977 struct netlink_callback *cb)
1978{
1979 struct net *net = sock_net(skb->sk);
1980 int h, s_h;
1981 int idx, s_idx;
1982 struct net_device *dev;
1983 struct in_device *in_dev;
1984 struct hlist_head *head;
1985
1986 s_h = cb->args[0];
1987 s_idx = idx = cb->args[1];
1988
1989 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1990 idx = 0;
1991 head = &net->dev_index_head[h];
1992 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001993 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1994 net->dev_base_seq;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001995 hlist_for_each_entry_rcu(dev, head, index_hlist) {
1996 if (idx < s_idx)
1997 goto cont;
1998 in_dev = __in_dev_get_rcu(dev);
1999 if (!in_dev)
2000 goto cont;
2001
2002 if (inet_netconf_fill_devconf(skb, dev->ifindex,
2003 &in_dev->cnf,
2004 NETLINK_CB(cb->skb).portid,
2005 cb->nlh->nlmsg_seq,
2006 RTM_NEWNETCONF,
2007 NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002008 NETCONFA_ALL) < 0) {
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002009 rcu_read_unlock();
2010 goto done;
2011 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00002012 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002013cont:
2014 idx++;
2015 }
2016 rcu_read_unlock();
2017 }
2018 if (h == NETDEV_HASHENTRIES) {
2019 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
2020 net->ipv4.devconf_all,
2021 NETLINK_CB(cb->skb).portid,
2022 cb->nlh->nlmsg_seq,
2023 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002024 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002025 goto done;
2026 else
2027 h++;
2028 }
2029 if (h == NETDEV_HASHENTRIES + 1) {
2030 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
2031 net->ipv4.devconf_dflt,
2032 NETLINK_CB(cb->skb).portid,
2033 cb->nlh->nlmsg_seq,
2034 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002035 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002036 goto done;
2037 else
2038 h++;
2039 }
2040done:
2041 cb->args[0] = h;
2042 cb->args[1] = idx;
2043
2044 return skb->len;
2045}
2046
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047#ifdef CONFIG_SYSCTL
2048
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002049static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07002050{
2051 struct net_device *dev;
2052
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002053 rcu_read_lock();
2054 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07002055 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002056
Herbert Xu31be3082007-06-04 23:35:37 -07002057 in_dev = __in_dev_get_rcu(dev);
2058 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002059 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07002060 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002061 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07002062}
2063
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002064/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002065static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002066{
2067 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002068 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002069
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002070 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002071 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
David Ahern3b022862017-03-28 14:28:02 -07002072 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2073 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002074 NETCONFA_IFINDEX_ALL,
2075 net->ipv4.devconf_all);
David Ahern3b022862017-03-28 14:28:02 -07002076 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2077 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002078 NETCONFA_IFINDEX_DEFAULT,
2079 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002080
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002081 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002082 struct in_device *in_dev;
Eric Dumazetfa178062016-07-08 05:18:24 +02002083
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002084 if (on)
2085 dev_disable_lro(dev);
Eric Dumazetfa178062016-07-08 05:18:24 +02002086
2087 in_dev = __in_dev_get_rtnl(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002088 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002089 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
David Ahern3b022862017-03-28 14:28:02 -07002090 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2091 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002092 dev->ifindex, &in_dev->cnf);
2093 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002094 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002095}
2096
stephen hemmingerf085ff12013-12-12 13:06:50 -08002097static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf)
2098{
2099 if (cnf == net->ipv4.devconf_dflt)
2100 return NETCONFA_IFINDEX_DEFAULT;
2101 else if (cnf == net->ipv4.devconf_all)
2102 return NETCONFA_IFINDEX_ALL;
2103 else {
2104 struct in_device *idev
2105 = container_of(cnf, struct in_device, cnf);
2106 return idev->dev->ifindex;
2107 }
2108}
2109
Joe Perchesfe2c6332013-06-11 23:04:25 -07002110static int devinet_conf_proc(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002111 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07002112 size_t *lenp, loff_t *ppos)
2113{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002114 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002115 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002116 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07002117
2118 if (write) {
2119 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002120 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07002121 int i = (int *)ctl->data - cnf->data;
stephen hemmingerf085ff12013-12-12 13:06:50 -08002122 int ifindex;
Herbert Xu31be3082007-06-04 23:35:37 -07002123
2124 set_bit(i, cnf->state);
2125
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002126 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002127 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00002128 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
2129 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002130 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002131 rt_cache_flush(net);
stephen hemmingerf085ff12013-12-12 13:06:50 -08002132
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002133 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
2134 new_value != old_value) {
stephen hemmingerf085ff12013-12-12 13:06:50 -08002135 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002136 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2137 NETCONFA_RP_FILTER,
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002138 ifindex, cnf);
2139 }
stephen hemmingerf085ff12013-12-12 13:06:50 -08002140 if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
2141 new_value != old_value) {
2142 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002143 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2144 NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002145 ifindex, cnf);
2146 }
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002147 if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
2148 new_value != old_value) {
2149 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002150 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2151 NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002152 ifindex, cnf);
2153 }
Herbert Xu31be3082007-06-04 23:35:37 -07002154 }
2155
2156 return ret;
2157}
2158
Joe Perchesfe2c6332013-06-11 23:04:25 -07002159static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002160 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 size_t *lenp, loff_t *ppos)
2162{
2163 int *valp = ctl->data;
2164 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00002165 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002166 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167
2168 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002169 struct net *net = ctl->extra2;
2170
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002171 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00002172 if (!rtnl_trylock()) {
2173 /* Restore the original values before restarting */
2174 *valp = val;
2175 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00002176 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00002177 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002178 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2179 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002180 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002181 struct ipv4_devconf *cnf = ctl->extra1;
2182 struct in_device *idev =
2183 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002184 if (*valp)
2185 dev_disable_lro(idev->dev);
David Ahern3b022862017-03-28 14:28:02 -07002186 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002187 NETCONFA_FORWARDING,
2188 idev->dev->ifindex,
2189 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002190 }
2191 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002192 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002193 } else
David Ahern3b022862017-03-28 14:28:02 -07002194 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2195 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002196 NETCONFA_IFINDEX_DEFAULT,
2197 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 }
2199
2200 return ret;
2201}
2202
Joe Perchesfe2c6332013-06-11 23:04:25 -07002203static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
David S. Miller323e1262010-12-12 21:55:08 -08002204 void __user *buffer,
2205 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206{
2207 int *valp = ctl->data;
2208 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002209 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07002210 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211
2212 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002213 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214
2215 return ret;
2216}
2217
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002218#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07002219 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07002220 .procname = name, \
2221 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00002222 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002223 .maxlen = sizeof(int), \
2224 .mode = mval, \
2225 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07002226 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002227 }
2228
2229#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002230 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002231
2232#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002233 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002234
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002235#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2236 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002237
2238#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002239 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07002240
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241static struct devinet_sysctl_table {
2242 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00002243 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244} devinet_sysctl = {
2245 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07002246 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002247 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07002248 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
2249
2250 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
2251 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
2252 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
2253 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
2254 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
2255 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
2256 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00002257 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08002258 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002259 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
2260 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
2261 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
2262 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
2263 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
2264 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
2265 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
2266 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
2267 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08002268 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00002269 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
William Manley5c6fe012013-08-06 19:03:14 +01002270 DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
2271 "force_igmp_version"),
William Manley26900482013-08-06 19:03:15 +01002272 DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
2273 "igmpv2_unsolicited_report_interval"),
2274 DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
2275 "igmpv3_unsolicited_report_interval"),
Andy Gospodarek0eeb0752015-06-23 13:45:37 -04002276 DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
2277 "ignore_routes_with_linkdown"),
Johannes Berg97daf332016-02-04 13:31:18 +01002278 DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
2279 "drop_gratuitous_arp"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002280
2281 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2282 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002283 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
2284 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00002285 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2286 "route_localnet"),
Johannes Berg12b74df2016-02-04 13:31:17 +01002287 DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
2288 "drop_unicast_in_l2_multicast"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290};
2291
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002292static int __devinet_sysctl_register(struct net *net, char *dev_name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002293 int ifindex, struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294{
2295 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002296 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002297 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11002298
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002299 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002301 goto out;
2302
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
2304 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07002305 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002306 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 }
2308
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002309 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002311 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002313 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
2315 p->sysctl = t;
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002316
David Ahern3b022862017-03-28 14:28:02 -07002317 inet_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_ALL,
2318 ifindex, p);
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002319 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002321free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002323out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002324 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325}
2326
David Ahernb5c96412017-03-28 14:28:03 -07002327static void __devinet_sysctl_unregister(struct net *net,
2328 struct ipv4_devconf *cnf, int ifindex)
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002329{
2330 struct devinet_sysctl_table *t = cnf->sysctl;
2331
David Ahernb5c96412017-03-28 14:28:03 -07002332 if (t) {
2333 cnf->sysctl = NULL;
2334 unregister_net_sysctl_table(t->sysctl_header);
2335 kfree(t);
2336 }
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002337
David Ahernb5c96412017-03-28 14:28:03 -07002338 inet_netconf_notify_devconf(net, RTM_DELNETCONF, 0, ifindex, NULL);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002339}
2340
WANG Cong20e61da2014-07-25 15:25:08 -07002341static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002342{
WANG Cong20e61da2014-07-25 15:25:08 -07002343 int err;
2344
2345 if (!sysctl_dev_name_is_allowed(idev->dev->name))
2346 return -EINVAL;
2347
2348 err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
2349 if (err)
2350 return err;
2351 err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002352 idev->dev->ifindex, &idev->cnf);
WANG Cong20e61da2014-07-25 15:25:08 -07002353 if (err)
2354 neigh_sysctl_unregister(idev->arp_parms);
2355 return err;
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002356}
2357
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002358static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359{
David Ahernb5c96412017-03-28 14:28:03 -07002360 struct net *net = dev_net(idev->dev);
2361
2362 __devinet_sysctl_unregister(net, &idev->cnf, idev->dev->ifindex);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002363 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002366static struct ctl_table ctl_forward_entry[] = {
2367 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002368 .procname = "ip_forward",
2369 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00002370 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002371 .maxlen = sizeof(int),
2372 .mode = 0644,
2373 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002374 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002375 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002376 },
2377 { },
2378};
Eric Dumazet2a75de02008-01-05 23:08:49 -08002379#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002380
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002381static __net_init int devinet_init_net(struct net *net)
2382{
2383 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002384 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002385#ifdef CONFIG_SYSCTL
2386 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002387 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002388#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002389
2390 err = -ENOMEM;
2391 all = &ipv4_devconf;
2392 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002393
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002394 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002395 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002396 if (!all)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002397 goto err_alloc_all;
2398
2399 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002400 if (!dflt)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002401 goto err_alloc_dflt;
2402
Eric Dumazet2a75de02008-01-05 23:08:49 -08002403#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002404 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002405 if (!tbl)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002406 goto err_alloc_ctl;
2407
Eric W. Biederman02291682010-02-14 03:25:51 +00002408 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002409 tbl[0].extra1 = all;
2410 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002411#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002412 }
2413
2414#ifdef CONFIG_SYSCTL
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002415 err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002416 if (err < 0)
2417 goto err_reg_all;
2418
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002419 err = __devinet_sysctl_register(net, "default",
2420 NETCONFA_IFINDEX_DEFAULT, dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002421 if (err < 0)
2422 goto err_reg_dflt;
2423
2424 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002425 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Ian Morris51456b22015-04-03 09:17:26 +01002426 if (!forw_hdr)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002427 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002428 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002429#endif
2430
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002431 net->ipv4.devconf_all = all;
2432 net->ipv4.devconf_dflt = dflt;
2433 return 0;
2434
2435#ifdef CONFIG_SYSCTL
2436err_reg_ctl:
David Ahernb5c96412017-03-28 14:28:03 -07002437 __devinet_sysctl_unregister(net, dflt, NETCONFA_IFINDEX_DEFAULT);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002438err_reg_dflt:
David Ahernb5c96412017-03-28 14:28:03 -07002439 __devinet_sysctl_unregister(net, all, NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002440err_reg_all:
2441 if (tbl != ctl_forward_entry)
2442 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002443err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08002444#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002445 if (dflt != &ipv4_devconf_dflt)
2446 kfree(dflt);
2447err_alloc_dflt:
2448 if (all != &ipv4_devconf)
2449 kfree(all);
2450err_alloc_all:
2451 return err;
2452}
2453
2454static __net_exit void devinet_exit_net(struct net *net)
2455{
Eric Dumazet2a75de02008-01-05 23:08:49 -08002456#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002457 struct ctl_table *tbl;
2458
2459 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002460 unregister_net_sysctl_table(net->ipv4.forw_hdr);
David Ahernb5c96412017-03-28 14:28:03 -07002461 __devinet_sysctl_unregister(net, net->ipv4.devconf_dflt,
2462 NETCONFA_IFINDEX_DEFAULT);
2463 __devinet_sysctl_unregister(net, net->ipv4.devconf_all,
2464 NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002465 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08002466#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002467 kfree(net->ipv4.devconf_dflt);
2468 kfree(net->ipv4.devconf_all);
2469}
2470
2471static __net_initdata struct pernet_operations devinet_ops = {
2472 .init = devinet_init_net,
2473 .exit = devinet_exit_net,
2474};
2475
Daniel Borkmann207895f2015-01-29 12:15:03 +01002476static struct rtnl_af_ops inet_af_ops __read_mostly = {
Thomas Graf9f0f7272010-11-16 04:32:48 +00002477 .family = AF_INET,
2478 .fill_link_af = inet_fill_link_af,
2479 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00002480 .validate_link_af = inet_validate_link_af,
2481 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00002482};
2483
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484void __init devinet_init(void)
2485{
David S. Millerfd23c3b2011-02-18 12:42:28 -08002486 int i;
2487
2488 for (i = 0; i < IN4_ADDR_HSIZE; i++)
2489 INIT_HLIST_HEAD(&inet_addr_lst[i]);
2490
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002491 register_pernet_subsys(&devinet_ops);
2492
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 register_gifconf(PF_INET, inet_gifconf);
2494 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07002495
viresh kumar906e0732014-01-22 12:23:32 +05302496 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +00002497
Thomas Graf9f0f7272010-11-16 04:32:48 +00002498 rtnl_af_register(&inet_af_ops);
2499
Florian Westphalb97bac62017-08-09 20:41:48 +02002500 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, 0);
2501 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, 0);
2502 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, 0);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002503 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
Florian Westphalb97bac62017-08-09 20:41:48 +02002504 inet_netconf_dump_devconf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505}