summaryrefslogtreecommitdiff
path: root/net/mac80211/tx.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-10-07 14:01:26 +0200
committerJohn W. Linville <linville@tuxdriver.com>2011-10-11 16:41:19 -0400
commit73b9f03a813d66484105c4ed648a1aa66fa267aa (patch)
tree37a60a9c61f4537c898a5d863e93f1b445864d7d /net/mac80211/tx.c
parenta26eb27ab430147a82e4a9f2f1ebfadf03d99550 (diff)
mac80211: parse radiotap header earlier
We can now move the radiotap header parsing into ieee80211_monitor_start_xmit(). This moves it out of the hotpath, and also helps the code since now the radiotap header will no longer be present in ieee80211_xmit() etc. which is easier to understand. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r--net/mac80211/tx.c201
1 files changed, 88 insertions, 113 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 7f7d45cf77d1..3d2b6b2749f6 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1035,103 +1035,6 @@ ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx)
/* actual transmit path */
-/*
- * deal with packet injection down monitor interface
- * with Radiotap Header -- only called for monitor mode interface
- */
-static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
- struct sk_buff *skb)
-{
- /*
- * this is the moment to interpret and discard the radiotap header that
- * must be at the start of the packet injected in Monitor mode
- *
- * Need to take some care with endian-ness since radiotap
- * args are little-endian
- */
-
- struct ieee80211_radiotap_iterator iterator;
- struct ieee80211_radiotap_header *rthdr =
- (struct ieee80211_radiotap_header *) skb->data;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
- NULL);
- u16 txflags;
-
- info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
- IEEE80211_TX_CTL_DONTFRAG;
-
- /*
- * for every radiotap entry that is present
- * (ieee80211_radiotap_iterator_next returns -ENOENT when no more
- * entries present, or -EINVAL on error)
- */
-
- while (!ret) {
- ret = ieee80211_radiotap_iterator_next(&iterator);
-
- if (ret)
- continue;
-
- /* see if this argument is something we can use */
- switch (iterator.this_arg_index) {
- /*
- * You must take care when dereferencing iterator.this_arg
- * for multibyte types... the pointer is not aligned. Use
- * get_unaligned((type *)iterator.this_arg) to dereference
- * iterator.this_arg for type "type" safely on all arches.
- */
- case IEEE80211_RADIOTAP_FLAGS:
- if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
- /*
- * this indicates that the skb we have been
- * handed has the 32-bit FCS CRC at the end...
- * we should react to that by snipping it off
- * because it will be recomputed and added
- * on transmission
- */
- if (skb->len < (iterator._max_length + FCS_LEN))
- return false;
-
- skb_trim(skb, skb->len - FCS_LEN);
- }
- if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
- info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT;
- if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
- info->flags &= ~IEEE80211_TX_CTL_DONTFRAG;
- break;
-
- case IEEE80211_RADIOTAP_TX_FLAGS:
- txflags = le16_to_cpu(get_unaligned((__le16*)
- iterator.this_arg));
- if (txflags & IEEE80211_RADIOTAP_F_TX_NOACK)
- info->flags |= IEEE80211_TX_CTL_NO_ACK;
- break;
-
- /*
- * Please update the file
- * Documentation/networking/mac80211-injection.txt
- * when parsing new fields here.
- */
-
- default:
- break;
- }
- }
-
- if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
- return false;
-
- /*
- * remove the radiotap header
- * iterator->_max_length was sanity-checked against
- * skb->len by iterator init
- */
- skb_pull(skb, iterator._max_length);
-
- return true;
-}
-
static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
struct sk_buff *skb,
struct ieee80211_tx_info *info,
@@ -1205,19 +1108,6 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
tx->sdata = sdata;
tx->channel = local->hw.conf.channel;
- /* process and remove the injection radiotap header */
- if (unlikely(info->flags & IEEE80211_TX_INTFL_HAS_RADIOTAP)) {
- if (!__ieee80211_parse_tx_radiotap(tx, skb))
- return TX_DROP;
-
- /*
- * __ieee80211_parse_tx_radiotap has now removed
- * the radiotap header that was present and pre-filled
- * 'tx' with tx control information.
- */
- info->flags &= ~IEEE80211_TX_INTFL_HAS_RADIOTAP;
- }
-
/*
* If this flag is set to true anywhere, and we get here,
* we are doing the needed processing, so remove the flag
@@ -1559,6 +1449,89 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
rcu_read_unlock();
}
+static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
+{
+ struct ieee80211_radiotap_iterator iterator;
+ struct ieee80211_radiotap_header *rthdr =
+ (struct ieee80211_radiotap_header *) skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
+ NULL);
+ u16 txflags;
+
+ info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
+ IEEE80211_TX_CTL_DONTFRAG;
+
+ /*
+ * for every radiotap entry that is present
+ * (ieee80211_radiotap_iterator_next returns -ENOENT when no more
+ * entries present, or -EINVAL on error)
+ */
+
+ while (!ret) {
+ ret = ieee80211_radiotap_iterator_next(&iterator);
+
+ if (ret)
+ continue;
+
+ /* see if this argument is something we can use */
+ switch (iterator.this_arg_index) {
+ /*
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ */
+ case IEEE80211_RADIOTAP_FLAGS:
+ if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
+ /*
+ * this indicates that the skb we have been
+ * handed has the 32-bit FCS CRC at the end...
+ * we should react to that by snipping it off
+ * because it will be recomputed and added
+ * on transmission
+ */
+ if (skb->len < (iterator._max_length + FCS_LEN))
+ return false;
+
+ skb_trim(skb, skb->len - FCS_LEN);
+ }
+ if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
+ info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT;
+ if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
+ info->flags &= ~IEEE80211_TX_CTL_DONTFRAG;
+ break;
+
+ case IEEE80211_RADIOTAP_TX_FLAGS:
+ txflags = get_unaligned_le16(iterator.this_arg);
+ if (txflags & IEEE80211_RADIOTAP_F_TX_NOACK)
+ info->flags |= IEEE80211_TX_CTL_NO_ACK;
+ break;
+
+ /*
+ * Please update the file
+ * Documentation/networking/mac80211-injection.txt
+ * when parsing new fields here.
+ */
+
+ default:
+ break;
+ }
+ }
+
+ if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
+ return false;
+
+ /*
+ * remove the radiotap header
+ * iterator->_max_length was sanity-checked against
+ * skb->len by iterator init
+ */
+ skb_pull(skb, iterator._max_length);
+
+ return true;
+}
+
netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
@@ -1646,8 +1619,11 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
memset(info, 0, sizeof(*info));
info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
- IEEE80211_TX_CTL_INJECTED |
- IEEE80211_TX_INTFL_HAS_RADIOTAP;
+ IEEE80211_TX_CTL_INJECTED;
+
+ /* process and remove the injection radiotap header */
+ if (!ieee80211_parse_tx_radiotap(skb))
+ goto fail;
rcu_read_lock();
@@ -1674,7 +1650,6 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
}
}
- /* pass the radiotap header up to xmit */
ieee80211_xmit(sdata, skb);
rcu_read_unlock();