mirror of https://gitee.com/openkylin/linux.git
Merge branch 'ifa_list-RCU'
Florian Westphal says: ==================== net: add rcu annotations for ifa_list v3: fix typo in patch1 commit message All other patches are unchanged. v2: remove ifa_list iteration in afs instead of conversion Eric Dumazet reported following problem: It looks that unless RTNL is held, accessing ifa_list needs proper RCU protection. indev->ifa_list can be changed under us by another cpu (which owns RTNL) [..] A proper rcu_dereference() with an happy sparse support would require adding __rcu attribute. This patch series does that: add __rcu to the ifa_list pointers. That makes sparse complain, so the series also adds the required rcu_assign_pointer/dereference helpers where needed. All patches except the last one are preparation work. Two new macros are introduced for in_ifaddr walks. Last patch adds the __rcu annotations and the assign_pointer/dereference helper calls. This patch is a bit large, but I found no better way -- other approaches (annotate-first or add helpers-first) all result in mid-series sparse warnings. This series is submitted vs. net-next rather than net for several reasons: 1. Its (mostly) compile-tested only 2. 3rd patch changes behaviour wrt. secondary addresses (see changelog) 3. The problem exists for a very long time (2004), so it doesn't seem to be urgent to fix this -- rcu use to free ifa_list predates the git era. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
feb3cf2e5e
|
@ -330,6 +330,7 @@ static void bond_delete_netdev_default_gids(struct ib_device *ib_dev,
|
|||
static void enum_netdev_ipv4_ips(struct ib_device *ib_dev,
|
||||
u8 port, struct net_device *ndev)
|
||||
{
|
||||
const struct in_ifaddr *ifa;
|
||||
struct in_device *in_dev;
|
||||
struct sin_list {
|
||||
struct list_head list;
|
||||
|
@ -349,7 +350,7 @@ static void enum_netdev_ipv4_ips(struct ib_device *ib_dev,
|
|||
return;
|
||||
}
|
||||
|
||||
for_ifa(in_dev) {
|
||||
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||
struct sin_list *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
|
||||
|
||||
if (!entry)
|
||||
|
@ -359,7 +360,7 @@ static void enum_netdev_ipv4_ips(struct ib_device *ib_dev,
|
|||
entry->ip.sin_addr.s_addr = ifa->ifa_address;
|
||||
list_add_tail(&entry->list, &sin_list);
|
||||
}
|
||||
endfor_ifa(in_dev);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
list_for_each_entry_safe(sin_iter, sin_temp, &sin_list, list) {
|
||||
|
|
|
@ -3230,17 +3230,22 @@ static int pick_local_ipaddrs(struct c4iw_dev *dev, struct iw_cm_id *cm_id)
|
|||
int found = 0;
|
||||
struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
|
||||
struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;
|
||||
const struct in_ifaddr *ifa;
|
||||
|
||||
ind = in_dev_get(dev->rdev.lldi.ports[0]);
|
||||
if (!ind)
|
||||
return -EADDRNOTAVAIL;
|
||||
for_primary_ifa(ind) {
|
||||
rcu_read_lock();
|
||||
in_dev_for_each_ifa_rcu(ifa, ind) {
|
||||
if (ifa->ifa_flags & IFA_F_SECONDARY)
|
||||
continue;
|
||||
laddr->sin_addr.s_addr = ifa->ifa_address;
|
||||
raddr->sin_addr.s_addr = ifa->ifa_address;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
endfor_ifa(ind);
|
||||
rcu_read_unlock();
|
||||
|
||||
in_dev_put(ind);
|
||||
return found ? 0 : -EADDRNOTAVAIL;
|
||||
}
|
||||
|
|
|
@ -1773,8 +1773,11 @@ static enum i40iw_status_code i40iw_add_mqh_4(
|
|||
if ((((rdma_vlan_dev_vlan_id(dev) < I40IW_NO_VLAN) &&
|
||||
(rdma_vlan_dev_real_dev(dev) == iwdev->netdev)) ||
|
||||
(dev == iwdev->netdev)) && (dev->flags & IFF_UP)) {
|
||||
const struct in_ifaddr *ifa;
|
||||
|
||||
idev = in_dev_get(dev);
|
||||
for_ifa(idev) {
|
||||
|
||||
in_dev_for_each_ifa_rtnl(ifa, idev) {
|
||||
i40iw_debug(&iwdev->sc_dev,
|
||||
I40IW_DEBUG_CM,
|
||||
"Allocating child CM Listener forIP=%pI4, vlan_id=%d, MAC=%pM\n",
|
||||
|
@ -1819,7 +1822,7 @@ static enum i40iw_status_code i40iw_add_mqh_4(
|
|||
cm_parent_listen_node->cm_core->stats_listen_nodes_created--;
|
||||
}
|
||||
}
|
||||
endfor_ifa(idev);
|
||||
|
||||
in_dev_put(idev);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1222,8 +1222,10 @@ static void i40iw_add_ipv4_addr(struct i40iw_device *iwdev)
|
|||
if ((((rdma_vlan_dev_vlan_id(dev) < 0xFFFF) &&
|
||||
(rdma_vlan_dev_real_dev(dev) == iwdev->netdev)) ||
|
||||
(dev == iwdev->netdev)) && (dev->flags & IFF_UP)) {
|
||||
const struct in_ifaddr *ifa;
|
||||
|
||||
idev = in_dev_get(dev);
|
||||
for_ifa(idev) {
|
||||
in_dev_for_each_ifa_rtnl(ifa, idev) {
|
||||
i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_CM,
|
||||
"IP=%pI4, vlan_id=%d, MAC=%pM\n", &ifa->ifa_address,
|
||||
rdma_vlan_dev_vlan_id(dev), dev->dev_addr);
|
||||
|
@ -1235,7 +1237,7 @@ static void i40iw_add_ipv4_addr(struct i40iw_device *iwdev)
|
|||
true,
|
||||
I40IW_ARP_ADD);
|
||||
}
|
||||
endfor_ifa(idev);
|
||||
|
||||
in_dev_put(idev);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -174,10 +174,14 @@ int i40iw_inetaddr_event(struct notifier_block *notifier,
|
|||
rcu_read_lock();
|
||||
in = __in_dev_get_rcu(upper_dev);
|
||||
|
||||
if (!in->ifa_list)
|
||||
local_ipaddr = 0;
|
||||
else
|
||||
local_ipaddr = ntohl(in->ifa_list->ifa_address);
|
||||
local_ipaddr = 0;
|
||||
if (in) {
|
||||
struct in_ifaddr *ifa;
|
||||
|
||||
ifa = rcu_dereference(in->ifa_list);
|
||||
if (ifa)
|
||||
local_ipaddr = ntohl(ifa->ifa_address);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
} else {
|
||||
|
|
|
@ -183,7 +183,13 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
|
|||
|
||||
rcu_read_lock();
|
||||
in = __in_dev_get_rcu(upper_dev);
|
||||
nesvnic->local_ipaddr = in->ifa_list->ifa_address;
|
||||
if (in) {
|
||||
struct in_ifaddr *ifa;
|
||||
|
||||
ifa = rcu_dereference(in->ifa_list);
|
||||
if (ifa)
|
||||
nesvnic->local_ipaddr = ifa->ifa_address;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
} else {
|
||||
nesvnic->local_ipaddr = ifa->ifa_address;
|
||||
|
|
|
@ -427,11 +427,16 @@ static void *usnic_ib_device_add(struct pci_dev *dev)
|
|||
if (netif_carrier_ok(us_ibdev->netdev))
|
||||
usnic_fwd_carrier_up(us_ibdev->ufdev);
|
||||
|
||||
ind = in_dev_get(netdev);
|
||||
if (ind->ifa_list)
|
||||
usnic_fwd_add_ipaddr(us_ibdev->ufdev,
|
||||
ind->ifa_list->ifa_address);
|
||||
in_dev_put(ind);
|
||||
rcu_read_lock();
|
||||
ind = __in_dev_get_rcu(netdev);
|
||||
if (ind) {
|
||||
const struct in_ifaddr *ifa;
|
||||
|
||||
ifa = rcu_dereference(ind->ifa_list);
|
||||
if (ifa)
|
||||
usnic_fwd_add_ipaddr(us_ibdev->ufdev, ifa->ifa_address);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
usnic_mac_ip_to_gid(us_ibdev->netdev->perm_addr,
|
||||
us_ibdev->ufdev->inaddr, &gid.raw[0]);
|
||||
|
|
|
@ -3248,6 +3248,7 @@ netxen_config_indev_addr(struct netxen_adapter *adapter,
|
|||
struct net_device *dev, unsigned long event)
|
||||
{
|
||||
struct in_device *indev;
|
||||
struct in_ifaddr *ifa;
|
||||
|
||||
if (!netxen_destip_supported(adapter))
|
||||
return;
|
||||
|
@ -3256,7 +3257,8 @@ netxen_config_indev_addr(struct netxen_adapter *adapter,
|
|||
if (!indev)
|
||||
return;
|
||||
|
||||
for_ifa(indev) {
|
||||
rcu_read_lock();
|
||||
in_dev_for_each_ifa_rcu(ifa, indev) {
|
||||
switch (event) {
|
||||
case NETDEV_UP:
|
||||
netxen_list_config_ip(adapter, ifa, NX_IP_UP);
|
||||
|
@ -3267,8 +3269,8 @@ netxen_config_indev_addr(struct netxen_adapter *adapter,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
} endfor_ifa(indev);
|
||||
|
||||
}
|
||||
rcu_read_unlock();
|
||||
in_dev_put(indev);
|
||||
}
|
||||
|
||||
|
|
|
@ -4119,13 +4119,14 @@ static void
|
|||
qlcnic_config_indev_addr(struct qlcnic_adapter *adapter,
|
||||
struct net_device *dev, unsigned long event)
|
||||
{
|
||||
const struct in_ifaddr *ifa;
|
||||
struct in_device *indev;
|
||||
|
||||
indev = in_dev_get(dev);
|
||||
if (!indev)
|
||||
return;
|
||||
|
||||
for_ifa(indev) {
|
||||
in_dev_for_each_ifa_rtnl(ifa, indev) {
|
||||
switch (event) {
|
||||
case NETDEV_UP:
|
||||
qlcnic_config_ipaddr(adapter,
|
||||
|
@ -4138,7 +4139,7 @@ qlcnic_config_indev_addr(struct qlcnic_adapter *adapter,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
} endfor_ifa(indev);
|
||||
}
|
||||
|
||||
in_dev_put(indev);
|
||||
}
|
||||
|
|
|
@ -1509,7 +1509,7 @@ static inline int velocity_get_ip(struct velocity_info *vptr)
|
|||
rcu_read_lock();
|
||||
in_dev = __in_dev_get_rcu(vptr->netdev);
|
||||
if (in_dev != NULL) {
|
||||
ifa = (struct in_ifaddr *) in_dev->ifa_list;
|
||||
ifa = rcu_dereference(in_dev->ifa_list);
|
||||
if (ifa != NULL) {
|
||||
memcpy(vptr->ip_addr, &ifa->ifa_address, 4);
|
||||
res = 0;
|
||||
|
|
|
@ -1012,7 +1012,7 @@ plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth)
|
|||
in_dev = __in_dev_get_rcu(dev);
|
||||
if (in_dev) {
|
||||
/* Any address will do - we take the first */
|
||||
const struct in_ifaddr *ifa = in_dev->ifa_list;
|
||||
const struct in_ifaddr *ifa = rcu_dereference(in_dev->ifa_list);
|
||||
if (ifa) {
|
||||
memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
|
||||
memset(eth->h_dest, 0xfc, 2);
|
||||
|
@ -1107,7 +1107,7 @@ plip_open(struct net_device *dev)
|
|||
/* Any address will do - we take the first. We already
|
||||
have the first two bytes filled with 0xfc, from
|
||||
plip_init_dev(). */
|
||||
struct in_ifaddr *ifa=in_dev->ifa_list;
|
||||
const struct in_ifaddr *ifa = rcu_dereference(in_dev->ifa_list);
|
||||
if (ifa != NULL) {
|
||||
memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
|
||||
}
|
||||
|
|
|
@ -3651,13 +3651,19 @@ vmxnet3_suspend(struct device *device)
|
|||
}
|
||||
|
||||
if (adapter->wol & WAKE_ARP) {
|
||||
in_dev = in_dev_get(netdev);
|
||||
if (!in_dev)
|
||||
goto skip_arp;
|
||||
rcu_read_lock();
|
||||
|
||||
ifa = (struct in_ifaddr *)in_dev->ifa_list;
|
||||
if (!ifa)
|
||||
in_dev = __in_dev_get_rcu(netdev);
|
||||
if (!in_dev) {
|
||||
rcu_read_unlock();
|
||||
goto skip_arp;
|
||||
}
|
||||
|
||||
ifa = rcu_dereference(in_dev->ifa_list);
|
||||
if (!ifa) {
|
||||
rcu_read_unlock();
|
||||
goto skip_arp;
|
||||
}
|
||||
|
||||
pmConf->filters[i].patternSize = ETH_HLEN + /* Ethernet header*/
|
||||
sizeof(struct arphdr) + /* ARP header */
|
||||
|
@ -3677,7 +3683,9 @@ vmxnet3_suspend(struct device *device)
|
|||
|
||||
/* The Unicast IPv4 address in 'tip' field. */
|
||||
arpreq += 2 * ETH_ALEN + sizeof(u32);
|
||||
*(u32 *)arpreq = ifa->ifa_address;
|
||||
*(__be32 *)arpreq = ifa->ifa_address;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
/* The mask for the relevant bits. */
|
||||
pmConf->filters[i].mask[0] = 0x00;
|
||||
|
@ -3686,7 +3694,6 @@ vmxnet3_suspend(struct device *device)
|
|||
pmConf->filters[i].mask[3] = 0x00;
|
||||
pmConf->filters[i].mask[4] = 0xC0; /* IPv4 TIP */
|
||||
pmConf->filters[i].mask[5] = 0x03; /* IPv4 TIP */
|
||||
in_dev_put(in_dev);
|
||||
|
||||
pmConf->wakeUpEvents |= VMXNET3_PM_WAKEUP_FILTER;
|
||||
i++;
|
||||
|
|
|
@ -196,16 +196,15 @@ static int cisco_rx(struct sk_buff *skb)
|
|||
mask = ~cpu_to_be32(0); /* is the mask correct? */
|
||||
|
||||
if (in_dev != NULL) {
|
||||
struct in_ifaddr **ifap = &in_dev->ifa_list;
|
||||
const struct in_ifaddr *ifa;
|
||||
|
||||
while (*ifap != NULL) {
|
||||
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||
if (strcmp(dev->name,
|
||||
(*ifap)->ifa_label) == 0) {
|
||||
addr = (*ifap)->ifa_local;
|
||||
mask = (*ifap)->ifa_mask;
|
||||
ifa->ifa_label) == 0) {
|
||||
addr = ifa->ifa_local;
|
||||
mask = ifa->ifa_mask;
|
||||
break;
|
||||
}
|
||||
ifap = &(*ifap)->ifa_next;
|
||||
}
|
||||
|
||||
cisco_keepalive_send(dev, CISCO_ADDR_REPLY,
|
||||
|
|
|
@ -2194,13 +2194,13 @@ static int ath6kl_wow_suspend_vif(struct ath6kl_vif *vif,
|
|||
if (!in_dev)
|
||||
return 0;
|
||||
|
||||
ifa = in_dev->ifa_list;
|
||||
ifa = rtnl_dereference(in_dev->ifa_list);
|
||||
memset(&ips, 0, sizeof(ips));
|
||||
|
||||
/* Configure IP addr only if IP address count < MAX_IP_ADDRS */
|
||||
while (index < MAX_IP_ADDRS && ifa) {
|
||||
ips[index] = ifa->ifa_local;
|
||||
ifa = ifa->ifa_next;
|
||||
ifa = rtnl_dereference(ifa->ifa_next);
|
||||
index++;
|
||||
}
|
||||
|
||||
|
|
|
@ -3268,7 +3268,7 @@ static void mwifiex_set_auto_arp_mef_entry(struct mwifiex_private *priv,
|
|||
in_dev = __in_dev_get_rtnl(adapter->priv[i]->netdev);
|
||||
if (!in_dev)
|
||||
continue;
|
||||
ifa = in_dev->ifa_list;
|
||||
ifa = rtnl_dereference(in_dev->ifa_list);
|
||||
if (!ifa || !ifa->ifa_local)
|
||||
continue;
|
||||
ips[i] = ifa->ifa_local;
|
||||
|
|
|
@ -70,9 +70,13 @@ net_open(struct net_device *dev)
|
|||
for (i = 0; i < ETH_ALEN; i++)
|
||||
dev->dev_addr[i] = 0xfc;
|
||||
if ((in_dev = dev->ip_ptr) != NULL) {
|
||||
struct in_ifaddr *ifa = in_dev->ifa_list;
|
||||
const struct in_ifaddr *ifa;
|
||||
|
||||
rcu_read_lock();
|
||||
ifa = rcu_dereference(in_dev->ifa_list);
|
||||
if (ifa != NULL)
|
||||
memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ifa->ifa_local)), &ifa->ifa_local, sizeof(ifa->ifa_local));
|
||||
rcu_read_unlock();
|
||||
}
|
||||
} else
|
||||
memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN);
|
||||
|
|
|
@ -29,7 +29,6 @@ kafs-y := \
|
|||
server.o \
|
||||
server_list.o \
|
||||
super.o \
|
||||
netdevices.o \
|
||||
vlclient.o \
|
||||
vl_list.o \
|
||||
vl_probe.o \
|
||||
|
|
|
@ -584,9 +584,8 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call)
|
|||
*/
|
||||
static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
|
||||
{
|
||||
struct afs_interface *ifs;
|
||||
struct afs_call *call = container_of(work, struct afs_call, work);
|
||||
int loop, nifs;
|
||||
int loop;
|
||||
|
||||
struct {
|
||||
struct /* InterfaceAddr */ {
|
||||
|
@ -604,19 +603,7 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
|
|||
|
||||
_enter("");
|
||||
|
||||
nifs = 0;
|
||||
ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL);
|
||||
if (ifs) {
|
||||
nifs = afs_get_ipv4_interfaces(call->net, ifs, 32, false);
|
||||
if (nifs < 0) {
|
||||
kfree(ifs);
|
||||
ifs = NULL;
|
||||
nifs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
reply.ia.nifs = htonl(nifs);
|
||||
|
||||
reply.ia.uuid[0] = call->net->uuid.time_low;
|
||||
reply.ia.uuid[1] = htonl(ntohs(call->net->uuid.time_mid));
|
||||
|
@ -626,15 +613,6 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
|
|||
for (loop = 0; loop < 6; loop++)
|
||||
reply.ia.uuid[loop + 5] = htonl((s8) call->net->uuid.node[loop]);
|
||||
|
||||
if (ifs) {
|
||||
for (loop = 0; loop < nifs; loop++) {
|
||||
reply.ia.ifaddr[loop] = ifs[loop].address.s_addr;
|
||||
reply.ia.netmask[loop] = ifs[loop].netmask.s_addr;
|
||||
reply.ia.mtu[loop] = htonl(ifs[loop].mtu);
|
||||
}
|
||||
kfree(ifs);
|
||||
}
|
||||
|
||||
reply.cap.capcount = htonl(1);
|
||||
reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION);
|
||||
afs_send_simple_reply(call, &reply, sizeof(reply));
|
||||
|
|
|
@ -724,15 +724,6 @@ struct afs_permits {
|
|||
struct afs_permit permits[]; /* List of permits sorted by key pointer */
|
||||
};
|
||||
|
||||
/*
|
||||
* record of one of a system's set of network interfaces
|
||||
*/
|
||||
struct afs_interface {
|
||||
struct in_addr address; /* IPv4 address bound to interface */
|
||||
struct in_addr netmask; /* netmask applied to address */
|
||||
unsigned mtu; /* MTU of interface */
|
||||
};
|
||||
|
||||
/*
|
||||
* Error prioritisation and accumulation.
|
||||
*/
|
||||
|
@ -1095,12 +1086,6 @@ extern const struct file_operations afs_mntpt_file_operations;
|
|||
extern struct vfsmount *afs_d_automount(struct path *);
|
||||
extern void afs_mntpt_kill_timer(void);
|
||||
|
||||
/*
|
||||
* netdevices.c
|
||||
*/
|
||||
extern int afs_get_ipv4_interfaces(struct afs_net *, struct afs_interface *,
|
||||
size_t, bool);
|
||||
|
||||
/*
|
||||
* proc.c
|
||||
*/
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* AFS network device helpers
|
||||
*
|
||||
* Copyright (c) 2007 Patrick McHardy <kaber@trash.net>
|
||||
*/
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* get a list of this system's interface IPv4 addresses, netmasks and MTUs
|
||||
* - maxbufs must be at least 1
|
||||
* - returns the number of interface records in the buffer
|
||||
*/
|
||||
int afs_get_ipv4_interfaces(struct afs_net *net, struct afs_interface *bufs,
|
||||
size_t maxbufs, bool wantloopback)
|
||||
{
|
||||
struct net_device *dev;
|
||||
struct in_device *idev;
|
||||
int n = 0;
|
||||
|
||||
ASSERT(maxbufs > 0);
|
||||
|
||||
rtnl_lock();
|
||||
for_each_netdev(net->net, dev) {
|
||||
if (dev->type == ARPHRD_LOOPBACK && !wantloopback)
|
||||
continue;
|
||||
idev = __in_dev_get_rtnl(dev);
|
||||
if (!idev)
|
||||
continue;
|
||||
for_primary_ifa(idev) {
|
||||
bufs[n].address.s_addr = ifa->ifa_address;
|
||||
bufs[n].netmask.s_addr = ifa->ifa_mask;
|
||||
bufs[n].mtu = dev->mtu;
|
||||
n++;
|
||||
if (n >= maxbufs)
|
||||
goto out;
|
||||
} endfor_ifa(idev);
|
||||
}
|
||||
out:
|
||||
rtnl_unlock();
|
||||
return n;
|
||||
}
|
|
@ -26,7 +26,7 @@ struct in_device {
|
|||
struct net_device *dev;
|
||||
refcount_t refcnt;
|
||||
int dead;
|
||||
struct in_ifaddr *ifa_list; /* IP ifaddr chain */
|
||||
struct in_ifaddr __rcu *ifa_list;/* IP ifaddr chain */
|
||||
|
||||
struct ip_mc_list __rcu *mc_list; /* IP multicast filter chain */
|
||||
struct ip_mc_list __rcu * __rcu *mc_hash;
|
||||
|
@ -136,7 +136,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
|
|||
|
||||
struct in_ifaddr {
|
||||
struct hlist_node hash;
|
||||
struct in_ifaddr *ifa_next;
|
||||
struct in_ifaddr __rcu *ifa_next;
|
||||
struct in_device *ifa_dev;
|
||||
struct rcu_head rcu_head;
|
||||
__be32 ifa_local;
|
||||
|
@ -186,7 +186,7 @@ __be32 inet_confirm_addr(struct net *net, struct in_device *in_dev, __be32 dst,
|
|||
struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
|
||||
__be32 mask);
|
||||
struct in_ifaddr *inet_lookup_ifaddr_rcu(struct net *net, __be32 addr);
|
||||
static __inline__ bool inet_ifa_match(__be32 addr, struct in_ifaddr *ifa)
|
||||
static inline bool inet_ifa_match(__be32 addr, const struct in_ifaddr *ifa)
|
||||
{
|
||||
return !((addr^ifa->ifa_address)&ifa->ifa_mask);
|
||||
}
|
||||
|
@ -206,14 +206,13 @@ static __inline__ bool bad_mask(__be32 mask, __be32 addr)
|
|||
return false;
|
||||
}
|
||||
|
||||
#define for_primary_ifa(in_dev) { struct in_ifaddr *ifa; \
|
||||
for (ifa = (in_dev)->ifa_list; ifa && !(ifa->ifa_flags&IFA_F_SECONDARY); ifa = ifa->ifa_next)
|
||||
#define in_dev_for_each_ifa_rtnl(ifa, in_dev) \
|
||||
for (ifa = rtnl_dereference((in_dev)->ifa_list); ifa; \
|
||||
ifa = rtnl_dereference(ifa->ifa_next))
|
||||
|
||||
#define for_ifa(in_dev) { struct in_ifaddr *ifa; \
|
||||
for (ifa = (in_dev)->ifa_list; ifa; ifa = ifa->ifa_next)
|
||||
|
||||
|
||||
#define endfor_ifa(in_dev) }
|
||||
#define in_dev_for_each_ifa_rcu(ifa, in_dev) \
|
||||
for (ifa = rcu_dereference((in_dev)->ifa_list); ifa; \
|
||||
ifa = rcu_dereference(ifa->ifa_next))
|
||||
|
||||
static inline struct in_device *__in_dev_get_rcu(const struct net_device *dev)
|
||||
{
|
||||
|
|
|
@ -696,16 +696,22 @@ int netpoll_setup(struct netpoll *np)
|
|||
|
||||
if (!np->local_ip.ip) {
|
||||
if (!np->ipv6) {
|
||||
in_dev = __in_dev_get_rtnl(ndev);
|
||||
const struct in_ifaddr *ifa;
|
||||
|
||||
if (!in_dev || !in_dev->ifa_list) {
|
||||
in_dev = __in_dev_get_rtnl(ndev);
|
||||
if (!in_dev)
|
||||
goto put_noaddr;
|
||||
|
||||
ifa = rtnl_dereference(in_dev->ifa_list);
|
||||
if (!ifa) {
|
||||
put_noaddr:
|
||||
np_err(np, "no IP address for %s, aborting\n",
|
||||
np->dev_name);
|
||||
err = -EDESTADDRREQ;
|
||||
goto put;
|
||||
}
|
||||
|
||||
np->local_ip.ip = in_dev->ifa_list->ifa_local;
|
||||
np->local_ip.ip = ifa->ifa_local;
|
||||
np_info(np, "local IP %pI4\n", &np->local_ip.ip);
|
||||
} else {
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
|
|
|
@ -2125,9 +2125,11 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
|
|||
rcu_read_lock();
|
||||
in_dev = __in_dev_get_rcu(pkt_dev->odev);
|
||||
if (in_dev) {
|
||||
if (in_dev->ifa_list) {
|
||||
pkt_dev->saddr_min =
|
||||
in_dev->ifa_list->ifa_address;
|
||||
const struct in_ifaddr *ifa;
|
||||
|
||||
ifa = rcu_dereference(in_dev->ifa_list);
|
||||
if (ifa) {
|
||||
pkt_dev->saddr_min = ifa->ifa_address;
|
||||
pkt_dev->saddr_max = pkt_dev->saddr_min;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -194,7 +194,8 @@ static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
|
|||
|
||||
static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
|
||||
static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain);
|
||||
static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
|
||||
static void inet_del_ifa(struct in_device *in_dev,
|
||||
struct in_ifaddr __rcu **ifap,
|
||||
int destroy);
|
||||
#ifdef CONFIG_SYSCTL
|
||||
static int devinet_sysctl_register(struct in_device *idev);
|
||||
|
@ -300,8 +301,8 @@ static void in_dev_rcu_put(struct rcu_head *head)
|
|||
|
||||
static void inetdev_destroy(struct in_device *in_dev)
|
||||
{
|
||||
struct in_ifaddr *ifa;
|
||||
struct net_device *dev;
|
||||
struct in_ifaddr *ifa;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
|
@ -311,7 +312,7 @@ static void inetdev_destroy(struct in_device *in_dev)
|
|||
|
||||
ip_mc_destroy_dev(in_dev);
|
||||
|
||||
while ((ifa = in_dev->ifa_list) != NULL) {
|
||||
while ((ifa = rtnl_dereference(in_dev->ifa_list)) != NULL) {
|
||||
inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
|
||||
inet_free_ifa(ifa);
|
||||
}
|
||||
|
@ -327,30 +328,35 @@ static void inetdev_destroy(struct in_device *in_dev)
|
|||
|
||||
int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
|
||||
{
|
||||
const struct in_ifaddr *ifa;
|
||||
|
||||
rcu_read_lock();
|
||||
for_primary_ifa(in_dev) {
|
||||
in_dev_for_each_ifa_rcu(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;
|
||||
}
|
||||
|
||||
static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
|
||||
int destroy, struct nlmsghdr *nlh, u32 portid)
|
||||
static void __inet_del_ifa(struct in_device *in_dev,
|
||||
struct in_ifaddr __rcu **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 *ifa, *ifa1;
|
||||
struct in_ifaddr *last_prim;
|
||||
struct in_ifaddr *prev_prom = NULL;
|
||||
int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
ifa1 = rtnl_dereference(*ifap);
|
||||
last_prim = rtnl_dereference(in_dev->ifa_list);
|
||||
if (in_dev->dead)
|
||||
goto no_promotions;
|
||||
|
||||
|
@ -359,9 +365,9 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
|
|||
**/
|
||||
|
||||
if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
|
||||
struct in_ifaddr **ifap1 = &ifa1->ifa_next;
|
||||
struct in_ifaddr __rcu **ifap1 = &ifa1->ifa_next;
|
||||
|
||||
while ((ifa = *ifap1) != NULL) {
|
||||
while ((ifa = rtnl_dereference(*ifap1)) != NULL) {
|
||||
if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
|
||||
ifa1->ifa_scope <= ifa->ifa_scope)
|
||||
last_prim = ifa;
|
||||
|
@ -394,7 +400,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
|
|||
* 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) {
|
||||
for (ifa = promote; ifa; ifa = rtnl_dereference(ifa->ifa_next)) {
|
||||
if (ifa1->ifa_mask == ifa->ifa_mask &&
|
||||
inet_ifa_match(ifa1->ifa_address, ifa))
|
||||
fib_del_ifaddr(ifa, ifa1);
|
||||
|
@ -420,19 +426,24 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
|
|||
blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
|
||||
|
||||
if (promote) {
|
||||
struct in_ifaddr *next_sec = promote->ifa_next;
|
||||
struct in_ifaddr *next_sec;
|
||||
|
||||
next_sec = rtnl_dereference(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;
|
||||
struct in_ifaddr *last_sec;
|
||||
|
||||
last_sec = rtnl_dereference(last_prim->ifa_next);
|
||||
rcu_assign_pointer(prev_prom->ifa_next, next_sec);
|
||||
rcu_assign_pointer(promote->ifa_next, last_sec);
|
||||
rcu_assign_pointer(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) {
|
||||
for (ifa = next_sec; ifa;
|
||||
ifa = rtnl_dereference(ifa->ifa_next)) {
|
||||
if (ifa1->ifa_mask != ifa->ifa_mask ||
|
||||
!inet_ifa_match(ifa1->ifa_address, ifa))
|
||||
continue;
|
||||
|
@ -444,7 +455,8 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
|
|||
inet_free_ifa(ifa1);
|
||||
}
|
||||
|
||||
static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
|
||||
static void inet_del_ifa(struct in_device *in_dev,
|
||||
struct in_ifaddr __rcu **ifap,
|
||||
int destroy)
|
||||
{
|
||||
__inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
|
||||
|
@ -457,9 +469,10 @@ static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
|
|||
static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
|
||||
u32 portid, struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct in_ifaddr __rcu **last_primary, **ifap;
|
||||
struct in_device *in_dev = ifa->ifa_dev;
|
||||
struct in_ifaddr *ifa1, **ifap, **last_primary;
|
||||
struct in_validator_info ivi;
|
||||
struct in_ifaddr *ifa1;
|
||||
int ret;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
@ -472,8 +485,10 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
|
|||
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) {
|
||||
ifap = &in_dev->ifa_list;
|
||||
ifa1 = rtnl_dereference(*ifap);
|
||||
|
||||
while (ifa1) {
|
||||
if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
|
||||
ifa->ifa_scope <= ifa1->ifa_scope)
|
||||
last_primary = &ifa1->ifa_next;
|
||||
|
@ -489,6 +504,9 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
|
|||
}
|
||||
ifa->ifa_flags |= IFA_F_SECONDARY;
|
||||
}
|
||||
|
||||
ifap = &ifa1->ifa_next;
|
||||
ifa1 = rtnl_dereference(*ifap);
|
||||
}
|
||||
|
||||
/* Allow any devices that wish to register ifaddr validtors to weigh
|
||||
|
@ -514,8 +532,8 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
|
|||
ifap = last_primary;
|
||||
}
|
||||
|
||||
ifa->ifa_next = *ifap;
|
||||
*ifap = ifa;
|
||||
rcu_assign_pointer(ifa->ifa_next, *ifap);
|
||||
rcu_assign_pointer(*ifap, ifa);
|
||||
|
||||
inet_hash_insert(dev_net(in_dev->dev), ifa);
|
||||
|
||||
|
@ -580,12 +598,14 @@ EXPORT_SYMBOL(inetdev_by_index);
|
|||
struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
|
||||
__be32 mask)
|
||||
{
|
||||
struct in_ifaddr *ifa;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
for_primary_ifa(in_dev) {
|
||||
in_dev_for_each_ifa_rtnl(ifa, in_dev) {
|
||||
if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
|
||||
return ifa;
|
||||
} endfor_ifa(in_dev);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -613,10 +633,12 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct in_ifaddr __rcu **ifap;
|
||||
struct nlattr *tb[IFA_MAX+1];
|
||||
struct in_device *in_dev;
|
||||
struct ifaddrmsg *ifm;
|
||||
struct in_ifaddr *ifa, **ifap;
|
||||
struct in_ifaddr *ifa;
|
||||
|
||||
int err = -EINVAL;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
@ -633,7 +655,7 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
goto errout;
|
||||
}
|
||||
|
||||
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
|
||||
for (ifap = &in_dev->ifa_list; (ifa = rtnl_dereference(*ifap)) != NULL;
|
||||
ifap = &ifa->ifa_next) {
|
||||
if (tb[IFA_LOCAL] &&
|
||||
ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
|
||||
|
@ -721,15 +743,20 @@ static void check_lifetime(struct work_struct *work)
|
|||
|
||||
if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
|
||||
age >= ifa->ifa_valid_lft) {
|
||||
struct in_ifaddr **ifap;
|
||||
struct in_ifaddr __rcu **ifap;
|
||||
struct in_ifaddr *tmp;
|
||||
|
||||
for (ifap = &ifa->ifa_dev->ifa_list;
|
||||
*ifap != NULL; ifap = &(*ifap)->ifa_next) {
|
||||
if (*ifap == ifa) {
|
||||
ifap = &ifa->ifa_dev->ifa_list;
|
||||
tmp = rtnl_dereference(*ifap);
|
||||
while (tmp) {
|
||||
tmp = rtnl_dereference(tmp->ifa_next);
|
||||
if (rtnl_dereference(*ifap) == ifa) {
|
||||
inet_del_ifa(ifa->ifa_dev,
|
||||
ifap, 1);
|
||||
break;
|
||||
}
|
||||
ifap = &tmp->ifa_next;
|
||||
tmp = rtnl_dereference(*ifap);
|
||||
}
|
||||
} else if (ifa->ifa_preferred_lft !=
|
||||
INFINITY_LIFE_TIME &&
|
||||
|
@ -873,13 +900,12 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
|
|||
static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
|
||||
{
|
||||
struct in_device *in_dev = ifa->ifa_dev;
|
||||
struct in_ifaddr *ifa1, **ifap;
|
||||
struct in_ifaddr *ifa1;
|
||||
|
||||
if (!ifa->ifa_local)
|
||||
return NULL;
|
||||
|
||||
for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
|
||||
ifap = &ifa1->ifa_next) {
|
||||
in_dev_for_each_ifa_rtnl(ifa1, in_dev) {
|
||||
if (ifa1->ifa_mask == ifa->ifa_mask &&
|
||||
inet_ifa_match(ifa1->ifa_address, ifa) &&
|
||||
ifa1->ifa_local == ifa->ifa_local)
|
||||
|
@ -974,8 +1000,8 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
|
|||
{
|
||||
struct sockaddr_in sin_orig;
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
|
||||
struct in_ifaddr __rcu **ifap = NULL;
|
||||
struct in_device *in_dev;
|
||||
struct in_ifaddr **ifap = NULL;
|
||||
struct in_ifaddr *ifa = NULL;
|
||||
struct net_device *dev;
|
||||
char *colon;
|
||||
|
@ -1046,7 +1072,9 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
|
|||
/* note: we only do this for a limited set of ioctls
|
||||
and only if the original address family was AF_INET.
|
||||
This is checked above. */
|
||||
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
|
||||
|
||||
for (ifap = &in_dev->ifa_list;
|
||||
(ifa = rtnl_dereference(*ifap)) != NULL;
|
||||
ifap = &ifa->ifa_next) {
|
||||
if (!strcmp(ifr->ifr_name, ifa->ifa_label) &&
|
||||
sin_orig.sin_addr.s_addr ==
|
||||
|
@ -1059,7 +1087,8 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
|
|||
4.3BSD-style and passed in junk so we fall back to
|
||||
comparing just the label */
|
||||
if (!ifa) {
|
||||
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
|
||||
for (ifap = &in_dev->ifa_list;
|
||||
(ifa = rtnl_dereference(*ifap)) != NULL;
|
||||
ifap = &ifa->ifa_next)
|
||||
if (!strcmp(ifr->ifr_name, ifa->ifa_label))
|
||||
break;
|
||||
|
@ -1208,7 +1237,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
|
|||
static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size)
|
||||
{
|
||||
struct in_device *in_dev = __in_dev_get_rtnl(dev);
|
||||
struct in_ifaddr *ifa;
|
||||
const struct in_ifaddr *ifa;
|
||||
struct ifreq ifr;
|
||||
int done = 0;
|
||||
|
||||
|
@ -1218,7 +1247,7 @@ static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int s
|
|||
if (!in_dev)
|
||||
goto out;
|
||||
|
||||
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
|
||||
in_dev_for_each_ifa_rtnl(ifa, in_dev) {
|
||||
if (!buf) {
|
||||
done += size;
|
||||
continue;
|
||||
|
@ -1246,17 +1275,22 @@ static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int s
|
|||
static __be32 in_dev_select_addr(const struct in_device *in_dev,
|
||||
int scope)
|
||||
{
|
||||
for_primary_ifa(in_dev) {
|
||||
const struct in_ifaddr *ifa;
|
||||
|
||||
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||
if (ifa->ifa_flags & IFA_F_SECONDARY)
|
||||
continue;
|
||||
if (ifa->ifa_scope != RT_SCOPE_LINK &&
|
||||
ifa->ifa_scope <= scope)
|
||||
return ifa->ifa_local;
|
||||
} endfor_ifa(in_dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
|
||||
{
|
||||
const struct in_ifaddr *ifa;
|
||||
__be32 addr = 0;
|
||||
struct in_device *in_dev;
|
||||
struct net *net = dev_net(dev);
|
||||
|
@ -1267,7 +1301,9 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
|
|||
if (!in_dev)
|
||||
goto no_in_dev;
|
||||
|
||||
for_primary_ifa(in_dev) {
|
||||
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||
if (ifa->ifa_flags & IFA_F_SECONDARY)
|
||||
continue;
|
||||
if (ifa->ifa_scope > scope)
|
||||
continue;
|
||||
if (!dst || inet_ifa_match(dst, ifa)) {
|
||||
|
@ -1276,7 +1312,7 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
|
|||
}
|
||||
if (!addr)
|
||||
addr = ifa->ifa_local;
|
||||
} endfor_ifa(in_dev);
|
||||
}
|
||||
|
||||
if (addr)
|
||||
goto out_unlock;
|
||||
|
@ -1321,10 +1357,11 @@ EXPORT_SYMBOL(inet_select_addr);
|
|||
static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
|
||||
__be32 local, int scope)
|
||||
{
|
||||
int same = 0;
|
||||
const struct in_ifaddr *ifa;
|
||||
__be32 addr = 0;
|
||||
int same = 0;
|
||||
|
||||
for_ifa(in_dev) {
|
||||
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||
if (!addr &&
|
||||
(local == ifa->ifa_local || !local) &&
|
||||
ifa->ifa_scope <= scope) {
|
||||
|
@ -1350,7 +1387,7 @@ static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
|
|||
same = 0;
|
||||
}
|
||||
}
|
||||
} endfor_ifa(in_dev);
|
||||
}
|
||||
|
||||
return same ? addr : 0;
|
||||
}
|
||||
|
@ -1424,7 +1461,7 @@ static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
|
|||
struct in_ifaddr *ifa;
|
||||
int named = 0;
|
||||
|
||||
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
|
||||
in_dev_for_each_ifa_rtnl(ifa, in_dev) {
|
||||
char old[IFNAMSIZ], *dot;
|
||||
|
||||
memcpy(old, ifa->ifa_label, IFNAMSIZ);
|
||||
|
@ -1454,10 +1491,9 @@ static void inetdev_send_gratuitous_arp(struct net_device *dev,
|
|||
struct in_device *in_dev)
|
||||
|
||||
{
|
||||
struct in_ifaddr *ifa;
|
||||
const struct in_ifaddr *ifa;
|
||||
|
||||
for (ifa = in_dev->ifa_list; ifa;
|
||||
ifa = ifa->ifa_next) {
|
||||
in_dev_for_each_ifa_rtnl(ifa, in_dev) {
|
||||
arp_send(ARPOP_REQUEST, ETH_P_ARP,
|
||||
ifa->ifa_local, dev,
|
||||
ifa->ifa_local, NULL,
|
||||
|
@ -1727,15 +1763,17 @@ static int in_dev_dump_addr(struct in_device *in_dev, struct sk_buff *skb,
|
|||
int ip_idx = 0;
|
||||
int err;
|
||||
|
||||
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next, ip_idx++) {
|
||||
if (ip_idx < s_ip_idx)
|
||||
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||
if (ip_idx < s_ip_idx) {
|
||||
ip_idx++;
|
||||
continue;
|
||||
|
||||
}
|
||||
err = inet_fill_ifaddr(skb, ifa, fillargs);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
|
||||
ip_idx++;
|
||||
}
|
||||
err = 0;
|
||||
|
||||
|
|
|
@ -540,14 +540,22 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
|
|||
cfg->fc_oif = dev->ifindex;
|
||||
cfg->fc_table = l3mdev_fib_table(dev);
|
||||
if (colon) {
|
||||
struct in_ifaddr *ifa;
|
||||
struct in_device *in_dev = __in_dev_get_rtnl(dev);
|
||||
const struct in_ifaddr *ifa;
|
||||
struct in_device *in_dev;
|
||||
|
||||
in_dev = __in_dev_get_rtnl(dev);
|
||||
if (!in_dev)
|
||||
return -ENODEV;
|
||||
|
||||
*colon = ':';
|
||||
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next)
|
||||
|
||||
rcu_read_lock();
|
||||
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||
if (strcmp(ifa->ifa_label, devname) == 0)
|
||||
break;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!ifa)
|
||||
return -ENODEV;
|
||||
cfg->fc_prefsrc = ifa->ifa_local;
|
||||
|
@ -1177,8 +1185,8 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
|
|||
*
|
||||
* Scan address list to be sure that addresses are really gone.
|
||||
*/
|
||||
|
||||
for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) {
|
||||
rcu_read_lock();
|
||||
in_dev_for_each_ifa_rcu(ifa1, in_dev) {
|
||||
if (ifa1 == ifa) {
|
||||
/* promotion, keep the IP */
|
||||
gone = 0;
|
||||
|
@ -1246,6 +1254,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
|
|||
}
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
no_promotions:
|
||||
if (!(ok & BRD_OK))
|
||||
|
@ -1415,6 +1424,7 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
|
|||
struct netdev_notifier_info_ext *info_ext = ptr;
|
||||
struct in_device *in_dev;
|
||||
struct net *net = dev_net(dev);
|
||||
struct in_ifaddr *ifa;
|
||||
unsigned int flags;
|
||||
|
||||
if (event == NETDEV_UNREGISTER) {
|
||||
|
@ -1429,9 +1439,9 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
|
|||
|
||||
switch (event) {
|
||||
case NETDEV_UP:
|
||||
for_ifa(in_dev) {
|
||||
in_dev_for_each_ifa_rtnl(ifa, in_dev) {
|
||||
fib_add_ifaddr(ifa);
|
||||
} endfor_ifa(in_dev);
|
||||
}
|
||||
#ifdef CONFIG_IP_ROUTE_MULTIPATH
|
||||
fib_sync_up(dev, RTNH_F_DEAD);
|
||||
#endif
|
||||
|
|
|
@ -336,14 +336,15 @@ static __be32 igmpv3_get_srcaddr(struct net_device *dev,
|
|||
const struct flowi4 *fl4)
|
||||
{
|
||||
struct in_device *in_dev = __in_dev_get_rcu(dev);
|
||||
const struct in_ifaddr *ifa;
|
||||
|
||||
if (!in_dev)
|
||||
return htonl(INADDR_ANY);
|
||||
|
||||
for_ifa(in_dev) {
|
||||
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||
if (fl4->saddr == ifa->ifa_local)
|
||||
return fl4->saddr;
|
||||
} endfor_ifa(in_dev);
|
||||
}
|
||||
|
||||
return htonl(INADDR_ANY);
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ EXPORT_SYMBOL_GPL(nf_tproxy_handle_time_wait4);
|
|||
|
||||
__be32 nf_tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr)
|
||||
{
|
||||
const struct in_ifaddr *ifa;
|
||||
struct in_device *indev;
|
||||
__be32 laddr;
|
||||
|
||||
|
@ -61,10 +62,14 @@ __be32 nf_tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr)
|
|||
|
||||
laddr = 0;
|
||||
indev = __in_dev_get_rcu(skb->dev);
|
||||
for_primary_ifa(indev) {
|
||||
|
||||
in_dev_for_each_ifa_rcu(ifa, indev) {
|
||||
if (ifa->ifa_flags & IFA_F_SECONDARY)
|
||||
continue;
|
||||
|
||||
laddr = ifa->ifa_local;
|
||||
break;
|
||||
} endfor_ifa(indev);
|
||||
}
|
||||
|
||||
return laddr ? laddr : daddr;
|
||||
}
|
||||
|
|
|
@ -3127,11 +3127,9 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
|
|||
struct in_device *in_dev = __in_dev_get_rtnl(dev);
|
||||
if (in_dev && (dev->flags & IFF_UP)) {
|
||||
struct in_ifaddr *ifa;
|
||||
|
||||
int flag = scope;
|
||||
|
||||
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
|
||||
|
||||
in_dev_for_each_ifa_rtnl(ifa, in_dev) {
|
||||
addr.s6_addr32[3] = ifa->ifa_local;
|
||||
|
||||
if (ifa->ifa_scope == RT_SCOPE_LINK)
|
||||
|
|
|
@ -354,11 +354,11 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
|
|||
sdata_lock(sdata);
|
||||
|
||||
/* Copy the addresses to the bss_conf list */
|
||||
ifa = idev->ifa_list;
|
||||
ifa = rtnl_dereference(idev->ifa_list);
|
||||
while (ifa) {
|
||||
if (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN)
|
||||
bss_conf->arp_addr_list[c] = ifa->ifa_address;
|
||||
ifa = ifa->ifa_next;
|
||||
ifa = rtnl_dereference(ifa->ifa_next);
|
||||
c++;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,12 +41,17 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
|
|||
|
||||
in_dev = __in_dev_get_rcu(rt->dst.dev);
|
||||
if (in_dev != NULL) {
|
||||
for_primary_ifa(in_dev) {
|
||||
const struct in_ifaddr *ifa;
|
||||
|
||||
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||
if (ifa->ifa_flags & IFA_F_SECONDARY)
|
||||
continue;
|
||||
|
||||
if (ifa->ifa_broadcast == iph->daddr) {
|
||||
mask = ifa->ifa_mask;
|
||||
break;
|
||||
}
|
||||
} endfor_ifa(in_dev);
|
||||
}
|
||||
}
|
||||
|
||||
if (mask == 0)
|
||||
|
|
|
@ -47,15 +47,17 @@ nf_nat_redirect_ipv4(struct sk_buff *skb,
|
|||
if (hooknum == NF_INET_LOCAL_OUT) {
|
||||
newdst = htonl(0x7F000001);
|
||||
} else {
|
||||
struct in_device *indev;
|
||||
struct in_ifaddr *ifa;
|
||||
const struct in_device *indev;
|
||||
|
||||
newdst = 0;
|
||||
|
||||
indev = __in_dev_get_rcu(skb->dev);
|
||||
if (indev && indev->ifa_list) {
|
||||
ifa = indev->ifa_list;
|
||||
newdst = ifa->ifa_local;
|
||||
if (indev) {
|
||||
const struct in_ifaddr *ifa;
|
||||
|
||||
ifa = rcu_dereference(indev->ifa_list);
|
||||
if (ifa)
|
||||
newdst = ifa->ifa_local;
|
||||
}
|
||||
|
||||
if (!newdst)
|
||||
|
|
|
@ -33,6 +33,7 @@ static inline int nf_osf_ttl(const struct sk_buff *skb,
|
|||
{
|
||||
struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
|
||||
const struct iphdr *ip = ip_hdr(skb);
|
||||
const struct in_ifaddr *ifa;
|
||||
int ret = 0;
|
||||
|
||||
if (ttl_check == NF_OSF_TTL_TRUE)
|
||||
|
@ -42,15 +43,13 @@ static inline int nf_osf_ttl(const struct sk_buff *skb,
|
|||
else if (ip->ttl <= f_ttl)
|
||||
return 1;
|
||||
|
||||
for_ifa(in_dev) {
|
||||
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||
if (inet_ifa_match(ip->saddr, ifa)) {
|
||||
ret = (ip->ttl == f_ttl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
endfor_ifa(in_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
|
|||
return;
|
||||
}
|
||||
|
||||
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
|
||||
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||
/* Add the address to the local list. */
|
||||
addr = kzalloc(sizeof(*addr), GFP_ATOMIC);
|
||||
if (addr) {
|
||||
|
|
|
@ -97,17 +97,19 @@ static int smc_clc_prfx_set4_rcu(struct dst_entry *dst, __be32 ipv4,
|
|||
struct smc_clc_msg_proposal_prefix *prop)
|
||||
{
|
||||
struct in_device *in_dev = __in_dev_get_rcu(dst->dev);
|
||||
const struct in_ifaddr *ifa;
|
||||
|
||||
if (!in_dev)
|
||||
return -ENODEV;
|
||||
for_ifa(in_dev) {
|
||||
|
||||
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||
if (!inet_ifa_match(ipv4, ifa))
|
||||
continue;
|
||||
prop->prefix_len = inet_mask_len(ifa->ifa_mask);
|
||||
prop->outgoing_subnet = ifa->ifa_address & ifa->ifa_mask;
|
||||
/* prop->ipv6_prefixes_cnt = 0; already done by memset before */
|
||||
return 0;
|
||||
} endfor_ifa(in_dev);
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
|
@ -190,14 +192,15 @@ static int smc_clc_prfx_match4_rcu(struct net_device *dev,
|
|||
struct smc_clc_msg_proposal_prefix *prop)
|
||||
{
|
||||
struct in_device *in_dev = __in_dev_get_rcu(dev);
|
||||
const struct in_ifaddr *ifa;
|
||||
|
||||
if (!in_dev)
|
||||
return -ENODEV;
|
||||
for_ifa(in_dev) {
|
||||
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||
if (prop->prefix_len == inet_mask_len(ifa->ifa_mask) &&
|
||||
inet_ifa_match(prop->outgoing_subnet, ifa))
|
||||
return 0;
|
||||
} endfor_ifa(in_dev);
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue