blob: f6db227c1fd9282c63d12848539b4c350945534d [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
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700542 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
543 if (err < 0)
544 goto errout;
545
546 ifm = nlmsg_data(nlh);
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800547 in_dev = inetdev_by_index(net, ifm->ifa_index);
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700548 if (in_dev == NULL) {
549 err = -ENODEV;
550 goto errout;
551 }
552
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
554 ifap = &ifa->ifa_next) {
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700555 if (tb[IFA_LOCAL] &&
Al Viroa7a628c2006-09-26 22:16:43 -0700556 ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 continue;
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700558
559 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
560 continue;
561
562 if (tb[IFA_ADDRESS] &&
563 (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
Al Viroa7a628c2006-09-26 22:16:43 -0700564 !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700565 continue;
566
Eric W. Biederman15e47302012-09-07 20:12:54 +0000567 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 return 0;
569 }
Thomas Grafdfdd5fd2006-08-04 23:04:17 -0700570
571 err = -EADDRNOTAVAIL;
572errout:
573 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574}
575
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800576static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
Thomas Graf5c753972006-08-04 23:03:53 -0700578 struct nlattr *tb[IFA_MAX+1];
579 struct in_ifaddr *ifa;
580 struct ifaddrmsg *ifm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 struct net_device *dev;
582 struct in_device *in_dev;
Denis V. Lunev7b218572008-01-31 18:47:00 -0800583 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584
Thomas Graf5c753972006-08-04 23:03:53 -0700585 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
586 if (err < 0)
587 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
Thomas Graf5c753972006-08-04 23:03:53 -0700589 ifm = nlmsg_data(nlh);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800590 err = -EINVAL;
591 if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700592 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800594 dev = __dev_get_by_index(net, ifm->ifa_index);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800595 err = -ENODEV;
596 if (dev == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700597 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
Thomas Graf5c753972006-08-04 23:03:53 -0700599 in_dev = __in_dev_get_rtnl(dev);
Denis V. Lunev7b218572008-01-31 18:47:00 -0800600 err = -ENOBUFS;
601 if (in_dev == NULL)
Herbert Xu71e27da2007-06-04 23:36:06 -0700602 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
Thomas Graf5c753972006-08-04 23:03:53 -0700604 ifa = inet_alloc_ifa();
Denis V. Lunev7b218572008-01-31 18:47:00 -0800605 if (ifa == NULL)
Thomas Graf5c753972006-08-04 23:03:53 -0700606 /*
607 * A potential indev allocation can be left alive, it stays
608 * assigned to its device and is destroy with it.
609 */
Thomas Graf5c753972006-08-04 23:03:53 -0700610 goto errout;
Thomas Graf5c753972006-08-04 23:03:53 -0700611
Pavel Emelyanova4e65d32007-12-07 23:55:43 -0800612 ipv4_devconf_setall(in_dev);
Thomas Graf5c753972006-08-04 23:03:53 -0700613 in_dev_hold(in_dev);
614
615 if (tb[IFA_ADDRESS] == NULL)
616 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
617
David S. Millerfd23c3b2011-02-18 12:42:28 -0800618 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
620 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 ifa->ifa_flags = ifm->ifa_flags;
622 ifa->ifa_scope = ifm->ifa_scope;
Thomas Graf5c753972006-08-04 23:03:53 -0700623 ifa->ifa_dev = in_dev;
624
Al Viroa7a628c2006-09-26 22:16:43 -0700625 ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]);
626 ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]);
Thomas Graf5c753972006-08-04 23:03:53 -0700627
628 if (tb[IFA_BROADCAST])
Al Viroa7a628c2006-09-26 22:16:43 -0700629 ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);
Thomas Graf5c753972006-08-04 23:03:53 -0700630
Thomas Graf5c753972006-08-04 23:03:53 -0700631 if (tb[IFA_LABEL])
632 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 else
634 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
635
Thomas Graf5c753972006-08-04 23:03:53 -0700636 return ifa;
637
638errout:
639 return ERR_PTR(err);
640}
641
642static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
643{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900644 struct net *net = sock_net(skb->sk);
Thomas Graf5c753972006-08-04 23:03:53 -0700645 struct in_ifaddr *ifa;
646
647 ASSERT_RTNL();
648
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -0800649 ifa = rtm_to_ifaddr(net, nlh);
Thomas Graf5c753972006-08-04 23:03:53 -0700650 if (IS_ERR(ifa))
651 return PTR_ERR(ifa);
652
Eric W. Biederman15e47302012-09-07 20:12:54 +0000653 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654}
655
656/*
657 * Determine a default network mask, based on the IP address.
658 */
659
Eric Dumazet40384992012-08-03 21:06:50 +0000660static int inet_abc_len(__be32 addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661{
662 int rc = -1; /* Something else, probably a multicast. */
663
Joe Perchesf97c1e02007-12-16 13:45:43 -0800664 if (ipv4_is_zeronet(addr))
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900665 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 else {
Al Viro714e85b2006-11-14 20:51:49 -0800667 __u32 haddr = ntohl(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Al Viro714e85b2006-11-14 20:51:49 -0800669 if (IN_CLASSA(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 rc = 8;
Al Viro714e85b2006-11-14 20:51:49 -0800671 else if (IN_CLASSB(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 rc = 16;
Al Viro714e85b2006-11-14 20:51:49 -0800673 else if (IN_CLASSC(haddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 rc = 24;
675 }
676
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900677 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678}
679
680
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800681int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682{
683 struct ifreq ifr;
684 struct sockaddr_in sin_orig;
685 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
686 struct in_device *in_dev;
687 struct in_ifaddr **ifap = NULL;
688 struct in_ifaddr *ifa = NULL;
689 struct net_device *dev;
690 char *colon;
691 int ret = -EFAULT;
692 int tryaddrmatch = 0;
693
694 /*
695 * Fetch the caller's info block into kernel space
696 */
697
698 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
699 goto out;
700 ifr.ifr_name[IFNAMSIZ - 1] = 0;
701
702 /* save original address for comparison */
703 memcpy(&sin_orig, sin, sizeof(*sin));
704
705 colon = strchr(ifr.ifr_name, ':');
706 if (colon)
707 *colon = 0;
708
Denis V. Luneve5b13cb2008-02-28 20:51:43 -0800709 dev_load(net, ifr.ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
Stephen Hemminger132adf52007-03-08 20:44:43 -0800711 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 case SIOCGIFADDR: /* Get interface address */
713 case SIOCGIFBRDADDR: /* Get the broadcast address */
714 case SIOCGIFDSTADDR: /* Get the destination address */
715 case SIOCGIFNETMASK: /* Get the netmask for the interface */
716 /* Note that these ioctls will not sleep,
717 so that we do not impose a lock.
718 One day we will be forced to put shlock here (I mean SMP)
719 */
720 tryaddrmatch = (sin_orig.sin_family == AF_INET);
721 memset(sin, 0, sizeof(*sin));
722 sin->sin_family = AF_INET;
723 break;
724
725 case SIOCSIFFLAGS:
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000726 ret = -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 if (!capable(CAP_NET_ADMIN))
728 goto out;
729 break;
730 case SIOCSIFADDR: /* Set interface address (and family) */
731 case SIOCSIFBRDADDR: /* Set the broadcast address */
732 case SIOCSIFDSTADDR: /* Set the destination address */
733 case SIOCSIFNETMASK: /* Set the netmask for the interface */
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +0000734 ret = -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 if (!capable(CAP_NET_ADMIN))
736 goto out;
737 ret = -EINVAL;
738 if (sin->sin_family != AF_INET)
739 goto out;
740 break;
741 default:
742 ret = -EINVAL;
743 goto out;
744 }
745
746 rtnl_lock();
747
748 ret = -ENODEV;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800749 dev = __dev_get_by_name(net, ifr.ifr_name);
750 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 goto done;
752
753 if (colon)
754 *colon = ':';
755
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800756 in_dev = __in_dev_get_rtnl(dev);
757 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 if (tryaddrmatch) {
759 /* Matthias Andree */
760 /* compare label and address (4.4BSD style) */
761 /* note: we only do this for a limited set of ioctls
762 and only if the original address family was AF_INET.
763 This is checked above. */
764 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
765 ifap = &ifa->ifa_next) {
766 if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
767 sin_orig.sin_addr.s_addr ==
David S. Miller6c91afe2011-03-09 13:27:16 -0800768 ifa->ifa_local) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 break; /* found */
770 }
771 }
772 }
773 /* we didn't get a match, maybe the application is
774 4.3BSD-style and passed in junk so we fall back to
775 comparing just the label */
776 if (!ifa) {
777 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
778 ifap = &ifa->ifa_next)
779 if (!strcmp(ifr.ifr_name, ifa->ifa_label))
780 break;
781 }
782 }
783
784 ret = -EADDRNOTAVAIL;
785 if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
786 goto done;
787
Stephen Hemminger132adf52007-03-08 20:44:43 -0800788 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 case SIOCGIFADDR: /* Get interface address */
790 sin->sin_addr.s_addr = ifa->ifa_local;
791 goto rarok;
792
793 case SIOCGIFBRDADDR: /* Get the broadcast address */
794 sin->sin_addr.s_addr = ifa->ifa_broadcast;
795 goto rarok;
796
797 case SIOCGIFDSTADDR: /* Get the destination address */
798 sin->sin_addr.s_addr = ifa->ifa_address;
799 goto rarok;
800
801 case SIOCGIFNETMASK: /* Get the netmask for the interface */
802 sin->sin_addr.s_addr = ifa->ifa_mask;
803 goto rarok;
804
805 case SIOCSIFFLAGS:
806 if (colon) {
807 ret = -EADDRNOTAVAIL;
808 if (!ifa)
809 break;
810 ret = 0;
811 if (!(ifr.ifr_flags & IFF_UP))
812 inet_del_ifa(in_dev, ifap, 1);
813 break;
814 }
815 ret = dev_change_flags(dev, ifr.ifr_flags);
816 break;
817
818 case SIOCSIFADDR: /* Set interface address (and family) */
819 ret = -EINVAL;
820 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
821 break;
822
823 if (!ifa) {
824 ret = -ENOBUFS;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800825 ifa = inet_alloc_ifa();
David S. Millerfd23c3b2011-02-18 12:42:28 -0800826 INIT_HLIST_NODE(&ifa->hash);
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800827 if (!ifa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 break;
829 if (colon)
830 memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
831 else
832 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
833 } else {
834 ret = 0;
835 if (ifa->ifa_local == sin->sin_addr.s_addr)
836 break;
837 inet_del_ifa(in_dev, ifap, 0);
838 ifa->ifa_broadcast = 0;
Bjorn Mork148f9722008-02-26 18:17:53 -0800839 ifa->ifa_scope = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 }
841
842 ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
843
844 if (!(dev->flags & IFF_POINTOPOINT)) {
845 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
846 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
847 if ((dev->flags & IFF_BROADCAST) &&
848 ifa->ifa_prefixlen < 31)
849 ifa->ifa_broadcast = ifa->ifa_address |
850 ~ifa->ifa_mask;
851 } else {
852 ifa->ifa_prefixlen = 32;
853 ifa->ifa_mask = inet_make_mask(32);
854 }
855 ret = inet_set_ifa(dev, ifa);
856 break;
857
858 case SIOCSIFBRDADDR: /* Set the broadcast address */
859 ret = 0;
860 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
861 inet_del_ifa(in_dev, ifap, 0);
862 ifa->ifa_broadcast = sin->sin_addr.s_addr;
863 inet_insert_ifa(ifa);
864 }
865 break;
866
867 case SIOCSIFDSTADDR: /* Set the destination address */
868 ret = 0;
869 if (ifa->ifa_address == sin->sin_addr.s_addr)
870 break;
871 ret = -EINVAL;
872 if (inet_abc_len(sin->sin_addr.s_addr) < 0)
873 break;
874 ret = 0;
875 inet_del_ifa(in_dev, ifap, 0);
876 ifa->ifa_address = sin->sin_addr.s_addr;
877 inet_insert_ifa(ifa);
878 break;
879
880 case SIOCSIFNETMASK: /* Set the netmask for the interface */
881
882 /*
883 * The mask we set must be legal.
884 */
885 ret = -EINVAL;
886 if (bad_mask(sin->sin_addr.s_addr, 0))
887 break;
888 ret = 0;
889 if (ifa->ifa_mask != sin->sin_addr.s_addr) {
Al Viroa144ea42006-09-28 18:00:55 -0700890 __be32 old_mask = ifa->ifa_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 inet_del_ifa(in_dev, ifap, 0);
892 ifa->ifa_mask = sin->sin_addr.s_addr;
893 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
894
895 /* See if current broadcast address matches
896 * with current netmask, then recalculate
897 * the broadcast address. Otherwise it's a
898 * funny address, so don't touch it since
899 * the user seems to know what (s)he's doing...
900 */
901 if ((dev->flags & IFF_BROADCAST) &&
902 (ifa->ifa_prefixlen < 31) &&
903 (ifa->ifa_broadcast ==
David Engeldcab5e12005-10-21 22:09:16 -0500904 (ifa->ifa_local|~old_mask))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 ifa->ifa_broadcast = (ifa->ifa_local |
906 ~sin->sin_addr.s_addr);
907 }
908 inet_insert_ifa(ifa);
909 }
910 break;
911 }
912done:
913 rtnl_unlock();
914out:
915 return ret;
916rarok:
917 rtnl_unlock();
918 ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
919 goto out;
920}
921
922static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
923{
Herbert Xue5ed6392005-10-03 14:35:55 -0700924 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 struct in_ifaddr *ifa;
926 struct ifreq ifr;
927 int done = 0;
928
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800929 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 goto out;
931
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800932 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 if (!buf) {
934 done += sizeof(ifr);
935 continue;
936 }
937 if (len < (int) sizeof(ifr))
938 break;
939 memset(&ifr, 0, sizeof(struct ifreq));
940 if (ifa->ifa_label)
941 strcpy(ifr.ifr_name, ifa->ifa_label);
942 else
943 strcpy(ifr.ifr_name, dev->name);
944
945 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
946 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
947 ifa->ifa_local;
948
949 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
950 done = -EFAULT;
951 break;
952 }
953 buf += sizeof(struct ifreq);
954 len -= sizeof(struct ifreq);
955 done += sizeof(struct ifreq);
956 }
957out:
958 return done;
959}
960
Al Viroa61ced52006-09-26 21:27:54 -0700961__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
Al Viroa61ced52006-09-26 21:27:54 -0700963 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900965 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966
967 rcu_read_lock();
Herbert Xue5ed6392005-10-03 14:35:55 -0700968 in_dev = __in_dev_get_rcu(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 if (!in_dev)
970 goto no_in_dev;
971
972 for_primary_ifa(in_dev) {
973 if (ifa->ifa_scope > scope)
974 continue;
975 if (!dst || inet_ifa_match(dst, ifa)) {
976 addr = ifa->ifa_local;
977 break;
978 }
979 if (!addr)
980 addr = ifa->ifa_local;
981 } endfor_ifa(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
983 if (addr)
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800984 goto out_unlock;
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800985no_in_dev:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
987 /* Not loopback addresses on loopback should be preferred
988 in this case. It is importnat that lo is the first interface
989 in dev_base list.
990 */
Eric Dumazetc6d14c82009-11-04 05:43:23 -0800991 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -0800992 in_dev = __in_dev_get_rcu(dev);
993 if (!in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 continue;
995
996 for_primary_ifa(in_dev) {
997 if (ifa->ifa_scope != RT_SCOPE_LINK &&
998 ifa->ifa_scope <= scope) {
999 addr = ifa->ifa_local;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001000 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 }
1002 } endfor_ifa(in_dev);
1003 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001004out_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 return addr;
1007}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001008EXPORT_SYMBOL(inet_select_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
Al Viro60cad5d2006-09-26 22:17:09 -07001010static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
1011 __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012{
1013 int same = 0;
Al Viroa144ea42006-09-28 18:00:55 -07001014 __be32 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016 for_ifa(in_dev) {
1017 if (!addr &&
1018 (local == ifa->ifa_local || !local) &&
1019 ifa->ifa_scope <= scope) {
1020 addr = ifa->ifa_local;
1021 if (same)
1022 break;
1023 }
1024 if (!same) {
1025 same = (!local || inet_ifa_match(local, ifa)) &&
1026 (!dst || inet_ifa_match(dst, ifa));
1027 if (same && addr) {
1028 if (local || !dst)
1029 break;
1030 /* Is the selected addr into dst subnet? */
1031 if (inet_ifa_match(addr, ifa))
1032 break;
1033 /* No, then can we use new local src? */
1034 if (ifa->ifa_scope <= scope) {
1035 addr = ifa->ifa_local;
1036 break;
1037 }
1038 /* search for large dst subnet for addr */
1039 same = 0;
1040 }
1041 }
1042 } endfor_ifa(in_dev);
1043
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001044 return same ? addr : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045}
1046
1047/*
1048 * Confirm that local IP address exists using wildcards:
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001049 * - in_dev: only on this interface, 0=any interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 * - dst: only in the same subnet as dst, 0=any dst
1051 * - local: address, 0=autoselect the local address
1052 * - scope: maximum allowed scope value for the local address
1053 */
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001054__be32 inet_confirm_addr(struct in_device *in_dev,
1055 __be32 dst, __be32 local, int scope)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056{
Al Viro60cad5d2006-09-26 22:17:09 -07001057 __be32 addr = 0;
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001058 struct net_device *dev;
Denis V. Lunev39a6d062008-01-14 23:06:19 -08001059 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
Denis V. Lunev39a6d062008-01-14 23:06:19 -08001061 if (scope != RT_SCOPE_LINK)
Denis V. Lunev9bd85e32008-01-14 23:05:55 -08001062 return confirm_addr_indev(in_dev, dst, local, scope);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001064 net = dev_net(in_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 rcu_read_lock();
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001066 for_each_netdev_rcu(net, dev) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001067 in_dev = __in_dev_get_rcu(dev);
1068 if (in_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 addr = confirm_addr_indev(in_dev, dst, local, scope);
1070 if (addr)
1071 break;
1072 }
1073 }
1074 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
1076 return addr;
1077}
Andy Gospodarekeaddcd72012-03-22 16:14:29 +00001078EXPORT_SYMBOL(inet_confirm_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
1080/*
1081 * Device notifier
1082 */
1083
1084int register_inetaddr_notifier(struct notifier_block *nb)
1085{
Alan Sterne041c682006-03-27 01:16:30 -08001086 return blocking_notifier_chain_register(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001088EXPORT_SYMBOL(register_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
1090int unregister_inetaddr_notifier(struct notifier_block *nb)
1091{
Alan Sterne041c682006-03-27 01:16:30 -08001092 return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093}
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001094EXPORT_SYMBOL(unregister_inetaddr_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001096/* Rename ifa_labels for a device name change. Make some effort to preserve
1097 * existing alias numbering and to create unique labels if possible.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098*/
1099static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001100{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 struct in_ifaddr *ifa;
1102 int named = 0;
1103
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001104 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1105 char old[IFNAMSIZ], *dot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
1107 memcpy(old, ifa->ifa_label, IFNAMSIZ);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001108 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 if (named++ == 0)
Thomas Graf573bf472008-06-10 15:40:04 -07001110 goto skip;
Mark McLoughlin44344b22008-01-04 00:56:25 -08001111 dot = strchr(old, ':');
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001112 if (dot == NULL) {
1113 sprintf(old, ":%d", named);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 dot = old;
1115 }
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001116 if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001117 strcat(ifa->ifa_label, dot);
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001118 else
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001119 strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
Thomas Graf573bf472008-06-10 15:40:04 -07001120skip:
1121 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001122 }
1123}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
Eric Dumazet40384992012-08-03 21:06:50 +00001125static bool inetdev_valid_mtu(unsigned int mtu)
Breno Leitao06770842008-09-02 17:28:58 -07001126{
1127 return mtu >= 68;
1128}
1129
Ian Campbelld11327ad2011-02-11 07:44:16 +00001130static void inetdev_send_gratuitous_arp(struct net_device *dev,
1131 struct in_device *in_dev)
1132
1133{
Zoltan Kissb76d0782011-07-24 13:09:30 +00001134 struct in_ifaddr *ifa;
Ian Campbelld11327ad2011-02-11 07:44:16 +00001135
Zoltan Kissb76d0782011-07-24 13:09:30 +00001136 for (ifa = in_dev->ifa_list; ifa;
1137 ifa = ifa->ifa_next) {
1138 arp_send(ARPOP_REQUEST, ETH_P_ARP,
1139 ifa->ifa_local, dev,
1140 ifa->ifa_local, NULL,
1141 dev->dev_addr, NULL);
1142 }
Ian Campbelld11327ad2011-02-11 07:44:16 +00001143}
1144
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145/* Called only under RTNL semaphore */
1146
1147static int inetdev_event(struct notifier_block *this, unsigned long event,
1148 void *ptr)
1149{
1150 struct net_device *dev = ptr;
Eric Dumazet748e2d92012-08-22 21:50:59 +00001151 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
1153 ASSERT_RTNL();
1154
1155 if (!in_dev) {
Herbert Xu8030f542007-02-22 01:53:47 +09001156 if (event == NETDEV_REGISTER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 in_dev = inetdev_init(dev);
Herbert Xub217d612007-07-30 17:04:52 -07001158 if (!in_dev)
1159 return notifier_from_errno(-ENOMEM);
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001160 if (dev->flags & IFF_LOOPBACK) {
Herbert Xu42f811b2007-06-04 23:34:44 -07001161 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
1162 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Herbert Xu8030f542007-02-22 01:53:47 +09001163 }
Breno Leitao06770842008-09-02 17:28:58 -07001164 } else if (event == NETDEV_CHANGEMTU) {
1165 /* Re-enabling IP */
1166 if (inetdev_valid_mtu(dev->mtu))
1167 in_dev = inetdev_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 }
1169 goto out;
1170 }
1171
1172 switch (event) {
1173 case NETDEV_REGISTER:
Joe Perches91df42b2012-05-15 14:11:54 +00001174 pr_debug("%s: bug\n", __func__);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001175 RCU_INIT_POINTER(dev->ip_ptr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 break;
1177 case NETDEV_UP:
Breno Leitao06770842008-09-02 17:28:58 -07001178 if (!inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 break;
Eric W. Biederman0cc217e2007-09-26 22:10:06 -07001180 if (dev->flags & IFF_LOOPBACK) {
Eric Dumazet9f9354b2009-11-04 22:05:10 -08001181 struct in_ifaddr *ifa = inet_alloc_ifa();
1182
1183 if (ifa) {
David S. Millerfd23c3b2011-02-18 12:42:28 -08001184 INIT_HLIST_NODE(&ifa->hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 ifa->ifa_local =
1186 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1187 ifa->ifa_prefixlen = 8;
1188 ifa->ifa_mask = inet_make_mask(8);
1189 in_dev_hold(in_dev);
1190 ifa->ifa_dev = in_dev;
1191 ifa->ifa_scope = RT_SCOPE_HOST;
1192 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1193 inet_insert_ifa(ifa);
1194 }
1195 }
1196 ip_mc_up(in_dev);
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001197 /* fall through */
1198 case NETDEV_CHANGEADDR:
Ian Campbelld11327ad2011-02-11 07:44:16 +00001199 if (!IN_DEV_ARP_NOTIFY(in_dev))
1200 break;
1201 /* fall through */
1202 case NETDEV_NOTIFY_PEERS:
Stephen Hemmingera21090c2009-10-07 03:18:17 -07001203 /* Send gratuitous ARP to notify of link change */
Ian Campbelld11327ad2011-02-11 07:44:16 +00001204 inetdev_send_gratuitous_arp(dev, in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 break;
1206 case NETDEV_DOWN:
1207 ip_mc_down(in_dev);
1208 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001209 case NETDEV_PRE_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001210 ip_mc_unmap(in_dev);
1211 break;
Jiri Pirko93d9b7d2010-03-10 10:28:56 +00001212 case NETDEV_POST_TYPE_CHANGE:
Moni Shoua75c78502009-09-15 02:37:40 -07001213 ip_mc_remap(in_dev);
1214 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 case NETDEV_CHANGEMTU:
Breno Leitao06770842008-09-02 17:28:58 -07001216 if (inetdev_valid_mtu(dev->mtu))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 break;
Breno Leitao06770842008-09-02 17:28:58 -07001218 /* disable IP when MTU is not enough */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 case NETDEV_UNREGISTER:
1220 inetdev_destroy(in_dev);
1221 break;
1222 case NETDEV_CHANGENAME:
1223 /* Do not notify about label change, this event is
1224 * not interesting to applications using netlink.
1225 */
1226 inetdev_changename(dev, in_dev);
1227
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001228 devinet_sysctl_unregister(in_dev);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001229 devinet_sysctl_register(in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 break;
1231 }
1232out:
1233 return NOTIFY_DONE;
1234}
1235
1236static struct notifier_block ip_netdev_notifier = {
Jianjun Kong539afed2008-11-03 02:48:48 -08001237 .notifier_call = inetdev_event,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238};
1239
Eric Dumazet40384992012-08-03 21:06:50 +00001240static size_t inet_nlmsg_size(void)
Thomas Graf339bf982006-11-10 14:10:15 -08001241{
1242 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
1243 + nla_total_size(4) /* IFA_ADDRESS */
1244 + nla_total_size(4) /* IFA_LOCAL */
1245 + nla_total_size(4) /* IFA_BROADCAST */
Thomas Graf339bf982006-11-10 14:10:15 -08001246 + nla_total_size(IFNAMSIZ); /* IFA_LABEL */
1247}
1248
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001250 u32 portid, u32 seq, int event, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251{
1252 struct ifaddrmsg *ifm;
1253 struct nlmsghdr *nlh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254
Eric W. Biederman15e47302012-09-07 20:12:54 +00001255 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
Thomas Graf47f68512006-08-04 23:04:36 -07001256 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001257 return -EMSGSIZE;
Thomas Graf47f68512006-08-04 23:04:36 -07001258
1259 ifm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 ifm->ifa_family = AF_INET;
1261 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
1262 ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT;
1263 ifm->ifa_scope = ifa->ifa_scope;
1264 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265
David S. Millerf3756b72012-04-01 20:39:02 -04001266 if ((ifa->ifa_address &&
1267 nla_put_be32(skb, IFA_ADDRESS, ifa->ifa_address)) ||
1268 (ifa->ifa_local &&
1269 nla_put_be32(skb, IFA_LOCAL, ifa->ifa_local)) ||
1270 (ifa->ifa_broadcast &&
1271 nla_put_be32(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
1272 (ifa->ifa_label[0] &&
1273 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)))
1274 goto nla_put_failure;
Thomas Graf47f68512006-08-04 23:04:36 -07001275
1276 return nlmsg_end(skb, nlh);
1277
1278nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08001279 nlmsg_cancel(skb, nlh);
1280 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281}
1282
1283static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1284{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001285 struct net *net = sock_net(skb->sk);
Eric Dumazeteec4df92009-11-12 07:44:25 +00001286 int h, s_h;
1287 int idx, s_idx;
1288 int ip_idx, s_ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 struct net_device *dev;
1290 struct in_device *in_dev;
1291 struct in_ifaddr *ifa;
Eric Dumazeteec4df92009-11-12 07:44:25 +00001292 struct hlist_head *head;
1293 struct hlist_node *node;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294
Eric Dumazeteec4df92009-11-12 07:44:25 +00001295 s_h = cb->args[0];
1296 s_idx = idx = cb->args[1];
1297 s_ip_idx = ip_idx = cb->args[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
Eric Dumazeteec4df92009-11-12 07:44:25 +00001299 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1300 idx = 0;
1301 head = &net->dev_index_head[h];
1302 rcu_read_lock();
1303 hlist_for_each_entry_rcu(dev, node, head, index_hlist) {
1304 if (idx < s_idx)
1305 goto cont;
Patrick McHardy4b97efd2010-03-26 20:27:49 -07001306 if (h > s_h || idx > s_idx)
Eric Dumazeteec4df92009-11-12 07:44:25 +00001307 s_ip_idx = 0;
1308 in_dev = __in_dev_get_rcu(dev);
1309 if (!in_dev)
1310 goto cont;
1311
1312 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1313 ifa = ifa->ifa_next, ip_idx++) {
1314 if (ip_idx < s_ip_idx)
1315 continue;
1316 if (inet_fill_ifaddr(skb, ifa,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001317 NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 cb->nlh->nlmsg_seq,
Eric Dumazeteec4df92009-11-12 07:44:25 +00001319 RTM_NEWADDR, NLM_F_MULTI) <= 0) {
1320 rcu_read_unlock();
1321 goto done;
1322 }
1323 }
Pavel Emelianov7562f872007-05-03 15:13:45 -07001324cont:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001325 idx++;
1326 }
1327 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 }
1329
1330done:
Eric Dumazeteec4df92009-11-12 07:44:25 +00001331 cb->args[0] = h;
1332 cb->args[1] = idx;
1333 cb->args[2] = ip_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334
1335 return skb->len;
1336}
1337
Jianjun Kong539afed2008-11-03 02:48:48 -08001338static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001339 u32 portid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340{
Thomas Graf47f68512006-08-04 23:04:36 -07001341 struct sk_buff *skb;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001342 u32 seq = nlh ? nlh->nlmsg_seq : 0;
1343 int err = -ENOBUFS;
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001344 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001346 net = dev_net(ifa->ifa_dev->dev);
Thomas Graf339bf982006-11-10 14:10:15 -08001347 skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
Thomas Graf47f68512006-08-04 23:04:36 -07001348 if (skb == NULL)
Thomas Grafd6062cb2006-08-15 00:33:59 -07001349 goto errout;
1350
Eric W. Biederman15e47302012-09-07 20:12:54 +00001351 err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08001352 if (err < 0) {
1353 /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
1354 WARN_ON(err == -EMSGSIZE);
1355 kfree_skb(skb);
1356 goto errout;
1357 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001358 rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001359 return;
Thomas Grafd6062cb2006-08-15 00:33:59 -07001360errout:
1361 if (err < 0)
Denis V. Lunev4b8aa9a2008-01-31 18:47:40 -08001362 rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363}
1364
Thomas Graf9f0f7272010-11-16 04:32:48 +00001365static size_t inet_get_link_af_size(const struct net_device *dev)
1366{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001367 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001368
1369 if (!in_dev)
1370 return 0;
1371
1372 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
1373}
1374
1375static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
1376{
Eric Dumazet1fc19af2011-05-09 20:55:03 -07001377 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
Thomas Graf9f0f7272010-11-16 04:32:48 +00001378 struct nlattr *nla;
1379 int i;
1380
1381 if (!in_dev)
1382 return -ENODATA;
1383
1384 nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4);
1385 if (nla == NULL)
1386 return -EMSGSIZE;
1387
1388 for (i = 0; i < IPV4_DEVCONF_MAX; i++)
1389 ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i];
1390
1391 return 0;
1392}
1393
1394static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1395 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1396};
1397
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001398static int inet_validate_link_af(const struct net_device *dev,
1399 const struct nlattr *nla)
Thomas Graf9f0f7272010-11-16 04:32:48 +00001400{
Thomas Graf9f0f7272010-11-16 04:32:48 +00001401 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1402 int err, rem;
1403
Eric Dumazetf7fce742010-12-01 06:03:06 +00001404 if (dev && !__in_dev_get_rtnl(dev))
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001405 return -EAFNOSUPPORT;
Thomas Graf9f0f7272010-11-16 04:32:48 +00001406
1407 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy);
1408 if (err < 0)
1409 return err;
1410
1411 if (tb[IFLA_INET_CONF]) {
1412 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
1413 int cfgid = nla_type(a);
1414
1415 if (nla_len(a) < 4)
1416 return -EINVAL;
1417
1418 if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX)
1419 return -EINVAL;
1420 }
1421 }
1422
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001423 return 0;
1424}
1425
1426static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1427{
Eric Dumazetf7fce742010-12-01 06:03:06 +00001428 struct in_device *in_dev = __in_dev_get_rtnl(dev);
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001429 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1430 int rem;
1431
1432 if (!in_dev)
1433 return -EAFNOSUPPORT;
1434
1435 if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL) < 0)
1436 BUG();
1437
Thomas Graf9f0f7272010-11-16 04:32:48 +00001438 if (tb[IFLA_INET_CONF]) {
1439 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1440 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
1441 }
1442
1443 return 0;
1444}
1445
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001446static int inet_netconf_msgsize_devconf(int type)
1447{
1448 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1449 + nla_total_size(4); /* NETCONFA_IFINDEX */
1450
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001451 /* type -1 is used for ALL */
1452 if (type == -1 || type == NETCONFA_FORWARDING)
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001453 size += nla_total_size(4);
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001454 if (type == -1 || type == NETCONFA_RP_FILTER)
1455 size += nla_total_size(4);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001456
1457 return size;
1458}
1459
1460static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1461 struct ipv4_devconf *devconf, u32 portid,
1462 u32 seq, int event, unsigned int flags,
1463 int type)
1464{
1465 struct nlmsghdr *nlh;
1466 struct netconfmsg *ncm;
1467
1468 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1469 flags);
1470 if (nlh == NULL)
1471 return -EMSGSIZE;
1472
1473 ncm = nlmsg_data(nlh);
1474 ncm->ncm_family = AF_INET;
1475
1476 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1477 goto nla_put_failure;
1478
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001479 /* type -1 is used for ALL */
1480 if ((type == -1 || type == NETCONFA_FORWARDING) &&
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001481 nla_put_s32(skb, NETCONFA_FORWARDING,
1482 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1483 goto nla_put_failure;
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001484 if ((type == -1 || type == NETCONFA_RP_FILTER) &&
1485 nla_put_s32(skb, NETCONFA_RP_FILTER,
1486 IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
1487 goto nla_put_failure;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001488
1489 return nlmsg_end(skb, nlh);
1490
1491nla_put_failure:
1492 nlmsg_cancel(skb, nlh);
1493 return -EMSGSIZE;
1494}
1495
1496static void inet_netconf_notify_devconf(struct net *net, int type, int ifindex,
1497 struct ipv4_devconf *devconf)
1498{
1499 struct sk_buff *skb;
1500 int err = -ENOBUFS;
1501
1502 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_ATOMIC);
1503 if (skb == NULL)
1504 goto errout;
1505
1506 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
1507 RTM_NEWNETCONF, 0, type);
1508 if (err < 0) {
1509 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1510 WARN_ON(err == -EMSGSIZE);
1511 kfree_skb(skb);
1512 goto errout;
1513 }
1514 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_ATOMIC);
1515 return;
1516errout:
1517 if (err < 0)
1518 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
1519}
1520
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001521static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
1522 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
1523 [NETCONFA_FORWARDING] = { .len = sizeof(int) },
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001524 [NETCONFA_RP_FILTER] = { .len = sizeof(int) },
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001525};
1526
1527static int inet_netconf_get_devconf(struct sk_buff *in_skb,
1528 struct nlmsghdr *nlh,
1529 void *arg)
1530{
1531 struct net *net = sock_net(in_skb->sk);
1532 struct nlattr *tb[NETCONFA_MAX+1];
1533 struct netconfmsg *ncm;
1534 struct sk_buff *skb;
1535 struct ipv4_devconf *devconf;
1536 struct in_device *in_dev;
1537 struct net_device *dev;
1538 int ifindex;
1539 int err;
1540
1541 err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
1542 devconf_ipv4_policy);
1543 if (err < 0)
1544 goto errout;
1545
1546 err = EINVAL;
1547 if (!tb[NETCONFA_IFINDEX])
1548 goto errout;
1549
1550 ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
1551 switch (ifindex) {
1552 case NETCONFA_IFINDEX_ALL:
1553 devconf = net->ipv4.devconf_all;
1554 break;
1555 case NETCONFA_IFINDEX_DEFAULT:
1556 devconf = net->ipv4.devconf_dflt;
1557 break;
1558 default:
1559 dev = __dev_get_by_index(net, ifindex);
1560 if (dev == NULL)
1561 goto errout;
1562 in_dev = __in_dev_get_rtnl(dev);
1563 if (in_dev == NULL)
1564 goto errout;
1565 devconf = &in_dev->cnf;
1566 break;
1567 }
1568
1569 err = -ENOBUFS;
1570 skb = nlmsg_new(inet_netconf_msgsize_devconf(-1), GFP_ATOMIC);
1571 if (skb == NULL)
1572 goto errout;
1573
1574 err = inet_netconf_fill_devconf(skb, ifindex, devconf,
1575 NETLINK_CB(in_skb).portid,
1576 nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
1577 -1);
1578 if (err < 0) {
1579 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1580 WARN_ON(err == -EMSGSIZE);
1581 kfree_skb(skb);
1582 goto errout;
1583 }
1584 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
1585errout:
1586 return err;
1587}
1588
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589#ifdef CONFIG_SYSCTL
1590
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001591static void devinet_copy_dflt_conf(struct net *net, int i)
Herbert Xu31be3082007-06-04 23:35:37 -07001592{
1593 struct net_device *dev;
1594
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001595 rcu_read_lock();
1596 for_each_netdev_rcu(net, dev) {
Herbert Xu31be3082007-06-04 23:35:37 -07001597 struct in_device *in_dev;
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001598
Herbert Xu31be3082007-06-04 23:35:37 -07001599 in_dev = __in_dev_get_rcu(dev);
1600 if (in_dev && !test_bit(i, in_dev->cnf.state))
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001601 in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
Herbert Xu31be3082007-06-04 23:35:37 -07001602 }
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001603 rcu_read_unlock();
Herbert Xu31be3082007-06-04 23:35:37 -07001604}
1605
Eric Dumazetc6d14c82009-11-04 05:43:23 -08001606/* called with RTNL locked */
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001607static void inet_forward_change(struct net *net)
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001608{
1609 struct net_device *dev;
Pavel Emelyanov586f1212007-12-16 13:32:48 -08001610 int on = IPV4_DEVCONF_ALL(net, FORWARDING);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001611
Pavel Emelyanov586f1212007-12-16 13:32:48 -08001612 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001613 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001614 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1615 NETCONFA_IFINDEX_ALL,
1616 net->ipv4.devconf_all);
1617 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1618 NETCONFA_IFINDEX_DEFAULT,
1619 net->ipv4.devconf_dflt);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001620
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001621 for_each_netdev(net, dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001622 struct in_device *in_dev;
Ben Hutchings0187bdf2008-06-19 16:15:47 -07001623 if (on)
1624 dev_disable_lro(dev);
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001625 rcu_read_lock();
1626 in_dev = __in_dev_get_rcu(dev);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001627 if (in_dev) {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001628 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001629 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1630 dev->ifindex, &in_dev->cnf);
1631 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001632 rcu_read_unlock();
1633 }
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001634}
1635
Herbert Xu31be3082007-06-04 23:35:37 -07001636static int devinet_conf_proc(ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001637 void __user *buffer,
Herbert Xu31be3082007-06-04 23:35:37 -07001638 size_t *lenp, loff_t *ppos)
1639{
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00001640 int old_value = *(int *)ctl->data;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001641 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00001642 int new_value = *(int *)ctl->data;
Herbert Xu31be3082007-06-04 23:35:37 -07001643
1644 if (write) {
1645 struct ipv4_devconf *cnf = ctl->extra1;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001646 struct net *net = ctl->extra2;
Herbert Xu31be3082007-06-04 23:35:37 -07001647 int i = (int *)ctl->data - cnf->data;
1648
1649 set_bit(i, cnf->state);
1650
Pavel Emelyanov9355bbd2007-12-16 13:32:16 -08001651 if (cnf == net->ipv4.devconf_dflt)
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001652 devinet_copy_dflt_conf(net, i);
Thomas Grafd0daebc32012-06-12 00:44:01 +00001653 if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
1654 i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
Peter Pan(潘卫平)d01ff0a2011-12-01 15:47:06 +00001655 if ((new_value == 0) && (old_value != 0))
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00001656 rt_cache_flush(net);
Nicolas Dichtelcc535df2012-10-29 04:53:27 +00001657 if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
1658 new_value != old_value) {
1659 int ifindex;
1660
1661 if (cnf == net->ipv4.devconf_dflt)
1662 ifindex = NETCONFA_IFINDEX_DEFAULT;
1663 else if (cnf == net->ipv4.devconf_all)
1664 ifindex = NETCONFA_IFINDEX_ALL;
1665 else {
1666 struct in_device *idev =
1667 container_of(cnf, struct in_device,
1668 cnf);
1669 ifindex = idev->dev->ifindex;
1670 }
1671 inet_netconf_notify_devconf(net, NETCONFA_RP_FILTER,
1672 ifindex, cnf);
1673 }
Herbert Xu31be3082007-06-04 23:35:37 -07001674 }
1675
1676 return ret;
1677}
1678
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679static int devinet_sysctl_forward(ctl_table *ctl, int write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001680 void __user *buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 size_t *lenp, loff_t *ppos)
1682{
1683 int *valp = ctl->data;
1684 int val = *valp;
Eric W. Biederman88af1822010-02-19 13:22:59 +00001685 loff_t pos = *ppos;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001686 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
1688 if (write && *valp != val) {
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001689 struct net *net = ctl->extra2;
1690
Ben Hutchings0187bdf2008-06-19 16:15:47 -07001691 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
Eric W. Biederman88af1822010-02-19 13:22:59 +00001692 if (!rtnl_trylock()) {
1693 /* Restore the original values before restarting */
1694 *valp = val;
1695 *ppos = pos;
Eric W. Biederman9b8adb52009-05-13 16:59:21 +00001696 return restart_syscall();
Eric W. Biederman88af1822010-02-19 13:22:59 +00001697 }
Ben Hutchings0187bdf2008-06-19 16:15:47 -07001698 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
1699 inet_forward_change(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001700 } else {
Ben Hutchings0187bdf2008-06-19 16:15:47 -07001701 struct ipv4_devconf *cnf = ctl->extra1;
1702 struct in_device *idev =
1703 container_of(cnf, struct in_device, cnf);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001704 if (*valp)
1705 dev_disable_lro(idev->dev);
1706 inet_netconf_notify_devconf(net,
1707 NETCONFA_FORWARDING,
1708 idev->dev->ifindex,
1709 cnf);
Ben Hutchings0187bdf2008-06-19 16:15:47 -07001710 }
1711 rtnl_unlock();
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00001712 rt_cache_flush(net);
Nicolas Dichteledc9e742012-10-25 22:28:52 +00001713 } else
1714 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1715 NETCONFA_IFINDEX_DEFAULT,
1716 net->ipv4.devconf_dflt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 }
1718
1719 return ret;
1720}
1721
David S. Miller323e1262010-12-12 21:55:08 -08001722static int ipv4_doint_and_flush(ctl_table *ctl, int write,
1723 void __user *buffer,
1724 size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725{
1726 int *valp = ctl->data;
1727 int val = *valp;
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001728 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Denis V. Lunev76e6ebf2008-07-05 19:00:44 -07001729 struct net *net = ctl->extra2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730
1731 if (write && *valp != val)
Nicolas Dichtel4ccfe6d2012-09-07 00:45:29 +00001732 rt_cache_flush(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733
1734 return ret;
1735}
1736
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001737#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
Herbert Xu42f811b2007-06-04 23:34:44 -07001738 { \
Herbert Xu42f811b2007-06-04 23:34:44 -07001739 .procname = name, \
1740 .data = ipv4_devconf.data + \
Eric W. Biederman02291682010-02-14 03:25:51 +00001741 IPV4_DEVCONF_ ## attr - 1, \
Herbert Xu42f811b2007-06-04 23:34:44 -07001742 .maxlen = sizeof(int), \
1743 .mode = mval, \
1744 .proc_handler = proc, \
Herbert Xu31be3082007-06-04 23:35:37 -07001745 .extra1 = &ipv4_devconf, \
Herbert Xu42f811b2007-06-04 23:34:44 -07001746 }
1747
1748#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001749 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07001750
1751#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001752 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07001753
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001754#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
1755 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
Herbert Xu42f811b2007-06-04 23:34:44 -07001756
1757#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001758 DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
Herbert Xu42f811b2007-06-04 23:34:44 -07001759
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760static struct devinet_sysctl_table {
1761 struct ctl_table_header *sysctl_header;
Eric W. Biederman02291682010-02-14 03:25:51 +00001762 struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763} devinet_sysctl = {
1764 .devinet_vars = {
Herbert Xu42f811b2007-06-04 23:34:44 -07001765 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001766 devinet_sysctl_forward),
Herbert Xu42f811b2007-06-04 23:34:44 -07001767 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
1768
1769 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
1770 DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
1771 DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),
1772 DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),
1773 DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
1774 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
1775 "accept_source_route"),
Patrick McHardy8153a102009-12-03 01:25:58 +00001776 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
Jamal Hadi Salim28f6aee2009-12-25 17:30:22 -08001777 DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
Herbert Xu42f811b2007-06-04 23:34:44 -07001778 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
1779 DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
1780 DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
1781 DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
1782 DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
1783 DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
1784 DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
1785 DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
1786 DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
Stephen Hemmingereefef1c2009-02-01 01:04:33 -08001787 DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
Jesper Dangaard Brouer65324142010-01-05 05:50:47 +00001788 DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
Herbert Xu42f811b2007-06-04 23:34:44 -07001789
1790 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
1791 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
1792 DEVINET_SYSCTL_FLUSHING_ENTRY(FORCE_IGMP_VERSION,
1793 "force_igmp_version"),
1794 DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
1795 "promote_secondaries"),
Thomas Grafd0daebc32012-06-12 00:44:01 +00001796 DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
1797 "route_localnet"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799};
1800
Pavel Emelyanovea40b322007-12-16 13:30:07 -08001801static int __devinet_sysctl_register(struct net *net, char *dev_name,
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001802 struct ipv4_devconf *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803{
1804 int i;
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001805 struct devinet_sysctl_table *t;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00001806 char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
Pavel Emelyanovbfada692007-12-02 00:57:08 +11001807
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001808 t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 if (!t)
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001810 goto out;
1811
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
1813 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
Herbert Xu31be3082007-06-04 23:35:37 -07001814 t->devinet_vars[i].extra1 = p;
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001815 t->devinet_vars[i].extra2 = net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 }
1817
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00001818 snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00001820 t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 if (!t->sysctl_header)
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00001822 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823
1824 p->sysctl = t;
Pavel Emelyanovea40b322007-12-16 13:30:07 -08001825 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001827free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 kfree(t);
Pavel Emelyanov9fa89642007-12-02 00:17:46 +11001829out:
Pavel Emelyanovea40b322007-12-16 13:30:07 -08001830 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831}
1832
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001833static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
1834{
1835 struct devinet_sysctl_table *t = cnf->sysctl;
1836
1837 if (t == NULL)
1838 return;
1839
1840 cnf->sysctl = NULL;
Lucian Adrian Grijincuff538812011-05-01 01:44:01 +00001841 unregister_net_sysctl_table(t->sysctl_header);
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001842 kfree(t);
1843}
1844
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001845static void devinet_sysctl_register(struct in_device *idev)
1846{
Eric W. Biederman54716e32010-02-14 03:27:03 +00001847 neigh_sysctl_register(idev->dev, idev->arp_parms, "ipv4", NULL);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001848 __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001849 &idev->cnf);
Pavel Emelyanov66f27a52007-12-02 00:55:54 +11001850}
1851
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001852static void devinet_sysctl_unregister(struct in_device *idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853{
Pavel Emelyanov51602b22007-12-11 02:17:40 -08001854 __devinet_sysctl_unregister(&idev->cnf);
1855 neigh_sysctl_unregister(idev->arp_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001858static struct ctl_table ctl_forward_entry[] = {
1859 {
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001860 .procname = "ip_forward",
1861 .data = &ipv4_devconf.data[
Eric W. Biederman02291682010-02-14 03:25:51 +00001862 IPV4_DEVCONF_FORWARDING - 1],
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001863 .maxlen = sizeof(int),
1864 .mode = 0644,
1865 .proc_handler = devinet_sysctl_forward,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001866 .extra1 = &ipv4_devconf,
Pavel Emelyanovc0ce9fb2007-12-16 13:31:14 -08001867 .extra2 = &init_net,
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001868 },
1869 { },
1870};
Eric Dumazet2a75de02008-01-05 23:08:49 -08001871#endif
Pavel Emelyanov68dd2992007-12-05 01:44:58 -08001872
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001873static __net_init int devinet_init_net(struct net *net)
1874{
1875 int err;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001876 struct ipv4_devconf *all, *dflt;
Eric Dumazet2a75de02008-01-05 23:08:49 -08001877#ifdef CONFIG_SYSCTL
1878 struct ctl_table *tbl = ctl_forward_entry;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001879 struct ctl_table_header *forw_hdr;
Eric Dumazet2a75de02008-01-05 23:08:49 -08001880#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001881
1882 err = -ENOMEM;
1883 all = &ipv4_devconf;
1884 dflt = &ipv4_devconf_dflt;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001885
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08001886 if (!net_eq(net, &init_net)) {
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001887 all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
1888 if (all == NULL)
1889 goto err_alloc_all;
1890
1891 dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
1892 if (dflt == NULL)
1893 goto err_alloc_dflt;
1894
Eric Dumazet2a75de02008-01-05 23:08:49 -08001895#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001896 tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
1897 if (tbl == NULL)
1898 goto err_alloc_ctl;
1899
Eric W. Biederman02291682010-02-14 03:25:51 +00001900 tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001901 tbl[0].extra1 = all;
1902 tbl[0].extra2 = net;
Eric Dumazet2a75de02008-01-05 23:08:49 -08001903#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001904 }
1905
1906#ifdef CONFIG_SYSCTL
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001907 err = __devinet_sysctl_register(net, "all", all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001908 if (err < 0)
1909 goto err_reg_all;
1910
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001911 err = __devinet_sysctl_register(net, "default", dflt);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001912 if (err < 0)
1913 goto err_reg_dflt;
1914
1915 err = -ENOMEM;
Eric W. Biederman8607ddb2012-04-19 13:42:09 +00001916 forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001917 if (forw_hdr == NULL)
1918 goto err_reg_ctl;
Eric Dumazet2a75de02008-01-05 23:08:49 -08001919 net->ipv4.forw_hdr = forw_hdr;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001920#endif
1921
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001922 net->ipv4.devconf_all = all;
1923 net->ipv4.devconf_dflt = dflt;
1924 return 0;
1925
1926#ifdef CONFIG_SYSCTL
1927err_reg_ctl:
1928 __devinet_sysctl_unregister(dflt);
1929err_reg_dflt:
1930 __devinet_sysctl_unregister(all);
1931err_reg_all:
1932 if (tbl != ctl_forward_entry)
1933 kfree(tbl);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001934err_alloc_ctl:
Eric Dumazet2a75de02008-01-05 23:08:49 -08001935#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001936 if (dflt != &ipv4_devconf_dflt)
1937 kfree(dflt);
1938err_alloc_dflt:
1939 if (all != &ipv4_devconf)
1940 kfree(all);
1941err_alloc_all:
1942 return err;
1943}
1944
1945static __net_exit void devinet_exit_net(struct net *net)
1946{
Eric Dumazet2a75de02008-01-05 23:08:49 -08001947#ifdef CONFIG_SYSCTL
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001948 struct ctl_table *tbl;
1949
1950 tbl = net->ipv4.forw_hdr->ctl_table_arg;
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001951 unregister_net_sysctl_table(net->ipv4.forw_hdr);
1952 __devinet_sysctl_unregister(net->ipv4.devconf_dflt);
1953 __devinet_sysctl_unregister(net->ipv4.devconf_all);
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001954 kfree(tbl);
Eric Dumazet2a75de02008-01-05 23:08:49 -08001955#endif
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001956 kfree(net->ipv4.devconf_dflt);
1957 kfree(net->ipv4.devconf_all);
1958}
1959
1960static __net_initdata struct pernet_operations devinet_ops = {
1961 .init = devinet_init_net,
1962 .exit = devinet_exit_net,
1963};
1964
Thomas Graf9f0f7272010-11-16 04:32:48 +00001965static struct rtnl_af_ops inet_af_ops = {
1966 .family = AF_INET,
1967 .fill_link_af = inet_fill_link_af,
1968 .get_link_af_size = inet_get_link_af_size,
Thomas Grafcf7afbf2010-11-22 01:31:54 +00001969 .validate_link_af = inet_validate_link_af,
1970 .set_link_af = inet_set_link_af,
Thomas Graf9f0f7272010-11-16 04:32:48 +00001971};
1972
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973void __init devinet_init(void)
1974{
David S. Millerfd23c3b2011-02-18 12:42:28 -08001975 int i;
1976
1977 for (i = 0; i < IN4_ADDR_HSIZE; i++)
1978 INIT_HLIST_HEAD(&inet_addr_lst[i]);
1979
Pavel Emelyanov752d14d2007-12-16 13:31:47 -08001980 register_pernet_subsys(&devinet_ops);
1981
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 register_gifconf(PF_INET, inet_gifconf);
1983 register_netdevice_notifier(&ip_netdev_notifier);
Thomas Graf63f34442007-03-22 11:55:17 -07001984
Thomas Graf9f0f7272010-11-16 04:32:48 +00001985 rtnl_af_register(&inet_af_ops);
1986
Greg Rosec7ac8672011-06-10 01:27:09 +00001987 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL);
1988 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, NULL);
1989 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, NULL);
Nicolas Dichtel9e551112012-10-25 22:28:53 +00001990 rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
1991 NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992}
1993