aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-07-10 13:32:08 -0400
committerJohn W. Linville <linville@tuxdriver.com>2007-07-12 16:07:24 -0400
commitb306f45300866adc01b84f7aa083bfcd9cbb89c4 (patch)
tree8e8a49b9687377ef7d42a383b66bd61f3b50519d /net
parente4c967c6d88ca94365dd8e2a7bbd22eedb8d7ae7 (diff)
[PATCH] mac80211: show transmitted frames on monitor interfaces
This patch makes mac80211 show transmitted frames on monitor interfaces, including radiotap headers that indicate some transmission parameters. The shown parameters will need to be expanded, but this should work as a basis to work from. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Jiri Benc <jbenc@suse.cz> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/ieee80211.c140
-rw-r--r--net/mac80211/ieee80211_i.h1
2 files changed, 118 insertions, 23 deletions
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 8b57eaa2a271..85f23fd866ad 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -57,6 +57,17 @@ static const unsigned char eapol_header[] =
57 { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e }; 57 { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e };
58 58
59 59
60/*
61 * For seeing transmitted packets on monitor interfaces
62 * we have a radiotap header too.
63 */
64struct ieee80211_tx_status_rtap_hdr {
65 struct ieee80211_radiotap_header hdr;
66 __le16 tx_flags;
67 u8 data_retries;
68} __attribute__ ((packed));
69
70
60static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata, 71static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata,
61 struct ieee80211_hdr *hdr) 72 struct ieee80211_hdr *hdr)
62{ 73{
@@ -529,7 +540,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
529 /* reserve enough extra head and tail room for possible 540 /* reserve enough extra head and tail room for possible
530 * encryption */ 541 * encryption */
531 frag = frags[i] = 542 frag = frags[i] =
532 dev_alloc_skb(tx->local->hw.extra_tx_headroom + 543 dev_alloc_skb(tx->local->tx_headroom +
533 frag_threshold + 544 frag_threshold +
534 IEEE80211_ENCRYPT_HEADROOM + 545 IEEE80211_ENCRYPT_HEADROOM +
535 IEEE80211_ENCRYPT_TAILROOM); 546 IEEE80211_ENCRYPT_TAILROOM);
@@ -538,8 +549,8 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
538 /* Make sure that all fragments use the same priority so 549 /* Make sure that all fragments use the same priority so
539 * that they end up using the same TX queue */ 550 * that they end up using the same TX queue */
540 frag->priority = first->priority; 551 frag->priority = first->priority;
541 skb_reserve(frag, tx->local->hw.extra_tx_headroom + 552 skb_reserve(frag, tx->local->tx_headroom +
542 IEEE80211_ENCRYPT_HEADROOM); 553 IEEE80211_ENCRYPT_HEADROOM);
543 fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen); 554 fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen);
544 memcpy(fhdr, first->data, hdrlen); 555 memcpy(fhdr, first->data, hdrlen);
545 if (i == num_fragm - 2) 556 if (i == num_fragm - 2)
@@ -1636,8 +1647,7 @@ static int ieee80211_master_start_xmit(struct sk_buff *skb,
1636 } 1647 }
1637 osdata = IEEE80211_DEV_TO_SUB_IF(odev); 1648 osdata = IEEE80211_DEV_TO_SUB_IF(odev);
1638 1649
1639 headroom = osdata->local->hw.extra_tx_headroom + 1650 headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM;
1640 IEEE80211_ENCRYPT_HEADROOM;
1641 if (skb_headroom(skb) < headroom) { 1651 if (skb_headroom(skb) < headroom) {
1642 if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) { 1652 if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) {
1643 dev_kfree_skb(skb); 1653 dev_kfree_skb(skb);
@@ -1833,7 +1843,7 @@ static int ieee80211_subif_start_xmit(struct sk_buff *skb,
1833 * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and 1843 * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
1834 * alloc_skb() (net/core/skbuff.c) 1844 * alloc_skb() (net/core/skbuff.c)
1835 */ 1845 */
1836 head_need = hdrlen + encaps_len + local->hw.extra_tx_headroom; 1846 head_need = hdrlen + encaps_len + local->tx_headroom;
1837 head_need -= skb_headroom(skb); 1847 head_need -= skb_headroom(skb);
1838 1848
1839 /* We are going to modify skb data, so make a copy of it if happens to 1849 /* We are going to modify skb data, so make a copy of it if happens to
@@ -1920,9 +1930,9 @@ ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
1920 return 0; 1930 return 0;
1921 } 1931 }
1922 1932
1923 if (skb_headroom(skb) < sdata->local->hw.extra_tx_headroom) { 1933 if (skb_headroom(skb) < sdata->local->tx_headroom) {
1924 if (pskb_expand_head(skb, 1934 if (pskb_expand_head(skb, sdata->local->tx_headroom,
1925 sdata->local->hw.extra_tx_headroom, 0, GFP_ATOMIC)) { 1935 0, GFP_ATOMIC)) {
1926 dev_kfree_skb(skb); 1936 dev_kfree_skb(skb);
1927 return 0; 1937 return 0;
1928 } 1938 }
@@ -2061,12 +2071,12 @@ struct sk_buff * ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,
2061 bh_len = ap->beacon_head_len; 2071 bh_len = ap->beacon_head_len;
2062 bt_len = ap->beacon_tail_len; 2072 bt_len = ap->beacon_tail_len;
2063 2073
2064 skb = dev_alloc_skb(local->hw.extra_tx_headroom + 2074 skb = dev_alloc_skb(local->tx_headroom +
2065 bh_len + bt_len + 256 /* maximum TIM len */); 2075 bh_len + bt_len + 256 /* maximum TIM len */);
2066 if (!skb) 2076 if (!skb)
2067 return NULL; 2077 return NULL;
2068 2078
2069 skb_reserve(skb, local->hw.extra_tx_headroom); 2079 skb_reserve(skb, local->tx_headroom);
2070 memcpy(skb_put(skb, bh_len), b_head, bh_len); 2080 memcpy(skb_put(skb, bh_len), b_head, bh_len);
2071 2081
2072 ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); 2082 ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
@@ -4498,6 +4508,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
4498 struct ieee80211_local *local = hw_to_local(hw); 4508 struct ieee80211_local *local = hw_to_local(hw);
4499 u16 frag, type; 4509 u16 frag, type;
4500 u32 msg_type; 4510 u32 msg_type;
4511 struct ieee80211_tx_status_rtap_hdr *rthdr;
4512 struct ieee80211_sub_if_data *sdata;
4513 int monitors;
4501 4514
4502 if (!status) { 4515 if (!status) {
4503 printk(KERN_ERR 4516 printk(KERN_ERR
@@ -4609,27 +4622,100 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
4609 local->dot11FailedCount++; 4622 local->dot11FailedCount++;
4610 } 4623 }
4611 4624
4612 if (!(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) 4625 msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ?
4613 || unlikely(!local->apdev)) { 4626 ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail;
4627
4628 /* this was a transmitted frame, but now we want to reuse it */
4629 skb_orphan(skb);
4630
4631 if ((status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) &&
4632 local->apdev) {
4633 if (local->monitors) {
4634 skb2 = skb_clone(skb, GFP_ATOMIC);
4635 } else {
4636 skb2 = skb;
4637 skb = NULL;
4638 }
4639
4640 if (skb2)
4641 /* Send frame to hostapd */
4642 ieee80211_rx_mgmt(local, skb2, NULL, msg_type);
4643
4644 if (!skb)
4645 return;
4646 }
4647
4648 if (!local->monitors) {
4614 dev_kfree_skb(skb); 4649 dev_kfree_skb(skb);
4615 return; 4650 return;
4616 } 4651 }
4617 4652
4618 msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ? 4653 /* send frame to monitor interfaces now */
4619 ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail;
4620 4654
4621 /* skb was the original skb used for TX. Clone it and give the clone 4655 if (skb_headroom(skb) < sizeof(*rthdr)) {
4622 * to netif_rx(). Free original skb. */ 4656 printk(KERN_ERR "ieee80211_tx_status: headroom too small\n");
4623 skb2 = skb_copy(skb, GFP_ATOMIC);
4624 if (!skb2) {
4625 dev_kfree_skb(skb); 4657 dev_kfree_skb(skb);
4626 return; 4658 return;
4627 } 4659 }
4628 dev_kfree_skb(skb);
4629 skb = skb2;
4630 4660
4631 /* Send frame to hostapd */ 4661 rthdr = (struct ieee80211_tx_status_rtap_hdr*)
4632 ieee80211_rx_mgmt(local, skb, NULL, msg_type); 4662 skb_push(skb, sizeof(*rthdr));
4663
4664 memset(rthdr, 0, sizeof(*rthdr));
4665 rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
4666 rthdr->hdr.it_present =
4667 cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
4668 (1 << IEEE80211_RADIOTAP_DATA_RETRIES));
4669
4670 if (!(status->flags & IEEE80211_TX_STATUS_ACK) &&
4671 !is_multicast_ether_addr(hdr->addr1))
4672 rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
4673
4674 if ((status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
4675 (status->control.flags & IEEE80211_TXCTL_USE_CTS_PROTECT))
4676 rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
4677 else if (status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS)
4678 rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
4679
4680 rthdr->data_retries = status->retry_count;
4681
4682 read_lock(&local->sub_if_lock);
4683 monitors = local->monitors;
4684 list_for_each_entry(sdata, &local->sub_if_list, list) {
4685 /*
4686 * Using the monitors counter is possibly racy, but
4687 * if the value is wrong we simply either clone the skb
4688 * once too much or forget sending it to one monitor iface
4689 * The latter case isn't nice but fixing the race is much
4690 * more complicated.
4691 */
4692 if (!monitors || !skb)
4693 goto out;
4694
4695 if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
4696 if (!netif_running(sdata->dev))
4697 continue;
4698 monitors--;
4699 if (monitors)
4700 skb2 = skb_clone(skb, GFP_KERNEL);
4701 else
4702 skb2 = NULL;
4703 skb->dev = sdata->dev;
4704 /* XXX: is this sufficient for BPF? */
4705 skb_set_mac_header(skb, 0);
4706 skb->ip_summed = CHECKSUM_UNNECESSARY;
4707 skb->pkt_type = PACKET_OTHERHOST;
4708 skb->protocol = htons(ETH_P_802_2);
4709 memset(skb->cb, 0, sizeof(skb->cb));
4710 netif_rx(skb);
4711 skb = skb2;
4712 break;
4713 }
4714 }
4715 out:
4716 read_unlock(&local->sub_if_lock);
4717 if (skb)
4718 dev_kfree_skb(skb);
4633} 4719}
4634EXPORT_SYMBOL(ieee80211_tx_status); 4720EXPORT_SYMBOL(ieee80211_tx_status);
4635 4721
@@ -4926,6 +5012,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
4926 goto fail_workqueue; 5012 goto fail_workqueue;
4927 } 5013 }
4928 5014
5015 /*
5016 * The hardware needs headroom for sending the frame,
5017 * and we need some headroom for passing the frame to monitor
5018 * interfaces, but never both at the same time.
5019 */
5020 local->tx_headroom = max(local->hw.extra_tx_headroom,
5021 sizeof(struct ieee80211_tx_status_rtap_hdr));
5022
4929 debugfs_hw_add(local); 5023 debugfs_hw_add(local);
4930 5024
4931 local->hw.conf.beacon_int = 1000; 5025 local->hw.conf.beacon_int = 1000;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index af4d14d0b969..5a91e179efa0 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -392,6 +392,7 @@ struct ieee80211_local {
392 int monitors; 392 int monitors;
393 struct iw_statistics wstats; 393 struct iw_statistics wstats;
394 u8 wstats_flags; 394 u8 wstats_flags;
395 int tx_headroom; /* required headroom for hardware/radiotap */
395 396
396 enum { 397 enum {
397 IEEE80211_DEV_UNINITIALIZED = 0, 398 IEEE80211_DEV_UNINITIALIZED = 0,