blob: a57d3b40369e06516c31b42d458c9def067a47f3 [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
29#include <asm/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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/string.h>
36#include <linux/mm.h>
37#include <linux/socket.h>
38#include <linux/sockios.h>
39#include <linux/in.h>
40#include <linux/errno.h>
41#include <linux/interrupt.h>
Thomas Graf18237302006-08-04 23:04:54 -070042#include <linux/if_addr.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/if_ether.h>
44#include <linux/inet.h>
45#include <linux/netdevice.h>
46#include <linux/etherdevice.h>
47#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <linux/init.h>
49#include <linux/notifier.h>
50#include <linux/inetdevice.h>
51#include <linux/igmp.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090052#include <linux/slab.h>
David S. Millerfd23c3b2011-02-18 12:42:28 -080053#include <linux/hash.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#ifdef CONFIG_SYSCTL
55#include <linux/sysctl.h>
56#endif
57#include <linux/kmod.h>
Nicolas Dichteledc9e742012-10-25 22:28:52 +000058#include <linux/netconf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020060#include <net/arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <net/ip.h>
62#include <net/route.h>
63#include <net/ip_fib.h>
Thomas Graf63f34442007-03-22 11:55:17 -070064#include <net/rtnetlink.h>
Pavel Emelyanov752d14d2007-12-16 13:31:47 -080065#include <net/net_namespace.h>
Jiri Pirko5c766d62013-01-24 09:41:41 +000066#include <net/addrconf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
David S. Miller406b6f92011-03-22 21:56:23 -070068#include "fib_lookup.h"
69
Matteo Croce41504372019-07-01 19:01:55 +020070#define IPV6ONLY_FLAGS \
71 (IFA_F_NODAD | IFA_F_OPTIMISTIC | IFA_F_DADFAILED | \
72 IFA_F_HOMEADDRESS | IFA_F_TENTATIVE | \
73 IFA_F_MANAGETEMPADDR | IFA_F_STABLE_PRIVACY)
74
Adrian Bunk0027ba82008-01-31 17:17:31 -080075static struct ipv4_devconf ipv4_devconf = {
Herbert Xu42f811b2007-06-04 23:34:44 -070076 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000077 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
78 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
79 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
80 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
William Manley26900482013-08-06 19:03:15 +010081 [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
82 [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
Herbert Xu42f811b2007-06-04 23:34:44 -070083 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070084};
85
86static struct ipv4_devconf ipv4_devconf_dflt = {
Herbert Xu42f811b2007-06-04 23:34:44 -070087 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000088 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
89 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
90 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
91 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
92 [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
William Manley26900482013-08-06 19:03:15 +010093 [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
94 [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
Herbert Xu42f811b2007-06-04 23:34:44 -070095 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070096};
97
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -080098#define IPV4_DEVCONF_DFLT(net, attr) \
99 IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr)
Herbert Xu42f811b2007-06-04 23:34:44 -0700100
Patrick McHardyef7c79e2007-06-05 12:38:30 -0700101static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
Thomas Graf5c753972006-08-04 23:03:53 -0700102 [IFA_LOCAL] = { .type = NLA_U32 },
103 [IFA_ADDRESS] = { .type = NLA_U32 },
104 [IFA_BROADCAST] = { .type = NLA_U32 },
Thomas Graf5176f912006-08-26 20:13:18 -0700105 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
Jiri Pirko5c766d62013-01-24 09:41:41 +0000106 [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100107 [IFA_FLAGS] = { .type = NLA_U32 },
Thomas Graf5c753972006-08-04 23:03:53 -0700108};
109
Eric Dumazet40384992012-08-03 21:06:50 +0000110#define IN4_ADDR_HSIZE_SHIFT 8
111#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT)
112
David S. Millerfd23c3b2011-02-18 12:42:28 -0800113static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
David S. Millerfd23c3b2011-02-18 12:42:28 -0800114
Eric Dumazet6eada012015-03-18 14:05:33 -0700115static u32 inet_addr_hash(const struct net *net, __be32 addr)
David S. Millerfd23c3b2011-02-18 12:42:28 -0800116{
Eric Dumazet40384992012-08-03 21:06:50 +0000117 u32 val = (__force u32) addr ^ net_hash_mix(net);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800118
Eric Dumazet40384992012-08-03 21:06:50 +0000119 return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800120}
121
122static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
123{
Eric Dumazet40384992012-08-03 21:06:50 +0000124 u32 hash = inet_addr_hash(net, ifa->ifa_local);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800125
WANG Cong32a4be42014-05-06 11:15:56 -0700126 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800127 hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800128}
129
130static void inet_hash_remove(struct in_ifaddr *ifa)
131{
WANG Cong32a4be42014-05-06 11:15:56 -0700132 ASSERT_RTNL();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800133 hlist_del_init_rcu(&ifa->hash);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800134}
135
David S. Miller9435eb12011-02-18 12:43:09 -0800136/**
137 * __ip_dev_find - find the first device with a given source address.
138 * @net: the net namespace
139 * @addr: the source address
140 * @devref: if true, take a reference on the found device
141 *
142 * If a caller uses devref=false, it should be protected by RCU, or RTNL
143 */
144struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
145{
Eric Dumazet40384992012-08-03 21:06:50 +0000146 u32 hash = inet_addr_hash(net, addr);
David S. Miller9435eb12011-02-18 12:43:09 -0800147 struct net_device *result = NULL;
148 struct in_ifaddr *ifa;
David S. Miller9435eb12011-02-18 12:43:09 -0800149
150 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800151 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash) {
David S. Millere0660082011-03-03 11:24:19 -0800152 if (ifa->ifa_local == addr) {
Eric Dumazet40384992012-08-03 21:06:50 +0000153 struct net_device *dev = ifa->ifa_dev->dev;
154
155 if (!net_eq(dev_net(dev), net))
156 continue;
David S. Miller9435eb12011-02-18 12:43:09 -0800157 result = dev;
158 break;
159 }
160 }
David S. Miller406b6f92011-03-22 21:56:23 -0700161 if (!result) {
162 struct flowi4 fl4 = { .daddr = addr };
163 struct fib_result res = { 0 };
164 struct fib_table *local;
165
166 /* Fallback to FIB local table so that communication
167 * over loopback subnets work.
168 */
169 local = fib_get_table(net, RT_TABLE_LOCAL);
170 if (local &&
171 !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
172 res.type == RTN_LOCAL)
173 result = FIB_RES_DEV(res);
174 }
David S. Miller9435eb12011-02-18 12:43:09 -0800175 if (result && devref)
176 dev_hold(result);
177 rcu_read_unlock();
178 return result;
179}
180EXPORT_SYMBOL(__ip_dev_find);
181
Thomas Grafd6062cb2006-08-15 00:33:59 -0700182static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Alan Sterne041c682006-03-27 01:16:30 -0800184static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
186 int destroy);
187#ifdef CONFIG_SYSCTL
WANG Cong20e61da2014-07-25 15:25:08 -0700188static int devinet_sysctl_register(struct in_device *idev);
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800189static void devinet_sysctl_unregister(struct in_device *idev);
190#else
WANG Cong20e61da2014-07-25 15:25:08 -0700191static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800192{
WANG Cong20e61da2014-07-25 15:25:08 -0700193 return 0;
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800194}
Eric Dumazet40384992012-08-03 21:06:50 +0000195static void devinet_sysctl_unregister(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800196{
197}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198#endif
199
200/* Locks all the inet devices. */
201
202static struct in_ifaddr *inet_alloc_ifa(void)
203{
Alexey Dobriyan93adcc82008-10-28 13:25:09 -0700204 return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205}
206
207static void inet_rcu_free_ifa(struct rcu_head *head)
208{
209 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
210 if (ifa->ifa_dev)
211 in_dev_put(ifa->ifa_dev);
212 kfree(ifa);
213}
214
Eric Dumazet40384992012-08-03 21:06:50 +0000215static void inet_free_ifa(struct in_ifaddr *ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216{
217 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
218}
219
220void in_dev_finish_destroy(struct in_device *idev)
221{
222 struct net_device *dev = idev->dev;
223
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700224 WARN_ON(idev->ifa_list);
225 WARN_ON(idev->mc_list);
Eric Dumazete9897072013-06-07 08:48:57 -0700226 kfree(rcu_dereference_protected(idev->mc_hash, 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227#ifdef NET_REFCNT_DEBUG
Joe Perches91df42b2012-05-15 14:11:54 +0000228 pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229#endif
230 dev_put(dev);
231 if (!idev->dead)
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800232 pr_err("Freeing alive in_device %p\n", idev);
233 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 kfree(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800236EXPORT_SYMBOL(in_dev_finish_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
Herbert Xu71e27da2007-06-04 23:36:06 -0700238static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239{
240 struct in_device *in_dev;
WANG Cong20e61da2014-07-25 15:25:08 -0700241 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
243 ASSERT_RTNL();
244
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700245 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 if (!in_dev)
247 goto out;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900248 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -0800249 sizeof(in_dev->cnf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 in_dev->cnf.sysctl = NULL;
251 in_dev->dev = dev;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800252 in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
253 if (!in_dev->arp_parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 goto out_kfree;
Ben Hutchings0187bdf2008-06-19 16:15:47 -0700255 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
256 dev_disable_lro(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 /* Reference in_dev->dev */
258 dev_hold(dev);
David L Stevens30c4cf52007-01-04 12:31:14 -0800259 /* Account for reference dev->ip_ptr (below) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 in_dev_hold(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
WANG Cong20e61da2014-07-25 15:25:08 -0700262 err = devinet_sysctl_register(in_dev);
263 if (err) {
264 in_dev->dead = 1;
Yang Yingliangd2d51112020-05-30 11:34:33 +0800265 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
WANG Cong20e61da2014-07-25 15:25:08 -0700266 in_dev_put(in_dev);
267 in_dev = NULL;
268 goto out;
269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 ip_mc_init_dev(in_dev);
271 if (dev->flags & IFF_UP)
272 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800273
David L Stevens30c4cf52007-01-04 12:31:14 -0800274 /* we can receive as soon as ip_ptr is set -- do this last */
Eric Dumazetcf778b02012-01-12 04:41:32 +0000275 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800276out:
WANG Cong20e61da2014-07-25 15:25:08 -0700277 return in_dev ?: ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278out_kfree:
279 kfree(in_dev);
280 in_dev = NULL;
281 goto out;
282}
283
284static void in_dev_rcu_put(struct rcu_head *head)
285{
286 struct in_device *idev = container_of(head, struct in_device, rcu_head);
287 in_dev_put(idev);
288}
289
290static void inetdev_destroy(struct in_device *in_dev)
291{
292 struct in_ifaddr *ifa;
293 struct net_device *dev;
294
295 ASSERT_RTNL();
296
297 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
299 in_dev->dead = 1;
300
301 ip_mc_destroy_dev(in_dev);
302
303 while ((ifa = in_dev->ifa_list) != NULL) {
304 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
305 inet_free_ifa(ifa);
306 }
307
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000308 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800310 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
312 arp_ifdown(dev);
313
314 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
315}
316
Al Viroff428d72006-09-26 22:13:35 -0700317int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
319 rcu_read_lock();
320 for_primary_ifa(in_dev) {
321 if (inet_ifa_match(a, ifa)) {
322 if (!b || inet_ifa_match(b, ifa)) {
323 rcu_read_unlock();
324 return 1;
325 }
326 }
327 } endfor_ifa(in_dev);
328 rcu_read_unlock();
329 return 0;
330}
331
Thomas Grafd6062cb2006-08-15 00:33:59 -0700332static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000333 int destroy, struct nlmsghdr *nlh, u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
Harald Welte8f937c62005-05-29 20:23:46 -0700335 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800336 struct in_ifaddr *ifa, *ifa1 = *ifap;
337 struct in_ifaddr *last_prim = in_dev->ifa_list;
338 struct in_ifaddr *prev_prom = NULL;
339 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
341 ASSERT_RTNL();
342
David S. Millerfbd40ea2016-03-13 23:28:00 -0400343 if (in_dev->dead)
344 goto no_promotions;
345
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900346 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700347 * unless alias promotion is set
348 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
350 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
352
353 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900354 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800355 ifa1->ifa_scope <= ifa->ifa_scope)
356 last_prim = ifa;
357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
359 ifa1->ifa_mask != ifa->ifa_mask ||
360 !inet_ifa_match(ifa1->ifa_address, ifa)) {
361 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800362 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 continue;
364 }
365
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800366 if (!do_promote) {
David S. Millerfd23c3b2011-02-18 12:42:28 -0800367 inet_hash_remove(ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700368 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
Eric W. Biederman15e47302012-09-07 20:12:54 +0000370 rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800371 blocking_notifier_call_chain(&inetaddr_chain,
372 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700373 inet_free_ifa(ifa);
374 } else {
375 promote = ifa;
376 break;
377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 }
379 }
380
Julian Anastasov2d230e22011-03-19 12:13:52 +0000381 /* On promotion all secondaries from subnet are changing
382 * the primary IP, we must remove all their routes silently
383 * and later to add them back with new prefsrc. Do this
384 * while all addresses are on the device list.
385 */
386 for (ifa = promote; ifa; ifa = ifa->ifa_next) {
387 if (ifa1->ifa_mask == ifa->ifa_mask &&
388 inet_ifa_match(ifa1->ifa_address, ifa))
389 fib_del_ifaddr(ifa, ifa1);
390 }
391
David S. Millerfbd40ea2016-03-13 23:28:00 -0400392no_promotions:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 /* 2. Unlink it */
394
395 *ifap = ifa1->ifa_next;
David S. Millerfd23c3b2011-02-18 12:42:28 -0800396 inet_hash_remove(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
398 /* 3. Announce address deletion */
399
400 /* Send message first, then call notifier.
401 At first sight, FIB update triggered by notifier
402 will refer to already deleted ifaddr, that could confuse
403 netlink listeners. It is not true: look, gated sees
404 that route deleted and if it still thinks that ifaddr
405 is valid, it will try to restore deleted routes... Grr.
406 So that, this order is correct.
407 */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000408 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800409 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800410
411 if (promote) {
Julian Anastasov04024b92011-03-19 12:13:54 +0000412 struct in_ifaddr *next_sec = promote->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800413
414 if (prev_prom) {
415 prev_prom->ifa_next = promote->ifa_next;
416 promote->ifa_next = last_prim->ifa_next;
417 last_prim->ifa_next = promote;
418 }
419
420 promote->ifa_flags &= ~IFA_F_SECONDARY;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000421 rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800422 blocking_notifier_call_chain(&inetaddr_chain,
423 NETDEV_UP, promote);
Julian Anastasov04024b92011-03-19 12:13:54 +0000424 for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800425 if (ifa1->ifa_mask != ifa->ifa_mask ||
426 !inet_ifa_match(ifa1->ifa_address, ifa))
427 continue;
428 fib_add_ifaddr(ifa);
429 }
430
431 }
Herbert Xu63630972007-06-07 18:35:38 -0700432 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434}
435
Thomas Grafd6062cb2006-08-15 00:33:59 -0700436static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
437 int destroy)
438{
439 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
440}
441
Jiri Pirko5c766d62013-01-24 09:41:41 +0000442static void check_lifetime(struct work_struct *work);
443
444static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
445
Thomas Grafd6062cb2006-08-15 00:33:59 -0700446static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000447 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
449 struct in_device *in_dev = ifa->ifa_dev;
450 struct in_ifaddr *ifa1, **ifap, **last_primary;
451
452 ASSERT_RTNL();
453
454 if (!ifa->ifa_local) {
455 inet_free_ifa(ifa);
456 return 0;
457 }
458
459 ifa->ifa_flags &= ~IFA_F_SECONDARY;
460 last_primary = &in_dev->ifa_list;
461
Matteo Croce41504372019-07-01 19:01:55 +0200462 /* Don't set IPv6 only flags to IPv4 addresses */
463 ifa->ifa_flags &= ~IPV6ONLY_FLAGS;
464
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
466 ifap = &ifa1->ifa_next) {
467 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
468 ifa->ifa_scope <= ifa1->ifa_scope)
469 last_primary = &ifa1->ifa_next;
470 if (ifa1->ifa_mask == ifa->ifa_mask &&
471 inet_ifa_match(ifa1->ifa_address, ifa)) {
472 if (ifa1->ifa_local == ifa->ifa_local) {
473 inet_free_ifa(ifa);
474 return -EEXIST;
475 }
476 if (ifa1->ifa_scope != ifa->ifa_scope) {
477 inet_free_ifa(ifa);
478 return -EINVAL;
479 }
480 ifa->ifa_flags |= IFA_F_SECONDARY;
481 }
482 }
483
484 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500485 prandom_seed((__force u32) ifa->ifa_local);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 ifap = last_primary;
487 }
488
489 ifa->ifa_next = *ifap;
490 *ifap = ifa;
491
David S. Millerfd23c3b2011-02-18 12:42:28 -0800492 inet_hash_insert(dev_net(in_dev->dev), ifa);
493
Jiri Pirko5c766d62013-01-24 09:41:41 +0000494 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530495 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000496
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 /* Send message first, then call notifier.
498 Notifier will trigger FIB update, so that
499 listeners of netlink will know about new ifaddr */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000500 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800501 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
503 return 0;
504}
505
Thomas Grafd6062cb2006-08-15 00:33:59 -0700506static int inet_insert_ifa(struct in_ifaddr *ifa)
507{
508 return __inet_insert_ifa(ifa, NULL, 0);
509}
510
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
512{
Herbert Xue5ed6392005-10-03 14:35:55 -0700513 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
515 ASSERT_RTNL();
516
517 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700518 inet_free_ifa(ifa);
519 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700521 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100522 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700524 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 in_dev_hold(in_dev);
526 ifa->ifa_dev = in_dev;
527 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800528 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 ifa->ifa_scope = RT_SCOPE_HOST;
530 return inet_insert_ifa(ifa);
531}
532
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000533/* Caller must hold RCU or RTNL :
534 * We dont take a reference on found in_device
535 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800536struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537{
538 struct net_device *dev;
539 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000540
541 rcu_read_lock();
542 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000544 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000545 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 return in_dev;
547}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800548EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
550/* Called only from RTNL semaphored context. No locks. */
551
Al Viro60cad5d2006-09-26 22:17:09 -0700552struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
553 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554{
555 ASSERT_RTNL();
556
557 for_primary_ifa(in_dev) {
558 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
559 return ifa;
560 } endfor_ifa(in_dev);
561 return NULL;
562}
563
Taras Chornyi1cd63cc2020-04-09 20:25:24 +0300564static int ip_mc_autojoin_config(struct net *net, bool join,
565 const struct in_ifaddr *ifa)
Madhu Challa93a714d2015-02-25 09:58:35 -0800566{
Taras Chornyi1cd63cc2020-04-09 20:25:24 +0300567#if defined(CONFIG_IP_MULTICAST)
Madhu Challa93a714d2015-02-25 09:58:35 -0800568 struct ip_mreqn mreq = {
569 .imr_multiaddr.s_addr = ifa->ifa_address,
570 .imr_ifindex = ifa->ifa_dev->dev->ifindex,
571 };
Taras Chornyi1cd63cc2020-04-09 20:25:24 +0300572 struct sock *sk = net->ipv4.mc_autojoin_sk;
Madhu Challa93a714d2015-02-25 09:58:35 -0800573 int ret;
574
575 ASSERT_RTNL();
576
577 lock_sock(sk);
578 if (join)
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300579 ret = ip_mc_join_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800580 else
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300581 ret = ip_mc_leave_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800582 release_sock(sk);
583
584 return ret;
Taras Chornyi1cd63cc2020-04-09 20:25:24 +0300585#else
586 return -EOPNOTSUPP;
587#endif
Madhu Challa93a714d2015-02-25 09:58:35 -0800588}
589
Thomas Graf661d2962013-03-21 07:45:29 +0000590static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900592 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700593 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700595 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700597 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
599 ASSERT_RTNL();
600
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700601 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
602 if (err < 0)
603 goto errout;
604
605 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800606 in_dev = inetdev_by_index(net, ifm->ifa_index);
Ian Morris51456b22015-04-03 09:17:26 +0100607 if (!in_dev) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700608 err = -ENODEV;
609 goto errout;
610 }
611
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
613 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700614 if (tb[IFA_LOCAL] &&
Jiri Benc67b61f62015-03-29 16:59:26 +0200615 ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700617
618 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
619 continue;
620
621 if (tb[IFA_ADDRESS] &&
622 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Jiri Benc67b61f62015-03-29 16:59:26 +0200623 !inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700624 continue;
625
Madhu Challa93a714d2015-02-25 09:58:35 -0800626 if (ipv4_is_multicast(ifa->ifa_address))
Taras Chornyi1cd63cc2020-04-09 20:25:24 +0300627 ip_mc_autojoin_config(net, false, ifa);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000628 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 return 0;
630 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700631
632 err = -EADDRNOTAVAIL;
633errout:
634 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635}
636
Jiri Pirko5c766d62013-01-24 09:41:41 +0000637#define INFINITY_LIFE_TIME 0xFFFFFFFF
638
639static void check_lifetime(struct work_struct *work)
640{
641 unsigned long now, next, next_sec, next_sched;
642 struct in_ifaddr *ifa;
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000643 struct hlist_node *n;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000644 int i;
645
646 now = jiffies;
647 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
648
Jiri Pirko5c766d62013-01-24 09:41:41 +0000649 for (i = 0; i < IN4_ADDR_HSIZE; i++) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000650 bool change_needed = false;
651
652 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800653 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
Jiri Pirko5c766d62013-01-24 09:41:41 +0000654 unsigned long age;
655
656 if (ifa->ifa_flags & IFA_F_PERMANENT)
657 continue;
658
659 /* We try to batch several events at once. */
660 age = (now - ifa->ifa_tstamp +
661 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
662
663 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
664 age >= ifa->ifa_valid_lft) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000665 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000666 } else if (ifa->ifa_preferred_lft ==
667 INFINITY_LIFE_TIME) {
668 continue;
669 } else if (age >= ifa->ifa_preferred_lft) {
670 if (time_before(ifa->ifa_tstamp +
671 ifa->ifa_valid_lft * HZ, next))
672 next = ifa->ifa_tstamp +
673 ifa->ifa_valid_lft * HZ;
674
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000675 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
676 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000677 } else if (time_before(ifa->ifa_tstamp +
678 ifa->ifa_preferred_lft * HZ,
679 next)) {
680 next = ifa->ifa_tstamp +
681 ifa->ifa_preferred_lft * HZ;
682 }
683 }
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000684 rcu_read_unlock();
685 if (!change_needed)
686 continue;
687 rtnl_lock();
688 hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
689 unsigned long age;
690
691 if (ifa->ifa_flags & IFA_F_PERMANENT)
692 continue;
693
694 /* We try to batch several events at once. */
695 age = (now - ifa->ifa_tstamp +
696 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
697
698 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
699 age >= ifa->ifa_valid_lft) {
700 struct in_ifaddr **ifap;
701
702 for (ifap = &ifa->ifa_dev->ifa_list;
703 *ifap != NULL; ifap = &(*ifap)->ifa_next) {
704 if (*ifap == ifa) {
705 inet_del_ifa(ifa->ifa_dev,
706 ifap, 1);
707 break;
708 }
709 }
710 } else if (ifa->ifa_preferred_lft !=
711 INFINITY_LIFE_TIME &&
712 age >= ifa->ifa_preferred_lft &&
713 !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
714 ifa->ifa_flags |= IFA_F_DEPRECATED;
715 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
716 }
717 }
718 rtnl_unlock();
Jiri Pirko5c766d62013-01-24 09:41:41 +0000719 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000720
721 next_sec = round_jiffies_up(next);
722 next_sched = next;
723
724 /* If rounded timeout is accurate enough, accept it. */
725 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
726 next_sched = next_sec;
727
728 now = jiffies;
729 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
730 if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
731 next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
732
viresh kumar906e0732014-01-22 12:23:32 +0530733 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work,
734 next_sched - now);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000735}
736
737static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
738 __u32 prefered_lft)
739{
740 unsigned long timeout;
741
742 ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
743
744 timeout = addrconf_timeout_fixup(valid_lft, HZ);
745 if (addrconf_finite_timeout(timeout))
746 ifa->ifa_valid_lft = timeout;
747 else
748 ifa->ifa_flags |= IFA_F_PERMANENT;
749
750 timeout = addrconf_timeout_fixup(prefered_lft, HZ);
751 if (addrconf_finite_timeout(timeout)) {
752 if (timeout == 0)
753 ifa->ifa_flags |= IFA_F_DEPRECATED;
754 ifa->ifa_preferred_lft = timeout;
755 }
756 ifa->ifa_tstamp = jiffies;
757 if (!ifa->ifa_cstamp)
758 ifa->ifa_cstamp = ifa->ifa_tstamp;
759}
760
761static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
762 __u32 *pvalid_lft, __u32 *pprefered_lft)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763{
Thomas Graf5c753972006-08-04 23:03:53 -0700764 struct nlattr *tb[IFA_MAX+1];
765 struct in_ifaddr *ifa;
766 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 struct net_device *dev;
768 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800769 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
Thomas Graf5c753972006-08-04 23:03:53 -0700771 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
772 if (err < 0)
773 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
Thomas Graf5c753972006-08-04 23:03:53 -0700775 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800776 err = -EINVAL;
Ian Morris51456b22015-04-03 09:17:26 +0100777 if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL])
Thomas Graf5c753972006-08-04 23:03:53 -0700778 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800780 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800781 err = -ENODEV;
Ian Morris51456b22015-04-03 09:17:26 +0100782 if (!dev)
Thomas Graf5c753972006-08-04 23:03:53 -0700783 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
Thomas Graf5c753972006-08-04 23:03:53 -0700785 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800786 err = -ENOBUFS;
Ian Morris51456b22015-04-03 09:17:26 +0100787 if (!in_dev)
Herbert Xu71e27da2007-06-04 23:36:06 -0700788 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
Thomas Graf5c753972006-08-04 23:03:53 -0700790 ifa = inet_alloc_ifa();
Ian Morris51456b22015-04-03 09:17:26 +0100791 if (!ifa)
Thomas Graf5c753972006-08-04 23:03:53 -0700792 /*
793 * A potential indev allocation can be left alive, it stays
794 * assigned to its device and is destroy with it.
795 */
Thomas Graf5c753972006-08-04 23:03:53 -0700796 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700797
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800798 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100799 neigh_parms_data_state_setall(in_dev->arp_parms);
Thomas Graf5c753972006-08-04 23:03:53 -0700800 in_dev_hold(in_dev);
801
Ian Morris51456b22015-04-03 09:17:26 +0100802 if (!tb[IFA_ADDRESS])
Thomas Graf5c753972006-08-04 23:03:53 -0700803 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
804
David S. Millerfd23c3b2011-02-18 12:42:28 -0800805 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
807 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100808 ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
809 ifm->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700811 ifa->ifa_dev = in_dev;
812
Jiri Benc67b61f62015-03-29 16:59:26 +0200813 ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]);
814 ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700815
816 if (tb[IFA_BROADCAST])
Jiri Benc67b61f62015-03-29 16:59:26 +0200817 ifa->ifa_broadcast = nla_get_in_addr(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700818
Thomas Graf5c753972006-08-04 23:03:53 -0700819 if (tb[IFA_LABEL])
820 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 else
822 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
823
Jiri Pirko5c766d62013-01-24 09:41:41 +0000824 if (tb[IFA_CACHEINFO]) {
825 struct ifa_cacheinfo *ci;
826
827 ci = nla_data(tb[IFA_CACHEINFO]);
828 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
829 err = -EINVAL;
Daniel Borkmann446266b2013-08-02 11:32:43 +0200830 goto errout_free;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000831 }
832 *pvalid_lft = ci->ifa_valid;
833 *pprefered_lft = ci->ifa_prefered;
834 }
835
Thomas Graf5c753972006-08-04 23:03:53 -0700836 return ifa;
837
Daniel Borkmann446266b2013-08-02 11:32:43 +0200838errout_free:
839 inet_free_ifa(ifa);
Thomas Graf5c753972006-08-04 23:03:53 -0700840errout:
841 return ERR_PTR(err);
842}
843
Jiri Pirko5c766d62013-01-24 09:41:41 +0000844static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
845{
846 struct in_device *in_dev = ifa->ifa_dev;
847 struct in_ifaddr *ifa1, **ifap;
848
849 if (!ifa->ifa_local)
850 return NULL;
851
852 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
853 ifap = &ifa1->ifa_next) {
854 if (ifa1->ifa_mask == ifa->ifa_mask &&
855 inet_ifa_match(ifa1->ifa_address, ifa) &&
856 ifa1->ifa_local == ifa->ifa_local)
857 return ifa1;
858 }
859 return NULL;
860}
861
Thomas Graf661d2962013-03-21 07:45:29 +0000862static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
Thomas Graf5c753972006-08-04 23:03:53 -0700863{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900864 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700865 struct in_ifaddr *ifa;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000866 struct in_ifaddr *ifa_existing;
867 __u32 valid_lft = INFINITY_LIFE_TIME;
868 __u32 prefered_lft = INFINITY_LIFE_TIME;
Thomas Graf5c753972006-08-04 23:03:53 -0700869
870 ASSERT_RTNL();
871
Jiri Pirko5c766d62013-01-24 09:41:41 +0000872 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft);
Thomas Graf5c753972006-08-04 23:03:53 -0700873 if (IS_ERR(ifa))
874 return PTR_ERR(ifa);
875
Jiri Pirko5c766d62013-01-24 09:41:41 +0000876 ifa_existing = find_matching_ifa(ifa);
877 if (!ifa_existing) {
878 /* It would be best to check for !NLM_F_CREATE here but
stephen hemminger614d0562014-05-16 20:46:58 -0700879 * userspace already relies on not having to provide this.
Jiri Pirko5c766d62013-01-24 09:41:41 +0000880 */
881 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Madhu Challa93a714d2015-02-25 09:58:35 -0800882 if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
Taras Chornyi1cd63cc2020-04-09 20:25:24 +0300883 int ret = ip_mc_autojoin_config(net, true, ifa);
Madhu Challa93a714d2015-02-25 09:58:35 -0800884
885 if (ret < 0) {
886 inet_free_ifa(ifa);
887 return ret;
888 }
889 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000890 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
891 } else {
892 inet_free_ifa(ifa);
893
894 if (nlh->nlmsg_flags & NLM_F_EXCL ||
895 !(nlh->nlmsg_flags & NLM_F_REPLACE))
896 return -EEXIST;
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000897 ifa = ifa_existing;
898 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Jiri Pirko05a324b2013-04-04 23:39:38 +0000899 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530900 queue_delayed_work(system_power_efficient_wq,
901 &check_lifetime_work, 0);
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000902 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000903 }
904 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905}
906
907/*
908 * Determine a default network mask, based on the IP address.
909 */
910
Eric Dumazet40384992012-08-03 21:06:50 +0000911static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912{
913 int rc = -1; /* Something else, probably a multicast. */
914
Joe Perchesf97c1e02007-12-16 13:45:43 -0800915 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900916 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 else {
Al Viro714e85b2006-11-14 20:51:49 -0800918 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
Al Viro714e85b2006-11-14 20:51:49 -0800920 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800922 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800924 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 rc = 24;
926 }
927
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900928 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929}
930
931
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800932int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933{
934 struct ifreq ifr;
935 struct sockaddr_in sin_orig;
936 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
937 struct in_device *in_dev;
938 struct in_ifaddr **ifap = NULL;
939 struct in_ifaddr *ifa = NULL;
940 struct net_device *dev;
941 char *colon;
942 int ret = -EFAULT;
943 int tryaddrmatch = 0;
944
945 /*
946 * Fetch the caller's info block into kernel space
947 */
948
949 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
950 goto out;
951 ifr.ifr_name[IFNAMSIZ - 1] = 0;
952
953 /* save original address for comparison */
954 memcpy(&sin_orig, sin, sizeof(*sin));
955
956 colon = strchr(ifr.ifr_name, ':');
957 if (colon)
958 *colon = 0;
959
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800960 dev_load(net, ifr.ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Stephen Hemminger132adf52007-03-08 20:44:43 -0800962 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 case SIOCGIFADDR: /* Get interface address */
964 case SIOCGIFBRDADDR: /* Get the broadcast address */
965 case SIOCGIFDSTADDR: /* Get the destination address */
966 case SIOCGIFNETMASK: /* Get the netmask for the interface */
967 /* Note that these ioctls will not sleep,
968 so that we do not impose a lock.
969 One day we will be forced to put shlock here (I mean SMP)
970 */
971 tryaddrmatch = (sin_orig.sin_family == AF_INET);
972 memset(sin, 0, sizeof(*sin));
973 sin->sin_family = AF_INET;
974 break;
975
976 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000977 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000978 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 goto out;
980 break;
981 case SIOCSIFADDR: /* Set interface address (and family) */
982 case SIOCSIFBRDADDR: /* Set the broadcast address */
983 case SIOCSIFDSTADDR: /* Set the destination address */
984 case SIOCSIFNETMASK: /* Set the netmask for the interface */
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000985 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000986 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 goto out;
988 ret = -EINVAL;
989 if (sin->sin_family != AF_INET)
990 goto out;
991 break;
992 default:
993 ret = -EINVAL;
994 goto out;
995 }
996
997 rtnl_lock();
998
999 ret = -ENODEV;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001000 dev = __dev_get_by_name(net, ifr.ifr_name);
1001 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 goto done;
1003
1004 if (colon)
1005 *colon = ':';
1006
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001007 in_dev = __in_dev_get_rtnl(dev);
1008 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 if (tryaddrmatch) {
1010 /* Matthias Andree */
1011 /* compare label and address (4.4BSD style) */
1012 /* note: we only do this for a limited set of ioctls
1013 and only if the original address family was AF_INET.
1014 This is checked above. */
1015 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1016 ifap = &ifa->ifa_next) {
1017 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
1018 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -08001019 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 break; /* found */
1021 }
1022 }
1023 }
1024 /* we didn't get a match, maybe the application is
1025 4.3BSD-style and passed in junk so we fall back to
1026 comparing just the label */
1027 if (!ifa) {
1028 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1029 ifap = &ifa->ifa_next)
1030 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
1031 break;
1032 }
1033 }
1034
1035 ret = -EADDRNOTAVAIL;
1036 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
1037 goto done;
1038
Stephen Hemminger132adf52007-03-08 20:44:43 -08001039 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 case SIOCGIFADDR: /* Get interface address */
1041 sin->sin_addr.s_addr = ifa->ifa_local;
1042 goto rarok;
1043
1044 case SIOCGIFBRDADDR: /* Get the broadcast address */
1045 sin->sin_addr.s_addr = ifa->ifa_broadcast;
1046 goto rarok;
1047
1048 case SIOCGIFDSTADDR: /* Get the destination address */
1049 sin->sin_addr.s_addr = ifa->ifa_address;
1050 goto rarok;
1051
1052 case SIOCGIFNETMASK: /* Get the netmask for the interface */
1053 sin->sin_addr.s_addr = ifa->ifa_mask;
1054 goto rarok;
1055
1056 case SIOCSIFFLAGS:
1057 if (colon) {
1058 ret = -EADDRNOTAVAIL;
1059 if (!ifa)
1060 break;
1061 ret = 0;
1062 if (!(ifr.ifr_flags & IFF_UP))
1063 inet_del_ifa(in_dev, ifap, 1);
1064 break;
1065 }
1066 ret = dev_change_flags(dev, ifr.ifr_flags);
1067 break;
1068
1069 case SIOCSIFADDR: /* Set interface address (and family) */
1070 ret = -EINVAL;
1071 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1072 break;
1073
1074 if (!ifa) {
1075 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001076 ifa = inet_alloc_ifa();
1077 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 break;
Xi Wangc7e2e1d2013-01-05 11:19:24 +00001079 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 if (colon)
1081 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
1082 else
1083 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1084 } else {
1085 ret = 0;
1086 if (ifa->ifa_local == sin->sin_addr.s_addr)
1087 break;
1088 inet_del_ifa(in_dev, ifap, 0);
1089 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -08001090 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 }
1092
1093 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
1094
1095 if (!(dev->flags & IFF_POINTOPOINT)) {
1096 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
1097 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
1098 if ((dev->flags & IFF_BROADCAST) &&
1099 ifa->ifa_prefixlen < 31)
1100 ifa->ifa_broadcast = ifa->ifa_address |
1101 ~ifa->ifa_mask;
1102 } else {
1103 ifa->ifa_prefixlen = 32;
1104 ifa->ifa_mask = inet_make_mask(32);
1105 }
Jiri Pirko5c766d62013-01-24 09:41:41 +00001106 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 ret = inet_set_ifa(dev, ifa);
1108 break;
1109
1110 case SIOCSIFBRDADDR: /* Set the broadcast address */
1111 ret = 0;
1112 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
1113 inet_del_ifa(in_dev, ifap, 0);
1114 ifa->ifa_broadcast = sin->sin_addr.s_addr;
1115 inet_insert_ifa(ifa);
1116 }
1117 break;
1118
1119 case SIOCSIFDSTADDR: /* Set the destination address */
1120 ret = 0;
1121 if (ifa->ifa_address == sin->sin_addr.s_addr)
1122 break;
1123 ret = -EINVAL;
1124 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1125 break;
1126 ret = 0;
1127 inet_del_ifa(in_dev, ifap, 0);
1128 ifa->ifa_address = sin->sin_addr.s_addr;
1129 inet_insert_ifa(ifa);
1130 break;
1131
1132 case SIOCSIFNETMASK: /* Set the netmask for the interface */
1133
1134 /*
1135 * The mask we set must be legal.
1136 */
1137 ret = -EINVAL;
1138 if (bad_mask(sin->sin_addr.s_addr, 0))
1139 break;
1140 ret = 0;
1141 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -07001142 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 inet_del_ifa(in_dev, ifap, 0);
1144 ifa->ifa_mask = sin->sin_addr.s_addr;
1145 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
1146
1147 /* See if current broadcast address matches
1148 * with current netmask, then recalculate
1149 * the broadcast address. Otherwise it's a
1150 * funny address, so don't touch it since
1151 * the user seems to know what (s)he's doing...
1152 */
1153 if ((dev->flags & IFF_BROADCAST) &&
1154 (ifa->ifa_prefixlen < 31) &&
1155 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -05001156 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 ifa->ifa_broadcast = (ifa->ifa_local |
1158 ~sin->sin_addr.s_addr);
1159 }
1160 inet_insert_ifa(ifa);
1161 }
1162 break;
1163 }
1164done:
1165 rtnl_unlock();
1166out:
1167 return ret;
1168rarok:
1169 rtnl_unlock();
1170 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
1171 goto out;
1172}
1173
1174static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
1175{
Herbert Xue5ed6392005-10-03 14:35:55 -07001176 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 struct in_ifaddr *ifa;
1178 struct ifreq ifr;
1179 int done = 0;
1180
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001181 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 goto out;
1183
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001184 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 if (!buf) {
1186 done += sizeof(ifr);
1187 continue;
1188 }
1189 if (len < (int) sizeof(ifr))
1190 break;
1191 memset(&ifr, 0, sizeof(struct ifreq));
Dan Carpenter4299c8a2013-07-29 22:15:19 +03001192 strcpy(ifr.ifr_name, ifa->ifa_label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
1194 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
1195 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1196 ifa->ifa_local;
1197
1198 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
1199 done = -EFAULT;
1200 break;
1201 }
1202 buf += sizeof(struct ifreq);
1203 len -= sizeof(struct ifreq);
1204 done += sizeof(struct ifreq);
1205 }
1206out:
1207 return done;
1208}
1209
Al Viroa61ced52006-09-26 21:27:54 -07001210__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211{
Al Viroa61ced52006-09-26 21:27:54 -07001212 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001214 struct net *net = dev_net(dev);
David Ahern3f2fb9a2016-02-24 11:47:02 -08001215 int master_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
1217 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001218 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 if (!in_dev)
1220 goto no_in_dev;
1221
1222 for_primary_ifa(in_dev) {
1223 if (ifa->ifa_scope > scope)
1224 continue;
1225 if (!dst || inet_ifa_match(dst, ifa)) {
1226 addr = ifa->ifa_local;
1227 break;
1228 }
1229 if (!addr)
1230 addr = ifa->ifa_local;
1231 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
1233 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001234 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001235no_in_dev:
David Ahern3f2fb9a2016-02-24 11:47:02 -08001236 master_idx = l3mdev_master_ifindex_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237
David Lamparter17b693c2016-02-24 11:47:03 -08001238 /* For VRFs, the VRF device takes the place of the loopback device,
1239 * with addresses on it being preferred. Note in such cases the
1240 * loopback device will be among the devices that fail the master_idx
1241 * equality check in the loop below.
1242 */
1243 if (master_idx &&
1244 (dev = dev_get_by_index_rcu(net, master_idx)) &&
1245 (in_dev = __in_dev_get_rcu(dev))) {
1246 for_primary_ifa(in_dev) {
1247 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1248 ifa->ifa_scope <= scope) {
1249 addr = ifa->ifa_local;
1250 goto out_unlock;
1251 }
1252 } endfor_ifa(in_dev);
1253 }
1254
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 /* Not loopback addresses on loopback should be preferred
Stephen Hemmingerca9f1fd2015-02-14 13:47:54 -05001256 in this case. It is important that lo is the first interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 in dev_base list.
1258 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001259 for_each_netdev_rcu(net, dev) {
David Ahern3f2fb9a2016-02-24 11:47:02 -08001260 if (l3mdev_master_ifindex_rcu(dev) != master_idx)
1261 continue;
1262
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001263 in_dev = __in_dev_get_rcu(dev);
1264 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 continue;
1266
1267 for_primary_ifa(in_dev) {
1268 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1269 ifa->ifa_scope <= scope) {
1270 addr = ifa->ifa_local;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001271 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 }
1273 } endfor_ifa(in_dev);
1274 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001275out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 return addr;
1278}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001279EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
Al Viro60cad5d2006-09-26 22:17:09 -07001281static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1282 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283{
1284 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001285 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286
1287 for_ifa(in_dev) {
1288 if (!addr &&
1289 (local == ifa->ifa_local || !local) &&
1290 ifa->ifa_scope <= scope) {
1291 addr = ifa->ifa_local;
1292 if (same)
1293 break;
1294 }
1295 if (!same) {
1296 same = (!local || inet_ifa_match(local, ifa)) &&
1297 (!dst || inet_ifa_match(dst, ifa));
1298 if (same && addr) {
1299 if (local || !dst)
1300 break;
1301 /* Is the selected addr into dst subnet? */
1302 if (inet_ifa_match(addr, ifa))
1303 break;
1304 /* No, then can we use new local src? */
1305 if (ifa->ifa_scope <= scope) {
1306 addr = ifa->ifa_local;
1307 break;
1308 }
1309 /* search for large dst subnet for addr */
1310 same = 0;
1311 }
1312 }
1313 } endfor_ifa(in_dev);
1314
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001315 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316}
1317
1318/*
1319 * Confirm that local IP address exists using wildcards:
Nicolas Dichtelb601fa12013-12-10 15:02:40 +01001320 * - net: netns to check, cannot be NULL
1321 * - in_dev: only on this interface, NULL=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 * - dst: only in the same subnet as dst, 0=any dst
1323 * - local: address, 0=autoselect the local address
1324 * - scope: maximum allowed scope value for the local address
1325 */
Nicolas Dichtelb601fa12013-12-10 15:02:40 +01001326__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001327 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328{
Al Viro60cad5d2006-09-26 22:17:09 -07001329 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001330 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331
Ian Morris00db4122015-04-03 09:17:27 +01001332 if (in_dev)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001333 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001336 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001337 in_dev = __in_dev_get_rcu(dev);
1338 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 addr = confirm_addr_indev(in_dev, dst, local, scope);
1340 if (addr)
1341 break;
1342 }
1343 }
1344 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
1346 return addr;
1347}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001348EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
1350/*
1351 * Device notifier
1352 */
1353
1354int register_inetaddr_notifier(struct notifier_block *nb)
1355{
Alan Sterne041c682006-03-27 01:16:30 -08001356 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001358EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
1360int unregister_inetaddr_notifier(struct notifier_block *nb)
1361{
Alan Sterne041c682006-03-27 01:16:30 -08001362 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001364EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001366/* Rename ifa_labels for a device name change. Make some effort to preserve
1367 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368*/
1369static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001370{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 struct in_ifaddr *ifa;
1372 int named = 0;
1373
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001374 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1375 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
1377 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001378 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001380 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001381 dot = strchr(old, ':');
Ian Morris51456b22015-04-03 09:17:26 +01001382 if (!dot) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001383 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 dot = old;
1385 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001386 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001387 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001388 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001389 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001390skip:
1391 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001392 }
1393}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
Ian Campbelld11327ad2011-02-11 07:44:16 +00001395static void inetdev_send_gratuitous_arp(struct net_device *dev,
1396 struct in_device *in_dev)
1397
1398{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001399 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001400
Zoltan Kissb76d0782011-07-24 13:09:30 +00001401 for (ifa = in_dev->ifa_list; ifa;
1402 ifa = ifa->ifa_next) {
1403 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1404 ifa->ifa_local, dev,
1405 ifa->ifa_local, NULL,
1406 dev->dev_addr, NULL);
1407 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001408}
1409
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410/* Called only under RTNL semaphore */
1411
1412static int inetdev_event(struct notifier_block *this, unsigned long event,
1413 void *ptr)
1414{
Jiri Pirko351638e2013-05-28 01:30:21 +00001415 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazet748e2d92012-08-22 21:50:59 +00001416 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417
1418 ASSERT_RTNL();
1419
1420 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001421 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 in_dev = inetdev_init(dev);
WANG Cong20e61da2014-07-25 15:25:08 -07001423 if (IS_ERR(in_dev))
1424 return notifier_from_errno(PTR_ERR(in_dev));
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001425 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001426 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1427 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001428 }
Breno Leitao06770842008-09-02 17:28:58 -07001429 } else if (event == NETDEV_CHANGEMTU) {
1430 /* Re-enabling IP */
1431 if (inetdev_valid_mtu(dev->mtu))
1432 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 }
1434 goto out;
1435 }
1436
1437 switch (event) {
1438 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001439 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001440 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 break;
1442 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001443 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001445 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001446 struct in_ifaddr *ifa = inet_alloc_ifa();
1447
1448 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001449 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 ifa->ifa_local =
1451 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1452 ifa->ifa_prefixlen = 8;
1453 ifa->ifa_mask = inet_make_mask(8);
1454 in_dev_hold(in_dev);
1455 ifa->ifa_dev = in_dev;
1456 ifa->ifa_scope = RT_SCOPE_HOST;
1457 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Jiri Pirko5c766d62013-01-24 09:41:41 +00001458 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1459 INFINITY_LIFE_TIME);
Jiri Pirkodfd15822014-01-07 15:55:45 +01001460 ipv4_devconf_setall(in_dev);
1461 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 inet_insert_ifa(ifa);
1463 }
1464 }
1465 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001466 /* fall through */
1467 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001468 if (!IN_DEV_ARP_NOTIFY(in_dev))
1469 break;
1470 /* fall through */
1471 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001472 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001473 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 break;
1475 case NETDEV_DOWN:
1476 ip_mc_down(in_dev);
1477 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001478 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001479 ip_mc_unmap(in_dev);
1480 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001481 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001482 ip_mc_remap(in_dev);
1483 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001485 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 break;
Breno Leitao06770842008-09-02 17:28:58 -07001487 /* disable IP when MTU is not enough */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 case NETDEV_UNREGISTER:
1489 inetdev_destroy(in_dev);
1490 break;
1491 case NETDEV_CHANGENAME:
1492 /* Do not notify about label change, this event is
1493 * not interesting to applications using netlink.
1494 */
1495 inetdev_changename(dev, in_dev);
1496
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001497 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001498 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 break;
1500 }
1501out:
1502 return NOTIFY_DONE;
1503}
1504
1505static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001506 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507};
1508
Eric Dumazet40384992012-08-03 21:06:50 +00001509static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001510{
1511 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1512 + nla_total_size(4) /* IFA_ADDRESS */
1513 + nla_total_size(4) /* IFA_LOCAL */
1514 + nla_total_size(4) /* IFA_BROADCAST */
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001515 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001516 + nla_total_size(4) /* IFA_FLAGS */
1517 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
Thomas Graf339bf982006-11-10 14:10:15 -08001518}
1519
Jiri Pirko5c766d62013-01-24 09:41:41 +00001520static inline u32 cstamp_delta(unsigned long cstamp)
1521{
1522 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1523}
1524
1525static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1526 unsigned long tstamp, u32 preferred, u32 valid)
1527{
1528 struct ifa_cacheinfo ci;
1529
1530 ci.cstamp = cstamp_delta(cstamp);
1531 ci.tstamp = cstamp_delta(tstamp);
1532 ci.ifa_prefered = preferred;
1533 ci.ifa_valid = valid;
1534
1535 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1536}
1537
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001539 u32 portid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540{
1541 struct ifaddrmsg *ifm;
1542 struct nlmsghdr *nlh;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001543 u32 preferred, valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
Eric W. Biederman15e47302012-09-07 20:12:54 +00001545 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
Ian Morris51456b22015-04-03 09:17:26 +01001546 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08001547 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001548
1549 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 ifm->ifa_family = AF_INET;
1551 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001552 ifm->ifa_flags = ifa->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 ifm->ifa_scope = ifa->ifa_scope;
1554 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555
Jiri Pirko5c766d62013-01-24 09:41:41 +00001556 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1557 preferred = ifa->ifa_preferred_lft;
1558 valid = ifa->ifa_valid_lft;
1559 if (preferred != INFINITY_LIFE_TIME) {
1560 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1561
1562 if (preferred > tval)
1563 preferred -= tval;
1564 else
1565 preferred = 0;
1566 if (valid != INFINITY_LIFE_TIME) {
1567 if (valid > tval)
1568 valid -= tval;
1569 else
1570 valid = 0;
1571 }
1572 }
1573 } else {
1574 preferred = INFINITY_LIFE_TIME;
1575 valid = INFINITY_LIFE_TIME;
1576 }
David S. Millerf3756b72012-04-01 20:39:02 -04001577 if ((ifa->ifa_address &&
Jiri Benc930345e2015-03-29 16:59:25 +02001578 nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001579 (ifa->ifa_local &&
Jiri Benc930345e2015-03-29 16:59:25 +02001580 nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001581 (ifa->ifa_broadcast &&
Jiri Benc930345e2015-03-29 16:59:25 +02001582 nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001583 (ifa->ifa_label[0] &&
Jiri Pirko5c766d62013-01-24 09:41:41 +00001584 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001585 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
Jiri Pirko5c766d62013-01-24 09:41:41 +00001586 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1587 preferred, valid))
David S. Millerf3756b72012-04-01 20:39:02 -04001588 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001589
Johannes Berg053c0952015-01-16 22:09:00 +01001590 nlmsg_end(skb, nlh);
1591 return 0;
Thomas Graf47f68512006-08-04 23:04:36 -07001592
1593nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001594 nlmsg_cancel(skb, nlh);
1595 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596}
1597
1598static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1599{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001600 struct net *net = sock_net(skb->sk);
Eric Dumazeteec4df92009-11-12 07:44:25 +00001601 int h, s_h;
1602 int idx, s_idx;
1603 int ip_idx, s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 struct net_device *dev;
1605 struct in_device *in_dev;
1606 struct in_ifaddr *ifa;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001607 struct hlist_head *head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608
Eric Dumazeteec4df92009-11-12 07:44:25 +00001609 s_h = cb->args[0];
1610 s_idx = idx = cb->args[1];
1611 s_ip_idx = ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612
Eric Dumazeteec4df92009-11-12 07:44:25 +00001613 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1614 idx = 0;
1615 head = &net->dev_index_head[h];
1616 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001617 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1618 net->dev_base_seq;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001619 hlist_for_each_entry_rcu(dev, head, index_hlist) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001620 if (idx < s_idx)
1621 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001622 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001623 s_ip_idx = 0;
1624 in_dev = __in_dev_get_rcu(dev);
1625 if (!in_dev)
1626 goto cont;
1627
1628 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1629 ifa = ifa->ifa_next, ip_idx++) {
1630 if (ip_idx < s_ip_idx)
1631 continue;
1632 if (inet_fill_ifaddr(skb, ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001633 NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 cb->nlh->nlmsg_seq,
Johannes Berg053c0952015-01-16 22:09:00 +01001635 RTM_NEWADDR, NLM_F_MULTI) < 0) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001636 rcu_read_unlock();
1637 goto done;
1638 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001639 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Eric Dumazeteec4df92009-11-12 07:44:25 +00001640 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001641cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001642 idx++;
1643 }
1644 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 }
1646
1647done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001648 cb->args[0] = h;
1649 cb->args[1] = idx;
1650 cb->args[2] = ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651
1652 return skb->len;
1653}
1654
Jianjun Kong539afed2008-11-03 02:48:48 -08001655static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001656 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657{
Thomas Graf47f68512006-08-04 23:04:36 -07001658 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001659 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1660 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001661 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001663 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001664 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001665 if (!skb)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001666 goto errout;
1667
Eric W. Biederman15e47302012-09-07 20:12:54 +00001668 err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001669 if (err < 0) {
1670 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1671 WARN_ON(err == -EMSGSIZE);
1672 kfree_skb(skb);
1673 goto errout;
1674 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001675 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001676 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001677errout:
1678 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001679 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680}
1681
Arad, Ronenb1974ed2015-10-19 09:23:28 -07001682static size_t inet_get_link_af_size(const struct net_device *dev,
1683 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001684{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001685 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001686
1687 if (!in_dev)
1688 return 0;
1689
1690 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1691}
1692
Sowmini Varadhand5566fd2015-09-11 16:48:48 -04001693static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
1694 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001695{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001696 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001697 struct nlattr *nla;
1698 int i;
1699
1700 if (!in_dev)
1701 return -ENODATA;
1702
1703 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
Ian Morris51456b22015-04-03 09:17:26 +01001704 if (!nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001705 return -EMSGSIZE;
1706
1707 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1708 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1709
1710 return 0;
1711}
1712
1713static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1714 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1715};
1716
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001717static int inet_validate_link_af(const struct net_device *dev,
1718 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001719{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001720 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1721 int err, rem;
1722
Eric Dumazetf7fce742010-12-01 06:03:06 +00001723 if (dev && !__in_dev_get_rtnl(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001724 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001725
1726 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy);
1727 if (err < 0)
1728 return err;
1729
1730 if (tb[IFLA_INET_CONF]) {
1731 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1732 int cfgid = nla_type(a);
1733
1734 if (nla_len(a) < 4)
1735 return -EINVAL;
1736
1737 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1738 return -EINVAL;
1739 }
1740 }
1741
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001742 return 0;
1743}
1744
1745static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1746{
Eric Dumazetf7fce742010-12-01 06:03:06 +00001747 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001748 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1749 int rem;
1750
1751 if (!in_dev)
1752 return -EAFNOSUPPORT;
1753
1754 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL) < 0)
1755 BUG();
1756
Thomas Graf9f0f7272010-11-16 04:32:48 +00001757 if (tb[IFLA_INET_CONF]) {
1758 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1759 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1760 }
1761
1762 return 0;
1763}
1764
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001765static int inet_netconf_msgsize_devconf(int type)
1766{
1767 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1768 + nla_total_size(4); /* NETCONFA_IFINDEX */
Zhang Shengju136ba622016-03-10 08:55:50 +00001769 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001770
Zhang Shengju136ba622016-03-10 08:55:50 +00001771 if (type == NETCONFA_ALL)
1772 all = true;
1773
1774 if (all || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001775 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001776 if (all || type == NETCONFA_RP_FILTER)
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001777 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001778 if (all || type == NETCONFA_MC_FORWARDING)
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001779 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001780 if (all || type == NETCONFA_PROXY_NEIGH)
stephen hemmingerf085ff12013-12-12 13:06:50 -08001781 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001782 if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001783 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001784
1785 return size;
1786}
1787
1788static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1789 struct ipv4_devconf *devconf, u32 portid,
1790 u32 seq, int event, unsigned int flags,
1791 int type)
1792{
1793 struct nlmsghdr *nlh;
1794 struct netconfmsg *ncm;
Zhang Shengju136ba622016-03-10 08:55:50 +00001795 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001796
1797 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1798 flags);
Ian Morris51456b22015-04-03 09:17:26 +01001799 if (!nlh)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001800 return -EMSGSIZE;
1801
Zhang Shengju136ba622016-03-10 08:55:50 +00001802 if (type == NETCONFA_ALL)
1803 all = true;
1804
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001805 ncm = nlmsg_data(nlh);
1806 ncm->ncm_family = AF_INET;
1807
1808 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1809 goto nla_put_failure;
1810
Zhang Shengju136ba622016-03-10 08:55:50 +00001811 if ((all || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001812 nla_put_s32(skb, NETCONFA_FORWARDING,
1813 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1814 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001815 if ((all || type == NETCONFA_RP_FILTER) &&
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001816 nla_put_s32(skb, NETCONFA_RP_FILTER,
1817 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
1818 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001819 if ((all || type == NETCONFA_MC_FORWARDING) &&
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001820 nla_put_s32(skb, NETCONFA_MC_FORWARDING,
1821 IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
1822 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001823 if ((all || type == NETCONFA_PROXY_NEIGH) &&
stephen hemminger09aea5d2013-12-17 22:35:52 -08001824 nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08001825 IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
1826 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001827 if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001828 nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
1829 IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
1830 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001831
Johannes Berg053c0952015-01-16 22:09:00 +01001832 nlmsg_end(skb, nlh);
1833 return 0;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001834
1835nla_put_failure:
1836 nlmsg_cancel(skb, nlh);
1837 return -EMSGSIZE;
1838}
1839
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001840void inet_netconf_notify_devconf(struct net *net, int type, int ifindex,
1841 struct ipv4_devconf *devconf)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001842{
1843 struct sk_buff *skb;
1844 int err = -ENOBUFS;
1845
Eric Dumazetfa178062016-07-08 05:18:24 +02001846 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001847 if (!skb)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001848 goto errout;
1849
1850 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
1851 RTM_NEWNETCONF, 0, type);
1852 if (err < 0) {
1853 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1854 WARN_ON(err == -EMSGSIZE);
1855 kfree_skb(skb);
1856 goto errout;
1857 }
Eric Dumazetfa178062016-07-08 05:18:24 +02001858 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001859 return;
1860errout:
1861 if (err < 0)
1862 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
1863}
1864
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001865static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
1866 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
1867 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001868 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
stephen hemminger09aea5d2013-12-17 22:35:52 -08001869 [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) },
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001870 [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001871};
1872
1873static int inet_netconf_get_devconf(struct sk_buff *in_skb,
Thomas Graf661d2962013-03-21 07:45:29 +00001874 struct nlmsghdr *nlh)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001875{
1876 struct net *net = sock_net(in_skb->sk);
1877 struct nlattr *tb[NETCONFA_MAX+1];
1878 struct netconfmsg *ncm;
1879 struct sk_buff *skb;
1880 struct ipv4_devconf *devconf;
1881 struct in_device *in_dev;
1882 struct net_device *dev;
1883 int ifindex;
1884 int err;
1885
1886 err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
1887 devconf_ipv4_policy);
1888 if (err < 0)
1889 goto errout;
1890
Anton Protopopova97eb332016-02-16 21:43:16 -05001891 err = -EINVAL;
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001892 if (!tb[NETCONFA_IFINDEX])
1893 goto errout;
1894
1895 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
1896 switch (ifindex) {
1897 case NETCONFA_IFINDEX_ALL:
1898 devconf = net->ipv4.devconf_all;
1899 break;
1900 case NETCONFA_IFINDEX_DEFAULT:
1901 devconf = net->ipv4.devconf_dflt;
1902 break;
1903 default:
1904 dev = __dev_get_by_index(net, ifindex);
Ian Morris51456b22015-04-03 09:17:26 +01001905 if (!dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001906 goto errout;
1907 in_dev = __in_dev_get_rtnl(dev);
Ian Morris51456b22015-04-03 09:17:26 +01001908 if (!in_dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001909 goto errout;
1910 devconf = &in_dev->cnf;
1911 break;
1912 }
1913
1914 err = -ENOBUFS;
Eric Dumazetfa178062016-07-08 05:18:24 +02001915 skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001916 if (!skb)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001917 goto errout;
1918
1919 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
1920 NETLINK_CB(in_skb).portid,
1921 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
Zhang Shengju136ba622016-03-10 08:55:50 +00001922 NETCONFA_ALL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001923 if (err < 0) {
1924 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1925 WARN_ON(err == -EMSGSIZE);
1926 kfree_skb(skb);
1927 goto errout;
1928 }
1929 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
1930errout:
1931 return err;
1932}
1933
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001934static int inet_netconf_dump_devconf(struct sk_buff *skb,
1935 struct netlink_callback *cb)
1936{
1937 struct net *net = sock_net(skb->sk);
1938 int h, s_h;
1939 int idx, s_idx;
1940 struct net_device *dev;
1941 struct in_device *in_dev;
1942 struct hlist_head *head;
1943
1944 s_h = cb->args[0];
1945 s_idx = idx = cb->args[1];
1946
1947 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1948 idx = 0;
1949 head = &net->dev_index_head[h];
1950 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001951 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1952 net->dev_base_seq;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001953 hlist_for_each_entry_rcu(dev, head, index_hlist) {
1954 if (idx < s_idx)
1955 goto cont;
1956 in_dev = __in_dev_get_rcu(dev);
1957 if (!in_dev)
1958 goto cont;
1959
1960 if (inet_netconf_fill_devconf(skb, dev->ifindex,
1961 &in_dev->cnf,
1962 NETLINK_CB(cb->skb).portid,
1963 cb->nlh->nlmsg_seq,
1964 RTM_NEWNETCONF,
1965 NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00001966 NETCONFA_ALL) < 0) {
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001967 rcu_read_unlock();
1968 goto done;
1969 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001970 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001971cont:
1972 idx++;
1973 }
1974 rcu_read_unlock();
1975 }
1976 if (h == NETDEV_HASHENTRIES) {
1977 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
1978 net->ipv4.devconf_all,
1979 NETLINK_CB(cb->skb).portid,
1980 cb->nlh->nlmsg_seq,
1981 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00001982 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001983 goto done;
1984 else
1985 h++;
1986 }
1987 if (h == NETDEV_HASHENTRIES + 1) {
1988 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
1989 net->ipv4.devconf_dflt,
1990 NETLINK_CB(cb->skb).portid,
1991 cb->nlh->nlmsg_seq,
1992 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00001993 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001994 goto done;
1995 else
1996 h++;
1997 }
1998done:
1999 cb->args[0] = h;
2000 cb->args[1] = idx;
2001
2002 return skb->len;
2003}
2004
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005#ifdef CONFIG_SYSCTL
2006
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002007static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07002008{
2009 struct net_device *dev;
2010
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002011 rcu_read_lock();
2012 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07002013 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002014
Herbert Xu31be3082007-06-04 23:35:37 -07002015 in_dev = __in_dev_get_rcu(dev);
2016 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002017 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07002018 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002019 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07002020}
2021
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002022/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002023static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002024{
2025 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002026 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002027
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002028 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002029 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002030 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
2031 NETCONFA_IFINDEX_ALL,
2032 net->ipv4.devconf_all);
2033 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
2034 NETCONFA_IFINDEX_DEFAULT,
2035 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002036
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002037 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002038 struct in_device *in_dev;
Eric Dumazetfa178062016-07-08 05:18:24 +02002039
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002040 if (on)
2041 dev_disable_lro(dev);
Eric Dumazetfa178062016-07-08 05:18:24 +02002042
2043 in_dev = __in_dev_get_rtnl(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002044 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002045 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002046 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
2047 dev->ifindex, &in_dev->cnf);
2048 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002049 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002050}
2051
stephen hemmingerf085ff12013-12-12 13:06:50 -08002052static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf)
2053{
2054 if (cnf == net->ipv4.devconf_dflt)
2055 return NETCONFA_IFINDEX_DEFAULT;
2056 else if (cnf == net->ipv4.devconf_all)
2057 return NETCONFA_IFINDEX_ALL;
2058 else {
2059 struct in_device *idev
2060 = container_of(cnf, struct in_device, cnf);
2061 return idev->dev->ifindex;
2062 }
2063}
2064
Joe Perchesfe2c6332013-06-11 23:04:25 -07002065static int devinet_conf_proc(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002066 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07002067 size_t *lenp, loff_t *ppos)
2068{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002069 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002070 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002071 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07002072
2073 if (write) {
2074 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002075 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07002076 int i = (int *)ctl->data - cnf->data;
stephen hemmingerf085ff12013-12-12 13:06:50 -08002077 int ifindex;
Herbert Xu31be3082007-06-04 23:35:37 -07002078
2079 set_bit(i, cnf->state);
2080
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002081 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002082 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00002083 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
2084 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002085 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002086 rt_cache_flush(net);
stephen hemmingerf085ff12013-12-12 13:06:50 -08002087
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002088 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
2089 new_value != old_value) {
stephen hemmingerf085ff12013-12-12 13:06:50 -08002090 ifindex = devinet_conf_ifindex(net, cnf);
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002091 inet_netconf_notify_devconf(net, NETCONFA_RP_FILTER,
2092 ifindex, cnf);
2093 }
stephen hemmingerf085ff12013-12-12 13:06:50 -08002094 if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
2095 new_value != old_value) {
2096 ifindex = devinet_conf_ifindex(net, cnf);
stephen hemminger09aea5d2013-12-17 22:35:52 -08002097 inet_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002098 ifindex, cnf);
2099 }
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002100 if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
2101 new_value != old_value) {
2102 ifindex = devinet_conf_ifindex(net, cnf);
2103 inet_netconf_notify_devconf(net, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
2104 ifindex, cnf);
2105 }
Herbert Xu31be3082007-06-04 23:35:37 -07002106 }
2107
2108 return ret;
2109}
2110
Joe Perchesfe2c6332013-06-11 23:04:25 -07002111static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002112 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 size_t *lenp, loff_t *ppos)
2114{
2115 int *valp = ctl->data;
2116 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00002117 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002118 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119
2120 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002121 struct net *net = ctl->extra2;
2122
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002123 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00002124 if (!rtnl_trylock()) {
2125 /* Restore the original values before restarting */
2126 *valp = val;
2127 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00002128 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00002129 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002130 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2131 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002132 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002133 struct ipv4_devconf *cnf = ctl->extra1;
2134 struct in_device *idev =
2135 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002136 if (*valp)
2137 dev_disable_lro(idev->dev);
2138 inet_netconf_notify_devconf(net,
2139 NETCONFA_FORWARDING,
2140 idev->dev->ifindex,
2141 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002142 }
2143 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002144 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002145 } else
2146 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
2147 NETCONFA_IFINDEX_DEFAULT,
2148 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 }
2150
2151 return ret;
2152}
2153
Joe Perchesfe2c6332013-06-11 23:04:25 -07002154static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
David S. Miller323e1262010-12-12 21:55:08 -08002155 void __user *buffer,
2156 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157{
2158 int *valp = ctl->data;
2159 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002160 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07002161 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162
2163 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002164 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165
2166 return ret;
2167}
2168
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002169#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07002170 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07002171 .procname = name, \
2172 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00002173 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002174 .maxlen = sizeof(int), \
2175 .mode = mval, \
2176 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07002177 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002178 }
2179
2180#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002181 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002182
2183#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002184 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002185
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002186#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2187 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002188
2189#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002190 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07002191
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192static struct devinet_sysctl_table {
2193 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00002194 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195} devinet_sysctl = {
2196 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07002197 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002198 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07002199 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
2200
2201 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
2202 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
2203 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
2204 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
2205 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
2206 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
2207 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00002208 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08002209 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002210 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
2211 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
2212 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
2213 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
2214 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
2215 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
2216 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
2217 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
2218 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08002219 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00002220 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
William Manley5c6fe012013-08-06 19:03:14 +01002221 DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
2222 "force_igmp_version"),
William Manley26900482013-08-06 19:03:15 +01002223 DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
2224 "igmpv2_unsolicited_report_interval"),
2225 DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
2226 "igmpv3_unsolicited_report_interval"),
Andy Gospodarek0eeb0752015-06-23 13:45:37 -04002227 DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
2228 "ignore_routes_with_linkdown"),
Johannes Berg97daf332016-02-04 13:31:18 +01002229 DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
2230 "drop_gratuitous_arp"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002231
2232 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2233 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002234 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
2235 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00002236 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2237 "route_localnet"),
Johannes Berg12b74df2016-02-04 13:31:17 +01002238 DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
2239 "drop_unicast_in_l2_multicast"),
Subash Abhinov Kasiviswanathan5ce78152017-11-05 17:36:53 -07002240 DEVINET_SYSCTL_RW_ENTRY(NF_IPV4_DEFRAG_SKIP,
2241 "nf_ipv4_defrag_skip"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243};
2244
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002245static int __devinet_sysctl_register(struct net *net, char *dev_name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002246 int ifindex, struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247{
2248 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002249 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002250 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11002251
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002252 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002254 goto out;
2255
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
2257 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07002258 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002259 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 }
2261
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002262 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002264 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002266 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267
2268 p->sysctl = t;
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002269
2270 inet_netconf_notify_devconf(net, NETCONFA_ALL, ifindex, p);
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002271 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002273free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002275out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002276 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277}
2278
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002279static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
2280{
2281 struct devinet_sysctl_table *t = cnf->sysctl;
2282
Ian Morris51456b22015-04-03 09:17:26 +01002283 if (!t)
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002284 return;
2285
2286 cnf->sysctl = NULL;
Lucian Adrian Grijincuff538812011-05-01 01:44:01 +00002287 unregister_net_sysctl_table(t->sysctl_header);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002288 kfree(t);
2289}
2290
WANG Cong20e61da2014-07-25 15:25:08 -07002291static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002292{
WANG Cong20e61da2014-07-25 15:25:08 -07002293 int err;
2294
2295 if (!sysctl_dev_name_is_allowed(idev->dev->name))
2296 return -EINVAL;
2297
2298 err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
2299 if (err)
2300 return err;
2301 err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002302 idev->dev->ifindex, &idev->cnf);
WANG Cong20e61da2014-07-25 15:25:08 -07002303 if (err)
2304 neigh_sysctl_unregister(idev->arp_parms);
2305 return err;
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002306}
2307
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002308static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309{
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002310 __devinet_sysctl_unregister(&idev->cnf);
2311 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002314static struct ctl_table ctl_forward_entry[] = {
2315 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002316 .procname = "ip_forward",
2317 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00002318 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002319 .maxlen = sizeof(int),
2320 .mode = 0644,
2321 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002322 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002323 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002324 },
2325 { },
2326};
Eric Dumazet2a75de02008-01-05 23:08:49 -08002327#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002328
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002329static __net_init int devinet_init_net(struct net *net)
2330{
2331 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002332 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002333#ifdef CONFIG_SYSCTL
2334 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002335 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002336#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002337
2338 err = -ENOMEM;
2339 all = &ipv4_devconf;
2340 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002341
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002342 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002343 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002344 if (!all)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002345 goto err_alloc_all;
2346
2347 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002348 if (!dflt)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002349 goto err_alloc_dflt;
2350
Eric Dumazet2a75de02008-01-05 23:08:49 -08002351#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002352 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002353 if (!tbl)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002354 goto err_alloc_ctl;
2355
Eric W. Biederman02291682010-02-14 03:25:51 +00002356 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002357 tbl[0].extra1 = all;
2358 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002359#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002360 }
2361
2362#ifdef CONFIG_SYSCTL
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002363 err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002364 if (err < 0)
2365 goto err_reg_all;
2366
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002367 err = __devinet_sysctl_register(net, "default",
2368 NETCONFA_IFINDEX_DEFAULT, dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002369 if (err < 0)
2370 goto err_reg_dflt;
2371
2372 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002373 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Ian Morris51456b22015-04-03 09:17:26 +01002374 if (!forw_hdr)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002375 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002376 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002377#endif
2378
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002379 net->ipv4.devconf_all = all;
2380 net->ipv4.devconf_dflt = dflt;
2381 return 0;
2382
2383#ifdef CONFIG_SYSCTL
2384err_reg_ctl:
2385 __devinet_sysctl_unregister(dflt);
2386err_reg_dflt:
2387 __devinet_sysctl_unregister(all);
2388err_reg_all:
2389 if (tbl != ctl_forward_entry)
2390 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002391err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08002392#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002393 if (dflt != &ipv4_devconf_dflt)
2394 kfree(dflt);
2395err_alloc_dflt:
2396 if (all != &ipv4_devconf)
2397 kfree(all);
2398err_alloc_all:
2399 return err;
2400}
2401
2402static __net_exit void devinet_exit_net(struct net *net)
2403{
Eric Dumazet2a75de02008-01-05 23:08:49 -08002404#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002405 struct ctl_table *tbl;
2406
2407 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002408 unregister_net_sysctl_table(net->ipv4.forw_hdr);
2409 __devinet_sysctl_unregister(net->ipv4.devconf_dflt);
2410 __devinet_sysctl_unregister(net->ipv4.devconf_all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002411 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08002412#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002413 kfree(net->ipv4.devconf_dflt);
2414 kfree(net->ipv4.devconf_all);
2415}
2416
2417static __net_initdata struct pernet_operations devinet_ops = {
2418 .init = devinet_init_net,
2419 .exit = devinet_exit_net,
2420};
2421
Daniel Borkmann207895f2015-01-29 12:15:03 +01002422static struct rtnl_af_ops inet_af_ops __read_mostly = {
Thomas Graf9f0f7272010-11-16 04:32:48 +00002423 .family = AF_INET,
2424 .fill_link_af = inet_fill_link_af,
2425 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00002426 .validate_link_af = inet_validate_link_af,
2427 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00002428};
2429
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430void __init devinet_init(void)
2431{
David S. Millerfd23c3b2011-02-18 12:42:28 -08002432 int i;
2433
2434 for (i = 0; i < IN4_ADDR_HSIZE; i++)
2435 INIT_HLIST_HEAD(&inet_addr_lst[i]);
2436
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002437 register_pernet_subsys(&devinet_ops);
2438
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 register_gifconf(PF_INET, inet_gifconf);
2440 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07002441
viresh kumar906e0732014-01-22 12:23:32 +05302442 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +00002443
Thomas Graf9f0f7272010-11-16 04:32:48 +00002444 rtnl_af_register(&inet_af_ops);
2445
Greg Rosec7ac8672011-06-10 01:27:09 +00002446 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL);
2447 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, NULL);
2448 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, NULL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002449 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002450 inet_netconf_dump_devconf, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451}