blob: 259622a5e690a1012443a3739ae4a457f6a1368b [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
David S. Miller406b6f92011-03-22 21:56:23 -070067#include "fib_lookup.h"
68
Adrian Bunk0027ba82008-01-31 17:17:31 -080069static struct ipv4_devconf ipv4_devconf = {
Herbert Xu42f811b2007-06-04 23:34:44 -070070 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000071 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
72 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
73 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
74 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
Herbert Xu42f811b2007-06-04 23:34:44 -070075 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070076};
77
78static struct ipv4_devconf ipv4_devconf_dflt = {
Herbert Xu42f811b2007-06-04 23:34:44 -070079 .data = {
Eric W. Biederman02291682010-02-14 03:25:51 +000080 [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
81 [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
82 [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
83 [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
84 [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
Herbert Xu42f811b2007-06-04 23:34:44 -070085 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070086};
87
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -080088#define IPV4_DEVCONF_DFLT(net, attr) \
89 IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr)
Herbert Xu42f811b2007-06-04 23:34:44 -070090
Patrick McHardyef7c79e2007-06-05 12:38:30 -070091static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
Thomas Graf5c753972006-08-04 23:03:53 -070092 [IFA_LOCAL] = { .type = NLA_U32 },
93 [IFA_ADDRESS] = { .type = NLA_U32 },
94 [IFA_BROADCAST] = { .type = NLA_U32 },
Thomas Graf5176f912006-08-26 20:13:18 -070095 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
Thomas Graf5c753972006-08-04 23:03:53 -070096};
97
Eric Dumazet40384992012-08-03 21:06:50 +000098#define IN4_ADDR_HSIZE_SHIFT 8
99#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT)
100
David S. Millerfd23c3b2011-02-18 12:42:28 -0800101static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
102static DEFINE_SPINLOCK(inet_addr_hash_lock);
103
Eric Dumazet40384992012-08-03 21:06:50 +0000104static u32 inet_addr_hash(struct net *net, __be32 addr)
David S. Millerfd23c3b2011-02-18 12:42:28 -0800105{
Eric Dumazet40384992012-08-03 21:06:50 +0000106 u32 val = (__force u32) addr ^ net_hash_mix(net);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800107
Eric Dumazet40384992012-08-03 21:06:50 +0000108 return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800109}
110
111static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
112{
Eric Dumazet40384992012-08-03 21:06:50 +0000113 u32 hash = inet_addr_hash(net, ifa->ifa_local);
David S. Millerfd23c3b2011-02-18 12:42:28 -0800114
115 spin_lock(&inet_addr_hash_lock);
116 hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
117 spin_unlock(&inet_addr_hash_lock);
118}
119
120static void inet_hash_remove(struct in_ifaddr *ifa)
121{
122 spin_lock(&inet_addr_hash_lock);
123 hlist_del_init_rcu(&ifa->hash);
124 spin_unlock(&inet_addr_hash_lock);
125}
126
David S. Miller9435eb12011-02-18 12:43:09 -0800127/**
128 * __ip_dev_find - find the first device with a given source address.
129 * @net: the net namespace
130 * @addr: the source address
131 * @devref: if true, take a reference on the found device
132 *
133 * If a caller uses devref=false, it should be protected by RCU, or RTNL
134 */
135struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
136{
Eric Dumazet40384992012-08-03 21:06:50 +0000137 u32 hash = inet_addr_hash(net, addr);
David S. Miller9435eb12011-02-18 12:43:09 -0800138 struct net_device *result = NULL;
139 struct in_ifaddr *ifa;
140 struct hlist_node *node;
141
142 rcu_read_lock();
143 hlist_for_each_entry_rcu(ifa, node, &inet_addr_lst[hash], hash) {
David S. Millere0660082011-03-03 11:24:19 -0800144 if (ifa->ifa_local == addr) {
Eric Dumazet40384992012-08-03 21:06:50 +0000145 struct net_device *dev = ifa->ifa_dev->dev;
146
147 if (!net_eq(dev_net(dev), net))
148 continue;
David S. Miller9435eb12011-02-18 12:43:09 -0800149 result = dev;
150 break;
151 }
152 }
David S. Miller406b6f92011-03-22 21:56:23 -0700153 if (!result) {
154 struct flowi4 fl4 = { .daddr = addr };
155 struct fib_result res = { 0 };
156 struct fib_table *local;
157
158 /* Fallback to FIB local table so that communication
159 * over loopback subnets work.
160 */
161 local = fib_get_table(net, RT_TABLE_LOCAL);
162 if (local &&
163 !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
164 res.type == RTN_LOCAL)
165 result = FIB_RES_DEV(res);
166 }
David S. Miller9435eb12011-02-18 12:43:09 -0800167 if (result && devref)
168 dev_hold(result);
169 rcu_read_unlock();
170 return result;
171}
172EXPORT_SYMBOL(__ip_dev_find);
173
Thomas Grafd6062cb2006-08-15 00:33:59 -0700174static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175
Alan Sterne041c682006-03-27 01:16:30 -0800176static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
178 int destroy);
179#ifdef CONFIG_SYSCTL
Pavel Emelyanov66f27a52007-12-02 00:55:54 +1100180static void devinet_sysctl_register(struct in_device *idev);
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800181static void devinet_sysctl_unregister(struct in_device *idev);
182#else
Eric Dumazet40384992012-08-03 21:06:50 +0000183static void devinet_sysctl_register(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800184{
185}
Eric Dumazet40384992012-08-03 21:06:50 +0000186static void devinet_sysctl_unregister(struct in_device *idev)
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800187{
188}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189#endif
190
191/* Locks all the inet devices. */
192
193static struct in_ifaddr *inet_alloc_ifa(void)
194{
Alexey Dobriyan93adcc82008-10-28 13:25:09 -0700195 return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196}
197
198static void inet_rcu_free_ifa(struct rcu_head *head)
199{
200 struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
201 if (ifa->ifa_dev)
202 in_dev_put(ifa->ifa_dev);
203 kfree(ifa);
204}
205
Eric Dumazet40384992012-08-03 21:06:50 +0000206static void inet_free_ifa(struct in_ifaddr *ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207{
208 call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
209}
210
211void in_dev_finish_destroy(struct in_device *idev)
212{
213 struct net_device *dev = idev->dev;
214
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700215 WARN_ON(idev->ifa_list);
216 WARN_ON(idev->mc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217#ifdef NET_REFCNT_DEBUG
Joe Perches91df42b2012-05-15 14:11:54 +0000218 pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219#endif
220 dev_put(dev);
221 if (!idev->dead)
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800222 pr_err("Freeing alive in_device %p\n", idev);
223 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 kfree(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800226EXPORT_SYMBOL(in_dev_finish_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
Herbert Xu71e27da2007-06-04 23:36:06 -0700228static struct in_device *inetdev_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229{
230 struct in_device *in_dev;
231
232 ASSERT_RTNL();
233
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700234 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 if (!in_dev)
236 goto out;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900237 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -0800238 sizeof(in_dev->cnf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 in_dev->cnf.sysctl = NULL;
240 in_dev->dev = dev;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800241 in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
242 if (!in_dev->arp_parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 goto out_kfree;
Ben Hutchings0187bdf2008-06-19 16:15:47 -0700244 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
245 dev_disable_lro(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 /* Reference in_dev->dev */
247 dev_hold(dev);
David L Stevens30c4cf52007-01-04 12:31:14 -0800248 /* Account for reference dev->ip_ptr (below) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 in_dev_hold(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
Pavel Emelyanov66f27a52007-12-02 00:55:54 +1100251 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 ip_mc_init_dev(in_dev);
253 if (dev->flags & IFF_UP)
254 ip_mc_up(in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800255
David L Stevens30c4cf52007-01-04 12:31:14 -0800256 /* we can receive as soon as ip_ptr is set -- do this last */
Eric Dumazetcf778b02012-01-12 04:41:32 +0000257 rcu_assign_pointer(dev->ip_ptr, in_dev);
Jarek Poplawski483479e2007-01-09 14:38:31 -0800258out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 return in_dev;
260out_kfree:
261 kfree(in_dev);
262 in_dev = NULL;
263 goto out;
264}
265
266static void in_dev_rcu_put(struct rcu_head *head)
267{
268 struct in_device *idev = container_of(head, struct in_device, rcu_head);
269 in_dev_put(idev);
270}
271
272static void inetdev_destroy(struct in_device *in_dev)
273{
274 struct in_ifaddr *ifa;
275 struct net_device *dev;
276
277 ASSERT_RTNL();
278
279 dev = in_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
281 in_dev->dead = 1;
282
283 ip_mc_destroy_dev(in_dev);
284
285 while ((ifa = in_dev->ifa_list) != NULL) {
286 inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
287 inet_free_ifa(ifa);
288 }
289
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000290 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
Pavel Emelyanov51602b22007-12-11 02:17:40 -0800292 devinet_sysctl_unregister(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 neigh_parms_release(&arp_tbl, in_dev->arp_parms);
294 arp_ifdown(dev);
295
296 call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
297}
298
Al Viroff428d72006-09-26 22:13:35 -0700299int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300{
301 rcu_read_lock();
302 for_primary_ifa(in_dev) {
303 if (inet_ifa_match(a, ifa)) {
304 if (!b || inet_ifa_match(b, ifa)) {
305 rcu_read_unlock();
306 return 1;
307 }
308 }
309 } endfor_ifa(in_dev);
310 rcu_read_unlock();
311 return 0;
312}
313
Thomas Grafd6062cb2006-08-15 00:33:59 -0700314static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000315 int destroy, struct nlmsghdr *nlh, u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316{
Harald Welte8f937c62005-05-29 20:23:46 -0700317 struct in_ifaddr *promote = NULL;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800318 struct in_ifaddr *ifa, *ifa1 = *ifap;
319 struct in_ifaddr *last_prim = in_dev->ifa_list;
320 struct in_ifaddr *prev_prom = NULL;
321 int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
323 ASSERT_RTNL();
324
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900325 /* 1. Deleting primary ifaddr forces deletion all secondaries
Harald Welte8f937c62005-05-29 20:23:46 -0700326 * unless alias promotion is set
327 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 struct in_ifaddr **ifap1 = &ifa1->ifa_next;
331
332 while ((ifa = *ifap1) != NULL) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900333 if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800334 ifa1->ifa_scope <= ifa->ifa_scope)
335 last_prim = ifa;
336
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
338 ifa1->ifa_mask != ifa->ifa_mask ||
339 !inet_ifa_match(ifa1->ifa_address, ifa)) {
340 ifap1 = &ifa->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800341 prev_prom = ifa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 continue;
343 }
344
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800345 if (!do_promote) {
David S. Millerfd23c3b2011-02-18 12:42:28 -0800346 inet_hash_remove(ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700347 *ifap1 = ifa->ifa_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
Eric W. Biederman15e47302012-09-07 20:12:54 +0000349 rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800350 blocking_notifier_call_chain(&inetaddr_chain,
351 NETDEV_DOWN, ifa);
Harald Welte8f937c62005-05-29 20:23:46 -0700352 inet_free_ifa(ifa);
353 } else {
354 promote = ifa;
355 break;
356 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 }
358 }
359
Julian Anastasov2d230e22011-03-19 12:13:52 +0000360 /* On promotion all secondaries from subnet are changing
361 * the primary IP, we must remove all their routes silently
362 * and later to add them back with new prefsrc. Do this
363 * while all addresses are on the device list.
364 */
365 for (ifa = promote; ifa; ifa = ifa->ifa_next) {
366 if (ifa1->ifa_mask == ifa->ifa_mask &&
367 inet_ifa_match(ifa1->ifa_address, ifa))
368 fib_del_ifaddr(ifa, ifa1);
369 }
370
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 /* 2. Unlink it */
372
373 *ifap = ifa1->ifa_next;
David S. Millerfd23c3b2011-02-18 12:42:28 -0800374 inet_hash_remove(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 /* 3. Announce address deletion */
377
378 /* Send message first, then call notifier.
379 At first sight, FIB update triggered by notifier
380 will refer to already deleted ifaddr, that could confuse
381 netlink listeners. It is not true: look, gated sees
382 that route deleted and if it still thinks that ifaddr
383 is valid, it will try to restore deleted routes... Grr.
384 So that, this order is correct.
385 */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000386 rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800387 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800388
389 if (promote) {
Julian Anastasov04024b92011-03-19 12:13:54 +0000390 struct in_ifaddr *next_sec = promote->ifa_next;
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800391
392 if (prev_prom) {
393 prev_prom->ifa_next = promote->ifa_next;
394 promote->ifa_next = last_prim->ifa_next;
395 last_prim->ifa_next = promote;
396 }
397
398 promote->ifa_flags &= ~IFA_F_SECONDARY;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000399 rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800400 blocking_notifier_call_chain(&inetaddr_chain,
401 NETDEV_UP, promote);
Julian Anastasov04024b92011-03-19 12:13:54 +0000402 for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
Jamal Hadi Salim0ff60a42005-11-22 14:47:37 -0800403 if (ifa1->ifa_mask != ifa->ifa_mask ||
404 !inet_ifa_match(ifa1->ifa_address, ifa))
405 continue;
406 fib_add_ifaddr(ifa);
407 }
408
409 }
Herbert Xu63630972007-06-07 18:35:38 -0700410 if (destroy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 inet_free_ifa(ifa1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412}
413
Thomas Grafd6062cb2006-08-15 00:33:59 -0700414static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
415 int destroy)
416{
417 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
418}
419
420static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000421 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422{
423 struct in_device *in_dev = ifa->ifa_dev;
424 struct in_ifaddr *ifa1, **ifap, **last_primary;
425
426 ASSERT_RTNL();
427
428 if (!ifa->ifa_local) {
429 inet_free_ifa(ifa);
430 return 0;
431 }
432
433 ifa->ifa_flags &= ~IFA_F_SECONDARY;
434 last_primary = &in_dev->ifa_list;
435
436 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
437 ifap = &ifa1->ifa_next) {
438 if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
439 ifa->ifa_scope <= ifa1->ifa_scope)
440 last_primary = &ifa1->ifa_next;
441 if (ifa1->ifa_mask == ifa->ifa_mask &&
442 inet_ifa_match(ifa1->ifa_address, ifa)) {
443 if (ifa1->ifa_local == ifa->ifa_local) {
444 inet_free_ifa(ifa);
445 return -EEXIST;
446 }
447 if (ifa1->ifa_scope != ifa->ifa_scope) {
448 inet_free_ifa(ifa);
449 return -EINVAL;
450 }
451 ifa->ifa_flags |= IFA_F_SECONDARY;
452 }
453 }
454
455 if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
456 net_srandom(ifa->ifa_local);
457 ifap = last_primary;
458 }
459
460 ifa->ifa_next = *ifap;
461 *ifap = ifa;
462
David S. Millerfd23c3b2011-02-18 12:42:28 -0800463 inet_hash_insert(dev_net(in_dev->dev), ifa);
464
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 /* Send message first, then call notifier.
466 Notifier will trigger FIB update, so that
467 listeners of netlink will know about new ifaddr */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000468 rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
Alan Sterne041c682006-03-27 01:16:30 -0800469 blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470
471 return 0;
472}
473
Thomas Grafd6062cb2006-08-15 00:33:59 -0700474static int inet_insert_ifa(struct in_ifaddr *ifa)
475{
476 return __inet_insert_ifa(ifa, NULL, 0);
477}
478
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
480{
Herbert Xue5ed6392005-10-03 14:35:55 -0700481 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
483 ASSERT_RTNL();
484
485 if (!in_dev) {
Herbert Xu71e27da2007-06-04 23:36:06 -0700486 inet_free_ifa(ifa);
487 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 }
Herbert Xu71e27da2007-06-04 23:36:06 -0700489 ipv4_devconf_setall(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 if (ifa->ifa_dev != in_dev) {
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700491 WARN_ON(ifa->ifa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 in_dev_hold(in_dev);
493 ifa->ifa_dev = in_dev;
494 }
Joe Perchesf97c1e02007-12-16 13:45:43 -0800495 if (ipv4_is_loopback(ifa->ifa_local))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 ifa->ifa_scope = RT_SCOPE_HOST;
497 return inet_insert_ifa(ifa);
498}
499
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000500/* Caller must hold RCU or RTNL :
501 * We dont take a reference on found in_device
502 */
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800503struct in_device *inetdev_by_index(struct net *net, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504{
505 struct net_device *dev;
506 struct in_device *in_dev = NULL;
Eric Dumazetc148fc22009-11-01 19:23:04 +0000507
508 rcu_read_lock();
509 dev = dev_get_by_index_rcu(net, ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 if (dev)
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000511 in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Eric Dumazetc148fc22009-11-01 19:23:04 +0000512 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 return in_dev;
514}
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800515EXPORT_SYMBOL(inetdev_by_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
517/* Called only from RTNL semaphored context. No locks. */
518
Al Viro60cad5d2006-09-26 22:17:09 -0700519struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
520 __be32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521{
522 ASSERT_RTNL();
523
524 for_primary_ifa(in_dev) {
525 if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
526 return ifa;
527 } endfor_ifa(in_dev);
528 return NULL;
529}
530
531static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
532{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900533 struct net *net = sock_net(skb->sk);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700534 struct nlattr *tb[IFA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 struct in_device *in_dev;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700536 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 struct in_ifaddr *ifa, **ifap;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700538 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539
540 ASSERT_RTNL();
541
Eric W. Biedermandfc47ef2012-11-16 03:03:00 +0000542 if (!capable(CAP_NET_ADMIN))
543 return -EPERM;
544
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700545 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
546 if (err < 0)
547 goto errout;
548
549 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800550 in_dev = inetdev_by_index(net, ifm->ifa_index);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700551 if (in_dev == NULL) {
552 err = -ENODEV;
553 goto errout;
554 }
555
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
557 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700558 if (tb[IFA_LOCAL] &&
Al Viroa7a628c2006-09-26 22:16:43 -0700559 ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700561
562 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
563 continue;
564
565 if (tb[IFA_ADDRESS] &&
566 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Al Viroa7a628c2006-09-26 22:16:43 -0700567 !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700568 continue;
569
Eric W. Biederman15e47302012-09-07 20:12:54 +0000570 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 return 0;
572 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700573
574 err = -EADDRNOTAVAIL;
575errout:
576 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577}
578
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800579static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580{
Thomas Graf5c753972006-08-04 23:03:53 -0700581 struct nlattr *tb[IFA_MAX+1];
582 struct in_ifaddr *ifa;
583 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 struct net_device *dev;
585 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800586 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
Thomas Graf5c753972006-08-04 23:03:53 -0700588 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
589 if (err < 0)
590 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
Thomas Graf5c753972006-08-04 23:03:53 -0700592 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800593 err = -EINVAL;
594 if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700595 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800597 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800598 err = -ENODEV;
599 if (dev == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700600 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Thomas Graf5c753972006-08-04 23:03:53 -0700602 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800603 err = -ENOBUFS;
604 if (in_dev == NULL)
Herbert Xu71e27da2007-06-04 23:36:06 -0700605 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
Thomas Graf5c753972006-08-04 23:03:53 -0700607 ifa = inet_alloc_ifa();
Denis V. Lunev7b218572008-01-31 18:47:00 -0800608 if (ifa == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700609 /*
610 * A potential indev allocation can be left alive, it stays
611 * assigned to its device and is destroy with it.
612 */
Thomas Graf5c753972006-08-04 23:03:53 -0700613 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700614
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800615 ipv4_devconf_setall(in_dev);
Thomas Graf5c753972006-08-04 23:03:53 -0700616 in_dev_hold(in_dev);
617
618 if (tb[IFA_ADDRESS] == NULL)
619 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
620
David S. Millerfd23c3b2011-02-18 12:42:28 -0800621 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
623 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 ifa->ifa_flags = ifm->ifa_flags;
625 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700626 ifa->ifa_dev = in_dev;
627
Al Viroa7a628c2006-09-26 22:16:43 -0700628 ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]);
629 ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700630
631 if (tb[IFA_BROADCAST])
Al Viroa7a628c2006-09-26 22:16:43 -0700632 ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700633
Thomas Graf5c753972006-08-04 23:03:53 -0700634 if (tb[IFA_LABEL])
635 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 else
637 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
638
Thomas Graf5c753972006-08-04 23:03:53 -0700639 return ifa;
640
641errout:
642 return ERR_PTR(err);
643}
644
645static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
646{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900647 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700648 struct in_ifaddr *ifa;
649
650 ASSERT_RTNL();
651
Eric W. Biedermandfc47ef2012-11-16 03:03:00 +0000652 if (!capable(CAP_NET_ADMIN))
653 return -EPERM;
654
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800655 ifa = rtm_to_ifaddr(net, nlh);
Thomas Graf5c753972006-08-04 23:03:53 -0700656 if (IS_ERR(ifa))
657 return PTR_ERR(ifa);
658
Eric W. Biederman15e47302012-09-07 20:12:54 +0000659 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660}
661
662/*
663 * Determine a default network mask, based on the IP address.
664 */
665
Eric Dumazet40384992012-08-03 21:06:50 +0000666static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667{
668 int rc = -1; /* Something else, probably a multicast. */
669
Joe Perchesf97c1e02007-12-16 13:45:43 -0800670 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900671 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 else {
Al Viro714e85b2006-11-14 20:51:49 -0800673 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
Al Viro714e85b2006-11-14 20:51:49 -0800675 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800677 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800679 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 rc = 24;
681 }
682
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900683 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684}
685
686
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800687int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688{
689 struct ifreq ifr;
690 struct sockaddr_in sin_orig;
691 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
692 struct in_device *in_dev;
693 struct in_ifaddr **ifap = NULL;
694 struct in_ifaddr *ifa = NULL;
695 struct net_device *dev;
696 char *colon;
697 int ret = -EFAULT;
698 int tryaddrmatch = 0;
699
700 /*
701 * Fetch the caller's info block into kernel space
702 */
703
704 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
705 goto out;
706 ifr.ifr_name[IFNAMSIZ - 1] = 0;
707
708 /* save original address for comparison */
709 memcpy(&sin_orig, sin, sizeof(*sin));
710
711 colon = strchr(ifr.ifr_name, ':');
712 if (colon)
713 *colon = 0;
714
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800715 dev_load(net, ifr.ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
Stephen Hemminger132adf52007-03-08 20:44:43 -0800717 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 case SIOCGIFADDR: /* Get interface address */
719 case SIOCGIFBRDADDR: /* Get the broadcast address */
720 case SIOCGIFDSTADDR: /* Get the destination address */
721 case SIOCGIFNETMASK: /* Get the netmask for the interface */
722 /* Note that these ioctls will not sleep,
723 so that we do not impose a lock.
724 One day we will be forced to put shlock here (I mean SMP)
725 */
726 tryaddrmatch = (sin_orig.sin_family == AF_INET);
727 memset(sin, 0, sizeof(*sin));
728 sin->sin_family = AF_INET;
729 break;
730
731 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000732 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000733 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 goto out;
735 break;
736 case SIOCSIFADDR: /* Set interface address (and family) */
737 case SIOCSIFBRDADDR: /* Set the broadcast address */
738 case SIOCSIFDSTADDR: /* Set the destination address */
739 case SIOCSIFNETMASK: /* Set the netmask for the interface */
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000740 ret = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +0000741 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 goto out;
743 ret = -EINVAL;
744 if (sin->sin_family != AF_INET)
745 goto out;
746 break;
747 default:
748 ret = -EINVAL;
749 goto out;
750 }
751
752 rtnl_lock();
753
754 ret = -ENODEV;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800755 dev = __dev_get_by_name(net, ifr.ifr_name);
756 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 goto done;
758
759 if (colon)
760 *colon = ':';
761
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800762 in_dev = __in_dev_get_rtnl(dev);
763 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 if (tryaddrmatch) {
765 /* Matthias Andree */
766 /* compare label and address (4.4BSD style) */
767 /* note: we only do this for a limited set of ioctls
768 and only if the original address family was AF_INET.
769 This is checked above. */
770 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
771 ifap = &ifa->ifa_next) {
772 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
773 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -0800774 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 break; /* found */
776 }
777 }
778 }
779 /* we didn't get a match, maybe the application is
780 4.3BSD-style and passed in junk so we fall back to
781 comparing just the label */
782 if (!ifa) {
783 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
784 ifap = &ifa->ifa_next)
785 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
786 break;
787 }
788 }
789
790 ret = -EADDRNOTAVAIL;
791 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
792 goto done;
793
Stephen Hemminger132adf52007-03-08 20:44:43 -0800794 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 case SIOCGIFADDR: /* Get interface address */
796 sin->sin_addr.s_addr = ifa->ifa_local;
797 goto rarok;
798
799 case SIOCGIFBRDADDR: /* Get the broadcast address */
800 sin->sin_addr.s_addr = ifa->ifa_broadcast;
801 goto rarok;
802
803 case SIOCGIFDSTADDR: /* Get the destination address */
804 sin->sin_addr.s_addr = ifa->ifa_address;
805 goto rarok;
806
807 case SIOCGIFNETMASK: /* Get the netmask for the interface */
808 sin->sin_addr.s_addr = ifa->ifa_mask;
809 goto rarok;
810
811 case SIOCSIFFLAGS:
812 if (colon) {
813 ret = -EADDRNOTAVAIL;
814 if (!ifa)
815 break;
816 ret = 0;
817 if (!(ifr.ifr_flags & IFF_UP))
818 inet_del_ifa(in_dev, ifap, 1);
819 break;
820 }
821 ret = dev_change_flags(dev, ifr.ifr_flags);
822 break;
823
824 case SIOCSIFADDR: /* Set interface address (and family) */
825 ret = -EINVAL;
826 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
827 break;
828
829 if (!ifa) {
830 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800831 ifa = inet_alloc_ifa();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800832 INIT_HLIST_NODE(&ifa->hash);
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800833 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 break;
835 if (colon)
836 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
837 else
838 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
839 } else {
840 ret = 0;
841 if (ifa->ifa_local == sin->sin_addr.s_addr)
842 break;
843 inet_del_ifa(in_dev, ifap, 0);
844 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -0800845 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 }
847
848 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
849
850 if (!(dev->flags & IFF_POINTOPOINT)) {
851 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
852 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
853 if ((dev->flags & IFF_BROADCAST) &&
854 ifa->ifa_prefixlen < 31)
855 ifa->ifa_broadcast = ifa->ifa_address |
856 ~ifa->ifa_mask;
857 } else {
858 ifa->ifa_prefixlen = 32;
859 ifa->ifa_mask = inet_make_mask(32);
860 }
861 ret = inet_set_ifa(dev, ifa);
862 break;
863
864 case SIOCSIFBRDADDR: /* Set the broadcast address */
865 ret = 0;
866 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
867 inet_del_ifa(in_dev, ifap, 0);
868 ifa->ifa_broadcast = sin->sin_addr.s_addr;
869 inet_insert_ifa(ifa);
870 }
871 break;
872
873 case SIOCSIFDSTADDR: /* Set the destination address */
874 ret = 0;
875 if (ifa->ifa_address == sin->sin_addr.s_addr)
876 break;
877 ret = -EINVAL;
878 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
879 break;
880 ret = 0;
881 inet_del_ifa(in_dev, ifap, 0);
882 ifa->ifa_address = sin->sin_addr.s_addr;
883 inet_insert_ifa(ifa);
884 break;
885
886 case SIOCSIFNETMASK: /* Set the netmask for the interface */
887
888 /*
889 * The mask we set must be legal.
890 */
891 ret = -EINVAL;
892 if (bad_mask(sin->sin_addr.s_addr, 0))
893 break;
894 ret = 0;
895 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -0700896 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 inet_del_ifa(in_dev, ifap, 0);
898 ifa->ifa_mask = sin->sin_addr.s_addr;
899 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
900
901 /* See if current broadcast address matches
902 * with current netmask, then recalculate
903 * the broadcast address. Otherwise it's a
904 * funny address, so don't touch it since
905 * the user seems to know what (s)he's doing...
906 */
907 if ((dev->flags & IFF_BROADCAST) &&
908 (ifa->ifa_prefixlen < 31) &&
909 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -0500910 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 ifa->ifa_broadcast = (ifa->ifa_local |
912 ~sin->sin_addr.s_addr);
913 }
914 inet_insert_ifa(ifa);
915 }
916 break;
917 }
918done:
919 rtnl_unlock();
920out:
921 return ret;
922rarok:
923 rtnl_unlock();
924 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
925 goto out;
926}
927
928static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
929{
Herbert Xue5ed6392005-10-03 14:35:55 -0700930 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 struct in_ifaddr *ifa;
932 struct ifreq ifr;
933 int done = 0;
934
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800935 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 goto out;
937
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800938 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 if (!buf) {
940 done += sizeof(ifr);
941 continue;
942 }
943 if (len < (int) sizeof(ifr))
944 break;
945 memset(&ifr, 0, sizeof(struct ifreq));
946 if (ifa->ifa_label)
947 strcpy(ifr.ifr_name, ifa->ifa_label);
948 else
949 strcpy(ifr.ifr_name, dev->name);
950
951 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
952 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
953 ifa->ifa_local;
954
955 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
956 done = -EFAULT;
957 break;
958 }
959 buf += sizeof(struct ifreq);
960 len -= sizeof(struct ifreq);
961 done += sizeof(struct ifreq);
962 }
963out:
964 return done;
965}
966
Al Viroa61ced52006-09-26 21:27:54 -0700967__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968{
Al Viroa61ced52006-09-26 21:27:54 -0700969 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900971 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
973 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -0700974 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 if (!in_dev)
976 goto no_in_dev;
977
978 for_primary_ifa(in_dev) {
979 if (ifa->ifa_scope > scope)
980 continue;
981 if (!dst || inet_ifa_match(dst, ifa)) {
982 addr = ifa->ifa_local;
983 break;
984 }
985 if (!addr)
986 addr = ifa->ifa_local;
987 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800990 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800991no_in_dev:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
993 /* Not loopback addresses on loopback should be preferred
994 in this case. It is importnat that lo is the first interface
995 in dev_base list.
996 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800997 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800998 in_dev = __in_dev_get_rcu(dev);
999 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 continue;
1001
1002 for_primary_ifa(in_dev) {
1003 if (ifa->ifa_scope != RT_SCOPE_LINK &&
1004 ifa->ifa_scope <= scope) {
1005 addr = ifa->ifa_local;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001006 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 }
1008 } endfor_ifa(in_dev);
1009 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001010out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 return addr;
1013}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001014EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
Al Viro60cad5d2006-09-26 22:17:09 -07001016static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1017 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018{
1019 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001020 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
1022 for_ifa(in_dev) {
1023 if (!addr &&
1024 (local == ifa->ifa_local || !local) &&
1025 ifa->ifa_scope <= scope) {
1026 addr = ifa->ifa_local;
1027 if (same)
1028 break;
1029 }
1030 if (!same) {
1031 same = (!local || inet_ifa_match(local, ifa)) &&
1032 (!dst || inet_ifa_match(dst, ifa));
1033 if (same && addr) {
1034 if (local || !dst)
1035 break;
1036 /* Is the selected addr into dst subnet? */
1037 if (inet_ifa_match(addr, ifa))
1038 break;
1039 /* No, then can we use new local src? */
1040 if (ifa->ifa_scope <= scope) {
1041 addr = ifa->ifa_local;
1042 break;
1043 }
1044 /* search for large dst subnet for addr */
1045 same = 0;
1046 }
1047 }
1048 } endfor_ifa(in_dev);
1049
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001050 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051}
1052
1053/*
1054 * Confirm that local IP address exists using wildcards:
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001055 * - in_dev: only on this interface, 0=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 * - dst: only in the same subnet as dst, 0=any dst
1057 * - local: address, 0=autoselect the local address
1058 * - scope: maximum allowed scope value for the local address
1059 */
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001060__be32 inet_confirm_addr(struct in_device *in_dev,
1061 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062{
Al Viro60cad5d2006-09-26 22:17:09 -07001063 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001064 struct net_device *dev;
Denis V. Lunev39a6d062008-01-14 23:06:19 -08001065 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
Denis V. Lunev39a6d062008-01-14 23:06:19 -08001067 if (scope != RT_SCOPE_LINK)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001068 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001070 net = dev_net(in_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001072 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001073 in_dev = __in_dev_get_rcu(dev);
1074 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 addr = confirm_addr_indev(in_dev, dst, local, scope);
1076 if (addr)
1077 break;
1078 }
1079 }
1080 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
1082 return addr;
1083}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001084EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085
1086/*
1087 * Device notifier
1088 */
1089
1090int register_inetaddr_notifier(struct notifier_block *nb)
1091{
Alan Sterne041c682006-03-27 01:16:30 -08001092 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001094EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
1096int unregister_inetaddr_notifier(struct notifier_block *nb)
1097{
Alan Sterne041c682006-03-27 01:16:30 -08001098 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001100EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001102/* Rename ifa_labels for a device name change. Make some effort to preserve
1103 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104*/
1105static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001106{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 struct in_ifaddr *ifa;
1108 int named = 0;
1109
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001110 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1111 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112
1113 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001114 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001116 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001117 dot = strchr(old, ':');
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001118 if (dot == NULL) {
1119 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 dot = old;
1121 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001122 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001123 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001124 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001125 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001126skip:
1127 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001128 }
1129}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
Eric Dumazet40384992012-08-03 21:06:50 +00001131static bool inetdev_valid_mtu(unsigned int mtu)
Breno Leitao06770842008-09-02 17:28:58 -07001132{
1133 return mtu >= 68;
1134}
1135
Ian Campbelld11327ad2011-02-11 07:44:16 +00001136static void inetdev_send_gratuitous_arp(struct net_device *dev,
1137 struct in_device *in_dev)
1138
1139{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001140 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001141
Zoltan Kissb76d0782011-07-24 13:09:30 +00001142 for (ifa = in_dev->ifa_list; ifa;
1143 ifa = ifa->ifa_next) {
1144 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1145 ifa->ifa_local, dev,
1146 ifa->ifa_local, NULL,
1147 dev->dev_addr, NULL);
1148 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001149}
1150
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151/* Called only under RTNL semaphore */
1152
1153static int inetdev_event(struct notifier_block *this, unsigned long event,
1154 void *ptr)
1155{
1156 struct net_device *dev = ptr;
Eric Dumazet748e2d92012-08-22 21:50:59 +00001157 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158
1159 ASSERT_RTNL();
1160
1161 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001162 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 in_dev = inetdev_init(dev);
Herbert Xub217d612007-07-30 17:04:52 -07001164 if (!in_dev)
1165 return notifier_from_errno(-ENOMEM);
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001166 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001167 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1168 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001169 }
Breno Leitao06770842008-09-02 17:28:58 -07001170 } else if (event == NETDEV_CHANGEMTU) {
1171 /* Re-enabling IP */
1172 if (inetdev_valid_mtu(dev->mtu))
1173 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 }
1175 goto out;
1176 }
1177
1178 switch (event) {
1179 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001180 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001181 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 break;
1183 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001184 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001186 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001187 struct in_ifaddr *ifa = inet_alloc_ifa();
1188
1189 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001190 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 ifa->ifa_local =
1192 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1193 ifa->ifa_prefixlen = 8;
1194 ifa->ifa_mask = inet_make_mask(8);
1195 in_dev_hold(in_dev);
1196 ifa->ifa_dev = in_dev;
1197 ifa->ifa_scope = RT_SCOPE_HOST;
1198 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1199 inet_insert_ifa(ifa);
1200 }
1201 }
1202 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001203 /* fall through */
1204 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001205 if (!IN_DEV_ARP_NOTIFY(in_dev))
1206 break;
1207 /* fall through */
1208 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001209 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001210 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 break;
1212 case NETDEV_DOWN:
1213 ip_mc_down(in_dev);
1214 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001215 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001216 ip_mc_unmap(in_dev);
1217 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001218 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001219 ip_mc_remap(in_dev);
1220 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001222 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 break;
Breno Leitao06770842008-09-02 17:28:58 -07001224 /* disable IP when MTU is not enough */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 case NETDEV_UNREGISTER:
1226 inetdev_destroy(in_dev);
1227 break;
1228 case NETDEV_CHANGENAME:
1229 /* Do not notify about label change, this event is
1230 * not interesting to applications using netlink.
1231 */
1232 inetdev_changename(dev, in_dev);
1233
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001234 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001235 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 break;
1237 }
1238out:
1239 return NOTIFY_DONE;
1240}
1241
1242static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001243 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244};
1245
Eric Dumazet40384992012-08-03 21:06:50 +00001246static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001247{
1248 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1249 + nla_total_size(4) /* IFA_ADDRESS */
1250 + nla_total_size(4) /* IFA_LOCAL */
1251 + nla_total_size(4) /* IFA_BROADCAST */
Thomas Graf339bf982006-11-10 14:10:15 -08001252 + nla_total_size(IFNAMSIZ); /* IFA_LABEL */
1253}
1254
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001256 u32 portid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257{
1258 struct ifaddrmsg *ifm;
1259 struct nlmsghdr *nlh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
Eric W. Biederman15e47302012-09-07 20:12:54 +00001261 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
Thomas Graf47f68512006-08-04 23:04:36 -07001262 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001263 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001264
1265 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 ifm->ifa_family = AF_INET;
1267 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
1268 ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT;
1269 ifm->ifa_scope = ifa->ifa_scope;
1270 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271
David S. Millerf3756b72012-04-01 20:39:02 -04001272 if ((ifa->ifa_address &&
1273 nla_put_be32(skb, IFA_ADDRESS, ifa->ifa_address)) ||
1274 (ifa->ifa_local &&
1275 nla_put_be32(skb, IFA_LOCAL, ifa->ifa_local)) ||
1276 (ifa->ifa_broadcast &&
1277 nla_put_be32(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
1278 (ifa->ifa_label[0] &&
1279 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)))
1280 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001281
1282 return nlmsg_end(skb, nlh);
1283
1284nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001285 nlmsg_cancel(skb, nlh);
1286 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287}
1288
1289static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1290{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001291 struct net *net = sock_net(skb->sk);
Eric Dumazeteec4df92009-11-12 07:44:25 +00001292 int h, s_h;
1293 int idx, s_idx;
1294 int ip_idx, s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 struct net_device *dev;
1296 struct in_device *in_dev;
1297 struct in_ifaddr *ifa;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001298 struct hlist_head *head;
1299 struct hlist_node *node;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
Eric Dumazeteec4df92009-11-12 07:44:25 +00001301 s_h = cb->args[0];
1302 s_idx = idx = cb->args[1];
1303 s_ip_idx = ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304
Eric Dumazeteec4df92009-11-12 07:44:25 +00001305 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1306 idx = 0;
1307 head = &net->dev_index_head[h];
1308 rcu_read_lock();
1309 hlist_for_each_entry_rcu(dev, node, head, index_hlist) {
1310 if (idx < s_idx)
1311 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001312 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001313 s_ip_idx = 0;
1314 in_dev = __in_dev_get_rcu(dev);
1315 if (!in_dev)
1316 goto cont;
1317
1318 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1319 ifa = ifa->ifa_next, ip_idx++) {
1320 if (ip_idx < s_ip_idx)
1321 continue;
1322 if (inet_fill_ifaddr(skb, ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001323 NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 cb->nlh->nlmsg_seq,
Eric Dumazeteec4df92009-11-12 07:44:25 +00001325 RTM_NEWADDR, NLM_F_MULTI) <= 0) {
1326 rcu_read_unlock();
1327 goto done;
1328 }
1329 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001330cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001331 idx++;
1332 }
1333 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 }
1335
1336done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001337 cb->args[0] = h;
1338 cb->args[1] = idx;
1339 cb->args[2] = ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340
1341 return skb->len;
1342}
1343
Jianjun Kong539afed2008-11-03 02:48:48 -08001344static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001345 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346{
Thomas Graf47f68512006-08-04 23:04:36 -07001347 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001348 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1349 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001350 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001352 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001353 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Thomas Graf47f68512006-08-04 23:04:36 -07001354 if (skb == NULL)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001355 goto errout;
1356
Eric W. Biederman15e47302012-09-07 20:12:54 +00001357 err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001358 if (err < 0) {
1359 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1360 WARN_ON(err == -EMSGSIZE);
1361 kfree_skb(skb);
1362 goto errout;
1363 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001364 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001365 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001366errout:
1367 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001368 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369}
1370
Thomas Graf9f0f7272010-11-16 04:32:48 +00001371static size_t inet_get_link_af_size(const struct net_device *dev)
1372{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001373 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001374
1375 if (!in_dev)
1376 return 0;
1377
1378 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1379}
1380
1381static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
1382{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001383 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001384 struct nlattr *nla;
1385 int i;
1386
1387 if (!in_dev)
1388 return -ENODATA;
1389
1390 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
1391 if (nla == NULL)
1392 return -EMSGSIZE;
1393
1394 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1395 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1396
1397 return 0;
1398}
1399
1400static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1401 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1402};
1403
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001404static int inet_validate_link_af(const struct net_device *dev,
1405 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001406{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001407 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1408 int err, rem;
1409
Eric Dumazetf7fce742010-12-01 06:03:06 +00001410 if (dev && !__in_dev_get_rtnl(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001411 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001412
1413 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy);
1414 if (err < 0)
1415 return err;
1416
1417 if (tb[IFLA_INET_CONF]) {
1418 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1419 int cfgid = nla_type(a);
1420
1421 if (nla_len(a) < 4)
1422 return -EINVAL;
1423
1424 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1425 return -EINVAL;
1426 }
1427 }
1428
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001429 return 0;
1430}
1431
1432static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1433{
Eric Dumazetf7fce742010-12-01 06:03:06 +00001434 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001435 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1436 int rem;
1437
1438 if (!in_dev)
1439 return -EAFNOSUPPORT;
1440
1441 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL) < 0)
1442 BUG();
1443
Thomas Graf9f0f7272010-11-16 04:32:48 +00001444 if (tb[IFLA_INET_CONF]) {
1445 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1446 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1447 }
1448
1449 return 0;
1450}
1451
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001452static int inet_netconf_msgsize_devconf(int type)
1453{
1454 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1455 + nla_total_size(4); /* NETCONFA_IFINDEX */
1456
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001457 /* type -1 is used for ALL */
1458 if (type == -1 || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001459 size += nla_total_size(4);
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001460 if (type == -1 || type == NETCONFA_RP_FILTER)
1461 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001462
1463 return size;
1464}
1465
1466static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1467 struct ipv4_devconf *devconf, u32 portid,
1468 u32 seq, int event, unsigned int flags,
1469 int type)
1470{
1471 struct nlmsghdr *nlh;
1472 struct netconfmsg *ncm;
1473
1474 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1475 flags);
1476 if (nlh == NULL)
1477 return -EMSGSIZE;
1478
1479 ncm = nlmsg_data(nlh);
1480 ncm->ncm_family = AF_INET;
1481
1482 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1483 goto nla_put_failure;
1484
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001485 /* type -1 is used for ALL */
1486 if ((type == -1 || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001487 nla_put_s32(skb, NETCONFA_FORWARDING,
1488 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1489 goto nla_put_failure;
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001490 if ((type == -1 || type == NETCONFA_RP_FILTER) &&
1491 nla_put_s32(skb, NETCONFA_RP_FILTER,
1492 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
1493 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001494
1495 return nlmsg_end(skb, nlh);
1496
1497nla_put_failure:
1498 nlmsg_cancel(skb, nlh);
1499 return -EMSGSIZE;
1500}
1501
1502static void inet_netconf_notify_devconf(struct net *net, int type, int ifindex,
1503 struct ipv4_devconf *devconf)
1504{
1505 struct sk_buff *skb;
1506 int err = -ENOBUFS;
1507
1508 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_ATOMIC);
1509 if (skb == NULL)
1510 goto errout;
1511
1512 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
1513 RTM_NEWNETCONF, 0, type);
1514 if (err < 0) {
1515 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1516 WARN_ON(err == -EMSGSIZE);
1517 kfree_skb(skb);
1518 goto errout;
1519 }
1520 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_ATOMIC);
1521 return;
1522errout:
1523 if (err < 0)
1524 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
1525}
1526
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001527static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
1528 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
1529 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001530 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001531};
1532
1533static int inet_netconf_get_devconf(struct sk_buff *in_skb,
1534 struct nlmsghdr *nlh,
1535 void *arg)
1536{
1537 struct net *net = sock_net(in_skb->sk);
1538 struct nlattr *tb[NETCONFA_MAX+1];
1539 struct netconfmsg *ncm;
1540 struct sk_buff *skb;
1541 struct ipv4_devconf *devconf;
1542 struct in_device *in_dev;
1543 struct net_device *dev;
1544 int ifindex;
1545 int err;
1546
1547 err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
1548 devconf_ipv4_policy);
1549 if (err < 0)
1550 goto errout;
1551
1552 err = EINVAL;
1553 if (!tb[NETCONFA_IFINDEX])
1554 goto errout;
1555
1556 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
1557 switch (ifindex) {
1558 case NETCONFA_IFINDEX_ALL:
1559 devconf = net->ipv4.devconf_all;
1560 break;
1561 case NETCONFA_IFINDEX_DEFAULT:
1562 devconf = net->ipv4.devconf_dflt;
1563 break;
1564 default:
1565 dev = __dev_get_by_index(net, ifindex);
1566 if (dev == NULL)
1567 goto errout;
1568 in_dev = __in_dev_get_rtnl(dev);
1569 if (in_dev == NULL)
1570 goto errout;
1571 devconf = &in_dev->cnf;
1572 break;
1573 }
1574
1575 err = -ENOBUFS;
1576 skb = nlmsg_new(inet_netconf_msgsize_devconf(-1), GFP_ATOMIC);
1577 if (skb == NULL)
1578 goto errout;
1579
1580 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
1581 NETLINK_CB(in_skb).portid,
1582 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
1583 -1);
1584 if (err < 0) {
1585 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1586 WARN_ON(err == -EMSGSIZE);
1587 kfree_skb(skb);
1588 goto errout;
1589 }
1590 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
1591errout:
1592 return err;
1593}
1594
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595#ifdef CONFIG_SYSCTL
1596
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001597static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07001598{
1599 struct net_device *dev;
1600
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001601 rcu_read_lock();
1602 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07001603 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001604
Herbert Xu31be3082007-06-04 23:35:37 -07001605 in_dev = __in_dev_get_rcu(dev);
1606 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001607 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07001608 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001609 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07001610}
1611
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001612/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001613static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001614{
1615 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08001616 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001617
Pavel Emelyanov586f1212007-12-16 13:32:48 -08001618 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001619 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001620 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1621 NETCONFA_IFINDEX_ALL,
1622 net->ipv4.devconf_all);
1623 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1624 NETCONFA_IFINDEX_DEFAULT,
1625 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001626
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001627 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001628 struct in_device *in_dev;
Ben Hutchings0187bdf2008-06-19 16:15:47 -07001629 if (on)
1630 dev_disable_lro(dev);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001631 rcu_read_lock();
1632 in_dev = __in_dev_get_rcu(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001633 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001634 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001635 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1636 dev->ifindex, &in_dev->cnf);
1637 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001638 rcu_read_unlock();
1639 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001640}
1641
Herbert Xu31be3082007-06-04 23:35:37 -07001642static int devinet_conf_proc(ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001643 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07001644 size_t *lenp, loff_t *ppos)
1645{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00001646 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001647 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00001648 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07001649
1650 if (write) {
1651 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001652 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07001653 int i = (int *)ctl->data - cnf->data;
1654
1655 set_bit(i, cnf->state);
1656
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001657 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001658 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00001659 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
1660 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00001661 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00001662 rt_cache_flush(net);
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001663 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
1664 new_value != old_value) {
1665 int ifindex;
1666
1667 if (cnf == net->ipv4.devconf_dflt)
1668 ifindex = NETCONFA_IFINDEX_DEFAULT;
1669 else if (cnf == net->ipv4.devconf_all)
1670 ifindex = NETCONFA_IFINDEX_ALL;
1671 else {
1672 struct in_device *idev =
1673 container_of(cnf, struct in_device,
1674 cnf);
1675 ifindex = idev->dev->ifindex;
1676 }
1677 inet_netconf_notify_devconf(net, NETCONFA_RP_FILTER,
1678 ifindex, cnf);
1679 }
Herbert Xu31be3082007-06-04 23:35:37 -07001680 }
1681
1682 return ret;
1683}
1684
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685static int devinet_sysctl_forward(ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001686 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 size_t *lenp, loff_t *ppos)
1688{
1689 int *valp = ctl->data;
1690 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00001691 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001692 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
1694 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001695 struct net *net = ctl->extra2;
1696
Ben Hutchings0187bdf2008-06-19 16:15:47 -07001697 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00001698 if (!rtnl_trylock()) {
1699 /* Restore the original values before restarting */
1700 *valp = val;
1701 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00001702 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00001703 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07001704 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
1705 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001706 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07001707 struct ipv4_devconf *cnf = ctl->extra1;
1708 struct in_device *idev =
1709 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001710 if (*valp)
1711 dev_disable_lro(idev->dev);
1712 inet_netconf_notify_devconf(net,
1713 NETCONFA_FORWARDING,
1714 idev->dev->ifindex,
1715 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07001716 }
1717 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00001718 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001719 } else
1720 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1721 NETCONFA_IFINDEX_DEFAULT,
1722 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 }
1724
1725 return ret;
1726}
1727
David S. Miller323e1262010-12-12 21:55:08 -08001728static int ipv4_doint_and_flush(ctl_table *ctl, int write,
1729 void __user *buffer,
1730 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731{
1732 int *valp = ctl->data;
1733 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001734 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07001735 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736
1737 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00001738 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739
1740 return ret;
1741}
1742
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001743#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07001744 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07001745 .procname = name, \
1746 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00001747 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07001748 .maxlen = sizeof(int), \
1749 .mode = mval, \
1750 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07001751 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07001752 }
1753
1754#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001755 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07001756
1757#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001758 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07001759
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001760#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
1761 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07001762
1763#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001764 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07001765
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766static struct devinet_sysctl_table {
1767 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00001768 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769} devinet_sysctl = {
1770 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07001771 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001772 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07001773 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
1774
1775 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
1776 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
1777 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
1778 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
1779 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
1780 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
1781 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00001782 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08001783 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07001784 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
1785 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
1786 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
1787 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
1788 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
1789 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
1790 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
1791 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
1792 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001793 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00001794 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
Herbert Xu42f811b2007-06-04 23:34:44 -07001795
1796 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
1797 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
1798 DEVINET_SYSCTL_FLUSHING_ENTRY(FORCE_IGMP_VERSION,
1799 "force_igmp_version"),
1800 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
1801 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00001802 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
1803 "route_localnet"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805};
1806
Pavel Emelyanovea40b322007-12-16 13:30:07 -08001807static int __devinet_sysctl_register(struct net *net, char *dev_name,
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001808 struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809{
1810 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001811 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00001812 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11001813
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001814 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001816 goto out;
1817
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
1819 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07001820 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001821 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 }
1823
Eric W. Biederman464dc802012-11-16 03:02:59 +00001824 /* Don't export sysctls to unprivileged users */
1825 if (net->user_ns != &init_user_ns)
1826 t->devinet_vars[0].procname = NULL;
1827
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00001828 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00001830 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00001832 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833
1834 p->sysctl = t;
Pavel Emelyanovea40b322007-12-16 13:30:07 -08001835 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001837free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001839out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08001840 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841}
1842
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001843static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
1844{
1845 struct devinet_sysctl_table *t = cnf->sysctl;
1846
1847 if (t == NULL)
1848 return;
1849
1850 cnf->sysctl = NULL;
Lucian Adrian Grijincuff538812011-05-01 01:44:01 +00001851 unregister_net_sysctl_table(t->sysctl_header);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001852 kfree(t);
1853}
1854
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001855static void devinet_sysctl_register(struct in_device *idev)
1856{
Eric W. Biederman54716e32010-02-14 03:27:03 +00001857 neigh_sysctl_register(idev->dev, idev->arp_parms, "ipv4", NULL);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001858 __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001859 &idev->cnf);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001860}
1861
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001862static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863{
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001864 __devinet_sysctl_unregister(&idev->cnf);
1865 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001868static struct ctl_table ctl_forward_entry[] = {
1869 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001870 .procname = "ip_forward",
1871 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00001872 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001873 .maxlen = sizeof(int),
1874 .mode = 0644,
1875 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001876 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001877 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001878 },
1879 { },
1880};
Eric Dumazet2a75de02008-01-05 23:08:49 -08001881#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001882
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001883static __net_init int devinet_init_net(struct net *net)
1884{
1885 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001886 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08001887#ifdef CONFIG_SYSCTL
1888 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001889 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08001890#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001891
1892 err = -ENOMEM;
1893 all = &ipv4_devconf;
1894 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001895
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08001896 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001897 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
1898 if (all == NULL)
1899 goto err_alloc_all;
1900
1901 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
1902 if (dflt == NULL)
1903 goto err_alloc_dflt;
1904
Eric Dumazet2a75de02008-01-05 23:08:49 -08001905#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001906 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
1907 if (tbl == NULL)
1908 goto err_alloc_ctl;
1909
Eric W. Biederman02291682010-02-14 03:25:51 +00001910 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001911 tbl[0].extra1 = all;
1912 tbl[0].extra2 = net;
Eric W. Biederman464dc802012-11-16 03:02:59 +00001913
1914 /* Don't export sysctls to unprivileged users */
1915 if (net->user_ns != &init_user_ns)
1916 tbl[0].procname = NULL;
Eric Dumazet2a75de02008-01-05 23:08:49 -08001917#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001918 }
1919
1920#ifdef CONFIG_SYSCTL
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001921 err = __devinet_sysctl_register(net, "all", all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001922 if (err < 0)
1923 goto err_reg_all;
1924
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001925 err = __devinet_sysctl_register(net, "default", dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001926 if (err < 0)
1927 goto err_reg_dflt;
1928
1929 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00001930 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001931 if (forw_hdr == NULL)
1932 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08001933 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001934#endif
1935
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001936 net->ipv4.devconf_all = all;
1937 net->ipv4.devconf_dflt = dflt;
1938 return 0;
1939
1940#ifdef CONFIG_SYSCTL
1941err_reg_ctl:
1942 __devinet_sysctl_unregister(dflt);
1943err_reg_dflt:
1944 __devinet_sysctl_unregister(all);
1945err_reg_all:
1946 if (tbl != ctl_forward_entry)
1947 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001948err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08001949#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001950 if (dflt != &ipv4_devconf_dflt)
1951 kfree(dflt);
1952err_alloc_dflt:
1953 if (all != &ipv4_devconf)
1954 kfree(all);
1955err_alloc_all:
1956 return err;
1957}
1958
1959static __net_exit void devinet_exit_net(struct net *net)
1960{
Eric Dumazet2a75de02008-01-05 23:08:49 -08001961#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001962 struct ctl_table *tbl;
1963
1964 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001965 unregister_net_sysctl_table(net->ipv4.forw_hdr);
1966 __devinet_sysctl_unregister(net->ipv4.devconf_dflt);
1967 __devinet_sysctl_unregister(net->ipv4.devconf_all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001968 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08001969#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001970 kfree(net->ipv4.devconf_dflt);
1971 kfree(net->ipv4.devconf_all);
1972}
1973
1974static __net_initdata struct pernet_operations devinet_ops = {
1975 .init = devinet_init_net,
1976 .exit = devinet_exit_net,
1977};
1978
Thomas Graf9f0f7272010-11-16 04:32:48 +00001979static struct rtnl_af_ops inet_af_ops = {
1980 .family = AF_INET,
1981 .fill_link_af = inet_fill_link_af,
1982 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001983 .validate_link_af = inet_validate_link_af,
1984 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00001985};
1986
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987void __init devinet_init(void)
1988{
David S. Millerfd23c3b2011-02-18 12:42:28 -08001989 int i;
1990
1991 for (i = 0; i < IN4_ADDR_HSIZE; i++)
1992 INIT_HLIST_HEAD(&inet_addr_lst[i]);
1993
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001994 register_pernet_subsys(&devinet_ops);
1995
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 register_gifconf(PF_INET, inet_gifconf);
1997 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07001998
Thomas Graf9f0f7272010-11-16 04:32:48 +00001999 rtnl_af_register(&inet_af_ops);
2000
Greg Rosec7ac8672011-06-10 01:27:09 +00002001 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL);
2002 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, NULL);
2003 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, NULL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00002004 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
2005 NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006}
2007