Skip to content

Commit

Permalink
mac80211: parse radiotap header earlier
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johannes Berg authored and John W. Linville committed Oct 11, 2011
1 parent a26eb27 commit 73b9f03
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 116 deletions.
4 changes: 1 addition & 3 deletions include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,6 @@ struct ieee80211_bss_conf {
* @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted
* after TX status because the destination was asleep, it must not
* be modified again (no seqno assignment, crypto, etc.)
* @IEEE80211_TX_INTFL_HAS_RADIOTAP: This frame was injected and still
* has a radiotap header at skb->data.
* @IEEE80211_TX_INTFL_NL80211_FRAME_TX: Frame was requested through nl80211
* MLME command (internal to mac80211 to figure out whether to send TX
* status to user space)
Expand Down Expand Up @@ -402,7 +400,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_CTL_POLL_RESPONSE = BIT(17),
IEEE80211_TX_CTL_MORE_FRAMES = BIT(18),
IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19),
IEEE80211_TX_INTFL_HAS_RADIOTAP = BIT(20),
/* hole at 20, use later */
IEEE80211_TX_INTFL_NL80211_FRAME_TX = BIT(21),
IEEE80211_TX_CTL_LDPC = BIT(22),
IEEE80211_TX_CTL_STBC = BIT(23) | BIT(24),
Expand Down
201 changes: 88 additions & 113 deletions net/mac80211/tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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();

Expand All @@ -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();

Expand Down

0 comments on commit 73b9f03

Please sign in to comment.