diff options
author | David S. Miller <davem@davemloft.net> | 2008-05-15 03:52:37 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-05-15 03:52:37 -0400 |
commit | f42a44494bcdf03fc851c03d438464d59c0ceaf5 (patch) | |
tree | 986ea7b54e9fc79a64863fd7e92eabd99ffd37a3 /net/mac80211/rx.c | |
parent | 63fe46da9c380b3f2bbdf3765044649517cc717c (diff) | |
parent | ef85ad541f9a6ccd3f89ec73f92b2d6f45a9d3e8 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 214 |
1 files changed, 143 insertions, 71 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9b5a3cbec265..fa68305fd59e 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -77,6 +77,134 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status, | |||
77 | return 0; | 77 | return 0; |
78 | } | 78 | } |
79 | 79 | ||
80 | static int | ||
81 | ieee80211_rx_radiotap_len(struct ieee80211_local *local, | ||
82 | struct ieee80211_rx_status *status) | ||
83 | { | ||
84 | int len; | ||
85 | |||
86 | /* always present fields */ | ||
87 | len = sizeof(struct ieee80211_radiotap_header) + 9; | ||
88 | |||
89 | if (status->flag & RX_FLAG_TSFT) | ||
90 | len += 8; | ||
91 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DB || | ||
92 | local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | ||
93 | len += 1; | ||
94 | if (local->hw.flags & IEEE80211_HW_NOISE_DBM) | ||
95 | len += 1; | ||
96 | |||
97 | if (len & 1) /* padding for RX_FLAGS if necessary */ | ||
98 | len++; | ||
99 | |||
100 | /* make sure radiotap starts at a naturally aligned address */ | ||
101 | if (len % 8) | ||
102 | len = roundup(len, 8); | ||
103 | |||
104 | return len; | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * ieee80211_add_rx_radiotap_header - add radiotap header | ||
109 | * | ||
110 | * add a radiotap header containing all the fields which the hardware provided. | ||
111 | */ | ||
112 | static void | ||
113 | ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | ||
114 | struct sk_buff *skb, | ||
115 | struct ieee80211_rx_status *status, | ||
116 | struct ieee80211_rate *rate, | ||
117 | int rtap_len) | ||
118 | { | ||
119 | struct ieee80211_radiotap_header *rthdr; | ||
120 | unsigned char *pos; | ||
121 | |||
122 | rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); | ||
123 | memset(rthdr, 0, rtap_len); | ||
124 | |||
125 | /* radiotap header, set always present flags */ | ||
126 | rthdr->it_present = | ||
127 | cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | | ||
128 | (1 << IEEE80211_RADIOTAP_RATE) | | ||
129 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | ||
130 | (1 << IEEE80211_RADIOTAP_ANTENNA) | | ||
131 | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); | ||
132 | rthdr->it_len = cpu_to_le16(rtap_len); | ||
133 | |||
134 | pos = (unsigned char *)(rthdr+1); | ||
135 | |||
136 | /* the order of the following fields is important */ | ||
137 | |||
138 | /* IEEE80211_RADIOTAP_TSFT */ | ||
139 | if (status->flag & RX_FLAG_TSFT) { | ||
140 | *(__le64 *)pos = cpu_to_le64(status->mactime); | ||
141 | rthdr->it_present |= | ||
142 | cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); | ||
143 | pos += 8; | ||
144 | } | ||
145 | |||
146 | /* IEEE80211_RADIOTAP_FLAGS */ | ||
147 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | ||
148 | *pos |= IEEE80211_RADIOTAP_F_FCS; | ||
149 | pos++; | ||
150 | |||
151 | /* IEEE80211_RADIOTAP_RATE */ | ||
152 | *pos = rate->bitrate / 5; | ||
153 | pos++; | ||
154 | |||
155 | /* IEEE80211_RADIOTAP_CHANNEL */ | ||
156 | *(__le16 *)pos = cpu_to_le16(status->freq); | ||
157 | pos += 2; | ||
158 | if (status->band == IEEE80211_BAND_5GHZ) | ||
159 | *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_OFDM | | ||
160 | IEEE80211_CHAN_5GHZ); | ||
161 | else | ||
162 | *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_DYN | | ||
163 | IEEE80211_CHAN_2GHZ); | ||
164 | pos += 2; | ||
165 | |||
166 | /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */ | ||
167 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { | ||
168 | *pos = status->signal; | ||
169 | rthdr->it_present |= | ||
170 | cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL); | ||
171 | pos++; | ||
172 | } | ||
173 | |||
174 | /* IEEE80211_RADIOTAP_DBM_ANTNOISE */ | ||
175 | if (local->hw.flags & IEEE80211_HW_NOISE_DBM) { | ||
176 | *pos = status->noise; | ||
177 | rthdr->it_present |= | ||
178 | cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE); | ||
179 | pos++; | ||
180 | } | ||
181 | |||
182 | /* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */ | ||
183 | |||
184 | /* IEEE80211_RADIOTAP_ANTENNA */ | ||
185 | *pos = status->antenna; | ||
186 | pos++; | ||
187 | |||
188 | /* IEEE80211_RADIOTAP_DB_ANTSIGNAL */ | ||
189 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DB) { | ||
190 | *pos = status->signal; | ||
191 | rthdr->it_present |= | ||
192 | cpu_to_le32(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL); | ||
193 | pos++; | ||
194 | } | ||
195 | |||
196 | /* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */ | ||
197 | |||
198 | /* IEEE80211_RADIOTAP_RX_FLAGS */ | ||
199 | /* ensure 2 byte alignment for the 2 byte field as required */ | ||
200 | if ((pos - (unsigned char *)rthdr) & 1) | ||
201 | pos++; | ||
202 | /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */ | ||
203 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) | ||
204 | *(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS); | ||
205 | pos += 2; | ||
206 | } | ||
207 | |||
80 | /* | 208 | /* |
81 | * This function copies a received frame to all monitor interfaces and | 209 | * This function copies a received frame to all monitor interfaces and |
82 | * returns a cleaned-up SKB that no longer includes the FCS nor the | 210 | * returns a cleaned-up SKB that no longer includes the FCS nor the |
@@ -89,17 +217,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
89 | { | 217 | { |
90 | struct ieee80211_sub_if_data *sdata; | 218 | struct ieee80211_sub_if_data *sdata; |
91 | int needed_headroom = 0; | 219 | int needed_headroom = 0; |
92 | struct ieee80211_radiotap_header *rthdr; | ||
93 | __le64 *rttsft = NULL; | ||
94 | struct ieee80211_rtap_fixed_data { | ||
95 | u8 flags; | ||
96 | u8 rate; | ||
97 | __le16 chan_freq; | ||
98 | __le16 chan_flags; | ||
99 | u8 antsignal; | ||
100 | u8 padding_for_rxflags; | ||
101 | __le16 rx_flags; | ||
102 | } __attribute__ ((packed)) *rtfixed; | ||
103 | struct sk_buff *skb, *skb2; | 220 | struct sk_buff *skb, *skb2; |
104 | struct net_device *prev_dev = NULL; | 221 | struct net_device *prev_dev = NULL; |
105 | int present_fcs_len = 0; | 222 | int present_fcs_len = 0; |
@@ -116,8 +233,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
116 | if (status->flag & RX_FLAG_RADIOTAP) | 233 | if (status->flag & RX_FLAG_RADIOTAP) |
117 | rtap_len = ieee80211_get_radiotap_len(origskb->data); | 234 | rtap_len = ieee80211_get_radiotap_len(origskb->data); |
118 | else | 235 | else |
119 | /* room for radiotap header, always present fields and TSFT */ | 236 | /* room for the radiotap header based on driver features */ |
120 | needed_headroom = sizeof(*rthdr) + sizeof(*rtfixed) + 8; | 237 | needed_headroom = ieee80211_rx_radiotap_len(local, status); |
121 | 238 | ||
122 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | 239 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) |
123 | present_fcs_len = FCS_LEN; | 240 | present_fcs_len = FCS_LEN; |
@@ -163,55 +280,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
163 | } | 280 | } |
164 | 281 | ||
165 | /* if necessary, prepend radiotap information */ | 282 | /* if necessary, prepend radiotap information */ |
166 | if (!(status->flag & RX_FLAG_RADIOTAP)) { | 283 | if (!(status->flag & RX_FLAG_RADIOTAP)) |
167 | rtfixed = (void *) skb_push(skb, sizeof(*rtfixed)); | 284 | ieee80211_add_rx_radiotap_header(local, skb, status, rate, |
168 | rtap_len = sizeof(*rthdr) + sizeof(*rtfixed); | 285 | needed_headroom); |
169 | if (status->flag & RX_FLAG_TSFT) { | ||
170 | rttsft = (void *) skb_push(skb, sizeof(*rttsft)); | ||
171 | rtap_len += 8; | ||
172 | } | ||
173 | rthdr = (void *) skb_push(skb, sizeof(*rthdr)); | ||
174 | memset(rthdr, 0, sizeof(*rthdr)); | ||
175 | memset(rtfixed, 0, sizeof(*rtfixed)); | ||
176 | rthdr->it_present = | ||
177 | cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | | ||
178 | (1 << IEEE80211_RADIOTAP_RATE) | | ||
179 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | ||
180 | (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | | ||
181 | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); | ||
182 | rtfixed->flags = 0; | ||
183 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | ||
184 | rtfixed->flags |= IEEE80211_RADIOTAP_F_FCS; | ||
185 | |||
186 | if (rttsft) { | ||
187 | *rttsft = cpu_to_le64(status->mactime); | ||
188 | rthdr->it_present |= | ||
189 | cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); | ||
190 | } | ||
191 | |||
192 | /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */ | ||
193 | rtfixed->rx_flags = 0; | ||
194 | if (status->flag & | ||
195 | (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) | ||
196 | rtfixed->rx_flags |= | ||
197 | cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS); | ||
198 | |||
199 | rtfixed->rate = rate->bitrate / 5; | ||
200 | |||
201 | rtfixed->chan_freq = cpu_to_le16(status->freq); | ||
202 | |||
203 | if (status->band == IEEE80211_BAND_5GHZ) | ||
204 | rtfixed->chan_flags = | ||
205 | cpu_to_le16(IEEE80211_CHAN_OFDM | | ||
206 | IEEE80211_CHAN_5GHZ); | ||
207 | else | ||
208 | rtfixed->chan_flags = | ||
209 | cpu_to_le16(IEEE80211_CHAN_DYN | | ||
210 | IEEE80211_CHAN_2GHZ); | ||
211 | |||
212 | rtfixed->antsignal = status->ssi; | ||
213 | rthdr->it_len = cpu_to_le16(rtap_len); | ||
214 | } | ||
215 | 286 | ||
216 | skb_reset_mac_header(skb); | 287 | skb_reset_mac_header(skb); |
217 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 288 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
@@ -479,7 +550,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
479 | ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL && | 550 | ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL && |
480 | (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) && | 551 | (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) && |
481 | rx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS && | 552 | rx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS && |
482 | (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) { | 553 | (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) { |
483 | if ((!(rx->fc & IEEE80211_FCTL_FROMDS) && | 554 | if ((!(rx->fc & IEEE80211_FCTL_FROMDS) && |
484 | !(rx->fc & IEEE80211_FCTL_TODS) && | 555 | !(rx->fc & IEEE80211_FCTL_TODS) && |
485 | (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) | 556 | (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) |
@@ -630,8 +701,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) | |||
630 | 701 | ||
631 | if (sdata->bss) | 702 | if (sdata->bss) |
632 | atomic_inc(&sdata->bss->num_sta_ps); | 703 | atomic_inc(&sdata->bss->num_sta_ps); |
633 | sta->flags |= WLAN_STA_PS; | 704 | set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL); |
634 | sta->flags &= ~WLAN_STA_PSPOLL; | ||
635 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 705 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
636 | printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n", | 706 | printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n", |
637 | dev->name, print_mac(mac, sta->addr), sta->aid); | 707 | dev->name, print_mac(mac, sta->addr), sta->aid); |
@@ -652,7 +722,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) | |||
652 | if (sdata->bss) | 722 | if (sdata->bss) |
653 | atomic_dec(&sdata->bss->num_sta_ps); | 723 | atomic_dec(&sdata->bss->num_sta_ps); |
654 | 724 | ||
655 | sta->flags &= ~(WLAN_STA_PS | WLAN_STA_PSPOLL); | 725 | clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL); |
656 | 726 | ||
657 | if (!skb_queue_empty(&sta->ps_tx_buf)) | 727 | if (!skb_queue_empty(&sta->ps_tx_buf)) |
658 | sta_info_clear_tim_bit(sta); | 728 | sta_info_clear_tim_bit(sta); |
@@ -720,16 +790,17 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
720 | 790 | ||
721 | sta->rx_fragments++; | 791 | sta->rx_fragments++; |
722 | sta->rx_bytes += rx->skb->len; | 792 | sta->rx_bytes += rx->skb->len; |
723 | sta->last_rssi = rx->status->ssi; | ||
724 | sta->last_signal = rx->status->signal; | 793 | sta->last_signal = rx->status->signal; |
794 | sta->last_qual = rx->status->qual; | ||
725 | sta->last_noise = rx->status->noise; | 795 | sta->last_noise = rx->status->noise; |
726 | 796 | ||
727 | if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) { | 797 | if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) { |
728 | /* Change STA power saving mode only in the end of a frame | 798 | /* Change STA power saving mode only in the end of a frame |
729 | * exchange sequence */ | 799 | * exchange sequence */ |
730 | if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM)) | 800 | if (test_sta_flags(sta, WLAN_STA_PS) && |
801 | !(rx->fc & IEEE80211_FCTL_PM)) | ||
731 | rx->sent_ps_buffered += ap_sta_ps_end(dev, sta); | 802 | rx->sent_ps_buffered += ap_sta_ps_end(dev, sta); |
732 | else if (!(sta->flags & WLAN_STA_PS) && | 803 | else if (!test_sta_flags(sta, WLAN_STA_PS) && |
733 | (rx->fc & IEEE80211_FCTL_PM)) | 804 | (rx->fc & IEEE80211_FCTL_PM)) |
734 | ap_sta_ps_start(dev, sta); | 805 | ap_sta_ps_start(dev, sta); |
735 | } | 806 | } |
@@ -983,7 +1054,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) | |||
983 | * Tell TX path to send one frame even though the STA may | 1054 | * Tell TX path to send one frame even though the STA may |
984 | * still remain is PS mode after this frame exchange. | 1055 | * still remain is PS mode after this frame exchange. |
985 | */ | 1056 | */ |
986 | rx->sta->flags |= WLAN_STA_PSPOLL; | 1057 | set_sta_flags(rx->sta, WLAN_STA_PSPOLL); |
987 | 1058 | ||
988 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 1059 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
989 | printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n", | 1060 | printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n", |
@@ -1046,7 +1117,8 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx) | |||
1046 | static int | 1117 | static int |
1047 | ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) | 1118 | ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) |
1048 | { | 1119 | { |
1049 | if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) { | 1120 | if (unlikely(!rx->sta || |
1121 | !test_sta_flags(rx->sta, WLAN_STA_AUTHORIZED))) { | ||
1050 | #ifdef CONFIG_MAC80211_DEBUG | 1122 | #ifdef CONFIG_MAC80211_DEBUG |
1051 | if (net_ratelimit()) | 1123 | if (net_ratelimit()) |
1052 | printk(KERN_DEBUG "%s: dropped frame " | 1124 | printk(KERN_DEBUG "%s: dropped frame " |