blob: e831ff51ac5b4c820d6b2478c893910eab6f0a0c [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;
265 in_dev_put(in_dev);
266 in_dev = NULL;
267 goto out;
268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 ip_mc_init_dev(in_dev);
270 if (dev->flags & IFF_UP)
271 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800272
David L Stevens30c4cf52007-01-04 12:31:14 -0800273 /* we can receive as soon as ip_ptr is set -- do this last */
Eric Dumazetcf778b02012-01-12 04:41:32 +0000274 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800275out:
WANG Cong20e61da2014-07-25 15:25:08 -0700276 return in_dev ?: ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277out_kfree:
278 kfree(in_dev);
279 in_dev = NULL;
280 goto out;
281}
282
283static void in_dev_rcu_put(struct rcu_head *head)
284{
285 struct in_device *idev = container_of(head, struct in_device, rcu_head);
286 in_dev_put(idev);
287}
288
289static void inetdev_destroy(struct in_device *in_dev)
290{
291 struct in_ifaddr *ifa;
292 struct net_device *dev;
293
294 ASSERT_RTNL();
295
296 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298 in_dev->dead = 1;
299
300 ip_mc_destroy_dev(in_dev);
301
302 while ((ifa = in_dev->ifa_list) != NULL) {
303 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
304 inet_free_ifa(ifa);
305 }
306
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000307 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800309 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
311 arp_ifdown(dev);
312
313 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
314}
315
Al Viroff428d72006-09-26 22:13:35 -0700316int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
318 rcu_read_lock();
319 for_primary_ifa(in_dev) {
320 if (inet_ifa_match(a, ifa)) {
321 if (!b || inet_ifa_match(b, ifa)) {
322 rcu_read_unlock();
323 return 1;
324 }
325 }
326 } endfor_ifa(in_dev);
327 rcu_read_unlock();
328 return 0;
329}
330
Thomas Grafd6062cb2006-08-15 00:33:59 -0700331static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000332 int destroy, struct nlmsghdr *nlh, u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333{
Harald Welte8f937c62005-05-29 20:23:46 -0700334 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800335 struct in_ifaddr *ifa, *ifa1 = *ifap;
336 struct in_ifaddr *last_prim = in_dev->ifa_list;
337 struct in_ifaddr *prev_prom = NULL;
338 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
340 ASSERT_RTNL();
341
David S. Millerfbd40ea2016-03-13 23:28:00 -0400342 if (in_dev->dead)
343 goto no_promotions;
344
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900345 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700346 * unless alias promotion is set
347 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
351
352 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900353 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800354 ifa1->ifa_scope <= ifa->ifa_scope)
355 last_prim = ifa;
356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
358 ifa1->ifa_mask != ifa->ifa_mask ||
359 !inet_ifa_match(ifa1->ifa_address, ifa)) {
360 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800361 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 continue;
363 }
364
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800365 if (!do_promote) {
David S. Millerfd23c3b2011-02-18 12:42:28 -0800366 inet_hash_remove(ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700367 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
Eric W. Biederman15e47302012-09-07 20:12:54 +0000369 rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800370 blocking_notifier_call_chain(&inetaddr_chain,
371 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700372 inet_free_ifa(ifa);
373 } else {
374 promote = ifa;
375 break;
376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 }
378 }
379
Julian Anastasov2d230e22011-03-19 12:13:52 +0000380 /* On promotion all secondaries from subnet are changing
381 * the primary IP, we must remove all their routes silently
382 * and later to add them back with new prefsrc. Do this
383 * while all addresses are on the device list.
384 */
385 for (ifa = promote; ifa; ifa = ifa->ifa_next) {
386 if (ifa1->ifa_mask == ifa->ifa_mask &&
387 inet_ifa_match(ifa1->ifa_address, ifa))
388 fib_del_ifaddr(ifa, ifa1);
389 }
390
David S. Millerfbd40ea2016-03-13 23:28:00 -0400391no_promotions:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 /* 2. Unlink it */
393
394 *ifap = ifa1->ifa_next;
David S. Millerfd23c3b2011-02-18 12:42:28 -0800395 inet_hash_remove(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
397 /* 3. Announce address deletion */
398
399 /* Send message first, then call notifier.
400 At first sight, FIB update triggered by notifier
401 will refer to already deleted ifaddr, that could confuse
402 netlink listeners. It is not true: look, gated sees
403 that route deleted and if it still thinks that ifaddr
404 is valid, it will try to restore deleted routes... Grr.
405 So that, this order is correct.
406 */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000407 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800408 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800409
410 if (promote) {
Julian Anastasov04024b92011-03-19 12:13:54 +0000411 struct in_ifaddr *next_sec = promote->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800412
413 if (prev_prom) {
414 prev_prom->ifa_next = promote->ifa_next;
415 promote->ifa_next = last_prim->ifa_next;
416 last_prim->ifa_next = promote;
417 }
418
419 promote->ifa_flags &= ~IFA_F_SECONDARY;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000420 rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800421 blocking_notifier_call_chain(&inetaddr_chain,
422 NETDEV_UP, promote);
Julian Anastasov04024b92011-03-19 12:13:54 +0000423 for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800424 if (ifa1->ifa_mask != ifa->ifa_mask ||
425 !inet_ifa_match(ifa1->ifa_address, ifa))
426 continue;
427 fib_add_ifaddr(ifa);
428 }
429
430 }
Herbert Xu63630972007-06-07 18:35:38 -0700431 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433}
434
Thomas Grafd6062cb2006-08-15 00:33:59 -0700435static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
436 int destroy)
437{
438 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
439}
440
Jiri Pirko5c766d62013-01-24 09:41:41 +0000441static void check_lifetime(struct work_struct *work);
442
443static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
444
Thomas Grafd6062cb2006-08-15 00:33:59 -0700445static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000446 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447{
448 struct in_device *in_dev = ifa->ifa_dev;
449 struct in_ifaddr *ifa1, **ifap, **last_primary;
450
451 ASSERT_RTNL();
452
453 if (!ifa->ifa_local) {
454 inet_free_ifa(ifa);
455 return 0;
456 }
457
458 ifa->ifa_flags &= ~IFA_F_SECONDARY;
459 last_primary = &in_dev->ifa_list;
460
Matteo Croce41504372019-07-01 19:01:55 +0200461 /* Don't set IPv6 only flags to IPv4 addresses */
462 ifa->ifa_flags &= ~IPV6ONLY_FLAGS;
463
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
465 ifap = &ifa1->ifa_next) {
466 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
467 ifa->ifa_scope <= ifa1->ifa_scope)
468 last_primary = &ifa1->ifa_next;
469 if (ifa1->ifa_mask == ifa->ifa_mask &&
470 inet_ifa_match(ifa1->ifa_address, ifa)) {
471 if (ifa1->ifa_local == ifa->ifa_local) {
472 inet_free_ifa(ifa);
473 return -EEXIST;
474 }
475 if (ifa1->ifa_scope != ifa->ifa_scope) {
476 inet_free_ifa(ifa);
477 return -EINVAL;
478 }
479 ifa->ifa_flags |= IFA_F_SECONDARY;
480 }
481 }
482
483 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500484 prandom_seed((__force u32) ifa->ifa_local);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 ifap = last_primary;
486 }
487
488 ifa->ifa_next = *ifap;
489 *ifap = ifa;
490
David S. Millerfd23c3b2011-02-18 12:42:28 -0800491 inet_hash_insert(dev_net(in_dev->dev), ifa);
492
Jiri Pirko5c766d62013-01-24 09:41:41 +0000493 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530494 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000495
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 /* Send message first, then call notifier.
497 Notifier will trigger FIB update, so that
498 listeners of netlink will know about new ifaddr */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000499 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800500 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
502 return 0;
503}
504
Thomas Grafd6062cb2006-08-15 00:33:59 -0700505static int inet_insert_ifa(struct in_ifaddr *ifa)
506{
507 return __inet_insert_ifa(ifa, NULL, 0);
508}
509
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
511{
Herbert Xue5ed6392005-10-03 14:35:55 -0700512 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
514 ASSERT_RTNL();
515
516 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700517 inet_free_ifa(ifa);
518 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700520 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100521 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700523 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 in_dev_hold(in_dev);
525 ifa->ifa_dev = in_dev;
526 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800527 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 ifa->ifa_scope = RT_SCOPE_HOST;
529 return inet_insert_ifa(ifa);
530}
531
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000532/* Caller must hold RCU or RTNL :
533 * We dont take a reference on found in_device
534 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800535struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
537 struct net_device *dev;
538 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000539
540 rcu_read_lock();
541 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000543 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000544 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 return in_dev;
546}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800547EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549/* Called only from RTNL semaphored context. No locks. */
550
Al Viro60cad5d2006-09-26 22:17:09 -0700551struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
552 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553{
554 ASSERT_RTNL();
555
556 for_primary_ifa(in_dev) {
557 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
558 return ifa;
559 } endfor_ifa(in_dev);
560 return NULL;
561}
562
Madhu Challa93a714d2015-02-25 09:58:35 -0800563static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa)
564{
565 struct ip_mreqn mreq = {
566 .imr_multiaddr.s_addr = ifa->ifa_address,
567 .imr_ifindex = ifa->ifa_dev->dev->ifindex,
568 };
569 int ret;
570
571 ASSERT_RTNL();
572
573 lock_sock(sk);
574 if (join)
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300575 ret = ip_mc_join_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800576 else
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300577 ret = ip_mc_leave_group(sk, &mreq);
Madhu Challa93a714d2015-02-25 09:58:35 -0800578 release_sock(sk);
579
580 return ret;
581}
582
Thomas Graf661d2962013-03-21 07:45:29 +0000583static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900585 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700586 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700588 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700590 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
592 ASSERT_RTNL();
593
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700594 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
595 if (err < 0)
596 goto errout;
597
598 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800599 in_dev = inetdev_by_index(net, ifm->ifa_index);
Ian Morris51456b22015-04-03 09:17:26 +0100600 if (!in_dev) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700601 err = -ENODEV;
602 goto errout;
603 }
604
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
606 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700607 if (tb[IFA_LOCAL] &&
Jiri Benc67b61f62015-03-29 16:59:26 +0200608 ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700610
611 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
612 continue;
613
614 if (tb[IFA_ADDRESS] &&
615 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Jiri Benc67b61f62015-03-29 16:59:26 +0200616 !inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700617 continue;
618
Madhu Challa93a714d2015-02-25 09:58:35 -0800619 if (ipv4_is_multicast(ifa->ifa_address))
620 ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000621 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 return 0;
623 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700624
625 err = -EADDRNOTAVAIL;
626errout:
627 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628}
629
Jiri Pirko5c766d62013-01-24 09:41:41 +0000630#define INFINITY_LIFE_TIME 0xFFFFFFFF
631
632static void check_lifetime(struct work_struct *work)
633{
634 unsigned long now, next, next_sec, next_sched;
635 struct in_ifaddr *ifa;
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000636 struct hlist_node *n;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000637 int i;
638
639 now = jiffies;
640 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
641
Jiri Pirko5c766d62013-01-24 09:41:41 +0000642 for (i = 0; i < IN4_ADDR_HSIZE; i++) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000643 bool change_needed = false;
644
645 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800646 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
Jiri Pirko5c766d62013-01-24 09:41:41 +0000647 unsigned long age;
648
649 if (ifa->ifa_flags & IFA_F_PERMANENT)
650 continue;
651
652 /* We try to batch several events at once. */
653 age = (now - ifa->ifa_tstamp +
654 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
655
656 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
657 age >= ifa->ifa_valid_lft) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000658 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000659 } else if (ifa->ifa_preferred_lft ==
660 INFINITY_LIFE_TIME) {
661 continue;
662 } else if (age >= ifa->ifa_preferred_lft) {
663 if (time_before(ifa->ifa_tstamp +
664 ifa->ifa_valid_lft * HZ, next))
665 next = ifa->ifa_tstamp +
666 ifa->ifa_valid_lft * HZ;
667
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000668 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
669 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000670 } else if (time_before(ifa->ifa_tstamp +
671 ifa->ifa_preferred_lft * HZ,
672 next)) {
673 next = ifa->ifa_tstamp +
674 ifa->ifa_preferred_lft * HZ;
675 }
676 }
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000677 rcu_read_unlock();
678 if (!change_needed)
679 continue;
680 rtnl_lock();
681 hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
682 unsigned long age;
683
684 if (ifa->ifa_flags & IFA_F_PERMANENT)
685 continue;
686
687 /* We try to batch several events at once. */
688 age = (now - ifa->ifa_tstamp +
689 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
690
691 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
692 age >= ifa->ifa_valid_lft) {
693 struct in_ifaddr **ifap;
694
695 for (ifap = &ifa->ifa_dev->ifa_list;
696 *ifap != NULL; ifap = &(*ifap)->ifa_next) {
697 if (*ifap == ifa) {
698 inet_del_ifa(ifa->ifa_dev,
699 ifap, 1);
700 break;
701 }
702 }
703 } else if (ifa->ifa_preferred_lft !=
704 INFINITY_LIFE_TIME &&
705 age >= ifa->ifa_preferred_lft &&
706 !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
707 ifa->ifa_flags |= IFA_F_DEPRECATED;
708 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
709 }
710 }
711 rtnl_unlock();
Jiri Pirko5c766d62013-01-24 09:41:41 +0000712 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000713
714 next_sec = round_jiffies_up(next);
715 next_sched = next;
716
717 /* If rounded timeout is accurate enough, accept it. */
718 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
719 next_sched = next_sec;
720
721 now = jiffies;
722 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
723 if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
724 next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
725
viresh kumar906e0732014-01-22 12:23:32 +0530726 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work,
727 next_sched - now);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000728}
729
730static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
731 __u32 prefered_lft)
732{
733 unsigned long timeout;
734
735 ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
736
737 timeout = addrconf_timeout_fixup(valid_lft, HZ);
738 if (addrconf_finite_timeout(timeout))
739 ifa->ifa_valid_lft = timeout;
740 else
741 ifa->ifa_flags |= IFA_F_PERMANENT;
742
743 timeout = addrconf_timeout_fixup(prefered_lft, HZ);
744 if (addrconf_finite_timeout(timeout)) {
745 if (timeout == 0)
746 ifa->ifa_flags |= IFA_F_DEPRECATED;
747 ifa->ifa_preferred_lft = timeout;
748 }
749 ifa->ifa_tstamp = jiffies;
750 if (!ifa->ifa_cstamp)
751 ifa->ifa_cstamp = ifa->ifa_tstamp;
752}
753
754static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
755 __u32 *pvalid_lft, __u32 *pprefered_lft)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756{
Thomas Graf5c753972006-08-04 23:03:53 -0700757 struct nlattr *tb[IFA_MAX+1];
758 struct in_ifaddr *ifa;
759 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 struct net_device *dev;
761 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800762 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
Thomas Graf5c753972006-08-04 23:03:53 -0700764 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
765 if (err < 0)
766 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Thomas Graf5c753972006-08-04 23:03:53 -0700768 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800769 err = -EINVAL;
Ian Morris51456b22015-04-03 09:17:26 +0100770 if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL])
Thomas Graf5c753972006-08-04 23:03:53 -0700771 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800773 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800774 err = -ENODEV;
Ian Morris51456b22015-04-03 09:17:26 +0100775 if (!dev)
Thomas Graf5c753972006-08-04 23:03:53 -0700776 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
Thomas Graf5c753972006-08-04 23:03:53 -0700778 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800779 err = -ENOBUFS;
Ian Morris51456b22015-04-03 09:17:26 +0100780 if (!in_dev)
Herbert Xu71e27da2007-06-04 23:36:06 -0700781 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
Thomas Graf5c753972006-08-04 23:03:53 -0700783 ifa = inet_alloc_ifa();
Ian Morris51456b22015-04-03 09:17:26 +0100784 if (!ifa)
Thomas Graf5c753972006-08-04 23:03:53 -0700785 /*
786 * A potential indev allocation can be left alive, it stays
787 * assigned to its device and is destroy with it.
788 */
Thomas Graf5c753972006-08-04 23:03:53 -0700789 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700790
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800791 ipv4_devconf_setall(in_dev);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +0100792 neigh_parms_data_state_setall(in_dev->arp_parms);
Thomas Graf5c753972006-08-04 23:03:53 -0700793 in_dev_hold(in_dev);
794
Ian Morris51456b22015-04-03 09:17:26 +0100795 if (!tb[IFA_ADDRESS])
Thomas Graf5c753972006-08-04 23:03:53 -0700796 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
797
David S. Millerfd23c3b2011-02-18 12:42:28 -0800798 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
800 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Jiri Pirkoad6c8132013-12-08 12:16:10 +0100801 ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
802 ifm->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700804 ifa->ifa_dev = in_dev;
805
Jiri Benc67b61f62015-03-29 16:59:26 +0200806 ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]);
807 ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700808
809 if (tb[IFA_BROADCAST])
Jiri Benc67b61f62015-03-29 16:59:26 +0200810 ifa->ifa_broadcast = nla_get_in_addr(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700811
Thomas Graf5c753972006-08-04 23:03:53 -0700812 if (tb[IFA_LABEL])
813 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 else
815 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
816
Jiri Pirko5c766d62013-01-24 09:41:41 +0000817 if (tb[IFA_CACHEINFO]) {
818 struct ifa_cacheinfo *ci;
819
820 ci = nla_data(tb[IFA_CACHEINFO]);
821 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
822 err = -EINVAL;
Daniel Borkmann446266b2013-08-02 11:32:43 +0200823 goto errout_free;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000824 }
825 *pvalid_lft = ci->ifa_valid;
826 *pprefered_lft = ci->ifa_prefered;
827 }
828
Thomas Graf5c753972006-08-04 23:03:53 -0700829 return ifa;
830
Daniel Borkmann446266b2013-08-02 11:32:43 +0200831errout_free:
832 inet_free_ifa(ifa);
Thomas Graf5c753972006-08-04 23:03:53 -0700833errout:
834 return ERR_PTR(err);
835}
836
Jiri Pirko5c766d62013-01-24 09:41:41 +0000837static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
838{
839 struct in_device *in_dev = ifa->ifa_dev;
840 struct in_ifaddr *ifa1, **ifap;
841
842 if (!ifa->ifa_local)
843 return NULL;
844
845 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
846 ifap = &ifa1->ifa_next) {
847 if (ifa1->ifa_mask == ifa->ifa_mask &&
848 inet_ifa_match(ifa1->ifa_address, ifa) &&
849 ifa1->ifa_local == ifa->ifa_local)
850 return ifa1;
851 }
852 return NULL;
853}
854
Thomas Graf661d2962013-03-21 07:45:29 +0000855static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
Thomas Graf5c753972006-08-04 23:03:53 -0700856{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900857 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700858 struct in_ifaddr *ifa;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000859 struct in_ifaddr *ifa_existing;
860 __u32 valid_lft = INFINITY_LIFE_TIME;
861 __u32 prefered_lft = INFINITY_LIFE_TIME;
Thomas Graf5c753972006-08-04 23:03:53 -0700862
863 ASSERT_RTNL();
864
Jiri Pirko5c766d62013-01-24 09:41:41 +0000865 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft);
Thomas Graf5c753972006-08-04 23:03:53 -0700866 if (IS_ERR(ifa))
867 return PTR_ERR(ifa);
868
Jiri Pirko5c766d62013-01-24 09:41:41 +0000869 ifa_existing = find_matching_ifa(ifa);
870 if (!ifa_existing) {
871 /* It would be best to check for !NLM_F_CREATE here but
stephen hemminger614d0562014-05-16 20:46:58 -0700872 * userspace already relies on not having to provide this.
Jiri Pirko5c766d62013-01-24 09:41:41 +0000873 */
874 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Madhu Challa93a714d2015-02-25 09:58:35 -0800875 if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
876 int ret = ip_mc_config(net->ipv4.mc_autojoin_sk,
877 true, ifa);
878
879 if (ret < 0) {
880 inet_free_ifa(ifa);
881 return ret;
882 }
883 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000884 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
885 } else {
886 inet_free_ifa(ifa);
887
888 if (nlh->nlmsg_flags & NLM_F_EXCL ||
889 !(nlh->nlmsg_flags & NLM_F_REPLACE))
890 return -EEXIST;
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000891 ifa = ifa_existing;
892 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Jiri Pirko05a324b2013-04-04 23:39:38 +0000893 cancel_delayed_work(&check_lifetime_work);
viresh kumar906e0732014-01-22 12:23:32 +0530894 queue_delayed_work(system_power_efficient_wq,
895 &check_lifetime_work, 0);
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000896 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000897 }
898 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899}
900
901/*
902 * Determine a default network mask, based on the IP address.
903 */
904
Eric Dumazet40384992012-08-03 21:06:50 +0000905static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906{
907 int rc = -1; /* Something else, probably a multicast. */
908
Joe Perchesf97c1e02007-12-16 13:45:43 -0800909 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900910 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 else {
Al Viro714e85b2006-11-14 20:51:49 -0800912 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
Al Viro714e85b2006-11-14 20:51:49 -0800914 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800916 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800918 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 rc = 24;
920 }
921
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900922 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923}
924
925
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800926int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927{
928 struct ifreq ifr;
929 struct sockaddr_in sin_orig;
930 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
931 struct in_device *in_dev;
932 struct in_ifaddr **ifap = NULL;
933 struct in_ifaddr *ifa = NULL;
934 struct net_device *dev;
935 char *colon;
936 int ret = -EFAULT;
937 int tryaddrmatch = 0;
938
939 /*
940 * Fetch the caller's info block into kernel space
941 */
942
943 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
944 goto out;
945 ifr.ifr_name[IFNAMSIZ - 1] = 0;
946
947 /* save original address for comparison */
948 memcpy(&sin_orig, sin, sizeof(*sin));
949
950 colon = strchr(ifr.ifr_name, ':');
951 if (colon)
952 *colon = 0;
953
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800954 dev_load(net, ifr.ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
Stephen Hemminger132adf52007-03-08 20:44:43 -0800956 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 case SIOCGIFADDR: /* Get interface address */
958 case SIOCGIFBRDADDR: /* Get the broadcast address */
959 case SIOCGIFDSTADDR: /* Get the destination address */
960 case SIOCGIFNETMASK: /* Get the netmask for the interface */
961 /* Note that these ioctls will not sleep,
962 so that we do not impose a lock.
963 One day we will be forced to put shlock here (I mean SMP)
964 */
965 tryaddrmatch = (sin_orig.sin_family == AF_INET);
966 memset(sin, 0, sizeof(*sin));
967 sin->sin_family = AF_INET;
968 break;
969
970 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000971 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000972 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 goto out;
974 break;
975 case SIOCSIFADDR: /* Set interface address (and family) */
976 case SIOCSIFBRDADDR: /* Set the broadcast address */
977 case SIOCSIFDSTADDR: /* Set the destination address */
978 case SIOCSIFNETMASK: /* Set the netmask for the interface */
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000979 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000980 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 goto out;
982 ret = -EINVAL;
983 if (sin->sin_family != AF_INET)
984 goto out;
985 break;
986 default:
987 ret = -EINVAL;
988 goto out;
989 }
990
991 rtnl_lock();
992
993 ret = -ENODEV;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800994 dev = __dev_get_by_name(net, ifr.ifr_name);
995 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 goto done;
997
998 if (colon)
999 *colon = ':';
1000
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001001 in_dev = __in_dev_get_rtnl(dev);
1002 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 if (tryaddrmatch) {
1004 /* Matthias Andree */
1005 /* compare label and address (4.4BSD style) */
1006 /* note: we only do this for a limited set of ioctls
1007 and only if the original address family was AF_INET.
1008 This is checked above. */
1009 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1010 ifap = &ifa->ifa_next) {
1011 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
1012 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -08001013 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 break; /* found */
1015 }
1016 }
1017 }
1018 /* we didn't get a match, maybe the application is
1019 4.3BSD-style and passed in junk so we fall back to
1020 comparing just the label */
1021 if (!ifa) {
1022 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1023 ifap = &ifa->ifa_next)
1024 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
1025 break;
1026 }
1027 }
1028
1029 ret = -EADDRNOTAVAIL;
1030 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
1031 goto done;
1032
Stephen Hemminger132adf52007-03-08 20:44:43 -08001033 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 case SIOCGIFADDR: /* Get interface address */
1035 sin->sin_addr.s_addr = ifa->ifa_local;
1036 goto rarok;
1037
1038 case SIOCGIFBRDADDR: /* Get the broadcast address */
1039 sin->sin_addr.s_addr = ifa->ifa_broadcast;
1040 goto rarok;
1041
1042 case SIOCGIFDSTADDR: /* Get the destination address */
1043 sin->sin_addr.s_addr = ifa->ifa_address;
1044 goto rarok;
1045
1046 case SIOCGIFNETMASK: /* Get the netmask for the interface */
1047 sin->sin_addr.s_addr = ifa->ifa_mask;
1048 goto rarok;
1049
1050 case SIOCSIFFLAGS:
1051 if (colon) {
1052 ret = -EADDRNOTAVAIL;
1053 if (!ifa)
1054 break;
1055 ret = 0;
1056 if (!(ifr.ifr_flags & IFF_UP))
1057 inet_del_ifa(in_dev, ifap, 1);
1058 break;
1059 }
1060 ret = dev_change_flags(dev, ifr.ifr_flags);
1061 break;
1062
1063 case SIOCSIFADDR: /* Set interface address (and family) */
1064 ret = -EINVAL;
1065 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1066 break;
1067
1068 if (!ifa) {
1069 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001070 ifa = inet_alloc_ifa();
1071 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 break;
Xi Wangc7e2e1d2013-01-05 11:19:24 +00001073 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 if (colon)
1075 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
1076 else
1077 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1078 } else {
1079 ret = 0;
1080 if (ifa->ifa_local == sin->sin_addr.s_addr)
1081 break;
1082 inet_del_ifa(in_dev, ifap, 0);
1083 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -08001084 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 }
1086
1087 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
1088
1089 if (!(dev->flags & IFF_POINTOPOINT)) {
1090 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
1091 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
1092 if ((dev->flags & IFF_BROADCAST) &&
1093 ifa->ifa_prefixlen < 31)
1094 ifa->ifa_broadcast = ifa->ifa_address |
1095 ~ifa->ifa_mask;
1096 } else {
1097 ifa->ifa_prefixlen = 32;
1098 ifa->ifa_mask = inet_make_mask(32);
1099 }
Jiri Pirko5c766d62013-01-24 09:41:41 +00001100 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 ret = inet_set_ifa(dev, ifa);
1102 break;
1103
1104 case SIOCSIFBRDADDR: /* Set the broadcast address */
1105 ret = 0;
1106 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
1107 inet_del_ifa(in_dev, ifap, 0);
1108 ifa->ifa_broadcast = sin->sin_addr.s_addr;
1109 inet_insert_ifa(ifa);
1110 }
1111 break;
1112
1113 case SIOCSIFDSTADDR: /* Set the destination address */
1114 ret = 0;
1115 if (ifa->ifa_address == sin->sin_addr.s_addr)
1116 break;
1117 ret = -EINVAL;
1118 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1119 break;
1120 ret = 0;
1121 inet_del_ifa(in_dev, ifap, 0);
1122 ifa->ifa_address = sin->sin_addr.s_addr;
1123 inet_insert_ifa(ifa);
1124 break;
1125
1126 case SIOCSIFNETMASK: /* Set the netmask for the interface */
1127
1128 /*
1129 * The mask we set must be legal.
1130 */
1131 ret = -EINVAL;
1132 if (bad_mask(sin->sin_addr.s_addr, 0))
1133 break;
1134 ret = 0;
1135 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -07001136 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 inet_del_ifa(in_dev, ifap, 0);
1138 ifa->ifa_mask = sin->sin_addr.s_addr;
1139 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
1140
1141 /* See if current broadcast address matches
1142 * with current netmask, then recalculate
1143 * the broadcast address. Otherwise it's a
1144 * funny address, so don't touch it since
1145 * the user seems to know what (s)he's doing...
1146 */
1147 if ((dev->flags & IFF_BROADCAST) &&
1148 (ifa->ifa_prefixlen < 31) &&
1149 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -05001150 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 ifa->ifa_broadcast = (ifa->ifa_local |
1152 ~sin->sin_addr.s_addr);
1153 }
1154 inet_insert_ifa(ifa);
1155 }
1156 break;
1157 }
1158done:
1159 rtnl_unlock();
1160out:
1161 return ret;
1162rarok:
1163 rtnl_unlock();
1164 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
1165 goto out;
1166}
1167
1168static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
1169{
Herbert Xue5ed6392005-10-03 14:35:55 -07001170 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 struct in_ifaddr *ifa;
1172 struct ifreq ifr;
1173 int done = 0;
1174
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001175 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 goto out;
1177
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001178 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 if (!buf) {
1180 done += sizeof(ifr);
1181 continue;
1182 }
1183 if (len < (int) sizeof(ifr))
1184 break;
1185 memset(&ifr, 0, sizeof(struct ifreq));
Dan Carpenter4299c8a2013-07-29 22:15:19 +03001186 strcpy(ifr.ifr_name, ifa->ifa_label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187
1188 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
1189 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1190 ifa->ifa_local;
1191
1192 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
1193 done = -EFAULT;
1194 break;
1195 }
1196 buf += sizeof(struct ifreq);
1197 len -= sizeof(struct ifreq);
1198 done += sizeof(struct ifreq);
1199 }
1200out:
1201 return done;
1202}
1203
Al Viroa61ced52006-09-26 21:27:54 -07001204__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205{
Al Viroa61ced52006-09-26 21:27:54 -07001206 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001208 struct net *net = dev_net(dev);
David Ahern3f2fb9a2016-02-24 11:47:02 -08001209 int master_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
1211 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001212 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 if (!in_dev)
1214 goto no_in_dev;
1215
1216 for_primary_ifa(in_dev) {
1217 if (ifa->ifa_scope > scope)
1218 continue;
1219 if (!dst || inet_ifa_match(dst, ifa)) {
1220 addr = ifa->ifa_local;
1221 break;
1222 }
1223 if (!addr)
1224 addr = ifa->ifa_local;
1225 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
1227 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001228 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001229no_in_dev:
David Ahern3f2fb9a2016-02-24 11:47:02 -08001230 master_idx = l3mdev_master_ifindex_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231
David Lamparter17b693c2016-02-24 11:47:03 -08001232 /* For VRFs, the VRF device takes the place of the loopback device,
1233 * with addresses on it being preferred. Note in such cases the
1234 * loopback device will be among the devices that fail the master_idx
1235 * equality check in the loop below.
1236 */
1237 if (master_idx &&
1238 (dev = dev_get_by_index_rcu(net, master_idx)) &&
1239 (in_dev = __in_dev_get_rcu(dev))) {
1240 for_primary_ifa(in_dev) {
1241 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1242 ifa->ifa_scope <= scope) {
1243 addr = ifa->ifa_local;
1244 goto out_unlock;
1245 }
1246 } endfor_ifa(in_dev);
1247 }
1248
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 /* Not loopback addresses on loopback should be preferred
Stephen Hemmingerca9f1fd2015-02-14 13:47:54 -05001250 in this case. It is important that lo is the first interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 in dev_base list.
1252 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001253 for_each_netdev_rcu(net, dev) {
David Ahern3f2fb9a2016-02-24 11:47:02 -08001254 if (l3mdev_master_ifindex_rcu(dev) != master_idx)
1255 continue;
1256
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001257 in_dev = __in_dev_get_rcu(dev);
1258 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 continue;
1260
1261 for_primary_ifa(in_dev) {
1262 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1263 ifa->ifa_scope <= scope) {
1264 addr = ifa->ifa_local;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001265 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 }
1267 } endfor_ifa(in_dev);
1268 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001269out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 return addr;
1272}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001273EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274
Al Viro60cad5d2006-09-26 22:17:09 -07001275static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1276 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277{
1278 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001279 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
1281 for_ifa(in_dev) {
1282 if (!addr &&
1283 (local == ifa->ifa_local || !local) &&
1284 ifa->ifa_scope <= scope) {
1285 addr = ifa->ifa_local;
1286 if (same)
1287 break;
1288 }
1289 if (!same) {
1290 same = (!local || inet_ifa_match(local, ifa)) &&
1291 (!dst || inet_ifa_match(dst, ifa));
1292 if (same && addr) {
1293 if (local || !dst)
1294 break;
1295 /* Is the selected addr into dst subnet? */
1296 if (inet_ifa_match(addr, ifa))
1297 break;
1298 /* No, then can we use new local src? */
1299 if (ifa->ifa_scope <= scope) {
1300 addr = ifa->ifa_local;
1301 break;
1302 }
1303 /* search for large dst subnet for addr */
1304 same = 0;
1305 }
1306 }
1307 } endfor_ifa(in_dev);
1308
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001309 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310}
1311
1312/*
1313 * Confirm that local IP address exists using wildcards:
Nicolas Dichtelb601fa12013-12-10 15:02:40 +01001314 * - net: netns to check, cannot be NULL
1315 * - in_dev: only on this interface, NULL=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 * - dst: only in the same subnet as dst, 0=any dst
1317 * - local: address, 0=autoselect the local address
1318 * - scope: maximum allowed scope value for the local address
1319 */
Nicolas Dichtelb601fa12013-12-10 15:02:40 +01001320__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev,
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001321 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322{
Al Viro60cad5d2006-09-26 22:17:09 -07001323 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001324 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325
Ian Morris00db4122015-04-03 09:17:27 +01001326 if (in_dev)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001327 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001330 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001331 in_dev = __in_dev_get_rcu(dev);
1332 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 addr = confirm_addr_indev(in_dev, dst, local, scope);
1334 if (addr)
1335 break;
1336 }
1337 }
1338 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339
1340 return addr;
1341}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001342EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
1344/*
1345 * Device notifier
1346 */
1347
1348int register_inetaddr_notifier(struct notifier_block *nb)
1349{
Alan Sterne041c682006-03-27 01:16:30 -08001350 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001352EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
1354int unregister_inetaddr_notifier(struct notifier_block *nb)
1355{
Alan Sterne041c682006-03-27 01:16:30 -08001356 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001358EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001360/* Rename ifa_labels for a device name change. Make some effort to preserve
1361 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362*/
1363static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001364{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 struct in_ifaddr *ifa;
1366 int named = 0;
1367
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001368 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1369 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
1371 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001372 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001374 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001375 dot = strchr(old, ':');
Ian Morris51456b22015-04-03 09:17:26 +01001376 if (!dot) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001377 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 dot = old;
1379 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001380 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001381 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001382 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001383 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001384skip:
1385 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001386 }
1387}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388
Ian Campbelld11327ad2011-02-11 07:44:16 +00001389static void inetdev_send_gratuitous_arp(struct net_device *dev,
1390 struct in_device *in_dev)
1391
1392{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001393 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001394
Zoltan Kissb76d0782011-07-24 13:09:30 +00001395 for (ifa = in_dev->ifa_list; ifa;
1396 ifa = ifa->ifa_next) {
1397 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1398 ifa->ifa_local, dev,
1399 ifa->ifa_local, NULL,
1400 dev->dev_addr, NULL);
1401 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001402}
1403
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404/* Called only under RTNL semaphore */
1405
1406static int inetdev_event(struct notifier_block *this, unsigned long event,
1407 void *ptr)
1408{
Jiri Pirko351638e2013-05-28 01:30:21 +00001409 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazet748e2d92012-08-22 21:50:59 +00001410 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
1412 ASSERT_RTNL();
1413
1414 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001415 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 in_dev = inetdev_init(dev);
WANG Cong20e61da2014-07-25 15:25:08 -07001417 if (IS_ERR(in_dev))
1418 return notifier_from_errno(PTR_ERR(in_dev));
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001419 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001420 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1421 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001422 }
Breno Leitao06770842008-09-02 17:28:58 -07001423 } else if (event == NETDEV_CHANGEMTU) {
1424 /* Re-enabling IP */
1425 if (inetdev_valid_mtu(dev->mtu))
1426 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 }
1428 goto out;
1429 }
1430
1431 switch (event) {
1432 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001433 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001434 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 break;
1436 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001437 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001439 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001440 struct in_ifaddr *ifa = inet_alloc_ifa();
1441
1442 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001443 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 ifa->ifa_local =
1445 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1446 ifa->ifa_prefixlen = 8;
1447 ifa->ifa_mask = inet_make_mask(8);
1448 in_dev_hold(in_dev);
1449 ifa->ifa_dev = in_dev;
1450 ifa->ifa_scope = RT_SCOPE_HOST;
1451 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Jiri Pirko5c766d62013-01-24 09:41:41 +00001452 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1453 INFINITY_LIFE_TIME);
Jiri Pirkodfd15822014-01-07 15:55:45 +01001454 ipv4_devconf_setall(in_dev);
1455 neigh_parms_data_state_setall(in_dev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 inet_insert_ifa(ifa);
1457 }
1458 }
1459 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001460 /* fall through */
1461 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001462 if (!IN_DEV_ARP_NOTIFY(in_dev))
1463 break;
1464 /* fall through */
1465 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001466 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001467 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 break;
1469 case NETDEV_DOWN:
1470 ip_mc_down(in_dev);
1471 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001472 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001473 ip_mc_unmap(in_dev);
1474 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001475 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001476 ip_mc_remap(in_dev);
1477 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001479 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 break;
Breno Leitao06770842008-09-02 17:28:58 -07001481 /* disable IP when MTU is not enough */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 case NETDEV_UNREGISTER:
1483 inetdev_destroy(in_dev);
1484 break;
1485 case NETDEV_CHANGENAME:
1486 /* Do not notify about label change, this event is
1487 * not interesting to applications using netlink.
1488 */
1489 inetdev_changename(dev, in_dev);
1490
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001491 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001492 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 break;
1494 }
1495out:
1496 return NOTIFY_DONE;
1497}
1498
1499static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001500 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501};
1502
Eric Dumazet40384992012-08-03 21:06:50 +00001503static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001504{
1505 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1506 + nla_total_size(4) /* IFA_ADDRESS */
1507 + nla_total_size(4) /* IFA_LOCAL */
1508 + nla_total_size(4) /* IFA_BROADCAST */
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001509 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
Geert Uytterhoeven63b5f152014-02-05 08:38:25 +01001510 + nla_total_size(4) /* IFA_FLAGS */
1511 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
Thomas Graf339bf982006-11-10 14:10:15 -08001512}
1513
Jiri Pirko5c766d62013-01-24 09:41:41 +00001514static inline u32 cstamp_delta(unsigned long cstamp)
1515{
1516 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1517}
1518
1519static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1520 unsigned long tstamp, u32 preferred, u32 valid)
1521{
1522 struct ifa_cacheinfo ci;
1523
1524 ci.cstamp = cstamp_delta(cstamp);
1525 ci.tstamp = cstamp_delta(tstamp);
1526 ci.ifa_prefered = preferred;
1527 ci.ifa_valid = valid;
1528
1529 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1530}
1531
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001533 u32 portid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534{
1535 struct ifaddrmsg *ifm;
1536 struct nlmsghdr *nlh;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001537 u32 preferred, valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538
Eric W. Biederman15e47302012-09-07 20:12:54 +00001539 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
Ian Morris51456b22015-04-03 09:17:26 +01001540 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08001541 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001542
1543 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 ifm->ifa_family = AF_INET;
1545 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001546 ifm->ifa_flags = ifa->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 ifm->ifa_scope = ifa->ifa_scope;
1548 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
Jiri Pirko5c766d62013-01-24 09:41:41 +00001550 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1551 preferred = ifa->ifa_preferred_lft;
1552 valid = ifa->ifa_valid_lft;
1553 if (preferred != INFINITY_LIFE_TIME) {
1554 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1555
1556 if (preferred > tval)
1557 preferred -= tval;
1558 else
1559 preferred = 0;
1560 if (valid != INFINITY_LIFE_TIME) {
1561 if (valid > tval)
1562 valid -= tval;
1563 else
1564 valid = 0;
1565 }
1566 }
1567 } else {
1568 preferred = INFINITY_LIFE_TIME;
1569 valid = INFINITY_LIFE_TIME;
1570 }
David S. Millerf3756b72012-04-01 20:39:02 -04001571 if ((ifa->ifa_address &&
Jiri Benc930345e2015-03-29 16:59:25 +02001572 nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001573 (ifa->ifa_local &&
Jiri Benc930345e2015-03-29 16:59:25 +02001574 nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001575 (ifa->ifa_broadcast &&
Jiri Benc930345e2015-03-29 16:59:25 +02001576 nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
David S. Millerf3756b72012-04-01 20:39:02 -04001577 (ifa->ifa_label[0] &&
Jiri Pirko5c766d62013-01-24 09:41:41 +00001578 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
Jiri Pirkoad6c8132013-12-08 12:16:10 +01001579 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
Jiri Pirko5c766d62013-01-24 09:41:41 +00001580 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1581 preferred, valid))
David S. Millerf3756b72012-04-01 20:39:02 -04001582 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001583
Johannes Berg053c0952015-01-16 22:09:00 +01001584 nlmsg_end(skb, nlh);
1585 return 0;
Thomas Graf47f68512006-08-04 23:04:36 -07001586
1587nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001588 nlmsg_cancel(skb, nlh);
1589 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590}
1591
1592static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1593{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001594 struct net *net = sock_net(skb->sk);
Eric Dumazeteec4df92009-11-12 07:44:25 +00001595 int h, s_h;
1596 int idx, s_idx;
1597 int ip_idx, s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 struct net_device *dev;
1599 struct in_device *in_dev;
1600 struct in_ifaddr *ifa;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001601 struct hlist_head *head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602
Eric Dumazeteec4df92009-11-12 07:44:25 +00001603 s_h = cb->args[0];
1604 s_idx = idx = cb->args[1];
1605 s_ip_idx = ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
Eric Dumazeteec4df92009-11-12 07:44:25 +00001607 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1608 idx = 0;
1609 head = &net->dev_index_head[h];
1610 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001611 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1612 net->dev_base_seq;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001613 hlist_for_each_entry_rcu(dev, head, index_hlist) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001614 if (idx < s_idx)
1615 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001616 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001617 s_ip_idx = 0;
1618 in_dev = __in_dev_get_rcu(dev);
1619 if (!in_dev)
1620 goto cont;
1621
1622 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1623 ifa = ifa->ifa_next, ip_idx++) {
1624 if (ip_idx < s_ip_idx)
1625 continue;
1626 if (inet_fill_ifaddr(skb, ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001627 NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 cb->nlh->nlmsg_seq,
Johannes Berg053c0952015-01-16 22:09:00 +01001629 RTM_NEWADDR, NLM_F_MULTI) < 0) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001630 rcu_read_unlock();
1631 goto done;
1632 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001633 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Eric Dumazeteec4df92009-11-12 07:44:25 +00001634 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001635cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001636 idx++;
1637 }
1638 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 }
1640
1641done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001642 cb->args[0] = h;
1643 cb->args[1] = idx;
1644 cb->args[2] = ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
1646 return skb->len;
1647}
1648
Jianjun Kong539afed2008-11-03 02:48:48 -08001649static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001650 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651{
Thomas Graf47f68512006-08-04 23:04:36 -07001652 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001653 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1654 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001655 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001657 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001658 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001659 if (!skb)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001660 goto errout;
1661
Eric W. Biederman15e47302012-09-07 20:12:54 +00001662 err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001663 if (err < 0) {
1664 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1665 WARN_ON(err == -EMSGSIZE);
1666 kfree_skb(skb);
1667 goto errout;
1668 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001669 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001670 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001671errout:
1672 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001673 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674}
1675
Arad, Ronenb1974ed2015-10-19 09:23:28 -07001676static size_t inet_get_link_af_size(const struct net_device *dev,
1677 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001678{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001679 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001680
1681 if (!in_dev)
1682 return 0;
1683
1684 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1685}
1686
Sowmini Varadhand5566fd2015-09-11 16:48:48 -04001687static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
1688 u32 ext_filter_mask)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001689{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001690 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001691 struct nlattr *nla;
1692 int i;
1693
1694 if (!in_dev)
1695 return -ENODATA;
1696
1697 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
Ian Morris51456b22015-04-03 09:17:26 +01001698 if (!nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001699 return -EMSGSIZE;
1700
1701 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1702 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1703
1704 return 0;
1705}
1706
1707static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1708 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1709};
1710
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001711static int inet_validate_link_af(const struct net_device *dev,
1712 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001713{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001714 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1715 int err, rem;
1716
Eric Dumazetf7fce742010-12-01 06:03:06 +00001717 if (dev && !__in_dev_get_rtnl(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001718 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001719
1720 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy);
1721 if (err < 0)
1722 return err;
1723
1724 if (tb[IFLA_INET_CONF]) {
1725 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1726 int cfgid = nla_type(a);
1727
1728 if (nla_len(a) < 4)
1729 return -EINVAL;
1730
1731 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1732 return -EINVAL;
1733 }
1734 }
1735
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001736 return 0;
1737}
1738
1739static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1740{
Eric Dumazetf7fce742010-12-01 06:03:06 +00001741 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001742 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1743 int rem;
1744
1745 if (!in_dev)
1746 return -EAFNOSUPPORT;
1747
1748 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL) < 0)
1749 BUG();
1750
Thomas Graf9f0f7272010-11-16 04:32:48 +00001751 if (tb[IFLA_INET_CONF]) {
1752 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1753 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1754 }
1755
1756 return 0;
1757}
1758
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001759static int inet_netconf_msgsize_devconf(int type)
1760{
1761 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1762 + nla_total_size(4); /* NETCONFA_IFINDEX */
Zhang Shengju136ba622016-03-10 08:55:50 +00001763 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001764
Zhang Shengju136ba622016-03-10 08:55:50 +00001765 if (type == NETCONFA_ALL)
1766 all = true;
1767
1768 if (all || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001769 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001770 if (all || type == NETCONFA_RP_FILTER)
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001771 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001772 if (all || type == NETCONFA_MC_FORWARDING)
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001773 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001774 if (all || type == NETCONFA_PROXY_NEIGH)
stephen hemmingerf085ff12013-12-12 13:06:50 -08001775 size += nla_total_size(4);
Zhang Shengju136ba622016-03-10 08:55:50 +00001776 if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001777 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001778
1779 return size;
1780}
1781
1782static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1783 struct ipv4_devconf *devconf, u32 portid,
1784 u32 seq, int event, unsigned int flags,
1785 int type)
1786{
1787 struct nlmsghdr *nlh;
1788 struct netconfmsg *ncm;
Zhang Shengju136ba622016-03-10 08:55:50 +00001789 bool all = false;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001790
1791 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1792 flags);
Ian Morris51456b22015-04-03 09:17:26 +01001793 if (!nlh)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001794 return -EMSGSIZE;
1795
Zhang Shengju136ba622016-03-10 08:55:50 +00001796 if (type == NETCONFA_ALL)
1797 all = true;
1798
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001799 ncm = nlmsg_data(nlh);
1800 ncm->ncm_family = AF_INET;
1801
1802 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1803 goto nla_put_failure;
1804
Zhang Shengju136ba622016-03-10 08:55:50 +00001805 if ((all || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001806 nla_put_s32(skb, NETCONFA_FORWARDING,
1807 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1808 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001809 if ((all || type == NETCONFA_RP_FILTER) &&
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001810 nla_put_s32(skb, NETCONFA_RP_FILTER,
1811 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
1812 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001813 if ((all || type == NETCONFA_MC_FORWARDING) &&
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001814 nla_put_s32(skb, NETCONFA_MC_FORWARDING,
1815 IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
1816 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001817 if ((all || type == NETCONFA_PROXY_NEIGH) &&
stephen hemminger09aea5d2013-12-17 22:35:52 -08001818 nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08001819 IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
1820 goto nla_put_failure;
Zhang Shengju136ba622016-03-10 08:55:50 +00001821 if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001822 nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
1823 IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
1824 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001825
Johannes Berg053c0952015-01-16 22:09:00 +01001826 nlmsg_end(skb, nlh);
1827 return 0;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001828
1829nla_put_failure:
1830 nlmsg_cancel(skb, nlh);
1831 return -EMSGSIZE;
1832}
1833
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001834void inet_netconf_notify_devconf(struct net *net, int type, int ifindex,
1835 struct ipv4_devconf *devconf)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001836{
1837 struct sk_buff *skb;
1838 int err = -ENOBUFS;
1839
Eric Dumazetfa178062016-07-08 05:18:24 +02001840 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001841 if (!skb)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001842 goto errout;
1843
1844 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
1845 RTM_NEWNETCONF, 0, type);
1846 if (err < 0) {
1847 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1848 WARN_ON(err == -EMSGSIZE);
1849 kfree_skb(skb);
1850 goto errout;
1851 }
Eric Dumazetfa178062016-07-08 05:18:24 +02001852 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001853 return;
1854errout:
1855 if (err < 0)
1856 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
1857}
1858
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001859static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
1860 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
1861 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001862 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
stephen hemminger09aea5d2013-12-17 22:35:52 -08001863 [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) },
Andy Gospodarek974d7af2015-07-07 13:56:57 -04001864 [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001865};
1866
1867static int inet_netconf_get_devconf(struct sk_buff *in_skb,
Thomas Graf661d2962013-03-21 07:45:29 +00001868 struct nlmsghdr *nlh)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001869{
1870 struct net *net = sock_net(in_skb->sk);
1871 struct nlattr *tb[NETCONFA_MAX+1];
1872 struct netconfmsg *ncm;
1873 struct sk_buff *skb;
1874 struct ipv4_devconf *devconf;
1875 struct in_device *in_dev;
1876 struct net_device *dev;
1877 int ifindex;
1878 int err;
1879
1880 err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
1881 devconf_ipv4_policy);
1882 if (err < 0)
1883 goto errout;
1884
Anton Protopopova97eb332016-02-16 21:43:16 -05001885 err = -EINVAL;
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001886 if (!tb[NETCONFA_IFINDEX])
1887 goto errout;
1888
1889 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
1890 switch (ifindex) {
1891 case NETCONFA_IFINDEX_ALL:
1892 devconf = net->ipv4.devconf_all;
1893 break;
1894 case NETCONFA_IFINDEX_DEFAULT:
1895 devconf = net->ipv4.devconf_dflt;
1896 break;
1897 default:
1898 dev = __dev_get_by_index(net, ifindex);
Ian Morris51456b22015-04-03 09:17:26 +01001899 if (!dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001900 goto errout;
1901 in_dev = __in_dev_get_rtnl(dev);
Ian Morris51456b22015-04-03 09:17:26 +01001902 if (!in_dev)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001903 goto errout;
1904 devconf = &in_dev->cnf;
1905 break;
1906 }
1907
1908 err = -ENOBUFS;
Eric Dumazetfa178062016-07-08 05:18:24 +02001909 skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01001910 if (!skb)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001911 goto errout;
1912
1913 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
1914 NETLINK_CB(in_skb).portid,
1915 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
Zhang Shengju136ba622016-03-10 08:55:50 +00001916 NETCONFA_ALL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001917 if (err < 0) {
1918 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1919 WARN_ON(err == -EMSGSIZE);
1920 kfree_skb(skb);
1921 goto errout;
1922 }
1923 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
1924errout:
1925 return err;
1926}
1927
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001928static int inet_netconf_dump_devconf(struct sk_buff *skb,
1929 struct netlink_callback *cb)
1930{
1931 struct net *net = sock_net(skb->sk);
1932 int h, s_h;
1933 int idx, s_idx;
1934 struct net_device *dev;
1935 struct in_device *in_dev;
1936 struct hlist_head *head;
1937
1938 s_h = cb->args[0];
1939 s_idx = idx = cb->args[1];
1940
1941 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1942 idx = 0;
1943 head = &net->dev_index_head[h];
1944 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001945 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1946 net->dev_base_seq;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001947 hlist_for_each_entry_rcu(dev, head, index_hlist) {
1948 if (idx < s_idx)
1949 goto cont;
1950 in_dev = __in_dev_get_rcu(dev);
1951 if (!in_dev)
1952 goto cont;
1953
1954 if (inet_netconf_fill_devconf(skb, dev->ifindex,
1955 &in_dev->cnf,
1956 NETLINK_CB(cb->skb).portid,
1957 cb->nlh->nlmsg_seq,
1958 RTM_NEWNETCONF,
1959 NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00001960 NETCONFA_ALL) < 0) {
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001961 rcu_read_unlock();
1962 goto done;
1963 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001964 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001965cont:
1966 idx++;
1967 }
1968 rcu_read_unlock();
1969 }
1970 if (h == NETDEV_HASHENTRIES) {
1971 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
1972 net->ipv4.devconf_all,
1973 NETLINK_CB(cb->skb).portid,
1974 cb->nlh->nlmsg_seq,
1975 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00001976 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001977 goto done;
1978 else
1979 h++;
1980 }
1981 if (h == NETDEV_HASHENTRIES + 1) {
1982 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
1983 net->ipv4.devconf_dflt,
1984 NETLINK_CB(cb->skb).portid,
1985 cb->nlh->nlmsg_seq,
1986 RTM_NEWNETCONF, NLM_F_MULTI,
Zhang Shengju136ba622016-03-10 08:55:50 +00001987 NETCONFA_ALL) < 0)
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001988 goto done;
1989 else
1990 h++;
1991 }
1992done:
1993 cb->args[0] = h;
1994 cb->args[1] = idx;
1995
1996 return skb->len;
1997}
1998
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999#ifdef CONFIG_SYSCTL
2000
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002001static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07002002{
2003 struct net_device *dev;
2004
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002005 rcu_read_lock();
2006 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07002007 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002008
Herbert Xu31be3082007-06-04 23:35:37 -07002009 in_dev = __in_dev_get_rcu(dev);
2010 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002011 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07002012 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002013 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07002014}
2015
Eric Dumazetc6d14c82009-11-04 05:43:23 -08002016/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002017static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002018{
2019 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002020 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002021
Pavel Emelyanov586f1212007-12-16 13:32:48 -08002022 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002023 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002024 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
2025 NETCONFA_IFINDEX_ALL,
2026 net->ipv4.devconf_all);
2027 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
2028 NETCONFA_IFINDEX_DEFAULT,
2029 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002030
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002031 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002032 struct in_device *in_dev;
Eric Dumazetfa178062016-07-08 05:18:24 +02002033
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002034 if (on)
2035 dev_disable_lro(dev);
Eric Dumazetfa178062016-07-08 05:18:24 +02002036
2037 in_dev = __in_dev_get_rtnl(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002038 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002039 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002040 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
2041 dev->ifindex, &in_dev->cnf);
2042 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002043 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002044}
2045
stephen hemmingerf085ff12013-12-12 13:06:50 -08002046static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf)
2047{
2048 if (cnf == net->ipv4.devconf_dflt)
2049 return NETCONFA_IFINDEX_DEFAULT;
2050 else if (cnf == net->ipv4.devconf_all)
2051 return NETCONFA_IFINDEX_ALL;
2052 else {
2053 struct in_device *idev
2054 = container_of(cnf, struct in_device, cnf);
2055 return idev->dev->ifindex;
2056 }
2057}
2058
Joe Perchesfe2c6332013-06-11 23:04:25 -07002059static int devinet_conf_proc(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002060 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07002061 size_t *lenp, loff_t *ppos)
2062{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002063 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002064 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002065 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07002066
2067 if (write) {
2068 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002069 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07002070 int i = (int *)ctl->data - cnf->data;
stephen hemmingerf085ff12013-12-12 13:06:50 -08002071 int ifindex;
Herbert Xu31be3082007-06-04 23:35:37 -07002072
2073 set_bit(i, cnf->state);
2074
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08002075 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002076 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00002077 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
2078 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00002079 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002080 rt_cache_flush(net);
stephen hemmingerf085ff12013-12-12 13:06:50 -08002081
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002082 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
2083 new_value != old_value) {
stephen hemmingerf085ff12013-12-12 13:06:50 -08002084 ifindex = devinet_conf_ifindex(net, cnf);
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00002085 inet_netconf_notify_devconf(net, NETCONFA_RP_FILTER,
2086 ifindex, cnf);
2087 }
stephen hemmingerf085ff12013-12-12 13:06:50 -08002088 if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
2089 new_value != old_value) {
2090 ifindex = devinet_conf_ifindex(net, cnf);
stephen hemminger09aea5d2013-12-17 22:35:52 -08002091 inet_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH,
stephen hemmingerf085ff12013-12-12 13:06:50 -08002092 ifindex, cnf);
2093 }
Andy Gospodarek974d7af2015-07-07 13:56:57 -04002094 if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
2095 new_value != old_value) {
2096 ifindex = devinet_conf_ifindex(net, cnf);
2097 inet_netconf_notify_devconf(net, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
2098 ifindex, cnf);
2099 }
Herbert Xu31be3082007-06-04 23:35:37 -07002100 }
2101
2102 return ret;
2103}
2104
Joe Perchesfe2c6332013-06-11 23:04:25 -07002105static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002106 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 size_t *lenp, loff_t *ppos)
2108{
2109 int *valp = ctl->data;
2110 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00002111 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002112 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113
2114 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002115 struct net *net = ctl->extra2;
2116
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002117 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00002118 if (!rtnl_trylock()) {
2119 /* Restore the original values before restarting */
2120 *valp = val;
2121 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00002122 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00002123 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002124 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2125 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002126 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002127 struct ipv4_devconf *cnf = ctl->extra1;
2128 struct in_device *idev =
2129 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002130 if (*valp)
2131 dev_disable_lro(idev->dev);
2132 inet_netconf_notify_devconf(net,
2133 NETCONFA_FORWARDING,
2134 idev->dev->ifindex,
2135 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002136 }
2137 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002138 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002139 } else
2140 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
2141 NETCONFA_IFINDEX_DEFAULT,
2142 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 }
2144
2145 return ret;
2146}
2147
Joe Perchesfe2c6332013-06-11 23:04:25 -07002148static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
David S. Miller323e1262010-12-12 21:55:08 -08002149 void __user *buffer,
2150 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151{
2152 int *valp = ctl->data;
2153 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002154 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07002155 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156
2157 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002158 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159
2160 return ret;
2161}
2162
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002163#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07002164 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07002165 .procname = name, \
2166 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00002167 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002168 .maxlen = sizeof(int), \
2169 .mode = mval, \
2170 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07002171 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002172 }
2173
2174#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002175 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002176
2177#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002178 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002179
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002180#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2181 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002182
2183#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002184 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07002185
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186static struct devinet_sysctl_table {
2187 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00002188 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189} devinet_sysctl = {
2190 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07002191 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002192 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07002193 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
2194
2195 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
2196 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
2197 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
2198 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
2199 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
2200 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
2201 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00002202 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08002203 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002204 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
2205 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
2206 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
2207 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
2208 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
2209 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
2210 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
2211 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
2212 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08002213 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00002214 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
William Manley5c6fe012013-08-06 19:03:14 +01002215 DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
2216 "force_igmp_version"),
William Manley26900482013-08-06 19:03:15 +01002217 DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL,
2218 "igmpv2_unsolicited_report_interval"),
2219 DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
2220 "igmpv3_unsolicited_report_interval"),
Andy Gospodarek0eeb0752015-06-23 13:45:37 -04002221 DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
2222 "ignore_routes_with_linkdown"),
Johannes Berg97daf332016-02-04 13:31:18 +01002223 DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
2224 "drop_gratuitous_arp"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002225
2226 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2227 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002228 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
2229 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00002230 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2231 "route_localnet"),
Johannes Berg12b74df2016-02-04 13:31:17 +01002232 DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
2233 "drop_unicast_in_l2_multicast"),
Subash Abhinov Kasiviswanathan5ce78152017-11-05 17:36:53 -07002234 DEVINET_SYSCTL_RW_ENTRY(NF_IPV4_DEFRAG_SKIP,
2235 "nf_ipv4_defrag_skip"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237};
2238
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002239static int __devinet_sysctl_register(struct net *net, char *dev_name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002240 int ifindex, struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241{
2242 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002243 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002244 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11002245
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002246 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002248 goto out;
2249
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
2251 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07002252 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002253 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 }
2255
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002256 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002258 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002260 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261
2262 p->sysctl = t;
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002263
2264 inet_netconf_notify_devconf(net, NETCONFA_ALL, ifindex, p);
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002265 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002267free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002269out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002270 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271}
2272
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002273static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
2274{
2275 struct devinet_sysctl_table *t = cnf->sysctl;
2276
Ian Morris51456b22015-04-03 09:17:26 +01002277 if (!t)
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002278 return;
2279
2280 cnf->sysctl = NULL;
Lucian Adrian Grijincuff538812011-05-01 01:44:01 +00002281 unregister_net_sysctl_table(t->sysctl_header);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002282 kfree(t);
2283}
2284
WANG Cong20e61da2014-07-25 15:25:08 -07002285static int devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002286{
WANG Cong20e61da2014-07-25 15:25:08 -07002287 int err;
2288
2289 if (!sysctl_dev_name_is_allowed(idev->dev->name))
2290 return -EINVAL;
2291
2292 err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
2293 if (err)
2294 return err;
2295 err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002296 idev->dev->ifindex, &idev->cnf);
WANG Cong20e61da2014-07-25 15:25:08 -07002297 if (err)
2298 neigh_sysctl_unregister(idev->arp_parms);
2299 return err;
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002300}
2301
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002302static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303{
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002304 __devinet_sysctl_unregister(&idev->cnf);
2305 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002308static struct ctl_table ctl_forward_entry[] = {
2309 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002310 .procname = "ip_forward",
2311 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00002312 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002313 .maxlen = sizeof(int),
2314 .mode = 0644,
2315 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002316 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002317 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002318 },
2319 { },
2320};
Eric Dumazet2a75de02008-01-05 23:08:49 -08002321#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002322
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002323static __net_init int devinet_init_net(struct net *net)
2324{
2325 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002326 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002327#ifdef CONFIG_SYSCTL
2328 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002329 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002330#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002331
2332 err = -ENOMEM;
2333 all = &ipv4_devconf;
2334 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002335
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002336 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002337 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002338 if (!all)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002339 goto err_alloc_all;
2340
2341 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002342 if (!dflt)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002343 goto err_alloc_dflt;
2344
Eric Dumazet2a75de02008-01-05 23:08:49 -08002345#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002346 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
Ian Morris51456b22015-04-03 09:17:26 +01002347 if (!tbl)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002348 goto err_alloc_ctl;
2349
Eric W. Biederman02291682010-02-14 03:25:51 +00002350 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002351 tbl[0].extra1 = all;
2352 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002353#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002354 }
2355
2356#ifdef CONFIG_SYSCTL
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002357 err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002358 if (err < 0)
2359 goto err_reg_all;
2360
Nicolas Dichtel29c994e2016-08-30 10:09:22 +02002361 err = __devinet_sysctl_register(net, "default",
2362 NETCONFA_IFINDEX_DEFAULT, dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002363 if (err < 0)
2364 goto err_reg_dflt;
2365
2366 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002367 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Ian Morris51456b22015-04-03 09:17:26 +01002368 if (!forw_hdr)
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002369 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002370 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002371#endif
2372
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002373 net->ipv4.devconf_all = all;
2374 net->ipv4.devconf_dflt = dflt;
2375 return 0;
2376
2377#ifdef CONFIG_SYSCTL
2378err_reg_ctl:
2379 __devinet_sysctl_unregister(dflt);
2380err_reg_dflt:
2381 __devinet_sysctl_unregister(all);
2382err_reg_all:
2383 if (tbl != ctl_forward_entry)
2384 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002385err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08002386#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002387 if (dflt != &ipv4_devconf_dflt)
2388 kfree(dflt);
2389err_alloc_dflt:
2390 if (all != &ipv4_devconf)
2391 kfree(all);
2392err_alloc_all:
2393 return err;
2394}
2395
2396static __net_exit void devinet_exit_net(struct net *net)
2397{
Eric Dumazet2a75de02008-01-05 23:08:49 -08002398#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002399 struct ctl_table *tbl;
2400
2401 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002402 unregister_net_sysctl_table(net->ipv4.forw_hdr);
2403 __devinet_sysctl_unregister(net->ipv4.devconf_dflt);
2404 __devinet_sysctl_unregister(net->ipv4.devconf_all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002405 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08002406#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002407 kfree(net->ipv4.devconf_dflt);
2408 kfree(net->ipv4.devconf_all);
2409}
2410
2411static __net_initdata struct pernet_operations devinet_ops = {
2412 .init = devinet_init_net,
2413 .exit = devinet_exit_net,
2414};
2415
Daniel Borkmann207895f2015-01-29 12:15:03 +01002416static struct rtnl_af_ops inet_af_ops __read_mostly = {
Thomas Graf9f0f7272010-11-16 04:32:48 +00002417 .family = AF_INET,
2418 .fill_link_af = inet_fill_link_af,
2419 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00002420 .validate_link_af = inet_validate_link_af,
2421 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00002422};
2423
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424void __init devinet_init(void)
2425{
David S. Millerfd23c3b2011-02-18 12:42:28 -08002426 int i;
2427
2428 for (i = 0; i < IN4_ADDR_HSIZE; i++)
2429 INIT_HLIST_HEAD(&inet_addr_lst[i]);
2430
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002431 register_pernet_subsys(&devinet_ops);
2432
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 register_gifconf(PF_INET, inet_gifconf);
2434 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07002435
viresh kumar906e0732014-01-22 12:23:32 +05302436 queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
Jiri Pirko5c766d62013-01-24 09:41:41 +00002437
Thomas Graf9f0f7272010-11-16 04:32:48 +00002438 rtnl_af_register(&inet_af_ops);
2439
Greg Rosec7ac8672011-06-10 01:27:09 +00002440 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL);
2441 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, NULL);
2442 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, NULL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002443 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002444 inet_netconf_dump_devconf, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445}