Release 4.11 net/ipv4/devinet.c
/*
* NET3 IP device support routines.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Derived from the IP parts of dev.c 1.0.19
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
*
* Additional Authors:
* Alan Cox, <gw4pts@gw4pts.ampr.org>
* Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
* Changes:
* Alexey Kuznetsov: pa_* fields are replaced with ifaddr
* lists.
* Cyrus Durgin: updated for kmod
* Matthias Andree: in devinet_ioctl, compare label and
* address (4.4BSD alias style support),
* fall back to comparing just the label
* if no match found.
*/
#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/capability.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched/signal.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/in.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/if_addr.h>
#include <linux/if_ether.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/notifier.h>
#include <linux/inetdevice.h>
#include <linux/igmp.h>
#include <linux/slab.h>
#include <linux/hash.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif
#include <linux/kmod.h>
#include <linux/netconf.h>
#include <net/arp.h>
#include <net/ip.h>
#include <net/route.h>
#include <net/ip_fib.h>
#include <net/rtnetlink.h>
#include <net/net_namespace.h>
#include <net/addrconf.h>
static struct ipv4_devconf ipv4_devconf = {
.data = {
[IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
[IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
[IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
[IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
[IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
[IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
},
};
static struct ipv4_devconf ipv4_devconf_dflt = {
.data = {
[IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
[IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
[IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
[IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
[IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
[IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
[IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
},
};
#define IPV4_DEVCONF_DFLT(net, attr) \
IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr)
static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
[IFA_LOCAL] = { .type = NLA_U32 },
[IFA_ADDRESS] = { .type = NLA_U32 },
[IFA_BROADCAST] = { .type = NLA_U32 },
[IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
[IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
[IFA_FLAGS] = { .type = NLA_U32 },
};
#define IN4_ADDR_HSIZE_SHIFT 8
#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT)
static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
static u32 inet_addr_hash(const struct net *net, __be32 addr)
{
u32 val = (__force u32) addr ^ net_hash_mix(net);
return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 29 | 78.38% | 1 | 33.33% |
Eric Dumazet | 8 | 21.62% | 2 | 66.67% |
Total | 37 | 100.00% | 3 | 100.00% |
static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
{
u32 hash = inet_addr_hash(net, ifa->ifa_local);
ASSERT_RTNL();
hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 42 | 93.33% | 2 | 50.00% |
Américo Wang | 2 | 4.44% | 1 | 25.00% |
Eric Dumazet | 1 | 2.22% | 1 | 25.00% |
Total | 45 | 100.00% | 4 | 100.00% |
static void inet_hash_remove(struct in_ifaddr *ifa)
{
ASSERT_RTNL();
hlist_del_init_rcu(&ifa->hash);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 20 | 90.91% | 1 | 50.00% |
Américo Wang | 2 | 9.09% | 1 | 50.00% |
Total | 22 | 100.00% | 2 | 100.00% |
/**
* __ip_dev_find - find the first device with a given source address.
* @net: the net namespace
* @addr: the source address
* @devref: if true, take a reference on the found device
*
* If a caller uses devref=false, it should be protected by RCU, or RTNL
*/
struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
{
u32 hash = inet_addr_hash(net, addr);
struct net_device *result = NULL;
struct in_ifaddr *ifa;
rcu_read_lock();
hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash) {
if (ifa->ifa_local == addr) {
struct net_device *dev = ifa->ifa_dev->dev;
if (!net_eq(dev_net(dev), net))
continue;
result = dev;
break;
}
}
if (!result) {
struct flowi4 fl4 = { .daddr = addr };
struct fib_result res = { 0 };
struct fib_table *local;
/* Fallback to FIB local table so that communication
* over loopback subnets work.
*/
local = fib_get_table(net, RT_TABLE_LOCAL);
if (local &&
!fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) &&
res.type == RTN_LOCAL)
result = FIB_RES_DEV(res);
}
if (result && devref)
dev_hold(result);
rcu_read_unlock();
return result;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 172 | 94.51% | 2 | 66.67% |
Eric Dumazet | 10 | 5.49% | 1 | 33.33% |
Total | 182 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(__ip_dev_find);
static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
int destroy);
#ifdef CONFIG_SYSCTL
static int devinet_sysctl_register(struct in_device *idev);
static void devinet_sysctl_unregister(struct in_device *idev);
#else
static int devinet_sysctl_register(struct in_device *idev)
{
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Pavel Emelyanov | 8 | 57.14% | 1 | 50.00% |
Américo Wang | 6 | 42.86% | 1 | 50.00% |
Total | 14 | 100.00% | 2 | 100.00% |
static void devinet_sysctl_unregister(struct in_device *idev)
{
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Pavel Emelyanov | 10 | 100.00% | 1 | 100.00% |
Total | 10 | 100.00% | 1 | 100.00% |
#endif
/* Locks all the inet devices. */
static struct in_ifaddr *inet_alloc_ifa(void)
{
return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 18 | 81.82% | 3 | 60.00% |
Alexey Dobriyan | 3 | 13.64% | 1 | 20.00% |
Panagiotis Issaris | 1 | 4.55% | 1 | 20.00% |
Total | 22 | 100.00% | 5 | 100.00% |
static void inet_rcu_free_ifa(struct rcu_head *head)
{
struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
if (ifa->ifa_dev)
in_dev_put(ifa->ifa_dev);
kfree(ifa);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 24 | 54.55% | 4 | 66.67% |
Herbert Xu | 18 | 40.91% | 1 | 16.67% |
David S. Miller | 2 | 4.55% | 1 | 16.67% |
Total | 44 | 100.00% | 6 | 100.00% |
static void inet_free_ifa(struct in_ifaddr *ifa)
{
call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 10 | 47.62% | 1 | 25.00% |
Herbert Xu | 9 | 42.86% | 1 | 25.00% |
Linus Torvalds (pre-git) | 2 | 9.52% | 2 | 50.00% |
Total | 21 | 100.00% | 4 | 100.00% |
void in_dev_finish_destroy(struct in_device *idev)
{
struct net_device *dev = idev->dev;
WARN_ON(idev->ifa_list);
WARN_ON(idev->mc_list);
kfree(rcu_dereference_protected(idev->mc_hash, 1));
#ifdef NET_REFCNT_DEBUG
pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
#endif
dev_put(dev);
if (!idev->dead)
pr_err("Freeing alive in_device %p\n", idev);
else
kfree(idev);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 72 | 78.26% | 2 | 28.57% |
Eric Dumazet | 13 | 14.13% | 2 | 28.57% |
Joe Perches | 4 | 4.35% | 1 | 14.29% |
Ilpo Järvinen | 2 | 2.17% | 1 | 14.29% |
Arnaldo Carvalho de Melo | 1 | 1.09% | 1 | 14.29% |
Total | 92 | 100.00% | 7 | 100.00% |
EXPORT_SYMBOL(in_dev_finish_destroy);
static struct in_device *inetdev_init(struct net_device *dev)
{
struct in_device *in_dev;
int err = -ENOMEM;
ASSERT_RTNL();
in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
if (!in_dev)
goto out;
memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
sizeof(in_dev->cnf));
in_dev->cnf.sysctl = NULL;
in_dev->dev = dev;
in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
if (!in_dev->arp_parms)
goto out_kfree;
if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
dev_disable_lro(dev);
/* Reference in_dev->dev */
dev_hold(dev);
/* Account for reference dev->ip_ptr (below) */
in_dev_hold(in_dev);
err = devinet_sysctl_register(in_dev);
if (err) {
in_dev->dead = 1;
in_dev_put(in_dev);
in_dev = NULL;
goto out;
}
ip_mc_init_dev(in_dev);
if (dev->flags & IFF_UP)
ip_mc_up(in_dev);
/* we can receive as soon as ip_ptr is set -- do this last */
rcu_assign_pointer(dev->ip_ptr, in_dev);
out:
return in_dev ?: ERR_PTR(err);
out_kfree:
kfree(in_dev);
in_dev = NULL;
goto out;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 109 | 49.55% | 7 | 35.00% |
Américo Wang | 38 | 17.27% | 1 | 5.00% |
Arnaldo Carvalho de Melo | 20 | 9.09% | 1 | 5.00% |
Ben Hutchings | 16 | 7.27% | 1 | 5.00% |
David L Stevens | 15 | 6.82% | 2 | 10.00% |
Eric Dumazet | 8 | 3.64% | 2 | 10.00% |
Pavel Emelyanov | 5 | 2.27% | 1 | 5.00% |
Hideaki Yoshifuji / 吉藤英明 | 3 | 1.36% | 1 | 5.00% |
David S. Miller | 2 | 0.91% | 1 | 5.00% |
Jarek Poplawski | 2 | 0.91% | 1 | 5.00% |
Herbert Xu | 1 | 0.45% | 1 | 5.00% |
Panagiotis Issaris | 1 | 0.45% | 1 | 5.00% |
Total | 220 | 100.00% | 20 | 100.00% |
static void in_dev_rcu_put(struct rcu_head *head)
{
struct in_device *idev = container_of(head, struct in_device, rcu_head);
in_dev_put(idev);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 31 | 100.00% | 1 | 100.00% |
Total | 31 | 100.00% | 1 | 100.00% |
static void inetdev_destroy(struct in_device *in_dev)
{
struct in_ifaddr *ifa;
struct net_device *dev;
ASSERT_RTNL();
dev = in_dev->dev;
in_dev->dead = 1;
ip_mc_destroy_dev(in_dev);
while ((ifa = in_dev->ifa_list) != NULL) {
inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
inet_free_ifa(ifa);
}
RCU_INIT_POINTER(dev->ip_ptr, NULL);
devinet_sysctl_unregister(in_dev);
neigh_parms_release(&arp_tbl, in_dev->arp_parms);
arp_ifdown(dev);
call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 78 | 70.27% | 4 | 33.33% |
Herbert Xu | 24 | 21.62% | 4 | 33.33% |
Hideaki Yoshifuji / 吉藤英明 | 4 | 3.60% | 1 | 8.33% |
Eric Dumazet | 3 | 2.70% | 1 | 8.33% |
Pavel Emelyanov | 1 | 0.90% | 1 | 8.33% |
Stephen Hemminger | 1 | 0.90% | 1 | 8.33% |
Total | 111 | 100.00% | 12 | 100.00% |
int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
{
rcu_read_lock();
for_primary_ifa(in_dev) {
if (inet_ifa_match(a, ifa)) {
if (!b || inet_ifa_match(b, ifa)) {
rcu_read_unlock();
return 1;
}
}
} endfor_ifa(in_dev);
rcu_read_unlock();
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 59 | 88.06% | 5 | 71.43% |
David S. Miller | 6 | 8.96% | 1 | 14.29% |
Al Viro | 2 | 2.99% | 1 | 14.29% |
Total | 67 | 100.00% | 7 | 100.00% |
static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
int destroy, struct nlmsghdr *nlh, u32 portid)
{
struct in_ifaddr *promote = NULL;
struct in_ifaddr *ifa, *ifa1 = *ifap;
struct in_ifaddr *last_prim = in_dev->ifa_list;
struct in_ifaddr *prev_prom = NULL;
int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
ASSERT_RTNL();
if (in_dev->dead)
goto no_promotions;
/* 1. Deleting primary ifaddr forces deletion all secondaries
* unless alias promotion is set
**/
if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
struct in_ifaddr **ifap1 = &ifa1->ifa_next;
while ((ifa = *ifap1) != NULL) {
if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
ifa1->ifa_scope <= ifa->ifa_scope)
last_prim = ifa;
if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
ifa1->ifa_mask != ifa->ifa_mask ||
!inet_ifa_match(ifa1->ifa_address, ifa)) {
ifap1 = &ifa->ifa_next;
prev_prom = ifa;
continue;
}
if (!do_promote) {
inet_hash_remove(ifa);
*ifap1 = ifa->ifa_next;
rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
blocking_notifier_call_chain(&inetaddr_chain,
NETDEV_DOWN, ifa);
inet_free_ifa(ifa);
} else {
promote = ifa;
break;
}
}
}
/* On promotion all secondaries from subnet are changing
* the primary IP, we must remove all their routes silently
* and later to add them back with new prefsrc. Do this
* while all addresses are on the device list.
*/
for (ifa = promote; ifa; ifa = ifa->ifa_next) {
if (ifa1->ifa_mask == ifa->ifa_mask &&
inet_ifa_match(ifa1->ifa_address, ifa))
fib_del_ifaddr(ifa, ifa1);
}
no_promotions:
/* 2. Unlink it */
*ifap = ifa1->ifa_next;
inet_hash_remove(ifa1);
/* 3. Announce address deletion */
/* Send message first, then call notifier.
At first sight, FIB update triggered by notifier
will refer to already deleted ifaddr, that could confuse
netlink listeners. It is not true: look, gated sees
that route deleted and if it still thinks that ifaddr
is valid, it will try to restore deleted routes... Grr.
So that, this order is correct.
*/
rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
if (promote) {
struct in_ifaddr *next_sec = promote->ifa_next;
if (prev_prom) {
prev_prom->ifa_next = promote->ifa_next;
promote->ifa_next = last_prim->ifa_next;
last_prim->ifa_next = promote;
}
promote->ifa_flags &= ~IFA_F_SECONDARY;
rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
blocking_notifier_call_chain(&inetaddr_chain,
NETDEV_UP, promote);
for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
if (ifa1->ifa_mask != ifa->ifa_mask ||
!inet_ifa_match(ifa1->ifa_address, ifa))
continue;
fib_add_ifaddr(ifa);
}
}
if (destroy)
inet_free_ifa(ifa1);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 167 | 37.78% | 7 | 38.89% |
Jamal Hadi Salim | 130 | 29.41% | 1 | 5.56% |
Julian Anastasov | 53 | 11.99% | 2 | 11.11% |
Harald Welte | 45 | 10.18% | 1 | 5.56% |
David S. Miller | 21 | 4.75% | 2 | 11.11% |
Thomas Graf | 17 | 3.85% | 1 | 5.56% |
Eric W. Biedermann | 4 | 0.90% | 1 | 5.56% |
Alan Stern | 3 | 0.68% | 1 | 5.56% |
Herbert Xu | 1 | 0.23% | 1 | 5.56% |
Hideaki Yoshifuji / 吉藤英明 | 1 | 0.23% | 1 | 5.56% |
Total | 442 | 100.00% | 18 | 100.00% |
static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
int destroy)
{
__inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 31 | 93.94% | 1 | 50.00% |
Linus Torvalds (pre-git) | 2 | 6.06% | 1 | 50.00% |
Total | 33 | 100.00% | 2 | 100.00% |
static void check_lifetime(struct work_struct *work);
static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
u32 portid)
{
struct in_device *in_dev = ifa->ifa_dev;
struct in_ifaddr *ifa1, **ifap, **last_primary;
ASSERT_RTNL();
if (!ifa->ifa_local) {
inet_free_ifa(ifa);
return 0;
}
ifa->ifa_flags &= ~IFA_F_SECONDARY;
last_primary = &in_dev->ifa_list;
for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
ifap = &ifa1->ifa_next) {
if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
ifa->ifa_scope <= ifa1->ifa_scope)
last_primary = &ifa1->ifa_next;
if (ifa1->ifa_mask == ifa->ifa_mask &&
inet_ifa_match(ifa1->ifa_address, ifa)) {
if (ifa1->ifa_local == ifa->ifa_local) {
inet_free_ifa(ifa);
return -EEXIST;
}
if (ifa1->ifa_scope != ifa->ifa_scope) {
inet_free_ifa(ifa);
return -EINVAL;
}
ifa->ifa_flags |= IFA_F_SECONDARY;
}
}
if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
prandom_seed((__force u32) ifa->ifa_local);
ifap = last_primary;
}
ifa->ifa_next = *ifap;
*ifap = ifa;
inet_hash_insert(dev_net(in_dev->dev), ifa);
cancel_delayed_work(&check_lifetime_work);
queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
/* Send message first, then call notifier.
Notifier will trigger FIB update, so that
listeners of netlink will know about new ifaddr */
rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 237 | 81.72% | 5 | 35.71% |
Jiri Pirko | 13 | 4.48% | 1 | 7.14% |
Thomas Graf | 13 | 4.48% | 1 | 7.14% |
David S. Miller | 12 | 4.14% | 1 | 7.14% |
Aruna-Hewapathirane | 5 | 1.72% | 1 | 7.14% |
Viresh Kumar | 3 | 1.03% | 1 | 7.14% |
Herbert Xu | 3 | 1.03% | 1 | 7.14% |
Eric W. Biedermann | 2 | 0.69% | 1 | 7.14% |
Alan Stern | 1 | 0.34% | 1 | 7.14% |
Arnaldo Carvalho de Melo | 1 | 0.34% | 1 | 7.14% |
Total | 290 | 100.00% | 14 | 100.00% |
static int inet_insert_ifa(struct in_ifaddr *ifa)
{
return __inet_insert_ifa(ifa, NULL, 0);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 21 | 100.00% | 1 | 100.00% |
Total | 21 | 100.00% | 1 | 100.00% |
static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
{
struct in_device *in_dev = __in_dev_get_rtnl(dev);
ASSERT_RTNL();
if (!in_dev) {
inet_free_ifa(ifa);
return -ENOBUFS;
}
ipv4_devconf_setall(in_dev);
neigh_parms_data_state_setall(in_dev->arp_parms);
if (ifa->ifa_dev != in_dev) {
WARN_ON(ifa->ifa_dev);
in_dev_hold(in_dev);
ifa->ifa_dev = in_dev;
}
if (ipv4_is_loopback(ifa->ifa_local))
ifa->ifa_scope = RT_SCOPE_HOST;
return inet_insert_ifa(ifa);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 89 | 83.96% | 5 | 41.67% |
Herbert Xu | 7 | 6.60% | 3 | 25.00% |
Jiri Pirko | 7 | 6.60% | 1 | 8.33% |
Joe Perches | 1 | 0.94% | 1 | 8.33% |
Ilpo Järvinen | 1 | 0.94% | 1 | 8.33% |
Arnaldo Carvalho de Melo | 1 | 0.94% | 1 | 8.33% |
Total | 106 | 100.00% | 12 | 100.00% |
/* Caller must hold RCU or RTNL :
* We dont take a reference on found in_device
*/
struct in_device *inetdev_by_index(struct net *net, int ifindex)
{
struct net_device *dev;
struct in_device *in_dev = NULL;
rcu_read_lock();
dev = dev_get_by_index_rcu(net, ifindex);
if (dev)
in_dev = rcu_dereference_rtnl(dev->ip_ptr);
rcu_read_unlock();
return in_dev;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 43 | 74.14% | 5 | 55.56% |
Eric Dumazet | 8 | 13.79% | 2 | 22.22% |
Denis V. Lunev | 6 | 10.34% | 1 | 11.11% |
Eric W. Biedermann | 1 | 1.72% | 1 | 11.11% |
Total | 58 | 100.00% | 9 | 100.00% |
EXPORT_SYMBOL(inetdev_by_index);
/* Called only from RTNL semaphored context. No locks. */
struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
__be32 mask)
{
ASSERT_RTNL();
for_primary_ifa(in_dev) {
if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
return ifa;
} endfor_ifa(in_dev);
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 51 | 96.23% | 5 | 83.33% |
Al Viro | 2 | 3.77% | 1 | 16.67% |
Total | 53 | 100.00% | 6 | 100.00% |
static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa)
{
struct ip_mreqn mreq = {
.imr_multiaddr.s_addr = ifa->ifa_address,
.imr_ifindex = ifa->ifa_dev->dev->ifindex,
};
int ret;
ASSERT_RTNL();
lock_sock(sk);
if (join)
ret = ip_mc_join_group(sk, &mreq);
else
ret = ip_mc_leave_group(sk, &mreq);
release_sock(sk);
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Madhu Challa | 88 | 97.78% | 1 | 50.00% |
Marcelo Ricardo Leitner | 2 | 2.22% | 1 | 50.00% |
Total | 90 | 100.00% | 2 | 100.00% |
static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct nlattr *tb[IFA_MAX+1];
struct in_device *in_dev;
struct ifaddrmsg *ifm;
struct in_ifaddr *ifa, **ifap;
int err = -EINVAL;
ASSERT_RTNL();
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
if (err < 0)
goto errout;
ifm = nlmsg_data(nlh);
in_dev = inetdev_by_index(net, ifm->ifa_index);
if (!in_dev) {
err = -ENODEV;
goto errout;
}
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
ifap = &ifa->ifa_next) {
if (tb[IFA_LOCAL] &&
ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
continue;
if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
continue;
if (tb[IFA_ADDRESS] &&
(ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
!inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa)))
continue;
if (ipv4_is_multicast(ifa->ifa_address))
ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa);
__inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
return 0;
}
err = -EADDRNOTAVAIL;
errout:
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 139 | 49.82% | 6 | 33.33% |
Thomas Graf | 96 | 34.41% | 3 | 16.67% |
Madhu Challa | 22 | 7.89% | 1 | 5.56% |
Denis V. Lunev | 11 | 3.94% | 2 | 11.11% |
Arnaldo Carvalho de Melo | 3 | 1.08% | 1 | 5.56% |
Hideaki Yoshifuji / 吉藤英明 | 3 | 1.08% | 1 | 5.56% |
Jiri Benc | 2 | 0.72% | 1 | 5.56% |
Ian Morris | 1 | 0.36% | 1 | 5.56% |
Eric W. Biedermann | 1 | 0.36% | 1 | 5.56% |
Adrian Bunk | 1 | 0.36% | 1 | 5.56% |
Total | 279 | 100.00% | 18 | 100.00% |
#define INFINITY_LIFE_TIME 0xFFFFFFFF
static void check_lifetime(struct work_struct *work)
{
unsigned long now, next, next_sec, next_sched;
struct in_ifaddr *ifa;
struct hlist_node *n;
int i;
now = jiffies;
next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
for (i = 0; i < IN4_ADDR_HSIZE; i++) {
bool change_needed = false;
rcu_read_lock();
hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
unsigned long age;
if (ifa->ifa_flags & IFA_F_PERMANENT)
continue;
/* We try to batch several events at once. */
age = (now - ifa->ifa_tstamp +
ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
age >= ifa->ifa_valid_lft) {
change_needed = true;
} else if (ifa->ifa_preferred_lft ==
INFINITY_LIFE_TIME) {
continue;
} else if (age >= ifa->ifa_preferred_lft) {
if (time_before(ifa->ifa_tstamp +
ifa->ifa_valid_lft * HZ, next))
next = ifa->ifa_tstamp +
ifa->ifa_valid_lft * HZ;
if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
change_needed = true;
} else if (time_before(ifa->ifa_tstamp +
ifa->ifa_preferred_lft * HZ