blob: df14815a3b8ce74aeb613458ffaf5f6eee4a263d [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{
Eric Dumazet40384992012-08-03 21:06:50 +0000140 u32 hash = inet_addr_hash(net, addr);
David S. Miller9435eb12011-02-18 12:43:09 -0800141 struct net_device *result = NULL;
142 struct in_ifaddr *ifa;
David S. Miller9435eb12011-02-18 12:43:09 -0800143
144 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800145 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash) {
David S. Millere0660082011-03-03 11:24:19 -0800146 if (ifa->ifa_local == addr) {
Eric Dumazet40384992012-08-03 21:06:50 +0000147 struct net_device *dev = ifa->ifa_dev->dev;
148
149 if (!net_eq(dev_net(dev), net))
150 continue;
David S. Miller9435eb12011-02-18 12:43:09 -0800151 result = dev;
152 break;
153 }
154 }
David S. Miller406b6f92011-03-22 21:56:23 -0700155 if (!result) {
156 struct flowi4 fl4 = { .daddr = addr };
157 struct fib_result res = { 0 };
158 struct fib_table *local;
159
160 /* Fallback to FIB local table so that communication
161 * over loopback subnets work.
162 */
163 local = fib_get_table(net, RT_TABLE_LOCAL);
164 if (local &&
165 !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
166 res.type == RTN_LOCAL)
167 result = FIB_RES_DEV(res);
168 }
David S. Miller9435eb12011-02-18 12:43:09 -0800169 if (result && devref)
170 dev_hold(result);
171 rcu_read_unlock();
172 return result;
173}
174EXPORT_SYMBOL(__ip_dev_find);
175
Thomas Grafd6062cb2006-08-15 00:33:59 -0700176static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
Alan Sterne041c682006-03-27 01:16:30 -0800178static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
180 int destroy);
181#ifdef CONFIG_SYSCTL
WANG Cong20e61da2014-07-25 15:25:08 -0700182static int devinet_sysctl_register(struct in_device *idev);
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800183static void devinet_sysctl_unregister(struct in_device *idev);
184#else
WANG Cong20e61da2014-07-25 15:25:08 -0700185static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800186{
WANG Cong20e61da2014-07-25 15:25:08 -0700187 return 0;
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800188}
Eric Dumazet40384992012-08-03 21:06:50 +0000189static void devinet_sysctl_unregister(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800190{
191}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192#endif
193
194/* Locks all the inet devices. */
195
196static struct in_ifaddr *inet_alloc_ifa(void)
197{
Alexey Dobriyan93adcc82008-10-28 13:25:09 -0700198 return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199}
200
201static void inet_rcu_free_ifa(struct rcu_head *head)
202{
203 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
204 if (ifa->ifa_dev)
205 in_dev_put(ifa->ifa_dev);
206 kfree(ifa);
207}
208
Eric Dumazet40384992012-08-03 21:06:50 +0000209static void inet_free_ifa(struct in_ifaddr *ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210{
211 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
212}
213
214void in_dev_finish_destroy(struct in_device *idev)
215{
216 struct net_device *dev = idev->dev;
217
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700218 WARN_ON(idev->ifa_list);
219 WARN_ON(idev->mc_list);
Eric Dumazete9897072013-06-07 08:48:57 -0700220 kfree(rcu_dereference_protected(idev->mc_hash, 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221#ifdef NET_REFCNT_DEBUG
Joe Perches91df42b2012-05-15 14:11:54 +0000222 pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223#endif
224 dev_put(dev);
225 if (!idev->dead)
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800226 pr_err("Freeing alive in_device %p\n", idev);
227 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 kfree(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800230EXPORT_SYMBOL(in_dev_finish_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
Herbert Xu71e27da2007-06-04 23:36:06 -0700232static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233{
234 struct in_device *in_dev;
WANG Cong20e61da2014-07-25 15:25:08 -0700235 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
237 ASSERT_RTNL();
238
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700239 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 if (!in_dev)
241 goto out;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900242 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -0800243 sizeof(in_dev->cnf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 in_dev->cnf.sysctl = NULL;
245 in_dev->dev = dev;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800246 in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
247 if (!in_dev->arp_parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 goto out_kfree;
Ben Hutchings0187bdf2008-06-19 16:15:47 -0700249 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
250 dev_disable_lro(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 /* Reference in_dev->dev */
252 dev_hold(dev);
David L Stevens30c4cf52007-01-04 12:31:14 -0800253 /* Account for reference dev->ip_ptr (below) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 in_dev_hold(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
WANG Cong20e61da2014-07-25 15:25:08 -0700256 err = devinet_sysctl_register(in_dev);
257 if (err) {
258 in_dev->dead = 1;
259 in_dev_put(in_dev);
260 in_dev = NULL;
261 goto out;
262 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 ip_mc_init_dev(in_dev);
264 if (dev->flags & IFF_UP)
265 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800266
David L Stevens30c4cf52007-01-04 12:31:14 -0800267 /* we can receive as soon as ip_ptr is set -- do this last */
Eric Dumazetcf778b02012-01-12 04:41:32 +0000268 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800269out:
WANG Cong20e61da2014-07-25 15:25:08 -0700270 return in_dev ?: ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271out_kfree:
272 kfree(in_dev);
273 in_dev = NULL;
274 goto out;
275}
276
277static void in_dev_rcu_put(struct rcu_head *head)
278{
279 struct in_device *idev = container_of(head, struct in_device, rcu_head);
280 in_dev_put(idev);
281}
282
283static void inetdev_destroy(struct in_device *in_dev)
284{
285 struct in_ifaddr *ifa;
286 struct net_device *dev;
287
288 ASSERT_RTNL();
289
290 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
292 in_dev->dead = 1;
293
294 ip_mc_destroy_dev(in_dev);
295
296 while ((ifa = in_dev->ifa_list) != NULL) {
297 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
298 inet_free_ifa(ifa);
299 }
300
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000301 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800303 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
305 arp_ifdown(dev);
306
307 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
308}
309
Al Viroff428d72006-09-26 22:13:35 -0700310int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311{
312 rcu_read_lock();
313 for_primary_ifa(in_dev) {
314 if (inet_ifa_match(a, ifa)) {
315 if (!b || inet_ifa_match(b, ifa)) {
316 rcu_read_unlock();
317 return 1;
318 }
319 }
320 } endfor_ifa(in_dev);
321 rcu_read_unlock();
322 return 0;
323}
324
Thomas Grafd6062cb2006-08-15 00:33:59 -0700325static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000326 int destroy, struct nlmsghdr *nlh, u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327{
Harald Welte8f937c62005-05-29 20:23:46 -0700328 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800329 struct in_ifaddr *ifa, *ifa1 = *ifap;
330 struct in_ifaddr *last_prim = in_dev->ifa_list;
331 struct in_ifaddr *prev_prom = NULL;
332 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
334 ASSERT_RTNL();
335
David S. Millerfbd40ea2016-03-13 23:28:00 -0400336 if (in_dev->dead)
337 goto no_promotions;
338
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900339 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700340 * unless alias promotion is set
341 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
343 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
345
346 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900347 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800348 ifa1->ifa_scope <= ifa->ifa_scope)
349 last_prim = ifa;
350
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
352 ifa1->ifa_mask != ifa->ifa_mask ||
353 !inet_ifa_match(ifa1->ifa_address, ifa)) {
354 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800355 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 continue;
357 }
358
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800359 if (!do_promote) {
David S. Millerfd23c3b2011-02-18 12:42:28 -0800360 inet_hash_remove(ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700361 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
Eric W. Biederman15e47302012-09-07 20:12:54 +0000363 rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800364 blocking_notifier_call_chain(&inetaddr_chain,
365 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700366 inet_free_ifa(ifa);
367 } else {
368 promote = ifa;
369 break;
370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 }
372 }
373
Julian Anastasov2d230e22011-03-19 12:13:52 +0000374 /* On promotion all secondaries from subnet are changing
375 * the primary IP, we must remove all their routes silently
376 * and later to add them back with new prefsrc. Do this
377 * while all addresses are on the device list.
378 */
379 for (ifa = promote; ifa; ifa = ifa->ifa_next) {
380 if (ifa1->ifa_mask == ifa->ifa_mask &&
381 inet_ifa_match(ifa1->ifa_address, ifa))
382 fib_del_ifaddr(ifa, ifa1);
383 }
384
David S. Millerfbd40ea2016-03-13 23:28:00 -0400385no_promotions:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 /* 2. Unlink it */
387
388 *ifap = ifa1->ifa_next;
David S. Millerfd23c3b2011-02-18 12:42:28 -0800389 inet_hash_remove(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
391 /* 3. Announce address deletion */
392
393 /* Send message first, then call notifier.
394 At first sight, FIB update triggered by notifier
395 will refer to already deleted ifaddr, that could confuse
396 netlink listeners. It is not true: look, gated sees
397 that route deleted and if it still thinks that ifaddr
398 is valid, it will try to restore deleted routes... Grr.
399 So that, this order is correct.
400 */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000401 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800402 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800403
404 if (promote) {
Julian Anastasov04024b92011-03-19 12:13:54 +0000405 struct in_ifaddr *next_sec = promote->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800406
407 if (prev_prom) {
408 prev_prom->ifa_next = promote->ifa_next;
409 promote->ifa_next = last_prim->ifa_next;
410 last_prim->ifa_next = promote;
411 }
412
413 promote->ifa_flags &= ~IFA_F_SECONDARY;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000414 rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800415 blocking_notifier_call_chain(&inetaddr_chain,
416 NETDEV_UP, promote);
Julian Anastasov04024b92011-03-19 12:13:54 +0000417 for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800418 if (ifa1->ifa_mask != ifa->ifa_mask ||
419 !inet_ifa_match(ifa1->ifa_address, ifa))
420 continue;
421 fib_add_ifaddr(ifa);
422 }
423
424 }
Herbert Xu63630972007-06-07 18:35:38 -0700425 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427}
428
Thomas Grafd6062cb2006-08-15 00:33:59 -0700429static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
430 int destroy)
431{
432 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
433}
434
Jiri Pirko5c766d62013-01-24 09:41:41 +0000435static void check_lifetime(struct work_struct *work);
436
437static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
438
Thomas Grafd6062cb2006-08-15 00:33:59 -0700439static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000440 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441{
442 struct in_device *in_dev = ifa->ifa_dev;
443 struct in_ifaddr *ifa1, **ifap, **last_primary;
444
445 ASSERT_RTNL();
446
447 if (!ifa->ifa_local) {
448 inet_free_ifa(ifa);
449 return 0;
450 }
451
452 ifa->ifa_flags &= ~IFA_F_SECONDARY;
453 last_primary = &in_dev->ifa_list;
454
455 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
456 ifap = &ifa1->ifa_next) {
457 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
458 ifa->ifa_scope <= ifa1->ifa_scope)
459 last_primary = &ifa1->ifa_next;
460 if (ifa1->ifa_mask == ifa->ifa_mask &&
461 inet_ifa_match(ifa1->ifa_address, ifa)) {
462 if (ifa1->ifa_local == ifa->ifa_local) {
463 inet_free_ifa(ifa);
464 return -EEXIST;
465 }
466 if (ifa1->ifa_scope != ifa->ifa_scope) {
467 inet_free_ifa(ifa);
468 return -EINVAL;
469 }
470 ifa->ifa_flags |= IFA_F_SECONDARY;
471 }
472 }
473
474 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500475 prandom_seed((__force u32) ifa->ifa_local);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 ifap = last_primary;
477 }
478
479 ifa->ifa_next = *ifap;
480 *ifap = ifa;
481
David S. Millerfd23c3b2011-02-18 12:42:28 -0800482 inet_hash_insert(dev_net(in_dev->dev), ifa);
483
Jiri Pirko5c766d62013-01-24 09:41:41 +0000484 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530485 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 /* Send message first, then call notifier.
488 Notifier will trigger FIB update, so that
489 listeners of netlink will know about new ifaddr */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000490 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800491 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
493 return 0;
494}
495
Thomas Grafd6062cb2006-08-15 00:33:59 -0700496static int inet_insert_ifa(struct in_ifaddr *ifa)
497{
498 return __inet_insert_ifa(ifa, NULL, 0);
499}
500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
502{
Herbert Xue5ed6392005-10-03 14:35:55 -0700503 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
505 ASSERT_RTNL();
506
507 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700508 inet_free_ifa(ifa);
509 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700511 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100512 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700514 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 in_dev_hold(in_dev);
516 ifa->ifa_dev = in_dev;
517 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800518 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 ifa->ifa_scope = RT_SCOPE_HOST;
520 return inet_insert_ifa(ifa);
521}
522
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000523/* Caller must hold RCU or RTNL :
524 * We dont take a reference on found in_device
525 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800526struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527{
528 struct net_device *dev;
529 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000530
531 rcu_read_lock();
532 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000534 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000535 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 return in_dev;
537}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800538EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539
540/* Called only from RTNL semaphored context. No locks. */
541
Al Viro60cad5d2006-09-26 22:17:09 -0700542struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
543 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544{
545 ASSERT_RTNL();
546
547 for_primary_ifa(in_dev) {
548 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
549 return ifa;
550 } endfor_ifa(in_dev);
551 return NULL;
552}
553
Madhu Challa93a714d2015-02-25 09:58:35 -0800554static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa)
555{
556 struct ip_mreqn mreq = {
557 .imr_multiaddr.s_addr = ifa->ifa_address,
558 .imr_ifindex = ifa->ifa_dev->dev->ifindex,
559 };
560 int ret;
561
562 ASSERT_RTNL();
563
564 lock_sock(sk);
565 if (join)
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300566 ret = ip_mc_join_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800567 else
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300568 ret = ip_mc_leave_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800569 release_sock(sk);
570
571 return ret;
572}
573
David Ahernc21ef3e2017-04-16 09:48:24 -0700574static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
575 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900577 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700578 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700580 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700582 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
584 ASSERT_RTNL();
585
Johannes Bergfceb6432017-04-12 14:34:07 +0200586 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -0700587 extack);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700588 if (err < 0)
589 goto errout;
590
591 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800592 in_dev = inetdev_by_index(net, ifm->ifa_index);
Ian Morris51456b22015-04-03 09:17:26 +0100593 if (!in_dev) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700594 err = -ENODEV;
595 goto errout;
596 }
597
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
599 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700600 if (tb[IFA_LOCAL] &&
Jiri Benc67b61f62015-03-29 16:59:26 +0200601 ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700603
604 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
605 continue;
606
607 if (tb[IFA_ADDRESS] &&
608 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Jiri Benc67b61f62015-03-29 16:59:26 +0200609 !inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700610 continue;
611
Madhu Challa93a714d2015-02-25 09:58:35 -0800612 if (ipv4_is_multicast(ifa->ifa_address))
613 ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000614 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 return 0;
616 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700617
618 err = -EADDRNOTAVAIL;
619errout:
620 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621}
622
Jiri Pirko5c766d62013-01-24 09:41:41 +0000623#define INFINITY_LIFE_TIME 0xFFFFFFFF
624
625static void check_lifetime(struct work_struct *work)
626{
627 unsigned long now, next, next_sec, next_sched;
628 struct in_ifaddr *ifa;
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000629 struct hlist_node *n;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000630 int i;
631
632 now = jiffies;
633 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
634
Jiri Pirko5c766d62013-01-24 09:41:41 +0000635 for (i = 0; i < IN4_ADDR_HSIZE; i++) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000636 bool change_needed = false;
637
638 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800639 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
Jiri Pirko5c766d62013-01-24 09:41:41 +0000640 unsigned long age;
641
642 if (ifa->ifa_flags & IFA_F_PERMANENT)
643 continue;
644
645 /* We try to batch several events at once. */
646 age = (now - ifa->ifa_tstamp +
647 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
648
649 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
650 age >= ifa->ifa_valid_lft) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000651 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000652 } else if (ifa->ifa_preferred_lft ==
653 INFINITY_LIFE_TIME) {
654 continue;
655 } else if (age >= ifa->ifa_preferred_lft) {
656 if (time_before(ifa->ifa_tstamp +
657 ifa->ifa_valid_lft * HZ, next))
658 next = ifa->ifa_tstamp +
659 ifa->ifa_valid_lft * HZ;
660
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000661 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
662 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000663 } else if (time_before(ifa->ifa_tstamp +
664 ifa->ifa_preferred_lft * HZ,
665 next)) {
666 next = ifa->ifa_tstamp +
667 ifa->ifa_preferred_lft * HZ;
668 }
669 }
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000670 rcu_read_unlock();
671 if (!change_needed)
672 continue;
673 rtnl_lock();
674 hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
675 unsigned long age;
676
677 if (ifa->ifa_flags & IFA_F_PERMANENT)
678 continue;
679
680 /* We try to batch several events at once. */
681 age = (now - ifa->ifa_tstamp +
682 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
683
684 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
685 age >= ifa->ifa_valid_lft) {
686 struct in_ifaddr **ifap;
687
688 for (ifap = &ifa->ifa_dev->ifa_list;
689 *ifap != NULL; ifap = &(*ifap)->ifa_next) {
690 if (*ifap == ifa) {
691 inet_del_ifa(ifa->ifa_dev,
692 ifap, 1);
693 break;
694 }
695 }
696 } else if (ifa->ifa_preferred_lft !=
697 INFINITY_LIFE_TIME &&
698 age >= ifa->ifa_preferred_lft &&
699 !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
700 ifa->ifa_flags |= IFA_F_DEPRECATED;
701 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
702 }
703 }
704 rtnl_unlock();
Jiri Pirko5c766d62013-01-24 09:41:41 +0000705 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000706
707 next_sec = round_jiffies_up(next);
708 next_sched = next;
709
710 /* If rounded timeout is accurate enough, accept it. */
711 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
712 next_sched = next_sec;
713
714 now = jiffies;
715 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
716 if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
717 next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
718
viresh kumar906e0732014-01-22 12:23:32 +0530719 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work,
720 next_sched - now);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000721}
722
723static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
724 __u32 prefered_lft)
725{
726 unsigned long timeout;
727
728 ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
729
730 timeout = addrconf_timeout_fixup(valid_lft, HZ);
731 if (addrconf_finite_timeout(timeout))
732 ifa->ifa_valid_lft = timeout;
733 else
734 ifa->ifa_flags |= IFA_F_PERMANENT;
735
736 timeout = addrconf_timeout_fixup(prefered_lft, HZ);
737 if (addrconf_finite_timeout(timeout)) {
738 if (timeout == 0)
739 ifa->ifa_flags |= IFA_F_DEPRECATED;
740 ifa->ifa_preferred_lft = timeout;
741 }
742 ifa->ifa_tstamp = jiffies;
743 if (!ifa->ifa_cstamp)
744 ifa->ifa_cstamp = ifa->ifa_tstamp;
745}
746
747static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
748 __u32 *pvalid_lft, __u32 *pprefered_lft)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749{
Thomas Graf5c753972006-08-04 23:03:53 -0700750 struct nlattr *tb[IFA_MAX+1];
751 struct in_ifaddr *ifa;
752 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 struct net_device *dev;
754 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800755 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Johannes Bergfceb6432017-04-12 14:34:07 +0200757 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy,
758 NULL);
Thomas Graf5c753972006-08-04 23:03:53 -0700759 if (err < 0)
760 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
Thomas Graf5c753972006-08-04 23:03:53 -0700762 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800763 err = -EINVAL;
Ian Morris51456b22015-04-03 09:17:26 +0100764 if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL])
Thomas Graf5c753972006-08-04 23:03:53 -0700765 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800767 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800768 err = -ENODEV;
Ian Morris51456b22015-04-03 09:17:26 +0100769 if (!dev)
Thomas Graf5c753972006-08-04 23:03:53 -0700770 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Thomas Graf5c753972006-08-04 23:03:53 -0700772 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800773 err = -ENOBUFS;
Ian Morris51456b22015-04-03 09:17:26 +0100774 if (!in_dev)
Herbert Xu71e27da2007-06-04 23:36:06 -0700775 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
Thomas Graf5c753972006-08-04 23:03:53 -0700777 ifa = inet_alloc_ifa();
Ian Morris51456b22015-04-03 09:17:26 +0100778 if (!ifa)
Thomas Graf5c753972006-08-04 23:03:53 -0700779 /*
780 * A potential indev allocation can be left alive, it stays
781 * assigned to its device and is destroy with it.
782 */
Thomas Graf5c753972006-08-04 23:03:53 -0700783 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700784
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800785 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100786 neigh_parms_data_state_setall(in_dev->arp_parms);
Thomas Graf5c753972006-08-04 23:03:53 -0700787 in_dev_hold(in_dev);
788
Ian Morris51456b22015-04-03 09:17:26 +0100789 if (!tb[IFA_ADDRESS])
Thomas Graf5c753972006-08-04 23:03:53 -0700790 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
791
David S. Millerfd23c3b2011-02-18 12:42:28 -0800792 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
794 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100795 ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
796 ifm->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700798 ifa->ifa_dev = in_dev;
799
Jiri Benc67b61f62015-03-29 16:59:26 +0200800 ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]);
801 ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700802
803 if (tb[IFA_BROADCAST])
Jiri Benc67b61f62015-03-29 16:59:26 +0200804 ifa->ifa_broadcast = nla_get_in_addr(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700805
Thomas Graf5c753972006-08-04 23:03:53 -0700806 if (tb[IFA_LABEL])
807 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 else
809 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
810
Jiri Pirko5c766d62013-01-24 09:41:41 +0000811 if (tb[IFA_CACHEINFO]) {
812 struct ifa_cacheinfo *ci;
813
814 ci = nla_data(tb[IFA_CACHEINFO]);
815 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
816 err = -EINVAL;
Daniel Borkmann446266b2013-08-02 11:32:43 +0200817 goto errout_free;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000818 }
819 *pvalid_lft = ci->ifa_valid;
820 *pprefered_lft = ci->ifa_prefered;
821 }
822
Thomas Graf5c753972006-08-04 23:03:53 -0700823 return ifa;
824
Daniel Borkmann446266b2013-08-02 11:32:43 +0200825errout_free:
826 inet_free_ifa(ifa);
Thomas Graf5c753972006-08-04 23:03:53 -0700827errout:
828 return ERR_PTR(err);
829}
830
Jiri Pirko5c766d62013-01-24 09:41:41 +0000831static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
832{
833 struct in_device *in_dev = ifa->ifa_dev;
834 struct in_ifaddr *ifa1, **ifap;
835
836 if (!ifa->ifa_local)
837 return NULL;
838
839 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
840 ifap = &ifa1->ifa_next) {
841 if (ifa1->ifa_mask == ifa->ifa_mask &&
842 inet_ifa_match(ifa1->ifa_address, ifa) &&
843 ifa1->ifa_local == ifa->ifa_local)
844 return ifa1;
845 }
846 return NULL;
847}
848
David Ahernc21ef3e2017-04-16 09:48:24 -0700849static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
850 struct netlink_ext_ack *extack)
Thomas Graf5c753972006-08-04 23:03:53 -0700851{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900852 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700853 struct in_ifaddr *ifa;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000854 struct in_ifaddr *ifa_existing;
855 __u32 valid_lft = INFINITY_LIFE_TIME;
856 __u32 prefered_lft = INFINITY_LIFE_TIME;
Thomas Graf5c753972006-08-04 23:03:53 -0700857
858 ASSERT_RTNL();
859
Jiri Pirko5c766d62013-01-24 09:41:41 +0000860 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft);
Thomas Graf5c753972006-08-04 23:03:53 -0700861 if (IS_ERR(ifa))
862 return PTR_ERR(ifa);
863
Jiri Pirko5c766d62013-01-24 09:41:41 +0000864 ifa_existing = find_matching_ifa(ifa);
865 if (!ifa_existing) {
866 /* It would be best to check for !NLM_F_CREATE here but
stephen hemminger614d0562014-05-16 20:46:58 -0700867 * userspace already relies on not having to provide this.
Jiri Pirko5c766d62013-01-24 09:41:41 +0000868 */
869 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Madhu Challa93a714d2015-02-25 09:58:35 -0800870 if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
871 int ret = ip_mc_config(net->ipv4.mc_autojoin_sk,
872 true, ifa);
873
874 if (ret < 0) {
875 inet_free_ifa(ifa);
876 return ret;
877 }
878 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000879 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
880 } else {
881 inet_free_ifa(ifa);
882
883 if (nlh->nlmsg_flags & NLM_F_EXCL ||
884 !(nlh->nlmsg_flags & NLM_F_REPLACE))
885 return -EEXIST;
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000886 ifa = ifa_existing;
887 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Jiri Pirko05a324b2013-04-04 23:39:38 +0000888 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530889 queue_delayed_work(system_power_efficient_wq,
890 &check_lifetime_work, 0);
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000891 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000892 }
893 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894}
895
896/*
897 * Determine a default network mask, based on the IP address.
898 */
899
Eric Dumazet40384992012-08-03 21:06:50 +0000900static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901{
902 int rc = -1; /* Something else, probably a multicast. */
903
Joe Perchesf97c1e02007-12-16 13:45:43 -0800904 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900905 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 else {
Al Viro714e85b2006-11-14 20:51:49 -0800907 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
Al Viro714e85b2006-11-14 20:51:49 -0800909 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800911 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800913 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 rc = 24;
915 }
916
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900917 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918}
919
920
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800921int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922{
923 struct ifreq ifr;
924 struct sockaddr_in sin_orig;
925 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
926 struct in_device *in_dev;
927 struct in_ifaddr **ifap = NULL;
928 struct in_ifaddr *ifa = NULL;
929 struct net_device *dev;
930 char *colon;
931 int ret = -EFAULT;
932 int tryaddrmatch = 0;
933
934 /*
935 * Fetch the caller's info block into kernel space
936 */
937
938 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
939 goto out;
940 ifr.ifr_name[IFNAMSIZ - 1] = 0;
941
942 /* save original address for comparison */
943 memcpy(&sin_orig, sin, sizeof(*sin));
944
945 colon = strchr(ifr.ifr_name, ':');
946 if (colon)
947 *colon = 0;
948
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800949 dev_load(net, ifr.ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
Stephen Hemminger132adf52007-03-08 20:44:43 -0800951 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 case SIOCGIFADDR: /* Get interface address */
953 case SIOCGIFBRDADDR: /* Get the broadcast address */
954 case SIOCGIFDSTADDR: /* Get the destination address */
955 case SIOCGIFNETMASK: /* Get the netmask for the interface */
956 /* Note that these ioctls will not sleep,
957 so that we do not impose a lock.
958 One day we will be forced to put shlock here (I mean SMP)
959 */
960 tryaddrmatch = (sin_orig.sin_family == AF_INET);
961 memset(sin, 0, sizeof(*sin));
962 sin->sin_family = AF_INET;
963 break;
964
965 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000966 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000967 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 goto out;
969 break;
970 case SIOCSIFADDR: /* Set interface address (and family) */
971 case SIOCSIFBRDADDR: /* Set the broadcast address */
972 case SIOCSIFDSTADDR: /* Set the destination address */
973 case SIOCSIFNETMASK: /* Set the netmask for the interface */
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000974 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000975 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 goto out;
977 ret = -EINVAL;
978 if (sin->sin_family != AF_INET)
979 goto out;
980 break;
981 default:
982 ret = -EINVAL;
983 goto out;
984 }
985
986 rtnl_lock();
987
988 ret = -ENODEV;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800989 dev = __dev_get_by_name(net, ifr.ifr_name);
990 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 goto done;
992
993 if (colon)
994 *colon = ':';
995
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800996 in_dev = __in_dev_get_rtnl(dev);
997 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 if (tryaddrmatch) {
999 /* Matthias Andree */
1000 /* compare label and address (4.4BSD style) */
1001 /* note: we only do this for a limited set of ioctls
1002 and only if the original address family was AF_INET.
1003 This is checked above. */
1004 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1005 ifap = &ifa->ifa_next) {
1006 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
1007 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -08001008 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 break; /* found */
1010 }
1011 }
1012 }
1013 /* we didn't get a match, maybe the application is
1014 4.3BSD-style and passed in junk so we fall back to
1015 comparing just the label */
1016 if (!ifa) {
1017 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1018 ifap = &ifa->ifa_next)
1019 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
1020 break;
1021 }
1022 }
1023
1024 ret = -EADDRNOTAVAIL;
1025 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
1026 goto done;
1027
Stephen Hemminger132adf52007-03-08 20:44:43 -08001028 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 case SIOCGIFADDR: /* Get interface address */
1030 sin->sin_addr.s_addr = ifa->ifa_local;
1031 goto rarok;
1032
1033 case SIOCGIFBRDADDR: /* Get the broadcast address */
1034 sin->sin_addr.s_addr = ifa->ifa_broadcast;
1035 goto rarok;
1036
1037 case SIOCGIFDSTADDR: /* Get the destination address */
1038 sin->sin_addr.s_addr = ifa->ifa_address;
1039 goto rarok;
1040
1041 case SIOCGIFNETMASK: /* Get the netmask for the interface */
1042 sin->sin_addr.s_addr = ifa->ifa_mask;
1043 goto rarok;
1044
1045 case SIOCSIFFLAGS:
1046 if (colon) {
1047 ret = -EADDRNOTAVAIL;
1048 if (!ifa)
1049 break;
1050 ret = 0;
1051 if (!(ifr.ifr_flags & IFF_UP))
1052 inet_del_ifa(in_dev, ifap, 1);
1053 break;
1054 }
1055 ret = dev_change_flags(dev, ifr.ifr_flags);
1056 break;
1057
1058 case SIOCSIFADDR: /* Set interface address (and family) */
1059 ret = -EINVAL;
1060 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1061 break;
1062
1063 if (!ifa) {
1064 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001065 ifa = inet_alloc_ifa();
1066 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 break;
Xi Wangc7e2e1d2013-01-05 11:19:24 +00001068 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 if (colon)
1070 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
1071 else
1072 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1073 } else {
1074 ret = 0;
1075 if (ifa->ifa_local == sin->sin_addr.s_addr)
1076 break;
1077 inet_del_ifa(in_dev, ifap, 0);
1078 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -08001079 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 }
1081
1082 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
1083
1084 if (!(dev->flags & IFF_POINTOPOINT)) {
1085 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
1086 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
1087 if ((dev->flags & IFF_BROADCAST) &&
1088 ifa->ifa_prefixlen < 31)
1089 ifa->ifa_broadcast = ifa->ifa_address |
1090 ~ifa->ifa_mask;
1091 } else {
1092 ifa->ifa_prefixlen = 32;
1093 ifa->ifa_mask = inet_make_mask(32);
1094 }
Jiri Pirko5c766d62013-01-24 09:41:41 +00001095 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 ret = inet_set_ifa(dev, ifa);
1097 break;
1098
1099 case SIOCSIFBRDADDR: /* Set the broadcast address */
1100 ret = 0;
1101 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
1102 inet_del_ifa(in_dev, ifap, 0);
1103 ifa->ifa_broadcast = sin->sin_addr.s_addr;
1104 inet_insert_ifa(ifa);
1105 }
1106 break;
1107
1108 case SIOCSIFDSTADDR: /* Set the destination address */
1109 ret = 0;
1110 if (ifa->ifa_address == sin->sin_addr.s_addr)
1111 break;
1112 ret = -EINVAL;
1113 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1114 break;
1115 ret = 0;
1116 inet_del_ifa(in_dev, ifap, 0);
1117 ifa->ifa_address = sin->sin_addr.s_addr;
1118 inet_insert_ifa(ifa);
1119 break;
1120
1121 case SIOCSIFNETMASK: /* Set the netmask for the interface */
1122
1123 /*
1124 * The mask we set must be legal.
1125 */
1126 ret = -EINVAL;
1127 if (bad_mask(sin->sin_addr.s_addr, 0))
1128 break;
1129 ret = 0;
1130 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -07001131 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 inet_del_ifa(in_dev, ifap, 0);
1133 ifa->ifa_mask = sin->sin_addr.s_addr;
1134 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
1135
1136 /* See if current broadcast address matches
1137 * with current netmask, then recalculate
1138 * the broadcast address. Otherwise it's a
1139 * funny address, so don't touch it since
1140 * the user seems to know what (s)he's doing...
1141 */
1142 if ((dev->flags & IFF_BROADCAST) &&
1143 (ifa->ifa_prefixlen < 31) &&
1144 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -05001145 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 ifa->ifa_broadcast = (ifa->ifa_local |
1147 ~sin->sin_addr.s_addr);
1148 }
1149 inet_insert_ifa(ifa);
1150 }
1151 break;
1152 }
1153done:
1154 rtnl_unlock();
1155out:
1156 return ret;
1157rarok:
1158 rtnl_unlock();
1159 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
1160 goto out;
1161}
1162
1163static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
1164{
Herbert Xue5ed6392005-10-03 14:35:55 -07001165 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 struct in_ifaddr *ifa;
1167 struct ifreq ifr;
1168 int done = 0;
1169
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001170 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 goto out;
1172
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001173 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 if (!buf) {
1175 done += sizeof(ifr);
1176 continue;
1177 }
1178 if (len < (int) sizeof(ifr))
1179 break;
1180 memset(&ifr, 0, sizeof(struct ifreq));
Dan Carpenter4299c8a2013-07-29 22:15:19 +03001181 strcpy(ifr.ifr_name, ifa->ifa_label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182
1183 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
1184 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1185 ifa->ifa_local;
1186
1187 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
1188 done = -EFAULT;
1189 break;
1190 }
1191 buf += sizeof(struct ifreq);
1192 len -= sizeof(struct ifreq);
1193 done += sizeof(struct ifreq);
1194 }
1195out:
1196 return done;
1197}
1198
Gao Feng8b57fd12017-03-10 12:38:47 +08001199static __be32 in_dev_select_addr(const struct in_device *in_dev,
1200 int scope)
1201{
1202 for_primary_ifa(in_dev) {
1203 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1204 ifa->ifa_scope <= scope)
1205 return ifa->ifa_local;
1206 } endfor_ifa(in_dev);
1207
1208 return 0;
1209}
1210
Al Viroa61ced52006-09-26 21:27:54 -07001211__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212{
Al Viroa61ced52006-09-26 21:27:54 -07001213 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001215 struct net *net = dev_net(dev);
David Ahern3f2fb9a2016-02-24 11:47:02 -08001216 int master_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
1218 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001219 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 if (!in_dev)
1221 goto no_in_dev;
1222
1223 for_primary_ifa(in_dev) {
1224 if (ifa->ifa_scope > scope)
1225 continue;
1226 if (!dst || inet_ifa_match(dst, ifa)) {
1227 addr = ifa->ifa_local;
1228 break;
1229 }
1230 if (!addr)
1231 addr = ifa->ifa_local;
1232 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
1234 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001235 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001236no_in_dev:
David Ahern3f2fb9a2016-02-24 11:47:02 -08001237 master_idx = l3mdev_master_ifindex_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
David Lamparter17b693c2016-02-24 11:47:03 -08001239 /* For VRFs, the VRF device takes the place of the loopback device,
1240 * with addresses on it being preferred. Note in such cases the
1241 * loopback device will be among the devices that fail the master_idx
1242 * equality check in the loop below.
1243 */
1244 if (master_idx &&
1245 (dev = dev_get_by_index_rcu(net, master_idx)) &&
1246 (in_dev = __in_dev_get_rcu(dev))) {
Gao Feng8b57fd12017-03-10 12:38:47 +08001247 addr = in_dev_select_addr(in_dev, scope);
1248 if (addr)
1249 goto out_unlock;
David Lamparter17b693c2016-02-24 11:47:03 -08001250 }
1251
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 /* Not loopback addresses on loopback should be preferred
Stephen Hemmingerca9f1fd2015-02-14 13:47:54 -05001253 in this case. It is important that lo is the first interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 in dev_base list.
1255 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001256 for_each_netdev_rcu(net, dev) {
David Ahern3f2fb9a2016-02-24 11:47:02 -08001257 if (l3mdev_master_ifindex_rcu(dev) != master_idx)
1258 continue;
1259
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001260 in_dev = __in_dev_get_rcu(dev);
1261 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 continue;
1263
Gao Feng8b57fd12017-03-10 12:38:47 +08001264 addr = in_dev_select_addr(in_dev, scope);
1265 if (addr)
1266 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001268out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 return addr;
1271}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001272EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
Al Viro60cad5d2006-09-26 22:17:09 -07001274static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1275 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276{
1277 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001278 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
1280 for_ifa(in_dev) {
1281 if (!addr &&
1282 (local == ifa->ifa_local || !local) &&
1283 ifa->ifa_scope <= scope) {
1284 addr = ifa->ifa_local;
1285 if (same)
1286 break;
1287 }
1288 if (!same) {
1289 same = (!local || inet_ifa_match(local, ifa)) &&
1290 (!dst || inet_ifa_match(dst, ifa));
1291 if (same && addr) {
1292 if (local || !dst)
1293 break;
1294 /* Is the selected addr into dst subnet? */
1295 if (inet_ifa_match(addr, ifa))
1296 break;
1297 /* No, then can we use new local src? */
1298 if (ifa->ifa_scope <= scope) {
1299 addr = ifa->ifa_local;
1300 break;
1301 }
1302 /* search for large dst subnet for addr */
1303 same = 0;
1304 }
1305 }
1306 } endfor_ifa(in_dev);
1307
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001308 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309}
1310
1311/*
1312 * Confirm that local IP address exists using wildcards:
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001313 * - net: netns to check, cannot be NULL
1314 * - in_dev: only on this interface, NULL=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 * - dst: only in the same subnet as dst, 0=any dst
1316 * - local: address, 0=autoselect the local address
1317 * - scope: maximum allowed scope value for the local address
1318 */
Nicolas Dichtelb601fa192013-12-10 15:02:40 +01001319__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001320 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321{
Al Viro60cad5d2006-09-26 22:17:09 -07001322 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001323 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
Ian Morris00db4122015-04-03 09:17:27 +01001325 if (in_dev)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001326 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001329 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001330 in_dev = __in_dev_get_rcu(dev);
1331 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 addr = confirm_addr_indev(in_dev, dst, local, scope);
1333 if (addr)
1334 break;
1335 }
1336 }
1337 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338
1339 return addr;
1340}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001341EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342
1343/*
1344 * Device notifier
1345 */
1346
1347int register_inetaddr_notifier(struct notifier_block *nb)
1348{
Alan Sterne041c682006-03-27 01:16:30 -08001349 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001351EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352
1353int unregister_inetaddr_notifier(struct notifier_block *nb)
1354{
Alan Sterne041c682006-03-27 01:16:30 -08001355 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001357EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001359/* Rename ifa_labels for a device name change. Make some effort to preserve
1360 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361*/
1362static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001363{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 struct in_ifaddr *ifa;
1365 int named = 0;
1366
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001367 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1368 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369
1370 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001371 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001373 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001374 dot = strchr(old, ':');
Ian Morris51456b22015-04-03 09:17:26 +01001375 if (!dot) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001376 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 dot = old;
1378 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001379 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001380 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001381 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001382 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001383skip:
1384 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001385 }
1386}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
Eric Dumazet40384992012-08-03 21:06:50 +00001388static bool inetdev_valid_mtu(unsigned int mtu)
Breno Leitao06770842008-09-02 17:28:58 -07001389{
1390 return mtu >= 68;
1391}
1392
Ian Campbelld11327ad2011-02-11 07:44:16 +00001393static void inetdev_send_gratuitous_arp(struct net_device *dev,
1394 struct in_device *in_dev)
1395
1396{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001397 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001398
Zoltan Kissb76d0782011-07-24 13:09:30 +00001399 for (ifa = in_dev->ifa_list; ifa;
1400 ifa = ifa->ifa_next) {
1401 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1402 ifa->ifa_local, dev,
1403 ifa->ifa_local, NULL,
1404 dev->dev_addr, NULL);
1405 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001406}
1407
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408/* Called only under RTNL semaphore */
1409
1410static int inetdev_event(struct notifier_block *this, unsigned long event,
1411 void *ptr)
1412{
Jiri Pirko351638e2013-05-28 01:30:21 +00001413 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazet748e2d92012-08-22 21:50:59 +00001414 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415
1416 ASSERT_RTNL();
1417
1418 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001419 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 in_dev = inetdev_init(dev);
WANG Cong20e61da2014-07-25 15:25:08 -07001421 if (IS_ERR(in_dev))
1422 return notifier_from_errno(PTR_ERR(in_dev));
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001423 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001424 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1425 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001426 }
Breno Leitao06770842008-09-02 17:28:58 -07001427 } else if (event == NETDEV_CHANGEMTU) {
1428 /* Re-enabling IP */
1429 if (inetdev_valid_mtu(dev->mtu))
1430 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 }
1432 goto out;
1433 }
1434
1435 switch (event) {
1436 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001437 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001438 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 break;
1440 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001441 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001443 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001444 struct in_ifaddr *ifa = inet_alloc_ifa();
1445
1446 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001447 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 ifa->ifa_local =
1449 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1450 ifa->ifa_prefixlen = 8;
1451 ifa->ifa_mask = inet_make_mask(8);
1452 in_dev_hold(in_dev);
1453 ifa->ifa_dev = in_dev;
1454 ifa->ifa_scope = RT_SCOPE_HOST;
1455 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Jiri Pirko5c766d62013-01-24 09:41:41 +00001456 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1457 INFINITY_LIFE_TIME);
Jiri Pirkodfd15822014-01-07 15:55:45 +01001458 ipv4_devconf_setall(in_dev);
1459 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 inet_insert_ifa(ifa);
1461 }
1462 }
1463 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001464 /* fall through */
1465 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001466 if (!IN_DEV_ARP_NOTIFY(in_dev))
1467 break;
1468 /* fall through */
1469 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001470 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001471 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 break;
1473 case NETDEV_DOWN:
1474 ip_mc_down(in_dev);
1475 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001476 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001477 ip_mc_unmap(in_dev);
1478 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001479 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001480 ip_mc_remap(in_dev);
1481 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001483 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 break;
Breno Leitao06770842008-09-02 17:28:58 -07001485 /* disable IP when MTU is not enough */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 case NETDEV_UNREGISTER:
1487 inetdev_destroy(in_dev);
1488 break;
1489 case NETDEV_CHANGENAME:
1490 /* Do not notify about label change, this event is
1491 * not interesting to applications using netlink.
1492 */
1493 inetdev_changename(dev, in_dev);
1494
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001495 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001496 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 break;
1498 }
1499out:
1500 return NOTIFY_DONE;
1501}
1502
1503static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001504 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505};
1506
Eric Dumazet40384992012-08-03 21:06:50 +00001507static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001508{
1509 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1510 + nla_total_size(4) /* IFA_ADDRESS */
1511 + nla_total_size(4) /* IFA_LOCAL */
1512 + nla_total_size(4) /* IFA_BROADCAST */
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001513 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001514 + nla_total_size(4) /* IFA_FLAGS */
1515 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
Thomas Graf339bf982006-11-10 14:10:15 -08001516}
1517
Jiri Pirko5c766d62013-01-24 09:41:41 +00001518static inline u32 cstamp_delta(unsigned long cstamp)
1519{
1520 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1521}
1522
1523static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1524 unsigned long tstamp, u32 preferred, u32 valid)
1525{
1526 struct ifa_cacheinfo ci;
1527
1528 ci.cstamp = cstamp_delta(cstamp);
1529 ci.tstamp = cstamp_delta(tstamp);
1530 ci.ifa_prefered = preferred;
1531 ci.ifa_valid = valid;
1532
1533 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1534}
1535
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001537 u32 portid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538{
1539 struct ifaddrmsg *ifm;
1540 struct nlmsghdr *nlh;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001541 u32 preferred, valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542
Eric W. Biederman15e47302012-09-07 20:12:54 +00001543 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
Ian Morris51456b22015-04-03 09:17:26 +01001544 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08001545 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001546
1547 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 ifm->ifa_family = AF_INET;
1549 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001550 ifm->ifa_flags = ifa->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 ifm->ifa_scope = ifa->ifa_scope;
1552 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553
Jiri Pirko5c766d62013-01-24 09:41:41 +00001554 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1555 preferred = ifa->ifa_preferred_lft;
1556 valid = ifa->ifa_valid_lft;
1557 if (preferred != INFINITY_LIFE_TIME) {
1558 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1559
1560 if (preferred > tval)
1561 preferred -= tval;
1562 else
1563 preferred = 0;
1564 if (valid != INFINITY_LIFE_TIME) {
1565 if (valid > tval)
1566 valid -= tval;
1567 else
1568 valid = 0;
1569 }
1570 }
1571 } else {
1572 preferred = INFINITY_LIFE_TIME;
1573 valid = INFINITY_LIFE_TIME;
1574 }
David S. Millerf3756b72012-04-01 20:39:02 -04001575 if ((ifa->ifa_address &&
Jiri Benc930345e2015-03-29 16:59:25 +02001576 nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001577 (ifa->ifa_local &&
Jiri Benc930345e2015-03-29 16:59:25 +02001578 nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001579 (ifa->ifa_broadcast &&
Jiri Benc930345e2015-03-29 16:59:25 +02001580 nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001581 (ifa->ifa_label[0] &&
Jiri Pirko5c766d62013-01-24 09:41:41 +00001582 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001583 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
Jiri Pirko5c766d62013-01-24 09:41:41 +00001584 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1585 preferred, valid))
David S. Millerf3756b72012-04-01 20:39:02 -04001586 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001587
Johannes Berg053c0952015-01-16 22:09:00 +01001588 nlmsg_end(skb, nlh);
1589 return 0;
Thomas Graf47f68512006-08-04 23:04:36 -07001590
1591nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001592 nlmsg_cancel(skb, nlh);
1593 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594}
1595
1596static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1597{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001598 struct net *net = sock_net(skb->sk);
Eric Dumazeteec4df92009-11-12 07:44:25 +00001599 int h, s_h;
1600 int idx, s_idx;
1601 int ip_idx, s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 struct net_device *dev;
1603 struct in_device *in_dev;
1604 struct in_ifaddr *ifa;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001605 struct hlist_head *head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
Eric Dumazeteec4df92009-11-12 07:44:25 +00001607 s_h = cb->args[0];
1608 s_idx = idx = cb->args[1];
1609 s_ip_idx = ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610
Eric Dumazeteec4df92009-11-12 07:44:25 +00001611 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1612 idx = 0;
1613 head = &net->dev_index_head[h];
1614 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001615 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1616 net->dev_base_seq;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001617 hlist_for_each_entry_rcu(dev, head, index_hlist) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001618 if (idx < s_idx)
1619 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001620 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001621 s_ip_idx = 0;
1622 in_dev = __in_dev_get_rcu(dev);
1623 if (!in_dev)
1624 goto cont;
1625
1626 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1627 ifa = ifa->ifa_next, ip_idx++) {
1628 if (ip_idx < s_ip_idx)
1629 continue;
1630 if (inet_fill_ifaddr(skb, ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001631 NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 cb->nlh->nlmsg_seq,
Johannes Berg053c0952015-01-16 22:09:00 +01001633 RTM_NEWADDR, NLM_F_MULTI) < 0) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001634 rcu_read_unlock();
1635 goto done;
1636 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001637 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Eric Dumazeteec4df92009-11-12 07:44:25 +00001638 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001639cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001640 idx++;
1641 }
1642 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 }
1644
1645done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001646 cb->args[0] = h;
1647 cb->args[1] = idx;
1648 cb->args[2] = ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649
1650 return skb->len;
1651}
1652
Jianjun Kong539afed2008-11-03 02:48:48 -08001653static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001654 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655{
Thomas Graf47f68512006-08-04 23:04:36 -07001656 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001657 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1658 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001659 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001661 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001662 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001663 if (!skb)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001664 goto errout;
1665
Eric W. Biederman15e47302012-09-07 20:12:54 +00001666 err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001667 if (err < 0) {
1668 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1669 WARN_ON(err == -EMSGSIZE);
1670 kfree_skb(skb);
1671 goto errout;
1672 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001673 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001674 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001675errout:
1676 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001677 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678}
1679
Arad, Ronenb1974ed2015-10-19 09:23:28 -07001680static size_t inet_get_link_af_size(const struct net_device *dev,
1681 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001682{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001683 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001684
1685 if (!in_dev)
1686 return 0;
1687
1688 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1689}
1690
Sowmini Varadhand5566fd2015-09-11 16:48:48 -04001691static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
1692 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001693{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001694 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001695 struct nlattr *nla;
1696 int i;
1697
1698 if (!in_dev)
1699 return -ENODATA;
1700
1701 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
Ian Morris51456b22015-04-03 09:17:26 +01001702 if (!nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001703 return -EMSGSIZE;
1704
1705 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1706 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1707
1708 return 0;
1709}
1710
1711static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1712 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1713};
1714
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001715static int inet_validate_link_af(const struct net_device *dev,
1716 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001717{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001718 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1719 int err, rem;
1720
Eric Dumazetf7fce742010-12-01 06:03:06 +00001721 if (dev && !__in_dev_get_rtnl(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001722 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001723
Johannes Bergfceb6432017-04-12 14:34:07 +02001724 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy, NULL);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001725 if (err < 0)
1726 return err;
1727
1728 if (tb[IFLA_INET_CONF]) {
1729 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1730 int cfgid = nla_type(a);
1731
1732 if (nla_len(a) < 4)
1733 return -EINVAL;
1734
1735 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1736 return -EINVAL;
1737 }
1738 }
1739
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001740 return 0;
1741}
1742
1743static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1744{
Eric Dumazetf7fce742010-12-01 06:03:06 +00001745 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001746 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1747 int rem;
1748
1749 if (!in_dev)
1750 return -EAFNOSUPPORT;
1751
Johannes Bergfceb6432017-04-12 14:34:07 +02001752 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0)
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001753 BUG();
1754
Thomas Graf9f0f7272010-11-16 04:32:48 +00001755 if (tb[IFLA_INET_CONF]) {
1756 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1757 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1758 }
1759
1760 return 0;
1761}
1762
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001763static int inet_netconf_msgsize_devconf(int type)
1764{
1765 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1766 + nla_total_size(4); /* NETCONFA_IFINDEX */
Zhang Shengju136ba622016-03-10 08:55:50 +00001767 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001768
Zhang Shengju136ba622016-03-10 08:55:50 +00001769 if (type == NETCONFA_ALL)
1770 all = true;
1771
1772 if (all || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001773 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001774 if (all || type == NETCONFA_RP_FILTER)
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001775 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001776 if (all || type == NETCONFA_MC_FORWARDING)
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001777 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001778 if (all || type == NETCONFA_PROXY_NEIGH)
stephen hemmingerf085ff12013-12-12 13:06:50 -08001779 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001780 if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001781 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001782
1783 return size;
1784}
1785
1786static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1787 struct ipv4_devconf *devconf, u32 portid,
1788 u32 seq, int event, unsigned int flags,
1789 int type)
1790{
1791 struct nlmsghdr *nlh;
1792 struct netconfmsg *ncm;
Zhang Shengju136ba622016-03-10 08:55:50 +00001793 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001794
1795 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1796 flags);
Ian Morris51456b22015-04-03 09:17:26 +01001797 if (!nlh)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001798 return -EMSGSIZE;
1799
Zhang Shengju136ba622016-03-10 08:55:50 +00001800 if (type == NETCONFA_ALL)
1801 all = true;
1802
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001803 ncm = nlmsg_data(nlh);
1804 ncm->ncm_family = AF_INET;
1805
1806 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1807 goto nla_put_failure;
1808
David Ahernb5c96412017-03-28 14:28:03 -07001809 if (!devconf)
1810 goto out;
1811
Zhang Shengju136ba622016-03-10 08:55:50 +00001812 if ((all || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001813 nla_put_s32(skb, NETCONFA_FORWARDING,
1814 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1815 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001816 if ((all || type == NETCONFA_RP_FILTER) &&
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001817 nla_put_s32(skb, NETCONFA_RP_FILTER,
1818 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
1819 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001820 if ((all || type == NETCONFA_MC_FORWARDING) &&
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001821 nla_put_s32(skb, NETCONFA_MC_FORWARDING,
1822 IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
1823 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001824 if ((all || type == NETCONFA_PROXY_NEIGH) &&
stephen hemminger09aea5d2013-12-17 22:35:52 -08001825 nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08001826 IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
1827 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001828 if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001829 nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
1830 IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
1831 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001832
David Ahernb5c96412017-03-28 14:28:03 -07001833out:
Johannes Berg053c0952015-01-16 22:09:00 +01001834 nlmsg_end(skb, nlh);
1835 return 0;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001836
1837nla_put_failure:
1838 nlmsg_cancel(skb, nlh);
1839 return -EMSGSIZE;
1840}
1841
David Ahern3b022862017-03-28 14:28:02 -07001842void inet_netconf_notify_devconf(struct net *net, int event, int type,
1843 int ifindex, struct ipv4_devconf *devconf)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001844{
1845 struct sk_buff *skb;
1846 int err = -ENOBUFS;
1847
Eric Dumazetfa178062016-07-08 05:18:24 +02001848 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001849 if (!skb)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001850 goto errout;
1851
1852 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
David Ahern3b022862017-03-28 14:28:02 -07001853 event, 0, type);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001854 if (err < 0) {
1855 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1856 WARN_ON(err == -EMSGSIZE);
1857 kfree_skb(skb);
1858 goto errout;
1859 }
Eric Dumazetfa178062016-07-08 05:18:24 +02001860 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001861 return;
1862errout:
1863 if (err < 0)
1864 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
1865}
1866
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001867static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
1868 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
1869 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001870 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
stephen hemminger09aea5d2013-12-17 22:35:52 -08001871 [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) },
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001872 [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001873};
1874
1875static int inet_netconf_get_devconf(struct sk_buff *in_skb,
David Ahernc21ef3e2017-04-16 09:48:24 -07001876 struct nlmsghdr *nlh,
1877 struct netlink_ext_ack *extack)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001878{
1879 struct net *net = sock_net(in_skb->sk);
1880 struct nlattr *tb[NETCONFA_MAX+1];
1881 struct netconfmsg *ncm;
1882 struct sk_buff *skb;
1883 struct ipv4_devconf *devconf;
1884 struct in_device *in_dev;
1885 struct net_device *dev;
1886 int ifindex;
1887 int err;
1888
1889 err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
David Ahernc21ef3e2017-04-16 09:48:24 -07001890 devconf_ipv4_policy, extack);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001891 if (err < 0)
1892 goto errout;
1893
Anton Protopopova97eb332016-02-16 21:43:16 -05001894 err = -EINVAL;
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001895 if (!tb[NETCONFA_IFINDEX])
1896 goto errout;
1897
1898 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
1899 switch (ifindex) {
1900 case NETCONFA_IFINDEX_ALL:
1901 devconf = net->ipv4.devconf_all;
1902 break;
1903 case NETCONFA_IFINDEX_DEFAULT:
1904 devconf = net->ipv4.devconf_dflt;
1905 break;
1906 default:
1907 dev = __dev_get_by_index(net, ifindex);
Ian Morris51456b22015-04-03 09:17:26 +01001908 if (!dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001909 goto errout;
1910 in_dev = __in_dev_get_rtnl(dev);
Ian Morris51456b22015-04-03 09:17:26 +01001911 if (!in_dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001912 goto errout;
1913 devconf = &in_dev->cnf;
1914 break;
1915 }
1916
1917 err = -ENOBUFS;
Eric Dumazetfa178062016-07-08 05:18:24 +02001918 skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001919 if (!skb)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001920 goto errout;
1921
1922 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
1923 NETLINK_CB(in_skb).portid,
1924 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
Zhang Shengju136ba622016-03-10 08:55:50 +00001925 NETCONFA_ALL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001926 if (err < 0) {
1927 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1928 WARN_ON(err == -EMSGSIZE);
1929 kfree_skb(skb);
1930 goto errout;
1931 }
1932 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
1933errout:
1934 return err;
1935}
1936
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001937static int inet_netconf_dump_devconf(struct sk_buff *skb,
1938 struct netlink_callback *cb)
1939{
1940 struct net *net = sock_net(skb->sk);
1941 int h, s_h;
1942 int idx, s_idx;
1943 struct net_device *dev;
1944 struct in_device *in_dev;
1945 struct hlist_head *head;
1946
1947 s_h = cb->args[0];
1948 s_idx = idx = cb->args[1];
1949
1950 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1951 idx = 0;
1952 head = &net->dev_index_head[h];
1953 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001954 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1955 net->dev_base_seq;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001956 hlist_for_each_entry_rcu(dev, head, index_hlist) {
1957 if (idx < s_idx)
1958 goto cont;
1959 in_dev = __in_dev_get_rcu(dev);
1960 if (!in_dev)
1961 goto cont;
1962
1963 if (inet_netconf_fill_devconf(skb, dev->ifindex,
1964 &in_dev->cnf,
1965 NETLINK_CB(cb->skb).portid,
1966 cb->nlh->nlmsg_seq,
1967 RTM_NEWNETCONF,
1968 NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00001969 NETCONFA_ALL) < 0) {
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001970 rcu_read_unlock();
1971 goto done;
1972 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001973 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001974cont:
1975 idx++;
1976 }
1977 rcu_read_unlock();
1978 }
1979 if (h == NETDEV_HASHENTRIES) {
1980 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
1981 net->ipv4.devconf_all,
1982 NETLINK_CB(cb->skb).portid,
1983 cb->nlh->nlmsg_seq,
1984 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00001985 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001986 goto done;
1987 else
1988 h++;
1989 }
1990 if (h == NETDEV_HASHENTRIES + 1) {
1991 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
1992 net->ipv4.devconf_dflt,
1993 NETLINK_CB(cb->skb).portid,
1994 cb->nlh->nlmsg_seq,
1995 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00001996 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001997 goto done;
1998 else
1999 h++;
2000 }
2001done:
2002 cb->args[0] = h;
2003 cb->args[1] = idx;
2004
2005 return skb->len;
2006}
2007
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008#ifdef CONFIG_SYSCTL
2009
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002010static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07002011{
2012 struct net_device *dev;
2013
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002014 rcu_read_lock();
2015 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07002016 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002017
Herbert Xu31be3082007-06-04 23:35:37 -07002018 in_dev = __in_dev_get_rcu(dev);
2019 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002020 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07002021 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002022 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07002023}
2024
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002025/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002026static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002027{
2028 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002029 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002030
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002031 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002032 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
David Ahern3b022862017-03-28 14:28:02 -07002033 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2034 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002035 NETCONFA_IFINDEX_ALL,
2036 net->ipv4.devconf_all);
David Ahern3b022862017-03-28 14:28:02 -07002037 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2038 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002039 NETCONFA_IFINDEX_DEFAULT,
2040 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002041
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002042 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002043 struct in_device *in_dev;
Eric Dumazetfa178062016-07-08 05:18:24 +02002044
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002045 if (on)
2046 dev_disable_lro(dev);
Eric Dumazetfa178062016-07-08 05:18:24 +02002047
2048 in_dev = __in_dev_get_rtnl(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002049 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002050 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
David Ahern3b022862017-03-28 14:28:02 -07002051 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2052 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002053 dev->ifindex, &in_dev->cnf);
2054 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002055 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002056}
2057
stephen hemmingerf085ff12013-12-12 13:06:50 -08002058static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf)
2059{
2060 if (cnf == net->ipv4.devconf_dflt)
2061 return NETCONFA_IFINDEX_DEFAULT;
2062 else if (cnf == net->ipv4.devconf_all)
2063 return NETCONFA_IFINDEX_ALL;
2064 else {
2065 struct in_device *idev
2066 = container_of(cnf, struct in_device, cnf);
2067 return idev->dev->ifindex;
2068 }
2069}
2070
Joe Perchesfe2c6332013-06-11 23:04:25 -07002071static int devinet_conf_proc(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002072 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07002073 size_t *lenp, loff_t *ppos)
2074{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002075 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002076 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002077 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07002078
2079 if (write) {
2080 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002081 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07002082 int i = (int *)ctl->data - cnf->data;
stephen hemmingerf085ff12013-12-12 13:06:50 -08002083 int ifindex;
Herbert Xu31be3082007-06-04 23:35:37 -07002084
2085 set_bit(i, cnf->state);
2086
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002087 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002088 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00002089 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
2090 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002091 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002092 rt_cache_flush(net);
stephen hemmingerf085ff12013-12-12 13:06:50 -08002093
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002094 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
2095 new_value != old_value) {
stephen hemmingerf085ff12013-12-12 13:06:50 -08002096 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002097 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2098 NETCONFA_RP_FILTER,
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002099 ifindex, cnf);
2100 }
stephen hemmingerf085ff12013-12-12 13:06:50 -08002101 if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
2102 new_value != old_value) {
2103 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002104 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2105 NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002106 ifindex, cnf);
2107 }
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002108 if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
2109 new_value != old_value) {
2110 ifindex = devinet_conf_ifindex(net, cnf);
David Ahern3b022862017-03-28 14:28:02 -07002111 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2112 NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002113 ifindex, cnf);
2114 }
Herbert Xu31be3082007-06-04 23:35:37 -07002115 }
2116
2117 return ret;
2118}
2119
Joe Perchesfe2c6332013-06-11 23:04:25 -07002120static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002121 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 size_t *lenp, loff_t *ppos)
2123{
2124 int *valp = ctl->data;
2125 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00002126 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002127 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128
2129 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002130 struct net *net = ctl->extra2;
2131
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002132 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00002133 if (!rtnl_trylock()) {
2134 /* Restore the original values before restarting */
2135 *valp = val;
2136 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00002137 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00002138 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002139 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2140 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002141 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002142 struct ipv4_devconf *cnf = ctl->extra1;
2143 struct in_device *idev =
2144 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002145 if (*valp)
2146 dev_disable_lro(idev->dev);
David Ahern3b022862017-03-28 14:28:02 -07002147 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002148 NETCONFA_FORWARDING,
2149 idev->dev->ifindex,
2150 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002151 }
2152 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002153 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002154 } else
David Ahern3b022862017-03-28 14:28:02 -07002155 inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
2156 NETCONFA_FORWARDING,
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002157 NETCONFA_IFINDEX_DEFAULT,
2158 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 }
2160
2161 return ret;
2162}
2163
Joe Perchesfe2c6332013-06-11 23:04:25 -07002164static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
David S. Miller323e1262010-12-12 21:55:08 -08002165 void __user *buffer,
2166 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167{
2168 int *valp = ctl->data;
2169 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002170 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07002171 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172
2173 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002174 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175
2176 return ret;
2177}
2178
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002179#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07002180 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07002181 .procname = name, \
2182 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00002183 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002184 .maxlen = sizeof(int), \
2185 .mode = mval, \
2186 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07002187 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002188 }
2189
2190#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002191 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002192
2193#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002194 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002195
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002196#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2197 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002198
2199#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002200 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07002201
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202static struct devinet_sysctl_table {
2203 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00002204 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205} devinet_sysctl = {
2206 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07002207 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002208 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07002209 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
2210
2211 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
2212 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
2213 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
2214 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
2215 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
2216 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
2217 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00002218 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08002219 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002220 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
2221 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
2222 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
2223 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
2224 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
2225 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
2226 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
2227 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
2228 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08002229 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00002230 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
William Manley5c6fe012013-08-06 19:03:14 +01002231 DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
2232 "force_igmp_version"),
William Manley26900482013-08-06 19:03:15 +01002233 DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
2234 "igmpv2_unsolicited_report_interval"),
2235 DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
2236 "igmpv3_unsolicited_report_interval"),
Andy Gospodarek0eeb0752015-06-23 13:45:37 -04002237 DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
2238 "ignore_routes_with_linkdown"),
Johannes Berg97daf332016-02-04 13:31:18 +01002239 DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
2240 "drop_gratuitous_arp"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002241
2242 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2243 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002244 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
2245 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00002246 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2247 "route_localnet"),
Johannes Berg12b74df2016-02-04 13:31:17 +01002248 DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
2249 "drop_unicast_in_l2_multicast"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251};
2252
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002253static int __devinet_sysctl_register(struct net *net, char *dev_name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002254 int ifindex, struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255{
2256 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002257 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002258 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11002259
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002260 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002262 goto out;
2263
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
2265 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07002266 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002267 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 }
2269
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002270 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002272 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002274 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275
2276 p->sysctl = t;
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002277
David Ahern3b022862017-03-28 14:28:02 -07002278 inet_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_ALL,
2279 ifindex, p);
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002280 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002282free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002284out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002285 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286}
2287
David Ahernb5c96412017-03-28 14:28:03 -07002288static void __devinet_sysctl_unregister(struct net *net,
2289 struct ipv4_devconf *cnf, int ifindex)
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002290{
2291 struct devinet_sysctl_table *t = cnf->sysctl;
2292
David Ahernb5c96412017-03-28 14:28:03 -07002293 if (t) {
2294 cnf->sysctl = NULL;
2295 unregister_net_sysctl_table(t->sysctl_header);
2296 kfree(t);
2297 }
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002298
David Ahernb5c96412017-03-28 14:28:03 -07002299 inet_netconf_notify_devconf(net, RTM_DELNETCONF, 0, ifindex, NULL);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002300}
2301
WANG Cong20e61da2014-07-25 15:25:08 -07002302static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002303{
WANG Cong20e61da2014-07-25 15:25:08 -07002304 int err;
2305
2306 if (!sysctl_dev_name_is_allowed(idev->dev->name))
2307 return -EINVAL;
2308
2309 err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
2310 if (err)
2311 return err;
2312 err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002313 idev->dev->ifindex, &idev->cnf);
WANG Cong20e61da2014-07-25 15:25:08 -07002314 if (err)
2315 neigh_sysctl_unregister(idev->arp_parms);
2316 return err;
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002317}
2318
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002319static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320{
David Ahernb5c96412017-03-28 14:28:03 -07002321 struct net *net = dev_net(idev->dev);
2322
2323 __devinet_sysctl_unregister(net, &idev->cnf, idev->dev->ifindex);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002324 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002327static struct ctl_table ctl_forward_entry[] = {
2328 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002329 .procname = "ip_forward",
2330 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00002331 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002332 .maxlen = sizeof(int),
2333 .mode = 0644,
2334 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002335 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002336 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002337 },
2338 { },
2339};
Eric Dumazet2a75de02008-01-05 23:08:49 -08002340#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002341
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002342static __net_init int devinet_init_net(struct net *net)
2343{
2344 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002345 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002346#ifdef CONFIG_SYSCTL
2347 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002348 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002349#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002350
2351 err = -ENOMEM;
2352 all = &ipv4_devconf;
2353 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002354
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002355 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002356 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002357 if (!all)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002358 goto err_alloc_all;
2359
2360 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002361 if (!dflt)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002362 goto err_alloc_dflt;
2363
Eric Dumazet2a75de02008-01-05 23:08:49 -08002364#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002365 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002366 if (!tbl)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002367 goto err_alloc_ctl;
2368
Eric W. Biederman02291682010-02-14 03:25:51 +00002369 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002370 tbl[0].extra1 = all;
2371 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002372#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002373 }
2374
2375#ifdef CONFIG_SYSCTL
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002376 err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002377 if (err < 0)
2378 goto err_reg_all;
2379
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002380 err = __devinet_sysctl_register(net, "default",
2381 NETCONFA_IFINDEX_DEFAULT, dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002382 if (err < 0)
2383 goto err_reg_dflt;
2384
2385 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002386 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Ian Morris51456b22015-04-03 09:17:26 +01002387 if (!forw_hdr)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002388 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002389 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002390#endif
2391
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002392 net->ipv4.devconf_all = all;
2393 net->ipv4.devconf_dflt = dflt;
2394 return 0;
2395
2396#ifdef CONFIG_SYSCTL
2397err_reg_ctl:
David Ahernb5c96412017-03-28 14:28:03 -07002398 __devinet_sysctl_unregister(net, dflt, NETCONFA_IFINDEX_DEFAULT);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002399err_reg_dflt:
David Ahernb5c96412017-03-28 14:28:03 -07002400 __devinet_sysctl_unregister(net, all, NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002401err_reg_all:
2402 if (tbl != ctl_forward_entry)
2403 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002404err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08002405#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002406 if (dflt != &ipv4_devconf_dflt)
2407 kfree(dflt);
2408err_alloc_dflt:
2409 if (all != &ipv4_devconf)
2410 kfree(all);
2411err_alloc_all:
2412 return err;
2413}
2414
2415static __net_exit void devinet_exit_net(struct net *net)
2416{
Eric Dumazet2a75de02008-01-05 23:08:49 -08002417#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002418 struct ctl_table *tbl;
2419
2420 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002421 unregister_net_sysctl_table(net->ipv4.forw_hdr);
David Ahernb5c96412017-03-28 14:28:03 -07002422 __devinet_sysctl_unregister(net, net->ipv4.devconf_dflt,
2423 NETCONFA_IFINDEX_DEFAULT);
2424 __devinet_sysctl_unregister(net, net->ipv4.devconf_all,
2425 NETCONFA_IFINDEX_ALL);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002426 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08002427#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002428 kfree(net->ipv4.devconf_dflt);
2429 kfree(net->ipv4.devconf_all);
2430}
2431
2432static __net_initdata struct pernet_operations devinet_ops = {
2433 .init = devinet_init_net,
2434 .exit = devinet_exit_net,
2435};
2436
Daniel Borkmann207895f2015-01-29 12:15:03 +01002437static struct rtnl_af_ops inet_af_ops __read_mostly = {
Thomas Graf9f0f7272010-11-16 04:32:48 +00002438 .family = AF_INET,
2439 .fill_link_af = inet_fill_link_af,
2440 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00002441 .validate_link_af = inet_validate_link_af,
2442 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00002443};
2444
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445void __init devinet_init(void)
2446{
David S. Millerfd23c3b2011-02-18 12:42:28 -08002447 int i;
2448
2449 for (i = 0; i < IN4_ADDR_HSIZE; i++)
2450 INIT_HLIST_HEAD(&inet_addr_lst[i]);
2451
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002452 register_pernet_subsys(&devinet_ops);
2453
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 register_gifconf(PF_INET, inet_gifconf);
2455 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07002456
viresh kumar906e0732014-01-22 12:23:32 +05302457 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +00002458
Thomas Graf9f0f7272010-11-16 04:32:48 +00002459 rtnl_af_register(&inet_af_ops);
2460
Greg Rosec7ac8672011-06-10 01:27:09 +00002461 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL);
2462 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, NULL);
2463 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, NULL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002464 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002465 inet_netconf_dump_devconf, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466}