summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c3
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c21
-rw-r--r--include/net/mac80211.h1
-rw-r--r--net/mac80211/tx.c64
-rw-r--r--net/mac80211/util.c37
5 files changed, 101 insertions, 25 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index da8aa83481f7..631d65b73edf 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -258,7 +258,8 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
txi = IEEE80211_SKB_CB(skb);
- hwsim_check_magic(txi->control.vif);
+ if (txi->control.vif)
+ hwsim_check_magic(txi->control.vif);
if (txi->control.sta)
hwsim_check_sta_magic(txi->control.sta);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index a5e965068c83..b7f4fe8fba6e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -155,7 +155,6 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
- struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
struct ieee80211_rate *rate =
ieee80211_get_tx_rate(rt2x00dev->hw, tx_info);
@@ -278,16 +277,22 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
* sequence counter given by mac80211.
*/
if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
- spin_lock_irqsave(&intf->seqlock, irqflags);
+ if (likely(tx_info->control.vif)) {
+ struct rt2x00_intf *intf;
- if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
- intf->seqno += 0x10;
- hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
- hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
+ intf = vif_to_intf(tx_info->control.vif);
- spin_unlock_irqrestore(&intf->seqlock, irqflags);
+ spin_lock_irqsave(&intf->seqlock, irqflags);
- __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
+ if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
+ intf->seqno += 0x10;
+ hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+ hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
+
+ spin_unlock_irqrestore(&intf->seqlock, irqflags);
+
+ __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
+ }
}
/*
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index d6669fd3ffa8..003e4a03874e 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -330,6 +330,7 @@ struct ieee80211_tx_info {
union {
struct {
+ /* NB: vif can be NULL for injected frames */
struct ieee80211_vif *vif;
struct ieee80211_key_conf *hw_key;
struct ieee80211_sta *sta;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 698c8233e6b3..c12f361d7185 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -624,7 +624,14 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
u8 *qc;
int tid;
- /* only for injected frames */
+ /*
+ * Packet injection may want to control the sequence
+ * number, if we have no matching interface then we
+ * neither assign one ourselves nor ask the driver to.
+ */
+ if (unlikely(!info->control.vif))
+ return TX_CONTINUE;
+
if (unlikely(ieee80211_is_ctl(hdr->frame_control)))
return TX_CONTINUE;
@@ -849,7 +856,6 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
sband = tx->local->hw.wiphy->bands[tx->channel->band];
skb->do_not_encrypt = 1;
- info->flags |= IEEE80211_TX_CTL_INJECTED;
tx->flags &= ~IEEE80211_TX_FRAGMENTED;
/*
@@ -981,7 +987,7 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
/* process and remove the injection radiotap header */
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) {
+ if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) {
if (__ieee80211_parse_tx_radiotap(tx, skb) == TX_DROP)
return TX_DROP;
@@ -1300,6 +1306,11 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
struct ieee80211_sub_if_data *osdata;
int headroom;
bool may_encrypt;
+ enum {
+ NOT_MONITOR,
+ FOUND_SDATA,
+ UNKNOWN_ADDRESS,
+ } monitor_iface = NOT_MONITOR;
int ret;
if (skb->iif)
@@ -1335,6 +1346,50 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.mesh,
fwded_frames);
}
+ } else if (unlikely(osdata->vif.type == NL80211_IFTYPE_MONITOR)) {
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_local *local = osdata->local;
+ struct ieee80211_hdr *hdr;
+ int hdrlen;
+ 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;
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+ /* check the header is complete in the frame */
+ if (likely(skb->len >= len_rthdr + hdrlen)) {
+ /*
+ * We process outgoing injected frames that have a
+ * local address we handle as though they are our
+ * own frames.
+ * This code here isn't entirely correct, the local
+ * MAC address is not necessarily enough to find
+ * the interface to use; for that proper VLAN/WDS
+ * support we will need a different mechanism.
+ */
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &local->interfaces,
+ list) {
+ if (!netif_running(sdata->dev))
+ continue;
+ if (compare_ether_addr(sdata->dev->dev_addr,
+ hdr->addr2)) {
+ dev_hold(sdata->dev);
+ dev_put(odev);
+ osdata = sdata;
+ odev = osdata->dev;
+ skb->iif = sdata->dev->ifindex;
+ monitor_iface = FOUND_SDATA;
+ break;
+ }
+ }
+ rcu_read_unlock();
+ }
}
may_encrypt = !skb->do_not_encrypt;
@@ -1355,7 +1410,8 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
osdata = container_of(osdata->bss,
struct ieee80211_sub_if_data,
u.ap);
- info->control.vif = &osdata->vif;
+ if (likely(monitor_iface != UNKNOWN_ADDRESS))
+ info->control.vif = &osdata->vif;
ret = ieee80211_tx(odev, skb);
dev_put(odev);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 6eb222369bcb..f32561ec224c 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -231,16 +231,21 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
struct ieee80211_rate *rate)
{
struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_sub_if_data *sdata;
u16 dur;
int erp;
+ bool short_preamble = false;
erp = 0;
- if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
- erp = rate->flags & IEEE80211_RATE_ERP_G;
+ if (vif) {
+ sdata = vif_to_sdata(vif);
+ short_preamble = sdata->bss_conf.use_short_preamble;
+ if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+ erp = rate->flags & IEEE80211_RATE_ERP_G;
+ }
dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp,
- sdata->bss_conf.use_short_preamble);
+ short_preamble);
return cpu_to_le16(dur);
}
@@ -252,7 +257,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_rate *rate;
- struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_sub_if_data *sdata;
bool short_preamble;
int erp;
u16 dur;
@@ -260,13 +265,17 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- short_preamble = sdata->bss_conf.use_short_preamble;
+ short_preamble = false;
rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
erp = 0;
- if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
- erp = rate->flags & IEEE80211_RATE_ERP_G;
+ if (vif) {
+ sdata = vif_to_sdata(vif);
+ short_preamble = sdata->bss_conf.use_short_preamble;
+ if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+ erp = rate->flags & IEEE80211_RATE_ERP_G;
+ }
/* CTS duration */
dur = ieee80211_frame_duration(local, 10, rate->bitrate,
@@ -289,7 +298,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_rate *rate;
- struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_sub_if_data *sdata;
bool short_preamble;
int erp;
u16 dur;
@@ -297,12 +306,16 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- short_preamble = sdata->bss_conf.use_short_preamble;
+ short_preamble = false;
rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
erp = 0;
- if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
- erp = rate->flags & IEEE80211_RATE_ERP_G;
+ if (vif) {
+ sdata = vif_to_sdata(vif);
+ short_preamble = sdata->bss_conf.use_short_preamble;
+ if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+ erp = rate->flags & IEEE80211_RATE_ERP_G;
+ }
/* Data frame duration */
dur = ieee80211_frame_duration(local, frame_len, rate->bitrate,
OpenPOWER on IntegriCloud