aboutsummaryrefslogtreecommitdiff
path: root/net/mac80211
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/iface.c16
-rw-r--r--net/mac80211/rx.c2
-rw-r--r--net/mac80211/tx.c75
3 files changed, 46 insertions, 47 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 2f797a86ced..559d698369c 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -335,7 +335,10 @@ static int ieee80211_stop(struct net_device *dev)
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_init_conf conf;
struct sta_info *sta;
+ unsigned long flags;
+ struct sk_buff *skb, *tmp;
u32 hw_reconf_flags = 0;
+ int i;
/*
* Stop TX on this interface first.
@@ -551,6 +554,18 @@ static int ieee80211_stop(struct net_device *dev)
if (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;
}
@@ -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);
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 */
sdata = netdev_priv(ndev);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 66c797cc85c..d9df819eef3 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1539,7 +1539,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
info = IEEE80211_SKB_CB(fwd_skb);
memset(info, 0, sizeof(*info));
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);
if (is_multicast_ether_addr(fwd_hdr->addr3))
memcpy(fwd_hdr->addr1, fwd_hdr->addr3,
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 2572509d556..ffd3b10f269 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -400,6 +400,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
sta_info_set_tim_bit(sta);
info->control.jiffies = jiffies;
+ info->control.vif = &tx->sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
skb_queue_tail(&sta->ps_tx_buf, tx->skb);
return TX_QUEUED;
@@ -696,7 +697,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
* number, if we have no matching interface then we
* 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;
if (unlikely(ieee80211_is_ctl(hdr->frame_control)))
@@ -1092,6 +1093,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
} else if (*state != HT_AGG_STATE_IDLE) {
/* in progress */
queued = true;
+ info->control.vif = &sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
__skb_queue_tail(&tid_tx->pending, skb);
}
@@ -1143,6 +1145,7 @@ static int __ieee80211_tx(struct ieee80211_local *local,
{
struct sk_buff *skb = *skbp, *next;
struct ieee80211_tx_info *info;
+ struct ieee80211_sub_if_data *sdata;
unsigned long flags;
int ret, len;
bool fragm = false;
@@ -1167,7 +1170,24 @@ static int __ieee80211_tx(struct ieee80211_local *local,
next = skb->next;
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);
+ info->control.vif = &sdata->vif;
if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) {
dev_kfree_skb(skb);
ret = NETDEV_TX_OK;
@@ -1386,11 +1406,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *tmp_sdata;
int headroom;
bool may_encrypt;
- enum {
- NOT_MONITOR,
- FOUND_SDATA,
- UNKNOWN_ADDRESS,
- } monitor_iface = NOT_MONITOR;
dev_hold(sdata->dev);
@@ -1424,7 +1439,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
u16 len_rthdr;
info->flags |= IEEE80211_TX_CTL_INJECTED;
- monitor_iface = UNKNOWN_ADDRESS;
len_rthdr = ieee80211_get_radiotap_len(skb->data);
hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
@@ -1454,7 +1468,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
dev_hold(tmp_sdata->dev);
dev_put(sdata->dev);
sdata = tmp_sdata;
- monitor_iface = FOUND_SDATA;
break;
}
}
@@ -1476,13 +1489,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
return;
}
- tmp_sdata = sdata;
- 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;
+ info->control.vif = &sdata->vif;
ieee80211_select_queue(local, skb);
ieee80211_tx(sdata, skb, false);
@@ -1534,9 +1541,6 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
if (unlikely(skb->len < len_rthdr))
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
* header still being in there. We are being given
@@ -1810,8 +1814,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
nh_pos += hdrlen;
h_pos += hdrlen;
- skb->iif = dev->ifindex;
-
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
@@ -1856,32 +1858,13 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
struct ieee80211_hdr *hdr;
- struct net_device *dev;
int ret;
bool result = true;
- /* does interface still exist? */
- 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;
- }
+ sdata = vif_to_sdata(info->control.vif);
if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) {
- /* do not use sdata, it may have been changed above */
- ieee80211_tx(IEEE80211_DEV_TO_SUB_IF(dev), skb, true);
+ ieee80211_tx(sdata, skb, true);
} else {
hdr = (struct ieee80211_hdr *)skb->data;
sta = sta_info_get(local, hdr->addr1);
@@ -1891,9 +1874,6 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
result = false;
}
- out:
- dev_put(dev);
-
return result;
}
@@ -1921,10 +1901,16 @@ void ieee80211_tx_pending(unsigned long data)
while (!skb_queue_empty(&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,
flags);
txok = ieee80211_tx_pending_skb(local, skb);
+ dev_put(sdata->dev);
if (!txok)
__skb_queue_head(&local->pending[i], skb);
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,
skb_set_network_header(skb, 0);
skb_set_transport_header(skb, 0);
- skb->iif = sdata->dev->ifindex;
if (!encrypt)
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;