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>
This commit is contained in:
parent
a26eb27ab4
commit
73b9f03a81
|
@ -349,8 +349,6 @@ struct ieee80211_bss_conf {
|
||||||
* @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted
|
* @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted
|
||||||
* after TX status because the destination was asleep, it must not
|
* after TX status because the destination was asleep, it must not
|
||||||
* be modified again (no seqno assignment, crypto, etc.)
|
* 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
|
* @IEEE80211_TX_INTFL_NL80211_FRAME_TX: Frame was requested through nl80211
|
||||||
* MLME command (internal to mac80211 to figure out whether to send TX
|
* MLME command (internal to mac80211 to figure out whether to send TX
|
||||||
* status to user space)
|
* status to user space)
|
||||||
|
@ -402,7 +400,7 @@ enum mac80211_tx_control_flags {
|
||||||
IEEE80211_TX_CTL_POLL_RESPONSE = BIT(17),
|
IEEE80211_TX_CTL_POLL_RESPONSE = BIT(17),
|
||||||
IEEE80211_TX_CTL_MORE_FRAMES = BIT(18),
|
IEEE80211_TX_CTL_MORE_FRAMES = BIT(18),
|
||||||
IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19),
|
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_INTFL_NL80211_FRAME_TX = BIT(21),
|
||||||
IEEE80211_TX_CTL_LDPC = BIT(22),
|
IEEE80211_TX_CTL_LDPC = BIT(22),
|
||||||
IEEE80211_TX_CTL_STBC = BIT(23) | BIT(24),
|
IEEE80211_TX_CTL_STBC = BIT(23) | BIT(24),
|
||||||
|
|
|
@ -1035,103 +1035,6 @@ ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx)
|
||||||
|
|
||||||
/* actual transmit path */
|
/* 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,
|
static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
|
||||||
struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
struct ieee80211_tx_info *info,
|
struct ieee80211_tx_info *info,
|
||||||
|
@ -1205,19 +1108,6 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
|
||||||
tx->sdata = sdata;
|
tx->sdata = sdata;
|
||||||
tx->channel = local->hw.conf.channel;
|
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,
|
* If this flag is set to true anywhere, and we get here,
|
||||||
* we are doing the needed processing, so remove the flag
|
* 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();
|
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,
|
netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
|
||||||
struct net_device *dev)
|
struct net_device *dev)
|
||||||
{
|
{
|
||||||
|
@ -1646,8 +1619,11 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
|
||||||
memset(info, 0, sizeof(*info));
|
memset(info, 0, sizeof(*info));
|
||||||
|
|
||||||
info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
|
info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
|
||||||
IEEE80211_TX_CTL_INJECTED |
|
IEEE80211_TX_CTL_INJECTED;
|
||||||
IEEE80211_TX_INTFL_HAS_RADIOTAP;
|
|
||||||
|
/* process and remove the injection radiotap header */
|
||||||
|
if (!ieee80211_parse_tx_radiotap(skb))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
rcu_read_lock();
|
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);
|
ieee80211_xmit(sdata, skb);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue