blob: e056c0067f2cff22a89dd8f68cd4f0913529ad55 [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,
David Ahernde95e042017-10-18 09:56:54 -0700447 u32 portid, struct netlink_ext_ack *extack)
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;
David Ahernde95e042017-10-18 09:56:54 -0700492 ivi.extack = extack;
Krister Johansen3ad7d242017-06-08 13:12:14 -0700493 ret = blocking_notifier_call_chain(&inetaddr_validator_chain,
494 NETDEV_UP, &ivi);
495 ret = notifier_to_errno(ret);
496 if (ret) {
497 inet_free_ifa(ifa);
498 return ret;
499 }
500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500502 prandom_seed((__force u32) ifa->ifa_local);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 ifap = last_primary;
504 }
505
506 ifa->ifa_next = *ifap;
507 *ifap = ifa;
508
David S. Millerfd23c3b2011-02-18 12:42:28 -0800509 inet_hash_insert(dev_net(in_dev->dev), ifa);
510
Jiri Pirko5c766d62013-01-24 09:41:41 +0000511 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530512 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000513
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 /* Send message first, then call notifier.
515 Notifier will trigger FIB update, so that
516 listeners of netlink will know about new ifaddr */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000517 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800518 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
520 return 0;
521}
522
Thomas Grafd6062cb2006-08-15 00:33:59 -0700523static int inet_insert_ifa(struct in_ifaddr *ifa)
524{
David Ahernde95e042017-10-18 09:56:54 -0700525 return __inet_insert_ifa(ifa, NULL, 0, NULL);
Thomas Grafd6062cb2006-08-15 00:33:59 -0700526}
527
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
529{
Herbert Xue5ed6392005-10-03 14:35:55 -0700530 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
532 ASSERT_RTNL();
533
534 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700535 inet_free_ifa(ifa);
536 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700538 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100539 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700541 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 in_dev_hold(in_dev);
543 ifa->ifa_dev = in_dev;
544 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800545 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 ifa->ifa_scope = RT_SCOPE_HOST;
547 return inet_insert_ifa(ifa);
548}
549
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000550/* Caller must hold RCU or RTNL :
551 * We dont take a reference on found in_device
552 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800553struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554{
555 struct net_device *dev;
556 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000557
558 rcu_read_lock();
559 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000561 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000562 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 return in_dev;
564}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800565EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
567/* Called only from RTNL semaphored context. No locks. */
568
Al Viro60cad5d2006-09-26 22:17:09 -0700569struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
570 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571{
572 ASSERT_RTNL();
573
574 for_primary_ifa(in_dev) {
575 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
576 return ifa;
577 } endfor_ifa(in_dev);
578 return NULL;
579}
580
Madhu Challa93a714d2015-02-25 09:58:35 -0800581static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa)
582{
583 struct ip_mreqn mreq = {
584 .imr_multiaddr.s_addr = ifa->ifa_address,
585 .imr_ifindex = ifa->ifa_dev->dev->ifindex,
586 };
587 int ret;
588
589 ASSERT_RTNL();
590
591 lock_sock(sk);
592 if (join)
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300593 ret = ip_mc_join_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800594 else
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300595 ret = ip_mc_leave_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800596 release_sock(sk);
597
598 return ret;
599}
600
David Ahernc21ef3e2017-04-16 09:48:24 -0700601static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
602 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900604 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700605 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700607 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700609 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610
611 ASSERT_RTNL();
612
Johannes Bergfceb6432017-04-12 14:34:07 +0200613 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -0700614 extack);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700615 if (err < 0)
616 goto errout;
617
618 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800619 in_dev = inetdev_by_index(net, ifm->ifa_index);
Ian Morris51456b22015-04-03 09:17:26 +0100620 if (!in_dev) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700621 err = -ENODEV;
622 goto errout;
623 }
624
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
626 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700627 if (tb[IFA_LOCAL] &&
Jiri Benc67b61f62015-03-29 16:59:26 +0200628 ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700630
631 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
632 continue;
633
634 if (tb[IFA_ADDRESS] &&
635 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Jiri Benc67b61f62015-03-29 16:59:26 +0200636 !inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700637 continue;
638
Madhu Challa93a714d2015-02-25 09:58:35 -0800639 if (ipv4_is_multicast(ifa->ifa_address))
640 ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000641 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 return 0;
643 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700644
645 err = -EADDRNOTAVAIL;
646errout:
647 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648}
649
Jiri Pirko5c766d62013-01-24 09:41:41 +0000650#define INFINITY_LIFE_TIME 0xFFFFFFFF
651
652static void check_lifetime(struct work_struct *work)
653{
654 unsigned long now, next, next_sec, next_sched;
655 struct in_ifaddr *ifa;
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000656 struct hlist_node *n;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000657 int i;
658
659 now = jiffies;
660 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
661
Jiri Pirko5c766d62013-01-24 09:41:41 +0000662 for (i = 0; i < IN4_ADDR_HSIZE; i++) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000663 bool change_needed = false;
664
665 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800666 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
Jiri Pirko5c766d62013-01-24 09:41:41 +0000667 unsigned long age;
668
669 if (ifa->ifa_flags & IFA_F_PERMANENT)
670 continue;
671
672 /* We try to batch several events at once. */
673 age = (now - ifa->ifa_tstamp +
674 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
675
676 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
677 age >= ifa->ifa_valid_lft) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000678 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000679 } else if (ifa->ifa_preferred_lft ==
680 INFINITY_LIFE_TIME) {
681 continue;
682 } else if (age >= ifa->ifa_preferred_lft) {
683 if (time_before(ifa->ifa_tstamp +
684 ifa->ifa_valid_lft * HZ, next))
685 next = ifa->ifa_tstamp +
686 ifa->ifa_valid_lft * HZ;
687
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000688 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
689 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000690 } else if (time_before(ifa->ifa_tstamp +
691 ifa->ifa_preferred_lft * HZ,
692 next)) {
693 next = ifa->ifa_tstamp +
694 ifa->ifa_preferred_lft * HZ;
695 }
696 }
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000697 rcu_read_unlock();
698 if (!change_needed)
699 continue;
700 rtnl_lock();
701 hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
702 unsigned long age;
703
704 if (ifa->ifa_flags & IFA_F_PERMANENT)
705 continue;
706
707 /* We try to batch several events at once. */
708 age = (now - ifa->ifa_tstamp +
709 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
710
711 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
712 age >= ifa->ifa_valid_lft) {
713 struct in_ifaddr **ifap;
714
715 for (ifap = &ifa->ifa_dev->ifa_list;
716 *ifap != NULL; ifap = &(*ifap)->ifa_next) {
717 if (*ifap == ifa) {
718 inet_del_ifa(ifa->ifa_dev,
719 ifap, 1);
720 break;
721 }
722 }
723 } else if (ifa->ifa_preferred_lft !=
724 INFINITY_LIFE_TIME &&
725 age >= ifa->ifa_preferred_lft &&
726 !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
727 ifa->ifa_flags |= IFA_F_DEPRECATED;
728 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
729 }
730 }
731 rtnl_unlock();
Jiri Pirko5c766d62013-01-24 09:41:41 +0000732 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000733
734 next_sec = round_jiffies_up(next);
735 next_sched = next;
736
737 /* If rounded timeout is accurate enough, accept it. */
738 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
739 next_sched = next_sec;
740
741 now = jiffies;
742 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
743 if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
744 next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
745
viresh kumar906e0732014-01-22 12:23:32 +0530746 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work,
747 next_sched - now);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000748}
749
750static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
751 __u32 prefered_lft)
752{
753 unsigned long timeout;
754
755 ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
756
757 timeout = addrconf_timeout_fixup(valid_lft, HZ);
758 if (addrconf_finite_timeout(timeout))
759 ifa->ifa_valid_lft = timeout;
760 else
761 ifa->ifa_flags |= IFA_F_PERMANENT;
762
763 timeout = addrconf_timeout_fixup(prefered_lft, HZ);
764 if (addrconf_finite_timeout(timeout)) {
765 if (timeout == 0)
766 ifa->ifa_flags |= IFA_F_DEPRECATED;
767 ifa->ifa_preferred_lft = timeout;
768 }
769 ifa->ifa_tstamp = jiffies;
770 if (!ifa->ifa_cstamp)
771 ifa->ifa_cstamp = ifa->ifa_tstamp;
772}
773
774static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
775 __u32 *pvalid_lft, __u32 *pprefered_lft)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776{
Thomas Graf5c753972006-08-04 23:03:53 -0700777 struct nlattr *tb[IFA_MAX+1];
778 struct in_ifaddr *ifa;
779 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 struct net_device *dev;
781 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800782 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
Johannes Bergfceb6432017-04-12 14:34:07 +0200784 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
785 NULL);
Thomas Graf5c753972006-08-04 23:03:53 -0700786 if (err < 0)
787 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
Thomas Graf5c753972006-08-04 23:03:53 -0700789 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800790 err = -EINVAL;
Ian Morris51456b22015-04-03 09:17:26 +0100791 if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL])
Thomas Graf5c753972006-08-04 23:03:53 -0700792 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800794 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800795 err = -ENODEV;
Ian Morris51456b22015-04-03 09:17:26 +0100796 if (!dev)
Thomas Graf5c753972006-08-04 23:03:53 -0700797 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
Thomas Graf5c753972006-08-04 23:03:53 -0700799 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800800 err = -ENOBUFS;
Ian Morris51456b22015-04-03 09:17:26 +0100801 if (!in_dev)
Herbert Xu71e27da2007-06-04 23:36:06 -0700802 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
Thomas Graf5c753972006-08-04 23:03:53 -0700804 ifa = inet_alloc_ifa();
Ian Morris51456b22015-04-03 09:17:26 +0100805 if (!ifa)
Thomas Graf5c753972006-08-04 23:03:53 -0700806 /*
807 * A potential indev allocation can be left alive, it stays
808 * assigned to its device and is destroy with it.
809 */
Thomas Graf5c753972006-08-04 23:03:53 -0700810 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700811
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800812 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100813 neigh_parms_data_state_setall(in_dev->arp_parms);
Thomas Graf5c753972006-08-04 23:03:53 -0700814 in_dev_hold(in_dev);
815
Ian Morris51456b22015-04-03 09:17:26 +0100816 if (!tb[IFA_ADDRESS])
Thomas Graf5c753972006-08-04 23:03:53 -0700817 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
818
David S. Millerfd23c3b2011-02-18 12:42:28 -0800819 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
821 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100822 ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
823 ifm->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700825 ifa->ifa_dev = in_dev;
826
Jiri Benc67b61f62015-03-29 16:59:26 +0200827 ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]);
828 ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700829
830 if (tb[IFA_BROADCAST])
Jiri Benc67b61f62015-03-29 16:59:26 +0200831 ifa->ifa_broadcast = nla_get_in_addr(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700832
Thomas Graf5c753972006-08-04 23:03:53 -0700833 if (tb[IFA_LABEL])
834 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 else
836 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
837
Jiri Pirko5c766d62013-01-24 09:41:41 +0000838 if (tb[IFA_CACHEINFO]) {
839 struct ifa_cacheinfo *ci;
840
841 ci = nla_data(tb[IFA_CACHEINFO]);
842 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
843 err = -EINVAL;
Daniel Borkmann446266b2013-08-02 11:32:43 +0200844 goto errout_free;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000845 }
846 *pvalid_lft = ci->ifa_valid;
847 *pprefered_lft = ci->ifa_prefered;
848 }
849
Thomas Graf5c753972006-08-04 23:03:53 -0700850 return ifa;
851
Daniel Borkmann446266b2013-08-02 11:32:43 +0200852errout_free:
853 inet_free_ifa(ifa);
Thomas Graf5c753972006-08-04 23:03:53 -0700854errout:
855 return ERR_PTR(err);
856}
857
Jiri Pirko5c766d62013-01-24 09:41:41 +0000858static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
859{
860 struct in_device *in_dev = ifa->ifa_dev;
861 struct in_ifaddr *ifa1, **ifap;
862
863 if (!ifa->ifa_local)
864 return NULL;
865
866 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
867 ifap = &ifa1->ifa_next) {
868 if (ifa1->ifa_mask == ifa->ifa_mask &&
869 inet_ifa_match(ifa1->ifa_address, ifa) &&
870 ifa1->ifa_local == ifa->ifa_local)
871 return ifa1;
872 }
873 return NULL;
874}
875
David Ahernc21ef3e2017-04-16 09:48:24 -0700876static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
877 struct netlink_ext_ack *extack)
Thomas Graf5c753972006-08-04 23:03:53 -0700878{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900879 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700880 struct in_ifaddr *ifa;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000881 struct in_ifaddr *ifa_existing;
882 __u32 valid_lft = INFINITY_LIFE_TIME;
883 __u32 prefered_lft = INFINITY_LIFE_TIME;
Thomas Graf5c753972006-08-04 23:03:53 -0700884
885 ASSERT_RTNL();
886
Jiri Pirko5c766d62013-01-24 09:41:41 +0000887 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft);
Thomas Graf5c753972006-08-04 23:03:53 -0700888 if (IS_ERR(ifa))
889 return PTR_ERR(ifa);
890
Jiri Pirko5c766d62013-01-24 09:41:41 +0000891 ifa_existing = find_matching_ifa(ifa);
892 if (!ifa_existing) {
893 /* It would be best to check for !NLM_F_CREATE here but
stephen hemminger614d0562014-05-16 20:46:58 -0700894 * userspace already relies on not having to provide this.
Jiri Pirko5c766d62013-01-24 09:41:41 +0000895 */
896 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Madhu Challa93a714d2015-02-25 09:58:35 -0800897 if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
898 int ret = ip_mc_config(net->ipv4.mc_autojoin_sk,
899 true, ifa);
900
901 if (ret < 0) {
902 inet_free_ifa(ifa);
903 return ret;
904 }
905 }
David Ahernde95e042017-10-18 09:56:54 -0700906 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid,
907 extack);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000908 } else {
909 inet_free_ifa(ifa);
910
911 if (nlh->nlmsg_flags & NLM_F_EXCL ||
912 !(nlh->nlmsg_flags & NLM_F_REPLACE))
913 return -EEXIST;
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000914 ifa = ifa_existing;
915 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Jiri Pirko05a324b2013-04-04 23:39:38 +0000916 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530917 queue_delayed_work(system_power_efficient_wq,
918 &check_lifetime_work, 0);
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000919 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000920 }
921 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922}
923
924/*
925 * Determine a default network mask, based on the IP address.
926 */
927
Eric Dumazet40384992012-08-03 21:06:50 +0000928static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929{
930 int rc = -1; /* Something else, probably a multicast. */
931
Joe Perchesf97c1e02007-12-16 13:45:43 -0800932 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900933 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 else {
Al Viro714e85b2006-11-14 20:51:49 -0800935 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
Al Viro714e85b2006-11-14 20:51:49 -0800937 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800939 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800941 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 rc = 24;
943 }
944
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900945 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946}
947
948
Al Viro03aef172017-07-01 07:53:12 -0400949int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 struct sockaddr_in sin_orig;
Al Viro03aef172017-07-01 07:53:12 -0400952 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 struct in_device *in_dev;
954 struct in_ifaddr **ifap = NULL;
955 struct in_ifaddr *ifa = NULL;
956 struct net_device *dev;
957 char *colon;
958 int ret = -EFAULT;
959 int tryaddrmatch = 0;
960
Al Viro03aef172017-07-01 07:53:12 -0400961 ifr->ifr_name[IFNAMSIZ - 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
963 /* save original address for comparison */
964 memcpy(&sin_orig, sin, sizeof(*sin));
965
Al Viro03aef172017-07-01 07:53:12 -0400966 colon = strchr(ifr->ifr_name, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 if (colon)
968 *colon = 0;
969
Al Viro03aef172017-07-01 07:53:12 -0400970 dev_load(net, ifr->ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
Stephen Hemminger132adf52007-03-08 20:44:43 -0800972 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 case SIOCGIFADDR: /* Get interface address */
974 case SIOCGIFBRDADDR: /* Get the broadcast address */
975 case SIOCGIFDSTADDR: /* Get the destination address */
976 case SIOCGIFNETMASK: /* Get the netmask for the interface */
977 /* Note that these ioctls will not sleep,
978 so that we do not impose a lock.
979 One day we will be forced to put shlock here (I mean SMP)
980 */
981 tryaddrmatch = (sin_orig.sin_family == AF_INET);
982 memset(sin, 0, sizeof(*sin));
983 sin->sin_family = AF_INET;
984 break;
985
986 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000987 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000988 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 goto out;
990 break;
991 case SIOCSIFADDR: /* Set interface address (and family) */
992 case SIOCSIFBRDADDR: /* Set the broadcast address */
993 case SIOCSIFDSTADDR: /* Set the destination address */
994 case SIOCSIFNETMASK: /* Set the netmask for the interface */
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000995 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000996 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 goto out;
998 ret = -EINVAL;
999 if (sin->sin_family != AF_INET)
1000 goto out;
1001 break;
1002 default:
1003 ret = -EINVAL;
1004 goto out;
1005 }
1006
1007 rtnl_lock();
1008
1009 ret = -ENODEV;
Al Viro03aef172017-07-01 07:53:12 -04001010 dev = __dev_get_by_name(net, ifr->ifr_name);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001011 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 goto done;
1013
1014 if (colon)
1015 *colon = ':';
1016
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001017 in_dev = __in_dev_get_rtnl(dev);
1018 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 if (tryaddrmatch) {
1020 /* Matthias Andree */
1021 /* compare label and address (4.4BSD style) */
1022 /* note: we only do this for a limited set of ioctls
1023 and only if the original address family was AF_INET.
1024 This is checked above. */
1025 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1026 ifap = &ifa->ifa_next) {
Al Viro03aef172017-07-01 07:53:12 -04001027 if (!strcmp(ifr->ifr_name, ifa->ifa_label) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -08001029 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 break; /* found */
1031 }
1032 }
1033 }
1034 /* we didn't get a match, maybe the application is
1035 4.3BSD-style and passed in junk so we fall back to
1036 comparing just the label */
1037 if (!ifa) {
1038 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1039 ifap = &ifa->ifa_next)
Al Viro03aef172017-07-01 07:53:12 -04001040 if (!strcmp(ifr->ifr_name, ifa->ifa_label))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 break;
1042 }
1043 }
1044
1045 ret = -EADDRNOTAVAIL;
1046 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
1047 goto done;
1048
Stephen Hemminger132adf52007-03-08 20:44:43 -08001049 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 case SIOCGIFADDR: /* Get interface address */
1051 sin->sin_addr.s_addr = ifa->ifa_local;
Al Viro03aef172017-07-01 07:53:12 -04001052 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
1054 case SIOCGIFBRDADDR: /* Get the broadcast address */
1055 sin->sin_addr.s_addr = ifa->ifa_broadcast;
Al Viro03aef172017-07-01 07:53:12 -04001056 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
1058 case SIOCGIFDSTADDR: /* Get the destination address */
1059 sin->sin_addr.s_addr = ifa->ifa_address;
Al Viro03aef172017-07-01 07:53:12 -04001060 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
1062 case SIOCGIFNETMASK: /* Get the netmask for the interface */
1063 sin->sin_addr.s_addr = ifa->ifa_mask;
Al Viro03aef172017-07-01 07:53:12 -04001064 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
1066 case SIOCSIFFLAGS:
1067 if (colon) {
1068 ret = -EADDRNOTAVAIL;
1069 if (!ifa)
1070 break;
1071 ret = 0;
Al Viro03aef172017-07-01 07:53:12 -04001072 if (!(ifr->ifr_flags & IFF_UP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 inet_del_ifa(in_dev, ifap, 1);
1074 break;
1075 }
Al Viro03aef172017-07-01 07:53:12 -04001076 ret = dev_change_flags(dev, ifr->ifr_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 break;
1078
1079 case SIOCSIFADDR: /* Set interface address (and family) */
1080 ret = -EINVAL;
1081 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1082 break;
1083
1084 if (!ifa) {
1085 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001086 ifa = inet_alloc_ifa();
1087 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 break;
Xi Wangc7e2e1d2013-01-05 11:19:24 +00001089 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 if (colon)
Al Viro03aef172017-07-01 07:53:12 -04001091 memcpy(ifa->ifa_label, ifr->ifr_name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 else
1093 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1094 } else {
1095 ret = 0;
1096 if (ifa->ifa_local == sin->sin_addr.s_addr)
1097 break;
1098 inet_del_ifa(in_dev, ifap, 0);
1099 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -08001100 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 }
1102
1103 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
1104
1105 if (!(dev->flags & IFF_POINTOPOINT)) {
1106 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
1107 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
1108 if ((dev->flags & IFF_BROADCAST) &&
1109 ifa->ifa_prefixlen < 31)
1110 ifa->ifa_broadcast = ifa->ifa_address |
1111 ~ifa->ifa_mask;
1112 } else {
1113 ifa->ifa_prefixlen = 32;
1114 ifa->ifa_mask = inet_make_mask(32);
1115 }
Jiri Pirko5c766d62013-01-24 09:41:41 +00001116 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 ret = inet_set_ifa(dev, ifa);
1118 break;
1119
1120 case SIOCSIFBRDADDR: /* Set the broadcast address */
1121 ret = 0;
1122 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
1123 inet_del_ifa(in_dev, ifap, 0);
1124 ifa->ifa_broadcast = sin->sin_addr.s_addr;
1125 inet_insert_ifa(ifa);
1126 }
1127 break;
1128
1129 case SIOCSIFDSTADDR: /* Set the destination address */
1130 ret = 0;
1131 if (ifa->ifa_address == sin->sin_addr.s_addr)
1132 break;
1133 ret = -EINVAL;
1134 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1135 break;
1136 ret = 0;
1137 inet_del_ifa(in_dev, ifap, 0);
1138 ifa->ifa_address = sin->sin_addr.s_addr;
1139 inet_insert_ifa(ifa);
1140 break;
1141
1142 case SIOCSIFNETMASK: /* Set the netmask for the interface */
1143
1144 /*
1145 * The mask we set must be legal.
1146 */
1147 ret = -EINVAL;
1148 if (bad_mask(sin->sin_addr.s_addr, 0))
1149 break;
1150 ret = 0;
1151 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -07001152 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 inet_del_ifa(in_dev, ifap, 0);
1154 ifa->ifa_mask = sin->sin_addr.s_addr;
1155 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
1156
1157 /* See if current broadcast address matches
1158 * with current netmask, then recalculate
1159 * the broadcast address. Otherwise it's a
1160 * funny address, so don't touch it since
1161 * the user seems to know what (s)he's doing...
1162 */
1163 if ((dev->flags & IFF_BROADCAST) &&
1164 (ifa->ifa_prefixlen < 31) &&
1165 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -05001166 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 ifa->ifa_broadcast = (ifa->ifa_local |
1168 ~sin->sin_addr.s_addr);
1169 }
1170 inet_insert_ifa(ifa);
1171 }
1172 break;
1173 }
1174done:
1175 rtnl_unlock();
1176out:
1177 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178}
1179
Al Viro36fd6332017-06-26 13:19:16 -04001180static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181{
Herbert Xue5ed6392005-10-03 14:35:55 -07001182 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 struct in_ifaddr *ifa;
1184 struct ifreq ifr;
1185 int done = 0;
1186
Al Viro36fd6332017-06-26 13:19:16 -04001187 if (WARN_ON(size > sizeof(struct ifreq)))
1188 goto out;
1189
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001190 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 goto out;
1192
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001193 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 if (!buf) {
Al Viro36fd6332017-06-26 13:19:16 -04001195 done += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 continue;
1197 }
Al Viro36fd6332017-06-26 13:19:16 -04001198 if (len < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 break;
1200 memset(&ifr, 0, sizeof(struct ifreq));
Dan Carpenter4299c8a2013-07-29 22:15:19 +03001201 strcpy(ifr.ifr_name, ifa->ifa_label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202
1203 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
1204 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1205 ifa->ifa_local;
1206
Al Viro36fd6332017-06-26 13:19:16 -04001207 if (copy_to_user(buf + done, &ifr, size)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 done = -EFAULT;
1209 break;
1210 }
Al Viro36fd6332017-06-26 13:19:16 -04001211 len -= size;
1212 done += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 }
1214out:
1215 return done;
1216}
1217
Gao Feng8b57fd12017-03-10 12:38:47 +08001218static __be32 in_dev_select_addr(const struct in_device *in_dev,
1219 int scope)
1220{
1221 for_primary_ifa(in_dev) {
1222 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1223 ifa->ifa_scope <= scope)
1224 return ifa->ifa_local;
1225 } endfor_ifa(in_dev);
1226
1227 return 0;
1228}
1229
Al Viroa61ced52006-09-26 21:27:54 -07001230__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231{
Al Viroa61ced52006-09-26 21:27:54 -07001232 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001234 struct net *net = dev_net(dev);
David Ahern3f2fb9a2016-02-24 11:47:02 -08001235 int master_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
1237 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001238 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 if (!in_dev)
1240 goto no_in_dev;
1241
1242 for_primary_ifa(in_dev) {
1243 if (ifa->ifa_scope > scope)
1244 continue;
1245 if (!dst || inet_ifa_match(dst, ifa)) {
1246 addr = ifa->ifa_local;
1247 break;
1248 }
1249 if (!addr)
1250 addr = ifa->ifa_local;
1251 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252
1253 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001254 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001255no_in_dev:
David Ahern3f2fb9a2016-02-24 11:47:02 -08001256 master_idx = l3mdev_master_ifindex_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
David Lamparter17b693c2016-02-24 11:47:03 -08001258 /* For VRFs, the VRF device takes the place of the loopback device,
1259 * with addresses on it being preferred. Note in such cases the
1260 * loopback device will be among the devices that fail the master_idx
1261 * equality check in the loop below.
1262 */
1263 if (master_idx &&
1264 (dev = dev_get_by_index_rcu(net, master_idx)) &&
1265 (in_dev = __in_dev_get_rcu(dev))) {
Gao Feng8b57fd12017-03-10 12:38:47 +08001266 addr = in_dev_select_addr(in_dev, scope);
1267 if (addr)
1268 goto out_unlock;
David Lamparter17b693c2016-02-24 11:47:03 -08001269 }
1270
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 /* Not loopback addresses on loopback should be preferred
Stephen Hemmingerca9f1fd2015-02-14 13:47:54 -05001272 in this case. It is important that lo is the first interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 in dev_base list.
1274 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001275 for_each_netdev_rcu(net, dev) {
David Ahern3f2fb9a2016-02-24 11:47:02 -08001276 if (l3mdev_master_ifindex_rcu(dev) != master_idx)
1277 continue;
1278
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001279 in_dev = __in_dev_get_rcu(dev);
1280 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 continue;
1282
Gao Feng8b57fd12017-03-10 12:38:47 +08001283 addr = in_dev_select_addr(in_dev, scope);
1284 if (addr)
1285 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001287out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 return addr;
1290}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001291EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292
Al Viro60cad5d2006-09-26 22:17:09 -07001293static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1294 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295{
1296 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001297 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
1299 for_ifa(in_dev) {
1300 if (!addr &&
1301 (local == ifa->ifa_local || !local) &&
1302 ifa->ifa_scope <= scope) {
1303 addr = ifa->ifa_local;
1304 if (same)
1305 break;
1306 }
1307 if (!same) {
1308 same = (!local || inet_ifa_match(local, ifa)) &&
1309 (!dst || inet_ifa_match(dst, ifa));
1310 if (same && addr) {
1311 if (local || !dst)
1312 break;
1313 /* Is the selected addr into dst subnet? */
1314 if (inet_ifa_match(addr, ifa))
1315 break;
1316 /* No, then can we use new local src? */
1317 if (ifa->ifa_scope <= scope) {
1318 addr = ifa->ifa_local;
1319 break;
1320 }
1321 /* search for large dst subnet for addr */
1322 same = 0;
1323 }
1324 }
1325 } endfor_ifa(in_dev);
1326
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001327 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328}
1329
1330/*
1331 * Confirm that local IP address exists using wildcards:
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001332 * - net: netns to check, cannot be NULL
1333 * - in_dev: only on this interface, NULL=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 * - dst: only in the same subnet as dst, 0=any dst
1335 * - local: address, 0=autoselect the local address
1336 * - scope: maximum allowed scope value for the local address
1337 */
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001338__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001339 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340{
Al Viro60cad5d2006-09-26 22:17:09 -07001341 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001342 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
Ian Morris00db4122015-04-03 09:17:27 +01001344 if (in_dev)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001345 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001348 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001349 in_dev = __in_dev_get_rcu(dev);
1350 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 addr = confirm_addr_indev(in_dev, dst, local, scope);
1352 if (addr)
1353 break;
1354 }
1355 }
1356 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
1358 return addr;
1359}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001360EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
1362/*
1363 * Device notifier
1364 */
1365
1366int register_inetaddr_notifier(struct notifier_block *nb)
1367{
Alan Sterne041c682006-03-27 01:16:30 -08001368 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001370EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
1372int unregister_inetaddr_notifier(struct notifier_block *nb)
1373{
Alan Sterne041c682006-03-27 01:16:30 -08001374 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001376EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
Krister Johansen3ad7d242017-06-08 13:12:14 -07001378int register_inetaddr_validator_notifier(struct notifier_block *nb)
1379{
1380 return blocking_notifier_chain_register(&inetaddr_validator_chain, nb);
1381}
1382EXPORT_SYMBOL(register_inetaddr_validator_notifier);
1383
1384int unregister_inetaddr_validator_notifier(struct notifier_block *nb)
1385{
1386 return blocking_notifier_chain_unregister(&inetaddr_validator_chain,
1387 nb);
1388}
1389EXPORT_SYMBOL(unregister_inetaddr_validator_notifier);
1390
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001391/* Rename ifa_labels for a device name change. Make some effort to preserve
1392 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393*/
1394static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001395{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 struct in_ifaddr *ifa;
1397 int named = 0;
1398
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001399 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1400 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
1402 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001403 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001405 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001406 dot = strchr(old, ':');
Ian Morris51456b22015-04-03 09:17:26 +01001407 if (!dot) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001408 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 dot = old;
1410 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001411 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001412 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001413 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001414 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001415skip:
1416 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001417 }
1418}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419
Eric Dumazet40384992012-08-03 21:06:50 +00001420static bool inetdev_valid_mtu(unsigned int mtu)
Breno Leitao06770842008-09-02 17:28:58 -07001421{
Eric Dumazetb5476022017-12-11 07:17:39 -08001422 return mtu >= IPV4_MIN_MTU;
Breno Leitao06770842008-09-02 17:28:58 -07001423}
1424
Ian Campbelld11327ad2011-02-11 07:44:16 +00001425static void inetdev_send_gratuitous_arp(struct net_device *dev,
1426 struct in_device *in_dev)
1427
1428{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001429 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001430
Zoltan Kissb76d0782011-07-24 13:09:30 +00001431 for (ifa = in_dev->ifa_list; ifa;
1432 ifa = ifa->ifa_next) {
1433 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1434 ifa->ifa_local, dev,
1435 ifa->ifa_local, NULL,
1436 dev->dev_addr, NULL);
1437 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001438}
1439
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440/* Called only under RTNL semaphore */
1441
1442static int inetdev_event(struct notifier_block *this, unsigned long event,
1443 void *ptr)
1444{
Jiri Pirko351638e2013-05-28 01:30:21 +00001445 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazet748e2d92012-08-22 21:50:59 +00001446 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447
1448 ASSERT_RTNL();
1449
1450 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001451 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 in_dev = inetdev_init(dev);
WANG Cong20e61da2014-07-25 15:25:08 -07001453 if (IS_ERR(in_dev))
1454 return notifier_from_errno(PTR_ERR(in_dev));
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001455 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001456 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1457 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001458 }
Breno Leitao06770842008-09-02 17:28:58 -07001459 } else if (event == NETDEV_CHANGEMTU) {
1460 /* Re-enabling IP */
1461 if (inetdev_valid_mtu(dev->mtu))
1462 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 }
1464 goto out;
1465 }
1466
1467 switch (event) {
1468 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001469 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001470 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 break;
1472 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001473 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001475 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001476 struct in_ifaddr *ifa = inet_alloc_ifa();
1477
1478 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001479 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 ifa->ifa_local =
1481 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1482 ifa->ifa_prefixlen = 8;
1483 ifa->ifa_mask = inet_make_mask(8);
1484 in_dev_hold(in_dev);
1485 ifa->ifa_dev = in_dev;
1486 ifa->ifa_scope = RT_SCOPE_HOST;
1487 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Jiri Pirko5c766d62013-01-24 09:41:41 +00001488 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1489 INFINITY_LIFE_TIME);
Jiri Pirkodfd15822014-01-07 15:55:45 +01001490 ipv4_devconf_setall(in_dev);
1491 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 inet_insert_ifa(ifa);
1493 }
1494 }
1495 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001496 /* fall through */
1497 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001498 if (!IN_DEV_ARP_NOTIFY(in_dev))
1499 break;
1500 /* fall through */
1501 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001502 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001503 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 break;
1505 case NETDEV_DOWN:
1506 ip_mc_down(in_dev);
1507 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001508 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001509 ip_mc_unmap(in_dev);
1510 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001511 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001512 ip_mc_remap(in_dev);
1513 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001515 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 break;
Breno Leitao06770842008-09-02 17:28:58 -07001517 /* disable IP when MTU is not enough */
Gustavo A. R. Silvafcfd6df2017-10-16 15:48:55 -05001518 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 case NETDEV_UNREGISTER:
1520 inetdev_destroy(in_dev);
1521 break;
1522 case NETDEV_CHANGENAME:
1523 /* Do not notify about label change, this event is
1524 * not interesting to applications using netlink.
1525 */
1526 inetdev_changename(dev, in_dev);
1527
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001528 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001529 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 break;
1531 }
1532out:
1533 return NOTIFY_DONE;
1534}
1535
1536static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001537 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538};
1539
Eric Dumazet40384992012-08-03 21:06:50 +00001540static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001541{
1542 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1543 + nla_total_size(4) /* IFA_ADDRESS */
1544 + nla_total_size(4) /* IFA_LOCAL */
1545 + nla_total_size(4) /* IFA_BROADCAST */
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001546 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001547 + nla_total_size(4) /* IFA_FLAGS */
1548 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
Thomas Graf339bf982006-11-10 14:10:15 -08001549}
1550
Jiri Pirko5c766d62013-01-24 09:41:41 +00001551static inline u32 cstamp_delta(unsigned long cstamp)
1552{
1553 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1554}
1555
1556static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1557 unsigned long tstamp, u32 preferred, u32 valid)
1558{
1559 struct ifa_cacheinfo ci;
1560
1561 ci.cstamp = cstamp_delta(cstamp);
1562 ci.tstamp = cstamp_delta(tstamp);
1563 ci.ifa_prefered = preferred;
1564 ci.ifa_valid = valid;
1565
1566 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1567}
1568
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001570 u32 portid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571{
1572 struct ifaddrmsg *ifm;
1573 struct nlmsghdr *nlh;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001574 u32 preferred, valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
Eric W. Biederman15e47302012-09-07 20:12:54 +00001576 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
Ian Morris51456b22015-04-03 09:17:26 +01001577 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08001578 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001579
1580 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 ifm->ifa_family = AF_INET;
1582 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001583 ifm->ifa_flags = ifa->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 ifm->ifa_scope = ifa->ifa_scope;
1585 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
Jiri Pirko5c766d62013-01-24 09:41:41 +00001587 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1588 preferred = ifa->ifa_preferred_lft;
1589 valid = ifa->ifa_valid_lft;
1590 if (preferred != INFINITY_LIFE_TIME) {
1591 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1592
1593 if (preferred > tval)
1594 preferred -= tval;
1595 else
1596 preferred = 0;
1597 if (valid != INFINITY_LIFE_TIME) {
1598 if (valid > tval)
1599 valid -= tval;
1600 else
1601 valid = 0;
1602 }
1603 }
1604 } else {
1605 preferred = INFINITY_LIFE_TIME;
1606 valid = INFINITY_LIFE_TIME;
1607 }
David S. Millerf3756b72012-04-01 20:39:02 -04001608 if ((ifa->ifa_address &&
Jiri Benc930345e2015-03-29 16:59:25 +02001609 nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001610 (ifa->ifa_local &&
Jiri Benc930345e2015-03-29 16:59:25 +02001611 nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001612 (ifa->ifa_broadcast &&
Jiri Benc930345e2015-03-29 16:59:25 +02001613 nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001614 (ifa->ifa_label[0] &&
Jiri Pirko5c766d62013-01-24 09:41:41 +00001615 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001616 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
Jiri Pirko5c766d62013-01-24 09:41:41 +00001617 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1618 preferred, valid))
David S. Millerf3756b72012-04-01 20:39:02 -04001619 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001620
Johannes Berg053c0952015-01-16 22:09:00 +01001621 nlmsg_end(skb, nlh);
1622 return 0;
Thomas Graf47f68512006-08-04 23:04:36 -07001623
1624nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001625 nlmsg_cancel(skb, nlh);
1626 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627}
1628
1629static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1630{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001631 struct net *net = sock_net(skb->sk);
Eric Dumazeteec4df92009-11-12 07:44:25 +00001632 int h, s_h;
1633 int idx, s_idx;
1634 int ip_idx, s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 struct net_device *dev;
1636 struct in_device *in_dev;
1637 struct in_ifaddr *ifa;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001638 struct hlist_head *head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639
Eric Dumazeteec4df92009-11-12 07:44:25 +00001640 s_h = cb->args[0];
1641 s_idx = idx = cb->args[1];
1642 s_ip_idx = ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
Eric Dumazeteec4df92009-11-12 07:44:25 +00001644 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1645 idx = 0;
1646 head = &net->dev_index_head[h];
1647 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001648 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1649 net->dev_base_seq;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001650 hlist_for_each_entry_rcu(dev, head, index_hlist) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001651 if (idx < s_idx)
1652 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001653 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001654 s_ip_idx = 0;
1655 in_dev = __in_dev_get_rcu(dev);
1656 if (!in_dev)
1657 goto cont;
1658
1659 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1660 ifa = ifa->ifa_next, ip_idx++) {
1661 if (ip_idx < s_ip_idx)
1662 continue;
1663 if (inet_fill_ifaddr(skb, ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001664 NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 cb->nlh->nlmsg_seq,
Johannes Berg053c0952015-01-16 22:09:00 +01001666 RTM_NEWADDR, NLM_F_MULTI) < 0) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001667 rcu_read_unlock();
1668 goto done;
1669 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001670 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Eric Dumazeteec4df92009-11-12 07:44:25 +00001671 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001672cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001673 idx++;
1674 }
1675 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 }
1677
1678done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001679 cb->args[0] = h;
1680 cb->args[1] = idx;
1681 cb->args[2] = ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682
1683 return skb->len;
1684}
1685
Jianjun Kong539afed2008-11-03 02:48:48 -08001686static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001687 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688{
Thomas Graf47f68512006-08-04 23:04:36 -07001689 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001690 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1691 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001692 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001694 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001695 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001696 if (!skb)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001697 goto errout;
1698
Eric W. Biederman15e47302012-09-07 20:12:54 +00001699 err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001700 if (err < 0) {
1701 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1702 WARN_ON(err == -EMSGSIZE);
1703 kfree_skb(skb);
1704 goto errout;
1705 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001706 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001707 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001708errout:
1709 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001710 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711}
1712
Arad, Ronenb1974ed2015-10-19 09:23:28 -07001713static size_t inet_get_link_af_size(const struct net_device *dev,
1714 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001715{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001716 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001717
1718 if (!in_dev)
1719 return 0;
1720
1721 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1722}
1723
Sowmini Varadhand5566fd2015-09-11 16:48:48 -04001724static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
1725 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001726{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001727 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001728 struct nlattr *nla;
1729 int i;
1730
1731 if (!in_dev)
1732 return -ENODATA;
1733
1734 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
Ian Morris51456b22015-04-03 09:17:26 +01001735 if (!nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001736 return -EMSGSIZE;
1737
1738 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1739 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1740
1741 return 0;
1742}
1743
1744static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1745 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1746};
1747
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001748static int inet_validate_link_af(const struct net_device *dev,
1749 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001750{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001751 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1752 int err, rem;
1753
Florian Westphal5fa85a02017-10-16 15:44:36 +02001754 if (dev && !__in_dev_get_rcu(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001755 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001756
Johannes Bergfceb6432017-04-12 14:34:07 +02001757 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy, NULL);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001758 if (err < 0)
1759 return err;
1760
1761 if (tb[IFLA_INET_CONF]) {
1762 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1763 int cfgid = nla_type(a);
1764
1765 if (nla_len(a) < 4)
1766 return -EINVAL;
1767
1768 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1769 return -EINVAL;
1770 }
1771 }
1772
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001773 return 0;
1774}
1775
1776static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1777{
Florian Westphal5fa85a02017-10-16 15:44:36 +02001778 struct in_device *in_dev = __in_dev_get_rcu(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001779 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1780 int rem;
1781
1782 if (!in_dev)
1783 return -EAFNOSUPPORT;
1784
Johannes Bergfceb6432017-04-12 14:34:07 +02001785 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0)
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001786 BUG();
1787
Thomas Graf9f0f7272010-11-16 04:32:48 +00001788 if (tb[IFLA_INET_CONF]) {
1789 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1790 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1791 }
1792
1793 return 0;
1794}
1795
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001796static int inet_netconf_msgsize_devconf(int type)
1797{
1798 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1799 + nla_total_size(4); /* NETCONFA_IFINDEX */
Zhang Shengju136ba622016-03-10 08:55:50 +00001800 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001801
Zhang Shengju136ba622016-03-10 08:55:50 +00001802 if (type == NETCONFA_ALL)
1803 all = true;
1804
1805 if (all || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001806 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001807 if (all || type == NETCONFA_RP_FILTER)
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001808 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001809 if (all || type == NETCONFA_MC_FORWARDING)
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001810 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001811 if (all || type == NETCONFA_PROXY_NEIGH)
stephen hemmingerf085ff12013-12-12 13:06:50 -08001812 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001813 if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001814 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001815
1816 return size;
1817}
1818
1819static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1820 struct ipv4_devconf *devconf, u32 portid,
1821 u32 seq, int event, unsigned int flags,
1822 int type)
1823{
1824 struct nlmsghdr *nlh;
1825 struct netconfmsg *ncm;
Zhang Shengju136ba622016-03-10 08:55:50 +00001826 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001827
1828 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1829 flags);
Ian Morris51456b22015-04-03 09:17:26 +01001830 if (!nlh)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001831 return -EMSGSIZE;
1832
Zhang Shengju136ba622016-03-10 08:55:50 +00001833 if (type == NETCONFA_ALL)
1834 all = true;
1835
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001836 ncm = nlmsg_data(nlh);
1837 ncm->ncm_family = AF_INET;
1838
1839 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1840 goto nla_put_failure;
1841
David Ahernb5c96412017-03-28 14:28:03 -07001842 if (!devconf)
1843 goto out;
1844
Zhang Shengju136ba622016-03-10 08:55:50 +00001845 if ((all || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001846 nla_put_s32(skb, NETCONFA_FORWARDING,
1847 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1848 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001849 if ((all || type == NETCONFA_RP_FILTER) &&
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001850 nla_put_s32(skb, NETCONFA_RP_FILTER,
1851 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
1852 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001853 if ((all || type == NETCONFA_MC_FORWARDING) &&
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001854 nla_put_s32(skb, NETCONFA_MC_FORWARDING,
1855 IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
1856 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001857 if ((all || type == NETCONFA_PROXY_NEIGH) &&
stephen hemminger09aea5d2013-12-17 22:35:52 -08001858 nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08001859 IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
1860 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001861 if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001862 nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
1863 IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
1864 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001865
David Ahernb5c96412017-03-28 14:28:03 -07001866out:
Johannes Berg053c0952015-01-16 22:09:00 +01001867 nlmsg_end(skb, nlh);
1868 return 0;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001869
1870nla_put_failure:
1871 nlmsg_cancel(skb, nlh);
1872 return -EMSGSIZE;
1873}
1874
David Ahern3b022862017-03-28 14:28:02 -07001875void inet_netconf_notify_devconf(struct net *net, int event, int type,
1876 int ifindex, struct ipv4_devconf *devconf)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001877{
1878 struct sk_buff *skb;
1879 int err = -ENOBUFS;
1880
Eric Dumazetfa178062016-07-08 05:18:24 +02001881 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001882 if (!skb)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001883 goto errout;
1884
1885 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
David Ahern3b022862017-03-28 14:28:02 -07001886 event, 0, type);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001887 if (err < 0) {
1888 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1889 WARN_ON(err == -EMSGSIZE);
1890 kfree_skb(skb);
1891 goto errout;
1892 }
Eric Dumazetfa178062016-07-08 05:18:24 +02001893 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001894 return;
1895errout:
1896 if (err < 0)
1897 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
1898}
1899
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001900static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
1901 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
1902 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001903 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
stephen hemminger09aea5d2013-12-17 22:35:52 -08001904 [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) },
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001905 [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001906};
1907
1908static int inet_netconf_get_devconf(struct sk_buff *in_skb,
David Ahernc21ef3e2017-04-16 09:48:24 -07001909 struct nlmsghdr *nlh,
1910 struct netlink_ext_ack *extack)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001911{
1912 struct net *net = sock_net(in_skb->sk);
1913 struct nlattr *tb[NETCONFA_MAX+1];
1914 struct netconfmsg *ncm;
1915 struct sk_buff *skb;
1916 struct ipv4_devconf *devconf;
1917 struct in_device *in_dev;
1918 struct net_device *dev;
1919 int ifindex;
1920 int err;
1921
1922 err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
David Ahernc21ef3e2017-04-16 09:48:24 -07001923 devconf_ipv4_policy, extack);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001924 if (err < 0)
1925 goto errout;
1926
Anton Protopopova97eb332016-02-16 21:43:16 -05001927 err = -EINVAL;
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001928 if (!tb[NETCONFA_IFINDEX])
1929 goto errout;
1930
1931 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
1932 switch (ifindex) {
1933 case NETCONFA_IFINDEX_ALL:
1934 devconf = net->ipv4.devconf_all;
1935 break;
1936 case NETCONFA_IFINDEX_DEFAULT:
1937 devconf = net->ipv4.devconf_dflt;
1938 break;
1939 default:
1940 dev = __dev_get_by_index(net, ifindex);
Ian Morris51456b22015-04-03 09:17:26 +01001941 if (!dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001942 goto errout;
1943 in_dev = __in_dev_get_rtnl(dev);
Ian Morris51456b22015-04-03 09:17:26 +01001944 if (!in_dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001945 goto errout;
1946 devconf = &in_dev->cnf;
1947 break;
1948 }
1949
1950 err = -ENOBUFS;
Eric Dumazetfa178062016-07-08 05:18:24 +02001951 skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001952 if (!skb)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001953 goto errout;
1954
1955 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
1956 NETLINK_CB(in_skb).portid,
1957 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
Zhang Shengju136ba622016-03-10 08:55:50 +00001958 NETCONFA_ALL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001959 if (err < 0) {
1960 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1961 WARN_ON(err == -EMSGSIZE);
1962 kfree_skb(skb);
1963 goto errout;
1964 }
1965 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
1966errout:
1967 return err;
1968}
1969
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001970static int inet_netconf_dump_devconf(struct sk_buff *skb,
1971 struct netlink_callback *cb)
1972{
1973 struct net *net = sock_net(skb->sk);
1974 int h, s_h;
1975 int idx, s_idx;
1976 struct net_device *dev;
1977 struct in_device *in_dev;
1978 struct hlist_head *head;
1979
1980 s_h = cb->args[0];
1981 s_idx = idx = cb->args[1];
1982
1983 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1984 idx = 0;
1985 head = &net->dev_index_head[h];
1986 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001987 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1988 net->dev_base_seq;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001989 hlist_for_each_entry_rcu(dev, head, index_hlist) {
1990 if (idx < s_idx)
1991 goto cont;
1992 in_dev = __in_dev_get_rcu(dev);
1993 if (!in_dev)
1994 goto cont;
1995
1996 if (inet_netconf_fill_devconf(skb, dev->ifindex,
1997 &in_dev->cnf,
1998 NETLINK_CB(cb->skb).portid,
1999 cb->nlh->nlmsg_seq,
2000 RTM_NEWNETCONF,
2001 NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002002 NETCONFA_ALL) < 0) {
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002003 rcu_read_unlock();
2004 goto done;
2005 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00002006 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002007cont:
2008 idx++;
2009 }
2010 rcu_read_unlock();
2011 }
2012 if (h == NETDEV_HASHENTRIES) {
2013 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
2014 net->ipv4.devconf_all,
2015 NETLINK_CB(cb->skb).portid,
2016 cb->nlh->nlmsg_seq,
2017 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002018 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002019 goto done;
2020 else
2021 h++;
2022 }
2023 if (h == NETDEV_HASHENTRIES + 1) {
2024 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
2025 net->ipv4.devconf_dflt,
2026 NETLINK_CB(cb->skb).portid,
2027 cb->nlh->nlmsg_seq,
2028 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002029 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002030 goto done;
2031 else
2032 h++;
2033 }
2034done:
2035 cb->args[0] = h;
2036 cb->args[1] = idx;
2037
2038 return skb->len;
2039}
2040
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041#ifdef CONFIG_SYSCTL
2042
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002043static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07002044{
2045 struct net_device *dev;
2046
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002047 rcu_read_lock();
2048 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07002049 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002050
Herbert Xu31be3082007-06-04 23:35:37 -07002051 in_dev = __in_dev_get_rcu(dev);
2052 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002053 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07002054 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002055 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07002056}
2057
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002058/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002059static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002060{
2061 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002062 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002063
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002064 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002065 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
David Ahern3b022862017-03-28 14:28:02 -07002066 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2067 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002068 NETCONFA_IFINDEX_ALL,
2069 net->ipv4.devconf_all);
David Ahern3b022862017-03-28 14:28:02 -07002070 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2071 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002072 NETCONFA_IFINDEX_DEFAULT,
2073 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002074
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002075 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002076 struct in_device *in_dev;
Eric Dumazetfa178062016-07-08 05:18:24 +02002077
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002078 if (on)
2079 dev_disable_lro(dev);
Eric Dumazetfa178062016-07-08 05:18:24 +02002080
2081 in_dev = __in_dev_get_rtnl(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002082 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002083 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
David Ahern3b022862017-03-28 14:28:02 -07002084 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2085 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002086 dev->ifindex, &in_dev->cnf);
2087 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002088 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002089}
2090
stephen hemmingerf085ff12013-12-12 13:06:50 -08002091static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf)
2092{
2093 if (cnf == net->ipv4.devconf_dflt)
2094 return NETCONFA_IFINDEX_DEFAULT;
2095 else if (cnf == net->ipv4.devconf_all)
2096 return NETCONFA_IFINDEX_ALL;
2097 else {
2098 struct in_device *idev
2099 = container_of(cnf, struct in_device, cnf);
2100 return idev->dev->ifindex;
2101 }
2102}
2103
Joe Perchesfe2c6332013-06-11 23:04:25 -07002104static int devinet_conf_proc(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002105 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07002106 size_t *lenp, loff_t *ppos)
2107{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002108 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002109 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002110 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07002111
2112 if (write) {
2113 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002114 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07002115 int i = (int *)ctl->data - cnf->data;
stephen hemmingerf085ff12013-12-12 13:06:50 -08002116 int ifindex;
Herbert Xu31be3082007-06-04 23:35:37 -07002117
2118 set_bit(i, cnf->state);
2119
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002120 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002121 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00002122 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
2123 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002124 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002125 rt_cache_flush(net);
stephen hemmingerf085ff12013-12-12 13:06:50 -08002126
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002127 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
2128 new_value != old_value) {
stephen hemmingerf085ff12013-12-12 13:06:50 -08002129 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002130 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2131 NETCONFA_RP_FILTER,
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002132 ifindex, cnf);
2133 }
stephen hemmingerf085ff12013-12-12 13:06:50 -08002134 if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
2135 new_value != old_value) {
2136 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002137 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2138 NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002139 ifindex, cnf);
2140 }
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002141 if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
2142 new_value != old_value) {
2143 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002144 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2145 NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002146 ifindex, cnf);
2147 }
Herbert Xu31be3082007-06-04 23:35:37 -07002148 }
2149
2150 return ret;
2151}
2152
Joe Perchesfe2c6332013-06-11 23:04:25 -07002153static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002154 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 size_t *lenp, loff_t *ppos)
2156{
2157 int *valp = ctl->data;
2158 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00002159 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002160 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161
2162 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002163 struct net *net = ctl->extra2;
2164
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002165 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00002166 if (!rtnl_trylock()) {
2167 /* Restore the original values before restarting */
2168 *valp = val;
2169 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00002170 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00002171 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002172 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2173 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002174 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002175 struct ipv4_devconf *cnf = ctl->extra1;
2176 struct in_device *idev =
2177 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002178 if (*valp)
2179 dev_disable_lro(idev->dev);
David Ahern3b022862017-03-28 14:28:02 -07002180 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002181 NETCONFA_FORWARDING,
2182 idev->dev->ifindex,
2183 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002184 }
2185 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002186 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002187 } else
David Ahern3b022862017-03-28 14:28:02 -07002188 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2189 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002190 NETCONFA_IFINDEX_DEFAULT,
2191 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 }
2193
2194 return ret;
2195}
2196
Joe Perchesfe2c6332013-06-11 23:04:25 -07002197static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
David S. Miller323e1262010-12-12 21:55:08 -08002198 void __user *buffer,
2199 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200{
2201 int *valp = ctl->data;
2202 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002203 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07002204 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205
2206 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002207 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208
2209 return ret;
2210}
2211
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002212#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07002213 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07002214 .procname = name, \
2215 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00002216 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002217 .maxlen = sizeof(int), \
2218 .mode = mval, \
2219 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07002220 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002221 }
2222
2223#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002224 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002225
2226#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002227 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002228
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002229#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2230 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002231
2232#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002233 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07002234
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235static struct devinet_sysctl_table {
2236 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00002237 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238} devinet_sysctl = {
2239 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07002240 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002241 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07002242 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
2243
2244 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
2245 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
2246 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
2247 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
2248 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
2249 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
2250 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00002251 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08002252 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002253 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
2254 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
2255 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
2256 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
2257 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
2258 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
2259 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
2260 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
2261 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08002262 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00002263 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
William Manley5c6fe012013-08-06 19:03:14 +01002264 DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
2265 "force_igmp_version"),
William Manley26900482013-08-06 19:03:15 +01002266 DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
2267 "igmpv2_unsolicited_report_interval"),
2268 DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
2269 "igmpv3_unsolicited_report_interval"),
Andy Gospodarek0eeb0752015-06-23 13:45:37 -04002270 DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
2271 "ignore_routes_with_linkdown"),
Johannes Berg97daf332016-02-04 13:31:18 +01002272 DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
2273 "drop_gratuitous_arp"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002274
2275 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2276 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002277 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
2278 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00002279 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2280 "route_localnet"),
Johannes Berg12b74df2016-02-04 13:31:17 +01002281 DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
2282 "drop_unicast_in_l2_multicast"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284};
2285
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002286static int __devinet_sysctl_register(struct net *net, char *dev_name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002287 int ifindex, struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288{
2289 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002290 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002291 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11002292
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002293 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002295 goto out;
2296
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
2298 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07002299 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002300 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 }
2302
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002303 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002305 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002307 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308
2309 p->sysctl = t;
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002310
David Ahern3b022862017-03-28 14:28:02 -07002311 inet_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_ALL,
2312 ifindex, p);
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002313 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002315free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002317out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002318 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319}
2320
David Ahernb5c96412017-03-28 14:28:03 -07002321static void __devinet_sysctl_unregister(struct net *net,
2322 struct ipv4_devconf *cnf, int ifindex)
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002323{
2324 struct devinet_sysctl_table *t = cnf->sysctl;
2325
David Ahernb5c96412017-03-28 14:28:03 -07002326 if (t) {
2327 cnf->sysctl = NULL;
2328 unregister_net_sysctl_table(t->sysctl_header);
2329 kfree(t);
2330 }
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002331
David Ahernb5c96412017-03-28 14:28:03 -07002332 inet_netconf_notify_devconf(net, RTM_DELNETCONF, 0, ifindex, NULL);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002333}
2334
WANG Cong20e61da2014-07-25 15:25:08 -07002335static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002336{
WANG Cong20e61da2014-07-25 15:25:08 -07002337 int err;
2338
2339 if (!sysctl_dev_name_is_allowed(idev->dev->name))
2340 return -EINVAL;
2341
2342 err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
2343 if (err)
2344 return err;
2345 err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002346 idev->dev->ifindex, &idev->cnf);
WANG Cong20e61da2014-07-25 15:25:08 -07002347 if (err)
2348 neigh_sysctl_unregister(idev->arp_parms);
2349 return err;
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002350}
2351
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002352static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353{
David Ahernb5c96412017-03-28 14:28:03 -07002354 struct net *net = dev_net(idev->dev);
2355
2356 __devinet_sysctl_unregister(net, &idev->cnf, idev->dev->ifindex);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002357 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002360static struct ctl_table ctl_forward_entry[] = {
2361 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002362 .procname = "ip_forward",
2363 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00002364 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002365 .maxlen = sizeof(int),
2366 .mode = 0644,
2367 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002368 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002369 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002370 },
2371 { },
2372};
Eric Dumazet2a75de02008-01-05 23:08:49 -08002373#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002374
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002375static __net_init int devinet_init_net(struct net *net)
2376{
2377 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002378 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002379#ifdef CONFIG_SYSCTL
2380 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002381 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002382#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002383
2384 err = -ENOMEM;
2385 all = &ipv4_devconf;
2386 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002387
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002388 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002389 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002390 if (!all)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002391 goto err_alloc_all;
2392
2393 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002394 if (!dflt)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002395 goto err_alloc_dflt;
2396
Eric Dumazet2a75de02008-01-05 23:08:49 -08002397#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002398 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002399 if (!tbl)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002400 goto err_alloc_ctl;
2401
Eric W. Biederman02291682010-02-14 03:25:51 +00002402 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002403 tbl[0].extra1 = all;
2404 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002405#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002406 }
2407
2408#ifdef CONFIG_SYSCTL
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002409 err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002410 if (err < 0)
2411 goto err_reg_all;
2412
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002413 err = __devinet_sysctl_register(net, "default",
2414 NETCONFA_IFINDEX_DEFAULT, dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002415 if (err < 0)
2416 goto err_reg_dflt;
2417
2418 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002419 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Ian Morris51456b22015-04-03 09:17:26 +01002420 if (!forw_hdr)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002421 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002422 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002423#endif
2424
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002425 net->ipv4.devconf_all = all;
2426 net->ipv4.devconf_dflt = dflt;
2427 return 0;
2428
2429#ifdef CONFIG_SYSCTL
2430err_reg_ctl:
David Ahernb5c96412017-03-28 14:28:03 -07002431 __devinet_sysctl_unregister(net, dflt, NETCONFA_IFINDEX_DEFAULT);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002432err_reg_dflt:
David Ahernb5c96412017-03-28 14:28:03 -07002433 __devinet_sysctl_unregister(net, all, NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002434err_reg_all:
2435 if (tbl != ctl_forward_entry)
2436 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002437err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08002438#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002439 if (dflt != &ipv4_devconf_dflt)
2440 kfree(dflt);
2441err_alloc_dflt:
2442 if (all != &ipv4_devconf)
2443 kfree(all);
2444err_alloc_all:
2445 return err;
2446}
2447
2448static __net_exit void devinet_exit_net(struct net *net)
2449{
Eric Dumazet2a75de02008-01-05 23:08:49 -08002450#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002451 struct ctl_table *tbl;
2452
2453 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002454 unregister_net_sysctl_table(net->ipv4.forw_hdr);
David Ahernb5c96412017-03-28 14:28:03 -07002455 __devinet_sysctl_unregister(net, net->ipv4.devconf_dflt,
2456 NETCONFA_IFINDEX_DEFAULT);
2457 __devinet_sysctl_unregister(net, net->ipv4.devconf_all,
2458 NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002459 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08002460#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002461 kfree(net->ipv4.devconf_dflt);
2462 kfree(net->ipv4.devconf_all);
2463}
2464
2465static __net_initdata struct pernet_operations devinet_ops = {
2466 .init = devinet_init_net,
2467 .exit = devinet_exit_net,
2468};
2469
Daniel Borkmann207895fd32015-01-29 12:15:03 +01002470static struct rtnl_af_ops inet_af_ops __read_mostly = {
Thomas Graf9f0f7272010-11-16 04:32:48 +00002471 .family = AF_INET,
2472 .fill_link_af = inet_fill_link_af,
2473 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00002474 .validate_link_af = inet_validate_link_af,
2475 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00002476};
2477
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478void __init devinet_init(void)
2479{
David S. Millerfd23c3b2011-02-18 12:42:28 -08002480 int i;
2481
2482 for (i = 0; i < IN4_ADDR_HSIZE; i++)
2483 INIT_HLIST_HEAD(&inet_addr_lst[i]);
2484
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002485 register_pernet_subsys(&devinet_ops);
2486
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 register_gifconf(PF_INET, inet_gifconf);
2488 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07002489
viresh kumar906e0732014-01-22 12:23:32 +05302490 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +00002491
Thomas Graf9f0f7272010-11-16 04:32:48 +00002492 rtnl_af_register(&inet_af_ops);
2493
Florian Westphalb97bac62017-08-09 20:41:48 +02002494 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, 0);
2495 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, 0);
2496 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, 0);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002497 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
Florian Westphalb97bac62017-08-09 20:41:48 +02002498 inet_netconf_dump_devconf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499}