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,
|
static void enum_netdev_ipv4_ips(struct ib_device *ib_dev,
|
||||||
u8 port, struct net_device *ndev)
|
u8 port, struct net_device *ndev)
|
||||||
{
|
{
|
||||||
|
const struct in_ifaddr *ifa;
|
||||||
struct in_device *in_dev;
|
struct in_device *in_dev;
|
||||||
struct sin_list {
|
struct sin_list {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
@ -349,7 +350,7 @@ static void enum_netdev_ipv4_ips(struct ib_device *ib_dev,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for_ifa(in_dev) {
|
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||||
struct sin_list *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
|
struct sin_list *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
|
||||||
|
|
||||||
if (!entry)
|
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;
|
entry->ip.sin_addr.s_addr = ifa->ifa_address;
|
||||||
list_add_tail(&entry->list, &sin_list);
|
list_add_tail(&entry->list, &sin_list);
|
||||||
}
|
}
|
||||||
endfor_ifa(in_dev);
|
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
list_for_each_entry_safe(sin_iter, sin_temp, &sin_list, list) {
|
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;
|
int found = 0;
|
||||||
struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
|
struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
|
||||||
struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->m_remote_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]);
|
ind = in_dev_get(dev->rdev.lldi.ports[0]);
|
||||||
if (!ind)
|
if (!ind)
|
||||||
return -EADDRNOTAVAIL;
|
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;
|
laddr->sin_addr.s_addr = ifa->ifa_address;
|
||||||
raddr->sin_addr.s_addr = ifa->ifa_address;
|
raddr->sin_addr.s_addr = ifa->ifa_address;
|
||||||
found = 1;
|
found = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
endfor_ifa(ind);
|
rcu_read_unlock();
|
||||||
|
|
||||||
in_dev_put(ind);
|
in_dev_put(ind);
|
||||||
return found ? 0 : -EADDRNOTAVAIL;
|
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) &&
|
if ((((rdma_vlan_dev_vlan_id(dev) < I40IW_NO_VLAN) &&
|
||||||
(rdma_vlan_dev_real_dev(dev) == iwdev->netdev)) ||
|
(rdma_vlan_dev_real_dev(dev) == iwdev->netdev)) ||
|
||||||
(dev == iwdev->netdev)) && (dev->flags & IFF_UP)) {
|
(dev == iwdev->netdev)) && (dev->flags & IFF_UP)) {
|
||||||
|
const struct in_ifaddr *ifa;
|
||||||
|
|
||||||
idev = in_dev_get(dev);
|
idev = in_dev_get(dev);
|
||||||
for_ifa(idev) {
|
|
||||||
|
in_dev_for_each_ifa_rtnl(ifa, idev) {
|
||||||
i40iw_debug(&iwdev->sc_dev,
|
i40iw_debug(&iwdev->sc_dev,
|
||||||
I40IW_DEBUG_CM,
|
I40IW_DEBUG_CM,
|
||||||
"Allocating child CM Listener forIP=%pI4, vlan_id=%d, MAC=%pM\n",
|
"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--;
|
cm_parent_listen_node->cm_core->stats_listen_nodes_created--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
endfor_ifa(idev);
|
|
||||||
in_dev_put(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) &&
|
if ((((rdma_vlan_dev_vlan_id(dev) < 0xFFFF) &&
|
||||||
(rdma_vlan_dev_real_dev(dev) == iwdev->netdev)) ||
|
(rdma_vlan_dev_real_dev(dev) == iwdev->netdev)) ||
|
||||||
(dev == iwdev->netdev)) && (dev->flags & IFF_UP)) {
|
(dev == iwdev->netdev)) && (dev->flags & IFF_UP)) {
|
||||||
|
const struct in_ifaddr *ifa;
|
||||||
|
|
||||||
idev = in_dev_get(dev);
|
idev = in_dev_get(dev);
|
||||||
for_ifa(idev) {
|
in_dev_for_each_ifa_rtnl(ifa, idev) {
|
||||||
i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_CM,
|
i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_CM,
|
||||||
"IP=%pI4, vlan_id=%d, MAC=%pM\n", &ifa->ifa_address,
|
"IP=%pI4, vlan_id=%d, MAC=%pM\n", &ifa->ifa_address,
|
||||||
rdma_vlan_dev_vlan_id(dev), dev->dev_addr);
|
rdma_vlan_dev_vlan_id(dev), dev->dev_addr);
|
||||||
|
@ -1235,7 +1237,7 @@ static void i40iw_add_ipv4_addr(struct i40iw_device *iwdev)
|
||||||
true,
|
true,
|
||||||
I40IW_ARP_ADD);
|
I40IW_ARP_ADD);
|
||||||
}
|
}
|
||||||
endfor_ifa(idev);
|
|
||||||
in_dev_put(idev);
|
in_dev_put(idev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,10 +174,14 @@ int i40iw_inetaddr_event(struct notifier_block *notifier,
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
in = __in_dev_get_rcu(upper_dev);
|
in = __in_dev_get_rcu(upper_dev);
|
||||||
|
|
||||||
if (!in->ifa_list)
|
|
||||||
local_ipaddr = 0;
|
local_ipaddr = 0;
|
||||||
else
|
if (in) {
|
||||||
local_ipaddr = ntohl(in->ifa_list->ifa_address);
|
struct in_ifaddr *ifa;
|
||||||
|
|
||||||
|
ifa = rcu_dereference(in->ifa_list);
|
||||||
|
if (ifa)
|
||||||
|
local_ipaddr = ntohl(ifa->ifa_address);
|
||||||
|
}
|
||||||
|
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -183,7 +183,13 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
in = __in_dev_get_rcu(upper_dev);
|
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();
|
rcu_read_unlock();
|
||||||
} else {
|
} else {
|
||||||
nesvnic->local_ipaddr = ifa->ifa_address;
|
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))
|
if (netif_carrier_ok(us_ibdev->netdev))
|
||||||
usnic_fwd_carrier_up(us_ibdev->ufdev);
|
usnic_fwd_carrier_up(us_ibdev->ufdev);
|
||||||
|
|
||||||
ind = in_dev_get(netdev);
|
rcu_read_lock();
|
||||||
if (ind->ifa_list)
|
ind = __in_dev_get_rcu(netdev);
|
||||||
usnic_fwd_add_ipaddr(us_ibdev->ufdev,
|
if (ind) {
|
||||||
ind->ifa_list->ifa_address);
|
const struct in_ifaddr *ifa;
|
||||||
in_dev_put(ind);
|
|
||||||
|
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,
|
usnic_mac_ip_to_gid(us_ibdev->netdev->perm_addr,
|
||||||
us_ibdev->ufdev->inaddr, &gid.raw[0]);
|
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 net_device *dev, unsigned long event)
|
||||||
{
|
{
|
||||||
struct in_device *indev;
|
struct in_device *indev;
|
||||||
|
struct in_ifaddr *ifa;
|
||||||
|
|
||||||
if (!netxen_destip_supported(adapter))
|
if (!netxen_destip_supported(adapter))
|
||||||
return;
|
return;
|
||||||
|
@ -3256,7 +3257,8 @@ netxen_config_indev_addr(struct netxen_adapter *adapter,
|
||||||
if (!indev)
|
if (!indev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for_ifa(indev) {
|
rcu_read_lock();
|
||||||
|
in_dev_for_each_ifa_rcu(ifa, indev) {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case NETDEV_UP:
|
case NETDEV_UP:
|
||||||
netxen_list_config_ip(adapter, ifa, NX_IP_UP);
|
netxen_list_config_ip(adapter, ifa, NX_IP_UP);
|
||||||
|
@ -3267,8 +3269,8 @@ netxen_config_indev_addr(struct netxen_adapter *adapter,
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} endfor_ifa(indev);
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
in_dev_put(indev);
|
in_dev_put(indev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4119,13 +4119,14 @@ static void
|
||||||
qlcnic_config_indev_addr(struct qlcnic_adapter *adapter,
|
qlcnic_config_indev_addr(struct qlcnic_adapter *adapter,
|
||||||
struct net_device *dev, unsigned long event)
|
struct net_device *dev, unsigned long event)
|
||||||
{
|
{
|
||||||
|
const struct in_ifaddr *ifa;
|
||||||
struct in_device *indev;
|
struct in_device *indev;
|
||||||
|
|
||||||
indev = in_dev_get(dev);
|
indev = in_dev_get(dev);
|
||||||
if (!indev)
|
if (!indev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for_ifa(indev) {
|
in_dev_for_each_ifa_rtnl(ifa, indev) {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case NETDEV_UP:
|
case NETDEV_UP:
|
||||||
qlcnic_config_ipaddr(adapter,
|
qlcnic_config_ipaddr(adapter,
|
||||||
|
@ -4138,7 +4139,7 @@ qlcnic_config_indev_addr(struct qlcnic_adapter *adapter,
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} endfor_ifa(indev);
|
}
|
||||||
|
|
||||||
in_dev_put(indev);
|
in_dev_put(indev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1509,7 +1509,7 @@ static inline int velocity_get_ip(struct velocity_info *vptr)
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
in_dev = __in_dev_get_rcu(vptr->netdev);
|
in_dev = __in_dev_get_rcu(vptr->netdev);
|
||||||
if (in_dev != NULL) {
|
if (in_dev != NULL) {
|
||||||
ifa = (struct in_ifaddr *) in_dev->ifa_list;
|
ifa = rcu_dereference(in_dev->ifa_list);
|
||||||
if (ifa != NULL) {
|
if (ifa != NULL) {
|
||||||
memcpy(vptr->ip_addr, &ifa->ifa_address, 4);
|
memcpy(vptr->ip_addr, &ifa->ifa_address, 4);
|
||||||
res = 0;
|
res = 0;
|
||||||
|
|
|
@ -1012,7 +1012,7 @@ plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth)
|
||||||
in_dev = __in_dev_get_rcu(dev);
|
in_dev = __in_dev_get_rcu(dev);
|
||||||
if (in_dev) {
|
if (in_dev) {
|
||||||
/* Any address will do - we take the first */
|
/* 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) {
|
if (ifa) {
|
||||||
memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
|
memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
|
||||||
memset(eth->h_dest, 0xfc, 2);
|
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
|
/* Any address will do - we take the first. We already
|
||||||
have the first two bytes filled with 0xfc, from
|
have the first two bytes filled with 0xfc, from
|
||||||
plip_init_dev(). */
|
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) {
|
if (ifa != NULL) {
|
||||||
memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
|
memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3651,13 +3651,19 @@ vmxnet3_suspend(struct device *device)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adapter->wol & WAKE_ARP) {
|
if (adapter->wol & WAKE_ARP) {
|
||||||
in_dev = in_dev_get(netdev);
|
rcu_read_lock();
|
||||||
if (!in_dev)
|
|
||||||
goto skip_arp;
|
|
||||||
|
|
||||||
ifa = (struct in_ifaddr *)in_dev->ifa_list;
|
in_dev = __in_dev_get_rcu(netdev);
|
||||||
if (!ifa)
|
if (!in_dev) {
|
||||||
|
rcu_read_unlock();
|
||||||
goto skip_arp;
|
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*/
|
pmConf->filters[i].patternSize = ETH_HLEN + /* Ethernet header*/
|
||||||
sizeof(struct arphdr) + /* ARP header */
|
sizeof(struct arphdr) + /* ARP header */
|
||||||
|
@ -3677,7 +3683,9 @@ vmxnet3_suspend(struct device *device)
|
||||||
|
|
||||||
/* The Unicast IPv4 address in 'tip' field. */
|
/* The Unicast IPv4 address in 'tip' field. */
|
||||||
arpreq += 2 * ETH_ALEN + sizeof(u32);
|
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. */
|
/* The mask for the relevant bits. */
|
||||||
pmConf->filters[i].mask[0] = 0x00;
|
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[3] = 0x00;
|
||||||
pmConf->filters[i].mask[4] = 0xC0; /* IPv4 TIP */
|
pmConf->filters[i].mask[4] = 0xC0; /* IPv4 TIP */
|
||||||
pmConf->filters[i].mask[5] = 0x03; /* IPv4 TIP */
|
pmConf->filters[i].mask[5] = 0x03; /* IPv4 TIP */
|
||||||
in_dev_put(in_dev);
|
|
||||||
|
|
||||||
pmConf->wakeUpEvents |= VMXNET3_PM_WAKEUP_FILTER;
|
pmConf->wakeUpEvents |= VMXNET3_PM_WAKEUP_FILTER;
|
||||||
i++;
|
i++;
|
||||||
|
|
|
@ -196,16 +196,15 @@ static int cisco_rx(struct sk_buff *skb)
|
||||||
mask = ~cpu_to_be32(0); /* is the mask correct? */
|
mask = ~cpu_to_be32(0); /* is the mask correct? */
|
||||||
|
|
||||||
if (in_dev != NULL) {
|
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,
|
if (strcmp(dev->name,
|
||||||
(*ifap)->ifa_label) == 0) {
|
ifa->ifa_label) == 0) {
|
||||||
addr = (*ifap)->ifa_local;
|
addr = ifa->ifa_local;
|
||||||
mask = (*ifap)->ifa_mask;
|
mask = ifa->ifa_mask;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ifap = &(*ifap)->ifa_next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cisco_keepalive_send(dev, CISCO_ADDR_REPLY,
|
cisco_keepalive_send(dev, CISCO_ADDR_REPLY,
|
||||||
|
|
|
@ -2194,13 +2194,13 @@ static int ath6kl_wow_suspend_vif(struct ath6kl_vif *vif,
|
||||||
if (!in_dev)
|
if (!in_dev)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ifa = in_dev->ifa_list;
|
ifa = rtnl_dereference(in_dev->ifa_list);
|
||||||
memset(&ips, 0, sizeof(ips));
|
memset(&ips, 0, sizeof(ips));
|
||||||
|
|
||||||
/* Configure IP addr only if IP address count < MAX_IP_ADDRS */
|
/* Configure IP addr only if IP address count < MAX_IP_ADDRS */
|
||||||
while (index < MAX_IP_ADDRS && ifa) {
|
while (index < MAX_IP_ADDRS && ifa) {
|
||||||
ips[index] = ifa->ifa_local;
|
ips[index] = ifa->ifa_local;
|
||||||
ifa = ifa->ifa_next;
|
ifa = rtnl_dereference(ifa->ifa_next);
|
||||||
index++;
|
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);
|
in_dev = __in_dev_get_rtnl(adapter->priv[i]->netdev);
|
||||||
if (!in_dev)
|
if (!in_dev)
|
||||||
continue;
|
continue;
|
||||||
ifa = in_dev->ifa_list;
|
ifa = rtnl_dereference(in_dev->ifa_list);
|
||||||
if (!ifa || !ifa->ifa_local)
|
if (!ifa || !ifa->ifa_local)
|
||||||
continue;
|
continue;
|
||||||
ips[i] = ifa->ifa_local;
|
ips[i] = ifa->ifa_local;
|
||||||
|
|
|
@ -70,9 +70,13 @@ net_open(struct net_device *dev)
|
||||||
for (i = 0; i < ETH_ALEN; i++)
|
for (i = 0; i < ETH_ALEN; i++)
|
||||||
dev->dev_addr[i] = 0xfc;
|
dev->dev_addr[i] = 0xfc;
|
||||||
if ((in_dev = dev->ip_ptr) != NULL) {
|
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)
|
if (ifa != NULL)
|
||||||
memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ifa->ifa_local)), &ifa->ifa_local, sizeof(ifa->ifa_local));
|
memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ifa->ifa_local)), &ifa->ifa_local, sizeof(ifa->ifa_local));
|
||||||
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN);
|
memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN);
|
||||||
|
|
|
@ -29,7 +29,6 @@ kafs-y := \
|
||||||
server.o \
|
server.o \
|
||||||
server_list.o \
|
server_list.o \
|
||||||
super.o \
|
super.o \
|
||||||
netdevices.o \
|
|
||||||
vlclient.o \
|
vlclient.o \
|
||||||
vl_list.o \
|
vl_list.o \
|
||||||
vl_probe.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)
|
static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct afs_interface *ifs;
|
|
||||||
struct afs_call *call = container_of(work, struct afs_call, work);
|
struct afs_call *call = container_of(work, struct afs_call, work);
|
||||||
int loop, nifs;
|
int loop;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct /* InterfaceAddr */ {
|
struct /* InterfaceAddr */ {
|
||||||
|
@ -604,19 +603,7 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
|
||||||
|
|
||||||
_enter("");
|
_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));
|
memset(&reply, 0, sizeof(reply));
|
||||||
reply.ia.nifs = htonl(nifs);
|
|
||||||
|
|
||||||
reply.ia.uuid[0] = call->net->uuid.time_low;
|
reply.ia.uuid[0] = call->net->uuid.time_low;
|
||||||
reply.ia.uuid[1] = htonl(ntohs(call->net->uuid.time_mid));
|
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++)
|
for (loop = 0; loop < 6; loop++)
|
||||||
reply.ia.uuid[loop + 5] = htonl((s8) call->net->uuid.node[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.capcount = htonl(1);
|
||||||
reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION);
|
reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION);
|
||||||
afs_send_simple_reply(call, &reply, sizeof(reply));
|
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 */
|
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.
|
* 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 struct vfsmount *afs_d_automount(struct path *);
|
||||||
extern void afs_mntpt_kill_timer(void);
|
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
|
* 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;
|
struct net_device *dev;
|
||||||
refcount_t refcnt;
|
refcount_t refcnt;
|
||||||
int dead;
|
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 *mc_list; /* IP multicast filter chain */
|
||||||
struct ip_mc_list __rcu * __rcu *mc_hash;
|
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 in_ifaddr {
|
||||||
struct hlist_node hash;
|
struct hlist_node hash;
|
||||||
struct in_ifaddr *ifa_next;
|
struct in_ifaddr __rcu *ifa_next;
|
||||||
struct in_device *ifa_dev;
|
struct in_device *ifa_dev;
|
||||||
struct rcu_head rcu_head;
|
struct rcu_head rcu_head;
|
||||||
__be32 ifa_local;
|
__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,
|
struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
|
||||||
__be32 mask);
|
__be32 mask);
|
||||||
struct in_ifaddr *inet_lookup_ifaddr_rcu(struct net *net, __be32 addr);
|
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);
|
return !((addr^ifa->ifa_address)&ifa->ifa_mask);
|
||||||
}
|
}
|
||||||
|
@ -206,14 +206,13 @@ static __inline__ bool bad_mask(__be32 mask, __be32 addr)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define for_primary_ifa(in_dev) { struct in_ifaddr *ifa; \
|
#define in_dev_for_each_ifa_rtnl(ifa, in_dev) \
|
||||||
for (ifa = (in_dev)->ifa_list; ifa && !(ifa->ifa_flags&IFA_F_SECONDARY); ifa = ifa->ifa_next)
|
for (ifa = rtnl_dereference((in_dev)->ifa_list); ifa; \
|
||||||
|
ifa = rtnl_dereference(ifa->ifa_next))
|
||||||
|
|
||||||
#define for_ifa(in_dev) { struct in_ifaddr *ifa; \
|
#define in_dev_for_each_ifa_rcu(ifa, in_dev) \
|
||||||
for (ifa = (in_dev)->ifa_list; ifa; ifa = ifa->ifa_next)
|
for (ifa = rcu_dereference((in_dev)->ifa_list); ifa; \
|
||||||
|
ifa = rcu_dereference(ifa->ifa_next))
|
||||||
|
|
||||||
#define endfor_ifa(in_dev) }
|
|
||||||
|
|
||||||
static inline struct in_device *__in_dev_get_rcu(const struct net_device *dev)
|
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->local_ip.ip) {
|
||||||
if (!np->ipv6) {
|
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_err(np, "no IP address for %s, aborting\n",
|
||||||
np->dev_name);
|
np->dev_name);
|
||||||
err = -EDESTADDRREQ;
|
err = -EDESTADDRREQ;
|
||||||
goto put;
|
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);
|
np_info(np, "local IP %pI4\n", &np->local_ip.ip);
|
||||||
} else {
|
} else {
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
|
|
@ -2125,9 +2125,11 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
in_dev = __in_dev_get_rcu(pkt_dev->odev);
|
in_dev = __in_dev_get_rcu(pkt_dev->odev);
|
||||||
if (in_dev) {
|
if (in_dev) {
|
||||||
if (in_dev->ifa_list) {
|
const struct in_ifaddr *ifa;
|
||||||
pkt_dev->saddr_min =
|
|
||||||
in_dev->ifa_list->ifa_address;
|
ifa = rcu_dereference(in_dev->ifa_list);
|
||||||
|
if (ifa) {
|
||||||
|
pkt_dev->saddr_min = ifa->ifa_address;
|
||||||
pkt_dev->saddr_max = pkt_dev->saddr_min;
|
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_chain);
|
||||||
static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_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);
|
int destroy);
|
||||||
#ifdef CONFIG_SYSCTL
|
#ifdef CONFIG_SYSCTL
|
||||||
static int devinet_sysctl_register(struct in_device *idev);
|
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)
|
static void inetdev_destroy(struct in_device *in_dev)
|
||||||
{
|
{
|
||||||
struct in_ifaddr *ifa;
|
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
|
struct in_ifaddr *ifa;
|
||||||
|
|
||||||
ASSERT_RTNL();
|
ASSERT_RTNL();
|
||||||
|
|
||||||
|
@ -311,7 +312,7 @@ static void inetdev_destroy(struct in_device *in_dev)
|
||||||
|
|
||||||
ip_mc_destroy_dev(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_del_ifa(in_dev, &in_dev->ifa_list, 0);
|
||||||
inet_free_ifa(ifa);
|
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)
|
int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
|
||||||
{
|
{
|
||||||
|
const struct in_ifaddr *ifa;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
for_primary_ifa(in_dev) {
|
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||||
if (inet_ifa_match(a, ifa)) {
|
if (inet_ifa_match(a, ifa)) {
|
||||||
if (!b || inet_ifa_match(b, ifa)) {
|
if (!b || inet_ifa_match(b, ifa)) {
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} endfor_ifa(in_dev);
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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, struct nlmsghdr *nlh, u32 portid)
|
int destroy, struct nlmsghdr *nlh, u32 portid)
|
||||||
{
|
{
|
||||||
struct in_ifaddr *promote = NULL;
|
struct in_ifaddr *promote = NULL;
|
||||||
struct in_ifaddr *ifa, *ifa1 = *ifap;
|
struct in_ifaddr *ifa, *ifa1;
|
||||||
struct in_ifaddr *last_prim = in_dev->ifa_list;
|
struct in_ifaddr *last_prim;
|
||||||
struct in_ifaddr *prev_prom = NULL;
|
struct in_ifaddr *prev_prom = NULL;
|
||||||
int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
|
int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
|
||||||
|
|
||||||
ASSERT_RTNL();
|
ASSERT_RTNL();
|
||||||
|
|
||||||
|
ifa1 = rtnl_dereference(*ifap);
|
||||||
|
last_prim = rtnl_dereference(in_dev->ifa_list);
|
||||||
if (in_dev->dead)
|
if (in_dev->dead)
|
||||||
goto no_promotions;
|
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)) {
|
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) &&
|
if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
|
||||||
ifa1->ifa_scope <= ifa->ifa_scope)
|
ifa1->ifa_scope <= ifa->ifa_scope)
|
||||||
last_prim = ifa;
|
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
|
* and later to add them back with new prefsrc. Do this
|
||||||
* while all addresses are on the device list.
|
* 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 &&
|
if (ifa1->ifa_mask == ifa->ifa_mask &&
|
||||||
inet_ifa_match(ifa1->ifa_address, ifa))
|
inet_ifa_match(ifa1->ifa_address, ifa))
|
||||||
fib_del_ifaddr(ifa, ifa1);
|
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);
|
blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
|
||||||
|
|
||||||
if (promote) {
|
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) {
|
if (prev_prom) {
|
||||||
prev_prom->ifa_next = promote->ifa_next;
|
struct in_ifaddr *last_sec;
|
||||||
promote->ifa_next = last_prim->ifa_next;
|
|
||||||
last_prim->ifa_next = promote;
|
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;
|
promote->ifa_flags &= ~IFA_F_SECONDARY;
|
||||||
rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
|
rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
|
||||||
blocking_notifier_call_chain(&inetaddr_chain,
|
blocking_notifier_call_chain(&inetaddr_chain,
|
||||||
NETDEV_UP, promote);
|
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 ||
|
if (ifa1->ifa_mask != ifa->ifa_mask ||
|
||||||
!inet_ifa_match(ifa1->ifa_address, ifa))
|
!inet_ifa_match(ifa1->ifa_address, ifa))
|
||||||
continue;
|
continue;
|
||||||
|
@ -444,7 +455,8 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
|
||||||
inet_free_ifa(ifa1);
|
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)
|
int destroy)
|
||||||
{
|
{
|
||||||
__inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
|
__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,
|
static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
|
||||||
u32 portid, struct netlink_ext_ack *extack)
|
u32 portid, struct netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
|
struct in_ifaddr __rcu **last_primary, **ifap;
|
||||||
struct in_device *in_dev = ifa->ifa_dev;
|
struct in_device *in_dev = ifa->ifa_dev;
|
||||||
struct in_ifaddr *ifa1, **ifap, **last_primary;
|
|
||||||
struct in_validator_info ivi;
|
struct in_validator_info ivi;
|
||||||
|
struct in_ifaddr *ifa1;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ASSERT_RTNL();
|
ASSERT_RTNL();
|
||||||
|
@ -472,8 +485,10 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
|
||||||
ifa->ifa_flags &= ~IFA_F_SECONDARY;
|
ifa->ifa_flags &= ~IFA_F_SECONDARY;
|
||||||
last_primary = &in_dev->ifa_list;
|
last_primary = &in_dev->ifa_list;
|
||||||
|
|
||||||
for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
|
ifap = &in_dev->ifa_list;
|
||||||
ifap = &ifa1->ifa_next) {
|
ifa1 = rtnl_dereference(*ifap);
|
||||||
|
|
||||||
|
while (ifa1) {
|
||||||
if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
|
if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
|
||||||
ifa->ifa_scope <= ifa1->ifa_scope)
|
ifa->ifa_scope <= ifa1->ifa_scope)
|
||||||
last_primary = &ifa1->ifa_next;
|
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;
|
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
|
/* 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;
|
ifap = last_primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
ifa->ifa_next = *ifap;
|
rcu_assign_pointer(ifa->ifa_next, *ifap);
|
||||||
*ifap = ifa;
|
rcu_assign_pointer(*ifap, ifa);
|
||||||
|
|
||||||
inet_hash_insert(dev_net(in_dev->dev), 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,
|
struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
|
||||||
__be32 mask)
|
__be32 mask)
|
||||||
{
|
{
|
||||||
|
struct in_ifaddr *ifa;
|
||||||
|
|
||||||
ASSERT_RTNL();
|
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))
|
if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
|
||||||
return ifa;
|
return ifa;
|
||||||
} endfor_ifa(in_dev);
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,10 +633,12 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||||
struct netlink_ext_ack *extack)
|
struct netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(skb->sk);
|
struct net *net = sock_net(skb->sk);
|
||||||
|
struct in_ifaddr __rcu **ifap;
|
||||||
struct nlattr *tb[IFA_MAX+1];
|
struct nlattr *tb[IFA_MAX+1];
|
||||||
struct in_device *in_dev;
|
struct in_device *in_dev;
|
||||||
struct ifaddrmsg *ifm;
|
struct ifaddrmsg *ifm;
|
||||||
struct in_ifaddr *ifa, **ifap;
|
struct in_ifaddr *ifa;
|
||||||
|
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
|
|
||||||
ASSERT_RTNL();
|
ASSERT_RTNL();
|
||||||
|
@ -633,7 +655,7 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||||
goto errout;
|
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) {
|
ifap = &ifa->ifa_next) {
|
||||||
if (tb[IFA_LOCAL] &&
|
if (tb[IFA_LOCAL] &&
|
||||||
ifa->ifa_local != nla_get_in_addr(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 &&
|
if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
|
||||||
age >= ifa->ifa_valid_lft) {
|
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 = &ifa->ifa_dev->ifa_list;
|
||||||
*ifap != NULL; ifap = &(*ifap)->ifa_next) {
|
tmp = rtnl_dereference(*ifap);
|
||||||
if (*ifap == ifa) {
|
while (tmp) {
|
||||||
|
tmp = rtnl_dereference(tmp->ifa_next);
|
||||||
|
if (rtnl_dereference(*ifap) == ifa) {
|
||||||
inet_del_ifa(ifa->ifa_dev,
|
inet_del_ifa(ifa->ifa_dev,
|
||||||
ifap, 1);
|
ifap, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
ifap = &tmp->ifa_next;
|
||||||
|
tmp = rtnl_dereference(*ifap);
|
||||||
}
|
}
|
||||||
} else if (ifa->ifa_preferred_lft !=
|
} else if (ifa->ifa_preferred_lft !=
|
||||||
INFINITY_LIFE_TIME &&
|
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)
|
static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
|
||||||
{
|
{
|
||||||
struct in_device *in_dev = ifa->ifa_dev;
|
struct in_device *in_dev = ifa->ifa_dev;
|
||||||
struct in_ifaddr *ifa1, **ifap;
|
struct in_ifaddr *ifa1;
|
||||||
|
|
||||||
if (!ifa->ifa_local)
|
if (!ifa->ifa_local)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
|
in_dev_for_each_ifa_rtnl(ifa1, in_dev) {
|
||||||
ifap = &ifa1->ifa_next) {
|
|
||||||
if (ifa1->ifa_mask == ifa->ifa_mask &&
|
if (ifa1->ifa_mask == ifa->ifa_mask &&
|
||||||
inet_ifa_match(ifa1->ifa_address, ifa) &&
|
inet_ifa_match(ifa1->ifa_address, ifa) &&
|
||||||
ifa1->ifa_local == ifa->ifa_local)
|
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_orig;
|
||||||
struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
|
struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
|
||||||
|
struct in_ifaddr __rcu **ifap = NULL;
|
||||||
struct in_device *in_dev;
|
struct in_device *in_dev;
|
||||||
struct in_ifaddr **ifap = NULL;
|
|
||||||
struct in_ifaddr *ifa = NULL;
|
struct in_ifaddr *ifa = NULL;
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
char *colon;
|
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
|
/* note: we only do this for a limited set of ioctls
|
||||||
and only if the original address family was AF_INET.
|
and only if the original address family was AF_INET.
|
||||||
This is checked above. */
|
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) {
|
ifap = &ifa->ifa_next) {
|
||||||
if (!strcmp(ifr->ifr_name, ifa->ifa_label) &&
|
if (!strcmp(ifr->ifr_name, ifa->ifa_label) &&
|
||||||
sin_orig.sin_addr.s_addr ==
|
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
|
4.3BSD-style and passed in junk so we fall back to
|
||||||
comparing just the label */
|
comparing just the label */
|
||||||
if (!ifa) {
|
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)
|
ifap = &ifa->ifa_next)
|
||||||
if (!strcmp(ifr->ifr_name, ifa->ifa_label))
|
if (!strcmp(ifr->ifr_name, ifa->ifa_label))
|
||||||
break;
|
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)
|
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_device *in_dev = __in_dev_get_rtnl(dev);
|
||||||
struct in_ifaddr *ifa;
|
const struct in_ifaddr *ifa;
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
int done = 0;
|
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)
|
if (!in_dev)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
|
in_dev_for_each_ifa_rtnl(ifa, in_dev) {
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
done += size;
|
done += size;
|
||||||
continue;
|
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,
|
static __be32 in_dev_select_addr(const struct in_device *in_dev,
|
||||||
int scope)
|
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 &&
|
if (ifa->ifa_scope != RT_SCOPE_LINK &&
|
||||||
ifa->ifa_scope <= scope)
|
ifa->ifa_scope <= scope)
|
||||||
return ifa->ifa_local;
|
return ifa->ifa_local;
|
||||||
} endfor_ifa(in_dev);
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
|
__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
|
||||||
{
|
{
|
||||||
|
const struct in_ifaddr *ifa;
|
||||||
__be32 addr = 0;
|
__be32 addr = 0;
|
||||||
struct in_device *in_dev;
|
struct in_device *in_dev;
|
||||||
struct net *net = dev_net(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)
|
if (!in_dev)
|
||||||
goto no_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)
|
if (ifa->ifa_scope > scope)
|
||||||
continue;
|
continue;
|
||||||
if (!dst || inet_ifa_match(dst, ifa)) {
|
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)
|
if (!addr)
|
||||||
addr = ifa->ifa_local;
|
addr = ifa->ifa_local;
|
||||||
} endfor_ifa(in_dev);
|
}
|
||||||
|
|
||||||
if (addr)
|
if (addr)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
@ -1321,10 +1357,11 @@ EXPORT_SYMBOL(inet_select_addr);
|
||||||
static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
|
static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
|
||||||
__be32 local, int scope)
|
__be32 local, int scope)
|
||||||
{
|
{
|
||||||
int same = 0;
|
const struct in_ifaddr *ifa;
|
||||||
__be32 addr = 0;
|
__be32 addr = 0;
|
||||||
|
int same = 0;
|
||||||
|
|
||||||
for_ifa(in_dev) {
|
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||||
if (!addr &&
|
if (!addr &&
|
||||||
(local == ifa->ifa_local || !local) &&
|
(local == ifa->ifa_local || !local) &&
|
||||||
ifa->ifa_scope <= scope) {
|
ifa->ifa_scope <= scope) {
|
||||||
|
@ -1350,7 +1387,7 @@ static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
|
||||||
same = 0;
|
same = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} endfor_ifa(in_dev);
|
}
|
||||||
|
|
||||||
return same ? addr : 0;
|
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;
|
struct in_ifaddr *ifa;
|
||||||
int named = 0;
|
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;
|
char old[IFNAMSIZ], *dot;
|
||||||
|
|
||||||
memcpy(old, ifa->ifa_label, IFNAMSIZ);
|
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_device *in_dev)
|
||||||
|
|
||||||
{
|
{
|
||||||
struct in_ifaddr *ifa;
|
const struct in_ifaddr *ifa;
|
||||||
|
|
||||||
for (ifa = in_dev->ifa_list; ifa;
|
in_dev_for_each_ifa_rtnl(ifa, in_dev) {
|
||||||
ifa = ifa->ifa_next) {
|
|
||||||
arp_send(ARPOP_REQUEST, ETH_P_ARP,
|
arp_send(ARPOP_REQUEST, ETH_P_ARP,
|
||||||
ifa->ifa_local, dev,
|
ifa->ifa_local, dev,
|
||||||
ifa->ifa_local, NULL,
|
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 ip_idx = 0;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next, ip_idx++) {
|
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||||
if (ip_idx < s_ip_idx)
|
if (ip_idx < s_ip_idx) {
|
||||||
|
ip_idx++;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
err = inet_fill_ifaddr(skb, ifa, fillargs);
|
err = inet_fill_ifaddr(skb, ifa, fillargs);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
|
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
|
||||||
|
ip_idx++;
|
||||||
}
|
}
|
||||||
err = 0;
|
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_oif = dev->ifindex;
|
||||||
cfg->fc_table = l3mdev_fib_table(dev);
|
cfg->fc_table = l3mdev_fib_table(dev);
|
||||||
if (colon) {
|
if (colon) {
|
||||||
struct in_ifaddr *ifa;
|
const struct in_ifaddr *ifa;
|
||||||
struct in_device *in_dev = __in_dev_get_rtnl(dev);
|
struct in_device *in_dev;
|
||||||
|
|
||||||
|
in_dev = __in_dev_get_rtnl(dev);
|
||||||
if (!in_dev)
|
if (!in_dev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
*colon = ':';
|
*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)
|
if (strcmp(ifa->ifa_label, devname) == 0)
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
if (!ifa)
|
if (!ifa)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
cfg->fc_prefsrc = ifa->ifa_local;
|
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.
|
* Scan address list to be sure that addresses are really gone.
|
||||||
*/
|
*/
|
||||||
|
rcu_read_lock();
|
||||||
for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) {
|
in_dev_for_each_ifa_rcu(ifa1, in_dev) {
|
||||||
if (ifa1 == ifa) {
|
if (ifa1 == ifa) {
|
||||||
/* promotion, keep the IP */
|
/* promotion, keep the IP */
|
||||||
gone = 0;
|
gone = 0;
|
||||||
|
@ -1246,6 +1254,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
no_promotions:
|
no_promotions:
|
||||||
if (!(ok & BRD_OK))
|
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 netdev_notifier_info_ext *info_ext = ptr;
|
||||||
struct in_device *in_dev;
|
struct in_device *in_dev;
|
||||||
struct net *net = dev_net(dev);
|
struct net *net = dev_net(dev);
|
||||||
|
struct in_ifaddr *ifa;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
|
||||||
if (event == NETDEV_UNREGISTER) {
|
if (event == NETDEV_UNREGISTER) {
|
||||||
|
@ -1429,9 +1439,9 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case NETDEV_UP:
|
case NETDEV_UP:
|
||||||
for_ifa(in_dev) {
|
in_dev_for_each_ifa_rtnl(ifa, in_dev) {
|
||||||
fib_add_ifaddr(ifa);
|
fib_add_ifaddr(ifa);
|
||||||
} endfor_ifa(in_dev);
|
}
|
||||||
#ifdef CONFIG_IP_ROUTE_MULTIPATH
|
#ifdef CONFIG_IP_ROUTE_MULTIPATH
|
||||||
fib_sync_up(dev, RTNH_F_DEAD);
|
fib_sync_up(dev, RTNH_F_DEAD);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -336,14 +336,15 @@ static __be32 igmpv3_get_srcaddr(struct net_device *dev,
|
||||||
const struct flowi4 *fl4)
|
const struct flowi4 *fl4)
|
||||||
{
|
{
|
||||||
struct in_device *in_dev = __in_dev_get_rcu(dev);
|
struct in_device *in_dev = __in_dev_get_rcu(dev);
|
||||||
|
const struct in_ifaddr *ifa;
|
||||||
|
|
||||||
if (!in_dev)
|
if (!in_dev)
|
||||||
return htonl(INADDR_ANY);
|
return htonl(INADDR_ANY);
|
||||||
|
|
||||||
for_ifa(in_dev) {
|
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||||
if (fl4->saddr == ifa->ifa_local)
|
if (fl4->saddr == ifa->ifa_local)
|
||||||
return fl4->saddr;
|
return fl4->saddr;
|
||||||
} endfor_ifa(in_dev);
|
}
|
||||||
|
|
||||||
return htonl(INADDR_ANY);
|
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)
|
__be32 nf_tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr)
|
||||||
{
|
{
|
||||||
|
const struct in_ifaddr *ifa;
|
||||||
struct in_device *indev;
|
struct in_device *indev;
|
||||||
__be32 laddr;
|
__be32 laddr;
|
||||||
|
|
||||||
|
@ -61,10 +62,14 @@ __be32 nf_tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr)
|
||||||
|
|
||||||
laddr = 0;
|
laddr = 0;
|
||||||
indev = __in_dev_get_rcu(skb->dev);
|
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;
|
laddr = ifa->ifa_local;
|
||||||
break;
|
break;
|
||||||
} endfor_ifa(indev);
|
}
|
||||||
|
|
||||||
return laddr ? laddr : daddr;
|
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);
|
struct in_device *in_dev = __in_dev_get_rtnl(dev);
|
||||||
if (in_dev && (dev->flags & IFF_UP)) {
|
if (in_dev && (dev->flags & IFF_UP)) {
|
||||||
struct in_ifaddr *ifa;
|
struct in_ifaddr *ifa;
|
||||||
|
|
||||||
int flag = scope;
|
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;
|
addr.s6_addr32[3] = ifa->ifa_local;
|
||||||
|
|
||||||
if (ifa->ifa_scope == RT_SCOPE_LINK)
|
if (ifa->ifa_scope == RT_SCOPE_LINK)
|
||||||
|
|
|
@ -354,11 +354,11 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
|
||||||
sdata_lock(sdata);
|
sdata_lock(sdata);
|
||||||
|
|
||||||
/* Copy the addresses to the bss_conf list */
|
/* Copy the addresses to the bss_conf list */
|
||||||
ifa = idev->ifa_list;
|
ifa = rtnl_dereference(idev->ifa_list);
|
||||||
while (ifa) {
|
while (ifa) {
|
||||||
if (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN)
|
if (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN)
|
||||||
bss_conf->arp_addr_list[c] = ifa->ifa_address;
|
bss_conf->arp_addr_list[c] = ifa->ifa_address;
|
||||||
ifa = ifa->ifa_next;
|
ifa = rtnl_dereference(ifa->ifa_next);
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,12 +41,17 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
|
||||||
|
|
||||||
in_dev = __in_dev_get_rcu(rt->dst.dev);
|
in_dev = __in_dev_get_rcu(rt->dst.dev);
|
||||||
if (in_dev != NULL) {
|
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) {
|
if (ifa->ifa_broadcast == iph->daddr) {
|
||||||
mask = ifa->ifa_mask;
|
mask = ifa->ifa_mask;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} endfor_ifa(in_dev);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mask == 0)
|
if (mask == 0)
|
||||||
|
|
|
@ -47,14 +47,16 @@ nf_nat_redirect_ipv4(struct sk_buff *skb,
|
||||||
if (hooknum == NF_INET_LOCAL_OUT) {
|
if (hooknum == NF_INET_LOCAL_OUT) {
|
||||||
newdst = htonl(0x7F000001);
|
newdst = htonl(0x7F000001);
|
||||||
} else {
|
} else {
|
||||||
struct in_device *indev;
|
const struct in_device *indev;
|
||||||
struct in_ifaddr *ifa;
|
|
||||||
|
|
||||||
newdst = 0;
|
newdst = 0;
|
||||||
|
|
||||||
indev = __in_dev_get_rcu(skb->dev);
|
indev = __in_dev_get_rcu(skb->dev);
|
||||||
if (indev && indev->ifa_list) {
|
if (indev) {
|
||||||
ifa = indev->ifa_list;
|
const struct in_ifaddr *ifa;
|
||||||
|
|
||||||
|
ifa = rcu_dereference(indev->ifa_list);
|
||||||
|
if (ifa)
|
||||||
newdst = ifa->ifa_local;
|
newdst = ifa->ifa_local;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
|
||||||
const struct iphdr *ip = ip_hdr(skb);
|
const struct iphdr *ip = ip_hdr(skb);
|
||||||
|
const struct in_ifaddr *ifa;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (ttl_check == NF_OSF_TTL_TRUE)
|
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)
|
else if (ip->ttl <= f_ttl)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
for_ifa(in_dev) {
|
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||||
if (inet_ifa_match(ip->saddr, ifa)) {
|
if (inet_ifa_match(ip->saddr, ifa)) {
|
||||||
ret = (ip->ttl == f_ttl);
|
ret = (ip->ttl == f_ttl);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
endfor_ifa(in_dev);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
|
||||||
return;
|
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. */
|
/* Add the address to the local list. */
|
||||||
addr = kzalloc(sizeof(*addr), GFP_ATOMIC);
|
addr = kzalloc(sizeof(*addr), GFP_ATOMIC);
|
||||||
if (addr) {
|
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 smc_clc_msg_proposal_prefix *prop)
|
||||||
{
|
{
|
||||||
struct in_device *in_dev = __in_dev_get_rcu(dst->dev);
|
struct in_device *in_dev = __in_dev_get_rcu(dst->dev);
|
||||||
|
const struct in_ifaddr *ifa;
|
||||||
|
|
||||||
if (!in_dev)
|
if (!in_dev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
for_ifa(in_dev) {
|
|
||||||
|
in_dev_for_each_ifa_rcu(ifa, in_dev) {
|
||||||
if (!inet_ifa_match(ipv4, ifa))
|
if (!inet_ifa_match(ipv4, ifa))
|
||||||
continue;
|
continue;
|
||||||
prop->prefix_len = inet_mask_len(ifa->ifa_mask);
|
prop->prefix_len = inet_mask_len(ifa->ifa_mask);
|
||||||
prop->outgoing_subnet = ifa->ifa_address & ifa->ifa_mask;
|
prop->outgoing_subnet = ifa->ifa_address & ifa->ifa_mask;
|
||||||
/* prop->ipv6_prefixes_cnt = 0; already done by memset before */
|
/* prop->ipv6_prefixes_cnt = 0; already done by memset before */
|
||||||
return 0;
|
return 0;
|
||||||
} endfor_ifa(in_dev);
|
}
|
||||||
return -ENOENT;
|
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 smc_clc_msg_proposal_prefix *prop)
|
||||||
{
|
{
|
||||||
struct in_device *in_dev = __in_dev_get_rcu(dev);
|
struct in_device *in_dev = __in_dev_get_rcu(dev);
|
||||||
|
const struct in_ifaddr *ifa;
|
||||||
|
|
||||||
if (!in_dev)
|
if (!in_dev)
|
||||||
return -ENODEV;
|
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) &&
|
if (prop->prefix_len == inet_mask_len(ifa->ifa_mask) &&
|
||||||
inet_ifa_match(prop->outgoing_subnet, ifa))
|
inet_ifa_match(prop->outgoing_subnet, ifa))
|
||||||
return 0;
|
return 0;
|
||||||
} endfor_ifa(in_dev);
|
}
|
||||||
|
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue