Commit 5061b0c2 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

mac80211: cooperate more with network namespaces

There are still two places in mac80211 that hardcode
the initial net namespace (init_net). One of them is
mandated by cfg80211 and will be removed by a separate
patch, the other one is used for finding the network
device of a pending packet via its ifindex.

Remove the latter use by keeping track of the device
pointer itself, via the vif pointer, and avoid it
going stale by dropping pending frames for a given
interface when the interface is removed.

To keep track of the vif pointer for the correct
interface, change the info->control.vif pointer's
internal use to always be the correct vif, and only
move it to the vif the driver expects (or NULL for
monitor interfaces and injected packets) right before
giving the packet to the driver.
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 70034918
...@@ -335,7 +335,10 @@ static int ieee80211_stop(struct net_device *dev) ...@@ -335,7 +335,10 @@ static int ieee80211_stop(struct net_device *dev)
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ieee80211_if_init_conf conf; struct ieee80211_if_init_conf conf;
struct sta_info *sta; struct sta_info *sta;
unsigned long flags;
struct sk_buff *skb, *tmp;
u32 hw_reconf_flags = 0; u32 hw_reconf_flags = 0;
int i;
/* /*
* Stop TX on this interface first. * Stop TX on this interface first.
...@@ -551,6 +554,18 @@ static int ieee80211_stop(struct net_device *dev) ...@@ -551,6 +554,18 @@ static int ieee80211_stop(struct net_device *dev)
if (hw_reconf_flags) if (hw_reconf_flags)
ieee80211_hw_config(local, hw_reconf_flags); ieee80211_hw_config(local, hw_reconf_flags);
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
skb_queue_walk_safe(&local->pending[i], skb, tmp) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (info->control.vif == &sdata->vif) {
__skb_unlink(skb, &local->pending[i]);
dev_kfree_skb_irq(skb);
}
}
}
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
return 0; return 0;
} }
...@@ -788,7 +803,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, ...@@ -788,7 +803,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
ndev->features |= NETIF_F_NETNS_LOCAL;
/* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
sdata = netdev_priv(ndev); sdata = netdev_priv(ndev);
......
...@@ -1539,7 +1539,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) ...@@ -1539,7 +1539,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
info = IEEE80211_SKB_CB(fwd_skb); info = IEEE80211_SKB_CB(fwd_skb);
memset(info, 0, sizeof(*info)); memset(info, 0, sizeof(*info));
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
fwd_skb->iif = rx->dev->ifindex; info->control.vif = &rx->sdata->vif;
ieee80211_select_queue(local, fwd_skb); ieee80211_select_queue(local, fwd_skb);
if (is_multicast_ether_addr(fwd_hdr->addr3)) if (is_multicast_ether_addr(fwd_hdr->addr3))
memcpy(fwd_hdr->addr1, fwd_hdr->addr3, memcpy(fwd_hdr->addr1, fwd_hdr->addr3,
......
...@@ -400,6 +400,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) ...@@ -400,6 +400,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
sta_info_set_tim_bit(sta); sta_info_set_tim_bit(sta);
info->control.jiffies = jiffies; info->control.jiffies = jiffies;
info->control.vif = &tx->sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
skb_queue_tail(&sta->ps_tx_buf, tx->skb); skb_queue_tail(&sta->ps_tx_buf, tx->skb);
return TX_QUEUED; return TX_QUEUED;
...@@ -696,7 +697,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) ...@@ -696,7 +697,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
* number, if we have no matching interface then we * number, if we have no matching interface then we
* neither assign one ourselves nor ask the driver to. * neither assign one ourselves nor ask the driver to.
*/ */
if (unlikely(!info->control.vif)) if (unlikely(info->control.vif->type == NL80211_IFTYPE_MONITOR))
return TX_CONTINUE; return TX_CONTINUE;
if (unlikely(ieee80211_is_ctl(hdr->frame_control))) if (unlikely(ieee80211_is_ctl(hdr->frame_control)))
...@@ -1092,6 +1093,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, ...@@ -1092,6 +1093,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
} else if (*state != HT_AGG_STATE_IDLE) { } else if (*state != HT_AGG_STATE_IDLE) {
/* in progress */ /* in progress */
queued = true; queued = true;
info->control.vif = &sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
__skb_queue_tail(&tid_tx->pending, skb); __skb_queue_tail(&tid_tx->pending, skb);
} }
...@@ -1143,6 +1145,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, ...@@ -1143,6 +1145,7 @@ static int __ieee80211_tx(struct ieee80211_local *local,
{ {
struct sk_buff *skb = *skbp, *next; struct sk_buff *skb = *skbp, *next;
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
struct ieee80211_sub_if_data *sdata;
unsigned long flags; unsigned long flags;
int ret, len; int ret, len;
bool fragm = false; bool fragm = false;
...@@ -1167,7 +1170,24 @@ static int __ieee80211_tx(struct ieee80211_local *local, ...@@ -1167,7 +1170,24 @@ static int __ieee80211_tx(struct ieee80211_local *local,
next = skb->next; next = skb->next;
len = skb->len; len = skb->len;
sdata = vif_to_sdata(info->control.vif);
switch (sdata->vif.type) {
case NL80211_IFTYPE_MONITOR:
info->control.vif = NULL;
break;
case NL80211_IFTYPE_AP_VLAN:
info->control.vif = &container_of(sdata->bss,
struct ieee80211_sub_if_data, u.ap)->vif;
break;
default:
/* keep */
break;
}
ret = drv_tx(local, skb); ret = drv_tx(local, skb);
info->control.vif = &sdata->vif;
if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) { if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) {
dev_kfree_skb(skb); dev_kfree_skb(skb);
ret = NETDEV_TX_OK; ret = NETDEV_TX_OK;
...@@ -1386,11 +1406,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, ...@@ -1386,11 +1406,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *tmp_sdata; struct ieee80211_sub_if_data *tmp_sdata;
int headroom; int headroom;
bool may_encrypt; bool may_encrypt;
enum {
NOT_MONITOR,
FOUND_SDATA,
UNKNOWN_ADDRESS,
} monitor_iface = NOT_MONITOR;
dev_hold(sdata->dev); dev_hold(sdata->dev);
...@@ -1424,7 +1439,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, ...@@ -1424,7 +1439,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
u16 len_rthdr; u16 len_rthdr;
info->flags |= IEEE80211_TX_CTL_INJECTED; info->flags |= IEEE80211_TX_CTL_INJECTED;
monitor_iface = UNKNOWN_ADDRESS;
len_rthdr = ieee80211_get_radiotap_len(skb->data); len_rthdr = ieee80211_get_radiotap_len(skb->data);
hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
...@@ -1454,7 +1468,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, ...@@ -1454,7 +1468,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
dev_hold(tmp_sdata->dev); dev_hold(tmp_sdata->dev);
dev_put(sdata->dev); dev_put(sdata->dev);
sdata = tmp_sdata; sdata = tmp_sdata;
monitor_iface = FOUND_SDATA;
break; break;
} }
} }
...@@ -1476,13 +1489,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, ...@@ -1476,13 +1489,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
return; return;
} }
tmp_sdata = sdata; info->control.vif = &sdata->vif;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
tmp_sdata = container_of(sdata->bss,
struct ieee80211_sub_if_data,
u.ap);
if (likely(monitor_iface != UNKNOWN_ADDRESS))
info->control.vif = &tmp_sdata->vif;
ieee80211_select_queue(local, skb); ieee80211_select_queue(local, skb);
ieee80211_tx(sdata, skb, false); ieee80211_tx(sdata, skb, false);
...@@ -1534,9 +1541,6 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, ...@@ -1534,9 +1541,6 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
if (unlikely(skb->len < len_rthdr)) if (unlikely(skb->len < len_rthdr))
goto fail; /* skb too short for claimed rt header extent */ goto fail; /* skb too short for claimed rt header extent */
/* needed because we set skb device to master */
skb->iif = dev->ifindex;
/* /*
* fix up the pointers accounting for the radiotap * fix up the pointers accounting for the radiotap
* header still being in there. We are being given * header still being in there. We are being given
...@@ -1810,8 +1814,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, ...@@ -1810,8 +1814,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
nh_pos += hdrlen; nh_pos += hdrlen;
h_pos += hdrlen; h_pos += hdrlen;
skb->iif = dev->ifindex;
dev->stats.tx_packets++; dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len; dev->stats.tx_bytes += skb->len;
...@@ -1856,32 +1858,13 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, ...@@ -1856,32 +1858,13 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct sta_info *sta; struct sta_info *sta;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
struct net_device *dev;
int ret; int ret;
bool result = true; bool result = true;
/* does interface still exist? */ sdata = vif_to_sdata(info->control.vif);
dev = dev_get_by_index(&init_net, skb->iif);
if (!dev) {
dev_kfree_skb(skb);
return true;
}
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss,
struct ieee80211_sub_if_data,
u.ap);
if (unlikely(info->control.vif && info->control.vif != &sdata->vif)) {
dev_kfree_skb(skb);
result = true;
goto out;
}
if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) {
/* do not use sdata, it may have been changed above */ ieee80211_tx(sdata, skb, true);
ieee80211_tx(IEEE80211_DEV_TO_SUB_IF(dev), skb, true);
} else { } else {
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
sta = sta_info_get(local, hdr->addr1); sta = sta_info_get(local, hdr->addr1);
...@@ -1891,9 +1874,6 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, ...@@ -1891,9 +1874,6 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
result = false; result = false;
} }
out:
dev_put(dev);
return result; return result;
} }
...@@ -1921,10 +1901,16 @@ void ieee80211_tx_pending(unsigned long data) ...@@ -1921,10 +1901,16 @@ void ieee80211_tx_pending(unsigned long data)
while (!skb_queue_empty(&local->pending[i])) { while (!skb_queue_empty(&local->pending[i])) {
struct sk_buff *skb = __skb_dequeue(&local->pending[i]); struct sk_buff *skb = __skb_dequeue(&local->pending[i]);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_sub_if_data *sdata;
sdata = vif_to_sdata(info->control.vif);
dev_hold(sdata->dev);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, spin_unlock_irqrestore(&local->queue_stop_reason_lock,
flags); flags);
txok = ieee80211_tx_pending_skb(local, skb); txok = ieee80211_tx_pending_skb(local, skb);
dev_put(sdata->dev);
if (!txok) if (!txok)
__skb_queue_head(&local->pending[i], skb); __skb_queue_head(&local->pending[i], skb);
spin_lock_irqsave(&local->queue_stop_reason_lock, spin_lock_irqsave(&local->queue_stop_reason_lock,
...@@ -2234,7 +2220,6 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, ...@@ -2234,7 +2220,6 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
skb_set_network_header(skb, 0); skb_set_network_header(skb, 0);
skb_set_transport_header(skb, 0); skb_set_transport_header(skb, 0);
skb->iif = sdata->dev->ifindex;
if (!encrypt) if (!encrypt)
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment