blob: 8d48c392adccec6dc1f2ca8e3c8fd5a6750283e5 [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
Adrian Bunk0027ba82008-01-31 17:17:31 -080070static struct ipv4_devconf ipv4_devconf = {
Herbert Xu42f811b2007-06-04 23:34:44 -070071 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000072 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
73 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
74 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
75 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
Herbert Xu42f811b2007-06-04 23:34:44 -070076 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070077};
78
79static struct ipv4_devconf ipv4_devconf_dflt = {
Herbert Xu42f811b2007-06-04 23:34:44 -070080 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000081 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
82 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
83 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
84 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
85 [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
Herbert Xu42f811b2007-06-04 23:34:44 -070086 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070087};
88
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -080089#define IPV4_DEVCONF_DFLT(net, attr) \
90 IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr)
Herbert Xu42f811b2007-06-04 23:34:44 -070091
Patrick McHardyef7c79e2007-06-05 12:38:30 -070092static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
Thomas Graf5c753972006-08-04 23:03:53 -070093 [IFA_LOCAL] = { .type = NLA_U32 },
94 [IFA_ADDRESS] = { .type = NLA_U32 },
95 [IFA_BROADCAST] = { .type = NLA_U32 },
Thomas Graf5176f912006-08-26 20:13:18 -070096 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
Jiri Pirko5c766d62013-01-24 09:41:41 +000097 [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
Thomas Graf5c753972006-08-04 23:03:53 -070098};
99
Eric Dumazet40384992012-08-03 21:06:50 +0000100#define IN4_ADDR_HSIZE_SHIFT 8
101#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT)
102
David S. Millerfd23c3b2011-02-18 12:42:28 -0800103static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
104static DEFINE_SPINLOCK(inet_addr_hash_lock);
105
Eric Dumazet40384992012-08-03 21:06:50 +0000106static u32 inet_addr_hash(struct net *net, __be32 addr)
David S. Millerfd23c3b2011-02-18 12:42:28 -0800107{
Eric Dumazet40384992012-08-03 21:06:50 +0000108 u32 val = (__force u32) addr ^ net_hash_mix(net);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800109
Eric Dumazet40384992012-08-03 21:06:50 +0000110 return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800111}
112
113static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
114{
Eric Dumazet40384992012-08-03 21:06:50 +0000115 u32 hash = inet_addr_hash(net, ifa->ifa_local);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800116
117 spin_lock(&inet_addr_hash_lock);
118 hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
119 spin_unlock(&inet_addr_hash_lock);
120}
121
122static void inet_hash_remove(struct in_ifaddr *ifa)
123{
124 spin_lock(&inet_addr_hash_lock);
125 hlist_del_init_rcu(&ifa->hash);
126 spin_unlock(&inet_addr_hash_lock);
127}
128
David S. Miller9435eb12011-02-18 12:43:09 -0800129/**
130 * __ip_dev_find - find the first device with a given source address.
131 * @net: the net namespace
132 * @addr: the source address
133 * @devref: if true, take a reference on the found device
134 *
135 * If a caller uses devref=false, it should be protected by RCU, or RTNL
136 */
137struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
138{
Eric Dumazet40384992012-08-03 21:06:50 +0000139 u32 hash = inet_addr_hash(net, addr);
David S. Miller9435eb12011-02-18 12:43:09 -0800140 struct net_device *result = NULL;
141 struct in_ifaddr *ifa;
David S. Miller9435eb12011-02-18 12:43:09 -0800142
143 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800144 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash) {
David S. Millere0660082011-03-03 11:24:19 -0800145 if (ifa->ifa_local == addr) {
Eric Dumazet40384992012-08-03 21:06:50 +0000146 struct net_device *dev = ifa->ifa_dev->dev;
147
148 if (!net_eq(dev_net(dev), net))
149 continue;
David S. Miller9435eb12011-02-18 12:43:09 -0800150 result = dev;
151 break;
152 }
153 }
David S. Miller406b6f92011-03-22 21:56:23 -0700154 if (!result) {
155 struct flowi4 fl4 = { .daddr = addr };
156 struct fib_result res = { 0 };
157 struct fib_table *local;
158
159 /* Fallback to FIB local table so that communication
160 * over loopback subnets work.
161 */
162 local = fib_get_table(net, RT_TABLE_LOCAL);
163 if (local &&
164 !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
165 res.type == RTN_LOCAL)
166 result = FIB_RES_DEV(res);
167 }
David S. Miller9435eb12011-02-18 12:43:09 -0800168 if (result && devref)
169 dev_hold(result);
170 rcu_read_unlock();
171 return result;
172}
173EXPORT_SYMBOL(__ip_dev_find);
174
Thomas Grafd6062cb2006-08-15 00:33:59 -0700175static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
Alan Sterne041c682006-03-27 01:16:30 -0800177static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
179 int destroy);
180#ifdef CONFIG_SYSCTL
Pavel Emelyanov66f27a52007-12-02 00:55:54 +1100181static void devinet_sysctl_register(struct in_device *idev);
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800182static void devinet_sysctl_unregister(struct in_device *idev);
183#else
Eric Dumazet40384992012-08-03 21:06:50 +0000184static void devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800185{
186}
Eric Dumazet40384992012-08-03 21:06:50 +0000187static void devinet_sysctl_unregister(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800188{
189}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190#endif
191
192/* Locks all the inet devices. */
193
194static struct in_ifaddr *inet_alloc_ifa(void)
195{
Alexey Dobriyan93adcc82008-10-28 13:25:09 -0700196 return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197}
198
199static void inet_rcu_free_ifa(struct rcu_head *head)
200{
201 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
202 if (ifa->ifa_dev)
203 in_dev_put(ifa->ifa_dev);
204 kfree(ifa);
205}
206
Eric Dumazet40384992012-08-03 21:06:50 +0000207static void inet_free_ifa(struct in_ifaddr *ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
209 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
210}
211
212void in_dev_finish_destroy(struct in_device *idev)
213{
214 struct net_device *dev = idev->dev;
215
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700216 WARN_ON(idev->ifa_list);
217 WARN_ON(idev->mc_list);
Eric Dumazete9897072013-06-07 08:48:57 -0700218 kfree(rcu_dereference_protected(idev->mc_hash, 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219#ifdef NET_REFCNT_DEBUG
Joe Perches91df42b2012-05-15 14:11:54 +0000220 pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221#endif
222 dev_put(dev);
223 if (!idev->dead)
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800224 pr_err("Freeing alive in_device %p\n", idev);
225 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 kfree(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800228EXPORT_SYMBOL(in_dev_finish_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
Herbert Xu71e27da2007-06-04 23:36:06 -0700230static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
232 struct in_device *in_dev;
233
234 ASSERT_RTNL();
235
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700236 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 if (!in_dev)
238 goto out;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900239 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -0800240 sizeof(in_dev->cnf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 in_dev->cnf.sysctl = NULL;
242 in_dev->dev = dev;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800243 in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
244 if (!in_dev->arp_parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 goto out_kfree;
Ben Hutchings0187bdf2008-06-19 16:15:47 -0700246 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
247 dev_disable_lro(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 /* Reference in_dev->dev */
249 dev_hold(dev);
David L Stevens30c4cf52007-01-04 12:31:14 -0800250 /* Account for reference dev->ip_ptr (below) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 in_dev_hold(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
Pavel Emelyanov66f27a52007-12-02 00:55:54 +1100253 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 ip_mc_init_dev(in_dev);
255 if (dev->flags & IFF_UP)
256 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800257
David L Stevens30c4cf52007-01-04 12:31:14 -0800258 /* we can receive as soon as ip_ptr is set -- do this last */
Eric Dumazetcf778b02012-01-12 04:41:32 +0000259 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800260out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 return in_dev;
262out_kfree:
263 kfree(in_dev);
264 in_dev = NULL;
265 goto out;
266}
267
268static void in_dev_rcu_put(struct rcu_head *head)
269{
270 struct in_device *idev = container_of(head, struct in_device, rcu_head);
271 in_dev_put(idev);
272}
273
274static void inetdev_destroy(struct in_device *in_dev)
275{
276 struct in_ifaddr *ifa;
277 struct net_device *dev;
278
279 ASSERT_RTNL();
280
281 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
283 in_dev->dead = 1;
284
285 ip_mc_destroy_dev(in_dev);
286
287 while ((ifa = in_dev->ifa_list) != NULL) {
288 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
289 inet_free_ifa(ifa);
290 }
291
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000292 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800294 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
296 arp_ifdown(dev);
297
298 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
299}
300
Al Viroff428d72006-09-26 22:13:35 -0700301int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302{
303 rcu_read_lock();
304 for_primary_ifa(in_dev) {
305 if (inet_ifa_match(a, ifa)) {
306 if (!b || inet_ifa_match(b, ifa)) {
307 rcu_read_unlock();
308 return 1;
309 }
310 }
311 } endfor_ifa(in_dev);
312 rcu_read_unlock();
313 return 0;
314}
315
Thomas Grafd6062cb2006-08-15 00:33:59 -0700316static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000317 int destroy, struct nlmsghdr *nlh, u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
Harald Welte8f937c62005-05-29 20:23:46 -0700319 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800320 struct in_ifaddr *ifa, *ifa1 = *ifap;
321 struct in_ifaddr *last_prim = in_dev->ifa_list;
322 struct in_ifaddr *prev_prom = NULL;
323 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325 ASSERT_RTNL();
326
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900327 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700328 * unless alias promotion is set
329 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
333
334 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900335 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800336 ifa1->ifa_scope <= ifa->ifa_scope)
337 last_prim = ifa;
338
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
340 ifa1->ifa_mask != ifa->ifa_mask ||
341 !inet_ifa_match(ifa1->ifa_address, ifa)) {
342 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800343 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 continue;
345 }
346
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800347 if (!do_promote) {
David S. Millerfd23c3b2011-02-18 12:42:28 -0800348 inet_hash_remove(ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700349 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Eric W. Biederman15e47302012-09-07 20:12:54 +0000351 rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800352 blocking_notifier_call_chain(&inetaddr_chain,
353 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700354 inet_free_ifa(ifa);
355 } else {
356 promote = ifa;
357 break;
358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 }
360 }
361
Julian Anastasov2d230e22011-03-19 12:13:52 +0000362 /* On promotion all secondaries from subnet are changing
363 * the primary IP, we must remove all their routes silently
364 * and later to add them back with new prefsrc. Do this
365 * while all addresses are on the device list.
366 */
367 for (ifa = promote; ifa; ifa = ifa->ifa_next) {
368 if (ifa1->ifa_mask == ifa->ifa_mask &&
369 inet_ifa_match(ifa1->ifa_address, ifa))
370 fib_del_ifaddr(ifa, ifa1);
371 }
372
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 /* 2. Unlink it */
374
375 *ifap = ifa1->ifa_next;
David S. Millerfd23c3b2011-02-18 12:42:28 -0800376 inet_hash_remove(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
378 /* 3. Announce address deletion */
379
380 /* Send message first, then call notifier.
381 At first sight, FIB update triggered by notifier
382 will refer to already deleted ifaddr, that could confuse
383 netlink listeners. It is not true: look, gated sees
384 that route deleted and if it still thinks that ifaddr
385 is valid, it will try to restore deleted routes... Grr.
386 So that, this order is correct.
387 */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000388 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800389 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800390
391 if (promote) {
Julian Anastasov04024b92011-03-19 12:13:54 +0000392 struct in_ifaddr *next_sec = promote->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800393
394 if (prev_prom) {
395 prev_prom->ifa_next = promote->ifa_next;
396 promote->ifa_next = last_prim->ifa_next;
397 last_prim->ifa_next = promote;
398 }
399
400 promote->ifa_flags &= ~IFA_F_SECONDARY;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000401 rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800402 blocking_notifier_call_chain(&inetaddr_chain,
403 NETDEV_UP, promote);
Julian Anastasov04024b92011-03-19 12:13:54 +0000404 for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800405 if (ifa1->ifa_mask != ifa->ifa_mask ||
406 !inet_ifa_match(ifa1->ifa_address, ifa))
407 continue;
408 fib_add_ifaddr(ifa);
409 }
410
411 }
Herbert Xu63630972007-06-07 18:35:38 -0700412 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414}
415
Thomas Grafd6062cb2006-08-15 00:33:59 -0700416static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
417 int destroy)
418{
419 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
420}
421
Jiri Pirko5c766d62013-01-24 09:41:41 +0000422static void check_lifetime(struct work_struct *work);
423
424static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
425
Thomas Grafd6062cb2006-08-15 00:33:59 -0700426static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000427 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428{
429 struct in_device *in_dev = ifa->ifa_dev;
430 struct in_ifaddr *ifa1, **ifap, **last_primary;
431
432 ASSERT_RTNL();
433
434 if (!ifa->ifa_local) {
435 inet_free_ifa(ifa);
436 return 0;
437 }
438
439 ifa->ifa_flags &= ~IFA_F_SECONDARY;
440 last_primary = &in_dev->ifa_list;
441
442 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
443 ifap = &ifa1->ifa_next) {
444 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
445 ifa->ifa_scope <= ifa1->ifa_scope)
446 last_primary = &ifa1->ifa_next;
447 if (ifa1->ifa_mask == ifa->ifa_mask &&
448 inet_ifa_match(ifa1->ifa_address, ifa)) {
449 if (ifa1->ifa_local == ifa->ifa_local) {
450 inet_free_ifa(ifa);
451 return -EEXIST;
452 }
453 if (ifa1->ifa_scope != ifa->ifa_scope) {
454 inet_free_ifa(ifa);
455 return -EINVAL;
456 }
457 ifa->ifa_flags |= IFA_F_SECONDARY;
458 }
459 }
460
461 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
462 net_srandom(ifa->ifa_local);
463 ifap = last_primary;
464 }
465
466 ifa->ifa_next = *ifap;
467 *ifap = ifa;
468
David S. Millerfd23c3b2011-02-18 12:42:28 -0800469 inet_hash_insert(dev_net(in_dev->dev), ifa);
470
Jiri Pirko5c766d62013-01-24 09:41:41 +0000471 cancel_delayed_work(&check_lifetime_work);
472 schedule_delayed_work(&check_lifetime_work, 0);
473
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 /* Send message first, then call notifier.
475 Notifier will trigger FIB update, so that
476 listeners of netlink will know about new ifaddr */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000477 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800478 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
480 return 0;
481}
482
Thomas Grafd6062cb2006-08-15 00:33:59 -0700483static int inet_insert_ifa(struct in_ifaddr *ifa)
484{
485 return __inet_insert_ifa(ifa, NULL, 0);
486}
487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
489{
Herbert Xue5ed6392005-10-03 14:35:55 -0700490 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
492 ASSERT_RTNL();
493
494 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700495 inet_free_ifa(ifa);
496 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700498 ipv4_devconf_setall(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700500 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 in_dev_hold(in_dev);
502 ifa->ifa_dev = in_dev;
503 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800504 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 ifa->ifa_scope = RT_SCOPE_HOST;
506 return inet_insert_ifa(ifa);
507}
508
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000509/* Caller must hold RCU or RTNL :
510 * We dont take a reference on found in_device
511 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800512struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513{
514 struct net_device *dev;
515 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000516
517 rcu_read_lock();
518 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000520 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000521 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 return in_dev;
523}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800524EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
526/* Called only from RTNL semaphored context. No locks. */
527
Al Viro60cad5d2006-09-26 22:17:09 -0700528struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
529 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530{
531 ASSERT_RTNL();
532
533 for_primary_ifa(in_dev) {
534 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
535 return ifa;
536 } endfor_ifa(in_dev);
537 return NULL;
538}
539
Thomas Graf661d2962013-03-21 07:45:29 +0000540static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900542 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700543 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700545 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700547 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549 ASSERT_RTNL();
550
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700551 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
552 if (err < 0)
553 goto errout;
554
555 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800556 in_dev = inetdev_by_index(net, ifm->ifa_index);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700557 if (in_dev == NULL) {
558 err = -ENODEV;
559 goto errout;
560 }
561
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
563 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700564 if (tb[IFA_LOCAL] &&
Al Viroa7a628c2006-09-26 22:16:43 -0700565 ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700567
568 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
569 continue;
570
571 if (tb[IFA_ADDRESS] &&
572 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Al Viroa7a628c2006-09-26 22:16:43 -0700573 !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700574 continue;
575
Eric W. Biederman15e47302012-09-07 20:12:54 +0000576 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 return 0;
578 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700579
580 err = -EADDRNOTAVAIL;
581errout:
582 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583}
584
Jiri Pirko5c766d62013-01-24 09:41:41 +0000585#define INFINITY_LIFE_TIME 0xFFFFFFFF
586
587static void check_lifetime(struct work_struct *work)
588{
589 unsigned long now, next, next_sec, next_sched;
590 struct in_ifaddr *ifa;
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000591 struct hlist_node *n;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000592 int i;
593
594 now = jiffies;
595 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
596
Jiri Pirko5c766d62013-01-24 09:41:41 +0000597 for (i = 0; i < IN4_ADDR_HSIZE; i++) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000598 bool change_needed = false;
599
600 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800601 hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
Jiri Pirko5c766d62013-01-24 09:41:41 +0000602 unsigned long age;
603
604 if (ifa->ifa_flags & IFA_F_PERMANENT)
605 continue;
606
607 /* We try to batch several events at once. */
608 age = (now - ifa->ifa_tstamp +
609 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
610
611 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
612 age >= ifa->ifa_valid_lft) {
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000613 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000614 } else if (ifa->ifa_preferred_lft ==
615 INFINITY_LIFE_TIME) {
616 continue;
617 } else if (age >= ifa->ifa_preferred_lft) {
618 if (time_before(ifa->ifa_tstamp +
619 ifa->ifa_valid_lft * HZ, next))
620 next = ifa->ifa_tstamp +
621 ifa->ifa_valid_lft * HZ;
622
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000623 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
624 change_needed = true;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000625 } else if (time_before(ifa->ifa_tstamp +
626 ifa->ifa_preferred_lft * HZ,
627 next)) {
628 next = ifa->ifa_tstamp +
629 ifa->ifa_preferred_lft * HZ;
630 }
631 }
Jiri Pirkoc988d1e2013-04-04 23:39:39 +0000632 rcu_read_unlock();
633 if (!change_needed)
634 continue;
635 rtnl_lock();
636 hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
637 unsigned long age;
638
639 if (ifa->ifa_flags & IFA_F_PERMANENT)
640 continue;
641
642 /* We try to batch several events at once. */
643 age = (now - ifa->ifa_tstamp +
644 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
645
646 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
647 age >= ifa->ifa_valid_lft) {
648 struct in_ifaddr **ifap;
649
650 for (ifap = &ifa->ifa_dev->ifa_list;
651 *ifap != NULL; ifap = &(*ifap)->ifa_next) {
652 if (*ifap == ifa) {
653 inet_del_ifa(ifa->ifa_dev,
654 ifap, 1);
655 break;
656 }
657 }
658 } else if (ifa->ifa_preferred_lft !=
659 INFINITY_LIFE_TIME &&
660 age >= ifa->ifa_preferred_lft &&
661 !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
662 ifa->ifa_flags |= IFA_F_DEPRECATED;
663 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
664 }
665 }
666 rtnl_unlock();
Jiri Pirko5c766d62013-01-24 09:41:41 +0000667 }
Jiri Pirko5c766d62013-01-24 09:41:41 +0000668
669 next_sec = round_jiffies_up(next);
670 next_sched = next;
671
672 /* If rounded timeout is accurate enough, accept it. */
673 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
674 next_sched = next_sec;
675
676 now = jiffies;
677 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
678 if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
679 next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
680
681 schedule_delayed_work(&check_lifetime_work, next_sched - now);
682}
683
684static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
685 __u32 prefered_lft)
686{
687 unsigned long timeout;
688
689 ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
690
691 timeout = addrconf_timeout_fixup(valid_lft, HZ);
692 if (addrconf_finite_timeout(timeout))
693 ifa->ifa_valid_lft = timeout;
694 else
695 ifa->ifa_flags |= IFA_F_PERMANENT;
696
697 timeout = addrconf_timeout_fixup(prefered_lft, HZ);
698 if (addrconf_finite_timeout(timeout)) {
699 if (timeout == 0)
700 ifa->ifa_flags |= IFA_F_DEPRECATED;
701 ifa->ifa_preferred_lft = timeout;
702 }
703 ifa->ifa_tstamp = jiffies;
704 if (!ifa->ifa_cstamp)
705 ifa->ifa_cstamp = ifa->ifa_tstamp;
706}
707
708static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
709 __u32 *pvalid_lft, __u32 *pprefered_lft)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710{
Thomas Graf5c753972006-08-04 23:03:53 -0700711 struct nlattr *tb[IFA_MAX+1];
712 struct in_ifaddr *ifa;
713 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 struct net_device *dev;
715 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800716 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
Thomas Graf5c753972006-08-04 23:03:53 -0700718 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
719 if (err < 0)
720 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
Thomas Graf5c753972006-08-04 23:03:53 -0700722 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800723 err = -EINVAL;
724 if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700725 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800727 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800728 err = -ENODEV;
729 if (dev == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700730 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
Thomas Graf5c753972006-08-04 23:03:53 -0700732 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800733 err = -ENOBUFS;
734 if (in_dev == NULL)
Herbert Xu71e27da2007-06-04 23:36:06 -0700735 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
Thomas Graf5c753972006-08-04 23:03:53 -0700737 ifa = inet_alloc_ifa();
Denis V. Lunev7b218572008-01-31 18:47:00 -0800738 if (ifa == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700739 /*
740 * A potential indev allocation can be left alive, it stays
741 * assigned to its device and is destroy with it.
742 */
Thomas Graf5c753972006-08-04 23:03:53 -0700743 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700744
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800745 ipv4_devconf_setall(in_dev);
Thomas Graf5c753972006-08-04 23:03:53 -0700746 in_dev_hold(in_dev);
747
748 if (tb[IFA_ADDRESS] == NULL)
749 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
750
David S. Millerfd23c3b2011-02-18 12:42:28 -0800751 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
753 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 ifa->ifa_flags = ifm->ifa_flags;
755 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700756 ifa->ifa_dev = in_dev;
757
Al Viroa7a628c2006-09-26 22:16:43 -0700758 ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]);
759 ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700760
761 if (tb[IFA_BROADCAST])
Al Viroa7a628c2006-09-26 22:16:43 -0700762 ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700763
Thomas Graf5c753972006-08-04 23:03:53 -0700764 if (tb[IFA_LABEL])
765 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 else
767 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
768
Jiri Pirko5c766d62013-01-24 09:41:41 +0000769 if (tb[IFA_CACHEINFO]) {
770 struct ifa_cacheinfo *ci;
771
772 ci = nla_data(tb[IFA_CACHEINFO]);
773 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
774 err = -EINVAL;
775 goto errout;
776 }
777 *pvalid_lft = ci->ifa_valid;
778 *pprefered_lft = ci->ifa_prefered;
779 }
780
Thomas Graf5c753972006-08-04 23:03:53 -0700781 return ifa;
782
783errout:
784 return ERR_PTR(err);
785}
786
Jiri Pirko5c766d62013-01-24 09:41:41 +0000787static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
788{
789 struct in_device *in_dev = ifa->ifa_dev;
790 struct in_ifaddr *ifa1, **ifap;
791
792 if (!ifa->ifa_local)
793 return NULL;
794
795 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
796 ifap = &ifa1->ifa_next) {
797 if (ifa1->ifa_mask == ifa->ifa_mask &&
798 inet_ifa_match(ifa1->ifa_address, ifa) &&
799 ifa1->ifa_local == ifa->ifa_local)
800 return ifa1;
801 }
802 return NULL;
803}
804
Thomas Graf661d2962013-03-21 07:45:29 +0000805static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
Thomas Graf5c753972006-08-04 23:03:53 -0700806{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900807 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700808 struct in_ifaddr *ifa;
Jiri Pirko5c766d62013-01-24 09:41:41 +0000809 struct in_ifaddr *ifa_existing;
810 __u32 valid_lft = INFINITY_LIFE_TIME;
811 __u32 prefered_lft = INFINITY_LIFE_TIME;
Thomas Graf5c753972006-08-04 23:03:53 -0700812
813 ASSERT_RTNL();
814
Jiri Pirko5c766d62013-01-24 09:41:41 +0000815 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft);
Thomas Graf5c753972006-08-04 23:03:53 -0700816 if (IS_ERR(ifa))
817 return PTR_ERR(ifa);
818
Jiri Pirko5c766d62013-01-24 09:41:41 +0000819 ifa_existing = find_matching_ifa(ifa);
820 if (!ifa_existing) {
821 /* It would be best to check for !NLM_F_CREATE here but
822 * userspace alreay relies on not having to provide this.
823 */
824 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
825 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
826 } else {
827 inet_free_ifa(ifa);
828
829 if (nlh->nlmsg_flags & NLM_F_EXCL ||
830 !(nlh->nlmsg_flags & NLM_F_REPLACE))
831 return -EEXIST;
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000832 ifa = ifa_existing;
833 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
Jiri Pirko05a324b2013-04-04 23:39:38 +0000834 cancel_delayed_work(&check_lifetime_work);
835 schedule_delayed_work(&check_lifetime_work, 0);
Jiri Pirko34e2ed32013-04-04 08:33:00 +0000836 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
837 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Jiri Pirko5c766d62013-01-24 09:41:41 +0000838 }
839 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840}
841
842/*
843 * Determine a default network mask, based on the IP address.
844 */
845
Eric Dumazet40384992012-08-03 21:06:50 +0000846static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847{
848 int rc = -1; /* Something else, probably a multicast. */
849
Joe Perchesf97c1e02007-12-16 13:45:43 -0800850 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900851 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 else {
Al Viro714e85b2006-11-14 20:51:49 -0800853 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854
Al Viro714e85b2006-11-14 20:51:49 -0800855 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800857 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800859 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 rc = 24;
861 }
862
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900863 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864}
865
866
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800867int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868{
869 struct ifreq ifr;
870 struct sockaddr_in sin_orig;
871 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
872 struct in_device *in_dev;
873 struct in_ifaddr **ifap = NULL;
874 struct in_ifaddr *ifa = NULL;
875 struct net_device *dev;
876 char *colon;
877 int ret = -EFAULT;
878 int tryaddrmatch = 0;
879
880 /*
881 * Fetch the caller's info block into kernel space
882 */
883
884 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
885 goto out;
886 ifr.ifr_name[IFNAMSIZ - 1] = 0;
887
888 /* save original address for comparison */
889 memcpy(&sin_orig, sin, sizeof(*sin));
890
891 colon = strchr(ifr.ifr_name, ':');
892 if (colon)
893 *colon = 0;
894
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800895 dev_load(net, ifr.ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896
Stephen Hemminger132adf52007-03-08 20:44:43 -0800897 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 case SIOCGIFADDR: /* Get interface address */
899 case SIOCGIFBRDADDR: /* Get the broadcast address */
900 case SIOCGIFDSTADDR: /* Get the destination address */
901 case SIOCGIFNETMASK: /* Get the netmask for the interface */
902 /* Note that these ioctls will not sleep,
903 so that we do not impose a lock.
904 One day we will be forced to put shlock here (I mean SMP)
905 */
906 tryaddrmatch = (sin_orig.sin_family == AF_INET);
907 memset(sin, 0, sizeof(*sin));
908 sin->sin_family = AF_INET;
909 break;
910
911 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000912 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000913 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 goto out;
915 break;
916 case SIOCSIFADDR: /* Set interface address (and family) */
917 case SIOCSIFBRDADDR: /* Set the broadcast address */
918 case SIOCSIFDSTADDR: /* Set the destination address */
919 case SIOCSIFNETMASK: /* Set the netmask for the interface */
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000920 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000921 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 goto out;
923 ret = -EINVAL;
924 if (sin->sin_family != AF_INET)
925 goto out;
926 break;
927 default:
928 ret = -EINVAL;
929 goto out;
930 }
931
932 rtnl_lock();
933
934 ret = -ENODEV;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800935 dev = __dev_get_by_name(net, ifr.ifr_name);
936 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 goto done;
938
939 if (colon)
940 *colon = ':';
941
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800942 in_dev = __in_dev_get_rtnl(dev);
943 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 if (tryaddrmatch) {
945 /* Matthias Andree */
946 /* compare label and address (4.4BSD style) */
947 /* note: we only do this for a limited set of ioctls
948 and only if the original address family was AF_INET.
949 This is checked above. */
950 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
951 ifap = &ifa->ifa_next) {
952 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
953 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -0800954 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 break; /* found */
956 }
957 }
958 }
959 /* we didn't get a match, maybe the application is
960 4.3BSD-style and passed in junk so we fall back to
961 comparing just the label */
962 if (!ifa) {
963 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
964 ifap = &ifa->ifa_next)
965 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
966 break;
967 }
968 }
969
970 ret = -EADDRNOTAVAIL;
971 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
972 goto done;
973
Stephen Hemminger132adf52007-03-08 20:44:43 -0800974 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 case SIOCGIFADDR: /* Get interface address */
976 sin->sin_addr.s_addr = ifa->ifa_local;
977 goto rarok;
978
979 case SIOCGIFBRDADDR: /* Get the broadcast address */
980 sin->sin_addr.s_addr = ifa->ifa_broadcast;
981 goto rarok;
982
983 case SIOCGIFDSTADDR: /* Get the destination address */
984 sin->sin_addr.s_addr = ifa->ifa_address;
985 goto rarok;
986
987 case SIOCGIFNETMASK: /* Get the netmask for the interface */
988 sin->sin_addr.s_addr = ifa->ifa_mask;
989 goto rarok;
990
991 case SIOCSIFFLAGS:
992 if (colon) {
993 ret = -EADDRNOTAVAIL;
994 if (!ifa)
995 break;
996 ret = 0;
997 if (!(ifr.ifr_flags & IFF_UP))
998 inet_del_ifa(in_dev, ifap, 1);
999 break;
1000 }
1001 ret = dev_change_flags(dev, ifr.ifr_flags);
1002 break;
1003
1004 case SIOCSIFADDR: /* Set interface address (and family) */
1005 ret = -EINVAL;
1006 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1007 break;
1008
1009 if (!ifa) {
1010 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001011 ifa = inet_alloc_ifa();
1012 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 break;
Xi Wangc7e2e1d2013-01-05 11:19:24 +00001014 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 if (colon)
1016 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
1017 else
1018 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1019 } else {
1020 ret = 0;
1021 if (ifa->ifa_local == sin->sin_addr.s_addr)
1022 break;
1023 inet_del_ifa(in_dev, ifap, 0);
1024 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -08001025 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 }
1027
1028 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
1029
1030 if (!(dev->flags & IFF_POINTOPOINT)) {
1031 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
1032 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
1033 if ((dev->flags & IFF_BROADCAST) &&
1034 ifa->ifa_prefixlen < 31)
1035 ifa->ifa_broadcast = ifa->ifa_address |
1036 ~ifa->ifa_mask;
1037 } else {
1038 ifa->ifa_prefixlen = 32;
1039 ifa->ifa_mask = inet_make_mask(32);
1040 }
Jiri Pirko5c766d62013-01-24 09:41:41 +00001041 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 ret = inet_set_ifa(dev, ifa);
1043 break;
1044
1045 case SIOCSIFBRDADDR: /* Set the broadcast address */
1046 ret = 0;
1047 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
1048 inet_del_ifa(in_dev, ifap, 0);
1049 ifa->ifa_broadcast = sin->sin_addr.s_addr;
1050 inet_insert_ifa(ifa);
1051 }
1052 break;
1053
1054 case SIOCSIFDSTADDR: /* Set the destination address */
1055 ret = 0;
1056 if (ifa->ifa_address == sin->sin_addr.s_addr)
1057 break;
1058 ret = -EINVAL;
1059 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
1060 break;
1061 ret = 0;
1062 inet_del_ifa(in_dev, ifap, 0);
1063 ifa->ifa_address = sin->sin_addr.s_addr;
1064 inet_insert_ifa(ifa);
1065 break;
1066
1067 case SIOCSIFNETMASK: /* Set the netmask for the interface */
1068
1069 /*
1070 * The mask we set must be legal.
1071 */
1072 ret = -EINVAL;
1073 if (bad_mask(sin->sin_addr.s_addr, 0))
1074 break;
1075 ret = 0;
1076 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -07001077 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 inet_del_ifa(in_dev, ifap, 0);
1079 ifa->ifa_mask = sin->sin_addr.s_addr;
1080 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
1081
1082 /* See if current broadcast address matches
1083 * with current netmask, then recalculate
1084 * the broadcast address. Otherwise it's a
1085 * funny address, so don't touch it since
1086 * the user seems to know what (s)he's doing...
1087 */
1088 if ((dev->flags & IFF_BROADCAST) &&
1089 (ifa->ifa_prefixlen < 31) &&
1090 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -05001091 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 ifa->ifa_broadcast = (ifa->ifa_local |
1093 ~sin->sin_addr.s_addr);
1094 }
1095 inet_insert_ifa(ifa);
1096 }
1097 break;
1098 }
1099done:
1100 rtnl_unlock();
1101out:
1102 return ret;
1103rarok:
1104 rtnl_unlock();
1105 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
1106 goto out;
1107}
1108
1109static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
1110{
Herbert Xue5ed6392005-10-03 14:35:55 -07001111 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 struct in_ifaddr *ifa;
1113 struct ifreq ifr;
1114 int done = 0;
1115
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001116 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 goto out;
1118
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001119 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 if (!buf) {
1121 done += sizeof(ifr);
1122 continue;
1123 }
1124 if (len < (int) sizeof(ifr))
1125 break;
1126 memset(&ifr, 0, sizeof(struct ifreq));
1127 if (ifa->ifa_label)
1128 strcpy(ifr.ifr_name, ifa->ifa_label);
1129 else
1130 strcpy(ifr.ifr_name, dev->name);
1131
1132 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
1133 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1134 ifa->ifa_local;
1135
1136 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
1137 done = -EFAULT;
1138 break;
1139 }
1140 buf += sizeof(struct ifreq);
1141 len -= sizeof(struct ifreq);
1142 done += sizeof(struct ifreq);
1143 }
1144out:
1145 return done;
1146}
1147
Al Viroa61ced52006-09-26 21:27:54 -07001148__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149{
Al Viroa61ced52006-09-26 21:27:54 -07001150 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001152 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153
1154 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -07001155 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 if (!in_dev)
1157 goto no_in_dev;
1158
1159 for_primary_ifa(in_dev) {
1160 if (ifa->ifa_scope > scope)
1161 continue;
1162 if (!dst || inet_ifa_match(dst, ifa)) {
1163 addr = ifa->ifa_local;
1164 break;
1165 }
1166 if (!addr)
1167 addr = ifa->ifa_local;
1168 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
1170 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001171 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001172no_in_dev:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173
1174 /* Not loopback addresses on loopback should be preferred
1175 in this case. It is importnat that lo is the first interface
1176 in dev_base list.
1177 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001178 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001179 in_dev = __in_dev_get_rcu(dev);
1180 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 continue;
1182
1183 for_primary_ifa(in_dev) {
1184 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1185 ifa->ifa_scope <= scope) {
1186 addr = ifa->ifa_local;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001187 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 }
1189 } endfor_ifa(in_dev);
1190 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001191out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 return addr;
1194}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001195EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196
Al Viro60cad5d2006-09-26 22:17:09 -07001197static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1198 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199{
1200 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001201 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202
1203 for_ifa(in_dev) {
1204 if (!addr &&
1205 (local == ifa->ifa_local || !local) &&
1206 ifa->ifa_scope <= scope) {
1207 addr = ifa->ifa_local;
1208 if (same)
1209 break;
1210 }
1211 if (!same) {
1212 same = (!local || inet_ifa_match(local, ifa)) &&
1213 (!dst || inet_ifa_match(dst, ifa));
1214 if (same && addr) {
1215 if (local || !dst)
1216 break;
1217 /* Is the selected addr into dst subnet? */
1218 if (inet_ifa_match(addr, ifa))
1219 break;
1220 /* No, then can we use new local src? */
1221 if (ifa->ifa_scope <= scope) {
1222 addr = ifa->ifa_local;
1223 break;
1224 }
1225 /* search for large dst subnet for addr */
1226 same = 0;
1227 }
1228 }
1229 } endfor_ifa(in_dev);
1230
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001231 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232}
1233
1234/*
1235 * Confirm that local IP address exists using wildcards:
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001236 * - in_dev: only on this interface, 0=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 * - dst: only in the same subnet as dst, 0=any dst
1238 * - local: address, 0=autoselect the local address
1239 * - scope: maximum allowed scope value for the local address
1240 */
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001241__be32 inet_confirm_addr(struct in_device *in_dev,
1242 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243{
Al Viro60cad5d2006-09-26 22:17:09 -07001244 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001245 struct net_device *dev;
Denis V. Lunev39a6d062008-01-14 23:06:19 -08001246 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247
Denis V. Lunev39a6d062008-01-14 23:06:19 -08001248 if (scope != RT_SCOPE_LINK)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001249 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001251 net = dev_net(in_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001253 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001254 in_dev = __in_dev_get_rcu(dev);
1255 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 addr = confirm_addr_indev(in_dev, dst, local, scope);
1257 if (addr)
1258 break;
1259 }
1260 }
1261 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262
1263 return addr;
1264}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001265EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266
1267/*
1268 * Device notifier
1269 */
1270
1271int register_inetaddr_notifier(struct notifier_block *nb)
1272{
Alan Sterne041c682006-03-27 01:16:30 -08001273 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001275EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276
1277int unregister_inetaddr_notifier(struct notifier_block *nb)
1278{
Alan Sterne041c682006-03-27 01:16:30 -08001279 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001281EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001283/* Rename ifa_labels for a device name change. Make some effort to preserve
1284 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285*/
1286static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001287{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 struct in_ifaddr *ifa;
1289 int named = 0;
1290
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001291 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1292 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
1294 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001295 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001297 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001298 dot = strchr(old, ':');
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001299 if (dot == NULL) {
1300 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 dot = old;
1302 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001303 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001304 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001305 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001306 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001307skip:
1308 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001309 }
1310}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311
Eric Dumazet40384992012-08-03 21:06:50 +00001312static bool inetdev_valid_mtu(unsigned int mtu)
Breno Leitao06770842008-09-02 17:28:58 -07001313{
1314 return mtu >= 68;
1315}
1316
Ian Campbelld11327ad2011-02-11 07:44:16 +00001317static void inetdev_send_gratuitous_arp(struct net_device *dev,
1318 struct in_device *in_dev)
1319
1320{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001321 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001322
Zoltan Kissb76d0782011-07-24 13:09:30 +00001323 for (ifa = in_dev->ifa_list; ifa;
1324 ifa = ifa->ifa_next) {
1325 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1326 ifa->ifa_local, dev,
1327 ifa->ifa_local, NULL,
1328 dev->dev_addr, NULL);
1329 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001330}
1331
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332/* Called only under RTNL semaphore */
1333
1334static int inetdev_event(struct notifier_block *this, unsigned long event,
1335 void *ptr)
1336{
Jiri Pirko351638e2013-05-28 01:30:21 +00001337 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Eric Dumazet748e2d92012-08-22 21:50:59 +00001338 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339
1340 ASSERT_RTNL();
1341
1342 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001343 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 in_dev = inetdev_init(dev);
Herbert Xub217d612007-07-30 17:04:52 -07001345 if (!in_dev)
1346 return notifier_from_errno(-ENOMEM);
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001347 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001348 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1349 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001350 }
Breno Leitao06770842008-09-02 17:28:58 -07001351 } else if (event == NETDEV_CHANGEMTU) {
1352 /* Re-enabling IP */
1353 if (inetdev_valid_mtu(dev->mtu))
1354 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 }
1356 goto out;
1357 }
1358
1359 switch (event) {
1360 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001361 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001362 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 break;
1364 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001365 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001367 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001368 struct in_ifaddr *ifa = inet_alloc_ifa();
1369
1370 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001371 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 ifa->ifa_local =
1373 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1374 ifa->ifa_prefixlen = 8;
1375 ifa->ifa_mask = inet_make_mask(8);
1376 in_dev_hold(in_dev);
1377 ifa->ifa_dev = in_dev;
1378 ifa->ifa_scope = RT_SCOPE_HOST;
1379 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Jiri Pirko5c766d62013-01-24 09:41:41 +00001380 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1381 INFINITY_LIFE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 inet_insert_ifa(ifa);
1383 }
1384 }
1385 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001386 /* fall through */
1387 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001388 if (!IN_DEV_ARP_NOTIFY(in_dev))
1389 break;
1390 /* fall through */
1391 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001392 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001393 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 break;
1395 case NETDEV_DOWN:
1396 ip_mc_down(in_dev);
1397 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001398 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001399 ip_mc_unmap(in_dev);
1400 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001401 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001402 ip_mc_remap(in_dev);
1403 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001405 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 break;
Breno Leitao06770842008-09-02 17:28:58 -07001407 /* disable IP when MTU is not enough */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 case NETDEV_UNREGISTER:
1409 inetdev_destroy(in_dev);
1410 break;
1411 case NETDEV_CHANGENAME:
1412 /* Do not notify about label change, this event is
1413 * not interesting to applications using netlink.
1414 */
1415 inetdev_changename(dev, in_dev);
1416
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001417 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001418 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 break;
1420 }
1421out:
1422 return NOTIFY_DONE;
1423}
1424
1425static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001426 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427};
1428
Eric Dumazet40384992012-08-03 21:06:50 +00001429static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001430{
1431 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1432 + nla_total_size(4) /* IFA_ADDRESS */
1433 + nla_total_size(4) /* IFA_LOCAL */
1434 + nla_total_size(4) /* IFA_BROADCAST */
Thomas Graf339bf982006-11-10 14:10:15 -08001435 + nla_total_size(IFNAMSIZ); /* IFA_LABEL */
1436}
1437
Jiri Pirko5c766d62013-01-24 09:41:41 +00001438static inline u32 cstamp_delta(unsigned long cstamp)
1439{
1440 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1441}
1442
1443static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1444 unsigned long tstamp, u32 preferred, u32 valid)
1445{
1446 struct ifa_cacheinfo ci;
1447
1448 ci.cstamp = cstamp_delta(cstamp);
1449 ci.tstamp = cstamp_delta(tstamp);
1450 ci.ifa_prefered = preferred;
1451 ci.ifa_valid = valid;
1452
1453 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1454}
1455
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001457 u32 portid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458{
1459 struct ifaddrmsg *ifm;
1460 struct nlmsghdr *nlh;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001461 u32 preferred, valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462
Eric W. Biederman15e47302012-09-07 20:12:54 +00001463 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
Thomas Graf47f68512006-08-04 23:04:36 -07001464 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001465 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001466
1467 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 ifm->ifa_family = AF_INET;
1469 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
Jiri Pirko5c766d62013-01-24 09:41:41 +00001470 ifm->ifa_flags = ifa->ifa_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 ifm->ifa_scope = ifa->ifa_scope;
1472 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473
Jiri Pirko5c766d62013-01-24 09:41:41 +00001474 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1475 preferred = ifa->ifa_preferred_lft;
1476 valid = ifa->ifa_valid_lft;
1477 if (preferred != INFINITY_LIFE_TIME) {
1478 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1479
1480 if (preferred > tval)
1481 preferred -= tval;
1482 else
1483 preferred = 0;
1484 if (valid != INFINITY_LIFE_TIME) {
1485 if (valid > tval)
1486 valid -= tval;
1487 else
1488 valid = 0;
1489 }
1490 }
1491 } else {
1492 preferred = INFINITY_LIFE_TIME;
1493 valid = INFINITY_LIFE_TIME;
1494 }
David S. Millerf3756b72012-04-01 20:39:02 -04001495 if ((ifa->ifa_address &&
1496 nla_put_be32(skb, IFA_ADDRESS, ifa->ifa_address)) ||
1497 (ifa->ifa_local &&
1498 nla_put_be32(skb, IFA_LOCAL, ifa->ifa_local)) ||
1499 (ifa->ifa_broadcast &&
1500 nla_put_be32(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
1501 (ifa->ifa_label[0] &&
Jiri Pirko5c766d62013-01-24 09:41:41 +00001502 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
1503 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1504 preferred, valid))
David S. Millerf3756b72012-04-01 20:39:02 -04001505 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001506
1507 return nlmsg_end(skb, nlh);
1508
1509nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001510 nlmsg_cancel(skb, nlh);
1511 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512}
1513
1514static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1515{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001516 struct net *net = sock_net(skb->sk);
Eric Dumazeteec4df92009-11-12 07:44:25 +00001517 int h, s_h;
1518 int idx, s_idx;
1519 int ip_idx, s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 struct net_device *dev;
1521 struct in_device *in_dev;
1522 struct in_ifaddr *ifa;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001523 struct hlist_head *head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524
Eric Dumazeteec4df92009-11-12 07:44:25 +00001525 s_h = cb->args[0];
1526 s_idx = idx = cb->args[1];
1527 s_ip_idx = ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528
Eric Dumazeteec4df92009-11-12 07:44:25 +00001529 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1530 idx = 0;
1531 head = &net->dev_index_head[h];
1532 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001533 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1534 net->dev_base_seq;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001535 hlist_for_each_entry_rcu(dev, head, index_hlist) {
Eric Dumazeteec4df92009-11-12 07:44:25 +00001536 if (idx < s_idx)
1537 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001538 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001539 s_ip_idx = 0;
1540 in_dev = __in_dev_get_rcu(dev);
1541 if (!in_dev)
1542 goto cont;
1543
1544 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1545 ifa = ifa->ifa_next, ip_idx++) {
1546 if (ip_idx < s_ip_idx)
1547 continue;
1548 if (inet_fill_ifaddr(skb, ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001549 NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 cb->nlh->nlmsg_seq,
Eric Dumazeteec4df92009-11-12 07:44:25 +00001551 RTM_NEWADDR, NLM_F_MULTI) <= 0) {
1552 rcu_read_unlock();
1553 goto done;
1554 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001555 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Eric Dumazeteec4df92009-11-12 07:44:25 +00001556 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001557cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001558 idx++;
1559 }
1560 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 }
1562
1563done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001564 cb->args[0] = h;
1565 cb->args[1] = idx;
1566 cb->args[2] = ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567
1568 return skb->len;
1569}
1570
Jianjun Kong539afed2008-11-03 02:48:48 -08001571static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001572 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573{
Thomas Graf47f68512006-08-04 23:04:36 -07001574 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001575 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1576 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001577 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001579 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001580 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Thomas Graf47f68512006-08-04 23:04:36 -07001581 if (skb == NULL)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001582 goto errout;
1583
Eric W. Biederman15e47302012-09-07 20:12:54 +00001584 err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001585 if (err < 0) {
1586 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1587 WARN_ON(err == -EMSGSIZE);
1588 kfree_skb(skb);
1589 goto errout;
1590 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001591 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001592 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001593errout:
1594 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001595 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596}
1597
Thomas Graf9f0f7272010-11-16 04:32:48 +00001598static size_t inet_get_link_af_size(const struct net_device *dev)
1599{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001600 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001601
1602 if (!in_dev)
1603 return 0;
1604
1605 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1606}
1607
1608static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
1609{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001610 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001611 struct nlattr *nla;
1612 int i;
1613
1614 if (!in_dev)
1615 return -ENODATA;
1616
1617 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
1618 if (nla == NULL)
1619 return -EMSGSIZE;
1620
1621 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1622 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1623
1624 return 0;
1625}
1626
1627static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1628 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1629};
1630
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001631static int inet_validate_link_af(const struct net_device *dev,
1632 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001633{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001634 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1635 int err, rem;
1636
Eric Dumazetf7fce742010-12-01 06:03:06 +00001637 if (dev && !__in_dev_get_rtnl(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001638 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001639
1640 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy);
1641 if (err < 0)
1642 return err;
1643
1644 if (tb[IFLA_INET_CONF]) {
1645 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1646 int cfgid = nla_type(a);
1647
1648 if (nla_len(a) < 4)
1649 return -EINVAL;
1650
1651 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1652 return -EINVAL;
1653 }
1654 }
1655
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001656 return 0;
1657}
1658
1659static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1660{
Eric Dumazetf7fce742010-12-01 06:03:06 +00001661 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001662 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1663 int rem;
1664
1665 if (!in_dev)
1666 return -EAFNOSUPPORT;
1667
1668 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL) < 0)
1669 BUG();
1670
Thomas Graf9f0f7272010-11-16 04:32:48 +00001671 if (tb[IFLA_INET_CONF]) {
1672 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1673 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1674 }
1675
1676 return 0;
1677}
1678
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001679static int inet_netconf_msgsize_devconf(int type)
1680{
1681 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1682 + nla_total_size(4); /* NETCONFA_IFINDEX */
1683
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001684 /* type -1 is used for ALL */
1685 if (type == -1 || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001686 size += nla_total_size(4);
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001687 if (type == -1 || type == NETCONFA_RP_FILTER)
1688 size += nla_total_size(4);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001689 if (type == -1 || type == NETCONFA_MC_FORWARDING)
1690 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001691
1692 return size;
1693}
1694
1695static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1696 struct ipv4_devconf *devconf, u32 portid,
1697 u32 seq, int event, unsigned int flags,
1698 int type)
1699{
1700 struct nlmsghdr *nlh;
1701 struct netconfmsg *ncm;
1702
1703 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1704 flags);
1705 if (nlh == NULL)
1706 return -EMSGSIZE;
1707
1708 ncm = nlmsg_data(nlh);
1709 ncm->ncm_family = AF_INET;
1710
1711 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1712 goto nla_put_failure;
1713
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001714 /* type -1 is used for ALL */
1715 if ((type == -1 || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001716 nla_put_s32(skb, NETCONFA_FORWARDING,
1717 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1718 goto nla_put_failure;
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001719 if ((type == -1 || type == NETCONFA_RP_FILTER) &&
1720 nla_put_s32(skb, NETCONFA_RP_FILTER,
1721 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
1722 goto nla_put_failure;
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001723 if ((type == -1 || type == NETCONFA_MC_FORWARDING) &&
1724 nla_put_s32(skb, NETCONFA_MC_FORWARDING,
1725 IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
1726 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001727
1728 return nlmsg_end(skb, nlh);
1729
1730nla_put_failure:
1731 nlmsg_cancel(skb, nlh);
1732 return -EMSGSIZE;
1733}
1734
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001735void inet_netconf_notify_devconf(struct net *net, int type, int ifindex,
1736 struct ipv4_devconf *devconf)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001737{
1738 struct sk_buff *skb;
1739 int err = -ENOBUFS;
1740
1741 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_ATOMIC);
1742 if (skb == NULL)
1743 goto errout;
1744
1745 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
1746 RTM_NEWNETCONF, 0, type);
1747 if (err < 0) {
1748 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1749 WARN_ON(err == -EMSGSIZE);
1750 kfree_skb(skb);
1751 goto errout;
1752 }
1753 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_ATOMIC);
1754 return;
1755errout:
1756 if (err < 0)
1757 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
1758}
1759
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001760static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
1761 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
1762 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001763 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001764};
1765
1766static int inet_netconf_get_devconf(struct sk_buff *in_skb,
Thomas Graf661d2962013-03-21 07:45:29 +00001767 struct nlmsghdr *nlh)
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001768{
1769 struct net *net = sock_net(in_skb->sk);
1770 struct nlattr *tb[NETCONFA_MAX+1];
1771 struct netconfmsg *ncm;
1772 struct sk_buff *skb;
1773 struct ipv4_devconf *devconf;
1774 struct in_device *in_dev;
1775 struct net_device *dev;
1776 int ifindex;
1777 int err;
1778
1779 err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
1780 devconf_ipv4_policy);
1781 if (err < 0)
1782 goto errout;
1783
1784 err = EINVAL;
1785 if (!tb[NETCONFA_IFINDEX])
1786 goto errout;
1787
1788 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
1789 switch (ifindex) {
1790 case NETCONFA_IFINDEX_ALL:
1791 devconf = net->ipv4.devconf_all;
1792 break;
1793 case NETCONFA_IFINDEX_DEFAULT:
1794 devconf = net->ipv4.devconf_dflt;
1795 break;
1796 default:
1797 dev = __dev_get_by_index(net, ifindex);
1798 if (dev == NULL)
1799 goto errout;
1800 in_dev = __in_dev_get_rtnl(dev);
1801 if (in_dev == NULL)
1802 goto errout;
1803 devconf = &in_dev->cnf;
1804 break;
1805 }
1806
1807 err = -ENOBUFS;
1808 skb = nlmsg_new(inet_netconf_msgsize_devconf(-1), GFP_ATOMIC);
1809 if (skb == NULL)
1810 goto errout;
1811
1812 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
1813 NETLINK_CB(in_skb).portid,
1814 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
1815 -1);
1816 if (err < 0) {
1817 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1818 WARN_ON(err == -EMSGSIZE);
1819 kfree_skb(skb);
1820 goto errout;
1821 }
1822 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
1823errout:
1824 return err;
1825}
1826
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001827static int inet_netconf_dump_devconf(struct sk_buff *skb,
1828 struct netlink_callback *cb)
1829{
1830 struct net *net = sock_net(skb->sk);
1831 int h, s_h;
1832 int idx, s_idx;
1833 struct net_device *dev;
1834 struct in_device *in_dev;
1835 struct hlist_head *head;
1836
1837 s_h = cb->args[0];
1838 s_idx = idx = cb->args[1];
1839
1840 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1841 idx = 0;
1842 head = &net->dev_index_head[h];
1843 rcu_read_lock();
Nicolas Dichtel04652772013-03-22 06:28:42 +00001844 cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1845 net->dev_base_seq;
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001846 hlist_for_each_entry_rcu(dev, head, index_hlist) {
1847 if (idx < s_idx)
1848 goto cont;
1849 in_dev = __in_dev_get_rcu(dev);
1850 if (!in_dev)
1851 goto cont;
1852
1853 if (inet_netconf_fill_devconf(skb, dev->ifindex,
1854 &in_dev->cnf,
1855 NETLINK_CB(cb->skb).portid,
1856 cb->nlh->nlmsg_seq,
1857 RTM_NEWNETCONF,
1858 NLM_F_MULTI,
1859 -1) <= 0) {
1860 rcu_read_unlock();
1861 goto done;
1862 }
Nicolas Dichtel04652772013-03-22 06:28:42 +00001863 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Nicolas Dichtel7a674202013-03-05 23:42:06 +00001864cont:
1865 idx++;
1866 }
1867 rcu_read_unlock();
1868 }
1869 if (h == NETDEV_HASHENTRIES) {
1870 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
1871 net->ipv4.devconf_all,
1872 NETLINK_CB(cb->skb).portid,
1873 cb->nlh->nlmsg_seq,
1874 RTM_NEWNETCONF, NLM_F_MULTI,
1875 -1) <= 0)
1876 goto done;
1877 else
1878 h++;
1879 }
1880 if (h == NETDEV_HASHENTRIES + 1) {
1881 if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
1882 net->ipv4.devconf_dflt,
1883 NETLINK_CB(cb->skb).portid,
1884 cb->nlh->nlmsg_seq,
1885 RTM_NEWNETCONF, NLM_F_MULTI,
1886 -1) <= 0)
1887 goto done;
1888 else
1889 h++;
1890 }
1891done:
1892 cb->args[0] = h;
1893 cb->args[1] = idx;
1894
1895 return skb->len;
1896}
1897
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898#ifdef CONFIG_SYSCTL
1899
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001900static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07001901{
1902 struct net_device *dev;
1903
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001904 rcu_read_lock();
1905 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07001906 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001907
Herbert Xu31be3082007-06-04 23:35:37 -07001908 in_dev = __in_dev_get_rcu(dev);
1909 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001910 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07001911 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001912 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07001913}
1914
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001915/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001916static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001917{
1918 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08001919 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001920
Pavel Emelyanov586f1212007-12-16 13:32:48 -08001921 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001922 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001923 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1924 NETCONFA_IFINDEX_ALL,
1925 net->ipv4.devconf_all);
1926 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1927 NETCONFA_IFINDEX_DEFAULT,
1928 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001929
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001930 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001931 struct in_device *in_dev;
Ben Hutchings0187bdf2008-06-19 16:15:47 -07001932 if (on)
1933 dev_disable_lro(dev);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001934 rcu_read_lock();
1935 in_dev = __in_dev_get_rcu(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001936 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001937 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001938 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1939 dev->ifindex, &in_dev->cnf);
1940 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001941 rcu_read_unlock();
1942 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001943}
1944
Joe Perchesfe2c6332013-06-11 23:04:25 -07001945static int devinet_conf_proc(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001946 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07001947 size_t *lenp, loff_t *ppos)
1948{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00001949 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001950 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00001951 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07001952
1953 if (write) {
1954 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001955 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07001956 int i = (int *)ctl->data - cnf->data;
1957
1958 set_bit(i, cnf->state);
1959
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001960 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001961 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00001962 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
1963 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00001964 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00001965 rt_cache_flush(net);
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001966 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
1967 new_value != old_value) {
1968 int ifindex;
1969
1970 if (cnf == net->ipv4.devconf_dflt)
1971 ifindex = NETCONFA_IFINDEX_DEFAULT;
1972 else if (cnf == net->ipv4.devconf_all)
1973 ifindex = NETCONFA_IFINDEX_ALL;
1974 else {
1975 struct in_device *idev =
1976 container_of(cnf, struct in_device,
1977 cnf);
1978 ifindex = idev->dev->ifindex;
1979 }
1980 inet_netconf_notify_devconf(net, NETCONFA_RP_FILTER,
1981 ifindex, cnf);
1982 }
Herbert Xu31be3082007-06-04 23:35:37 -07001983 }
1984
1985 return ret;
1986}
1987
Joe Perchesfe2c6332013-06-11 23:04:25 -07001988static int devinet_sysctl_forward(struct ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001989 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 size_t *lenp, loff_t *ppos)
1991{
1992 int *valp = ctl->data;
1993 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00001994 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001995 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996
1997 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001998 struct net *net = ctl->extra2;
1999
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002000 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00002001 if (!rtnl_trylock()) {
2002 /* Restore the original values before restarting */
2003 *valp = val;
2004 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00002005 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00002006 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002007 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
2008 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002009 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002010 struct ipv4_devconf *cnf = ctl->extra1;
2011 struct in_device *idev =
2012 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002013 if (*valp)
2014 dev_disable_lro(idev->dev);
2015 inet_netconf_notify_devconf(net,
2016 NETCONFA_FORWARDING,
2017 idev->dev->ifindex,
2018 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07002019 }
2020 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002021 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00002022 } else
2023 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
2024 NETCONFA_IFINDEX_DEFAULT,
2025 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 }
2027
2028 return ret;
2029}
2030
Joe Perchesfe2c6332013-06-11 23:04:25 -07002031static int ipv4_doint_and_flush(struct ctl_table *ctl, int write,
David S. Miller323e1262010-12-12 21:55:08 -08002032 void __user *buffer,
2033 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034{
2035 int *valp = ctl->data;
2036 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002037 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07002038 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039
2040 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00002041 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042
2043 return ret;
2044}
2045
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002046#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07002047 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07002048 .procname = name, \
2049 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00002050 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002051 .maxlen = sizeof(int), \
2052 .mode = mval, \
2053 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07002054 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07002055 }
2056
2057#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002058 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002059
2060#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002061 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002062
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002063#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
2064 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07002065
2066#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002067 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07002068
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069static struct devinet_sysctl_table {
2070 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00002071 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072} devinet_sysctl = {
2073 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07002074 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002075 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07002076 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
2077
2078 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
2079 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
2080 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
2081 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
2082 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
2083 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
2084 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00002085 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08002086 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002087 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
2088 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
2089 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
2090 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
2091 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
2092 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
2093 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
2094 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
2095 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08002096 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00002097 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
Herbert Xu42f811b2007-06-04 23:34:44 -07002098
2099 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2100 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
2101 DEVINET_SYSCTL_FLUSHING_ENTRY(FORCE_IGMP_VERSION,
2102 "force_igmp_version"),
2103 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
2104 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00002105 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
2106 "route_localnet"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108};
2109
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002110static int __devinet_sysctl_register(struct net *net, char *dev_name,
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002111 struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112{
2113 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002114 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002115 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11002116
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002117 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002119 goto out;
2120
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
2122 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07002123 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002124 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 }
2126
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002127 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002129 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002131 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132
2133 p->sysctl = t;
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002134 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002136free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11002138out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08002139 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140}
2141
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002142static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
2143{
2144 struct devinet_sysctl_table *t = cnf->sysctl;
2145
2146 if (t == NULL)
2147 return;
2148
2149 cnf->sysctl = NULL;
Lucian Adrian Grijincuff538812011-05-01 01:44:01 +00002150 unregister_net_sysctl_table(t->sysctl_header);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002151 kfree(t);
2152}
2153
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002154static void devinet_sysctl_register(struct in_device *idev)
2155{
Eric W. Biederman54716e32010-02-14 03:27:03 +00002156 neigh_sysctl_register(idev->dev, idev->arp_parms, "ipv4", NULL);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002157 __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002158 &idev->cnf);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11002159}
2160
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002161static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162{
Pavel Emelyanov51602b22007-12-11 02:17:40 -08002163 __devinet_sysctl_unregister(&idev->cnf);
2164 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002167static struct ctl_table ctl_forward_entry[] = {
2168 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002169 .procname = "ip_forward",
2170 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00002171 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002172 .maxlen = sizeof(int),
2173 .mode = 0644,
2174 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002175 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08002176 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002177 },
2178 { },
2179};
Eric Dumazet2a75de02008-01-05 23:08:49 -08002180#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08002181
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002182static __net_init int devinet_init_net(struct net *net)
2183{
2184 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002185 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002186#ifdef CONFIG_SYSCTL
2187 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002188 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002189#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002190
2191 err = -ENOMEM;
2192 all = &ipv4_devconf;
2193 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002194
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002195 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002196 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
2197 if (all == NULL)
2198 goto err_alloc_all;
2199
2200 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
2201 if (dflt == NULL)
2202 goto err_alloc_dflt;
2203
Eric Dumazet2a75de02008-01-05 23:08:49 -08002204#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002205 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
2206 if (tbl == NULL)
2207 goto err_alloc_ctl;
2208
Eric W. Biederman02291682010-02-14 03:25:51 +00002209 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002210 tbl[0].extra1 = all;
2211 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002212#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002213 }
2214
2215#ifdef CONFIG_SYSCTL
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002216 err = __devinet_sysctl_register(net, "all", all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002217 if (err < 0)
2218 goto err_reg_all;
2219
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002220 err = __devinet_sysctl_register(net, "default", dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002221 if (err < 0)
2222 goto err_reg_dflt;
2223
2224 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00002225 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002226 if (forw_hdr == NULL)
2227 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08002228 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002229#endif
2230
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002231 net->ipv4.devconf_all = all;
2232 net->ipv4.devconf_dflt = dflt;
2233 return 0;
2234
2235#ifdef CONFIG_SYSCTL
2236err_reg_ctl:
2237 __devinet_sysctl_unregister(dflt);
2238err_reg_dflt:
2239 __devinet_sysctl_unregister(all);
2240err_reg_all:
2241 if (tbl != ctl_forward_entry)
2242 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002243err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08002244#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002245 if (dflt != &ipv4_devconf_dflt)
2246 kfree(dflt);
2247err_alloc_dflt:
2248 if (all != &ipv4_devconf)
2249 kfree(all);
2250err_alloc_all:
2251 return err;
2252}
2253
2254static __net_exit void devinet_exit_net(struct net *net)
2255{
Eric Dumazet2a75de02008-01-05 23:08:49 -08002256#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002257 struct ctl_table *tbl;
2258
2259 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002260 unregister_net_sysctl_table(net->ipv4.forw_hdr);
2261 __devinet_sysctl_unregister(net->ipv4.devconf_dflt);
2262 __devinet_sysctl_unregister(net->ipv4.devconf_all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002263 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08002264#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002265 kfree(net->ipv4.devconf_dflt);
2266 kfree(net->ipv4.devconf_all);
2267}
2268
2269static __net_initdata struct pernet_operations devinet_ops = {
2270 .init = devinet_init_net,
2271 .exit = devinet_exit_net,
2272};
2273
Thomas Graf9f0f7272010-11-16 04:32:48 +00002274static struct rtnl_af_ops inet_af_ops = {
2275 .family = AF_INET,
2276 .fill_link_af = inet_fill_link_af,
2277 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00002278 .validate_link_af = inet_validate_link_af,
2279 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00002280};
2281
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282void __init devinet_init(void)
2283{
David S. Millerfd23c3b2011-02-18 12:42:28 -08002284 int i;
2285
2286 for (i = 0; i < IN4_ADDR_HSIZE; i++)
2287 INIT_HLIST_HEAD(&inet_addr_lst[i]);
2288
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08002289 register_pernet_subsys(&devinet_ops);
2290
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 register_gifconf(PF_INET, inet_gifconf);
2292 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07002293
Jiri Pirko5c766d62013-01-24 09:41:41 +00002294 schedule_delayed_work(&check_lifetime_work, 0);
2295
Thomas Graf9f0f7272010-11-16 04:32:48 +00002296 rtnl_af_register(&inet_af_ops);
2297
Greg Rosec7ac8672011-06-10 01:27:09 +00002298 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL);
2299 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, NULL);
2300 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, NULL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002301 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
Nicolas Dichtel7a674202013-03-05 23:42:06 +00002302 inet_netconf_dump_devconf, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303}
2304