diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/ieee80211.c | 140 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 |
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 | */ | ||
64 | struct ieee80211_tx_status_rtap_hdr { | ||
65 | struct ieee80211_radiotap_header hdr; | ||
66 | __le16 tx_flags; | ||
67 | u8 data_retries; | ||
68 | } __attribute__ ((packed)); | ||
69 | |||
70 | |||
60 | static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata, | 71 | static 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 | } |
4634 | EXPORT_SYMBOL(ieee80211_tx_status); | 4720 | EXPORT_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, |