blob: 40f001782c1b37314ecd197ab65cb3adc68f50c7 [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 */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001051 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 sin->sin_addr.s_addr = ifa->ifa_local;
Al Viro03aef172017-07-01 07:53:12 -04001053 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054
1055 case SIOCGIFBRDADDR: /* Get the broadcast address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001056 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 sin->sin_addr.s_addr = ifa->ifa_broadcast;
Al Viro03aef172017-07-01 07:53:12 -04001058 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
1060 case SIOCGIFDSTADDR: /* Get the destination address */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001061 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 sin->sin_addr.s_addr = ifa->ifa_address;
Al Viro03aef172017-07-01 07:53:12 -04001063 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
1065 case SIOCGIFNETMASK: /* Get the netmask for the interface */
Tonghao Zhang30e948a2018-01-28 03:38:58 -08001066 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 sin->sin_addr.s_addr = ifa->ifa_mask;
Al Viro03aef172017-07-01 07:53:12 -04001068 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
1070 case SIOCSIFFLAGS:
1071 if (colon) {
1072 ret = -EADDRNOTAVAIL;
1073 if (!ifa)
1074 break;
1075 ret = 0;
Al Viro03aef172017-07-01 07:53:12 -04001076 if (!(ifr->ifr_flags & IFF_UP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 inet_del_ifa(in_dev, ifap, 1);
1078 break;
1079 }
Al Viro03aef172017-07-01 07:53:12 -04001080 ret = dev_change_flags(dev, ifr->ifr_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 break;
1082
1083 case SIOCSIFADDR: /* Set interface address (and family) */
1084 ret = -EINVAL;
1085 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1086 break;
1087
1088 if (!ifa) {
1089 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001090 ifa = inet_alloc_ifa();
1091 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 break;
Xi Wangc7e2e1d2013-01-05 11:19:24 +00001093 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 if (colon)
Al Viro03aef172017-07-01 07:53:12 -04001095 memcpy(ifa->ifa_label, ifr->ifr_name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 else
1097 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1098 } else {
1099 ret = 0;
1100 if (ifa->ifa_local == sin->sin_addr.s_addr)
1101 break;
1102 inet_del_ifa(in_dev, ifap, 0);
1103 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -08001104 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 }
1106
1107 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
1108
1109 if (!(dev->flags & IFF_POINTOPOINT)) {
1110 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
1111 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
1112 if ((dev->flags & IFF_BROADCAST) &&
1113 ifa->ifa_prefixlen < 31)
1114 ifa->ifa_broadcast = ifa->ifa_address |
1115 ~ifa->ifa_mask;
1116 } else {
1117 ifa->ifa_prefixlen = 32;
1118 ifa->ifa_mask = inet_make_mask(32);
1119 }
Jiri Pirko5c766d62013-01-24 09:41:41 +00001120 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 ret = inet_set_ifa(dev, ifa);
1122 break;
1123
1124 case SIOCSIFBRDADDR: /* Set the broadcast address */
1125 ret = 0;
1126 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
1127 inet_del_ifa(in_dev, ifap, 0);
1128 ifa->ifa_broadcast = sin->sin_addr.s_addr;
1129 inet_insert_ifa(ifa);
1130 }
1131 break;
1132
1133 case SIOCSIFDSTADDR: /* Set the destination address */
1134 ret = 0;
1135 if (ifa->ifa_address == sin->sin_addr.s_addr)
1136 break;
1137 ret = -EINVAL;
1138 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1139 break;
1140 ret = 0;
1141 inet_del_ifa(in_dev, ifap, 0);
1142 ifa->ifa_address = sin->sin_addr.s_addr;
1143 inet_insert_ifa(ifa);
1144 break;
1145
1146 case SIOCSIFNETMASK: /* Set the netmask for the interface */
1147
1148 /*
1149 * The mask we set must be legal.
1150 */
1151 ret = -EINVAL;
1152 if (bad_mask(sin->sin_addr.s_addr, 0))
1153 break;
1154 ret = 0;
1155 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -07001156 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 inet_del_ifa(in_dev, ifap, 0);
1158 ifa->ifa_mask = sin->sin_addr.s_addr;
1159 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
1160
1161 /* See if current broadcast address matches
1162 * with current netmask, then recalculate
1163 * the broadcast address. Otherwise it's a
1164 * funny address, so don't touch it since
1165 * the user seems to know what (s)he's doing...
1166 */
1167 if ((dev->flags & IFF_BROADCAST) &&
1168 (ifa->ifa_prefixlen < 31) &&
1169 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -05001170 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 ifa->ifa_broadcast = (ifa->ifa_local |
1172 ~sin->sin_addr.s_addr);
1173 }
1174 inet_insert_ifa(ifa);
1175 }
1176 break;
1177 }
1178done:
1179 rtnl_unlock();
1180out:
1181 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182}
1183
Al Viro36fd6332017-06-26 13:19:16 -04001184static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185{
Herbert Xue5ed6392005-10-03 14:35:55 -07001186 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 struct in_ifaddr *ifa;
1188 struct ifreq ifr;
1189 int done = 0;
1190
Al Viro36fd6332017-06-26 13:19:16 -04001191 if (WARN_ON(size > sizeof(struct ifreq)))
1192 goto out;
1193
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001194 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 goto out;
1196
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001197 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 if (!buf) {
Al Viro36fd6332017-06-26 13:19:16 -04001199 done += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 continue;
1201 }
Al Viro36fd6332017-06-26 13:19:16 -04001202 if (len < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 break;
1204 memset(&ifr, 0, sizeof(struct ifreq));
Dan Carpenter4299c8a2013-07-29 22:15:19 +03001205 strcpy(ifr.ifr_name, ifa->ifa_label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206
1207 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
1208 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1209 ifa->ifa_local;
1210
Al Viro36fd6332017-06-26 13:19:16 -04001211 if (copy_to_user(buf + done, &ifr, size)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 done = -EFAULT;
1213 break;
1214 }
Al Viro36fd6332017-06-26 13:19:16 -04001215 len -= size;
1216 done += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 }
1218out:
1219 return done;
1220}
1221
Gao Feng8b57fd12017-03-10 12:38:47 +08001222static __be32 in_dev_select_addr(const struct in_device *in_dev,
1223 int scope)
1224{
1225 for_primary_ifa(in_dev) {
1226 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1227 ifa->ifa_scope <= scope)
1228 return ifa->ifa_local;
1229 } endfor_ifa(in_dev);
1230
1231 return 0;
1232}
1233
Al Viroa61ced52006-09-26 21:27:54 -07001234__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235{
Al Viroa61ced52006-09-26 21:27:54 -07001236 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001238 struct net *net = dev_net(dev);
David Ahern3f2fb9a2016-02-24 11:47:02 -08001239 int master_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
1241 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001242 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 if (!in_dev)
1244 goto no_in_dev;
1245
1246 for_primary_ifa(in_dev) {
1247 if (ifa->ifa_scope > scope)
1248 continue;
1249 if (!dst || inet_ifa_match(dst, ifa)) {
1250 addr = ifa->ifa_local;
1251 break;
1252 }
1253 if (!addr)
1254 addr = ifa->ifa_local;
1255 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
1257 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001258 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001259no_in_dev:
David Ahern3f2fb9a2016-02-24 11:47:02 -08001260 master_idx = l3mdev_master_ifindex_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261
David Lamparter17b693c2016-02-24 11:47:03 -08001262 /* For VRFs, the VRF device takes the place of the loopback device,
1263 * with addresses on it being preferred. Note in such cases the
1264 * loopback device will be among the devices that fail the master_idx
1265 * equality check in the loop below.
1266 */
1267 if (master_idx &&
1268 (dev = dev_get_by_index_rcu(net, master_idx)) &&
1269 (in_dev = __in_dev_get_rcu(dev))) {
Gao Feng8b57fd12017-03-10 12:38:47 +08001270 addr = in_dev_select_addr(in_dev, scope);
1271 if (addr)
1272 goto out_unlock;
David Lamparter17b693c2016-02-24 11:47:03 -08001273 }
1274
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 /* Not loopback addresses on loopback should be preferred
Stephen Hemmingerca9f1fd2015-02-14 13:47:54 -05001276 in this case. It is important that lo is the first interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 in dev_base list.
1278 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001279 for_each_netdev_rcu(net, dev) {
David Ahern3f2fb9a2016-02-24 11:47:02 -08001280 if (l3mdev_master_ifindex_rcu(dev) != master_idx)
1281 continue;
1282
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001283 in_dev = __in_dev_get_rcu(dev);
1284 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 continue;
1286
Gao Feng8b57fd12017-03-10 12:38:47 +08001287 addr = in_dev_select_addr(in_dev, scope);
1288 if (addr)
1289 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001291out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 return addr;
1294}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001295EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
Al Viro60cad5d2006-09-26 22:17:09 -07001297static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1298 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299{
1300 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001301 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302
1303 for_ifa(in_dev) {
1304 if (!addr &&
1305 (local == ifa->ifa_local || !local) &&
1306 ifa->ifa_scope <= scope) {
1307 addr = ifa->ifa_local;
1308 if (same)
1309 break;
1310 }
1311 if (!same) {
1312 same = (!local || inet_ifa_match(local, ifa)) &&
1313 (!dst || inet_ifa_match(dst, ifa));
1314 if (same && addr) {
1315 if (local || !dst)
1316 break;
1317 /* Is the selected addr into dst subnet? */
1318 if (inet_ifa_match(addr, ifa))
1319 break;
1320 /* No, then can we use new local src? */
1321 if (ifa->ifa_scope <= scope) {
1322 addr = ifa->ifa_local;
1323 break;
1324 }
1325 /* search for large dst subnet for addr */
1326 same = 0;
1327 }
1328 }
1329 } endfor_ifa(in_dev);
1330
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001331 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332}
1333
1334/*
1335 * Confirm that local IP address exists using wildcards:
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001336 * - net: netns to check, cannot be NULL
1337 * - in_dev: only on this interface, NULL=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 * - dst: only in the same subnet as dst, 0=any dst
1339 * - local: address, 0=autoselect the local address
1340 * - scope: maximum allowed scope value for the local address
1341 */
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001342__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001343 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344{
Al Viro60cad5d2006-09-26 22:17:09 -07001345 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001346 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
Ian Morris00db4122015-04-03 09:17:27 +01001348 if (in_dev)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001349 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001352 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001353 in_dev = __in_dev_get_rcu(dev);
1354 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 addr = confirm_addr_indev(in_dev, dst, local, scope);
1356 if (addr)
1357 break;
1358 }
1359 }
1360 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
1362 return addr;
1363}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001364EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
1366/*
1367 * Device notifier
1368 */
1369
1370int register_inetaddr_notifier(struct notifier_block *nb)
1371{
Alan Sterne041c682006-03-27 01:16:30 -08001372 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001374EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375
1376int unregister_inetaddr_notifier(struct notifier_block *nb)
1377{
Alan Sterne041c682006-03-27 01:16:30 -08001378 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001380EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381
Krister Johansen3ad7d242017-06-08 13:12:14 -07001382int register_inetaddr_validator_notifier(struct notifier_block *nb)
1383{
1384 return blocking_notifier_chain_register(&inetaddr_validator_chain, nb);
1385}
1386EXPORT_SYMBOL(register_inetaddr_validator_notifier);
1387
1388int unregister_inetaddr_validator_notifier(struct notifier_block *nb)
1389{
1390 return blocking_notifier_chain_unregister(&inetaddr_validator_chain,
1391 nb);
1392}
1393EXPORT_SYMBOL(unregister_inetaddr_validator_notifier);
1394
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001395/* Rename ifa_labels for a device name change. Make some effort to preserve
1396 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397*/
1398static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001399{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 struct in_ifaddr *ifa;
1401 int named = 0;
1402
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001403 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1404 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
1406 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001407 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001409 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001410 dot = strchr(old, ':');
Ian Morris51456b22015-04-03 09:17:26 +01001411 if (!dot) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001412 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 dot = old;
1414 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001415 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001416 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001417 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001418 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001419skip:
1420 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001421 }
1422}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
Eric Dumazet40384992012-08-03 21:06:50 +00001424static bool inetdev_valid_mtu(unsigned int mtu)
Breno Leitao06770842008-09-02 17:28:58 -07001425{
Eric Dumazetb5476022017-12-11 07:17:39 -08001426 return mtu >= IPV4_MIN_MTU;
Breno Leitao06770842008-09-02 17:28:58 -07001427}
1428
Ian Campbelld11327ad2011-02-11 07:44:16 +00001429static void inetdev_send_gratuitous_arp(struct net_device *dev,
1430 struct in_device *in_dev)
1431
1432{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001433 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001434
Zoltan Kissb76d0782011-07-24 13:09:30 +00001435 for (ifa = in_dev->ifa_list; ifa;
1436 ifa = ifa->ifa_next) {
1437 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1438 ifa->ifa_local, dev,
1439 ifa->ifa_local, NULL,
1440 dev->dev_addr, NULL);
1441 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001442}
1443
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444/* Called only under RTNL semaphore */
1445
1446static int inetdev_event(struct notifier_block *this, unsigned long event,
1447 void *ptr)
1448{
Jiri Pirko351638e2013-05-28 01:30:21 +00001449 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazet748e2d92012-08-22 21:50:59 +00001450 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451
1452 ASSERT_RTNL();
1453
1454 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001455 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 in_dev = inetdev_init(dev);
WANG Cong20e61da2014-07-25 15:25:08 -07001457 if (IS_ERR(in_dev))
1458 return notifier_from_errno(PTR_ERR(in_dev));
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001459 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001460 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1461 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001462 }
Breno Leitao06770842008-09-02 17:28:58 -07001463 } else if (event == NETDEV_CHANGEMTU) {
1464 /* Re-enabling IP */
1465 if (inetdev_valid_mtu(dev->mtu))
1466 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 }
1468 goto out;
1469 }
1470
1471 switch (event) {
1472 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001473 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001474 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 break;
1476 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001477 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001479 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001480 struct in_ifaddr *ifa = inet_alloc_ifa();
1481
1482 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001483 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 ifa->ifa_local =
1485 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1486 ifa->ifa_prefixlen = 8;
1487 ifa->ifa_mask = inet_make_mask(8);
1488 in_dev_hold(in_dev);
1489 ifa->ifa_dev = in_dev;
1490 ifa->ifa_scope = RT_SCOPE_HOST;
1491 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Jiri Pirko5c766d62013-01-24 09:41:41 +00001492 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1493 INFINITY_LIFE_TIME);
Jiri Pirkodfd15822014-01-07 15:55:45 +01001494 ipv4_devconf_setall(in_dev);
1495 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 inet_insert_ifa(ifa);
1497 }
1498 }
1499 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001500 /* fall through */
1501 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001502 if (!IN_DEV_ARP_NOTIFY(in_dev))
1503 break;
1504 /* fall through */
1505 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001506 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001507 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 break;
1509 case NETDEV_DOWN:
1510 ip_mc_down(in_dev);
1511 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001512 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001513 ip_mc_unmap(in_dev);
1514 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001515 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001516 ip_mc_remap(in_dev);
1517 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001519 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 break;
Breno Leitao06770842008-09-02 17:28:58 -07001521 /* disable IP when MTU is not enough */
Gustavo A. R. Silvafcfd6df2017-10-16 15:48:55 -05001522 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 case NETDEV_UNREGISTER:
1524 inetdev_destroy(in_dev);
1525 break;
1526 case NETDEV_CHANGENAME:
1527 /* Do not notify about label change, this event is
1528 * not interesting to applications using netlink.
1529 */
1530 inetdev_changename(dev, in_dev);
1531
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001532 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001533 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 break;
1535 }
1536out:
1537 return NOTIFY_DONE;
1538}
1539
1540static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001541 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542};
1543
Eric Dumazet40384992012-08-03 21:06:50 +00001544static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001545{
1546 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1547 + nla_total_size(4) /* IFA_ADDRESS */
1548 + nla_total_size(4) /* IFA_LOCAL */
1549 + nla_total_size(4) /* IFA_BROADCAST */
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001550 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001551 + nla_total_size(4) /* IFA_FLAGS */
1552 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
Thomas Graf339bf982006-11-10 14:10:15 -08001553}
1554
Jiri Pirko5c766d62013-01-24 09:41:41 +00001555static inline u32 cstamp_delta(unsigned long cstamp)
1556{
1557 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1558}
1559
1560static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1561 unsigned long tstamp, u32 preferred, u32 valid)
1562{
1563 struct ifa_cacheinfo ci;
1564
1565 ci.cstamp = cstamp_delta(cstamp);
1566 ci.tstamp = cstamp_delta(tstamp);
1567 ci.ifa_prefered = preferred;
1568 ci.ifa_valid = valid;
1569
1570 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1571}
1572
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001574 u32 portid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575{
1576 struct ifaddrmsg *ifm;
1577 struct nlmsghdr *nlh;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001578 u32 preferred, valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
Eric W. Biederman15e47302012-09-07 20:12:54 +00001580 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
Ian Morris51456b22015-04-03 09:17:26 +01001581 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08001582 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001583
1584 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 ifm->ifa_family = AF_INET;
1586 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001587 ifm->ifa_flags = ifa->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 ifm->ifa_scope = ifa->ifa_scope;
1589 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
Jiri Pirko5c766d62013-01-24 09:41:41 +00001591 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1592 preferred = ifa->ifa_preferred_lft;
1593 valid = ifa->ifa_valid_lft;
1594 if (preferred != INFINITY_LIFE_TIME) {
1595 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1596
1597 if (preferred > tval)
1598 preferred -= tval;
1599 else
1600 preferred = 0;
1601 if (valid != INFINITY_LIFE_TIME) {
1602 if (valid > tval)
1603 valid -= tval;
1604 else
1605 valid = 0;
1606 }
1607 }
1608 } else {
1609 preferred = INFINITY_LIFE_TIME;
1610 valid = INFINITY_LIFE_TIME;
1611 }
David S. Millerf3756b72012-04-01 20:39:02 -04001612 if ((ifa->ifa_address &&
Jiri Benc930345e2015-03-29 16:59:25 +02001613 nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001614 (ifa->ifa_local &&
Jiri Benc930345e2015-03-29 16:59:25 +02001615 nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001616 (ifa->ifa_broadcast &&
Jiri Benc930345e2015-03-29 16:59:25 +02001617 nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001618 (ifa->ifa_label[0] &&
Jiri Pirko5c766d62013-01-24 09:41:41 +00001619 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001620 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
Jiri Pirko5c766d62013-01-24 09:41:41 +00001621 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1622 preferred, valid))
David S. Millerf3756b72012-04-01 20:39:02 -04001623 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001624
Johannes Berg053c0952015-01-16 22:09:00 +01001625 nlmsg_end(skb, nlh);
1626 return 0;
Thomas Graf47f68512006-08-04 23:04:36 -07001627
1628nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001629 nlmsg_cancel(skb, nlh);
1630 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631}
1632
1633static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1634{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001635 struct net *net = sock_net(skb->sk);
Eric Dumazeteec4df92009-11-12 07:44:25 +00001636 int h, s_h;
1637 int idx, s_idx;
1638 int ip_idx, s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 struct net_device *dev;
1640 struct in_device *in_dev;
1641 struct in_ifaddr *ifa;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001642 struct hlist_head *head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
Eric Dumazeteec4df92009-11-12 07:44:25 +00001644 s_h = cb->args[0];
1645 s_idx = idx = cb->args[1];
1646 s_ip_idx = ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647
Eric Dumazeteec4df92009-11-12 07:44:25 +00001648 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1649 idx = 0;
1650 head = &net->dev_index_head[h];
1651 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001652 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1653 net->dev_base_seq;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001654 hlist_for_each_entry_rcu(dev, head, index_hlist) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001655 if (idx < s_idx)
1656 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001657 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001658 s_ip_idx = 0;
1659 in_dev = __in_dev_get_rcu(dev);
1660 if (!in_dev)
1661 goto cont;
1662
1663 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1664 ifa = ifa->ifa_next, ip_idx++) {
1665 if (ip_idx < s_ip_idx)
1666 continue;
1667 if (inet_fill_ifaddr(skb, ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001668 NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 cb->nlh->nlmsg_seq,
Johannes Berg053c0952015-01-16 22:09:00 +01001670 RTM_NEWADDR, NLM_F_MULTI) < 0) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001671 rcu_read_unlock();
1672 goto done;
1673 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001674 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Eric Dumazeteec4df92009-11-12 07:44:25 +00001675 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001676cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001677 idx++;
1678 }
1679 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 }
1681
1682done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001683 cb->args[0] = h;
1684 cb->args[1] = idx;
1685 cb->args[2] = ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
1687 return skb->len;
1688}
1689
Jianjun Kong539afed2008-11-03 02:48:48 -08001690static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001691 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692{
Thomas Graf47f68512006-08-04 23:04:36 -07001693 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001694 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1695 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001696 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001698 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001699 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001700 if (!skb)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001701 goto errout;
1702
Eric W. Biederman15e47302012-09-07 20:12:54 +00001703 err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001704 if (err < 0) {
1705 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1706 WARN_ON(err == -EMSGSIZE);
1707 kfree_skb(skb);
1708 goto errout;
1709 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001710 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001711 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001712errout:
1713 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001714 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715}
1716
Arad, Ronenb1974ed2015-10-19 09:23:28 -07001717static size_t inet_get_link_af_size(const struct net_device *dev,
1718 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001719{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001720 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001721
1722 if (!in_dev)
1723 return 0;
1724
1725 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1726}
1727
Sowmini Varadhand5566fd2015-09-11 16:48:48 -04001728static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
1729 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001730{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001731 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001732 struct nlattr *nla;
1733 int i;
1734
1735 if (!in_dev)
1736 return -ENODATA;
1737
1738 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
Ian Morris51456b22015-04-03 09:17:26 +01001739 if (!nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001740 return -EMSGSIZE;
1741
1742 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1743 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1744
1745 return 0;
1746}
1747
1748static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1749 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1750};
1751
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001752static int inet_validate_link_af(const struct net_device *dev,
1753 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001754{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001755 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1756 int err, rem;
1757
Florian Westphal5fa85a02017-10-16 15:44:36 +02001758 if (dev && !__in_dev_get_rcu(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001759 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001760
Johannes Bergfceb6432017-04-12 14:34:07 +02001761 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy, NULL);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001762 if (err < 0)
1763 return err;
1764
1765 if (tb[IFLA_INET_CONF]) {
1766 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1767 int cfgid = nla_type(a);
1768
1769 if (nla_len(a) < 4)
1770 return -EINVAL;
1771
1772 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1773 return -EINVAL;
1774 }
1775 }
1776
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001777 return 0;
1778}
1779
1780static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1781{
Florian Westphal5fa85a02017-10-16 15:44:36 +02001782 struct in_device *in_dev = __in_dev_get_rcu(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001783 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1784 int rem;
1785
1786 if (!in_dev)
1787 return -EAFNOSUPPORT;
1788
Johannes Bergfceb6432017-04-12 14:34:07 +02001789 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0)
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001790 BUG();
1791
Thomas Graf9f0f7272010-11-16 04:32:48 +00001792 if (tb[IFLA_INET_CONF]) {
1793 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1794 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1795 }
1796
1797 return 0;
1798}
1799
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001800static int inet_netconf_msgsize_devconf(int type)
1801{
1802 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1803 + nla_total_size(4); /* NETCONFA_IFINDEX */
Zhang Shengju136ba622016-03-10 08:55:50 +00001804 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001805
Zhang Shengju136ba622016-03-10 08:55:50 +00001806 if (type == NETCONFA_ALL)
1807 all = true;
1808
1809 if (all || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001810 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001811 if (all || type == NETCONFA_RP_FILTER)
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001812 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001813 if (all || type == NETCONFA_MC_FORWARDING)
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001814 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001815 if (all || type == NETCONFA_PROXY_NEIGH)
stephen hemmingerf085ff12013-12-12 13:06:50 -08001816 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001817 if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001818 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001819
1820 return size;
1821}
1822
1823static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1824 struct ipv4_devconf *devconf, u32 portid,
1825 u32 seq, int event, unsigned int flags,
1826 int type)
1827{
1828 struct nlmsghdr *nlh;
1829 struct netconfmsg *ncm;
Zhang Shengju136ba622016-03-10 08:55:50 +00001830 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001831
1832 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1833 flags);
Ian Morris51456b22015-04-03 09:17:26 +01001834 if (!nlh)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001835 return -EMSGSIZE;
1836
Zhang Shengju136ba622016-03-10 08:55:50 +00001837 if (type == NETCONFA_ALL)
1838 all = true;
1839
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001840 ncm = nlmsg_data(nlh);
1841 ncm->ncm_family = AF_INET;
1842
1843 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1844 goto nla_put_failure;
1845
David Ahernb5c96412017-03-28 14:28:03 -07001846 if (!devconf)
1847 goto out;
1848
Zhang Shengju136ba622016-03-10 08:55:50 +00001849 if ((all || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001850 nla_put_s32(skb, NETCONFA_FORWARDING,
1851 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1852 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001853 if ((all || type == NETCONFA_RP_FILTER) &&
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001854 nla_put_s32(skb, NETCONFA_RP_FILTER,
1855 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
1856 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001857 if ((all || type == NETCONFA_MC_FORWARDING) &&
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001858 nla_put_s32(skb, NETCONFA_MC_FORWARDING,
1859 IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
1860 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001861 if ((all || type == NETCONFA_PROXY_NEIGH) &&
stephen hemminger09aea5d2013-12-17 22:35:52 -08001862 nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08001863 IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
1864 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001865 if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001866 nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
1867 IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
1868 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001869
David Ahernb5c96412017-03-28 14:28:03 -07001870out:
Johannes Berg053c0952015-01-16 22:09:00 +01001871 nlmsg_end(skb, nlh);
1872 return 0;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001873
1874nla_put_failure:
1875 nlmsg_cancel(skb, nlh);
1876 return -EMSGSIZE;
1877}
1878
David Ahern3b022862017-03-28 14:28:02 -07001879void inet_netconf_notify_devconf(struct net *net, int event, int type,
1880 int ifindex, struct ipv4_devconf *devconf)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001881{
1882 struct sk_buff *skb;
1883 int err = -ENOBUFS;
1884
Eric Dumazetfa178062016-07-08 05:18:24 +02001885 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001886 if (!skb)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001887 goto errout;
1888
1889 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
David Ahern3b022862017-03-28 14:28:02 -07001890 event, 0, type);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001891 if (err < 0) {
1892 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1893 WARN_ON(err == -EMSGSIZE);
1894 kfree_skb(skb);
1895 goto errout;
1896 }
Eric Dumazetfa178062016-07-08 05:18:24 +02001897 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001898 return;
1899errout:
1900 if (err < 0)
1901 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
1902}
1903
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001904static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
1905 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
1906 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001907 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
stephen hemminger09aea5d2013-12-17 22:35:52 -08001908 [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) },
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001909 [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001910};
1911
1912static int inet_netconf_get_devconf(struct sk_buff *in_skb,
David Ahernc21ef3e2017-04-16 09:48:24 -07001913 struct nlmsghdr *nlh,
1914 struct netlink_ext_ack *extack)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001915{
1916 struct net *net = sock_net(in_skb->sk);
1917 struct nlattr *tb[NETCONFA_MAX+1];
1918 struct netconfmsg *ncm;
1919 struct sk_buff *skb;
1920 struct ipv4_devconf *devconf;
1921 struct in_device *in_dev;
1922 struct net_device *dev;
1923 int ifindex;
1924 int err;
1925
1926 err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
David Ahernc21ef3e2017-04-16 09:48:24 -07001927 devconf_ipv4_policy, extack);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001928 if (err < 0)
1929 goto errout;
1930
Anton Protopopova97eb332016-02-16 21:43:16 -05001931 err = -EINVAL;
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001932 if (!tb[NETCONFA_IFINDEX])
1933 goto errout;
1934
1935 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
1936 switch (ifindex) {
1937 case NETCONFA_IFINDEX_ALL:
1938 devconf = net->ipv4.devconf_all;
1939 break;
1940 case NETCONFA_IFINDEX_DEFAULT:
1941 devconf = net->ipv4.devconf_dflt;
1942 break;
1943 default:
1944 dev = __dev_get_by_index(net, ifindex);
Ian Morris51456b22015-04-03 09:17:26 +01001945 if (!dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001946 goto errout;
1947 in_dev = __in_dev_get_rtnl(dev);
Ian Morris51456b22015-04-03 09:17:26 +01001948 if (!in_dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001949 goto errout;
1950 devconf = &in_dev->cnf;
1951 break;
1952 }
1953
1954 err = -ENOBUFS;
Eric Dumazetfa178062016-07-08 05:18:24 +02001955 skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001956 if (!skb)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001957 goto errout;
1958
1959 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
1960 NETLINK_CB(in_skb).portid,
1961 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
Zhang Shengju136ba622016-03-10 08:55:50 +00001962 NETCONFA_ALL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001963 if (err < 0) {
1964 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1965 WARN_ON(err == -EMSGSIZE);
1966 kfree_skb(skb);
1967 goto errout;
1968 }
1969 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
1970errout:
1971 return err;
1972}
1973
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001974static int inet_netconf_dump_devconf(struct sk_buff *skb,
1975 struct netlink_callback *cb)
1976{
1977 struct net *net = sock_net(skb->sk);
1978 int h, s_h;
1979 int idx, s_idx;
1980 struct net_device *dev;
1981 struct in_device *in_dev;
1982 struct hlist_head *head;
1983
1984 s_h = cb->args[0];
1985 s_idx = idx = cb->args[1];
1986
1987 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1988 idx = 0;
1989 head = &net->dev_index_head[h];
1990 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001991 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1992 net->dev_base_seq;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001993 hlist_for_each_entry_rcu(dev, head, index_hlist) {
1994 if (idx < s_idx)
1995 goto cont;
1996 in_dev = __in_dev_get_rcu(dev);
1997 if (!in_dev)
1998 goto cont;
1999
2000 if (inet_netconf_fill_devconf(skb, dev->ifindex,
2001 &in_dev->cnf,
2002 NETLINK_CB(cb->skb).portid,
2003 cb->nlh->nlmsg_seq,
2004 RTM_NEWNETCONF,
2005 NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002006 NETCONFA_ALL) < 0) {
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002007 rcu_read_unlock();
2008 goto done;
2009 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00002010 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002011cont:
2012 idx++;
2013 }
2014 rcu_read_unlock();
2015 }
2016 if (h == NETDEV_HASHENTRIES) {
2017 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
2018 net->ipv4.devconf_all,
2019 NETLINK_CB(cb->skb).portid,
2020 cb->nlh->nlmsg_seq,
2021 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002022 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002023 goto done;
2024 else
2025 h++;
2026 }
2027 if (h == NETDEV_HASHENTRIES + 1) {
2028 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
2029 net->ipv4.devconf_dflt,
2030 NETLINK_CB(cb->skb).portid,
2031 cb->nlh->nlmsg_seq,
2032 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00002033 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002034 goto done;
2035 else
2036 h++;
2037 }
2038done:
2039 cb->args[0] = h;
2040 cb->args[1] = idx;
2041
2042 return skb->len;
2043}
2044
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045#ifdef CONFIG_SYSCTL
2046
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002047static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07002048{
2049 struct net_device *dev;
2050
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002051 rcu_read_lock();
2052 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07002053 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002054
Herbert Xu31be3082007-06-04 23:35:37 -07002055 in_dev = __in_dev_get_rcu(dev);
2056 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002057 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07002058 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002059 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07002060}
2061
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002062/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002063static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002064{
2065 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002066 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002067
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002068 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002069 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
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_ALL,
2073 net->ipv4.devconf_all);
David Ahern3b022862017-03-28 14:28:02 -07002074 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2075 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002076 NETCONFA_IFINDEX_DEFAULT,
2077 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002078
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002079 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002080 struct in_device *in_dev;
Eric Dumazetfa178062016-07-08 05:18:24 +02002081
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002082 if (on)
2083 dev_disable_lro(dev);
Eric Dumazetfa178062016-07-08 05:18:24 +02002084
2085 in_dev = __in_dev_get_rtnl(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002086 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002087 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
David Ahern3b022862017-03-28 14:28:02 -07002088 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2089 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002090 dev->ifindex, &in_dev->cnf);
2091 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002092 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002093}
2094
stephen hemmingerf085ff12013-12-12 13:06:50 -08002095static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf)
2096{
2097 if (cnf == net->ipv4.devconf_dflt)
2098 return NETCONFA_IFINDEX_DEFAULT;
2099 else if (cnf == net->ipv4.devconf_all)
2100 return NETCONFA_IFINDEX_ALL;
2101 else {
2102 struct in_device *idev
2103 = container_of(cnf, struct in_device, cnf);
2104 return idev->dev->ifindex;
2105 }
2106}
2107
Joe Perchesfe2c6332013-06-11 23:04:25 -07002108static int devinet_conf_proc(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002109 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07002110 size_t *lenp, loff_t *ppos)
2111{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002112 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002113 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002114 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07002115
2116 if (write) {
2117 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002118 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07002119 int i = (int *)ctl->data - cnf->data;
stephen hemmingerf085ff12013-12-12 13:06:50 -08002120 int ifindex;
Herbert Xu31be3082007-06-04 23:35:37 -07002121
2122 set_bit(i, cnf->state);
2123
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002124 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002125 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00002126 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
2127 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002128 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002129 rt_cache_flush(net);
stephen hemmingerf085ff12013-12-12 13:06:50 -08002130
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002131 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
2132 new_value != old_value) {
stephen hemmingerf085ff12013-12-12 13:06:50 -08002133 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002134 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2135 NETCONFA_RP_FILTER,
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002136 ifindex, cnf);
2137 }
stephen hemmingerf085ff12013-12-12 13:06:50 -08002138 if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
2139 new_value != old_value) {
2140 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002141 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2142 NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002143 ifindex, cnf);
2144 }
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002145 if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
2146 new_value != old_value) {
2147 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002148 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2149 NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002150 ifindex, cnf);
2151 }
Herbert Xu31be3082007-06-04 23:35:37 -07002152 }
2153
2154 return ret;
2155}
2156
Joe Perchesfe2c6332013-06-11 23:04:25 -07002157static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002158 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 size_t *lenp, loff_t *ppos)
2160{
2161 int *valp = ctl->data;
2162 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00002163 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002164 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165
2166 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002167 struct net *net = ctl->extra2;
2168
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002169 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00002170 if (!rtnl_trylock()) {
2171 /* Restore the original values before restarting */
2172 *valp = val;
2173 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00002174 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00002175 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002176 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2177 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002178 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002179 struct ipv4_devconf *cnf = ctl->extra1;
2180 struct in_device *idev =
2181 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002182 if (*valp)
2183 dev_disable_lro(idev->dev);
David Ahern3b022862017-03-28 14:28:02 -07002184 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002185 NETCONFA_FORWARDING,
2186 idev->dev->ifindex,
2187 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002188 }
2189 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002190 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002191 } else
David Ahern3b022862017-03-28 14:28:02 -07002192 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2193 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002194 NETCONFA_IFINDEX_DEFAULT,
2195 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 }
2197
2198 return ret;
2199}
2200
Joe Perchesfe2c6332013-06-11 23:04:25 -07002201static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
David S. Miller323e1262010-12-12 21:55:08 -08002202 void __user *buffer,
2203 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204{
2205 int *valp = ctl->data;
2206 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002207 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07002208 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209
2210 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002211 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212
2213 return ret;
2214}
2215
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002216#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07002217 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07002218 .procname = name, \
2219 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00002220 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002221 .maxlen = sizeof(int), \
2222 .mode = mval, \
2223 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07002224 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002225 }
2226
2227#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002228 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002229
2230#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002231 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002232
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002233#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2234 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002235
2236#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002237 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07002238
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239static struct devinet_sysctl_table {
2240 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00002241 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242} devinet_sysctl = {
2243 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07002244 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002245 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07002246 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
2247
2248 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
2249 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
2250 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
2251 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
2252 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
2253 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
2254 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00002255 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08002256 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002257 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
2258 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
2259 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
2260 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
2261 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
2262 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
2263 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
2264 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
2265 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08002266 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00002267 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
William Manley5c6fe012013-08-06 19:03:14 +01002268 DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
2269 "force_igmp_version"),
William Manley26900482013-08-06 19:03:15 +01002270 DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
2271 "igmpv2_unsolicited_report_interval"),
2272 DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
2273 "igmpv3_unsolicited_report_interval"),
Andy Gospodarek0eeb0752015-06-23 13:45:37 -04002274 DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
2275 "ignore_routes_with_linkdown"),
Johannes Berg97daf332016-02-04 13:31:18 +01002276 DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
2277 "drop_gratuitous_arp"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002278
2279 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2280 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002281 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
2282 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00002283 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2284 "route_localnet"),
Johannes Berg12b74df2016-02-04 13:31:17 +01002285 DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
2286 "drop_unicast_in_l2_multicast"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288};
2289
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002290static int __devinet_sysctl_register(struct net *net, char *dev_name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002291 int ifindex, struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292{
2293 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002294 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002295 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11002296
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002297 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002299 goto out;
2300
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
2302 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07002303 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002304 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 }
2306
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002307 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002309 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002311 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312
2313 p->sysctl = t;
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002314
David Ahern3b022862017-03-28 14:28:02 -07002315 inet_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_ALL,
2316 ifindex, p);
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002317 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002319free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002321out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002322 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323}
2324
David Ahernb5c96412017-03-28 14:28:03 -07002325static void __devinet_sysctl_unregister(struct net *net,
2326 struct ipv4_devconf *cnf, int ifindex)
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002327{
2328 struct devinet_sysctl_table *t = cnf->sysctl;
2329
David Ahernb5c96412017-03-28 14:28:03 -07002330 if (t) {
2331 cnf->sysctl = NULL;
2332 unregister_net_sysctl_table(t->sysctl_header);
2333 kfree(t);
2334 }
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002335
David Ahernb5c96412017-03-28 14:28:03 -07002336 inet_netconf_notify_devconf(net, RTM_DELNETCONF, 0, ifindex, NULL);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002337}
2338
WANG Cong20e61da2014-07-25 15:25:08 -07002339static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002340{
WANG Cong20e61da2014-07-25 15:25:08 -07002341 int err;
2342
2343 if (!sysctl_dev_name_is_allowed(idev->dev->name))
2344 return -EINVAL;
2345
2346 err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
2347 if (err)
2348 return err;
2349 err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002350 idev->dev->ifindex, &idev->cnf);
WANG Cong20e61da2014-07-25 15:25:08 -07002351 if (err)
2352 neigh_sysctl_unregister(idev->arp_parms);
2353 return err;
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002354}
2355
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002356static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357{
David Ahernb5c96412017-03-28 14:28:03 -07002358 struct net *net = dev_net(idev->dev);
2359
2360 __devinet_sysctl_unregister(net, &idev->cnf, idev->dev->ifindex);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002361 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002364static struct ctl_table ctl_forward_entry[] = {
2365 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002366 .procname = "ip_forward",
2367 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00002368 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002369 .maxlen = sizeof(int),
2370 .mode = 0644,
2371 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002372 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002373 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002374 },
2375 { },
2376};
Eric Dumazet2a75de02008-01-05 23:08:49 -08002377#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002378
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002379static __net_init int devinet_init_net(struct net *net)
2380{
2381 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002382 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002383#ifdef CONFIG_SYSCTL
2384 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002385 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002386#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002387
2388 err = -ENOMEM;
2389 all = &ipv4_devconf;
2390 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002391
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002392 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002393 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002394 if (!all)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002395 goto err_alloc_all;
2396
2397 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002398 if (!dflt)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002399 goto err_alloc_dflt;
2400
Eric Dumazet2a75de02008-01-05 23:08:49 -08002401#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002402 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002403 if (!tbl)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002404 goto err_alloc_ctl;
2405
Eric W. Biederman02291682010-02-14 03:25:51 +00002406 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002407 tbl[0].extra1 = all;
2408 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002409#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002410 }
2411
2412#ifdef CONFIG_SYSCTL
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002413 err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002414 if (err < 0)
2415 goto err_reg_all;
2416
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002417 err = __devinet_sysctl_register(net, "default",
2418 NETCONFA_IFINDEX_DEFAULT, dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002419 if (err < 0)
2420 goto err_reg_dflt;
2421
2422 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002423 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Ian Morris51456b22015-04-03 09:17:26 +01002424 if (!forw_hdr)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002425 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002426 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002427#endif
2428
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002429 net->ipv4.devconf_all = all;
2430 net->ipv4.devconf_dflt = dflt;
2431 return 0;
2432
2433#ifdef CONFIG_SYSCTL
2434err_reg_ctl:
David Ahernb5c96412017-03-28 14:28:03 -07002435 __devinet_sysctl_unregister(net, dflt, NETCONFA_IFINDEX_DEFAULT);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002436err_reg_dflt:
David Ahernb5c96412017-03-28 14:28:03 -07002437 __devinet_sysctl_unregister(net, all, NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002438err_reg_all:
2439 if (tbl != ctl_forward_entry)
2440 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002441err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08002442#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002443 if (dflt != &ipv4_devconf_dflt)
2444 kfree(dflt);
2445err_alloc_dflt:
2446 if (all != &ipv4_devconf)
2447 kfree(all);
2448err_alloc_all:
2449 return err;
2450}
2451
2452static __net_exit void devinet_exit_net(struct net *net)
2453{
Eric Dumazet2a75de02008-01-05 23:08:49 -08002454#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002455 struct ctl_table *tbl;
2456
2457 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002458 unregister_net_sysctl_table(net->ipv4.forw_hdr);
David Ahernb5c96412017-03-28 14:28:03 -07002459 __devinet_sysctl_unregister(net, net->ipv4.devconf_dflt,
2460 NETCONFA_IFINDEX_DEFAULT);
2461 __devinet_sysctl_unregister(net, net->ipv4.devconf_all,
2462 NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002463 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08002464#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002465 kfree(net->ipv4.devconf_dflt);
2466 kfree(net->ipv4.devconf_all);
2467}
2468
2469static __net_initdata struct pernet_operations devinet_ops = {
2470 .init = devinet_init_net,
2471 .exit = devinet_exit_net,
2472};
2473
Daniel Borkmann207895f2015-01-29 12:15:03 +01002474static struct rtnl_af_ops inet_af_ops __read_mostly = {
Thomas Graf9f0f7272010-11-16 04:32:48 +00002475 .family = AF_INET,
2476 .fill_link_af = inet_fill_link_af,
2477 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00002478 .validate_link_af = inet_validate_link_af,
2479 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00002480};
2481
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482void __init devinet_init(void)
2483{
David S. Millerfd23c3b2011-02-18 12:42:28 -08002484 int i;
2485
2486 for (i = 0; i < IN4_ADDR_HSIZE; i++)
2487 INIT_HLIST_HEAD(&inet_addr_lst[i]);
2488
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002489 register_pernet_subsys(&devinet_ops);
2490
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 register_gifconf(PF_INET, inet_gifconf);
2492 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07002493
viresh kumar906e0732014-01-22 12:23:32 +05302494 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +00002495
Thomas Graf9f0f7272010-11-16 04:32:48 +00002496 rtnl_af_register(&inet_af_ops);
2497
Florian Westphalb97bac62017-08-09 20:41:48 +02002498 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, 0);
2499 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, 0);
2500 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, 0);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002501 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
Florian Westphalb97bac62017-08-09 20:41:48 +02002502 inet_netconf_dump_devconf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503}