diff options
author | David S. Miller <davem@davemloft.net> | 2008-03-11 22:17:18 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-03-11 22:17:18 -0400 |
commit | ba73d4c84a7344f1b5635c2b4e96796e8c13a126 (patch) | |
tree | d4a3e2cfc5f3a046a2b9baa898f0c201c75ba898 | |
parent | b8ad0cbc58f703972e9e37c4e2a8081dd7e6a551 (diff) | |
parent | deedf504302ff747985db081352e045ff7087a11 (diff) |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireless-2.6.26
104 files changed, 10988 insertions, 3552 deletions
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 300e1707893f..9ebd1f00c6e7 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile | |||
@@ -11,7 +11,8 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \ | |||
11 | procfs-guide.xml writing_usb_driver.xml networking.xml \ | 11 | procfs-guide.xml writing_usb_driver.xml networking.xml \ |
12 | kernel-api.xml filesystems.xml lsm.xml usb.xml \ | 12 | kernel-api.xml filesystems.xml lsm.xml usb.xml \ |
13 | gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ | 13 | gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ |
14 | genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml | 14 | genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \ |
15 | mac80211.xml | ||
15 | 16 | ||
16 | ### | 17 | ### |
17 | # The build process is as follows (targets): | 18 | # The build process is as follows (targets): |
diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl new file mode 100644 index 000000000000..b651e0a4b1c0 --- /dev/null +++ b/Documentation/DocBook/mac80211.tmpl | |||
@@ -0,0 +1,335 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" | ||
3 | "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []> | ||
4 | |||
5 | <book id="mac80211-developers-guide"> | ||
6 | <bookinfo> | ||
7 | <title>The mac80211 subsystem for kernel developers</title> | ||
8 | |||
9 | <authorgroup> | ||
10 | <author> | ||
11 | <firstname>Johannes</firstname> | ||
12 | <surname>Berg</surname> | ||
13 | <affiliation> | ||
14 | <address><email>johannes@sipsolutions.net</email></address> | ||
15 | </affiliation> | ||
16 | </author> | ||
17 | </authorgroup> | ||
18 | |||
19 | <copyright> | ||
20 | <year>2007</year> | ||
21 | <year>2008</year> | ||
22 | <holder>Johannes Berg</holder> | ||
23 | </copyright> | ||
24 | |||
25 | <legalnotice> | ||
26 | <para> | ||
27 | This documentation is free software; you can redistribute | ||
28 | it and/or modify it under the terms of the GNU General Public | ||
29 | License version 2 as published by the Free Software Foundation. | ||
30 | </para> | ||
31 | |||
32 | <para> | ||
33 | This documentation is distributed in the hope that it will be | ||
34 | useful, but WITHOUT ANY WARRANTY; without even the implied | ||
35 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
36 | See the GNU General Public License for more details. | ||
37 | </para> | ||
38 | |||
39 | <para> | ||
40 | You should have received a copy of the GNU General Public | ||
41 | License along with this documentation; if not, write to the Free | ||
42 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
43 | MA 02111-1307 USA | ||
44 | </para> | ||
45 | |||
46 | <para> | ||
47 | For more details see the file COPYING in the source | ||
48 | distribution of Linux. | ||
49 | </para> | ||
50 | </legalnotice> | ||
51 | |||
52 | <abstract> | ||
53 | !Pinclude/net/mac80211.h Introduction | ||
54 | !Pinclude/net/mac80211.h Warning | ||
55 | </abstract> | ||
56 | </bookinfo> | ||
57 | |||
58 | <toc></toc> | ||
59 | |||
60 | <!-- | ||
61 | Generally, this document shall be ordered by increasing complexity. | ||
62 | It is important to note that readers should be able to read only | ||
63 | the first few sections to get a working driver and only advanced | ||
64 | usage should require reading the full document. | ||
65 | --> | ||
66 | |||
67 | <part> | ||
68 | <title>The basic mac80211 driver interface</title> | ||
69 | <partintro> | ||
70 | <para> | ||
71 | You should read and understand the information contained | ||
72 | within this part of the book while implementing a driver. | ||
73 | In some chapters, advanced usage is noted, that may be | ||
74 | skipped at first. | ||
75 | </para> | ||
76 | <para> | ||
77 | This part of the book only covers station and monitor mode | ||
78 | functionality, additional information required to implement | ||
79 | the other modes is covered in the second part of the book. | ||
80 | </para> | ||
81 | </partintro> | ||
82 | |||
83 | <chapter id="basics"> | ||
84 | <title>Basic hardware handling</title> | ||
85 | <para>TBD</para> | ||
86 | <para> | ||
87 | This chapter shall contain information on getting a hw | ||
88 | struct allocated and registered with mac80211. | ||
89 | </para> | ||
90 | <para> | ||
91 | Since it is required to allocate rates/modes before registering | ||
92 | a hw struct, this chapter shall also contain information on setting | ||
93 | up the rate/mode structs. | ||
94 | </para> | ||
95 | <para> | ||
96 | Additionally, some discussion about the callbacks and | ||
97 | the general programming model should be in here, including | ||
98 | the definition of ieee80211_ops which will be referred to | ||
99 | a lot. | ||
100 | </para> | ||
101 | <para> | ||
102 | Finally, a discussion of hardware capabilities should be done | ||
103 | with references to other parts of the book. | ||
104 | </para> | ||
105 | <!-- intentionally multiple !F lines to get proper order --> | ||
106 | !Finclude/net/mac80211.h ieee80211_hw | ||
107 | !Finclude/net/mac80211.h ieee80211_hw_flags | ||
108 | !Finclude/net/mac80211.h SET_IEEE80211_DEV | ||
109 | !Finclude/net/mac80211.h SET_IEEE80211_PERM_ADDR | ||
110 | !Finclude/net/mac80211.h ieee80211_ops | ||
111 | !Finclude/net/mac80211.h ieee80211_alloc_hw | ||
112 | !Finclude/net/mac80211.h ieee80211_register_hw | ||
113 | !Finclude/net/mac80211.h ieee80211_get_tx_led_name | ||
114 | !Finclude/net/mac80211.h ieee80211_get_rx_led_name | ||
115 | !Finclude/net/mac80211.h ieee80211_get_assoc_led_name | ||
116 | !Finclude/net/mac80211.h ieee80211_get_radio_led_name | ||
117 | !Finclude/net/mac80211.h ieee80211_unregister_hw | ||
118 | !Finclude/net/mac80211.h ieee80211_free_hw | ||
119 | </chapter> | ||
120 | |||
121 | <chapter id="phy-handling"> | ||
122 | <title>PHY configuration</title> | ||
123 | <para>TBD</para> | ||
124 | <para> | ||
125 | This chapter should describe PHY handling including | ||
126 | start/stop callbacks and the various structures used. | ||
127 | </para> | ||
128 | !Finclude/net/mac80211.h ieee80211_conf | ||
129 | !Finclude/net/mac80211.h ieee80211_conf_flags | ||
130 | </chapter> | ||
131 | |||
132 | <chapter id="iface-handling"> | ||
133 | <title>Virtual interfaces</title> | ||
134 | <para>TBD</para> | ||
135 | <para> | ||
136 | This chapter should describe virtual interface basics | ||
137 | that are relevant to the driver (VLANs, MGMT etc are not.) | ||
138 | It should explain the use of the add_iface/remove_iface | ||
139 | callbacks as well as the interface configuration callbacks. | ||
140 | </para> | ||
141 | <para>Things related to AP mode should be discussed there.</para> | ||
142 | <para> | ||
143 | Things related to supporting multiple interfaces should be | ||
144 | in the appropriate chapter, a BIG FAT note should be here about | ||
145 | this though and the recommendation to allow only a single | ||
146 | interface in STA mode at first! | ||
147 | </para> | ||
148 | !Finclude/net/mac80211.h ieee80211_if_types | ||
149 | !Finclude/net/mac80211.h ieee80211_if_init_conf | ||
150 | !Finclude/net/mac80211.h ieee80211_if_conf | ||
151 | </chapter> | ||
152 | |||
153 | <chapter id="rx-tx"> | ||
154 | <title>Receive and transmit processing</title> | ||
155 | <sect1> | ||
156 | <title>what should be here</title> | ||
157 | <para>TBD</para> | ||
158 | <para> | ||
159 | This should describe the receive and transmit | ||
160 | paths in mac80211/the drivers as well as | ||
161 | transmit status handling. | ||
162 | </para> | ||
163 | </sect1> | ||
164 | <sect1> | ||
165 | <title>Frame format</title> | ||
166 | !Pinclude/net/mac80211.h Frame format | ||
167 | </sect1> | ||
168 | <sect1> | ||
169 | <title>Alignment issues</title> | ||
170 | <para>TBD</para> | ||
171 | </sect1> | ||
172 | <sect1> | ||
173 | <title>Calling into mac80211 from interrupts</title> | ||
174 | !Pinclude/net/mac80211.h Calling mac80211 from interrupts | ||
175 | </sect1> | ||
176 | <sect1> | ||
177 | <title>functions/definitions</title> | ||
178 | !Finclude/net/mac80211.h ieee80211_rx_status | ||
179 | !Finclude/net/mac80211.h mac80211_rx_flags | ||
180 | !Finclude/net/mac80211.h ieee80211_tx_control | ||
181 | !Finclude/net/mac80211.h ieee80211_tx_status_flags | ||
182 | !Finclude/net/mac80211.h ieee80211_rx | ||
183 | !Finclude/net/mac80211.h ieee80211_rx_irqsafe | ||
184 | !Finclude/net/mac80211.h ieee80211_tx_status | ||
185 | !Finclude/net/mac80211.h ieee80211_tx_status_irqsafe | ||
186 | !Finclude/net/mac80211.h ieee80211_rts_get | ||
187 | !Finclude/net/mac80211.h ieee80211_rts_duration | ||
188 | !Finclude/net/mac80211.h ieee80211_ctstoself_get | ||
189 | !Finclude/net/mac80211.h ieee80211_ctstoself_duration | ||
190 | !Finclude/net/mac80211.h ieee80211_generic_frame_duration | ||
191 | !Finclude/net/mac80211.h ieee80211_get_hdrlen_from_skb | ||
192 | !Finclude/net/mac80211.h ieee80211_get_hdrlen | ||
193 | !Finclude/net/mac80211.h ieee80211_wake_queue | ||
194 | !Finclude/net/mac80211.h ieee80211_stop_queue | ||
195 | !Finclude/net/mac80211.h ieee80211_start_queues | ||
196 | !Finclude/net/mac80211.h ieee80211_stop_queues | ||
197 | !Finclude/net/mac80211.h ieee80211_wake_queues | ||
198 | </sect1> | ||
199 | </chapter> | ||
200 | |||
201 | <chapter id="filters"> | ||
202 | <title>Frame filtering</title> | ||
203 | !Pinclude/net/mac80211.h Frame filtering | ||
204 | !Finclude/net/mac80211.h ieee80211_filter_flags | ||
205 | </chapter> | ||
206 | </part> | ||
207 | |||
208 | <part id="advanced"> | ||
209 | <title>Advanced driver interface</title> | ||
210 | <partintro> | ||
211 | <para> | ||
212 | Information contained within this part of the book is | ||
213 | of interest only for advanced interaction of mac80211 | ||
214 | with drivers to exploit more hardware capabilities and | ||
215 | improve performance. | ||
216 | </para> | ||
217 | </partintro> | ||
218 | |||
219 | <chapter id="hardware-crypto-offload"> | ||
220 | <title>Hardware crypto acceleration</title> | ||
221 | !Pinclude/net/mac80211.h Hardware crypto acceleration | ||
222 | <!-- intentionally multiple !F lines to get proper order --> | ||
223 | !Finclude/net/mac80211.h set_key_cmd | ||
224 | !Finclude/net/mac80211.h ieee80211_key_conf | ||
225 | !Finclude/net/mac80211.h ieee80211_key_alg | ||
226 | !Finclude/net/mac80211.h ieee80211_key_flags | ||
227 | </chapter> | ||
228 | |||
229 | <chapter id="qos"> | ||
230 | <title>Multiple queues and QoS support</title> | ||
231 | <para>TBD</para> | ||
232 | !Finclude/net/mac80211.h ieee80211_tx_queue_params | ||
233 | !Finclude/net/mac80211.h ieee80211_tx_queue_stats_data | ||
234 | !Finclude/net/mac80211.h ieee80211_tx_queue | ||
235 | </chapter> | ||
236 | |||
237 | <chapter id="AP"> | ||
238 | <title>Access point mode support</title> | ||
239 | <para>TBD</para> | ||
240 | <para>Some parts of the if_conf should be discussed here instead</para> | ||
241 | <para> | ||
242 | Insert notes about VLAN interfaces with hw crypto here or | ||
243 | in the hw crypto chapter. | ||
244 | </para> | ||
245 | !Finclude/net/mac80211.h ieee80211_get_buffered_bc | ||
246 | !Finclude/net/mac80211.h ieee80211_beacon_get | ||
247 | </chapter> | ||
248 | |||
249 | <chapter id="multi-iface"> | ||
250 | <title>Supporting multiple virtual interfaces</title> | ||
251 | <para>TBD</para> | ||
252 | <para> | ||
253 | Note: WDS with identical MAC address should almost always be OK | ||
254 | </para> | ||
255 | <para> | ||
256 | Insert notes about having multiple virtual interfaces with | ||
257 | different MAC addresses here, note which configurations are | ||
258 | supported by mac80211, add notes about supporting hw crypto | ||
259 | with it. | ||
260 | </para> | ||
261 | </chapter> | ||
262 | |||
263 | <chapter id="hardware-scan-offload"> | ||
264 | <title>Hardware scan offload</title> | ||
265 | <para>TBD</para> | ||
266 | !Finclude/net/mac80211.h ieee80211_scan_completed | ||
267 | </chapter> | ||
268 | </part> | ||
269 | |||
270 | <part id="rate-control"> | ||
271 | <title>Rate control interface</title> | ||
272 | <partintro> | ||
273 | <para>TBD</para> | ||
274 | <para> | ||
275 | This part of the book describes the rate control algorithm | ||
276 | interface and how it relates to mac80211 and drivers. | ||
277 | </para> | ||
278 | </partintro> | ||
279 | <chapter id="dummy"> | ||
280 | <title>dummy chapter</title> | ||
281 | <para>TBD</para> | ||
282 | </chapter> | ||
283 | </part> | ||
284 | |||
285 | <part id="internal"> | ||
286 | <title>Internals</title> | ||
287 | <partintro> | ||
288 | <para>TBD</para> | ||
289 | <para> | ||
290 | This part of the book describes mac80211 internals. | ||
291 | </para> | ||
292 | </partintro> | ||
293 | |||
294 | <chapter id="key-handling"> | ||
295 | <title>Key handling</title> | ||
296 | <sect1> | ||
297 | <title>Key handling basics</title> | ||
298 | !Pnet/mac80211/key.c Key handling basics | ||
299 | </sect1> | ||
300 | <sect1> | ||
301 | <title>MORE TBD</title> | ||
302 | <para>TBD</para> | ||
303 | </sect1> | ||
304 | </chapter> | ||
305 | |||
306 | <chapter id="rx-processing"> | ||
307 | <title>Receive processing</title> | ||
308 | <para>TBD</para> | ||
309 | </chapter> | ||
310 | |||
311 | <chapter id="tx-processing"> | ||
312 | <title>Transmit processing</title> | ||
313 | <para>TBD</para> | ||
314 | </chapter> | ||
315 | |||
316 | <chapter id="sta-info"> | ||
317 | <title>Station info handling</title> | ||
318 | <sect1> | ||
319 | <title>Programming information</title> | ||
320 | !Fnet/mac80211/sta_info.h sta_info | ||
321 | !Fnet/mac80211/sta_info.h ieee80211_sta_info_flags | ||
322 | </sect1> | ||
323 | <sect1> | ||
324 | <title>STA information lifetime rules</title> | ||
325 | !Pnet/mac80211/sta_info.c STA information lifetime rules | ||
326 | </sect1> | ||
327 | </chapter> | ||
328 | |||
329 | <chapter id="synchronisation"> | ||
330 | <title>Synchronisation</title> | ||
331 | <para>TBD</para> | ||
332 | <para>Locking, lots of RCU</para> | ||
333 | </chapter> | ||
334 | </part> | ||
335 | </book> | ||
diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index 18223d9833f1..b21830771ea5 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h | |||
@@ -140,7 +140,8 @@ enum ath5k_radio { | |||
140 | AR5K_RF5110 = 0, | 140 | AR5K_RF5110 = 0, |
141 | AR5K_RF5111 = 1, | 141 | AR5K_RF5111 = 1, |
142 | AR5K_RF5112 = 2, | 142 | AR5K_RF5112 = 2, |
143 | AR5K_RF5413 = 3, | 143 | AR5K_RF2413 = 3, |
144 | AR5K_RF5413 = 4, | ||
144 | }; | 145 | }; |
145 | 146 | ||
146 | /* | 147 | /* |
@@ -168,12 +169,15 @@ struct ath5k_srev_name { | |||
168 | #define AR5K_SREV_VER_AR5212 0x50 | 169 | #define AR5K_SREV_VER_AR5212 0x50 |
169 | #define AR5K_SREV_VER_AR5213 0x55 | 170 | #define AR5K_SREV_VER_AR5213 0x55 |
170 | #define AR5K_SREV_VER_AR5213A 0x59 | 171 | #define AR5K_SREV_VER_AR5213A 0x59 |
171 | #define AR5K_SREV_VER_AR2424 0xa0 | 172 | #define AR5K_SREV_VER_AR2413 0x78 |
172 | #define AR5K_SREV_VER_AR5424 0xa3 | 173 | #define AR5K_SREV_VER_AR2414 0x79 |
174 | #define AR5K_SREV_VER_AR2424 0xa0 /* PCI-E */ | ||
175 | #define AR5K_SREV_VER_AR5424 0xa3 /* PCI-E */ | ||
173 | #define AR5K_SREV_VER_AR5413 0xa4 | 176 | #define AR5K_SREV_VER_AR5413 0xa4 |
174 | #define AR5K_SREV_VER_AR5414 0xa5 | 177 | #define AR5K_SREV_VER_AR5414 0xa5 |
175 | #define AR5K_SREV_VER_AR5416 0xc0 /* ? */ | 178 | #define AR5K_SREV_VER_AR5416 0xc0 /* PCI-E */ |
176 | #define AR5K_SREV_VER_AR5418 0xca | 179 | #define AR5K_SREV_VER_AR5418 0xca /* PCI-E */ |
180 | #define AR5K_SREV_VER_AR2425 0xe2 /* PCI-E */ | ||
177 | 181 | ||
178 | #define AR5K_SREV_RAD_5110 0x00 | 182 | #define AR5K_SREV_RAD_5110 0x00 |
179 | #define AR5K_SREV_RAD_5111 0x10 | 183 | #define AR5K_SREV_RAD_5111 0x10 |
@@ -183,8 +187,9 @@ struct ath5k_srev_name { | |||
183 | #define AR5K_SREV_RAD_5112A 0x35 | 187 | #define AR5K_SREV_RAD_5112A 0x35 |
184 | #define AR5K_SREV_RAD_2112 0x40 | 188 | #define AR5K_SREV_RAD_2112 0x40 |
185 | #define AR5K_SREV_RAD_2112A 0x45 | 189 | #define AR5K_SREV_RAD_2112A 0x45 |
190 | #define AR5K_SREV_RAD_SC0 0x56 /* Found on 2413/2414 */ | ||
186 | #define AR5K_SREV_RAD_SC1 0x63 /* Found on 5413/5414 */ | 191 | #define AR5K_SREV_RAD_SC1 0x63 /* Found on 5413/5414 */ |
187 | #define AR5K_SREV_RAD_SC2 0xa2 /* Found on 2424/5424 */ | 192 | #define AR5K_SREV_RAD_SC2 0xa2 /* Found on 2424-5/5424 */ |
188 | #define AR5K_SREV_RAD_5133 0xc0 /* MIMO found on 5418 */ | 193 | #define AR5K_SREV_RAD_5133 0xc0 /* MIMO found on 5418 */ |
189 | 194 | ||
190 | /* IEEE defs */ | 195 | /* IEEE defs */ |
@@ -268,12 +273,13 @@ enum ath5k_driver_mode { | |||
268 | #define SHPREAMBLE_FLAG(_ix) \ | 273 | #define SHPREAMBLE_FLAG(_ix) \ |
269 | (HAS_SHPREAMBLE(_ix) ? AR5K_SET_SHORT_PREAMBLE : 0) | 274 | (HAS_SHPREAMBLE(_ix) ? AR5K_SET_SHORT_PREAMBLE : 0) |
270 | 275 | ||
276 | |||
271 | /****************\ | 277 | /****************\ |
272 | TX DEFINITIONS | 278 | TX DEFINITIONS |
273 | \****************/ | 279 | \****************/ |
274 | 280 | ||
275 | /* | 281 | /* |
276 | * Tx Descriptor | 282 | * TX Status |
277 | */ | 283 | */ |
278 | struct ath5k_tx_status { | 284 | struct ath5k_tx_status { |
279 | u16 ts_seqnum; | 285 | u16 ts_seqnum; |
@@ -421,7 +427,7 @@ enum ath5k_dmasize { | |||
421 | \****************/ | 427 | \****************/ |
422 | 428 | ||
423 | /* | 429 | /* |
424 | * Rx Descriptor | 430 | * RX Status |
425 | */ | 431 | */ |
426 | struct ath5k_rx_status { | 432 | struct ath5k_rx_status { |
427 | u16 rs_datalen; | 433 | u16 rs_datalen; |
@@ -452,8 +458,6 @@ struct ath5k_mib_stats { | |||
452 | }; | 458 | }; |
453 | 459 | ||
454 | 460 | ||
455 | |||
456 | |||
457 | /**************************\ | 461 | /**************************\ |
458 | BEACON TIMERS DEFINITIONS | 462 | BEACON TIMERS DEFINITIONS |
459 | \**************************/ | 463 | \**************************/ |
@@ -495,29 +499,23 @@ struct ath5k_beacon_state { | |||
495 | #define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10) | 499 | #define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10) |
496 | 500 | ||
497 | 501 | ||
498 | |||
499 | /********************\ | 502 | /********************\ |
500 | COMMON DEFINITIONS | 503 | COMMON DEFINITIONS |
501 | \********************/ | 504 | \********************/ |
502 | 505 | ||
503 | /* | 506 | /* |
504 | * Atheros descriptor | 507 | * Atheros hardware descriptor |
508 | * This is read and written to by the hardware | ||
505 | */ | 509 | */ |
506 | struct ath5k_desc { | 510 | struct ath5k_desc { |
507 | u32 ds_link; | 511 | u32 ds_link; /* physical address of the next descriptor */ |
508 | u32 ds_data; | 512 | u32 ds_data; /* physical address of data buffer (skb) */ |
509 | u32 ds_ctl0; | ||
510 | u32 ds_ctl1; | ||
511 | u32 ds_hw[4]; | ||
512 | 513 | ||
513 | union { | 514 | union { |
514 | struct ath5k_rx_status rx; | 515 | struct ath5k_hw_5210_tx_desc ds_tx5210; |
515 | struct ath5k_tx_status tx; | 516 | struct ath5k_hw_5212_tx_desc ds_tx5212; |
516 | } ds_us; | 517 | struct ath5k_hw_all_rx_desc ds_rx; |
517 | 518 | } ud; | |
518 | #define ds_rxstat ds_us.rx | ||
519 | #define ds_txstat ds_us.tx | ||
520 | |||
521 | } __packed; | 519 | } __packed; |
522 | 520 | ||
523 | #define AR5K_RXDESC_INTREQ 0x0020 | 521 | #define AR5K_RXDESC_INTREQ 0x0020 |
@@ -961,6 +959,7 @@ struct ath5k_hw { | |||
961 | u16 ah_phy_revision; | 959 | u16 ah_phy_revision; |
962 | u16 ah_radio_5ghz_revision; | 960 | u16 ah_radio_5ghz_revision; |
963 | u16 ah_radio_2ghz_revision; | 961 | u16 ah_radio_2ghz_revision; |
962 | u32 ah_phy_spending; | ||
964 | 963 | ||
965 | enum ath5k_version ah_version; | 964 | enum ath5k_version ah_version; |
966 | enum ath5k_radio ah_radio; | 965 | enum ath5k_radio ah_radio; |
@@ -1036,8 +1035,10 @@ struct ath5k_hw { | |||
1036 | int (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *, | 1035 | int (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *, |
1037 | unsigned int, unsigned int, unsigned int, unsigned int, | 1036 | unsigned int, unsigned int, unsigned int, unsigned int, |
1038 | unsigned int, unsigned int); | 1037 | unsigned int, unsigned int); |
1039 | int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *); | 1038 | int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, |
1040 | int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *); | 1039 | struct ath5k_tx_status *); |
1040 | int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *, | ||
1041 | struct ath5k_rx_status *); | ||
1041 | }; | 1042 | }; |
1042 | 1043 | ||
1043 | /* | 1044 | /* |
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 393b5f3c25a7..b5c0a0d7a81c 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c | |||
@@ -118,6 +118,8 @@ static struct ath5k_srev_name srev_names[] = { | |||
118 | { "5212", AR5K_VERSION_VER, AR5K_SREV_VER_AR5212 }, | 118 | { "5212", AR5K_VERSION_VER, AR5K_SREV_VER_AR5212 }, |
119 | { "5213", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213 }, | 119 | { "5213", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213 }, |
120 | { "5213A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213A }, | 120 | { "5213A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213A }, |
121 | { "2413", AR5K_VERSION_VER, AR5K_SREV_VER_AR2413 }, | ||
122 | { "2414", AR5K_VERSION_VER, AR5K_SREV_VER_AR2414 }, | ||
121 | { "2424", AR5K_VERSION_VER, AR5K_SREV_VER_AR2424 }, | 123 | { "2424", AR5K_VERSION_VER, AR5K_SREV_VER_AR2424 }, |
122 | { "5424", AR5K_VERSION_VER, AR5K_SREV_VER_AR5424 }, | 124 | { "5424", AR5K_VERSION_VER, AR5K_SREV_VER_AR5424 }, |
123 | { "5413", AR5K_VERSION_VER, AR5K_SREV_VER_AR5413 }, | 125 | { "5413", AR5K_VERSION_VER, AR5K_SREV_VER_AR5413 }, |
@@ -132,6 +134,7 @@ static struct ath5k_srev_name srev_names[] = { | |||
132 | { "5112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112A }, | 134 | { "5112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112A }, |
133 | { "2112", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112 }, | 135 | { "2112", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112 }, |
134 | { "2112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112A }, | 136 | { "2112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112A }, |
137 | { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC0 }, | ||
135 | { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC1 }, | 138 | { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC1 }, |
136 | { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC2 }, | 139 | { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC2 }, |
137 | { "5133", AR5K_VERSION_RAD, AR5K_SREV_RAD_5133 }, | 140 | { "5133", AR5K_VERSION_RAD, AR5K_SREV_RAD_5133 }, |
@@ -280,7 +283,8 @@ static int ath5k_rx_start(struct ath5k_softc *sc); | |||
280 | static void ath5k_rx_stop(struct ath5k_softc *sc); | 283 | static void ath5k_rx_stop(struct ath5k_softc *sc); |
281 | static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc, | 284 | static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc, |
282 | struct ath5k_desc *ds, | 285 | struct ath5k_desc *ds, |
283 | struct sk_buff *skb); | 286 | struct sk_buff *skb, |
287 | struct ath5k_rx_status *rs); | ||
284 | static void ath5k_tasklet_rx(unsigned long data); | 288 | static void ath5k_tasklet_rx(unsigned long data); |
285 | /* Tx handling */ | 289 | /* Tx handling */ |
286 | static void ath5k_tx_processq(struct ath5k_softc *sc, | 290 | static void ath5k_tx_processq(struct ath5k_softc *sc, |
@@ -1560,8 +1564,7 @@ ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq) | |||
1560 | */ | 1564 | */ |
1561 | spin_lock_bh(&txq->lock); | 1565 | spin_lock_bh(&txq->lock); |
1562 | list_for_each_entry_safe(bf, bf0, &txq->q, list) { | 1566 | list_for_each_entry_safe(bf, bf0, &txq->q, list) { |
1563 | ath5k_debug_printtxbuf(sc, bf, !sc->ah->ah_proc_tx_desc(sc->ah, | 1567 | ath5k_debug_printtxbuf(sc, bf); |
1564 | bf->desc)); | ||
1565 | 1568 | ||
1566 | ath5k_txbuf_free(sc, bf); | 1569 | ath5k_txbuf_free(sc, bf); |
1567 | 1570 | ||
@@ -1686,20 +1689,20 @@ ath5k_rx_stop(struct ath5k_softc *sc) | |||
1686 | 1689 | ||
1687 | static unsigned int | 1690 | static unsigned int |
1688 | ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, | 1691 | ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, |
1689 | struct sk_buff *skb) | 1692 | struct sk_buff *skb, struct ath5k_rx_status *rs) |
1690 | { | 1693 | { |
1691 | struct ieee80211_hdr *hdr = (void *)skb->data; | 1694 | struct ieee80211_hdr *hdr = (void *)skb->data; |
1692 | unsigned int keyix, hlen = ieee80211_get_hdrlen_from_skb(skb); | 1695 | unsigned int keyix, hlen = ieee80211_get_hdrlen_from_skb(skb); |
1693 | 1696 | ||
1694 | if (!(ds->ds_rxstat.rs_status & AR5K_RXERR_DECRYPT) && | 1697 | if (!(rs->rs_status & AR5K_RXERR_DECRYPT) && |
1695 | ds->ds_rxstat.rs_keyix != AR5K_RXKEYIX_INVALID) | 1698 | rs->rs_keyix != AR5K_RXKEYIX_INVALID) |
1696 | return RX_FLAG_DECRYPTED; | 1699 | return RX_FLAG_DECRYPTED; |
1697 | 1700 | ||
1698 | /* Apparently when a default key is used to decrypt the packet | 1701 | /* Apparently when a default key is used to decrypt the packet |
1699 | the hw does not set the index used to decrypt. In such cases | 1702 | the hw does not set the index used to decrypt. In such cases |
1700 | get the index from the packet. */ | 1703 | get the index from the packet. */ |
1701 | if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) && | 1704 | if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) && |
1702 | !(ds->ds_rxstat.rs_status & AR5K_RXERR_DECRYPT) && | 1705 | !(rs->rs_status & AR5K_RXERR_DECRYPT) && |
1703 | skb->len >= hlen + 4) { | 1706 | skb->len >= hlen + 4) { |
1704 | keyix = skb->data[hlen + 3] >> 6; | 1707 | keyix = skb->data[hlen + 3] >> 6; |
1705 | 1708 | ||
@@ -1712,8 +1715,10 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, | |||
1712 | 1715 | ||
1713 | 1716 | ||
1714 | static void | 1717 | static void |
1715 | ath5k_check_ibss_hw_merge(struct ath5k_softc *sc, struct sk_buff *skb) | 1718 | ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, |
1719 | struct ieee80211_rx_status *rxs) | ||
1716 | { | 1720 | { |
1721 | u64 tsf, bc_tstamp; | ||
1717 | u32 hw_tu; | 1722 | u32 hw_tu; |
1718 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; | 1723 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; |
1719 | 1724 | ||
@@ -1724,16 +1729,45 @@ ath5k_check_ibss_hw_merge(struct ath5k_softc *sc, struct sk_buff *skb) | |||
1724 | le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS && | 1729 | le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS && |
1725 | memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) { | 1730 | memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) { |
1726 | /* | 1731 | /* |
1727 | * Received an IBSS beacon with the same BSSID. Hardware might | 1732 | * Received an IBSS beacon with the same BSSID. Hardware *must* |
1728 | * have updated the TSF, check if we need to update timers. | 1733 | * have updated the local TSF. We have to work around various |
1734 | * hardware bugs, though... | ||
1729 | */ | 1735 | */ |
1730 | hw_tu = TSF_TO_TU(ath5k_hw_get_tsf64(sc->ah)); | 1736 | tsf = ath5k_hw_get_tsf64(sc->ah); |
1731 | if (hw_tu >= sc->nexttbtt) { | 1737 | bc_tstamp = le64_to_cpu(mgmt->u.beacon.timestamp); |
1732 | ath5k_beacon_update_timers(sc, | 1738 | hw_tu = TSF_TO_TU(tsf); |
1733 | le64_to_cpu(mgmt->u.beacon.timestamp)); | 1739 | |
1740 | ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, | ||
1741 | "beacon %llx mactime %llx (diff %lld) tsf now %llx\n", | ||
1742 | bc_tstamp, rxs->mactime, | ||
1743 | (rxs->mactime - bc_tstamp), tsf); | ||
1744 | |||
1745 | /* | ||
1746 | * Sometimes the HW will give us a wrong tstamp in the rx | ||
1747 | * status, causing the timestamp extension to go wrong. | ||
1748 | * (This seems to happen especially with beacon frames bigger | ||
1749 | * than 78 byte (incl. FCS)) | ||
1750 | * But we know that the receive timestamp must be later than the | ||
1751 | * timestamp of the beacon since HW must have synced to that. | ||
1752 | * | ||
1753 | * NOTE: here we assume mactime to be after the frame was | ||
1754 | * received, not like mac80211 which defines it at the start. | ||
1755 | */ | ||
1756 | if (bc_tstamp > rxs->mactime) { | ||
1734 | ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, | 1757 | ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, |
1735 | "detected HW merge from received beacon\n"); | 1758 | "fixing mactime from %llx to %llx\n", |
1759 | rxs->mactime, tsf); | ||
1760 | rxs->mactime = tsf; | ||
1736 | } | 1761 | } |
1762 | |||
1763 | /* | ||
1764 | * Local TSF might have moved higher than our beacon timers, | ||
1765 | * in that case we have to update them to continue sending | ||
1766 | * beacons. This also takes care of synchronizing beacon sending | ||
1767 | * times with other stations. | ||
1768 | */ | ||
1769 | if (hw_tu >= sc->nexttbtt) | ||
1770 | ath5k_beacon_update_timers(sc, bc_tstamp); | ||
1737 | } | 1771 | } |
1738 | } | 1772 | } |
1739 | 1773 | ||
@@ -1742,12 +1776,11 @@ static void | |||
1742 | ath5k_tasklet_rx(unsigned long data) | 1776 | ath5k_tasklet_rx(unsigned long data) |
1743 | { | 1777 | { |
1744 | struct ieee80211_rx_status rxs = {}; | 1778 | struct ieee80211_rx_status rxs = {}; |
1779 | struct ath5k_rx_status rs = {}; | ||
1745 | struct sk_buff *skb; | 1780 | struct sk_buff *skb; |
1746 | struct ath5k_softc *sc = (void *)data; | 1781 | struct ath5k_softc *sc = (void *)data; |
1747 | struct ath5k_buf *bf; | 1782 | struct ath5k_buf *bf; |
1748 | struct ath5k_desc *ds; | 1783 | struct ath5k_desc *ds; |
1749 | u16 len; | ||
1750 | u8 stat; | ||
1751 | int ret; | 1784 | int ret; |
1752 | int hdrlen; | 1785 | int hdrlen; |
1753 | int pad; | 1786 | int pad; |
@@ -1770,7 +1803,7 @@ ath5k_tasklet_rx(unsigned long data) | |||
1770 | if (unlikely(ds->ds_link == bf->daddr)) /* this is the end */ | 1803 | if (unlikely(ds->ds_link == bf->daddr)) /* this is the end */ |
1771 | break; | 1804 | break; |
1772 | 1805 | ||
1773 | ret = sc->ah->ah_proc_rx_desc(sc->ah, ds); | 1806 | ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs); |
1774 | if (unlikely(ret == -EINPROGRESS)) | 1807 | if (unlikely(ret == -EINPROGRESS)) |
1775 | break; | 1808 | break; |
1776 | else if (unlikely(ret)) { | 1809 | else if (unlikely(ret)) { |
@@ -1779,16 +1812,15 @@ ath5k_tasklet_rx(unsigned long data) | |||
1779 | return; | 1812 | return; |
1780 | } | 1813 | } |
1781 | 1814 | ||
1782 | if (unlikely(ds->ds_rxstat.rs_more)) { | 1815 | if (unlikely(rs.rs_more)) { |
1783 | ATH5K_WARN(sc, "unsupported jumbo\n"); | 1816 | ATH5K_WARN(sc, "unsupported jumbo\n"); |
1784 | goto next; | 1817 | goto next; |
1785 | } | 1818 | } |
1786 | 1819 | ||
1787 | stat = ds->ds_rxstat.rs_status; | 1820 | if (unlikely(rs.rs_status)) { |
1788 | if (unlikely(stat)) { | 1821 | if (rs.rs_status & AR5K_RXERR_PHY) |
1789 | if (stat & AR5K_RXERR_PHY) | ||
1790 | goto next; | 1822 | goto next; |
1791 | if (stat & AR5K_RXERR_DECRYPT) { | 1823 | if (rs.rs_status & AR5K_RXERR_DECRYPT) { |
1792 | /* | 1824 | /* |
1793 | * Decrypt error. If the error occurred | 1825 | * Decrypt error. If the error occurred |
1794 | * because there was no hardware key, then | 1826 | * because there was no hardware key, then |
@@ -1799,30 +1831,29 @@ ath5k_tasklet_rx(unsigned long data) | |||
1799 | * | 1831 | * |
1800 | * XXX do key cache faulting | 1832 | * XXX do key cache faulting |
1801 | */ | 1833 | */ |
1802 | if (ds->ds_rxstat.rs_keyix == | 1834 | if (rs.rs_keyix == AR5K_RXKEYIX_INVALID && |
1803 | AR5K_RXKEYIX_INVALID && | 1835 | !(rs.rs_status & AR5K_RXERR_CRC)) |
1804 | !(stat & AR5K_RXERR_CRC)) | ||
1805 | goto accept; | 1836 | goto accept; |
1806 | } | 1837 | } |
1807 | if (stat & AR5K_RXERR_MIC) { | 1838 | if (rs.rs_status & AR5K_RXERR_MIC) { |
1808 | rxs.flag |= RX_FLAG_MMIC_ERROR; | 1839 | rxs.flag |= RX_FLAG_MMIC_ERROR; |
1809 | goto accept; | 1840 | goto accept; |
1810 | } | 1841 | } |
1811 | 1842 | ||
1812 | /* let crypto-error packets fall through in MNTR */ | 1843 | /* let crypto-error packets fall through in MNTR */ |
1813 | if ((stat & ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) || | 1844 | if ((rs.rs_status & |
1845 | ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) || | ||
1814 | sc->opmode != IEEE80211_IF_TYPE_MNTR) | 1846 | sc->opmode != IEEE80211_IF_TYPE_MNTR) |
1815 | goto next; | 1847 | goto next; |
1816 | } | 1848 | } |
1817 | accept: | 1849 | accept: |
1818 | len = ds->ds_rxstat.rs_datalen; | 1850 | pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, |
1819 | pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, len, | 1851 | rs.rs_datalen, PCI_DMA_FROMDEVICE); |
1820 | PCI_DMA_FROMDEVICE); | ||
1821 | pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, | 1852 | pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, |
1822 | PCI_DMA_FROMDEVICE); | 1853 | PCI_DMA_FROMDEVICE); |
1823 | bf->skb = NULL; | 1854 | bf->skb = NULL; |
1824 | 1855 | ||
1825 | skb_put(skb, len); | 1856 | skb_put(skb, rs.rs_datalen); |
1826 | 1857 | ||
1827 | /* | 1858 | /* |
1828 | * the hardware adds a padding to 4 byte boundaries between | 1859 | * the hardware adds a padding to 4 byte boundaries between |
@@ -1844,8 +1875,19 @@ accept: | |||
1844 | * 15bit only. that means TSF extension has to be done within | 1875 | * 15bit only. that means TSF extension has to be done within |
1845 | * 32768usec (about 32ms). it might be necessary to move this to | 1876 | * 32768usec (about 32ms). it might be necessary to move this to |
1846 | * the interrupt handler, like it is done in madwifi. | 1877 | * the interrupt handler, like it is done in madwifi. |
1878 | * | ||
1879 | * Unfortunately we don't know when the hardware takes the rx | ||
1880 | * timestamp (beginning of phy frame, data frame, end of rx?). | ||
1881 | * The only thing we know is that it is hardware specific... | ||
1882 | * On AR5213 it seems the rx timestamp is at the end of the | ||
1883 | * frame, but i'm not sure. | ||
1884 | * | ||
1885 | * NOTE: mac80211 defines mactime at the beginning of the first | ||
1886 | * data symbol. Since we don't have any time references it's | ||
1887 | * impossible to comply to that. This affects IBSS merge only | ||
1888 | * right now, so it's not too bad... | ||
1847 | */ | 1889 | */ |
1848 | rxs.mactime = ath5k_extend_tsf(sc->ah, ds->ds_rxstat.rs_tstamp); | 1890 | rxs.mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp); |
1849 | rxs.flag |= RX_FLAG_TSFT; | 1891 | rxs.flag |= RX_FLAG_TSFT; |
1850 | 1892 | ||
1851 | rxs.freq = sc->curchan->center_freq; | 1893 | rxs.freq = sc->curchan->center_freq; |
@@ -1859,26 +1901,25 @@ accept: | |||
1859 | /* noise floor in dBm, from the last noise calibration */ | 1901 | /* noise floor in dBm, from the last noise calibration */ |
1860 | rxs.noise = sc->ah->ah_noise_floor; | 1902 | rxs.noise = sc->ah->ah_noise_floor; |
1861 | /* signal level in dBm */ | 1903 | /* signal level in dBm */ |
1862 | rxs.ssi = rxs.noise + ds->ds_rxstat.rs_rssi; | 1904 | rxs.ssi = rxs.noise + rs.rs_rssi; |
1863 | /* | 1905 | /* |
1864 | * "signal" is actually displayed as Link Quality by iwconfig | 1906 | * "signal" is actually displayed as Link Quality by iwconfig |
1865 | * we provide a percentage based on rssi (assuming max rssi 64) | 1907 | * we provide a percentage based on rssi (assuming max rssi 64) |
1866 | */ | 1908 | */ |
1867 | rxs.signal = ds->ds_rxstat.rs_rssi * 100 / 64; | 1909 | rxs.signal = rs.rs_rssi * 100 / 64; |
1868 | 1910 | ||
1869 | rxs.antenna = ds->ds_rxstat.rs_antenna; | 1911 | rxs.antenna = rs.rs_antenna; |
1870 | rxs.rate_idx = ath5k_hw_to_driver_rix(sc, | 1912 | rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); |
1871 | ds->ds_rxstat.rs_rate); | 1913 | rxs.flag |= ath5k_rx_decrypted(sc, ds, skb, &rs); |
1872 | rxs.flag |= ath5k_rx_decrypted(sc, ds, skb); | ||
1873 | 1914 | ||
1874 | ath5k_debug_dump_skb(sc, skb, "RX ", 0); | 1915 | ath5k_debug_dump_skb(sc, skb, "RX ", 0); |
1875 | 1916 | ||
1876 | /* check beacons in IBSS mode */ | 1917 | /* check beacons in IBSS mode */ |
1877 | if (sc->opmode == IEEE80211_IF_TYPE_IBSS) | 1918 | if (sc->opmode == IEEE80211_IF_TYPE_IBSS) |
1878 | ath5k_check_ibss_hw_merge(sc, skb); | 1919 | ath5k_check_ibss_tsf(sc, skb, &rxs); |
1879 | 1920 | ||
1880 | __ieee80211_rx(sc->hw, skb, &rxs); | 1921 | __ieee80211_rx(sc->hw, skb, &rxs); |
1881 | sc->led_rxrate = ds->ds_rxstat.rs_rate; | 1922 | sc->led_rxrate = rs.rs_rate; |
1882 | ath5k_led_event(sc, ATH_LED_RX); | 1923 | ath5k_led_event(sc, ATH_LED_RX); |
1883 | next: | 1924 | next: |
1884 | list_move_tail(&bf->list, &sc->rxbuf); | 1925 | list_move_tail(&bf->list, &sc->rxbuf); |
@@ -1897,6 +1938,7 @@ static void | |||
1897 | ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) | 1938 | ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) |
1898 | { | 1939 | { |
1899 | struct ieee80211_tx_status txs = {}; | 1940 | struct ieee80211_tx_status txs = {}; |
1941 | struct ath5k_tx_status ts = {}; | ||
1900 | struct ath5k_buf *bf, *bf0; | 1942 | struct ath5k_buf *bf, *bf0; |
1901 | struct ath5k_desc *ds; | 1943 | struct ath5k_desc *ds; |
1902 | struct sk_buff *skb; | 1944 | struct sk_buff *skb; |
@@ -1909,7 +1951,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) | |||
1909 | /* TODO only one segment */ | 1951 | /* TODO only one segment */ |
1910 | pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr, | 1952 | pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr, |
1911 | sc->desc_len, PCI_DMA_FROMDEVICE); | 1953 | sc->desc_len, PCI_DMA_FROMDEVICE); |
1912 | ret = sc->ah->ah_proc_tx_desc(sc->ah, ds); | 1954 | ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); |
1913 | if (unlikely(ret == -EINPROGRESS)) | 1955 | if (unlikely(ret == -EINPROGRESS)) |
1914 | break; | 1956 | break; |
1915 | else if (unlikely(ret)) { | 1957 | else if (unlikely(ret)) { |
@@ -1924,17 +1966,16 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) | |||
1924 | PCI_DMA_TODEVICE); | 1966 | PCI_DMA_TODEVICE); |
1925 | 1967 | ||
1926 | txs.control = bf->ctl; | 1968 | txs.control = bf->ctl; |
1927 | txs.retry_count = ds->ds_txstat.ts_shortretry + | 1969 | txs.retry_count = ts.ts_shortretry + ts.ts_longretry / 6; |
1928 | ds->ds_txstat.ts_longretry / 6; | 1970 | if (unlikely(ts.ts_status)) { |
1929 | if (unlikely(ds->ds_txstat.ts_status)) { | ||
1930 | sc->ll_stats.dot11ACKFailureCount++; | 1971 | sc->ll_stats.dot11ACKFailureCount++; |
1931 | if (ds->ds_txstat.ts_status & AR5K_TXERR_XRETRY) | 1972 | if (ts.ts_status & AR5K_TXERR_XRETRY) |
1932 | txs.excessive_retries = 1; | 1973 | txs.excessive_retries = 1; |
1933 | else if (ds->ds_txstat.ts_status & AR5K_TXERR_FILT) | 1974 | else if (ts.ts_status & AR5K_TXERR_FILT) |
1934 | txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED; | 1975 | txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED; |
1935 | } else { | 1976 | } else { |
1936 | txs.flags |= IEEE80211_TX_STATUS_ACK; | 1977 | txs.flags |= IEEE80211_TX_STATUS_ACK; |
1937 | txs.ack_signal = ds->ds_txstat.ts_rssi; | 1978 | txs.ack_signal = ts.ts_rssi; |
1938 | } | 1979 | } |
1939 | 1980 | ||
1940 | ieee80211_tx_status(sc->hw, skb, &txs); | 1981 | ieee80211_tx_status(sc->hw, skb, &txs); |
@@ -2108,7 +2149,7 @@ ath5k_beacon_send(struct ath5k_softc *sc) | |||
2108 | * beacon timer registers. | 2149 | * beacon timer registers. |
2109 | * | 2150 | * |
2110 | * This is called in a variety of situations, e.g. when a beacon is received, | 2151 | * This is called in a variety of situations, e.g. when a beacon is received, |
2111 | * when a HW merge has been detected, but also when an new IBSS is created or | 2152 | * when a TSF update has been detected, but also when an new IBSS is created or |
2112 | * when we otherwise know we have to update the timers, but we keep it in this | 2153 | * when we otherwise know we have to update the timers, but we keep it in this |
2113 | * function to have it all together in one place. | 2154 | * function to have it all together in one place. |
2114 | */ | 2155 | */ |
@@ -2208,7 +2249,7 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) | |||
2208 | * another AP to associate with. | 2249 | * another AP to associate with. |
2209 | * | 2250 | * |
2210 | * In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA | 2251 | * In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA |
2211 | * interrupts to detect HW merges only. | 2252 | * interrupts to detect TSF updates only. |
2212 | * | 2253 | * |
2213 | * AP mode is missing. | 2254 | * AP mode is missing. |
2214 | */ | 2255 | */ |
@@ -2228,7 +2269,7 @@ ath5k_beacon_config(struct ath5k_softc *sc) | |||
2228 | * hardware send the beacons automatically. We have to load it | 2269 | * hardware send the beacons automatically. We have to load it |
2229 | * only once here. | 2270 | * only once here. |
2230 | * We use the SWBA interrupt only to keep track of the beacon | 2271 | * We use the SWBA interrupt only to keep track of the beacon |
2231 | * timers in order to detect HW merges (automatic TSF updates). | 2272 | * timers in order to detect automatic TSF updates. |
2232 | */ | 2273 | */ |
2233 | ath5k_beaconq_config(sc); | 2274 | ath5k_beaconq_config(sc); |
2234 | 2275 | ||
@@ -2441,8 +2482,8 @@ ath5k_intr(int irq, void *dev_id) | |||
2441 | * | 2482 | * |
2442 | * In IBSS mode we use this interrupt just to | 2483 | * In IBSS mode we use this interrupt just to |
2443 | * keep track of the next TBTT (target beacon | 2484 | * keep track of the next TBTT (target beacon |
2444 | * transmission time) in order to detect hardware | 2485 | * transmission time) in order to detect wether |
2445 | * merges (TSF updates). | 2486 | * automatic TSF updates happened. |
2446 | */ | 2487 | */ |
2447 | if (sc->opmode == IEEE80211_IF_TYPE_IBSS) { | 2488 | if (sc->opmode == IEEE80211_IF_TYPE_IBSS) { |
2448 | /* XXX: only if VEOL suppported */ | 2489 | /* XXX: only if VEOL suppported */ |
diff --git a/drivers/net/wireless/ath5k/debug.c b/drivers/net/wireless/ath5k/debug.c index 05bf4fb8f907..41d5fa34b544 100644 --- a/drivers/net/wireless/ath5k/debug.c +++ b/drivers/net/wireless/ath5k/debug.c | |||
@@ -200,7 +200,8 @@ static ssize_t read_file_tsf(struct file *file, char __user *user_buf, | |||
200 | { | 200 | { |
201 | struct ath5k_softc *sc = file->private_data; | 201 | struct ath5k_softc *sc = file->private_data; |
202 | char buf[100]; | 202 | char buf[100]; |
203 | snprintf(buf, sizeof(buf), "0x%016llx\n", ath5k_hw_get_tsf64(sc->ah)); | 203 | snprintf(buf, sizeof(buf), "0x%016llx\n", |
204 | (unsigned long long)ath5k_hw_get_tsf64(sc->ah)); | ||
204 | return simple_read_from_buffer(user_buf, count, ppos, buf, 19); | 205 | return simple_read_from_buffer(user_buf, count, ppos, buf, 19); |
205 | } | 206 | } |
206 | 207 | ||
@@ -271,7 +272,8 @@ static ssize_t read_file_beacon(struct file *file, char __user *user_buf, | |||
271 | 272 | ||
272 | tsf = ath5k_hw_get_tsf64(sc->ah); | 273 | tsf = ath5k_hw_get_tsf64(sc->ah); |
273 | len += snprintf(buf+len, sizeof(buf)-len, | 274 | len += snprintf(buf+len, sizeof(buf)-len, |
274 | "TSF\t\t0x%016llx\tTU: %08x\n", tsf, TSF_TO_TU(tsf)); | 275 | "TSF\t\t0x%016llx\tTU: %08x\n", |
276 | (unsigned long long)tsf, TSF_TO_TU(tsf)); | ||
275 | 277 | ||
276 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | 278 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); |
277 | } | 279 | } |
@@ -497,15 +499,18 @@ ath5k_debug_dump_bands(struct ath5k_softc *sc) | |||
497 | } | 499 | } |
498 | 500 | ||
499 | static inline void | 501 | static inline void |
500 | ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done) | 502 | ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done, |
503 | struct ath5k_rx_status *rs) | ||
501 | { | 504 | { |
502 | struct ath5k_desc *ds = bf->desc; | 505 | struct ath5k_desc *ds = bf->desc; |
506 | struct ath5k_hw_all_rx_desc *rd = &ds->ud.ds_rx; | ||
503 | 507 | ||
504 | printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n", | 508 | printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n", |
505 | ds, (unsigned long long)bf->daddr, | 509 | ds, (unsigned long long)bf->daddr, |
506 | ds->ds_link, ds->ds_data, ds->ds_ctl0, ds->ds_ctl1, | 510 | ds->ds_link, ds->ds_data, |
507 | ds->ds_hw[0], ds->ds_hw[1], | 511 | rd->rx_ctl.rx_control_0, rd->rx_ctl.rx_control_1, |
508 | !done ? ' ' : (ds->ds_rxstat.rs_status == 0) ? '*' : '!'); | 512 | rd->u.rx_stat.rx_status_0, rd->u.rx_stat.rx_status_0, |
513 | !done ? ' ' : (rs->rs_status == 0) ? '*' : '!'); | ||
509 | } | 514 | } |
510 | 515 | ||
511 | void | 516 | void |
@@ -513,6 +518,7 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) | |||
513 | { | 518 | { |
514 | struct ath5k_desc *ds; | 519 | struct ath5k_desc *ds; |
515 | struct ath5k_buf *bf; | 520 | struct ath5k_buf *bf; |
521 | struct ath5k_rx_status rs = {}; | ||
516 | int status; | 522 | int status; |
517 | 523 | ||
518 | if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) | 524 | if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) |
@@ -524,9 +530,9 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) | |||
524 | spin_lock_bh(&sc->rxbuflock); | 530 | spin_lock_bh(&sc->rxbuflock); |
525 | list_for_each_entry(bf, &sc->rxbuf, list) { | 531 | list_for_each_entry(bf, &sc->rxbuf, list) { |
526 | ds = bf->desc; | 532 | ds = bf->desc; |
527 | status = ah->ah_proc_rx_desc(ah, ds); | 533 | status = ah->ah_proc_rx_desc(ah, ds, &rs); |
528 | if (!status) | 534 | if (!status) |
529 | ath5k_debug_printrxbuf(bf, status == 0); | 535 | ath5k_debug_printrxbuf(bf, status == 0, &rs); |
530 | } | 536 | } |
531 | spin_unlock_bh(&sc->rxbuflock); | 537 | spin_unlock_bh(&sc->rxbuflock); |
532 | } | 538 | } |
@@ -550,19 +556,24 @@ ath5k_debug_dump_skb(struct ath5k_softc *sc, | |||
550 | } | 556 | } |
551 | 557 | ||
552 | void | 558 | void |
553 | ath5k_debug_printtxbuf(struct ath5k_softc *sc, | 559 | ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) |
554 | struct ath5k_buf *bf, int done) | ||
555 | { | 560 | { |
556 | struct ath5k_desc *ds = bf->desc; | 561 | struct ath5k_desc *ds = bf->desc; |
562 | struct ath5k_hw_5212_tx_desc *td = &ds->ud.ds_tx5212; | ||
563 | struct ath5k_tx_status ts = {}; | ||
564 | int done; | ||
557 | 565 | ||
558 | if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) | 566 | if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) |
559 | return; | 567 | return; |
560 | 568 | ||
569 | done = sc->ah->ah_proc_tx_desc(sc->ah, bf->desc, &ts); | ||
570 | |||
561 | printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x " | 571 | printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x " |
562 | "%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link, | 572 | "%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link, |
563 | ds->ds_data, ds->ds_ctl0, ds->ds_ctl1, | 573 | ds->ds_data, td->tx_ctl.tx_control_0, td->tx_ctl.tx_control_1, |
564 | ds->ds_hw[0], ds->ds_hw[1], ds->ds_hw[2], ds->ds_hw[3], | 574 | td->tx_ctl.tx_control_2, td->tx_ctl.tx_control_3, |
565 | !done ? ' ' : (ds->ds_txstat.ts_status == 0) ? '*' : '!'); | 575 | td->tx_stat.tx_status_0, td->tx_stat.tx_status_1, |
576 | done ? ' ' : (ts.ts_status == 0) ? '*' : '!'); | ||
566 | } | 577 | } |
567 | 578 | ||
568 | #endif /* ifdef CONFIG_ATH5K_DEBUG */ | 579 | #endif /* ifdef CONFIG_ATH5K_DEBUG */ |
diff --git a/drivers/net/wireless/ath5k/debug.h b/drivers/net/wireless/ath5k/debug.h index 8c0b5c57c76b..2cf8d18b10e3 100644 --- a/drivers/net/wireless/ath5k/debug.h +++ b/drivers/net/wireless/ath5k/debug.h | |||
@@ -160,8 +160,7 @@ ath5k_debug_dump_skb(struct ath5k_softc *sc, | |||
160 | struct sk_buff *skb, const char *prefix, int tx); | 160 | struct sk_buff *skb, const char *prefix, int tx); |
161 | 161 | ||
162 | void | 162 | void |
163 | ath5k_debug_printtxbuf(struct ath5k_softc *sc, | 163 | ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf); |
164 | struct ath5k_buf *bf, int done); | ||
165 | 164 | ||
166 | #else /* no debugging */ | 165 | #else /* no debugging */ |
167 | 166 | ||
@@ -199,8 +198,7 @@ ath5k_debug_dump_skb(struct ath5k_softc *sc, | |||
199 | struct sk_buff *skb, const char *prefix, int tx) {} | 198 | struct sk_buff *skb, const char *prefix, int tx) {} |
200 | 199 | ||
201 | static inline void | 200 | static inline void |
202 | ath5k_debug_printtxbuf(struct ath5k_softc *sc, | 201 | ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) {} |
203 | struct ath5k_buf *bf, int done) {} | ||
204 | 202 | ||
205 | #endif /* ifdef CONFIG_ATH5K_DEBUG */ | 203 | #endif /* ifdef CONFIG_ATH5K_DEBUG */ |
206 | 204 | ||
diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index eec2b806a0de..a4e312d4226e 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c | |||
@@ -48,14 +48,18 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *, struct ath5k_desc *, | |||
48 | static int ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *, struct ath5k_desc *, | 48 | static int ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *, struct ath5k_desc *, |
49 | unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, | 49 | unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, |
50 | unsigned int); | 50 | unsigned int); |
51 | static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *, struct ath5k_desc *); | 51 | static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *, struct ath5k_desc *, |
52 | struct ath5k_tx_status *); | ||
52 | static int ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *, struct ath5k_desc *, | 53 | static int ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *, struct ath5k_desc *, |
53 | unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, | 54 | unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, |
54 | unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, | 55 | unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, |
55 | unsigned int, unsigned int); | 56 | unsigned int, unsigned int); |
56 | static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *, struct ath5k_desc *); | 57 | static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *, struct ath5k_desc *, |
57 | static int ath5k_hw_proc_new_rx_status(struct ath5k_hw *, struct ath5k_desc *); | 58 | struct ath5k_tx_status *); |
58 | static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *, struct ath5k_desc *); | 59 | static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *, struct ath5k_desc *, |
60 | struct ath5k_rx_status *); | ||
61 | static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *, struct ath5k_desc *, | ||
62 | struct ath5k_rx_status *); | ||
59 | static int ath5k_hw_get_capabilities(struct ath5k_hw *); | 63 | static int ath5k_hw_get_capabilities(struct ath5k_hw *); |
60 | 64 | ||
61 | static int ath5k_eeprom_init(struct ath5k_hw *); | 65 | static int ath5k_eeprom_init(struct ath5k_hw *); |
@@ -174,9 +178,9 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) | |||
174 | } | 178 | } |
175 | 179 | ||
176 | if (ah->ah_version == AR5K_AR5212) | 180 | if (ah->ah_version == AR5K_AR5212) |
177 | ah->ah_proc_rx_desc = ath5k_hw_proc_new_rx_status; | 181 | ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status; |
178 | else if (ah->ah_version <= AR5K_AR5211) | 182 | else if (ah->ah_version <= AR5K_AR5211) |
179 | ah->ah_proc_rx_desc = ath5k_hw_proc_old_rx_status; | 183 | ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status; |
180 | 184 | ||
181 | /* Bring device out of sleep and reset it's units */ | 185 | /* Bring device out of sleep and reset it's units */ |
182 | ret = ath5k_hw_nic_wakeup(ah, AR5K_INIT_MODE, true); | 186 | ret = ath5k_hw_nic_wakeup(ah, AR5K_INIT_MODE, true); |
@@ -208,7 +212,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) | |||
208 | 212 | ||
209 | /* Identify single chip solutions */ | 213 | /* Identify single chip solutions */ |
210 | if((srev <= AR5K_SREV_VER_AR5414) && | 214 | if((srev <= AR5K_SREV_VER_AR5414) && |
211 | (srev >= AR5K_SREV_VER_AR2424)) { | 215 | (srev >= AR5K_SREV_VER_AR2413)) { |
212 | ah->ah_single_chip = true; | 216 | ah->ah_single_chip = true; |
213 | } else { | 217 | } else { |
214 | ah->ah_single_chip = false; | 218 | ah->ah_single_chip = false; |
@@ -223,10 +227,33 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) | |||
223 | ah->ah_radio = AR5K_RF5110; | 227 | ah->ah_radio = AR5K_RF5110; |
224 | } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) { | 228 | } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) { |
225 | ah->ah_radio = AR5K_RF5111; | 229 | ah->ah_radio = AR5K_RF5111; |
226 | } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) { | 230 | ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111; |
231 | } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC0) { | ||
232 | |||
227 | ah->ah_radio = AR5K_RF5112; | 233 | ah->ah_radio = AR5K_RF5112; |
234 | |||
235 | if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) { | ||
236 | ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112; | ||
237 | } else { | ||
238 | ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A; | ||
239 | } | ||
240 | |||
241 | } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) { | ||
242 | ah->ah_radio = AR5K_RF2413; | ||
243 | ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A; | ||
228 | } else { | 244 | } else { |
245 | |||
229 | ah->ah_radio = AR5K_RF5413; | 246 | ah->ah_radio = AR5K_RF5413; |
247 | |||
248 | if (ah->ah_mac_srev <= AR5K_SREV_VER_AR5424 && | ||
249 | ah->ah_mac_srev >= AR5K_SREV_VER_AR2424) | ||
250 | ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5424; | ||
251 | else if (ah->ah_mac_srev >= AR5K_SREV_VER_AR2425) | ||
252 | ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112; | ||
253 | else | ||
254 | ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A; | ||
255 | |||
256 | |||
230 | } | 257 | } |
231 | 258 | ||
232 | ah->ah_phy = AR5K_PHY(0); | 259 | ah->ah_phy = AR5K_PHY(0); |
@@ -277,7 +304,8 @@ err: | |||
277 | */ | 304 | */ |
278 | static int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) | 305 | static int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) |
279 | { | 306 | { |
280 | u32 turbo, mode, clock; | 307 | struct pci_dev *pdev = ah->ah_sc->pdev; |
308 | u32 turbo, mode, clock, bus_flags; | ||
281 | int ret; | 309 | int ret; |
282 | 310 | ||
283 | turbo = 0; | 311 | turbo = 0; |
@@ -354,9 +382,15 @@ static int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) | |||
354 | AR5K_PHY_TURBO); | 382 | AR5K_PHY_TURBO); |
355 | } | 383 | } |
356 | 384 | ||
357 | /* ...reset chipset and PCI device */ | 385 | /* reseting PCI on PCI-E cards results card to hang |
358 | if (ah->ah_single_chip == false && ath5k_hw_nic_reset(ah, | 386 | * and always return 0xffff... so we ingore that flag |
359 | AR5K_RESET_CTL_CHIP | AR5K_RESET_CTL_PCI)) { | 387 | * for PCI-E cards */ |
388 | bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; | ||
389 | |||
390 | /* Reset chipset */ | ||
391 | ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | | ||
392 | AR5K_RESET_CTL_BASEBAND | bus_flags); | ||
393 | if (ret) { | ||
360 | ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip + PCI\n"); | 394 | ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip + PCI\n"); |
361 | return -EIO; | 395 | return -EIO; |
362 | } | 396 | } |
@@ -565,7 +599,8 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, | |||
565 | struct ieee80211_channel *channel, bool change_channel) | 599 | struct ieee80211_channel *channel, bool change_channel) |
566 | { | 600 | { |
567 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | 601 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
568 | u32 data, s_seq, s_ant, s_led[3]; | 602 | struct pci_dev *pdev = ah->ah_sc->pdev; |
603 | u32 data, s_seq, s_ant, s_led[3], dma_size; | ||
569 | unsigned int i, mode, freq, ee_mode, ant[2]; | 604 | unsigned int i, mode, freq, ee_mode, ant[2]; |
570 | int ret; | 605 | int ret; |
571 | 606 | ||
@@ -617,7 +652,8 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, | |||
617 | if (ah->ah_version != AR5K_AR5210) { | 652 | if (ah->ah_version != AR5K_AR5210) { |
618 | if (ah->ah_radio != AR5K_RF5111 && | 653 | if (ah->ah_radio != AR5K_RF5111 && |
619 | ah->ah_radio != AR5K_RF5112 && | 654 | ah->ah_radio != AR5K_RF5112 && |
620 | ah->ah_radio != AR5K_RF5413) { | 655 | ah->ah_radio != AR5K_RF5413 && |
656 | ah->ah_radio != AR5K_RF2413) { | ||
621 | ATH5K_ERR(ah->ah_sc, | 657 | ATH5K_ERR(ah->ah_sc, |
622 | "invalid phy radio: %u\n", ah->ah_radio); | 658 | "invalid phy radio: %u\n", ah->ah_radio); |
623 | return -EINVAL; | 659 | return -EINVAL; |
@@ -692,15 +728,26 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, | |||
692 | /* | 728 | /* |
693 | * Write some more initial register settings | 729 | * Write some more initial register settings |
694 | */ | 730 | */ |
695 | if (ah->ah_version > AR5K_AR5211){ /* found on 5213+ */ | 731 | if (ah->ah_version == AR5K_AR5212) { |
696 | ath5k_hw_reg_write(ah, 0x0002a002, AR5K_PHY(11)); | 732 | ath5k_hw_reg_write(ah, 0x0002a002, AR5K_PHY(11)); |
697 | 733 | ||
698 | if (channel->hw_value == CHANNEL_G) | 734 | if (channel->hw_value == CHANNEL_G) |
699 | ath5k_hw_reg_write(ah, 0x00f80d80, AR5K_PHY(83)); /* 0x00fc0ec0 */ | 735 | if (ah->ah_mac_srev < AR5K_SREV_VER_AR2413) |
736 | ath5k_hw_reg_write(ah, 0x00f80d80, | ||
737 | AR5K_PHY(83)); | ||
738 | else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2424) | ||
739 | ath5k_hw_reg_write(ah, 0x00380140, | ||
740 | AR5K_PHY(83)); | ||
741 | else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2425) | ||
742 | ath5k_hw_reg_write(ah, 0x00fc0ec0, | ||
743 | AR5K_PHY(83)); | ||
744 | else /* 2425 */ | ||
745 | ath5k_hw_reg_write(ah, 0x00fc0fc0, | ||
746 | AR5K_PHY(83)); | ||
700 | else | 747 | else |
701 | ath5k_hw_reg_write(ah, 0x00000000, AR5K_PHY(83)); | 748 | ath5k_hw_reg_write(ah, 0x00000000, |
749 | AR5K_PHY(83)); | ||
702 | 750 | ||
703 | ath5k_hw_reg_write(ah, 0x000001b5, 0xa228); /* 0x000009b5 */ | ||
704 | ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); | 751 | ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); |
705 | ath5k_hw_reg_write(ah, 0x0000000f, 0x8060); | 752 | ath5k_hw_reg_write(ah, 0x0000000f, 0x8060); |
706 | ath5k_hw_reg_write(ah, 0x00000000, 0xa254); | 753 | ath5k_hw_reg_write(ah, 0x00000000, 0xa254); |
@@ -876,13 +923,24 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, | |||
876 | 923 | ||
877 | /* | 924 | /* |
878 | * Set Rx/Tx DMA Configuration | 925 | * Set Rx/Tx DMA Configuration |
879 | *(passing dma size not available on 5210) | 926 | * |
927 | * Set maximum DMA size (512) except for PCI-E cards since | ||
928 | * it causes rx overruns and tx errors (tested on 5424 but since | ||
929 | * rx overruns also occur on 5416/5418 with madwifi we set 128 | ||
930 | * for all PCI-E cards to be safe). | ||
931 | * | ||
932 | * In dumps this is 128 for allchips. | ||
933 | * | ||
934 | * XXX: need to check 5210 for this | ||
935 | * TODO: Check out tx triger level, it's always 64 on dumps but I | ||
936 | * guess we can tweak it and see how it goes ;-) | ||
880 | */ | 937 | */ |
938 | dma_size = (pdev->is_pcie) ? AR5K_DMASIZE_128B : AR5K_DMASIZE_512B; | ||
881 | if (ah->ah_version != AR5K_AR5210) { | 939 | if (ah->ah_version != AR5K_AR5210) { |
882 | AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_SDMAMR, | 940 | AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, |
883 | AR5K_DMASIZE_512B | AR5K_TXCFG_DMASIZE); | 941 | AR5K_TXCFG_SDMAMR, dma_size); |
884 | AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_SDMAMW, | 942 | AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, |
885 | AR5K_DMASIZE_512B); | 943 | AR5K_RXCFG_SDMAMW, dma_size); |
886 | } | 944 | } |
887 | 945 | ||
888 | /* | 946 | /* |
@@ -972,6 +1030,8 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, | |||
972 | 1030 | ||
973 | /* | 1031 | /* |
974 | * Set the 32MHz reference clock on 5212 phy clock sleep register | 1032 | * Set the 32MHz reference clock on 5212 phy clock sleep register |
1033 | * | ||
1034 | * TODO: Find out how to switch to external 32Khz clock to save power | ||
975 | */ | 1035 | */ |
976 | if (ah->ah_version == AR5K_AR5212) { | 1036 | if (ah->ah_version == AR5K_AR5212) { |
977 | ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR); | 1037 | ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR); |
@@ -979,9 +1039,15 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, | |||
979 | ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL); | 1039 | ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL); |
980 | ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK); | 1040 | ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK); |
981 | ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY); | 1041 | ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY); |
982 | ath5k_hw_reg_write(ah, ah->ah_radio == AR5K_RF5111 ? | 1042 | ath5k_hw_reg_write(ah, ah->ah_phy_spending, AR5K_PHY_SPENDING); |
983 | AR5K_PHY_SPENDING_RF5111 : AR5K_PHY_SPENDING_RF5112, | 1043 | } |
984 | AR5K_PHY_SPENDING); | 1044 | |
1045 | if (ah->ah_version == AR5K_AR5212) { | ||
1046 | ath5k_hw_reg_write(ah, 0x000100aa, 0x8118); | ||
1047 | ath5k_hw_reg_write(ah, 0x00003210, 0x811c); | ||
1048 | ath5k_hw_reg_write(ah, 0x00000052, 0x8108); | ||
1049 | if (ah->ah_mac_srev >= AR5K_SREV_VER_AR2413) | ||
1050 | ath5k_hw_reg_write(ah, 0x00000004, 0x8120); | ||
985 | } | 1051 | } |
986 | 1052 | ||
987 | /* | 1053 | /* |
@@ -2228,8 +2294,8 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) | |||
2228 | * Set simple BSSID mask on 5212 | 2294 | * Set simple BSSID mask on 5212 |
2229 | */ | 2295 | */ |
2230 | if (ah->ah_version == AR5K_AR5212) { | 2296 | if (ah->ah_version == AR5K_AR5212) { |
2231 | ath5k_hw_reg_write(ah, 0xfffffff, AR5K_BSS_IDM0); | 2297 | ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM0); |
2232 | ath5k_hw_reg_write(ah, 0xfffffff, AR5K_BSS_IDM1); | 2298 | ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM1); |
2233 | } | 2299 | } |
2234 | 2300 | ||
2235 | /* | 2301 | /* |
@@ -2374,6 +2440,8 @@ void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) | |||
2374 | { | 2440 | { |
2375 | ATH5K_TRACE(ah->ah_sc); | 2441 | ATH5K_TRACE(ah->ah_sc); |
2376 | AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); | 2442 | AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); |
2443 | |||
2444 | /* TODO: ANI Support */ | ||
2377 | } | 2445 | } |
2378 | 2446 | ||
2379 | /* | 2447 | /* |
@@ -2383,6 +2451,8 @@ void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah) | |||
2383 | { | 2451 | { |
2384 | ATH5K_TRACE(ah->ah_sc); | 2452 | ATH5K_TRACE(ah->ah_sc); |
2385 | AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); | 2453 | AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); |
2454 | |||
2455 | /* TODO: ANI Support */ | ||
2386 | } | 2456 | } |
2387 | 2457 | ||
2388 | /* | 2458 | /* |
@@ -3456,10 +3526,10 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, | |||
3456 | unsigned int rtscts_rate, unsigned int rtscts_duration) | 3526 | unsigned int rtscts_rate, unsigned int rtscts_duration) |
3457 | { | 3527 | { |
3458 | u32 frame_type; | 3528 | u32 frame_type; |
3459 | struct ath5k_hw_2w_tx_desc *tx_desc; | 3529 | struct ath5k_hw_2w_tx_ctl *tx_ctl; |
3460 | unsigned int frame_len; | 3530 | unsigned int frame_len; |
3461 | 3531 | ||
3462 | tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0; | 3532 | tx_ctl = &desc->ud.ds_tx5210.tx_ctl; |
3463 | 3533 | ||
3464 | /* | 3534 | /* |
3465 | * Validate input | 3535 | * Validate input |
@@ -3478,12 +3548,8 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, | |||
3478 | return -EINVAL; | 3548 | return -EINVAL; |
3479 | } | 3549 | } |
3480 | 3550 | ||
3481 | /* Clear status descriptor */ | 3551 | /* Clear descriptor */ |
3482 | memset(desc->ds_hw, 0, sizeof(struct ath5k_hw_tx_status)); | 3552 | memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc)); |
3483 | |||
3484 | /* Initialize control descriptor */ | ||
3485 | tx_desc->tx_control_0 = 0; | ||
3486 | tx_desc->tx_control_1 = 0; | ||
3487 | 3553 | ||
3488 | /* Setup control descriptor */ | 3554 | /* Setup control descriptor */ |
3489 | 3555 | ||
@@ -3495,7 +3561,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, | |||
3495 | if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) | 3561 | if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) |
3496 | return -EINVAL; | 3562 | return -EINVAL; |
3497 | 3563 | ||
3498 | tx_desc->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; | 3564 | tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; |
3499 | 3565 | ||
3500 | /* Verify and set buffer length */ | 3566 | /* Verify and set buffer length */ |
3501 | 3567 | ||
@@ -3506,7 +3572,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, | |||
3506 | if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN) | 3572 | if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN) |
3507 | return -EINVAL; | 3573 | return -EINVAL; |
3508 | 3574 | ||
3509 | tx_desc->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; | 3575 | tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; |
3510 | 3576 | ||
3511 | /* | 3577 | /* |
3512 | * Verify and set header length | 3578 | * Verify and set header length |
@@ -3515,7 +3581,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, | |||
3515 | if (ah->ah_version == AR5K_AR5210) { | 3581 | if (ah->ah_version == AR5K_AR5210) { |
3516 | if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN) | 3582 | if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN) |
3517 | return -EINVAL; | 3583 | return -EINVAL; |
3518 | tx_desc->tx_control_0 |= | 3584 | tx_ctl->tx_control_0 |= |
3519 | AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN); | 3585 | AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN); |
3520 | } | 3586 | } |
3521 | 3587 | ||
@@ -3531,19 +3597,19 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, | |||
3531 | frame_type = type /*<< 2 ?*/; | 3597 | frame_type = type /*<< 2 ?*/; |
3532 | } | 3598 | } |
3533 | 3599 | ||
3534 | tx_desc->tx_control_0 |= | 3600 | tx_ctl->tx_control_0 |= |
3535 | AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) | | 3601 | AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) | |
3536 | AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE); | 3602 | AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE); |
3537 | } else { | 3603 | } else { |
3538 | tx_desc->tx_control_0 |= | 3604 | tx_ctl->tx_control_0 |= |
3539 | AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) | | 3605 | AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) | |
3540 | AR5K_REG_SM(antenna_mode, AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT); | 3606 | AR5K_REG_SM(antenna_mode, AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT); |
3541 | tx_desc->tx_control_1 |= | 3607 | tx_ctl->tx_control_1 |= |
3542 | AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE); | 3608 | AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE); |
3543 | } | 3609 | } |
3544 | #define _TX_FLAGS(_c, _flag) \ | 3610 | #define _TX_FLAGS(_c, _flag) \ |
3545 | if (flags & AR5K_TXDESC_##_flag) \ | 3611 | if (flags & AR5K_TXDESC_##_flag) \ |
3546 | tx_desc->tx_control_##_c |= \ | 3612 | tx_ctl->tx_control_##_c |= \ |
3547 | AR5K_2W_TX_DESC_CTL##_c##_##_flag | 3613 | AR5K_2W_TX_DESC_CTL##_c##_##_flag |
3548 | 3614 | ||
3549 | _TX_FLAGS(0, CLRDMASK); | 3615 | _TX_FLAGS(0, CLRDMASK); |
@@ -3558,9 +3624,9 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, | |||
3558 | * WEP crap | 3624 | * WEP crap |
3559 | */ | 3625 | */ |
3560 | if (key_index != AR5K_TXKEYIX_INVALID) { | 3626 | if (key_index != AR5K_TXKEYIX_INVALID) { |
3561 | tx_desc->tx_control_0 |= | 3627 | tx_ctl->tx_control_0 |= |
3562 | AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; | 3628 | AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; |
3563 | tx_desc->tx_control_1 |= | 3629 | tx_ctl->tx_control_1 |= |
3564 | AR5K_REG_SM(key_index, | 3630 | AR5K_REG_SM(key_index, |
3565 | AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); | 3631 | AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); |
3566 | } | 3632 | } |
@@ -3570,7 +3636,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, | |||
3570 | */ | 3636 | */ |
3571 | if ((ah->ah_version == AR5K_AR5210) && | 3637 | if ((ah->ah_version == AR5K_AR5210) && |
3572 | (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA))) | 3638 | (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA))) |
3573 | tx_desc->tx_control_1 |= rtscts_duration & | 3639 | tx_ctl->tx_control_1 |= rtscts_duration & |
3574 | AR5K_2W_TX_DESC_CTL1_RTS_DURATION; | 3640 | AR5K_2W_TX_DESC_CTL1_RTS_DURATION; |
3575 | 3641 | ||
3576 | return 0; | 3642 | return 0; |
@@ -3586,13 +3652,11 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, | |||
3586 | unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate, | 3652 | unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate, |
3587 | unsigned int rtscts_duration) | 3653 | unsigned int rtscts_duration) |
3588 | { | 3654 | { |
3589 | struct ath5k_hw_4w_tx_desc *tx_desc; | 3655 | struct ath5k_hw_4w_tx_ctl *tx_ctl; |
3590 | struct ath5k_hw_tx_status *tx_status; | ||
3591 | unsigned int frame_len; | 3656 | unsigned int frame_len; |
3592 | 3657 | ||
3593 | ATH5K_TRACE(ah->ah_sc); | 3658 | ATH5K_TRACE(ah->ah_sc); |
3594 | tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0; | 3659 | tx_ctl = &desc->ud.ds_tx5212.tx_ctl; |
3595 | tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[2]; | ||
3596 | 3660 | ||
3597 | /* | 3661 | /* |
3598 | * Validate input | 3662 | * Validate input |
@@ -3611,14 +3675,8 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, | |||
3611 | return -EINVAL; | 3675 | return -EINVAL; |
3612 | } | 3676 | } |
3613 | 3677 | ||
3614 | /* Clear status descriptor */ | 3678 | /* Clear descriptor */ |
3615 | memset(tx_status, 0, sizeof(struct ath5k_hw_tx_status)); | 3679 | memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); |
3616 | |||
3617 | /* Initialize control descriptor */ | ||
3618 | tx_desc->tx_control_0 = 0; | ||
3619 | tx_desc->tx_control_1 = 0; | ||
3620 | tx_desc->tx_control_2 = 0; | ||
3621 | tx_desc->tx_control_3 = 0; | ||
3622 | 3680 | ||
3623 | /* Setup control descriptor */ | 3681 | /* Setup control descriptor */ |
3624 | 3682 | ||
@@ -3630,7 +3688,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, | |||
3630 | if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) | 3688 | if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) |
3631 | return -EINVAL; | 3689 | return -EINVAL; |
3632 | 3690 | ||
3633 | tx_desc->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; | 3691 | tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; |
3634 | 3692 | ||
3635 | /* Verify and set buffer length */ | 3693 | /* Verify and set buffer length */ |
3636 | 3694 | ||
@@ -3641,20 +3699,20 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, | |||
3641 | if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) | 3699 | if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) |
3642 | return -EINVAL; | 3700 | return -EINVAL; |
3643 | 3701 | ||
3644 | tx_desc->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; | 3702 | tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; |
3645 | 3703 | ||
3646 | tx_desc->tx_control_0 |= | 3704 | tx_ctl->tx_control_0 |= |
3647 | AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | | 3705 | AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | |
3648 | AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); | 3706 | AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); |
3649 | tx_desc->tx_control_1 |= AR5K_REG_SM(type, | 3707 | tx_ctl->tx_control_1 |= AR5K_REG_SM(type, |
3650 | AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); | 3708 | AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); |
3651 | tx_desc->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES, | 3709 | tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES, |
3652 | AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); | 3710 | AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); |
3653 | tx_desc->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; | 3711 | tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; |
3654 | 3712 | ||
3655 | #define _TX_FLAGS(_c, _flag) \ | 3713 | #define _TX_FLAGS(_c, _flag) \ |
3656 | if (flags & AR5K_TXDESC_##_flag) \ | 3714 | if (flags & AR5K_TXDESC_##_flag) \ |
3657 | tx_desc->tx_control_##_c |= \ | 3715 | tx_ctl->tx_control_##_c |= \ |
3658 | AR5K_4W_TX_DESC_CTL##_c##_##_flag | 3716 | AR5K_4W_TX_DESC_CTL##_c##_##_flag |
3659 | 3717 | ||
3660 | _TX_FLAGS(0, CLRDMASK); | 3718 | _TX_FLAGS(0, CLRDMASK); |
@@ -3670,8 +3728,8 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, | |||
3670 | * WEP crap | 3728 | * WEP crap |
3671 | */ | 3729 | */ |
3672 | if (key_index != AR5K_TXKEYIX_INVALID) { | 3730 | if (key_index != AR5K_TXKEYIX_INVALID) { |
3673 | tx_desc->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; | 3731 | tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; |
3674 | tx_desc->tx_control_1 |= AR5K_REG_SM(key_index, | 3732 | tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, |
3675 | AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); | 3733 | AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); |
3676 | } | 3734 | } |
3677 | 3735 | ||
@@ -3682,9 +3740,9 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, | |||
3682 | if ((flags & AR5K_TXDESC_RTSENA) && | 3740 | if ((flags & AR5K_TXDESC_RTSENA) && |
3683 | (flags & AR5K_TXDESC_CTSENA)) | 3741 | (flags & AR5K_TXDESC_CTSENA)) |
3684 | return -EINVAL; | 3742 | return -EINVAL; |
3685 | tx_desc->tx_control_2 |= rtscts_duration & | 3743 | tx_ctl->tx_control_2 |= rtscts_duration & |
3686 | AR5K_4W_TX_DESC_CTL2_RTS_DURATION; | 3744 | AR5K_4W_TX_DESC_CTL2_RTS_DURATION; |
3687 | tx_desc->tx_control_3 |= AR5K_REG_SM(rtscts_rate, | 3745 | tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate, |
3688 | AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); | 3746 | AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); |
3689 | } | 3747 | } |
3690 | 3748 | ||
@@ -3699,7 +3757,7 @@ ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, | |||
3699 | unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2, | 3757 | unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2, |
3700 | unsigned int tx_rate3, u_int tx_tries3) | 3758 | unsigned int tx_rate3, u_int tx_tries3) |
3701 | { | 3759 | { |
3702 | struct ath5k_hw_4w_tx_desc *tx_desc; | 3760 | struct ath5k_hw_4w_tx_ctl *tx_ctl; |
3703 | 3761 | ||
3704 | /* | 3762 | /* |
3705 | * Rates can be 0 as long as the retry count is 0 too. | 3763 | * Rates can be 0 as long as the retry count is 0 too. |
@@ -3716,14 +3774,14 @@ ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, | |||
3716 | } | 3774 | } |
3717 | 3775 | ||
3718 | if (ah->ah_version == AR5K_AR5212) { | 3776 | if (ah->ah_version == AR5K_AR5212) { |
3719 | tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0; | 3777 | tx_ctl = &desc->ud.ds_tx5212.tx_ctl; |
3720 | 3778 | ||
3721 | #define _XTX_TRIES(_n) \ | 3779 | #define _XTX_TRIES(_n) \ |
3722 | if (tx_tries##_n) { \ | 3780 | if (tx_tries##_n) { \ |
3723 | tx_desc->tx_control_2 |= \ | 3781 | tx_ctl->tx_control_2 |= \ |
3724 | AR5K_REG_SM(tx_tries##_n, \ | 3782 | AR5K_REG_SM(tx_tries##_n, \ |
3725 | AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n); \ | 3783 | AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n); \ |
3726 | tx_desc->tx_control_3 |= \ | 3784 | tx_ctl->tx_control_3 |= \ |
3727 | AR5K_REG_SM(tx_rate##_n, \ | 3785 | AR5K_REG_SM(tx_rate##_n, \ |
3728 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n); \ | 3786 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n); \ |
3729 | } | 3787 | } |
@@ -3744,13 +3802,15 @@ ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, | |||
3744 | * Proccess the tx status descriptor on 5210/5211 | 3802 | * Proccess the tx status descriptor on 5210/5211 |
3745 | */ | 3803 | */ |
3746 | static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, | 3804 | static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, |
3747 | struct ath5k_desc *desc) | 3805 | struct ath5k_desc *desc, struct ath5k_tx_status *ts) |
3748 | { | 3806 | { |
3807 | struct ath5k_hw_2w_tx_ctl *tx_ctl; | ||
3749 | struct ath5k_hw_tx_status *tx_status; | 3808 | struct ath5k_hw_tx_status *tx_status; |
3750 | struct ath5k_hw_2w_tx_desc *tx_desc; | ||
3751 | 3809 | ||
3752 | tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0; | 3810 | ATH5K_TRACE(ah->ah_sc); |
3753 | tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[0]; | 3811 | |
3812 | tx_ctl = &desc->ud.ds_tx5210.tx_ctl; | ||
3813 | tx_status = &desc->ud.ds_tx5210.tx_stat; | ||
3754 | 3814 | ||
3755 | /* No frame has been send or error */ | 3815 | /* No frame has been send or error */ |
3756 | if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) | 3816 | if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) |
@@ -3759,32 +3819,32 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, | |||
3759 | /* | 3819 | /* |
3760 | * Get descriptor status | 3820 | * Get descriptor status |
3761 | */ | 3821 | */ |
3762 | desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, | 3822 | ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, |
3763 | AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); | 3823 | AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); |
3764 | desc->ds_us.tx.ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, | 3824 | ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, |
3765 | AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); | 3825 | AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); |
3766 | desc->ds_us.tx.ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, | 3826 | ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, |
3767 | AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); | 3827 | AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); |
3768 | /*TODO: desc->ds_us.tx.ts_virtcol + test*/ | 3828 | /*TODO: ts->ts_virtcol + test*/ |
3769 | desc->ds_us.tx.ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, | 3829 | ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, |
3770 | AR5K_DESC_TX_STATUS1_SEQ_NUM); | 3830 | AR5K_DESC_TX_STATUS1_SEQ_NUM); |
3771 | desc->ds_us.tx.ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, | 3831 | ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, |
3772 | AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); | 3832 | AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); |
3773 | desc->ds_us.tx.ts_antenna = 1; | 3833 | ts->ts_antenna = 1; |
3774 | desc->ds_us.tx.ts_status = 0; | 3834 | ts->ts_status = 0; |
3775 | desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_0, | 3835 | ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_0, |
3776 | AR5K_2W_TX_DESC_CTL0_XMIT_RATE); | 3836 | AR5K_2W_TX_DESC_CTL0_XMIT_RATE); |
3777 | 3837 | ||
3778 | if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){ | 3838 | if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){ |
3779 | if (tx_status->tx_status_0 & | 3839 | if (tx_status->tx_status_0 & |
3780 | AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) | 3840 | AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) |
3781 | desc->ds_us.tx.ts_status |= AR5K_TXERR_XRETRY; | 3841 | ts->ts_status |= AR5K_TXERR_XRETRY; |
3782 | 3842 | ||
3783 | if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) | 3843 | if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) |
3784 | desc->ds_us.tx.ts_status |= AR5K_TXERR_FIFO; | 3844 | ts->ts_status |= AR5K_TXERR_FIFO; |
3785 | 3845 | ||
3786 | if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) | 3846 | if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) |
3787 | desc->ds_us.tx.ts_status |= AR5K_TXERR_FILT; | 3847 | ts->ts_status |= AR5K_TXERR_FILT; |
3788 | } | 3848 | } |
3789 | 3849 | ||
3790 | return 0; | 3850 | return 0; |
@@ -3794,14 +3854,15 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, | |||
3794 | * Proccess a tx descriptor on 5212 | 3854 | * Proccess a tx descriptor on 5212 |
3795 | */ | 3855 | */ |
3796 | static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, | 3856 | static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, |
3797 | struct ath5k_desc *desc) | 3857 | struct ath5k_desc *desc, struct ath5k_tx_status *ts) |
3798 | { | 3858 | { |
3859 | struct ath5k_hw_4w_tx_ctl *tx_ctl; | ||
3799 | struct ath5k_hw_tx_status *tx_status; | 3860 | struct ath5k_hw_tx_status *tx_status; |
3800 | struct ath5k_hw_4w_tx_desc *tx_desc; | ||
3801 | 3861 | ||
3802 | ATH5K_TRACE(ah->ah_sc); | 3862 | ATH5K_TRACE(ah->ah_sc); |
3803 | tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0; | 3863 | |
3804 | tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[2]; | 3864 | tx_ctl = &desc->ud.ds_tx5212.tx_ctl; |
3865 | tx_status = &desc->ud.ds_tx5212.tx_stat; | ||
3805 | 3866 | ||
3806 | /* No frame has been send or error */ | 3867 | /* No frame has been send or error */ |
3807 | if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) | 3868 | if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) |
@@ -3810,42 +3871,42 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, | |||
3810 | /* | 3871 | /* |
3811 | * Get descriptor status | 3872 | * Get descriptor status |
3812 | */ | 3873 | */ |
3813 | desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, | 3874 | ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, |
3814 | AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); | 3875 | AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); |
3815 | desc->ds_us.tx.ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, | 3876 | ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, |
3816 | AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); | 3877 | AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); |
3817 | desc->ds_us.tx.ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, | 3878 | ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, |
3818 | AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); | 3879 | AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); |
3819 | desc->ds_us.tx.ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, | 3880 | ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, |
3820 | AR5K_DESC_TX_STATUS1_SEQ_NUM); | 3881 | AR5K_DESC_TX_STATUS1_SEQ_NUM); |
3821 | desc->ds_us.tx.ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, | 3882 | ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, |
3822 | AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); | 3883 | AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); |
3823 | desc->ds_us.tx.ts_antenna = (tx_status->tx_status_1 & | 3884 | ts->ts_antenna = (tx_status->tx_status_1 & |
3824 | AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1; | 3885 | AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1; |
3825 | desc->ds_us.tx.ts_status = 0; | 3886 | ts->ts_status = 0; |
3826 | 3887 | ||
3827 | switch (AR5K_REG_MS(tx_status->tx_status_1, | 3888 | switch (AR5K_REG_MS(tx_status->tx_status_1, |
3828 | AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) { | 3889 | AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) { |
3829 | case 0: | 3890 | case 0: |
3830 | desc->ds_us.tx.ts_rate = tx_desc->tx_control_3 & | 3891 | ts->ts_rate = tx_ctl->tx_control_3 & |
3831 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; | 3892 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; |
3832 | break; | 3893 | break; |
3833 | case 1: | 3894 | case 1: |
3834 | desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3, | 3895 | ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, |
3835 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); | 3896 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); |
3836 | desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2, | 3897 | ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, |
3837 | AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); | 3898 | AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); |
3838 | break; | 3899 | break; |
3839 | case 2: | 3900 | case 2: |
3840 | desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3, | 3901 | ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, |
3841 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); | 3902 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); |
3842 | desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2, | 3903 | ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, |
3843 | AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); | 3904 | AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); |
3844 | break; | 3905 | break; |
3845 | case 3: | 3906 | case 3: |
3846 | desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3, | 3907 | ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, |
3847 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); | 3908 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); |
3848 | desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2, | 3909 | ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, |
3849 | AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3); | 3910 | AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3); |
3850 | break; | 3911 | break; |
3851 | } | 3912 | } |
@@ -3853,13 +3914,13 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, | |||
3853 | if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){ | 3914 | if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){ |
3854 | if (tx_status->tx_status_0 & | 3915 | if (tx_status->tx_status_0 & |
3855 | AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) | 3916 | AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) |
3856 | desc->ds_us.tx.ts_status |= AR5K_TXERR_XRETRY; | 3917 | ts->ts_status |= AR5K_TXERR_XRETRY; |
3857 | 3918 | ||
3858 | if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) | 3919 | if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) |
3859 | desc->ds_us.tx.ts_status |= AR5K_TXERR_FIFO; | 3920 | ts->ts_status |= AR5K_TXERR_FIFO; |
3860 | 3921 | ||
3861 | if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) | 3922 | if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) |
3862 | desc->ds_us.tx.ts_status |= AR5K_TXERR_FILT; | 3923 | ts->ts_status |= AR5K_TXERR_FILT; |
3863 | } | 3924 | } |
3864 | 3925 | ||
3865 | return 0; | 3926 | return 0; |
@@ -3875,31 +3936,27 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, | |||
3875 | int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, | 3936 | int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, |
3876 | u32 size, unsigned int flags) | 3937 | u32 size, unsigned int flags) |
3877 | { | 3938 | { |
3878 | struct ath5k_rx_desc *rx_desc; | 3939 | struct ath5k_hw_rx_ctl *rx_ctl; |
3879 | 3940 | ||
3880 | ATH5K_TRACE(ah->ah_sc); | 3941 | ATH5K_TRACE(ah->ah_sc); |
3881 | rx_desc = (struct ath5k_rx_desc *)&desc->ds_ctl0; | 3942 | rx_ctl = &desc->ud.ds_rx.rx_ctl; |
3882 | 3943 | ||
3883 | /* | 3944 | /* |
3884 | *Clear ds_hw | 3945 | * Clear the descriptor |
3885 | * If we don't clean the status descriptor, | 3946 | * If we don't clean the status descriptor, |
3886 | * while scanning we get too many results, | 3947 | * while scanning we get too many results, |
3887 | * most of them virtual, after some secs | 3948 | * most of them virtual, after some secs |
3888 | * of scanning system hangs. M.F. | 3949 | * of scanning system hangs. M.F. |
3889 | */ | 3950 | */ |
3890 | memset(desc->ds_hw, 0, sizeof(desc->ds_hw)); | 3951 | memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc)); |
3891 | |||
3892 | /*Initialize rx descriptor*/ | ||
3893 | rx_desc->rx_control_0 = 0; | ||
3894 | rx_desc->rx_control_1 = 0; | ||
3895 | 3952 | ||
3896 | /* Setup descriptor */ | 3953 | /* Setup descriptor */ |
3897 | rx_desc->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN; | 3954 | rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN; |
3898 | if (unlikely(rx_desc->rx_control_1 != size)) | 3955 | if (unlikely(rx_ctl->rx_control_1 != size)) |
3899 | return -EINVAL; | 3956 | return -EINVAL; |
3900 | 3957 | ||
3901 | if (flags & AR5K_RXDESC_INTREQ) | 3958 | if (flags & AR5K_RXDESC_INTREQ) |
3902 | rx_desc->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ; | 3959 | rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ; |
3903 | 3960 | ||
3904 | return 0; | 3961 | return 0; |
3905 | } | 3962 | } |
@@ -3907,67 +3964,68 @@ int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, | |||
3907 | /* | 3964 | /* |
3908 | * Proccess the rx status descriptor on 5210/5211 | 3965 | * Proccess the rx status descriptor on 5210/5211 |
3909 | */ | 3966 | */ |
3910 | static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *ah, | 3967 | static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, |
3911 | struct ath5k_desc *desc) | 3968 | struct ath5k_desc *desc, struct ath5k_rx_status *rs) |
3912 | { | 3969 | { |
3913 | struct ath5k_hw_old_rx_status *rx_status; | 3970 | struct ath5k_hw_rx_status *rx_status; |
3914 | 3971 | ||
3915 | rx_status = (struct ath5k_hw_old_rx_status *)&desc->ds_hw[0]; | 3972 | rx_status = &desc->ud.ds_rx.u.rx_stat; |
3916 | 3973 | ||
3917 | /* No frame received / not ready */ | 3974 | /* No frame received / not ready */ |
3918 | if (unlikely((rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_DONE) | 3975 | if (unlikely((rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_DONE) |
3919 | == 0)) | 3976 | == 0)) |
3920 | return -EINPROGRESS; | 3977 | return -EINPROGRESS; |
3921 | 3978 | ||
3922 | /* | 3979 | /* |
3923 | * Frame receive status | 3980 | * Frame receive status |
3924 | */ | 3981 | */ |
3925 | desc->ds_us.rx.rs_datalen = rx_status->rx_status_0 & | 3982 | rs->rs_datalen = rx_status->rx_status_0 & |
3926 | AR5K_OLD_RX_DESC_STATUS0_DATA_LEN; | 3983 | AR5K_5210_RX_DESC_STATUS0_DATA_LEN; |
3927 | desc->ds_us.rx.rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, | 3984 | rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, |
3928 | AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL); | 3985 | AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL); |
3929 | desc->ds_us.rx.rs_rate = AR5K_REG_MS(rx_status->rx_status_0, | 3986 | rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, |
3930 | AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE); | 3987 | AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE); |
3931 | desc->ds_us.rx.rs_antenna = rx_status->rx_status_0 & | 3988 | rs->rs_antenna = rx_status->rx_status_0 & |
3932 | AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA; | 3989 | AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA; |
3933 | desc->ds_us.rx.rs_more = rx_status->rx_status_0 & | 3990 | rs->rs_more = rx_status->rx_status_0 & |
3934 | AR5K_OLD_RX_DESC_STATUS0_MORE; | 3991 | AR5K_5210_RX_DESC_STATUS0_MORE; |
3935 | desc->ds_us.rx.rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, | 3992 | /* TODO: this timestamp is 13 bit, later on we assume 15 bit */ |
3936 | AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); | 3993 | rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, |
3937 | desc->ds_us.rx.rs_status = 0; | 3994 | AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); |
3995 | rs->rs_status = 0; | ||
3938 | 3996 | ||
3939 | /* | 3997 | /* |
3940 | * Key table status | 3998 | * Key table status |
3941 | */ | 3999 | */ |
3942 | if (rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_VALID) | 4000 | if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID) |
3943 | desc->ds_us.rx.rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, | 4001 | rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, |
3944 | AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX); | 4002 | AR5K_5210_RX_DESC_STATUS1_KEY_INDEX); |
3945 | else | 4003 | else |
3946 | desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID; | 4004 | rs->rs_keyix = AR5K_RXKEYIX_INVALID; |
3947 | 4005 | ||
3948 | /* | 4006 | /* |
3949 | * Receive/descriptor errors | 4007 | * Receive/descriptor errors |
3950 | */ | 4008 | */ |
3951 | if ((rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_FRAME_RECEIVE_OK) | 4009 | if ((rx_status->rx_status_1 & |
3952 | == 0) { | 4010 | AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) { |
3953 | if (rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_CRC_ERROR) | 4011 | if (rx_status->rx_status_1 & |
3954 | desc->ds_us.rx.rs_status |= AR5K_RXERR_CRC; | 4012 | AR5K_5210_RX_DESC_STATUS1_CRC_ERROR) |
4013 | rs->rs_status |= AR5K_RXERR_CRC; | ||
3955 | 4014 | ||
3956 | if (rx_status->rx_status_1 & | 4015 | if (rx_status->rx_status_1 & |
3957 | AR5K_OLD_RX_DESC_STATUS1_FIFO_OVERRUN) | 4016 | AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN) |
3958 | desc->ds_us.rx.rs_status |= AR5K_RXERR_FIFO; | 4017 | rs->rs_status |= AR5K_RXERR_FIFO; |
3959 | 4018 | ||
3960 | if (rx_status->rx_status_1 & | 4019 | if (rx_status->rx_status_1 & |
3961 | AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR) { | 4020 | AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) { |
3962 | desc->ds_us.rx.rs_status |= AR5K_RXERR_PHY; | 4021 | rs->rs_status |= AR5K_RXERR_PHY; |
3963 | desc->ds_us.rx.rs_phyerr = | 4022 | rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1, |
3964 | AR5K_REG_MS(rx_status->rx_status_1, | 4023 | AR5K_5210_RX_DESC_STATUS1_PHY_ERROR); |
3965 | AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR); | ||
3966 | } | 4024 | } |
3967 | 4025 | ||
3968 | if (rx_status->rx_status_1 & | 4026 | if (rx_status->rx_status_1 & |
3969 | AR5K_OLD_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) | 4027 | AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) |
3970 | desc->ds_us.rx.rs_status |= AR5K_RXERR_DECRYPT; | 4028 | rs->rs_status |= AR5K_RXERR_DECRYPT; |
3971 | } | 4029 | } |
3972 | 4030 | ||
3973 | return 0; | 4031 | return 0; |
@@ -3976,71 +4034,72 @@ static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *ah, | |||
3976 | /* | 4034 | /* |
3977 | * Proccess the rx status descriptor on 5212 | 4035 | * Proccess the rx status descriptor on 5212 |
3978 | */ | 4036 | */ |
3979 | static int ath5k_hw_proc_new_rx_status(struct ath5k_hw *ah, | 4037 | static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, |
3980 | struct ath5k_desc *desc) | 4038 | struct ath5k_desc *desc, struct ath5k_rx_status *rs) |
3981 | { | 4039 | { |
3982 | struct ath5k_hw_new_rx_status *rx_status; | 4040 | struct ath5k_hw_rx_status *rx_status; |
3983 | struct ath5k_hw_rx_error *rx_err; | 4041 | struct ath5k_hw_rx_error *rx_err; |
3984 | 4042 | ||
3985 | ATH5K_TRACE(ah->ah_sc); | 4043 | ATH5K_TRACE(ah->ah_sc); |
3986 | rx_status = (struct ath5k_hw_new_rx_status *)&desc->ds_hw[0]; | 4044 | rx_status = &desc->ud.ds_rx.u.rx_stat; |
3987 | 4045 | ||
3988 | /* Overlay on error */ | 4046 | /* Overlay on error */ |
3989 | rx_err = (struct ath5k_hw_rx_error *)&desc->ds_hw[0]; | 4047 | rx_err = &desc->ud.ds_rx.u.rx_err; |
3990 | 4048 | ||
3991 | /* No frame received / not ready */ | 4049 | /* No frame received / not ready */ |
3992 | if (unlikely((rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_DONE) | 4050 | if (unlikely((rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_DONE) |
3993 | == 0)) | 4051 | == 0)) |
3994 | return -EINPROGRESS; | 4052 | return -EINPROGRESS; |
3995 | 4053 | ||
3996 | /* | 4054 | /* |
3997 | * Frame receive status | 4055 | * Frame receive status |
3998 | */ | 4056 | */ |
3999 | desc->ds_us.rx.rs_datalen = rx_status->rx_status_0 & | 4057 | rs->rs_datalen = rx_status->rx_status_0 & |
4000 | AR5K_NEW_RX_DESC_STATUS0_DATA_LEN; | 4058 | AR5K_5212_RX_DESC_STATUS0_DATA_LEN; |
4001 | desc->ds_us.rx.rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, | 4059 | rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, |
4002 | AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL); | 4060 | AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL); |
4003 | desc->ds_us.rx.rs_rate = AR5K_REG_MS(rx_status->rx_status_0, | 4061 | rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, |
4004 | AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE); | 4062 | AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE); |
4005 | desc->ds_us.rx.rs_antenna = rx_status->rx_status_0 & | 4063 | rs->rs_antenna = rx_status->rx_status_0 & |
4006 | AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA; | 4064 | AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA; |
4007 | desc->ds_us.rx.rs_more = rx_status->rx_status_0 & | 4065 | rs->rs_more = rx_status->rx_status_0 & |
4008 | AR5K_NEW_RX_DESC_STATUS0_MORE; | 4066 | AR5K_5212_RX_DESC_STATUS0_MORE; |
4009 | desc->ds_us.rx.rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, | 4067 | rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, |
4010 | AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); | 4068 | AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); |
4011 | desc->ds_us.rx.rs_status = 0; | 4069 | rs->rs_status = 0; |
4012 | 4070 | ||
4013 | /* | 4071 | /* |
4014 | * Key table status | 4072 | * Key table status |
4015 | */ | 4073 | */ |
4016 | if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID) | 4074 | if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) |
4017 | desc->ds_us.rx.rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, | 4075 | rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, |
4018 | AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX); | 4076 | AR5K_5212_RX_DESC_STATUS1_KEY_INDEX); |
4019 | else | 4077 | else |
4020 | desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID; | 4078 | rs->rs_keyix = AR5K_RXKEYIX_INVALID; |
4021 | 4079 | ||
4022 | /* | 4080 | /* |
4023 | * Receive/descriptor errors | 4081 | * Receive/descriptor errors |
4024 | */ | 4082 | */ |
4025 | if ((rx_status->rx_status_1 & | 4083 | if ((rx_status->rx_status_1 & |
4026 | AR5K_NEW_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) { | 4084 | AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) { |
4027 | if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR) | 4085 | if (rx_status->rx_status_1 & |
4028 | desc->ds_us.rx.rs_status |= AR5K_RXERR_CRC; | 4086 | AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) |
4087 | rs->rs_status |= AR5K_RXERR_CRC; | ||
4029 | 4088 | ||
4030 | if (rx_status->rx_status_1 & | 4089 | if (rx_status->rx_status_1 & |
4031 | AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR) { | 4090 | AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { |
4032 | desc->ds_us.rx.rs_status |= AR5K_RXERR_PHY; | 4091 | rs->rs_status |= AR5K_RXERR_PHY; |
4033 | desc->ds_us.rx.rs_phyerr = | 4092 | rs->rs_phyerr = AR5K_REG_MS(rx_err->rx_error_1, |
4034 | AR5K_REG_MS(rx_err->rx_error_1, | 4093 | AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE); |
4035 | AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE); | ||
4036 | } | 4094 | } |
4037 | 4095 | ||
4038 | if (rx_status->rx_status_1 & | 4096 | if (rx_status->rx_status_1 & |
4039 | AR5K_NEW_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) | 4097 | AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) |
4040 | desc->ds_us.rx.rs_status |= AR5K_RXERR_DECRYPT; | 4098 | rs->rs_status |= AR5K_RXERR_DECRYPT; |
4041 | 4099 | ||
4042 | if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_MIC_ERROR) | 4100 | if (rx_status->rx_status_1 & |
4043 | desc->ds_us.rx.rs_status |= AR5K_RXERR_MIC; | 4101 | AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) |
4102 | rs->rs_status |= AR5K_RXERR_MIC; | ||
4044 | } | 4103 | } |
4045 | 4104 | ||
4046 | return 0; | 4105 | return 0; |
diff --git a/drivers/net/wireless/ath5k/hw.h b/drivers/net/wireless/ath5k/hw.h index d9a7c0973f53..64fca8dcb386 100644 --- a/drivers/net/wireless/ath5k/hw.h +++ b/drivers/net/wireless/ath5k/hw.h | |||
@@ -173,7 +173,10 @@ struct ath5k_eeprom_info { | |||
173 | * (rX: reserved fields possibily used by future versions of the ar5k chipset) | 173 | * (rX: reserved fields possibily used by future versions of the ar5k chipset) |
174 | */ | 174 | */ |
175 | 175 | ||
176 | struct ath5k_rx_desc { | 176 | /* |
177 | * common hardware RX control descriptor | ||
178 | */ | ||
179 | struct ath5k_hw_rx_ctl { | ||
177 | u32 rx_control_0; /* RX control word 0 */ | 180 | u32 rx_control_0; /* RX control word 0 */ |
178 | 181 | ||
179 | #define AR5K_DESC_RX_CTL0 0x00000000 | 182 | #define AR5K_DESC_RX_CTL0 0x00000000 |
@@ -185,69 +188,63 @@ struct ath5k_rx_desc { | |||
185 | } __packed; | 188 | } __packed; |
186 | 189 | ||
187 | /* | 190 | /* |
188 | * 5210/5211 rx status descriptor | 191 | * common hardware RX status descriptor |
192 | * 5210/11 and 5212 differ only in the flags defined below | ||
189 | */ | 193 | */ |
190 | struct ath5k_hw_old_rx_status { | 194 | struct ath5k_hw_rx_status { |
191 | u32 rx_status_0; /* RX status word 0 */ | 195 | u32 rx_status_0; /* RX status word 0 */ |
192 | |||
193 | #define AR5K_OLD_RX_DESC_STATUS0_DATA_LEN 0x00000fff | ||
194 | #define AR5K_OLD_RX_DESC_STATUS0_MORE 0x00001000 | ||
195 | #define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE 0x00078000 | ||
196 | #define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE_S 15 | ||
197 | #define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x07f80000 | ||
198 | #define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 19 | ||
199 | #define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA 0x38000000 | ||
200 | #define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 27 | ||
201 | |||
202 | u32 rx_status_1; /* RX status word 1 */ | 196 | u32 rx_status_1; /* RX status word 1 */ |
203 | |||
204 | #define AR5K_OLD_RX_DESC_STATUS1_DONE 0x00000001 | ||
205 | #define AR5K_OLD_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 | ||
206 | #define AR5K_OLD_RX_DESC_STATUS1_CRC_ERROR 0x00000004 | ||
207 | #define AR5K_OLD_RX_DESC_STATUS1_FIFO_OVERRUN 0x00000008 | ||
208 | #define AR5K_OLD_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000010 | ||
209 | #define AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR 0x000000e0 | ||
210 | #define AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR_S 5 | ||
211 | #define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 | ||
212 | #define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX 0x00007e00 | ||
213 | #define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_S 9 | ||
214 | #define AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x0fff8000 | ||
215 | #define AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 15 | ||
216 | #define AR5K_OLD_RX_DESC_STATUS1_KEY_CACHE_MISS 0x10000000 | ||
217 | } __packed; | 197 | } __packed; |
218 | 198 | ||
199 | /* 5210/5211 */ | ||
200 | #define AR5K_5210_RX_DESC_STATUS0_DATA_LEN 0x00000fff | ||
201 | #define AR5K_5210_RX_DESC_STATUS0_MORE 0x00001000 | ||
202 | #define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE 0x00078000 | ||
203 | #define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE_S 15 | ||
204 | #define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x07f80000 | ||
205 | #define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 19 | ||
206 | #define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA 0x38000000 | ||
207 | #define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 27 | ||
208 | #define AR5K_5210_RX_DESC_STATUS1_DONE 0x00000001 | ||
209 | #define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 | ||
210 | #define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR 0x00000004 | ||
211 | #define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN 0x00000008 | ||
212 | #define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000010 | ||
213 | #define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR 0x000000e0 | ||
214 | #define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR_S 5 | ||
215 | #define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 | ||
216 | #define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX 0x00007e00 | ||
217 | #define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_S 9 | ||
218 | #define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x0fff8000 | ||
219 | #define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 15 | ||
220 | #define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS 0x10000000 | ||
221 | |||
222 | /* 5212 */ | ||
223 | #define AR5K_5212_RX_DESC_STATUS0_DATA_LEN 0x00000fff | ||
224 | #define AR5K_5212_RX_DESC_STATUS0_MORE 0x00001000 | ||
225 | #define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR 0x00002000 | ||
226 | #define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE 0x000f8000 | ||
227 | #define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE_S 15 | ||
228 | #define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x0ff00000 | ||
229 | #define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 20 | ||
230 | #define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA 0xf0000000 | ||
231 | #define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 28 | ||
232 | #define AR5K_5212_RX_DESC_STATUS1_DONE 0x00000001 | ||
233 | #define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 | ||
234 | #define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR 0x00000004 | ||
235 | #define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000008 | ||
236 | #define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR 0x00000010 | ||
237 | #define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR 0x00000020 | ||
238 | #define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 | ||
239 | #define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX 0x0000fe00 | ||
240 | #define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_S 9 | ||
241 | #define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x7fff0000 | ||
242 | #define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 16 | ||
243 | #define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS 0x80000000 | ||
244 | |||
219 | /* | 245 | /* |
220 | * 5212 rx status descriptor | 246 | * common hardware RX error descriptor |
221 | */ | 247 | */ |
222 | struct ath5k_hw_new_rx_status { | ||
223 | u32 rx_status_0; /* RX status word 0 */ | ||
224 | |||
225 | #define AR5K_NEW_RX_DESC_STATUS0_DATA_LEN 0x00000fff | ||
226 | #define AR5K_NEW_RX_DESC_STATUS0_MORE 0x00001000 | ||
227 | #define AR5K_NEW_RX_DESC_STATUS0_DECOMP_CRC_ERROR 0x00002000 | ||
228 | #define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE 0x000f8000 | ||
229 | #define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE_S 15 | ||
230 | #define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x0ff00000 | ||
231 | #define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 20 | ||
232 | #define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA 0xf0000000 | ||
233 | #define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 28 | ||
234 | |||
235 | u32 rx_status_1; /* RX status word 1 */ | ||
236 | |||
237 | #define AR5K_NEW_RX_DESC_STATUS1_DONE 0x00000001 | ||
238 | #define AR5K_NEW_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 | ||
239 | #define AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR 0x00000004 | ||
240 | #define AR5K_NEW_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000008 | ||
241 | #define AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR 0x00000010 | ||
242 | #define AR5K_NEW_RX_DESC_STATUS1_MIC_ERROR 0x00000020 | ||
243 | #define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 | ||
244 | #define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX 0x0000fe00 | ||
245 | #define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_S 9 | ||
246 | #define AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x7fff0000 | ||
247 | #define AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 16 | ||
248 | #define AR5K_NEW_RX_DESC_STATUS1_KEY_CACHE_MISS 0x80000000 | ||
249 | } __packed; | ||
250 | |||
251 | struct ath5k_hw_rx_error { | 248 | struct ath5k_hw_rx_error { |
252 | u32 rx_error_0; /* RX error word 0 */ | 249 | u32 rx_error_0; /* RX error word 0 */ |
253 | 250 | ||
@@ -268,7 +265,10 @@ struct ath5k_hw_rx_error { | |||
268 | #define AR5K_DESC_RX_PHY_ERROR_SERVICE 0xc0 | 265 | #define AR5K_DESC_RX_PHY_ERROR_SERVICE 0xc0 |
269 | #define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR 0xe0 | 266 | #define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR 0xe0 |
270 | 267 | ||
271 | struct ath5k_hw_2w_tx_desc { | 268 | /* |
269 | * 5210/5211 hardware 2-word TX control descriptor | ||
270 | */ | ||
271 | struct ath5k_hw_2w_tx_ctl { | ||
272 | u32 tx_control_0; /* TX control word 0 */ | 272 | u32 tx_control_0; /* TX control word 0 */ |
273 | 273 | ||
274 | #define AR5K_2W_TX_DESC_CTL0_FRAME_LEN 0x00000fff | 274 | #define AR5K_2W_TX_DESC_CTL0_FRAME_LEN 0x00000fff |
@@ -314,9 +314,9 @@ struct ath5k_hw_2w_tx_desc { | |||
314 | #define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 0x10 | 314 | #define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 0x10 |
315 | 315 | ||
316 | /* | 316 | /* |
317 | * 5212 4-word tx control descriptor | 317 | * 5212 hardware 4-word TX control descriptor |
318 | */ | 318 | */ |
319 | struct ath5k_hw_4w_tx_desc { | 319 | struct ath5k_hw_4w_tx_ctl { |
320 | u32 tx_control_0; /* TX control word 0 */ | 320 | u32 tx_control_0; /* TX control word 0 */ |
321 | 321 | ||
322 | #define AR5K_4W_TX_DESC_CTL0_FRAME_LEN 0x00000fff | 322 | #define AR5K_4W_TX_DESC_CTL0_FRAME_LEN 0x00000fff |
@@ -374,7 +374,7 @@ struct ath5k_hw_4w_tx_desc { | |||
374 | } __packed; | 374 | } __packed; |
375 | 375 | ||
376 | /* | 376 | /* |
377 | * Common tx status descriptor | 377 | * Common TX status descriptor |
378 | */ | 378 | */ |
379 | struct ath5k_hw_tx_status { | 379 | struct ath5k_hw_tx_status { |
380 | u32 tx_status_0; /* TX status word 0 */ | 380 | u32 tx_status_0; /* TX status word 0 */ |
@@ -415,6 +415,34 @@ struct ath5k_hw_tx_status { | |||
415 | 415 | ||
416 | 416 | ||
417 | /* | 417 | /* |
418 | * 5210/5211 hardware TX descriptor | ||
419 | */ | ||
420 | struct ath5k_hw_5210_tx_desc { | ||
421 | struct ath5k_hw_2w_tx_ctl tx_ctl; | ||
422 | struct ath5k_hw_tx_status tx_stat; | ||
423 | } __packed; | ||
424 | |||
425 | /* | ||
426 | * 5212 hardware TX descriptor | ||
427 | */ | ||
428 | struct ath5k_hw_5212_tx_desc { | ||
429 | struct ath5k_hw_4w_tx_ctl tx_ctl; | ||
430 | struct ath5k_hw_tx_status tx_stat; | ||
431 | } __packed; | ||
432 | |||
433 | /* | ||
434 | * common hardware RX descriptor | ||
435 | */ | ||
436 | struct ath5k_hw_all_rx_desc { | ||
437 | struct ath5k_hw_rx_ctl rx_ctl; | ||
438 | union { | ||
439 | struct ath5k_hw_rx_status rx_stat; | ||
440 | struct ath5k_hw_rx_error rx_err; | ||
441 | } u; | ||
442 | } __packed; | ||
443 | |||
444 | |||
445 | /* | ||
418 | * AR5K REGISTER ACCESS | 446 | * AR5K REGISTER ACCESS |
419 | */ | 447 | */ |
420 | 448 | ||
diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath5k/initvals.c index cfcb1fe7bd34..fdbab2f08178 100644 --- a/drivers/net/wireless/ath5k/initvals.c +++ b/drivers/net/wireless/ath5k/initvals.c | |||
@@ -678,8 +678,8 @@ static const struct ath5k_ini ar5212_ini[] = { | |||
678 | { AR5K_PHY(644), 0x00806333 }, | 678 | { AR5K_PHY(644), 0x00806333 }, |
679 | { AR5K_PHY(645), 0x00106c10 }, | 679 | { AR5K_PHY(645), 0x00106c10 }, |
680 | { AR5K_PHY(646), 0x009c4060 }, | 680 | { AR5K_PHY(646), 0x009c4060 }, |
681 | /*{ AR5K_PHY(647), 0x1483800a },*/ /* Old value */ | ||
682 | { AR5K_PHY(647), 0x1483800a }, | 681 | { AR5K_PHY(647), 0x1483800a }, |
682 | /* { AR5K_PHY(648), 0x018830c6 },*/ /* 2413 */ | ||
683 | { AR5K_PHY(648), 0x01831061 }, | 683 | { AR5K_PHY(648), 0x01831061 }, |
684 | { AR5K_PHY(649), 0x00000400 }, | 684 | { AR5K_PHY(649), 0x00000400 }, |
685 | /*{ AR5K_PHY(650), 0x000001b5 },*/ | 685 | /*{ AR5K_PHY(650), 0x000001b5 },*/ |
@@ -1081,6 +1081,207 @@ static const struct ath5k_ini_mode rf5413_ini_mode_end[] = { | |||
1081 | { 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0 } }, | 1081 | { 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0 } }, |
1082 | }; | 1082 | }; |
1083 | 1083 | ||
1084 | /* Initial mode-specific settings for RF2413/2414 (Written after ar5212_ini) */ | ||
1085 | /* XXX: No dumps for turbog yet, so turbog is the same with g here with some | ||
1086 | * minor tweaking based on dumps from other chips */ | ||
1087 | static const struct ath5k_ini_mode rf2413_ini_mode_end[] = { | ||
1088 | { AR5K_TXCFG, | ||
1089 | /* b g gTurbo */ | ||
1090 | { 0x00000015, 0x00000015, 0x00000015 } }, | ||
1091 | { AR5K_USEC_5211, | ||
1092 | { 0x04e01395, 0x12e013ab, 0x098813cf } }, | ||
1093 | { AR5K_PHY(10), | ||
1094 | { 0x05020000, 0x0a020001, 0x0a020001 } }, | ||
1095 | { AR5K_PHY(13), | ||
1096 | { 0x00000e00, 0x00000e00, 0x00000e00 } }, | ||
1097 | { AR5K_PHY(14), | ||
1098 | { 0x0000000a, 0x0000000a, 0x0000000a } }, | ||
1099 | { AR5K_PHY(18), | ||
1100 | { 0x001a6a64, 0x001a6a64, 0x001a6a64 } }, | ||
1101 | { AR5K_PHY(20), | ||
1102 | { 0x0de8b0da, 0x0c98b0da, 0x0c98b0da } }, | ||
1103 | { AR5K_PHY_SIG, | ||
1104 | { 0x7ee80d2e, 0x7ec80d2e, 0x7ec80d2e } }, | ||
1105 | { AR5K_PHY_AGCCOARSE, | ||
1106 | { 0x3137665e, 0x3139605e, 0x3139605e } }, | ||
1107 | { AR5K_PHY(27), | ||
1108 | { 0x050cb081, 0x050cb081, 0x050cb081 } }, | ||
1109 | { AR5K_PHY_RX_DELAY, | ||
1110 | { 0x0000044c, 0x00000898, 0x000007d0 } }, | ||
1111 | { AR5K_PHY_FRAME_CTL_5211, | ||
1112 | { 0xf7b80d00, 0xf7b81000, 0xf7b81000 } }, | ||
1113 | { AR5K_PHY_CCKTXCTL, | ||
1114 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1115 | { AR5K_PHY(642), | ||
1116 | { 0xd03e6788, 0xd03e6788, 0xd03e6788 } }, | ||
1117 | { AR5K_PHY_GAIN_2GHZ, | ||
1118 | { 0x0042c140, 0x0042c140, 0x0042c140 } }, | ||
1119 | { 0xa21c, | ||
1120 | { 0x1863800a, 0x1883800a, 0x1883800a } }, | ||
1121 | { AR5K_DCU_FP, | ||
1122 | { 0x000003e0, 0x000003e0, 0x000003e0 } }, | ||
1123 | { 0x8060, | ||
1124 | { 0x0000000f, 0x0000000f, 0x0000000f } }, | ||
1125 | { 0x8118, | ||
1126 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1127 | { 0x811c, | ||
1128 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1129 | { 0x8120, | ||
1130 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1131 | { 0x8124, | ||
1132 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1133 | { 0x8128, | ||
1134 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1135 | { 0x812c, | ||
1136 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1137 | { 0x8130, | ||
1138 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1139 | { 0x8134, | ||
1140 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1141 | { 0x8138, | ||
1142 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1143 | { 0x813c, | ||
1144 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1145 | { 0x8140, | ||
1146 | { 0x800000a8, 0x800000a8, 0x800000a8 } }, | ||
1147 | { 0x8144, | ||
1148 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1149 | { AR5K_PHY_AGC, | ||
1150 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1151 | { AR5K_PHY(11), | ||
1152 | { 0x0000a000, 0x0000a000, 0x0000a000 } }, | ||
1153 | { AR5K_PHY(15), | ||
1154 | { 0x00200400, 0x00200400, 0x00200400 } }, | ||
1155 | { AR5K_PHY(19), | ||
1156 | { 0x1284233c, 0x1284233c, 0x1284233c } }, | ||
1157 | { AR5K_PHY_SCR, | ||
1158 | { 0x0000001f, 0x0000001f, 0x0000001f } }, | ||
1159 | { AR5K_PHY_SLMT, | ||
1160 | { 0x00000080, 0x00000080, 0x00000080 } }, | ||
1161 | { AR5K_PHY_SCAL, | ||
1162 | { 0x0000000e, 0x0000000e, 0x0000000e } }, | ||
1163 | { AR5K_PHY(86), | ||
1164 | { 0x000000ff, 0x000000ff, 0x000000ff } }, | ||
1165 | { AR5K_PHY(96), | ||
1166 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1167 | { AR5K_PHY(97), | ||
1168 | { 0x02800000, 0x02800000, 0x02800000 } }, | ||
1169 | { AR5K_PHY(104), | ||
1170 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1171 | { AR5K_PHY(120), | ||
1172 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1173 | { AR5K_PHY(121), | ||
1174 | { 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa } }, | ||
1175 | { AR5K_PHY(122), | ||
1176 | { 0x3c466478, 0x3c466478, 0x3c466478 } }, | ||
1177 | { AR5K_PHY(123), | ||
1178 | { 0x000000aa, 0x000000aa, 0x000000aa } }, | ||
1179 | { AR5K_PHY_SCLOCK, | ||
1180 | { 0x0000000c, 0x0000000c, 0x0000000c } }, | ||
1181 | { AR5K_PHY_SDELAY, | ||
1182 | { 0x000000ff, 0x000000ff, 0x000000ff } }, | ||
1183 | { AR5K_PHY_SPENDING, | ||
1184 | { 0x00000014, 0x00000014, 0x00000014 } }, | ||
1185 | { 0xa228, | ||
1186 | { 0x000009b5, 0x000009b5, 0x000009b5 } }, | ||
1187 | { 0xa23c, | ||
1188 | { 0x93c889af, 0x93c889af, 0x93c889af } }, | ||
1189 | { 0xa24c, | ||
1190 | { 0x00000001, 0x00000001, 0x00000001 } }, | ||
1191 | { 0xa250, | ||
1192 | { 0x0000a000, 0x0000a000, 0x0000a000 } }, | ||
1193 | { 0xa254, | ||
1194 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1195 | { 0xa258, | ||
1196 | { 0x0cc75380, 0x0cc75380, 0x0cc75380 } }, | ||
1197 | { 0xa25c, | ||
1198 | { 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01 } }, | ||
1199 | { 0xa260, | ||
1200 | { 0x5f690f01, 0x5f690f01, 0x5f690f01 } }, | ||
1201 | { 0xa264, | ||
1202 | { 0x00418a11, 0x00418a11, 0x00418a11 } }, | ||
1203 | { 0xa268, | ||
1204 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1205 | { 0xa26c, | ||
1206 | { 0x0c30c16a, 0x0c30c16a, 0x0c30c16a } }, | ||
1207 | { 0xa270, | ||
1208 | { 0x00820820, 0x00820820, 0x00820820 } }, | ||
1209 | { 0xa274, | ||
1210 | { 0x001b7caa, 0x001b7caa, 0x001b7caa } }, | ||
1211 | { 0xa278, | ||
1212 | { 0x1ce739ce, 0x1ce739ce, 0x1ce739ce } }, | ||
1213 | { 0xa27c, | ||
1214 | { 0x051701ce, 0x051701ce, 0x051701ce } }, | ||
1215 | { 0xa300, | ||
1216 | { 0x18010000, 0x18010000, 0x18010000 } }, | ||
1217 | { 0xa304, | ||
1218 | { 0x30032602, 0x30032602, 0x30032602 } }, | ||
1219 | { 0xa308, | ||
1220 | { 0x48073e06, 0x48073e06, 0x48073e06 } }, | ||
1221 | { 0xa30c, | ||
1222 | { 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } }, | ||
1223 | { 0xa310, | ||
1224 | { 0x641a600f, 0x641a600f, 0x641a600f } }, | ||
1225 | { 0xa314, | ||
1226 | { 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } }, | ||
1227 | { 0xa318, | ||
1228 | { 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } }, | ||
1229 | { 0xa31c, | ||
1230 | { 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } }, | ||
1231 | { 0xa320, | ||
1232 | { 0x9d4f970f, 0x9d4f970f, 0x9d4f970f } }, | ||
1233 | { 0xa324, | ||
1234 | { 0xa5cfa18f, 0xa5cfa18f, 0xa5cfa18f } }, | ||
1235 | { 0xa328, | ||
1236 | { 0xb55faf1f, 0xb55faf1f, 0xb55faf1f } }, | ||
1237 | { 0xa32c, | ||
1238 | { 0xbddfb99f, 0xbddfb99f, 0xbddfb99f } }, | ||
1239 | { 0xa330, | ||
1240 | { 0xcd7fc73f, 0xcd7fc73f, 0xcd7fc73f } }, | ||
1241 | { 0xa334, | ||
1242 | { 0xd5ffd1bf, 0xd5ffd1bf, 0xd5ffd1bf } }, | ||
1243 | { 0xa338, | ||
1244 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1245 | { 0xa33c, | ||
1246 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1247 | { 0xa340, | ||
1248 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1249 | { 0xa344, | ||
1250 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
1251 | { 0xa348, | ||
1252 | { 0x3fffffff, 0x3fffffff, 0x3fffffff } }, | ||
1253 | { 0xa34c, | ||
1254 | { 0x3fffffff, 0x3fffffff, 0x3fffffff } }, | ||
1255 | { 0xa350, | ||
1256 | { 0x3fffffff, 0x3fffffff, 0x3fffffff } }, | ||
1257 | { 0xa354, | ||
1258 | { 0x0003ffff, 0x0003ffff, 0x0003ffff } }, | ||
1259 | { 0xa358, | ||
1260 | { 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f } }, | ||
1261 | { 0xa35c, | ||
1262 | { 0x066c420f, 0x066c420f, 0x066c420f } }, | ||
1263 | { 0xa360, | ||
1264 | { 0x0f282207, 0x0f282207, 0x0f282207 } }, | ||
1265 | { 0xa364, | ||
1266 | { 0x17601685, 0x17601685, 0x17601685 } }, | ||
1267 | { 0xa368, | ||
1268 | { 0x1f801104, 0x1f801104, 0x1f801104 } }, | ||
1269 | { 0xa36c, | ||
1270 | { 0x37a00c03, 0x37a00c03, 0x37a00c03 } }, | ||
1271 | { 0xa370, | ||
1272 | { 0x3fc40883, 0x3fc40883, 0x3fc40883 } }, | ||
1273 | { 0xa374, | ||
1274 | { 0x57c00803, 0x57c00803, 0x57c00803 } }, | ||
1275 | { 0xa378, | ||
1276 | { 0x5fd80682, 0x5fd80682, 0x5fd80682 } }, | ||
1277 | { 0xa37c, | ||
1278 | { 0x7fe00482, 0x7fe00482, 0x7fe00482 } }, | ||
1279 | { 0xa380, | ||
1280 | { 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba } }, | ||
1281 | { 0xa384, | ||
1282 | { 0xf3307ff0, 0xf3307ff0, 0xf3307ff0 } }, | ||
1283 | }; | ||
1284 | |||
1084 | /* | 1285 | /* |
1085 | * Initial BaseBand Gain settings for RF5111/5112 (AR5210 comes with | 1286 | * Initial BaseBand Gain settings for RF5111/5112 (AR5210 comes with |
1086 | * RF5110 only so initial BB Gain settings are included in AR5K_AR5210_INI) | 1287 | * RF5110 only so initial BB Gain settings are included in AR5K_AR5210_INI) |
@@ -1290,29 +1491,57 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) | |||
1290 | 1491 | ||
1291 | /* Second set of mode-specific settings */ | 1492 | /* Second set of mode-specific settings */ |
1292 | if (ah->ah_radio == AR5K_RF5111){ | 1493 | if (ah->ah_radio == AR5K_RF5111){ |
1494 | |||
1293 | ath5k_hw_ini_mode_registers(ah, | 1495 | ath5k_hw_ini_mode_registers(ah, |
1294 | ARRAY_SIZE(ar5212_rf5111_ini_mode_end), | 1496 | ARRAY_SIZE(ar5212_rf5111_ini_mode_end), |
1295 | ar5212_rf5111_ini_mode_end, mode); | 1497 | ar5212_rf5111_ini_mode_end, mode); |
1498 | |||
1296 | /* Baseband gain table */ | 1499 | /* Baseband gain table */ |
1297 | ath5k_hw_ini_registers(ah, | 1500 | ath5k_hw_ini_registers(ah, |
1298 | ARRAY_SIZE(rf5111_ini_bbgain), | 1501 | ARRAY_SIZE(rf5111_ini_bbgain), |
1299 | rf5111_ini_bbgain, change_channel); | 1502 | rf5111_ini_bbgain, change_channel); |
1503 | |||
1300 | } else if (ah->ah_radio == AR5K_RF5112){ | 1504 | } else if (ah->ah_radio == AR5K_RF5112){ |
1505 | |||
1301 | ath5k_hw_ini_mode_registers(ah, | 1506 | ath5k_hw_ini_mode_registers(ah, |
1302 | ARRAY_SIZE(ar5212_rf5112_ini_mode_end), | 1507 | ARRAY_SIZE(ar5212_rf5112_ini_mode_end), |
1303 | ar5212_rf5112_ini_mode_end, mode); | 1508 | ar5212_rf5112_ini_mode_end, mode); |
1304 | /* Baseband gain table */ | 1509 | |
1305 | ath5k_hw_ini_registers(ah, | 1510 | ath5k_hw_ini_registers(ah, |
1306 | ARRAY_SIZE(rf5112_ini_bbgain), | 1511 | ARRAY_SIZE(rf5112_ini_bbgain), |
1307 | rf5112_ini_bbgain, change_channel); | 1512 | rf5112_ini_bbgain, change_channel); |
1513 | |||
1308 | } else if (ah->ah_radio == AR5K_RF5413){ | 1514 | } else if (ah->ah_radio == AR5K_RF5413){ |
1515 | |||
1309 | ath5k_hw_ini_mode_registers(ah, | 1516 | ath5k_hw_ini_mode_registers(ah, |
1310 | ARRAY_SIZE(rf5413_ini_mode_end), | 1517 | ARRAY_SIZE(rf5413_ini_mode_end), |
1311 | rf5413_ini_mode_end, mode); | 1518 | rf5413_ini_mode_end, mode); |
1519 | |||
1520 | ath5k_hw_ini_registers(ah, | ||
1521 | ARRAY_SIZE(rf5112_ini_bbgain), | ||
1522 | rf5112_ini_bbgain, change_channel); | ||
1523 | |||
1524 | } else if (ah->ah_radio == AR5K_RF2413) { | ||
1525 | |||
1526 | if (mode < 2) { | ||
1527 | ATH5K_ERR(ah->ah_sc, | ||
1528 | "unsupported channel mode: %d\n", mode); | ||
1529 | return -EINVAL; | ||
1530 | } | ||
1531 | mode = mode - 2; | ||
1532 | |||
1533 | /* Override a setting from ar5212_ini */ | ||
1534 | ath5k_hw_reg_write(ah, 0x018830c6, AR5K_PHY(648)); | ||
1535 | |||
1536 | ath5k_hw_ini_mode_registers(ah, | ||
1537 | ARRAY_SIZE(rf2413_ini_mode_end), | ||
1538 | rf2413_ini_mode_end, mode); | ||
1539 | |||
1312 | /* Baseband gain table */ | 1540 | /* Baseband gain table */ |
1313 | ath5k_hw_ini_registers(ah, | 1541 | ath5k_hw_ini_registers(ah, |
1314 | ARRAY_SIZE(rf5112_ini_bbgain), | 1542 | ARRAY_SIZE(rf5112_ini_bbgain), |
1315 | rf5112_ini_bbgain, change_channel); | 1543 | rf5112_ini_bbgain, change_channel); |
1544 | |||
1316 | } | 1545 | } |
1317 | /* For AR5211 */ | 1546 | /* For AR5211 */ |
1318 | } else if (ah->ah_version == AR5K_AR5211) { | 1547 | } else if (ah->ah_version == AR5K_AR5211) { |
diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index 405195ffb24d..ee1dc0fc6ea2 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath5k/phy.c | |||
@@ -666,6 +666,75 @@ static const struct ath5k_ini_rf rfregs_5413[] = { | |||
666 | { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, | 666 | { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, |
667 | }; | 667 | }; |
668 | 668 | ||
669 | /* RF2413/2414 mode-specific init registers */ | ||
670 | static const struct ath5k_ini_rf rfregs_2413[] = { | ||
671 | { 1, AR5K_RF_BUFFER_CONTROL_4, | ||
672 | { 0x00000020, 0x00000020, 0x00000020 } }, | ||
673 | { 2, AR5K_RF_BUFFER_CONTROL_3, | ||
674 | { 0x02001408, 0x02001408, 0x02001408 } }, | ||
675 | { 3, AR5K_RF_BUFFER_CONTROL_6, | ||
676 | { 0x00e020c0, 0x00e020c0, 0x00e020c0 } }, | ||
677 | { 6, AR5K_RF_BUFFER, | ||
678 | { 0xf0000000, 0xf0000000, 0xf0000000 } }, | ||
679 | { 6, AR5K_RF_BUFFER, | ||
680 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
681 | { 6, AR5K_RF_BUFFER, | ||
682 | { 0x03000000, 0x03000000, 0x03000000 } }, | ||
683 | { 6, AR5K_RF_BUFFER, | ||
684 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
685 | { 6, AR5K_RF_BUFFER, | ||
686 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
687 | { 6, AR5K_RF_BUFFER, | ||
688 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
689 | { 6, AR5K_RF_BUFFER, | ||
690 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
691 | { 6, AR5K_RF_BUFFER, | ||
692 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
693 | { 6, AR5K_RF_BUFFER, | ||
694 | { 0x40400000, 0x40400000, 0x40400000 } }, | ||
695 | { 6, AR5K_RF_BUFFER, | ||
696 | { 0x65050000, 0x65050000, 0x65050000 } }, | ||
697 | { 6, AR5K_RF_BUFFER, | ||
698 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
699 | { 6, AR5K_RF_BUFFER, | ||
700 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
701 | { 6, AR5K_RF_BUFFER, | ||
702 | { 0x00420000, 0x00420000, 0x00420000 } }, | ||
703 | { 6, AR5K_RF_BUFFER, | ||
704 | { 0x00b50000, 0x00b50000, 0x00b50000 } }, | ||
705 | { 6, AR5K_RF_BUFFER, | ||
706 | { 0x00030000, 0x00030000, 0x00030000 } }, | ||
707 | { 6, AR5K_RF_BUFFER, | ||
708 | { 0x00f70000, 0x00f70000, 0x00f70000 } }, | ||
709 | { 6, AR5K_RF_BUFFER, | ||
710 | { 0x009d0000, 0x009d0000, 0x009d0000 } }, | ||
711 | { 6, AR5K_RF_BUFFER, | ||
712 | { 0x00220000, 0x00220000, 0x00220000 } }, | ||
713 | { 6, AR5K_RF_BUFFER, | ||
714 | { 0x04220000, 0x04220000, 0x04220000 } }, | ||
715 | { 6, AR5K_RF_BUFFER, | ||
716 | { 0x00230018, 0x00230018, 0x00230018 } }, | ||
717 | { 6, AR5K_RF_BUFFER, | ||
718 | { 0x00280050, 0x00280050, 0x00280050 } }, | ||
719 | { 6, AR5K_RF_BUFFER, | ||
720 | { 0x005000c3, 0x005000c3, 0x005000c3 } }, | ||
721 | { 6, AR5K_RF_BUFFER, | ||
722 | { 0x0004007f, 0x0004007f, 0x0004007f } }, | ||
723 | { 6, AR5K_RF_BUFFER, | ||
724 | { 0x00000458, 0x00000458, 0x00000458 } }, | ||
725 | { 6, AR5K_RF_BUFFER, | ||
726 | { 0x00000000, 0x00000000, 0x00000000 } }, | ||
727 | { 6, AR5K_RF_BUFFER, | ||
728 | { 0x0000c000, 0x0000c000, 0x0000c000 } }, | ||
729 | { 6, AR5K_RF_BUFFER_CONTROL_5, | ||
730 | { 0x00400230, 0x00400230, 0x00400230 } }, | ||
731 | { 7, AR5K_RF_BUFFER, | ||
732 | { 0x00006400, 0x00006400, 0x00006400 } }, | ||
733 | { 7, AR5K_RF_BUFFER, | ||
734 | { 0x00000800, 0x00000800, 0x00000800 } }, | ||
735 | { 7, AR5K_RF_BUFFER_CONTROL_2, | ||
736 | { 0x0000000e, 0x0000000e, 0x0000000e } }, | ||
737 | }; | ||
669 | 738 | ||
670 | /* Initial RF Gain settings for RF5112 */ | 739 | /* Initial RF Gain settings for RF5112 */ |
671 | static const struct ath5k_ini_rfgain rfgain_5112[] = { | 740 | static const struct ath5k_ini_rfgain rfgain_5112[] = { |
@@ -805,6 +874,74 @@ static const struct ath5k_ini_rfgain rfgain_5413[] = { | |||
805 | { AR5K_RF_GAIN(63), { 0x000000f9, 0x000000f9 } }, | 874 | { AR5K_RF_GAIN(63), { 0x000000f9, 0x000000f9 } }, |
806 | }; | 875 | }; |
807 | 876 | ||
877 | /* Initial RF Gain settings for RF2413 */ | ||
878 | static const struct ath5k_ini_rfgain rfgain_2413[] = { | ||
879 | { AR5K_RF_GAIN(0), { 0x00000000 } }, | ||
880 | { AR5K_RF_GAIN(1), { 0x00000040 } }, | ||
881 | { AR5K_RF_GAIN(2), { 0x00000080 } }, | ||
882 | { AR5K_RF_GAIN(3), { 0x00000181 } }, | ||
883 | { AR5K_RF_GAIN(4), { 0x000001c1 } }, | ||
884 | { AR5K_RF_GAIN(5), { 0x00000001 } }, | ||
885 | { AR5K_RF_GAIN(6), { 0x00000041 } }, | ||
886 | { AR5K_RF_GAIN(7), { 0x00000081 } }, | ||
887 | { AR5K_RF_GAIN(8), { 0x00000168 } }, | ||
888 | { AR5K_RF_GAIN(9), { 0x000001a8 } }, | ||
889 | { AR5K_RF_GAIN(10), { 0x000001e8 } }, | ||
890 | { AR5K_RF_GAIN(11), { 0x00000028 } }, | ||
891 | { AR5K_RF_GAIN(12), { 0x00000068 } }, | ||
892 | { AR5K_RF_GAIN(13), { 0x00000189 } }, | ||
893 | { AR5K_RF_GAIN(14), { 0x000001c9 } }, | ||
894 | { AR5K_RF_GAIN(15), { 0x00000009 } }, | ||
895 | { AR5K_RF_GAIN(16), { 0x00000049 } }, | ||
896 | { AR5K_RF_GAIN(17), { 0x00000089 } }, | ||
897 | { AR5K_RF_GAIN(18), { 0x00000190 } }, | ||
898 | { AR5K_RF_GAIN(19), { 0x000001d0 } }, | ||
899 | { AR5K_RF_GAIN(20), { 0x00000010 } }, | ||
900 | { AR5K_RF_GAIN(21), { 0x00000050 } }, | ||
901 | { AR5K_RF_GAIN(22), { 0x00000090 } }, | ||
902 | { AR5K_RF_GAIN(23), { 0x00000191 } }, | ||
903 | { AR5K_RF_GAIN(24), { 0x000001d1 } }, | ||
904 | { AR5K_RF_GAIN(25), { 0x00000011 } }, | ||
905 | { AR5K_RF_GAIN(26), { 0x00000051 } }, | ||
906 | { AR5K_RF_GAIN(27), { 0x00000091 } }, | ||
907 | { AR5K_RF_GAIN(28), { 0x00000178 } }, | ||
908 | { AR5K_RF_GAIN(29), { 0x000001b8 } }, | ||
909 | { AR5K_RF_GAIN(30), { 0x000001f8 } }, | ||
910 | { AR5K_RF_GAIN(31), { 0x00000038 } }, | ||
911 | { AR5K_RF_GAIN(32), { 0x00000078 } }, | ||
912 | { AR5K_RF_GAIN(33), { 0x00000199 } }, | ||
913 | { AR5K_RF_GAIN(34), { 0x000001d9 } }, | ||
914 | { AR5K_RF_GAIN(35), { 0x00000019 } }, | ||
915 | { AR5K_RF_GAIN(36), { 0x00000059 } }, | ||
916 | { AR5K_RF_GAIN(37), { 0x00000099 } }, | ||
917 | { AR5K_RF_GAIN(38), { 0x000000d9 } }, | ||
918 | { AR5K_RF_GAIN(39), { 0x000000f9 } }, | ||
919 | { AR5K_RF_GAIN(40), { 0x000000f9 } }, | ||
920 | { AR5K_RF_GAIN(41), { 0x000000f9 } }, | ||
921 | { AR5K_RF_GAIN(42), { 0x000000f9 } }, | ||
922 | { AR5K_RF_GAIN(43), { 0x000000f9 } }, | ||
923 | { AR5K_RF_GAIN(44), { 0x000000f9 } }, | ||
924 | { AR5K_RF_GAIN(45), { 0x000000f9 } }, | ||
925 | { AR5K_RF_GAIN(46), { 0x000000f9 } }, | ||
926 | { AR5K_RF_GAIN(47), { 0x000000f9 } }, | ||
927 | { AR5K_RF_GAIN(48), { 0x000000f9 } }, | ||
928 | { AR5K_RF_GAIN(49), { 0x000000f9 } }, | ||
929 | { AR5K_RF_GAIN(50), { 0x000000f9 } }, | ||
930 | { AR5K_RF_GAIN(51), { 0x000000f9 } }, | ||
931 | { AR5K_RF_GAIN(52), { 0x000000f9 } }, | ||
932 | { AR5K_RF_GAIN(53), { 0x000000f9 } }, | ||
933 | { AR5K_RF_GAIN(54), { 0x000000f9 } }, | ||
934 | { AR5K_RF_GAIN(55), { 0x000000f9 } }, | ||
935 | { AR5K_RF_GAIN(56), { 0x000000f9 } }, | ||
936 | { AR5K_RF_GAIN(57), { 0x000000f9 } }, | ||
937 | { AR5K_RF_GAIN(58), { 0x000000f9 } }, | ||
938 | { AR5K_RF_GAIN(59), { 0x000000f9 } }, | ||
939 | { AR5K_RF_GAIN(60), { 0x000000f9 } }, | ||
940 | { AR5K_RF_GAIN(61), { 0x000000f9 } }, | ||
941 | { AR5K_RF_GAIN(62), { 0x000000f9 } }, | ||
942 | { AR5K_RF_GAIN(63), { 0x000000f9 } }, | ||
943 | }; | ||
944 | |||
808 | static const struct ath5k_gain_opt rfgain_opt_5112 = { | 945 | static const struct ath5k_gain_opt rfgain_opt_5112 = { |
809 | 1, | 946 | 1, |
810 | 8, | 947 | 8, |
@@ -955,7 +1092,6 @@ static s32 ath5k_hw_rfregs_gain_adjust(struct ath5k_hw *ah) | |||
955 | go = &rfgain_opt_5111; | 1092 | go = &rfgain_opt_5111; |
956 | break; | 1093 | break; |
957 | case AR5K_RF5112: | 1094 | case AR5K_RF5112: |
958 | case AR5K_RF5413: /* ??? */ | ||
959 | go = &rfgain_opt_5112; | 1095 | go = &rfgain_opt_5112; |
960 | break; | 1096 | break; |
961 | default: | 1097 | default: |
@@ -1226,8 +1362,21 @@ static int ath5k_hw_rf5413_rfregs(struct ath5k_hw *ah, | |||
1226 | 1362 | ||
1227 | rf = ah->ah_rf_banks; | 1363 | rf = ah->ah_rf_banks; |
1228 | 1364 | ||
1229 | rf_ini = rfregs_5413; | 1365 | if (ah->ah_radio == AR5K_RF5413) { |
1230 | rf_size = ARRAY_SIZE(rfregs_5413); | 1366 | rf_ini = rfregs_5413; |
1367 | rf_size = ARRAY_SIZE(rfregs_5413); | ||
1368 | } else if (ah->ah_radio == AR5K_RF2413) { | ||
1369 | rf_ini = rfregs_2413; | ||
1370 | rf_size = ARRAY_SIZE(rfregs_2413); | ||
1371 | if (mode < 2) { | ||
1372 | ATH5K_ERR(ah->ah_sc, | ||
1373 | "invalid channel mode: %i\n", mode); | ||
1374 | return -EINVAL; | ||
1375 | } | ||
1376 | mode = mode - 2; | ||
1377 | } else { | ||
1378 | return -EINVAL; | ||
1379 | } | ||
1231 | 1380 | ||
1232 | /* Copy values to modify them */ | 1381 | /* Copy values to modify them */ |
1233 | for (i = 0; i < rf_size; i++) { | 1382 | for (i = 0; i < rf_size; i++) { |
@@ -1286,6 +1435,10 @@ int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, | |||
1286 | ah->ah_rf_banks_size = sizeof(rfregs_5413); | 1435 | ah->ah_rf_banks_size = sizeof(rfregs_5413); |
1287 | func = ath5k_hw_rf5413_rfregs; | 1436 | func = ath5k_hw_rf5413_rfregs; |
1288 | break; | 1437 | break; |
1438 | case AR5K_RF2413: | ||
1439 | ah->ah_rf_banks_size = sizeof(rfregs_2413); | ||
1440 | func = ath5k_hw_rf5413_rfregs; | ||
1441 | break; | ||
1289 | default: | 1442 | default: |
1290 | return -EINVAL; | 1443 | return -EINVAL; |
1291 | } | 1444 | } |
@@ -1324,6 +1477,11 @@ int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq) | |||
1324 | ath5k_rfg = rfgain_5413; | 1477 | ath5k_rfg = rfgain_5413; |
1325 | size = ARRAY_SIZE(rfgain_5413); | 1478 | size = ARRAY_SIZE(rfgain_5413); |
1326 | break; | 1479 | break; |
1480 | case AR5K_RF2413: | ||
1481 | ath5k_rfg = rfgain_2413; | ||
1482 | size = ARRAY_SIZE(rfgain_2413); | ||
1483 | freq = 0; /* only 2Ghz */ | ||
1484 | break; | ||
1327 | default: | 1485 | default: |
1328 | return -EINVAL; | 1486 | return -EINVAL; |
1329 | } | 1487 | } |
@@ -1398,7 +1556,6 @@ int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah) | |||
1398 | ah->ah_gain.g_active = 1; | 1556 | ah->ah_gain.g_active = 1; |
1399 | break; | 1557 | break; |
1400 | case AR5K_RF5112: | 1558 | case AR5K_RF5112: |
1401 | case AR5K_RF5413: /* ??? */ | ||
1402 | ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default; | 1559 | ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default; |
1403 | ah->ah_gain.g_step = | 1560 | ah->ah_gain.g_step = |
1404 | &rfgain_opt_5112.go_step[ah->ah_gain.g_step_idx]; | 1561 | &rfgain_opt_5112.go_step[ah->ah_gain.g_step_idx]; |
@@ -2019,6 +2176,15 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, | |||
2019 | return -EINVAL; | 2176 | return -EINVAL; |
2020 | } | 2177 | } |
2021 | 2178 | ||
2179 | /* | ||
2180 | * RF2413 for some reason can't | ||
2181 | * transmit anything if we call | ||
2182 | * this funtion, so we skip it | ||
2183 | * until we fix txpower. | ||
2184 | */ | ||
2185 | if (ah->ah_radio == AR5K_RF2413) | ||
2186 | return 0; | ||
2187 | |||
2022 | /* Reset TX power values */ | 2188 | /* Reset TX power values */ |
2023 | memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); | 2189 | memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); |
2024 | ah->ah_txpower.txp_tpc = tpc; | 2190 | ah->ah_txpower.txp_tpc = tpc; |
diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h index 2f41c8398602..30629b3e37c2 100644 --- a/drivers/net/wireless/ath5k/reg.h +++ b/drivers/net/wireless/ath5k/reg.h | |||
@@ -1923,7 +1923,9 @@ after DFS is enabled */ | |||
1923 | #define AR5K_PHY_SDELAY_32MHZ 0x000000ff | 1923 | #define AR5K_PHY_SDELAY_32MHZ 0x000000ff |
1924 | #define AR5K_PHY_SPENDING 0x99f8 | 1924 | #define AR5K_PHY_SPENDING 0x99f8 |
1925 | #define AR5K_PHY_SPENDING_RF5111 0x00000018 | 1925 | #define AR5K_PHY_SPENDING_RF5111 0x00000018 |
1926 | #define AR5K_PHY_SPENDING_RF5112 0x00000014 | 1926 | #define AR5K_PHY_SPENDING_RF5112 0x00000014 /* <- i 've only seen this on 2425 dumps ! */ |
1927 | #define AR5K_PHY_SPENDING_RF5112A 0x0000000e /* but since i only have 5112A-based chips */ | ||
1928 | #define AR5K_PHY_SPENDING_RF5424 0x00000012 /* to test it might be also for old 5112. */ | ||
1927 | 1929 | ||
1928 | /* | 1930 | /* |
1929 | * Misc PHY/radio registers [5110 - 5111] | 1931 | * Misc PHY/radio registers [5110 - 5111] |
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 33459d61a717..d40be1568517 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h | |||
@@ -99,6 +99,8 @@ | |||
99 | #define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */ | 99 | #define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */ |
100 | #define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */ | 100 | #define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */ |
101 | #define B43_MMIO_RNG 0x65A | 101 | #define B43_MMIO_RNG 0x65A |
102 | #define B43_MMIO_IFSCTL 0x688 /* Interframe space control */ | ||
103 | #define B43_MMIO_IFSCTL_USE_EDCF 0x0004 | ||
102 | #define B43_MMIO_POWERUP_DELAY 0x6A8 | 104 | #define B43_MMIO_POWERUP_DELAY 0x6A8 |
103 | 105 | ||
104 | /* SPROM boardflags_lo values */ | 106 | /* SPROM boardflags_lo values */ |
@@ -587,15 +589,13 @@ struct b43_phy { | |||
587 | 589 | ||
588 | /* Data structures for DMA transmission, per 80211 core. */ | 590 | /* Data structures for DMA transmission, per 80211 core. */ |
589 | struct b43_dma { | 591 | struct b43_dma { |
590 | struct b43_dmaring *tx_ring0; | 592 | struct b43_dmaring *tx_ring_AC_BK; /* Background */ |
591 | struct b43_dmaring *tx_ring1; | 593 | struct b43_dmaring *tx_ring_AC_BE; /* Best Effort */ |
592 | struct b43_dmaring *tx_ring2; | 594 | struct b43_dmaring *tx_ring_AC_VI; /* Video */ |
593 | struct b43_dmaring *tx_ring3; | 595 | struct b43_dmaring *tx_ring_AC_VO; /* Voice */ |
594 | struct b43_dmaring *tx_ring4; | 596 | struct b43_dmaring *tx_ring_mcast; /* Multicast */ |
595 | struct b43_dmaring *tx_ring5; | 597 | |
596 | 598 | struct b43_dmaring *rx_ring; | |
597 | struct b43_dmaring *rx_ring0; | ||
598 | struct b43_dmaring *rx_ring3; /* only available on core.rev < 5 */ | ||
599 | }; | 599 | }; |
600 | 600 | ||
601 | /* Context information for a noise calculation (Link Quality). */ | 601 | /* Context information for a noise calculation (Link Quality). */ |
@@ -621,6 +621,35 @@ struct b43_key { | |||
621 | u8 algorithm; | 621 | u8 algorithm; |
622 | }; | 622 | }; |
623 | 623 | ||
624 | /* SHM offsets to the QOS data structures for the 4 different queues. */ | ||
625 | #define B43_QOS_PARAMS(queue) (B43_SHM_SH_EDCFQ + \ | ||
626 | (B43_NR_QOSPARAMS * sizeof(u16) * (queue))) | ||
627 | #define B43_QOS_BACKGROUND B43_QOS_PARAMS(0) | ||
628 | #define B43_QOS_BESTEFFORT B43_QOS_PARAMS(1) | ||
629 | #define B43_QOS_VIDEO B43_QOS_PARAMS(2) | ||
630 | #define B43_QOS_VOICE B43_QOS_PARAMS(3) | ||
631 | |||
632 | /* QOS parameter hardware data structure offsets. */ | ||
633 | #define B43_NR_QOSPARAMS 22 | ||
634 | enum { | ||
635 | B43_QOSPARAM_TXOP = 0, | ||
636 | B43_QOSPARAM_CWMIN, | ||
637 | B43_QOSPARAM_CWMAX, | ||
638 | B43_QOSPARAM_CWCUR, | ||
639 | B43_QOSPARAM_AIFS, | ||
640 | B43_QOSPARAM_BSLOTS, | ||
641 | B43_QOSPARAM_REGGAP, | ||
642 | B43_QOSPARAM_STATUS, | ||
643 | }; | ||
644 | |||
645 | /* QOS parameters for a queue. */ | ||
646 | struct b43_qos_params { | ||
647 | /* The QOS parameters */ | ||
648 | struct ieee80211_tx_queue_params p; | ||
649 | /* Does this need to get uploaded to hardware? */ | ||
650 | bool need_hw_update; | ||
651 | }; | ||
652 | |||
624 | struct b43_wldev; | 653 | struct b43_wldev; |
625 | 654 | ||
626 | /* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */ | 655 | /* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */ |
@@ -673,6 +702,12 @@ struct b43_wl { | |||
673 | struct sk_buff *current_beacon; | 702 | struct sk_buff *current_beacon; |
674 | bool beacon0_uploaded; | 703 | bool beacon0_uploaded; |
675 | bool beacon1_uploaded; | 704 | bool beacon1_uploaded; |
705 | |||
706 | /* The current QOS parameters for the 4 queues. | ||
707 | * This is protected by the irq_lock. */ | ||
708 | struct b43_qos_params qos_params[4]; | ||
709 | /* Workqueue for updating QOS parameters in hardware. */ | ||
710 | struct work_struct qos_update_work; | ||
676 | }; | 711 | }; |
677 | 712 | ||
678 | /* In-memory representation of a cached microcode file. */ | 713 | /* In-memory representation of a cached microcode file. */ |
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 3dfb28a34be9..663aed4e9e05 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/delay.h> | 38 | #include <linux/delay.h> |
39 | #include <linux/skbuff.h> | 39 | #include <linux/skbuff.h> |
40 | #include <linux/etherdevice.h> | 40 | #include <linux/etherdevice.h> |
41 | #include <asm/div64.h> | ||
41 | 42 | ||
42 | 43 | ||
43 | /* 32bit DMA ops. */ | 44 | /* 32bit DMA ops. */ |
@@ -291,52 +292,6 @@ static inline int request_slot(struct b43_dmaring *ring) | |||
291 | return slot; | 292 | return slot; |
292 | } | 293 | } |
293 | 294 | ||
294 | /* Mac80211-queue to b43-ring mapping */ | ||
295 | static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev, | ||
296 | int queue_priority) | ||
297 | { | ||
298 | struct b43_dmaring *ring; | ||
299 | |||
300 | /*FIXME: For now we always run on TX-ring-1 */ | ||
301 | return dev->dma.tx_ring1; | ||
302 | |||
303 | /* 0 = highest priority */ | ||
304 | switch (queue_priority) { | ||
305 | default: | ||
306 | B43_WARN_ON(1); | ||
307 | /* fallthrough */ | ||
308 | case 0: | ||
309 | ring = dev->dma.tx_ring3; | ||
310 | break; | ||
311 | case 1: | ||
312 | ring = dev->dma.tx_ring2; | ||
313 | break; | ||
314 | case 2: | ||
315 | ring = dev->dma.tx_ring1; | ||
316 | break; | ||
317 | case 3: | ||
318 | ring = dev->dma.tx_ring0; | ||
319 | break; | ||
320 | } | ||
321 | |||
322 | return ring; | ||
323 | } | ||
324 | |||
325 | /* b43-ring to mac80211-queue mapping */ | ||
326 | static inline int txring_to_priority(struct b43_dmaring *ring) | ||
327 | { | ||
328 | static const u8 idx_to_prio[] = { 3, 2, 1, 0, }; | ||
329 | unsigned int index; | ||
330 | |||
331 | /*FIXME: have only one queue, for now */ | ||
332 | return 0; | ||
333 | |||
334 | index = ring->index; | ||
335 | if (B43_WARN_ON(index >= ARRAY_SIZE(idx_to_prio))) | ||
336 | index = 0; | ||
337 | return idx_to_prio[index]; | ||
338 | } | ||
339 | |||
340 | static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx) | 295 | static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx) |
341 | { | 296 | { |
342 | static const u16 map64[] = { | 297 | static const u16 map64[] = { |
@@ -924,16 +879,52 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, | |||
924 | goto out; | 879 | goto out; |
925 | } | 880 | } |
926 | 881 | ||
882 | #define divide(a, b) ({ \ | ||
883 | typeof(a) __a = a; \ | ||
884 | do_div(__a, b); \ | ||
885 | __a; \ | ||
886 | }) | ||
887 | |||
888 | #define modulo(a, b) ({ \ | ||
889 | typeof(a) __a = a; \ | ||
890 | do_div(__a, b); \ | ||
891 | }) | ||
892 | |||
927 | /* Main cleanup function. */ | 893 | /* Main cleanup function. */ |
928 | static void b43_destroy_dmaring(struct b43_dmaring *ring) | 894 | static void b43_destroy_dmaring(struct b43_dmaring *ring, |
895 | const char *ringname) | ||
929 | { | 896 | { |
930 | if (!ring) | 897 | if (!ring) |
931 | return; | 898 | return; |
932 | 899 | ||
933 | b43dbg(ring->dev->wl, "DMA-%u 0x%04X (%s) max used slots: %d/%d\n", | 900 | #ifdef CONFIG_B43_DEBUG |
934 | (unsigned int)(ring->type), | 901 | { |
935 | ring->mmio_base, | 902 | /* Print some statistics. */ |
936 | (ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots); | 903 | u64 failed_packets = ring->nr_failed_tx_packets; |
904 | u64 succeed_packets = ring->nr_succeed_tx_packets; | ||
905 | u64 nr_packets = failed_packets + succeed_packets; | ||
906 | u64 permille_failed = 0, average_tries = 0; | ||
907 | |||
908 | if (nr_packets) | ||
909 | permille_failed = divide(failed_packets * 1000, nr_packets); | ||
910 | if (nr_packets) | ||
911 | average_tries = divide(ring->nr_total_packet_tries * 100, nr_packets); | ||
912 | |||
913 | b43dbg(ring->dev->wl, "DMA-%u %s: " | ||
914 | "Used slots %d/%d, Failed frames %llu/%llu = %llu.%01llu%%, " | ||
915 | "Average tries %llu.%02llu\n", | ||
916 | (unsigned int)(ring->type), ringname, | ||
917 | ring->max_used_slots, | ||
918 | ring->nr_slots, | ||
919 | (unsigned long long)failed_packets, | ||
920 | (unsigned long long)nr_packets, | ||
921 | (unsigned long long)divide(permille_failed, 10), | ||
922 | (unsigned long long)modulo(permille_failed, 10), | ||
923 | (unsigned long long)divide(average_tries, 100), | ||
924 | (unsigned long long)modulo(average_tries, 100)); | ||
925 | } | ||
926 | #endif /* DEBUG */ | ||
927 | |||
937 | /* Device IRQs are disabled prior entering this function, | 928 | /* Device IRQs are disabled prior entering this function, |
938 | * so no need to take care of concurrency with rx handler stuff. | 929 | * so no need to take care of concurrency with rx handler stuff. |
939 | */ | 930 | */ |
@@ -946,33 +937,26 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring) | |||
946 | kfree(ring); | 937 | kfree(ring); |
947 | } | 938 | } |
948 | 939 | ||
940 | #define destroy_ring(dma, ring) do { \ | ||
941 | b43_destroy_dmaring((dma)->ring, __stringify(ring)); \ | ||
942 | (dma)->ring = NULL; \ | ||
943 | } while (0) | ||
944 | |||
949 | void b43_dma_free(struct b43_wldev *dev) | 945 | void b43_dma_free(struct b43_wldev *dev) |
950 | { | 946 | { |
951 | struct b43_dma *dma = &dev->dma; | 947 | struct b43_dma *dma = &dev->dma; |
952 | 948 | ||
953 | b43_destroy_dmaring(dma->rx_ring3); | 949 | destroy_ring(dma, rx_ring); |
954 | dma->rx_ring3 = NULL; | 950 | destroy_ring(dma, tx_ring_AC_BK); |
955 | b43_destroy_dmaring(dma->rx_ring0); | 951 | destroy_ring(dma, tx_ring_AC_BE); |
956 | dma->rx_ring0 = NULL; | 952 | destroy_ring(dma, tx_ring_AC_VI); |
957 | 953 | destroy_ring(dma, tx_ring_AC_VO); | |
958 | b43_destroy_dmaring(dma->tx_ring5); | 954 | destroy_ring(dma, tx_ring_mcast); |
959 | dma->tx_ring5 = NULL; | ||
960 | b43_destroy_dmaring(dma->tx_ring4); | ||
961 | dma->tx_ring4 = NULL; | ||
962 | b43_destroy_dmaring(dma->tx_ring3); | ||
963 | dma->tx_ring3 = NULL; | ||
964 | b43_destroy_dmaring(dma->tx_ring2); | ||
965 | dma->tx_ring2 = NULL; | ||
966 | b43_destroy_dmaring(dma->tx_ring1); | ||
967 | dma->tx_ring1 = NULL; | ||
968 | b43_destroy_dmaring(dma->tx_ring0); | ||
969 | dma->tx_ring0 = NULL; | ||
970 | } | 955 | } |
971 | 956 | ||
972 | int b43_dma_init(struct b43_wldev *dev) | 957 | int b43_dma_init(struct b43_wldev *dev) |
973 | { | 958 | { |
974 | struct b43_dma *dma = &dev->dma; | 959 | struct b43_dma *dma = &dev->dma; |
975 | struct b43_dmaring *ring; | ||
976 | int err; | 960 | int err; |
977 | u64 dmamask; | 961 | u64 dmamask; |
978 | enum b43_dmatype type; | 962 | enum b43_dmatype type; |
@@ -1002,83 +986,57 @@ int b43_dma_init(struct b43_wldev *dev) | |||
1002 | 986 | ||
1003 | err = -ENOMEM; | 987 | err = -ENOMEM; |
1004 | /* setup TX DMA channels. */ | 988 | /* setup TX DMA channels. */ |
1005 | ring = b43_setup_dmaring(dev, 0, 1, type); | 989 | dma->tx_ring_AC_BK = b43_setup_dmaring(dev, 0, 1, type); |
1006 | if (!ring) | 990 | if (!dma->tx_ring_AC_BK) |
1007 | goto out; | 991 | goto out; |
1008 | dma->tx_ring0 = ring; | ||
1009 | 992 | ||
1010 | ring = b43_setup_dmaring(dev, 1, 1, type); | 993 | dma->tx_ring_AC_BE = b43_setup_dmaring(dev, 1, 1, type); |
1011 | if (!ring) | 994 | if (!dma->tx_ring_AC_BE) |
1012 | goto err_destroy_tx0; | 995 | goto err_destroy_bk; |
1013 | dma->tx_ring1 = ring; | ||
1014 | 996 | ||
1015 | ring = b43_setup_dmaring(dev, 2, 1, type); | 997 | dma->tx_ring_AC_VI = b43_setup_dmaring(dev, 2, 1, type); |
1016 | if (!ring) | 998 | if (!dma->tx_ring_AC_VI) |
1017 | goto err_destroy_tx1; | 999 | goto err_destroy_be; |
1018 | dma->tx_ring2 = ring; | ||
1019 | 1000 | ||
1020 | ring = b43_setup_dmaring(dev, 3, 1, type); | 1001 | dma->tx_ring_AC_VO = b43_setup_dmaring(dev, 3, 1, type); |
1021 | if (!ring) | 1002 | if (!dma->tx_ring_AC_VO) |
1022 | goto err_destroy_tx2; | 1003 | goto err_destroy_vi; |
1023 | dma->tx_ring3 = ring; | ||
1024 | 1004 | ||
1025 | ring = b43_setup_dmaring(dev, 4, 1, type); | 1005 | dma->tx_ring_mcast = b43_setup_dmaring(dev, 4, 1, type); |
1026 | if (!ring) | 1006 | if (!dma->tx_ring_mcast) |
1027 | goto err_destroy_tx3; | 1007 | goto err_destroy_vo; |
1028 | dma->tx_ring4 = ring; | ||
1029 | 1008 | ||
1030 | ring = b43_setup_dmaring(dev, 5, 1, type); | 1009 | /* setup RX DMA channel. */ |
1031 | if (!ring) | 1010 | dma->rx_ring = b43_setup_dmaring(dev, 0, 0, type); |
1032 | goto err_destroy_tx4; | 1011 | if (!dma->rx_ring) |
1033 | dma->tx_ring5 = ring; | 1012 | goto err_destroy_mcast; |
1034 | 1013 | ||
1035 | /* setup RX DMA channels. */ | 1014 | /* No support for the TX status DMA ring. */ |
1036 | ring = b43_setup_dmaring(dev, 0, 0, type); | 1015 | B43_WARN_ON(dev->dev->id.revision < 5); |
1037 | if (!ring) | ||
1038 | goto err_destroy_tx5; | ||
1039 | dma->rx_ring0 = ring; | ||
1040 | |||
1041 | if (dev->dev->id.revision < 5) { | ||
1042 | ring = b43_setup_dmaring(dev, 3, 0, type); | ||
1043 | if (!ring) | ||
1044 | goto err_destroy_rx0; | ||
1045 | dma->rx_ring3 = ring; | ||
1046 | } | ||
1047 | 1016 | ||
1048 | b43dbg(dev->wl, "%u-bit DMA initialized\n", | 1017 | b43dbg(dev->wl, "%u-bit DMA initialized\n", |
1049 | (unsigned int)type); | 1018 | (unsigned int)type); |
1050 | err = 0; | 1019 | err = 0; |
1051 | out: | 1020 | out: |
1052 | return err; | 1021 | return err; |
1053 | 1022 | ||
1054 | err_destroy_rx0: | 1023 | err_destroy_mcast: |
1055 | b43_destroy_dmaring(dma->rx_ring0); | 1024 | destroy_ring(dma, tx_ring_mcast); |
1056 | dma->rx_ring0 = NULL; | 1025 | err_destroy_vo: |
1057 | err_destroy_tx5: | 1026 | destroy_ring(dma, tx_ring_AC_VO); |
1058 | b43_destroy_dmaring(dma->tx_ring5); | 1027 | err_destroy_vi: |
1059 | dma->tx_ring5 = NULL; | 1028 | destroy_ring(dma, tx_ring_AC_VI); |
1060 | err_destroy_tx4: | 1029 | err_destroy_be: |
1061 | b43_destroy_dmaring(dma->tx_ring4); | 1030 | destroy_ring(dma, tx_ring_AC_BE); |
1062 | dma->tx_ring4 = NULL; | 1031 | err_destroy_bk: |
1063 | err_destroy_tx3: | 1032 | destroy_ring(dma, tx_ring_AC_BK); |
1064 | b43_destroy_dmaring(dma->tx_ring3); | 1033 | return err; |
1065 | dma->tx_ring3 = NULL; | ||
1066 | err_destroy_tx2: | ||
1067 | b43_destroy_dmaring(dma->tx_ring2); | ||
1068 | dma->tx_ring2 = NULL; | ||
1069 | err_destroy_tx1: | ||
1070 | b43_destroy_dmaring(dma->tx_ring1); | ||
1071 | dma->tx_ring1 = NULL; | ||
1072 | err_destroy_tx0: | ||
1073 | b43_destroy_dmaring(dma->tx_ring0); | ||
1074 | dma->tx_ring0 = NULL; | ||
1075 | goto out; | ||
1076 | } | 1034 | } |
1077 | 1035 | ||
1078 | /* Generate a cookie for the TX header. */ | 1036 | /* Generate a cookie for the TX header. */ |
1079 | static u16 generate_cookie(struct b43_dmaring *ring, int slot) | 1037 | static u16 generate_cookie(struct b43_dmaring *ring, int slot) |
1080 | { | 1038 | { |
1081 | u16 cookie = 0x1000; | 1039 | u16 cookie; |
1082 | 1040 | ||
1083 | /* Use the upper 4 bits of the cookie as | 1041 | /* Use the upper 4 bits of the cookie as |
1084 | * DMA controller ID and store the slot number | 1042 | * DMA controller ID and store the slot number |
@@ -1088,30 +1046,9 @@ static u16 generate_cookie(struct b43_dmaring *ring, int slot) | |||
1088 | * It can also not be 0xFFFF because that is special | 1046 | * It can also not be 0xFFFF because that is special |
1089 | * for multicast frames. | 1047 | * for multicast frames. |
1090 | */ | 1048 | */ |
1091 | switch (ring->index) { | 1049 | cookie = (((u16)ring->index + 1) << 12); |
1092 | case 0: | ||
1093 | cookie = 0x1000; | ||
1094 | break; | ||
1095 | case 1: | ||
1096 | cookie = 0x2000; | ||
1097 | break; | ||
1098 | case 2: | ||
1099 | cookie = 0x3000; | ||
1100 | break; | ||
1101 | case 3: | ||
1102 | cookie = 0x4000; | ||
1103 | break; | ||
1104 | case 4: | ||
1105 | cookie = 0x5000; | ||
1106 | break; | ||
1107 | case 5: | ||
1108 | cookie = 0x6000; | ||
1109 | break; | ||
1110 | default: | ||
1111 | B43_WARN_ON(1); | ||
1112 | } | ||
1113 | B43_WARN_ON(slot & ~0x0FFF); | 1050 | B43_WARN_ON(slot & ~0x0FFF); |
1114 | cookie |= (u16) slot; | 1051 | cookie |= (u16)slot; |
1115 | 1052 | ||
1116 | return cookie; | 1053 | return cookie; |
1117 | } | 1054 | } |
@@ -1125,22 +1062,19 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot) | |||
1125 | 1062 | ||
1126 | switch (cookie & 0xF000) { | 1063 | switch (cookie & 0xF000) { |
1127 | case 0x1000: | 1064 | case 0x1000: |
1128 | ring = dma->tx_ring0; | 1065 | ring = dma->tx_ring_AC_BK; |
1129 | break; | 1066 | break; |
1130 | case 0x2000: | 1067 | case 0x2000: |
1131 | ring = dma->tx_ring1; | 1068 | ring = dma->tx_ring_AC_BE; |
1132 | break; | 1069 | break; |
1133 | case 0x3000: | 1070 | case 0x3000: |
1134 | ring = dma->tx_ring2; | 1071 | ring = dma->tx_ring_AC_VI; |
1135 | break; | 1072 | break; |
1136 | case 0x4000: | 1073 | case 0x4000: |
1137 | ring = dma->tx_ring3; | 1074 | ring = dma->tx_ring_AC_VO; |
1138 | break; | 1075 | break; |
1139 | case 0x5000: | 1076 | case 0x5000: |
1140 | ring = dma->tx_ring4; | 1077 | ring = dma->tx_ring_mcast; |
1141 | break; | ||
1142 | case 0x6000: | ||
1143 | ring = dma->tx_ring5; | ||
1144 | break; | 1078 | break; |
1145 | default: | 1079 | default: |
1146 | B43_WARN_ON(1); | 1080 | B43_WARN_ON(1); |
@@ -1272,6 +1206,37 @@ static inline int should_inject_overflow(struct b43_dmaring *ring) | |||
1272 | return 0; | 1206 | return 0; |
1273 | } | 1207 | } |
1274 | 1208 | ||
1209 | /* Static mapping of mac80211's queues (priorities) to b43 DMA rings. */ | ||
1210 | static struct b43_dmaring * select_ring_by_priority(struct b43_wldev *dev, | ||
1211 | u8 queue_prio) | ||
1212 | { | ||
1213 | struct b43_dmaring *ring; | ||
1214 | |||
1215 | if (b43_modparam_qos) { | ||
1216 | /* 0 = highest priority */ | ||
1217 | switch (queue_prio) { | ||
1218 | default: | ||
1219 | B43_WARN_ON(1); | ||
1220 | /* fallthrough */ | ||
1221 | case 0: | ||
1222 | ring = dev->dma.tx_ring_AC_VO; | ||
1223 | break; | ||
1224 | case 1: | ||
1225 | ring = dev->dma.tx_ring_AC_VI; | ||
1226 | break; | ||
1227 | case 2: | ||
1228 | ring = dev->dma.tx_ring_AC_BE; | ||
1229 | break; | ||
1230 | case 3: | ||
1231 | ring = dev->dma.tx_ring_AC_BK; | ||
1232 | break; | ||
1233 | } | ||
1234 | } else | ||
1235 | ring = dev->dma.tx_ring_AC_BE; | ||
1236 | |||
1237 | return ring; | ||
1238 | } | ||
1239 | |||
1275 | int b43_dma_tx(struct b43_wldev *dev, | 1240 | int b43_dma_tx(struct b43_wldev *dev, |
1276 | struct sk_buff *skb, struct ieee80211_tx_control *ctl) | 1241 | struct sk_buff *skb, struct ieee80211_tx_control *ctl) |
1277 | { | 1242 | { |
@@ -1288,13 +1253,13 @@ int b43_dma_tx(struct b43_wldev *dev, | |||
1288 | hdr = (struct ieee80211_hdr *)skb->data; | 1253 | hdr = (struct ieee80211_hdr *)skb->data; |
1289 | if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { | 1254 | if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { |
1290 | /* The multicast ring will be sent after the DTIM */ | 1255 | /* The multicast ring will be sent after the DTIM */ |
1291 | ring = dev->dma.tx_ring4; | 1256 | ring = dev->dma.tx_ring_mcast; |
1292 | /* Set the more-data bit. Ucode will clear it on | 1257 | /* Set the more-data bit. Ucode will clear it on |
1293 | * the last frame for us. */ | 1258 | * the last frame for us. */ |
1294 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); | 1259 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); |
1295 | } else { | 1260 | } else { |
1296 | /* Decide by priority where to put this frame. */ | 1261 | /* Decide by priority where to put this frame. */ |
1297 | ring = priority_to_txring(dev, ctl->queue); | 1262 | ring = select_ring_by_priority(dev, ctl->queue); |
1298 | } | 1263 | } |
1299 | 1264 | ||
1300 | spin_lock_irqsave(&ring->lock, flags); | 1265 | spin_lock_irqsave(&ring->lock, flags); |
@@ -1309,6 +1274,11 @@ int b43_dma_tx(struct b43_wldev *dev, | |||
1309 | * That would be a mac80211 bug. */ | 1274 | * That would be a mac80211 bug. */ |
1310 | B43_WARN_ON(ring->stopped); | 1275 | B43_WARN_ON(ring->stopped); |
1311 | 1276 | ||
1277 | /* Assign the queue number to the ring (if not already done before) | ||
1278 | * so TX status handling can use it. The queue to ring mapping is | ||
1279 | * static, so we don't need to store it per frame. */ | ||
1280 | ring->queue_prio = ctl->queue; | ||
1281 | |||
1312 | err = dma_tx_fragment(ring, skb, ctl); | 1282 | err = dma_tx_fragment(ring, skb, ctl); |
1313 | if (unlikely(err == -ENOKEY)) { | 1283 | if (unlikely(err == -ENOKEY)) { |
1314 | /* Drop this packet, as we don't have the encryption key | 1284 | /* Drop this packet, as we don't have the encryption key |
@@ -1325,7 +1295,7 @@ int b43_dma_tx(struct b43_wldev *dev, | |||
1325 | if ((free_slots(ring) < SLOTS_PER_PACKET) || | 1295 | if ((free_slots(ring) < SLOTS_PER_PACKET) || |
1326 | should_inject_overflow(ring)) { | 1296 | should_inject_overflow(ring)) { |
1327 | /* This TX ring is full. */ | 1297 | /* This TX ring is full. */ |
1328 | ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring)); | 1298 | ieee80211_stop_queue(dev->wl->hw, ctl->queue); |
1329 | ring->stopped = 1; | 1299 | ring->stopped = 1; |
1330 | if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { | 1300 | if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { |
1331 | b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); | 1301 | b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); |
@@ -1337,6 +1307,38 @@ out_unlock: | |||
1337 | return err; | 1307 | return err; |
1338 | } | 1308 | } |
1339 | 1309 | ||
1310 | static void b43_fill_txstatus_report(struct b43_dmaring *ring, | ||
1311 | struct ieee80211_tx_status *report, | ||
1312 | const struct b43_txstatus *status) | ||
1313 | { | ||
1314 | bool frame_failed = 0; | ||
1315 | |||
1316 | if (status->acked) { | ||
1317 | /* The frame was ACKed. */ | ||
1318 | report->flags |= IEEE80211_TX_STATUS_ACK; | ||
1319 | } else { | ||
1320 | /* The frame was not ACKed... */ | ||
1321 | if (!(report->control.flags & IEEE80211_TXCTL_NO_ACK)) { | ||
1322 | /* ...but we expected an ACK. */ | ||
1323 | frame_failed = 1; | ||
1324 | report->excessive_retries = 1; | ||
1325 | } | ||
1326 | } | ||
1327 | if (status->frame_count == 0) { | ||
1328 | /* The frame was not transmitted at all. */ | ||
1329 | report->retry_count = 0; | ||
1330 | } else { | ||
1331 | report->retry_count = status->frame_count - 1; | ||
1332 | #ifdef CONFIG_B43_DEBUG | ||
1333 | if (frame_failed) | ||
1334 | ring->nr_failed_tx_packets++; | ||
1335 | else | ||
1336 | ring->nr_succeed_tx_packets++; | ||
1337 | ring->nr_total_packet_tries += status->frame_count; | ||
1338 | #endif /* DEBUG */ | ||
1339 | } | ||
1340 | } | ||
1341 | |||
1340 | void b43_dma_handle_txstatus(struct b43_wldev *dev, | 1342 | void b43_dma_handle_txstatus(struct b43_wldev *dev, |
1341 | const struct b43_txstatus *status) | 1343 | const struct b43_txstatus *status) |
1342 | { | 1344 | { |
@@ -1371,18 +1373,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, | |||
1371 | * status of the transmission. | 1373 | * status of the transmission. |
1372 | * Some fields of txstat are already filled in dma_tx(). | 1374 | * Some fields of txstat are already filled in dma_tx(). |
1373 | */ | 1375 | */ |
1374 | if (status->acked) { | 1376 | b43_fill_txstatus_report(ring, &(meta->txstat), status); |
1375 | meta->txstat.flags |= IEEE80211_TX_STATUS_ACK; | ||
1376 | } else { | ||
1377 | if (!(meta->txstat.control.flags | ||
1378 | & IEEE80211_TXCTL_NO_ACK)) | ||
1379 | meta->txstat.excessive_retries = 1; | ||
1380 | } | ||
1381 | if (status->frame_count == 0) { | ||
1382 | /* The frame was not transmitted at all. */ | ||
1383 | meta->txstat.retry_count = 0; | ||
1384 | } else | ||
1385 | meta->txstat.retry_count = status->frame_count - 1; | ||
1386 | ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb, | 1377 | ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb, |
1387 | &(meta->txstat)); | 1378 | &(meta->txstat)); |
1388 | /* skb is freed by ieee80211_tx_status_irqsafe() */ | 1379 | /* skb is freed by ieee80211_tx_status_irqsafe() */ |
@@ -1404,7 +1395,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, | |||
1404 | dev->stats.last_tx = jiffies; | 1395 | dev->stats.last_tx = jiffies; |
1405 | if (ring->stopped) { | 1396 | if (ring->stopped) { |
1406 | B43_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET); | 1397 | B43_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET); |
1407 | ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring)); | 1398 | ieee80211_wake_queue(dev->wl->hw, ring->queue_prio); |
1408 | ring->stopped = 0; | 1399 | ring->stopped = 0; |
1409 | if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { | 1400 | if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { |
1410 | b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); | 1401 | b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); |
@@ -1425,7 +1416,7 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev, | |||
1425 | 1416 | ||
1426 | for (i = 0; i < nr_queues; i++) { | 1417 | for (i = 0; i < nr_queues; i++) { |
1427 | data = &(stats->data[i]); | 1418 | data = &(stats->data[i]); |
1428 | ring = priority_to_txring(dev, i); | 1419 | ring = select_ring_by_priority(dev, i); |
1429 | 1420 | ||
1430 | spin_lock_irqsave(&ring->lock, flags); | 1421 | spin_lock_irqsave(&ring->lock, flags); |
1431 | data->len = ring->used_slots / SLOTS_PER_PACKET; | 1422 | data->len = ring->used_slots / SLOTS_PER_PACKET; |
@@ -1451,25 +1442,6 @@ static void dma_rx(struct b43_dmaring *ring, int *slot) | |||
1451 | sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize); | 1442 | sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize); |
1452 | skb = meta->skb; | 1443 | skb = meta->skb; |
1453 | 1444 | ||
1454 | if (ring->index == 3) { | ||
1455 | /* We received an xmit status. */ | ||
1456 | struct b43_hwtxstatus *hw = (struct b43_hwtxstatus *)skb->data; | ||
1457 | int i = 0; | ||
1458 | |||
1459 | while (hw->cookie == 0) { | ||
1460 | if (i > 100) | ||
1461 | break; | ||
1462 | i++; | ||
1463 | udelay(2); | ||
1464 | barrier(); | ||
1465 | } | ||
1466 | b43_handle_hwtxstatus(ring->dev, hw); | ||
1467 | /* recycle the descriptor buffer. */ | ||
1468 | sync_descbuffer_for_device(ring, meta->dmaaddr, | ||
1469 | ring->rx_buffersize); | ||
1470 | |||
1471 | return; | ||
1472 | } | ||
1473 | rxhdr = (struct b43_rxhdr_fw4 *)skb->data; | 1445 | rxhdr = (struct b43_rxhdr_fw4 *)skb->data; |
1474 | len = le16_to_cpu(rxhdr->frame_len); | 1446 | len = le16_to_cpu(rxhdr->frame_len); |
1475 | if (len == 0) { | 1447 | if (len == 0) { |
@@ -1526,7 +1498,7 @@ static void dma_rx(struct b43_dmaring *ring, int *slot) | |||
1526 | skb_pull(skb, ring->frameoffset); | 1498 | skb_pull(skb, ring->frameoffset); |
1527 | 1499 | ||
1528 | b43_rx(ring->dev, skb, rxhdr); | 1500 | b43_rx(ring->dev, skb, rxhdr); |
1529 | drop: | 1501 | drop: |
1530 | return; | 1502 | return; |
1531 | } | 1503 | } |
1532 | 1504 | ||
@@ -1572,21 +1544,19 @@ static void b43_dma_tx_resume_ring(struct b43_dmaring *ring) | |||
1572 | void b43_dma_tx_suspend(struct b43_wldev *dev) | 1544 | void b43_dma_tx_suspend(struct b43_wldev *dev) |
1573 | { | 1545 | { |
1574 | b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); | 1546 | b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); |
1575 | b43_dma_tx_suspend_ring(dev->dma.tx_ring0); | 1547 | b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_BK); |
1576 | b43_dma_tx_suspend_ring(dev->dma.tx_ring1); | 1548 | b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_BE); |
1577 | b43_dma_tx_suspend_ring(dev->dma.tx_ring2); | 1549 | b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_VI); |
1578 | b43_dma_tx_suspend_ring(dev->dma.tx_ring3); | 1550 | b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_VO); |
1579 | b43_dma_tx_suspend_ring(dev->dma.tx_ring4); | 1551 | b43_dma_tx_suspend_ring(dev->dma.tx_ring_mcast); |
1580 | b43_dma_tx_suspend_ring(dev->dma.tx_ring5); | ||
1581 | } | 1552 | } |
1582 | 1553 | ||
1583 | void b43_dma_tx_resume(struct b43_wldev *dev) | 1554 | void b43_dma_tx_resume(struct b43_wldev *dev) |
1584 | { | 1555 | { |
1585 | b43_dma_tx_resume_ring(dev->dma.tx_ring5); | 1556 | b43_dma_tx_resume_ring(dev->dma.tx_ring_mcast); |
1586 | b43_dma_tx_resume_ring(dev->dma.tx_ring4); | 1557 | b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_VO); |
1587 | b43_dma_tx_resume_ring(dev->dma.tx_ring3); | 1558 | b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_VI); |
1588 | b43_dma_tx_resume_ring(dev->dma.tx_ring2); | 1559 | b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_BE); |
1589 | b43_dma_tx_resume_ring(dev->dma.tx_ring1); | 1560 | b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_BK); |
1590 | b43_dma_tx_resume_ring(dev->dma.tx_ring0); | ||
1591 | b43_power_saving_ctl_bits(dev, 0); | 1561 | b43_power_saving_ctl_bits(dev, 0); |
1592 | } | 1562 | } |
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index c0d6b69e6501..ea27085dec0e 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h | |||
@@ -245,6 +245,9 @@ struct b43_dmaring { | |||
245 | enum b43_dmatype type; | 245 | enum b43_dmatype type; |
246 | /* Boolean. Is this ring stopped at ieee80211 level? */ | 246 | /* Boolean. Is this ring stopped at ieee80211 level? */ |
247 | bool stopped; | 247 | bool stopped; |
248 | /* The QOS priority assigned to this ring. Only used for TX rings. | ||
249 | * This is the mac80211 "queue" value. */ | ||
250 | u8 queue_prio; | ||
248 | /* Lock, only used for TX. */ | 251 | /* Lock, only used for TX. */ |
249 | spinlock_t lock; | 252 | spinlock_t lock; |
250 | struct b43_wldev *dev; | 253 | struct b43_wldev *dev; |
@@ -253,7 +256,13 @@ struct b43_dmaring { | |||
253 | int max_used_slots; | 256 | int max_used_slots; |
254 | /* Last time we injected a ring overflow. */ | 257 | /* Last time we injected a ring overflow. */ |
255 | unsigned long last_injected_overflow; | 258 | unsigned long last_injected_overflow; |
256 | #endif /* CONFIG_B43_DEBUG */ | 259 | /* Statistics: Number of successfully transmitted packets */ |
260 | u64 nr_succeed_tx_packets; | ||
261 | /* Statistics: Number of failed TX packets */ | ||
262 | u64 nr_failed_tx_packets; | ||
263 | /* Statistics: Total number of TX plus all retries. */ | ||
264 | u64 nr_total_packet_tries; | ||
265 | #endif /* CONFIG_B43_DEBUG */ | ||
257 | }; | 266 | }; |
258 | 267 | ||
259 | static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset) | 268 | static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset) |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index f745308faaad..694e29570e5d 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -78,6 +78,11 @@ static int modparam_nohwcrypt; | |||
78 | module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); | 78 | module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); |
79 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); | 79 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); |
80 | 80 | ||
81 | int b43_modparam_qos = 1; | ||
82 | module_param_named(qos, b43_modparam_qos, int, 0444); | ||
83 | MODULE_PARM_DESC(qos, "Enable QOS support (default on)"); | ||
84 | |||
85 | |||
81 | static const struct ssb_device_id b43_ssb_tbl[] = { | 86 | static const struct ssb_device_id b43_ssb_tbl[] = { |
82 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5), | 87 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5), |
83 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6), | 88 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6), |
@@ -1589,11 +1594,10 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) | |||
1589 | 1594 | ||
1590 | /* Check the DMA reason registers for received data. */ | 1595 | /* Check the DMA reason registers for received data. */ |
1591 | if (dma_reason[0] & B43_DMAIRQ_RX_DONE) | 1596 | if (dma_reason[0] & B43_DMAIRQ_RX_DONE) |
1592 | b43_dma_rx(dev->dma.rx_ring0); | 1597 | b43_dma_rx(dev->dma.rx_ring); |
1593 | if (dma_reason[3] & B43_DMAIRQ_RX_DONE) | ||
1594 | b43_dma_rx(dev->dma.rx_ring3); | ||
1595 | B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE); | 1598 | B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE); |
1596 | B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE); | 1599 | B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE); |
1600 | B43_WARN_ON(dma_reason[3] & B43_DMAIRQ_RX_DONE); | ||
1597 | B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE); | 1601 | B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE); |
1598 | B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE); | 1602 | B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE); |
1599 | 1603 | ||
@@ -2708,10 +2712,178 @@ out: | |||
2708 | return NETDEV_TX_OK; | 2712 | return NETDEV_TX_OK; |
2709 | } | 2713 | } |
2710 | 2714 | ||
2715 | /* Locking: wl->irq_lock */ | ||
2716 | static void b43_qos_params_upload(struct b43_wldev *dev, | ||
2717 | const struct ieee80211_tx_queue_params *p, | ||
2718 | u16 shm_offset) | ||
2719 | { | ||
2720 | u16 params[B43_NR_QOSPARAMS]; | ||
2721 | int cw_min, cw_max, aifs, bslots, tmp; | ||
2722 | unsigned int i; | ||
2723 | |||
2724 | const u16 aCWmin = 0x0001; | ||
2725 | const u16 aCWmax = 0x03FF; | ||
2726 | |||
2727 | /* Calculate the default values for the parameters, if needed. */ | ||
2728 | switch (shm_offset) { | ||
2729 | case B43_QOS_VOICE: | ||
2730 | aifs = (p->aifs == -1) ? 2 : p->aifs; | ||
2731 | cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 4 - 1) : p->cw_min; | ||
2732 | cw_max = (p->cw_max == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_max; | ||
2733 | break; | ||
2734 | case B43_QOS_VIDEO: | ||
2735 | aifs = (p->aifs == -1) ? 2 : p->aifs; | ||
2736 | cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_min; | ||
2737 | cw_max = (p->cw_max == 0) ? aCWmin : p->cw_max; | ||
2738 | break; | ||
2739 | case B43_QOS_BESTEFFORT: | ||
2740 | aifs = (p->aifs == -1) ? 3 : p->aifs; | ||
2741 | cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min; | ||
2742 | cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max; | ||
2743 | break; | ||
2744 | case B43_QOS_BACKGROUND: | ||
2745 | aifs = (p->aifs == -1) ? 7 : p->aifs; | ||
2746 | cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min; | ||
2747 | cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max; | ||
2748 | break; | ||
2749 | default: | ||
2750 | B43_WARN_ON(1); | ||
2751 | return; | ||
2752 | } | ||
2753 | if (cw_min <= 0) | ||
2754 | cw_min = aCWmin; | ||
2755 | if (cw_max <= 0) | ||
2756 | cw_max = aCWmin; | ||
2757 | bslots = b43_read16(dev, B43_MMIO_RNG) % cw_min; | ||
2758 | |||
2759 | memset(¶ms, 0, sizeof(params)); | ||
2760 | |||
2761 | params[B43_QOSPARAM_TXOP] = p->txop * 32; | ||
2762 | params[B43_QOSPARAM_CWMIN] = cw_min; | ||
2763 | params[B43_QOSPARAM_CWMAX] = cw_max; | ||
2764 | params[B43_QOSPARAM_CWCUR] = cw_min; | ||
2765 | params[B43_QOSPARAM_AIFS] = aifs; | ||
2766 | params[B43_QOSPARAM_BSLOTS] = bslots; | ||
2767 | params[B43_QOSPARAM_REGGAP] = bslots + aifs; | ||
2768 | |||
2769 | for (i = 0; i < ARRAY_SIZE(params); i++) { | ||
2770 | if (i == B43_QOSPARAM_STATUS) { | ||
2771 | tmp = b43_shm_read16(dev, B43_SHM_SHARED, | ||
2772 | shm_offset + (i * 2)); | ||
2773 | /* Mark the parameters as updated. */ | ||
2774 | tmp |= 0x100; | ||
2775 | b43_shm_write16(dev, B43_SHM_SHARED, | ||
2776 | shm_offset + (i * 2), | ||
2777 | tmp); | ||
2778 | } else { | ||
2779 | b43_shm_write16(dev, B43_SHM_SHARED, | ||
2780 | shm_offset + (i * 2), | ||
2781 | params[i]); | ||
2782 | } | ||
2783 | } | ||
2784 | } | ||
2785 | |||
2786 | /* Update the QOS parameters in hardware. */ | ||
2787 | static void b43_qos_update(struct b43_wldev *dev) | ||
2788 | { | ||
2789 | struct b43_wl *wl = dev->wl; | ||
2790 | struct b43_qos_params *params; | ||
2791 | unsigned long flags; | ||
2792 | unsigned int i; | ||
2793 | |||
2794 | /* Mapping of mac80211 queues to b43 SHM offsets. */ | ||
2795 | static const u16 qos_shm_offsets[] = { | ||
2796 | [0] = B43_QOS_VOICE, | ||
2797 | [1] = B43_QOS_VIDEO, | ||
2798 | [2] = B43_QOS_BESTEFFORT, | ||
2799 | [3] = B43_QOS_BACKGROUND, | ||
2800 | }; | ||
2801 | BUILD_BUG_ON(ARRAY_SIZE(qos_shm_offsets) != ARRAY_SIZE(wl->qos_params)); | ||
2802 | |||
2803 | b43_mac_suspend(dev); | ||
2804 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
2805 | |||
2806 | for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) { | ||
2807 | params = &(wl->qos_params[i]); | ||
2808 | if (params->need_hw_update) { | ||
2809 | b43_qos_params_upload(dev, &(params->p), | ||
2810 | qos_shm_offsets[i]); | ||
2811 | params->need_hw_update = 0; | ||
2812 | } | ||
2813 | } | ||
2814 | |||
2815 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
2816 | b43_mac_enable(dev); | ||
2817 | } | ||
2818 | |||
2819 | static void b43_qos_clear(struct b43_wl *wl) | ||
2820 | { | ||
2821 | struct b43_qos_params *params; | ||
2822 | unsigned int i; | ||
2823 | |||
2824 | for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) { | ||
2825 | params = &(wl->qos_params[i]); | ||
2826 | |||
2827 | memset(&(params->p), 0, sizeof(params->p)); | ||
2828 | params->p.aifs = -1; | ||
2829 | params->need_hw_update = 1; | ||
2830 | } | ||
2831 | } | ||
2832 | |||
2833 | /* Initialize the core's QOS capabilities */ | ||
2834 | static void b43_qos_init(struct b43_wldev *dev) | ||
2835 | { | ||
2836 | struct b43_wl *wl = dev->wl; | ||
2837 | unsigned int i; | ||
2838 | |||
2839 | /* Upload the current QOS parameters. */ | ||
2840 | for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) | ||
2841 | wl->qos_params[i].need_hw_update = 1; | ||
2842 | b43_qos_update(dev); | ||
2843 | |||
2844 | /* Enable QOS support. */ | ||
2845 | b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF); | ||
2846 | b43_write16(dev, B43_MMIO_IFSCTL, | ||
2847 | b43_read16(dev, B43_MMIO_IFSCTL) | ||
2848 | | B43_MMIO_IFSCTL_USE_EDCF); | ||
2849 | } | ||
2850 | |||
2851 | static void b43_qos_update_work(struct work_struct *work) | ||
2852 | { | ||
2853 | struct b43_wl *wl = container_of(work, struct b43_wl, qos_update_work); | ||
2854 | struct b43_wldev *dev; | ||
2855 | |||
2856 | mutex_lock(&wl->mutex); | ||
2857 | dev = wl->current_dev; | ||
2858 | if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) | ||
2859 | b43_qos_update(dev); | ||
2860 | mutex_unlock(&wl->mutex); | ||
2861 | } | ||
2862 | |||
2711 | static int b43_op_conf_tx(struct ieee80211_hw *hw, | 2863 | static int b43_op_conf_tx(struct ieee80211_hw *hw, |
2712 | int queue, | 2864 | int _queue, |
2713 | const struct ieee80211_tx_queue_params *params) | 2865 | const struct ieee80211_tx_queue_params *params) |
2714 | { | 2866 | { |
2867 | struct b43_wl *wl = hw_to_b43_wl(hw); | ||
2868 | unsigned long flags; | ||
2869 | unsigned int queue = (unsigned int)_queue; | ||
2870 | struct b43_qos_params *p; | ||
2871 | |||
2872 | if (queue >= ARRAY_SIZE(wl->qos_params)) { | ||
2873 | /* Queue not available or don't support setting | ||
2874 | * params on this queue. Return success to not | ||
2875 | * confuse mac80211. */ | ||
2876 | return 0; | ||
2877 | } | ||
2878 | |||
2879 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
2880 | p = &(wl->qos_params[queue]); | ||
2881 | memcpy(&(p->p), params, sizeof(p->p)); | ||
2882 | p->need_hw_update = 1; | ||
2883 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
2884 | |||
2885 | queue_work(hw->workqueue, &wl->qos_update_work); | ||
2886 | |||
2715 | return 0; | 2887 | return 0; |
2716 | } | 2888 | } |
2717 | 2889 | ||
@@ -3732,6 +3904,7 @@ static int b43_op_start(struct ieee80211_hw *hw) | |||
3732 | memset(wl->mac_addr, 0, ETH_ALEN); | 3904 | memset(wl->mac_addr, 0, ETH_ALEN); |
3733 | wl->filter_flags = 0; | 3905 | wl->filter_flags = 0; |
3734 | wl->radiotap_enabled = 0; | 3906 | wl->radiotap_enabled = 0; |
3907 | b43_qos_clear(wl); | ||
3735 | 3908 | ||
3736 | /* First register RFkill. | 3909 | /* First register RFkill. |
3737 | * LEDs that are registered later depend on it. */ | 3910 | * LEDs that are registered later depend on it. */ |
@@ -3773,6 +3946,7 @@ static void b43_op_stop(struct ieee80211_hw *hw) | |||
3773 | struct b43_wldev *dev = wl->current_dev; | 3946 | struct b43_wldev *dev = wl->current_dev; |
3774 | 3947 | ||
3775 | b43_rfkill_exit(dev); | 3948 | b43_rfkill_exit(dev); |
3949 | cancel_work_sync(&(wl->qos_update_work)); | ||
3776 | 3950 | ||
3777 | mutex_lock(&wl->mutex); | 3951 | mutex_lock(&wl->mutex); |
3778 | if (b43_status(dev) >= B43_STAT_STARTED) | 3952 | if (b43_status(dev) >= B43_STAT_STARTED) |
@@ -3835,6 +4009,16 @@ static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw, | |||
3835 | return 0; | 4009 | return 0; |
3836 | } | 4010 | } |
3837 | 4011 | ||
4012 | static void b43_op_sta_notify(struct ieee80211_hw *hw, | ||
4013 | struct ieee80211_vif *vif, | ||
4014 | enum sta_notify_cmd notify_cmd, | ||
4015 | const u8 *addr) | ||
4016 | { | ||
4017 | struct b43_wl *wl = hw_to_b43_wl(hw); | ||
4018 | |||
4019 | B43_WARN_ON(!vif || wl->vif != vif); | ||
4020 | } | ||
4021 | |||
3838 | static const struct ieee80211_ops b43_hw_ops = { | 4022 | static const struct ieee80211_ops b43_hw_ops = { |
3839 | .tx = b43_op_tx, | 4023 | .tx = b43_op_tx, |
3840 | .conf_tx = b43_op_conf_tx, | 4024 | .conf_tx = b43_op_conf_tx, |
@@ -3851,6 +4035,7 @@ static const struct ieee80211_ops b43_hw_ops = { | |||
3851 | .set_retry_limit = b43_op_set_retry_limit, | 4035 | .set_retry_limit = b43_op_set_retry_limit, |
3852 | .set_tim = b43_op_beacon_set_tim, | 4036 | .set_tim = b43_op_beacon_set_tim, |
3853 | .beacon_update = b43_op_ibss_beacon_update, | 4037 | .beacon_update = b43_op_ibss_beacon_update, |
4038 | .sta_notify = b43_op_sta_notify, | ||
3854 | }; | 4039 | }; |
3855 | 4040 | ||
3856 | /* Hard-reset the chip. Do not call this directly. | 4041 | /* Hard-reset the chip. Do not call this directly. |
@@ -4122,7 +4307,7 @@ static int b43_wireless_init(struct ssb_device *dev) | |||
4122 | hw->max_signal = 100; | 4307 | hw->max_signal = 100; |
4123 | hw->max_rssi = -110; | 4308 | hw->max_rssi = -110; |
4124 | hw->max_noise = -110; | 4309 | hw->max_noise = -110; |
4125 | hw->queues = 1; /* FIXME: hardware has more queues */ | 4310 | hw->queues = b43_modparam_qos ? 4 : 1; |
4126 | SET_IEEE80211_DEV(hw, dev->dev); | 4311 | SET_IEEE80211_DEV(hw, dev->dev); |
4127 | if (is_valid_ether_addr(sprom->et1mac)) | 4312 | if (is_valid_ether_addr(sprom->et1mac)) |
4128 | SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); | 4313 | SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); |
@@ -4138,6 +4323,7 @@ static int b43_wireless_init(struct ssb_device *dev) | |||
4138 | spin_lock_init(&wl->shm_lock); | 4323 | spin_lock_init(&wl->shm_lock); |
4139 | mutex_init(&wl->mutex); | 4324 | mutex_init(&wl->mutex); |
4140 | INIT_LIST_HEAD(&wl->devlist); | 4325 | INIT_LIST_HEAD(&wl->devlist); |
4326 | INIT_WORK(&wl->qos_update_work, b43_qos_update_work); | ||
4141 | 4327 | ||
4142 | ssb_set_devtypedata(dev, wl); | 4328 | ssb_set_devtypedata(dev, wl); |
4143 | b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); | 4329 | b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); |
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 24a79f5d6ff5..1197975f9207 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h | |||
@@ -38,6 +38,10 @@ | |||
38 | /* Magic helper macro to pad structures. Ignore those above. It's magic. */ | 38 | /* Magic helper macro to pad structures. Ignore those above. It's magic. */ |
39 | #define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) | 39 | #define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) |
40 | 40 | ||
41 | |||
42 | extern int b43_modparam_qos; | ||
43 | |||
44 | |||
41 | /* Lightweight function to convert a frequency (in Mhz) to a channel number. */ | 45 | /* Lightweight function to convert a frequency (in Mhz) to a channel number. */ |
42 | static inline u8 b43_freq_to_channel_5ghz(int freq) | 46 | static inline u8 b43_freq_to_channel_5ghz(int freq) |
43 | { | 47 | { |
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 187c11bee0f1..ec10a8e182f9 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c | |||
@@ -705,30 +705,3 @@ void b43_tx_resume(struct b43_wldev *dev) | |||
705 | { | 705 | { |
706 | b43_dma_tx_resume(dev); | 706 | b43_dma_tx_resume(dev); |
707 | } | 707 | } |
708 | |||
709 | #if 0 | ||
710 | static void upload_qos_parms(struct b43_wldev *dev, | ||
711 | const u16 * parms, u16 offset) | ||
712 | { | ||
713 | int i; | ||
714 | |||
715 | for (i = 0; i < B43_NR_QOSPARMS; i++) { | ||
716 | b43_shm_write16(dev, B43_SHM_SHARED, | ||
717 | offset + (i * 2), parms[i]); | ||
718 | } | ||
719 | } | ||
720 | #endif | ||
721 | |||
722 | /* Initialize the QoS parameters */ | ||
723 | void b43_qos_init(struct b43_wldev *dev) | ||
724 | { | ||
725 | /* FIXME: This function must probably be called from the mac80211 | ||
726 | * config callback. */ | ||
727 | return; | ||
728 | |||
729 | b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF); | ||
730 | //FIXME kill magic | ||
731 | b43_write16(dev, 0x688, b43_read16(dev, 0x688) | 0x4); | ||
732 | |||
733 | /*TODO: We might need some stack support here to get the values. */ | ||
734 | } | ||
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index 41765039552b..bf58a8a85258 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h | |||
@@ -302,18 +302,6 @@ void b43_handle_hwtxstatus(struct b43_wldev *dev, | |||
302 | void b43_tx_suspend(struct b43_wldev *dev); | 302 | void b43_tx_suspend(struct b43_wldev *dev); |
303 | void b43_tx_resume(struct b43_wldev *dev); | 303 | void b43_tx_resume(struct b43_wldev *dev); |
304 | 304 | ||
305 | #define B43_NR_QOSPARMS 22 | ||
306 | enum { | ||
307 | B43_QOSPARM_TXOP = 0, | ||
308 | B43_QOSPARM_CWMIN, | ||
309 | B43_QOSPARM_CWMAX, | ||
310 | B43_QOSPARM_CWCUR, | ||
311 | B43_QOSPARM_AIFS, | ||
312 | B43_QOSPARM_BSLOTS, | ||
313 | B43_QOSPARM_REGGAP, | ||
314 | B43_QOSPARM_STATUS, | ||
315 | }; | ||
316 | void b43_qos_init(struct b43_wldev *dev); | ||
317 | 305 | ||
318 | /* Helper functions for converting the key-table index from "firmware-format" | 306 | /* Helper functions for converting the key-table index from "firmware-format" |
319 | * to "raw-format" and back. The firmware API changed for this at some revision. | 307 | * to "raw-format" and back. The firmware API changed for this at some revision. |
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 24c3e3ddafc6..5b7c0160e1fa 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig | |||
@@ -1,7 +1,12 @@ | |||
1 | config IWLCORE | ||
2 | tristate "Intel Wireless Wifi Core" | ||
3 | depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL | ||
4 | |||
1 | config IWL4965 | 5 | config IWL4965 |
2 | tristate "Intel Wireless WiFi 4965AGN" | 6 | tristate "Intel Wireless WiFi 4965AGN" |
3 | depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL | 7 | depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL |
4 | select FW_LOADER | 8 | select FW_LOADER |
9 | select IWLCORE | ||
5 | ---help--- | 10 | ---help--- |
6 | Select to build the driver supporting the: | 11 | Select to build the driver supporting the: |
7 | 12 | ||
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 3bbd38358d53..6b85cca9b3f1 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile | |||
@@ -1,3 +1,6 @@ | |||
1 | obj-$(CONFIG_IWLCORE) += iwlcore.o | ||
2 | iwlcore-objs = iwl-core.o | ||
3 | |||
1 | obj-$(CONFIG_IWL3945) += iwl3945.o | 4 | obj-$(CONFIG_IWL3945) += iwl3945.o |
2 | iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o | 5 | iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o |
3 | 6 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h index 20fbb32c33bd..8b7ef9f1b57b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h | |||
@@ -666,26 +666,26 @@ struct iwl3945_rx_frame_hdr { | |||
666 | u8 payload[0]; | 666 | u8 payload[0]; |
667 | } __attribute__ ((packed)); | 667 | } __attribute__ ((packed)); |
668 | 668 | ||
669 | #define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0) | 669 | #define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0) |
670 | #define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1) | 670 | #define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1) |
671 | 671 | ||
672 | #define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0) | 672 | #define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0) |
673 | #define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1) | 673 | #define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1) |
674 | #define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2) | 674 | #define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2) |
675 | #define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3) | 675 | #define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3) |
676 | #define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0) | 676 | #define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0) |
677 | 677 | ||
678 | #define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) | 678 | #define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) |
679 | #define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) | 679 | #define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) |
680 | #define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8) | 680 | #define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8) |
681 | #define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8) | 681 | #define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8) |
682 | #define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8) | 682 | #define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8) |
683 | 683 | ||
684 | #define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11) | 684 | #define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11) |
685 | #define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11) | 685 | #define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11) |
686 | #define RX_RES_STATUS_DECRYPT_OK (0x3 << 11) | 686 | #define RX_RES_STATUS_DECRYPT_OK (0x3 << 11) |
687 | #define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11) | 687 | #define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11) |
688 | #define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11) | 688 | #define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11) |
689 | 689 | ||
690 | struct iwl3945_rx_frame_end { | 690 | struct iwl3945_rx_frame_end { |
691 | __le32 status; | 691 | __le32 status; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-core.h b/drivers/net/wireless/iwlwifi/iwl-3945-core.h new file mode 100644 index 000000000000..bc12f97ba0b1 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-3945-core.h | |||
@@ -0,0 +1,80 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2008 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Tomas Winkler <tomas.winkler@intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | *****************************************************************************/ | ||
62 | |||
63 | #ifndef __iwl_3945_dev_h__ | ||
64 | #define __iwl_3945_dev_h__ | ||
65 | |||
66 | #define IWL_PCI_DEVICE(dev, subdev, cfg) \ | ||
67 | .vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \ | ||
68 | .subvendor = PCI_ANY_ID, .subdevice = (subdev), \ | ||
69 | .driver_data = (kernel_ulong_t)&(cfg) | ||
70 | |||
71 | #define IWL_SKU_G 0x1 | ||
72 | #define IWL_SKU_A 0x2 | ||
73 | |||
74 | struct iwl_3945_cfg { | ||
75 | const char *name; | ||
76 | const char *fw_name; | ||
77 | unsigned int sku; | ||
78 | }; | ||
79 | |||
80 | #endif /* __iwl_dev_h__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h index f853c6b9f76e..28ecfe8d39a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h | |||
@@ -40,6 +40,15 @@ do { if (iwl3945_debug_level & (level)) \ | |||
40 | do { if ((iwl3945_debug_level & (level)) && net_ratelimit()) \ | 40 | do { if ((iwl3945_debug_level & (level)) && net_ratelimit()) \ |
41 | printk(KERN_ERR DRV_NAME": %c %s " fmt, \ | 41 | printk(KERN_ERR DRV_NAME": %c %s " fmt, \ |
42 | in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) | 42 | in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) |
43 | |||
44 | static inline void iwl3945_print_hex_dump(int level, void *p, u32 len) | ||
45 | { | ||
46 | if (!(iwl3945_debug_level & level)) | ||
47 | return; | ||
48 | |||
49 | print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, | ||
50 | p, len, 1); | ||
51 | } | ||
43 | #else | 52 | #else |
44 | static inline void IWL_DEBUG(int level, const char *fmt, ...) | 53 | static inline void IWL_DEBUG(int level, const char *fmt, ...) |
45 | { | 54 | { |
@@ -47,7 +56,12 @@ static inline void IWL_DEBUG(int level, const char *fmt, ...) | |||
47 | static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) | 56 | static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) |
48 | { | 57 | { |
49 | } | 58 | } |
50 | #endif /* CONFIG_IWL3945_DEBUG */ | 59 | static inline void iwl3945_print_hex_dump(int level, void *p, u32 len) |
60 | { | ||
61 | } | ||
62 | #endif /* CONFIG_IWL3945_DEBUG */ | ||
63 | |||
64 | |||
51 | 65 | ||
52 | /* | 66 | /* |
53 | * To use the debug system; | 67 | * To use the debug system; |
@@ -143,6 +157,7 @@ static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) | |||
143 | IWL_DEBUG_LIMIT(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a) | 157 | IWL_DEBUG_LIMIT(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a) |
144 | #define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a) | 158 | #define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a) |
145 | #define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a) | 159 | #define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a) |
160 | #define IWL_DEBUG_STATS_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_STATS, f, ## a) | ||
146 | #define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a) | 161 | #define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a) |
147 | #define IWL_DEBUG_QOS(f, a...) IWL_DEBUG(IWL_DL_QOS, f, ## a) | 162 | #define IWL_DEBUG_QOS(f, a...) IWL_DEBUG(IWL_DL_QOS, f, ## a) |
148 | #define IWL_DEBUG_RADIO(f, a...) IWL_DEBUG(IWL_DL_RADIO, f, ## a) | 163 | #define IWL_DEBUG_RADIO(f, a...) IWL_DEBUG(IWL_DL_RADIO, f, ## a) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index 6693767adc9f..7dc19136f41a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h | |||
@@ -321,180 +321,6 @@ struct iwl3945_eeprom { | |||
321 | #define PCI_REG_WUM8 0x0E8 | 321 | #define PCI_REG_WUM8 0x0E8 |
322 | #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) | 322 | #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) |
323 | 323 | ||
324 | /*=== CSR (control and status registers) ===*/ | ||
325 | #define CSR_BASE (0x000) | ||
326 | |||
327 | #define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */ | ||
328 | #define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ | ||
329 | #define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */ | ||
330 | #define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */ | ||
331 | #define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/ | ||
332 | #define CSR_GPIO_IN (CSR_BASE+0x018) /* read external chip pins */ | ||
333 | #define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/ | ||
334 | #define CSR_GP_CNTRL (CSR_BASE+0x024) | ||
335 | |||
336 | /* | ||
337 | * Hardware revision info | ||
338 | * Bit fields: | ||
339 | * 31-8: Reserved | ||
340 | * 7-4: Type of device: 0x0 = 4965, 0xd = 3945 | ||
341 | * 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D | ||
342 | * 1-0: "Dash" value, as in A-1, etc. | ||
343 | */ | ||
344 | #define CSR_HW_REV (CSR_BASE+0x028) | ||
345 | |||
346 | /* EEPROM reads */ | ||
347 | #define CSR_EEPROM_REG (CSR_BASE+0x02c) | ||
348 | #define CSR_EEPROM_GP (CSR_BASE+0x030) | ||
349 | #define CSR_GP_UCODE (CSR_BASE+0x044) | ||
350 | #define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) | ||
351 | #define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058) | ||
352 | #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) | ||
353 | #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) | ||
354 | #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) | ||
355 | |||
356 | /* Analog phase-lock-loop configuration (3945 only) | ||
357 | * Set bit 24. */ | ||
358 | #define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) | ||
359 | |||
360 | /* Bits for CSR_HW_IF_CONFIG_REG */ | ||
361 | #define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB (0x00000100) | ||
362 | #define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM (0x00000200) | ||
363 | #define CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400) | ||
364 | #define CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800) | ||
365 | #define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000) | ||
366 | #define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000) | ||
367 | #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) | ||
368 | |||
369 | /* interrupt flags in INTA, set by uCode or hardware (e.g. dma), | ||
370 | * acknowledged (reset) by host writing "1" to flagged bits. */ | ||
371 | #define CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */ | ||
372 | #define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */ | ||
373 | #define CSR_INT_BIT_DNLD (1 << 28) /* uCode Download */ | ||
374 | #define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */ | ||
375 | #define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */ | ||
376 | #define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ | ||
377 | #define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ | ||
378 | #define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ | ||
379 | #define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */ | ||
380 | #define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ | ||
381 | #define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ | ||
382 | |||
383 | #define CSR_INI_SET_MASK (CSR_INT_BIT_FH_RX | \ | ||
384 | CSR_INT_BIT_HW_ERR | \ | ||
385 | CSR_INT_BIT_FH_TX | \ | ||
386 | CSR_INT_BIT_SW_ERR | \ | ||
387 | CSR_INT_BIT_RF_KILL | \ | ||
388 | CSR_INT_BIT_SW_RX | \ | ||
389 | CSR_INT_BIT_WAKEUP | \ | ||
390 | CSR_INT_BIT_ALIVE) | ||
391 | |||
392 | /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ | ||
393 | #define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */ | ||
394 | #define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ | ||
395 | #define CSR_FH_INT_BIT_RX_CHNL2 (1 << 18) /* Rx channel 2 (3945 only) */ | ||
396 | #define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ | ||
397 | #define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ | ||
398 | #define CSR_FH_INT_BIT_TX_CHNL6 (1 << 6) /* Tx channel 6 (3945 only) */ | ||
399 | #define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ | ||
400 | #define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ | ||
401 | |||
402 | #define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ | ||
403 | CSR_FH_INT_BIT_RX_CHNL2 | \ | ||
404 | CSR_FH_INT_BIT_RX_CHNL1 | \ | ||
405 | CSR_FH_INT_BIT_RX_CHNL0) | ||
406 | |||
407 | #define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL6 | \ | ||
408 | CSR_FH_INT_BIT_TX_CHNL1 | \ | ||
409 | CSR_FH_INT_BIT_TX_CHNL0) | ||
410 | |||
411 | |||
412 | /* RESET */ | ||
413 | #define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001) | ||
414 | #define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002) | ||
415 | #define CSR_RESET_REG_FLAG_SW_RESET (0x00000080) | ||
416 | #define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) | ||
417 | #define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) | ||
418 | |||
419 | /* GP (general purpose) CONTROL */ | ||
420 | #define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) | ||
421 | #define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) | ||
422 | #define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) | ||
423 | #define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) | ||
424 | |||
425 | #define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) | ||
426 | |||
427 | #define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) | ||
428 | #define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000) | ||
429 | #define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) | ||
430 | |||
431 | |||
432 | /* EEPROM REG */ | ||
433 | #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) | ||
434 | #define CSR_EEPROM_REG_BIT_CMD (0x00000002) | ||
435 | |||
436 | /* EEPROM GP */ | ||
437 | #define CSR_EEPROM_GP_VALID_MSK (0x00000006) | ||
438 | #define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) | ||
439 | #define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) | ||
440 | |||
441 | /* UCODE DRV GP */ | ||
442 | #define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) | ||
443 | #define CSR_UCODE_SW_BIT_RFKILL (0x00000002) | ||
444 | #define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) | ||
445 | #define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) | ||
446 | |||
447 | /* GPIO */ | ||
448 | #define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) | ||
449 | #define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000) | ||
450 | #define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER | ||
451 | |||
452 | /* GI Chicken Bits */ | ||
453 | #define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) | ||
454 | #define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) | ||
455 | |||
456 | /* CSR_ANA_PLL_CFG */ | ||
457 | #define CSR_ANA_PLL_CFG_SH (0x00880300) | ||
458 | |||
459 | /*=== HBUS (Host-side Bus) ===*/ | ||
460 | #define HBUS_BASE (0x400) | ||
461 | |||
462 | /* | ||
463 | * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM | ||
464 | * structures, error log, event log, verifying uCode load). | ||
465 | * First write to address register, then read from or write to data register | ||
466 | * to complete the job. Once the address register is set up, accesses to | ||
467 | * data registers auto-increment the address by one dword. | ||
468 | * Bit usage for address registers (read or write): | ||
469 | * 0-31: memory address within device | ||
470 | */ | ||
471 | #define HBUS_TARG_MEM_RADDR (HBUS_BASE+0x00c) | ||
472 | #define HBUS_TARG_MEM_WADDR (HBUS_BASE+0x010) | ||
473 | #define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018) | ||
474 | #define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c) | ||
475 | |||
476 | /* | ||
477 | * Registers for accessing device's internal peripheral registers | ||
478 | * (e.g. SCD, BSM, etc.). First write to address register, | ||
479 | * then read from or write to data register to complete the job. | ||
480 | * Bit usage for address registers (read or write): | ||
481 | * 0-15: register address (offset) within device | ||
482 | * 24-25: (# bytes - 1) to read or write (e.g. 3 for dword) | ||
483 | */ | ||
484 | #define HBUS_TARG_PRPH_WADDR (HBUS_BASE+0x044) | ||
485 | #define HBUS_TARG_PRPH_RADDR (HBUS_BASE+0x048) | ||
486 | #define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c) | ||
487 | #define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050) | ||
488 | |||
489 | /* | ||
490 | * Per-Tx-queue write pointer (index, really!) (3945 and 4965). | ||
491 | * Indicates index to next TFD that driver will fill (1 past latest filled). | ||
492 | * Bit usage: | ||
493 | * 0-7: queue write index | ||
494 | * 11-8: queue selector | ||
495 | */ | ||
496 | #define HBUS_TARG_WRPTR (HBUS_BASE+0x060) | ||
497 | |||
498 | /* SCD (3945 Tx Frame Scheduler) */ | 324 | /* SCD (3945 Tx Frame Scheduler) */ |
499 | #define SCD_BASE (CSR_BASE + 0x2E00) | 325 | #define SCD_BASE (CSR_BASE + 0x2E00) |
500 | 326 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index a8223c4cc97c..08604eb8291b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c | |||
@@ -158,9 +158,9 @@ static void iwl3945_clear_window(struct iwl3945_rate_scale_data *window) | |||
158 | { | 158 | { |
159 | window->data = 0; | 159 | window->data = 0; |
160 | window->success_counter = 0; | 160 | window->success_counter = 0; |
161 | window->success_ratio = IWL_INVALID_VALUE; | 161 | window->success_ratio = -1; |
162 | window->counter = 0; | 162 | window->counter = 0; |
163 | window->average_tpt = IWL_INVALID_VALUE; | 163 | window->average_tpt = IWL_INV_TPT; |
164 | window->stamp = 0; | 164 | window->stamp = 0; |
165 | } | 165 | } |
166 | 166 | ||
@@ -459,22 +459,23 @@ static void rs_tx_status(void *priv_rate, | |||
459 | struct iwl3945_rs_sta *rs_sta; | 459 | struct iwl3945_rs_sta *rs_sta; |
460 | struct ieee80211_supported_band *sband; | 460 | struct ieee80211_supported_band *sband; |
461 | 461 | ||
462 | IWL_DEBUG_RATE("enter\n"); | ||
463 | |||
462 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 464 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
463 | 465 | ||
464 | IWL_DEBUG_RATE("enter\n"); | ||
465 | 466 | ||
466 | retries = tx_resp->retry_count; | 467 | retries = tx_resp->retry_count; |
467 | /* FIXME : this is wrong */ | 468 | first_index = tx_resp->control.tx_rate->hw_value; |
468 | first_index = &sband->bitrates[0] - tx_resp->control.tx_rate; | ||
469 | if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { | 469 | if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { |
470 | IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index); | 470 | IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index); |
471 | return; | 471 | return; |
472 | } | 472 | } |
473 | 473 | ||
474 | rcu_read_lock(); | ||
475 | |||
474 | sta = sta_info_get(local, hdr->addr1); | 476 | sta = sta_info_get(local, hdr->addr1); |
475 | if (!sta || !sta->rate_ctrl_priv) { | 477 | if (!sta || !sta->rate_ctrl_priv) { |
476 | if (sta) | 478 | rcu_read_unlock(); |
477 | sta_info_put(sta); | ||
478 | IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); | 479 | IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); |
479 | return; | 480 | return; |
480 | } | 481 | } |
@@ -547,7 +548,7 @@ static void rs_tx_status(void *priv_rate, | |||
547 | 548 | ||
548 | spin_unlock_irqrestore(&rs_sta->lock, flags); | 549 | spin_unlock_irqrestore(&rs_sta->lock, flags); |
549 | 550 | ||
550 | sta_info_put(sta); | 551 | rcu_read_unlock(); |
551 | 552 | ||
552 | IWL_DEBUG_RATE("leave\n"); | 553 | IWL_DEBUG_RATE("leave\n"); |
553 | 554 | ||
@@ -633,7 +634,7 @@ static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta, | |||
633 | * | 634 | * |
634 | */ | 635 | */ |
635 | static void rs_get_rate(void *priv_rate, struct net_device *dev, | 636 | static void rs_get_rate(void *priv_rate, struct net_device *dev, |
636 | struct ieee80211_supported_band *band, | 637 | struct ieee80211_supported_band *sband, |
637 | struct sk_buff *skb, | 638 | struct sk_buff *skb, |
638 | struct rate_selection *sel) | 639 | struct rate_selection *sel) |
639 | { | 640 | { |
@@ -643,9 +644,9 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, | |||
643 | int index; | 644 | int index; |
644 | struct iwl3945_rs_sta *rs_sta; | 645 | struct iwl3945_rs_sta *rs_sta; |
645 | struct iwl3945_rate_scale_data *window = NULL; | 646 | struct iwl3945_rate_scale_data *window = NULL; |
646 | int current_tpt = IWL_INVALID_VALUE; | 647 | int current_tpt = IWL_INV_TPT; |
647 | int low_tpt = IWL_INVALID_VALUE; | 648 | int low_tpt = IWL_INV_TPT; |
648 | int high_tpt = IWL_INVALID_VALUE; | 649 | int high_tpt = IWL_INV_TPT; |
649 | u32 fail_count; | 650 | u32 fail_count; |
650 | s8 scale_action = 0; | 651 | s8 scale_action = 0; |
651 | unsigned long flags; | 652 | unsigned long flags; |
@@ -658,6 +659,8 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, | |||
658 | 659 | ||
659 | IWL_DEBUG_RATE("enter\n"); | 660 | IWL_DEBUG_RATE("enter\n"); |
660 | 661 | ||
662 | rcu_read_lock(); | ||
663 | |||
661 | sta = sta_info_get(local, hdr->addr1); | 664 | sta = sta_info_get(local, hdr->addr1); |
662 | 665 | ||
663 | /* Send management frames and broadcast/multicast data using lowest | 666 | /* Send management frames and broadcast/multicast data using lowest |
@@ -667,16 +670,15 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, | |||
667 | is_multicast_ether_addr(hdr->addr1) || | 670 | is_multicast_ether_addr(hdr->addr1) || |
668 | !sta || !sta->rate_ctrl_priv) { | 671 | !sta || !sta->rate_ctrl_priv) { |
669 | IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); | 672 | IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); |
670 | sel->rate = rate_lowest(local, band, sta); | 673 | sel->rate = rate_lowest(local, sband, sta); |
671 | if (sta) | 674 | rcu_read_unlock(); |
672 | sta_info_put(sta); | ||
673 | return; | 675 | return; |
674 | } | 676 | } |
675 | 677 | ||
676 | rate_mask = sta->supp_rates[band->band]; | 678 | rate_mask = sta->supp_rates[sband->band]; |
677 | index = min(sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1); | 679 | index = min(sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1); |
678 | 680 | ||
679 | if (priv->band == IEEE80211_BAND_5GHZ) | 681 | if (sband->band == IEEE80211_BAND_5GHZ) |
680 | rate_mask = rate_mask << IWL_FIRST_OFDM_RATE; | 682 | rate_mask = rate_mask << IWL_FIRST_OFDM_RATE; |
681 | 683 | ||
682 | rs_sta = (void *)sta->rate_ctrl_priv; | 684 | rs_sta = (void *)sta->rate_ctrl_priv; |
@@ -708,7 +710,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, | |||
708 | 710 | ||
709 | if (((fail_count <= IWL_RATE_MIN_FAILURE_TH) && | 711 | if (((fail_count <= IWL_RATE_MIN_FAILURE_TH) && |
710 | (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) { | 712 | (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) { |
711 | window->average_tpt = IWL_INVALID_VALUE; | 713 | window->average_tpt = IWL_INV_TPT; |
712 | spin_unlock_irqrestore(&rs_sta->lock, flags); | 714 | spin_unlock_irqrestore(&rs_sta->lock, flags); |
713 | 715 | ||
714 | IWL_DEBUG_RATE("Invalid average_tpt on rate %d: " | 716 | IWL_DEBUG_RATE("Invalid average_tpt on rate %d: " |
@@ -727,7 +729,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, | |||
727 | current_tpt = window->average_tpt; | 729 | current_tpt = window->average_tpt; |
728 | 730 | ||
729 | high_low = iwl3945_get_adjacent_rate(rs_sta, index, rate_mask, | 731 | high_low = iwl3945_get_adjacent_rate(rs_sta, index, rate_mask, |
730 | band->band); | 732 | sband->band); |
731 | low = high_low & 0xff; | 733 | low = high_low & 0xff; |
732 | high = (high_low >> 8) & 0xff; | 734 | high = (high_low >> 8) & 0xff; |
733 | 735 | ||
@@ -744,19 +746,16 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, | |||
744 | if ((window->success_ratio < IWL_RATE_DECREASE_TH) || !current_tpt) { | 746 | if ((window->success_ratio < IWL_RATE_DECREASE_TH) || !current_tpt) { |
745 | IWL_DEBUG_RATE("decrease rate because of low success_ratio\n"); | 747 | IWL_DEBUG_RATE("decrease rate because of low success_ratio\n"); |
746 | scale_action = -1; | 748 | scale_action = -1; |
747 | } else if ((low_tpt == IWL_INVALID_VALUE) && | 749 | } else if ((low_tpt == IWL_INV_TPT) && (high_tpt == IWL_INV_TPT)) |
748 | (high_tpt == IWL_INVALID_VALUE)) | ||
749 | scale_action = 1; | 750 | scale_action = 1; |
750 | else if ((low_tpt != IWL_INVALID_VALUE) && | 751 | else if ((low_tpt != IWL_INV_TPT) && (high_tpt != IWL_INV_TPT) && |
751 | (high_tpt != IWL_INVALID_VALUE) | 752 | (low_tpt < current_tpt) && (high_tpt < current_tpt)) { |
752 | && (low_tpt < current_tpt) | ||
753 | && (high_tpt < current_tpt)) { | ||
754 | IWL_DEBUG_RATE("No action -- low [%d] & high [%d] < " | 753 | IWL_DEBUG_RATE("No action -- low [%d] & high [%d] < " |
755 | "current_tpt [%d]\n", | 754 | "current_tpt [%d]\n", |
756 | low_tpt, high_tpt, current_tpt); | 755 | low_tpt, high_tpt, current_tpt); |
757 | scale_action = 0; | 756 | scale_action = 0; |
758 | } else { | 757 | } else { |
759 | if (high_tpt != IWL_INVALID_VALUE) { | 758 | if (high_tpt != IWL_INV_TPT) { |
760 | if (high_tpt > current_tpt) | 759 | if (high_tpt > current_tpt) |
761 | scale_action = 1; | 760 | scale_action = 1; |
762 | else { | 761 | else { |
@@ -764,7 +763,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, | |||
764 | ("decrease rate because of high tpt\n"); | 763 | ("decrease rate because of high tpt\n"); |
765 | scale_action = -1; | 764 | scale_action = -1; |
766 | } | 765 | } |
767 | } else if (low_tpt != IWL_INVALID_VALUE) { | 766 | } else if (low_tpt != IWL_INV_TPT) { |
768 | if (low_tpt > current_tpt) { | 767 | if (low_tpt > current_tpt) { |
769 | IWL_DEBUG_RATE | 768 | IWL_DEBUG_RATE |
770 | ("decrease rate because of low tpt\n"); | 769 | ("decrease rate because of low tpt\n"); |
@@ -806,16 +805,16 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, | |||
806 | out: | 805 | out: |
807 | 806 | ||
808 | sta->last_txrate_idx = index; | 807 | sta->last_txrate_idx = index; |
809 | if (priv->band == IEEE80211_BAND_5GHZ) | 808 | if (sband->band == IEEE80211_BAND_5GHZ) |
810 | sta->txrate_idx = sta->last_txrate_idx - IWL_FIRST_OFDM_RATE; | 809 | sta->txrate_idx = sta->last_txrate_idx - IWL_FIRST_OFDM_RATE; |
811 | else | 810 | else |
812 | sta->txrate_idx = sta->last_txrate_idx; | 811 | sta->txrate_idx = sta->last_txrate_idx; |
813 | 812 | ||
814 | sta_info_put(sta); | 813 | rcu_read_unlock(); |
815 | 814 | ||
816 | IWL_DEBUG_RATE("leave: %d\n", index); | 815 | IWL_DEBUG_RATE("leave: %d\n", index); |
817 | 816 | ||
818 | sel->rate = &priv->ieee_rates[index]; | 817 | sel->rate = &sband->bitrates[sta->txrate_idx]; |
819 | } | 818 | } |
820 | 819 | ||
821 | static struct rate_control_ops rs_ops = { | 820 | static struct rate_control_ops rs_ops = { |
@@ -843,13 +842,15 @@ int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) | |||
843 | unsigned long now = jiffies; | 842 | unsigned long now = jiffies; |
844 | u32 max_time = 0; | 843 | u32 max_time = 0; |
845 | 844 | ||
845 | rcu_read_lock(); | ||
846 | |||
846 | sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); | 847 | sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); |
847 | if (!sta || !sta->rate_ctrl_priv) { | 848 | if (!sta || !sta->rate_ctrl_priv) { |
848 | if (sta) { | 849 | if (sta) |
849 | sta_info_put(sta); | ||
850 | IWL_DEBUG_RATE("leave - no private rate data!\n"); | 850 | IWL_DEBUG_RATE("leave - no private rate data!\n"); |
851 | } else | 851 | else |
852 | IWL_DEBUG_RATE("leave - no station!\n"); | 852 | IWL_DEBUG_RATE("leave - no station!\n"); |
853 | rcu_read_unlock(); | ||
853 | return sprintf(buf, "station %d not found\n", sta_id); | 854 | return sprintf(buf, "station %d not found\n", sta_id); |
854 | } | 855 | } |
855 | 856 | ||
@@ -890,7 +891,7 @@ int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) | |||
890 | i = j; | 891 | i = j; |
891 | } | 892 | } |
892 | spin_unlock_irqrestore(&rs_sta->lock, flags); | 893 | spin_unlock_irqrestore(&rs_sta->lock, flags); |
893 | sta_info_put(sta); | 894 | rcu_read_unlock(); |
894 | 895 | ||
895 | /* Display the average rate of all samples taken. | 896 | /* Display the average rate of all samples taken. |
896 | * | 897 | * |
@@ -927,11 +928,12 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) | |||
927 | return; | 928 | return; |
928 | } | 929 | } |
929 | 930 | ||
931 | rcu_read_lock(); | ||
932 | |||
930 | sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); | 933 | sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); |
931 | if (!sta || !sta->rate_ctrl_priv) { | 934 | if (!sta || !sta->rate_ctrl_priv) { |
932 | if (sta) | ||
933 | sta_info_put(sta); | ||
934 | IWL_DEBUG_RATE("leave - no private rate data!\n"); | 935 | IWL_DEBUG_RATE("leave - no private rate data!\n"); |
936 | rcu_read_unlock(); | ||
935 | return; | 937 | return; |
936 | } | 938 | } |
937 | 939 | ||
@@ -958,7 +960,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) | |||
958 | break; | 960 | break; |
959 | } | 961 | } |
960 | 962 | ||
961 | sta_info_put(sta); | 963 | rcu_read_unlock(); |
962 | spin_unlock_irqrestore(&rs_sta->lock, flags); | 964 | spin_unlock_irqrestore(&rs_sta->lock, flags); |
963 | 965 | ||
964 | rssi = priv->last_rx_rssi; | 966 | rssi = priv->last_rx_rssi; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h index d5e9220f871d..b082a093ee26 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h | |||
@@ -36,8 +36,8 @@ struct iwl3945_rate_info { | |||
36 | u8 next_rs; /* next rate used in rs algo */ | 36 | u8 next_rs; /* next rate used in rs algo */ |
37 | u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ | 37 | u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ |
38 | u8 next_rs_tgg; /* next rate used in TGG rs algo */ | 38 | u8 next_rs_tgg; /* next rate used in TGG rs algo */ |
39 | u8 table_rs_index; /* index in rate scale table cmd */ | 39 | u8 table_rs_index; /* index in rate scale table cmd */ |
40 | u8 prev_table_rs; /* prev in rate table cmd */ | 40 | u8 prev_table_rs; /* prev in rate table cmd */ |
41 | }; | 41 | }; |
42 | 42 | ||
43 | /* | 43 | /* |
@@ -159,7 +159,7 @@ enum { | |||
159 | 159 | ||
160 | #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) | 160 | #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) |
161 | 161 | ||
162 | #define IWL_INVALID_VALUE -1 | 162 | #define IWL_INV_TPT -1 |
163 | 163 | ||
164 | #define IWL_MIN_RSSI_VAL -100 | 164 | #define IWL_MIN_RSSI_VAL -100 |
165 | #define IWL_MAX_RSSI_VAL 0 | 165 | #define IWL_MAX_RSSI_VAL 0 |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 82d282730b75..50a641c0c5b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <asm/unaligned.h> | 39 | #include <asm/unaligned.h> |
40 | #include <net/mac80211.h> | 40 | #include <net/mac80211.h> |
41 | 41 | ||
42 | #include "iwl-3945-core.h" | ||
42 | #include "iwl-3945.h" | 43 | #include "iwl-3945.h" |
43 | #include "iwl-helpers.h" | 44 | #include "iwl-helpers.h" |
44 | #include "iwl-3945-rs.h" | 45 | #include "iwl-3945-rs.h" |
@@ -183,6 +184,16 @@ void iwl3945_disable_events(struct iwl3945_priv *priv) | |||
183 | 184 | ||
184 | } | 185 | } |
185 | 186 | ||
187 | static int iwl3945_hwrate_to_plcp_idx(u8 plcp) | ||
188 | { | ||
189 | int idx; | ||
190 | |||
191 | for (idx = 0; idx < IWL_RATE_COUNT; idx++) | ||
192 | if (iwl3945_rates[idx].plcp == plcp) | ||
193 | return idx; | ||
194 | return -1; | ||
195 | } | ||
196 | |||
186 | /** | 197 | /** |
187 | * iwl3945_get_antenna_flags - Get antenna flags for RXON command | 198 | * iwl3945_get_antenna_flags - Get antenna flags for RXON command |
188 | * @priv: eeprom and antenna fields are used to determine antenna flags | 199 | * @priv: eeprom and antenna fields are used to determine antenna flags |
@@ -216,14 +227,126 @@ __le32 iwl3945_get_antenna_flags(const struct iwl3945_priv *priv) | |||
216 | return 0; /* "diversity" is default if error */ | 227 | return 0; /* "diversity" is default if error */ |
217 | } | 228 | } |
218 | 229 | ||
230 | #ifdef CONFIG_IWL3945_DEBUG | ||
231 | #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x | ||
232 | |||
233 | static const char *iwl3945_get_tx_fail_reason(u32 status) | ||
234 | { | ||
235 | switch (status & TX_STATUS_MSK) { | ||
236 | case TX_STATUS_SUCCESS: | ||
237 | return "SUCCESS"; | ||
238 | TX_STATUS_ENTRY(SHORT_LIMIT); | ||
239 | TX_STATUS_ENTRY(LONG_LIMIT); | ||
240 | TX_STATUS_ENTRY(FIFO_UNDERRUN); | ||
241 | TX_STATUS_ENTRY(MGMNT_ABORT); | ||
242 | TX_STATUS_ENTRY(NEXT_FRAG); | ||
243 | TX_STATUS_ENTRY(LIFE_EXPIRE); | ||
244 | TX_STATUS_ENTRY(DEST_PS); | ||
245 | TX_STATUS_ENTRY(ABORTED); | ||
246 | TX_STATUS_ENTRY(BT_RETRY); | ||
247 | TX_STATUS_ENTRY(STA_INVALID); | ||
248 | TX_STATUS_ENTRY(FRAG_DROPPED); | ||
249 | TX_STATUS_ENTRY(TID_DISABLE); | ||
250 | TX_STATUS_ENTRY(FRAME_FLUSHED); | ||
251 | TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL); | ||
252 | TX_STATUS_ENTRY(TX_LOCKED); | ||
253 | TX_STATUS_ENTRY(NO_BEACON_ON_RADAR); | ||
254 | } | ||
255 | |||
256 | return "UNKNOWN"; | ||
257 | } | ||
258 | #else | ||
259 | static inline const char *iwl3945_get_tx_fail_reason(u32 status) | ||
260 | { | ||
261 | return ""; | ||
262 | } | ||
263 | #endif | ||
264 | |||
265 | |||
266 | /** | ||
267 | * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd | ||
268 | * | ||
269 | * When FW advances 'R' index, all entries between old and new 'R' index | ||
270 | * need to be reclaimed. As result, some free space forms. If there is | ||
271 | * enough free space (> low mark), wake the stack that feeds us. | ||
272 | */ | ||
273 | static void iwl3945_tx_queue_reclaim(struct iwl3945_priv *priv, | ||
274 | int txq_id, int index) | ||
275 | { | ||
276 | struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; | ||
277 | struct iwl3945_queue *q = &txq->q; | ||
278 | struct iwl3945_tx_info *tx_info; | ||
279 | |||
280 | BUG_ON(txq_id == IWL_CMD_QUEUE_NUM); | ||
281 | |||
282 | for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index; | ||
283 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { | ||
284 | |||
285 | tx_info = &txq->txb[txq->q.read_ptr]; | ||
286 | ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0], | ||
287 | &tx_info->status); | ||
288 | tx_info->skb[0] = NULL; | ||
289 | iwl3945_hw_txq_free_tfd(priv, txq); | ||
290 | } | ||
291 | |||
292 | if (iwl3945_queue_space(q) > q->low_mark && (txq_id >= 0) && | ||
293 | (txq_id != IWL_CMD_QUEUE_NUM) && | ||
294 | priv->mac80211_registered) | ||
295 | ieee80211_wake_queue(priv->hw, txq_id); | ||
296 | } | ||
297 | |||
298 | /** | ||
299 | * iwl3945_rx_reply_tx - Handle Tx response | ||
300 | */ | ||
301 | static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, | ||
302 | struct iwl3945_rx_mem_buffer *rxb) | ||
303 | { | ||
304 | struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; | ||
305 | u16 sequence = le16_to_cpu(pkt->hdr.sequence); | ||
306 | int txq_id = SEQ_TO_QUEUE(sequence); | ||
307 | int index = SEQ_TO_INDEX(sequence); | ||
308 | struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; | ||
309 | struct ieee80211_tx_status *tx_status; | ||
310 | struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; | ||
311 | u32 status = le32_to_cpu(tx_resp->status); | ||
312 | int rate_idx; | ||
313 | |||
314 | if ((index >= txq->q.n_bd) || (iwl3945_x2_queue_used(&txq->q, index) == 0)) { | ||
315 | IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " | ||
316 | "is out of range [0-%d] %d %d\n", txq_id, | ||
317 | index, txq->q.n_bd, txq->q.write_ptr, | ||
318 | txq->q.read_ptr); | ||
319 | return; | ||
320 | } | ||
321 | |||
322 | tx_status = &(txq->txb[txq->q.read_ptr].status); | ||
323 | |||
324 | tx_status->retry_count = tx_resp->failure_frame; | ||
325 | /* tx_status->rts_retry_count = tx_resp->failure_rts; */ | ||
326 | tx_status->flags = ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ? | ||
327 | IEEE80211_TX_STATUS_ACK : 0; | ||
328 | |||
329 | IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n", | ||
330 | txq_id, iwl3945_get_tx_fail_reason(status), status, | ||
331 | tx_resp->rate, tx_resp->failure_frame); | ||
332 | |||
333 | rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate); | ||
334 | tx_status->control.tx_rate = &priv->ieee_rates[rate_idx]; | ||
335 | IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); | ||
336 | iwl3945_tx_queue_reclaim(priv, txq_id, index); | ||
337 | |||
338 | if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) | ||
339 | IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); | ||
340 | } | ||
341 | |||
342 | |||
343 | |||
219 | /***************************************************************************** | 344 | /***************************************************************************** |
220 | * | 345 | * |
221 | * Intel PRO/Wireless 3945ABG/BG Network Connection | 346 | * Intel PRO/Wireless 3945ABG/BG Network Connection |
222 | * | 347 | * |
223 | * RX handler implementations | 348 | * RX handler implementations |
224 | * | 349 | * |
225 | * Used by iwl-base.c | ||
226 | * | ||
227 | *****************************************************************************/ | 350 | *****************************************************************************/ |
228 | 351 | ||
229 | void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb) | 352 | void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb) |
@@ -238,6 +361,156 @@ void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, struct iwl3945_rx_mem_b | |||
238 | priv->last_statistics_time = jiffies; | 361 | priv->last_statistics_time = jiffies; |
239 | } | 362 | } |
240 | 363 | ||
364 | /****************************************************************************** | ||
365 | * | ||
366 | * Misc. internal state and helper functions | ||
367 | * | ||
368 | ******************************************************************************/ | ||
369 | #ifdef CONFIG_IWL3945_DEBUG | ||
370 | |||
371 | /** | ||
372 | * iwl3945_report_frame - dump frame to syslog during debug sessions | ||
373 | * | ||
374 | * You may hack this function to show different aspects of received frames, | ||
375 | * including selective frame dumps. | ||
376 | * group100 parameter selects whether to show 1 out of 100 good frames. | ||
377 | */ | ||
378 | static void iwl3945_dbg_report_frame(struct iwl3945_priv *priv, | ||
379 | struct iwl3945_rx_packet *pkt, | ||
380 | struct ieee80211_hdr *header, int group100) | ||
381 | { | ||
382 | u32 to_us; | ||
383 | u32 print_summary = 0; | ||
384 | u32 print_dump = 0; /* set to 1 to dump all frames' contents */ | ||
385 | u32 hundred = 0; | ||
386 | u32 dataframe = 0; | ||
387 | u16 fc; | ||
388 | u16 seq_ctl; | ||
389 | u16 channel; | ||
390 | u16 phy_flags; | ||
391 | u16 length; | ||
392 | u16 status; | ||
393 | u16 bcn_tmr; | ||
394 | u32 tsf_low; | ||
395 | u64 tsf; | ||
396 | u8 rssi; | ||
397 | u8 agc; | ||
398 | u16 sig_avg; | ||
399 | u16 noise_diff; | ||
400 | struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); | ||
401 | struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); | ||
402 | struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); | ||
403 | u8 *data = IWL_RX_DATA(pkt); | ||
404 | |||
405 | /* MAC header */ | ||
406 | fc = le16_to_cpu(header->frame_control); | ||
407 | seq_ctl = le16_to_cpu(header->seq_ctrl); | ||
408 | |||
409 | /* metadata */ | ||
410 | channel = le16_to_cpu(rx_hdr->channel); | ||
411 | phy_flags = le16_to_cpu(rx_hdr->phy_flags); | ||
412 | length = le16_to_cpu(rx_hdr->len); | ||
413 | |||
414 | /* end-of-frame status and timestamp */ | ||
415 | status = le32_to_cpu(rx_end->status); | ||
416 | bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); | ||
417 | tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; | ||
418 | tsf = le64_to_cpu(rx_end->timestamp); | ||
419 | |||
420 | /* signal statistics */ | ||
421 | rssi = rx_stats->rssi; | ||
422 | agc = rx_stats->agc; | ||
423 | sig_avg = le16_to_cpu(rx_stats->sig_avg); | ||
424 | noise_diff = le16_to_cpu(rx_stats->noise_diff); | ||
425 | |||
426 | to_us = !compare_ether_addr(header->addr1, priv->mac_addr); | ||
427 | |||
428 | /* if data frame is to us and all is good, | ||
429 | * (optionally) print summary for only 1 out of every 100 */ | ||
430 | if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == | ||
431 | (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { | ||
432 | dataframe = 1; | ||
433 | if (!group100) | ||
434 | print_summary = 1; /* print each frame */ | ||
435 | else if (priv->framecnt_to_us < 100) { | ||
436 | priv->framecnt_to_us++; | ||
437 | print_summary = 0; | ||
438 | } else { | ||
439 | priv->framecnt_to_us = 0; | ||
440 | print_summary = 1; | ||
441 | hundred = 1; | ||
442 | } | ||
443 | } else { | ||
444 | /* print summary for all other frames */ | ||
445 | print_summary = 1; | ||
446 | } | ||
447 | |||
448 | if (print_summary) { | ||
449 | char *title; | ||
450 | u32 rate; | ||
451 | |||
452 | if (hundred) | ||
453 | title = "100Frames"; | ||
454 | else if (fc & IEEE80211_FCTL_RETRY) | ||
455 | title = "Retry"; | ||
456 | else if (ieee80211_is_assoc_response(fc)) | ||
457 | title = "AscRsp"; | ||
458 | else if (ieee80211_is_reassoc_response(fc)) | ||
459 | title = "RasRsp"; | ||
460 | else if (ieee80211_is_probe_response(fc)) { | ||
461 | title = "PrbRsp"; | ||
462 | print_dump = 1; /* dump frame contents */ | ||
463 | } else if (ieee80211_is_beacon(fc)) { | ||
464 | title = "Beacon"; | ||
465 | print_dump = 1; /* dump frame contents */ | ||
466 | } else if (ieee80211_is_atim(fc)) | ||
467 | title = "ATIM"; | ||
468 | else if (ieee80211_is_auth(fc)) | ||
469 | title = "Auth"; | ||
470 | else if (ieee80211_is_deauth(fc)) | ||
471 | title = "DeAuth"; | ||
472 | else if (ieee80211_is_disassoc(fc)) | ||
473 | title = "DisAssoc"; | ||
474 | else | ||
475 | title = "Frame"; | ||
476 | |||
477 | rate = iwl3945_hwrate_to_plcp_idx(rx_hdr->rate); | ||
478 | if (rate == -1) | ||
479 | rate = 0; | ||
480 | else | ||
481 | rate = iwl3945_rates[rate].ieee / 2; | ||
482 | |||
483 | /* print frame summary. | ||
484 | * MAC addresses show just the last byte (for brevity), | ||
485 | * but you can hack it to show more, if you'd like to. */ | ||
486 | if (dataframe) | ||
487 | IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " | ||
488 | "len=%u, rssi=%d, chnl=%d, rate=%u, \n", | ||
489 | title, fc, header->addr1[5], | ||
490 | length, rssi, channel, rate); | ||
491 | else { | ||
492 | /* src/dst addresses assume managed mode */ | ||
493 | IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " | ||
494 | "src=0x%02x, rssi=%u, tim=%lu usec, " | ||
495 | "phy=0x%02x, chnl=%d\n", | ||
496 | title, fc, header->addr1[5], | ||
497 | header->addr3[5], rssi, | ||
498 | tsf_low - priv->scan_start_tsf, | ||
499 | phy_flags, channel); | ||
500 | } | ||
501 | } | ||
502 | if (print_dump) | ||
503 | iwl3945_print_hex_dump(IWL_DL_RX, data, length); | ||
504 | } | ||
505 | #else | ||
506 | static inline void iwl3945_dbg_report_frame(struct iwl3945_priv *priv, | ||
507 | struct iwl3945_rx_packet *pkt, | ||
508 | struct ieee80211_hdr *header, int group100) | ||
509 | { | ||
510 | } | ||
511 | #endif | ||
512 | |||
513 | |||
241 | static void iwl3945_add_radiotap(struct iwl3945_priv *priv, | 514 | static void iwl3945_add_radiotap(struct iwl3945_priv *priv, |
242 | struct sk_buff *skb, | 515 | struct sk_buff *skb, |
243 | struct iwl3945_rx_frame_hdr *rx_hdr, | 516 | struct iwl3945_rx_frame_hdr *rx_hdr, |
@@ -376,24 +649,28 @@ static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data, | |||
376 | static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, | 649 | static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, |
377 | struct iwl3945_rx_mem_buffer *rxb) | 650 | struct iwl3945_rx_mem_buffer *rxb) |
378 | { | 651 | { |
652 | struct ieee80211_hdr *header; | ||
653 | struct ieee80211_rx_status rx_status; | ||
379 | struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; | 654 | struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; |
380 | struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); | 655 | struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); |
381 | struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); | 656 | struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); |
382 | struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); | 657 | struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); |
383 | struct ieee80211_hdr *header; | 658 | int snr; |
384 | u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg); | 659 | u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg); |
385 | u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff); | 660 | u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff); |
386 | struct ieee80211_rx_status stats = { | ||
387 | .mactime = le64_to_cpu(rx_end->timestamp), | ||
388 | .freq = ieee80211chan2mhz(le16_to_cpu(rx_hdr->channel)), | ||
389 | .band = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? | ||
390 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ, | ||
391 | .antenna = 0, | ||
392 | .rate_idx = iwl3945_rate_index_from_plcp(rx_hdr->rate), | ||
393 | .flag = 0, | ||
394 | }; | ||
395 | u8 network_packet; | 661 | u8 network_packet; |
396 | int snr; | 662 | |
663 | rx_status.antenna = 0; | ||
664 | rx_status.flag = 0; | ||
665 | rx_status.mactime = le64_to_cpu(rx_end->timestamp); | ||
666 | rx_status.freq = ieee80211chan2mhz(le16_to_cpu(rx_hdr->channel)); | ||
667 | rx_status.band = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? | ||
668 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; | ||
669 | |||
670 | rx_status.rate_idx = iwl3945_hwrate_to_plcp_idx(rx_hdr->rate); | ||
671 | |||
672 | if (rx_status.band == IEEE80211_BAND_5GHZ) | ||
673 | rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; | ||
397 | 674 | ||
398 | if ((unlikely(rx_stats->phy_count > 20))) { | 675 | if ((unlikely(rx_stats->phy_count > 20))) { |
399 | IWL_DEBUG_DROP | 676 | IWL_DEBUG_DROP |
@@ -409,12 +686,12 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, | |||
409 | } | 686 | } |
410 | 687 | ||
411 | if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { | 688 | if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { |
412 | iwl3945_handle_data_packet(priv, 1, rxb, &stats); | 689 | iwl3945_handle_data_packet(priv, 1, rxb, &rx_status); |
413 | return; | 690 | return; |
414 | } | 691 | } |
415 | 692 | ||
416 | /* Convert 3945's rssi indicator to dBm */ | 693 | /* Convert 3945's rssi indicator to dBm */ |
417 | stats.ssi = rx_stats->rssi - IWL_RSSI_OFFSET; | 694 | rx_status.ssi = rx_stats->rssi - IWL_RSSI_OFFSET; |
418 | 695 | ||
419 | /* Set default noise value to -127 */ | 696 | /* Set default noise value to -127 */ |
420 | if (priv->last_rx_noise == 0) | 697 | if (priv->last_rx_noise == 0) |
@@ -430,50 +707,47 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, | |||
430 | * signal-to-noise ratio (SNR) is (sig_avg / noise_diff). | 707 | * signal-to-noise ratio (SNR) is (sig_avg / noise_diff). |
431 | * Convert linear SNR to dB SNR, then subtract that from rssi dBm | 708 | * Convert linear SNR to dB SNR, then subtract that from rssi dBm |
432 | * to obtain noise level in dBm. | 709 | * to obtain noise level in dBm. |
433 | * Calculate stats.signal (quality indicator in %) based on SNR. */ | 710 | * Calculate rx_status.signal (quality indicator in %) based on SNR. */ |
434 | if (rx_stats_noise_diff) { | 711 | if (rx_stats_noise_diff) { |
435 | snr = rx_stats_sig_avg / rx_stats_noise_diff; | 712 | snr = rx_stats_sig_avg / rx_stats_noise_diff; |
436 | stats.noise = stats.ssi - iwl3945_calc_db_from_ratio(snr); | 713 | rx_status.noise = rx_status.ssi - |
437 | stats.signal = iwl3945_calc_sig_qual(stats.ssi, stats.noise); | 714 | iwl3945_calc_db_from_ratio(snr); |
715 | rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi, | ||
716 | rx_status.noise); | ||
438 | 717 | ||
439 | /* If noise info not available, calculate signal quality indicator (%) | 718 | /* If noise info not available, calculate signal quality indicator (%) |
440 | * using just the dBm signal level. */ | 719 | * using just the dBm signal level. */ |
441 | } else { | 720 | } else { |
442 | stats.noise = priv->last_rx_noise; | 721 | rx_status.noise = priv->last_rx_noise; |
443 | stats.signal = iwl3945_calc_sig_qual(stats.ssi, 0); | 722 | rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi, 0); |
444 | } | 723 | } |
445 | 724 | ||
446 | 725 | ||
447 | IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n", | 726 | IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n", |
448 | stats.ssi, stats.noise, stats.signal, | 727 | rx_status.ssi, rx_status.noise, rx_status.signal, |
449 | rx_stats_sig_avg, rx_stats_noise_diff); | 728 | rx_stats_sig_avg, rx_stats_noise_diff); |
450 | 729 | ||
451 | /* can be covered by iwl3945_report_frame() in most cases */ | ||
452 | /* IWL_DEBUG_RX("RX status: 0x%08X\n", rx_end->status); */ | ||
453 | |||
454 | header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); | 730 | header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); |
455 | 731 | ||
456 | network_packet = iwl3945_is_network_packet(priv, header); | 732 | network_packet = iwl3945_is_network_packet(priv, header); |
457 | 733 | ||
458 | #ifdef CONFIG_IWL3945_DEBUG | 734 | IWL_DEBUG_STATS_LIMIT("[%c] %d RSSI:%d Signal:%u, Noise:%u, Rate:%u\n", |
459 | if (iwl3945_debug_level & IWL_DL_STATS && net_ratelimit()) | 735 | network_packet ? '*' : ' ', |
460 | IWL_DEBUG_STATS | 736 | le16_to_cpu(rx_hdr->channel), |
461 | ("[%c] %d RSSI: %d Signal: %u, Noise: %u, Rate: %u\n", | 737 | rx_status.ssi, rx_status.ssi, |
462 | network_packet ? '*' : ' ', | 738 | rx_status.ssi, rx_status.rate_idx); |
463 | le16_to_cpu(rx_hdr->channel), | ||
464 | stats.ssi, stats.ssi, | ||
465 | stats.ssi, stats.rate_idx); | ||
466 | 739 | ||
740 | #ifdef CONFIG_IWL3945_DEBUG | ||
467 | if (iwl3945_debug_level & (IWL_DL_RX)) | 741 | if (iwl3945_debug_level & (IWL_DL_RX)) |
468 | /* Set "1" to report good data frames in groups of 100 */ | 742 | /* Set "1" to report good data frames in groups of 100 */ |
469 | iwl3945_report_frame(priv, pkt, header, 1); | 743 | iwl3945_dbg_report_frame(priv, pkt, header, 1); |
470 | #endif | 744 | #endif |
471 | 745 | ||
472 | if (network_packet) { | 746 | if (network_packet) { |
473 | priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp); | 747 | priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp); |
474 | priv->last_tsf = le64_to_cpu(rx_end->timestamp); | 748 | priv->last_tsf = le64_to_cpu(rx_end->timestamp); |
475 | priv->last_rx_rssi = stats.ssi; | 749 | priv->last_rx_rssi = rx_status.ssi; |
476 | priv->last_rx_noise = stats.noise; | 750 | priv->last_rx_noise = rx_status.noise; |
477 | } | 751 | } |
478 | 752 | ||
479 | switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) { | 753 | switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) { |
@@ -560,7 +834,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, | |||
560 | } | 834 | } |
561 | } | 835 | } |
562 | 836 | ||
563 | iwl3945_handle_data_packet(priv, 0, rxb, &stats); | 837 | iwl3945_handle_data_packet(priv, 0, rxb, &rx_status); |
564 | break; | 838 | break; |
565 | 839 | ||
566 | case IEEE80211_FTYPE_CTL: | 840 | case IEEE80211_FTYPE_CTL: |
@@ -577,7 +851,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, | |||
577 | print_mac(mac2, header->addr2), | 851 | print_mac(mac2, header->addr2), |
578 | print_mac(mac3, header->addr3)); | 852 | print_mac(mac3, header->addr3)); |
579 | else | 853 | else |
580 | iwl3945_handle_data_packet(priv, 1, rxb, &stats); | 854 | iwl3945_handle_data_packet(priv, 1, rxb, &rx_status); |
581 | break; | 855 | break; |
582 | } | 856 | } |
583 | } | 857 | } |
@@ -993,19 +1267,19 @@ int iwl3945_hw_nic_init(struct iwl3945_priv *priv) | |||
993 | if (rev_id & PCI_CFG_REV_ID_BIT_RTP) | 1267 | if (rev_id & PCI_CFG_REV_ID_BIT_RTP) |
994 | IWL_DEBUG_INFO("RTP type \n"); | 1268 | IWL_DEBUG_INFO("RTP type \n"); |
995 | else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) { | 1269 | else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) { |
996 | IWL_DEBUG_INFO("ALM-MB type\n"); | 1270 | IWL_DEBUG_INFO("3945 RADIO-MB type\n"); |
997 | iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, | 1271 | iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, |
998 | CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB); | 1272 | CSR39_HW_IF_CONFIG_REG_BIT_3945_MB); |
999 | } else { | 1273 | } else { |
1000 | IWL_DEBUG_INFO("ALM-MM type\n"); | 1274 | IWL_DEBUG_INFO("3945 RADIO-MM type\n"); |
1001 | iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, | 1275 | iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, |
1002 | CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM); | 1276 | CSR39_HW_IF_CONFIG_REG_BIT_3945_MM); |
1003 | } | 1277 | } |
1004 | 1278 | ||
1005 | if (EEPROM_SKU_CAP_OP_MODE_MRC == priv->eeprom.sku_cap) { | 1279 | if (EEPROM_SKU_CAP_OP_MODE_MRC == priv->eeprom.sku_cap) { |
1006 | IWL_DEBUG_INFO("SKU OP mode is mrc\n"); | 1280 | IWL_DEBUG_INFO("SKU OP mode is mrc\n"); |
1007 | iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, | 1281 | iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, |
1008 | CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC); | 1282 | CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC); |
1009 | } else | 1283 | } else |
1010 | IWL_DEBUG_INFO("SKU OP mode is basic\n"); | 1284 | IWL_DEBUG_INFO("SKU OP mode is basic\n"); |
1011 | 1285 | ||
@@ -1013,24 +1287,24 @@ int iwl3945_hw_nic_init(struct iwl3945_priv *priv) | |||
1013 | IWL_DEBUG_INFO("3945ABG revision is 0x%X\n", | 1287 | IWL_DEBUG_INFO("3945ABG revision is 0x%X\n", |
1014 | priv->eeprom.board_revision); | 1288 | priv->eeprom.board_revision); |
1015 | iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, | 1289 | iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, |
1016 | CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE); | 1290 | CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE); |
1017 | } else { | 1291 | } else { |
1018 | IWL_DEBUG_INFO("3945ABG revision is 0x%X\n", | 1292 | IWL_DEBUG_INFO("3945ABG revision is 0x%X\n", |
1019 | priv->eeprom.board_revision); | 1293 | priv->eeprom.board_revision); |
1020 | iwl3945_clear_bit(priv, CSR_HW_IF_CONFIG_REG, | 1294 | iwl3945_clear_bit(priv, CSR_HW_IF_CONFIG_REG, |
1021 | CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE); | 1295 | CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE); |
1022 | } | 1296 | } |
1023 | 1297 | ||
1024 | if (priv->eeprom.almgor_m_version <= 1) { | 1298 | if (priv->eeprom.almgor_m_version <= 1) { |
1025 | iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, | 1299 | iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, |
1026 | CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A); | 1300 | CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A); |
1027 | IWL_DEBUG_INFO("Card M type A version is 0x%X\n", | 1301 | IWL_DEBUG_INFO("Card M type A version is 0x%X\n", |
1028 | priv->eeprom.almgor_m_version); | 1302 | priv->eeprom.almgor_m_version); |
1029 | } else { | 1303 | } else { |
1030 | IWL_DEBUG_INFO("Card M type B version is 0x%X\n", | 1304 | IWL_DEBUG_INFO("Card M type B version is 0x%X\n", |
1031 | priv->eeprom.almgor_m_version); | 1305 | priv->eeprom.almgor_m_version); |
1032 | iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, | 1306 | iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, |
1033 | CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B); | 1307 | CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B); |
1034 | } | 1308 | } |
1035 | spin_unlock_irqrestore(&priv->lock, flags); | 1309 | spin_unlock_irqrestore(&priv->lock, flags); |
1036 | 1310 | ||
@@ -2348,6 +2622,7 @@ unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv, | |||
2348 | 2622 | ||
2349 | void iwl3945_hw_rx_handler_setup(struct iwl3945_priv *priv) | 2623 | void iwl3945_hw_rx_handler_setup(struct iwl3945_priv *priv) |
2350 | { | 2624 | { |
2625 | priv->rx_handlers[REPLY_TX] = iwl3945_rx_reply_tx; | ||
2351 | priv->rx_handlers[REPLY_3945_RX] = iwl3945_rx_reply_rx; | 2626 | priv->rx_handlers[REPLY_3945_RX] = iwl3945_rx_reply_rx; |
2352 | } | 2627 | } |
2353 | 2628 | ||
@@ -2362,9 +2637,25 @@ void iwl3945_hw_cancel_deferred_work(struct iwl3945_priv *priv) | |||
2362 | cancel_delayed_work(&priv->thermal_periodic); | 2637 | cancel_delayed_work(&priv->thermal_periodic); |
2363 | } | 2638 | } |
2364 | 2639 | ||
2640 | static struct iwl_3945_cfg iwl3945_bg_cfg = { | ||
2641 | .name = "3945BG", | ||
2642 | .fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode", | ||
2643 | .sku = IWL_SKU_G, | ||
2644 | }; | ||
2645 | |||
2646 | static struct iwl_3945_cfg iwl3945_abg_cfg = { | ||
2647 | .name = "3945ABG", | ||
2648 | .fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode", | ||
2649 | .sku = IWL_SKU_A|IWL_SKU_G, | ||
2650 | }; | ||
2651 | |||
2365 | struct pci_device_id iwl3945_hw_card_ids[] = { | 2652 | struct pci_device_id iwl3945_hw_card_ids[] = { |
2366 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4222)}, | 2653 | {IWL_PCI_DEVICE(0x4222, 0x1005, iwl3945_bg_cfg)}, |
2367 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4227)}, | 2654 | {IWL_PCI_DEVICE(0x4222, 0x1034, iwl3945_bg_cfg)}, |
2655 | {IWL_PCI_DEVICE(0x4222, 0x1044, iwl3945_bg_cfg)}, | ||
2656 | {IWL_PCI_DEVICE(0x4227, 0x1014, iwl3945_bg_cfg)}, | ||
2657 | {IWL_PCI_DEVICE(0x4222, PCI_ANY_ID, iwl3945_abg_cfg)}, | ||
2658 | {IWL_PCI_DEVICE(0x4227, PCI_ANY_ID, iwl3945_abg_cfg)}, | ||
2368 | {0} | 2659 | {0} |
2369 | }; | 2660 | }; |
2370 | 2661 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index dde389d31637..0ab22d366d93 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h | |||
@@ -40,10 +40,17 @@ | |||
40 | extern struct pci_device_id iwl3945_hw_card_ids[]; | 40 | extern struct pci_device_id iwl3945_hw_card_ids[]; |
41 | 41 | ||
42 | #define DRV_NAME "iwl3945" | 42 | #define DRV_NAME "iwl3945" |
43 | #include "iwl-3945-hw.h" | 43 | #include "iwl-csr.h" |
44 | #include "iwl-prph.h" | 44 | #include "iwl-prph.h" |
45 | #include "iwl-3945-hw.h" | ||
45 | #include "iwl-3945-debug.h" | 46 | #include "iwl-3945-debug.h" |
46 | 47 | ||
48 | /* Change firmware file name, using "-" and incrementing number, | ||
49 | * *only* when uCode interface or architecture changes so that it | ||
50 | * is not compatible with earlier drivers. | ||
51 | * This number will also appear in << 8 position of 1st dword of uCode file */ | ||
52 | #define IWL3945_UCODE_API "-1" | ||
53 | |||
47 | /* Default noise level to report when noise measurement is not available. | 54 | /* Default noise level to report when noise measurement is not available. |
48 | * This may be because we're: | 55 | * This may be because we're: |
49 | * 1) Not associated (4965, no beacon statistics being sent to driver) | 56 | * 1) Not associated (4965, no beacon statistics being sent to driver) |
@@ -109,6 +116,9 @@ struct iwl3945_queue { | |||
109 | * space less than this */ | 116 | * space less than this */ |
110 | } __attribute__ ((packed)); | 117 | } __attribute__ ((packed)); |
111 | 118 | ||
119 | int iwl3945_queue_space(const struct iwl3945_queue *q); | ||
120 | int iwl3945_x2_queue_used(const struct iwl3945_queue *q, int i); | ||
121 | |||
112 | #define MAX_NUM_OF_TBS (20) | 122 | #define MAX_NUM_OF_TBS (20) |
113 | 123 | ||
114 | /* One for each TFD */ | 124 | /* One for each TFD */ |
@@ -558,16 +568,6 @@ extern int iwl3945_is_network_packet(struct iwl3945_priv *priv, | |||
558 | struct ieee80211_hdr *header); | 568 | struct ieee80211_hdr *header); |
559 | extern int iwl3945_power_init_handle(struct iwl3945_priv *priv); | 569 | extern int iwl3945_power_init_handle(struct iwl3945_priv *priv); |
560 | extern int iwl3945_eeprom_init(struct iwl3945_priv *priv); | 570 | extern int iwl3945_eeprom_init(struct iwl3945_priv *priv); |
561 | #ifdef CONFIG_IWL3945_DEBUG | ||
562 | extern void iwl3945_report_frame(struct iwl3945_priv *priv, | ||
563 | struct iwl3945_rx_packet *pkt, | ||
564 | struct ieee80211_hdr *header, int group100); | ||
565 | #else | ||
566 | static inline void iwl3945_report_frame(struct iwl3945_priv *priv, | ||
567 | struct iwl3945_rx_packet *pkt, | ||
568 | struct ieee80211_hdr *header, | ||
569 | int group100) {} | ||
570 | #endif | ||
571 | extern void iwl3945_handle_data_packet_monitor(struct iwl3945_priv *priv, | 571 | extern void iwl3945_handle_data_packet_monitor(struct iwl3945_priv *priv, |
572 | struct iwl3945_rx_mem_buffer *rxb, | 572 | struct iwl3945_rx_mem_buffer *rxb, |
573 | void *data, short len, | 573 | void *data, short len, |
@@ -691,6 +691,7 @@ struct iwl3945_priv { | |||
691 | struct ieee80211_hw *hw; | 691 | struct ieee80211_hw *hw; |
692 | struct ieee80211_channel *ieee_channels; | 692 | struct ieee80211_channel *ieee_channels; |
693 | struct ieee80211_rate *ieee_rates; | 693 | struct ieee80211_rate *ieee_rates; |
694 | struct iwl_3945_cfg *cfg; /* device configuration */ | ||
694 | 695 | ||
695 | /* temporary frame storage list */ | 696 | /* temporary frame storage list */ |
696 | struct list_head free_frames; | 697 | struct list_head free_frames; |
@@ -800,7 +801,6 @@ struct iwl3945_priv { | |||
800 | struct iwl3945_tx_queue txq[IWL_MAX_NUM_QUEUES]; | 801 | struct iwl3945_tx_queue txq[IWL_MAX_NUM_QUEUES]; |
801 | 802 | ||
802 | unsigned long status; | 803 | unsigned long status; |
803 | u32 config; | ||
804 | 804 | ||
805 | int last_rx_rssi; /* From Rx packet statisitics */ | 805 | int last_rx_rssi; /* From Rx packet statisitics */ |
806 | int last_rx_noise; /* From beacon statistics */ | 806 | int last_rx_noise; /* From beacon statistics */ |
@@ -830,7 +830,6 @@ struct iwl3945_priv { | |||
830 | int is_open; | 830 | int is_open; |
831 | 831 | ||
832 | u8 mac80211_registered; | 832 | u8 mac80211_registered; |
833 | int is_abg; | ||
834 | 833 | ||
835 | u32 notif_missed_beacons; | 834 | u32 notif_missed_beacons; |
836 | 835 | ||
@@ -950,16 +949,6 @@ static inline int is_channel_ibss(const struct iwl3945_channel_info *ch) | |||
950 | return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; | 949 | return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; |
951 | } | 950 | } |
952 | 951 | ||
953 | static inline int iwl3945_rate_index_from_plcp(int plcp) | ||
954 | { | ||
955 | int i; | ||
956 | |||
957 | for (i = 0; i < IWL_RATE_COUNT; i++) | ||
958 | if (iwl3945_rates[i].plcp == plcp) | ||
959 | return i; | ||
960 | return -1; | ||
961 | } | ||
962 | |||
963 | extern const struct iwl3945_channel_info *iwl3945_get_channel_info( | 952 | extern const struct iwl3945_channel_info *iwl3945_get_channel_info( |
964 | const struct iwl3945_priv *priv, enum ieee80211_band band, u16 channel); | 953 | const struct iwl3945_priv *priv, enum ieee80211_band band, u16 channel); |
965 | 954 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h index b21ffea325cf..327eabce182c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h | |||
@@ -875,26 +875,26 @@ struct iwl4965_rx_frame_hdr { | |||
875 | u8 payload[0]; | 875 | u8 payload[0]; |
876 | } __attribute__ ((packed)); | 876 | } __attribute__ ((packed)); |
877 | 877 | ||
878 | #define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0) | 878 | #define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0) |
879 | #define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1) | 879 | #define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1) |
880 | 880 | ||
881 | #define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0) | 881 | #define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0) |
882 | #define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1) | 882 | #define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1) |
883 | #define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2) | 883 | #define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2) |
884 | #define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3) | 884 | #define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3) |
885 | #define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0) | 885 | #define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0) |
886 | 886 | ||
887 | #define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) | 887 | #define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) |
888 | #define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) | 888 | #define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) |
889 | #define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8) | 889 | #define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8) |
890 | #define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8) | 890 | #define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8) |
891 | #define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8) | 891 | #define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8) |
892 | 892 | ||
893 | #define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11) | 893 | #define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11) |
894 | #define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11) | 894 | #define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11) |
895 | #define RX_RES_STATUS_DECRYPT_OK (0x3 << 11) | 895 | #define RX_RES_STATUS_DECRYPT_OK (0x3 << 11) |
896 | #define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11) | 896 | #define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11) |
897 | #define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11) | 897 | #define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11) |
898 | 898 | ||
899 | struct iwl4965_rx_frame_end { | 899 | struct iwl4965_rx_frame_end { |
900 | __le32 status; | 900 | __le32 status; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-debug.h b/drivers/net/wireless/iwlwifi/iwl-4965-debug.h index 36696bbf170c..baf07c715cf8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-debug.h | |||
@@ -40,15 +40,30 @@ do { if (iwl4965_debug_level & (level)) \ | |||
40 | do { if ((iwl4965_debug_level & (level)) && net_ratelimit()) \ | 40 | do { if ((iwl4965_debug_level & (level)) && net_ratelimit()) \ |
41 | printk(KERN_ERR DRV_NAME": %c %s " fmt, \ | 41 | printk(KERN_ERR DRV_NAME": %c %s " fmt, \ |
42 | in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) | 42 | in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) |
43 | |||
44 | static inline void iwl4965_print_hex_dump(int level, void *p, u32 len) | ||
45 | { | ||
46 | if (!(iwl4965_debug_level & level)) | ||
47 | return; | ||
48 | |||
49 | print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, | ||
50 | p, len, 1); | ||
51 | } | ||
43 | #else | 52 | #else |
53 | |||
44 | static inline void IWL_DEBUG(int level, const char *fmt, ...) | 54 | static inline void IWL_DEBUG(int level, const char *fmt, ...) |
45 | { | 55 | { |
46 | } | 56 | } |
47 | static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) | 57 | static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) |
48 | { | 58 | { |
49 | } | 59 | } |
60 | static inline void iwl4965_print_hex_dump(int level, void *p, u32 len) | ||
61 | { | ||
62 | } | ||
50 | #endif /* CONFIG_IWL4965_DEBUG */ | 63 | #endif /* CONFIG_IWL4965_DEBUG */ |
51 | 64 | ||
65 | |||
66 | |||
52 | /* | 67 | /* |
53 | * To use the debug system; | 68 | * To use the debug system; |
54 | * | 69 | * |
@@ -143,6 +158,7 @@ static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) | |||
143 | IWL_DEBUG_LIMIT(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a) | 158 | IWL_DEBUG_LIMIT(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a) |
144 | #define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a) | 159 | #define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a) |
145 | #define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a) | 160 | #define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a) |
161 | #define IWL_DEBUG_STATS_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_STATS, f, ## a) | ||
146 | #define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a) | 162 | #define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a) |
147 | #define IWL_DEBUG_QOS(f, a...) IWL_DEBUG(IWL_DL_QOS, f, ## a) | 163 | #define IWL_DEBUG_QOS(f, a...) IWL_DEBUG(IWL_DL_QOS, f, ## a) |
148 | #define IWL_DEBUG_RADIO(f, a...) IWL_DEBUG(IWL_DL_RADIO, f, ## a) | 164 | #define IWL_DEBUG_RADIO(f, a...) IWL_DEBUG(IWL_DL_RADIO, f, ## a) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index cc726215ab93..24413a479a3f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h | |||
@@ -410,181 +410,6 @@ struct iwl4965_eeprom { | |||
410 | #define PCI_REG_WUM8 0x0E8 | 410 | #define PCI_REG_WUM8 0x0E8 |
411 | #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) | 411 | #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) |
412 | 412 | ||
413 | /*=== CSR (control and status registers) ===*/ | ||
414 | #define CSR_BASE (0x000) | ||
415 | |||
416 | #define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */ | ||
417 | #define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ | ||
418 | #define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */ | ||
419 | #define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */ | ||
420 | #define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/ | ||
421 | #define CSR_GPIO_IN (CSR_BASE+0x018) /* read external chip pins */ | ||
422 | #define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/ | ||
423 | #define CSR_GP_CNTRL (CSR_BASE+0x024) | ||
424 | |||
425 | /* | ||
426 | * Hardware revision info | ||
427 | * Bit fields: | ||
428 | * 31-8: Reserved | ||
429 | * 7-4: Type of device: 0x0 = 4965, 0xd = 3945 | ||
430 | * 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D | ||
431 | * 1-0: "Dash" value, as in A-1, etc. | ||
432 | * | ||
433 | * NOTE: Revision step affects calculation of CCK txpower for 4965. | ||
434 | */ | ||
435 | #define CSR_HW_REV (CSR_BASE+0x028) | ||
436 | |||
437 | /* EEPROM reads */ | ||
438 | #define CSR_EEPROM_REG (CSR_BASE+0x02c) | ||
439 | #define CSR_EEPROM_GP (CSR_BASE+0x030) | ||
440 | #define CSR_GP_UCODE (CSR_BASE+0x044) | ||
441 | #define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) | ||
442 | #define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058) | ||
443 | #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) | ||
444 | #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) | ||
445 | #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) | ||
446 | |||
447 | /* | ||
448 | * Indicates hardware rev, to determine CCK backoff for txpower calculation. | ||
449 | * Bit fields: | ||
450 | * 3-2: 0 = A, 1 = B, 2 = C, 3 = D step | ||
451 | */ | ||
452 | #define CSR_HW_REV_WA_REG (CSR_BASE+0x22C) | ||
453 | |||
454 | /* Hardware interface configuration bits */ | ||
455 | #define CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R (0x00000010) | ||
456 | #define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) | ||
457 | #define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) | ||
458 | #define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) | ||
459 | #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) | ||
460 | |||
461 | /* interrupt flags in INTA, set by uCode or hardware (e.g. dma), | ||
462 | * acknowledged (reset) by host writing "1" to flagged bits. */ | ||
463 | #define CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */ | ||
464 | #define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */ | ||
465 | #define CSR_INT_BIT_DNLD (1 << 28) /* uCode Download */ | ||
466 | #define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */ | ||
467 | #define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */ | ||
468 | #define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ | ||
469 | #define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ | ||
470 | #define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ | ||
471 | #define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */ | ||
472 | #define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ | ||
473 | #define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ | ||
474 | |||
475 | #define CSR_INI_SET_MASK (CSR_INT_BIT_FH_RX | \ | ||
476 | CSR_INT_BIT_HW_ERR | \ | ||
477 | CSR_INT_BIT_FH_TX | \ | ||
478 | CSR_INT_BIT_SW_ERR | \ | ||
479 | CSR_INT_BIT_RF_KILL | \ | ||
480 | CSR_INT_BIT_SW_RX | \ | ||
481 | CSR_INT_BIT_WAKEUP | \ | ||
482 | CSR_INT_BIT_ALIVE) | ||
483 | |||
484 | /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ | ||
485 | #define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */ | ||
486 | #define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ | ||
487 | #define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ | ||
488 | #define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ | ||
489 | #define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ | ||
490 | #define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ | ||
491 | |||
492 | #define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ | ||
493 | CSR_FH_INT_BIT_RX_CHNL1 | \ | ||
494 | CSR_FH_INT_BIT_RX_CHNL0) | ||
495 | |||
496 | #define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ | ||
497 | CSR_FH_INT_BIT_TX_CHNL0) | ||
498 | |||
499 | |||
500 | /* RESET */ | ||
501 | #define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001) | ||
502 | #define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002) | ||
503 | #define CSR_RESET_REG_FLAG_SW_RESET (0x00000080) | ||
504 | #define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) | ||
505 | #define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) | ||
506 | |||
507 | /* GP (general purpose) CONTROL */ | ||
508 | #define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) | ||
509 | #define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) | ||
510 | #define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) | ||
511 | #define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) | ||
512 | |||
513 | #define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) | ||
514 | |||
515 | #define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) | ||
516 | #define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000) | ||
517 | #define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) | ||
518 | |||
519 | |||
520 | /* EEPROM REG */ | ||
521 | #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) | ||
522 | #define CSR_EEPROM_REG_BIT_CMD (0x00000002) | ||
523 | |||
524 | /* EEPROM GP */ | ||
525 | #define CSR_EEPROM_GP_VALID_MSK (0x00000006) | ||
526 | #define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) | ||
527 | #define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) | ||
528 | |||
529 | /* UCODE DRV GP */ | ||
530 | #define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) | ||
531 | #define CSR_UCODE_SW_BIT_RFKILL (0x00000002) | ||
532 | #define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) | ||
533 | #define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) | ||
534 | |||
535 | /* GPIO */ | ||
536 | #define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) | ||
537 | #define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000) | ||
538 | #define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER | ||
539 | |||
540 | /* GI Chicken Bits */ | ||
541 | #define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) | ||
542 | #define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) | ||
543 | |||
544 | /*=== HBUS (Host-side Bus) ===*/ | ||
545 | #define HBUS_BASE (0x400) | ||
546 | |||
547 | /* | ||
548 | * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM | ||
549 | * structures, error log, event log, verifying uCode load). | ||
550 | * First write to address register, then read from or write to data register | ||
551 | * to complete the job. Once the address register is set up, accesses to | ||
552 | * data registers auto-increment the address by one dword. | ||
553 | * Bit usage for address registers (read or write): | ||
554 | * 0-31: memory address within device | ||
555 | */ | ||
556 | #define HBUS_TARG_MEM_RADDR (HBUS_BASE+0x00c) | ||
557 | #define HBUS_TARG_MEM_WADDR (HBUS_BASE+0x010) | ||
558 | #define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018) | ||
559 | #define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c) | ||
560 | |||
561 | /* | ||
562 | * Registers for accessing device's internal peripheral registers | ||
563 | * (e.g. SCD, BSM, etc.). First write to address register, | ||
564 | * then read from or write to data register to complete the job. | ||
565 | * Bit usage for address registers (read or write): | ||
566 | * 0-15: register address (offset) within device | ||
567 | * 24-25: (# bytes - 1) to read or write (e.g. 3 for dword) | ||
568 | */ | ||
569 | #define HBUS_TARG_PRPH_WADDR (HBUS_BASE+0x044) | ||
570 | #define HBUS_TARG_PRPH_RADDR (HBUS_BASE+0x048) | ||
571 | #define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c) | ||
572 | #define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050) | ||
573 | |||
574 | /* | ||
575 | * Per-Tx-queue write pointer (index, really!) (3945 and 4965). | ||
576 | * Driver sets this to indicate index to next TFD that driver will fill | ||
577 | * (1 past latest filled). | ||
578 | * Bit usage: | ||
579 | * 0-7: queue write index (0-255) | ||
580 | * 11-8: queue selector (0-15) | ||
581 | */ | ||
582 | #define HBUS_TARG_WRPTR (HBUS_BASE+0x060) | ||
583 | |||
584 | #define HBUS_TARG_MBX_C (HBUS_BASE+0x030) | ||
585 | |||
586 | #define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) | ||
587 | |||
588 | #define TFD_QUEUE_SIZE_MAX (256) | 413 | #define TFD_QUEUE_SIZE_MAX (256) |
589 | 414 | ||
590 | #define IWL_NUM_SCAN_RATES (2) | 415 | #define IWL_NUM_SCAN_RATES (2) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 48a6a85355ec..25e73864c2a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c | |||
@@ -570,7 +570,7 @@ static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, | |||
570 | int index; | 570 | int index; |
571 | u32 ant_msk; | 571 | u32 ant_msk; |
572 | 572 | ||
573 | index = iwl4965_rate_index_from_plcp(mcs_rate->rate_n_flags); | 573 | index = iwl4965_hwrate_to_plcp_idx(mcs_rate->rate_n_flags); |
574 | 574 | ||
575 | if (index == IWL_RATE_INVALID) { | 575 | if (index == IWL_RATE_INVALID) { |
576 | *rate_idx = -1; | 576 | *rate_idx = -1; |
@@ -823,6 +823,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, | |||
823 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 823 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
824 | struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate; | 824 | struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate; |
825 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 825 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
826 | struct ieee80211_hw *hw = local_to_hw(local); | ||
826 | struct iwl4965_rate_scale_data *window = NULL; | 827 | struct iwl4965_rate_scale_data *window = NULL; |
827 | struct iwl4965_rate_scale_data *search_win = NULL; | 828 | struct iwl4965_rate_scale_data *search_win = NULL; |
828 | struct iwl4965_rate tx_mcs; | 829 | struct iwl4965_rate tx_mcs; |
@@ -847,23 +848,22 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, | |||
847 | if (retries > 15) | 848 | if (retries > 15) |
848 | retries = 15; | 849 | retries = 15; |
849 | 850 | ||
851 | rcu_read_lock(); | ||
850 | 852 | ||
851 | sta = sta_info_get(local, hdr->addr1); | 853 | sta = sta_info_get(local, hdr->addr1); |
852 | 854 | ||
853 | if (!sta || !sta->rate_ctrl_priv) { | 855 | if (!sta || !sta->rate_ctrl_priv) |
854 | if (sta) | 856 | goto out; |
855 | sta_info_put(sta); | 857 | |
856 | return; | ||
857 | } | ||
858 | 858 | ||
859 | lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; | 859 | lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; |
860 | 860 | ||
861 | if (!priv->lq_mngr.lq_ready) | 861 | if (!priv->lq_mngr.lq_ready) |
862 | return; | 862 | goto out; |
863 | 863 | ||
864 | if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && | 864 | if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && |
865 | !lq_sta->ibss_sta_added) | 865 | !lq_sta->ibss_sta_added) |
866 | return; | 866 | goto out; |
867 | 867 | ||
868 | table = &lq_sta->lq; | 868 | table = &lq_sta->lq; |
869 | active_index = lq_sta->active_tbl; | 869 | active_index = lq_sta->active_tbl; |
@@ -884,17 +884,6 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, | |||
884 | search_win = (struct iwl4965_rate_scale_data *) | 884 | search_win = (struct iwl4965_rate_scale_data *) |
885 | &(search_tbl->win[0]); | 885 | &(search_tbl->win[0]); |
886 | 886 | ||
887 | tx_mcs.rate_n_flags = tx_resp->control.tx_rate->hw_value; | ||
888 | |||
889 | rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, | ||
890 | &tbl_type, &rs_index); | ||
891 | if ((rs_index < 0) || (rs_index >= IWL_RATE_COUNT)) { | ||
892 | IWL_DEBUG_RATE("bad rate index at: %d rate 0x%X\n", | ||
893 | rs_index, tx_mcs.rate_n_flags); | ||
894 | sta_info_put(sta); | ||
895 | return; | ||
896 | } | ||
897 | |||
898 | /* | 887 | /* |
899 | * Ignore this Tx frame response if its initial rate doesn't match | 888 | * Ignore this Tx frame response if its initial rate doesn't match |
900 | * that of latest Link Quality command. There may be stragglers | 889 | * that of latest Link Quality command. There may be stragglers |
@@ -903,14 +892,29 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, | |||
903 | * to check "search" mode, or a prior "search" mode after we've moved | 892 | * to check "search" mode, or a prior "search" mode after we've moved |
904 | * to a new "search" mode (which might become the new "active" mode). | 893 | * to a new "search" mode (which might become the new "active" mode). |
905 | */ | 894 | */ |
906 | if (retries && | 895 | tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[0].rate_n_flags); |
907 | (tx_mcs.rate_n_flags != | 896 | rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index); |
908 | le32_to_cpu(table->rs_table[0].rate_n_flags))) { | 897 | if (priv->band == IEEE80211_BAND_5GHZ) |
909 | IWL_DEBUG_RATE("initial rate does not match 0x%x 0x%x\n", | 898 | rs_index -= IWL_FIRST_OFDM_RATE; |
910 | tx_mcs.rate_n_flags, | 899 | |
911 | le32_to_cpu(table->rs_table[0].rate_n_flags)); | 900 | if ((tx_resp->control.tx_rate == NULL) || |
912 | sta_info_put(sta); | 901 | (tbl_type.is_SGI ^ |
913 | return; | 902 | !!(tx_resp->control.flags & IEEE80211_TXCTL_SHORT_GI)) || |
903 | (tbl_type.is_fat ^ | ||
904 | !!(tx_resp->control.flags & IEEE80211_TXCTL_40_MHZ_WIDTH)) || | ||
905 | (tbl_type.is_dup ^ | ||
906 | !!(tx_resp->control.flags & IEEE80211_TXCTL_DUP_DATA)) || | ||
907 | (tbl_type.antenna_type ^ | ||
908 | tx_resp->control.antenna_sel_tx) || | ||
909 | (!!(tx_mcs.rate_n_flags & RATE_MCS_HT_MSK) ^ | ||
910 | !!(tx_resp->control.flags & IEEE80211_TXCTL_OFDM_HT)) || | ||
911 | (!!(tx_mcs.rate_n_flags & RATE_MCS_GF_MSK) ^ | ||
912 | !!(tx_resp->control.flags & IEEE80211_TXCTL_GREEN_FIELD)) || | ||
913 | (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != | ||
914 | tx_resp->control.tx_rate->bitrate)) { | ||
915 | IWL_DEBUG_RATE("initial rate does not match 0x%x\n", | ||
916 | tx_mcs.rate_n_flags); | ||
917 | goto out; | ||
914 | } | 918 | } |
915 | 919 | ||
916 | /* Update frame history window with "failure" for each Tx retry. */ | 920 | /* Update frame history window with "failure" for each Tx retry. */ |
@@ -959,14 +963,8 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, | |||
959 | * if Tx was successful first try, use original rate, | 963 | * if Tx was successful first try, use original rate, |
960 | * else look up the rate that was, finally, successful. | 964 | * else look up the rate that was, finally, successful. |
961 | */ | 965 | */ |
962 | if (!tx_resp->retry_count) | 966 | tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[index].rate_n_flags); |
963 | tx_mcs.rate_n_flags = tx_resp->control.tx_rate->hw_value; | 967 | rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index); |
964 | else | ||
965 | tx_mcs.rate_n_flags = | ||
966 | le32_to_cpu(table->rs_table[index].rate_n_flags); | ||
967 | |||
968 | rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, | ||
969 | &tbl_type, &rs_index); | ||
970 | 968 | ||
971 | /* Update frame history window with "success" if Tx got ACKed ... */ | 969 | /* Update frame history window with "success" if Tx got ACKed ... */ |
972 | if (tx_resp->flags & IEEE80211_TX_STATUS_ACK) | 970 | if (tx_resp->flags & IEEE80211_TX_STATUS_ACK) |
@@ -1025,7 +1023,8 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, | |||
1025 | 1023 | ||
1026 | /* See if there's a better rate or modulation mode to try. */ | 1024 | /* See if there's a better rate or modulation mode to try. */ |
1027 | rs_rate_scale_perform(priv, dev, hdr, sta); | 1025 | rs_rate_scale_perform(priv, dev, hdr, sta); |
1028 | sta_info_put(sta); | 1026 | out: |
1027 | rcu_read_unlock(); | ||
1029 | return; | 1028 | return; |
1030 | } | 1029 | } |
1031 | 1030 | ||
@@ -1921,7 +1920,7 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
1921 | tbl = &(lq_sta->lq_info[active_tbl]); | 1920 | tbl = &(lq_sta->lq_info[active_tbl]); |
1922 | 1921 | ||
1923 | /* Revert to "active" rate and throughput info */ | 1922 | /* Revert to "active" rate and throughput info */ |
1924 | index = iwl4965_rate_index_from_plcp( | 1923 | index = iwl4965_hwrate_to_plcp_idx( |
1925 | tbl->current_rate.rate_n_flags); | 1924 | tbl->current_rate.rate_n_flags); |
1926 | current_tpt = lq_sta->last_tpt; | 1925 | current_tpt = lq_sta->last_tpt; |
1927 | 1926 | ||
@@ -2077,7 +2076,7 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
2077 | rs_rate_scale_clear_window(&(tbl->win[i])); | 2076 | rs_rate_scale_clear_window(&(tbl->win[i])); |
2078 | 2077 | ||
2079 | /* Use new "search" start rate */ | 2078 | /* Use new "search" start rate */ |
2080 | index = iwl4965_rate_index_from_plcp( | 2079 | index = iwl4965_hwrate_to_plcp_idx( |
2081 | tbl->current_rate.rate_n_flags); | 2080 | tbl->current_rate.rate_n_flags); |
2082 | 2081 | ||
2083 | IWL_DEBUG_HT("Switch current mcs: %X index: %d\n", | 2082 | IWL_DEBUG_HT("Switch current mcs: %X index: %d\n", |
@@ -2219,6 +2218,8 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, | |||
2219 | 2218 | ||
2220 | IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); | 2219 | IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); |
2221 | 2220 | ||
2221 | rcu_read_lock(); | ||
2222 | |||
2222 | sta = sta_info_get(local, hdr->addr1); | 2223 | sta = sta_info_get(local, hdr->addr1); |
2223 | 2224 | ||
2224 | /* Send management frames and broadcast/multicast data using lowest | 2225 | /* Send management frames and broadcast/multicast data using lowest |
@@ -2227,9 +2228,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, | |||
2227 | if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || | 2228 | if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || |
2228 | !sta || !sta->rate_ctrl_priv) { | 2229 | !sta || !sta->rate_ctrl_priv) { |
2229 | sel->rate = rate_lowest(local, sband, sta); | 2230 | sel->rate = rate_lowest(local, sband, sta); |
2230 | if (sta) | 2231 | goto out; |
2231 | sta_info_put(sta); | ||
2232 | return; | ||
2233 | } | 2232 | } |
2234 | 2233 | ||
2235 | lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; | 2234 | lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; |
@@ -2256,14 +2255,15 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, | |||
2256 | goto done; | 2255 | goto done; |
2257 | } | 2256 | } |
2258 | 2257 | ||
2259 | done: | 2258 | done: |
2260 | if ((i < 0) || (i > IWL_RATE_COUNT)) { | 2259 | if ((i < 0) || (i > IWL_RATE_COUNT)) { |
2261 | sel->rate = rate_lowest(local, sband, sta); | 2260 | sel->rate = rate_lowest(local, sband, sta); |
2262 | return; | 2261 | goto out; |
2263 | } | 2262 | } |
2264 | sta_info_put(sta); | ||
2265 | 2263 | ||
2266 | sel->rate = &priv->ieee_rates[i]; | 2264 | sel->rate = &priv->ieee_rates[i]; |
2265 | out: | ||
2266 | rcu_read_unlock(); | ||
2267 | } | 2267 | } |
2268 | 2268 | ||
2269 | static void *rs_alloc_sta(void *priv, gfp_t gfp) | 2269 | static void *rs_alloc_sta(void *priv, gfp_t gfp) |
@@ -2735,13 +2735,15 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) | |||
2735 | u32 max_time = 0; | 2735 | u32 max_time = 0; |
2736 | u8 lq_type, antenna; | 2736 | u8 lq_type, antenna; |
2737 | 2737 | ||
2738 | rcu_read_lock(); | ||
2739 | |||
2738 | sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); | 2740 | sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); |
2739 | if (!sta || !sta->rate_ctrl_priv) { | 2741 | if (!sta || !sta->rate_ctrl_priv) { |
2740 | if (sta) { | 2742 | if (sta) |
2741 | sta_info_put(sta); | ||
2742 | IWL_DEBUG_RATE("leave - no private rate data!\n"); | 2743 | IWL_DEBUG_RATE("leave - no private rate data!\n"); |
2743 | } else | 2744 | else |
2744 | IWL_DEBUG_RATE("leave - no station!\n"); | 2745 | IWL_DEBUG_RATE("leave - no station!\n"); |
2746 | rcu_read_unlock(); | ||
2745 | return sprintf(buf, "station %d not found\n", sta_id); | 2747 | return sprintf(buf, "station %d not found\n", sta_id); |
2746 | } | 2748 | } |
2747 | 2749 | ||
@@ -2808,7 +2810,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) | |||
2808 | "active_search %d rate index %d\n", lq_type, antenna, | 2810 | "active_search %d rate index %d\n", lq_type, antenna, |
2809 | lq_sta->search_better_tbl, sta->last_txrate_idx); | 2811 | lq_sta->search_better_tbl, sta->last_txrate_idx); |
2810 | 2812 | ||
2811 | sta_info_put(sta); | 2813 | rcu_read_unlock(); |
2812 | return cnt; | 2814 | return cnt; |
2813 | } | 2815 | } |
2814 | 2816 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h index 13b6c72eeb73..911f21396fd0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h | |||
@@ -259,7 +259,7 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) | |||
259 | return rate; | 259 | return rate; |
260 | } | 260 | } |
261 | 261 | ||
262 | extern int iwl4965_rate_index_from_plcp(int plcp); | 262 | extern int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags); |
263 | 263 | ||
264 | /** | 264 | /** |
265 | * iwl4965_fill_rs_info - Fill an output text buffer with the rate representation | 265 | * iwl4965_fill_rs_info - Fill an output text buffer with the rate representation |
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index a9c30bcb65b8..2f01a490c9ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/etherdevice.h> | 38 | #include <linux/etherdevice.h> |
39 | #include <asm/unaligned.h> | 39 | #include <asm/unaligned.h> |
40 | 40 | ||
41 | #include "iwl-core.h" | ||
41 | #include "iwl-4965.h" | 42 | #include "iwl-4965.h" |
42 | #include "iwl-helpers.h" | 43 | #include "iwl-helpers.h" |
43 | 44 | ||
@@ -122,6 +123,64 @@ static u8 is_single_stream(struct iwl4965_priv *priv) | |||
122 | return 0; | 123 | return 0; |
123 | } | 124 | } |
124 | 125 | ||
126 | int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags) | ||
127 | { | ||
128 | int idx = 0; | ||
129 | |||
130 | /* 4965 HT rate format */ | ||
131 | if (rate_n_flags & RATE_MCS_HT_MSK) { | ||
132 | idx = (rate_n_flags & 0xff); | ||
133 | |||
134 | if (idx >= IWL_RATE_MIMO_6M_PLCP) | ||
135 | idx = idx - IWL_RATE_MIMO_6M_PLCP; | ||
136 | |||
137 | idx += IWL_FIRST_OFDM_RATE; | ||
138 | /* skip 9M not supported in ht*/ | ||
139 | if (idx >= IWL_RATE_9M_INDEX) | ||
140 | idx += 1; | ||
141 | if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE)) | ||
142 | return idx; | ||
143 | |||
144 | /* 4965 legacy rate format, search for match in table */ | ||
145 | } else { | ||
146 | for (idx = 0; idx < ARRAY_SIZE(iwl4965_rates); idx++) | ||
147 | if (iwl4965_rates[idx].plcp == (rate_n_flags & 0xFF)) | ||
148 | return idx; | ||
149 | } | ||
150 | |||
151 | return -1; | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * translate ucode response to mac80211 tx status control values | ||
156 | */ | ||
157 | void iwl4965_hwrate_to_tx_control(struct iwl4965_priv *priv, u32 rate_n_flags, | ||
158 | struct ieee80211_tx_control *control) | ||
159 | { | ||
160 | int rate_index; | ||
161 | |||
162 | control->antenna_sel_tx = | ||
163 | ((rate_n_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_A_POS); | ||
164 | if (rate_n_flags & RATE_MCS_HT_MSK) | ||
165 | control->flags |= IEEE80211_TXCTL_OFDM_HT; | ||
166 | if (rate_n_flags & RATE_MCS_GF_MSK) | ||
167 | control->flags |= IEEE80211_TXCTL_GREEN_FIELD; | ||
168 | if (rate_n_flags & RATE_MCS_FAT_MSK) | ||
169 | control->flags |= IEEE80211_TXCTL_40_MHZ_WIDTH; | ||
170 | if (rate_n_flags & RATE_MCS_DUP_MSK) | ||
171 | control->flags |= IEEE80211_TXCTL_DUP_DATA; | ||
172 | if (rate_n_flags & RATE_MCS_SGI_MSK) | ||
173 | control->flags |= IEEE80211_TXCTL_SHORT_GI; | ||
174 | /* since iwl4965_hwrate_to_plcp_idx is band indifferent, we always use | ||
175 | * IEEE80211_BAND_2GHZ band as it contains all the rates */ | ||
176 | rate_index = iwl4965_hwrate_to_plcp_idx(rate_n_flags); | ||
177 | if (rate_index == -1) | ||
178 | control->tx_rate = NULL; | ||
179 | else | ||
180 | control->tx_rate = | ||
181 | &priv->bands[IEEE80211_BAND_2GHZ].bitrates[rate_index]; | ||
182 | } | ||
183 | |||
125 | /* | 184 | /* |
126 | * Determine how many receiver/antenna chains to use. | 185 | * Determine how many receiver/antenna chains to use. |
127 | * More provides better reception via diversity. Fewer saves power. | 186 | * More provides better reception via diversity. Fewer saves power. |
@@ -546,9 +605,9 @@ int iwl4965_hw_nic_init(struct iwl4965_priv *priv) | |||
546 | /* set CSR_HW_CONFIG_REG for uCode use */ | 605 | /* set CSR_HW_CONFIG_REG for uCode use */ |
547 | 606 | ||
548 | iwl4965_set_bit(priv, CSR_HW_IF_CONFIG_REG, | 607 | iwl4965_set_bit(priv, CSR_HW_IF_CONFIG_REG, |
549 | CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R | | 608 | CSR49_HW_IF_CONFIG_REG_BIT_4965_R | |
550 | CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | | 609 | CSR49_HW_IF_CONFIG_REG_BIT_RADIO_SI | |
551 | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); | 610 | CSR49_HW_IF_CONFIG_REG_BIT_MAC_SI); |
552 | 611 | ||
553 | rc = iwl4965_grab_nic_access(priv); | 612 | rc = iwl4965_grab_nic_access(priv); |
554 | if (rc < 0) { | 613 | if (rc < 0) { |
@@ -3523,6 +3582,160 @@ static void iwl4965_update_ps_mode(struct iwl4965_priv *priv, u16 ps_bit, u8 *ad | |||
3523 | } | 3582 | } |
3524 | } | 3583 | } |
3525 | } | 3584 | } |
3585 | #ifdef CONFIG_IWL4965_DEBUG | ||
3586 | |||
3587 | /** | ||
3588 | * iwl4965_dbg_report_frame - dump frame to syslog during debug sessions | ||
3589 | * | ||
3590 | * You may hack this function to show different aspects of received frames, | ||
3591 | * including selective frame dumps. | ||
3592 | * group100 parameter selects whether to show 1 out of 100 good frames. | ||
3593 | * | ||
3594 | * TODO: This was originally written for 3945, need to audit for | ||
3595 | * proper operation with 4965. | ||
3596 | */ | ||
3597 | static void iwl4965_dbg_report_frame(struct iwl4965_priv *priv, | ||
3598 | struct iwl4965_rx_packet *pkt, | ||
3599 | struct ieee80211_hdr *header, int group100) | ||
3600 | { | ||
3601 | u32 to_us; | ||
3602 | u32 print_summary = 0; | ||
3603 | u32 print_dump = 0; /* set to 1 to dump all frames' contents */ | ||
3604 | u32 hundred = 0; | ||
3605 | u32 dataframe = 0; | ||
3606 | u16 fc; | ||
3607 | u16 seq_ctl; | ||
3608 | u16 channel; | ||
3609 | u16 phy_flags; | ||
3610 | int rate_sym; | ||
3611 | u16 length; | ||
3612 | u16 status; | ||
3613 | u16 bcn_tmr; | ||
3614 | u32 tsf_low; | ||
3615 | u64 tsf; | ||
3616 | u8 rssi; | ||
3617 | u8 agc; | ||
3618 | u16 sig_avg; | ||
3619 | u16 noise_diff; | ||
3620 | struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); | ||
3621 | struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); | ||
3622 | struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); | ||
3623 | u8 *data = IWL_RX_DATA(pkt); | ||
3624 | |||
3625 | if (likely(!(iwl4965_debug_level & IWL_DL_RX))) | ||
3626 | return; | ||
3627 | |||
3628 | /* MAC header */ | ||
3629 | fc = le16_to_cpu(header->frame_control); | ||
3630 | seq_ctl = le16_to_cpu(header->seq_ctrl); | ||
3631 | |||
3632 | /* metadata */ | ||
3633 | channel = le16_to_cpu(rx_hdr->channel); | ||
3634 | phy_flags = le16_to_cpu(rx_hdr->phy_flags); | ||
3635 | rate_sym = rx_hdr->rate; | ||
3636 | length = le16_to_cpu(rx_hdr->len); | ||
3637 | |||
3638 | /* end-of-frame status and timestamp */ | ||
3639 | status = le32_to_cpu(rx_end->status); | ||
3640 | bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); | ||
3641 | tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; | ||
3642 | tsf = le64_to_cpu(rx_end->timestamp); | ||
3643 | |||
3644 | /* signal statistics */ | ||
3645 | rssi = rx_stats->rssi; | ||
3646 | agc = rx_stats->agc; | ||
3647 | sig_avg = le16_to_cpu(rx_stats->sig_avg); | ||
3648 | noise_diff = le16_to_cpu(rx_stats->noise_diff); | ||
3649 | |||
3650 | to_us = !compare_ether_addr(header->addr1, priv->mac_addr); | ||
3651 | |||
3652 | /* if data frame is to us and all is good, | ||
3653 | * (optionally) print summary for only 1 out of every 100 */ | ||
3654 | if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == | ||
3655 | (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { | ||
3656 | dataframe = 1; | ||
3657 | if (!group100) | ||
3658 | print_summary = 1; /* print each frame */ | ||
3659 | else if (priv->framecnt_to_us < 100) { | ||
3660 | priv->framecnt_to_us++; | ||
3661 | print_summary = 0; | ||
3662 | } else { | ||
3663 | priv->framecnt_to_us = 0; | ||
3664 | print_summary = 1; | ||
3665 | hundred = 1; | ||
3666 | } | ||
3667 | } else { | ||
3668 | /* print summary for all other frames */ | ||
3669 | print_summary = 1; | ||
3670 | } | ||
3671 | |||
3672 | if (print_summary) { | ||
3673 | char *title; | ||
3674 | int rate_idx; | ||
3675 | u32 bitrate; | ||
3676 | |||
3677 | if (hundred) | ||
3678 | title = "100Frames"; | ||
3679 | else if (fc & IEEE80211_FCTL_RETRY) | ||
3680 | title = "Retry"; | ||
3681 | else if (ieee80211_is_assoc_response(fc)) | ||
3682 | title = "AscRsp"; | ||
3683 | else if (ieee80211_is_reassoc_response(fc)) | ||
3684 | title = "RasRsp"; | ||
3685 | else if (ieee80211_is_probe_response(fc)) { | ||
3686 | title = "PrbRsp"; | ||
3687 | print_dump = 1; /* dump frame contents */ | ||
3688 | } else if (ieee80211_is_beacon(fc)) { | ||
3689 | title = "Beacon"; | ||
3690 | print_dump = 1; /* dump frame contents */ | ||
3691 | } else if (ieee80211_is_atim(fc)) | ||
3692 | title = "ATIM"; | ||
3693 | else if (ieee80211_is_auth(fc)) | ||
3694 | title = "Auth"; | ||
3695 | else if (ieee80211_is_deauth(fc)) | ||
3696 | title = "DeAuth"; | ||
3697 | else if (ieee80211_is_disassoc(fc)) | ||
3698 | title = "DisAssoc"; | ||
3699 | else | ||
3700 | title = "Frame"; | ||
3701 | |||
3702 | rate_idx = iwl4965_hwrate_to_plcp_idx(rate_sym); | ||
3703 | if (unlikely(rate_idx == -1)) | ||
3704 | bitrate = 0; | ||
3705 | else | ||
3706 | bitrate = iwl4965_rates[rate_idx].ieee / 2; | ||
3707 | |||
3708 | /* print frame summary. | ||
3709 | * MAC addresses show just the last byte (for brevity), | ||
3710 | * but you can hack it to show more, if you'd like to. */ | ||
3711 | if (dataframe) | ||
3712 | IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " | ||
3713 | "len=%u, rssi=%d, chnl=%d, rate=%u, \n", | ||
3714 | title, fc, header->addr1[5], | ||
3715 | length, rssi, channel, bitrate); | ||
3716 | else { | ||
3717 | /* src/dst addresses assume managed mode */ | ||
3718 | IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " | ||
3719 | "src=0x%02x, rssi=%u, tim=%lu usec, " | ||
3720 | "phy=0x%02x, chnl=%d\n", | ||
3721 | title, fc, header->addr1[5], | ||
3722 | header->addr3[5], rssi, | ||
3723 | tsf_low - priv->scan_start_tsf, | ||
3724 | phy_flags, channel); | ||
3725 | } | ||
3726 | } | ||
3727 | if (print_dump) | ||
3728 | iwl4965_print_hex_dump(IWL_DL_RX, data, length); | ||
3729 | } | ||
3730 | #else | ||
3731 | static inline void iwl4965_dbg_report_frame(struct iwl4965_priv *priv, | ||
3732 | struct iwl4965_rx_packet *pkt, | ||
3733 | struct ieee80211_hdr *header, | ||
3734 | int group100) | ||
3735 | { | ||
3736 | } | ||
3737 | #endif | ||
3738 | |||
3526 | 3739 | ||
3527 | #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) | 3740 | #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) |
3528 | 3741 | ||
@@ -3531,6 +3744,8 @@ static void iwl4965_update_ps_mode(struct iwl4965_priv *priv, u16 ps_bit, u8 *ad | |||
3531 | static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, | 3744 | static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, |
3532 | struct iwl4965_rx_mem_buffer *rxb) | 3745 | struct iwl4965_rx_mem_buffer *rxb) |
3533 | { | 3746 | { |
3747 | struct ieee80211_hdr *header; | ||
3748 | struct ieee80211_rx_status rx_status; | ||
3534 | struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; | 3749 | struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; |
3535 | /* Use phy data (Rx signal strength, etc.) contained within | 3750 | /* Use phy data (Rx signal strength, etc.) contained within |
3536 | * this rx packet for legacy frames, | 3751 | * this rx packet for legacy frames, |
@@ -3541,27 +3756,29 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, | |||
3541 | (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; | 3756 | (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; |
3542 | __le32 *rx_end; | 3757 | __le32 *rx_end; |
3543 | unsigned int len = 0; | 3758 | unsigned int len = 0; |
3544 | struct ieee80211_hdr *header; | ||
3545 | u16 fc; | 3759 | u16 fc; |
3546 | struct ieee80211_rx_status stats = { | ||
3547 | .mactime = le64_to_cpu(rx_start->timestamp), | ||
3548 | .freq = ieee80211chan2mhz(le16_to_cpu(rx_start->channel)), | ||
3549 | .band = | ||
3550 | (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? | ||
3551 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ, | ||
3552 | .antenna = 0, | ||
3553 | .rate_idx = iwl4965_rate_index_from_plcp( | ||
3554 | le32_to_cpu(rx_start->rate_n_flags)), | ||
3555 | .flag = 0, | ||
3556 | }; | ||
3557 | u8 network_packet; | 3760 | u8 network_packet; |
3558 | 3761 | ||
3762 | rx_status.mactime = le64_to_cpu(rx_start->timestamp); | ||
3763 | rx_status.freq = ieee80211chan2mhz(le16_to_cpu(rx_start->channel)); | ||
3764 | rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? | ||
3765 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; | ||
3766 | rx_status.rate_idx = iwl4965_hwrate_to_plcp_idx( | ||
3767 | le32_to_cpu(rx_start->rate_n_flags)); | ||
3768 | |||
3769 | if (rx_status.band == IEEE80211_BAND_5GHZ) | ||
3770 | rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; | ||
3771 | |||
3772 | rx_status.antenna = 0; | ||
3773 | rx_status.flag = 0; | ||
3774 | |||
3559 | if ((unlikely(rx_start->cfg_phy_cnt > 20))) { | 3775 | if ((unlikely(rx_start->cfg_phy_cnt > 20))) { |
3560 | IWL_DEBUG_DROP | 3776 | IWL_DEBUG_DROP |
3561 | ("dsp size out of range [0,20]: " | 3777 | ("dsp size out of range [0,20]: " |
3562 | "%d/n", rx_start->cfg_phy_cnt); | 3778 | "%d/n", rx_start->cfg_phy_cnt); |
3563 | return; | 3779 | return; |
3564 | } | 3780 | } |
3781 | |||
3565 | if (!include_phy) { | 3782 | if (!include_phy) { |
3566 | if (priv->last_phy_res[0]) | 3783 | if (priv->last_phy_res[0]) |
3567 | rx_start = (struct iwl4965_rx_phy_res *) | 3784 | rx_start = (struct iwl4965_rx_phy_res *) |
@@ -3580,7 +3797,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, | |||
3580 | + rx_start->cfg_phy_cnt); | 3797 | + rx_start->cfg_phy_cnt); |
3581 | 3798 | ||
3582 | len = le16_to_cpu(rx_start->byte_count); | 3799 | len = le16_to_cpu(rx_start->byte_count); |
3583 | rx_end = (__le32 *) (pkt->u.raw + rx_start->cfg_phy_cnt + | 3800 | rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + |
3584 | sizeof(struct iwl4965_rx_phy_res) + len); | 3801 | sizeof(struct iwl4965_rx_phy_res) + len); |
3585 | } else { | 3802 | } else { |
3586 | struct iwl4965_rx_mpdu_res_start *amsdu = | 3803 | struct iwl4965_rx_mpdu_res_start *amsdu = |
@@ -3603,7 +3820,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, | |||
3603 | priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); | 3820 | priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); |
3604 | 3821 | ||
3605 | /* Find max signal strength (dBm) among 3 antenna/receiver chains */ | 3822 | /* Find max signal strength (dBm) among 3 antenna/receiver chains */ |
3606 | stats.ssi = iwl4965_calc_rssi(rx_start); | 3823 | rx_status.ssi = iwl4965_calc_rssi(rx_start); |
3607 | 3824 | ||
3608 | /* Meaningful noise values are available only from beacon statistics, | 3825 | /* Meaningful noise values are available only from beacon statistics, |
3609 | * which are gathered only when associated, and indicate noise | 3826 | * which are gathered only when associated, and indicate noise |
@@ -3611,32 +3828,29 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, | |||
3611 | * Ignore these noise values while scanning (other channels) */ | 3828 | * Ignore these noise values while scanning (other channels) */ |
3612 | if (iwl4965_is_associated(priv) && | 3829 | if (iwl4965_is_associated(priv) && |
3613 | !test_bit(STATUS_SCANNING, &priv->status)) { | 3830 | !test_bit(STATUS_SCANNING, &priv->status)) { |
3614 | stats.noise = priv->last_rx_noise; | 3831 | rx_status.noise = priv->last_rx_noise; |
3615 | stats.signal = iwl4965_calc_sig_qual(stats.ssi, stats.noise); | 3832 | rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi, |
3833 | rx_status.noise); | ||
3616 | } else { | 3834 | } else { |
3617 | stats.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | 3835 | rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; |
3618 | stats.signal = iwl4965_calc_sig_qual(stats.ssi, 0); | 3836 | rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi, 0); |
3619 | } | 3837 | } |
3620 | 3838 | ||
3621 | /* Reset beacon noise level if not associated. */ | 3839 | /* Reset beacon noise level if not associated. */ |
3622 | if (!iwl4965_is_associated(priv)) | 3840 | if (!iwl4965_is_associated(priv)) |
3623 | priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | 3841 | priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; |
3624 | 3842 | ||
3625 | #ifdef CONFIG_IWL4965_DEBUG | 3843 | /* Set "1" to report good data frames in groups of 100 */ |
3626 | /* TODO: Parts of iwl4965_report_frame are broken for 4965 */ | 3844 | /* FIXME: need to optimze the call: */ |
3627 | if (iwl4965_debug_level & (IWL_DL_RX)) | 3845 | iwl4965_dbg_report_frame(priv, pkt, header, 1); |
3628 | /* Set "1" to report good data frames in groups of 100 */ | 3846 | |
3629 | iwl4965_report_frame(priv, pkt, header, 1); | 3847 | IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", |
3630 | 3848 | rx_status.ssi, rx_status.noise, rx_status.signal, | |
3631 | if (iwl4965_debug_level & (IWL_DL_RX | IWL_DL_STATS)) | 3849 | rx_status.mactime); |
3632 | IWL_DEBUG_RX("Rssi %d, noise %d, qual %d, TSF %lu\n", | ||
3633 | stats.ssi, stats.noise, stats.signal, | ||
3634 | (long unsigned int)le64_to_cpu(rx_start->timestamp)); | ||
3635 | #endif | ||
3636 | 3850 | ||
3637 | network_packet = iwl4965_is_network_packet(priv, header); | 3851 | network_packet = iwl4965_is_network_packet(priv, header); |
3638 | if (network_packet) { | 3852 | if (network_packet) { |
3639 | priv->last_rx_rssi = stats.ssi; | 3853 | priv->last_rx_rssi = rx_status.ssi; |
3640 | priv->last_beacon_time = priv->ucode_beacon_time; | 3854 | priv->last_beacon_time = priv->ucode_beacon_time; |
3641 | priv->last_tsf = le64_to_cpu(rx_start->timestamp); | 3855 | priv->last_tsf = le64_to_cpu(rx_start->timestamp); |
3642 | } | 3856 | } |
@@ -3739,7 +3953,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, | |||
3739 | return; | 3953 | return; |
3740 | } | 3954 | } |
3741 | } | 3955 | } |
3742 | iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &stats); | 3956 | iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &rx_status); |
3743 | break; | 3957 | break; |
3744 | 3958 | ||
3745 | case IEEE80211_FTYPE_CTL: | 3959 | case IEEE80211_FTYPE_CTL: |
@@ -3748,7 +3962,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, | |||
3748 | case IEEE80211_STYPE_BACK_REQ: | 3962 | case IEEE80211_STYPE_BACK_REQ: |
3749 | IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n"); | 3963 | IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n"); |
3750 | iwl4965_handle_data_packet(priv, 0, include_phy, | 3964 | iwl4965_handle_data_packet(priv, 0, include_phy, |
3751 | rxb, &stats); | 3965 | rxb, &rx_status); |
3752 | break; | 3966 | break; |
3753 | default: | 3967 | default: |
3754 | break; | 3968 | break; |
@@ -3778,7 +3992,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, | |||
3778 | print_mac(mac3, header->addr3)); | 3992 | print_mac(mac3, header->addr3)); |
3779 | else | 3993 | else |
3780 | iwl4965_handle_data_packet(priv, 1, include_phy, rxb, | 3994 | iwl4965_handle_data_packet(priv, 1, include_phy, rxb, |
3781 | &stats); | 3995 | &rx_status); |
3782 | break; | 3996 | break; |
3783 | } | 3997 | } |
3784 | default: | 3998 | default: |
@@ -3900,11 +4114,10 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl4965_priv *priv, | |||
3900 | tx_status->flags |= IEEE80211_TX_STATUS_AMPDU; | 4114 | tx_status->flags |= IEEE80211_TX_STATUS_AMPDU; |
3901 | tx_status->ampdu_ack_map = successes; | 4115 | tx_status->ampdu_ack_map = successes; |
3902 | tx_status->ampdu_ack_len = agg->frame_count; | 4116 | tx_status->ampdu_ack_len = agg->frame_count; |
3903 | /* FIXME Wrong rate | 4117 | iwl4965_hwrate_to_tx_control(priv, agg->rate_n_flags, |
3904 | tx_status->control.tx_rate = agg->rate_n_flags; | 4118 | &tx_status->control); |
3905 | */ | ||
3906 | 4119 | ||
3907 | IWL_DEBUG_TX_REPLY("Bitmap %llx\n", bitmap); | 4120 | IWL_DEBUG_TX_REPLY("Bitmap %llx\n", (unsigned long long)bitmap); |
3908 | 4121 | ||
3909 | return 0; | 4122 | return 0; |
3910 | } | 4123 | } |
@@ -3925,16 +4138,23 @@ static void iwl4965_tx_queue_stop_scheduler(struct iwl4965_priv *priv, | |||
3925 | 4138 | ||
3926 | /** | 4139 | /** |
3927 | * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID | 4140 | * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID |
4141 | * priv->lock must be held by the caller | ||
3928 | */ | 4142 | */ |
3929 | static int iwl4965_tx_queue_agg_disable(struct iwl4965_priv *priv, u16 txq_id, | 4143 | static int iwl4965_tx_queue_agg_disable(struct iwl4965_priv *priv, u16 txq_id, |
3930 | u16 ssn_idx, u8 tx_fifo) | 4144 | u16 ssn_idx, u8 tx_fifo) |
3931 | { | 4145 | { |
4146 | int ret = 0; | ||
4147 | |||
3932 | if (IWL_BACK_QUEUE_FIRST_ID > txq_id) { | 4148 | if (IWL_BACK_QUEUE_FIRST_ID > txq_id) { |
3933 | IWL_WARNING("queue number too small: %d, must be > %d\n", | 4149 | IWL_WARNING("queue number too small: %d, must be > %d\n", |
3934 | txq_id, IWL_BACK_QUEUE_FIRST_ID); | 4150 | txq_id, IWL_BACK_QUEUE_FIRST_ID); |
3935 | return -EINVAL; | 4151 | return -EINVAL; |
3936 | } | 4152 | } |
3937 | 4153 | ||
4154 | ret = iwl4965_grab_nic_access(priv); | ||
4155 | if (ret) | ||
4156 | return ret; | ||
4157 | |||
3938 | iwl4965_tx_queue_stop_scheduler(priv, txq_id); | 4158 | iwl4965_tx_queue_stop_scheduler(priv, txq_id); |
3939 | 4159 | ||
3940 | iwl4965_clear_bits_prph(priv, KDR_SCD_QUEUECHAIN_SEL, (1 << txq_id)); | 4160 | iwl4965_clear_bits_prph(priv, KDR_SCD_QUEUECHAIN_SEL, (1 << txq_id)); |
@@ -3948,6 +4168,8 @@ static int iwl4965_tx_queue_agg_disable(struct iwl4965_priv *priv, u16 txq_id, | |||
3948 | iwl4965_txq_ctx_deactivate(priv, txq_id); | 4168 | iwl4965_txq_ctx_deactivate(priv, txq_id); |
3949 | iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); | 4169 | iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); |
3950 | 4170 | ||
4171 | iwl4965_release_nic_access(priv); | ||
4172 | |||
3951 | return 0; | 4173 | return 0; |
3952 | } | 4174 | } |
3953 | 4175 | ||
@@ -4040,12 +4262,12 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl4965_priv *priv, | |||
4040 | "%d, scd_ssn = %d\n", | 4262 | "%d, scd_ssn = %d\n", |
4041 | ba_resp->tid, | 4263 | ba_resp->tid, |
4042 | ba_resp->seq_ctl, | 4264 | ba_resp->seq_ctl, |
4043 | ba_resp->bitmap, | 4265 | (unsigned long long)ba_resp->bitmap, |
4044 | ba_resp->scd_flow, | 4266 | ba_resp->scd_flow, |
4045 | ba_resp->scd_ssn); | 4267 | ba_resp->scd_ssn); |
4046 | IWL_DEBUG_TX_REPLY("DAT start_idx = %d, bitmap = 0x%llx \n", | 4268 | IWL_DEBUG_TX_REPLY("DAT start_idx = %d, bitmap = 0x%llx \n", |
4047 | agg->start_idx, | 4269 | agg->start_idx, |
4048 | agg->bitmap); | 4270 | (unsigned long long)agg->bitmap); |
4049 | 4271 | ||
4050 | /* Update driver's record of ACK vs. not for each frame in window */ | 4272 | /* Update driver's record of ACK vs. not for each frame in window */ |
4051 | iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp); | 4273 | iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp); |
@@ -4232,7 +4454,7 @@ static u8 iwl4965_is_channel_extension(struct iwl4965_priv *priv, | |||
4232 | if (!is_channel_valid(ch_info)) | 4454 | if (!is_channel_valid(ch_info)) |
4233 | return 0; | 4455 | return 0; |
4234 | 4456 | ||
4235 | if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO) | 4457 | if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE) |
4236 | return 0; | 4458 | return 0; |
4237 | 4459 | ||
4238 | if ((ch_info->fat_extension_channel == extension_chan_offset) || | 4460 | if ((ch_info->fat_extension_channel == extension_chan_offset) || |
@@ -4249,7 +4471,7 @@ static u8 iwl4965_is_fat_tx_allowed(struct iwl4965_priv *priv, | |||
4249 | 4471 | ||
4250 | if ((!iwl_ht_conf->is_ht) || | 4472 | if ((!iwl_ht_conf->is_ht) || |
4251 | (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) || | 4473 | (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) || |
4252 | (iwl_ht_conf->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO)) | 4474 | (iwl_ht_conf->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE)) |
4253 | return 0; | 4475 | return 0; |
4254 | 4476 | ||
4255 | if (sta_ht_inf) { | 4477 | if (sta_ht_inf) { |
@@ -4294,9 +4516,7 @@ void iwl4965_set_rxon_ht(struct iwl4965_priv *priv, struct iwl_ht_info *ht_info) | |||
4294 | case IWL_EXT_CHANNEL_OFFSET_BELOW: | 4516 | case IWL_EXT_CHANNEL_OFFSET_BELOW: |
4295 | rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; | 4517 | rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; |
4296 | break; | 4518 | break; |
4297 | case IWL_EXT_CHANNEL_OFFSET_AUTO: | 4519 | case IWL_EXT_CHANNEL_OFFSET_NONE: |
4298 | rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; | ||
4299 | break; | ||
4300 | default: | 4520 | default: |
4301 | rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; | 4521 | rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; |
4302 | break; | 4522 | break; |
@@ -4419,7 +4639,7 @@ static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da, | |||
4419 | int tx_fifo; | 4639 | int tx_fifo; |
4420 | int txq_id; | 4640 | int txq_id; |
4421 | int ssn = -1; | 4641 | int ssn = -1; |
4422 | int rc = 0; | 4642 | int ret = 0; |
4423 | unsigned long flags; | 4643 | unsigned long flags; |
4424 | struct iwl4965_tid_data *tid_data; | 4644 | struct iwl4965_tid_data *tid_data; |
4425 | DECLARE_MAC_BUF(mac); | 4645 | DECLARE_MAC_BUF(mac); |
@@ -4452,12 +4672,12 @@ static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da, | |||
4452 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 4672 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
4453 | 4673 | ||
4454 | *start_seq_num = ssn; | 4674 | *start_seq_num = ssn; |
4455 | rc = iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo, | 4675 | ret = iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo, |
4456 | sta_id, tid, ssn); | 4676 | sta_id, tid, ssn); |
4457 | if (rc) | 4677 | if (ret) |
4458 | return rc; | 4678 | return ret; |
4459 | 4679 | ||
4460 | rc = 0; | 4680 | ret = 0; |
4461 | if (tid_data->tfds_in_queue == 0) { | 4681 | if (tid_data->tfds_in_queue == 0) { |
4462 | printk(KERN_ERR "HW queue is empty\n"); | 4682 | printk(KERN_ERR "HW queue is empty\n"); |
4463 | tid_data->agg.state = IWL_AGG_ON; | 4683 | tid_data->agg.state = IWL_AGG_ON; |
@@ -4467,7 +4687,7 @@ static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da, | |||
4467 | tid_data->tfds_in_queue); | 4687 | tid_data->tfds_in_queue); |
4468 | tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; | 4688 | tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; |
4469 | } | 4689 | } |
4470 | return rc; | 4690 | return ret; |
4471 | } | 4691 | } |
4472 | 4692 | ||
4473 | static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da, | 4693 | static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da, |
@@ -4477,7 +4697,7 @@ static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da, | |||
4477 | struct iwl4965_priv *priv = hw->priv; | 4697 | struct iwl4965_priv *priv = hw->priv; |
4478 | int tx_fifo_id, txq_id, sta_id, ssn = -1; | 4698 | int tx_fifo_id, txq_id, sta_id, ssn = -1; |
4479 | struct iwl4965_tid_data *tid_data; | 4699 | struct iwl4965_tid_data *tid_data; |
4480 | int rc, write_ptr, read_ptr; | 4700 | int ret, write_ptr, read_ptr; |
4481 | unsigned long flags; | 4701 | unsigned long flags; |
4482 | DECLARE_MAC_BUF(mac); | 4702 | DECLARE_MAC_BUF(mac); |
4483 | 4703 | ||
@@ -4517,17 +4737,11 @@ static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da, | |||
4517 | priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; | 4737 | priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; |
4518 | 4738 | ||
4519 | spin_lock_irqsave(&priv->lock, flags); | 4739 | spin_lock_irqsave(&priv->lock, flags); |
4520 | rc = iwl4965_grab_nic_access(priv); | 4740 | ret = iwl4965_tx_queue_agg_disable(priv, txq_id, ssn, tx_fifo_id); |
4521 | if (rc) { | ||
4522 | spin_unlock_irqrestore(&priv->lock, flags); | ||
4523 | return rc; | ||
4524 | } | ||
4525 | rc = iwl4965_tx_queue_agg_disable(priv, txq_id, ssn, tx_fifo_id); | ||
4526 | iwl4965_release_nic_access(priv); | ||
4527 | spin_unlock_irqrestore(&priv->lock, flags); | 4741 | spin_unlock_irqrestore(&priv->lock, flags); |
4528 | 4742 | ||
4529 | if (rc) | 4743 | if (ret) |
4530 | return rc; | 4744 | return ret; |
4531 | 4745 | ||
4532 | ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, da, tid); | 4746 | ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, da, tid); |
4533 | 4747 | ||
@@ -4610,9 +4824,15 @@ void iwl4965_hw_cancel_deferred_work(struct iwl4965_priv *priv) | |||
4610 | cancel_delayed_work(&priv->init_alive_start); | 4824 | cancel_delayed_work(&priv->init_alive_start); |
4611 | } | 4825 | } |
4612 | 4826 | ||
4827 | static struct iwl_cfg iwl4965_agn_cfg = { | ||
4828 | .name = "4965AGN", | ||
4829 | .fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode", | ||
4830 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, | ||
4831 | }; | ||
4832 | |||
4613 | struct pci_device_id iwl4965_hw_card_ids[] = { | 4833 | struct pci_device_id iwl4965_hw_card_ids[] = { |
4614 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4229)}, | 4834 | {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)}, |
4615 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4230)}, | 4835 | {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)}, |
4616 | {0} | 4836 | {0} |
4617 | }; | 4837 | }; |
4618 | 4838 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index ce17e4fec838..057fa15d62fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h | |||
@@ -41,9 +41,17 @@ extern struct pci_device_id iwl4965_hw_card_ids[]; | |||
41 | 41 | ||
42 | #define DRV_NAME "iwl4965" | 42 | #define DRV_NAME "iwl4965" |
43 | #include "iwl-4965-hw.h" | 43 | #include "iwl-4965-hw.h" |
44 | #include "iwl-csr.h" | ||
44 | #include "iwl-prph.h" | 45 | #include "iwl-prph.h" |
45 | #include "iwl-4965-debug.h" | 46 | #include "iwl-4965-debug.h" |
46 | 47 | ||
48 | /* Change firmware file name, using "-" and incrementing number, | ||
49 | * *only* when uCode interface or architecture changes so that it | ||
50 | * is not compatible with earlier drivers. | ||
51 | * This number will also appear in << 8 position of 1st dword of uCode file */ | ||
52 | #define IWL4965_UCODE_API "-1" | ||
53 | |||
54 | |||
47 | /* Default noise level to report when noise measurement is not available. | 55 | /* Default noise level to report when noise measurement is not available. |
48 | * This may be because we're: | 56 | * This may be because we're: |
49 | * 1) Not associated (4965, no beacon statistics being sent to driver) | 57 | * 1) Not associated (4965, no beacon statistics being sent to driver) |
@@ -633,16 +641,6 @@ extern int iwl4965_is_network_packet(struct iwl4965_priv *priv, | |||
633 | struct ieee80211_hdr *header); | 641 | struct ieee80211_hdr *header); |
634 | extern int iwl4965_power_init_handle(struct iwl4965_priv *priv); | 642 | extern int iwl4965_power_init_handle(struct iwl4965_priv *priv); |
635 | extern int iwl4965_eeprom_init(struct iwl4965_priv *priv); | 643 | extern int iwl4965_eeprom_init(struct iwl4965_priv *priv); |
636 | #ifdef CONFIG_IWL4965_DEBUG | ||
637 | extern void iwl4965_report_frame(struct iwl4965_priv *priv, | ||
638 | struct iwl4965_rx_packet *pkt, | ||
639 | struct ieee80211_hdr *header, int group100); | ||
640 | #else | ||
641 | static inline void iwl4965_report_frame(struct iwl4965_priv *priv, | ||
642 | struct iwl4965_rx_packet *pkt, | ||
643 | struct ieee80211_hdr *header, | ||
644 | int group100) {} | ||
645 | #endif | ||
646 | extern void iwl4965_handle_data_packet_monitor(struct iwl4965_priv *priv, | 644 | extern void iwl4965_handle_data_packet_monitor(struct iwl4965_priv *priv, |
647 | struct iwl4965_rx_mem_buffer *rxb, | 645 | struct iwl4965_rx_mem_buffer *rxb, |
648 | void *data, short len, | 646 | void *data, short len, |
@@ -767,6 +765,9 @@ extern int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, | |||
767 | const struct iwl4965_eeprom_channel *eeprom_ch, | 765 | const struct iwl4965_eeprom_channel *eeprom_ch, |
768 | u8 fat_extension_channel); | 766 | u8 fat_extension_channel); |
769 | extern void iwl4965_rf_kill_ct_config(struct iwl4965_priv *priv); | 767 | extern void iwl4965_rf_kill_ct_config(struct iwl4965_priv *priv); |
768 | extern void iwl4965_hwrate_to_tx_control(struct iwl4965_priv *priv, | ||
769 | u32 rate_n_flags, | ||
770 | struct ieee80211_tx_control *control); | ||
770 | 771 | ||
771 | #ifdef CONFIG_IWL4965_HT | 772 | #ifdef CONFIG_IWL4965_HT |
772 | void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info, | 773 | void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info, |
@@ -808,11 +809,10 @@ struct iwl4965_kw { | |||
808 | #define IWL_OPERATION_MODE_MIXED 2 | 809 | #define IWL_OPERATION_MODE_MIXED 2 |
809 | #define IWL_OPERATION_MODE_20MHZ 3 | 810 | #define IWL_OPERATION_MODE_20MHZ 3 |
810 | 811 | ||
811 | #define IWL_EXT_CHANNEL_OFFSET_AUTO 0 | 812 | #define IWL_EXT_CHANNEL_OFFSET_NONE 0 |
812 | #define IWL_EXT_CHANNEL_OFFSET_ABOVE 1 | 813 | #define IWL_EXT_CHANNEL_OFFSET_ABOVE 1 |
813 | #define IWL_EXT_CHANNEL_OFFSET_ 2 | 814 | #define IWL_EXT_CHANNEL_OFFSET_RESERVE1 2 |
814 | #define IWL_EXT_CHANNEL_OFFSET_BELOW 3 | 815 | #define IWL_EXT_CHANNEL_OFFSET_BELOW 3 |
815 | #define IWL_EXT_CHANNEL_OFFSET_MAX 4 | ||
816 | 816 | ||
817 | #define NRG_NUM_PREV_STAT_L 20 | 817 | #define NRG_NUM_PREV_STAT_L 20 |
818 | #define NUM_RX_CHAINS (3) | 818 | #define NUM_RX_CHAINS (3) |
@@ -974,6 +974,7 @@ struct iwl4965_priv { | |||
974 | struct ieee80211_hw *hw; | 974 | struct ieee80211_hw *hw; |
975 | struct ieee80211_channel *ieee_channels; | 975 | struct ieee80211_channel *ieee_channels; |
976 | struct ieee80211_rate *ieee_rates; | 976 | struct ieee80211_rate *ieee_rates; |
977 | struct iwl_cfg *cfg; | ||
977 | 978 | ||
978 | /* temporary frame storage list */ | 979 | /* temporary frame storage list */ |
979 | struct list_head free_frames; | 980 | struct list_head free_frames; |
@@ -1104,7 +1105,6 @@ struct iwl4965_priv { | |||
1104 | u32 scd_base_addr; /* scheduler sram base address */ | 1105 | u32 scd_base_addr; /* scheduler sram base address */ |
1105 | 1106 | ||
1106 | unsigned long status; | 1107 | unsigned long status; |
1107 | u32 config; | ||
1108 | 1108 | ||
1109 | int last_rx_rssi; /* From Rx packet statisitics */ | 1109 | int last_rx_rssi; /* From Rx packet statisitics */ |
1110 | int last_rx_noise; /* From beacon statistics */ | 1110 | int last_rx_noise; /* From beacon statistics */ |
@@ -1134,7 +1134,6 @@ struct iwl4965_priv { | |||
1134 | int is_open; | 1134 | int is_open; |
1135 | 1135 | ||
1136 | u8 mac80211_registered; | 1136 | u8 mac80211_registered; |
1137 | int is_abg; | ||
1138 | 1137 | ||
1139 | u32 notif_missed_beacons; | 1138 | u32 notif_missed_beacons; |
1140 | 1139 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c new file mode 100644 index 000000000000..675b34b696b4 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -0,0 +1,47 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2008 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Tomas Winkler <tomas.winkler@intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | *****************************************************************************/ | ||
31 | |||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/version.h> | ||
35 | |||
36 | #include "iwl-4965-debug.h" | ||
37 | #include "iwl-core.h" | ||
38 | |||
39 | MODULE_DESCRIPTION("iwl core"); | ||
40 | MODULE_VERSION(IWLWIFI_VERSION); | ||
41 | MODULE_AUTHOR(DRV_COPYRIGHT); | ||
42 | MODULE_LICENSE("GPL/BSD"); | ||
43 | |||
44 | #ifdef CONFIG_IWL4965_DEBUG | ||
45 | u32 iwl4965_debug_level; | ||
46 | EXPORT_SYMBOL(iwl4965_debug_level); | ||
47 | #endif | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h new file mode 100644 index 000000000000..bdd32f891683 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -0,0 +1,84 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2008 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Tomas Winkler <tomas.winkler@intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | *****************************************************************************/ | ||
62 | |||
63 | #ifndef __iwl_core_h__ | ||
64 | #define __iwl_core_h__ | ||
65 | |||
66 | #define IWLWIFI_VERSION "1.2.26k" | ||
67 | #define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation" | ||
68 | |||
69 | #define IWL_PCI_DEVICE(dev, subdev, cfg) \ | ||
70 | .vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \ | ||
71 | .subvendor = PCI_ANY_ID, .subdevice = (subdev), \ | ||
72 | .driver_data = (kernel_ulong_t)&(cfg) | ||
73 | |||
74 | #define IWL_SKU_G 0x1 | ||
75 | #define IWL_SKU_A 0x2 | ||
76 | #define IWL_SKU_N 0x8 | ||
77 | |||
78 | struct iwl_cfg { | ||
79 | const char *name; | ||
80 | const char *fw_name; | ||
81 | unsigned int sku; | ||
82 | }; | ||
83 | |||
84 | #endif /* __iwl_core_h__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h new file mode 100644 index 000000000000..7016e5b41c58 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h | |||
@@ -0,0 +1,259 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * James P. Ketrenos <ipw2100-admin@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | /*=== CSR (control and status registers) ===*/ | ||
64 | #define CSR_BASE (0x000) | ||
65 | |||
66 | #define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */ | ||
67 | #define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ | ||
68 | #define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */ | ||
69 | #define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */ | ||
70 | #define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/ | ||
71 | #define CSR_GPIO_IN (CSR_BASE+0x018) /* read external chip pins */ | ||
72 | #define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/ | ||
73 | #define CSR_GP_CNTRL (CSR_BASE+0x024) | ||
74 | |||
75 | /* | ||
76 | * Hardware revision info | ||
77 | * Bit fields: | ||
78 | * 31-8: Reserved | ||
79 | * 7-4: Type of device: 0x0 = 4965, 0xd = 3945 | ||
80 | * 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D | ||
81 | * 1-0: "Dash" value, as in A-1, etc. | ||
82 | * | ||
83 | * NOTE: Revision step affects calculation of CCK txpower for 4965. | ||
84 | */ | ||
85 | #define CSR_HW_REV (CSR_BASE+0x028) | ||
86 | |||
87 | /* EEPROM reads */ | ||
88 | #define CSR_EEPROM_REG (CSR_BASE+0x02c) | ||
89 | #define CSR_EEPROM_GP (CSR_BASE+0x030) | ||
90 | #define CSR_GP_UCODE (CSR_BASE+0x044) | ||
91 | #define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) | ||
92 | #define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058) | ||
93 | #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) | ||
94 | #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) | ||
95 | #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) | ||
96 | |||
97 | /* Analog phase-lock-loop configuration (3945 only) | ||
98 | * Set bit 24. */ | ||
99 | #define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) | ||
100 | /* | ||
101 | * Indicates hardware rev, to determine CCK backoff for txpower calculation. | ||
102 | * Bit fields: | ||
103 | * 3-2: 0 = A, 1 = B, 2 = C, 3 = D step | ||
104 | */ | ||
105 | #define CSR_HW_REV_WA_REG (CSR_BASE+0x22C) | ||
106 | |||
107 | /* Bits for CSR_HW_IF_CONFIG_REG */ | ||
108 | #define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010) | ||
109 | #define CSR49_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) | ||
110 | #define CSR49_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) | ||
111 | #define CSR49_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) | ||
112 | |||
113 | #define CSR39_HW_IF_CONFIG_REG_BIT_3945_MB (0x00000100) | ||
114 | #define CSR39_HW_IF_CONFIG_REG_BIT_3945_MM (0x00000200) | ||
115 | #define CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400) | ||
116 | #define CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800) | ||
117 | #define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000) | ||
118 | #define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000) | ||
119 | |||
120 | #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) | ||
121 | |||
122 | /* interrupt flags in INTA, set by uCode or hardware (e.g. dma), | ||
123 | * acknowledged (reset) by host writing "1" to flagged bits. */ | ||
124 | #define CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */ | ||
125 | #define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */ | ||
126 | #define CSR_INT_BIT_DNLD (1 << 28) /* uCode Download */ | ||
127 | #define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */ | ||
128 | #define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */ | ||
129 | #define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ | ||
130 | #define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ | ||
131 | #define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ | ||
132 | #define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */ | ||
133 | #define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ | ||
134 | #define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ | ||
135 | |||
136 | #define CSR_INI_SET_MASK (CSR_INT_BIT_FH_RX | \ | ||
137 | CSR_INT_BIT_HW_ERR | \ | ||
138 | CSR_INT_BIT_FH_TX | \ | ||
139 | CSR_INT_BIT_SW_ERR | \ | ||
140 | CSR_INT_BIT_RF_KILL | \ | ||
141 | CSR_INT_BIT_SW_RX | \ | ||
142 | CSR_INT_BIT_WAKEUP | \ | ||
143 | CSR_INT_BIT_ALIVE) | ||
144 | |||
145 | /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ | ||
146 | #define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */ | ||
147 | #define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ | ||
148 | #define CSR39_FH_INT_BIT_RX_CHNL2 (1 << 18) /* Rx channel 2 (3945 only) */ | ||
149 | #define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ | ||
150 | #define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ | ||
151 | #define CSR39_FH_INT_BIT_TX_CHNL6 (1 << 6) /* Tx channel 6 (3945 only) */ | ||
152 | #define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ | ||
153 | #define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ | ||
154 | |||
155 | #define CSR39_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ | ||
156 | CSR39_FH_INT_BIT_RX_CHNL2 | \ | ||
157 | CSR_FH_INT_BIT_RX_CHNL1 | \ | ||
158 | CSR_FH_INT_BIT_RX_CHNL0) | ||
159 | |||
160 | |||
161 | #define CSR39_FH_INT_TX_MASK (CSR39_FH_INT_BIT_TX_CHNL6 | \ | ||
162 | CSR_FH_INT_BIT_TX_CHNL1 | \ | ||
163 | CSR_FH_INT_BIT_TX_CHNL0) | ||
164 | |||
165 | #define CSR49_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ | ||
166 | CSR_FH_INT_BIT_RX_CHNL1 | \ | ||
167 | CSR_FH_INT_BIT_RX_CHNL0) | ||
168 | |||
169 | #define CSR49_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ | ||
170 | CSR_FH_INT_BIT_TX_CHNL0) | ||
171 | |||
172 | |||
173 | /* RESET */ | ||
174 | #define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001) | ||
175 | #define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002) | ||
176 | #define CSR_RESET_REG_FLAG_SW_RESET (0x00000080) | ||
177 | #define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) | ||
178 | #define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) | ||
179 | |||
180 | /* GP (general purpose) CONTROL */ | ||
181 | #define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) | ||
182 | #define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) | ||
183 | #define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) | ||
184 | #define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) | ||
185 | |||
186 | #define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) | ||
187 | |||
188 | #define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) | ||
189 | #define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000) | ||
190 | #define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) | ||
191 | |||
192 | |||
193 | /* EEPROM REG */ | ||
194 | #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) | ||
195 | #define CSR_EEPROM_REG_BIT_CMD (0x00000002) | ||
196 | |||
197 | /* EEPROM GP */ | ||
198 | #define CSR_EEPROM_GP_VALID_MSK (0x00000006) | ||
199 | #define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) | ||
200 | #define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) | ||
201 | |||
202 | /* UCODE DRV GP */ | ||
203 | #define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) | ||
204 | #define CSR_UCODE_SW_BIT_RFKILL (0x00000002) | ||
205 | #define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) | ||
206 | #define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) | ||
207 | |||
208 | /* GPIO */ | ||
209 | #define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) | ||
210 | #define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000) | ||
211 | #define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER | ||
212 | |||
213 | /* GI Chicken Bits */ | ||
214 | #define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) | ||
215 | #define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) | ||
216 | |||
217 | /*=== HBUS (Host-side Bus) ===*/ | ||
218 | #define HBUS_BASE (0x400) | ||
219 | /* | ||
220 | * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM | ||
221 | * structures, error log, event log, verifying uCode load). | ||
222 | * First write to address register, then read from or write to data register | ||
223 | * to complete the job. Once the address register is set up, accesses to | ||
224 | * data registers auto-increment the address by one dword. | ||
225 | * Bit usage for address registers (read or write): | ||
226 | * 0-31: memory address within device | ||
227 | */ | ||
228 | #define HBUS_TARG_MEM_RADDR (HBUS_BASE+0x00c) | ||
229 | #define HBUS_TARG_MEM_WADDR (HBUS_BASE+0x010) | ||
230 | #define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018) | ||
231 | #define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c) | ||
232 | |||
233 | /* | ||
234 | * Registers for accessing device's internal peripheral registers | ||
235 | * (e.g. SCD, BSM, etc.). First write to address register, | ||
236 | * then read from or write to data register to complete the job. | ||
237 | * Bit usage for address registers (read or write): | ||
238 | * 0-15: register address (offset) within device | ||
239 | * 24-25: (# bytes - 1) to read or write (e.g. 3 for dword) | ||
240 | */ | ||
241 | #define HBUS_TARG_PRPH_WADDR (HBUS_BASE+0x044) | ||
242 | #define HBUS_TARG_PRPH_RADDR (HBUS_BASE+0x048) | ||
243 | #define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c) | ||
244 | #define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050) | ||
245 | |||
246 | /* | ||
247 | * Per-Tx-queue write pointer (index, really!) (3945 and 4965). | ||
248 | * Indicates index to next TFD that driver will fill (1 past latest filled). | ||
249 | * Bit usage: | ||
250 | * 0-7: queue write index | ||
251 | * 11-8: queue selector | ||
252 | */ | ||
253 | #define HBUS_TARG_WRPTR (HBUS_BASE+0x060) | ||
254 | #define HBUS_TARG_MBX_C (HBUS_BASE+0x030) | ||
255 | |||
256 | #define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) | ||
257 | |||
258 | |||
259 | |||
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c new file mode 100644 index 000000000000..0064387dea91 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c | |||
@@ -0,0 +1,205 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2008 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Tomas Winkler <tomas.winkler@intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | *****************************************************************************/ | ||
62 | |||
63 | |||
64 | #include <linux/kernel.h> | ||
65 | #include <linux/module.h> | ||
66 | #include <linux/version.h> | ||
67 | #include <linux/init.h> | ||
68 | |||
69 | #include <net/mac80211.h> | ||
70 | |||
71 | #include "iwl-4965-commands.h" | ||
72 | #include "iwl-4965.h" | ||
73 | #include "iwl-core.h" | ||
74 | #include "iwl-4965-debug.h" | ||
75 | #include "iwl-eeprom.h" | ||
76 | #include "iwl-4965-io.h" | ||
77 | |||
78 | /****************************************************************************** | ||
79 | * | ||
80 | * EEPROM related functions | ||
81 | * | ||
82 | ******************************************************************************/ | ||
83 | |||
84 | int iwlcore_eeprom_verify_signature(struct iwl4965_priv *priv) | ||
85 | { | ||
86 | u32 gp = iwl4965_read32(priv, CSR_EEPROM_GP); | ||
87 | if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) { | ||
88 | IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp); | ||
89 | return -ENOENT; | ||
90 | } | ||
91 | return 0; | ||
92 | } | ||
93 | EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); | ||
94 | |||
95 | /* | ||
96 | * The device's EEPROM semaphore prevents conflicts between driver and uCode | ||
97 | * when accessing the EEPROM; each access is a series of pulses to/from the | ||
98 | * EEPROM chip, not a single event, so even reads could conflict if they | ||
99 | * weren't arbitrated by the semaphore. | ||
100 | */ | ||
101 | int iwlcore_eeprom_acquire_semaphore(struct iwl4965_priv *priv) | ||
102 | { | ||
103 | u16 count; | ||
104 | int ret; | ||
105 | |||
106 | for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { | ||
107 | /* Request semaphore */ | ||
108 | iwl4965_set_bit(priv, CSR_HW_IF_CONFIG_REG, | ||
109 | CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); | ||
110 | |||
111 | /* See if we got it */ | ||
112 | ret = iwl4965_poll_bit(priv, CSR_HW_IF_CONFIG_REG, | ||
113 | CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, | ||
114 | CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, | ||
115 | EEPROM_SEM_TIMEOUT); | ||
116 | if (ret >= 0) { | ||
117 | IWL_DEBUG_IO("Acquired semaphore after %d tries.\n", | ||
118 | count+1); | ||
119 | return ret; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | return ret; | ||
124 | } | ||
125 | EXPORT_SYMBOL(iwlcore_eeprom_acquire_semaphore); | ||
126 | |||
127 | void iwlcore_eeprom_release_semaphore(struct iwl4965_priv *priv) | ||
128 | { | ||
129 | iwl4965_clear_bit(priv, CSR_HW_IF_CONFIG_REG, | ||
130 | CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); | ||
131 | |||
132 | } | ||
133 | EXPORT_SYMBOL(iwlcore_eeprom_release_semaphore); | ||
134 | |||
135 | |||
136 | /** | ||
137 | * iwl_eeprom_init - read EEPROM contents | ||
138 | * | ||
139 | * Load the EEPROM contents from adapter into priv->eeprom | ||
140 | * | ||
141 | * NOTE: This routine uses the non-debug IO access functions. | ||
142 | */ | ||
143 | int iwl_eeprom_init(struct iwl4965_priv *priv) | ||
144 | { | ||
145 | u16 *e = (u16 *)&priv->eeprom; | ||
146 | u32 gp = iwl4965_read32(priv, CSR_EEPROM_GP); | ||
147 | u32 r; | ||
148 | int sz = sizeof(priv->eeprom); | ||
149 | int ret; | ||
150 | int i; | ||
151 | u16 addr; | ||
152 | |||
153 | /* The EEPROM structure has several padding buffers within it | ||
154 | * and when adding new EEPROM maps is subject to programmer errors | ||
155 | * which may be very difficult to identify without explicitly | ||
156 | * checking the resulting size of the eeprom map. */ | ||
157 | BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE); | ||
158 | |||
159 | if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) { | ||
160 | IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp); | ||
161 | return -ENOENT; | ||
162 | } | ||
163 | |||
164 | /* Make sure driver (instead of uCode) is allowed to read EEPROM */ | ||
165 | ret = priv->cfg->ops->lib->eeprom_ops.acquire_semaphore(priv); | ||
166 | if (ret < 0) { | ||
167 | IWL_ERROR("Failed to acquire EEPROM semaphore.\n"); | ||
168 | return -ENOENT; | ||
169 | } | ||
170 | |||
171 | /* eeprom is an array of 16bit values */ | ||
172 | for (addr = 0; addr < sz; addr += sizeof(u16)) { | ||
173 | _iwl4965_write32(priv, CSR_EEPROM_REG, addr << 1); | ||
174 | _iwl4965_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); | ||
175 | |||
176 | for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT; | ||
177 | i += IWL_EEPROM_ACCESS_DELAY) { | ||
178 | r = _iwl4965_read_direct32(priv, CSR_EEPROM_REG); | ||
179 | if (r & CSR_EEPROM_REG_READ_VALID_MSK) | ||
180 | break; | ||
181 | udelay(IWL_EEPROM_ACCESS_DELAY); | ||
182 | } | ||
183 | |||
184 | if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) { | ||
185 | IWL_ERROR("Time out reading EEPROM[%d]", addr); | ||
186 | ret = -ETIMEDOUT; | ||
187 | goto done; | ||
188 | } | ||
189 | e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); | ||
190 | } | ||
191 | ret = 0; | ||
192 | |||
193 | done: | ||
194 | priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv); | ||
195 | return ret; | ||
196 | } | ||
197 | EXPORT_SYMBOL(iwl_eeprom_init); | ||
198 | |||
199 | |||
200 | void iwl_eeprom_get_mac(const struct iwl4965_priv *priv, u8 *mac) | ||
201 | { | ||
202 | memcpy(mac, priv->eeprom.mac_address, 6); | ||
203 | } | ||
204 | EXPORT_SYMBOL(iwl_eeprom_get_mac); | ||
205 | |||
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h new file mode 100644 index 000000000000..7827566dcc8b --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h | |||
@@ -0,0 +1,399 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2008 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Tomas Winkler <tomas.winkler@intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | *****************************************************************************/ | ||
62 | |||
63 | #ifndef __iwl_eeprom_h__ | ||
64 | #define __iwl_eeprom_h__ | ||
65 | |||
66 | struct iwl4965_priv; | ||
67 | |||
68 | /* | ||
69 | * EEPROM access time values: | ||
70 | * | ||
71 | * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG, | ||
72 | * then clearing (with subsequent read/modify/write) CSR_EEPROM_REG bit | ||
73 | * CSR_EEPROM_REG_BIT_CMD (0x2). | ||
74 | * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1). | ||
75 | * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec. | ||
76 | * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG. | ||
77 | */ | ||
78 | #define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */ | ||
79 | #define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */ | ||
80 | |||
81 | #define IWL_EEPROM_SEM_TIMEOUT 10 /* milliseconds */ | ||
82 | #define IWL_EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ | ||
83 | |||
84 | |||
85 | /* | ||
86 | * Regulatory channel usage flags in EEPROM struct iwl4965_eeprom_channel.flags. | ||
87 | * | ||
88 | * IBSS and/or AP operation is allowed *only* on those channels with | ||
89 | * (VALID && IBSS && ACTIVE && !RADAR). This restriction is in place because | ||
90 | * RADAR detection is not supported by the 4965 driver, but is a | ||
91 | * requirement for establishing a new network for legal operation on channels | ||
92 | * requiring RADAR detection or restricting ACTIVE scanning. | ||
93 | * | ||
94 | * NOTE: "WIDE" flag does not indicate anything about "FAT" 40 MHz channels. | ||
95 | * It only indicates that 20 MHz channel use is supported; FAT channel | ||
96 | * usage is indicated by a separate set of regulatory flags for each | ||
97 | * FAT channel pair. | ||
98 | * | ||
99 | * NOTE: Using a channel inappropriately will result in a uCode error! | ||
100 | */ | ||
101 | #define IWL_NUM_TX_CALIB_GROUPS 5 | ||
102 | enum { | ||
103 | EEPROM_CHANNEL_VALID = (1 << 0), /* usable for this SKU/geo */ | ||
104 | EEPROM_CHANNEL_IBSS = (1 << 1), /* usable as an IBSS channel */ | ||
105 | /* Bit 2 Reserved */ | ||
106 | EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */ | ||
107 | EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */ | ||
108 | EEPROM_CHANNEL_WIDE = (1 << 5), /* 20 MHz channel okay */ | ||
109 | EEPROM_CHANNEL_NARROW = (1 << 6), /* 10 MHz channel (not used) */ | ||
110 | EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */ | ||
111 | }; | ||
112 | |||
113 | /* SKU Capabilities */ | ||
114 | #define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0) | ||
115 | #define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) | ||
116 | |||
117 | /* *regulatory* channel data format in eeprom, one for each channel. | ||
118 | * There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */ | ||
119 | struct iwl4965_eeprom_channel { | ||
120 | u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */ | ||
121 | s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ | ||
122 | } __attribute__ ((packed)); | ||
123 | |||
124 | /* 4965 has two radio transmitters (and 3 radio receivers) */ | ||
125 | #define EEPROM_TX_POWER_TX_CHAINS (2) | ||
126 | |||
127 | /* 4965 has room for up to 8 sets of txpower calibration data */ | ||
128 | #define EEPROM_TX_POWER_BANDS (8) | ||
129 | |||
130 | /* 4965 factory calibration measures txpower gain settings for | ||
131 | * each of 3 target output levels */ | ||
132 | #define EEPROM_TX_POWER_MEASUREMENTS (3) | ||
133 | |||
134 | #define EEPROM_4965_TX_POWER_VERSION (2) | ||
135 | |||
136 | /* 4965 driver does not work with txpower calibration version < 5. | ||
137 | * Look for this in calib_version member of struct iwl4965_eeprom. */ | ||
138 | #define EEPROM_TX_POWER_VERSION_NEW (5) | ||
139 | |||
140 | |||
141 | /* | ||
142 | * 4965 factory calibration data for one txpower level, on one channel, | ||
143 | * measured on one of the 2 tx chains (radio transmitter and associated | ||
144 | * antenna). EEPROM contains: | ||
145 | * | ||
146 | * 1) Temperature (degrees Celsius) of device when measurement was made. | ||
147 | * | ||
148 | * 2) Gain table index used to achieve the target measurement power. | ||
149 | * This refers to the "well-known" gain tables (see iwl-4965-hw.h). | ||
150 | * | ||
151 | * 3) Actual measured output power, in half-dBm ("34" = 17 dBm). | ||
152 | * | ||
153 | * 4) RF power amplifier detector level measurement (not used). | ||
154 | */ | ||
155 | struct iwl4965_eeprom_calib_measure { | ||
156 | u8 temperature; /* Device temperature (Celsius) */ | ||
157 | u8 gain_idx; /* Index into gain table */ | ||
158 | u8 actual_pow; /* Measured RF output power, half-dBm */ | ||
159 | s8 pa_det; /* Power amp detector level (not used) */ | ||
160 | } __attribute__ ((packed)); | ||
161 | |||
162 | |||
163 | /* | ||
164 | * 4965 measurement set for one channel. EEPROM contains: | ||
165 | * | ||
166 | * 1) Channel number measured | ||
167 | * | ||
168 | * 2) Measurements for each of 3 power levels for each of 2 radio transmitters | ||
169 | * (a.k.a. "tx chains") (6 measurements altogether) | ||
170 | */ | ||
171 | struct iwl4965_eeprom_calib_ch_info { | ||
172 | u8 ch_num; | ||
173 | struct iwl4965_eeprom_calib_measure | ||
174 | measurements[EEPROM_TX_POWER_TX_CHAINS] | ||
175 | [EEPROM_TX_POWER_MEASUREMENTS]; | ||
176 | } __attribute__ ((packed)); | ||
177 | |||
178 | /* | ||
179 | * 4965 txpower subband info. | ||
180 | * | ||
181 | * For each frequency subband, EEPROM contains the following: | ||
182 | * | ||
183 | * 1) First and last channels within range of the subband. "0" values | ||
184 | * indicate that this sample set is not being used. | ||
185 | * | ||
186 | * 2) Sample measurement sets for 2 channels close to the range endpoints. | ||
187 | */ | ||
188 | struct iwl4965_eeprom_calib_subband_info { | ||
189 | u8 ch_from; /* channel number of lowest channel in subband */ | ||
190 | u8 ch_to; /* channel number of highest channel in subband */ | ||
191 | struct iwl4965_eeprom_calib_ch_info ch1; | ||
192 | struct iwl4965_eeprom_calib_ch_info ch2; | ||
193 | } __attribute__ ((packed)); | ||
194 | |||
195 | |||
196 | /* | ||
197 | * 4965 txpower calibration info. EEPROM contains: | ||
198 | * | ||
199 | * 1) Factory-measured saturation power levels (maximum levels at which | ||
200 | * tx power amplifier can output a signal without too much distortion). | ||
201 | * There is one level for 2.4 GHz band and one for 5 GHz band. These | ||
202 | * values apply to all channels within each of the bands. | ||
203 | * | ||
204 | * 2) Factory-measured power supply voltage level. This is assumed to be | ||
205 | * constant (i.e. same value applies to all channels/bands) while the | ||
206 | * factory measurements are being made. | ||
207 | * | ||
208 | * 3) Up to 8 sets of factory-measured txpower calibration values. | ||
209 | * These are for different frequency ranges, since txpower gain | ||
210 | * characteristics of the analog radio circuitry vary with frequency. | ||
211 | * | ||
212 | * Not all sets need to be filled with data; | ||
213 | * struct iwl4965_eeprom_calib_subband_info contains range of channels | ||
214 | * (0 if unused) for each set of data. | ||
215 | */ | ||
216 | struct iwl4965_eeprom_calib_info { | ||
217 | u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */ | ||
218 | u8 saturation_power52; /* half-dBm */ | ||
219 | s16 voltage; /* signed */ | ||
220 | struct iwl4965_eeprom_calib_subband_info | ||
221 | band_info[EEPROM_TX_POWER_BANDS]; | ||
222 | } __attribute__ ((packed)); | ||
223 | |||
224 | |||
225 | |||
226 | /* | ||
227 | * 4965 EEPROM map | ||
228 | */ | ||
229 | struct iwl4965_eeprom { | ||
230 | u8 reserved0[16]; | ||
231 | #define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */ | ||
232 | u16 device_id; /* abs.ofs: 16 */ | ||
233 | u8 reserved1[2]; | ||
234 | #define EEPROM_PMC (2*0x0A) /* 2 bytes */ | ||
235 | u16 pmc; /* abs.ofs: 20 */ | ||
236 | u8 reserved2[20]; | ||
237 | #define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */ | ||
238 | u8 mac_address[6]; /* abs.ofs: 42 */ | ||
239 | u8 reserved3[58]; | ||
240 | #define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */ | ||
241 | u16 board_revision; /* abs.ofs: 106 */ | ||
242 | u8 reserved4[11]; | ||
243 | #define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */ | ||
244 | u8 board_pba_number[9]; /* abs.ofs: 119 */ | ||
245 | u8 reserved5[8]; | ||
246 | #define EEPROM_VERSION (2*0x44) /* 2 bytes */ | ||
247 | u16 version; /* abs.ofs: 136 */ | ||
248 | #define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */ | ||
249 | u8 sku_cap; /* abs.ofs: 138 */ | ||
250 | #define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */ | ||
251 | u8 leds_mode; /* abs.ofs: 139 */ | ||
252 | #define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */ | ||
253 | u16 oem_mode; | ||
254 | #define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */ | ||
255 | u16 wowlan_mode; /* abs.ofs: 142 */ | ||
256 | #define EEPROM_LEDS_TIME_INTERVAL (2*0x48) /* 2 bytes */ | ||
257 | u16 leds_time_interval; /* abs.ofs: 144 */ | ||
258 | #define EEPROM_LEDS_OFF_TIME (2*0x49) /* 1 bytes */ | ||
259 | u8 leds_off_time; /* abs.ofs: 146 */ | ||
260 | #define EEPROM_LEDS_ON_TIME (2*0x49+1) /* 1 bytes */ | ||
261 | u8 leds_on_time; /* abs.ofs: 147 */ | ||
262 | #define EEPROM_ALMGOR_M_VERSION (2*0x4A) /* 1 bytes */ | ||
263 | u8 almgor_m_version; /* abs.ofs: 148 */ | ||
264 | #define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */ | ||
265 | u8 antenna_switch_type; /* abs.ofs: 149 */ | ||
266 | u8 reserved6[8]; | ||
267 | #define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ | ||
268 | u16 board_revision_4965; /* abs.ofs: 158 */ | ||
269 | u8 reserved7[13]; | ||
270 | #define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */ | ||
271 | u8 board_pba_number_4965[9]; /* abs.ofs: 173 */ | ||
272 | u8 reserved8[10]; | ||
273 | #define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */ | ||
274 | u8 sku_id[4]; /* abs.ofs: 192 */ | ||
275 | |||
276 | /* | ||
277 | * Per-channel regulatory data. | ||
278 | * | ||
279 | * Each channel that *might* be supported by 3945 or 4965 has a fixed location | ||
280 | * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory | ||
281 | * txpower (MSB). | ||
282 | * | ||
283 | * Entries immediately below are for 20 MHz channel width. FAT (40 MHz) | ||
284 | * channels (only for 4965, not supported by 3945) appear later in the EEPROM. | ||
285 | * | ||
286 | * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 | ||
287 | */ | ||
288 | #define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */ | ||
289 | u16 band_1_count; /* abs.ofs: 196 */ | ||
290 | #define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */ | ||
291 | struct iwl4965_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */ | ||
292 | |||
293 | /* | ||
294 | * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196, | ||
295 | * 5.0 GHz channels 7, 8, 11, 12, 16 | ||
296 | * (4915-5080MHz) (none of these is ever supported) | ||
297 | */ | ||
298 | #define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */ | ||
299 | u16 band_2_count; /* abs.ofs: 226 */ | ||
300 | #define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */ | ||
301 | struct iwl4965_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */ | ||
302 | |||
303 | /* | ||
304 | * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 | ||
305 | * (5170-5320MHz) | ||
306 | */ | ||
307 | #define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */ | ||
308 | u16 band_3_count; /* abs.ofs: 254 */ | ||
309 | #define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */ | ||
310 | struct iwl4965_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */ | ||
311 | |||
312 | /* | ||
313 | * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 | ||
314 | * (5500-5700MHz) | ||
315 | */ | ||
316 | #define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */ | ||
317 | u16 band_4_count; /* abs.ofs: 280 */ | ||
318 | #define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */ | ||
319 | struct iwl4965_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */ | ||
320 | |||
321 | /* | ||
322 | * 5.7 GHz channels 145, 149, 153, 157, 161, 165 | ||
323 | * (5725-5825MHz) | ||
324 | */ | ||
325 | #define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */ | ||
326 | u16 band_5_count; /* abs.ofs: 304 */ | ||
327 | #define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ | ||
328 | struct iwl4965_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */ | ||
329 | |||
330 | u8 reserved10[2]; | ||
331 | |||
332 | |||
333 | /* | ||
334 | * 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) | ||
335 | * | ||
336 | * The channel listed is the center of the lower 20 MHz half of the channel. | ||
337 | * The overall center frequency is actually 2 channels (10 MHz) above that, | ||
338 | * and the upper half of each FAT channel is centered 4 channels (20 MHz) away | ||
339 | * from the lower half; e.g. the upper half of FAT channel 1 is channel 5, | ||
340 | * and the overall FAT channel width centers on channel 3. | ||
341 | * | ||
342 | * NOTE: The RXON command uses 20 MHz channel numbers to specify the | ||
343 | * control channel to which to tune. RXON also specifies whether the | ||
344 | * control channel is the upper or lower half of a FAT channel. | ||
345 | * | ||
346 | * NOTE: 4965 does not support FAT channels on 2.4 GHz. | ||
347 | */ | ||
348 | #define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */ | ||
349 | struct iwl4965_eeprom_channel band_24_channels[7]; /* abs.ofs: 320 */ | ||
350 | u8 reserved11[2]; | ||
351 | |||
352 | /* | ||
353 | * 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64), | ||
354 | * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) | ||
355 | */ | ||
356 | #define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */ | ||
357 | struct iwl4965_eeprom_channel band_52_channels[11]; /* abs.ofs: 336 */ | ||
358 | u8 reserved12[6]; | ||
359 | |||
360 | /* | ||
361 | * 4965 driver requires txpower calibration format version 5 or greater. | ||
362 | * Driver does not work with txpower calibration version < 5. | ||
363 | * This value is simply a 16-bit number, no major/minor versions here. | ||
364 | */ | ||
365 | #define EEPROM_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */ | ||
366 | u16 calib_version; /* abs.ofs: 364 */ | ||
367 | u8 reserved13[2]; | ||
368 | u8 reserved14[96]; /* abs.ofs: 368 */ | ||
369 | |||
370 | /* | ||
371 | * 4965 Txpower calibration data. | ||
372 | */ | ||
373 | #define EEPROM_IWL_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */ | ||
374 | struct iwl4965_eeprom_calib_info calib_info; /* abs.ofs: 464 */ | ||
375 | |||
376 | u8 reserved16[140]; /* fill out to full 1024 byte block */ | ||
377 | |||
378 | |||
379 | } __attribute__ ((packed)); | ||
380 | |||
381 | #define IWL_EEPROM_IMAGE_SIZE 1024 | ||
382 | |||
383 | /* End of EEPROM */ | ||
384 | |||
385 | struct iwl_eeprom_ops { | ||
386 | int (*verify_signature) (struct iwl4965_priv *priv); | ||
387 | int (*acquire_semaphore) (struct iwl4965_priv *priv); | ||
388 | void (*release_semaphore) (struct iwl4965_priv *priv); | ||
389 | }; | ||
390 | |||
391 | |||
392 | void iwl_eeprom_get_mac(const struct iwl4965_priv *priv, u8 *mac); | ||
393 | int iwl_eeprom_init(struct iwl4965_priv *priv); | ||
394 | |||
395 | int iwlcore_eeprom_verify_signature(struct iwl4965_priv *priv); | ||
396 | int iwlcore_eeprom_acquire_semaphore(struct iwl4965_priv *priv); | ||
397 | void iwlcore_eeprom_release_semaphore(struct iwl4965_priv *priv); | ||
398 | |||
399 | #endif /* __iwl_eeprom_h__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 8993cca81b40..736b88881b03 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h | |||
@@ -254,6 +254,26 @@ static inline u8 iwl_get_dma_hi_address(dma_addr_t addr) | |||
254 | return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0; | 254 | return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0; |
255 | } | 255 | } |
256 | 256 | ||
257 | /** | ||
258 | * iwl_queue_inc_wrap - increment queue index, wrap back to beginning | ||
259 | * @index -- current index | ||
260 | * @n_bd -- total number of entries in queue (must be power of 2) | ||
261 | */ | ||
262 | static inline int iwl_queue_inc_wrap(int index, int n_bd) | ||
263 | { | ||
264 | return ++index & (n_bd - 1); | ||
265 | } | ||
266 | |||
267 | /** | ||
268 | * iwl_queue_dec_wrap - decrement queue index, wrap back to end | ||
269 | * @index -- current index | ||
270 | * @n_bd -- total number of entries in queue (must be power of 2) | ||
271 | */ | ||
272 | static inline int iwl_queue_dec_wrap(int index, int n_bd) | ||
273 | { | ||
274 | return --index & (n_bd - 1); | ||
275 | } | ||
276 | |||
257 | /* TODO: Move fw_desc functions to iwl-pci.ko */ | 277 | /* TODO: Move fw_desc functions to iwl-pci.ko */ |
258 | static inline void iwl_free_fw_desc(struct pci_dev *pci_dev, | 278 | static inline void iwl_free_fw_desc(struct pci_dev *pci_dev, |
259 | struct fw_desc *desc) | 279 | struct fw_desc *desc) |
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 0fab832ce8c2..ecf749c2dc0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -46,6 +46,7 @@ | |||
46 | 46 | ||
47 | #include <asm/div64.h> | 47 | #include <asm/div64.h> |
48 | 48 | ||
49 | #include "iwl-3945-core.h" | ||
49 | #include "iwl-3945.h" | 50 | #include "iwl-3945.h" |
50 | #include "iwl-helpers.h" | 51 | #include "iwl-helpers.h" |
51 | 52 | ||
@@ -95,11 +96,6 @@ int iwl3945_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 8 Tx queues */ | |||
95 | #define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation" | 96 | #define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation" |
96 | #define DRV_VERSION IWLWIFI_VERSION | 97 | #define DRV_VERSION IWLWIFI_VERSION |
97 | 98 | ||
98 | /* Change firmware file name, using "-" and incrementing number, | ||
99 | * *only* when uCode interface or architecture changes so that it | ||
100 | * is not compatible with earlier drivers. | ||
101 | * This number will also appear in << 8 position of 1st dword of uCode file */ | ||
102 | #define IWL3945_UCODE_API "-1" | ||
103 | 99 | ||
104 | MODULE_DESCRIPTION(DRV_DESCRIPTION); | 100 | MODULE_DESCRIPTION(DRV_DESCRIPTION); |
105 | MODULE_VERSION(DRV_VERSION); | 101 | MODULE_VERSION(DRV_VERSION); |
@@ -162,17 +158,6 @@ static const char *iwl3945_escape_essid(const char *essid, u8 essid_len) | |||
162 | return escaped; | 158 | return escaped; |
163 | } | 159 | } |
164 | 160 | ||
165 | static void iwl3945_print_hex_dump(int level, void *p, u32 len) | ||
166 | { | ||
167 | #ifdef CONFIG_IWL3945_DEBUG | ||
168 | if (!(iwl3945_debug_level & level)) | ||
169 | return; | ||
170 | |||
171 | print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, | ||
172 | p, len, 1); | ||
173 | #endif | ||
174 | } | ||
175 | |||
176 | /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** | 161 | /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** |
177 | * DMA services | 162 | * DMA services |
178 | * | 163 | * |
@@ -198,7 +183,7 @@ static void iwl3945_print_hex_dump(int level, void *p, u32 len) | |||
198 | * (#0-3) for data tx via EDCA. An additional 2 HCCA queues are unused. | 183 | * (#0-3) for data tx via EDCA. An additional 2 HCCA queues are unused. |
199 | ***************************************************/ | 184 | ***************************************************/ |
200 | 185 | ||
201 | static int iwl3945_queue_space(const struct iwl3945_queue *q) | 186 | int iwl3945_queue_space(const struct iwl3945_queue *q) |
202 | { | 187 | { |
203 | int s = q->read_ptr - q->write_ptr; | 188 | int s = q->read_ptr - q->write_ptr; |
204 | 189 | ||
@@ -214,33 +199,14 @@ static int iwl3945_queue_space(const struct iwl3945_queue *q) | |||
214 | return s; | 199 | return s; |
215 | } | 200 | } |
216 | 201 | ||
217 | /** | 202 | int iwl3945_x2_queue_used(const struct iwl3945_queue *q, int i) |
218 | * iwl3945_queue_inc_wrap - increment queue index, wrap back to beginning | ||
219 | * @index -- current index | ||
220 | * @n_bd -- total number of entries in queue (must be power of 2) | ||
221 | */ | ||
222 | static inline int iwl3945_queue_inc_wrap(int index, int n_bd) | ||
223 | { | ||
224 | return ++index & (n_bd - 1); | ||
225 | } | ||
226 | |||
227 | /** | ||
228 | * iwl3945_queue_dec_wrap - increment queue index, wrap back to end | ||
229 | * @index -- current index | ||
230 | * @n_bd -- total number of entries in queue (must be power of 2) | ||
231 | */ | ||
232 | static inline int iwl3945_queue_dec_wrap(int index, int n_bd) | ||
233 | { | ||
234 | return --index & (n_bd - 1); | ||
235 | } | ||
236 | |||
237 | static inline int x2_queue_used(const struct iwl3945_queue *q, int i) | ||
238 | { | 203 | { |
239 | return q->write_ptr > q->read_ptr ? | 204 | return q->write_ptr > q->read_ptr ? |
240 | (i >= q->read_ptr && i < q->write_ptr) : | 205 | (i >= q->read_ptr && i < q->write_ptr) : |
241 | !(i < q->read_ptr && i >= q->write_ptr); | 206 | !(i < q->read_ptr && i >= q->write_ptr); |
242 | } | 207 | } |
243 | 208 | ||
209 | |||
244 | static inline u8 get_cmd_index(struct iwl3945_queue *q, u32 index, int is_huge) | 210 | static inline u8 get_cmd_index(struct iwl3945_queue *q, u32 index, int is_huge) |
245 | { | 211 | { |
246 | /* This is for scan command, the big buffer at end of command array */ | 212 | /* This is for scan command, the big buffer at end of command array */ |
@@ -261,8 +227,8 @@ static int iwl3945_queue_init(struct iwl3945_priv *priv, struct iwl3945_queue *q | |||
261 | q->n_window = slots_num; | 227 | q->n_window = slots_num; |
262 | q->id = id; | 228 | q->id = id; |
263 | 229 | ||
264 | /* count must be power-of-two size, otherwise iwl3945_queue_inc_wrap | 230 | /* count must be power-of-two size, otherwise iwl_queue_inc_wrap |
265 | * and iwl3945_queue_dec_wrap are broken. */ | 231 | * and iwl_queue_dec_wrap are broken. */ |
266 | BUG_ON(!is_power_of_2(count)); | 232 | BUG_ON(!is_power_of_2(count)); |
267 | 233 | ||
268 | /* slots_num must be power-of-two size, otherwise | 234 | /* slots_num must be power-of-two size, otherwise |
@@ -362,7 +328,7 @@ int iwl3945_tx_queue_init(struct iwl3945_priv *priv, | |||
362 | txq->need_update = 0; | 328 | txq->need_update = 0; |
363 | 329 | ||
364 | /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise | 330 | /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise |
365 | * iwl3945_queue_inc_wrap and iwl3945_queue_dec_wrap are broken. */ | 331 | * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ |
366 | BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); | 332 | BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); |
367 | 333 | ||
368 | /* Initialize queue high/low-water, head/tail indexes */ | 334 | /* Initialize queue high/low-water, head/tail indexes */ |
@@ -393,7 +359,7 @@ void iwl3945_tx_queue_free(struct iwl3945_priv *priv, struct iwl3945_tx_queue *t | |||
393 | 359 | ||
394 | /* first, empty all BD's */ | 360 | /* first, empty all BD's */ |
395 | for (; q->write_ptr != q->read_ptr; | 361 | for (; q->write_ptr != q->read_ptr; |
396 | q->read_ptr = iwl3945_queue_inc_wrap(q->read_ptr, q->n_bd)) | 362 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) |
397 | iwl3945_hw_txq_free_tfd(priv, txq); | 363 | iwl3945_hw_txq_free_tfd(priv, txq); |
398 | 364 | ||
399 | len = sizeof(struct iwl3945_cmd) * q->n_window; | 365 | len = sizeof(struct iwl3945_cmd) * q->n_window; |
@@ -732,7 +698,7 @@ static int iwl3945_enqueue_hcmd(struct iwl3945_priv *priv, struct iwl3945_host_c | |||
732 | txq->need_update = 1; | 698 | txq->need_update = 1; |
733 | 699 | ||
734 | /* Increment and update queue's write index */ | 700 | /* Increment and update queue's write index */ |
735 | q->write_ptr = iwl3945_queue_inc_wrap(q->write_ptr, q->n_bd); | 701 | q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); |
736 | ret = iwl3945_tx_queue_update_write_ptr(priv, txq); | 702 | ret = iwl3945_tx_queue_update_write_ptr(priv, txq); |
737 | 703 | ||
738 | spin_unlock_irqrestore(&priv->hcmd_lock, flags); | 704 | spin_unlock_irqrestore(&priv->hcmd_lock, flags); |
@@ -1630,151 +1596,6 @@ int iwl3945_eeprom_init(struct iwl3945_priv *priv) | |||
1630 | return 0; | 1596 | return 0; |
1631 | } | 1597 | } |
1632 | 1598 | ||
1633 | /****************************************************************************** | ||
1634 | * | ||
1635 | * Misc. internal state and helper functions | ||
1636 | * | ||
1637 | ******************************************************************************/ | ||
1638 | #ifdef CONFIG_IWL3945_DEBUG | ||
1639 | |||
1640 | /** | ||
1641 | * iwl3945_report_frame - dump frame to syslog during debug sessions | ||
1642 | * | ||
1643 | * You may hack this function to show different aspects of received frames, | ||
1644 | * including selective frame dumps. | ||
1645 | * group100 parameter selects whether to show 1 out of 100 good frames. | ||
1646 | */ | ||
1647 | void iwl3945_report_frame(struct iwl3945_priv *priv, | ||
1648 | struct iwl3945_rx_packet *pkt, | ||
1649 | struct ieee80211_hdr *header, int group100) | ||
1650 | { | ||
1651 | u32 to_us; | ||
1652 | u32 print_summary = 0; | ||
1653 | u32 print_dump = 0; /* set to 1 to dump all frames' contents */ | ||
1654 | u32 hundred = 0; | ||
1655 | u32 dataframe = 0; | ||
1656 | u16 fc; | ||
1657 | u16 seq_ctl; | ||
1658 | u16 channel; | ||
1659 | u16 phy_flags; | ||
1660 | int rate_sym; | ||
1661 | u16 length; | ||
1662 | u16 status; | ||
1663 | u16 bcn_tmr; | ||
1664 | u32 tsf_low; | ||
1665 | u64 tsf; | ||
1666 | u8 rssi; | ||
1667 | u8 agc; | ||
1668 | u16 sig_avg; | ||
1669 | u16 noise_diff; | ||
1670 | struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); | ||
1671 | struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); | ||
1672 | struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); | ||
1673 | u8 *data = IWL_RX_DATA(pkt); | ||
1674 | |||
1675 | /* MAC header */ | ||
1676 | fc = le16_to_cpu(header->frame_control); | ||
1677 | seq_ctl = le16_to_cpu(header->seq_ctrl); | ||
1678 | |||
1679 | /* metadata */ | ||
1680 | channel = le16_to_cpu(rx_hdr->channel); | ||
1681 | phy_flags = le16_to_cpu(rx_hdr->phy_flags); | ||
1682 | rate_sym = rx_hdr->rate; | ||
1683 | length = le16_to_cpu(rx_hdr->len); | ||
1684 | |||
1685 | /* end-of-frame status and timestamp */ | ||
1686 | status = le32_to_cpu(rx_end->status); | ||
1687 | bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); | ||
1688 | tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; | ||
1689 | tsf = le64_to_cpu(rx_end->timestamp); | ||
1690 | |||
1691 | /* signal statistics */ | ||
1692 | rssi = rx_stats->rssi; | ||
1693 | agc = rx_stats->agc; | ||
1694 | sig_avg = le16_to_cpu(rx_stats->sig_avg); | ||
1695 | noise_diff = le16_to_cpu(rx_stats->noise_diff); | ||
1696 | |||
1697 | to_us = !compare_ether_addr(header->addr1, priv->mac_addr); | ||
1698 | |||
1699 | /* if data frame is to us and all is good, | ||
1700 | * (optionally) print summary for only 1 out of every 100 */ | ||
1701 | if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == | ||
1702 | (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { | ||
1703 | dataframe = 1; | ||
1704 | if (!group100) | ||
1705 | print_summary = 1; /* print each frame */ | ||
1706 | else if (priv->framecnt_to_us < 100) { | ||
1707 | priv->framecnt_to_us++; | ||
1708 | print_summary = 0; | ||
1709 | } else { | ||
1710 | priv->framecnt_to_us = 0; | ||
1711 | print_summary = 1; | ||
1712 | hundred = 1; | ||
1713 | } | ||
1714 | } else { | ||
1715 | /* print summary for all other frames */ | ||
1716 | print_summary = 1; | ||
1717 | } | ||
1718 | |||
1719 | if (print_summary) { | ||
1720 | char *title; | ||
1721 | u32 rate; | ||
1722 | |||
1723 | if (hundred) | ||
1724 | title = "100Frames"; | ||
1725 | else if (fc & IEEE80211_FCTL_RETRY) | ||
1726 | title = "Retry"; | ||
1727 | else if (ieee80211_is_assoc_response(fc)) | ||
1728 | title = "AscRsp"; | ||
1729 | else if (ieee80211_is_reassoc_response(fc)) | ||
1730 | title = "RasRsp"; | ||
1731 | else if (ieee80211_is_probe_response(fc)) { | ||
1732 | title = "PrbRsp"; | ||
1733 | print_dump = 1; /* dump frame contents */ | ||
1734 | } else if (ieee80211_is_beacon(fc)) { | ||
1735 | title = "Beacon"; | ||
1736 | print_dump = 1; /* dump frame contents */ | ||
1737 | } else if (ieee80211_is_atim(fc)) | ||
1738 | title = "ATIM"; | ||
1739 | else if (ieee80211_is_auth(fc)) | ||
1740 | title = "Auth"; | ||
1741 | else if (ieee80211_is_deauth(fc)) | ||
1742 | title = "DeAuth"; | ||
1743 | else if (ieee80211_is_disassoc(fc)) | ||
1744 | title = "DisAssoc"; | ||
1745 | else | ||
1746 | title = "Frame"; | ||
1747 | |||
1748 | rate = iwl3945_rate_index_from_plcp(rate_sym); | ||
1749 | if (rate == -1) | ||
1750 | rate = 0; | ||
1751 | else | ||
1752 | rate = iwl3945_rates[rate].ieee / 2; | ||
1753 | |||
1754 | /* print frame summary. | ||
1755 | * MAC addresses show just the last byte (for brevity), | ||
1756 | * but you can hack it to show more, if you'd like to. */ | ||
1757 | if (dataframe) | ||
1758 | IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " | ||
1759 | "len=%u, rssi=%d, chnl=%d, rate=%u, \n", | ||
1760 | title, fc, header->addr1[5], | ||
1761 | length, rssi, channel, rate); | ||
1762 | else { | ||
1763 | /* src/dst addresses assume managed mode */ | ||
1764 | IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " | ||
1765 | "src=0x%02x, rssi=%u, tim=%lu usec, " | ||
1766 | "phy=0x%02x, chnl=%d\n", | ||
1767 | title, fc, header->addr1[5], | ||
1768 | header->addr3[5], rssi, | ||
1769 | tsf_low - priv->scan_start_tsf, | ||
1770 | phy_flags, channel); | ||
1771 | } | ||
1772 | } | ||
1773 | if (print_dump) | ||
1774 | iwl3945_print_hex_dump(IWL_DL_RX, data, length); | ||
1775 | } | ||
1776 | #endif | ||
1777 | |||
1778 | static void iwl3945_unset_hw_setting(struct iwl3945_priv *priv) | 1599 | static void iwl3945_unset_hw_setting(struct iwl3945_priv *priv) |
1779 | { | 1600 | { |
1780 | if (priv->hw_setting.shared_virt) | 1601 | if (priv->hw_setting.shared_virt) |
@@ -2242,34 +2063,6 @@ int iwl3945_is_network_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *h | |||
2242 | return 1; | 2063 | return 1; |
2243 | } | 2064 | } |
2244 | 2065 | ||
2245 | #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x | ||
2246 | |||
2247 | static const char *iwl3945_get_tx_fail_reason(u32 status) | ||
2248 | { | ||
2249 | switch (status & TX_STATUS_MSK) { | ||
2250 | case TX_STATUS_SUCCESS: | ||
2251 | return "SUCCESS"; | ||
2252 | TX_STATUS_ENTRY(SHORT_LIMIT); | ||
2253 | TX_STATUS_ENTRY(LONG_LIMIT); | ||
2254 | TX_STATUS_ENTRY(FIFO_UNDERRUN); | ||
2255 | TX_STATUS_ENTRY(MGMNT_ABORT); | ||
2256 | TX_STATUS_ENTRY(NEXT_FRAG); | ||
2257 | TX_STATUS_ENTRY(LIFE_EXPIRE); | ||
2258 | TX_STATUS_ENTRY(DEST_PS); | ||
2259 | TX_STATUS_ENTRY(ABORTED); | ||
2260 | TX_STATUS_ENTRY(BT_RETRY); | ||
2261 | TX_STATUS_ENTRY(STA_INVALID); | ||
2262 | TX_STATUS_ENTRY(FRAG_DROPPED); | ||
2263 | TX_STATUS_ENTRY(TID_DISABLE); | ||
2264 | TX_STATUS_ENTRY(FRAME_FLUSHED); | ||
2265 | TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL); | ||
2266 | TX_STATUS_ENTRY(TX_LOCKED); | ||
2267 | TX_STATUS_ENTRY(NO_BEACON_ON_RADAR); | ||
2268 | } | ||
2269 | |||
2270 | return "UNKNOWN"; | ||
2271 | } | ||
2272 | |||
2273 | /** | 2066 | /** |
2274 | * iwl3945_scan_cancel - Cancel any currently executing HW scan | 2067 | * iwl3945_scan_cancel - Cancel any currently executing HW scan |
2275 | * | 2068 | * |
@@ -2957,7 +2750,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, | |||
2957 | ieee80211_get_hdrlen(fc)); | 2750 | ieee80211_get_hdrlen(fc)); |
2958 | 2751 | ||
2959 | /* Tell device the write index *just past* this latest filled TFD */ | 2752 | /* Tell device the write index *just past* this latest filled TFD */ |
2960 | q->write_ptr = iwl3945_queue_inc_wrap(q->write_ptr, q->n_bd); | 2753 | q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); |
2961 | rc = iwl3945_tx_queue_update_write_ptr(priv, txq); | 2754 | rc = iwl3945_tx_queue_update_write_ptr(priv, txq); |
2962 | spin_unlock_irqrestore(&priv->lock, flags); | 2755 | spin_unlock_irqrestore(&priv->lock, flags); |
2963 | 2756 | ||
@@ -3317,125 +3110,6 @@ static int iwl3945_get_measurement(struct iwl3945_priv *priv, | |||
3317 | } | 3110 | } |
3318 | #endif | 3111 | #endif |
3319 | 3112 | ||
3320 | static void iwl3945_txstatus_to_ieee(struct iwl3945_priv *priv, | ||
3321 | struct iwl3945_tx_info *tx_sta) | ||
3322 | { | ||
3323 | |||
3324 | tx_sta->status.ack_signal = 0; | ||
3325 | tx_sta->status.excessive_retries = 0; | ||
3326 | tx_sta->status.queue_length = 0; | ||
3327 | tx_sta->status.queue_number = 0; | ||
3328 | |||
3329 | if (in_interrupt()) | ||
3330 | ieee80211_tx_status_irqsafe(priv->hw, | ||
3331 | tx_sta->skb[0], &(tx_sta->status)); | ||
3332 | else | ||
3333 | ieee80211_tx_status(priv->hw, | ||
3334 | tx_sta->skb[0], &(tx_sta->status)); | ||
3335 | |||
3336 | tx_sta->skb[0] = NULL; | ||
3337 | } | ||
3338 | |||
3339 | /** | ||
3340 | * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd | ||
3341 | * | ||
3342 | * When FW advances 'R' index, all entries between old and new 'R' index | ||
3343 | * need to be reclaimed. As result, some free space forms. If there is | ||
3344 | * enough free space (> low mark), wake the stack that feeds us. | ||
3345 | */ | ||
3346 | static int iwl3945_tx_queue_reclaim(struct iwl3945_priv *priv, int txq_id, int index) | ||
3347 | { | ||
3348 | struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; | ||
3349 | struct iwl3945_queue *q = &txq->q; | ||
3350 | int nfreed = 0; | ||
3351 | |||
3352 | if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) { | ||
3353 | IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " | ||
3354 | "is out of range [0-%d] %d %d.\n", txq_id, | ||
3355 | index, q->n_bd, q->write_ptr, q->read_ptr); | ||
3356 | return 0; | ||
3357 | } | ||
3358 | |||
3359 | for (index = iwl3945_queue_inc_wrap(index, q->n_bd); | ||
3360 | q->read_ptr != index; | ||
3361 | q->read_ptr = iwl3945_queue_inc_wrap(q->read_ptr, q->n_bd)) { | ||
3362 | if (txq_id != IWL_CMD_QUEUE_NUM) { | ||
3363 | iwl3945_txstatus_to_ieee(priv, | ||
3364 | &(txq->txb[txq->q.read_ptr])); | ||
3365 | iwl3945_hw_txq_free_tfd(priv, txq); | ||
3366 | } else if (nfreed > 1) { | ||
3367 | IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, | ||
3368 | q->write_ptr, q->read_ptr); | ||
3369 | queue_work(priv->workqueue, &priv->restart); | ||
3370 | } | ||
3371 | nfreed++; | ||
3372 | } | ||
3373 | |||
3374 | if (iwl3945_queue_space(q) > q->low_mark && (txq_id >= 0) && | ||
3375 | (txq_id != IWL_CMD_QUEUE_NUM) && | ||
3376 | priv->mac80211_registered) | ||
3377 | ieee80211_wake_queue(priv->hw, txq_id); | ||
3378 | |||
3379 | |||
3380 | return nfreed; | ||
3381 | } | ||
3382 | |||
3383 | static int iwl3945_is_tx_success(u32 status) | ||
3384 | { | ||
3385 | return (status & 0xFF) == 0x1; | ||
3386 | } | ||
3387 | |||
3388 | /****************************************************************************** | ||
3389 | * | ||
3390 | * Generic RX handler implementations | ||
3391 | * | ||
3392 | ******************************************************************************/ | ||
3393 | /** | ||
3394 | * iwl3945_rx_reply_tx - Handle Tx response | ||
3395 | */ | ||
3396 | static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, | ||
3397 | struct iwl3945_rx_mem_buffer *rxb) | ||
3398 | { | ||
3399 | struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; | ||
3400 | u16 sequence = le16_to_cpu(pkt->hdr.sequence); | ||
3401 | int txq_id = SEQ_TO_QUEUE(sequence); | ||
3402 | int index = SEQ_TO_INDEX(sequence); | ||
3403 | struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; | ||
3404 | struct ieee80211_tx_status *tx_status; | ||
3405 | struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; | ||
3406 | u32 status = le32_to_cpu(tx_resp->status); | ||
3407 | |||
3408 | if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) { | ||
3409 | IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " | ||
3410 | "is out of range [0-%d] %d %d\n", txq_id, | ||
3411 | index, txq->q.n_bd, txq->q.write_ptr, | ||
3412 | txq->q.read_ptr); | ||
3413 | return; | ||
3414 | } | ||
3415 | |||
3416 | tx_status = &(txq->txb[txq->q.read_ptr].status); | ||
3417 | |||
3418 | tx_status->retry_count = tx_resp->failure_frame; | ||
3419 | tx_status->queue_number = status; | ||
3420 | tx_status->queue_length = tx_resp->bt_kill_count; | ||
3421 | tx_status->queue_length |= tx_resp->failure_rts; | ||
3422 | |||
3423 | tx_status->flags = | ||
3424 | iwl3945_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; | ||
3425 | |||
3426 | IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n", | ||
3427 | txq_id, iwl3945_get_tx_fail_reason(status), status, | ||
3428 | tx_resp->rate, tx_resp->failure_frame); | ||
3429 | |||
3430 | IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); | ||
3431 | if (index != -1) | ||
3432 | iwl3945_tx_queue_reclaim(priv, txq_id, index); | ||
3433 | |||
3434 | if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) | ||
3435 | IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); | ||
3436 | } | ||
3437 | |||
3438 | |||
3439 | static void iwl3945_rx_reply_alive(struct iwl3945_priv *priv, | 3113 | static void iwl3945_rx_reply_alive(struct iwl3945_priv *priv, |
3440 | struct iwl3945_rx_mem_buffer *rxb) | 3114 | struct iwl3945_rx_mem_buffer *rxb) |
3441 | { | 3115 | { |
@@ -3782,13 +3456,44 @@ static void iwl3945_setup_rx_handlers(struct iwl3945_priv *priv) | |||
3782 | priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = | 3456 | priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = |
3783 | iwl3945_rx_scan_complete_notif; | 3457 | iwl3945_rx_scan_complete_notif; |
3784 | priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif; | 3458 | priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif; |
3785 | priv->rx_handlers[REPLY_TX] = iwl3945_rx_reply_tx; | ||
3786 | 3459 | ||
3787 | /* Set up hardware specific Rx handlers */ | 3460 | /* Set up hardware specific Rx handlers */ |
3788 | iwl3945_hw_rx_handler_setup(priv); | 3461 | iwl3945_hw_rx_handler_setup(priv); |
3789 | } | 3462 | } |
3790 | 3463 | ||
3791 | /** | 3464 | /** |
3465 | * iwl3945_cmd_queue_reclaim - Reclaim CMD queue entries | ||
3466 | * When FW advances 'R' index, all entries between old and new 'R' index | ||
3467 | * need to be reclaimed. | ||
3468 | */ | ||
3469 | static void iwl3945_cmd_queue_reclaim(struct iwl3945_priv *priv, | ||
3470 | int txq_id, int index) | ||
3471 | { | ||
3472 | struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; | ||
3473 | struct iwl3945_queue *q = &txq->q; | ||
3474 | int nfreed = 0; | ||
3475 | |||
3476 | if ((index >= q->n_bd) || (iwl3945_x2_queue_used(q, index) == 0)) { | ||
3477 | IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " | ||
3478 | "is out of range [0-%d] %d %d.\n", txq_id, | ||
3479 | index, q->n_bd, q->write_ptr, q->read_ptr); | ||
3480 | return; | ||
3481 | } | ||
3482 | |||
3483 | for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index; | ||
3484 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { | ||
3485 | if (nfreed > 1) { | ||
3486 | IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, | ||
3487 | q->write_ptr, q->read_ptr); | ||
3488 | queue_work(priv->workqueue, &priv->restart); | ||
3489 | break; | ||
3490 | } | ||
3491 | nfreed++; | ||
3492 | } | ||
3493 | } | ||
3494 | |||
3495 | |||
3496 | /** | ||
3792 | * iwl3945_tx_cmd_complete - Pull unused buffers off the queue and reclaim them | 3497 | * iwl3945_tx_cmd_complete - Pull unused buffers off the queue and reclaim them |
3793 | * @rxb: Rx buffer to reclaim | 3498 | * @rxb: Rx buffer to reclaim |
3794 | * | 3499 | * |
@@ -3807,12 +3512,6 @@ static void iwl3945_tx_cmd_complete(struct iwl3945_priv *priv, | |||
3807 | int cmd_index; | 3512 | int cmd_index; |
3808 | struct iwl3945_cmd *cmd; | 3513 | struct iwl3945_cmd *cmd; |
3809 | 3514 | ||
3810 | /* If a Tx command is being handled and it isn't in the actual | ||
3811 | * command queue then there a command routing bug has been introduced | ||
3812 | * in the queue management code. */ | ||
3813 | if (txq_id != IWL_CMD_QUEUE_NUM) | ||
3814 | IWL_ERROR("Error wrong command queue %d command id 0x%X\n", | ||
3815 | txq_id, pkt->hdr.cmd); | ||
3816 | BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); | 3515 | BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); |
3817 | 3516 | ||
3818 | cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); | 3517 | cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); |
@@ -3826,7 +3525,7 @@ static void iwl3945_tx_cmd_complete(struct iwl3945_priv *priv, | |||
3826 | !cmd->meta.u.callback(priv, cmd, rxb->skb)) | 3525 | !cmd->meta.u.callback(priv, cmd, rxb->skb)) |
3827 | rxb->skb = NULL; | 3526 | rxb->skb = NULL; |
3828 | 3527 | ||
3829 | iwl3945_tx_queue_reclaim(priv, txq_id, index); | 3528 | iwl3945_cmd_queue_reclaim(priv, txq_id, index); |
3830 | 3529 | ||
3831 | if (!(cmd->meta.flags & CMD_ASYNC)) { | 3530 | if (!(cmd->meta.flags & CMD_ASYNC)) { |
3832 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); | 3531 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); |
@@ -4506,8 +4205,7 @@ static void iwl3945_dump_nic_error_log(struct iwl3945_priv *priv) | |||
4506 | 4205 | ||
4507 | if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { | 4206 | if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { |
4508 | IWL_ERROR("Start IWL Error Log Dump:\n"); | 4207 | IWL_ERROR("Start IWL Error Log Dump:\n"); |
4509 | IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n", | 4208 | IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count); |
4510 | priv->status, priv->config, count); | ||
4511 | } | 4209 | } |
4512 | 4210 | ||
4513 | IWL_ERROR("Desc Time asrtPC blink2 " | 4211 | IWL_ERROR("Desc Time asrtPC blink2 " |
@@ -4727,9 +4425,9 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv) | |||
4727 | * atomic, make sure that inta covers all the interrupts that | 4425 | * atomic, make sure that inta covers all the interrupts that |
4728 | * we've discovered, even if FH interrupt came in just after | 4426 | * we've discovered, even if FH interrupt came in just after |
4729 | * reading CSR_INT. */ | 4427 | * reading CSR_INT. */ |
4730 | if (inta_fh & CSR_FH_INT_RX_MASK) | 4428 | if (inta_fh & CSR39_FH_INT_RX_MASK) |
4731 | inta |= CSR_INT_BIT_FH_RX; | 4429 | inta |= CSR_INT_BIT_FH_RX; |
4732 | if (inta_fh & CSR_FH_INT_TX_MASK) | 4430 | if (inta_fh & CSR39_FH_INT_TX_MASK) |
4733 | inta |= CSR_INT_BIT_FH_TX; | 4431 | inta |= CSR_INT_BIT_FH_TX; |
4734 | 4432 | ||
4735 | /* Now service all interrupt bits discovered above. */ | 4433 | /* Now service all interrupt bits discovered above. */ |
@@ -5119,11 +4817,12 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv) | |||
5119 | ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; | 4817 | ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; |
5120 | ch_info->min_power = 0; | 4818 | ch_info->min_power = 0; |
5121 | 4819 | ||
5122 | IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" | 4820 | IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x" |
5123 | " %ddBm): Ad-Hoc %ssupported\n", | 4821 | " %ddBm): Ad-Hoc %ssupported\n", |
5124 | ch_info->channel, | 4822 | ch_info->channel, |
5125 | is_channel_a_band(ch_info) ? | 4823 | is_channel_a_band(ch_info) ? |
5126 | "5.2" : "2.4", | 4824 | "5.2" : "2.4", |
4825 | CHECK_AND_PRINT(VALID), | ||
5127 | CHECK_AND_PRINT(IBSS), | 4826 | CHECK_AND_PRINT(IBSS), |
5128 | CHECK_AND_PRINT(ACTIVE), | 4827 | CHECK_AND_PRINT(ACTIVE), |
5129 | CHECK_AND_PRINT(RADAR), | 4828 | CHECK_AND_PRINT(RADAR), |
@@ -5333,7 +5032,7 @@ static void iwl3945_init_hw_rates(struct iwl3945_priv *priv, | |||
5333 | static int iwl3945_init_geos(struct iwl3945_priv *priv) | 5032 | static int iwl3945_init_geos(struct iwl3945_priv *priv) |
5334 | { | 5033 | { |
5335 | struct iwl3945_channel_info *ch; | 5034 | struct iwl3945_channel_info *ch; |
5336 | struct ieee80211_supported_band *band; | 5035 | struct ieee80211_supported_band *sband; |
5337 | struct ieee80211_channel *channels; | 5036 | struct ieee80211_channel *channels; |
5338 | struct ieee80211_channel *geo_ch; | 5037 | struct ieee80211_channel *geo_ch; |
5339 | struct ieee80211_rate *rates; | 5038 | struct ieee80211_rate *rates; |
@@ -5351,7 +5050,7 @@ static int iwl3945_init_geos(struct iwl3945_priv *priv) | |||
5351 | if (!channels) | 5050 | if (!channels) |
5352 | return -ENOMEM; | 5051 | return -ENOMEM; |
5353 | 5052 | ||
5354 | rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)), | 5053 | rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)), |
5355 | GFP_KERNEL); | 5054 | GFP_KERNEL); |
5356 | if (!rates) { | 5055 | if (!rates) { |
5357 | kfree(channels); | 5056 | kfree(channels); |
@@ -5359,38 +5058,38 @@ static int iwl3945_init_geos(struct iwl3945_priv *priv) | |||
5359 | } | 5058 | } |
5360 | 5059 | ||
5361 | /* 5.2GHz channels start after the 2.4GHz channels */ | 5060 | /* 5.2GHz channels start after the 2.4GHz channels */ |
5362 | band = &priv->bands[IEEE80211_BAND_5GHZ]; | 5061 | sband = &priv->bands[IEEE80211_BAND_5GHZ]; |
5363 | band->channels = &channels[ARRAY_SIZE(iwl3945_eeprom_band_1)]; | 5062 | sband->channels = &channels[ARRAY_SIZE(iwl3945_eeprom_band_1)]; |
5364 | band->bitrates = &rates[4]; | 5063 | /* just OFDM */ |
5365 | band->n_bitrates = 8; /* just OFDM */ | 5064 | sband->bitrates = &rates[IWL_FIRST_OFDM_RATE]; |
5366 | 5065 | sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE; | |
5367 | band = &priv->bands[IEEE80211_BAND_2GHZ]; | 5066 | |
5368 | band->channels = channels; | 5067 | sband = &priv->bands[IEEE80211_BAND_2GHZ]; |
5369 | band->bitrates = rates; | 5068 | sband->channels = channels; |
5370 | band->n_bitrates = 12; /* OFDM & CCK */ | 5069 | /* OFDM & CCK */ |
5070 | sband->bitrates = rates; | ||
5071 | sband->n_bitrates = IWL_RATE_COUNT; | ||
5371 | 5072 | ||
5372 | priv->ieee_channels = channels; | 5073 | priv->ieee_channels = channels; |
5373 | priv->ieee_rates = rates; | 5074 | priv->ieee_rates = rates; |
5374 | 5075 | ||
5375 | iwl3945_init_hw_rates(priv, rates); | 5076 | iwl3945_init_hw_rates(priv, rates); |
5376 | 5077 | ||
5377 | for (i = 0, geo_ch = channels; i < priv->channel_count; i++) { | 5078 | for (i = 0; i < priv->channel_count; i++) { |
5378 | ch = &priv->channel_info[i]; | 5079 | ch = &priv->channel_info[i]; |
5379 | 5080 | ||
5380 | if (!is_channel_valid(ch)) { | 5081 | /* FIXME: might be removed if scan is OK*/ |
5381 | IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- " | 5082 | if (!is_channel_valid(ch)) |
5382 | "skipping.\n", | ||
5383 | ch->channel, is_channel_a_band(ch) ? | ||
5384 | "5.2" : "2.4"); | ||
5385 | continue; | 5083 | continue; |
5386 | } | ||
5387 | 5084 | ||
5388 | if (is_channel_a_band(ch)) | 5085 | if (is_channel_a_band(ch)) |
5389 | geo_ch = &priv->bands[IEEE80211_BAND_5GHZ].channels[priv->bands[IEEE80211_BAND_5GHZ].n_channels++]; | 5086 | sband = &priv->bands[IEEE80211_BAND_5GHZ]; |
5390 | else | 5087 | else |
5391 | geo_ch = &priv->bands[IEEE80211_BAND_2GHZ].channels[priv->bands[IEEE80211_BAND_2GHZ].n_channels++]; | 5088 | sband = &priv->bands[IEEE80211_BAND_2GHZ]; |
5392 | 5089 | ||
5393 | geo_ch->center_freq = ieee80211chan2mhz(ch->channel); | 5090 | geo_ch = &sband->channels[sband->n_channels++]; |
5091 | |||
5092 | geo_ch->center_freq = ieee80211_channel_to_frequency(ch->channel); | ||
5394 | geo_ch->max_power = ch->max_power_avg; | 5093 | geo_ch->max_power = ch->max_power_avg; |
5395 | geo_ch->max_antenna_gain = 0xff; | 5094 | geo_ch->max_antenna_gain = 0xff; |
5396 | geo_ch->hw_value = ch->channel; | 5095 | geo_ch->hw_value = ch->channel; |
@@ -5408,16 +5107,28 @@ static int iwl3945_init_geos(struct iwl3945_priv *priv) | |||
5408 | if (ch->max_power_avg > priv->max_channel_txpower_limit) | 5107 | if (ch->max_power_avg > priv->max_channel_txpower_limit) |
5409 | priv->max_channel_txpower_limit = | 5108 | priv->max_channel_txpower_limit = |
5410 | ch->max_power_avg; | 5109 | ch->max_power_avg; |
5411 | } else | 5110 | } else { |
5412 | geo_ch->flags |= IEEE80211_CHAN_DISABLED; | 5111 | geo_ch->flags |= IEEE80211_CHAN_DISABLED; |
5112 | } | ||
5113 | |||
5114 | /* Save flags for reg domain usage */ | ||
5115 | geo_ch->orig_flags = geo_ch->flags; | ||
5116 | |||
5117 | IWL_DEBUG_INFO("Channel %d Freq=%d[%sGHz] %s flag=0%X\n", | ||
5118 | ch->channel, geo_ch->center_freq, | ||
5119 | is_channel_a_band(ch) ? "5.2" : "2.4", | ||
5120 | geo_ch->flags & IEEE80211_CHAN_DISABLED ? | ||
5121 | "restricted" : "valid", | ||
5122 | geo_ch->flags); | ||
5413 | } | 5123 | } |
5414 | 5124 | ||
5415 | if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && priv->is_abg) { | 5125 | if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && |
5126 | priv->cfg->sku & IWL_SKU_A) { | ||
5416 | printk(KERN_INFO DRV_NAME | 5127 | printk(KERN_INFO DRV_NAME |
5417 | ": Incorrectly detected BG card as ABG. Please send " | 5128 | ": Incorrectly detected BG card as ABG. Please send " |
5418 | "your PCI ID 0x%04X:0x%04X to maintainer.\n", | 5129 | "your PCI ID 0x%04X:0x%04X to maintainer.\n", |
5419 | priv->pci_dev->device, priv->pci_dev->subsystem_device); | 5130 | priv->pci_dev->device, priv->pci_dev->subsystem_device); |
5420 | priv->is_abg = 0; | 5131 | priv->cfg->sku &= ~IWL_SKU_A; |
5421 | } | 5132 | } |
5422 | 5133 | ||
5423 | printk(KERN_INFO DRV_NAME | 5134 | printk(KERN_INFO DRV_NAME |
@@ -5764,7 +5475,7 @@ static int iwl3945_read_ucode(struct iwl3945_priv *priv) | |||
5764 | int ret = 0; | 5475 | int ret = 0; |
5765 | const struct firmware *ucode_raw; | 5476 | const struct firmware *ucode_raw; |
5766 | /* firmware file name contains uCode/driver compatibility version */ | 5477 | /* firmware file name contains uCode/driver compatibility version */ |
5767 | const char *name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode"; | 5478 | const char *name = priv->cfg->fw_name; |
5768 | u8 *src; | 5479 | u8 *src; |
5769 | size_t len; | 5480 | size_t len; |
5770 | u32 ver, inst_size, data_size, init_size, init_data_size, boot_size; | 5481 | u32 ver, inst_size, data_size, init_size, init_data_size, boot_size; |
@@ -7152,6 +6863,12 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, | |||
7152 | if (conf == NULL) | 6863 | if (conf == NULL) |
7153 | return -EIO; | 6864 | return -EIO; |
7154 | 6865 | ||
6866 | if (priv->vif != vif) { | ||
6867 | IWL_DEBUG_MAC80211("leave - priv->vif != vif\n"); | ||
6868 | mutex_unlock(&priv->mutex); | ||
6869 | return 0; | ||
6870 | } | ||
6871 | |||
7155 | /* XXX: this MUST use conf->mac_addr */ | 6872 | /* XXX: this MUST use conf->mac_addr */ |
7156 | 6873 | ||
7157 | if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && | 6874 | if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && |
@@ -7176,17 +6893,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, | |||
7176 | if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && | 6893 | if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && |
7177 | !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { | 6894 | !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { |
7178 | */ | 6895 | */ |
7179 | if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { | ||
7180 | IWL_DEBUG_MAC80211("leave - scanning\n"); | ||
7181 | mutex_unlock(&priv->mutex); | ||
7182 | return 0; | ||
7183 | } | ||
7184 | |||
7185 | if (priv->vif != vif) { | ||
7186 | IWL_DEBUG_MAC80211("leave - priv->vif != vif\n"); | ||
7187 | mutex_unlock(&priv->mutex); | ||
7188 | return 0; | ||
7189 | } | ||
7190 | 6896 | ||
7191 | if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { | 6897 | if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { |
7192 | if (!conf->bssid) { | 6898 | if (!conf->bssid) { |
@@ -7884,31 +7590,6 @@ static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, | |||
7884 | show_measurement, store_measurement); | 7590 | show_measurement, store_measurement); |
7885 | #endif /* CONFIG_IWL3945_SPECTRUM_MEASUREMENT */ | 7591 | #endif /* CONFIG_IWL3945_SPECTRUM_MEASUREMENT */ |
7886 | 7592 | ||
7887 | static ssize_t show_rate(struct device *d, | ||
7888 | struct device_attribute *attr, char *buf) | ||
7889 | { | ||
7890 | struct iwl3945_priv *priv = dev_get_drvdata(d); | ||
7891 | unsigned long flags; | ||
7892 | int i; | ||
7893 | |||
7894 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
7895 | if (priv->iw_mode == IEEE80211_IF_TYPE_STA) | ||
7896 | i = priv->stations[IWL_AP_ID].current_rate.s.rate; | ||
7897 | else | ||
7898 | i = priv->stations[IWL_STA_ID].current_rate.s.rate; | ||
7899 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
7900 | |||
7901 | i = iwl3945_rate_index_from_plcp(i); | ||
7902 | if (i == -1) | ||
7903 | return sprintf(buf, "0\n"); | ||
7904 | |||
7905 | return sprintf(buf, "%d%s\n", | ||
7906 | (iwl3945_rates[i].ieee >> 1), | ||
7907 | (iwl3945_rates[i].ieee & 0x1) ? ".5" : ""); | ||
7908 | } | ||
7909 | |||
7910 | static DEVICE_ATTR(rate, S_IRUSR, show_rate, NULL); | ||
7911 | |||
7912 | static ssize_t store_retry_rate(struct device *d, | 7593 | static ssize_t store_retry_rate(struct device *d, |
7913 | struct device_attribute *attr, | 7594 | struct device_attribute *attr, |
7914 | const char *buf, size_t count) | 7595 | const char *buf, size_t count) |
@@ -8199,7 +7880,6 @@ static struct attribute *iwl3945_sysfs_entries[] = { | |||
8199 | &dev_attr_measurement.attr, | 7880 | &dev_attr_measurement.attr, |
8200 | #endif | 7881 | #endif |
8201 | &dev_attr_power_level.attr, | 7882 | &dev_attr_power_level.attr, |
8202 | &dev_attr_rate.attr, | ||
8203 | &dev_attr_retry_rate.attr, | 7883 | &dev_attr_retry_rate.attr, |
8204 | &dev_attr_rf_kill.attr, | 7884 | &dev_attr_rf_kill.attr, |
8205 | &dev_attr_rs_window.attr, | 7885 | &dev_attr_rs_window.attr, |
@@ -8238,9 +7918,9 @@ static struct ieee80211_ops iwl3945_hw_ops = { | |||
8238 | static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 7918 | static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
8239 | { | 7919 | { |
8240 | int err = 0; | 7920 | int err = 0; |
8241 | u32 pci_id; | ||
8242 | struct iwl3945_priv *priv; | 7921 | struct iwl3945_priv *priv; |
8243 | struct ieee80211_hw *hw; | 7922 | struct ieee80211_hw *hw; |
7923 | struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data); | ||
8244 | int i; | 7924 | int i; |
8245 | DECLARE_MAC_BUF(mac); | 7925 | DECLARE_MAC_BUF(mac); |
8246 | 7926 | ||
@@ -8276,6 +7956,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e | |||
8276 | priv->hw = hw; | 7956 | priv->hw = hw; |
8277 | 7957 | ||
8278 | priv->pci_dev = pdev; | 7958 | priv->pci_dev = pdev; |
7959 | priv->cfg = cfg; | ||
8279 | 7960 | ||
8280 | /* Select antenna (may be helpful if only one antenna is connected) */ | 7961 | /* Select antenna (may be helpful if only one antenna is connected) */ |
8281 | priv->antenna = (enum iwl3945_antenna)iwl3945_param_antenna; | 7962 | priv->antenna = (enum iwl3945_antenna)iwl3945_param_antenna; |
@@ -8365,32 +8046,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e | |||
8365 | 8046 | ||
8366 | priv->iw_mode = IEEE80211_IF_TYPE_STA; | 8047 | priv->iw_mode = IEEE80211_IF_TYPE_STA; |
8367 | 8048 | ||
8368 | pci_id = | ||
8369 | (priv->pci_dev->device << 16) | priv->pci_dev->subsystem_device; | ||
8370 | |||
8371 | switch (pci_id) { | ||
8372 | case 0x42221005: /* 0x4222 0x8086 0x1005 is BG SKU */ | ||
8373 | case 0x42221034: /* 0x4222 0x8086 0x1034 is BG SKU */ | ||
8374 | case 0x42271014: /* 0x4227 0x8086 0x1014 is BG SKU */ | ||
8375 | case 0x42221044: /* 0x4222 0x8086 0x1044 is BG SKU */ | ||
8376 | priv->is_abg = 0; | ||
8377 | break; | ||
8378 | |||
8379 | /* | ||
8380 | * Rest are assumed ABG SKU -- if this is not the | ||
8381 | * case then the card will get the wrong 'Detected' | ||
8382 | * line in the kernel log however the code that | ||
8383 | * initializes the GEO table will detect no A-band | ||
8384 | * channels and remove the is_abg mask. | ||
8385 | */ | ||
8386 | default: | ||
8387 | priv->is_abg = 1; | ||
8388 | break; | ||
8389 | } | ||
8390 | |||
8391 | printk(KERN_INFO DRV_NAME | 8049 | printk(KERN_INFO DRV_NAME |
8392 | ": Detected Intel PRO/Wireless 3945%sBG Network Connection\n", | 8050 | ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); |
8393 | priv->is_abg ? "A" : ""); | ||
8394 | 8051 | ||
8395 | /* Device-specific setup */ | 8052 | /* Device-specific setup */ |
8396 | if (iwl3945_hw_set_hw_setting(priv)) { | 8053 | if (iwl3945_hw_set_hw_setting(priv)) { |
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 20d012d4f37e..28c64c39ef02 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c | |||
@@ -45,13 +45,10 @@ | |||
45 | 45 | ||
46 | #include <asm/div64.h> | 46 | #include <asm/div64.h> |
47 | 47 | ||
48 | #include "iwl-core.h" | ||
48 | #include "iwl-4965.h" | 49 | #include "iwl-4965.h" |
49 | #include "iwl-helpers.h" | 50 | #include "iwl-helpers.h" |
50 | 51 | ||
51 | #ifdef CONFIG_IWL4965_DEBUG | ||
52 | u32 iwl4965_debug_level; | ||
53 | #endif | ||
54 | |||
55 | static int iwl4965_tx_queue_update_write_ptr(struct iwl4965_priv *priv, | 52 | static int iwl4965_tx_queue_update_write_ptr(struct iwl4965_priv *priv, |
56 | struct iwl4965_tx_queue *txq); | 53 | struct iwl4965_tx_queue *txq); |
57 | 54 | ||
@@ -90,15 +87,8 @@ int iwl4965_param_amsdu_size_8K; /* def: enable 8K amsdu size */ | |||
90 | #define VS | 87 | #define VS |
91 | #endif | 88 | #endif |
92 | 89 | ||
93 | #define IWLWIFI_VERSION "1.2.26k" VD VS | 90 | #define DRV_VERSION IWLWIFI_VERSION VD VS |
94 | #define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation" | ||
95 | #define DRV_VERSION IWLWIFI_VERSION | ||
96 | 91 | ||
97 | /* Change firmware file name, using "-" and incrementing number, | ||
98 | * *only* when uCode interface or architecture changes so that it | ||
99 | * is not compatible with earlier drivers. | ||
100 | * This number will also appear in << 8 position of 1st dword of uCode file */ | ||
101 | #define IWL4965_UCODE_API "-1" | ||
102 | 92 | ||
103 | MODULE_DESCRIPTION(DRV_DESCRIPTION); | 93 | MODULE_DESCRIPTION(DRV_DESCRIPTION); |
104 | MODULE_VERSION(DRV_VERSION); | 94 | MODULE_VERSION(DRV_VERSION); |
@@ -161,17 +151,6 @@ static const char *iwl4965_escape_essid(const char *essid, u8 essid_len) | |||
161 | return escaped; | 151 | return escaped; |
162 | } | 152 | } |
163 | 153 | ||
164 | static void iwl4965_print_hex_dump(int level, void *p, u32 len) | ||
165 | { | ||
166 | #ifdef CONFIG_IWL4965_DEBUG | ||
167 | if (!(iwl4965_debug_level & level)) | ||
168 | return; | ||
169 | |||
170 | print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, | ||
171 | p, len, 1); | ||
172 | #endif | ||
173 | } | ||
174 | |||
175 | /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** | 154 | /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** |
176 | * DMA services | 155 | * DMA services |
177 | * | 156 | * |
@@ -215,25 +194,6 @@ int iwl4965_queue_space(const struct iwl4965_queue *q) | |||
215 | return s; | 194 | return s; |
216 | } | 195 | } |
217 | 196 | ||
218 | /** | ||
219 | * iwl4965_queue_inc_wrap - increment queue index, wrap back to beginning | ||
220 | * @index -- current index | ||
221 | * @n_bd -- total number of entries in queue (must be power of 2) | ||
222 | */ | ||
223 | static inline int iwl4965_queue_inc_wrap(int index, int n_bd) | ||
224 | { | ||
225 | return ++index & (n_bd - 1); | ||
226 | } | ||
227 | |||
228 | /** | ||
229 | * iwl4965_queue_dec_wrap - decrement queue index, wrap back to end | ||
230 | * @index -- current index | ||
231 | * @n_bd -- total number of entries in queue (must be power of 2) | ||
232 | */ | ||
233 | static inline int iwl4965_queue_dec_wrap(int index, int n_bd) | ||
234 | { | ||
235 | return --index & (n_bd - 1); | ||
236 | } | ||
237 | 197 | ||
238 | static inline int x2_queue_used(const struct iwl4965_queue *q, int i) | 198 | static inline int x2_queue_used(const struct iwl4965_queue *q, int i) |
239 | { | 199 | { |
@@ -262,8 +222,8 @@ static int iwl4965_queue_init(struct iwl4965_priv *priv, struct iwl4965_queue *q | |||
262 | q->n_window = slots_num; | 222 | q->n_window = slots_num; |
263 | q->id = id; | 223 | q->id = id; |
264 | 224 | ||
265 | /* count must be power-of-two size, otherwise iwl4965_queue_inc_wrap | 225 | /* count must be power-of-two size, otherwise iwl_queue_inc_wrap |
266 | * and iwl4965_queue_dec_wrap are broken. */ | 226 | * and iwl_queue_dec_wrap are broken. */ |
267 | BUG_ON(!is_power_of_2(count)); | 227 | BUG_ON(!is_power_of_2(count)); |
268 | 228 | ||
269 | /* slots_num must be power-of-two size, otherwise | 229 | /* slots_num must be power-of-two size, otherwise |
@@ -363,7 +323,7 @@ int iwl4965_tx_queue_init(struct iwl4965_priv *priv, | |||
363 | txq->need_update = 0; | 323 | txq->need_update = 0; |
364 | 324 | ||
365 | /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise | 325 | /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise |
366 | * iwl4965_queue_inc_wrap and iwl4965_queue_dec_wrap are broken. */ | 326 | * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ |
367 | BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); | 327 | BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); |
368 | 328 | ||
369 | /* Initialize queue's high/low-water marks, and head/tail indexes */ | 329 | /* Initialize queue's high/low-water marks, and head/tail indexes */ |
@@ -394,7 +354,7 @@ void iwl4965_tx_queue_free(struct iwl4965_priv *priv, struct iwl4965_tx_queue *t | |||
394 | 354 | ||
395 | /* first, empty all BD's */ | 355 | /* first, empty all BD's */ |
396 | for (; q->write_ptr != q->read_ptr; | 356 | for (; q->write_ptr != q->read_ptr; |
397 | q->read_ptr = iwl4965_queue_inc_wrap(q->read_ptr, q->n_bd)) | 357 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) |
398 | iwl4965_hw_txq_free_tfd(priv, txq); | 358 | iwl4965_hw_txq_free_tfd(priv, txq); |
399 | 359 | ||
400 | len = sizeof(struct iwl4965_cmd) * q->n_window; | 360 | len = sizeof(struct iwl4965_cmd) * q->n_window; |
@@ -735,7 +695,7 @@ static int iwl4965_enqueue_hcmd(struct iwl4965_priv *priv, struct iwl4965_host_c | |||
735 | ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0); | 695 | ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0); |
736 | 696 | ||
737 | /* Increment and update queue's write index */ | 697 | /* Increment and update queue's write index */ |
738 | q->write_ptr = iwl4965_queue_inc_wrap(q->write_ptr, q->n_bd); | 698 | q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); |
739 | iwl4965_tx_queue_update_write_ptr(priv, txq); | 699 | iwl4965_tx_queue_update_write_ptr(priv, txq); |
740 | 700 | ||
741 | spin_unlock_irqrestore(&priv->hcmd_lock, flags); | 701 | spin_unlock_irqrestore(&priv->hcmd_lock, flags); |
@@ -1551,34 +1511,6 @@ unsigned int iwl4965_fill_beacon_frame(struct iwl4965_priv *priv, | |||
1551 | return priv->ibss_beacon->len; | 1511 | return priv->ibss_beacon->len; |
1552 | } | 1512 | } |
1553 | 1513 | ||
1554 | int iwl4965_rate_index_from_plcp(int plcp) | ||
1555 | { | ||
1556 | int i = 0; | ||
1557 | |||
1558 | /* 4965 HT rate format */ | ||
1559 | if (plcp & RATE_MCS_HT_MSK) { | ||
1560 | i = (plcp & 0xff); | ||
1561 | |||
1562 | if (i >= IWL_RATE_MIMO_6M_PLCP) | ||
1563 | i = i - IWL_RATE_MIMO_6M_PLCP; | ||
1564 | |||
1565 | i += IWL_FIRST_OFDM_RATE; | ||
1566 | /* skip 9M not supported in ht*/ | ||
1567 | if (i >= IWL_RATE_9M_INDEX) | ||
1568 | i += 1; | ||
1569 | if ((i >= IWL_FIRST_OFDM_RATE) && | ||
1570 | (i <= IWL_LAST_OFDM_RATE)) | ||
1571 | return i; | ||
1572 | |||
1573 | /* 4965 legacy rate format, search for match in table */ | ||
1574 | } else { | ||
1575 | for (i = 0; i < ARRAY_SIZE(iwl4965_rates); i++) | ||
1576 | if (iwl4965_rates[i].plcp == (plcp &0xFF)) | ||
1577 | return i; | ||
1578 | } | ||
1579 | return -1; | ||
1580 | } | ||
1581 | |||
1582 | static u8 iwl4965_rate_get_lowest_plcp(int rate_mask) | 1514 | static u8 iwl4965_rate_get_lowest_plcp(int rate_mask) |
1583 | { | 1515 | { |
1584 | u8 i; | 1516 | u8 i; |
@@ -1712,148 +1644,6 @@ done: | |||
1712 | * Misc. internal state and helper functions | 1644 | * Misc. internal state and helper functions |
1713 | * | 1645 | * |
1714 | ******************************************************************************/ | 1646 | ******************************************************************************/ |
1715 | #ifdef CONFIG_IWL4965_DEBUG | ||
1716 | |||
1717 | /** | ||
1718 | * iwl4965_report_frame - dump frame to syslog during debug sessions | ||
1719 | * | ||
1720 | * You may hack this function to show different aspects of received frames, | ||
1721 | * including selective frame dumps. | ||
1722 | * group100 parameter selects whether to show 1 out of 100 good frames. | ||
1723 | * | ||
1724 | * TODO: This was originally written for 3945, need to audit for | ||
1725 | * proper operation with 4965. | ||
1726 | */ | ||
1727 | void iwl4965_report_frame(struct iwl4965_priv *priv, | ||
1728 | struct iwl4965_rx_packet *pkt, | ||
1729 | struct ieee80211_hdr *header, int group100) | ||
1730 | { | ||
1731 | u32 to_us; | ||
1732 | u32 print_summary = 0; | ||
1733 | u32 print_dump = 0; /* set to 1 to dump all frames' contents */ | ||
1734 | u32 hundred = 0; | ||
1735 | u32 dataframe = 0; | ||
1736 | u16 fc; | ||
1737 | u16 seq_ctl; | ||
1738 | u16 channel; | ||
1739 | u16 phy_flags; | ||
1740 | int rate_sym; | ||
1741 | u16 length; | ||
1742 | u16 status; | ||
1743 | u16 bcn_tmr; | ||
1744 | u32 tsf_low; | ||
1745 | u64 tsf; | ||
1746 | u8 rssi; | ||
1747 | u8 agc; | ||
1748 | u16 sig_avg; | ||
1749 | u16 noise_diff; | ||
1750 | struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); | ||
1751 | struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); | ||
1752 | struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); | ||
1753 | u8 *data = IWL_RX_DATA(pkt); | ||
1754 | |||
1755 | /* MAC header */ | ||
1756 | fc = le16_to_cpu(header->frame_control); | ||
1757 | seq_ctl = le16_to_cpu(header->seq_ctrl); | ||
1758 | |||
1759 | /* metadata */ | ||
1760 | channel = le16_to_cpu(rx_hdr->channel); | ||
1761 | phy_flags = le16_to_cpu(rx_hdr->phy_flags); | ||
1762 | rate_sym = rx_hdr->rate; | ||
1763 | length = le16_to_cpu(rx_hdr->len); | ||
1764 | |||
1765 | /* end-of-frame status and timestamp */ | ||
1766 | status = le32_to_cpu(rx_end->status); | ||
1767 | bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); | ||
1768 | tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; | ||
1769 | tsf = le64_to_cpu(rx_end->timestamp); | ||
1770 | |||
1771 | /* signal statistics */ | ||
1772 | rssi = rx_stats->rssi; | ||
1773 | agc = rx_stats->agc; | ||
1774 | sig_avg = le16_to_cpu(rx_stats->sig_avg); | ||
1775 | noise_diff = le16_to_cpu(rx_stats->noise_diff); | ||
1776 | |||
1777 | to_us = !compare_ether_addr(header->addr1, priv->mac_addr); | ||
1778 | |||
1779 | /* if data frame is to us and all is good, | ||
1780 | * (optionally) print summary for only 1 out of every 100 */ | ||
1781 | if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == | ||
1782 | (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { | ||
1783 | dataframe = 1; | ||
1784 | if (!group100) | ||
1785 | print_summary = 1; /* print each frame */ | ||
1786 | else if (priv->framecnt_to_us < 100) { | ||
1787 | priv->framecnt_to_us++; | ||
1788 | print_summary = 0; | ||
1789 | } else { | ||
1790 | priv->framecnt_to_us = 0; | ||
1791 | print_summary = 1; | ||
1792 | hundred = 1; | ||
1793 | } | ||
1794 | } else { | ||
1795 | /* print summary for all other frames */ | ||
1796 | print_summary = 1; | ||
1797 | } | ||
1798 | |||
1799 | if (print_summary) { | ||
1800 | char *title; | ||
1801 | u32 rate; | ||
1802 | |||
1803 | if (hundred) | ||
1804 | title = "100Frames"; | ||
1805 | else if (fc & IEEE80211_FCTL_RETRY) | ||
1806 | title = "Retry"; | ||
1807 | else if (ieee80211_is_assoc_response(fc)) | ||
1808 | title = "AscRsp"; | ||
1809 | else if (ieee80211_is_reassoc_response(fc)) | ||
1810 | title = "RasRsp"; | ||
1811 | else if (ieee80211_is_probe_response(fc)) { | ||
1812 | title = "PrbRsp"; | ||
1813 | print_dump = 1; /* dump frame contents */ | ||
1814 | } else if (ieee80211_is_beacon(fc)) { | ||
1815 | title = "Beacon"; | ||
1816 | print_dump = 1; /* dump frame contents */ | ||
1817 | } else if (ieee80211_is_atim(fc)) | ||
1818 | title = "ATIM"; | ||
1819 | else if (ieee80211_is_auth(fc)) | ||
1820 | title = "Auth"; | ||
1821 | else if (ieee80211_is_deauth(fc)) | ||
1822 | title = "DeAuth"; | ||
1823 | else if (ieee80211_is_disassoc(fc)) | ||
1824 | title = "DisAssoc"; | ||
1825 | else | ||
1826 | title = "Frame"; | ||
1827 | |||
1828 | rate = iwl4965_rate_index_from_plcp(rate_sym); | ||
1829 | if (rate == -1) | ||
1830 | rate = 0; | ||
1831 | else | ||
1832 | rate = iwl4965_rates[rate].ieee / 2; | ||
1833 | |||
1834 | /* print frame summary. | ||
1835 | * MAC addresses show just the last byte (for brevity), | ||
1836 | * but you can hack it to show more, if you'd like to. */ | ||
1837 | if (dataframe) | ||
1838 | IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " | ||
1839 | "len=%u, rssi=%d, chnl=%d, rate=%u, \n", | ||
1840 | title, fc, header->addr1[5], | ||
1841 | length, rssi, channel, rate); | ||
1842 | else { | ||
1843 | /* src/dst addresses assume managed mode */ | ||
1844 | IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " | ||
1845 | "src=0x%02x, rssi=%u, tim=%lu usec, " | ||
1846 | "phy=0x%02x, chnl=%d\n", | ||
1847 | title, fc, header->addr1[5], | ||
1848 | header->addr3[5], rssi, | ||
1849 | tsf_low - priv->scan_start_tsf, | ||
1850 | phy_flags, channel); | ||
1851 | } | ||
1852 | } | ||
1853 | if (print_dump) | ||
1854 | iwl4965_print_hex_dump(IWL_DL_RX, data, length); | ||
1855 | } | ||
1856 | #endif | ||
1857 | 1647 | ||
1858 | static void iwl4965_unset_hw_setting(struct iwl4965_priv *priv) | 1648 | static void iwl4965_unset_hw_setting(struct iwl4965_priv *priv) |
1859 | { | 1649 | { |
@@ -3088,7 +2878,7 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv, | |||
3088 | iwl4965_tx_queue_update_wr_ptr(priv, txq, len); | 2878 | iwl4965_tx_queue_update_wr_ptr(priv, txq, len); |
3089 | 2879 | ||
3090 | /* Tell device the write index *just past* this latest filled TFD */ | 2880 | /* Tell device the write index *just past* this latest filled TFD */ |
3091 | q->write_ptr = iwl4965_queue_inc_wrap(q->write_ptr, q->n_bd); | 2881 | q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); |
3092 | rc = iwl4965_tx_queue_update_write_ptr(priv, txq); | 2882 | rc = iwl4965_tx_queue_update_write_ptr(priv, txq); |
3093 | spin_unlock_irqrestore(&priv->lock, flags); | 2883 | spin_unlock_irqrestore(&priv->lock, flags); |
3094 | 2884 | ||
@@ -3482,9 +3272,9 @@ int iwl4965_tx_queue_reclaim(struct iwl4965_priv *priv, int txq_id, int index) | |||
3482 | return 0; | 3272 | return 0; |
3483 | } | 3273 | } |
3484 | 3274 | ||
3485 | for (index = iwl4965_queue_inc_wrap(index, q->n_bd); | 3275 | for (index = iwl_queue_inc_wrap(index, q->n_bd); |
3486 | q->read_ptr != index; | 3276 | q->read_ptr != index; |
3487 | q->read_ptr = iwl4965_queue_inc_wrap(q->read_ptr, q->n_bd)) { | 3277 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { |
3488 | if (txq_id != IWL_CMD_QUEUE_NUM) { | 3278 | if (txq_id != IWL_CMD_QUEUE_NUM) { |
3489 | iwl4965_txstatus_to_ieee(priv, | 3279 | iwl4965_txstatus_to_ieee(priv, |
3490 | &(txq->txb[txq->q.read_ptr])); | 3280 | &(txq->txb[txq->q.read_ptr])); |
@@ -3591,9 +3381,9 @@ static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv, | |||
3591 | tx_status->control.flags &= ~IEEE80211_TXCTL_AMPDU; | 3381 | tx_status->control.flags &= ~IEEE80211_TXCTL_AMPDU; |
3592 | tx_status->flags = iwl4965_is_tx_success(status)? | 3382 | tx_status->flags = iwl4965_is_tx_success(status)? |
3593 | IEEE80211_TX_STATUS_ACK : 0; | 3383 | IEEE80211_TX_STATUS_ACK : 0; |
3594 | /* FIXME Wrong Rate | 3384 | iwl4965_hwrate_to_tx_control(priv, |
3595 | tx_status->control.tx_rate = | 3385 | le32_to_cpu(tx_resp->rate_n_flags), |
3596 | iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags); */ | 3386 | &tx_status->control); |
3597 | /* FIXME: code repetition end */ | 3387 | /* FIXME: code repetition end */ |
3598 | 3388 | ||
3599 | IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n", | 3389 | IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n", |
@@ -3729,7 +3519,7 @@ static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv, | |||
3729 | 3519 | ||
3730 | if (txq->q.read_ptr != (scd_ssn & 0xff)) { | 3520 | if (txq->q.read_ptr != (scd_ssn & 0xff)) { |
3731 | int freed; | 3521 | int freed; |
3732 | index = iwl4965_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); | 3522 | index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); |
3733 | IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " | 3523 | IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " |
3734 | "%d index %d\n", scd_ssn , index); | 3524 | "%d index %d\n", scd_ssn , index); |
3735 | freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); | 3525 | freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); |
@@ -3750,9 +3540,10 @@ static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv, | |||
3750 | tx_status->queue_number = status; | 3540 | tx_status->queue_number = status; |
3751 | tx_status->queue_length = tx_resp->bt_kill_count; | 3541 | tx_status->queue_length = tx_resp->bt_kill_count; |
3752 | tx_status->queue_length |= tx_resp->failure_rts; | 3542 | tx_status->queue_length |= tx_resp->failure_rts; |
3753 | |||
3754 | tx_status->flags = | 3543 | tx_status->flags = |
3755 | iwl4965_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; | 3544 | iwl4965_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; |
3545 | iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), | ||
3546 | &tx_status->control); | ||
3756 | 3547 | ||
3757 | IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x " | 3548 | IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x " |
3758 | "retries %d\n", txq_id, iwl4965_get_tx_fail_reason(status), | 3549 | "retries %d\n", txq_id, iwl4965_get_tx_fail_reason(status), |
@@ -4886,8 +4677,7 @@ static void iwl4965_dump_nic_error_log(struct iwl4965_priv *priv) | |||
4886 | 4677 | ||
4887 | if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { | 4678 | if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { |
4888 | IWL_ERROR("Start IWL Error Log Dump:\n"); | 4679 | IWL_ERROR("Start IWL Error Log Dump:\n"); |
4889 | IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n", | 4680 | IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count); |
4890 | priv->status, priv->config, count); | ||
4891 | } | 4681 | } |
4892 | 4682 | ||
4893 | desc = iwl4965_read_targ_mem(priv, base + 1 * sizeof(u32)); | 4683 | desc = iwl4965_read_targ_mem(priv, base + 1 * sizeof(u32)); |
@@ -5099,9 +4889,9 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv) | |||
5099 | * atomic, make sure that inta covers all the interrupts that | 4889 | * atomic, make sure that inta covers all the interrupts that |
5100 | * we've discovered, even if FH interrupt came in just after | 4890 | * we've discovered, even if FH interrupt came in just after |
5101 | * reading CSR_INT. */ | 4891 | * reading CSR_INT. */ |
5102 | if (inta_fh & CSR_FH_INT_RX_MASK) | 4892 | if (inta_fh & CSR49_FH_INT_RX_MASK) |
5103 | inta |= CSR_INT_BIT_FH_RX; | 4893 | inta |= CSR_INT_BIT_FH_RX; |
5104 | if (inta_fh & CSR_FH_INT_TX_MASK) | 4894 | if (inta_fh & CSR49_FH_INT_TX_MASK) |
5105 | inta |= CSR_INT_BIT_FH_TX; | 4895 | inta |= CSR_INT_BIT_FH_TX; |
5106 | 4896 | ||
5107 | /* Now service all interrupt bits discovered above. */ | 4897 | /* Now service all interrupt bits discovered above. */ |
@@ -5502,11 +5292,12 @@ static int iwl4965_init_channel_map(struct iwl4965_priv *priv) | |||
5502 | ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; | 5292 | ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; |
5503 | ch_info->min_power = 0; | 5293 | ch_info->min_power = 0; |
5504 | 5294 | ||
5505 | IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" | 5295 | IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x" |
5506 | " %ddBm): Ad-Hoc %ssupported\n", | 5296 | " %ddBm): Ad-Hoc %ssupported\n", |
5507 | ch_info->channel, | 5297 | ch_info->channel, |
5508 | is_channel_a_band(ch_info) ? | 5298 | is_channel_a_band(ch_info) ? |
5509 | "5.2" : "2.4", | 5299 | "5.2" : "2.4", |
5300 | CHECK_AND_PRINT(VALID), | ||
5510 | CHECK_AND_PRINT(IBSS), | 5301 | CHECK_AND_PRINT(IBSS), |
5511 | CHECK_AND_PRINT(ACTIVE), | 5302 | CHECK_AND_PRINT(ACTIVE), |
5512 | CHECK_AND_PRINT(RADAR), | 5303 | CHECK_AND_PRINT(RADAR), |
@@ -5749,7 +5540,7 @@ static void iwl4965_init_hw_rates(struct iwl4965_priv *priv, | |||
5749 | static int iwl4965_init_geos(struct iwl4965_priv *priv) | 5540 | static int iwl4965_init_geos(struct iwl4965_priv *priv) |
5750 | { | 5541 | { |
5751 | struct iwl4965_channel_info *ch; | 5542 | struct iwl4965_channel_info *ch; |
5752 | struct ieee80211_supported_band *band; | 5543 | struct ieee80211_supported_band *sband; |
5753 | struct ieee80211_channel *channels; | 5544 | struct ieee80211_channel *channels; |
5754 | struct ieee80211_channel *geo_ch; | 5545 | struct ieee80211_channel *geo_ch; |
5755 | struct ieee80211_rate *rates; | 5546 | struct ieee80211_rate *rates; |
@@ -5767,7 +5558,7 @@ static int iwl4965_init_geos(struct iwl4965_priv *priv) | |||
5767 | if (!channels) | 5558 | if (!channels) |
5768 | return -ENOMEM; | 5559 | return -ENOMEM; |
5769 | 5560 | ||
5770 | rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)), | 5561 | rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)), |
5771 | GFP_KERNEL); | 5562 | GFP_KERNEL); |
5772 | if (!rates) { | 5563 | if (!rates) { |
5773 | kfree(channels); | 5564 | kfree(channels); |
@@ -5775,42 +5566,42 @@ static int iwl4965_init_geos(struct iwl4965_priv *priv) | |||
5775 | } | 5566 | } |
5776 | 5567 | ||
5777 | /* 5.2GHz channels start after the 2.4GHz channels */ | 5568 | /* 5.2GHz channels start after the 2.4GHz channels */ |
5778 | band = &priv->bands[IEEE80211_BAND_5GHZ]; | 5569 | sband = &priv->bands[IEEE80211_BAND_5GHZ]; |
5779 | band->channels = &channels[ARRAY_SIZE(iwl4965_eeprom_band_1)]; | 5570 | sband->channels = &channels[ARRAY_SIZE(iwl4965_eeprom_band_1)]; |
5780 | band->bitrates = &rates[4]; | 5571 | /* just OFDM */ |
5781 | band->n_bitrates = 8; /* just OFDM */ | 5572 | sband->bitrates = &rates[IWL_FIRST_OFDM_RATE]; |
5573 | sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE; | ||
5782 | 5574 | ||
5783 | iwl4965_init_ht_hw_capab(&band->ht_info, IEEE80211_BAND_5GHZ); | 5575 | iwl4965_init_ht_hw_capab(&sband->ht_info, IEEE80211_BAND_5GHZ); |
5784 | 5576 | ||
5785 | band = &priv->bands[IEEE80211_BAND_2GHZ]; | 5577 | sband = &priv->bands[IEEE80211_BAND_2GHZ]; |
5786 | band->channels = channels; | 5578 | sband->channels = channels; |
5787 | band->bitrates = rates; | 5579 | /* OFDM & CCK */ |
5788 | band->n_bitrates = 12; /* OFDM & CCK */ | 5580 | sband->bitrates = rates; |
5581 | sband->n_bitrates = IWL_RATE_COUNT; | ||
5789 | 5582 | ||
5790 | iwl4965_init_ht_hw_capab(&band->ht_info, IEEE80211_BAND_2GHZ); | 5583 | iwl4965_init_ht_hw_capab(&sband->ht_info, IEEE80211_BAND_2GHZ); |
5791 | 5584 | ||
5792 | priv->ieee_channels = channels; | 5585 | priv->ieee_channels = channels; |
5793 | priv->ieee_rates = rates; | 5586 | priv->ieee_rates = rates; |
5794 | 5587 | ||
5795 | iwl4965_init_hw_rates(priv, rates); | 5588 | iwl4965_init_hw_rates(priv, rates); |
5796 | 5589 | ||
5797 | for (i = 0, geo_ch = channels; i < priv->channel_count; i++) { | 5590 | for (i = 0; i < priv->channel_count; i++) { |
5798 | ch = &priv->channel_info[i]; | 5591 | ch = &priv->channel_info[i]; |
5799 | 5592 | ||
5800 | if (!is_channel_valid(ch)) { | 5593 | /* FIXME: might be removed if scan is OK */ |
5801 | IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- " | 5594 | if (!is_channel_valid(ch)) |
5802 | "skipping.\n", | ||
5803 | ch->channel, is_channel_a_band(ch) ? | ||
5804 | "5.2" : "2.4"); | ||
5805 | continue; | 5595 | continue; |
5806 | } | ||
5807 | 5596 | ||
5808 | if (is_channel_a_band(ch)) { | 5597 | if (is_channel_a_band(ch)) |
5809 | geo_ch = &priv->bands[IEEE80211_BAND_5GHZ].channels[priv->bands[IEEE80211_BAND_5GHZ].n_channels++]; | 5598 | sband = &priv->bands[IEEE80211_BAND_5GHZ]; |
5810 | } else | 5599 | else |
5811 | geo_ch = &priv->bands[IEEE80211_BAND_2GHZ].channels[priv->bands[IEEE80211_BAND_2GHZ].n_channels++]; | 5600 | sband = &priv->bands[IEEE80211_BAND_2GHZ]; |
5601 | |||
5602 | geo_ch = &sband->channels[sband->n_channels++]; | ||
5812 | 5603 | ||
5813 | geo_ch->center_freq = ieee80211chan2mhz(ch->channel); | 5604 | geo_ch->center_freq = ieee80211_channel_to_frequency(ch->channel); |
5814 | geo_ch->max_power = ch->max_power_avg; | 5605 | geo_ch->max_power = ch->max_power_avg; |
5815 | geo_ch->max_antenna_gain = 0xff; | 5606 | geo_ch->max_antenna_gain = 0xff; |
5816 | geo_ch->hw_value = ch->channel; | 5607 | geo_ch->hw_value = ch->channel; |
@@ -5828,16 +5619,28 @@ static int iwl4965_init_geos(struct iwl4965_priv *priv) | |||
5828 | if (ch->max_power_avg > priv->max_channel_txpower_limit) | 5619 | if (ch->max_power_avg > priv->max_channel_txpower_limit) |
5829 | priv->max_channel_txpower_limit = | 5620 | priv->max_channel_txpower_limit = |
5830 | ch->max_power_avg; | 5621 | ch->max_power_avg; |
5831 | } else | 5622 | } else { |
5832 | geo_ch->flags |= IEEE80211_CHAN_DISABLED; | 5623 | geo_ch->flags |= IEEE80211_CHAN_DISABLED; |
5624 | } | ||
5625 | |||
5626 | /* Save flags for reg domain usage */ | ||
5627 | geo_ch->orig_flags = geo_ch->flags; | ||
5628 | |||
5629 | IWL_DEBUG_INFO("Channel %d Freq=%d[%sGHz] %s flag=0%X\n", | ||
5630 | ch->channel, geo_ch->center_freq, | ||
5631 | is_channel_a_band(ch) ? "5.2" : "2.4", | ||
5632 | geo_ch->flags & IEEE80211_CHAN_DISABLED ? | ||
5633 | "restricted" : "valid", | ||
5634 | geo_ch->flags); | ||
5833 | } | 5635 | } |
5834 | 5636 | ||
5835 | if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && priv->is_abg) { | 5637 | if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && |
5638 | priv->cfg->sku & IWL_SKU_A) { | ||
5836 | printk(KERN_INFO DRV_NAME | 5639 | printk(KERN_INFO DRV_NAME |
5837 | ": Incorrectly detected BG card as ABG. Please send " | 5640 | ": Incorrectly detected BG card as ABG. Please send " |
5838 | "your PCI ID 0x%04X:0x%04X to maintainer.\n", | 5641 | "your PCI ID 0x%04X:0x%04X to maintainer.\n", |
5839 | priv->pci_dev->device, priv->pci_dev->subsystem_device); | 5642 | priv->pci_dev->device, priv->pci_dev->subsystem_device); |
5840 | priv->is_abg = 0; | 5643 | priv->cfg->sku &= ~IWL_SKU_A; |
5841 | } | 5644 | } |
5842 | 5645 | ||
5843 | printk(KERN_INFO DRV_NAME | 5646 | printk(KERN_INFO DRV_NAME |
@@ -6186,7 +5989,7 @@ static int iwl4965_read_ucode(struct iwl4965_priv *priv) | |||
6186 | struct iwl4965_ucode *ucode; | 5989 | struct iwl4965_ucode *ucode; |
6187 | int ret; | 5990 | int ret; |
6188 | const struct firmware *ucode_raw; | 5991 | const struct firmware *ucode_raw; |
6189 | const char *name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode"; | 5992 | const char *name = priv->cfg->fw_name; |
6190 | u8 *src; | 5993 | u8 *src; |
6191 | size_t len; | 5994 | size_t len; |
6192 | u32 ver, inst_size, data_size, init_size, init_data_size, boot_size; | 5995 | u32 ver, inst_size, data_size, init_size, init_data_size, boot_size; |
@@ -7596,6 +7399,12 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, | |||
7596 | if (conf == NULL) | 7399 | if (conf == NULL) |
7597 | return -EIO; | 7400 | return -EIO; |
7598 | 7401 | ||
7402 | if (priv->vif != vif) { | ||
7403 | IWL_DEBUG_MAC80211("leave - priv->vif != vif\n"); | ||
7404 | mutex_unlock(&priv->mutex); | ||
7405 | return 0; | ||
7406 | } | ||
7407 | |||
7599 | if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && | 7408 | if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && |
7600 | (!conf->beacon || !conf->ssid_len)) { | 7409 | (!conf->beacon || !conf->ssid_len)) { |
7601 | IWL_DEBUG_MAC80211 | 7410 | IWL_DEBUG_MAC80211 |
@@ -7618,17 +7427,6 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, | |||
7618 | if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && | 7427 | if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && |
7619 | !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { | 7428 | !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { |
7620 | */ | 7429 | */ |
7621 | if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { | ||
7622 | IWL_DEBUG_MAC80211("leave - scanning\n"); | ||
7623 | mutex_unlock(&priv->mutex); | ||
7624 | return 0; | ||
7625 | } | ||
7626 | |||
7627 | if (priv->vif != vif) { | ||
7628 | IWL_DEBUG_MAC80211("leave - priv->vif != vif\n"); | ||
7629 | mutex_unlock(&priv->mutex); | ||
7630 | return 0; | ||
7631 | } | ||
7632 | 7430 | ||
7633 | if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { | 7431 | if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { |
7634 | if (!conf->bssid) { | 7432 | if (!conf->bssid) { |
@@ -8127,15 +7925,21 @@ static void iwl4965_ht_info_fill(struct ieee80211_conf *conf, | |||
8127 | iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); | 7925 | iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); |
8128 | iwl_conf->max_amsdu_size = | 7926 | iwl_conf->max_amsdu_size = |
8129 | !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); | 7927 | !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); |
7928 | |||
8130 | iwl_conf->supported_chan_width = | 7929 | iwl_conf->supported_chan_width = |
8131 | !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH); | 7930 | !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH); |
7931 | iwl_conf->extension_chan_offset = | ||
7932 | ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET; | ||
7933 | /* If no above or below channel supplied disable FAT channel */ | ||
7934 | if (iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_ABOVE && | ||
7935 | iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_BELOW) | ||
7936 | iwl_conf->supported_chan_width = 0; | ||
7937 | |||
8132 | iwl_conf->tx_mimo_ps_mode = | 7938 | iwl_conf->tx_mimo_ps_mode = |
8133 | (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); | 7939 | (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); |
8134 | memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); | 7940 | memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); |
8135 | 7941 | ||
8136 | iwl_conf->control_channel = ht_bss_conf->primary_channel; | 7942 | iwl_conf->control_channel = ht_bss_conf->primary_channel; |
8137 | iwl_conf->extension_chan_offset = | ||
8138 | ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET; | ||
8139 | iwl_conf->tx_chan_width = | 7943 | iwl_conf->tx_chan_width = |
8140 | !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH); | 7944 | !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH); |
8141 | iwl_conf->ht_protection = | 7945 | iwl_conf->ht_protection = |
@@ -8776,6 +8580,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e | |||
8776 | int err = 0; | 8580 | int err = 0; |
8777 | struct iwl4965_priv *priv; | 8581 | struct iwl4965_priv *priv; |
8778 | struct ieee80211_hw *hw; | 8582 | struct ieee80211_hw *hw; |
8583 | struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); | ||
8779 | int i; | 8584 | int i; |
8780 | DECLARE_MAC_BUF(mac); | 8585 | DECLARE_MAC_BUF(mac); |
8781 | 8586 | ||
@@ -8809,6 +8614,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e | |||
8809 | IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); | 8614 | IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); |
8810 | priv = hw->priv; | 8615 | priv = hw->priv; |
8811 | priv->hw = hw; | 8616 | priv->hw = hw; |
8617 | priv->cfg = cfg; | ||
8812 | 8618 | ||
8813 | priv->pci_dev = pdev; | 8619 | priv->pci_dev = pdev; |
8814 | priv->antenna = (enum iwl4965_antenna)iwl4965_param_antenna; | 8620 | priv->antenna = (enum iwl4965_antenna)iwl4965_param_antenna; |
@@ -8911,8 +8717,9 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e | |||
8911 | /* Choose which receivers/antennas to use */ | 8717 | /* Choose which receivers/antennas to use */ |
8912 | iwl4965_set_rxon_chain(priv); | 8718 | iwl4965_set_rxon_chain(priv); |
8913 | 8719 | ||
8720 | |||
8914 | printk(KERN_INFO DRV_NAME | 8721 | printk(KERN_INFO DRV_NAME |
8915 | ": Detected Intel Wireless WiFi Link 4965AGN\n"); | 8722 | ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); |
8916 | 8723 | ||
8917 | /* Device-specific setup */ | 8724 | /* Device-specific setup */ |
8918 | if (iwl4965_hw_set_hw_setting(priv)) { | 8725 | if (iwl4965_hw_set_hw_setting(priv)) { |
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 75f6191e718d..7fe37bedf313 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c | |||
@@ -349,11 +349,7 @@ static int assoc_helper_wpa_keys(struct lbs_private *priv, | |||
349 | 349 | ||
350 | if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { | 350 | if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { |
351 | clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); | 351 | clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); |
352 | ret = lbs_prepare_and_send_command(priv, | 352 | ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req); |
353 | CMD_802_11_KEY_MATERIAL, | ||
354 | CMD_ACT_SET, | ||
355 | CMD_OPTION_WAITFORRSP, | ||
356 | 0, assoc_req); | ||
357 | assoc_req->flags = flags; | 353 | assoc_req->flags = flags; |
358 | } | 354 | } |
359 | 355 | ||
@@ -363,11 +359,7 @@ static int assoc_helper_wpa_keys(struct lbs_private *priv, | |||
363 | if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { | 359 | if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { |
364 | clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); | 360 | clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); |
365 | 361 | ||
366 | ret = lbs_prepare_and_send_command(priv, | 362 | ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req); |
367 | CMD_802_11_KEY_MATERIAL, | ||
368 | CMD_ACT_SET, | ||
369 | CMD_OPTION_WAITFORRSP, | ||
370 | 0, assoc_req); | ||
371 | assoc_req->flags = flags; | 363 | assoc_req->flags = flags; |
372 | } | 364 | } |
373 | 365 | ||
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 3f9074df91e4..445c6dc09786 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c | |||
@@ -338,75 +338,103 @@ int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, | |||
338 | return ret; | 338 | return ret; |
339 | } | 339 | } |
340 | 340 | ||
341 | static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset, | 341 | static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam, |
342 | struct enc_key * pkey) | 342 | struct enc_key *key) |
343 | { | 343 | { |
344 | lbs_deb_enter(LBS_DEB_CMD); | 344 | lbs_deb_enter(LBS_DEB_CMD); |
345 | 345 | ||
346 | if (pkey->flags & KEY_INFO_WPA_ENABLED) { | 346 | if (key->flags & KEY_INFO_WPA_ENABLED) |
347 | pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED); | 347 | keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED); |
348 | } | 348 | if (key->flags & KEY_INFO_WPA_UNICAST) |
349 | if (pkey->flags & KEY_INFO_WPA_UNICAST) { | 349 | keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST); |
350 | pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST); | 350 | if (key->flags & KEY_INFO_WPA_MCAST) |
351 | } | 351 | keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST); |
352 | if (pkey->flags & KEY_INFO_WPA_MCAST) { | 352 | |
353 | pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST); | 353 | keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL); |
354 | } | 354 | keyparam->keytypeid = cpu_to_le16(key->type); |
355 | keyparam->keylen = cpu_to_le16(key->len); | ||
356 | memcpy(keyparam->key, key->key, key->len); | ||
355 | 357 | ||
356 | pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL); | 358 | /* Length field doesn't include the {type,length} header */ |
357 | pkeyparamset->keytypeid = cpu_to_le16(pkey->type); | 359 | keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4); |
358 | pkeyparamset->keylen = cpu_to_le16(pkey->len); | ||
359 | memcpy(pkeyparamset->key, pkey->key, pkey->len); | ||
360 | pkeyparamset->length = cpu_to_le16( sizeof(pkeyparamset->keytypeid) | ||
361 | + sizeof(pkeyparamset->keyinfo) | ||
362 | + sizeof(pkeyparamset->keylen) | ||
363 | + sizeof(pkeyparamset->key)); | ||
364 | lbs_deb_leave(LBS_DEB_CMD); | 360 | lbs_deb_leave(LBS_DEB_CMD); |
365 | } | 361 | } |
366 | 362 | ||
367 | static int lbs_cmd_802_11_key_material(struct lbs_private *priv, | 363 | int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, |
368 | struct cmd_ds_command *cmd, | 364 | struct assoc_request *assoc) |
369 | u16 cmd_action, | ||
370 | u32 cmd_oid, void *pdata_buf) | ||
371 | { | 365 | { |
372 | struct cmd_ds_802_11_key_material *pkeymaterial = | 366 | struct cmd_ds_802_11_key_material cmd; |
373 | &cmd->params.keymaterial; | ||
374 | struct assoc_request * assoc_req = pdata_buf; | ||
375 | int ret = 0; | 367 | int ret = 0; |
376 | int index = 0; | 368 | int index = 0; |
377 | 369 | ||
378 | lbs_deb_enter(LBS_DEB_CMD); | 370 | lbs_deb_enter(LBS_DEB_CMD); |
379 | 371 | ||
380 | cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL); | 372 | cmd.action = cpu_to_le16(cmd_action); |
381 | pkeymaterial->action = cpu_to_le16(cmd_action); | 373 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); |
382 | 374 | ||
383 | if (cmd_action == CMD_ACT_GET) { | 375 | if (cmd_action == CMD_ACT_GET) { |
384 | cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action)); | 376 | cmd.hdr.size = cpu_to_le16(S_DS_GEN + 2); |
385 | ret = 0; | 377 | } else { |
386 | goto done; | 378 | memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet)); |
387 | } | ||
388 | 379 | ||
389 | memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet)); | 380 | if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) { |
381 | set_one_wpa_key(&cmd.keyParamSet[index], | ||
382 | &assoc->wpa_unicast_key); | ||
383 | index++; | ||
384 | } | ||
390 | 385 | ||
391 | if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { | 386 | if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) { |
392 | set_one_wpa_key(&pkeymaterial->keyParamSet[index], | 387 | set_one_wpa_key(&cmd.keyParamSet[index], |
393 | &assoc_req->wpa_unicast_key); | 388 | &assoc->wpa_mcast_key); |
394 | index++; | 389 | index++; |
395 | } | 390 | } |
396 | 391 | ||
397 | if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { | 392 | /* The common header and as many keys as we included */ |
398 | set_one_wpa_key(&pkeymaterial->keyParamSet[index], | 393 | cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd), |
399 | &assoc_req->wpa_mcast_key); | 394 | keyParamSet[index])); |
400 | index++; | ||
401 | } | 395 | } |
396 | ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd); | ||
397 | /* Copy the returned key to driver private data */ | ||
398 | if (!ret && cmd_action == CMD_ACT_GET) { | ||
399 | void *buf_ptr = cmd.keyParamSet; | ||
400 | void *resp_end = &(&cmd)[1]; | ||
401 | |||
402 | while (buf_ptr < resp_end) { | ||
403 | struct MrvlIEtype_keyParamSet *keyparam = buf_ptr; | ||
404 | struct enc_key *key; | ||
405 | uint16_t param_set_len = le16_to_cpu(keyparam->length); | ||
406 | uint16_t key_len = le16_to_cpu(keyparam->keylen); | ||
407 | uint16_t key_flags = le16_to_cpu(keyparam->keyinfo); | ||
408 | uint16_t key_type = le16_to_cpu(keyparam->keytypeid); | ||
409 | void *end; | ||
410 | |||
411 | end = (void *)keyparam + sizeof(keyparam->type) | ||
412 | + sizeof(keyparam->length) + param_set_len; | ||
413 | |||
414 | /* Make sure we don't access past the end of the IEs */ | ||
415 | if (end > resp_end) | ||
416 | break; | ||
402 | 417 | ||
403 | cmd->size = cpu_to_le16( S_DS_GEN | 418 | if (key_flags & KEY_INFO_WPA_UNICAST) |
404 | + sizeof (pkeymaterial->action) | 419 | key = &priv->wpa_unicast_key; |
405 | + (index * sizeof(struct MrvlIEtype_keyParamSet))); | 420 | else if (key_flags & KEY_INFO_WPA_MCAST) |
421 | key = &priv->wpa_mcast_key; | ||
422 | else | ||
423 | break; | ||
406 | 424 | ||
407 | ret = 0; | 425 | /* Copy returned key into driver */ |
426 | memset(key, 0, sizeof(struct enc_key)); | ||
427 | if (key_len > sizeof(key->key)) | ||
428 | break; | ||
429 | key->type = key_type; | ||
430 | key->flags = key_flags; | ||
431 | key->len = key_len; | ||
432 | memcpy(key->key, keyparam->key, key->len); | ||
433 | |||
434 | buf_ptr = end + 1; | ||
435 | } | ||
436 | } | ||
408 | 437 | ||
409 | done: | ||
410 | lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); | 438 | lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); |
411 | return ret; | 439 | return ret; |
412 | } | 440 | } |
@@ -1354,10 +1382,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, | |||
1354 | ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action); | 1382 | ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action); |
1355 | break; | 1383 | break; |
1356 | 1384 | ||
1357 | case CMD_802_11_SCAN: | ||
1358 | ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf); | ||
1359 | break; | ||
1360 | |||
1361 | case CMD_MAC_CONTROL: | 1385 | case CMD_MAC_CONTROL: |
1362 | ret = lbs_cmd_mac_control(priv, cmdptr); | 1386 | ret = lbs_cmd_mac_control(priv, cmdptr); |
1363 | break; | 1387 | break; |
@@ -1435,11 +1459,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, | |||
1435 | ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr); | 1459 | ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr); |
1436 | break; | 1460 | break; |
1437 | 1461 | ||
1438 | case CMD_802_11_KEY_MATERIAL: | ||
1439 | ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action, | ||
1440 | cmd_oid, pdata_buf); | ||
1441 | break; | ||
1442 | |||
1443 | case CMD_802_11_PAIRWISE_TSC: | 1462 | case CMD_802_11_PAIRWISE_TSC: |
1444 | break; | 1463 | break; |
1445 | case CMD_802_11_GROUP_TSC: | 1464 | case CMD_802_11_GROUP_TSC: |
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index b9ab85cc7913..d250e6bc0609 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h | |||
@@ -57,5 +57,7 @@ int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, | |||
57 | struct assoc_request *assoc); | 57 | struct assoc_request *assoc); |
58 | int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, | 58 | int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, |
59 | uint16_t *enable); | 59 | uint16_t *enable); |
60 | int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, | ||
61 | struct assoc_request *assoc); | ||
60 | 62 | ||
61 | #endif /* _LBS_CMD_H */ | 63 | #endif /* _LBS_CMD_H */ |
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 5d90b83f28eb..15e4ebdcd477 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c | |||
@@ -204,61 +204,6 @@ static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv, | |||
204 | return 0; | 204 | return 0; |
205 | } | 205 | } |
206 | 206 | ||
207 | static int lbs_ret_802_11_key_material(struct lbs_private *priv, | ||
208 | struct cmd_ds_command *resp) | ||
209 | { | ||
210 | struct cmd_ds_802_11_key_material *pkeymaterial = | ||
211 | &resp->params.keymaterial; | ||
212 | u16 action = le16_to_cpu(pkeymaterial->action); | ||
213 | |||
214 | lbs_deb_enter(LBS_DEB_CMD); | ||
215 | |||
216 | /* Copy the returned key to driver private data */ | ||
217 | if (action == CMD_ACT_GET) { | ||
218 | u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet; | ||
219 | u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size)); | ||
220 | |||
221 | while (buf_ptr < resp_end) { | ||
222 | struct MrvlIEtype_keyParamSet * pkeyparamset = | ||
223 | (struct MrvlIEtype_keyParamSet *) buf_ptr; | ||
224 | struct enc_key * pkey; | ||
225 | u16 param_set_len = le16_to_cpu(pkeyparamset->length); | ||
226 | u16 key_len = le16_to_cpu(pkeyparamset->keylen); | ||
227 | u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo); | ||
228 | u16 key_type = le16_to_cpu(pkeyparamset->keytypeid); | ||
229 | u8 * end; | ||
230 | |||
231 | end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type) | ||
232 | + sizeof (pkeyparamset->length) | ||
233 | + param_set_len; | ||
234 | /* Make sure we don't access past the end of the IEs */ | ||
235 | if (end > resp_end) | ||
236 | break; | ||
237 | |||
238 | if (key_flags & KEY_INFO_WPA_UNICAST) | ||
239 | pkey = &priv->wpa_unicast_key; | ||
240 | else if (key_flags & KEY_INFO_WPA_MCAST) | ||
241 | pkey = &priv->wpa_mcast_key; | ||
242 | else | ||
243 | break; | ||
244 | |||
245 | /* Copy returned key into driver */ | ||
246 | memset(pkey, 0, sizeof(struct enc_key)); | ||
247 | if (key_len > sizeof(pkey->key)) | ||
248 | break; | ||
249 | pkey->type = key_type; | ||
250 | pkey->flags = key_flags; | ||
251 | pkey->len = key_len; | ||
252 | memcpy(pkey->key, pkeyparamset->key, pkey->len); | ||
253 | |||
254 | buf_ptr = end + 1; | ||
255 | } | ||
256 | } | ||
257 | |||
258 | lbs_deb_enter(LBS_DEB_CMD); | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | static int lbs_ret_802_11_mac_address(struct lbs_private *priv, | 207 | static int lbs_ret_802_11_mac_address(struct lbs_private *priv, |
263 | struct cmd_ds_command *resp) | 208 | struct cmd_ds_command *resp) |
264 | { | 209 | { |
@@ -407,10 +352,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, | |||
407 | ret = lbs_ret_reg_access(priv, respcmd, resp); | 352 | ret = lbs_ret_reg_access(priv, respcmd, resp); |
408 | break; | 353 | break; |
409 | 354 | ||
410 | case CMD_RET(CMD_802_11_SCAN): | ||
411 | ret = lbs_ret_80211_scan(priv, resp); | ||
412 | break; | ||
413 | |||
414 | case CMD_RET(CMD_802_11_GET_LOG): | 355 | case CMD_RET(CMD_802_11_GET_LOG): |
415 | ret = lbs_ret_get_log(priv, resp); | 356 | ret = lbs_ret_get_log(priv, resp); |
416 | break; | 357 | break; |
@@ -475,10 +416,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, | |||
475 | ret = lbs_ret_80211_ad_hoc_stop(priv, resp); | 416 | ret = lbs_ret_80211_ad_hoc_stop(priv, resp); |
476 | break; | 417 | break; |
477 | 418 | ||
478 | case CMD_RET(CMD_802_11_KEY_MATERIAL): | ||
479 | ret = lbs_ret_802_11_key_material(priv, resp); | ||
480 | break; | ||
481 | |||
482 | case CMD_RET(CMD_802_11_EEPROM_ACCESS): | 419 | case CMD_RET(CMD_802_11_EEPROM_ACCESS): |
483 | ret = lbs_ret_802_11_eeprom_access(priv, resp); | 420 | ret = lbs_ret_802_11_eeprom_access(priv, resp); |
484 | break; | 421 | break; |
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index d35b015b6657..56bc1aa2bb00 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h | |||
@@ -174,9 +174,11 @@ struct cmd_ds_802_11_subscribe_event { | |||
174 | * Define data structure for CMD_802_11_SCAN | 174 | * Define data structure for CMD_802_11_SCAN |
175 | */ | 175 | */ |
176 | struct cmd_ds_802_11_scan { | 176 | struct cmd_ds_802_11_scan { |
177 | u8 bsstype; | 177 | struct cmd_header hdr; |
178 | u8 bssid[ETH_ALEN]; | 178 | |
179 | u8 tlvbuffer[1]; | 179 | uint8_t bsstype; |
180 | uint8_t bssid[ETH_ALEN]; | ||
181 | uint8_t tlvbuffer[0]; | ||
180 | #if 0 | 182 | #if 0 |
181 | mrvlietypes_ssidparamset_t ssidParamSet; | 183 | mrvlietypes_ssidparamset_t ssidParamSet; |
182 | mrvlietypes_chanlistparamset_t ChanListParamSet; | 184 | mrvlietypes_chanlistparamset_t ChanListParamSet; |
@@ -185,9 +187,11 @@ struct cmd_ds_802_11_scan { | |||
185 | }; | 187 | }; |
186 | 188 | ||
187 | struct cmd_ds_802_11_scan_rsp { | 189 | struct cmd_ds_802_11_scan_rsp { |
190 | struct cmd_header hdr; | ||
191 | |||
188 | __le16 bssdescriptsize; | 192 | __le16 bssdescriptsize; |
189 | u8 nr_sets; | 193 | uint8_t nr_sets; |
190 | u8 bssdesc_and_tlvbuffer[1]; | 194 | uint8_t bssdesc_and_tlvbuffer[0]; |
191 | }; | 195 | }; |
192 | 196 | ||
193 | struct cmd_ds_802_11_get_log { | 197 | struct cmd_ds_802_11_get_log { |
@@ -572,6 +576,8 @@ struct cmd_ds_host_sleep { | |||
572 | } __attribute__ ((packed)); | 576 | } __attribute__ ((packed)); |
573 | 577 | ||
574 | struct cmd_ds_802_11_key_material { | 578 | struct cmd_ds_802_11_key_material { |
579 | struct cmd_header hdr; | ||
580 | |||
575 | __le16 action; | 581 | __le16 action; |
576 | struct MrvlIEtype_keyParamSet keyParamSet[2]; | 582 | struct MrvlIEtype_keyParamSet keyParamSet[2]; |
577 | } __attribute__ ((packed)); | 583 | } __attribute__ ((packed)); |
@@ -689,8 +695,6 @@ struct cmd_ds_command { | |||
689 | /* command Body */ | 695 | /* command Body */ |
690 | union { | 696 | union { |
691 | struct cmd_ds_802_11_ps_mode psmode; | 697 | struct cmd_ds_802_11_ps_mode psmode; |
692 | struct cmd_ds_802_11_scan scan; | ||
693 | struct cmd_ds_802_11_scan_rsp scanresp; | ||
694 | struct cmd_ds_mac_control macctrl; | 698 | struct cmd_ds_mac_control macctrl; |
695 | struct cmd_ds_802_11_associate associate; | 699 | struct cmd_ds_802_11_associate associate; |
696 | struct cmd_ds_802_11_deauthenticate deauth; | 700 | struct cmd_ds_802_11_deauthenticate deauth; |
@@ -712,7 +716,6 @@ struct cmd_ds_command { | |||
712 | struct cmd_ds_802_11_rssi_rsp rssirsp; | 716 | struct cmd_ds_802_11_rssi_rsp rssirsp; |
713 | struct cmd_ds_802_11_disassociate dassociate; | 717 | struct cmd_ds_802_11_disassociate dassociate; |
714 | struct cmd_ds_802_11_mac_address macadd; | 718 | struct cmd_ds_802_11_mac_address macadd; |
715 | struct cmd_ds_802_11_key_material keymaterial; | ||
716 | struct cmd_ds_mac_reg_access macreg; | 719 | struct cmd_ds_mac_reg_access macreg; |
717 | struct cmd_ds_bbp_reg_access bbpreg; | 720 | struct cmd_ds_bbp_reg_access bbpreg; |
718 | struct cmd_ds_rf_reg_access rfreg; | 721 | struct cmd_ds_rf_reg_access rfreg; |
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 7d4f3afa8cc5..99f11a56d84e 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include "dev.h" | 20 | #include "dev.h" |
21 | #include "scan.h" | 21 | #include "scan.h" |
22 | #include "join.h" | 22 | #include "join.h" |
23 | #include "cmd.h" | ||
23 | 24 | ||
24 | //! Approximate amount of data needed to pass a scan result back to iwlist | 25 | //! Approximate amount of data needed to pass a scan result back to iwlist |
25 | #define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \ | 26 | #define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \ |
@@ -39,10 +40,9 @@ | |||
39 | //! Memory needed to store a max number/size SSID TLV for a firmware scan | 40 | //! Memory needed to store a max number/size SSID TLV for a firmware scan |
40 | #define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvlietypes_ssidparamset)) | 41 | #define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvlietypes_ssidparamset)) |
41 | 42 | ||
42 | //! Maximum memory needed for a lbs_scan_cmd_config with all TLVs at max | 43 | //! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max |
43 | #define MAX_SCAN_CFG_ALLOC (sizeof(struct lbs_scan_cmd_config) \ | 44 | #define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan) \ |
44 | + CHAN_TLV_MAX_SIZE \ | 45 | + CHAN_TLV_MAX_SIZE + SSID_TLV_MAX_SIZE) |
45 | + SSID_TLV_MAX_SIZE) | ||
46 | 46 | ||
47 | //! The maximum number of channels the firmware can scan per command | 47 | //! The maximum number of channels the firmware can scan per command |
48 | #define MRVDRV_MAX_CHANNELS_PER_SCAN 14 | 48 | #define MRVDRV_MAX_CHANNELS_PER_SCAN 14 |
@@ -61,11 +61,8 @@ | |||
61 | //! Scan time specified in the channel TLV for each channel for active scans | 61 | //! Scan time specified in the channel TLV for each channel for active scans |
62 | #define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100 | 62 | #define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100 |
63 | 63 | ||
64 | static const u8 zeromac[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | 64 | static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, |
65 | static const u8 bcastmac[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | 65 | struct cmd_header *resp); |
66 | |||
67 | |||
68 | |||
69 | 66 | ||
70 | /*********************************************************************/ | 67 | /*********************************************************************/ |
71 | /* */ | 68 | /* */ |
@@ -90,7 +87,7 @@ static void lbs_unset_basic_rate_flags(u8 *rates, size_t len) | |||
90 | } | 87 | } |
91 | 88 | ||
92 | 89 | ||
93 | static inline void clear_bss_descriptor (struct bss_descriptor * bss) | 90 | static inline void clear_bss_descriptor(struct bss_descriptor *bss) |
94 | { | 91 | { |
95 | /* Don't blow away ->list, just BSS data */ | 92 | /* Don't blow away ->list, just BSS data */ |
96 | memset(bss, 0, offsetof(struct bss_descriptor, list)); | 93 | memset(bss, 0, offsetof(struct bss_descriptor, list)); |
@@ -104,7 +101,8 @@ static inline void clear_bss_descriptor (struct bss_descriptor * bss) | |||
104 | * | 101 | * |
105 | * @return 0: ssid is same, otherwise is different | 102 | * @return 0: ssid is same, otherwise is different |
106 | */ | 103 | */ |
107 | int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len) | 104 | int lbs_ssid_cmp(uint8_t *ssid1, uint8_t ssid1_len, uint8_t *ssid2, |
105 | uint8_t ssid2_len) | ||
108 | { | 106 | { |
109 | if (ssid1_len != ssid2_len) | 107 | if (ssid1_len != ssid2_len) |
110 | return -1; | 108 | return -1; |
@@ -113,73 +111,66 @@ int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len) | |||
113 | } | 111 | } |
114 | 112 | ||
115 | static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, | 113 | static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, |
116 | struct bss_descriptor * match_bss) | 114 | struct bss_descriptor *match_bss) |
117 | { | 115 | { |
118 | if ( !secinfo->wep_enabled | 116 | if (!secinfo->wep_enabled && !secinfo->WPAenabled |
119 | && !secinfo->WPAenabled | ||
120 | && !secinfo->WPA2enabled | 117 | && !secinfo->WPA2enabled |
121 | && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC | 118 | && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC |
122 | && match_bss->rsn_ie[0] != MFIE_TYPE_RSN | 119 | && match_bss->rsn_ie[0] != MFIE_TYPE_RSN |
123 | && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { | 120 | && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) |
124 | return 1; | 121 | return 1; |
125 | } | 122 | else |
126 | return 0; | 123 | return 0; |
127 | } | 124 | } |
128 | 125 | ||
129 | static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo, | 126 | static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo, |
130 | struct bss_descriptor * match_bss) | 127 | struct bss_descriptor *match_bss) |
131 | { | 128 | { |
132 | if ( secinfo->wep_enabled | 129 | if (secinfo->wep_enabled && !secinfo->WPAenabled |
133 | && !secinfo->WPAenabled | 130 | && !secinfo->WPA2enabled |
134 | && !secinfo->WPA2enabled | 131 | && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) |
135 | && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { | ||
136 | return 1; | 132 | return 1; |
137 | } | 133 | else |
138 | return 0; | 134 | return 0; |
139 | } | 135 | } |
140 | 136 | ||
141 | static inline int match_bss_wpa(struct lbs_802_11_security *secinfo, | 137 | static inline int match_bss_wpa(struct lbs_802_11_security *secinfo, |
142 | struct bss_descriptor * match_bss) | 138 | struct bss_descriptor *match_bss) |
143 | { | 139 | { |
144 | if ( !secinfo->wep_enabled | 140 | if (!secinfo->wep_enabled && secinfo->WPAenabled |
145 | && secinfo->WPAenabled | 141 | && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC) |
146 | && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC) | 142 | /* privacy bit may NOT be set in some APs like LinkSys WRT54G |
147 | /* privacy bit may NOT be set in some APs like LinkSys WRT54G | 143 | && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */ |
148 | && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { | 144 | ) |
149 | */ | ||
150 | ) { | ||
151 | return 1; | 145 | return 1; |
152 | } | 146 | else |
153 | return 0; | 147 | return 0; |
154 | } | 148 | } |
155 | 149 | ||
156 | static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo, | 150 | static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo, |
157 | struct bss_descriptor * match_bss) | 151 | struct bss_descriptor *match_bss) |
158 | { | 152 | { |
159 | if ( !secinfo->wep_enabled | 153 | if (!secinfo->wep_enabled && secinfo->WPA2enabled |
160 | && secinfo->WPA2enabled | 154 | && (match_bss->rsn_ie[0] == MFIE_TYPE_RSN) |
161 | && (match_bss->rsn_ie[0] == MFIE_TYPE_RSN) | 155 | /* privacy bit may NOT be set in some APs like LinkSys WRT54G |
162 | /* privacy bit may NOT be set in some APs like LinkSys WRT54G | 156 | && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */ |
163 | && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { | 157 | ) |
164 | */ | ||
165 | ) { | ||
166 | return 1; | 158 | return 1; |
167 | } | 159 | else |
168 | return 0; | 160 | return 0; |
169 | } | 161 | } |
170 | 162 | ||
171 | static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo, | 163 | static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo, |
172 | struct bss_descriptor * match_bss) | 164 | struct bss_descriptor *match_bss) |
173 | { | 165 | { |
174 | if ( !secinfo->wep_enabled | 166 | if (!secinfo->wep_enabled && !secinfo->WPAenabled |
175 | && !secinfo->WPAenabled | 167 | && !secinfo->WPA2enabled |
176 | && !secinfo->WPA2enabled | 168 | && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC) |
177 | && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC) | 169 | && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN) |
178 | && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN) | 170 | && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) |
179 | && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { | ||
180 | return 1; | 171 | return 1; |
181 | } | 172 | else |
182 | return 0; | 173 | return 0; |
183 | } | 174 | } |
184 | 175 | ||
185 | static inline int is_same_network(struct bss_descriptor *src, | 176 | static inline int is_same_network(struct bss_descriptor *src, |
@@ -214,7 +205,7 @@ static inline int is_same_network(struct bss_descriptor *src, | |||
214 | * @return Index in scantable, or error code if negative | 205 | * @return Index in scantable, or error code if negative |
215 | */ | 206 | */ |
216 | static int is_network_compatible(struct lbs_private *priv, | 207 | static int is_network_compatible(struct lbs_private *priv, |
217 | struct bss_descriptor * bss, u8 mode) | 208 | struct bss_descriptor *bss, uint8_t mode) |
218 | { | 209 | { |
219 | int matched = 0; | 210 | int matched = 0; |
220 | 211 | ||
@@ -228,43 +219,39 @@ static int is_network_compatible(struct lbs_private *priv, | |||
228 | } else if ((matched = match_bss_static_wep(&priv->secinfo, bss))) { | 219 | } else if ((matched = match_bss_static_wep(&priv->secinfo, bss))) { |
229 | goto done; | 220 | goto done; |
230 | } else if ((matched = match_bss_wpa(&priv->secinfo, bss))) { | 221 | } else if ((matched = match_bss_wpa(&priv->secinfo, bss))) { |
231 | lbs_deb_scan( | 222 | lbs_deb_scan("is_network_compatible() WPA: wpa_ie 0x%x " |
232 | "is_network_compatible() WPA: wpa_ie 0x%x " | 223 | "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s " |
233 | "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s " | 224 | "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0], |
234 | "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0], | 225 | priv->secinfo.wep_enabled ? "e" : "d", |
235 | priv->secinfo.wep_enabled ? "e" : "d", | 226 | priv->secinfo.WPAenabled ? "e" : "d", |
236 | priv->secinfo.WPAenabled ? "e" : "d", | 227 | priv->secinfo.WPA2enabled ? "e" : "d", |
237 | priv->secinfo.WPA2enabled ? "e" : "d", | 228 | (bss->capability & WLAN_CAPABILITY_PRIVACY)); |
238 | (bss->capability & WLAN_CAPABILITY_PRIVACY)); | ||
239 | goto done; | 229 | goto done; |
240 | } else if ((matched = match_bss_wpa2(&priv->secinfo, bss))) { | 230 | } else if ((matched = match_bss_wpa2(&priv->secinfo, bss))) { |
241 | lbs_deb_scan( | 231 | lbs_deb_scan("is_network_compatible() WPA2: wpa_ie 0x%x " |
242 | "is_network_compatible() WPA2: wpa_ie 0x%x " | 232 | "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s " |
243 | "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s " | 233 | "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0], |
244 | "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0], | 234 | priv->secinfo.wep_enabled ? "e" : "d", |
245 | priv->secinfo.wep_enabled ? "e" : "d", | 235 | priv->secinfo.WPAenabled ? "e" : "d", |
246 | priv->secinfo.WPAenabled ? "e" : "d", | 236 | priv->secinfo.WPA2enabled ? "e" : "d", |
247 | priv->secinfo.WPA2enabled ? "e" : "d", | 237 | (bss->capability & WLAN_CAPABILITY_PRIVACY)); |
248 | (bss->capability & WLAN_CAPABILITY_PRIVACY)); | ||
249 | goto done; | 238 | goto done; |
250 | } else if ((matched = match_bss_dynamic_wep(&priv->secinfo, bss))) { | 239 | } else if ((matched = match_bss_dynamic_wep(&priv->secinfo, bss))) { |
251 | lbs_deb_scan( | 240 | lbs_deb_scan("is_network_compatible() dynamic WEP: " |
252 | "is_network_compatible() dynamic WEP: " | 241 | "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n", |
253 | "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n", | 242 | bss->wpa_ie[0], bss->rsn_ie[0], |
254 | bss->wpa_ie[0], bss->rsn_ie[0], | 243 | (bss->capability & WLAN_CAPABILITY_PRIVACY)); |
255 | (bss->capability & WLAN_CAPABILITY_PRIVACY)); | ||
256 | goto done; | 244 | goto done; |
257 | } | 245 | } |
258 | 246 | ||
259 | /* bss security settings don't match those configured on card */ | 247 | /* bss security settings don't match those configured on card */ |
260 | lbs_deb_scan( | 248 | lbs_deb_scan("is_network_compatible() FAILED: wpa_ie 0x%x " |
261 | "is_network_compatible() FAILED: wpa_ie 0x%x " | 249 | "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n", |
262 | "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n", | 250 | bss->wpa_ie[0], bss->rsn_ie[0], |
263 | bss->wpa_ie[0], bss->rsn_ie[0], | 251 | priv->secinfo.wep_enabled ? "e" : "d", |
264 | priv->secinfo.wep_enabled ? "e" : "d", | 252 | priv->secinfo.WPAenabled ? "e" : "d", |
265 | priv->secinfo.WPAenabled ? "e" : "d", | 253 | priv->secinfo.WPA2enabled ? "e" : "d", |
266 | priv->secinfo.WPA2enabled ? "e" : "d", | 254 | (bss->capability & WLAN_CAPABILITY_PRIVACY)); |
267 | (bss->capability & WLAN_CAPABILITY_PRIVACY)); | ||
268 | 255 | ||
269 | done: | 256 | done: |
270 | lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched); | 257 | lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched); |
@@ -311,16 +298,15 @@ void lbs_scan_worker(struct work_struct *work) | |||
311 | * @return void | 298 | * @return void |
312 | */ | 299 | */ |
313 | static int lbs_scan_create_channel_list(struct lbs_private *priv, | 300 | static int lbs_scan_create_channel_list(struct lbs_private *priv, |
314 | struct chanscanparamset * scanchanlist, | 301 | struct chanscanparamset *scanchanlist, |
315 | u8 filteredscan) | 302 | uint8_t filteredscan) |
316 | { | 303 | { |
317 | |||
318 | struct region_channel *scanregion; | 304 | struct region_channel *scanregion; |
319 | struct chan_freq_power *cfp; | 305 | struct chan_freq_power *cfp; |
320 | int rgnidx; | 306 | int rgnidx; |
321 | int chanidx; | 307 | int chanidx; |
322 | int nextchan; | 308 | int nextchan; |
323 | u8 scantype; | 309 | uint8_t scantype; |
324 | 310 | ||
325 | chanidx = 0; | 311 | chanidx = 0; |
326 | 312 | ||
@@ -331,9 +317,8 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv, | |||
331 | scantype = CMD_SCAN_TYPE_ACTIVE; | 317 | scantype = CMD_SCAN_TYPE_ACTIVE; |
332 | 318 | ||
333 | for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) { | 319 | for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) { |
334 | if (priv->enable11d && | 320 | if (priv->enable11d && (priv->connect_status != LBS_CONNECTED) |
335 | (priv->connect_status != LBS_CONNECTED) && | 321 | && (priv->mesh_connect_status != LBS_CONNECTED)) { |
336 | (priv->mesh_connect_status != LBS_CONNECTED)) { | ||
337 | /* Scan all the supported chan for the first scan */ | 322 | /* Scan all the supported chan for the first scan */ |
338 | if (!priv->universal_channel[rgnidx].valid) | 323 | if (!priv->universal_channel[rgnidx].valid) |
339 | continue; | 324 | continue; |
@@ -348,45 +333,30 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv, | |||
348 | scanregion = &priv->region_channel[rgnidx]; | 333 | scanregion = &priv->region_channel[rgnidx]; |
349 | } | 334 | } |
350 | 335 | ||
351 | for (nextchan = 0; | 336 | for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) { |
352 | nextchan < scanregion->nrcfp; nextchan++, chanidx++) { | 337 | struct chanscanparamset *chan = &scanchanlist[chanidx]; |
353 | 338 | ||
354 | cfp = scanregion->CFP + nextchan; | 339 | cfp = scanregion->CFP + nextchan; |
355 | 340 | ||
356 | if (priv->enable11d) { | 341 | if (priv->enable11d) |
357 | scantype = | 342 | scantype = lbs_get_scan_type_11d(cfp->channel, |
358 | lbs_get_scan_type_11d(cfp->channel, | 343 | &priv->parsed_region_chan); |
359 | &priv-> | ||
360 | parsed_region_chan); | ||
361 | } | ||
362 | 344 | ||
363 | switch (scanregion->band) { | 345 | if (scanregion->band == BAND_B || scanregion->band == BAND_G) |
364 | case BAND_B: | 346 | chan->radiotype = CMD_SCAN_RADIO_TYPE_BG; |
365 | case BAND_G: | ||
366 | default: | ||
367 | scanchanlist[chanidx].radiotype = | ||
368 | CMD_SCAN_RADIO_TYPE_BG; | ||
369 | break; | ||
370 | } | ||
371 | 347 | ||
372 | if (scantype == CMD_SCAN_TYPE_PASSIVE) { | 348 | if (scantype == CMD_SCAN_TYPE_PASSIVE) { |
373 | scanchanlist[chanidx].maxscantime = | 349 | chan->maxscantime = cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME); |
374 | cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME); | 350 | chan->chanscanmode.passivescan = 1; |
375 | scanchanlist[chanidx].chanscanmode.passivescan = | ||
376 | 1; | ||
377 | } else { | 351 | } else { |
378 | scanchanlist[chanidx].maxscantime = | 352 | chan->maxscantime = cpu_to_le16(MRVDRV_ACTIVE_SCAN_CHAN_TIME); |
379 | cpu_to_le16(MRVDRV_ACTIVE_SCAN_CHAN_TIME); | 353 | chan->chanscanmode.passivescan = 0; |
380 | scanchanlist[chanidx].chanscanmode.passivescan = | ||
381 | 0; | ||
382 | } | 354 | } |
383 | 355 | ||
384 | scanchanlist[chanidx].channumber = cfp->channel; | 356 | chan->channumber = cfp->channel; |
385 | 357 | ||
386 | if (filteredscan) { | 358 | if (filteredscan) |
387 | scanchanlist[chanidx].chanscanmode. | 359 | chan->chanscanmode.disablechanfilt = 1; |
388 | disablechanfilt = 1; | ||
389 | } | ||
390 | } | 360 | } |
391 | } | 361 | } |
392 | return chanidx; | 362 | return chanidx; |
@@ -400,11 +370,11 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv, | |||
400 | * length 06 00 | 370 | * length 06 00 |
401 | * ssid 4d 4e 54 45 53 54 | 371 | * ssid 4d 4e 54 45 53 54 |
402 | */ | 372 | */ |
403 | static int lbs_scan_add_ssid_tlv(u8 *tlv, | 373 | static int lbs_scan_add_ssid_tlv(uint8_t *tlv, |
404 | const struct lbs_ioctl_user_scan_cfg *user_cfg) | 374 | const struct lbs_ioctl_user_scan_cfg *user_cfg) |
405 | { | 375 | { |
406 | struct mrvlietypes_ssidparamset *ssid_tlv = | 376 | struct mrvlietypes_ssidparamset *ssid_tlv = (void *)tlv; |
407 | (struct mrvlietypes_ssidparamset *)tlv; | 377 | |
408 | ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID); | 378 | ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID); |
409 | ssid_tlv->header.len = cpu_to_le16(user_cfg->ssid_len); | 379 | ssid_tlv->header.len = cpu_to_le16(user_cfg->ssid_len); |
410 | memcpy(ssid_tlv->ssid, user_cfg->ssid, user_cfg->ssid_len); | 380 | memcpy(ssid_tlv->ssid, user_cfg->ssid, user_cfg->ssid_len); |
@@ -437,13 +407,12 @@ static int lbs_scan_add_ssid_tlv(u8 *tlv, | |||
437 | * channel 13 00 0d 00 00 00 64 00 | 407 | * channel 13 00 0d 00 00 00 64 00 |
438 | * | 408 | * |
439 | */ | 409 | */ |
440 | static int lbs_scan_add_chanlist_tlv(u8 *tlv, | 410 | static int lbs_scan_add_chanlist_tlv(uint8_t *tlv, |
441 | struct chanscanparamset *chan_list, | 411 | struct chanscanparamset *chan_list, |
442 | int chan_count) | 412 | int chan_count) |
443 | { | 413 | { |
444 | size_t size = sizeof(struct chanscanparamset) * chan_count; | 414 | size_t size = sizeof(struct chanscanparamset) *chan_count; |
445 | struct mrvlietypes_chanlistparamset *chan_tlv = | 415 | struct mrvlietypes_chanlistparamset *chan_tlv = (void *)tlv; |
446 | (struct mrvlietypes_chanlistparamset *) tlv; | ||
447 | 416 | ||
448 | chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); | 417 | chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); |
449 | memcpy(chan_tlv->chanscanparam, chan_list, size); | 418 | memcpy(chan_tlv->chanscanparam, chan_list, size); |
@@ -462,11 +431,10 @@ static int lbs_scan_add_chanlist_tlv(u8 *tlv, | |||
462 | * The rates are in lbs_bg_rates[], but for the 802.11b | 431 | * The rates are in lbs_bg_rates[], but for the 802.11b |
463 | * rates the high bit isn't set. | 432 | * rates the high bit isn't set. |
464 | */ | 433 | */ |
465 | static int lbs_scan_add_rates_tlv(u8 *tlv) | 434 | static int lbs_scan_add_rates_tlv(uint8_t *tlv) |
466 | { | 435 | { |
467 | int i; | 436 | int i; |
468 | struct mrvlietypes_ratesparamset *rate_tlv = | 437 | struct mrvlietypes_ratesparamset *rate_tlv = (void *)tlv; |
469 | (struct mrvlietypes_ratesparamset *) tlv; | ||
470 | 438 | ||
471 | rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES); | 439 | rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES); |
472 | tlv += sizeof(rate_tlv->header); | 440 | tlv += sizeof(rate_tlv->header); |
@@ -492,24 +460,22 @@ static int lbs_scan_add_rates_tlv(u8 *tlv) | |||
492 | * Generate the CMD_802_11_SCAN command with the proper tlv | 460 | * Generate the CMD_802_11_SCAN command with the proper tlv |
493 | * for a bunch of channels. | 461 | * for a bunch of channels. |
494 | */ | 462 | */ |
495 | static int lbs_do_scan(struct lbs_private *priv, | 463 | static int lbs_do_scan(struct lbs_private *priv, uint8_t bsstype, |
496 | u8 bsstype, | 464 | struct chanscanparamset *chan_list, int chan_count, |
497 | struct chanscanparamset *chan_list, | 465 | const struct lbs_ioctl_user_scan_cfg *user_cfg) |
498 | int chan_count, | ||
499 | const struct lbs_ioctl_user_scan_cfg *user_cfg) | ||
500 | { | 466 | { |
501 | int ret = -ENOMEM; | 467 | int ret = -ENOMEM; |
502 | struct lbs_scan_cmd_config *scan_cmd; | 468 | struct cmd_ds_802_11_scan *scan_cmd; |
503 | u8 *tlv; /* pointer into our current, growing TLV storage area */ | 469 | uint8_t *tlv; /* pointer into our current, growing TLV storage area */ |
504 | 470 | ||
505 | lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, " | 471 | lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, chan_count %d", |
506 | "chan_count %d", | 472 | bsstype, chan_list[0].channumber, chan_count); |
507 | bsstype, chan_list[0].channumber, chan_count); | ||
508 | 473 | ||
509 | /* create the fixed part for scan command */ | 474 | /* create the fixed part for scan command */ |
510 | scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL); | 475 | scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL); |
511 | if (scan_cmd == NULL) | 476 | if (scan_cmd == NULL) |
512 | goto out; | 477 | goto out; |
478 | |||
513 | tlv = scan_cmd->tlvbuffer; | 479 | tlv = scan_cmd->tlvbuffer; |
514 | if (user_cfg) | 480 | if (user_cfg) |
515 | memcpy(scan_cmd->bssid, user_cfg->bssid, ETH_ALEN); | 481 | memcpy(scan_cmd->bssid, user_cfg->bssid, ETH_ALEN); |
@@ -523,13 +489,16 @@ static int lbs_do_scan(struct lbs_private *priv, | |||
523 | tlv += lbs_scan_add_rates_tlv(tlv); | 489 | tlv += lbs_scan_add_rates_tlv(tlv); |
524 | 490 | ||
525 | /* This is the final data we are about to send */ | 491 | /* This is the final data we are about to send */ |
526 | scan_cmd->tlvbufferlen = tlv - scan_cmd->tlvbuffer; | 492 | scan_cmd->hdr.size = cpu_to_le16(tlv - (uint8_t *)scan_cmd); |
527 | lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd, 1+6); | 493 | lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd, |
494 | sizeof(*scan_cmd)); | ||
528 | lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer, | 495 | lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer, |
529 | scan_cmd->tlvbufferlen); | 496 | tlv - scan_cmd->tlvbuffer); |
497 | |||
498 | ret = __lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr, | ||
499 | le16_to_cpu(scan_cmd->hdr.size), | ||
500 | lbs_ret_80211_scan, 0); | ||
530 | 501 | ||
531 | ret = lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, 0, | ||
532 | CMD_OPTION_WAITFORRSP, 0, scan_cmd); | ||
533 | out: | 502 | out: |
534 | kfree(scan_cmd); | 503 | kfree(scan_cmd); |
535 | lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); | 504 | lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); |
@@ -553,14 +522,14 @@ out: | |||
553 | * @return 0 or < 0 if error | 522 | * @return 0 or < 0 if error |
554 | */ | 523 | */ |
555 | int lbs_scan_networks(struct lbs_private *priv, | 524 | int lbs_scan_networks(struct lbs_private *priv, |
556 | const struct lbs_ioctl_user_scan_cfg *user_cfg, | 525 | const struct lbs_ioctl_user_scan_cfg *user_cfg, |
557 | int full_scan) | 526 | int full_scan) |
558 | { | 527 | { |
559 | int ret = -ENOMEM; | 528 | int ret = -ENOMEM; |
560 | struct chanscanparamset *chan_list; | 529 | struct chanscanparamset *chan_list; |
561 | struct chanscanparamset *curr_chans; | 530 | struct chanscanparamset *curr_chans; |
562 | int chan_count; | 531 | int chan_count; |
563 | u8 bsstype = CMD_BSS_TYPE_ANY; | 532 | uint8_t bsstype = CMD_BSS_TYPE_ANY; |
564 | int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD; | 533 | int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD; |
565 | int filteredscan = 0; | 534 | int filteredscan = 0; |
566 | union iwreq_data wrqu; | 535 | union iwreq_data wrqu; |
@@ -570,8 +539,7 @@ int lbs_scan_networks(struct lbs_private *priv, | |||
570 | DECLARE_MAC_BUF(mac); | 539 | DECLARE_MAC_BUF(mac); |
571 | #endif | 540 | #endif |
572 | 541 | ||
573 | lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", | 542 | lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan); |
574 | full_scan); | ||
575 | 543 | ||
576 | /* Cancel any partial outstanding partial scans if this scan | 544 | /* Cancel any partial outstanding partial scans if this scan |
577 | * is a full scan. | 545 | * is a full scan. |
@@ -583,26 +551,24 @@ int lbs_scan_networks(struct lbs_private *priv, | |||
583 | if (user_cfg) { | 551 | if (user_cfg) { |
584 | if (user_cfg->bsstype) | 552 | if (user_cfg->bsstype) |
585 | bsstype = user_cfg->bsstype; | 553 | bsstype = user_cfg->bsstype; |
586 | if (compare_ether_addr(user_cfg->bssid, &zeromac[0]) != 0) { | 554 | if (!is_zero_ether_addr(user_cfg->bssid)) { |
587 | numchannels = MRVDRV_MAX_CHANNELS_PER_SCAN; | 555 | numchannels = MRVDRV_MAX_CHANNELS_PER_SCAN; |
588 | filteredscan = 1; | 556 | filteredscan = 1; |
589 | } | 557 | } |
590 | } | 558 | } |
591 | lbs_deb_scan("numchannels %d, bsstype %d, " | 559 | lbs_deb_scan("numchannels %d, bsstype %d, filteredscan %d\n", |
592 | "filteredscan %d\n", | 560 | numchannels, bsstype, filteredscan); |
593 | numchannels, bsstype, filteredscan); | ||
594 | 561 | ||
595 | /* Create list of channels to scan */ | 562 | /* Create list of channels to scan */ |
596 | chan_list = kzalloc(sizeof(struct chanscanparamset) * | 563 | chan_list = kzalloc(sizeof(struct chanscanparamset) * |
597 | LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL); | 564 | LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL); |
598 | if (!chan_list) { | 565 | if (!chan_list) { |
599 | lbs_pr_alert("SCAN: chan_list empty\n"); | 566 | lbs_pr_alert("SCAN: chan_list empty\n"); |
600 | goto out; | 567 | goto out; |
601 | } | 568 | } |
602 | 569 | ||
603 | /* We want to scan all channels */ | 570 | /* We want to scan all channels */ |
604 | chan_count = lbs_scan_create_channel_list(priv, chan_list, | 571 | chan_count = lbs_scan_create_channel_list(priv, chan_list, filteredscan); |
605 | filteredscan); | ||
606 | 572 | ||
607 | netif_stop_queue(priv->dev); | 573 | netif_stop_queue(priv->dev); |
608 | netif_carrier_off(priv->dev); | 574 | netif_carrier_off(priv->dev); |
@@ -629,9 +595,9 @@ int lbs_scan_networks(struct lbs_private *priv, | |||
629 | while (chan_count) { | 595 | while (chan_count) { |
630 | int to_scan = min(numchannels, chan_count); | 596 | int to_scan = min(numchannels, chan_count); |
631 | lbs_deb_scan("scanning %d of %d channels\n", | 597 | lbs_deb_scan("scanning %d of %d channels\n", |
632 | to_scan, chan_count); | 598 | to_scan, chan_count); |
633 | ret = lbs_do_scan(priv, bsstype, curr_chans, | 599 | ret = lbs_do_scan(priv, bsstype, curr_chans, |
634 | to_scan, user_cfg); | 600 | to_scan, user_cfg); |
635 | if (ret) { | 601 | if (ret) { |
636 | lbs_pr_err("SCAN_CMD failed\n"); | 602 | lbs_pr_err("SCAN_CMD failed\n"); |
637 | goto out2; | 603 | goto out2; |
@@ -640,8 +606,7 @@ int lbs_scan_networks(struct lbs_private *priv, | |||
640 | chan_count -= to_scan; | 606 | chan_count -= to_scan; |
641 | 607 | ||
642 | /* somehow schedule the next part of the scan */ | 608 | /* somehow schedule the next part of the scan */ |
643 | if (chan_count && | 609 | if (chan_count && !full_scan && |
644 | !full_scan && | ||
645 | !priv->surpriseremoved) { | 610 | !priv->surpriseremoved) { |
646 | /* -1 marks just that we're currently scanning */ | 611 | /* -1 marks just that we're currently scanning */ |
647 | if (priv->scan_channel < 0) | 612 | if (priv->scan_channel < 0) |
@@ -650,7 +615,7 @@ int lbs_scan_networks(struct lbs_private *priv, | |||
650 | priv->scan_channel += to_scan; | 615 | priv->scan_channel += to_scan; |
651 | cancel_delayed_work(&priv->scan_work); | 616 | cancel_delayed_work(&priv->scan_work); |
652 | queue_delayed_work(priv->work_thread, &priv->scan_work, | 617 | queue_delayed_work(priv->work_thread, &priv->scan_work, |
653 | msecs_to_jiffies(300)); | 618 | msecs_to_jiffies(300)); |
654 | /* skip over GIWSCAN event */ | 619 | /* skip over GIWSCAN event */ |
655 | goto out; | 620 | goto out; |
656 | } | 621 | } |
@@ -665,8 +630,8 @@ int lbs_scan_networks(struct lbs_private *priv, | |||
665 | lbs_deb_scan("scan table:\n"); | 630 | lbs_deb_scan("scan table:\n"); |
666 | list_for_each_entry(iter, &priv->network_list, list) | 631 | list_for_each_entry(iter, &priv->network_list, list) |
667 | lbs_deb_scan("%02d: BSSID %s, RSSI %d, SSID '%s'\n", | 632 | lbs_deb_scan("%02d: BSSID %s, RSSI %d, SSID '%s'\n", |
668 | i++, print_mac(mac, iter->bssid), (s32) iter->rssi, | 633 | i++, print_mac(mac, iter->bssid), (int)iter->rssi, |
669 | escape_essid(iter->ssid, iter->ssid_len)); | 634 | escape_essid(iter->ssid, iter->ssid_len)); |
670 | mutex_unlock(&priv->lock); | 635 | mutex_unlock(&priv->lock); |
671 | #endif | 636 | #endif |
672 | 637 | ||
@@ -711,7 +676,7 @@ out: | |||
711 | * @return 0 or -1 | 676 | * @return 0 or -1 |
712 | */ | 677 | */ |
713 | static int lbs_process_bss(struct bss_descriptor *bss, | 678 | static int lbs_process_bss(struct bss_descriptor *bss, |
714 | u8 ** pbeaconinfo, int *bytesleft) | 679 | uint8_t **pbeaconinfo, int *bytesleft) |
715 | { | 680 | { |
716 | struct ieeetypes_fhparamset *pFH; | 681 | struct ieeetypes_fhparamset *pFH; |
717 | struct ieeetypes_dsparamset *pDS; | 682 | struct ieeetypes_dsparamset *pDS; |
@@ -719,9 +684,9 @@ static int lbs_process_bss(struct bss_descriptor *bss, | |||
719 | struct ieeetypes_ibssparamset *pibss; | 684 | struct ieeetypes_ibssparamset *pibss; |
720 | DECLARE_MAC_BUF(mac); | 685 | DECLARE_MAC_BUF(mac); |
721 | struct ieeetypes_countryinfoset *pcountryinfo; | 686 | struct ieeetypes_countryinfoset *pcountryinfo; |
722 | u8 *pos, *end, *p; | 687 | uint8_t *pos, *end, *p; |
723 | u8 n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; | 688 | uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; |
724 | u16 beaconsize = 0; | 689 | uint16_t beaconsize = 0; |
725 | int ret; | 690 | int ret; |
726 | 691 | ||
727 | lbs_deb_enter(LBS_DEB_SCAN); | 692 | lbs_deb_enter(LBS_DEB_SCAN); |
@@ -793,12 +758,11 @@ static int lbs_process_bss(struct bss_descriptor *bss, | |||
793 | 758 | ||
794 | /* process variable IE */ | 759 | /* process variable IE */ |
795 | while (pos <= end - 2) { | 760 | while (pos <= end - 2) { |
796 | struct ieee80211_info_element * elem = | 761 | struct ieee80211_info_element * elem = (void *)pos; |
797 | (struct ieee80211_info_element *) pos; | ||
798 | 762 | ||
799 | if (pos + elem->len > end) { | 763 | if (pos + elem->len > end) { |
800 | lbs_deb_scan("process_bss: error in processing IE, " | 764 | lbs_deb_scan("process_bss: error in processing IE, " |
801 | "bytes left < IE length\n"); | 765 | "bytes left < IE length\n"); |
802 | break; | 766 | break; |
803 | } | 767 | } |
804 | 768 | ||
@@ -812,7 +776,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, | |||
812 | break; | 776 | break; |
813 | 777 | ||
814 | case MFIE_TYPE_RATES: | 778 | case MFIE_TYPE_RATES: |
815 | n_basic_rates = min_t(u8, MAX_RATES, elem->len); | 779 | n_basic_rates = min_t(uint8_t, MAX_RATES, elem->len); |
816 | memcpy(bss->rates, elem->data, n_basic_rates); | 780 | memcpy(bss->rates, elem->data, n_basic_rates); |
817 | got_basic_rates = 1; | 781 | got_basic_rates = 1; |
818 | lbs_deb_scan("got RATES IE\n"); | 782 | lbs_deb_scan("got RATES IE\n"); |
@@ -853,19 +817,16 @@ static int lbs_process_bss(struct bss_descriptor *bss, | |||
853 | lbs_deb_scan("got COUNTRY IE\n"); | 817 | lbs_deb_scan("got COUNTRY IE\n"); |
854 | if (pcountryinfo->len < sizeof(pcountryinfo->countrycode) | 818 | if (pcountryinfo->len < sizeof(pcountryinfo->countrycode) |
855 | || pcountryinfo->len > 254) { | 819 | || pcountryinfo->len > 254) { |
856 | lbs_deb_scan("process_bss: 11D- Err " | 820 | lbs_deb_scan("process_bss: 11D- Err CountryInfo len %d, min %zd, max 254\n", |
857 | "CountryInfo len %d, min %zd, max 254\n", | 821 | pcountryinfo->len, sizeof(pcountryinfo->countrycode)); |
858 | pcountryinfo->len, | ||
859 | sizeof(pcountryinfo->countrycode)); | ||
860 | ret = -1; | 822 | ret = -1; |
861 | goto done; | 823 | goto done; |
862 | } | 824 | } |
863 | 825 | ||
864 | memcpy(&bss->countryinfo, | 826 | memcpy(&bss->countryinfo, pcountryinfo, pcountryinfo->len + 2); |
865 | pcountryinfo, pcountryinfo->len + 2); | ||
866 | lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo", | 827 | lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo", |
867 | (u8 *) pcountryinfo, | 828 | (uint8_t *) pcountryinfo, |
868 | (u32) (pcountryinfo->len + 2)); | 829 | (int) (pcountryinfo->len + 2)); |
869 | break; | 830 | break; |
870 | 831 | ||
871 | case MFIE_TYPE_RATES_EX: | 832 | case MFIE_TYPE_RATES_EX: |
@@ -889,26 +850,19 @@ static int lbs_process_bss(struct bss_descriptor *bss, | |||
889 | 850 | ||
890 | case MFIE_TYPE_GENERIC: | 851 | case MFIE_TYPE_GENERIC: |
891 | if (elem->len >= 4 && | 852 | if (elem->len >= 4 && |
892 | elem->data[0] == 0x00 && | 853 | elem->data[0] == 0x00 && elem->data[1] == 0x50 && |
893 | elem->data[1] == 0x50 && | 854 | elem->data[2] == 0xf2 && elem->data[3] == 0x01) { |
894 | elem->data[2] == 0xf2 && | 855 | bss->wpa_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); |
895 | elem->data[3] == 0x01) { | ||
896 | bss->wpa_ie_len = min(elem->len + 2, | ||
897 | MAX_WPA_IE_LEN); | ||
898 | memcpy(bss->wpa_ie, elem, bss->wpa_ie_len); | 856 | memcpy(bss->wpa_ie, elem, bss->wpa_ie_len); |
899 | lbs_deb_scan("got WPA IE\n"); | 857 | lbs_deb_scan("got WPA IE\n"); |
900 | lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie, | 858 | lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie, elem->len); |
901 | elem->len); | ||
902 | } else if (elem->len >= MARVELL_MESH_IE_LENGTH && | 859 | } else if (elem->len >= MARVELL_MESH_IE_LENGTH && |
903 | elem->data[0] == 0x00 && | 860 | elem->data[0] == 0x00 && elem->data[1] == 0x50 && |
904 | elem->data[1] == 0x50 && | 861 | elem->data[2] == 0x43 && elem->data[3] == 0x04) { |
905 | elem->data[2] == 0x43 && | ||
906 | elem->data[3] == 0x04) { | ||
907 | lbs_deb_scan("got mesh IE\n"); | 862 | lbs_deb_scan("got mesh IE\n"); |
908 | bss->mesh = 1; | 863 | bss->mesh = 1; |
909 | } else { | 864 | } else { |
910 | lbs_deb_scan("got generiec IE: " | 865 | lbs_deb_scan("got generic IE: %02x:%02x:%02x:%02x, len %d\n", |
911 | "%02x:%02x:%02x:%02x, len %d\n", | ||
912 | elem->data[0], elem->data[1], | 866 | elem->data[0], elem->data[1], |
913 | elem->data[2], elem->data[3], | 867 | elem->data[2], elem->data[3], |
914 | elem->len); | 868 | elem->len); |
@@ -920,12 +874,12 @@ static int lbs_process_bss(struct bss_descriptor *bss, | |||
920 | bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); | 874 | bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); |
921 | memcpy(bss->rsn_ie, elem, bss->rsn_ie_len); | 875 | memcpy(bss->rsn_ie, elem, bss->rsn_ie_len); |
922 | lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", | 876 | lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", |
923 | bss->rsn_ie, elem->len); | 877 | bss->rsn_ie, elem->len); |
924 | break; | 878 | break; |
925 | 879 | ||
926 | default: | 880 | default: |
927 | lbs_deb_scan("got IE 0x%04x, len %d\n", | 881 | lbs_deb_scan("got IE 0x%04x, len %d\n", |
928 | elem->id, elem->len); | 882 | elem->id, elem->len); |
929 | break; | 883 | break; |
930 | } | 884 | } |
931 | 885 | ||
@@ -955,18 +909,17 @@ done: | |||
955 | * @return index in BSSID list, or error return code (< 0) | 909 | * @return index in BSSID list, or error return code (< 0) |
956 | */ | 910 | */ |
957 | struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv, | 911 | struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv, |
958 | u8 * bssid, u8 mode) | 912 | uint8_t *bssid, uint8_t mode) |
959 | { | 913 | { |
960 | struct bss_descriptor * iter_bss; | 914 | struct bss_descriptor *iter_bss; |
961 | struct bss_descriptor * found_bss = NULL; | 915 | struct bss_descriptor *found_bss = NULL; |
962 | 916 | ||
963 | lbs_deb_enter(LBS_DEB_SCAN); | 917 | lbs_deb_enter(LBS_DEB_SCAN); |
964 | 918 | ||
965 | if (!bssid) | 919 | if (!bssid) |
966 | goto out; | 920 | goto out; |
967 | 921 | ||
968 | lbs_deb_hex(LBS_DEB_SCAN, "looking for", | 922 | lbs_deb_hex(LBS_DEB_SCAN, "looking for", bssid, ETH_ALEN); |
969 | bssid, ETH_ALEN); | ||
970 | 923 | ||
971 | /* Look through the scan table for a compatible match. The loop will | 924 | /* Look through the scan table for a compatible match. The loop will |
972 | * continue past a matched bssid that is not compatible in case there | 925 | * continue past a matched bssid that is not compatible in case there |
@@ -1008,10 +961,11 @@ out: | |||
1008 | * @return index in BSSID list | 961 | * @return index in BSSID list |
1009 | */ | 962 | */ |
1010 | struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv, | 963 | struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv, |
1011 | u8 *ssid, u8 ssid_len, u8 * bssid, u8 mode, | 964 | uint8_t *ssid, uint8_t ssid_len, |
1012 | int channel) | 965 | uint8_t *bssid, uint8_t mode, |
966 | int channel) | ||
1013 | { | 967 | { |
1014 | u8 bestrssi = 0; | 968 | uint8_t bestrssi = 0; |
1015 | struct bss_descriptor * iter_bss = NULL; | 969 | struct bss_descriptor * iter_bss = NULL; |
1016 | struct bss_descriptor * found_bss = NULL; | 970 | struct bss_descriptor * found_bss = NULL; |
1017 | struct bss_descriptor * tmp_oldest = NULL; | 971 | struct bss_descriptor * tmp_oldest = NULL; |
@@ -1026,7 +980,7 @@ struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv, | |||
1026 | tmp_oldest = iter_bss; | 980 | tmp_oldest = iter_bss; |
1027 | 981 | ||
1028 | if (lbs_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len, | 982 | if (lbs_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len, |
1029 | ssid, ssid_len) != 0) | 983 | ssid, ssid_len) != 0) |
1030 | continue; /* ssid doesn't match */ | 984 | continue; /* ssid doesn't match */ |
1031 | if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0) | 985 | if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0) |
1032 | continue; /* bssid doesn't match */ | 986 | continue; /* bssid doesn't match */ |
@@ -1076,13 +1030,12 @@ out: | |||
1076 | * | 1030 | * |
1077 | * @return index in BSSID list | 1031 | * @return index in BSSID list |
1078 | */ | 1032 | */ |
1079 | static struct bss_descriptor *lbs_find_best_ssid_in_list( | 1033 | static struct bss_descriptor *lbs_find_best_ssid_in_list(struct lbs_private *priv, |
1080 | struct lbs_private *priv, | 1034 | uint8_t mode) |
1081 | u8 mode) | ||
1082 | { | 1035 | { |
1083 | u8 bestrssi = 0; | 1036 | uint8_t bestrssi = 0; |
1084 | struct bss_descriptor * iter_bss; | 1037 | struct bss_descriptor *iter_bss; |
1085 | struct bss_descriptor * best_bss = NULL; | 1038 | struct bss_descriptor *best_bss = NULL; |
1086 | 1039 | ||
1087 | lbs_deb_enter(LBS_DEB_SCAN); | 1040 | lbs_deb_enter(LBS_DEB_SCAN); |
1088 | 1041 | ||
@@ -1124,11 +1077,12 @@ static struct bss_descriptor *lbs_find_best_ssid_in_list( | |||
1124 | * | 1077 | * |
1125 | * @return 0--success, otherwise--fail | 1078 | * @return 0--success, otherwise--fail |
1126 | */ | 1079 | */ |
1127 | int lbs_find_best_network_ssid(struct lbs_private *priv, | 1080 | int lbs_find_best_network_ssid(struct lbs_private *priv, uint8_t *out_ssid, |
1128 | u8 *out_ssid, u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode) | 1081 | uint8_t *out_ssid_len, uint8_t preferred_mode, |
1082 | uint8_t *out_mode) | ||
1129 | { | 1083 | { |
1130 | int ret = -1; | 1084 | int ret = -1; |
1131 | struct bss_descriptor * found; | 1085 | struct bss_descriptor *found; |
1132 | 1086 | ||
1133 | lbs_deb_enter(LBS_DEB_SCAN); | 1087 | lbs_deb_enter(LBS_DEB_SCAN); |
1134 | 1088 | ||
@@ -1163,14 +1117,14 @@ out: | |||
1163 | * | 1117 | * |
1164 | * @return 0-success, otherwise fail | 1118 | * @return 0-success, otherwise fail |
1165 | */ | 1119 | */ |
1166 | int lbs_send_specific_ssid_scan(struct lbs_private *priv, | 1120 | int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid, |
1167 | u8 *ssid, u8 ssid_len, u8 clear_ssid) | 1121 | uint8_t ssid_len, uint8_t clear_ssid) |
1168 | { | 1122 | { |
1169 | struct lbs_ioctl_user_scan_cfg scancfg; | 1123 | struct lbs_ioctl_user_scan_cfg scancfg; |
1170 | int ret = 0; | 1124 | int ret = 0; |
1171 | 1125 | ||
1172 | lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s', clear %d", | 1126 | lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s', clear %d", |
1173 | escape_essid(ssid, ssid_len), clear_ssid); | 1127 | escape_essid(ssid, ssid_len), clear_ssid); |
1174 | 1128 | ||
1175 | if (!ssid_len) | 1129 | if (!ssid_len) |
1176 | goto out; | 1130 | goto out; |
@@ -1204,17 +1158,17 @@ out: | |||
1204 | #define MAX_CUSTOM_LEN 64 | 1158 | #define MAX_CUSTOM_LEN 64 |
1205 | 1159 | ||
1206 | static inline char *lbs_translate_scan(struct lbs_private *priv, | 1160 | static inline char *lbs_translate_scan(struct lbs_private *priv, |
1207 | char *start, char *stop, | 1161 | char *start, char *stop, |
1208 | struct bss_descriptor *bss) | 1162 | struct bss_descriptor *bss) |
1209 | { | 1163 | { |
1210 | struct chan_freq_power *cfp; | 1164 | struct chan_freq_power *cfp; |
1211 | char *current_val; /* For rates */ | 1165 | char *current_val; /* For rates */ |
1212 | struct iw_event iwe; /* Temporary buffer */ | 1166 | struct iw_event iwe; /* Temporary buffer */ |
1213 | int j; | 1167 | int j; |
1214 | #define PERFECT_RSSI ((u8)50) | 1168 | #define PERFECT_RSSI ((uint8_t)50) |
1215 | #define WORST_RSSI ((u8)0) | 1169 | #define WORST_RSSI ((uint8_t)0) |
1216 | #define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI)) | 1170 | #define RSSI_DIFF ((uint8_t)(PERFECT_RSSI - WORST_RSSI)) |
1217 | u8 rssi; | 1171 | uint8_t rssi; |
1218 | 1172 | ||
1219 | lbs_deb_enter(LBS_DEB_SCAN); | 1173 | lbs_deb_enter(LBS_DEB_SCAN); |
1220 | 1174 | ||
@@ -1234,7 +1188,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, | |||
1234 | /* SSID */ | 1188 | /* SSID */ |
1235 | iwe.cmd = SIOCGIWESSID; | 1189 | iwe.cmd = SIOCGIWESSID; |
1236 | iwe.u.data.flags = 1; | 1190 | iwe.u.data.flags = 1; |
1237 | iwe.u.data.length = min((u32) bss->ssid_len, (u32) IW_ESSID_MAX_SIZE); | 1191 | iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IW_ESSID_MAX_SIZE); |
1238 | start = iwe_stream_add_point(start, stop, &iwe, bss->ssid); | 1192 | start = iwe_stream_add_point(start, stop, &iwe, bss->ssid); |
1239 | 1193 | ||
1240 | /* Mode */ | 1194 | /* Mode */ |
@@ -1255,28 +1209,26 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, | |||
1255 | 1209 | ||
1256 | rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE; | 1210 | rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE; |
1257 | iwe.u.qual.qual = | 1211 | iwe.u.qual.qual = |
1258 | (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) * | 1212 | (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) * |
1259 | (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) / | 1213 | (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) / |
1260 | (RSSI_DIFF * RSSI_DIFF); | 1214 | (RSSI_DIFF * RSSI_DIFF); |
1261 | if (iwe.u.qual.qual > 100) | 1215 | if (iwe.u.qual.qual > 100) |
1262 | iwe.u.qual.qual = 100; | 1216 | iwe.u.qual.qual = 100; |
1263 | 1217 | ||
1264 | if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { | 1218 | if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { |
1265 | iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; | 1219 | iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; |
1266 | } else { | 1220 | } else { |
1267 | iwe.u.qual.noise = | 1221 | iwe.u.qual.noise = CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]); |
1268 | CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]); | ||
1269 | } | 1222 | } |
1270 | 1223 | ||
1271 | /* Locally created ad-hoc BSSs won't have beacons if this is the | 1224 | /* Locally created ad-hoc BSSs won't have beacons if this is the |
1272 | * only station in the adhoc network; so get signal strength | 1225 | * only station in the adhoc network; so get signal strength |
1273 | * from receive statistics. | 1226 | * from receive statistics. |
1274 | */ | 1227 | */ |
1275 | if ((priv->mode == IW_MODE_ADHOC) | 1228 | if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate |
1276 | && priv->adhoccreate | ||
1277 | && !lbs_ssid_cmp(priv->curbssparams.ssid, | 1229 | && !lbs_ssid_cmp(priv->curbssparams.ssid, |
1278 | priv->curbssparams.ssid_len, | 1230 | priv->curbssparams.ssid_len, |
1279 | bss->ssid, bss->ssid_len)) { | 1231 | bss->ssid, bss->ssid_len)) { |
1280 | int snr, nf; | 1232 | int snr, nf; |
1281 | snr = priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; | 1233 | snr = priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; |
1282 | nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; | 1234 | nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; |
@@ -1307,14 +1259,13 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, | |||
1307 | current_val = iwe_stream_add_value(start, current_val, | 1259 | current_val = iwe_stream_add_value(start, current_val, |
1308 | stop, &iwe, IW_EV_PARAM_LEN); | 1260 | stop, &iwe, IW_EV_PARAM_LEN); |
1309 | } | 1261 | } |
1310 | if ((bss->mode == IW_MODE_ADHOC) | 1262 | if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate |
1311 | && !lbs_ssid_cmp(priv->curbssparams.ssid, | 1263 | && !lbs_ssid_cmp(priv->curbssparams.ssid, |
1312 | priv->curbssparams.ssid_len, | 1264 | priv->curbssparams.ssid_len, |
1313 | bss->ssid, bss->ssid_len) | 1265 | bss->ssid, bss->ssid_len)) { |
1314 | && priv->adhoccreate) { | ||
1315 | iwe.u.bitrate.value = 22 * 500000; | 1266 | iwe.u.bitrate.value = 22 * 500000; |
1316 | current_val = iwe_stream_add_value(start, current_val, | 1267 | current_val = iwe_stream_add_value(start, current_val, |
1317 | stop, &iwe, IW_EV_PARAM_LEN); | 1268 | stop, &iwe, IW_EV_PARAM_LEN); |
1318 | } | 1269 | } |
1319 | /* Check if we added any event */ | 1270 | /* Check if we added any event */ |
1320 | if((current_val - start) > IW_EV_LCP_LEN) | 1271 | if((current_val - start) > IW_EV_LCP_LEN) |
@@ -1343,8 +1294,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, | |||
1343 | char *p = custom; | 1294 | char *p = custom; |
1344 | 1295 | ||
1345 | iwe.cmd = IWEVCUSTOM; | 1296 | iwe.cmd = IWEVCUSTOM; |
1346 | p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), | 1297 | p += snprintf(p, MAX_CUSTOM_LEN, "mesh-type: olpc"); |
1347 | "mesh-type: olpc"); | ||
1348 | iwe.u.data.length = p - custom; | 1298 | iwe.u.data.length = p - custom; |
1349 | if (iwe.u.data.length) | 1299 | if (iwe.u.data.length) |
1350 | start = iwe_stream_add_point(start, stop, &iwe, custom); | 1300 | start = iwe_stream_add_point(start, stop, &iwe, custom); |
@@ -1367,7 +1317,7 @@ out: | |||
1367 | * @return 0 --success, otherwise fail | 1317 | * @return 0 --success, otherwise fail |
1368 | */ | 1318 | */ |
1369 | int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, | 1319 | int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, |
1370 | struct iw_param *wrqu, char *extra) | 1320 | struct iw_param *wrqu, char *extra) |
1371 | { | 1321 | { |
1372 | struct lbs_private *priv = dev->priv; | 1322 | struct lbs_private *priv = dev->priv; |
1373 | 1323 | ||
@@ -1391,7 +1341,7 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, | |||
1391 | 1341 | ||
1392 | if (!delayed_work_pending(&priv->scan_work)) | 1342 | if (!delayed_work_pending(&priv->scan_work)) |
1393 | queue_delayed_work(priv->work_thread, &priv->scan_work, | 1343 | queue_delayed_work(priv->work_thread, &priv->scan_work, |
1394 | msecs_to_jiffies(50)); | 1344 | msecs_to_jiffies(50)); |
1395 | /* set marker that currently a scan is taking place */ | 1345 | /* set marker that currently a scan is taking place */ |
1396 | priv->scan_channel = -1; | 1346 | priv->scan_channel = -1; |
1397 | 1347 | ||
@@ -1414,15 +1364,15 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, | |||
1414 | * @return 0 --success, otherwise fail | 1364 | * @return 0 --success, otherwise fail |
1415 | */ | 1365 | */ |
1416 | int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, | 1366 | int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, |
1417 | struct iw_point *dwrq, char *extra) | 1367 | struct iw_point *dwrq, char *extra) |
1418 | { | 1368 | { |
1419 | #define SCAN_ITEM_SIZE 128 | 1369 | #define SCAN_ITEM_SIZE 128 |
1420 | struct lbs_private *priv = dev->priv; | 1370 | struct lbs_private *priv = dev->priv; |
1421 | int err = 0; | 1371 | int err = 0; |
1422 | char *ev = extra; | 1372 | char *ev = extra; |
1423 | char *stop = ev + dwrq->length; | 1373 | char *stop = ev + dwrq->length; |
1424 | struct bss_descriptor * iter_bss; | 1374 | struct bss_descriptor *iter_bss; |
1425 | struct bss_descriptor * safe; | 1375 | struct bss_descriptor *safe; |
1426 | 1376 | ||
1427 | lbs_deb_enter(LBS_DEB_SCAN); | 1377 | lbs_deb_enter(LBS_DEB_SCAN); |
1428 | 1378 | ||
@@ -1431,14 +1381,13 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, | |||
1431 | return -EAGAIN; | 1381 | return -EAGAIN; |
1432 | 1382 | ||
1433 | /* Update RSSI if current BSS is a locally created ad-hoc BSS */ | 1383 | /* Update RSSI if current BSS is a locally created ad-hoc BSS */ |
1434 | if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) { | 1384 | if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) |
1435 | lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, | 1385 | lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, |
1436 | CMD_OPTION_WAITFORRSP, 0, NULL); | 1386 | CMD_OPTION_WAITFORRSP, 0, NULL); |
1437 | } | ||
1438 | 1387 | ||
1439 | mutex_lock(&priv->lock); | 1388 | mutex_lock(&priv->lock); |
1440 | list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) { | 1389 | list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) { |
1441 | char * next_ev; | 1390 | char *next_ev; |
1442 | unsigned long stale_time; | 1391 | unsigned long stale_time; |
1443 | 1392 | ||
1444 | if (stop - ev < SCAN_ITEM_SIZE) { | 1393 | if (stop - ev < SCAN_ITEM_SIZE) { |
@@ -1453,8 +1402,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, | |||
1453 | /* Prune old an old scan result */ | 1402 | /* Prune old an old scan result */ |
1454 | stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; | 1403 | stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; |
1455 | if (time_after(jiffies, stale_time)) { | 1404 | if (time_after(jiffies, stale_time)) { |
1456 | list_move_tail (&iter_bss->list, | 1405 | list_move_tail(&iter_bss->list, &priv->network_free_list); |
1457 | &priv->network_free_list); | ||
1458 | clear_bss_descriptor(iter_bss); | 1406 | clear_bss_descriptor(iter_bss); |
1459 | continue; | 1407 | continue; |
1460 | } | 1408 | } |
@@ -1485,44 +1433,6 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, | |||
1485 | 1433 | ||
1486 | 1434 | ||
1487 | /** | 1435 | /** |
1488 | * @brief Prepare a scan command to be sent to the firmware | ||
1489 | * | ||
1490 | * Called via lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, ...) | ||
1491 | * from cmd.c | ||
1492 | * | ||
1493 | * Sends a fixed length data part (specifying the BSS type and BSSID filters) | ||
1494 | * as well as a variable number/length of TLVs to the firmware. | ||
1495 | * | ||
1496 | * @param priv A pointer to struct lbs_private structure | ||
1497 | * @param cmd A pointer to cmd_ds_command structure to be sent to | ||
1498 | * firmware with the cmd_DS_801_11_SCAN structure | ||
1499 | * @param pdata_buf Void pointer cast of a lbs_scan_cmd_config struct used | ||
1500 | * to set the fields/TLVs for the command sent to firmware | ||
1501 | * | ||
1502 | * @return 0 or -1 | ||
1503 | */ | ||
1504 | int lbs_cmd_80211_scan(struct lbs_private *priv, | ||
1505 | struct cmd_ds_command *cmd, void *pdata_buf) | ||
1506 | { | ||
1507 | struct cmd_ds_802_11_scan *pscan = &cmd->params.scan; | ||
1508 | struct lbs_scan_cmd_config *pscancfg = pdata_buf; | ||
1509 | |||
1510 | lbs_deb_enter(LBS_DEB_SCAN); | ||
1511 | |||
1512 | /* Set fixed field variables in scan command */ | ||
1513 | pscan->bsstype = pscancfg->bsstype; | ||
1514 | memcpy(pscan->bssid, pscancfg->bssid, ETH_ALEN); | ||
1515 | memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen); | ||
1516 | |||
1517 | /* size is equal to the sizeof(fixed portions) + the TLV len + header */ | ||
1518 | cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN | ||
1519 | + pscancfg->tlvbufferlen + S_DS_GEN); | ||
1520 | |||
1521 | lbs_deb_leave(LBS_DEB_SCAN); | ||
1522 | return 0; | ||
1523 | } | ||
1524 | |||
1525 | /** | ||
1526 | * @brief This function handles the command response of scan | 1436 | * @brief This function handles the command response of scan |
1527 | * | 1437 | * |
1528 | * Called from handle_cmd_response() in cmdrespc. | 1438 | * Called from handle_cmd_response() in cmdrespc. |
@@ -1548,13 +1458,14 @@ int lbs_cmd_80211_scan(struct lbs_private *priv, | |||
1548 | * | 1458 | * |
1549 | * @return 0 or -1 | 1459 | * @return 0 or -1 |
1550 | */ | 1460 | */ |
1551 | int lbs_ret_80211_scan(struct lbs_private *priv, struct cmd_ds_command *resp) | 1461 | static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, |
1462 | struct cmd_header *resp) | ||
1552 | { | 1463 | { |
1553 | struct cmd_ds_802_11_scan_rsp *pscan; | 1464 | struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp; |
1554 | struct bss_descriptor * iter_bss; | 1465 | struct bss_descriptor *iter_bss; |
1555 | struct bss_descriptor * safe; | 1466 | struct bss_descriptor *safe; |
1556 | u8 *pbssinfo; | 1467 | uint8_t *bssinfo; |
1557 | u16 scanrespsize; | 1468 | uint16_t scanrespsize; |
1558 | int bytesleft; | 1469 | int bytesleft; |
1559 | int idx; | 1470 | int idx; |
1560 | int tlvbufsize; | 1471 | int tlvbufsize; |
@@ -1571,48 +1482,45 @@ int lbs_ret_80211_scan(struct lbs_private *priv, struct cmd_ds_command *resp) | |||
1571 | clear_bss_descriptor(iter_bss); | 1482 | clear_bss_descriptor(iter_bss); |
1572 | } | 1483 | } |
1573 | 1484 | ||
1574 | pscan = &resp->params.scanresp; | 1485 | if (scanresp->nr_sets > MAX_NETWORK_COUNT) { |
1575 | 1486 | lbs_deb_scan("SCAN_RESP: too many scan results (%d, max %d)\n", | |
1576 | if (pscan->nr_sets > MAX_NETWORK_COUNT) { | 1487 | scanresp->nr_sets, MAX_NETWORK_COUNT); |
1577 | lbs_deb_scan( | ||
1578 | "SCAN_RESP: too many scan results (%d, max %d)!!\n", | ||
1579 | pscan->nr_sets, MAX_NETWORK_COUNT); | ||
1580 | ret = -1; | 1488 | ret = -1; |
1581 | goto done; | 1489 | goto done; |
1582 | } | 1490 | } |
1583 | 1491 | ||
1584 | bytesleft = le16_to_cpu(pscan->bssdescriptsize); | 1492 | bytesleft = le16_to_cpu(scanresp->bssdescriptsize); |
1585 | lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft); | 1493 | lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft); |
1586 | 1494 | ||
1587 | scanrespsize = le16_to_cpu(resp->size); | 1495 | scanrespsize = le16_to_cpu(resp->size); |
1588 | lbs_deb_scan("SCAN_RESP: scan results %d\n", pscan->nr_sets); | 1496 | lbs_deb_scan("SCAN_RESP: scan results %d\n", scanresp->nr_sets); |
1589 | 1497 | ||
1590 | pbssinfo = pscan->bssdesc_and_tlvbuffer; | 1498 | bssinfo = scanresp->bssdesc_and_tlvbuffer; |
1591 | 1499 | ||
1592 | /* The size of the TLV buffer is equal to the entire command response | 1500 | /* The size of the TLV buffer is equal to the entire command response |
1593 | * size (scanrespsize) minus the fixed fields (sizeof()'s), the | 1501 | * size (scanrespsize) minus the fixed fields (sizeof()'s), the |
1594 | * BSS Descriptions (bssdescriptsize as bytesLef) and the command | 1502 | * BSS Descriptions (bssdescriptsize as bytesLef) and the command |
1595 | * response header (S_DS_GEN) | 1503 | * response header (S_DS_GEN) |
1596 | */ | 1504 | */ |
1597 | tlvbufsize = scanrespsize - (bytesleft + sizeof(pscan->bssdescriptsize) | 1505 | tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize) |
1598 | + sizeof(pscan->nr_sets) | 1506 | + sizeof(scanresp->nr_sets) |
1599 | + S_DS_GEN); | 1507 | + S_DS_GEN); |
1600 | 1508 | ||
1601 | /* | 1509 | /* |
1602 | * Process each scan response returned (pscan->nr_sets). Save | 1510 | * Process each scan response returned (scanresp->nr_sets). Save |
1603 | * the information in the newbssentry and then insert into the | 1511 | * the information in the newbssentry and then insert into the |
1604 | * driver scan table either as an update to an existing entry | 1512 | * driver scan table either as an update to an existing entry |
1605 | * or as an addition at the end of the table | 1513 | * or as an addition at the end of the table |
1606 | */ | 1514 | */ |
1607 | for (idx = 0; idx < pscan->nr_sets && bytesleft; idx++) { | 1515 | for (idx = 0; idx < scanresp->nr_sets && bytesleft; idx++) { |
1608 | struct bss_descriptor new; | 1516 | struct bss_descriptor new; |
1609 | struct bss_descriptor * found = NULL; | 1517 | struct bss_descriptor *found = NULL; |
1610 | struct bss_descriptor * oldest = NULL; | 1518 | struct bss_descriptor *oldest = NULL; |
1611 | DECLARE_MAC_BUF(mac); | 1519 | DECLARE_MAC_BUF(mac); |
1612 | 1520 | ||
1613 | /* Process the data fields and IEs returned for this BSS */ | 1521 | /* Process the data fields and IEs returned for this BSS */ |
1614 | memset(&new, 0, sizeof (struct bss_descriptor)); | 1522 | memset(&new, 0, sizeof (struct bss_descriptor)); |
1615 | if (lbs_process_bss(&new, &pbssinfo, &bytesleft) != 0) { | 1523 | if (lbs_process_bss(&new, &bssinfo, &bytesleft) != 0) { |
1616 | /* error parsing the scan response, skipped */ | 1524 | /* error parsing the scan response, skipped */ |
1617 | lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n"); | 1525 | lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n"); |
1618 | continue; | 1526 | continue; |
@@ -1647,8 +1555,7 @@ int lbs_ret_80211_scan(struct lbs_private *priv, struct cmd_ds_command *resp) | |||
1647 | continue; | 1555 | continue; |
1648 | } | 1556 | } |
1649 | 1557 | ||
1650 | lbs_deb_scan("SCAN_RESP: BSSID %s\n", | 1558 | lbs_deb_scan("SCAN_RESP: BSSID %s\n", print_mac(mac, new.bssid)); |
1651 | print_mac(mac, new.bssid)); | ||
1652 | 1559 | ||
1653 | /* Copy the locally created newbssentry to the scan table */ | 1560 | /* Copy the locally created newbssentry to the scan table */ |
1654 | memcpy(found, &new, offsetof(struct bss_descriptor, list)); | 1561 | memcpy(found, &new, offsetof(struct bss_descriptor, list)); |
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index 319f70dde350..10d1196acf78 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h | |||
@@ -17,57 +17,16 @@ | |||
17 | */ | 17 | */ |
18 | #define LBS_IOCTL_USER_SCAN_CHAN_MAX 50 | 18 | #define LBS_IOCTL_USER_SCAN_CHAN_MAX 50 |
19 | 19 | ||
20 | //! Infrastructure BSS scan type in lbs_scan_cmd_config | 20 | //! Infrastructure BSS scan type in cmd_ds_802_11_scan |
21 | #define LBS_SCAN_BSS_TYPE_BSS 1 | 21 | #define LBS_SCAN_BSS_TYPE_BSS 1 |
22 | 22 | ||
23 | //! Adhoc BSS scan type in lbs_scan_cmd_config | 23 | //! Adhoc BSS scan type in cmd_ds_802_11_scan |
24 | #define LBS_SCAN_BSS_TYPE_IBSS 2 | 24 | #define LBS_SCAN_BSS_TYPE_IBSS 2 |
25 | 25 | ||
26 | //! Adhoc or Infrastructure BSS scan type in lbs_scan_cmd_config, no filter | 26 | //! Adhoc or Infrastructure BSS scan type in cmd_ds_802_11_scan, no filter |
27 | #define LBS_SCAN_BSS_TYPE_ANY 3 | 27 | #define LBS_SCAN_BSS_TYPE_ANY 3 |
28 | 28 | ||
29 | /** | 29 | /** |
30 | * @brief Structure used internally in the wlan driver to configure a scan. | ||
31 | * | ||
32 | * Sent to the command processing module to configure the firmware | ||
33 | * scan command prepared by lbs_cmd_80211_scan. | ||
34 | * | ||
35 | * @sa lbs_scan_networks | ||
36 | * | ||
37 | */ | ||
38 | struct lbs_scan_cmd_config { | ||
39 | /** | ||
40 | * @brief BSS type to be sent in the firmware command | ||
41 | * | ||
42 | * Field can be used to restrict the types of networks returned in the | ||
43 | * scan. valid settings are: | ||
44 | * | ||
45 | * - LBS_SCAN_BSS_TYPE_BSS (infrastructure) | ||
46 | * - LBS_SCAN_BSS_TYPE_IBSS (adhoc) | ||
47 | * - LBS_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure) | ||
48 | */ | ||
49 | u8 bsstype; | ||
50 | |||
51 | /** | ||
52 | * @brief Specific BSSID used to filter scan results in the firmware | ||
53 | */ | ||
54 | u8 bssid[ETH_ALEN]; | ||
55 | |||
56 | /** | ||
57 | * @brief length of TLVs sent in command starting at tlvBuffer | ||
58 | */ | ||
59 | int tlvbufferlen; | ||
60 | |||
61 | /** | ||
62 | * @brief SSID TLV(s) and ChanList TLVs to be sent in the firmware command | ||
63 | * | ||
64 | * @sa TLV_TYPE_CHANLIST, mrvlietypes_chanlistparamset_t | ||
65 | * @sa TLV_TYPE_SSID, mrvlietypes_ssidparamset_t | ||
66 | */ | ||
67 | u8 tlvbuffer[1]; //!< SSID TLV(s) and ChanList TLVs are stored here | ||
68 | }; | ||
69 | |||
70 | /** | ||
71 | * @brief IOCTL channel sub-structure sent in lbs_ioctl_user_scan_cfg | 30 | * @brief IOCTL channel sub-structure sent in lbs_ioctl_user_scan_cfg |
72 | * | 31 | * |
73 | * Multiple instances of this structure are included in the IOCTL command | 32 | * Multiple instances of this structure are included in the IOCTL command |
@@ -179,13 +138,6 @@ int lbs_find_best_network_ssid(struct lbs_private *priv, u8 *out_ssid, | |||
179 | int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid, | 138 | int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid, |
180 | u8 ssid_len, u8 clear_ssid); | 139 | u8 ssid_len, u8 clear_ssid); |
181 | 140 | ||
182 | int lbs_cmd_80211_scan(struct lbs_private *priv, | ||
183 | struct cmd_ds_command *cmd, | ||
184 | void *pdata_buf); | ||
185 | |||
186 | int lbs_ret_80211_scan(struct lbs_private *priv, | ||
187 | struct cmd_ds_command *resp); | ||
188 | |||
189 | int lbs_scan_networks(struct lbs_private *priv, | 141 | int lbs_scan_networks(struct lbs_private *priv, |
190 | const struct lbs_ioctl_user_scan_cfg *puserscanin, | 142 | const struct lbs_ioctl_user_scan_cfg *puserscanin, |
191 | int full_scan); | 143 | int full_scan); |
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index f0d57958b34b..4031be420862 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h | |||
@@ -239,4 +239,17 @@ struct mrvlietypes_ledgpio { | |||
239 | struct led_pin ledpin[1]; | 239 | struct led_pin ledpin[1]; |
240 | } __attribute__ ((packed)); | 240 | } __attribute__ ((packed)); |
241 | 241 | ||
242 | struct led_bhv { | ||
243 | uint8_t firmwarestate; | ||
244 | uint8_t led; | ||
245 | uint8_t ledstate; | ||
246 | uint8_t ledarg; | ||
247 | } __attribute__ ((packed)); | ||
248 | |||
249 | |||
250 | struct mrvlietypes_ledbhv { | ||
251 | struct mrvlietypesheader header; | ||
252 | struct led_bhv ledbhv[1]; | ||
253 | } __attribute__ ((packed)); | ||
254 | |||
242 | #endif | 255 | #endif |
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index db96adf90ae2..0acb5c345734 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c | |||
@@ -809,6 +809,7 @@ static int hw_init_hmac(struct zd_chip *chip) | |||
809 | { CR_AFTER_PNP, 0x1 }, | 809 | { CR_AFTER_PNP, 0x1 }, |
810 | { CR_WEP_PROTECT, 0x114 }, | 810 | { CR_WEP_PROTECT, 0x114 }, |
811 | { CR_IFS_VALUE, IFS_VALUE_DEFAULT }, | 811 | { CR_IFS_VALUE, IFS_VALUE_DEFAULT }, |
812 | { CR_CAM_MODE, MODE_AP_WDS}, | ||
812 | }; | 813 | }; |
813 | 814 | ||
814 | ZD_ASSERT(mutex_is_locked(&chip->mutex)); | 815 | ZD_ASSERT(mutex_is_locked(&chip->mutex)); |
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index 5b6e3a3751ba..f8c061a9b6ec 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h | |||
@@ -489,6 +489,7 @@ enum { | |||
489 | 489 | ||
490 | #define CR_RX_OFFSET CTL_REG(0x065c) | 490 | #define CR_RX_OFFSET CTL_REG(0x065c) |
491 | 491 | ||
492 | #define CR_BCN_LENGTH CTL_REG(0x0664) | ||
492 | #define CR_PHY_DELAY CTL_REG(0x066C) | 493 | #define CR_PHY_DELAY CTL_REG(0x066C) |
493 | #define CR_BCN_FIFO CTL_REG(0x0670) | 494 | #define CR_BCN_FIFO CTL_REG(0x0670) |
494 | #define CR_SNIFFER_ON CTL_REG(0x0674) | 495 | #define CR_SNIFFER_ON CTL_REG(0x0674) |
@@ -545,6 +546,8 @@ enum { | |||
545 | #define RX_FILTER_CTRL (RX_FILTER_RTS | RX_FILTER_CTS | \ | 546 | #define RX_FILTER_CTRL (RX_FILTER_RTS | RX_FILTER_CTS | \ |
546 | RX_FILTER_CFEND | RX_FILTER_CFACK) | 547 | RX_FILTER_CFEND | RX_FILTER_CFACK) |
547 | 548 | ||
549 | #define BCN_MODE_IBSS 0x2000000 | ||
550 | |||
548 | /* Monitor mode sets filter to 0xfffff */ | 551 | /* Monitor mode sets filter to 0xfffff */ |
549 | 552 | ||
550 | #define CR_ACK_TIMEOUT_EXT CTL_REG(0x0690) | 553 | #define CR_ACK_TIMEOUT_EXT CTL_REG(0x0690) |
@@ -578,6 +581,11 @@ enum { | |||
578 | 581 | ||
579 | /* CAM: Continuous Access Mode (power management) */ | 582 | /* CAM: Continuous Access Mode (power management) */ |
580 | #define CR_CAM_MODE CTL_REG(0x0700) | 583 | #define CR_CAM_MODE CTL_REG(0x0700) |
584 | #define MODE_IBSS 0x0 | ||
585 | #define MODE_AP 0x1 | ||
586 | #define MODE_STA 0x2 | ||
587 | #define MODE_AP_WDS 0x3 | ||
588 | |||
581 | #define CR_CAM_ROLL_TB_LOW CTL_REG(0x0704) | 589 | #define CR_CAM_ROLL_TB_LOW CTL_REG(0x0704) |
582 | #define CR_CAM_ROLL_TB_HIGH CTL_REG(0x0708) | 590 | #define CR_CAM_ROLL_TB_HIGH CTL_REG(0x0708) |
583 | #define CR_CAM_ADDRESS CTL_REG(0x070C) | 591 | #define CR_CAM_ADDRESS CTL_REG(0x070C) |
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index f90f03f676de..69c45ca99051 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c | |||
@@ -475,6 +475,46 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, | |||
475 | /* FIXME: Management frame? */ | 475 | /* FIXME: Management frame? */ |
476 | } | 476 | } |
477 | 477 | ||
478 | void zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon) | ||
479 | { | ||
480 | struct zd_mac *mac = zd_hw_mac(hw); | ||
481 | u32 tmp, j = 0; | ||
482 | /* 4 more bytes for tail CRC */ | ||
483 | u32 full_len = beacon->len + 4; | ||
484 | zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 0); | ||
485 | zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp); | ||
486 | while (tmp & 0x2) { | ||
487 | zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp); | ||
488 | if ((++j % 100) == 0) { | ||
489 | printk(KERN_ERR "CR_BCN_FIFO_SEMAPHORE not ready\n"); | ||
490 | if (j >= 500) { | ||
491 | printk(KERN_ERR "Giving up beacon config.\n"); | ||
492 | return; | ||
493 | } | ||
494 | } | ||
495 | msleep(1); | ||
496 | } | ||
497 | |||
498 | zd_iowrite32(&mac->chip, CR_BCN_FIFO, full_len - 1); | ||
499 | if (zd_chip_is_zd1211b(&mac->chip)) | ||
500 | zd_iowrite32(&mac->chip, CR_BCN_LENGTH, full_len - 1); | ||
501 | |||
502 | for (j = 0 ; j < beacon->len; j++) | ||
503 | zd_iowrite32(&mac->chip, CR_BCN_FIFO, | ||
504 | *((u8 *)(beacon->data + j))); | ||
505 | |||
506 | for (j = 0; j < 4; j++) | ||
507 | zd_iowrite32(&mac->chip, CR_BCN_FIFO, 0x0); | ||
508 | |||
509 | zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 1); | ||
510 | /* 802.11b/g 2.4G CCK 1Mb | ||
511 | * 802.11a, not yet implemented, uses different values (see GPL vendor | ||
512 | * driver) | ||
513 | */ | ||
514 | zd_iowrite32(&mac->chip, CR_BCN_PLCP_CFG, 0x00000400 | | ||
515 | (full_len << 19)); | ||
516 | } | ||
517 | |||
478 | static int fill_ctrlset(struct zd_mac *mac, | 518 | static int fill_ctrlset(struct zd_mac *mac, |
479 | struct sk_buff *skb, | 519 | struct sk_buff *skb, |
480 | struct ieee80211_tx_control *control) | 520 | struct ieee80211_tx_control *control) |
@@ -709,6 +749,7 @@ static int zd_op_add_interface(struct ieee80211_hw *hw, | |||
709 | 749 | ||
710 | switch (conf->type) { | 750 | switch (conf->type) { |
711 | case IEEE80211_IF_TYPE_MNTR: | 751 | case IEEE80211_IF_TYPE_MNTR: |
752 | case IEEE80211_IF_TYPE_MESH_POINT: | ||
712 | case IEEE80211_IF_TYPE_STA: | 753 | case IEEE80211_IF_TYPE_STA: |
713 | mac->type = conf->type; | 754 | mac->type = conf->type; |
714 | break; | 755 | break; |
@@ -738,15 +779,43 @@ static int zd_op_config_interface(struct ieee80211_hw *hw, | |||
738 | struct ieee80211_if_conf *conf) | 779 | struct ieee80211_if_conf *conf) |
739 | { | 780 | { |
740 | struct zd_mac *mac = zd_hw_mac(hw); | 781 | struct zd_mac *mac = zd_hw_mac(hw); |
782 | int associated; | ||
783 | |||
784 | if (mac->type == IEEE80211_IF_TYPE_MESH_POINT) { | ||
785 | associated = true; | ||
786 | if (conf->beacon) { | ||
787 | zd_mac_config_beacon(hw, conf->beacon); | ||
788 | kfree_skb(conf->beacon); | ||
789 | zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS | | ||
790 | hw->conf.beacon_int); | ||
791 | } | ||
792 | } else | ||
793 | associated = is_valid_ether_addr(conf->bssid); | ||
741 | 794 | ||
742 | spin_lock_irq(&mac->lock); | 795 | spin_lock_irq(&mac->lock); |
743 | mac->associated = is_valid_ether_addr(conf->bssid); | 796 | mac->associated = associated; |
744 | spin_unlock_irq(&mac->lock); | 797 | spin_unlock_irq(&mac->lock); |
745 | 798 | ||
746 | /* TODO: do hardware bssid filtering */ | 799 | /* TODO: do hardware bssid filtering */ |
747 | return 0; | 800 | return 0; |
748 | } | 801 | } |
749 | 802 | ||
803 | void zd_process_intr(struct work_struct *work) | ||
804 | { | ||
805 | u16 int_status; | ||
806 | struct zd_mac *mac = container_of(work, struct zd_mac, process_intr); | ||
807 | |||
808 | int_status = le16_to_cpu(*(u16 *)(mac->intr_buffer+4)); | ||
809 | if (int_status & INT_CFG_NEXT_BCN) { | ||
810 | if (net_ratelimit()) | ||
811 | dev_dbg_f(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n"); | ||
812 | } else | ||
813 | dev_dbg_f(zd_mac_dev(mac), "Unsupported interrupt\n"); | ||
814 | |||
815 | zd_chip_enable_hwint(&mac->chip); | ||
816 | } | ||
817 | |||
818 | |||
750 | static void set_multicast_hash_handler(struct work_struct *work) | 819 | static void set_multicast_hash_handler(struct work_struct *work) |
751 | { | 820 | { |
752 | struct zd_mac *mac = | 821 | struct zd_mac *mac = |
@@ -912,7 +981,8 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) | |||
912 | 981 | ||
913 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band; | 982 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band; |
914 | 983 | ||
915 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS; | 984 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | |
985 | IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; | ||
916 | hw->max_rssi = 100; | 986 | hw->max_rssi = 100; |
917 | hw->max_signal = 100; | 987 | hw->max_signal = 100; |
918 | 988 | ||
@@ -926,6 +996,7 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) | |||
926 | INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler); | 996 | INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler); |
927 | INIT_WORK(&mac->set_rts_cts_work, set_rts_cts_work); | 997 | INIT_WORK(&mac->set_rts_cts_work, set_rts_cts_work); |
928 | INIT_WORK(&mac->set_rx_filter_work, set_rx_filter_handler); | 998 | INIT_WORK(&mac->set_rx_filter_work, set_rx_filter_handler); |
999 | INIT_WORK(&mac->process_intr, zd_process_intr); | ||
929 | 1000 | ||
930 | SET_IEEE80211_DEV(hw, &intf->dev); | 1001 | SET_IEEE80211_DEV(hw, &intf->dev); |
931 | return hw; | 1002 | return hw; |
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 67dea9739c8f..71170244d2c9 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h | |||
@@ -172,12 +172,15 @@ struct zd_tx_skb_control_block { | |||
172 | struct zd_mac { | 172 | struct zd_mac { |
173 | struct zd_chip chip; | 173 | struct zd_chip chip; |
174 | spinlock_t lock; | 174 | spinlock_t lock; |
175 | spinlock_t intr_lock; | ||
175 | struct ieee80211_hw *hw; | 176 | struct ieee80211_hw *hw; |
176 | struct housekeeping housekeeping; | 177 | struct housekeeping housekeeping; |
177 | struct work_struct set_multicast_hash_work; | 178 | struct work_struct set_multicast_hash_work; |
178 | struct work_struct set_rts_cts_work; | 179 | struct work_struct set_rts_cts_work; |
179 | struct work_struct set_rx_filter_work; | 180 | struct work_struct set_rx_filter_work; |
181 | struct work_struct process_intr; | ||
180 | struct zd_mc_hash multicast_hash; | 182 | struct zd_mc_hash multicast_hash; |
183 | u8 intr_buffer[USB_MAX_EP_INT_BUFFER]; | ||
181 | u8 regdomain; | 184 | u8 regdomain; |
182 | u8 default_regdomain; | 185 | u8 default_regdomain; |
183 | int type; | 186 | int type; |
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 7942b15acfe7..e34675c2f8fc 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c | |||
@@ -97,6 +97,7 @@ MODULE_DEVICE_TABLE(usb, usb_ids); | |||
97 | #define FW_ZD1211B_PREFIX "zd1211/zd1211b_" | 97 | #define FW_ZD1211B_PREFIX "zd1211/zd1211b_" |
98 | 98 | ||
99 | /* USB device initialization */ | 99 | /* USB device initialization */ |
100 | static void int_urb_complete(struct urb *urb); | ||
100 | 101 | ||
101 | static int request_fw_file( | 102 | static int request_fw_file( |
102 | const struct firmware **fw, const char *name, struct device *device) | 103 | const struct firmware **fw, const char *name, struct device *device) |
@@ -336,11 +337,18 @@ static inline void handle_regs_int(struct urb *urb) | |||
336 | struct zd_usb *usb = urb->context; | 337 | struct zd_usb *usb = urb->context; |
337 | struct zd_usb_interrupt *intr = &usb->intr; | 338 | struct zd_usb_interrupt *intr = &usb->intr; |
338 | int len; | 339 | int len; |
340 | u16 int_num; | ||
339 | 341 | ||
340 | ZD_ASSERT(in_interrupt()); | 342 | ZD_ASSERT(in_interrupt()); |
341 | spin_lock(&intr->lock); | 343 | spin_lock(&intr->lock); |
342 | 344 | ||
343 | if (intr->read_regs_enabled) { | 345 | int_num = le16_to_cpu(*(u16 *)(urb->transfer_buffer+2)); |
346 | if (int_num == CR_INTERRUPT) { | ||
347 | struct zd_mac *mac = zd_hw_mac(zd_usb_to_hw(urb->context)); | ||
348 | memcpy(&mac->intr_buffer, urb->transfer_buffer, | ||
349 | USB_MAX_EP_INT_BUFFER); | ||
350 | schedule_work(&mac->process_intr); | ||
351 | } else if (intr->read_regs_enabled) { | ||
344 | intr->read_regs.length = len = urb->actual_length; | 352 | intr->read_regs.length = len = urb->actual_length; |
345 | 353 | ||
346 | if (len > sizeof(intr->read_regs.buffer)) | 354 | if (len > sizeof(intr->read_regs.buffer)) |
@@ -351,7 +359,6 @@ static inline void handle_regs_int(struct urb *urb) | |||
351 | goto out; | 359 | goto out; |
352 | } | 360 | } |
353 | 361 | ||
354 | dev_dbg_f(urb_dev(urb), "regs interrupt ignored\n"); | ||
355 | out: | 362 | out: |
356 | spin_unlock(&intr->lock); | 363 | spin_unlock(&intr->lock); |
357 | } | 364 | } |
diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index adea792fb675..f69ef0ba2613 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig | |||
@@ -125,4 +125,13 @@ config SSB_DRIVER_EXTIF | |||
125 | 125 | ||
126 | If unsure, say N | 126 | If unsure, say N |
127 | 127 | ||
128 | config SSB_DRIVER_GIGE | ||
129 | bool "SSB Broadcom Gigabit Ethernet driver" | ||
130 | depends on SSB_PCIHOST_POSSIBLE && SSB_EMBEDDED && MIPS | ||
131 | help | ||
132 | Driver for the Sonics Silicon Backplane attached | ||
133 | Broadcom Gigabit Ethernet. | ||
134 | |||
135 | If unsure, say N | ||
136 | |||
128 | endmenu | 137 | endmenu |
diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile index de94c2eb7a37..910f35e32fc9 100644 --- a/drivers/ssb/Makefile +++ b/drivers/ssb/Makefile | |||
@@ -11,6 +11,7 @@ ssb-y += driver_chipcommon.o | |||
11 | ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o | 11 | ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o |
12 | ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o | 12 | ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o |
13 | ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o | 13 | ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o |
14 | ssb-$(CONFIG_SSB_DRIVER_GIGE) += driver_gige.o | ||
14 | 15 | ||
15 | # b43 pci-ssb-bridge driver | 16 | # b43 pci-ssb-bridge driver |
16 | # Not strictly a part of SSB, but kept here for convenience | 17 | # Not strictly a part of SSB, but kept here for convenience |
diff --git a/drivers/ssb/driver_gige.c b/drivers/ssb/driver_gige.c new file mode 100644 index 000000000000..172f90407b93 --- /dev/null +++ b/drivers/ssb/driver_gige.c | |||
@@ -0,0 +1,294 @@ | |||
1 | /* | ||
2 | * Sonics Silicon Backplane | ||
3 | * Broadcom Gigabit Ethernet core driver | ||
4 | * | ||
5 | * Copyright 2008, Broadcom Corporation | ||
6 | * Copyright 2008, Michael Buesch <mb@bu3sch.de> | ||
7 | * | ||
8 | * Licensed under the GNU/GPL. See COPYING for details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/ssb/ssb.h> | ||
12 | #include <linux/ssb/ssb_driver_gige.h> | ||
13 | #include <linux/pci.h> | ||
14 | #include <linux/pci_regs.h> | ||
15 | |||
16 | |||
17 | /* | ||
18 | MODULE_DESCRIPTION("SSB Broadcom Gigabit Ethernet driver"); | ||
19 | MODULE_AUTHOR("Michael Buesch"); | ||
20 | MODULE_LICENSE("GPL"); | ||
21 | */ | ||
22 | |||
23 | static const struct ssb_device_id ssb_gige_tbl[] = { | ||
24 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET_GBIT, SSB_ANY_REV), | ||
25 | SSB_DEVTABLE_END | ||
26 | }; | ||
27 | /* MODULE_DEVICE_TABLE(ssb, ssb_gige_tbl); */ | ||
28 | |||
29 | |||
30 | static inline u8 gige_read8(struct ssb_gige *dev, u16 offset) | ||
31 | { | ||
32 | return ssb_read8(dev->dev, offset); | ||
33 | } | ||
34 | |||
35 | static inline u16 gige_read16(struct ssb_gige *dev, u16 offset) | ||
36 | { | ||
37 | return ssb_read16(dev->dev, offset); | ||
38 | } | ||
39 | |||
40 | static inline u32 gige_read32(struct ssb_gige *dev, u16 offset) | ||
41 | { | ||
42 | return ssb_read32(dev->dev, offset); | ||
43 | } | ||
44 | |||
45 | static inline void gige_write8(struct ssb_gige *dev, | ||
46 | u16 offset, u8 value) | ||
47 | { | ||
48 | ssb_write8(dev->dev, offset, value); | ||
49 | } | ||
50 | |||
51 | static inline void gige_write16(struct ssb_gige *dev, | ||
52 | u16 offset, u16 value) | ||
53 | { | ||
54 | ssb_write16(dev->dev, offset, value); | ||
55 | } | ||
56 | |||
57 | static inline void gige_write32(struct ssb_gige *dev, | ||
58 | u16 offset, u32 value) | ||
59 | { | ||
60 | ssb_write32(dev->dev, offset, value); | ||
61 | } | ||
62 | |||
63 | static inline | ||
64 | u8 gige_pcicfg_read8(struct ssb_gige *dev, unsigned int offset) | ||
65 | { | ||
66 | BUG_ON(offset >= 256); | ||
67 | return gige_read8(dev, SSB_GIGE_PCICFG + offset); | ||
68 | } | ||
69 | |||
70 | static inline | ||
71 | u16 gige_pcicfg_read16(struct ssb_gige *dev, unsigned int offset) | ||
72 | { | ||
73 | BUG_ON(offset >= 256); | ||
74 | return gige_read16(dev, SSB_GIGE_PCICFG + offset); | ||
75 | } | ||
76 | |||
77 | static inline | ||
78 | u32 gige_pcicfg_read32(struct ssb_gige *dev, unsigned int offset) | ||
79 | { | ||
80 | BUG_ON(offset >= 256); | ||
81 | return gige_read32(dev, SSB_GIGE_PCICFG + offset); | ||
82 | } | ||
83 | |||
84 | static inline | ||
85 | void gige_pcicfg_write8(struct ssb_gige *dev, | ||
86 | unsigned int offset, u8 value) | ||
87 | { | ||
88 | BUG_ON(offset >= 256); | ||
89 | gige_write8(dev, SSB_GIGE_PCICFG + offset, value); | ||
90 | } | ||
91 | |||
92 | static inline | ||
93 | void gige_pcicfg_write16(struct ssb_gige *dev, | ||
94 | unsigned int offset, u16 value) | ||
95 | { | ||
96 | BUG_ON(offset >= 256); | ||
97 | gige_write16(dev, SSB_GIGE_PCICFG + offset, value); | ||
98 | } | ||
99 | |||
100 | static inline | ||
101 | void gige_pcicfg_write32(struct ssb_gige *dev, | ||
102 | unsigned int offset, u32 value) | ||
103 | { | ||
104 | BUG_ON(offset >= 256); | ||
105 | gige_write32(dev, SSB_GIGE_PCICFG + offset, value); | ||
106 | } | ||
107 | |||
108 | static int ssb_gige_pci_read_config(struct pci_bus *bus, unsigned int devfn, | ||
109 | int reg, int size, u32 *val) | ||
110 | { | ||
111 | struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops); | ||
112 | unsigned long flags; | ||
113 | |||
114 | if ((PCI_SLOT(devfn) > 0) || (PCI_FUNC(devfn) > 0)) | ||
115 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
116 | if (reg >= 256) | ||
117 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
118 | |||
119 | spin_lock_irqsave(&dev->lock, flags); | ||
120 | switch (size) { | ||
121 | case 1: | ||
122 | *val = gige_pcicfg_read8(dev, reg); | ||
123 | break; | ||
124 | case 2: | ||
125 | *val = gige_pcicfg_read16(dev, reg); | ||
126 | break; | ||
127 | case 4: | ||
128 | *val = gige_pcicfg_read32(dev, reg); | ||
129 | break; | ||
130 | default: | ||
131 | WARN_ON(1); | ||
132 | } | ||
133 | spin_unlock_irqrestore(&dev->lock, flags); | ||
134 | |||
135 | return PCIBIOS_SUCCESSFUL; | ||
136 | } | ||
137 | |||
138 | static int ssb_gige_pci_write_config(struct pci_bus *bus, unsigned int devfn, | ||
139 | int reg, int size, u32 val) | ||
140 | { | ||
141 | struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops); | ||
142 | unsigned long flags; | ||
143 | |||
144 | if ((PCI_SLOT(devfn) > 0) || (PCI_FUNC(devfn) > 0)) | ||
145 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
146 | if (reg >= 256) | ||
147 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
148 | |||
149 | spin_lock_irqsave(&dev->lock, flags); | ||
150 | switch (size) { | ||
151 | case 1: | ||
152 | gige_pcicfg_write8(dev, reg, val); | ||
153 | break; | ||
154 | case 2: | ||
155 | gige_pcicfg_write16(dev, reg, val); | ||
156 | break; | ||
157 | case 4: | ||
158 | gige_pcicfg_write32(dev, reg, val); | ||
159 | break; | ||
160 | default: | ||
161 | WARN_ON(1); | ||
162 | } | ||
163 | spin_unlock_irqrestore(&dev->lock, flags); | ||
164 | |||
165 | return PCIBIOS_SUCCESSFUL; | ||
166 | } | ||
167 | |||
168 | static int ssb_gige_probe(struct ssb_device *sdev, const struct ssb_device_id *id) | ||
169 | { | ||
170 | struct ssb_gige *dev; | ||
171 | u32 base, tmslow, tmshigh; | ||
172 | |||
173 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
174 | if (!dev) | ||
175 | return -ENOMEM; | ||
176 | dev->dev = sdev; | ||
177 | |||
178 | spin_lock_init(&dev->lock); | ||
179 | dev->pci_controller.pci_ops = &dev->pci_ops; | ||
180 | dev->pci_controller.io_resource = &dev->io_resource; | ||
181 | dev->pci_controller.mem_resource = &dev->mem_resource; | ||
182 | dev->pci_controller.io_map_base = 0x800; | ||
183 | dev->pci_ops.read = ssb_gige_pci_read_config; | ||
184 | dev->pci_ops.write = ssb_gige_pci_write_config; | ||
185 | |||
186 | dev->io_resource.name = SSB_GIGE_IO_RES_NAME; | ||
187 | dev->io_resource.start = 0x800; | ||
188 | dev->io_resource.end = 0x8FF; | ||
189 | dev->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED; | ||
190 | |||
191 | if (!ssb_device_is_enabled(sdev)) | ||
192 | ssb_device_enable(sdev, 0); | ||
193 | |||
194 | /* Setup BAR0. This is a 64k MMIO region. */ | ||
195 | base = ssb_admatch_base(ssb_read32(sdev, SSB_ADMATCH1)); | ||
196 | gige_pcicfg_write32(dev, PCI_BASE_ADDRESS_0, base); | ||
197 | gige_pcicfg_write32(dev, PCI_BASE_ADDRESS_1, 0); | ||
198 | |||
199 | dev->mem_resource.name = SSB_GIGE_MEM_RES_NAME; | ||
200 | dev->mem_resource.start = base; | ||
201 | dev->mem_resource.end = base + 0x10000 - 1; | ||
202 | dev->mem_resource.flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED; | ||
203 | |||
204 | /* Enable the memory region. */ | ||
205 | gige_pcicfg_write16(dev, PCI_COMMAND, | ||
206 | gige_pcicfg_read16(dev, PCI_COMMAND) | ||
207 | | PCI_COMMAND_MEMORY); | ||
208 | |||
209 | /* Write flushing is controlled by the Flush Status Control register. | ||
210 | * We want to flush every register write with a timeout and we want | ||
211 | * to disable the IRQ mask while flushing to avoid concurrency. | ||
212 | * Note that automatic write flushing does _not_ work from | ||
213 | * an IRQ handler. The driver must flush manually by reading a register. | ||
214 | */ | ||
215 | gige_write32(dev, SSB_GIGE_SHIM_FLUSHSTAT, 0x00000068); | ||
216 | |||
217 | /* Check if we have an RGMII or GMII PHY-bus. | ||
218 | * On RGMII do not bypass the DLLs */ | ||
219 | tmslow = ssb_read32(sdev, SSB_TMSLOW); | ||
220 | tmshigh = ssb_read32(sdev, SSB_TMSHIGH); | ||
221 | if (tmshigh & SSB_GIGE_TMSHIGH_RGMII) { | ||
222 | tmslow &= ~SSB_GIGE_TMSLOW_TXBYPASS; | ||
223 | tmslow &= ~SSB_GIGE_TMSLOW_RXBYPASS; | ||
224 | dev->has_rgmii = 1; | ||
225 | } else { | ||
226 | tmslow |= SSB_GIGE_TMSLOW_TXBYPASS; | ||
227 | tmslow |= SSB_GIGE_TMSLOW_RXBYPASS; | ||
228 | dev->has_rgmii = 0; | ||
229 | } | ||
230 | tmslow |= SSB_GIGE_TMSLOW_DLLEN; | ||
231 | ssb_write32(sdev, SSB_TMSLOW, tmslow); | ||
232 | |||
233 | ssb_set_drvdata(sdev, dev); | ||
234 | register_pci_controller(&dev->pci_controller); | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | bool pdev_is_ssb_gige_core(struct pci_dev *pdev) | ||
240 | { | ||
241 | if (!pdev->resource[0].name) | ||
242 | return 0; | ||
243 | return (strcmp(pdev->resource[0].name, SSB_GIGE_MEM_RES_NAME) == 0); | ||
244 | } | ||
245 | EXPORT_SYMBOL(pdev_is_ssb_gige_core); | ||
246 | |||
247 | int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, | ||
248 | struct pci_dev *pdev) | ||
249 | { | ||
250 | struct ssb_gige *dev = ssb_get_drvdata(sdev); | ||
251 | struct resource *res; | ||
252 | |||
253 | if (pdev->bus->ops != &dev->pci_ops) { | ||
254 | /* The PCI device is not on this SSB GigE bridge device. */ | ||
255 | return -ENODEV; | ||
256 | } | ||
257 | |||
258 | /* Fixup the PCI resources. */ | ||
259 | res = &(pdev->resource[0]); | ||
260 | res->flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED; | ||
261 | res->name = dev->mem_resource.name; | ||
262 | res->start = dev->mem_resource.start; | ||
263 | res->end = dev->mem_resource.end; | ||
264 | |||
265 | /* Fixup interrupt lines. */ | ||
266 | pdev->irq = ssb_mips_irq(sdev) + 2; | ||
267 | pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, pdev->irq); | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | int ssb_gige_map_irq(struct ssb_device *sdev, | ||
273 | const struct pci_dev *pdev) | ||
274 | { | ||
275 | struct ssb_gige *dev = ssb_get_drvdata(sdev); | ||
276 | |||
277 | if (pdev->bus->ops != &dev->pci_ops) { | ||
278 | /* The PCI device is not on this SSB GigE bridge device. */ | ||
279 | return -ENODEV; | ||
280 | } | ||
281 | |||
282 | return ssb_mips_irq(sdev) + 2; | ||
283 | } | ||
284 | |||
285 | static struct ssb_driver ssb_gige_driver = { | ||
286 | .name = "BCM-GigE", | ||
287 | .id_table = ssb_gige_tbl, | ||
288 | .probe = ssb_gige_probe, | ||
289 | }; | ||
290 | |||
291 | int ssb_gige_init(void) | ||
292 | { | ||
293 | return ssb_driver_register(&ssb_gige_driver); | ||
294 | } | ||
diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c index 3d3dd32bf3ab..e3fad3123ecb 100644 --- a/drivers/ssb/driver_mipscore.c +++ b/drivers/ssb/driver_mipscore.c | |||
@@ -209,6 +209,7 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) | |||
209 | /* fallthrough */ | 209 | /* fallthrough */ |
210 | case SSB_DEV_PCI: | 210 | case SSB_DEV_PCI: |
211 | case SSB_DEV_ETHERNET: | 211 | case SSB_DEV_ETHERNET: |
212 | case SSB_DEV_ETHERNET_GBIT: | ||
212 | case SSB_DEV_80211: | 213 | case SSB_DEV_80211: |
213 | case SSB_DEV_USB20_HOST: | 214 | case SSB_DEV_USB20_HOST: |
214 | /* These devices get their own IRQ line if available, the rest goes on IRQ0 */ | 215 | /* These devices get their own IRQ line if available, the rest goes on IRQ0 */ |
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 74b9a8aea52b..33a7d5620474 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c | |||
@@ -60,77 +60,6 @@ static DEFINE_SPINLOCK(cfgspace_lock); | |||
60 | /* Core to access the external PCI config space. Can only have one. */ | 60 | /* Core to access the external PCI config space. Can only have one. */ |
61 | static struct ssb_pcicore *extpci_core; | 61 | static struct ssb_pcicore *extpci_core; |
62 | 62 | ||
63 | static u32 ssb_pcicore_pcibus_iobase = 0x100; | ||
64 | static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA; | ||
65 | |||
66 | int pcibios_plat_dev_init(struct pci_dev *d) | ||
67 | { | ||
68 | struct resource *res; | ||
69 | int pos, size; | ||
70 | u32 *base; | ||
71 | |||
72 | ssb_printk(KERN_INFO "PCI: Fixing up device %s\n", | ||
73 | pci_name(d)); | ||
74 | |||
75 | /* Fix up resource bases */ | ||
76 | for (pos = 0; pos < 6; pos++) { | ||
77 | res = &d->resource[pos]; | ||
78 | if (res->flags & IORESOURCE_IO) | ||
79 | base = &ssb_pcicore_pcibus_iobase; | ||
80 | else | ||
81 | base = &ssb_pcicore_pcibus_membase; | ||
82 | res->flags |= IORESOURCE_PCI_FIXED; | ||
83 | if (res->end) { | ||
84 | size = res->end - res->start + 1; | ||
85 | if (*base & (size - 1)) | ||
86 | *base = (*base + size) & ~(size - 1); | ||
87 | res->start = *base; | ||
88 | res->end = res->start + size - 1; | ||
89 | *base += size; | ||
90 | pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start); | ||
91 | } | ||
92 | /* Fix up PCI bridge BAR0 only */ | ||
93 | if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0) | ||
94 | break; | ||
95 | } | ||
96 | /* Fix up interrupt lines */ | ||
97 | d->irq = ssb_mips_irq(extpci_core->dev) + 2; | ||
98 | pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq); | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static void __init ssb_fixup_pcibridge(struct pci_dev *dev) | ||
104 | { | ||
105 | u8 lat; | ||
106 | |||
107 | if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0) | ||
108 | return; | ||
109 | |||
110 | ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev)); | ||
111 | |||
112 | /* Enable PCI bridge bus mastering and memory space */ | ||
113 | pci_set_master(dev); | ||
114 | if (pcibios_enable_device(dev, ~0) < 0) { | ||
115 | ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n"); | ||
116 | return; | ||
117 | } | ||
118 | |||
119 | /* Enable PCI bridge BAR1 prefetch and burst */ | ||
120 | pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); | ||
121 | |||
122 | /* Make sure our latency is high enough to handle the devices behind us */ | ||
123 | lat = 168; | ||
124 | ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n", | ||
125 | pci_name(dev), lat); | ||
126 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); | ||
127 | } | ||
128 | DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge); | ||
129 | |||
130 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
131 | { | ||
132 | return ssb_mips_irq(extpci_core->dev) + 2; | ||
133 | } | ||
134 | 63 | ||
135 | static u32 get_cfgspace_addr(struct ssb_pcicore *pc, | 64 | static u32 get_cfgspace_addr(struct ssb_pcicore *pc, |
136 | unsigned int bus, unsigned int dev, | 65 | unsigned int bus, unsigned int dev, |
@@ -320,6 +249,95 @@ static struct pci_controller ssb_pcicore_controller = { | |||
320 | .mem_offset = 0x24000000, | 249 | .mem_offset = 0x24000000, |
321 | }; | 250 | }; |
322 | 251 | ||
252 | static u32 ssb_pcicore_pcibus_iobase = 0x100; | ||
253 | static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA; | ||
254 | |||
255 | /* This function is called when doing a pci_enable_device(). | ||
256 | * We must first check if the device is a device on the PCI-core bridge. */ | ||
257 | int ssb_pcicore_plat_dev_init(struct pci_dev *d) | ||
258 | { | ||
259 | struct resource *res; | ||
260 | int pos, size; | ||
261 | u32 *base; | ||
262 | |||
263 | if (d->bus->ops != &ssb_pcicore_pciops) { | ||
264 | /* This is not a device on the PCI-core bridge. */ | ||
265 | return -ENODEV; | ||
266 | } | ||
267 | |||
268 | ssb_printk(KERN_INFO "PCI: Fixing up device %s\n", | ||
269 | pci_name(d)); | ||
270 | |||
271 | /* Fix up resource bases */ | ||
272 | for (pos = 0; pos < 6; pos++) { | ||
273 | res = &d->resource[pos]; | ||
274 | if (res->flags & IORESOURCE_IO) | ||
275 | base = &ssb_pcicore_pcibus_iobase; | ||
276 | else | ||
277 | base = &ssb_pcicore_pcibus_membase; | ||
278 | res->flags |= IORESOURCE_PCI_FIXED; | ||
279 | if (res->end) { | ||
280 | size = res->end - res->start + 1; | ||
281 | if (*base & (size - 1)) | ||
282 | *base = (*base + size) & ~(size - 1); | ||
283 | res->start = *base; | ||
284 | res->end = res->start + size - 1; | ||
285 | *base += size; | ||
286 | pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start); | ||
287 | } | ||
288 | /* Fix up PCI bridge BAR0 only */ | ||
289 | if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0) | ||
290 | break; | ||
291 | } | ||
292 | /* Fix up interrupt lines */ | ||
293 | d->irq = ssb_mips_irq(extpci_core->dev) + 2; | ||
294 | pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq); | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | /* Early PCI fixup for a device on the PCI-core bridge. */ | ||
300 | static void ssb_pcicore_fixup_pcibridge(struct pci_dev *dev) | ||
301 | { | ||
302 | u8 lat; | ||
303 | |||
304 | if (dev->bus->ops != &ssb_pcicore_pciops) { | ||
305 | /* This is not a device on the PCI-core bridge. */ | ||
306 | return; | ||
307 | } | ||
308 | if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0) | ||
309 | return; | ||
310 | |||
311 | ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev)); | ||
312 | |||
313 | /* Enable PCI bridge bus mastering and memory space */ | ||
314 | pci_set_master(dev); | ||
315 | if (pcibios_enable_device(dev, ~0) < 0) { | ||
316 | ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n"); | ||
317 | return; | ||
318 | } | ||
319 | |||
320 | /* Enable PCI bridge BAR1 prefetch and burst */ | ||
321 | pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); | ||
322 | |||
323 | /* Make sure our latency is high enough to handle the devices behind us */ | ||
324 | lat = 168; | ||
325 | ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n", | ||
326 | pci_name(dev), lat); | ||
327 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); | ||
328 | } | ||
329 | DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_pcicore_fixup_pcibridge); | ||
330 | |||
331 | /* PCI device IRQ mapping. */ | ||
332 | int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
333 | { | ||
334 | if (dev->bus->ops != &ssb_pcicore_pciops) { | ||
335 | /* This is not a device on the PCI-core bridge. */ | ||
336 | return -ENODEV; | ||
337 | } | ||
338 | return ssb_mips_irq(extpci_core->dev) + 2; | ||
339 | } | ||
340 | |||
323 | static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) | 341 | static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) |
324 | { | 342 | { |
325 | u32 val; | 343 | u32 val; |
diff --git a/drivers/ssb/embedded.c b/drivers/ssb/embedded.c index d3ade821555c..7dc3a6b41397 100644 --- a/drivers/ssb/embedded.c +++ b/drivers/ssb/embedded.c | |||
@@ -10,6 +10,9 @@ | |||
10 | 10 | ||
11 | #include <linux/ssb/ssb.h> | 11 | #include <linux/ssb/ssb.h> |
12 | #include <linux/ssb/ssb_embedded.h> | 12 | #include <linux/ssb/ssb_embedded.h> |
13 | #include <linux/ssb/ssb_driver_pci.h> | ||
14 | #include <linux/ssb/ssb_driver_gige.h> | ||
15 | #include <linux/pci.h> | ||
13 | 16 | ||
14 | #include "ssb_private.h" | 17 | #include "ssb_private.h" |
15 | 18 | ||
@@ -130,3 +133,90 @@ u32 ssb_gpio_polarity(struct ssb_bus *bus, u32 mask, u32 value) | |||
130 | return res; | 133 | return res; |
131 | } | 134 | } |
132 | EXPORT_SYMBOL(ssb_gpio_polarity); | 135 | EXPORT_SYMBOL(ssb_gpio_polarity); |
136 | |||
137 | #ifdef CONFIG_SSB_DRIVER_GIGE | ||
138 | static int gige_pci_init_callback(struct ssb_bus *bus, unsigned long data) | ||
139 | { | ||
140 | struct pci_dev *pdev = (struct pci_dev *)data; | ||
141 | struct ssb_device *dev; | ||
142 | unsigned int i; | ||
143 | int res; | ||
144 | |||
145 | for (i = 0; i < bus->nr_devices; i++) { | ||
146 | dev = &(bus->devices[i]); | ||
147 | if (dev->id.coreid != SSB_DEV_ETHERNET_GBIT) | ||
148 | continue; | ||
149 | if (!dev->dev || | ||
150 | !dev->dev->driver || | ||
151 | !device_is_registered(dev->dev)) | ||
152 | continue; | ||
153 | res = ssb_gige_pcibios_plat_dev_init(dev, pdev); | ||
154 | if (res >= 0) | ||
155 | return res; | ||
156 | } | ||
157 | |||
158 | return -ENODEV; | ||
159 | } | ||
160 | #endif /* CONFIG_SSB_DRIVER_GIGE */ | ||
161 | |||
162 | int ssb_pcibios_plat_dev_init(struct pci_dev *dev) | ||
163 | { | ||
164 | int err; | ||
165 | |||
166 | err = ssb_pcicore_plat_dev_init(dev); | ||
167 | if (!err) | ||
168 | return 0; | ||
169 | #ifdef CONFIG_SSB_DRIVER_GIGE | ||
170 | err = ssb_for_each_bus_call((unsigned long)dev, gige_pci_init_callback); | ||
171 | if (err >= 0) | ||
172 | return err; | ||
173 | #endif | ||
174 | /* This is not a PCI device on any SSB device. */ | ||
175 | |||
176 | return -ENODEV; | ||
177 | } | ||
178 | |||
179 | #ifdef CONFIG_SSB_DRIVER_GIGE | ||
180 | static int gige_map_irq_callback(struct ssb_bus *bus, unsigned long data) | ||
181 | { | ||
182 | const struct pci_dev *pdev = (const struct pci_dev *)data; | ||
183 | struct ssb_device *dev; | ||
184 | unsigned int i; | ||
185 | int res; | ||
186 | |||
187 | for (i = 0; i < bus->nr_devices; i++) { | ||
188 | dev = &(bus->devices[i]); | ||
189 | if (dev->id.coreid != SSB_DEV_ETHERNET_GBIT) | ||
190 | continue; | ||
191 | if (!dev->dev || | ||
192 | !dev->dev->driver || | ||
193 | !device_is_registered(dev->dev)) | ||
194 | continue; | ||
195 | res = ssb_gige_map_irq(dev, pdev); | ||
196 | if (res >= 0) | ||
197 | return res; | ||
198 | } | ||
199 | |||
200 | return -ENODEV; | ||
201 | } | ||
202 | #endif /* CONFIG_SSB_DRIVER_GIGE */ | ||
203 | |||
204 | int ssb_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
205 | { | ||
206 | int res; | ||
207 | |||
208 | /* Check if this PCI device is a device on a SSB bus or device | ||
209 | * and return the IRQ number for it. */ | ||
210 | |||
211 | res = ssb_pcicore_pcibios_map_irq(dev, slot, pin); | ||
212 | if (res >= 0) | ||
213 | return res; | ||
214 | #ifdef CONFIG_SSB_DRIVER_GIGE | ||
215 | res = ssb_for_each_bus_call((unsigned long)dev, gige_map_irq_callback); | ||
216 | if (res >= 0) | ||
217 | return res; | ||
218 | #endif | ||
219 | /* This is not a PCI device on any SSB device. */ | ||
220 | |||
221 | return -ENODEV; | ||
222 | } | ||
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 8db40c4b86e9..49d7bbb9bea7 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | #include <linux/ssb/ssb.h> | 15 | #include <linux/ssb/ssb.h> |
16 | #include <linux/ssb/ssb_regs.h> | 16 | #include <linux/ssb/ssb_regs.h> |
17 | #include <linux/ssb/ssb_driver_gige.h> | ||
17 | #include <linux/dma-mapping.h> | 18 | #include <linux/dma-mapping.h> |
18 | #include <linux/pci.h> | 19 | #include <linux/pci.h> |
19 | 20 | ||
@@ -68,6 +69,25 @@ found: | |||
68 | } | 69 | } |
69 | #endif /* CONFIG_SSB_PCIHOST */ | 70 | #endif /* CONFIG_SSB_PCIHOST */ |
70 | 71 | ||
72 | int ssb_for_each_bus_call(unsigned long data, | ||
73 | int (*func)(struct ssb_bus *bus, unsigned long data)) | ||
74 | { | ||
75 | struct ssb_bus *bus; | ||
76 | int res; | ||
77 | |||
78 | ssb_buses_lock(); | ||
79 | list_for_each_entry(bus, &buses, list) { | ||
80 | res = func(bus, data); | ||
81 | if (res >= 0) { | ||
82 | ssb_buses_unlock(); | ||
83 | return res; | ||
84 | } | ||
85 | } | ||
86 | ssb_buses_unlock(); | ||
87 | |||
88 | return -ENODEV; | ||
89 | } | ||
90 | |||
71 | static struct ssb_device *ssb_device_get(struct ssb_device *dev) | 91 | static struct ssb_device *ssb_device_get(struct ssb_device *dev) |
72 | { | 92 | { |
73 | if (dev) | 93 | if (dev) |
@@ -1171,7 +1191,14 @@ static int __init ssb_modinit(void) | |||
1171 | err = b43_pci_ssb_bridge_init(); | 1191 | err = b43_pci_ssb_bridge_init(); |
1172 | if (err) { | 1192 | if (err) { |
1173 | ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge " | 1193 | ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge " |
1174 | "initialization failed"); | 1194 | "initialization failed\n"); |
1195 | /* don't fail SSB init because of this */ | ||
1196 | err = 0; | ||
1197 | } | ||
1198 | err = ssb_gige_init(); | ||
1199 | if (err) { | ||
1200 | ssb_printk(KERN_ERR "SSB Broadcom Gigabit Ethernet " | ||
1201 | "driver initialization failed\n"); | ||
1175 | /* don't fail SSB init because of this */ | 1202 | /* don't fail SSB init because of this */ |
1176 | err = 0; | 1203 | err = 0; |
1177 | } | 1204 | } |
@@ -1185,6 +1212,7 @@ fs_initcall(ssb_modinit); | |||
1185 | 1212 | ||
1186 | static void __exit ssb_modexit(void) | 1213 | static void __exit ssb_modexit(void) |
1187 | { | 1214 | { |
1215 | ssb_gige_exit(); | ||
1188 | b43_pci_ssb_bridge_exit(); | 1216 | b43_pci_ssb_bridge_exit(); |
1189 | bus_unregister(&ssb_bustype); | 1217 | bus_unregister(&ssb_bustype); |
1190 | } | 1218 | } |
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 21eca2b5118b..d03b20983b1e 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h | |||
@@ -118,6 +118,8 @@ extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m); | |||
118 | extern int ssb_devices_freeze(struct ssb_bus *bus); | 118 | extern int ssb_devices_freeze(struct ssb_bus *bus); |
119 | extern int ssb_devices_thaw(struct ssb_bus *bus); | 119 | extern int ssb_devices_thaw(struct ssb_bus *bus); |
120 | extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev); | 120 | extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev); |
121 | int ssb_for_each_bus_call(unsigned long data, | ||
122 | int (*func)(struct ssb_bus *bus, unsigned long data)); | ||
121 | 123 | ||
122 | /* b43_pci_bridge.c */ | 124 | /* b43_pci_bridge.c */ |
123 | #ifdef CONFIG_SSB_B43_PCI_BRIDGE | 125 | #ifdef CONFIG_SSB_B43_PCI_BRIDGE |
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index f577c8f1c66d..f27d11ab418b 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -97,6 +97,7 @@ | |||
97 | #define IEEE80211_MAX_FRAME_LEN 2352 | 97 | #define IEEE80211_MAX_FRAME_LEN 2352 |
98 | 98 | ||
99 | #define IEEE80211_MAX_SSID_LEN 32 | 99 | #define IEEE80211_MAX_SSID_LEN 32 |
100 | #define IEEE80211_MAX_MESH_ID_LEN 32 | ||
100 | 101 | ||
101 | struct ieee80211_hdr { | 102 | struct ieee80211_hdr { |
102 | __le16 frame_control; | 103 | __le16 frame_control; |
@@ -109,6 +110,16 @@ struct ieee80211_hdr { | |||
109 | } __attribute__ ((packed)); | 110 | } __attribute__ ((packed)); |
110 | 111 | ||
111 | 112 | ||
113 | struct ieee80211s_hdr { | ||
114 | u8 flags; | ||
115 | u8 ttl; | ||
116 | u8 seqnum[3]; | ||
117 | u8 eaddr1[6]; | ||
118 | u8 eaddr2[6]; | ||
119 | u8 eaddr3[6]; | ||
120 | } __attribute__ ((packed)); | ||
121 | |||
122 | |||
112 | struct ieee80211_mgmt { | 123 | struct ieee80211_mgmt { |
113 | __le16 frame_control; | 124 | __le16 frame_control; |
114 | __le16 duration; | 125 | __le16 duration; |
@@ -206,6 +217,23 @@ struct ieee80211_mgmt { | |||
206 | __le16 params; | 217 | __le16 params; |
207 | __le16 reason_code; | 218 | __le16 reason_code; |
208 | } __attribute__((packed)) delba; | 219 | } __attribute__((packed)) delba; |
220 | struct{ | ||
221 | u8 action_code; | ||
222 | /* capab_info for open and confirm, | ||
223 | * reason for close | ||
224 | */ | ||
225 | __le16 aux; | ||
226 | /* Followed in plink_confirm by status | ||
227 | * code, AID and supported rates, | ||
228 | * and directly by supported rates in | ||
229 | * plink_open and plink_close | ||
230 | */ | ||
231 | u8 variable[0]; | ||
232 | } __attribute__((packed)) plink_action; | ||
233 | struct{ | ||
234 | u8 action_code; | ||
235 | u8 variable[0]; | ||
236 | } __attribute__((packed)) mesh_action; | ||
209 | } u; | 237 | } u; |
210 | } __attribute__ ((packed)) action; | 238 | } __attribute__ ((packed)) action; |
211 | } u; | 239 | } u; |
@@ -437,6 +465,13 @@ enum ieee80211_eid { | |||
437 | WLAN_EID_TS_DELAY = 43, | 465 | WLAN_EID_TS_DELAY = 43, |
438 | WLAN_EID_TCLAS_PROCESSING = 44, | 466 | WLAN_EID_TCLAS_PROCESSING = 44, |
439 | WLAN_EID_QOS_CAPA = 46, | 467 | WLAN_EID_QOS_CAPA = 46, |
468 | /* 802.11s */ | ||
469 | WLAN_EID_MESH_CONFIG = 36, /* Pending IEEE 802.11 ANA approval */ | ||
470 | WLAN_EID_MESH_ID = 37, /* Pending IEEE 802.11 ANA approval */ | ||
471 | WLAN_EID_PEER_LINK = 40, /* Pending IEEE 802.11 ANA approval */ | ||
472 | WLAN_EID_PREQ = 53, /* Pending IEEE 802.11 ANA approval */ | ||
473 | WLAN_EID_PREP = 54, /* Pending IEEE 802.11 ANA approval */ | ||
474 | WLAN_EID_PERR = 55, /* Pending IEEE 802.11 ANA approval */ | ||
440 | /* 802.11h */ | 475 | /* 802.11h */ |
441 | WLAN_EID_PWR_CONSTRAINT = 32, | 476 | WLAN_EID_PWR_CONSTRAINT = 32, |
442 | WLAN_EID_PWR_CAPABILITY = 33, | 477 | WLAN_EID_PWR_CAPABILITY = 33, |
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index a9f0b93324a2..ea6517e58b04 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -78,6 +78,18 @@ | |||
78 | * or, if no MAC address given, all stations, on the interface identified | 78 | * or, if no MAC address given, all stations, on the interface identified |
79 | * by %NL80211_ATTR_IFINDEX. | 79 | * by %NL80211_ATTR_IFINDEX. |
80 | * | 80 | * |
81 | * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to | ||
82 | * destination %NL80211_ATTR_MAC on the interface identified by | ||
83 | * %NL80211_ATTR_IFINDEX. | ||
84 | * @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to | ||
85 | * destination %NL80211_ATTR_MAC on the interface identified by | ||
86 | * %NL80211_ATTR_IFINDEX. | ||
87 | * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the | ||
88 | * the interface identified by %NL80211_ATTR_IFINDEX. | ||
89 | * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC | ||
90 | * or, if no MAC address given, all mesh paths, on the interface identified | ||
91 | * by %NL80211_ATTR_IFINDEX. | ||
92 | * | ||
81 | * @NL80211_CMD_MAX: highest used command number | 93 | * @NL80211_CMD_MAX: highest used command number |
82 | * @__NL80211_CMD_AFTER_LAST: internal use | 94 | * @__NL80211_CMD_AFTER_LAST: internal use |
83 | */ | 95 | */ |
@@ -112,6 +124,11 @@ enum nl80211_commands { | |||
112 | 124 | ||
113 | /* add commands here */ | 125 | /* add commands here */ |
114 | 126 | ||
127 | NL80211_CMD_GET_MPATH, | ||
128 | NL80211_CMD_SET_MPATH, | ||
129 | NL80211_CMD_NEW_MPATH, | ||
130 | NL80211_CMD_DEL_MPATH, | ||
131 | |||
115 | /* used to define NL80211_CMD_MAX below */ | 132 | /* used to define NL80211_CMD_MAX below */ |
116 | __NL80211_CMD_AFTER_LAST, | 133 | __NL80211_CMD_AFTER_LAST, |
117 | NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1 | 134 | NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1 |
@@ -157,13 +174,21 @@ enum nl80211_commands { | |||
157 | * restriction (at most %NL80211_MAX_SUPP_RATES). | 174 | * restriction (at most %NL80211_MAX_SUPP_RATES). |
158 | * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station | 175 | * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station |
159 | * to, or the AP interface the station was originally added to to. | 176 | * to, or the AP interface the station was originally added to to. |
160 | * @NL80211_ATTR_STA_STATS: statistics for a station, part of station info | 177 | * @NL80211_ATTR_STA_INFO: information about a station, part of station info |
161 | * given for %NL80211_CMD_GET_STATION, nested attribute containing | 178 | * given for %NL80211_CMD_GET_STATION, nested attribute containing |
162 | * info as possible, see &enum nl80211_sta_stats. | 179 | * info as possible, see &enum nl80211_sta_info. |
163 | * | 180 | * |
164 | * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, | 181 | * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, |
165 | * consisting of a nested array. | 182 | * consisting of a nested array. |
166 | * | 183 | * |
184 | * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes). | ||
185 | * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link. | ||
186 | * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path. | ||
187 | * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path | ||
188 | * info given for %NL80211_CMD_GET_MPATH, nested attribute described at | ||
189 | * &enum nl80211_mpath_info. | ||
190 | * | ||
191 | * | ||
167 | * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of | 192 | * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of |
168 | * &enum nl80211_mntr_flags. | 193 | * &enum nl80211_mntr_flags. |
169 | * | 194 | * |
@@ -199,7 +224,7 @@ enum nl80211_attrs { | |||
199 | NL80211_ATTR_STA_LISTEN_INTERVAL, | 224 | NL80211_ATTR_STA_LISTEN_INTERVAL, |
200 | NL80211_ATTR_STA_SUPPORTED_RATES, | 225 | NL80211_ATTR_STA_SUPPORTED_RATES, |
201 | NL80211_ATTR_STA_VLAN, | 226 | NL80211_ATTR_STA_VLAN, |
202 | NL80211_ATTR_STA_STATS, | 227 | NL80211_ATTR_STA_INFO, |
203 | 228 | ||
204 | NL80211_ATTR_WIPHY_BANDS, | 229 | NL80211_ATTR_WIPHY_BANDS, |
205 | 230 | ||
@@ -207,6 +232,11 @@ enum nl80211_attrs { | |||
207 | 232 | ||
208 | /* add attributes here, update the policy in nl80211.c */ | 233 | /* add attributes here, update the policy in nl80211.c */ |
209 | 234 | ||
235 | NL80211_ATTR_MESH_ID, | ||
236 | NL80211_ATTR_STA_PLINK_ACTION, | ||
237 | NL80211_ATTR_MPATH_NEXT_HOP, | ||
238 | NL80211_ATTR_MPATH_INFO, | ||
239 | |||
210 | __NL80211_ATTR_AFTER_LAST, | 240 | __NL80211_ATTR_AFTER_LAST, |
211 | NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 | 241 | NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 |
212 | }; | 242 | }; |
@@ -223,6 +253,7 @@ enum nl80211_attrs { | |||
223 | * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points | 253 | * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points |
224 | * @NL80211_IFTYPE_WDS: wireless distribution interface | 254 | * @NL80211_IFTYPE_WDS: wireless distribution interface |
225 | * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames | 255 | * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames |
256 | * @NL80211_IFTYPE_MESH_POINT: mesh point | ||
226 | * @NL80211_IFTYPE_MAX: highest interface type number currently defined | 257 | * @NL80211_IFTYPE_MAX: highest interface type number currently defined |
227 | * @__NL80211_IFTYPE_AFTER_LAST: internal use | 258 | * @__NL80211_IFTYPE_AFTER_LAST: internal use |
228 | * | 259 | * |
@@ -238,6 +269,7 @@ enum nl80211_iftype { | |||
238 | NL80211_IFTYPE_AP_VLAN, | 269 | NL80211_IFTYPE_AP_VLAN, |
239 | NL80211_IFTYPE_WDS, | 270 | NL80211_IFTYPE_WDS, |
240 | NL80211_IFTYPE_MONITOR, | 271 | NL80211_IFTYPE_MONITOR, |
272 | NL80211_IFTYPE_MESH_POINT, | ||
241 | 273 | ||
242 | /* keep last */ | 274 | /* keep last */ |
243 | __NL80211_IFTYPE_AFTER_LAST, | 275 | __NL80211_IFTYPE_AFTER_LAST, |
@@ -267,27 +299,78 @@ enum nl80211_sta_flags { | |||
267 | }; | 299 | }; |
268 | 300 | ||
269 | /** | 301 | /** |
270 | * enum nl80211_sta_stats - station statistics | 302 | * enum nl80211_sta_info - station information |
271 | * | 303 | * |
272 | * These attribute types are used with %NL80211_ATTR_STA_STATS | 304 | * These attribute types are used with %NL80211_ATTR_STA_INFO |
273 | * when getting information about a station. | 305 | * when getting information about a station. |
274 | * | 306 | * |
275 | * @__NL80211_STA_STAT_INVALID: attribute number 0 is reserved | 307 | * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved |
276 | * @NL80211_STA_STAT_INACTIVE_TIME: time since last activity (u32, msecs) | 308 | * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) |
277 | * @NL80211_STA_STAT_RX_BYTES: total received bytes (u32, from this station) | 309 | * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station) |
278 | * @NL80211_STA_STAT_TX_BYTES: total transmitted bytes (u32, to this station) | 310 | * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) |
279 | * @__NL80211_STA_STAT_AFTER_LAST: internal | 311 | * @__NL80211_STA_INFO_AFTER_LAST: internal |
280 | * @NL80211_STA_STAT_MAX: highest possible station stats attribute | 312 | * @NL80211_STA_INFO_MAX: highest possible station info attribute |
313 | */ | ||
314 | enum nl80211_sta_info { | ||
315 | __NL80211_STA_INFO_INVALID, | ||
316 | NL80211_STA_INFO_INACTIVE_TIME, | ||
317 | NL80211_STA_INFO_RX_BYTES, | ||
318 | NL80211_STA_INFO_TX_BYTES, | ||
319 | NL80211_STA_INFO_LLID, | ||
320 | NL80211_STA_INFO_PLID, | ||
321 | NL80211_STA_INFO_PLINK_STATE, | ||
322 | |||
323 | /* keep last */ | ||
324 | __NL80211_STA_INFO_AFTER_LAST, | ||
325 | NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1 | ||
326 | }; | ||
327 | |||
328 | /** | ||
329 | * enum nl80211_mpath_flags - nl80211 mesh path flags | ||
330 | * | ||
331 | * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active | ||
332 | * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running | ||
333 | * @NL80211_MPATH_FLAG_DSN_VALID: the mesh path contains a valid DSN | ||
334 | * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set | ||
335 | * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded | ||
336 | */ | ||
337 | enum nl80211_mpath_flags { | ||
338 | NL80211_MPATH_FLAG_ACTIVE = 1<<0, | ||
339 | NL80211_MPATH_FLAG_RESOLVING = 1<<1, | ||
340 | NL80211_MPATH_FLAG_DSN_VALID = 1<<2, | ||
341 | NL80211_MPATH_FLAG_FIXED = 1<<3, | ||
342 | NL80211_MPATH_FLAG_RESOLVED = 1<<4, | ||
343 | }; | ||
344 | |||
345 | /** | ||
346 | * enum nl80211_mpath_info - mesh path information | ||
347 | * | ||
348 | * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting | ||
349 | * information about a mesh path. | ||
350 | * | ||
351 | * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved | ||
352 | * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination | ||
353 | * @NL80211_ATTR_MPATH_DSN: destination sequence number | ||
354 | * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path | ||
355 | * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now | ||
356 | * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in | ||
357 | * &enum nl80211_mpath_flags; | ||
358 | * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec | ||
359 | * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries | ||
281 | */ | 360 | */ |
282 | enum nl80211_sta_stats { | 361 | enum nl80211_mpath_info { |
283 | __NL80211_STA_STAT_INVALID, | 362 | __NL80211_MPATH_INFO_INVALID, |
284 | NL80211_STA_STAT_INACTIVE_TIME, | 363 | NL80211_MPATH_INFO_FRAME_QLEN, |
285 | NL80211_STA_STAT_RX_BYTES, | 364 | NL80211_MPATH_INFO_DSN, |
286 | NL80211_STA_STAT_TX_BYTES, | 365 | NL80211_MPATH_INFO_METRIC, |
366 | NL80211_MPATH_INFO_EXPTIME, | ||
367 | NL80211_MPATH_INFO_FLAGS, | ||
368 | NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, | ||
369 | NL80211_MPATH_INFO_DISCOVERY_RETRIES, | ||
287 | 370 | ||
288 | /* keep last */ | 371 | /* keep last */ |
289 | __NL80211_STA_STAT_AFTER_LAST, | 372 | __NL80211_MPATH_INFO_AFTER_LAST, |
290 | NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1 | 373 | NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1 |
291 | }; | 374 | }; |
292 | 375 | ||
293 | /** | 376 | /** |
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 860d28c6d149..b7c388972fcf 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h | |||
@@ -422,5 +422,12 @@ extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl); | |||
422 | extern u32 ssb_admatch_base(u32 adm); | 422 | extern u32 ssb_admatch_base(u32 adm); |
423 | extern u32 ssb_admatch_size(u32 adm); | 423 | extern u32 ssb_admatch_size(u32 adm); |
424 | 424 | ||
425 | /* PCI device mapping and fixup routines. | ||
426 | * Called from the architecture pcibios init code. | ||
427 | * These are only available on SSB_EMBEDDED configurations. */ | ||
428 | #ifdef CONFIG_SSB_EMBEDDED | ||
429 | int ssb_pcibios_plat_dev_init(struct pci_dev *dev); | ||
430 | int ssb_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin); | ||
431 | #endif /* CONFIG_SSB_EMBEDDED */ | ||
425 | 432 | ||
426 | #endif /* LINUX_SSB_H_ */ | 433 | #endif /* LINUX_SSB_H_ */ |
diff --git a/include/linux/ssb/ssb_driver_gige.h b/include/linux/ssb/ssb_driver_gige.h new file mode 100644 index 000000000000..01fbdf5fef22 --- /dev/null +++ b/include/linux/ssb/ssb_driver_gige.h | |||
@@ -0,0 +1,174 @@ | |||
1 | #ifndef LINUX_SSB_DRIVER_GIGE_H_ | ||
2 | #define LINUX_SSB_DRIVER_GIGE_H_ | ||
3 | |||
4 | #include <linux/ssb/ssb.h> | ||
5 | #include <linux/pci.h> | ||
6 | #include <linux/spinlock.h> | ||
7 | |||
8 | |||
9 | #ifdef CONFIG_SSB_DRIVER_GIGE | ||
10 | |||
11 | |||
12 | #define SSB_GIGE_PCIIO 0x0000 /* PCI I/O Registers (1024 bytes) */ | ||
13 | #define SSB_GIGE_RESERVED 0x0400 /* Reserved (1024 bytes) */ | ||
14 | #define SSB_GIGE_PCICFG 0x0800 /* PCI config space (256 bytes) */ | ||
15 | #define SSB_GIGE_SHIM_FLUSHSTAT 0x0C00 /* PCI to OCP: Flush status control (32bit) */ | ||
16 | #define SSB_GIGE_SHIM_FLUSHRDA 0x0C04 /* PCI to OCP: Flush read address (32bit) */ | ||
17 | #define SSB_GIGE_SHIM_FLUSHTO 0x0C08 /* PCI to OCP: Flush timeout counter (32bit) */ | ||
18 | #define SSB_GIGE_SHIM_BARRIER 0x0C0C /* PCI to OCP: Barrier register (32bit) */ | ||
19 | #define SSB_GIGE_SHIM_MAOCPSI 0x0C10 /* PCI to OCP: MaocpSI Control (32bit) */ | ||
20 | #define SSB_GIGE_SHIM_SIOCPMA 0x0C14 /* PCI to OCP: SiocpMa Control (32bit) */ | ||
21 | |||
22 | /* TM Status High flags */ | ||
23 | #define SSB_GIGE_TMSHIGH_RGMII 0x00010000 /* Have an RGMII PHY-bus */ | ||
24 | /* TM Status Low flags */ | ||
25 | #define SSB_GIGE_TMSLOW_TXBYPASS 0x00080000 /* TX bypass (no delay) */ | ||
26 | #define SSB_GIGE_TMSLOW_RXBYPASS 0x00100000 /* RX bypass (no delay) */ | ||
27 | #define SSB_GIGE_TMSLOW_DLLEN 0x01000000 /* Enable DLL controls */ | ||
28 | |||
29 | /* Boardflags (low) */ | ||
30 | #define SSB_GIGE_BFL_ROBOSWITCH 0x0010 | ||
31 | |||
32 | |||
33 | #define SSB_GIGE_MEM_RES_NAME "SSB Broadcom 47xx GigE memory" | ||
34 | #define SSB_GIGE_IO_RES_NAME "SSB Broadcom 47xx GigE I/O" | ||
35 | |||
36 | struct ssb_gige { | ||
37 | struct ssb_device *dev; | ||
38 | |||
39 | spinlock_t lock; | ||
40 | |||
41 | /* True, if the device has an RGMII bus. | ||
42 | * False, if the device has a GMII bus. */ | ||
43 | bool has_rgmii; | ||
44 | |||
45 | /* The PCI controller device. */ | ||
46 | struct pci_controller pci_controller; | ||
47 | struct pci_ops pci_ops; | ||
48 | struct resource mem_resource; | ||
49 | struct resource io_resource; | ||
50 | }; | ||
51 | |||
52 | /* Check whether a PCI device is a SSB Gigabit Ethernet core. */ | ||
53 | extern bool pdev_is_ssb_gige_core(struct pci_dev *pdev); | ||
54 | |||
55 | /* Convert a pci_dev pointer to a ssb_gige pointer. */ | ||
56 | static inline struct ssb_gige * pdev_to_ssb_gige(struct pci_dev *pdev) | ||
57 | { | ||
58 | if (!pdev_is_ssb_gige_core(pdev)) | ||
59 | return NULL; | ||
60 | return container_of(pdev->bus->ops, struct ssb_gige, pci_ops); | ||
61 | } | ||
62 | |||
63 | /* Returns whether the PHY is connected by an RGMII bus. */ | ||
64 | static inline bool ssb_gige_is_rgmii(struct pci_dev *pdev) | ||
65 | { | ||
66 | struct ssb_gige *dev = pdev_to_ssb_gige(pdev); | ||
67 | return (dev ? dev->has_rgmii : 0); | ||
68 | } | ||
69 | |||
70 | /* Returns whether we have a Roboswitch. */ | ||
71 | static inline bool ssb_gige_have_roboswitch(struct pci_dev *pdev) | ||
72 | { | ||
73 | struct ssb_gige *dev = pdev_to_ssb_gige(pdev); | ||
74 | if (dev) | ||
75 | return !!(dev->dev->bus->sprom.boardflags_lo & | ||
76 | SSB_GIGE_BFL_ROBOSWITCH); | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | /* Returns whether we can only do one DMA at once. */ | ||
81 | static inline bool ssb_gige_one_dma_at_once(struct pci_dev *pdev) | ||
82 | { | ||
83 | struct ssb_gige *dev = pdev_to_ssb_gige(pdev); | ||
84 | if (dev) | ||
85 | return ((dev->dev->bus->chip_id == 0x4785) && | ||
86 | (dev->dev->bus->chip_rev < 2)); | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | /* Returns whether we must flush posted writes. */ | ||
91 | static inline bool ssb_gige_must_flush_posted_writes(struct pci_dev *pdev) | ||
92 | { | ||
93 | struct ssb_gige *dev = pdev_to_ssb_gige(pdev); | ||
94 | if (dev) | ||
95 | return (dev->dev->bus->chip_id == 0x4785); | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | extern char * nvram_get(const char *name); | ||
100 | /* Get the device MAC address */ | ||
101 | static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr) | ||
102 | { | ||
103 | #ifdef CONFIG_BCM947XX | ||
104 | char *res = nvram_get("et0macaddr"); | ||
105 | if (res) | ||
106 | memcpy(macaddr, res, 6); | ||
107 | #endif | ||
108 | } | ||
109 | |||
110 | extern int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, | ||
111 | struct pci_dev *pdev); | ||
112 | extern int ssb_gige_map_irq(struct ssb_device *sdev, | ||
113 | const struct pci_dev *pdev); | ||
114 | |||
115 | /* The GigE driver is not a standalone module, because we don't have support | ||
116 | * for unregistering the driver. So we could not unload the module anyway. */ | ||
117 | extern int ssb_gige_init(void); | ||
118 | static inline void ssb_gige_exit(void) | ||
119 | { | ||
120 | /* Currently we can not unregister the GigE driver, | ||
121 | * because we can not unregister the PCI bridge. */ | ||
122 | BUG(); | ||
123 | } | ||
124 | |||
125 | |||
126 | #else /* CONFIG_SSB_DRIVER_GIGE */ | ||
127 | /* Gigabit Ethernet driver disabled */ | ||
128 | |||
129 | |||
130 | static inline int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, | ||
131 | struct pci_dev *pdev) | ||
132 | { | ||
133 | return -ENOSYS; | ||
134 | } | ||
135 | static inline int ssb_gige_map_irq(struct ssb_device *sdev, | ||
136 | const struct pci_dev *pdev) | ||
137 | { | ||
138 | return -ENOSYS; | ||
139 | } | ||
140 | static inline int ssb_gige_init(void) | ||
141 | { | ||
142 | return 0; | ||
143 | } | ||
144 | static inline void ssb_gige_exit(void) | ||
145 | { | ||
146 | } | ||
147 | |||
148 | static inline bool pdev_is_ssb_gige_core(struct pci_dev *pdev) | ||
149 | { | ||
150 | return 0; | ||
151 | } | ||
152 | static inline struct ssb_gige * pdev_to_ssb_gige(struct pci_dev *pdev) | ||
153 | { | ||
154 | return NULL; | ||
155 | } | ||
156 | static inline bool ssb_gige_is_rgmii(struct pci_dev *pdev) | ||
157 | { | ||
158 | return 0; | ||
159 | } | ||
160 | static inline bool ssb_gige_have_roboswitch(struct pci_dev *pdev) | ||
161 | { | ||
162 | return 0; | ||
163 | } | ||
164 | static inline bool ssb_gige_one_dma_at_once(struct pci_dev *pdev) | ||
165 | { | ||
166 | return 0; | ||
167 | } | ||
168 | static inline bool ssb_gige_must_flush_posted_writes(struct pci_dev *pdev) | ||
169 | { | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | #endif /* CONFIG_SSB_DRIVER_GIGE */ | ||
174 | #endif /* LINUX_SSB_DRIVER_GIGE_H_ */ | ||
diff --git a/include/linux/ssb/ssb_driver_pci.h b/include/linux/ssb/ssb_driver_pci.h index 5e25bac4ed31..41e330e51c2a 100644 --- a/include/linux/ssb/ssb_driver_pci.h +++ b/include/linux/ssb/ssb_driver_pci.h | |||
@@ -1,6 +1,11 @@ | |||
1 | #ifndef LINUX_SSB_PCICORE_H_ | 1 | #ifndef LINUX_SSB_PCICORE_H_ |
2 | #define LINUX_SSB_PCICORE_H_ | 2 | #define LINUX_SSB_PCICORE_H_ |
3 | 3 | ||
4 | #include <linux/types.h> | ||
5 | |||
6 | struct pci_dev; | ||
7 | |||
8 | |||
4 | #ifdef CONFIG_SSB_DRIVER_PCICORE | 9 | #ifdef CONFIG_SSB_DRIVER_PCICORE |
5 | 10 | ||
6 | /* PCI core registers. */ | 11 | /* PCI core registers. */ |
@@ -88,6 +93,9 @@ extern void ssb_pcicore_init(struct ssb_pcicore *pc); | |||
88 | extern int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, | 93 | extern int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, |
89 | struct ssb_device *dev); | 94 | struct ssb_device *dev); |
90 | 95 | ||
96 | int ssb_pcicore_plat_dev_init(struct pci_dev *d); | ||
97 | int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin); | ||
98 | |||
91 | 99 | ||
92 | #else /* CONFIG_SSB_DRIVER_PCICORE */ | 100 | #else /* CONFIG_SSB_DRIVER_PCICORE */ |
93 | 101 | ||
@@ -107,5 +115,16 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, | |||
107 | return 0; | 115 | return 0; |
108 | } | 116 | } |
109 | 117 | ||
118 | static inline | ||
119 | int ssb_pcicore_plat_dev_init(struct pci_dev *d) | ||
120 | { | ||
121 | return -ENODEV; | ||
122 | } | ||
123 | static inline | ||
124 | int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
125 | { | ||
126 | return -ENODEV; | ||
127 | } | ||
128 | |||
110 | #endif /* CONFIG_SSB_DRIVER_PCICORE */ | 129 | #endif /* CONFIG_SSB_DRIVER_PCICORE */ |
111 | #endif /* LINUX_SSB_PCICORE_H_ */ | 130 | #endif /* LINUX_SSB_PCICORE_H_ */ |
diff --git a/include/linux/wireless.h b/include/linux/wireless.h index 3160dfed73ca..2864b1699ecc 100644 --- a/include/linux/wireless.h +++ b/include/linux/wireless.h | |||
@@ -455,6 +455,7 @@ | |||
455 | #define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ | 455 | #define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ |
456 | #define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ | 456 | #define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ |
457 | #define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ | 457 | #define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ |
458 | #define IW_MODE_MESH 7 /* Mesh (IEEE 802.11s) network */ | ||
458 | 459 | ||
459 | /* Statistics flags (bitmask in updated) */ | 460 | /* Statistics flags (bitmask in updated) */ |
460 | #define IW_QUAL_QUAL_UPDATED 0x01 /* Value was updated since last read */ | 461 | #define IW_QUAL_QUAL_UPDATED 0x01 /* Value was updated since last read */ |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index ab4caf63954f..e00750836ba5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -12,6 +12,16 @@ | |||
12 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> | 12 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> |
13 | */ | 13 | */ |
14 | 14 | ||
15 | /** | ||
16 | * struct vif_params - describes virtual interface parameters | ||
17 | * @mesh_id: mesh ID to use | ||
18 | * @mesh_id_len: length of the mesh ID | ||
19 | */ | ||
20 | struct vif_params { | ||
21 | u8 *mesh_id; | ||
22 | int mesh_id_len; | ||
23 | }; | ||
24 | |||
15 | /* Radiotap header iteration | 25 | /* Radiotap header iteration |
16 | * implemented in net/wireless/radiotap.c | 26 | * implemented in net/wireless/radiotap.c |
17 | * docs in Documentation/networking/radiotap-headers.txt | 27 | * docs in Documentation/networking/radiotap-headers.txt |
@@ -109,6 +119,19 @@ enum station_flags { | |||
109 | }; | 119 | }; |
110 | 120 | ||
111 | /** | 121 | /** |
122 | * enum plink_action - actions to perform in mesh peers | ||
123 | * | ||
124 | * @PLINK_ACTION_INVALID: action 0 is reserved | ||
125 | * @PLINK_ACTION_OPEN: start mesh peer link establishment | ||
126 | * @PLINK_ACTION_BLOCL: block traffic from this mesh peer | ||
127 | */ | ||
128 | enum plink_actions { | ||
129 | PLINK_ACTION_INVALID, | ||
130 | PLINK_ACTION_OPEN, | ||
131 | PLINK_ACTION_BLOCK, | ||
132 | }; | ||
133 | |||
134 | /** | ||
112 | * struct station_parameters - station parameters | 135 | * struct station_parameters - station parameters |
113 | * | 136 | * |
114 | * Used to change and create a new station. | 137 | * Used to change and create a new station. |
@@ -128,39 +151,52 @@ struct station_parameters { | |||
128 | int listen_interval; | 151 | int listen_interval; |
129 | u16 aid; | 152 | u16 aid; |
130 | u8 supported_rates_len; | 153 | u8 supported_rates_len; |
154 | u8 plink_action; | ||
131 | }; | 155 | }; |
132 | 156 | ||
133 | /** | 157 | /** |
134 | * enum station_stats_flags - station statistics flags | 158 | * enum station_info_flags - station information flags |
135 | * | 159 | * |
136 | * Used by the driver to indicate which info in &struct station_stats | 160 | * Used by the driver to indicate which info in &struct station_info |
137 | * it has filled in during get_station(). | 161 | * it has filled in during get_station() or dump_station(). |
138 | * | 162 | * |
139 | * @STATION_STAT_INACTIVE_TIME: @inactive_time filled | 163 | * @STATION_INFO_INACTIVE_TIME: @inactive_time filled |
140 | * @STATION_STAT_RX_BYTES: @rx_bytes filled | 164 | * @STATION_INFO_RX_BYTES: @rx_bytes filled |
141 | * @STATION_STAT_TX_BYTES: @tx_bytes filled | 165 | * @STATION_INFO_TX_BYTES: @tx_bytes filled |
166 | * @STATION_INFO_LLID: @llid filled | ||
167 | * @STATION_INFO_PLID: @plid filled | ||
168 | * @STATION_INFO_PLINK_STATE: @plink_state filled | ||
142 | */ | 169 | */ |
143 | enum station_stats_flags { | 170 | enum station_info_flags { |
144 | STATION_STAT_INACTIVE_TIME = 1<<0, | 171 | STATION_INFO_INACTIVE_TIME = 1<<0, |
145 | STATION_STAT_RX_BYTES = 1<<1, | 172 | STATION_INFO_RX_BYTES = 1<<1, |
146 | STATION_STAT_TX_BYTES = 1<<2, | 173 | STATION_INFO_TX_BYTES = 1<<2, |
174 | STATION_INFO_LLID = 1<<3, | ||
175 | STATION_INFO_PLID = 1<<4, | ||
176 | STATION_INFO_PLINK_STATE = 1<<5, | ||
147 | }; | 177 | }; |
148 | 178 | ||
149 | /** | 179 | /** |
150 | * struct station_stats - station statistics | 180 | * struct station_info - station information |
151 | * | 181 | * |
152 | * Station information filled by driver for get_station(). | 182 | * Station information filled by driver for get_station() and dump_station. |
153 | * | 183 | * |
154 | * @filled: bitflag of flags from &enum station_stats_flags | 184 | * @filled: bitflag of flags from &enum station_info_flags |
155 | * @inactive_time: time since last station activity (tx/rx) in milliseconds | 185 | * @inactive_time: time since last station activity (tx/rx) in milliseconds |
156 | * @rx_bytes: bytes received from this station | 186 | * @rx_bytes: bytes received from this station |
157 | * @tx_bytes: bytes transmitted to this station | 187 | * @tx_bytes: bytes transmitted to this station |
188 | * @llid: mesh local link id | ||
189 | * @plid: mesh peer link id | ||
190 | * @plink_state: mesh peer link state | ||
158 | */ | 191 | */ |
159 | struct station_stats { | 192 | struct station_info { |
160 | u32 filled; | 193 | u32 filled; |
161 | u32 inactive_time; | 194 | u32 inactive_time; |
162 | u32 rx_bytes; | 195 | u32 rx_bytes; |
163 | u32 tx_bytes; | 196 | u32 tx_bytes; |
197 | u16 llid; | ||
198 | u16 plid; | ||
199 | u8 plink_state; | ||
164 | }; | 200 | }; |
165 | 201 | ||
166 | /** | 202 | /** |
@@ -183,6 +219,56 @@ enum monitor_flags { | |||
183 | MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES, | 219 | MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES, |
184 | }; | 220 | }; |
185 | 221 | ||
222 | /** | ||
223 | * enum mpath_info_flags - mesh path information flags | ||
224 | * | ||
225 | * Used by the driver to indicate which info in &struct mpath_info it has filled | ||
226 | * in during get_station() or dump_station(). | ||
227 | * | ||
228 | * MPATH_INFO_FRAME_QLEN: @frame_qlen filled | ||
229 | * MPATH_INFO_DSN: @dsn filled | ||
230 | * MPATH_INFO_METRIC: @metric filled | ||
231 | * MPATH_INFO_EXPTIME: @exptime filled | ||
232 | * MPATH_INFO_DISCOVERY_TIMEOUT: @discovery_timeout filled | ||
233 | * MPATH_INFO_DISCOVERY_RETRIES: @discovery_retries filled | ||
234 | * MPATH_INFO_FLAGS: @flags filled | ||
235 | */ | ||
236 | enum mpath_info_flags { | ||
237 | MPATH_INFO_FRAME_QLEN = BIT(0), | ||
238 | MPATH_INFO_DSN = BIT(1), | ||
239 | MPATH_INFO_METRIC = BIT(2), | ||
240 | MPATH_INFO_EXPTIME = BIT(3), | ||
241 | MPATH_INFO_DISCOVERY_TIMEOUT = BIT(4), | ||
242 | MPATH_INFO_DISCOVERY_RETRIES = BIT(5), | ||
243 | MPATH_INFO_FLAGS = BIT(6), | ||
244 | }; | ||
245 | |||
246 | /** | ||
247 | * struct mpath_info - mesh path information | ||
248 | * | ||
249 | * Mesh path information filled by driver for get_mpath() and dump_mpath(). | ||
250 | * | ||
251 | * @filled: bitfield of flags from &enum mpath_info_flags | ||
252 | * @frame_qlen: number of queued frames for this destination | ||
253 | * @dsn: destination sequence number | ||
254 | * @metric: metric (cost) of this mesh path | ||
255 | * @exptime: expiration time for the mesh path from now, in msecs | ||
256 | * @flags: mesh path flags | ||
257 | * @discovery_timeout: total mesh path discovery timeout, in msecs | ||
258 | * @discovery_retries: mesh path discovery retries | ||
259 | */ | ||
260 | struct mpath_info { | ||
261 | u32 filled; | ||
262 | u32 frame_qlen; | ||
263 | u32 dsn; | ||
264 | u32 metric; | ||
265 | u32 exptime; | ||
266 | u32 discovery_timeout; | ||
267 | u8 discovery_retries; | ||
268 | u8 flags; | ||
269 | }; | ||
270 | |||
271 | |||
186 | /* from net/wireless.h */ | 272 | /* from net/wireless.h */ |
187 | struct wiphy; | 273 | struct wiphy; |
188 | 274 | ||
@@ -230,13 +316,17 @@ struct wiphy; | |||
230 | * @del_station: Remove a station; @mac may be NULL to remove all stations. | 316 | * @del_station: Remove a station; @mac may be NULL to remove all stations. |
231 | * | 317 | * |
232 | * @change_station: Modify a given station. | 318 | * @change_station: Modify a given station. |
319 | * | ||
320 | * @set_mesh_cfg: set mesh parameters (by now, just mesh id) | ||
233 | */ | 321 | */ |
234 | struct cfg80211_ops { | 322 | struct cfg80211_ops { |
235 | int (*add_virtual_intf)(struct wiphy *wiphy, char *name, | 323 | int (*add_virtual_intf)(struct wiphy *wiphy, char *name, |
236 | enum nl80211_iftype type, u32 *flags); | 324 | enum nl80211_iftype type, u32 *flags, |
325 | struct vif_params *params); | ||
237 | int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex); | 326 | int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex); |
238 | int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex, | 327 | int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex, |
239 | enum nl80211_iftype type, u32 *flags); | 328 | enum nl80211_iftype type, u32 *flags, |
329 | struct vif_params *params); | ||
240 | 330 | ||
241 | int (*add_key)(struct wiphy *wiphy, struct net_device *netdev, | 331 | int (*add_key)(struct wiphy *wiphy, struct net_device *netdev, |
242 | u8 key_index, u8 *mac_addr, | 332 | u8 key_index, u8 *mac_addr, |
@@ -264,7 +354,22 @@ struct cfg80211_ops { | |||
264 | int (*change_station)(struct wiphy *wiphy, struct net_device *dev, | 354 | int (*change_station)(struct wiphy *wiphy, struct net_device *dev, |
265 | u8 *mac, struct station_parameters *params); | 355 | u8 *mac, struct station_parameters *params); |
266 | int (*get_station)(struct wiphy *wiphy, struct net_device *dev, | 356 | int (*get_station)(struct wiphy *wiphy, struct net_device *dev, |
267 | u8 *mac, struct station_stats *stats); | 357 | u8 *mac, struct station_info *sinfo); |
358 | int (*dump_station)(struct wiphy *wiphy, struct net_device *dev, | ||
359 | int idx, u8 *mac, struct station_info *sinfo); | ||
360 | |||
361 | int (*add_mpath)(struct wiphy *wiphy, struct net_device *dev, | ||
362 | u8 *dst, u8 *next_hop); | ||
363 | int (*del_mpath)(struct wiphy *wiphy, struct net_device *dev, | ||
364 | u8 *dst); | ||
365 | int (*change_mpath)(struct wiphy *wiphy, struct net_device *dev, | ||
366 | u8 *dst, u8 *next_hop); | ||
367 | int (*get_mpath)(struct wiphy *wiphy, struct net_device *dev, | ||
368 | u8 *dst, u8 *next_hop, | ||
369 | struct mpath_info *pinfo); | ||
370 | int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev, | ||
371 | int idx, u8 *dst, u8 *next_hop, | ||
372 | struct mpath_info *pinfo); | ||
268 | }; | 373 | }; |
269 | 374 | ||
270 | #endif /* __NET_CFG80211_H */ | 375 | #endif /* __NET_CFG80211_H */ |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7a80c3981237..5ab6a350ee6d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -205,6 +205,62 @@ struct ieee80211_bss_conf { | |||
205 | bool use_short_preamble; | 205 | bool use_short_preamble; |
206 | }; | 206 | }; |
207 | 207 | ||
208 | /** | ||
209 | * enum mac80211_tx_control_flags - flags to describe Tx configuration for | ||
210 | * the Tx frame | ||
211 | * | ||
212 | * These flags are used with the @flags member of &ieee80211_tx_control | ||
213 | * | ||
214 | * @IEEE80211_TXCTL_REQ_TX_STATUS: request TX status callback for this frame. | ||
215 | * @IEEE80211_TXCTL_DO_NOT_ENCRYPT: send this frame without encryption; | ||
216 | * e.g., for EAPOL frame | ||
217 | * @IEEE80211_TXCTL_USE_RTS_CTS: use RTS-CTS before sending frame | ||
218 | * @IEEE80211_TXCTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g., | ||
219 | * for combined 802.11g / 802.11b networks) | ||
220 | * @IEEE80211_TXCTL_NO_ACK: tell the low level not to wait for an ack | ||
221 | * @IEEE80211_TXCTL_RATE_CTRL_PROBE | ||
222 | * @EEE80211_TXCTL_CLEAR_PS_FILT: clear powersave filter | ||
223 | * for destination station | ||
224 | * @IEEE80211_TXCTL_REQUEUE: | ||
225 | * @IEEE80211_TXCTL_FIRST_FRAGMENT: this is a first fragment of the frame | ||
226 | * @IEEE80211_TXCTL_LONG_RETRY_LIMIT: this frame should be send using the | ||
227 | * through set_retry_limit configured long | ||
228 | * retry value | ||
229 | * @IEEE80211_TXCTL_EAPOL_FRAME: internal to mac80211 | ||
230 | * @IEEE80211_TXCTL_SEND_AFTER_DTIM: send this frame after DTIM beacon | ||
231 | * @IEEE80211_TXCTL_AMPDU: this frame should be sent as part of an A-MPDU | ||
232 | * @IEEE80211_TXCTL_OFDM_HT: this frame can be sent in HT OFDM rates. number | ||
233 | * of streams when this flag is on can be extracted | ||
234 | * from antenna_sel_tx, so if 1 antenna is marked | ||
235 | * use SISO, 2 antennas marked use MIMO, n antennas | ||
236 | * marked use MIMO_n. | ||
237 | * @IEEE80211_TXCTL_GREEN_FIELD: use green field protection for this frame | ||
238 | * @IEEE80211_TXCTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width | ||
239 | * @IEEE80211_TXCTL_DUP_DATA: duplicate data frame on both 20 Mhz channels | ||
240 | * @IEEE80211_TXCTL_SHORT_GI: send this frame using short guard interval | ||
241 | */ | ||
242 | enum mac80211_tx_control_flags { | ||
243 | IEEE80211_TXCTL_REQ_TX_STATUS = (1<<0), | ||
244 | IEEE80211_TXCTL_DO_NOT_ENCRYPT = (1<<1), | ||
245 | IEEE80211_TXCTL_USE_RTS_CTS = (1<<2), | ||
246 | IEEE80211_TXCTL_USE_CTS_PROTECT = (1<<3), | ||
247 | IEEE80211_TXCTL_NO_ACK = (1<<4), | ||
248 | IEEE80211_TXCTL_RATE_CTRL_PROBE = (1<<5), | ||
249 | IEEE80211_TXCTL_CLEAR_PS_FILT = (1<<6), | ||
250 | IEEE80211_TXCTL_REQUEUE = (1<<7), | ||
251 | IEEE80211_TXCTL_FIRST_FRAGMENT = (1<<8), | ||
252 | IEEE80211_TXCTL_SHORT_PREAMBLE = (1<<9), | ||
253 | IEEE80211_TXCTL_LONG_RETRY_LIMIT = (1<<10), | ||
254 | IEEE80211_TXCTL_EAPOL_FRAME = (1<<11), | ||
255 | IEEE80211_TXCTL_SEND_AFTER_DTIM = (1<<12), | ||
256 | IEEE80211_TXCTL_AMPDU = (1<<13), | ||
257 | IEEE80211_TXCTL_OFDM_HT = (1<<14), | ||
258 | IEEE80211_TXCTL_GREEN_FIELD = (1<<15), | ||
259 | IEEE80211_TXCTL_40_MHZ_WIDTH = (1<<16), | ||
260 | IEEE80211_TXCTL_DUP_DATA = (1<<17), | ||
261 | IEEE80211_TXCTL_SHORT_GI = (1<<18), | ||
262 | }; | ||
263 | |||
208 | /* Transmit control fields. This data structure is passed to low-level driver | 264 | /* Transmit control fields. This data structure is passed to low-level driver |
209 | * with each TX frame. The low-level driver is responsible for configuring | 265 | * with each TX frame. The low-level driver is responsible for configuring |
210 | * the hardware to use given values (depending on what is supported). */ | 266 | * the hardware to use given values (depending on what is supported). */ |
@@ -219,42 +275,14 @@ struct ieee80211_tx_control { | |||
219 | /* retry rate for the last retries */ | 275 | /* retry rate for the last retries */ |
220 | struct ieee80211_rate *alt_retry_rate; | 276 | struct ieee80211_rate *alt_retry_rate; |
221 | 277 | ||
222 | #define IEEE80211_TXCTL_REQ_TX_STATUS (1<<0)/* request TX status callback for | 278 | u32 flags; /* tx control flags defined above */ |
223 | * this frame */ | ||
224 | #define IEEE80211_TXCTL_DO_NOT_ENCRYPT (1<<1) /* send this frame without | ||
225 | * encryption; e.g., for EAPOL | ||
226 | * frames */ | ||
227 | #define IEEE80211_TXCTL_USE_RTS_CTS (1<<2) /* use RTS-CTS before sending | ||
228 | * frame */ | ||
229 | #define IEEE80211_TXCTL_USE_CTS_PROTECT (1<<3) /* use CTS protection for the | ||
230 | * frame (e.g., for combined | ||
231 | * 802.11g / 802.11b networks) */ | ||
232 | #define IEEE80211_TXCTL_NO_ACK (1<<4) /* tell the low level not to | ||
233 | * wait for an ack */ | ||
234 | #define IEEE80211_TXCTL_RATE_CTRL_PROBE (1<<5) | ||
235 | #define IEEE80211_TXCTL_CLEAR_PS_FILT (1<<6) /* clear powersave filter | ||
236 | * for destination station */ | ||
237 | #define IEEE80211_TXCTL_REQUEUE (1<<7) | ||
238 | #define IEEE80211_TXCTL_FIRST_FRAGMENT (1<<8) /* this is a first fragment of | ||
239 | * the frame */ | ||
240 | #define IEEE80211_TXCTL_SHORT_PREAMBLE (1<<9) | ||
241 | #define IEEE80211_TXCTL_LONG_RETRY_LIMIT (1<<10) /* this frame should be send | ||
242 | * using the through | ||
243 | * set_retry_limit configured | ||
244 | * long retry value */ | ||
245 | #define IEEE80211_TXCTL_EAPOL_FRAME (1<<11) /* internal to mac80211 */ | ||
246 | #define IEEE80211_TXCTL_SEND_AFTER_DTIM (1<<12) /* send this frame after DTIM | ||
247 | * beacon */ | ||
248 | #define IEEE80211_TXCTL_AMPDU (1<<13) /* this frame should be sent | ||
249 | * as part of an A-MPDU */ | ||
250 | u32 flags; /* tx control flags defined | ||
251 | * above */ | ||
252 | u8 key_idx; /* keyidx from hw->set_key(), undefined if | 279 | u8 key_idx; /* keyidx from hw->set_key(), undefined if |
253 | * IEEE80211_TXCTL_DO_NOT_ENCRYPT is set */ | 280 | * IEEE80211_TXCTL_DO_NOT_ENCRYPT is set */ |
254 | u8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. | 281 | u8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. |
255 | * This could be used when set_retry_limit | 282 | * This could be used when set_retry_limit |
256 | * is not implemented by the driver */ | 283 | * is not implemented by the driver */ |
257 | u8 antenna_sel_tx; /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */ | 284 | u8 antenna_sel_tx; /* 0 = default/diversity, otherwise bit |
285 | * position represents antenna number used */ | ||
258 | u8 icv_len; /* length of the ICV/MIC field in octets */ | 286 | u8 icv_len; /* length of the ICV/MIC field in octets */ |
259 | u8 iv_len; /* length of the IV field in octets */ | 287 | u8 iv_len; /* length of the IV field in octets */ |
260 | u8 queue; /* hardware queue to use for this frame; | 288 | u8 queue; /* hardware queue to use for this frame; |
@@ -407,7 +435,6 @@ enum ieee80211_conf_flags { | |||
407 | * @channel: the channel to tune to | 435 | * @channel: the channel to tune to |
408 | */ | 436 | */ |
409 | struct ieee80211_conf { | 437 | struct ieee80211_conf { |
410 | unsigned int regulatory_domain; | ||
411 | int radio_enabled; | 438 | int radio_enabled; |
412 | 439 | ||
413 | int beacon_int; | 440 | int beacon_int; |
@@ -437,12 +464,14 @@ struct ieee80211_conf { | |||
437 | * @IEEE80211_IF_TYPE_WDS: interface in WDS mode. | 464 | * @IEEE80211_IF_TYPE_WDS: interface in WDS mode. |
438 | * @IEEE80211_IF_TYPE_VLAN: VLAN interface bound to an AP, drivers | 465 | * @IEEE80211_IF_TYPE_VLAN: VLAN interface bound to an AP, drivers |
439 | * will never see this type. | 466 | * will never see this type. |
467 | * @IEEE80211_IF_TYPE_MESH_POINT: 802.11s mesh point | ||
440 | */ | 468 | */ |
441 | enum ieee80211_if_types { | 469 | enum ieee80211_if_types { |
442 | IEEE80211_IF_TYPE_INVALID, | 470 | IEEE80211_IF_TYPE_INVALID, |
443 | IEEE80211_IF_TYPE_AP, | 471 | IEEE80211_IF_TYPE_AP, |
444 | IEEE80211_IF_TYPE_STA, | 472 | IEEE80211_IF_TYPE_STA, |
445 | IEEE80211_IF_TYPE_IBSS, | 473 | IEEE80211_IF_TYPE_IBSS, |
474 | IEEE80211_IF_TYPE_MESH_POINT, | ||
446 | IEEE80211_IF_TYPE_MNTR, | 475 | IEEE80211_IF_TYPE_MNTR, |
447 | IEEE80211_IF_TYPE_WDS, | 476 | IEEE80211_IF_TYPE_WDS, |
448 | IEEE80211_IF_TYPE_VLAN, | 477 | IEEE80211_IF_TYPE_VLAN, |
@@ -464,6 +493,14 @@ struct ieee80211_vif { | |||
464 | u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); | 493 | u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); |
465 | }; | 494 | }; |
466 | 495 | ||
496 | static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) | ||
497 | { | ||
498 | #ifdef CONFIG_MAC80211_MESH | ||
499 | return vif->type == IEEE80211_IF_TYPE_MESH_POINT; | ||
500 | #endif | ||
501 | return false; | ||
502 | } | ||
503 | |||
467 | /** | 504 | /** |
468 | * struct ieee80211_if_init_conf - initial configuration of an interface | 505 | * struct ieee80211_if_init_conf - initial configuration of an interface |
469 | * | 506 | * |
@@ -1087,8 +1124,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
1087 | /** | 1124 | /** |
1088 | * ieee80211_register_hw - Register hardware device | 1125 | * ieee80211_register_hw - Register hardware device |
1089 | * | 1126 | * |
1090 | * You must call this function before any other functions | 1127 | * You must call this function before any other functions in |
1091 | * except ieee80211_register_hwmode. | 1128 | * mac80211. Note that before a hardware can be registered, you |
1129 | * need to fill the contained wiphy's information. | ||
1092 | * | 1130 | * |
1093 | * @hw: the device to register as returned by ieee80211_alloc_hw() | 1131 | * @hw: the device to register as returned by ieee80211_alloc_hw() |
1094 | */ | 1132 | */ |
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 45c7c0c3875e..3c3f62faae1e 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -81,6 +81,15 @@ config MAC80211_RC_SIMPLE | |||
81 | Say N unless you know what you are doing. | 81 | Say N unless you know what you are doing. |
82 | endmenu | 82 | endmenu |
83 | 83 | ||
84 | config MAC80211_MESH | ||
85 | bool "Enable mac80211 mesh networking (pre-802.11s) support" | ||
86 | depends on MAC80211 && EXPERIMENTAL | ||
87 | ---help--- | ||
88 | This options enables support of Draft 802.11s mesh networking. | ||
89 | The implementation is based on Draft 1.08 of the Mesh Networking | ||
90 | amendment. For more information visit http://o11s.org/. | ||
91 | |||
92 | |||
84 | config MAC80211_LEDS | 93 | config MAC80211_LEDS |
85 | bool "Enable LED triggers" | 94 | bool "Enable LED triggers" |
86 | depends on MAC80211 && LEDS_TRIGGERS | 95 | depends on MAC80211 && LEDS_TRIGGERS |
@@ -166,3 +175,10 @@ config MAC80211_VERBOSE_PS_DEBUG | |||
166 | ---help--- | 175 | ---help--- |
167 | Say Y here to print out verbose powersave | 176 | Say Y here to print out verbose powersave |
168 | mode debug messages. | 177 | mode debug messages. |
178 | |||
179 | config MAC80211_VERBOSE_MPL_DEBUG | ||
180 | bool "Verbose mesh peer link debugging" | ||
181 | depends on MAC80211_DEBUG && MAC80211_MESH | ||
182 | ---help--- | ||
183 | Say Y here to print out verbose mesh peer link | ||
184 | debug messages. | ||
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 9d7a19581a29..829ce4256b76 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
@@ -36,6 +36,12 @@ mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ | |||
36 | debugfs_netdev.o \ | 36 | debugfs_netdev.o \ |
37 | debugfs_key.o | 37 | debugfs_key.o |
38 | 38 | ||
39 | mac80211-$(CONFIG_MAC80211_MESH) += \ | ||
40 | mesh.o \ | ||
41 | mesh_pathtbl.o \ | ||
42 | mesh_plink.o \ | ||
43 | mesh_hwmp.o | ||
44 | |||
39 | 45 | ||
40 | # Build rate control algorithm(s) | 46 | # Build rate control algorithm(s) |
41 | CFLAGS_rc80211_simple.o += -DRC80211_SIMPLE_COMPILE | 47 | CFLAGS_rc80211_simple.o += -DRC80211_SIMPLE_COMPILE |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e7535ffc8e1c..6b183a3526b0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include "ieee80211_i.h" | 15 | #include "ieee80211_i.h" |
16 | #include "cfg.h" | 16 | #include "cfg.h" |
17 | #include "ieee80211_rate.h" | 17 | #include "ieee80211_rate.h" |
18 | #include "mesh.h" | ||
18 | 19 | ||
19 | static enum ieee80211_if_types | 20 | static enum ieee80211_if_types |
20 | nl80211_type_to_mac80211_type(enum nl80211_iftype type) | 21 | nl80211_type_to_mac80211_type(enum nl80211_iftype type) |
@@ -28,13 +29,18 @@ nl80211_type_to_mac80211_type(enum nl80211_iftype type) | |||
28 | return IEEE80211_IF_TYPE_STA; | 29 | return IEEE80211_IF_TYPE_STA; |
29 | case NL80211_IFTYPE_MONITOR: | 30 | case NL80211_IFTYPE_MONITOR: |
30 | return IEEE80211_IF_TYPE_MNTR; | 31 | return IEEE80211_IF_TYPE_MNTR; |
32 | #ifdef CONFIG_MAC80211_MESH | ||
33 | case NL80211_IFTYPE_MESH_POINT: | ||
34 | return IEEE80211_IF_TYPE_MESH_POINT; | ||
35 | #endif | ||
31 | default: | 36 | default: |
32 | return IEEE80211_IF_TYPE_INVALID; | 37 | return IEEE80211_IF_TYPE_INVALID; |
33 | } | 38 | } |
34 | } | 39 | } |
35 | 40 | ||
36 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | 41 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, |
37 | enum nl80211_iftype type, u32 *flags) | 42 | enum nl80211_iftype type, u32 *flags, |
43 | struct vif_params *params) | ||
38 | { | 44 | { |
39 | struct ieee80211_local *local = wiphy_priv(wiphy); | 45 | struct ieee80211_local *local = wiphy_priv(wiphy); |
40 | enum ieee80211_if_types itype; | 46 | enum ieee80211_if_types itype; |
@@ -49,7 +55,7 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | |||
49 | if (itype == IEEE80211_IF_TYPE_INVALID) | 55 | if (itype == IEEE80211_IF_TYPE_INVALID) |
50 | return -EINVAL; | 56 | return -EINVAL; |
51 | 57 | ||
52 | err = ieee80211_if_add(local->mdev, name, &dev, itype); | 58 | err = ieee80211_if_add(local->mdev, name, &dev, itype, params); |
53 | if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags) | 59 | if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags) |
54 | return err; | 60 | return err; |
55 | 61 | ||
@@ -78,7 +84,8 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) | |||
78 | } | 84 | } |
79 | 85 | ||
80 | static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, | 86 | static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, |
81 | enum nl80211_iftype type, u32 *flags) | 87 | enum nl80211_iftype type, u32 *flags, |
88 | struct vif_params *params) | ||
82 | { | 89 | { |
83 | struct ieee80211_local *local = wiphy_priv(wiphy); | 90 | struct ieee80211_local *local = wiphy_priv(wiphy); |
84 | struct net_device *dev; | 91 | struct net_device *dev; |
@@ -108,6 +115,11 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, | |||
108 | ieee80211_if_reinit(dev); | 115 | ieee80211_if_reinit(dev); |
109 | ieee80211_if_set_type(dev, itype); | 116 | ieee80211_if_set_type(dev, itype); |
110 | 117 | ||
118 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len) | ||
119 | ieee80211_if_sta_set_mesh_id(&sdata->u.sta, | ||
120 | params->mesh_id_len, | ||
121 | params->mesh_id); | ||
122 | |||
111 | if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags) | 123 | if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags) |
112 | return 0; | 124 | return 0; |
113 | 125 | ||
@@ -122,7 +134,6 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
122 | struct ieee80211_sub_if_data *sdata; | 134 | struct ieee80211_sub_if_data *sdata; |
123 | struct sta_info *sta = NULL; | 135 | struct sta_info *sta = NULL; |
124 | enum ieee80211_key_alg alg; | 136 | enum ieee80211_key_alg alg; |
125 | int ret; | ||
126 | struct ieee80211_key *key; | 137 | struct ieee80211_key *key; |
127 | 138 | ||
128 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 139 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
@@ -156,12 +167,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
156 | 167 | ||
157 | ieee80211_key_link(key, sdata, sta); | 168 | ieee80211_key_link(key, sdata, sta); |
158 | 169 | ||
159 | ret = 0; | 170 | return 0; |
160 | |||
161 | if (sta) | ||
162 | sta_info_put(sta); | ||
163 | |||
164 | return ret; | ||
165 | } | 171 | } |
166 | 172 | ||
167 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | 173 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, |
@@ -170,7 +176,6 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
170 | struct ieee80211_sub_if_data *sdata; | 176 | struct ieee80211_sub_if_data *sdata; |
171 | struct sta_info *sta; | 177 | struct sta_info *sta; |
172 | int ret; | 178 | int ret; |
173 | struct ieee80211_key *key; | ||
174 | 179 | ||
175 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 180 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
176 | 181 | ||
@@ -181,21 +186,18 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
181 | 186 | ||
182 | ret = 0; | 187 | ret = 0; |
183 | if (sta->key) { | 188 | if (sta->key) { |
184 | key = sta->key; | 189 | ieee80211_key_free(sta->key); |
185 | ieee80211_key_free(key); | ||
186 | WARN_ON(sta->key); | 190 | WARN_ON(sta->key); |
187 | } else | 191 | } else |
188 | ret = -ENOENT; | 192 | ret = -ENOENT; |
189 | 193 | ||
190 | sta_info_put(sta); | ||
191 | return ret; | 194 | return ret; |
192 | } | 195 | } |
193 | 196 | ||
194 | if (!sdata->keys[key_idx]) | 197 | if (!sdata->keys[key_idx]) |
195 | return -ENOENT; | 198 | return -ENOENT; |
196 | 199 | ||
197 | key = sdata->keys[key_idx]; | 200 | ieee80211_key_free(sdata->keys[key_idx]); |
198 | ieee80211_key_free(key); | ||
199 | WARN_ON(sdata->keys[key_idx]); | 201 | WARN_ON(sdata->keys[key_idx]); |
200 | 202 | ||
201 | return 0; | 203 | return 0; |
@@ -278,8 +280,6 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
278 | err = 0; | 280 | err = 0; |
279 | 281 | ||
280 | out: | 282 | out: |
281 | if (sta) | ||
282 | sta_info_put(sta); | ||
283 | return err; | 283 | return err; |
284 | } | 284 | } |
285 | 285 | ||
@@ -295,29 +295,73 @@ static int ieee80211_config_default_key(struct wiphy *wiphy, | |||
295 | return 0; | 295 | return 0; |
296 | } | 296 | } |
297 | 297 | ||
298 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | ||
299 | { | ||
300 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
301 | |||
302 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | ||
303 | STATION_INFO_RX_BYTES | | ||
304 | STATION_INFO_TX_BYTES; | ||
305 | |||
306 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | ||
307 | sinfo->rx_bytes = sta->rx_bytes; | ||
308 | sinfo->tx_bytes = sta->tx_bytes; | ||
309 | |||
310 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
311 | #ifdef CONFIG_MAC80211_MESH | ||
312 | sinfo->filled |= STATION_INFO_LLID | | ||
313 | STATION_INFO_PLID | | ||
314 | STATION_INFO_PLINK_STATE; | ||
315 | |||
316 | sinfo->llid = le16_to_cpu(sta->llid); | ||
317 | sinfo->plid = le16_to_cpu(sta->plid); | ||
318 | sinfo->plink_state = sta->plink_state; | ||
319 | #endif | ||
320 | } | ||
321 | } | ||
322 | |||
323 | |||
324 | static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, | ||
325 | int idx, u8 *mac, struct station_info *sinfo) | ||
326 | { | ||
327 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
328 | struct sta_info *sta; | ||
329 | int ret = -ENOENT; | ||
330 | |||
331 | rcu_read_lock(); | ||
332 | |||
333 | sta = sta_info_get_by_idx(local, idx, dev); | ||
334 | if (sta) { | ||
335 | ret = 0; | ||
336 | memcpy(mac, sta->addr, ETH_ALEN); | ||
337 | sta_set_sinfo(sta, sinfo); | ||
338 | } | ||
339 | |||
340 | rcu_read_unlock(); | ||
341 | |||
342 | return ret; | ||
343 | } | ||
344 | |||
298 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | 345 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, |
299 | u8 *mac, struct station_stats *stats) | 346 | u8 *mac, struct station_info *sinfo) |
300 | { | 347 | { |
301 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 348 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
302 | struct sta_info *sta; | 349 | struct sta_info *sta; |
350 | int ret = -ENOENT; | ||
303 | 351 | ||
304 | sta = sta_info_get(local, mac); | 352 | rcu_read_lock(); |
305 | if (!sta) | ||
306 | return -ENOENT; | ||
307 | 353 | ||
308 | /* XXX: verify sta->dev == dev */ | 354 | /* XXX: verify sta->dev == dev */ |
309 | 355 | ||
310 | stats->filled = STATION_STAT_INACTIVE_TIME | | 356 | sta = sta_info_get(local, mac); |
311 | STATION_STAT_RX_BYTES | | 357 | if (sta) { |
312 | STATION_STAT_TX_BYTES; | 358 | ret = 0; |
313 | 359 | sta_set_sinfo(sta, sinfo); | |
314 | stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | 360 | } |
315 | stats->rx_bytes = sta->rx_bytes; | ||
316 | stats->tx_bytes = sta->tx_bytes; | ||
317 | 361 | ||
318 | sta_info_put(sta); | 362 | rcu_read_unlock(); |
319 | 363 | ||
320 | return 0; | 364 | return ret; |
321 | } | 365 | } |
322 | 366 | ||
323 | /* | 367 | /* |
@@ -510,8 +554,8 @@ static void ieee80211_send_layer2_update(struct sta_info *sta) | |||
510 | msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ | 554 | msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ |
511 | msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ | 555 | msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ |
512 | 556 | ||
513 | skb->dev = sta->dev; | 557 | skb->dev = sta->sdata->dev; |
514 | skb->protocol = eth_type_trans(skb, sta->dev); | 558 | skb->protocol = eth_type_trans(skb, sta->sdata->dev); |
515 | memset(skb->cb, 0, sizeof(skb->cb)); | 559 | memset(skb->cb, 0, sizeof(skb->cb)); |
516 | netif_rx(skb); | 560 | netif_rx(skb); |
517 | } | 561 | } |
@@ -523,6 +567,13 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
523 | u32 rates; | 567 | u32 rates; |
524 | int i, j; | 568 | int i, j; |
525 | struct ieee80211_supported_band *sband; | 569 | struct ieee80211_supported_band *sband; |
570 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
571 | |||
572 | /* | ||
573 | * FIXME: updating the flags is racy when this function is | ||
574 | * called from ieee80211_change_station(), this will | ||
575 | * be resolved in a future patch. | ||
576 | */ | ||
526 | 577 | ||
527 | if (params->station_flags & STATION_FLAG_CHANGED) { | 578 | if (params->station_flags & STATION_FLAG_CHANGED) { |
528 | sta->flags &= ~WLAN_STA_AUTHORIZED; | 579 | sta->flags &= ~WLAN_STA_AUTHORIZED; |
@@ -538,6 +589,13 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
538 | sta->flags |= WLAN_STA_WME; | 589 | sta->flags |= WLAN_STA_WME; |
539 | } | 590 | } |
540 | 591 | ||
592 | /* | ||
593 | * FIXME: updating the following information is racy when this | ||
594 | * function is called from ieee80211_change_station(). | ||
595 | * However, all this information should be static so | ||
596 | * maybe we should just reject attemps to change it. | ||
597 | */ | ||
598 | |||
541 | if (params->aid) { | 599 | if (params->aid) { |
542 | sta->aid = params->aid; | 600 | sta->aid = params->aid; |
543 | if (sta->aid > IEEE80211_MAX_AID) | 601 | if (sta->aid > IEEE80211_MAX_AID) |
@@ -560,6 +618,17 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
560 | } | 618 | } |
561 | sta->supp_rates[local->oper_channel->band] = rates; | 619 | sta->supp_rates[local->oper_channel->band] = rates; |
562 | } | 620 | } |
621 | |||
622 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { | ||
623 | switch (params->plink_action) { | ||
624 | case PLINK_ACTION_OPEN: | ||
625 | mesh_plink_open(sta); | ||
626 | break; | ||
627 | case PLINK_ACTION_BLOCK: | ||
628 | mesh_plink_block(sta); | ||
629 | break; | ||
630 | } | ||
631 | } | ||
563 | } | 632 | } |
564 | 633 | ||
565 | static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | 634 | static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, |
@@ -568,6 +637,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
568 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 637 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
569 | struct sta_info *sta; | 638 | struct sta_info *sta; |
570 | struct ieee80211_sub_if_data *sdata; | 639 | struct ieee80211_sub_if_data *sdata; |
640 | int err; | ||
571 | 641 | ||
572 | /* Prevent a race with changing the rate control algorithm */ | 642 | /* Prevent a race with changing the rate control algorithm */ |
573 | if (!netif_running(dev)) | 643 | if (!netif_running(dev)) |
@@ -582,14 +652,15 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
582 | } else | 652 | } else |
583 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 653 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
584 | 654 | ||
585 | sta = sta_info_add(local, dev, mac, GFP_KERNEL); | 655 | if (compare_ether_addr(mac, dev->dev_addr) == 0) |
586 | if (IS_ERR(sta)) | 656 | return -EINVAL; |
587 | return PTR_ERR(sta); | ||
588 | 657 | ||
589 | sta->dev = sdata->dev; | 658 | if (is_multicast_ether_addr(mac)) |
590 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN || | 659 | return -EINVAL; |
591 | sdata->vif.type == IEEE80211_IF_TYPE_AP) | 660 | |
592 | ieee80211_send_layer2_update(sta); | 661 | sta = sta_info_alloc(sdata, mac, GFP_KERNEL); |
662 | if (!sta) | ||
663 | return -ENOMEM; | ||
593 | 664 | ||
594 | sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; | 665 | sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; |
595 | 666 | ||
@@ -597,7 +668,20 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
597 | 668 | ||
598 | rate_control_rate_init(sta, local); | 669 | rate_control_rate_init(sta, local); |
599 | 670 | ||
600 | sta_info_put(sta); | 671 | rcu_read_lock(); |
672 | |||
673 | err = sta_info_insert(sta); | ||
674 | if (err) { | ||
675 | sta_info_destroy(sta); | ||
676 | rcu_read_unlock(); | ||
677 | return err; | ||
678 | } | ||
679 | |||
680 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN || | ||
681 | sdata->vif.type == IEEE80211_IF_TYPE_AP) | ||
682 | ieee80211_send_layer2_update(sta); | ||
683 | |||
684 | rcu_read_unlock(); | ||
601 | 685 | ||
602 | return 0; | 686 | return 0; |
603 | } | 687 | } |
@@ -605,7 +689,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
605 | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | 689 | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, |
606 | u8 *mac) | 690 | u8 *mac) |
607 | { | 691 | { |
608 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 692 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
693 | struct ieee80211_local *local = sdata->local; | ||
609 | struct sta_info *sta; | 694 | struct sta_info *sta; |
610 | 695 | ||
611 | if (mac) { | 696 | if (mac) { |
@@ -614,10 +699,14 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | |||
614 | if (!sta) | 699 | if (!sta) |
615 | return -ENOENT; | 700 | return -ENOENT; |
616 | 701 | ||
617 | sta_info_free(sta); | 702 | sta_info_unlink(&sta); |
618 | sta_info_put(sta); | 703 | |
704 | if (sta) { | ||
705 | synchronize_rcu(); | ||
706 | sta_info_destroy(sta); | ||
707 | } | ||
619 | } else | 708 | } else |
620 | sta_info_flush(local, dev); | 709 | sta_info_flush(local, sdata); |
621 | 710 | ||
622 | return 0; | 711 | return 0; |
623 | } | 712 | } |
@@ -636,23 +725,190 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
636 | if (!sta) | 725 | if (!sta) |
637 | return -ENOENT; | 726 | return -ENOENT; |
638 | 727 | ||
639 | if (params->vlan && params->vlan != sta->dev) { | 728 | if (params->vlan && params->vlan != sta->sdata->dev) { |
640 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); | 729 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
641 | 730 | ||
642 | if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN || | 731 | if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN || |
643 | vlansdata->vif.type != IEEE80211_IF_TYPE_AP) | 732 | vlansdata->vif.type != IEEE80211_IF_TYPE_AP) |
644 | return -EINVAL; | 733 | return -EINVAL; |
645 | 734 | ||
646 | sta->dev = params->vlan; | 735 | sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
647 | ieee80211_send_layer2_update(sta); | 736 | ieee80211_send_layer2_update(sta); |
648 | } | 737 | } |
649 | 738 | ||
650 | sta_apply_parameters(local, sta, params); | 739 | sta_apply_parameters(local, sta, params); |
651 | 740 | ||
652 | sta_info_put(sta); | 741 | return 0; |
742 | } | ||
653 | 743 | ||
744 | #ifdef CONFIG_MAC80211_MESH | ||
745 | static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, | ||
746 | u8 *dst, u8 *next_hop) | ||
747 | { | ||
748 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
749 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
750 | struct mesh_path *mpath; | ||
751 | struct sta_info *sta; | ||
752 | int err; | ||
753 | |||
754 | if (!netif_running(dev)) | ||
755 | return -ENETDOWN; | ||
756 | |||
757 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) | ||
758 | return -ENOTSUPP; | ||
759 | |||
760 | rcu_read_lock(); | ||
761 | sta = sta_info_get(local, next_hop); | ||
762 | if (!sta) { | ||
763 | rcu_read_unlock(); | ||
764 | return -ENOENT; | ||
765 | } | ||
766 | |||
767 | err = mesh_path_add(dst, dev); | ||
768 | if (err) { | ||
769 | rcu_read_unlock(); | ||
770 | return err; | ||
771 | } | ||
772 | |||
773 | mpath = mesh_path_lookup(dst, dev); | ||
774 | if (!mpath) { | ||
775 | rcu_read_unlock(); | ||
776 | return -ENXIO; | ||
777 | } | ||
778 | mesh_path_fix_nexthop(mpath, sta); | ||
779 | |||
780 | rcu_read_unlock(); | ||
781 | return 0; | ||
782 | } | ||
783 | |||
784 | static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev, | ||
785 | u8 *dst) | ||
786 | { | ||
787 | if (dst) | ||
788 | return mesh_path_del(dst, dev); | ||
789 | |||
790 | mesh_path_flush(dev); | ||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | static int ieee80211_change_mpath(struct wiphy *wiphy, | ||
795 | struct net_device *dev, | ||
796 | u8 *dst, u8 *next_hop) | ||
797 | { | ||
798 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
799 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
800 | struct mesh_path *mpath; | ||
801 | struct sta_info *sta; | ||
802 | |||
803 | if (!netif_running(dev)) | ||
804 | return -ENETDOWN; | ||
805 | |||
806 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) | ||
807 | return -ENOTSUPP; | ||
808 | |||
809 | rcu_read_lock(); | ||
810 | |||
811 | sta = sta_info_get(local, next_hop); | ||
812 | if (!sta) { | ||
813 | rcu_read_unlock(); | ||
814 | return -ENOENT; | ||
815 | } | ||
816 | |||
817 | mpath = mesh_path_lookup(dst, dev); | ||
818 | if (!mpath) { | ||
819 | rcu_read_unlock(); | ||
820 | return -ENOENT; | ||
821 | } | ||
822 | |||
823 | mesh_path_fix_nexthop(mpath, sta); | ||
824 | |||
825 | rcu_read_unlock(); | ||
826 | return 0; | ||
827 | } | ||
828 | |||
829 | static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | ||
830 | struct mpath_info *pinfo) | ||
831 | { | ||
832 | if (mpath->next_hop) | ||
833 | memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN); | ||
834 | else | ||
835 | memset(next_hop, 0, ETH_ALEN); | ||
836 | |||
837 | pinfo->filled = MPATH_INFO_FRAME_QLEN | | ||
838 | MPATH_INFO_DSN | | ||
839 | MPATH_INFO_METRIC | | ||
840 | MPATH_INFO_EXPTIME | | ||
841 | MPATH_INFO_DISCOVERY_TIMEOUT | | ||
842 | MPATH_INFO_DISCOVERY_RETRIES | | ||
843 | MPATH_INFO_FLAGS; | ||
844 | |||
845 | pinfo->frame_qlen = mpath->frame_queue.qlen; | ||
846 | pinfo->dsn = mpath->dsn; | ||
847 | pinfo->metric = mpath->metric; | ||
848 | if (time_before(jiffies, mpath->exp_time)) | ||
849 | pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies); | ||
850 | pinfo->discovery_timeout = | ||
851 | jiffies_to_msecs(mpath->discovery_timeout); | ||
852 | pinfo->discovery_retries = mpath->discovery_retries; | ||
853 | pinfo->flags = 0; | ||
854 | if (mpath->flags & MESH_PATH_ACTIVE) | ||
855 | pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE; | ||
856 | if (mpath->flags & MESH_PATH_RESOLVING) | ||
857 | pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; | ||
858 | if (mpath->flags & MESH_PATH_DSN_VALID) | ||
859 | pinfo->flags |= NL80211_MPATH_FLAG_DSN_VALID; | ||
860 | if (mpath->flags & MESH_PATH_FIXED) | ||
861 | pinfo->flags |= NL80211_MPATH_FLAG_FIXED; | ||
862 | if (mpath->flags & MESH_PATH_RESOLVING) | ||
863 | pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; | ||
864 | |||
865 | pinfo->flags = mpath->flags; | ||
866 | } | ||
867 | |||
868 | static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev, | ||
869 | u8 *dst, u8 *next_hop, struct mpath_info *pinfo) | ||
870 | |||
871 | { | ||
872 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
873 | struct mesh_path *mpath; | ||
874 | |||
875 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) | ||
876 | return -ENOTSUPP; | ||
877 | |||
878 | rcu_read_lock(); | ||
879 | mpath = mesh_path_lookup(dst, dev); | ||
880 | if (!mpath) { | ||
881 | rcu_read_unlock(); | ||
882 | return -ENOENT; | ||
883 | } | ||
884 | memcpy(dst, mpath->dst, ETH_ALEN); | ||
885 | mpath_set_pinfo(mpath, next_hop, pinfo); | ||
886 | rcu_read_unlock(); | ||
887 | return 0; | ||
888 | } | ||
889 | |||
890 | static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, | ||
891 | int idx, u8 *dst, u8 *next_hop, | ||
892 | struct mpath_info *pinfo) | ||
893 | { | ||
894 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
895 | struct mesh_path *mpath; | ||
896 | |||
897 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) | ||
898 | return -ENOTSUPP; | ||
899 | |||
900 | rcu_read_lock(); | ||
901 | mpath = mesh_path_lookup_by_idx(idx, dev); | ||
902 | if (!mpath) { | ||
903 | rcu_read_unlock(); | ||
904 | return -ENOENT; | ||
905 | } | ||
906 | memcpy(dst, mpath->dst, ETH_ALEN); | ||
907 | mpath_set_pinfo(mpath, next_hop, pinfo); | ||
908 | rcu_read_unlock(); | ||
654 | return 0; | 909 | return 0; |
655 | } | 910 | } |
911 | #endif | ||
656 | 912 | ||
657 | struct cfg80211_ops mac80211_config_ops = { | 913 | struct cfg80211_ops mac80211_config_ops = { |
658 | .add_virtual_intf = ieee80211_add_iface, | 914 | .add_virtual_intf = ieee80211_add_iface, |
@@ -669,4 +925,12 @@ struct cfg80211_ops mac80211_config_ops = { | |||
669 | .del_station = ieee80211_del_station, | 925 | .del_station = ieee80211_del_station, |
670 | .change_station = ieee80211_change_station, | 926 | .change_station = ieee80211_change_station, |
671 | .get_station = ieee80211_get_station, | 927 | .get_station = ieee80211_get_station, |
928 | .dump_station = ieee80211_dump_station, | ||
929 | #ifdef CONFIG_MAC80211_MESH | ||
930 | .add_mpath = ieee80211_add_mpath, | ||
931 | .del_mpath = ieee80211_del_mpath, | ||
932 | .change_mpath = ieee80211_change_mpath, | ||
933 | .get_mpath = ieee80211_get_mpath, | ||
934 | .dump_mpath = ieee80211_dump_mpath, | ||
935 | #endif | ||
672 | }; | 936 | }; |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 29f7b98ba1fb..107b0fe778d6 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -39,6 +39,29 @@ static ssize_t ieee80211_if_read( | |||
39 | return ret; | 39 | return ret; |
40 | } | 40 | } |
41 | 41 | ||
42 | #ifdef CONFIG_MAC80211_MESH | ||
43 | static ssize_t ieee80211_if_write( | ||
44 | struct ieee80211_sub_if_data *sdata, | ||
45 | char const __user *userbuf, | ||
46 | size_t count, loff_t *ppos, | ||
47 | int (*format)(struct ieee80211_sub_if_data *, char *)) | ||
48 | { | ||
49 | char buf[10]; | ||
50 | int buf_size; | ||
51 | |||
52 | memset(buf, 0x00, sizeof(buf)); | ||
53 | buf_size = min(count, (sizeof(buf)-1)); | ||
54 | read_lock(&dev_base_lock); | ||
55 | if (copy_from_user(buf, userbuf, buf_size)) | ||
56 | goto endwrite; | ||
57 | if (sdata->dev->reg_state == NETREG_REGISTERED) | ||
58 | (*format)(sdata, buf); | ||
59 | endwrite: | ||
60 | read_unlock(&dev_base_lock); | ||
61 | return count; | ||
62 | } | ||
63 | #endif | ||
64 | |||
42 | #define IEEE80211_IF_FMT(name, field, format_string) \ | 65 | #define IEEE80211_IF_FMT(name, field, format_string) \ |
43 | static ssize_t ieee80211_if_fmt_##name( \ | 66 | static ssize_t ieee80211_if_fmt_##name( \ |
44 | const struct ieee80211_sub_if_data *sdata, char *buf, \ | 67 | const struct ieee80211_sub_if_data *sdata, char *buf, \ |
@@ -46,6 +69,19 @@ static ssize_t ieee80211_if_fmt_##name( \ | |||
46 | { \ | 69 | { \ |
47 | return scnprintf(buf, buflen, format_string, sdata->field); \ | 70 | return scnprintf(buf, buflen, format_string, sdata->field); \ |
48 | } | 71 | } |
72 | #define IEEE80211_IF_WFMT(name, field, type) \ | ||
73 | static int ieee80211_if_wfmt_##name( \ | ||
74 | struct ieee80211_sub_if_data *sdata, char *buf) \ | ||
75 | { \ | ||
76 | unsigned long tmp; \ | ||
77 | char *endp; \ | ||
78 | \ | ||
79 | tmp = simple_strtoul(buf, &endp, 0); \ | ||
80 | if ((endp == buf) || ((type)tmp != tmp)) \ | ||
81 | return -EINVAL; \ | ||
82 | sdata->field = tmp; \ | ||
83 | return 0; \ | ||
84 | } | ||
49 | #define IEEE80211_IF_FMT_DEC(name, field) \ | 85 | #define IEEE80211_IF_FMT_DEC(name, field) \ |
50 | IEEE80211_IF_FMT(name, field, "%d\n") | 86 | IEEE80211_IF_FMT(name, field, "%d\n") |
51 | #define IEEE80211_IF_FMT_HEX(name, field) \ | 87 | #define IEEE80211_IF_FMT_HEX(name, field) \ |
@@ -88,6 +124,34 @@ static const struct file_operations name##_ops = { \ | |||
88 | IEEE80211_IF_FMT_##format(name, field) \ | 124 | IEEE80211_IF_FMT_##format(name, field) \ |
89 | __IEEE80211_IF_FILE(name) | 125 | __IEEE80211_IF_FILE(name) |
90 | 126 | ||
127 | #define __IEEE80211_IF_WFILE(name) \ | ||
128 | static ssize_t ieee80211_if_read_##name(struct file *file, \ | ||
129 | char __user *userbuf, \ | ||
130 | size_t count, loff_t *ppos) \ | ||
131 | { \ | ||
132 | return ieee80211_if_read(file->private_data, \ | ||
133 | userbuf, count, ppos, \ | ||
134 | ieee80211_if_fmt_##name); \ | ||
135 | } \ | ||
136 | static ssize_t ieee80211_if_write_##name(struct file *file, \ | ||
137 | const char __user *userbuf, \ | ||
138 | size_t count, loff_t *ppos) \ | ||
139 | { \ | ||
140 | return ieee80211_if_write(file->private_data, \ | ||
141 | userbuf, count, ppos, \ | ||
142 | ieee80211_if_wfmt_##name); \ | ||
143 | } \ | ||
144 | static const struct file_operations name##_ops = { \ | ||
145 | .read = ieee80211_if_read_##name, \ | ||
146 | .write = ieee80211_if_write_##name, \ | ||
147 | .open = mac80211_open_file_generic, \ | ||
148 | } | ||
149 | |||
150 | #define IEEE80211_IF_WFILE(name, field, format, type) \ | ||
151 | IEEE80211_IF_FMT_##format(name, field) \ | ||
152 | IEEE80211_IF_WFMT(name, field, type) \ | ||
153 | __IEEE80211_IF_WFILE(name) | ||
154 | |||
91 | /* common attributes */ | 155 | /* common attributes */ |
92 | IEEE80211_IF_FILE(channel_use, channel_use, DEC); | 156 | IEEE80211_IF_FILE(channel_use, channel_use, DEC); |
93 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); | 157 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); |
@@ -106,6 +170,7 @@ IEEE80211_IF_FILE(assoc_tries, u.sta.assoc_tries, DEC); | |||
106 | IEEE80211_IF_FILE(auth_algs, u.sta.auth_algs, HEX); | 170 | IEEE80211_IF_FILE(auth_algs, u.sta.auth_algs, HEX); |
107 | IEEE80211_IF_FILE(auth_alg, u.sta.auth_alg, DEC); | 171 | IEEE80211_IF_FILE(auth_alg, u.sta.auth_alg, DEC); |
108 | IEEE80211_IF_FILE(auth_transaction, u.sta.auth_transaction, DEC); | 172 | IEEE80211_IF_FILE(auth_transaction, u.sta.auth_transaction, DEC); |
173 | IEEE80211_IF_FILE(num_beacons_sta, u.sta.num_beacons, DEC); | ||
109 | 174 | ||
110 | static ssize_t ieee80211_if_fmt_flags( | 175 | static ssize_t ieee80211_if_fmt_flags( |
111 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | 176 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) |
@@ -139,6 +204,42 @@ __IEEE80211_IF_FILE(num_buffered_multicast); | |||
139 | /* WDS attributes */ | 204 | /* WDS attributes */ |
140 | IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); | 205 | IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); |
141 | 206 | ||
207 | #ifdef CONFIG_MAC80211_MESH | ||
208 | /* Mesh stats attributes */ | ||
209 | IEEE80211_IF_FILE(fwded_frames, u.sta.mshstats.fwded_frames, DEC); | ||
210 | IEEE80211_IF_FILE(dropped_frames_ttl, u.sta.mshstats.dropped_frames_ttl, DEC); | ||
211 | IEEE80211_IF_FILE(dropped_frames_no_route, | ||
212 | u.sta.mshstats.dropped_frames_no_route, DEC); | ||
213 | IEEE80211_IF_FILE(estab_plinks, u.sta.mshstats.estab_plinks, ATOMIC); | ||
214 | |||
215 | /* Mesh parameters */ | ||
216 | IEEE80211_IF_WFILE(dot11MeshMaxRetries, | ||
217 | u.sta.mshcfg.dot11MeshMaxRetries, DEC, u8); | ||
218 | IEEE80211_IF_WFILE(dot11MeshRetryTimeout, | ||
219 | u.sta.mshcfg.dot11MeshRetryTimeout, DEC, u16); | ||
220 | IEEE80211_IF_WFILE(dot11MeshConfirmTimeout, | ||
221 | u.sta.mshcfg.dot11MeshConfirmTimeout, DEC, u16); | ||
222 | IEEE80211_IF_WFILE(dot11MeshHoldingTimeout, | ||
223 | u.sta.mshcfg.dot11MeshHoldingTimeout, DEC, u16); | ||
224 | IEEE80211_IF_WFILE(dot11MeshTTL, u.sta.mshcfg.dot11MeshTTL, DEC, u8); | ||
225 | IEEE80211_IF_WFILE(auto_open_plinks, u.sta.mshcfg.auto_open_plinks, DEC, bool); | ||
226 | IEEE80211_IF_WFILE(dot11MeshMaxPeerLinks, | ||
227 | u.sta.mshcfg.dot11MeshMaxPeerLinks, DEC, u16); | ||
228 | IEEE80211_IF_WFILE(dot11MeshHWMPactivePathTimeout, | ||
229 | u.sta.mshcfg.dot11MeshHWMPactivePathTimeout, DEC, u32); | ||
230 | IEEE80211_IF_WFILE(dot11MeshHWMPpreqMinInterval, | ||
231 | u.sta.mshcfg.dot11MeshHWMPpreqMinInterval, DEC, u16); | ||
232 | IEEE80211_IF_WFILE(dot11MeshHWMPnetDiameterTraversalTime, | ||
233 | u.sta.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC, u16); | ||
234 | IEEE80211_IF_WFILE(dot11MeshHWMPmaxPREQretries, | ||
235 | u.sta.mshcfg.dot11MeshHWMPmaxPREQretries, DEC, u8); | ||
236 | IEEE80211_IF_WFILE(path_refresh_time, | ||
237 | u.sta.mshcfg.path_refresh_time, DEC, u32); | ||
238 | IEEE80211_IF_WFILE(min_discovery_timeout, | ||
239 | u.sta.mshcfg.min_discovery_timeout, DEC, u16); | ||
240 | #endif | ||
241 | |||
242 | |||
142 | #define DEBUGFS_ADD(name, type)\ | 243 | #define DEBUGFS_ADD(name, type)\ |
143 | sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\ | 244 | sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\ |
144 | sdata->debugfsdir, sdata, &name##_ops); | 245 | sdata->debugfsdir, sdata, &name##_ops); |
@@ -161,6 +262,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) | |||
161 | DEBUGFS_ADD(auth_alg, sta); | 262 | DEBUGFS_ADD(auth_alg, sta); |
162 | DEBUGFS_ADD(auth_transaction, sta); | 263 | DEBUGFS_ADD(auth_transaction, sta); |
163 | DEBUGFS_ADD(flags, sta); | 264 | DEBUGFS_ADD(flags, sta); |
265 | DEBUGFS_ADD(num_beacons_sta, sta); | ||
164 | } | 266 | } |
165 | 267 | ||
166 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) | 268 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) |
@@ -192,12 +294,57 @@ static void add_monitor_files(struct ieee80211_sub_if_data *sdata) | |||
192 | { | 294 | { |
193 | } | 295 | } |
194 | 296 | ||
297 | #ifdef CONFIG_MAC80211_MESH | ||
298 | #define MESHSTATS_ADD(name)\ | ||
299 | sdata->mesh_stats.name = debugfs_create_file(#name, 0444,\ | ||
300 | sdata->mesh_stats_dir, sdata, &name##_ops); | ||
301 | |||
302 | static void add_mesh_stats(struct ieee80211_sub_if_data *sdata) | ||
303 | { | ||
304 | sdata->mesh_stats_dir = debugfs_create_dir("mesh_stats", | ||
305 | sdata->debugfsdir); | ||
306 | MESHSTATS_ADD(fwded_frames); | ||
307 | MESHSTATS_ADD(dropped_frames_ttl); | ||
308 | MESHSTATS_ADD(dropped_frames_no_route); | ||
309 | MESHSTATS_ADD(estab_plinks); | ||
310 | } | ||
311 | |||
312 | #define MESHPARAMS_ADD(name)\ | ||
313 | sdata->mesh_config.name = debugfs_create_file(#name, 0644,\ | ||
314 | sdata->mesh_config_dir, sdata, &name##_ops); | ||
315 | |||
316 | static void add_mesh_config(struct ieee80211_sub_if_data *sdata) | ||
317 | { | ||
318 | sdata->mesh_config_dir = debugfs_create_dir("mesh_config", | ||
319 | sdata->debugfsdir); | ||
320 | MESHPARAMS_ADD(dot11MeshMaxRetries); | ||
321 | MESHPARAMS_ADD(dot11MeshRetryTimeout); | ||
322 | MESHPARAMS_ADD(dot11MeshConfirmTimeout); | ||
323 | MESHPARAMS_ADD(dot11MeshHoldingTimeout); | ||
324 | MESHPARAMS_ADD(dot11MeshTTL); | ||
325 | MESHPARAMS_ADD(auto_open_plinks); | ||
326 | MESHPARAMS_ADD(dot11MeshMaxPeerLinks); | ||
327 | MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout); | ||
328 | MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval); | ||
329 | MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime); | ||
330 | MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries); | ||
331 | MESHPARAMS_ADD(path_refresh_time); | ||
332 | MESHPARAMS_ADD(min_discovery_timeout); | ||
333 | } | ||
334 | #endif | ||
335 | |||
195 | static void add_files(struct ieee80211_sub_if_data *sdata) | 336 | static void add_files(struct ieee80211_sub_if_data *sdata) |
196 | { | 337 | { |
197 | if (!sdata->debugfsdir) | 338 | if (!sdata->debugfsdir) |
198 | return; | 339 | return; |
199 | 340 | ||
200 | switch (sdata->vif.type) { | 341 | switch (sdata->vif.type) { |
342 | case IEEE80211_IF_TYPE_MESH_POINT: | ||
343 | #ifdef CONFIG_MAC80211_MESH | ||
344 | add_mesh_stats(sdata); | ||
345 | add_mesh_config(sdata); | ||
346 | #endif | ||
347 | /* fall through */ | ||
201 | case IEEE80211_IF_TYPE_STA: | 348 | case IEEE80211_IF_TYPE_STA: |
202 | case IEEE80211_IF_TYPE_IBSS: | 349 | case IEEE80211_IF_TYPE_IBSS: |
203 | add_sta_files(sdata); | 350 | add_sta_files(sdata); |
@@ -243,6 +390,7 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata) | |||
243 | DEBUGFS_DEL(auth_alg, sta); | 390 | DEBUGFS_DEL(auth_alg, sta); |
244 | DEBUGFS_DEL(auth_transaction, sta); | 391 | DEBUGFS_DEL(auth_transaction, sta); |
245 | DEBUGFS_DEL(flags, sta); | 392 | DEBUGFS_DEL(flags, sta); |
393 | DEBUGFS_DEL(num_beacons_sta, sta); | ||
246 | } | 394 | } |
247 | 395 | ||
248 | static void del_ap_files(struct ieee80211_sub_if_data *sdata) | 396 | static void del_ap_files(struct ieee80211_sub_if_data *sdata) |
@@ -274,12 +422,61 @@ static void del_monitor_files(struct ieee80211_sub_if_data *sdata) | |||
274 | { | 422 | { |
275 | } | 423 | } |
276 | 424 | ||
425 | #ifdef CONFIG_MAC80211_MESH | ||
426 | #define MESHSTATS_DEL(name) \ | ||
427 | do { \ | ||
428 | debugfs_remove(sdata->mesh_stats.name); \ | ||
429 | sdata->mesh_stats.name = NULL; \ | ||
430 | } while (0) | ||
431 | |||
432 | static void del_mesh_stats(struct ieee80211_sub_if_data *sdata) | ||
433 | { | ||
434 | MESHSTATS_DEL(fwded_frames); | ||
435 | MESHSTATS_DEL(dropped_frames_ttl); | ||
436 | MESHSTATS_DEL(dropped_frames_no_route); | ||
437 | MESHSTATS_DEL(estab_plinks); | ||
438 | debugfs_remove(sdata->mesh_stats_dir); | ||
439 | sdata->mesh_stats_dir = NULL; | ||
440 | } | ||
441 | |||
442 | #define MESHPARAMS_DEL(name) \ | ||
443 | do { \ | ||
444 | debugfs_remove(sdata->mesh_config.name); \ | ||
445 | sdata->mesh_config.name = NULL; \ | ||
446 | } while (0) | ||
447 | |||
448 | static void del_mesh_config(struct ieee80211_sub_if_data *sdata) | ||
449 | { | ||
450 | MESHPARAMS_DEL(dot11MeshMaxRetries); | ||
451 | MESHPARAMS_DEL(dot11MeshRetryTimeout); | ||
452 | MESHPARAMS_DEL(dot11MeshConfirmTimeout); | ||
453 | MESHPARAMS_DEL(dot11MeshHoldingTimeout); | ||
454 | MESHPARAMS_DEL(dot11MeshTTL); | ||
455 | MESHPARAMS_DEL(auto_open_plinks); | ||
456 | MESHPARAMS_DEL(dot11MeshMaxPeerLinks); | ||
457 | MESHPARAMS_DEL(dot11MeshHWMPactivePathTimeout); | ||
458 | MESHPARAMS_DEL(dot11MeshHWMPpreqMinInterval); | ||
459 | MESHPARAMS_DEL(dot11MeshHWMPnetDiameterTraversalTime); | ||
460 | MESHPARAMS_DEL(dot11MeshHWMPmaxPREQretries); | ||
461 | MESHPARAMS_DEL(path_refresh_time); | ||
462 | MESHPARAMS_DEL(min_discovery_timeout); | ||
463 | debugfs_remove(sdata->mesh_config_dir); | ||
464 | sdata->mesh_config_dir = NULL; | ||
465 | } | ||
466 | #endif | ||
467 | |||
277 | static void del_files(struct ieee80211_sub_if_data *sdata, int type) | 468 | static void del_files(struct ieee80211_sub_if_data *sdata, int type) |
278 | { | 469 | { |
279 | if (!sdata->debugfsdir) | 470 | if (!sdata->debugfsdir) |
280 | return; | 471 | return; |
281 | 472 | ||
282 | switch (type) { | 473 | switch (type) { |
474 | case IEEE80211_IF_TYPE_MESH_POINT: | ||
475 | #ifdef CONFIG_MAC80211_MESH | ||
476 | del_mesh_stats(sdata); | ||
477 | del_mesh_config(sdata); | ||
478 | #endif | ||
479 | /* fall through */ | ||
283 | case IEEE80211_IF_TYPE_STA: | 480 | case IEEE80211_IF_TYPE_STA: |
284 | case IEEE80211_IF_TYPE_IBSS: | 481 | case IEEE80211_IF_TYPE_IBSS: |
285 | del_sta_files(sdata); | 482 | del_sta_files(sdata); |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index ed7c9f3b4602..fc2c1a192ed2 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -51,7 +51,7 @@ static const struct file_operations sta_ ##name## _ops = { \ | |||
51 | STA_OPS(name) | 51 | STA_OPS(name) |
52 | 52 | ||
53 | STA_FILE(aid, aid, D); | 53 | STA_FILE(aid, aid, D); |
54 | STA_FILE(dev, dev->name, S); | 54 | STA_FILE(dev, sdata->dev->name, S); |
55 | STA_FILE(rx_packets, rx_packets, LU); | 55 | STA_FILE(rx_packets, rx_packets, LU); |
56 | STA_FILE(tx_packets, tx_packets, LU); | 56 | STA_FILE(tx_packets, tx_packets, LU); |
57 | STA_FILE(rx_bytes, rx_bytes, LU); | 57 | STA_FILE(rx_bytes, rx_bytes, LU); |
@@ -67,7 +67,7 @@ STA_FILE(last_rssi, last_rssi, D); | |||
67 | STA_FILE(last_signal, last_signal, D); | 67 | STA_FILE(last_signal, last_signal, D); |
68 | STA_FILE(last_noise, last_noise, D); | 68 | STA_FILE(last_noise, last_noise, D); |
69 | STA_FILE(channel_use, channel_use, D); | 69 | STA_FILE(channel_use, channel_use, D); |
70 | STA_FILE(wep_weak_iv_count, wep_weak_iv_count, D); | 70 | STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU); |
71 | 71 | ||
72 | static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | 72 | static ssize_t sta_flags_read(struct file *file, char __user *userbuf, |
73 | size_t count, loff_t *ppos) | 73 | size_t count, loff_t *ppos) |
@@ -200,7 +200,7 @@ static ssize_t sta_agg_status_write(struct file *file, | |||
200 | const char __user *user_buf, size_t count, loff_t *ppos) | 200 | const char __user *user_buf, size_t count, loff_t *ppos) |
201 | { | 201 | { |
202 | struct sta_info *sta = file->private_data; | 202 | struct sta_info *sta = file->private_data; |
203 | struct net_device *dev = sta->dev; | 203 | struct net_device *dev = sta->sdata->dev; |
204 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 204 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
205 | struct ieee80211_hw *hw = &local->hw; | 205 | struct ieee80211_hw *hw = &local->hw; |
206 | u8 *da = sta->addr; | 206 | u8 *da = sta->addr; |
diff --git a/net/mac80211/debugfs_sta.h b/net/mac80211/debugfs_sta.h index 574a1cd54b96..8b608903259f 100644 --- a/net/mac80211/debugfs_sta.h +++ b/net/mac80211/debugfs_sta.h | |||
@@ -1,6 +1,8 @@ | |||
1 | #ifndef __MAC80211_DEBUGFS_STA_H | 1 | #ifndef __MAC80211_DEBUGFS_STA_H |
2 | #define __MAC80211_DEBUGFS_STA_H | 2 | #define __MAC80211_DEBUGFS_STA_H |
3 | 3 | ||
4 | #include "sta_info.h" | ||
5 | |||
4 | #ifdef CONFIG_MAC80211_DEBUGFS | 6 | #ifdef CONFIG_MAC80211_DEBUGFS |
5 | void ieee80211_sta_debugfs_add(struct sta_info *sta); | 7 | void ieee80211_sta_debugfs_add(struct sta_info *sta); |
6 | void ieee80211_sta_debugfs_remove(struct sta_info *sta); | 8 | void ieee80211_sta_debugfs_remove(struct sta_info *sta); |
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 2133c9fd27a4..484b063a3538 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | #include "ieee80211_i.h" | 27 | #include "ieee80211_i.h" |
28 | #include "ieee80211_rate.h" | 28 | #include "ieee80211_rate.h" |
29 | #include "mesh.h" | ||
29 | #include "wep.h" | 30 | #include "wep.h" |
30 | #include "wme.h" | 31 | #include "wme.h" |
31 | #include "aes_ccm.h" | 32 | #include "aes_ccm.h" |
@@ -138,9 +139,15 @@ static void ieee80211_master_set_multicast_list(struct net_device *dev) | |||
138 | 139 | ||
139 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | 140 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) |
140 | { | 141 | { |
142 | int meshhdrlen; | ||
143 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
144 | |||
145 | meshhdrlen = (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) ? 5 : 0; | ||
146 | |||
141 | /* FIX: what would be proper limits for MTU? | 147 | /* FIX: what would be proper limits for MTU? |
142 | * This interface uses 802.3 frames. */ | 148 | * This interface uses 802.3 frames. */ |
143 | if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) { | 149 | if (new_mtu < 256 || |
150 | new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) { | ||
144 | printk(KERN_WARNING "%s: invalid MTU %d\n", | 151 | printk(KERN_WARNING "%s: invalid MTU %d\n", |
145 | dev->name, new_mtu); | 152 | dev->name, new_mtu); |
146 | return -EINVAL; | 153 | return -EINVAL; |
@@ -176,6 +183,7 @@ static int ieee80211_open(struct net_device *dev) | |||
176 | struct ieee80211_if_init_conf conf; | 183 | struct ieee80211_if_init_conf conf; |
177 | int res; | 184 | int res; |
178 | bool need_hw_reconfig = 0; | 185 | bool need_hw_reconfig = 0; |
186 | struct sta_info *sta; | ||
179 | 187 | ||
180 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 188 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
181 | 189 | ||
@@ -249,6 +257,20 @@ static int ieee80211_open(struct net_device *dev) | |||
249 | case IEEE80211_IF_TYPE_WDS: | 257 | case IEEE80211_IF_TYPE_WDS: |
250 | if (is_zero_ether_addr(sdata->u.wds.remote_addr)) | 258 | if (is_zero_ether_addr(sdata->u.wds.remote_addr)) |
251 | return -ENOLINK; | 259 | return -ENOLINK; |
260 | |||
261 | /* Create STA entry for the WDS peer */ | ||
262 | sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, | ||
263 | GFP_KERNEL); | ||
264 | if (!sta) | ||
265 | return -ENOMEM; | ||
266 | |||
267 | sta->flags |= WLAN_STA_AUTHORIZED; | ||
268 | |||
269 | res = sta_info_insert(sta); | ||
270 | if (res) { | ||
271 | sta_info_destroy(sta); | ||
272 | return res; | ||
273 | } | ||
252 | break; | 274 | break; |
253 | case IEEE80211_IF_TYPE_VLAN: | 275 | case IEEE80211_IF_TYPE_VLAN: |
254 | if (!sdata->u.vlan.ap) | 276 | if (!sdata->u.vlan.ap) |
@@ -258,6 +280,7 @@ static int ieee80211_open(struct net_device *dev) | |||
258 | case IEEE80211_IF_TYPE_STA: | 280 | case IEEE80211_IF_TYPE_STA: |
259 | case IEEE80211_IF_TYPE_MNTR: | 281 | case IEEE80211_IF_TYPE_MNTR: |
260 | case IEEE80211_IF_TYPE_IBSS: | 282 | case IEEE80211_IF_TYPE_IBSS: |
283 | case IEEE80211_IF_TYPE_MESH_POINT: | ||
261 | /* no special treatment */ | 284 | /* no special treatment */ |
262 | break; | 285 | break; |
263 | case IEEE80211_IF_TYPE_INVALID: | 286 | case IEEE80211_IF_TYPE_INVALID: |
@@ -359,24 +382,51 @@ static int ieee80211_open(struct net_device *dev) | |||
359 | 382 | ||
360 | static int ieee80211_stop(struct net_device *dev) | 383 | static int ieee80211_stop(struct net_device *dev) |
361 | { | 384 | { |
362 | struct ieee80211_sub_if_data *sdata; | 385 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
363 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 386 | struct ieee80211_local *local = sdata->local; |
364 | struct ieee80211_if_init_conf conf; | 387 | struct ieee80211_if_init_conf conf; |
365 | struct sta_info *sta; | 388 | struct sta_info *sta; |
366 | int i; | 389 | int i; |
367 | 390 | ||
368 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 391 | /* |
392 | * Stop TX on this interface first. | ||
393 | */ | ||
394 | netif_stop_queue(dev); | ||
369 | 395 | ||
370 | list_for_each_entry(sta, &local->sta_list, list) { | 396 | /* |
371 | if (sta->dev == dev) | 397 | * Now delete all active aggregation sessions. |
398 | */ | ||
399 | rcu_read_lock(); | ||
400 | |||
401 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
402 | if (sta->sdata == sdata) | ||
372 | for (i = 0; i < STA_TID_NUM; i++) | 403 | for (i = 0; i < STA_TID_NUM; i++) |
373 | ieee80211_sta_stop_rx_ba_session(sta->dev, | 404 | ieee80211_sta_stop_rx_ba_session(sdata->dev, |
374 | sta->addr, i, | 405 | sta->addr, i, |
375 | WLAN_BACK_RECIPIENT, | 406 | WLAN_BACK_RECIPIENT, |
376 | WLAN_REASON_QSTA_LEAVE_QBSS); | 407 | WLAN_REASON_QSTA_LEAVE_QBSS); |
377 | } | 408 | } |
378 | 409 | ||
379 | netif_stop_queue(dev); | 410 | rcu_read_unlock(); |
411 | |||
412 | /* | ||
413 | * Remove all stations associated with this interface. | ||
414 | * | ||
415 | * This must be done before calling ops->remove_interface() | ||
416 | * because otherwise we can later invoke ops->sta_notify() | ||
417 | * whenever the STAs are removed, and that invalidates driver | ||
418 | * assumptions about always getting a vif pointer that is valid | ||
419 | * (because if we remove a STA after ops->remove_interface() | ||
420 | * the driver will have removed the vif info already!) | ||
421 | * | ||
422 | * We could relax this and only unlink the stations from the | ||
423 | * hash table and list but keep them on a per-sdata list that | ||
424 | * will be inserted back again when the interface is brought | ||
425 | * up again, but I don't currently see a use case for that, | ||
426 | * except with WDS which gets a STA entry created when it is | ||
427 | * brought up. | ||
428 | */ | ||
429 | sta_info_flush(local, sdata); | ||
380 | 430 | ||
381 | /* | 431 | /* |
382 | * Don't count this interface for promisc/allmulti while it | 432 | * Don't count this interface for promisc/allmulti while it |
@@ -440,6 +490,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
440 | ieee80211_configure_filter(local); | 490 | ieee80211_configure_filter(local); |
441 | netif_tx_unlock_bh(local->mdev); | 491 | netif_tx_unlock_bh(local->mdev); |
442 | break; | 492 | break; |
493 | case IEEE80211_IF_TYPE_MESH_POINT: | ||
443 | case IEEE80211_IF_TYPE_STA: | 494 | case IEEE80211_IF_TYPE_STA: |
444 | case IEEE80211_IF_TYPE_IBSS: | 495 | case IEEE80211_IF_TYPE_IBSS: |
445 | sdata->u.sta.state = IEEE80211_DISABLED; | 496 | sdata->u.sta.state = IEEE80211_DISABLED; |
@@ -511,9 +562,12 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
511 | print_mac(mac, ra), tid); | 562 | print_mac(mac, ra), tid); |
512 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 563 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
513 | 564 | ||
565 | rcu_read_lock(); | ||
566 | |||
514 | sta = sta_info_get(local, ra); | 567 | sta = sta_info_get(local, ra); |
515 | if (!sta) { | 568 | if (!sta) { |
516 | printk(KERN_DEBUG "Could not find the station\n"); | 569 | printk(KERN_DEBUG "Could not find the station\n"); |
570 | rcu_read_unlock(); | ||
517 | return -ENOENT; | 571 | return -ENOENT; |
518 | } | 572 | } |
519 | 573 | ||
@@ -553,7 +607,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
553 | spin_unlock_bh(&local->mdev->queue_lock); | 607 | spin_unlock_bh(&local->mdev->queue_lock); |
554 | goto start_ba_exit; | 608 | goto start_ba_exit; |
555 | } | 609 | } |
556 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 610 | sdata = sta->sdata; |
557 | 611 | ||
558 | /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the | 612 | /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the |
559 | * call back right away, it must see that the flow has begun */ | 613 | * call back right away, it must see that the flow has begun */ |
@@ -590,7 +644,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
590 | sta->ampdu_mlme.dialog_token_allocator; | 644 | sta->ampdu_mlme.dialog_token_allocator; |
591 | sta->ampdu_mlme.tid_tx[tid].ssn = start_seq_num; | 645 | sta->ampdu_mlme.tid_tx[tid].ssn = start_seq_num; |
592 | 646 | ||
593 | ieee80211_send_addba_request(sta->dev, ra, tid, | 647 | ieee80211_send_addba_request(sta->sdata->dev, ra, tid, |
594 | sta->ampdu_mlme.tid_tx[tid].dialog_token, | 648 | sta->ampdu_mlme.tid_tx[tid].dialog_token, |
595 | sta->ampdu_mlme.tid_tx[tid].ssn, | 649 | sta->ampdu_mlme.tid_tx[tid].ssn, |
596 | 0x40, 5000); | 650 | 0x40, 5000); |
@@ -603,7 +657,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
603 | 657 | ||
604 | start_ba_exit: | 658 | start_ba_exit: |
605 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); | 659 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); |
606 | sta_info_put(sta); | 660 | rcu_read_unlock(); |
607 | return ret; | 661 | return ret; |
608 | } | 662 | } |
609 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); | 663 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); |
@@ -626,9 +680,12 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, | |||
626 | print_mac(mac, ra), tid); | 680 | print_mac(mac, ra), tid); |
627 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 681 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
628 | 682 | ||
683 | rcu_read_lock(); | ||
629 | sta = sta_info_get(local, ra); | 684 | sta = sta_info_get(local, ra); |
630 | if (!sta) | 685 | if (!sta) { |
686 | rcu_read_unlock(); | ||
631 | return -ENOENT; | 687 | return -ENOENT; |
688 | } | ||
632 | 689 | ||
633 | /* check if the TID is in aggregation */ | 690 | /* check if the TID is in aggregation */ |
634 | state = &sta->ampdu_mlme.tid_tx[tid].state; | 691 | state = &sta->ampdu_mlme.tid_tx[tid].state; |
@@ -662,7 +719,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, | |||
662 | 719 | ||
663 | stop_BA_exit: | 720 | stop_BA_exit: |
664 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); | 721 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); |
665 | sta_info_put(sta); | 722 | rcu_read_unlock(); |
666 | return ret; | 723 | return ret; |
667 | } | 724 | } |
668 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); | 725 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); |
@@ -680,8 +737,10 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
680 | return; | 737 | return; |
681 | } | 738 | } |
682 | 739 | ||
740 | rcu_read_lock(); | ||
683 | sta = sta_info_get(local, ra); | 741 | sta = sta_info_get(local, ra); |
684 | if (!sta) { | 742 | if (!sta) { |
743 | rcu_read_unlock(); | ||
685 | printk(KERN_DEBUG "Could not find station: %s\n", | 744 | printk(KERN_DEBUG "Could not find station: %s\n", |
686 | print_mac(mac, ra)); | 745 | print_mac(mac, ra)); |
687 | return; | 746 | return; |
@@ -694,7 +753,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
694 | printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", | 753 | printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", |
695 | *state); | 754 | *state); |
696 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); | 755 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); |
697 | sta_info_put(sta); | 756 | rcu_read_unlock(); |
698 | return; | 757 | return; |
699 | } | 758 | } |
700 | 759 | ||
@@ -707,7 +766,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
707 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | 766 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); |
708 | } | 767 | } |
709 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); | 768 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); |
710 | sta_info_put(sta); | 769 | rcu_read_unlock(); |
711 | } | 770 | } |
712 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); | 771 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); |
713 | 772 | ||
@@ -728,10 +787,12 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | |||
728 | printk(KERN_DEBUG "Stop a BA session requested on DA %s tid %d\n", | 787 | printk(KERN_DEBUG "Stop a BA session requested on DA %s tid %d\n", |
729 | print_mac(mac, ra), tid); | 788 | print_mac(mac, ra), tid); |
730 | 789 | ||
790 | rcu_read_lock(); | ||
731 | sta = sta_info_get(local, ra); | 791 | sta = sta_info_get(local, ra); |
732 | if (!sta) { | 792 | if (!sta) { |
733 | printk(KERN_DEBUG "Could not find station: %s\n", | 793 | printk(KERN_DEBUG "Could not find station: %s\n", |
734 | print_mac(mac, ra)); | 794 | print_mac(mac, ra)); |
795 | rcu_read_unlock(); | ||
735 | return; | 796 | return; |
736 | } | 797 | } |
737 | state = &sta->ampdu_mlme.tid_tx[tid].state; | 798 | state = &sta->ampdu_mlme.tid_tx[tid].state; |
@@ -739,13 +800,13 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | |||
739 | spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); | 800 | spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); |
740 | if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { | 801 | if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { |
741 | printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); | 802 | printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); |
742 | sta_info_put(sta); | ||
743 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); | 803 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); |
804 | rcu_read_unlock(); | ||
744 | return; | 805 | return; |
745 | } | 806 | } |
746 | 807 | ||
747 | if (*state & HT_AGG_STATE_INITIATOR_MSK) | 808 | if (*state & HT_AGG_STATE_INITIATOR_MSK) |
748 | ieee80211_send_delba(sta->dev, ra, tid, | 809 | ieee80211_send_delba(sta->sdata->dev, ra, tid, |
749 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); | 810 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); |
750 | 811 | ||
751 | agg_queue = sta->tid_to_tx_q[tid]; | 812 | agg_queue = sta->tid_to_tx_q[tid]; |
@@ -766,7 +827,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | |||
766 | sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0; | 827 | sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0; |
767 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); | 828 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); |
768 | 829 | ||
769 | sta_info_put(sta); | 830 | rcu_read_unlock(); |
770 | } | 831 | } |
771 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); | 832 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); |
772 | 833 | ||
@@ -867,44 +928,6 @@ void ieee80211_if_setup(struct net_device *dev) | |||
867 | dev->destructor = ieee80211_if_free; | 928 | dev->destructor = ieee80211_if_free; |
868 | } | 929 | } |
869 | 930 | ||
870 | /* WDS specialties */ | ||
871 | |||
872 | int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) | ||
873 | { | ||
874 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
875 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
876 | struct sta_info *sta; | ||
877 | DECLARE_MAC_BUF(mac); | ||
878 | |||
879 | if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) | ||
880 | return 0; | ||
881 | |||
882 | /* Create STA entry for the new peer */ | ||
883 | sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL); | ||
884 | if (IS_ERR(sta)) | ||
885 | return PTR_ERR(sta); | ||
886 | |||
887 | sta->flags |= WLAN_STA_AUTHORIZED; | ||
888 | |||
889 | sta_info_put(sta); | ||
890 | |||
891 | /* Remove STA entry for the old peer */ | ||
892 | sta = sta_info_get(local, sdata->u.wds.remote_addr); | ||
893 | if (sta) { | ||
894 | sta_info_free(sta); | ||
895 | sta_info_put(sta); | ||
896 | } else { | ||
897 | printk(KERN_DEBUG "%s: could not find STA entry for WDS link " | ||
898 | "peer %s\n", | ||
899 | dev->name, print_mac(mac, sdata->u.wds.remote_addr)); | ||
900 | } | ||
901 | |||
902 | /* Update WDS link data */ | ||
903 | memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN); | ||
904 | |||
905 | return 0; | ||
906 | } | ||
907 | |||
908 | /* everything else */ | 931 | /* everything else */ |
909 | 932 | ||
910 | static int __ieee80211_if_config(struct net_device *dev, | 933 | static int __ieee80211_if_config(struct net_device *dev, |
@@ -925,6 +948,9 @@ static int __ieee80211_if_config(struct net_device *dev, | |||
925 | conf.bssid = sdata->u.sta.bssid; | 948 | conf.bssid = sdata->u.sta.bssid; |
926 | conf.ssid = sdata->u.sta.ssid; | 949 | conf.ssid = sdata->u.sta.ssid; |
927 | conf.ssid_len = sdata->u.sta.ssid_len; | 950 | conf.ssid_len = sdata->u.sta.ssid_len; |
951 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
952 | conf.beacon = beacon; | ||
953 | ieee80211_start_mesh(dev); | ||
928 | } else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { | 954 | } else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { |
929 | conf.ssid = sdata->u.ap.ssid; | 955 | conf.ssid = sdata->u.ap.ssid; |
930 | conf.ssid_len = sdata->u.ap.ssid_len; | 956 | conf.ssid_len = sdata->u.ap.ssid_len; |
@@ -937,6 +963,11 @@ static int __ieee80211_if_config(struct net_device *dev, | |||
937 | 963 | ||
938 | int ieee80211_if_config(struct net_device *dev) | 964 | int ieee80211_if_config(struct net_device *dev) |
939 | { | 965 | { |
966 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
967 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
968 | if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && | ||
969 | (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE)) | ||
970 | return ieee80211_if_config_beacon(dev); | ||
940 | return __ieee80211_if_config(dev, NULL, NULL); | 971 | return __ieee80211_if_config(dev, NULL, NULL); |
941 | } | 972 | } |
942 | 973 | ||
@@ -1311,6 +1342,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
1311 | return; | 1342 | return; |
1312 | } | 1343 | } |
1313 | 1344 | ||
1345 | rcu_read_lock(); | ||
1346 | |||
1314 | if (status->excessive_retries) { | 1347 | if (status->excessive_retries) { |
1315 | struct sta_info *sta; | 1348 | struct sta_info *sta; |
1316 | sta = sta_info_get(local, hdr->addr1); | 1349 | sta = sta_info_get(local, hdr->addr1); |
@@ -1324,10 +1357,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
1324 | status->flags |= IEEE80211_TX_STATUS_TX_FILTERED; | 1357 | status->flags |= IEEE80211_TX_STATUS_TX_FILTERED; |
1325 | ieee80211_handle_filtered_frame(local, sta, | 1358 | ieee80211_handle_filtered_frame(local, sta, |
1326 | skb, status); | 1359 | skb, status); |
1327 | sta_info_put(sta); | 1360 | rcu_read_unlock(); |
1328 | return; | 1361 | return; |
1329 | } | 1362 | } |
1330 | sta_info_put(sta); | ||
1331 | } | 1363 | } |
1332 | } | 1364 | } |
1333 | 1365 | ||
@@ -1337,12 +1369,14 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
1337 | if (sta) { | 1369 | if (sta) { |
1338 | ieee80211_handle_filtered_frame(local, sta, skb, | 1370 | ieee80211_handle_filtered_frame(local, sta, skb, |
1339 | status); | 1371 | status); |
1340 | sta_info_put(sta); | 1372 | rcu_read_unlock(); |
1341 | return; | 1373 | return; |
1342 | } | 1374 | } |
1343 | } else | 1375 | } else |
1344 | rate_control_tx_status(local->mdev, skb, status); | 1376 | rate_control_tx_status(local->mdev, skb, status); |
1345 | 1377 | ||
1378 | rcu_read_unlock(); | ||
1379 | |||
1346 | ieee80211_led_tx(local, 0); | 1380 | ieee80211_led_tx(local, 0); |
1347 | 1381 | ||
1348 | /* SNMP counters | 1382 | /* SNMP counters |
@@ -1662,7 +1696,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
1662 | 1696 | ||
1663 | /* add one default STA interface */ | 1697 | /* add one default STA interface */ |
1664 | result = ieee80211_if_add(local->mdev, "wlan%d", NULL, | 1698 | result = ieee80211_if_add(local->mdev, "wlan%d", NULL, |
1665 | IEEE80211_IF_TYPE_STA); | 1699 | IEEE80211_IF_TYPE_STA, NULL); |
1666 | if (result) | 1700 | if (result) |
1667 | printk(KERN_WARNING "%s: Failed to add default virtual iface\n", | 1701 | printk(KERN_WARNING "%s: Failed to add default virtual iface\n", |
1668 | wiphy_name(local->hw.wiphy)); | 1702 | wiphy_name(local->hw.wiphy)); |
@@ -1801,6 +1835,9 @@ static void __exit ieee80211_exit(void) | |||
1801 | rc80211_simple_exit(); | 1835 | rc80211_simple_exit(); |
1802 | rc80211_pid_exit(); | 1836 | rc80211_pid_exit(); |
1803 | 1837 | ||
1838 | if (mesh_allocated) | ||
1839 | ieee80211s_stop(); | ||
1840 | |||
1804 | ieee80211_wme_unregister(); | 1841 | ieee80211_wme_unregister(); |
1805 | ieee80211_debugfs_netdev_exit(); | 1842 | ieee80211_debugfs_netdev_exit(); |
1806 | } | 1843 | } |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b07b3cbfd039..7f10ff5d4a0b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -90,6 +90,11 @@ struct ieee80211_sta_bss { | |||
90 | size_t wmm_ie_len; | 90 | size_t wmm_ie_len; |
91 | u8 *ht_ie; | 91 | u8 *ht_ie; |
92 | size_t ht_ie_len; | 92 | size_t ht_ie_len; |
93 | #ifdef CONFIG_MAC80211_MESH | ||
94 | u8 *mesh_id; | ||
95 | size_t mesh_id_len; | ||
96 | u8 *mesh_cfg; | ||
97 | #endif | ||
93 | #define IEEE80211_MAX_SUPP_RATES 32 | 98 | #define IEEE80211_MAX_SUPP_RATES 32 |
94 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | 99 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; |
95 | size_t supp_rates_len; | 100 | size_t supp_rates_len; |
@@ -107,32 +112,81 @@ struct ieee80211_sta_bss { | |||
107 | u8 erp_value; | 112 | u8 erp_value; |
108 | }; | 113 | }; |
109 | 114 | ||
115 | static inline u8 *bss_mesh_cfg(struct ieee80211_sta_bss *bss) | ||
116 | { | ||
117 | #ifdef CONFIG_MAC80211_MESH | ||
118 | return bss->mesh_cfg; | ||
119 | #endif | ||
120 | return NULL; | ||
121 | } | ||
122 | |||
123 | static inline u8 *bss_mesh_id(struct ieee80211_sta_bss *bss) | ||
124 | { | ||
125 | #ifdef CONFIG_MAC80211_MESH | ||
126 | return bss->mesh_id; | ||
127 | #endif | ||
128 | return NULL; | ||
129 | } | ||
130 | |||
131 | static inline u8 bss_mesh_id_len(struct ieee80211_sta_bss *bss) | ||
132 | { | ||
133 | #ifdef CONFIG_MAC80211_MESH | ||
134 | return bss->mesh_id_len; | ||
135 | #endif | ||
136 | return 0; | ||
137 | } | ||
138 | |||
110 | 139 | ||
111 | typedef unsigned __bitwise__ ieee80211_tx_result; | 140 | typedef unsigned __bitwise__ ieee80211_tx_result; |
112 | #define TX_CONTINUE ((__force ieee80211_tx_result) 0u) | 141 | #define TX_CONTINUE ((__force ieee80211_tx_result) 0u) |
113 | #define TX_DROP ((__force ieee80211_tx_result) 1u) | 142 | #define TX_DROP ((__force ieee80211_tx_result) 1u) |
114 | #define TX_QUEUED ((__force ieee80211_tx_result) 2u) | 143 | #define TX_QUEUED ((__force ieee80211_tx_result) 2u) |
115 | 144 | ||
145 | #define IEEE80211_TX_FRAGMENTED BIT(0) | ||
146 | #define IEEE80211_TX_UNICAST BIT(1) | ||
147 | #define IEEE80211_TX_PS_BUFFERED BIT(2) | ||
148 | #define IEEE80211_TX_PROBE_LAST_FRAG BIT(3) | ||
149 | #define IEEE80211_TX_INJECTED BIT(4) | ||
150 | |||
151 | struct ieee80211_tx_data { | ||
152 | struct sk_buff *skb; | ||
153 | struct net_device *dev; | ||
154 | struct ieee80211_local *local; | ||
155 | struct ieee80211_sub_if_data *sdata; | ||
156 | struct sta_info *sta; | ||
157 | u16 fc, ethertype; | ||
158 | struct ieee80211_key *key; | ||
159 | unsigned int flags; | ||
160 | |||
161 | struct ieee80211_tx_control *control; | ||
162 | struct ieee80211_channel *channel; | ||
163 | struct ieee80211_rate *rate; | ||
164 | /* use this rate (if set) for last fragment; rate can | ||
165 | * be set to lower rate for the first fragments, e.g., | ||
166 | * when using CTS protection with IEEE 802.11g. */ | ||
167 | struct ieee80211_rate *last_frag_rate; | ||
168 | |||
169 | /* Extra fragments (in addition to the first fragment | ||
170 | * in skb) */ | ||
171 | int num_extra_frag; | ||
172 | struct sk_buff **extra_frag; | ||
173 | }; | ||
174 | |||
175 | |||
116 | typedef unsigned __bitwise__ ieee80211_rx_result; | 176 | typedef unsigned __bitwise__ ieee80211_rx_result; |
117 | #define RX_CONTINUE ((__force ieee80211_rx_result) 0u) | 177 | #define RX_CONTINUE ((__force ieee80211_rx_result) 0u) |
118 | #define RX_DROP_UNUSABLE ((__force ieee80211_rx_result) 1u) | 178 | #define RX_DROP_UNUSABLE ((__force ieee80211_rx_result) 1u) |
119 | #define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u) | 179 | #define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u) |
120 | #define RX_QUEUED ((__force ieee80211_rx_result) 3u) | 180 | #define RX_QUEUED ((__force ieee80211_rx_result) 3u) |
121 | 181 | ||
122 | 182 | #define IEEE80211_RX_IN_SCAN BIT(0) | |
123 | /* flags used in struct ieee80211_txrx_data.flags */ | ||
124 | /* whether the MSDU was fragmented */ | ||
125 | #define IEEE80211_TXRXD_FRAGMENTED BIT(0) | ||
126 | #define IEEE80211_TXRXD_TXUNICAST BIT(1) | ||
127 | #define IEEE80211_TXRXD_TXPS_BUFFERED BIT(2) | ||
128 | #define IEEE80211_TXRXD_TXPROBE_LAST_FRAG BIT(3) | ||
129 | #define IEEE80211_TXRXD_RXIN_SCAN BIT(4) | ||
130 | /* frame is destined to interface currently processed (incl. multicast frames) */ | 183 | /* frame is destined to interface currently processed (incl. multicast frames) */ |
131 | #define IEEE80211_TXRXD_RXRA_MATCH BIT(5) | 184 | #define IEEE80211_RX_RA_MATCH BIT(1) |
132 | #define IEEE80211_TXRXD_TX_INJECTED BIT(6) | 185 | #define IEEE80211_RX_AMSDU BIT(2) |
133 | #define IEEE80211_TXRXD_RX_AMSDU BIT(7) | 186 | #define IEEE80211_RX_CMNTR_REPORTED BIT(3) |
134 | #define IEEE80211_TXRXD_RX_CMNTR_REPORTED BIT(8) | 187 | #define IEEE80211_RX_FRAGMENTED BIT(4) |
135 | struct ieee80211_txrx_data { | 188 | |
189 | struct ieee80211_rx_data { | ||
136 | struct sk_buff *skb; | 190 | struct sk_buff *skb; |
137 | struct net_device *dev; | 191 | struct net_device *dev; |
138 | struct ieee80211_local *local; | 192 | struct ieee80211_local *local; |
@@ -141,31 +195,14 @@ struct ieee80211_txrx_data { | |||
141 | u16 fc, ethertype; | 195 | u16 fc, ethertype; |
142 | struct ieee80211_key *key; | 196 | struct ieee80211_key *key; |
143 | unsigned int flags; | 197 | unsigned int flags; |
144 | union { | 198 | |
145 | struct { | 199 | struct ieee80211_rx_status *status; |
146 | struct ieee80211_tx_control *control; | 200 | struct ieee80211_rate *rate; |
147 | struct ieee80211_channel *channel; | 201 | int sent_ps_buffered; |
148 | struct ieee80211_rate *rate; | 202 | int queue; |
149 | /* use this rate (if set) for last fragment; rate can | 203 | int load; |
150 | * be set to lower rate for the first fragments, e.g., | 204 | u32 tkip_iv32; |
151 | * when using CTS protection with IEEE 802.11g. */ | 205 | u16 tkip_iv16; |
152 | struct ieee80211_rate *last_frag_rate; | ||
153 | |||
154 | /* Extra fragments (in addition to the first fragment | ||
155 | * in skb) */ | ||
156 | int num_extra_frag; | ||
157 | struct sk_buff **extra_frag; | ||
158 | } tx; | ||
159 | struct { | ||
160 | struct ieee80211_rx_status *status; | ||
161 | struct ieee80211_rate *rate; | ||
162 | int sent_ps_buffered; | ||
163 | int queue; | ||
164 | int load; | ||
165 | u32 tkip_iv32; | ||
166 | u16 tkip_iv16; | ||
167 | } rx; | ||
168 | } u; | ||
169 | }; | 206 | }; |
170 | 207 | ||
171 | /* flags used in struct ieee80211_tx_packet_data.flags */ | 208 | /* flags used in struct ieee80211_tx_packet_data.flags */ |
@@ -227,6 +264,41 @@ struct ieee80211_if_vlan { | |||
227 | struct list_head list; | 264 | struct list_head list; |
228 | }; | 265 | }; |
229 | 266 | ||
267 | struct mesh_stats { | ||
268 | __u32 fwded_frames; /* Mesh forwarded frames */ | ||
269 | __u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/ | ||
270 | __u32 dropped_frames_no_route; /* Not transmitted, no route found */ | ||
271 | atomic_t estab_plinks; | ||
272 | }; | ||
273 | |||
274 | #define PREQ_Q_F_START 0x1 | ||
275 | #define PREQ_Q_F_REFRESH 0x2 | ||
276 | struct mesh_preq_queue { | ||
277 | struct list_head list; | ||
278 | u8 dst[ETH_ALEN]; | ||
279 | u8 flags; | ||
280 | }; | ||
281 | |||
282 | struct mesh_config { | ||
283 | /* Timeouts in ms */ | ||
284 | /* Mesh plink management parameters */ | ||
285 | u16 dot11MeshRetryTimeout; | ||
286 | u16 dot11MeshConfirmTimeout; | ||
287 | u16 dot11MeshHoldingTimeout; | ||
288 | u16 dot11MeshMaxPeerLinks; | ||
289 | u8 dot11MeshMaxRetries; | ||
290 | u8 dot11MeshTTL; | ||
291 | bool auto_open_plinks; | ||
292 | /* HWMP parameters */ | ||
293 | u32 dot11MeshHWMPactivePathTimeout; | ||
294 | u16 dot11MeshHWMPpreqMinInterval; | ||
295 | u16 dot11MeshHWMPnetDiameterTraversalTime; | ||
296 | u8 dot11MeshHWMPmaxPREQretries; | ||
297 | u32 path_refresh_time; | ||
298 | u16 min_discovery_timeout; | ||
299 | }; | ||
300 | |||
301 | |||
230 | /* flags used in struct ieee80211_if_sta.flags */ | 302 | /* flags used in struct ieee80211_if_sta.flags */ |
231 | #define IEEE80211_STA_SSID_SET BIT(0) | 303 | #define IEEE80211_STA_SSID_SET BIT(0) |
232 | #define IEEE80211_STA_BSSID_SET BIT(1) | 304 | #define IEEE80211_STA_BSSID_SET BIT(1) |
@@ -245,7 +317,8 @@ struct ieee80211_if_sta { | |||
245 | enum { | 317 | enum { |
246 | IEEE80211_DISABLED, IEEE80211_AUTHENTICATE, | 318 | IEEE80211_DISABLED, IEEE80211_AUTHENTICATE, |
247 | IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED, | 319 | IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED, |
248 | IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED | 320 | IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED, |
321 | IEEE80211_MESH_UP | ||
249 | } state; | 322 | } state; |
250 | struct timer_list timer; | 323 | struct timer_list timer; |
251 | struct work_struct work; | 324 | struct work_struct work; |
@@ -254,6 +327,34 @@ struct ieee80211_if_sta { | |||
254 | size_t ssid_len; | 327 | size_t ssid_len; |
255 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; | 328 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; |
256 | size_t scan_ssid_len; | 329 | size_t scan_ssid_len; |
330 | #ifdef CONFIG_MAC80211_MESH | ||
331 | struct timer_list mesh_path_timer; | ||
332 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; | ||
333 | bool accepting_plinks; | ||
334 | size_t mesh_id_len; | ||
335 | /* Active Path Selection Protocol Identifier */ | ||
336 | u8 mesh_pp_id[4]; | ||
337 | /* Active Path Selection Metric Identifier */ | ||
338 | u8 mesh_pm_id[4]; | ||
339 | /* Congestion Control Mode Identifier */ | ||
340 | u8 mesh_cc_id[4]; | ||
341 | /* Local mesh Destination Sequence Number */ | ||
342 | u32 dsn; | ||
343 | /* Last used PREQ ID */ | ||
344 | u32 preq_id; | ||
345 | atomic_t mpaths; | ||
346 | /* Timestamp of last DSN update */ | ||
347 | unsigned long last_dsn_update; | ||
348 | /* Timestamp of last DSN sent */ | ||
349 | unsigned long last_preq; | ||
350 | struct mesh_rmc *rmc; | ||
351 | spinlock_t mesh_preq_queue_lock; | ||
352 | struct mesh_preq_queue preq_queue; | ||
353 | int preq_queue_len; | ||
354 | struct mesh_stats mshstats; | ||
355 | struct mesh_config mshcfg; | ||
356 | u8 mesh_seqnum[3]; | ||
357 | #endif | ||
257 | u16 aid; | 358 | u16 aid; |
258 | u16 ap_capab, capab; | 359 | u16 ap_capab, capab; |
259 | u8 *extra_ie; /* to be added to the end of AssocReq */ | 360 | u8 *extra_ie; /* to be added to the end of AssocReq */ |
@@ -286,8 +387,25 @@ struct ieee80211_if_sta { | |||
286 | u32 supp_rates_bits[IEEE80211_NUM_BANDS]; | 387 | u32 supp_rates_bits[IEEE80211_NUM_BANDS]; |
287 | 388 | ||
288 | int wmm_last_param_set; | 389 | int wmm_last_param_set; |
390 | int num_beacons; /* number of TXed beacon frames by this STA */ | ||
289 | }; | 391 | }; |
290 | 392 | ||
393 | static inline void ieee80211_if_sta_set_mesh_id(struct ieee80211_if_sta *ifsta, | ||
394 | u8 mesh_id_len, u8 *mesh_id) | ||
395 | { | ||
396 | #ifdef CONFIG_MAC80211_MESH | ||
397 | ifsta->mesh_id_len = mesh_id_len; | ||
398 | memcpy(ifsta->mesh_id, mesh_id, mesh_id_len); | ||
399 | #endif | ||
400 | } | ||
401 | |||
402 | #ifdef CONFIG_MAC80211_MESH | ||
403 | #define IEEE80211_IFSTA_MESH_CTR_INC(sta, name) \ | ||
404 | do { (sta)->mshstats.name++; } while (0) | ||
405 | #else | ||
406 | #define IEEE80211_IFSTA_MESH_CTR_INC(sta, name) \ | ||
407 | do { } while (0) | ||
408 | #endif | ||
291 | 409 | ||
292 | /* flags used in struct ieee80211_sub_if_data.flags */ | 410 | /* flags used in struct ieee80211_sub_if_data.flags */ |
293 | #define IEEE80211_SDATA_ALLMULTI BIT(0) | 411 | #define IEEE80211_SDATA_ALLMULTI BIT(0) |
@@ -365,6 +483,7 @@ struct ieee80211_sub_if_data { | |||
365 | struct dentry *auth_alg; | 483 | struct dentry *auth_alg; |
366 | struct dentry *auth_transaction; | 484 | struct dentry *auth_transaction; |
367 | struct dentry *flags; | 485 | struct dentry *flags; |
486 | struct dentry *num_beacons_sta; | ||
368 | } sta; | 487 | } sta; |
369 | struct { | 488 | struct { |
370 | struct dentry *channel_use; | 489 | struct dentry *channel_use; |
@@ -390,6 +509,35 @@ struct ieee80211_sub_if_data { | |||
390 | } monitor; | 509 | } monitor; |
391 | struct dentry *default_key; | 510 | struct dentry *default_key; |
392 | } debugfs; | 511 | } debugfs; |
512 | |||
513 | #ifdef CONFIG_MAC80211_MESH | ||
514 | struct dentry *mesh_stats_dir; | ||
515 | struct { | ||
516 | struct dentry *fwded_frames; | ||
517 | struct dentry *dropped_frames_ttl; | ||
518 | struct dentry *dropped_frames_no_route; | ||
519 | struct dentry *estab_plinks; | ||
520 | struct timer_list mesh_path_timer; | ||
521 | } mesh_stats; | ||
522 | |||
523 | struct dentry *mesh_config_dir; | ||
524 | struct { | ||
525 | struct dentry *dot11MeshRetryTimeout; | ||
526 | struct dentry *dot11MeshConfirmTimeout; | ||
527 | struct dentry *dot11MeshHoldingTimeout; | ||
528 | struct dentry *dot11MeshMaxRetries; | ||
529 | struct dentry *dot11MeshTTL; | ||
530 | struct dentry *auto_open_plinks; | ||
531 | struct dentry *dot11MeshMaxPeerLinks; | ||
532 | struct dentry *dot11MeshHWMPactivePathTimeout; | ||
533 | struct dentry *dot11MeshHWMPpreqMinInterval; | ||
534 | struct dentry *dot11MeshHWMPnetDiameterTraversalTime; | ||
535 | struct dentry *dot11MeshHWMPmaxPREQretries; | ||
536 | struct dentry *path_refresh_time; | ||
537 | struct dentry *min_discovery_timeout; | ||
538 | } mesh_config; | ||
539 | #endif | ||
540 | |||
393 | #endif | 541 | #endif |
394 | /* must be last, dynamically sized area in this! */ | 542 | /* must be last, dynamically sized area in this! */ |
395 | struct ieee80211_vif vif; | 543 | struct ieee80211_vif vif; |
@@ -426,6 +574,7 @@ struct ieee80211_local { | |||
426 | unsigned int filter_flags; /* FIF_* */ | 574 | unsigned int filter_flags; /* FIF_* */ |
427 | struct iw_statistics wstats; | 575 | struct iw_statistics wstats; |
428 | u8 wstats_flags; | 576 | u8 wstats_flags; |
577 | bool tim_in_locked_section; /* see ieee80211_beacon_get() */ | ||
429 | int tx_headroom; /* required headroom for hardware/radiotap */ | 578 | int tx_headroom; /* required headroom for hardware/radiotap */ |
430 | 579 | ||
431 | enum { | 580 | enum { |
@@ -443,9 +592,15 @@ struct ieee80211_local { | |||
443 | struct sk_buff_head skb_queue; | 592 | struct sk_buff_head skb_queue; |
444 | struct sk_buff_head skb_queue_unreliable; | 593 | struct sk_buff_head skb_queue_unreliable; |
445 | 594 | ||
446 | /* Station data structures */ | 595 | /* Station data */ |
447 | rwlock_t sta_lock; /* protects STA data structures */ | 596 | /* |
448 | int num_sta; /* number of stations in sta_list */ | 597 | * The lock only protects the list, hash, timer and counter |
598 | * against manipulation, reads are done in RCU. Additionally, | ||
599 | * the lock protects each BSS's TIM bitmap and a few items | ||
600 | * in a STA info structure. | ||
601 | */ | ||
602 | spinlock_t sta_lock; | ||
603 | unsigned long num_sta; | ||
449 | struct list_head sta_list; | 604 | struct list_head sta_list; |
450 | struct sta_info *sta_hash[STA_HASH_SIZE]; | 605 | struct sta_info *sta_hash[STA_HASH_SIZE]; |
451 | struct timer_list sta_cleanup; | 606 | struct timer_list sta_cleanup; |
@@ -617,6 +772,57 @@ struct ieee80211_ra_tid { | |||
617 | u16 tid; | 772 | u16 tid; |
618 | }; | 773 | }; |
619 | 774 | ||
775 | /* Parsed Information Elements */ | ||
776 | struct ieee802_11_elems { | ||
777 | /* pointers to IEs */ | ||
778 | u8 *ssid; | ||
779 | u8 *supp_rates; | ||
780 | u8 *fh_params; | ||
781 | u8 *ds_params; | ||
782 | u8 *cf_params; | ||
783 | u8 *tim; | ||
784 | u8 *ibss_params; | ||
785 | u8 *challenge; | ||
786 | u8 *wpa; | ||
787 | u8 *rsn; | ||
788 | u8 *erp_info; | ||
789 | u8 *ext_supp_rates; | ||
790 | u8 *wmm_info; | ||
791 | u8 *wmm_param; | ||
792 | u8 *ht_cap_elem; | ||
793 | u8 *ht_info_elem; | ||
794 | u8 *mesh_config; | ||
795 | u8 *mesh_id; | ||
796 | u8 *peer_link; | ||
797 | u8 *preq; | ||
798 | u8 *prep; | ||
799 | u8 *perr; | ||
800 | |||
801 | /* length of them, respectively */ | ||
802 | u8 ssid_len; | ||
803 | u8 supp_rates_len; | ||
804 | u8 fh_params_len; | ||
805 | u8 ds_params_len; | ||
806 | u8 cf_params_len; | ||
807 | u8 tim_len; | ||
808 | u8 ibss_params_len; | ||
809 | u8 challenge_len; | ||
810 | u8 wpa_len; | ||
811 | u8 rsn_len; | ||
812 | u8 erp_info_len; | ||
813 | u8 ext_supp_rates_len; | ||
814 | u8 wmm_info_len; | ||
815 | u8 wmm_param_len; | ||
816 | u8 ht_cap_elem_len; | ||
817 | u8 ht_info_elem_len; | ||
818 | u8 mesh_config_len; | ||
819 | u8 mesh_id_len; | ||
820 | u8 peer_link_len; | ||
821 | u8 preq_len; | ||
822 | u8 prep_len; | ||
823 | u8 perr_len; | ||
824 | }; | ||
825 | |||
620 | static inline struct ieee80211_local *hw_to_local( | 826 | static inline struct ieee80211_local *hw_to_local( |
621 | struct ieee80211_hw *hw) | 827 | struct ieee80211_hw *hw) |
622 | { | 828 | { |
@@ -651,8 +857,7 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) | |||
651 | int ieee80211_hw_config(struct ieee80211_local *local); | 857 | int ieee80211_hw_config(struct ieee80211_local *local); |
652 | int ieee80211_if_config(struct net_device *dev); | 858 | int ieee80211_if_config(struct net_device *dev); |
653 | int ieee80211_if_config_beacon(struct net_device *dev); | 859 | int ieee80211_if_config_beacon(struct net_device *dev); |
654 | void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx); | 860 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); |
655 | int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr); | ||
656 | void ieee80211_if_setup(struct net_device *dev); | 861 | void ieee80211_if_setup(struct net_device *dev); |
657 | int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht, | 862 | int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht, |
658 | struct ieee80211_ht_info *req_ht_cap, | 863 | struct ieee80211_ht_info *req_ht_cap, |
@@ -686,6 +891,7 @@ int ieee80211_set_compression(struct ieee80211_local *local, | |||
686 | struct net_device *dev, struct sta_info *sta); | 891 | struct net_device *dev, struct sta_info *sta); |
687 | int ieee80211_set_freq(struct ieee80211_local *local, int freq); | 892 | int ieee80211_set_freq(struct ieee80211_local *local, int freq); |
688 | /* ieee80211_sta.c */ | 893 | /* ieee80211_sta.c */ |
894 | #define IEEE80211_FC(type, stype) cpu_to_le16(type | stype) | ||
689 | void ieee80211_sta_timer(unsigned long data); | 895 | void ieee80211_sta_timer(unsigned long data); |
690 | void ieee80211_sta_work(struct work_struct *work); | 896 | void ieee80211_sta_work(struct work_struct *work); |
691 | void ieee80211_sta_scan_work(struct work_struct *work); | 897 | void ieee80211_sta_scan_work(struct work_struct *work); |
@@ -726,9 +932,25 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da, | |||
726 | u16 tid, u16 initiator, u16 reason); | 932 | u16 tid, u16 initiator, u16 reason); |
727 | void sta_rx_agg_session_timer_expired(unsigned long data); | 933 | void sta_rx_agg_session_timer_expired(unsigned long data); |
728 | void sta_addba_resp_timer_expired(unsigned long data); | 934 | void sta_addba_resp_timer_expired(unsigned long data); |
935 | u64 ieee80211_sta_get_rates(struct ieee80211_local *local, | ||
936 | struct ieee802_11_elems *elems, | ||
937 | enum ieee80211_band band); | ||
938 | void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, | ||
939 | int encrypt); | ||
940 | void ieee802_11_parse_elems(u8 *start, size_t len, | ||
941 | struct ieee802_11_elems *elems); | ||
942 | |||
943 | #ifdef CONFIG_MAC80211_MESH | ||
944 | void ieee80211_start_mesh(struct net_device *dev); | ||
945 | #else | ||
946 | static inline void ieee80211_start_mesh(struct net_device *dev) | ||
947 | {} | ||
948 | #endif | ||
949 | |||
729 | /* ieee80211_iface.c */ | 950 | /* ieee80211_iface.c */ |
730 | int ieee80211_if_add(struct net_device *dev, const char *name, | 951 | int ieee80211_if_add(struct net_device *dev, const char *name, |
731 | struct net_device **new_dev, int type); | 952 | struct net_device **new_dev, int type, |
953 | struct vif_params *params); | ||
732 | void ieee80211_if_set_type(struct net_device *dev, int type); | 954 | void ieee80211_if_set_type(struct net_device *dev, int type); |
733 | void ieee80211_if_reinit(struct net_device *dev); | 955 | void ieee80211_if_reinit(struct net_device *dev); |
734 | void __ieee80211_if_del(struct ieee80211_local *local, | 956 | void __ieee80211_if_del(struct ieee80211_local *local, |
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 677705046c6d..80954a512185 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include "ieee80211_i.h" | 15 | #include "ieee80211_i.h" |
16 | #include "sta_info.h" | 16 | #include "sta_info.h" |
17 | #include "debugfs_netdev.h" | 17 | #include "debugfs_netdev.h" |
18 | #include "mesh.h" | ||
18 | 19 | ||
19 | void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) | 20 | void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) |
20 | { | 21 | { |
@@ -39,7 +40,8 @@ static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata) | |||
39 | 40 | ||
40 | /* Must be called with rtnl lock held. */ | 41 | /* Must be called with rtnl lock held. */ |
41 | int ieee80211_if_add(struct net_device *dev, const char *name, | 42 | int ieee80211_if_add(struct net_device *dev, const char *name, |
42 | struct net_device **new_dev, int type) | 43 | struct net_device **new_dev, int type, |
44 | struct vif_params *params) | ||
43 | { | 45 | { |
44 | struct net_device *ndev; | 46 | struct net_device *ndev; |
45 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 47 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
@@ -78,6 +80,12 @@ int ieee80211_if_add(struct net_device *dev, const char *name, | |||
78 | ieee80211_debugfs_add_netdev(sdata); | 80 | ieee80211_debugfs_add_netdev(sdata); |
79 | ieee80211_if_set_type(ndev, type); | 81 | ieee80211_if_set_type(ndev, type); |
80 | 82 | ||
83 | if (ieee80211_vif_is_mesh(&sdata->vif) && | ||
84 | params && params->mesh_id_len) | ||
85 | ieee80211_if_sta_set_mesh_id(&sdata->u.sta, | ||
86 | params->mesh_id_len, | ||
87 | params->mesh_id); | ||
88 | |||
81 | /* we're under RTNL so all this is fine */ | 89 | /* we're under RTNL so all this is fine */ |
82 | if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) { | 90 | if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) { |
83 | __ieee80211_if_del(local, sdata); | 91 | __ieee80211_if_del(local, sdata); |
@@ -134,6 +142,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type) | |||
134 | sdata->bss = &sdata->u.ap; | 142 | sdata->bss = &sdata->u.ap; |
135 | INIT_LIST_HEAD(&sdata->u.ap.vlans); | 143 | INIT_LIST_HEAD(&sdata->u.ap.vlans); |
136 | break; | 144 | break; |
145 | case IEEE80211_IF_TYPE_MESH_POINT: | ||
137 | case IEEE80211_IF_TYPE_STA: | 146 | case IEEE80211_IF_TYPE_STA: |
138 | case IEEE80211_IF_TYPE_IBSS: { | 147 | case IEEE80211_IF_TYPE_IBSS: { |
139 | struct ieee80211_sub_if_data *msdata; | 148 | struct ieee80211_sub_if_data *msdata; |
@@ -155,6 +164,9 @@ void ieee80211_if_set_type(struct net_device *dev, int type) | |||
155 | 164 | ||
156 | msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev); | 165 | msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev); |
157 | sdata->bss = &msdata->u.ap; | 166 | sdata->bss = &msdata->u.ap; |
167 | |||
168 | if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
169 | ieee80211_mesh_init_sdata(sdata); | ||
158 | break; | 170 | break; |
159 | } | 171 | } |
160 | case IEEE80211_IF_TYPE_MNTR: | 172 | case IEEE80211_IF_TYPE_MNTR: |
@@ -175,8 +187,8 @@ void ieee80211_if_reinit(struct net_device *dev) | |||
175 | { | 187 | { |
176 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 188 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
177 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 189 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
178 | struct sta_info *sta; | ||
179 | struct sk_buff *skb; | 190 | struct sk_buff *skb; |
191 | int flushed; | ||
180 | 192 | ||
181 | ASSERT_RTNL(); | 193 | ASSERT_RTNL(); |
182 | 194 | ||
@@ -184,6 +196,10 @@ void ieee80211_if_reinit(struct net_device *dev) | |||
184 | 196 | ||
185 | ieee80211_if_sdata_deinit(sdata); | 197 | ieee80211_if_sdata_deinit(sdata); |
186 | 198 | ||
199 | /* Need to handle mesh specially to allow eliding the function call */ | ||
200 | if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
201 | mesh_rmc_free(dev); | ||
202 | |||
187 | switch (sdata->vif.type) { | 203 | switch (sdata->vif.type) { |
188 | case IEEE80211_IF_TYPE_INVALID: | 204 | case IEEE80211_IF_TYPE_INVALID: |
189 | /* cannot happen */ | 205 | /* cannot happen */ |
@@ -224,17 +240,9 @@ void ieee80211_if_reinit(struct net_device *dev) | |||
224 | break; | 240 | break; |
225 | } | 241 | } |
226 | case IEEE80211_IF_TYPE_WDS: | 242 | case IEEE80211_IF_TYPE_WDS: |
227 | sta = sta_info_get(local, sdata->u.wds.remote_addr); | 243 | /* nothing to do */ |
228 | if (sta) { | ||
229 | sta_info_free(sta); | ||
230 | sta_info_put(sta); | ||
231 | } else { | ||
232 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
233 | printk(KERN_DEBUG "%s: Someone had deleted my STA " | ||
234 | "entry for the WDS link\n", dev->name); | ||
235 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
236 | } | ||
237 | break; | 244 | break; |
245 | case IEEE80211_IF_TYPE_MESH_POINT: | ||
238 | case IEEE80211_IF_TYPE_STA: | 246 | case IEEE80211_IF_TYPE_STA: |
239 | case IEEE80211_IF_TYPE_IBSS: | 247 | case IEEE80211_IF_TYPE_IBSS: |
240 | kfree(sdata->u.sta.extra_ie); | 248 | kfree(sdata->u.sta.extra_ie); |
@@ -257,8 +265,8 @@ void ieee80211_if_reinit(struct net_device *dev) | |||
257 | break; | 265 | break; |
258 | } | 266 | } |
259 | 267 | ||
260 | /* remove all STAs that are bound to this virtual interface */ | 268 | flushed = sta_info_flush(local, sdata); |
261 | sta_info_flush(local, dev); | 269 | WARN_ON(flushed); |
262 | 270 | ||
263 | memset(&sdata->u, 0, sizeof(sdata->u)); | 271 | memset(&sdata->u, 0, sizeof(sdata->u)); |
264 | ieee80211_if_sdata_init(sdata); | 272 | ieee80211_if_sdata_init(sdata); |
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 7551db3f3abc..1d91575a0fe9 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c | |||
@@ -33,8 +33,7 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
33 | size_t key_len) | 33 | size_t key_len) |
34 | { | 34 | { |
35 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 35 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
36 | int ret; | 36 | struct sta_info *sta; |
37 | struct sta_info *sta = NULL; | ||
38 | struct ieee80211_key *key; | 37 | struct ieee80211_key *key; |
39 | struct ieee80211_sub_if_data *sdata; | 38 | struct ieee80211_sub_if_data *sdata; |
40 | 39 | ||
@@ -51,24 +50,23 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
51 | key = sdata->keys[idx]; | 50 | key = sdata->keys[idx]; |
52 | } else { | 51 | } else { |
53 | sta = sta_info_get(local, sta_addr); | 52 | sta = sta_info_get(local, sta_addr); |
54 | if (!sta) { | 53 | if (!sta) |
55 | ret = -ENOENT; | 54 | return -ENOENT; |
56 | key = NULL; | ||
57 | goto err_out; | ||
58 | } | ||
59 | |||
60 | key = sta->key; | 55 | key = sta->key; |
61 | } | 56 | } |
62 | 57 | ||
63 | if (!key) | 58 | if (!key) |
64 | ret = -ENOENT; | 59 | return -ENOENT; |
65 | else | 60 | |
66 | ret = 0; | 61 | ieee80211_key_free(key); |
62 | return 0; | ||
67 | } else { | 63 | } else { |
68 | key = ieee80211_key_alloc(alg, idx, key_len, _key); | 64 | key = ieee80211_key_alloc(alg, idx, key_len, _key); |
69 | if (!key) | 65 | if (!key) |
70 | return -ENOMEM; | 66 | return -ENOMEM; |
71 | 67 | ||
68 | sta = NULL; | ||
69 | |||
72 | if (!is_broadcast_ether_addr(sta_addr)) { | 70 | if (!is_broadcast_ether_addr(sta_addr)) { |
73 | set_tx_key = 0; | 71 | set_tx_key = 0; |
74 | /* | 72 | /* |
@@ -78,14 +76,14 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
78 | * work around this. | 76 | * work around this. |
79 | */ | 77 | */ |
80 | if (idx != 0 && alg != ALG_WEP) { | 78 | if (idx != 0 && alg != ALG_WEP) { |
81 | ret = -EINVAL; | 79 | ieee80211_key_free(key); |
82 | goto err_out; | 80 | return -EINVAL; |
83 | } | 81 | } |
84 | 82 | ||
85 | sta = sta_info_get(local, sta_addr); | 83 | sta = sta_info_get(local, sta_addr); |
86 | if (!sta) { | 84 | if (!sta) { |
87 | ret = -ENOENT; | 85 | ieee80211_key_free(key); |
88 | goto err_out; | 86 | return -ENOENT; |
89 | } | 87 | } |
90 | } | 88 | } |
91 | 89 | ||
@@ -93,18 +91,9 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
93 | 91 | ||
94 | if (set_tx_key || (!sta && !sdata->default_key && key)) | 92 | if (set_tx_key || (!sta && !sdata->default_key && key)) |
95 | ieee80211_set_default_key(sdata, idx); | 93 | ieee80211_set_default_key(sdata, idx); |
96 | |||
97 | /* don't free key later */ | ||
98 | key = NULL; | ||
99 | |||
100 | ret = 0; | ||
101 | } | 94 | } |
102 | 95 | ||
103 | err_out: | 96 | return 0; |
104 | if (sta) | ||
105 | sta_info_put(sta); | ||
106 | ieee80211_key_free(key); | ||
107 | return ret; | ||
108 | } | 97 | } |
109 | 98 | ||
110 | static int ieee80211_ioctl_siwgenie(struct net_device *dev, | 99 | static int ieee80211_ioctl_siwgenie(struct net_device *dev, |
@@ -479,10 +468,20 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, | |||
479 | ieee80211_sta_req_auth(dev, &sdata->u.sta); | 468 | ieee80211_sta_req_auth(dev, &sdata->u.sta); |
480 | return 0; | 469 | return 0; |
481 | } else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) { | 470 | } else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) { |
482 | if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data, | 471 | /* |
483 | ETH_ALEN) == 0) | 472 | * If it is necessary to update the WDS peer address |
484 | return 0; | 473 | * while the interface is running, then we need to do |
485 | return ieee80211_if_update_wds(dev, (u8 *) &ap_addr->sa_data); | 474 | * more work here, namely if it is running we need to |
475 | * add a new and remove the old STA entry, this is | ||
476 | * normally handled by _open() and _stop(). | ||
477 | */ | ||
478 | if (netif_running(dev)) | ||
479 | return -EBUSY; | ||
480 | |||
481 | memcpy(&sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data, | ||
482 | ETH_ALEN); | ||
483 | |||
484 | return 0; | ||
486 | } | 485 | } |
487 | 486 | ||
488 | return -EOPNOTSUPP; | 487 | return -EOPNOTSUPP; |
@@ -525,6 +524,7 @@ static int ieee80211_ioctl_siwscan(struct net_device *dev, | |||
525 | 524 | ||
526 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA && | 525 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA && |
527 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS && | 526 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS && |
527 | sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT && | ||
528 | sdata->vif.type != IEEE80211_IF_TYPE_AP) | 528 | sdata->vif.type != IEEE80211_IF_TYPE_AP) |
529 | return -EOPNOTSUPP; | 529 | return -EOPNOTSUPP; |
530 | 530 | ||
@@ -624,7 +624,7 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, | |||
624 | else | 624 | else |
625 | rate->value = 0; | 625 | rate->value = 0; |
626 | rate->value *= 100000; | 626 | rate->value *= 100000; |
627 | sta_info_put(sta); | 627 | |
628 | return 0; | 628 | return 0; |
629 | } | 629 | } |
630 | 630 | ||
@@ -999,7 +999,6 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev | |||
999 | wstats->qual.qual = sta->last_signal; | 999 | wstats->qual.qual = sta->last_signal; |
1000 | wstats->qual.noise = sta->last_noise; | 1000 | wstats->qual.noise = sta->last_noise; |
1001 | wstats->qual.updated = local->wstats_flags; | 1001 | wstats->qual.updated = local->wstats_flags; |
1002 | sta_info_put(sta); | ||
1003 | } | 1002 | } |
1004 | return wstats; | 1003 | return wstats; |
1005 | } | 1004 | } |
diff --git a/net/mac80211/ieee80211_rate.c b/net/mac80211/ieee80211_rate.c index ebe29b716b27..4de06f128d90 100644 --- a/net/mac80211/ieee80211_rate.c +++ b/net/mac80211/ieee80211_rate.c | |||
@@ -170,9 +170,12 @@ void rate_control_get_rate(struct net_device *dev, | |||
170 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 170 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
171 | struct rate_control_ref *ref = local->rate_ctrl; | 171 | struct rate_control_ref *ref = local->rate_ctrl; |
172 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 172 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
173 | struct sta_info *sta = sta_info_get(local, hdr->addr1); | 173 | struct sta_info *sta; |
174 | int i; | 174 | int i; |
175 | 175 | ||
176 | rcu_read_lock(); | ||
177 | sta = sta_info_get(local, hdr->addr1); | ||
178 | |||
176 | memset(sel, 0, sizeof(struct rate_selection)); | 179 | memset(sel, 0, sizeof(struct rate_selection)); |
177 | 180 | ||
178 | ref->ops->get_rate(ref->priv, dev, sband, skb, sel); | 181 | ref->ops->get_rate(ref->priv, dev, sband, skb, sel); |
@@ -190,8 +193,7 @@ void rate_control_get_rate(struct net_device *dev, | |||
190 | } | 193 | } |
191 | } | 194 | } |
192 | 195 | ||
193 | if (sta) | 196 | rcu_read_unlock(); |
194 | sta_info_put(sta); | ||
195 | } | 197 | } |
196 | 198 | ||
197 | struct rate_control_ref *rate_control_get(struct rate_control_ref *ref) | 199 | struct rate_control_ref *rate_control_get(struct rate_control_ref *ref) |
diff --git a/net/mac80211/ieee80211_rate.h b/net/mac80211/ieee80211_rate.h index 5f9a2ca49a57..bfd0a1982e4a 100644 --- a/net/mac80211/ieee80211_rate.h +++ b/net/mac80211/ieee80211_rate.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/netdevice.h> | 14 | #include <linux/netdevice.h> |
15 | #include <linux/skbuff.h> | 15 | #include <linux/skbuff.h> |
16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
17 | #include <linux/kref.h> | ||
17 | #include <net/mac80211.h> | 18 | #include <net/mac80211.h> |
18 | #include "ieee80211_i.h" | 19 | #include "ieee80211_i.h" |
19 | #include "sta_info.h" | 20 | #include "sta_info.h" |
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index ddb5832f37cb..8b991ebcbb4e 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/wireless.h> | 24 | #include <linux/wireless.h> |
25 | #include <linux/random.h> | 25 | #include <linux/random.h> |
26 | #include <linux/etherdevice.h> | 26 | #include <linux/etherdevice.h> |
27 | #include <linux/rtnetlink.h> | ||
27 | #include <net/iw_handler.h> | 28 | #include <net/iw_handler.h> |
28 | #include <asm/types.h> | 29 | #include <asm/types.h> |
29 | 30 | ||
@@ -31,12 +32,14 @@ | |||
31 | #include "ieee80211_i.h" | 32 | #include "ieee80211_i.h" |
32 | #include "ieee80211_rate.h" | 33 | #include "ieee80211_rate.h" |
33 | #include "ieee80211_led.h" | 34 | #include "ieee80211_led.h" |
35 | #include "mesh.h" | ||
34 | 36 | ||
35 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) | 37 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) |
36 | #define IEEE80211_AUTH_MAX_TRIES 3 | 38 | #define IEEE80211_AUTH_MAX_TRIES 3 |
37 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | 39 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) |
38 | #define IEEE80211_ASSOC_MAX_TRIES 3 | 40 | #define IEEE80211_ASSOC_MAX_TRIES 3 |
39 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) | 41 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) |
42 | #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) | ||
40 | #define IEEE80211_PROBE_INTERVAL (60 * HZ) | 43 | #define IEEE80211_PROBE_INTERVAL (60 * HZ) |
41 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) | 44 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) |
42 | #define IEEE80211_SCAN_INTERVAL (2 * HZ) | 45 | #define IEEE80211_SCAN_INTERVAL (2 * HZ) |
@@ -49,6 +52,7 @@ | |||
49 | #define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) | 52 | #define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) |
50 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) | 53 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) |
51 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) | 54 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) |
55 | #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) | ||
52 | 56 | ||
53 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 | 57 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 |
54 | 58 | ||
@@ -87,46 +91,8 @@ static int ieee80211_sta_config_auth(struct net_device *dev, | |||
87 | struct ieee80211_if_sta *ifsta); | 91 | struct ieee80211_if_sta *ifsta); |
88 | 92 | ||
89 | 93 | ||
90 | /* Parsed Information Elements */ | 94 | void ieee802_11_parse_elems(u8 *start, size_t len, |
91 | struct ieee802_11_elems { | 95 | struct ieee802_11_elems *elems) |
92 | /* pointers to IEs */ | ||
93 | u8 *ssid; | ||
94 | u8 *supp_rates; | ||
95 | u8 *fh_params; | ||
96 | u8 *ds_params; | ||
97 | u8 *cf_params; | ||
98 | u8 *tim; | ||
99 | u8 *ibss_params; | ||
100 | u8 *challenge; | ||
101 | u8 *wpa; | ||
102 | u8 *rsn; | ||
103 | u8 *erp_info; | ||
104 | u8 *ext_supp_rates; | ||
105 | u8 *wmm_info; | ||
106 | u8 *wmm_param; | ||
107 | u8 *ht_cap_elem; | ||
108 | u8 *ht_info_elem; | ||
109 | /* length of them, respectively */ | ||
110 | u8 ssid_len; | ||
111 | u8 supp_rates_len; | ||
112 | u8 fh_params_len; | ||
113 | u8 ds_params_len; | ||
114 | u8 cf_params_len; | ||
115 | u8 tim_len; | ||
116 | u8 ibss_params_len; | ||
117 | u8 challenge_len; | ||
118 | u8 wpa_len; | ||
119 | u8 rsn_len; | ||
120 | u8 erp_info_len; | ||
121 | u8 ext_supp_rates_len; | ||
122 | u8 wmm_info_len; | ||
123 | u8 wmm_param_len; | ||
124 | u8 ht_cap_elem_len; | ||
125 | u8 ht_info_elem_len; | ||
126 | }; | ||
127 | |||
128 | static void ieee802_11_parse_elems(u8 *start, size_t len, | ||
129 | struct ieee802_11_elems *elems) | ||
130 | { | 96 | { |
131 | size_t left = len; | 97 | size_t left = len; |
132 | u8 *pos = start; | 98 | u8 *pos = start; |
@@ -215,6 +181,30 @@ static void ieee802_11_parse_elems(u8 *start, size_t len, | |||
215 | elems->ht_info_elem = pos; | 181 | elems->ht_info_elem = pos; |
216 | elems->ht_info_elem_len = elen; | 182 | elems->ht_info_elem_len = elen; |
217 | break; | 183 | break; |
184 | case WLAN_EID_MESH_ID: | ||
185 | elems->mesh_id = pos; | ||
186 | elems->mesh_id_len = elen; | ||
187 | break; | ||
188 | case WLAN_EID_MESH_CONFIG: | ||
189 | elems->mesh_config = pos; | ||
190 | elems->mesh_config_len = elen; | ||
191 | break; | ||
192 | case WLAN_EID_PEER_LINK: | ||
193 | elems->peer_link = pos; | ||
194 | elems->peer_link_len = elen; | ||
195 | break; | ||
196 | case WLAN_EID_PREQ: | ||
197 | elems->preq = pos; | ||
198 | elems->preq_len = elen; | ||
199 | break; | ||
200 | case WLAN_EID_PREP: | ||
201 | elems->prep = pos; | ||
202 | elems->prep_len = elen; | ||
203 | break; | ||
204 | case WLAN_EID_PERR: | ||
205 | elems->perr = pos; | ||
206 | elems->perr_len = elen; | ||
207 | break; | ||
218 | default: | 208 | default: |
219 | break; | 209 | break; |
220 | } | 210 | } |
@@ -501,8 +491,8 @@ static void ieee80211_set_disassoc(struct net_device *dev, | |||
501 | ieee80211_set_associated(dev, ifsta, 0); | 491 | ieee80211_set_associated(dev, ifsta, 0); |
502 | } | 492 | } |
503 | 493 | ||
504 | static void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, | 494 | void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, |
505 | int encrypt) | 495 | int encrypt) |
506 | { | 496 | { |
507 | struct ieee80211_sub_if_data *sdata; | 497 | struct ieee80211_sub_if_data *sdata; |
508 | struct ieee80211_tx_packet_data *pkt_data; | 498 | struct ieee80211_tx_packet_data *pkt_data; |
@@ -856,6 +846,8 @@ static void ieee80211_associated(struct net_device *dev, | |||
856 | 846 | ||
857 | ifsta->state = IEEE80211_ASSOCIATED; | 847 | ifsta->state = IEEE80211_ASSOCIATED; |
858 | 848 | ||
849 | rcu_read_lock(); | ||
850 | |||
859 | sta = sta_info_get(local, ifsta->bssid); | 851 | sta = sta_info_get(local, ifsta->bssid); |
860 | if (!sta) { | 852 | if (!sta) { |
861 | printk(KERN_DEBUG "%s: No STA entry for own AP %s\n", | 853 | printk(KERN_DEBUG "%s: No STA entry for own AP %s\n", |
@@ -871,7 +863,7 @@ static void ieee80211_associated(struct net_device *dev, | |||
871 | "range\n", | 863 | "range\n", |
872 | dev->name, print_mac(mac, ifsta->bssid)); | 864 | dev->name, print_mac(mac, ifsta->bssid)); |
873 | disassoc = 1; | 865 | disassoc = 1; |
874 | sta_info_free(sta); | 866 | sta_info_unlink(&sta); |
875 | } else | 867 | } else |
876 | ieee80211_send_probe_req(dev, ifsta->bssid, | 868 | ieee80211_send_probe_req(dev, ifsta->bssid, |
877 | local->scan_ssid, | 869 | local->scan_ssid, |
@@ -887,8 +879,17 @@ static void ieee80211_associated(struct net_device *dev, | |||
887 | ifsta->ssid_len); | 879 | ifsta->ssid_len); |
888 | } | 880 | } |
889 | } | 881 | } |
890 | sta_info_put(sta); | ||
891 | } | 882 | } |
883 | |||
884 | rcu_read_unlock(); | ||
885 | |||
886 | if (disassoc && sta) { | ||
887 | synchronize_rcu(); | ||
888 | rtnl_lock(); | ||
889 | sta_info_destroy(sta); | ||
890 | rtnl_unlock(); | ||
891 | } | ||
892 | |||
892 | if (disassoc) { | 893 | if (disassoc) { |
893 | ifsta->state = IEEE80211_DISABLED; | 894 | ifsta->state = IEEE80211_DISABLED; |
894 | ieee80211_set_associated(dev, ifsta, 0); | 895 | ieee80211_set_associated(dev, ifsta, 0); |
@@ -1114,9 +1115,13 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, | |||
1114 | int ret = -EOPNOTSUPP; | 1115 | int ret = -EOPNOTSUPP; |
1115 | DECLARE_MAC_BUF(mac); | 1116 | DECLARE_MAC_BUF(mac); |
1116 | 1117 | ||
1118 | rcu_read_lock(); | ||
1119 | |||
1117 | sta = sta_info_get(local, mgmt->sa); | 1120 | sta = sta_info_get(local, mgmt->sa); |
1118 | if (!sta) | 1121 | if (!sta) { |
1122 | rcu_read_unlock(); | ||
1119 | return; | 1123 | return; |
1124 | } | ||
1120 | 1125 | ||
1121 | /* extract session parameters from addba request frame */ | 1126 | /* extract session parameters from addba request frame */ |
1122 | dialog_token = mgmt->u.action.u.addba_req.dialog_token; | 1127 | dialog_token = mgmt->u.action.u.addba_req.dialog_token; |
@@ -1208,9 +1213,9 @@ end: | |||
1208 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); | 1213 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); |
1209 | 1214 | ||
1210 | end_no_lock: | 1215 | end_no_lock: |
1211 | ieee80211_send_addba_resp(sta->dev, sta->addr, tid, dialog_token, | 1216 | ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid, |
1212 | status, 1, buf_size, timeout); | 1217 | dialog_token, status, 1, buf_size, timeout); |
1213 | sta_info_put(sta); | 1218 | rcu_read_unlock(); |
1214 | } | 1219 | } |
1215 | 1220 | ||
1216 | static void ieee80211_sta_process_addba_resp(struct net_device *dev, | 1221 | static void ieee80211_sta_process_addba_resp(struct net_device *dev, |
@@ -1224,9 +1229,13 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, | |||
1224 | u16 tid; | 1229 | u16 tid; |
1225 | u8 *state; | 1230 | u8 *state; |
1226 | 1231 | ||
1232 | rcu_read_lock(); | ||
1233 | |||
1227 | sta = sta_info_get(local, mgmt->sa); | 1234 | sta = sta_info_get(local, mgmt->sa); |
1228 | if (!sta) | 1235 | if (!sta) { |
1236 | rcu_read_unlock(); | ||
1229 | return; | 1237 | return; |
1238 | } | ||
1230 | 1239 | ||
1231 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); | 1240 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); |
1232 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | 1241 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; |
@@ -1241,7 +1250,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, | |||
1241 | #ifdef CONFIG_MAC80211_HT_DEBUG | 1250 | #ifdef CONFIG_MAC80211_HT_DEBUG |
1242 | printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); | 1251 | printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); |
1243 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 1252 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
1244 | sta_info_put(sta); | 1253 | rcu_read_unlock(); |
1245 | return; | 1254 | return; |
1246 | } | 1255 | } |
1247 | 1256 | ||
@@ -1255,7 +1264,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, | |||
1255 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); | 1264 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); |
1256 | printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" | 1265 | printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" |
1257 | "%d\n", *state); | 1266 | "%d\n", *state); |
1258 | sta_info_put(sta); | 1267 | rcu_read_unlock(); |
1259 | return; | 1268 | return; |
1260 | } | 1269 | } |
1261 | 1270 | ||
@@ -1282,7 +1291,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, | |||
1282 | ieee80211_stop_tx_ba_session(hw, sta->addr, tid, | 1291 | ieee80211_stop_tx_ba_session(hw, sta->addr, tid, |
1283 | WLAN_BACK_INITIATOR); | 1292 | WLAN_BACK_INITIATOR); |
1284 | } | 1293 | } |
1285 | sta_info_put(sta); | 1294 | rcu_read_unlock(); |
1286 | } | 1295 | } |
1287 | 1296 | ||
1288 | void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, | 1297 | void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, |
@@ -1337,16 +1346,20 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, | |||
1337 | struct sta_info *sta; | 1346 | struct sta_info *sta; |
1338 | int ret, i; | 1347 | int ret, i; |
1339 | 1348 | ||
1349 | rcu_read_lock(); | ||
1350 | |||
1340 | sta = sta_info_get(local, ra); | 1351 | sta = sta_info_get(local, ra); |
1341 | if (!sta) | 1352 | if (!sta) { |
1353 | rcu_read_unlock(); | ||
1342 | return; | 1354 | return; |
1355 | } | ||
1343 | 1356 | ||
1344 | /* check if TID is in operational state */ | 1357 | /* check if TID is in operational state */ |
1345 | spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); | 1358 | spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); |
1346 | if (sta->ampdu_mlme.tid_rx[tid].state | 1359 | if (sta->ampdu_mlme.tid_rx[tid].state |
1347 | != HT_AGG_STATE_OPERATIONAL) { | 1360 | != HT_AGG_STATE_OPERATIONAL) { |
1348 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); | 1361 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); |
1349 | sta_info_put(sta); | 1362 | rcu_read_unlock(); |
1350 | return; | 1363 | return; |
1351 | } | 1364 | } |
1352 | sta->ampdu_mlme.tid_rx[tid].state = | 1365 | sta->ampdu_mlme.tid_rx[tid].state = |
@@ -1385,7 +1398,7 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, | |||
1385 | kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf); | 1398 | kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf); |
1386 | 1399 | ||
1387 | sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE; | 1400 | sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE; |
1388 | sta_info_put(sta); | 1401 | rcu_read_unlock(); |
1389 | } | 1402 | } |
1390 | 1403 | ||
1391 | 1404 | ||
@@ -1398,9 +1411,13 @@ static void ieee80211_sta_process_delba(struct net_device *dev, | |||
1398 | u16 initiator; | 1411 | u16 initiator; |
1399 | DECLARE_MAC_BUF(mac); | 1412 | DECLARE_MAC_BUF(mac); |
1400 | 1413 | ||
1414 | rcu_read_lock(); | ||
1415 | |||
1401 | sta = sta_info_get(local, mgmt->sa); | 1416 | sta = sta_info_get(local, mgmt->sa); |
1402 | if (!sta) | 1417 | if (!sta) { |
1418 | rcu_read_unlock(); | ||
1403 | return; | 1419 | return; |
1420 | } | ||
1404 | 1421 | ||
1405 | params = le16_to_cpu(mgmt->u.action.u.delba.params); | 1422 | params = le16_to_cpu(mgmt->u.action.u.delba.params); |
1406 | tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; | 1423 | tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; |
@@ -1425,7 +1442,7 @@ static void ieee80211_sta_process_delba(struct net_device *dev, | |||
1425 | ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, | 1442 | ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, |
1426 | WLAN_BACK_RECIPIENT); | 1443 | WLAN_BACK_RECIPIENT); |
1427 | } | 1444 | } |
1428 | sta_info_put(sta); | 1445 | rcu_read_unlock(); |
1429 | } | 1446 | } |
1430 | 1447 | ||
1431 | /* | 1448 | /* |
@@ -1437,7 +1454,7 @@ void sta_addba_resp_timer_expired(unsigned long data) | |||
1437 | { | 1454 | { |
1438 | /* not an elegant detour, but there is no choice as the timer passes | 1455 | /* not an elegant detour, but there is no choice as the timer passes |
1439 | * only one argument, and both sta_info and TID are needed, so init | 1456 | * only one argument, and both sta_info and TID are needed, so init |
1440 | * flow in sta_info_add gives the TID as data, while the timer_to_id | 1457 | * flow in sta_info_create gives the TID as data, while the timer_to_id |
1441 | * array gives the sta through container_of */ | 1458 | * array gives the sta through container_of */ |
1442 | u16 tid = *(int *)data; | 1459 | u16 tid = *(int *)data; |
1443 | struct sta_info *temp_sta = container_of((void *)data, | 1460 | struct sta_info *temp_sta = container_of((void *)data, |
@@ -1448,9 +1465,13 @@ void sta_addba_resp_timer_expired(unsigned long data) | |||
1448 | struct sta_info *sta; | 1465 | struct sta_info *sta; |
1449 | u8 *state; | 1466 | u8 *state; |
1450 | 1467 | ||
1468 | rcu_read_lock(); | ||
1469 | |||
1451 | sta = sta_info_get(local, temp_sta->addr); | 1470 | sta = sta_info_get(local, temp_sta->addr); |
1452 | if (!sta) | 1471 | if (!sta) { |
1472 | rcu_read_unlock(); | ||
1453 | return; | 1473 | return; |
1474 | } | ||
1454 | 1475 | ||
1455 | state = &sta->ampdu_mlme.tid_tx[tid].state; | 1476 | state = &sta->ampdu_mlme.tid_tx[tid].state; |
1456 | /* check if the TID waits for addBA response */ | 1477 | /* check if the TID waits for addBA response */ |
@@ -1472,7 +1493,7 @@ void sta_addba_resp_timer_expired(unsigned long data) | |||
1472 | WLAN_BACK_INITIATOR); | 1493 | WLAN_BACK_INITIATOR); |
1473 | 1494 | ||
1474 | timer_expired_exit: | 1495 | timer_expired_exit: |
1475 | sta_info_put(sta); | 1496 | rcu_read_unlock(); |
1476 | } | 1497 | } |
1477 | 1498 | ||
1478 | /* | 1499 | /* |
@@ -1484,7 +1505,7 @@ void sta_rx_agg_session_timer_expired(unsigned long data) | |||
1484 | { | 1505 | { |
1485 | /* not an elegant detour, but there is no choice as the timer passes | 1506 | /* not an elegant detour, but there is no choice as the timer passes |
1486 | * only one argument, and verious sta_info are needed here, so init | 1507 | * only one argument, and verious sta_info are needed here, so init |
1487 | * flow in sta_info_add gives the TID as data, while the timer_to_id | 1508 | * flow in sta_info_create gives the TID as data, while the timer_to_id |
1488 | * array gives the sta through container_of */ | 1509 | * array gives the sta through container_of */ |
1489 | u8 *ptid = (u8 *)data; | 1510 | u8 *ptid = (u8 *)data; |
1490 | u8 *timer_to_id = ptid - *ptid; | 1511 | u8 *timer_to_id = ptid - *ptid; |
@@ -1492,8 +1513,8 @@ void sta_rx_agg_session_timer_expired(unsigned long data) | |||
1492 | timer_to_tid[0]); | 1513 | timer_to_tid[0]); |
1493 | 1514 | ||
1494 | printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); | 1515 | printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); |
1495 | ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr, (u16)*ptid, | 1516 | ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr, |
1496 | WLAN_BACK_TIMER, | 1517 | (u16)*ptid, WLAN_BACK_TIMER, |
1497 | WLAN_REASON_QSTA_TIMEOUT); | 1518 | WLAN_REASON_QSTA_TIMEOUT); |
1498 | } | 1519 | } |
1499 | 1520 | ||
@@ -1802,14 +1823,19 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1802 | if (ifsta->assocresp_ies) | 1823 | if (ifsta->assocresp_ies) |
1803 | memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); | 1824 | memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); |
1804 | 1825 | ||
1826 | rcu_read_lock(); | ||
1827 | |||
1805 | /* Add STA entry for the AP */ | 1828 | /* Add STA entry for the AP */ |
1806 | sta = sta_info_get(local, ifsta->bssid); | 1829 | sta = sta_info_get(local, ifsta->bssid); |
1807 | if (!sta) { | 1830 | if (!sta) { |
1808 | struct ieee80211_sta_bss *bss; | 1831 | struct ieee80211_sta_bss *bss; |
1809 | sta = sta_info_add(local, dev, ifsta->bssid, GFP_KERNEL); | 1832 | int err; |
1810 | if (IS_ERR(sta)) { | 1833 | |
1811 | printk(KERN_DEBUG "%s: failed to add STA entry for the" | 1834 | sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC); |
1812 | " AP (error %ld)\n", dev->name, PTR_ERR(sta)); | 1835 | if (!sta) { |
1836 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" | ||
1837 | " the AP\n", dev->name); | ||
1838 | rcu_read_unlock(); | ||
1813 | return; | 1839 | return; |
1814 | } | 1840 | } |
1815 | bss = ieee80211_rx_bss_get(dev, ifsta->bssid, | 1841 | bss = ieee80211_rx_bss_get(dev, ifsta->bssid, |
@@ -1821,9 +1847,27 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1821 | sta->last_noise = bss->noise; | 1847 | sta->last_noise = bss->noise; |
1822 | ieee80211_rx_bss_put(dev, bss); | 1848 | ieee80211_rx_bss_put(dev, bss); |
1823 | } | 1849 | } |
1850 | |||
1851 | err = sta_info_insert(sta); | ||
1852 | if (err) { | ||
1853 | printk(KERN_DEBUG "%s: failed to insert STA entry for" | ||
1854 | " the AP (error %d)\n", dev->name, err); | ||
1855 | sta_info_destroy(sta); | ||
1856 | rcu_read_unlock(); | ||
1857 | return; | ||
1858 | } | ||
1824 | } | 1859 | } |
1825 | 1860 | ||
1826 | sta->dev = dev; | 1861 | /* |
1862 | * FIXME: Do we really need to update the sta_info's information here? | ||
1863 | * We already know about the AP (we found it in our list) so it | ||
1864 | * should already be filled with the right info, no? | ||
1865 | * As is stands, all this is racy because typically we assume | ||
1866 | * the information that is filled in here (except flags) doesn't | ||
1867 | * change while a STA structure is alive. As such, it should move | ||
1868 | * to between the sta_info_alloc() and sta_info_insert() above. | ||
1869 | */ | ||
1870 | |||
1827 | sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | | 1871 | sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | |
1828 | WLAN_STA_AUTHORIZED; | 1872 | WLAN_STA_AUTHORIZED; |
1829 | 1873 | ||
@@ -1886,16 +1930,16 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1886 | 1930 | ||
1887 | if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { | 1931 | if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { |
1888 | sta->flags |= WLAN_STA_WME; | 1932 | sta->flags |= WLAN_STA_WME; |
1933 | rcu_read_unlock(); | ||
1889 | ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, | 1934 | ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, |
1890 | elems.wmm_param_len); | 1935 | elems.wmm_param_len); |
1891 | } | 1936 | } else |
1937 | rcu_read_unlock(); | ||
1892 | 1938 | ||
1893 | /* set AID, ieee80211_set_associated() will tell the driver */ | 1939 | /* set AID, ieee80211_set_associated() will tell the driver */ |
1894 | bss_conf->aid = aid; | 1940 | bss_conf->aid = aid; |
1895 | ieee80211_set_associated(dev, ifsta, 1); | 1941 | ieee80211_set_associated(dev, ifsta, 1); |
1896 | 1942 | ||
1897 | sta_info_put(sta); | ||
1898 | |||
1899 | ieee80211_associated(dev, ifsta); | 1943 | ieee80211_associated(dev, ifsta); |
1900 | } | 1944 | } |
1901 | 1945 | ||
@@ -1905,8 +1949,16 @@ static void __ieee80211_rx_bss_hash_add(struct net_device *dev, | |||
1905 | struct ieee80211_sta_bss *bss) | 1949 | struct ieee80211_sta_bss *bss) |
1906 | { | 1950 | { |
1907 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1951 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1908 | bss->hnext = local->sta_bss_hash[STA_HASH(bss->bssid)]; | 1952 | u8 hash_idx; |
1909 | local->sta_bss_hash[STA_HASH(bss->bssid)] = bss; | 1953 | |
1954 | if (bss_mesh_cfg(bss)) | ||
1955 | hash_idx = mesh_id_hash(bss_mesh_id(bss), | ||
1956 | bss_mesh_id_len(bss)); | ||
1957 | else | ||
1958 | hash_idx = STA_HASH(bss->bssid); | ||
1959 | |||
1960 | bss->hnext = local->sta_bss_hash[hash_idx]; | ||
1961 | local->sta_bss_hash[hash_idx] = bss; | ||
1910 | } | 1962 | } |
1911 | 1963 | ||
1912 | 1964 | ||
@@ -1959,7 +2011,6 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int freq, | |||
1959 | return bss; | 2011 | return bss; |
1960 | } | 2012 | } |
1961 | 2013 | ||
1962 | |||
1963 | static struct ieee80211_sta_bss * | 2014 | static struct ieee80211_sta_bss * |
1964 | ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, | 2015 | ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, |
1965 | u8 *ssid, u8 ssid_len) | 2016 | u8 *ssid, u8 ssid_len) |
@@ -1970,7 +2021,8 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, | |||
1970 | spin_lock_bh(&local->sta_bss_lock); | 2021 | spin_lock_bh(&local->sta_bss_lock); |
1971 | bss = local->sta_bss_hash[STA_HASH(bssid)]; | 2022 | bss = local->sta_bss_hash[STA_HASH(bssid)]; |
1972 | while (bss) { | 2023 | while (bss) { |
1973 | if (!memcmp(bss->bssid, bssid, ETH_ALEN) && | 2024 | if (!bss_mesh_cfg(bss) && |
2025 | !memcmp(bss->bssid, bssid, ETH_ALEN) && | ||
1974 | bss->freq == freq && | 2026 | bss->freq == freq && |
1975 | bss->ssid_len == ssid_len && | 2027 | bss->ssid_len == ssid_len && |
1976 | (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { | 2028 | (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { |
@@ -1983,6 +2035,72 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, | |||
1983 | return bss; | 2035 | return bss; |
1984 | } | 2036 | } |
1985 | 2037 | ||
2038 | #ifdef CONFIG_MAC80211_MESH | ||
2039 | static struct ieee80211_sta_bss * | ||
2040 | ieee80211_rx_mesh_bss_get(struct net_device *dev, u8 *mesh_id, int mesh_id_len, | ||
2041 | u8 *mesh_cfg, int freq) | ||
2042 | { | ||
2043 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
2044 | struct ieee80211_sta_bss *bss; | ||
2045 | |||
2046 | spin_lock_bh(&local->sta_bss_lock); | ||
2047 | bss = local->sta_bss_hash[mesh_id_hash(mesh_id, mesh_id_len)]; | ||
2048 | while (bss) { | ||
2049 | if (bss_mesh_cfg(bss) && | ||
2050 | !memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) && | ||
2051 | bss->freq == freq && | ||
2052 | mesh_id_len == bss->mesh_id_len && | ||
2053 | (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id, | ||
2054 | mesh_id_len))) { | ||
2055 | atomic_inc(&bss->users); | ||
2056 | break; | ||
2057 | } | ||
2058 | bss = bss->hnext; | ||
2059 | } | ||
2060 | spin_unlock_bh(&local->sta_bss_lock); | ||
2061 | return bss; | ||
2062 | } | ||
2063 | |||
2064 | static struct ieee80211_sta_bss * | ||
2065 | ieee80211_rx_mesh_bss_add(struct net_device *dev, u8 *mesh_id, int mesh_id_len, | ||
2066 | u8 *mesh_cfg, int freq) | ||
2067 | { | ||
2068 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
2069 | struct ieee80211_sta_bss *bss; | ||
2070 | |||
2071 | bss = kzalloc(sizeof(*bss), GFP_ATOMIC); | ||
2072 | if (!bss) | ||
2073 | return NULL; | ||
2074 | |||
2075 | bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC); | ||
2076 | if (!bss->mesh_cfg) { | ||
2077 | kfree(bss); | ||
2078 | return NULL; | ||
2079 | } | ||
2080 | |||
2081 | if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) { | ||
2082 | bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC); | ||
2083 | if (!bss->mesh_id) { | ||
2084 | kfree(bss->mesh_cfg); | ||
2085 | kfree(bss); | ||
2086 | return NULL; | ||
2087 | } | ||
2088 | memcpy(bss->mesh_id, mesh_id, mesh_id_len); | ||
2089 | } | ||
2090 | |||
2091 | atomic_inc(&bss->users); | ||
2092 | atomic_inc(&bss->users); | ||
2093 | memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN); | ||
2094 | bss->mesh_id_len = mesh_id_len; | ||
2095 | bss->freq = freq; | ||
2096 | spin_lock_bh(&local->sta_bss_lock); | ||
2097 | /* TODO: order by RSSI? */ | ||
2098 | list_add_tail(&bss->list, &local->sta_bss_list); | ||
2099 | __ieee80211_rx_bss_hash_add(dev, bss); | ||
2100 | spin_unlock_bh(&local->sta_bss_lock); | ||
2101 | return bss; | ||
2102 | } | ||
2103 | #endif | ||
1986 | 2104 | ||
1987 | static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) | 2105 | static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) |
1988 | { | 2106 | { |
@@ -1990,6 +2108,8 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) | |||
1990 | kfree(bss->rsn_ie); | 2108 | kfree(bss->rsn_ie); |
1991 | kfree(bss->wmm_ie); | 2109 | kfree(bss->wmm_ie); |
1992 | kfree(bss->ht_ie); | 2110 | kfree(bss->ht_ie); |
2111 | kfree(bss_mesh_id(bss)); | ||
2112 | kfree(bss_mesh_cfg(bss)); | ||
1993 | kfree(bss); | 2113 | kfree(bss); |
1994 | } | 2114 | } |
1995 | 2115 | ||
@@ -2185,6 +2305,42 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, | |||
2185 | return res; | 2305 | return res; |
2186 | } | 2306 | } |
2187 | 2307 | ||
2308 | u64 ieee80211_sta_get_rates(struct ieee80211_local *local, | ||
2309 | struct ieee802_11_elems *elems, | ||
2310 | enum ieee80211_band band) | ||
2311 | { | ||
2312 | struct ieee80211_supported_band *sband; | ||
2313 | struct ieee80211_rate *bitrates; | ||
2314 | size_t num_rates; | ||
2315 | u64 supp_rates; | ||
2316 | int i, j; | ||
2317 | sband = local->hw.wiphy->bands[band]; | ||
2318 | |||
2319 | if (!sband) { | ||
2320 | WARN_ON(1); | ||
2321 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
2322 | } | ||
2323 | |||
2324 | bitrates = sband->bitrates; | ||
2325 | num_rates = sband->n_bitrates; | ||
2326 | supp_rates = 0; | ||
2327 | for (i = 0; i < elems->supp_rates_len + | ||
2328 | elems->ext_supp_rates_len; i++) { | ||
2329 | u8 rate = 0; | ||
2330 | int own_rate; | ||
2331 | if (i < elems->supp_rates_len) | ||
2332 | rate = elems->supp_rates[i]; | ||
2333 | else if (elems->ext_supp_rates) | ||
2334 | rate = elems->ext_supp_rates | ||
2335 | [i - elems->supp_rates_len]; | ||
2336 | own_rate = 5 * (rate & 0x7f); | ||
2337 | for (j = 0; j < num_rates; j++) | ||
2338 | if (bitrates[j].bitrate == own_rate) | ||
2339 | supp_rates |= BIT(j); | ||
2340 | } | ||
2341 | return supp_rates; | ||
2342 | } | ||
2343 | |||
2188 | 2344 | ||
2189 | static void ieee80211_rx_bss_info(struct net_device *dev, | 2345 | static void ieee80211_rx_bss_info(struct net_device *dev, |
2190 | struct ieee80211_mgmt *mgmt, | 2346 | struct ieee80211_mgmt *mgmt, |
@@ -2219,41 +2375,23 @@ static void ieee80211_rx_bss_info(struct net_device *dev, | |||
2219 | beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); | 2375 | beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); |
2220 | ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); | 2376 | ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); |
2221 | 2377 | ||
2222 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && | 2378 | if (ieee80211_vif_is_mesh(&sdata->vif) && elems.mesh_id && |
2223 | memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && | 2379 | elems.mesh_config && mesh_matches_local(&elems, dev)) { |
2224 | (sta = sta_info_get(local, mgmt->sa))) { | 2380 | u64 rates = ieee80211_sta_get_rates(local, &elems, |
2225 | struct ieee80211_supported_band *sband; | 2381 | rx_status->band); |
2226 | struct ieee80211_rate *bitrates; | ||
2227 | size_t num_rates; | ||
2228 | u64 supp_rates, prev_rates; | ||
2229 | int i, j; | ||
2230 | 2382 | ||
2231 | sband = local->hw.wiphy->bands[rx_status->band]; | 2383 | mesh_neighbour_update(mgmt->sa, rates, dev, |
2384 | mesh_peer_accepts_plinks(&elems, dev)); | ||
2385 | } | ||
2232 | 2386 | ||
2233 | if (!sband) { | 2387 | rcu_read_lock(); |
2234 | WARN_ON(1); | ||
2235 | sband = local->hw.wiphy->bands[ | ||
2236 | local->hw.conf.channel->band]; | ||
2237 | } | ||
2238 | 2388 | ||
2239 | bitrates = sband->bitrates; | 2389 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && |
2240 | num_rates = sband->n_bitrates; | 2390 | memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && |
2241 | 2391 | (sta = sta_info_get(local, mgmt->sa))) { | |
2242 | supp_rates = 0; | 2392 | u64 prev_rates; |
2243 | for (i = 0; i < elems.supp_rates_len + | 2393 | u64 supp_rates = ieee80211_sta_get_rates(local, &elems, |
2244 | elems.ext_supp_rates_len; i++) { | 2394 | rx_status->band); |
2245 | u8 rate = 0; | ||
2246 | int own_rate; | ||
2247 | if (i < elems.supp_rates_len) | ||
2248 | rate = elems.supp_rates[i]; | ||
2249 | else if (elems.ext_supp_rates) | ||
2250 | rate = elems.ext_supp_rates | ||
2251 | [i - elems.supp_rates_len]; | ||
2252 | own_rate = 5 * (rate & 0x7f); | ||
2253 | for (j = 0; j < num_rates; j++) | ||
2254 | if (bitrates[j].bitrate == own_rate) | ||
2255 | supp_rates |= BIT(j); | ||
2256 | } | ||
2257 | 2395 | ||
2258 | prev_rates = sta->supp_rates[rx_status->band]; | 2396 | prev_rates = sta->supp_rates[rx_status->band]; |
2259 | sta->supp_rates[rx_status->band] &= supp_rates; | 2397 | sta->supp_rates[rx_status->band] &= supp_rates; |
@@ -2273,22 +2411,32 @@ static void ieee80211_rx_bss_info(struct net_device *dev, | |||
2273 | (unsigned long long) supp_rates, | 2411 | (unsigned long long) supp_rates, |
2274 | (unsigned long long) sta->supp_rates[rx_status->band]); | 2412 | (unsigned long long) sta->supp_rates[rx_status->band]); |
2275 | } | 2413 | } |
2276 | sta_info_put(sta); | ||
2277 | } | 2414 | } |
2278 | 2415 | ||
2279 | if (!elems.ssid) | 2416 | rcu_read_unlock(); |
2280 | return; | ||
2281 | 2417 | ||
2282 | if (elems.ds_params && elems.ds_params_len == 1) | 2418 | if (elems.ds_params && elems.ds_params_len == 1) |
2283 | freq = ieee80211_channel_to_frequency(elems.ds_params[0]); | 2419 | freq = ieee80211_channel_to_frequency(elems.ds_params[0]); |
2284 | else | 2420 | else |
2285 | freq = rx_status->freq; | 2421 | freq = rx_status->freq; |
2286 | 2422 | ||
2287 | bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq, | 2423 | #ifdef CONFIG_MAC80211_MESH |
2288 | elems.ssid, elems.ssid_len); | 2424 | if (elems.mesh_config) |
2289 | if (!bss) { | 2425 | bss = ieee80211_rx_mesh_bss_get(dev, elems.mesh_id, |
2290 | bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq, | 2426 | elems.mesh_id_len, elems.mesh_config, freq); |
2427 | else | ||
2428 | #endif | ||
2429 | bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq, | ||
2291 | elems.ssid, elems.ssid_len); | 2430 | elems.ssid, elems.ssid_len); |
2431 | if (!bss) { | ||
2432 | #ifdef CONFIG_MAC80211_MESH | ||
2433 | if (elems.mesh_config) | ||
2434 | bss = ieee80211_rx_mesh_bss_add(dev, elems.mesh_id, | ||
2435 | elems.mesh_id_len, elems.mesh_config, freq); | ||
2436 | else | ||
2437 | #endif | ||
2438 | bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq, | ||
2439 | elems.ssid, elems.ssid_len); | ||
2292 | if (!bss) | 2440 | if (!bss) |
2293 | return; | 2441 | return; |
2294 | } else { | 2442 | } else { |
@@ -2615,8 +2763,11 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, | |||
2615 | static void ieee80211_rx_mgmt_action(struct net_device *dev, | 2763 | static void ieee80211_rx_mgmt_action(struct net_device *dev, |
2616 | struct ieee80211_if_sta *ifsta, | 2764 | struct ieee80211_if_sta *ifsta, |
2617 | struct ieee80211_mgmt *mgmt, | 2765 | struct ieee80211_mgmt *mgmt, |
2618 | size_t len) | 2766 | size_t len, |
2767 | struct ieee80211_rx_status *rx_status) | ||
2619 | { | 2768 | { |
2769 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2770 | |||
2620 | if (len < IEEE80211_MIN_ACTION_SIZE) | 2771 | if (len < IEEE80211_MIN_ACTION_SIZE) |
2621 | return; | 2772 | return; |
2622 | 2773 | ||
@@ -2648,7 +2799,18 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev, | |||
2648 | break; | 2799 | break; |
2649 | } | 2800 | } |
2650 | break; | 2801 | break; |
2802 | case PLINK_CATEGORY: | ||
2803 | if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
2804 | mesh_rx_plink_frame(dev, mgmt, len, rx_status); | ||
2805 | break; | ||
2806 | case MESH_PATH_SEL_CATEGORY: | ||
2807 | if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
2808 | mesh_rx_path_sel_frame(dev, mgmt, len); | ||
2809 | break; | ||
2651 | default: | 2810 | default: |
2811 | if (net_ratelimit()) | ||
2812 | printk(KERN_DEBUG "%s: Rx unknown action frame - " | ||
2813 | "category=%d\n", dev->name, mgmt->u.action.category); | ||
2652 | break; | 2814 | break; |
2653 | } | 2815 | } |
2654 | } | 2816 | } |
@@ -2675,13 +2837,13 @@ void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb, | |||
2675 | case IEEE80211_STYPE_PROBE_REQ: | 2837 | case IEEE80211_STYPE_PROBE_REQ: |
2676 | case IEEE80211_STYPE_PROBE_RESP: | 2838 | case IEEE80211_STYPE_PROBE_RESP: |
2677 | case IEEE80211_STYPE_BEACON: | 2839 | case IEEE80211_STYPE_BEACON: |
2840 | case IEEE80211_STYPE_ACTION: | ||
2678 | memcpy(skb->cb, rx_status, sizeof(*rx_status)); | 2841 | memcpy(skb->cb, rx_status, sizeof(*rx_status)); |
2679 | case IEEE80211_STYPE_AUTH: | 2842 | case IEEE80211_STYPE_AUTH: |
2680 | case IEEE80211_STYPE_ASSOC_RESP: | 2843 | case IEEE80211_STYPE_ASSOC_RESP: |
2681 | case IEEE80211_STYPE_REASSOC_RESP: | 2844 | case IEEE80211_STYPE_REASSOC_RESP: |
2682 | case IEEE80211_STYPE_DEAUTH: | 2845 | case IEEE80211_STYPE_DEAUTH: |
2683 | case IEEE80211_STYPE_DISASSOC: | 2846 | case IEEE80211_STYPE_DISASSOC: |
2684 | case IEEE80211_STYPE_ACTION: | ||
2685 | skb_queue_tail(&ifsta->skb_queue, skb); | 2847 | skb_queue_tail(&ifsta->skb_queue, skb); |
2686 | queue_work(local->hw.workqueue, &ifsta->work); | 2848 | queue_work(local->hw.workqueue, &ifsta->work); |
2687 | return; | 2849 | return; |
@@ -2740,7 +2902,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev, | |||
2740 | ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len); | 2902 | ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len); |
2741 | break; | 2903 | break; |
2742 | case IEEE80211_STYPE_ACTION: | 2904 | case IEEE80211_STYPE_ACTION: |
2743 | ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len); | 2905 | ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len, rx_status); |
2744 | break; | 2906 | break; |
2745 | } | 2907 | } |
2746 | 2908 | ||
@@ -2789,45 +2951,50 @@ static int ieee80211_sta_active_ibss(struct net_device *dev) | |||
2789 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 2951 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
2790 | int active = 0; | 2952 | int active = 0; |
2791 | struct sta_info *sta; | 2953 | struct sta_info *sta; |
2954 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2955 | |||
2956 | rcu_read_lock(); | ||
2792 | 2957 | ||
2793 | read_lock_bh(&local->sta_lock); | 2958 | list_for_each_entry_rcu(sta, &local->sta_list, list) { |
2794 | list_for_each_entry(sta, &local->sta_list, list) { | 2959 | if (sta->sdata == sdata && |
2795 | if (sta->dev == dev && | ||
2796 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, | 2960 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, |
2797 | jiffies)) { | 2961 | jiffies)) { |
2798 | active++; | 2962 | active++; |
2799 | break; | 2963 | break; |
2800 | } | 2964 | } |
2801 | } | 2965 | } |
2802 | read_unlock_bh(&local->sta_lock); | 2966 | |
2967 | rcu_read_unlock(); | ||
2803 | 2968 | ||
2804 | return active; | 2969 | return active; |
2805 | } | 2970 | } |
2806 | 2971 | ||
2807 | 2972 | ||
2808 | static void ieee80211_sta_expire(struct net_device *dev) | 2973 | static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time) |
2809 | { | 2974 | { |
2810 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 2975 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
2811 | struct sta_info *sta, *tmp; | 2976 | struct sta_info *sta, *tmp; |
2812 | LIST_HEAD(tmp_list); | 2977 | LIST_HEAD(tmp_list); |
2813 | DECLARE_MAC_BUF(mac); | 2978 | DECLARE_MAC_BUF(mac); |
2979 | unsigned long flags; | ||
2814 | 2980 | ||
2815 | write_lock_bh(&local->sta_lock); | 2981 | spin_lock_irqsave(&local->sta_lock, flags); |
2816 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) | 2982 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) |
2817 | if (time_after(jiffies, sta->last_rx + | 2983 | if (time_after(jiffies, sta->last_rx + exp_time)) { |
2818 | IEEE80211_IBSS_INACTIVITY_LIMIT)) { | ||
2819 | printk(KERN_DEBUG "%s: expiring inactive STA %s\n", | 2984 | printk(KERN_DEBUG "%s: expiring inactive STA %s\n", |
2820 | dev->name, print_mac(mac, sta->addr)); | 2985 | dev->name, print_mac(mac, sta->addr)); |
2821 | __sta_info_get(sta); | 2986 | sta_info_unlink(&sta); |
2822 | sta_info_remove(sta); | 2987 | if (sta) |
2823 | list_add(&sta->list, &tmp_list); | 2988 | list_add(&sta->list, &tmp_list); |
2824 | } | 2989 | } |
2825 | write_unlock_bh(&local->sta_lock); | 2990 | spin_unlock_irqrestore(&local->sta_lock, flags); |
2826 | 2991 | ||
2827 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) { | 2992 | synchronize_rcu(); |
2828 | sta_info_free(sta); | 2993 | |
2829 | sta_info_put(sta); | 2994 | rtnl_lock(); |
2830 | } | 2995 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) |
2996 | sta_info_destroy(sta); | ||
2997 | rtnl_unlock(); | ||
2831 | } | 2998 | } |
2832 | 2999 | ||
2833 | 3000 | ||
@@ -2836,7 +3003,7 @@ static void ieee80211_sta_merge_ibss(struct net_device *dev, | |||
2836 | { | 3003 | { |
2837 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | 3004 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); |
2838 | 3005 | ||
2839 | ieee80211_sta_expire(dev); | 3006 | ieee80211_sta_expire(dev, IEEE80211_IBSS_INACTIVITY_LIMIT); |
2840 | if (ieee80211_sta_active_ibss(dev)) | 3007 | if (ieee80211_sta_active_ibss(dev)) |
2841 | return; | 3008 | return; |
2842 | 3009 | ||
@@ -2846,6 +3013,36 @@ static void ieee80211_sta_merge_ibss(struct net_device *dev, | |||
2846 | } | 3013 | } |
2847 | 3014 | ||
2848 | 3015 | ||
3016 | #ifdef CONFIG_MAC80211_MESH | ||
3017 | static void ieee80211_mesh_housekeeping(struct net_device *dev, | ||
3018 | struct ieee80211_if_sta *ifsta) | ||
3019 | { | ||
3020 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
3021 | bool free_plinks; | ||
3022 | |||
3023 | ieee80211_sta_expire(dev, IEEE80211_MESH_PEER_INACTIVITY_LIMIT); | ||
3024 | mesh_path_expire(dev); | ||
3025 | |||
3026 | free_plinks = mesh_plink_availables(sdata); | ||
3027 | if (free_plinks != sdata->u.sta.accepting_plinks) | ||
3028 | ieee80211_if_config_beacon(dev); | ||
3029 | |||
3030 | mod_timer(&ifsta->timer, jiffies + | ||
3031 | IEEE80211_MESH_HOUSEKEEPING_INTERVAL); | ||
3032 | } | ||
3033 | |||
3034 | |||
3035 | void ieee80211_start_mesh(struct net_device *dev) | ||
3036 | { | ||
3037 | struct ieee80211_if_sta *ifsta; | ||
3038 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
3039 | ifsta = &sdata->u.sta; | ||
3040 | ifsta->state = IEEE80211_MESH_UP; | ||
3041 | ieee80211_sta_timer((unsigned long)sdata); | ||
3042 | } | ||
3043 | #endif | ||
3044 | |||
3045 | |||
2849 | void ieee80211_sta_timer(unsigned long data) | 3046 | void ieee80211_sta_timer(unsigned long data) |
2850 | { | 3047 | { |
2851 | struct ieee80211_sub_if_data *sdata = | 3048 | struct ieee80211_sub_if_data *sdata = |
@@ -2857,7 +3054,6 @@ void ieee80211_sta_timer(unsigned long data) | |||
2857 | queue_work(local->hw.workqueue, &ifsta->work); | 3054 | queue_work(local->hw.workqueue, &ifsta->work); |
2858 | } | 3055 | } |
2859 | 3056 | ||
2860 | |||
2861 | void ieee80211_sta_work(struct work_struct *work) | 3057 | void ieee80211_sta_work(struct work_struct *work) |
2862 | { | 3058 | { |
2863 | struct ieee80211_sub_if_data *sdata = | 3059 | struct ieee80211_sub_if_data *sdata = |
@@ -2874,7 +3070,8 @@ void ieee80211_sta_work(struct work_struct *work) | |||
2874 | return; | 3070 | return; |
2875 | 3071 | ||
2876 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA && | 3072 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA && |
2877 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS) { | 3073 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS && |
3074 | sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) { | ||
2878 | printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface " | 3075 | printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface " |
2879 | "(type=%d)\n", dev->name, sdata->vif.type); | 3076 | "(type=%d)\n", dev->name, sdata->vif.type); |
2880 | return; | 3077 | return; |
@@ -2884,6 +3081,13 @@ void ieee80211_sta_work(struct work_struct *work) | |||
2884 | while ((skb = skb_dequeue(&ifsta->skb_queue))) | 3081 | while ((skb = skb_dequeue(&ifsta->skb_queue))) |
2885 | ieee80211_sta_rx_queued_mgmt(dev, skb); | 3082 | ieee80211_sta_rx_queued_mgmt(dev, skb); |
2886 | 3083 | ||
3084 | #ifdef CONFIG_MAC80211_MESH | ||
3085 | if (ifsta->preq_queue_len && | ||
3086 | time_after(jiffies, | ||
3087 | ifsta->last_preq + msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval))) | ||
3088 | mesh_path_start_discovery(dev); | ||
3089 | #endif | ||
3090 | |||
2887 | if (ifsta->state != IEEE80211_AUTHENTICATE && | 3091 | if (ifsta->state != IEEE80211_AUTHENTICATE && |
2888 | ifsta->state != IEEE80211_ASSOCIATE && | 3092 | ifsta->state != IEEE80211_ASSOCIATE && |
2889 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { | 3093 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { |
@@ -2919,6 +3123,11 @@ void ieee80211_sta_work(struct work_struct *work) | |||
2919 | case IEEE80211_IBSS_JOINED: | 3123 | case IEEE80211_IBSS_JOINED: |
2920 | ieee80211_sta_merge_ibss(dev, ifsta); | 3124 | ieee80211_sta_merge_ibss(dev, ifsta); |
2921 | break; | 3125 | break; |
3126 | #ifdef CONFIG_MAC80211_MESH | ||
3127 | case IEEE80211_MESH_UP: | ||
3128 | ieee80211_mesh_housekeeping(dev, ifsta); | ||
3129 | break; | ||
3130 | #endif | ||
2922 | default: | 3131 | default: |
2923 | printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n", | 3132 | printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n", |
2924 | ifsta->state); | 3133 | ifsta->state); |
@@ -3123,7 +3332,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, | |||
3123 | sband = local->hw.wiphy->bands[bss->band]; | 3332 | sband = local->hw.wiphy->bands[bss->band]; |
3124 | 3333 | ||
3125 | if (local->hw.conf.beacon_int == 0) | 3334 | if (local->hw.conf.beacon_int == 0) |
3126 | local->hw.conf.beacon_int = 100; | 3335 | local->hw.conf.beacon_int = 10000; |
3127 | bss->beacon_int = local->hw.conf.beacon_int; | 3336 | bss->beacon_int = local->hw.conf.beacon_int; |
3128 | bss->last_update = jiffies; | 3337 | bss->last_update = jiffies; |
3129 | bss->capability = WLAN_CAPABILITY_IBSS; | 3338 | bss->capability = WLAN_CAPABILITY_IBSS; |
@@ -3367,6 +3576,13 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
3367 | } | 3576 | } |
3368 | 3577 | ||
3369 | 3578 | ||
3579 | static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | ||
3580 | { | ||
3581 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA || | ||
3582 | ieee80211_vif_is_mesh(&sdata->vif)) | ||
3583 | ieee80211_sta_timer((unsigned long)sdata); | ||
3584 | } | ||
3585 | |||
3370 | void ieee80211_scan_completed(struct ieee80211_hw *hw) | 3586 | void ieee80211_scan_completed(struct ieee80211_hw *hw) |
3371 | { | 3587 | { |
3372 | struct ieee80211_local *local = hw_to_local(hw); | 3588 | struct ieee80211_local *local = hw_to_local(hw); |
@@ -3380,6 +3596,12 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) | |||
3380 | 3596 | ||
3381 | if (local->sta_hw_scanning) { | 3597 | if (local->sta_hw_scanning) { |
3382 | local->sta_hw_scanning = 0; | 3598 | local->sta_hw_scanning = 0; |
3599 | /* Restart STA timer for HW scan case */ | ||
3600 | rcu_read_lock(); | ||
3601 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | ||
3602 | ieee80211_restart_sta_timer(sdata); | ||
3603 | rcu_read_unlock(); | ||
3604 | |||
3383 | goto done; | 3605 | goto done; |
3384 | } | 3606 | } |
3385 | 3607 | ||
@@ -3406,11 +3628,12 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) | |||
3406 | if (sdata->dev == local->mdev) | 3628 | if (sdata->dev == local->mdev) |
3407 | continue; | 3629 | continue; |
3408 | 3630 | ||
3409 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { | 3631 | /* Tell AP we're back */ |
3410 | if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) | 3632 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA && |
3411 | ieee80211_send_nullfunc(local, sdata, 0); | 3633 | sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) |
3412 | ieee80211_sta_timer((unsigned long)sdata); | 3634 | ieee80211_send_nullfunc(local, sdata, 0); |
3413 | } | 3635 | |
3636 | ieee80211_restart_sta_timer(sdata); | ||
3414 | 3637 | ||
3415 | netif_wake_queue(sdata->dev); | 3638 | netif_wake_queue(sdata->dev); |
3416 | } | 3639 | } |
@@ -3654,15 +3877,25 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
3654 | 3877 | ||
3655 | memset(&iwe, 0, sizeof(iwe)); | 3878 | memset(&iwe, 0, sizeof(iwe)); |
3656 | iwe.cmd = SIOCGIWESSID; | 3879 | iwe.cmd = SIOCGIWESSID; |
3657 | iwe.u.data.length = bss->ssid_len; | 3880 | if (bss_mesh_cfg(bss)) { |
3658 | iwe.u.data.flags = 1; | 3881 | iwe.u.data.length = bss_mesh_id_len(bss); |
3659 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | 3882 | iwe.u.data.flags = 1; |
3660 | bss->ssid); | 3883 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, |
3884 | bss_mesh_id(bss)); | ||
3885 | } else { | ||
3886 | iwe.u.data.length = bss->ssid_len; | ||
3887 | iwe.u.data.flags = 1; | ||
3888 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | ||
3889 | bss->ssid); | ||
3890 | } | ||
3661 | 3891 | ||
3662 | if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { | 3892 | if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) |
3893 | || bss_mesh_cfg(bss)) { | ||
3663 | memset(&iwe, 0, sizeof(iwe)); | 3894 | memset(&iwe, 0, sizeof(iwe)); |
3664 | iwe.cmd = SIOCGIWMODE; | 3895 | iwe.cmd = SIOCGIWMODE; |
3665 | if (bss->capability & WLAN_CAPABILITY_ESS) | 3896 | if (bss_mesh_cfg(bss)) |
3897 | iwe.u.mode = IW_MODE_MESH; | ||
3898 | else if (bss->capability & WLAN_CAPABILITY_ESS) | ||
3666 | iwe.u.mode = IW_MODE_MASTER; | 3899 | iwe.u.mode = IW_MODE_MASTER; |
3667 | else | 3900 | else |
3668 | iwe.u.mode = IW_MODE_ADHOC; | 3901 | iwe.u.mode = IW_MODE_ADHOC; |
@@ -3751,6 +3984,45 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
3751 | } | 3984 | } |
3752 | } | 3985 | } |
3753 | 3986 | ||
3987 | if (bss_mesh_cfg(bss)) { | ||
3988 | char *buf; | ||
3989 | u8 *cfg = bss_mesh_cfg(bss); | ||
3990 | buf = kmalloc(50, GFP_ATOMIC); | ||
3991 | if (buf) { | ||
3992 | memset(&iwe, 0, sizeof(iwe)); | ||
3993 | iwe.cmd = IWEVCUSTOM; | ||
3994 | sprintf(buf, "Mesh network (version %d)", cfg[0]); | ||
3995 | iwe.u.data.length = strlen(buf); | ||
3996 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
3997 | &iwe, buf); | ||
3998 | sprintf(buf, "Path Selection Protocol ID: " | ||
3999 | "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3], | ||
4000 | cfg[4]); | ||
4001 | iwe.u.data.length = strlen(buf); | ||
4002 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
4003 | &iwe, buf); | ||
4004 | sprintf(buf, "Path Selection Metric ID: " | ||
4005 | "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7], | ||
4006 | cfg[8]); | ||
4007 | iwe.u.data.length = strlen(buf); | ||
4008 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
4009 | &iwe, buf); | ||
4010 | sprintf(buf, "Congestion Control Mode ID: " | ||
4011 | "0x%02X%02X%02X%02X", cfg[9], cfg[10], | ||
4012 | cfg[11], cfg[12]); | ||
4013 | iwe.u.data.length = strlen(buf); | ||
4014 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
4015 | &iwe, buf); | ||
4016 | sprintf(buf, "Channel Precedence: " | ||
4017 | "0x%02X%02X%02X%02X", cfg[13], cfg[14], | ||
4018 | cfg[15], cfg[16]); | ||
4019 | iwe.u.data.length = strlen(buf); | ||
4020 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
4021 | &iwe, buf); | ||
4022 | kfree(buf); | ||
4023 | } | ||
4024 | } | ||
4025 | |||
3754 | return current_ev; | 4026 | return current_ev; |
3755 | } | 4027 | } |
3756 | 4028 | ||
@@ -3819,8 +4091,8 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, | |||
3819 | printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", | 4091 | printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", |
3820 | wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); | 4092 | wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); |
3821 | 4093 | ||
3822 | sta = sta_info_add(local, dev, addr, GFP_ATOMIC); | 4094 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); |
3823 | if (IS_ERR(sta)) | 4095 | if (!sta) |
3824 | return NULL; | 4096 | return NULL; |
3825 | 4097 | ||
3826 | sta->flags |= WLAN_STA_AUTHORIZED; | 4098 | sta->flags |= WLAN_STA_AUTHORIZED; |
@@ -3830,7 +4102,12 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, | |||
3830 | 4102 | ||
3831 | rate_control_rate_init(sta, local); | 4103 | rate_control_rate_init(sta, local); |
3832 | 4104 | ||
3833 | return sta; /* caller will call sta_info_put() */ | 4105 | if (sta_info_insert(sta)) { |
4106 | sta_info_destroy(sta); | ||
4107 | return NULL; | ||
4108 | } | ||
4109 | |||
4110 | return sta; | ||
3834 | } | 4111 | } |
3835 | 4112 | ||
3836 | 4113 | ||
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index eac9c59dbc4d..f91fb4092652 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -20,8 +20,8 @@ | |||
20 | #include "aes_ccm.h" | 20 | #include "aes_ccm.h" |
21 | 21 | ||
22 | 22 | ||
23 | /* | 23 | /** |
24 | * Key handling basics | 24 | * DOC: Key handling basics |
25 | * | 25 | * |
26 | * Key handling in mac80211 is done based on per-interface (sub_if_data) | 26 | * Key handling in mac80211 is done based on per-interface (sub_if_data) |
27 | * keys and per-station keys. Since each station belongs to an interface, | 27 | * keys and per-station keys. Since each station belongs to an interface, |
@@ -174,6 +174,9 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
174 | { | 174 | { |
175 | int idx, defkey; | 175 | int idx, defkey; |
176 | 176 | ||
177 | if (new) | ||
178 | list_add(&new->list, &sdata->key_list); | ||
179 | |||
177 | if (sta) { | 180 | if (sta) { |
178 | rcu_assign_pointer(sta->key, new); | 181 | rcu_assign_pointer(sta->key, new); |
179 | } else { | 182 | } else { |
@@ -190,9 +193,6 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
190 | ieee80211_set_default_key(sdata, -1); | 193 | ieee80211_set_default_key(sdata, -1); |
191 | 194 | ||
192 | rcu_assign_pointer(sdata->keys[idx], new); | 195 | rcu_assign_pointer(sdata->keys[idx], new); |
193 | if (new) | ||
194 | list_add(&new->list, &sdata->key_list); | ||
195 | |||
196 | if (defkey && new) | 196 | if (defkey && new) |
197 | ieee80211_set_default_key(sdata, new->conf.keyidx); | 197 | ieee80211_set_default_key(sdata, new->conf.keyidx); |
198 | } | 198 | } |
@@ -240,14 +240,17 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
240 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { | 240 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { |
241 | struct sta_info *ap; | 241 | struct sta_info *ap; |
242 | 242 | ||
243 | rcu_read_lock(); | ||
244 | |||
243 | /* same here, the AP could be using QoS */ | 245 | /* same here, the AP could be using QoS */ |
244 | ap = sta_info_get(key->local, key->sdata->u.sta.bssid); | 246 | ap = sta_info_get(key->local, key->sdata->u.sta.bssid); |
245 | if (ap) { | 247 | if (ap) { |
246 | if (ap->flags & WLAN_STA_WME) | 248 | if (ap->flags & WLAN_STA_WME) |
247 | key->conf.flags |= | 249 | key->conf.flags |= |
248 | IEEE80211_KEY_FLAG_WMM_STA; | 250 | IEEE80211_KEY_FLAG_WMM_STA; |
249 | sta_info_put(ap); | ||
250 | } | 251 | } |
252 | |||
253 | rcu_read_unlock(); | ||
251 | } | 254 | } |
252 | } | 255 | } |
253 | 256 | ||
@@ -290,6 +293,9 @@ void ieee80211_key_free(struct ieee80211_key *key) | |||
290 | __ieee80211_key_replace(key->sdata, key->sta, | 293 | __ieee80211_key_replace(key->sdata, key->sta, |
291 | key, NULL); | 294 | key, NULL); |
292 | 295 | ||
296 | /* | ||
297 | * Do NOT remove this without looking at sta_info_destroy() | ||
298 | */ | ||
293 | synchronize_rcu(); | 299 | synchronize_rcu(); |
294 | 300 | ||
295 | /* | 301 | /* |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c new file mode 100644 index 000000000000..594a3356a508 --- /dev/null +++ b/net/mac80211/mesh.c | |||
@@ -0,0 +1,449 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008 open80211s Ltd. | ||
3 | * Authors: Luis Carlos Cobo <luisca@cozybit.com> | ||
4 | * Javier Cardona <javier@cozybit.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include "ieee80211_i.h" | ||
12 | #include "mesh.h" | ||
13 | |||
14 | #define PP_OFFSET 1 /* Path Selection Protocol */ | ||
15 | #define PM_OFFSET 5 /* Path Selection Metric */ | ||
16 | #define CC_OFFSET 9 /* Congestion Control Mode */ | ||
17 | #define CAPAB_OFFSET 17 | ||
18 | #define ACCEPT_PLINKS 0x80 | ||
19 | |||
20 | int mesh_allocated; | ||
21 | static struct kmem_cache *rm_cache; | ||
22 | |||
23 | void ieee80211s_init(void) | ||
24 | { | ||
25 | mesh_pathtbl_init(); | ||
26 | mesh_allocated = 1; | ||
27 | rm_cache = kmem_cache_create("mesh_rmc", sizeof(struct rmc_entry), | ||
28 | 0, 0, NULL); | ||
29 | } | ||
30 | |||
31 | void ieee80211s_stop(void) | ||
32 | { | ||
33 | mesh_pathtbl_unregister(); | ||
34 | kmem_cache_destroy(rm_cache); | ||
35 | } | ||
36 | |||
37 | /** | ||
38 | * mesh_matches_local - check if the config of a mesh point matches ours | ||
39 | * | ||
40 | * @ie: information elements of a management frame from the mesh peer | ||
41 | * @dev: local mesh interface | ||
42 | * | ||
43 | * This function checks if the mesh configuration of a mesh point matches the | ||
44 | * local mesh configuration, i.e. if both nodes belong to the same mesh network. | ||
45 | */ | ||
46 | bool mesh_matches_local(struct ieee802_11_elems *ie, struct net_device *dev) | ||
47 | { | ||
48 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
49 | struct ieee80211_if_sta *sta = &sdata->u.sta; | ||
50 | |||
51 | /* | ||
52 | * As support for each feature is added, check for matching | ||
53 | * - On mesh config capabilities | ||
54 | * - Power Save Support En | ||
55 | * - Sync support enabled | ||
56 | * - Sync support active | ||
57 | * - Sync support required from peer | ||
58 | * - MDA enabled | ||
59 | * - Power management control on fc | ||
60 | */ | ||
61 | if (sta->mesh_id_len == ie->mesh_id_len && | ||
62 | memcmp(sta->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && | ||
63 | memcmp(sta->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 && | ||
64 | memcmp(sta->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 && | ||
65 | memcmp(sta->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0) | ||
66 | return true; | ||
67 | |||
68 | return false; | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * mesh_peer_accepts_plinks - check if an mp is willing to establish peer links | ||
73 | * | ||
74 | * @ie: information elements of a management frame from the mesh peer | ||
75 | * @dev: local mesh interface | ||
76 | */ | ||
77 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie, | ||
78 | struct net_device *dev) | ||
79 | { | ||
80 | return (*(ie->mesh_config + CAPAB_OFFSET) & ACCEPT_PLINKS) != 0; | ||
81 | } | ||
82 | |||
83 | /** | ||
84 | * mesh_accept_plinks_update: update accepting_plink in local mesh beacons | ||
85 | * | ||
86 | * @sdata: mesh interface in which mesh beacons are going to be updated | ||
87 | */ | ||
88 | void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) | ||
89 | { | ||
90 | bool free_plinks; | ||
91 | |||
92 | /* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0, | ||
93 | * the mesh interface might be able to establish plinks with peers that | ||
94 | * are already on the table but are not on PLINK_ESTAB state. However, | ||
95 | * in general the mesh interface is not accepting peer link requests | ||
96 | * from new peers, and that must be reflected in the beacon | ||
97 | */ | ||
98 | free_plinks = mesh_plink_availables(sdata); | ||
99 | |||
100 | if (free_plinks != sdata->u.sta.accepting_plinks) | ||
101 | ieee80211_sta_timer((unsigned long) sdata); | ||
102 | } | ||
103 | |||
104 | void mesh_ids_set_default(struct ieee80211_if_sta *sta) | ||
105 | { | ||
106 | u8 def_id[4] = {0x00, 0x0F, 0xAC, 0xff}; | ||
107 | |||
108 | memcpy(sta->mesh_pp_id, def_id, 4); | ||
109 | memcpy(sta->mesh_pm_id, def_id, 4); | ||
110 | memcpy(sta->mesh_cc_id, def_id, 4); | ||
111 | } | ||
112 | |||
113 | int mesh_rmc_init(struct net_device *dev) | ||
114 | { | ||
115 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
116 | int i; | ||
117 | |||
118 | sdata->u.sta.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL); | ||
119 | if (!sdata->u.sta.rmc) | ||
120 | return -ENOMEM; | ||
121 | sdata->u.sta.rmc->idx_mask = RMC_BUCKETS - 1; | ||
122 | for (i = 0; i < RMC_BUCKETS; i++) | ||
123 | INIT_LIST_HEAD(&sdata->u.sta.rmc->bucket[i].list); | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | void mesh_rmc_free(struct net_device *dev) | ||
128 | { | ||
129 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
130 | struct mesh_rmc *rmc = sdata->u.sta.rmc; | ||
131 | struct rmc_entry *p, *n; | ||
132 | int i; | ||
133 | |||
134 | if (!sdata->u.sta.rmc) | ||
135 | return; | ||
136 | |||
137 | for (i = 0; i < RMC_BUCKETS; i++) | ||
138 | list_for_each_entry_safe(p, n, &rmc->bucket[i].list, list) { | ||
139 | list_del(&p->list); | ||
140 | kmem_cache_free(rm_cache, p); | ||
141 | } | ||
142 | |||
143 | kfree(rmc); | ||
144 | sdata->u.sta.rmc = NULL; | ||
145 | } | ||
146 | |||
147 | /** | ||
148 | * mesh_rmc_check - Check frame in recent multicast cache and add if absent. | ||
149 | * | ||
150 | * @sa: source address | ||
151 | * @mesh_hdr: mesh_header | ||
152 | * | ||
153 | * Returns: 0 if the frame is not in the cache, nonzero otherwise. | ||
154 | * | ||
155 | * Checks using the source address and the mesh sequence number if we have | ||
156 | * received this frame lately. If the frame is not in the cache, it is added to | ||
157 | * it. | ||
158 | */ | ||
159 | int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr, | ||
160 | struct net_device *dev) | ||
161 | { | ||
162 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
163 | struct mesh_rmc *rmc = sdata->u.sta.rmc; | ||
164 | u32 seqnum = 0; | ||
165 | int entries = 0; | ||
166 | u8 idx; | ||
167 | struct rmc_entry *p, *n; | ||
168 | |||
169 | /* Don't care about endianness since only match matters */ | ||
170 | memcpy(&seqnum, mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum)); | ||
171 | idx = mesh_hdr->seqnum[0] & rmc->idx_mask; | ||
172 | list_for_each_entry_safe(p, n, &rmc->bucket[idx].list, list) { | ||
173 | ++entries; | ||
174 | if (time_after(jiffies, p->exp_time) || | ||
175 | (entries == RMC_QUEUE_MAX_LEN)) { | ||
176 | list_del(&p->list); | ||
177 | kmem_cache_free(rm_cache, p); | ||
178 | --entries; | ||
179 | } else if ((seqnum == p->seqnum) | ||
180 | && (memcmp(sa, p->sa, ETH_ALEN) == 0)) | ||
181 | return -1; | ||
182 | } | ||
183 | |||
184 | p = kmem_cache_alloc(rm_cache, GFP_ATOMIC); | ||
185 | if (!p) { | ||
186 | printk(KERN_DEBUG "o11s: could not allocate RMC entry\n"); | ||
187 | return 0; | ||
188 | } | ||
189 | p->seqnum = seqnum; | ||
190 | p->exp_time = jiffies + RMC_TIMEOUT; | ||
191 | memcpy(p->sa, sa, ETH_ALEN); | ||
192 | list_add(&p->list, &rmc->bucket[idx].list); | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | void mesh_mgmt_ies_add(struct sk_buff *skb, struct net_device *dev) | ||
197 | { | ||
198 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
199 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
200 | struct ieee80211_supported_band *sband; | ||
201 | u8 *pos; | ||
202 | int len, i, rate; | ||
203 | |||
204 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
205 | len = sband->n_bitrates; | ||
206 | if (len > 8) | ||
207 | len = 8; | ||
208 | pos = skb_put(skb, len + 2); | ||
209 | *pos++ = WLAN_EID_SUPP_RATES; | ||
210 | *pos++ = len; | ||
211 | for (i = 0; i < len; i++) { | ||
212 | rate = sband->bitrates[i].bitrate; | ||
213 | *pos++ = (u8) (rate / 5); | ||
214 | } | ||
215 | |||
216 | if (sband->n_bitrates > len) { | ||
217 | pos = skb_put(skb, sband->n_bitrates - len + 2); | ||
218 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
219 | *pos++ = sband->n_bitrates - len; | ||
220 | for (i = len; i < sband->n_bitrates; i++) { | ||
221 | rate = sband->bitrates[i].bitrate; | ||
222 | *pos++ = (u8) (rate / 5); | ||
223 | } | ||
224 | } | ||
225 | |||
226 | pos = skb_put(skb, 2 + sdata->u.sta.mesh_id_len); | ||
227 | *pos++ = WLAN_EID_MESH_ID; | ||
228 | *pos++ = sdata->u.sta.mesh_id_len; | ||
229 | if (sdata->u.sta.mesh_id_len) | ||
230 | memcpy(pos, sdata->u.sta.mesh_id, sdata->u.sta.mesh_id_len); | ||
231 | |||
232 | pos = skb_put(skb, 21); | ||
233 | *pos++ = WLAN_EID_MESH_CONFIG; | ||
234 | *pos++ = MESH_CFG_LEN; | ||
235 | /* Version */ | ||
236 | *pos++ = 1; | ||
237 | |||
238 | /* Active path selection protocol ID */ | ||
239 | memcpy(pos, sdata->u.sta.mesh_pp_id, 4); | ||
240 | pos += 4; | ||
241 | |||
242 | /* Active path selection metric ID */ | ||
243 | memcpy(pos, sdata->u.sta.mesh_pm_id, 4); | ||
244 | pos += 4; | ||
245 | |||
246 | /* Congestion control mode identifier */ | ||
247 | memcpy(pos, sdata->u.sta.mesh_cc_id, 4); | ||
248 | pos += 4; | ||
249 | |||
250 | /* Channel precedence: | ||
251 | * Not running simple channel unification protocol | ||
252 | */ | ||
253 | memset(pos, 0x00, 4); | ||
254 | pos += 4; | ||
255 | |||
256 | /* Mesh capability */ | ||
257 | sdata->u.sta.accepting_plinks = mesh_plink_availables(sdata); | ||
258 | *pos++ = sdata->u.sta.accepting_plinks ? ACCEPT_PLINKS : 0x00; | ||
259 | *pos++ = 0x00; | ||
260 | |||
261 | return; | ||
262 | } | ||
263 | |||
264 | u32 mesh_table_hash(u8 *addr, struct net_device *dev, struct mesh_table *tbl) | ||
265 | { | ||
266 | /* Use last four bytes of hw addr and interface index as hash index */ | ||
267 | return jhash_2words(*(u32 *)(addr+2), dev->ifindex, tbl->hash_rnd) | ||
268 | & tbl->hash_mask; | ||
269 | } | ||
270 | |||
271 | u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len) | ||
272 | { | ||
273 | if (!mesh_id_len) | ||
274 | return 1; | ||
275 | else if (mesh_id_len == 1) | ||
276 | return (u8) mesh_id[0]; | ||
277 | else | ||
278 | return (u8) (mesh_id[0] + 2 * mesh_id[1]); | ||
279 | } | ||
280 | |||
281 | struct mesh_table *mesh_table_alloc(int size_order) | ||
282 | { | ||
283 | int i; | ||
284 | struct mesh_table *newtbl; | ||
285 | |||
286 | newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL); | ||
287 | if (!newtbl) | ||
288 | return NULL; | ||
289 | |||
290 | newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) * | ||
291 | (1 << size_order), GFP_KERNEL); | ||
292 | |||
293 | if (!newtbl->hash_buckets) { | ||
294 | kfree(newtbl); | ||
295 | return NULL; | ||
296 | } | ||
297 | |||
298 | newtbl->hashwlock = kmalloc(sizeof(spinlock_t) * | ||
299 | (1 << size_order), GFP_KERNEL); | ||
300 | if (!newtbl->hashwlock) { | ||
301 | kfree(newtbl->hash_buckets); | ||
302 | kfree(newtbl); | ||
303 | return NULL; | ||
304 | } | ||
305 | |||
306 | newtbl->size_order = size_order; | ||
307 | newtbl->hash_mask = (1 << size_order) - 1; | ||
308 | atomic_set(&newtbl->entries, 0); | ||
309 | get_random_bytes(&newtbl->hash_rnd, | ||
310 | sizeof(newtbl->hash_rnd)); | ||
311 | for (i = 0; i <= newtbl->hash_mask; i++) | ||
312 | spin_lock_init(&newtbl->hashwlock[i]); | ||
313 | |||
314 | return newtbl; | ||
315 | } | ||
316 | |||
317 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs) | ||
318 | { | ||
319 | struct hlist_head *mesh_hash; | ||
320 | struct hlist_node *p, *q; | ||
321 | int i; | ||
322 | |||
323 | mesh_hash = tbl->hash_buckets; | ||
324 | for (i = 0; i <= tbl->hash_mask; i++) { | ||
325 | spin_lock(&tbl->hashwlock[i]); | ||
326 | hlist_for_each_safe(p, q, &mesh_hash[i]) { | ||
327 | tbl->free_node(p, free_leafs); | ||
328 | atomic_dec(&tbl->entries); | ||
329 | } | ||
330 | spin_unlock(&tbl->hashwlock[i]); | ||
331 | } | ||
332 | kfree(tbl->hash_buckets); | ||
333 | kfree(tbl->hashwlock); | ||
334 | kfree(tbl); | ||
335 | } | ||
336 | |||
337 | static void ieee80211_mesh_path_timer(unsigned long data) | ||
338 | { | ||
339 | struct ieee80211_sub_if_data *sdata = | ||
340 | (struct ieee80211_sub_if_data *) data; | ||
341 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
342 | struct ieee80211_local *local = wdev_priv(&sdata->wdev); | ||
343 | |||
344 | queue_work(local->hw.workqueue, &ifsta->work); | ||
345 | } | ||
346 | |||
347 | struct mesh_table *mesh_table_grow(struct mesh_table *tbl) | ||
348 | { | ||
349 | struct mesh_table *newtbl; | ||
350 | struct hlist_head *oldhash; | ||
351 | struct hlist_node *p; | ||
352 | int err = 0; | ||
353 | int i; | ||
354 | |||
355 | if (atomic_read(&tbl->entries) | ||
356 | < tbl->mean_chain_len * (tbl->hash_mask + 1)) { | ||
357 | err = -EPERM; | ||
358 | goto endgrow; | ||
359 | } | ||
360 | |||
361 | newtbl = mesh_table_alloc(tbl->size_order + 1); | ||
362 | if (!newtbl) { | ||
363 | err = -ENOMEM; | ||
364 | goto endgrow; | ||
365 | } | ||
366 | |||
367 | newtbl->free_node = tbl->free_node; | ||
368 | newtbl->mean_chain_len = tbl->mean_chain_len; | ||
369 | newtbl->copy_node = tbl->copy_node; | ||
370 | atomic_set(&newtbl->entries, atomic_read(&tbl->entries)); | ||
371 | |||
372 | oldhash = tbl->hash_buckets; | ||
373 | for (i = 0; i <= tbl->hash_mask; i++) | ||
374 | hlist_for_each(p, &oldhash[i]) | ||
375 | tbl->copy_node(p, newtbl); | ||
376 | |||
377 | endgrow: | ||
378 | if (err) | ||
379 | return NULL; | ||
380 | else | ||
381 | return newtbl; | ||
382 | } | ||
383 | |||
384 | /** | ||
385 | * ieee80211_new_mesh_header - create a new mesh header | ||
386 | * @meshhdr: uninitialized mesh header | ||
387 | * @sdata: mesh interface to be used | ||
388 | * | ||
389 | * Return the header length. | ||
390 | */ | ||
391 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, | ||
392 | struct ieee80211_sub_if_data *sdata) | ||
393 | { | ||
394 | meshhdr->flags = 0; | ||
395 | meshhdr->ttl = sdata->u.sta.mshcfg.dot11MeshTTL; | ||
396 | |||
397 | meshhdr->seqnum[0] = sdata->u.sta.mesh_seqnum[0]++; | ||
398 | meshhdr->seqnum[1] = sdata->u.sta.mesh_seqnum[1]; | ||
399 | meshhdr->seqnum[2] = sdata->u.sta.mesh_seqnum[2]; | ||
400 | |||
401 | if (sdata->u.sta.mesh_seqnum[0] == 0) { | ||
402 | sdata->u.sta.mesh_seqnum[1]++; | ||
403 | if (sdata->u.sta.mesh_seqnum[1] == 0) | ||
404 | sdata->u.sta.mesh_seqnum[2]++; | ||
405 | } | ||
406 | |||
407 | return 5; | ||
408 | } | ||
409 | |||
410 | void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | ||
411 | { | ||
412 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
413 | |||
414 | ifsta->mshcfg.dot11MeshRetryTimeout = MESH_RET_T; | ||
415 | ifsta->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T; | ||
416 | ifsta->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T; | ||
417 | ifsta->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR; | ||
418 | ifsta->mshcfg.dot11MeshTTL = MESH_TTL; | ||
419 | ifsta->mshcfg.auto_open_plinks = true; | ||
420 | ifsta->mshcfg.dot11MeshMaxPeerLinks = | ||
421 | MESH_MAX_ESTAB_PLINKS; | ||
422 | ifsta->mshcfg.dot11MeshHWMPactivePathTimeout = | ||
423 | MESH_PATH_TIMEOUT; | ||
424 | ifsta->mshcfg.dot11MeshHWMPpreqMinInterval = | ||
425 | MESH_PREQ_MIN_INT; | ||
426 | ifsta->mshcfg.dot11MeshHWMPnetDiameterTraversalTime = | ||
427 | MESH_DIAM_TRAVERSAL_TIME; | ||
428 | ifsta->mshcfg.dot11MeshHWMPmaxPREQretries = | ||
429 | MESH_MAX_PREQ_RETRIES; | ||
430 | ifsta->mshcfg.path_refresh_time = | ||
431 | MESH_PATH_REFRESH_TIME; | ||
432 | ifsta->mshcfg.min_discovery_timeout = | ||
433 | MESH_MIN_DISCOVERY_TIMEOUT; | ||
434 | ifsta->accepting_plinks = true; | ||
435 | ifsta->preq_id = 0; | ||
436 | ifsta->dsn = 0; | ||
437 | atomic_set(&ifsta->mpaths, 0); | ||
438 | mesh_rmc_init(sdata->dev); | ||
439 | ifsta->last_preq = jiffies; | ||
440 | /* Allocate all mesh structures when creating the first mesh interface. */ | ||
441 | if (!mesh_allocated) | ||
442 | ieee80211s_init(); | ||
443 | mesh_ids_set_default(ifsta); | ||
444 | setup_timer(&ifsta->mesh_path_timer, | ||
445 | ieee80211_mesh_path_timer, | ||
446 | (unsigned long) sdata); | ||
447 | INIT_LIST_HEAD(&ifsta->preq_queue.list); | ||
448 | spin_lock_init(&ifsta->mesh_preq_queue_lock); | ||
449 | } | ||
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h new file mode 100644 index 000000000000..742003d3a841 --- /dev/null +++ b/net/mac80211/mesh.h | |||
@@ -0,0 +1,290 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008 open80211s Ltd. | ||
3 | * Authors: Luis Carlos Cobo <luisca@cozybit.com> | ||
4 | * Javier Cardona <javier@cozybit.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef IEEE80211S_H | ||
12 | #define IEEE80211S_H | ||
13 | |||
14 | #include <linux/types.h> | ||
15 | #include <linux/jhash.h> | ||
16 | #include "ieee80211_i.h" | ||
17 | |||
18 | |||
19 | /* Data structures */ | ||
20 | |||
21 | /** | ||
22 | * enum mesh_path_flags - mac80211 mesh path flags | ||
23 | * | ||
24 | * | ||
25 | * | ||
26 | * @MESH_PATH_ACTIVE: the mesh path is can be used for forwarding | ||
27 | * @MESH_PATH_RESOLVED: the discovery process is running for this mesh path | ||
28 | * @MESH_PATH_DSN_VALID: the mesh path contains a valid destination sequence | ||
29 | * number | ||
30 | * @MESH_PATH_FIXED: the mesh path has been manually set and should not be | ||
31 | * modified | ||
32 | * @MESH_PATH_RESOLVED: the mesh path can has been resolved | ||
33 | * | ||
34 | * MESH_PATH_RESOLVED and MESH_PATH_DELETE are used by the mesh path timer to | ||
35 | * decide when to stop or cancel the mesh path discovery. | ||
36 | */ | ||
37 | enum mesh_path_flags { | ||
38 | MESH_PATH_ACTIVE = BIT(0), | ||
39 | MESH_PATH_RESOLVING = BIT(1), | ||
40 | MESH_PATH_DSN_VALID = BIT(2), | ||
41 | MESH_PATH_FIXED = BIT(3), | ||
42 | MESH_PATH_RESOLVED = BIT(4), | ||
43 | }; | ||
44 | |||
45 | /** | ||
46 | * struct mesh_path - mac80211 mesh path structure | ||
47 | * | ||
48 | * @dst: mesh path destination mac address | ||
49 | * @dev: mesh path device | ||
50 | * @next_hop: mesh neighbor to which frames for this destination will be | ||
51 | * forwarded | ||
52 | * @timer: mesh path discovery timer | ||
53 | * @frame_queue: pending queue for frames sent to this destination while the | ||
54 | * path is unresolved | ||
55 | * @dsn: destination sequence number of the destination | ||
56 | * @metric: current metric to this destination | ||
57 | * @hop_count: hops to destination | ||
58 | * @exp_time: in jiffies, when the path will expire or when it expired | ||
59 | * @discovery_timeout: timeout (lapse in jiffies) used for the last discovery | ||
60 | * retry | ||
61 | * @discovery_retries: number of discovery retries | ||
62 | * @flags: mesh path flags, as specified on &enum mesh_path_flags | ||
63 | * @state_lock: mesh pat state lock | ||
64 | * | ||
65 | * | ||
66 | * The combination of dst and dev is unique in the mesh path table. Since the | ||
67 | * next_hop STA is only protected by RCU as well, deleting the STA must also | ||
68 | * remove/substitute the mesh_path structure and wait until that is no longer | ||
69 | * reachable before destroying the STA completely. | ||
70 | */ | ||
71 | struct mesh_path { | ||
72 | u8 dst[ETH_ALEN]; | ||
73 | struct net_device *dev; | ||
74 | struct sta_info *next_hop; | ||
75 | struct timer_list timer; | ||
76 | struct sk_buff_head frame_queue; | ||
77 | struct rcu_head rcu; | ||
78 | u32 dsn; | ||
79 | u32 metric; | ||
80 | u8 hop_count; | ||
81 | unsigned long exp_time; | ||
82 | u32 discovery_timeout; | ||
83 | u8 discovery_retries; | ||
84 | enum mesh_path_flags flags; | ||
85 | spinlock_t state_lock; | ||
86 | }; | ||
87 | |||
88 | /** | ||
89 | * struct mesh_table | ||
90 | * | ||
91 | * @hash_buckets: array of hash buckets of the table | ||
92 | * @hashwlock: array of locks to protect write operations, one per bucket | ||
93 | * @hash_mask: 2^size_order - 1, used to compute hash idx | ||
94 | * @hash_rnd: random value used for hash computations | ||
95 | * @entries: number of entries in the table | ||
96 | * @free_node: function to free nodes of the table | ||
97 | * @copy_node: fuction to copy nodes of the table | ||
98 | * @size_order: determines size of the table, there will be 2^size_order hash | ||
99 | * buckets | ||
100 | * @mean_chain_len: maximum average length for the hash buckets' list, if it is | ||
101 | * reached, the table will grow | ||
102 | */ | ||
103 | struct mesh_table { | ||
104 | /* Number of buckets will be 2^N */ | ||
105 | struct hlist_head *hash_buckets; | ||
106 | spinlock_t *hashwlock; /* One per bucket, for add/del */ | ||
107 | unsigned int hash_mask; /* (2^size_order) - 1 */ | ||
108 | __u32 hash_rnd; /* Used for hash generation */ | ||
109 | atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */ | ||
110 | void (*free_node) (struct hlist_node *p, bool free_leafs); | ||
111 | void (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl); | ||
112 | int size_order; | ||
113 | int mean_chain_len; | ||
114 | }; | ||
115 | |||
116 | /* Recent multicast cache */ | ||
117 | /* RMC_BUCKETS must be a power of 2, maximum 256 */ | ||
118 | #define RMC_BUCKETS 256 | ||
119 | #define RMC_QUEUE_MAX_LEN 4 | ||
120 | #define RMC_TIMEOUT (3 * HZ) | ||
121 | |||
122 | /** | ||
123 | * struct rmc_entry - entry in the Recent Multicast Cache | ||
124 | * | ||
125 | * @seqnum: mesh sequence number of the frame | ||
126 | * @exp_time: expiration time of the entry, in jiffies | ||
127 | * @sa: source address of the frame | ||
128 | * | ||
129 | * The Recent Multicast Cache keeps track of the latest multicast frames that | ||
130 | * have been received by a mesh interface and discards received multicast frames | ||
131 | * that are found in the cache. | ||
132 | */ | ||
133 | struct rmc_entry { | ||
134 | struct list_head list; | ||
135 | u32 seqnum; | ||
136 | unsigned long exp_time; | ||
137 | u8 sa[ETH_ALEN]; | ||
138 | }; | ||
139 | |||
140 | struct mesh_rmc { | ||
141 | struct rmc_entry bucket[RMC_BUCKETS]; | ||
142 | u8 idx_mask; | ||
143 | }; | ||
144 | |||
145 | |||
146 | /* Mesh IEs constants */ | ||
147 | #define MESH_CFG_LEN 19 | ||
148 | |||
149 | /* | ||
150 | * MESH_CFG_COMP_LEN Includes: | ||
151 | * - Active path selection protocol ID. | ||
152 | * - Active path selection metric ID. | ||
153 | * - Congestion control mode identifier. | ||
154 | * - Channel precedence. | ||
155 | * Does not include mesh capabilities, which may vary across nodes in the same | ||
156 | * mesh | ||
157 | */ | ||
158 | #define MESH_CFG_CMP_LEN 17 | ||
159 | |||
160 | /* Default values, timeouts in ms */ | ||
161 | #define MESH_TTL 5 | ||
162 | #define MESH_MAX_RETR 3 | ||
163 | #define MESH_RET_T 100 | ||
164 | #define MESH_CONF_T 100 | ||
165 | #define MESH_HOLD_T 100 | ||
166 | |||
167 | #define MESH_PATH_TIMEOUT 5000 | ||
168 | /* Minimum interval between two consecutive PREQs originated by the same | ||
169 | * interface | ||
170 | */ | ||
171 | #define MESH_PREQ_MIN_INT 10 | ||
172 | #define MESH_DIAM_TRAVERSAL_TIME 50 | ||
173 | /* Paths will be refreshed if they are closer than PATH_REFRESH_TIME to their | ||
174 | * expiration | ||
175 | */ | ||
176 | #define MESH_PATH_REFRESH_TIME 1000 | ||
177 | #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) | ||
178 | |||
179 | #define MESH_MAX_PREQ_RETRIES 4 | ||
180 | #define MESH_PATH_EXPIRE (600 * HZ) | ||
181 | |||
182 | /* Default maximum number of established plinks per interface */ | ||
183 | #define MESH_MAX_ESTAB_PLINKS 32 | ||
184 | |||
185 | /* Default maximum number of plinks per interface */ | ||
186 | #define MESH_MAX_PLINKS 256 | ||
187 | |||
188 | /* Maximum number of paths per interface */ | ||
189 | #define MESH_MAX_MPATHS 1024 | ||
190 | |||
191 | /* Pending ANA approval */ | ||
192 | #define PLINK_CATEGORY 30 | ||
193 | #define MESH_PATH_SEL_CATEGORY 32 | ||
194 | |||
195 | /* Mesh Header Flags */ | ||
196 | #define IEEE80211S_FLAGS_AE 0x3 | ||
197 | |||
198 | /* Public interfaces */ | ||
199 | /* Various */ | ||
200 | u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len); | ||
201 | int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); | ||
202 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, | ||
203 | struct ieee80211_sub_if_data *sdata); | ||
204 | int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, | ||
205 | struct net_device *dev); | ||
206 | bool mesh_matches_local(struct ieee802_11_elems *ie, struct net_device *dev); | ||
207 | void mesh_ids_set_default(struct ieee80211_if_sta *sta); | ||
208 | void mesh_mgmt_ies_add(struct sk_buff *skb, struct net_device *dev); | ||
209 | void mesh_rmc_free(struct net_device *dev); | ||
210 | int mesh_rmc_init(struct net_device *dev); | ||
211 | void ieee80211s_init(void); | ||
212 | void ieee80211s_stop(void); | ||
213 | void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); | ||
214 | |||
215 | /* Mesh paths */ | ||
216 | int mesh_nexthop_lookup(u8 *next_hop, struct sk_buff *skb, | ||
217 | struct net_device *dev); | ||
218 | void mesh_path_start_discovery(struct net_device *dev); | ||
219 | struct mesh_path *mesh_path_lookup(u8 *dst, struct net_device *dev); | ||
220 | struct mesh_path *mesh_path_lookup_by_idx(int idx, struct net_device *dev); | ||
221 | void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); | ||
222 | void mesh_path_expire(struct net_device *dev); | ||
223 | void mesh_path_flush(struct net_device *dev); | ||
224 | void mesh_rx_path_sel_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | ||
225 | size_t len); | ||
226 | int mesh_path_add(u8 *dst, struct net_device *dev); | ||
227 | /* Mesh plinks */ | ||
228 | void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, | ||
229 | bool add); | ||
230 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie, | ||
231 | struct net_device *dev); | ||
232 | void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); | ||
233 | void mesh_plink_broken(struct sta_info *sta); | ||
234 | void mesh_plink_deactivate(struct sta_info *sta); | ||
235 | int mesh_plink_open(struct sta_info *sta); | ||
236 | int mesh_plink_close(struct sta_info *sta); | ||
237 | void mesh_plink_block(struct sta_info *sta); | ||
238 | void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | ||
239 | size_t len, struct ieee80211_rx_status *rx_status); | ||
240 | |||
241 | /* Private interfaces */ | ||
242 | /* Mesh tables */ | ||
243 | struct mesh_table *mesh_table_alloc(int size_order); | ||
244 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs); | ||
245 | struct mesh_table *mesh_table_grow(struct mesh_table *tbl); | ||
246 | u32 mesh_table_hash(u8 *addr, struct net_device *dev, struct mesh_table *tbl); | ||
247 | /* Mesh paths */ | ||
248 | int mesh_path_error_tx(u8 *dest, __le32 dest_dsn, u8 *ra, | ||
249 | struct net_device *dev); | ||
250 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); | ||
251 | void mesh_path_flush_pending(struct mesh_path *mpath); | ||
252 | void mesh_path_tx_pending(struct mesh_path *mpath); | ||
253 | int mesh_pathtbl_init(void); | ||
254 | void mesh_pathtbl_unregister(void); | ||
255 | int mesh_path_del(u8 *addr, struct net_device *dev); | ||
256 | void mesh_path_timer(unsigned long data); | ||
257 | void mesh_path_flush_by_nexthop(struct sta_info *sta); | ||
258 | void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev); | ||
259 | |||
260 | #ifdef CONFIG_MAC80211_MESH | ||
261 | extern int mesh_allocated; | ||
262 | |||
263 | static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata) | ||
264 | { | ||
265 | return sdata->u.sta.mshcfg.dot11MeshMaxPeerLinks - | ||
266 | atomic_read(&sdata->u.sta.mshstats.estab_plinks); | ||
267 | } | ||
268 | |||
269 | static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata) | ||
270 | { | ||
271 | return (min_t(long, mesh_plink_free_count(sdata), | ||
272 | MESH_MAX_PLINKS - sdata->local->num_sta)) > 0; | ||
273 | } | ||
274 | |||
275 | static inline void mesh_path_activate(struct mesh_path *mpath) | ||
276 | { | ||
277 | mpath->flags |= MESH_PATH_ACTIVE | MESH_PATH_RESOLVED; | ||
278 | } | ||
279 | |||
280 | #define for_each_mesh_entry(x, p, node, i) \ | ||
281 | for (i = 0; i <= x->hash_mask; i++) \ | ||
282 | hlist_for_each_entry_rcu(node, p, &x->hash_buckets[i], list) | ||
283 | |||
284 | #else | ||
285 | #define mesh_allocated 0 | ||
286 | #endif | ||
287 | |||
288 | #define MESH_PREQ(skb) (skb->cb + 30) | ||
289 | |||
290 | #endif /* IEEE80211S_H */ | ||
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c new file mode 100644 index 000000000000..576a6e55323e --- /dev/null +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -0,0 +1,857 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008 open80211s Ltd. | ||
3 | * Author: Luis Carlos Cobo <luisca@cozybit.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <asm/unaligned.h> | ||
11 | #include "mesh.h" | ||
12 | |||
13 | #define IEEE80211_FC(type, stype) cpu_to_le16(type | stype) | ||
14 | |||
15 | #define TEST_FRAME_LEN 8192 | ||
16 | #define MAX_METRIC 0xffffffff | ||
17 | #define ARITH_SHIFT 8 | ||
18 | |||
19 | /* Number of frames buffered per destination for unresolved destinations */ | ||
20 | #define MESH_FRAME_QUEUE_LEN 10 | ||
21 | #define MAX_PREQ_QUEUE_LEN 64 | ||
22 | |||
23 | /* Destination only */ | ||
24 | #define MP_F_DO 0x1 | ||
25 | /* Reply and forward */ | ||
26 | #define MP_F_RF 0x2 | ||
27 | |||
28 | static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) | ||
29 | { | ||
30 | if (ae) | ||
31 | offset += 6; | ||
32 | return le32_to_cpu(get_unaligned((__le32 *) (preq_elem + offset))); | ||
33 | } | ||
34 | |||
35 | /* HWMP IE processing macros */ | ||
36 | #define AE_F (1<<6) | ||
37 | #define AE_F_SET(x) (*x & AE_F) | ||
38 | #define PREQ_IE_FLAGS(x) (*(x)) | ||
39 | #define PREQ_IE_HOPCOUNT(x) (*(x + 1)) | ||
40 | #define PREQ_IE_TTL(x) (*(x + 2)) | ||
41 | #define PREQ_IE_PREQ_ID(x) u32_field_get(x, 3, 0) | ||
42 | #define PREQ_IE_ORIG_ADDR(x) (x + 7) | ||
43 | #define PREQ_IE_ORIG_DSN(x) u32_field_get(x, 13, 0); | ||
44 | #define PREQ_IE_LIFETIME(x) u32_field_get(x, 17, AE_F_SET(x)); | ||
45 | #define PREQ_IE_METRIC(x) u32_field_get(x, 21, AE_F_SET(x)); | ||
46 | #define PREQ_IE_DST_F(x) (*(AE_F_SET(x) ? x + 32 : x + 26)) | ||
47 | #define PREQ_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 33 : x + 27) | ||
48 | #define PREQ_IE_DST_DSN(x) u32_field_get(x, 33, AE_F_SET(x)); | ||
49 | |||
50 | |||
51 | #define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x) | ||
52 | #define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x) | ||
53 | #define PREP_IE_TTL(x) PREQ_IE_TTL(x) | ||
54 | #define PREP_IE_ORIG_ADDR(x) (x + 3) | ||
55 | #define PREP_IE_ORIG_DSN(x) u32_field_get(x, 9, 0); | ||
56 | #define PREP_IE_LIFETIME(x) u32_field_get(x, 13, AE_F_SET(x)); | ||
57 | #define PREP_IE_METRIC(x) u32_field_get(x, 17, AE_F_SET(x)); | ||
58 | #define PREP_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21) | ||
59 | #define PREP_IE_DST_DSN(x) u32_field_get(x, 27, AE_F_SET(x)); | ||
60 | |||
61 | #define PERR_IE_DST_ADDR(x) (x + 2) | ||
62 | #define PERR_IE_DST_DSN(x) u32_field_get(x, 8, 0); | ||
63 | |||
64 | #define TU_TO_EXP_TIME(x) (jiffies + msecs_to_jiffies(x * 1024 / 1000)) | ||
65 | #define MSEC_TO_TU(x) (x*1000/1024) | ||
66 | #define DSN_GT(x, y) ((long) (y) - (long) (x) < 0) | ||
67 | #define DSN_LT(x, y) ((long) (x) - (long) (y) < 0) | ||
68 | |||
69 | #define net_traversal_jiffies(s) \ | ||
70 | msecs_to_jiffies(s->u.sta.mshcfg.dot11MeshHWMPnetDiameterTraversalTime) | ||
71 | #define default_lifetime(s) \ | ||
72 | MSEC_TO_TU(s->u.sta.mshcfg.dot11MeshHWMPactivePathTimeout) | ||
73 | #define min_preq_int_jiff(s) \ | ||
74 | (msecs_to_jiffies(s->u.sta.mshcfg.dot11MeshHWMPpreqMinInterval)) | ||
75 | #define max_preq_retries(s) (s->u.sta.mshcfg.dot11MeshHWMPmaxPREQretries) | ||
76 | #define disc_timeout_jiff(s) \ | ||
77 | msecs_to_jiffies(sdata->u.sta.mshcfg.min_discovery_timeout) | ||
78 | |||
79 | enum mpath_frame_type { | ||
80 | MPATH_PREQ = 0, | ||
81 | MPATH_PREP, | ||
82 | MPATH_PERR | ||
83 | }; | ||
84 | |||
85 | static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | ||
86 | u8 *orig_addr, __le32 orig_dsn, u8 dst_flags, u8 *dst, | ||
87 | __le32 dst_dsn, u8 *da, u8 hop_count, u8 ttl, __le32 lifetime, | ||
88 | __le32 metric, __le32 preq_id, struct net_device *dev) | ||
89 | { | ||
90 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
91 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | ||
92 | struct ieee80211_mgmt *mgmt; | ||
93 | u8 *pos; | ||
94 | int ie_len; | ||
95 | |||
96 | if (!skb) | ||
97 | return -1; | ||
98 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
99 | /* 25 is the size of the common mgmt part (24) plus the size of the | ||
100 | * common action part (1) | ||
101 | */ | ||
102 | mgmt = (struct ieee80211_mgmt *) | ||
103 | skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action)); | ||
104 | memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action)); | ||
105 | mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, | ||
106 | IEEE80211_STYPE_ACTION); | ||
107 | |||
108 | memcpy(mgmt->da, da, ETH_ALEN); | ||
109 | memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); | ||
110 | /* BSSID is left zeroed, wildcard value */ | ||
111 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; | ||
112 | mgmt->u.action.u.mesh_action.action_code = action; | ||
113 | |||
114 | switch (action) { | ||
115 | case MPATH_PREQ: | ||
116 | ie_len = 37; | ||
117 | pos = skb_put(skb, 2 + ie_len); | ||
118 | *pos++ = WLAN_EID_PREQ; | ||
119 | break; | ||
120 | case MPATH_PREP: | ||
121 | ie_len = 31; | ||
122 | pos = skb_put(skb, 2 + ie_len); | ||
123 | *pos++ = WLAN_EID_PREP; | ||
124 | break; | ||
125 | default: | ||
126 | kfree(skb); | ||
127 | return -ENOTSUPP; | ||
128 | break; | ||
129 | } | ||
130 | *pos++ = ie_len; | ||
131 | *pos++ = flags; | ||
132 | *pos++ = hop_count; | ||
133 | *pos++ = ttl; | ||
134 | if (action == MPATH_PREQ) { | ||
135 | memcpy(pos, &preq_id, 4); | ||
136 | pos += 4; | ||
137 | } | ||
138 | memcpy(pos, orig_addr, ETH_ALEN); | ||
139 | pos += ETH_ALEN; | ||
140 | memcpy(pos, &orig_dsn, 4); | ||
141 | pos += 4; | ||
142 | memcpy(pos, &lifetime, 4); | ||
143 | pos += 4; | ||
144 | memcpy(pos, &metric, 4); | ||
145 | pos += 4; | ||
146 | if (action == MPATH_PREQ) { | ||
147 | /* destination count */ | ||
148 | *pos++ = 1; | ||
149 | *pos++ = dst_flags; | ||
150 | } | ||
151 | memcpy(pos, dst, ETH_ALEN); | ||
152 | pos += ETH_ALEN; | ||
153 | memcpy(pos, &dst_dsn, 4); | ||
154 | |||
155 | ieee80211_sta_tx(dev, skb, 0); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | /** | ||
160 | * mesh_send_path error - Sends a PERR mesh management frame | ||
161 | * | ||
162 | * @dst: broken destination | ||
163 | * @dst_dsn: dsn of the broken destination | ||
164 | * @ra: node this frame is addressed to | ||
165 | */ | ||
166 | int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, | ||
167 | struct net_device *dev) | ||
168 | { | ||
169 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
170 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | ||
171 | struct ieee80211_mgmt *mgmt; | ||
172 | u8 *pos; | ||
173 | int ie_len; | ||
174 | |||
175 | if (!skb) | ||
176 | return -1; | ||
177 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
178 | /* 25 is the size of the common mgmt part (24) plus the size of the | ||
179 | * common action part (1) | ||
180 | */ | ||
181 | mgmt = (struct ieee80211_mgmt *) | ||
182 | skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action)); | ||
183 | memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action)); | ||
184 | mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, | ||
185 | IEEE80211_STYPE_ACTION); | ||
186 | |||
187 | memcpy(mgmt->da, ra, ETH_ALEN); | ||
188 | memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); | ||
189 | /* BSSID is left zeroed, wildcard value */ | ||
190 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; | ||
191 | mgmt->u.action.u.mesh_action.action_code = MPATH_PERR; | ||
192 | ie_len = 12; | ||
193 | pos = skb_put(skb, 2 + ie_len); | ||
194 | *pos++ = WLAN_EID_PERR; | ||
195 | *pos++ = ie_len; | ||
196 | /* mode flags, reserved */ | ||
197 | *pos++ = 0; | ||
198 | /* number of destinations */ | ||
199 | *pos++ = 1; | ||
200 | memcpy(pos, dst, ETH_ALEN); | ||
201 | pos += ETH_ALEN; | ||
202 | memcpy(pos, &dst_dsn, 4); | ||
203 | |||
204 | ieee80211_sta_tx(dev, skb, 0); | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static u32 airtime_link_metric_get(struct ieee80211_local *local, | ||
209 | struct sta_info *sta) | ||
210 | { | ||
211 | struct ieee80211_supported_band *sband; | ||
212 | /* This should be adjusted for each device */ | ||
213 | int device_constant = 1 << ARITH_SHIFT; | ||
214 | int test_frame_len = TEST_FRAME_LEN << ARITH_SHIFT; | ||
215 | int s_unit = 1 << ARITH_SHIFT; | ||
216 | int rate, err; | ||
217 | u32 tx_time, estimated_retx; | ||
218 | u64 result; | ||
219 | |||
220 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
221 | |||
222 | if (sta->fail_avg >= 100) | ||
223 | return MAX_METRIC; | ||
224 | err = (sta->fail_avg << ARITH_SHIFT) / 100; | ||
225 | |||
226 | /* bitrate is in units of 100 Kbps, while we need rate in units of | ||
227 | * 1Mbps. This will be corrected on tx_time computation. | ||
228 | */ | ||
229 | rate = sband->bitrates[sta->txrate_idx].bitrate; | ||
230 | tx_time = (device_constant + 10 * test_frame_len / rate); | ||
231 | estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err)); | ||
232 | result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ; | ||
233 | return (u32)result; | ||
234 | } | ||
235 | |||
236 | /** | ||
237 | * hwmp_route_info_get - Update routing info to originator and transmitter | ||
238 | * | ||
239 | * @dev: local mesh interface | ||
240 | * @mgmt: mesh management frame | ||
241 | * @hwmp_ie: hwmp information element (PREP or PREQ) | ||
242 | * | ||
243 | * This function updates the path routing information to the originator and the | ||
244 | * transmitter of a HWMP PREQ or PREP fram. | ||
245 | * | ||
246 | * Returns: metric to frame originator or 0 if the frame should not be further | ||
247 | * processed | ||
248 | * | ||
249 | * Notes: this function is the only place (besides user-provided info) where | ||
250 | * path routing information is updated. | ||
251 | */ | ||
252 | static u32 hwmp_route_info_get(struct net_device *dev, | ||
253 | struct ieee80211_mgmt *mgmt, | ||
254 | u8 *hwmp_ie) | ||
255 | { | ||
256 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
257 | struct mesh_path *mpath; | ||
258 | struct sta_info *sta; | ||
259 | bool fresh_info; | ||
260 | u8 *orig_addr, *ta; | ||
261 | u32 orig_dsn, orig_metric; | ||
262 | unsigned long orig_lifetime, exp_time; | ||
263 | u32 last_hop_metric, new_metric; | ||
264 | bool process = true; | ||
265 | u8 action = mgmt->u.action.u.mesh_action.action_code; | ||
266 | |||
267 | rcu_read_lock(); | ||
268 | sta = sta_info_get(local, mgmt->sa); | ||
269 | if (!sta) { | ||
270 | rcu_read_unlock(); | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | last_hop_metric = airtime_link_metric_get(local, sta); | ||
275 | /* Update and check originator routing info */ | ||
276 | fresh_info = true; | ||
277 | |||
278 | switch (action) { | ||
279 | case MPATH_PREQ: | ||
280 | orig_addr = PREQ_IE_ORIG_ADDR(hwmp_ie); | ||
281 | orig_dsn = PREQ_IE_ORIG_DSN(hwmp_ie); | ||
282 | orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie); | ||
283 | orig_metric = PREQ_IE_METRIC(hwmp_ie); | ||
284 | break; | ||
285 | case MPATH_PREP: | ||
286 | /* Originator here refers to the MP that was the destination in | ||
287 | * the Path Request. The draft refers to that MP as the | ||
288 | * destination address, even though usually it is the origin of | ||
289 | * the PREP frame. We divert from the nomenclature in the draft | ||
290 | * so that we can easily use a single function to gather path | ||
291 | * information from both PREQ and PREP frames. | ||
292 | */ | ||
293 | orig_addr = PREP_IE_ORIG_ADDR(hwmp_ie); | ||
294 | orig_dsn = PREP_IE_ORIG_DSN(hwmp_ie); | ||
295 | orig_lifetime = PREP_IE_LIFETIME(hwmp_ie); | ||
296 | orig_metric = PREP_IE_METRIC(hwmp_ie); | ||
297 | break; | ||
298 | default: | ||
299 | rcu_read_unlock(); | ||
300 | return 0; | ||
301 | } | ||
302 | new_metric = orig_metric + last_hop_metric; | ||
303 | if (new_metric < orig_metric) | ||
304 | new_metric = MAX_METRIC; | ||
305 | exp_time = TU_TO_EXP_TIME(orig_lifetime); | ||
306 | |||
307 | if (memcmp(orig_addr, dev->dev_addr, ETH_ALEN) == 0) { | ||
308 | /* This MP is the originator, we are not interested in this | ||
309 | * frame, except for updating transmitter's path info. | ||
310 | */ | ||
311 | process = false; | ||
312 | fresh_info = false; | ||
313 | } else { | ||
314 | mpath = mesh_path_lookup(orig_addr, dev); | ||
315 | if (mpath) { | ||
316 | spin_lock_bh(&mpath->state_lock); | ||
317 | if (mpath->flags & MESH_PATH_FIXED) | ||
318 | fresh_info = false; | ||
319 | else if ((mpath->flags & MESH_PATH_ACTIVE) && | ||
320 | (mpath->flags & MESH_PATH_DSN_VALID)) { | ||
321 | if (DSN_GT(mpath->dsn, orig_dsn) || | ||
322 | (mpath->dsn == orig_dsn && | ||
323 | action == MPATH_PREQ && | ||
324 | new_metric > mpath->metric)) { | ||
325 | process = false; | ||
326 | fresh_info = false; | ||
327 | } | ||
328 | } | ||
329 | } else { | ||
330 | mesh_path_add(orig_addr, dev); | ||
331 | mpath = mesh_path_lookup(orig_addr, dev); | ||
332 | if (!mpath) { | ||
333 | rcu_read_unlock(); | ||
334 | return 0; | ||
335 | } | ||
336 | spin_lock_bh(&mpath->state_lock); | ||
337 | } | ||
338 | |||
339 | if (fresh_info) { | ||
340 | mesh_path_assign_nexthop(mpath, sta); | ||
341 | mpath->flags |= MESH_PATH_DSN_VALID; | ||
342 | mpath->metric = new_metric; | ||
343 | mpath->dsn = orig_dsn; | ||
344 | mpath->exp_time = time_after(mpath->exp_time, exp_time) | ||
345 | ? mpath->exp_time : exp_time; | ||
346 | mesh_path_activate(mpath); | ||
347 | spin_unlock_bh(&mpath->state_lock); | ||
348 | mesh_path_tx_pending(mpath); | ||
349 | /* draft says preq_id should be saved to, but there does | ||
350 | * not seem to be any use for it, skipping by now | ||
351 | */ | ||
352 | } else | ||
353 | spin_unlock_bh(&mpath->state_lock); | ||
354 | } | ||
355 | |||
356 | /* Update and check transmitter routing info */ | ||
357 | ta = mgmt->sa; | ||
358 | if (memcmp(orig_addr, ta, ETH_ALEN) == 0) | ||
359 | fresh_info = false; | ||
360 | else { | ||
361 | fresh_info = true; | ||
362 | |||
363 | mpath = mesh_path_lookup(ta, dev); | ||
364 | if (mpath) { | ||
365 | spin_lock_bh(&mpath->state_lock); | ||
366 | if ((mpath->flags & MESH_PATH_FIXED) || | ||
367 | ((mpath->flags & MESH_PATH_ACTIVE) && | ||
368 | (last_hop_metric > mpath->metric))) | ||
369 | fresh_info = false; | ||
370 | } else { | ||
371 | mesh_path_add(ta, dev); | ||
372 | mpath = mesh_path_lookup(ta, dev); | ||
373 | if (!mpath) { | ||
374 | rcu_read_unlock(); | ||
375 | return 0; | ||
376 | } | ||
377 | spin_lock_bh(&mpath->state_lock); | ||
378 | } | ||
379 | |||
380 | if (fresh_info) { | ||
381 | mesh_path_assign_nexthop(mpath, sta); | ||
382 | mpath->flags &= ~MESH_PATH_DSN_VALID; | ||
383 | mpath->metric = last_hop_metric; | ||
384 | mpath->exp_time = time_after(mpath->exp_time, exp_time) | ||
385 | ? mpath->exp_time : exp_time; | ||
386 | mesh_path_activate(mpath); | ||
387 | spin_unlock_bh(&mpath->state_lock); | ||
388 | mesh_path_tx_pending(mpath); | ||
389 | } else | ||
390 | spin_unlock_bh(&mpath->state_lock); | ||
391 | } | ||
392 | |||
393 | rcu_read_unlock(); | ||
394 | |||
395 | return process ? new_metric : 0; | ||
396 | } | ||
397 | |||
398 | static void hwmp_preq_frame_process(struct net_device *dev, | ||
399 | struct ieee80211_mgmt *mgmt, | ||
400 | u8 *preq_elem, u32 metric) { | ||
401 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
402 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
403 | struct mesh_path *mpath; | ||
404 | u8 *dst_addr, *orig_addr; | ||
405 | u8 dst_flags, ttl; | ||
406 | u32 orig_dsn, dst_dsn, lifetime; | ||
407 | bool reply = false; | ||
408 | bool forward = true; | ||
409 | |||
410 | /* Update destination DSN, if present */ | ||
411 | dst_addr = PREQ_IE_DST_ADDR(preq_elem); | ||
412 | orig_addr = PREQ_IE_ORIG_ADDR(preq_elem); | ||
413 | dst_dsn = PREQ_IE_DST_DSN(preq_elem); | ||
414 | orig_dsn = PREQ_IE_ORIG_DSN(preq_elem); | ||
415 | dst_flags = PREQ_IE_DST_F(preq_elem); | ||
416 | |||
417 | if (memcmp(dst_addr, dev->dev_addr, ETH_ALEN) == 0) { | ||
418 | forward = false; | ||
419 | reply = true; | ||
420 | metric = 0; | ||
421 | if (time_after(jiffies, ifsta->last_dsn_update + | ||
422 | net_traversal_jiffies(sdata)) || | ||
423 | time_before(jiffies, ifsta->last_dsn_update)) { | ||
424 | dst_dsn = ++ifsta->dsn; | ||
425 | ifsta->last_dsn_update = jiffies; | ||
426 | } | ||
427 | } else { | ||
428 | rcu_read_lock(); | ||
429 | mpath = mesh_path_lookup(dst_addr, dev); | ||
430 | if (mpath) { | ||
431 | if ((!(mpath->flags & MESH_PATH_DSN_VALID)) || | ||
432 | DSN_LT(mpath->dsn, dst_dsn)) { | ||
433 | mpath->dsn = dst_dsn; | ||
434 | mpath->flags &= MESH_PATH_DSN_VALID; | ||
435 | } else if ((!(dst_flags & MP_F_DO)) && | ||
436 | (mpath->flags & MESH_PATH_ACTIVE)) { | ||
437 | reply = true; | ||
438 | metric = mpath->metric; | ||
439 | dst_dsn = mpath->dsn; | ||
440 | if (dst_flags & MP_F_RF) | ||
441 | dst_flags |= MP_F_DO; | ||
442 | else | ||
443 | forward = false; | ||
444 | } | ||
445 | } | ||
446 | rcu_read_unlock(); | ||
447 | } | ||
448 | |||
449 | if (reply) { | ||
450 | lifetime = PREQ_IE_LIFETIME(preq_elem); | ||
451 | ttl = ifsta->mshcfg.dot11MeshTTL; | ||
452 | if (ttl != 0) | ||
453 | mesh_path_sel_frame_tx(MPATH_PREP, 0, dst_addr, | ||
454 | cpu_to_le32(dst_dsn), 0, orig_addr, | ||
455 | cpu_to_le32(orig_dsn), mgmt->sa, 0, ttl, | ||
456 | cpu_to_le32(lifetime), cpu_to_le32(metric), | ||
457 | 0, dev); | ||
458 | else | ||
459 | ifsta->mshstats.dropped_frames_ttl++; | ||
460 | } | ||
461 | |||
462 | if (forward) { | ||
463 | u32 preq_id; | ||
464 | u8 hopcount, flags; | ||
465 | |||
466 | ttl = PREQ_IE_TTL(preq_elem); | ||
467 | lifetime = PREQ_IE_LIFETIME(preq_elem); | ||
468 | if (ttl <= 1) { | ||
469 | ifsta->mshstats.dropped_frames_ttl++; | ||
470 | return; | ||
471 | } | ||
472 | --ttl; | ||
473 | flags = PREQ_IE_FLAGS(preq_elem); | ||
474 | preq_id = PREQ_IE_PREQ_ID(preq_elem); | ||
475 | hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1; | ||
476 | mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, | ||
477 | cpu_to_le32(orig_dsn), dst_flags, dst_addr, | ||
478 | cpu_to_le32(dst_dsn), dev->broadcast, | ||
479 | hopcount, ttl, cpu_to_le32(lifetime), | ||
480 | cpu_to_le32(metric), cpu_to_le32(preq_id), | ||
481 | dev); | ||
482 | ifsta->mshstats.fwded_frames++; | ||
483 | } | ||
484 | } | ||
485 | |||
486 | |||
487 | static void hwmp_prep_frame_process(struct net_device *dev, | ||
488 | struct ieee80211_mgmt *mgmt, | ||
489 | u8 *prep_elem, u32 metric) | ||
490 | { | ||
491 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
492 | struct mesh_path *mpath; | ||
493 | u8 *dst_addr, *orig_addr; | ||
494 | u8 ttl, hopcount, flags; | ||
495 | u8 next_hop[ETH_ALEN]; | ||
496 | u32 dst_dsn, orig_dsn, lifetime; | ||
497 | |||
498 | /* Note that we divert from the draft nomenclature and denominate | ||
499 | * destination to what the draft refers to as origininator. So in this | ||
500 | * function destnation refers to the final destination of the PREP, | ||
501 | * which corresponds with the originator of the PREQ which this PREP | ||
502 | * replies | ||
503 | */ | ||
504 | dst_addr = PREP_IE_DST_ADDR(prep_elem); | ||
505 | if (memcmp(dst_addr, dev->dev_addr, ETH_ALEN) == 0) | ||
506 | /* destination, no forwarding required */ | ||
507 | return; | ||
508 | |||
509 | ttl = PREP_IE_TTL(prep_elem); | ||
510 | if (ttl <= 1) { | ||
511 | sdata->u.sta.mshstats.dropped_frames_ttl++; | ||
512 | return; | ||
513 | } | ||
514 | |||
515 | rcu_read_lock(); | ||
516 | mpath = mesh_path_lookup(dst_addr, dev); | ||
517 | if (mpath) | ||
518 | spin_lock_bh(&mpath->state_lock); | ||
519 | else | ||
520 | goto fail; | ||
521 | if (!(mpath->flags & MESH_PATH_ACTIVE)) { | ||
522 | spin_unlock_bh(&mpath->state_lock); | ||
523 | goto fail; | ||
524 | } | ||
525 | memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN); | ||
526 | spin_unlock_bh(&mpath->state_lock); | ||
527 | --ttl; | ||
528 | flags = PREP_IE_FLAGS(prep_elem); | ||
529 | lifetime = PREP_IE_LIFETIME(prep_elem); | ||
530 | hopcount = PREP_IE_HOPCOUNT(prep_elem) + 1; | ||
531 | orig_addr = PREP_IE_ORIG_ADDR(prep_elem); | ||
532 | dst_dsn = PREP_IE_DST_DSN(prep_elem); | ||
533 | orig_dsn = PREP_IE_ORIG_DSN(prep_elem); | ||
534 | |||
535 | mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, | ||
536 | cpu_to_le32(orig_dsn), 0, dst_addr, | ||
537 | cpu_to_le32(dst_dsn), mpath->next_hop->addr, hopcount, ttl, | ||
538 | cpu_to_le32(lifetime), cpu_to_le32(metric), | ||
539 | 0, dev); | ||
540 | rcu_read_unlock(); | ||
541 | sdata->u.sta.mshstats.fwded_frames++; | ||
542 | return; | ||
543 | |||
544 | fail: | ||
545 | rcu_read_unlock(); | ||
546 | sdata->u.sta.mshstats.dropped_frames_no_route++; | ||
547 | return; | ||
548 | } | ||
549 | |||
550 | static void hwmp_perr_frame_process(struct net_device *dev, | ||
551 | struct ieee80211_mgmt *mgmt, u8 *perr_elem) | ||
552 | { | ||
553 | struct mesh_path *mpath; | ||
554 | u8 *ta, *dst_addr; | ||
555 | u32 dst_dsn; | ||
556 | |||
557 | ta = mgmt->sa; | ||
558 | dst_addr = PERR_IE_DST_ADDR(perr_elem); | ||
559 | dst_dsn = PERR_IE_DST_DSN(perr_elem); | ||
560 | rcu_read_lock(); | ||
561 | mpath = mesh_path_lookup(dst_addr, dev); | ||
562 | if (mpath) { | ||
563 | spin_lock_bh(&mpath->state_lock); | ||
564 | if (mpath->flags & MESH_PATH_ACTIVE && | ||
565 | memcmp(ta, mpath->next_hop->addr, ETH_ALEN) == 0 && | ||
566 | (!(mpath->flags & MESH_PATH_DSN_VALID) || | ||
567 | DSN_GT(dst_dsn, mpath->dsn))) { | ||
568 | mpath->flags &= ~MESH_PATH_ACTIVE; | ||
569 | mpath->dsn = dst_dsn; | ||
570 | spin_unlock_bh(&mpath->state_lock); | ||
571 | mesh_path_error_tx(dst_addr, cpu_to_le32(dst_dsn), | ||
572 | dev->broadcast, dev); | ||
573 | } else | ||
574 | spin_unlock_bh(&mpath->state_lock); | ||
575 | } | ||
576 | rcu_read_unlock(); | ||
577 | } | ||
578 | |||
579 | |||
580 | |||
581 | void mesh_rx_path_sel_frame(struct net_device *dev, | ||
582 | struct ieee80211_mgmt *mgmt, | ||
583 | size_t len) | ||
584 | { | ||
585 | struct ieee802_11_elems elems; | ||
586 | size_t baselen; | ||
587 | u32 last_hop_metric; | ||
588 | |||
589 | baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; | ||
590 | ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, | ||
591 | len - baselen, &elems); | ||
592 | |||
593 | switch (mgmt->u.action.u.mesh_action.action_code) { | ||
594 | case MPATH_PREQ: | ||
595 | if (!elems.preq || elems.preq_len != 37) | ||
596 | /* Right now we support just 1 destination and no AE */ | ||
597 | return; | ||
598 | last_hop_metric = hwmp_route_info_get(dev, mgmt, elems.preq); | ||
599 | if (!last_hop_metric) | ||
600 | return; | ||
601 | hwmp_preq_frame_process(dev, mgmt, elems.preq, last_hop_metric); | ||
602 | break; | ||
603 | case MPATH_PREP: | ||
604 | if (!elems.prep || elems.prep_len != 31) | ||
605 | /* Right now we support no AE */ | ||
606 | return; | ||
607 | last_hop_metric = hwmp_route_info_get(dev, mgmt, elems.prep); | ||
608 | if (!last_hop_metric) | ||
609 | return; | ||
610 | hwmp_prep_frame_process(dev, mgmt, elems.prep, last_hop_metric); | ||
611 | break; | ||
612 | case MPATH_PERR: | ||
613 | if (!elems.perr || elems.perr_len != 12) | ||
614 | /* Right now we support only one destination per PERR */ | ||
615 | return; | ||
616 | hwmp_perr_frame_process(dev, mgmt, elems.perr); | ||
617 | default: | ||
618 | return; | ||
619 | } | ||
620 | |||
621 | } | ||
622 | |||
623 | /** | ||
624 | * mesh_queue_preq - queue a PREQ to a given destination | ||
625 | * | ||
626 | * @mpath: mesh path to discover | ||
627 | * @flags: special attributes of the PREQ to be sent | ||
628 | * | ||
629 | * Locking: the function must be called from within a rcu read lock block. | ||
630 | * | ||
631 | */ | ||
632 | static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) | ||
633 | { | ||
634 | struct ieee80211_sub_if_data *sdata = | ||
635 | IEEE80211_DEV_TO_SUB_IF(mpath->dev); | ||
636 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
637 | struct mesh_preq_queue *preq_node; | ||
638 | |||
639 | preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_KERNEL); | ||
640 | if (!preq_node) { | ||
641 | printk(KERN_DEBUG "Mesh HWMP: could not allocate PREQ node\n"); | ||
642 | return; | ||
643 | } | ||
644 | |||
645 | spin_lock(&ifsta->mesh_preq_queue_lock); | ||
646 | if (ifsta->preq_queue_len == MAX_PREQ_QUEUE_LEN) { | ||
647 | spin_unlock(&ifsta->mesh_preq_queue_lock); | ||
648 | kfree(preq_node); | ||
649 | if (printk_ratelimit()) | ||
650 | printk(KERN_DEBUG "Mesh HWMP: PREQ node queue full\n"); | ||
651 | return; | ||
652 | } | ||
653 | |||
654 | memcpy(preq_node->dst, mpath->dst, ETH_ALEN); | ||
655 | preq_node->flags = flags; | ||
656 | |||
657 | list_add_tail(&preq_node->list, &ifsta->preq_queue.list); | ||
658 | ++ifsta->preq_queue_len; | ||
659 | spin_unlock(&ifsta->mesh_preq_queue_lock); | ||
660 | |||
661 | if (time_after(jiffies, ifsta->last_preq + min_preq_int_jiff(sdata))) | ||
662 | queue_work(sdata->local->hw.workqueue, &ifsta->work); | ||
663 | |||
664 | else if (time_before(jiffies, ifsta->last_preq)) { | ||
665 | /* avoid long wait if did not send preqs for a long time | ||
666 | * and jiffies wrapped around | ||
667 | */ | ||
668 | ifsta->last_preq = jiffies - min_preq_int_jiff(sdata) - 1; | ||
669 | queue_work(sdata->local->hw.workqueue, &ifsta->work); | ||
670 | } else | ||
671 | mod_timer(&ifsta->mesh_path_timer, ifsta->last_preq + | ||
672 | min_preq_int_jiff(sdata)); | ||
673 | } | ||
674 | |||
675 | /** | ||
676 | * mesh_path_start_discovery - launch a path discovery from the PREQ queue | ||
677 | * | ||
678 | * @dev: local mesh interface | ||
679 | */ | ||
680 | void mesh_path_start_discovery(struct net_device *dev) | ||
681 | { | ||
682 | struct ieee80211_sub_if_data *sdata = | ||
683 | IEEE80211_DEV_TO_SUB_IF(dev); | ||
684 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
685 | struct mesh_preq_queue *preq_node; | ||
686 | struct mesh_path *mpath; | ||
687 | u8 ttl, dst_flags; | ||
688 | u32 lifetime; | ||
689 | |||
690 | spin_lock(&ifsta->mesh_preq_queue_lock); | ||
691 | if (!ifsta->preq_queue_len || | ||
692 | time_before(jiffies, ifsta->last_preq + | ||
693 | min_preq_int_jiff(sdata))) { | ||
694 | spin_unlock(&ifsta->mesh_preq_queue_lock); | ||
695 | return; | ||
696 | } | ||
697 | |||
698 | preq_node = list_first_entry(&ifsta->preq_queue.list, | ||
699 | struct mesh_preq_queue, list); | ||
700 | list_del(&preq_node->list); | ||
701 | --ifsta->preq_queue_len; | ||
702 | spin_unlock(&ifsta->mesh_preq_queue_lock); | ||
703 | |||
704 | rcu_read_lock(); | ||
705 | mpath = mesh_path_lookup(preq_node->dst, dev); | ||
706 | if (!mpath) | ||
707 | goto enddiscovery; | ||
708 | |||
709 | spin_lock_bh(&mpath->state_lock); | ||
710 | if (preq_node->flags & PREQ_Q_F_START) { | ||
711 | if (mpath->flags & MESH_PATH_RESOLVING) { | ||
712 | spin_unlock_bh(&mpath->state_lock); | ||
713 | goto enddiscovery; | ||
714 | } else { | ||
715 | mpath->flags &= ~MESH_PATH_RESOLVED; | ||
716 | mpath->flags |= MESH_PATH_RESOLVING; | ||
717 | mpath->discovery_retries = 0; | ||
718 | mpath->discovery_timeout = disc_timeout_jiff(sdata); | ||
719 | } | ||
720 | } else if (!(mpath->flags & MESH_PATH_RESOLVING) || | ||
721 | mpath->flags & MESH_PATH_RESOLVED) { | ||
722 | mpath->flags &= ~MESH_PATH_RESOLVING; | ||
723 | spin_unlock_bh(&mpath->state_lock); | ||
724 | goto enddiscovery; | ||
725 | } | ||
726 | |||
727 | ifsta->last_preq = jiffies; | ||
728 | |||
729 | if (time_after(jiffies, ifsta->last_dsn_update + | ||
730 | net_traversal_jiffies(sdata)) || | ||
731 | time_before(jiffies, ifsta->last_dsn_update)) { | ||
732 | ++ifsta->dsn; | ||
733 | sdata->u.sta.last_dsn_update = jiffies; | ||
734 | } | ||
735 | lifetime = default_lifetime(sdata); | ||
736 | ttl = sdata->u.sta.mshcfg.dot11MeshTTL; | ||
737 | if (ttl == 0) { | ||
738 | sdata->u.sta.mshstats.dropped_frames_ttl++; | ||
739 | spin_unlock_bh(&mpath->state_lock); | ||
740 | goto enddiscovery; | ||
741 | } | ||
742 | |||
743 | if (preq_node->flags & PREQ_Q_F_REFRESH) | ||
744 | dst_flags = MP_F_DO; | ||
745 | else | ||
746 | dst_flags = MP_F_RF; | ||
747 | |||
748 | spin_unlock_bh(&mpath->state_lock); | ||
749 | mesh_path_sel_frame_tx(MPATH_PREQ, 0, dev->dev_addr, | ||
750 | cpu_to_le32(ifsta->dsn), dst_flags, mpath->dst, | ||
751 | cpu_to_le32(mpath->dsn), dev->broadcast, 0, | ||
752 | ttl, cpu_to_le32(lifetime), 0, | ||
753 | cpu_to_le32(ifsta->preq_id++), dev); | ||
754 | mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); | ||
755 | |||
756 | enddiscovery: | ||
757 | rcu_read_unlock(); | ||
758 | kfree(preq_node); | ||
759 | } | ||
760 | |||
761 | /** | ||
762 | * ieee80211s_lookup_nexthop - put the appropriate next hop on a mesh frame | ||
763 | * | ||
764 | * @next_hop: output argument for next hop address | ||
765 | * @skb: frame to be sent | ||
766 | * @dev: network device the frame will be sent through | ||
767 | * | ||
768 | * Returns: 0 if the next hop was found. Nonzero otherwise. If no next hop is | ||
769 | * found, the function will start a path discovery and queue the frame so it is | ||
770 | * sent when the path is resolved. This means the caller must not free the skb | ||
771 | * in this case. | ||
772 | */ | ||
773 | int mesh_nexthop_lookup(u8 *next_hop, struct sk_buff *skb, | ||
774 | struct net_device *dev) | ||
775 | { | ||
776 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
777 | struct sk_buff *skb_to_free = NULL; | ||
778 | struct mesh_path *mpath; | ||
779 | int err = 0; | ||
780 | |||
781 | rcu_read_lock(); | ||
782 | mpath = mesh_path_lookup(skb->data, dev); | ||
783 | |||
784 | if (!mpath) { | ||
785 | mesh_path_add(skb->data, dev); | ||
786 | mpath = mesh_path_lookup(skb->data, dev); | ||
787 | if (!mpath) { | ||
788 | dev_kfree_skb(skb); | ||
789 | sdata->u.sta.mshstats.dropped_frames_no_route++; | ||
790 | err = -ENOSPC; | ||
791 | goto endlookup; | ||
792 | } | ||
793 | } | ||
794 | |||
795 | if (mpath->flags & MESH_PATH_ACTIVE) { | ||
796 | if (time_after(jiffies, mpath->exp_time - | ||
797 | msecs_to_jiffies(sdata->u.sta.mshcfg.path_refresh_time)) | ||
798 | && skb->pkt_type != PACKET_OTHERHOST | ||
799 | && !(mpath->flags & MESH_PATH_RESOLVING) | ||
800 | && !(mpath->flags & MESH_PATH_FIXED)) { | ||
801 | mesh_queue_preq(mpath, | ||
802 | PREQ_Q_F_START | PREQ_Q_F_REFRESH); | ||
803 | } | ||
804 | memcpy(next_hop, mpath->next_hop->addr, | ||
805 | ETH_ALEN); | ||
806 | } else { | ||
807 | if (!(mpath->flags & MESH_PATH_RESOLVING)) { | ||
808 | /* Start discovery only if it is not running yet */ | ||
809 | mesh_queue_preq(mpath, PREQ_Q_F_START); | ||
810 | } | ||
811 | |||
812 | if (skb_queue_len(&mpath->frame_queue) >= | ||
813 | MESH_FRAME_QUEUE_LEN) { | ||
814 | skb_to_free = mpath->frame_queue.next; | ||
815 | skb_unlink(skb_to_free, &mpath->frame_queue); | ||
816 | } | ||
817 | |||
818 | skb_queue_tail(&mpath->frame_queue, skb); | ||
819 | if (skb_to_free) | ||
820 | mesh_path_discard_frame(skb_to_free, dev); | ||
821 | err = -ENOENT; | ||
822 | } | ||
823 | |||
824 | endlookup: | ||
825 | rcu_read_unlock(); | ||
826 | return err; | ||
827 | } | ||
828 | |||
829 | void mesh_path_timer(unsigned long data) | ||
830 | { | ||
831 | struct ieee80211_sub_if_data *sdata; | ||
832 | struct mesh_path *mpath; | ||
833 | |||
834 | rcu_read_lock(); | ||
835 | mpath = (struct mesh_path *) data; | ||
836 | mpath = rcu_dereference(mpath); | ||
837 | if (!mpath) | ||
838 | goto endmpathtimer; | ||
839 | spin_lock_bh(&mpath->state_lock); | ||
840 | sdata = IEEE80211_DEV_TO_SUB_IF(mpath->dev); | ||
841 | if (mpath->flags & MESH_PATH_RESOLVED || | ||
842 | (!(mpath->flags & MESH_PATH_RESOLVING))) | ||
843 | mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED); | ||
844 | else if (mpath->discovery_retries < max_preq_retries(sdata)) { | ||
845 | ++mpath->discovery_retries; | ||
846 | mpath->discovery_timeout *= 2; | ||
847 | mesh_queue_preq(mpath, 0); | ||
848 | } else { | ||
849 | mpath->flags = 0; | ||
850 | mpath->exp_time = jiffies; | ||
851 | mesh_path_flush_pending(mpath); | ||
852 | } | ||
853 | |||
854 | spin_unlock_bh(&mpath->state_lock); | ||
855 | endmpathtimer: | ||
856 | rcu_read_unlock(); | ||
857 | } | ||
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c new file mode 100644 index 000000000000..5845dc21ce85 --- /dev/null +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -0,0 +1,516 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008 open80211s Ltd. | ||
3 | * Author: Luis Carlos Cobo <luisca@cozybit.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/etherdevice.h> | ||
11 | #include <linux/list.h> | ||
12 | #include <linux/netdevice.h> | ||
13 | #include <linux/random.h> | ||
14 | #include <linux/spinlock.h> | ||
15 | #include <linux/string.h> | ||
16 | #include <net/mac80211.h> | ||
17 | #include "ieee80211_i.h" | ||
18 | #include "mesh.h" | ||
19 | |||
20 | /* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */ | ||
21 | #define INIT_PATHS_SIZE_ORDER 2 | ||
22 | |||
23 | /* Keep the mean chain length below this constant */ | ||
24 | #define MEAN_CHAIN_LEN 2 | ||
25 | |||
26 | #define MPATH_EXPIRED(mpath) ((mpath->flags & MESH_PATH_ACTIVE) && \ | ||
27 | time_after(jiffies, mpath->exp_time) && \ | ||
28 | !(mpath->flags & MESH_PATH_FIXED)) | ||
29 | |||
30 | struct mpath_node { | ||
31 | struct hlist_node list; | ||
32 | struct rcu_head rcu; | ||
33 | /* This indirection allows two different tables to point to the same | ||
34 | * mesh_path structure, useful when resizing | ||
35 | */ | ||
36 | struct mesh_path *mpath; | ||
37 | }; | ||
38 | |||
39 | static struct mesh_table *mesh_paths; | ||
40 | |||
41 | /* This lock will have the grow table function as writer and add / delete nodes | ||
42 | * as readers. When reading the table (i.e. doing lookups) we are well protected | ||
43 | * by RCU | ||
44 | */ | ||
45 | static DEFINE_RWLOCK(pathtbl_resize_lock); | ||
46 | |||
47 | /** | ||
48 | * | ||
49 | * mesh_path_assign_nexthop - update mesh path next hop | ||
50 | * | ||
51 | * @mpath: mesh path to update | ||
52 | * @sta: next hop to assign | ||
53 | * | ||
54 | * Locking: mpath->state_lock must be held when calling this function | ||
55 | */ | ||
56 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta) | ||
57 | { | ||
58 | rcu_assign_pointer(mpath->next_hop, sta); | ||
59 | } | ||
60 | |||
61 | |||
62 | /** | ||
63 | * mesh_path_lookup - look up a path in the mesh path table | ||
64 | * @dst: hardware address (ETH_ALEN length) of destination | ||
65 | * @dev: local interface | ||
66 | * | ||
67 | * Returns: pointer to the mesh path structure, or NULL if not found | ||
68 | * | ||
69 | * Locking: must be called within a read rcu section. | ||
70 | */ | ||
71 | struct mesh_path *mesh_path_lookup(u8 *dst, struct net_device *dev) | ||
72 | { | ||
73 | struct mesh_path *mpath; | ||
74 | struct hlist_node *n; | ||
75 | struct hlist_head *bucket; | ||
76 | struct mesh_table *tbl; | ||
77 | struct mpath_node *node; | ||
78 | |||
79 | tbl = rcu_dereference(mesh_paths); | ||
80 | |||
81 | bucket = &tbl->hash_buckets[mesh_table_hash(dst, dev, tbl)]; | ||
82 | hlist_for_each_entry_rcu(node, n, bucket, list) { | ||
83 | mpath = node->mpath; | ||
84 | if (mpath->dev == dev && | ||
85 | memcmp(dst, mpath->dst, ETH_ALEN) == 0) { | ||
86 | if (MPATH_EXPIRED(mpath)) { | ||
87 | spin_lock_bh(&mpath->state_lock); | ||
88 | if (MPATH_EXPIRED(mpath)) | ||
89 | mpath->flags &= ~MESH_PATH_ACTIVE; | ||
90 | spin_unlock_bh(&mpath->state_lock); | ||
91 | } | ||
92 | return mpath; | ||
93 | } | ||
94 | } | ||
95 | return NULL; | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * mesh_path_lookup_by_idx - look up a path in the mesh path table by its index | ||
100 | * @idx: index | ||
101 | * @dev: local interface, or NULL for all entries | ||
102 | * | ||
103 | * Returns: pointer to the mesh path structure, or NULL if not found. | ||
104 | * | ||
105 | * Locking: must be called within a read rcu section. | ||
106 | */ | ||
107 | struct mesh_path *mesh_path_lookup_by_idx(int idx, struct net_device *dev) | ||
108 | { | ||
109 | struct mpath_node *node; | ||
110 | struct hlist_node *p; | ||
111 | int i; | ||
112 | int j = 0; | ||
113 | |||
114 | for_each_mesh_entry(mesh_paths, p, node, i) { | ||
115 | if (dev && node->mpath->dev != dev) | ||
116 | continue; | ||
117 | if (j++ == idx) { | ||
118 | if (MPATH_EXPIRED(node->mpath)) { | ||
119 | spin_lock_bh(&node->mpath->state_lock); | ||
120 | if (MPATH_EXPIRED(node->mpath)) | ||
121 | node->mpath->flags &= ~MESH_PATH_ACTIVE; | ||
122 | spin_unlock_bh(&node->mpath->state_lock); | ||
123 | } | ||
124 | return node->mpath; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | return NULL; | ||
129 | } | ||
130 | |||
131 | /** | ||
132 | * mesh_path_add - allocate and add a new path to the mesh path table | ||
133 | * @addr: destination address of the path (ETH_ALEN length) | ||
134 | * @dev: local interface | ||
135 | * | ||
136 | * Returns: 0 on sucess | ||
137 | * | ||
138 | * State: the initial state of the new path is set to 0 | ||
139 | */ | ||
140 | int mesh_path_add(u8 *dst, struct net_device *dev) | ||
141 | { | ||
142 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
143 | struct mesh_path *mpath, *new_mpath; | ||
144 | struct mpath_node *node, *new_node; | ||
145 | struct hlist_head *bucket; | ||
146 | struct hlist_node *n; | ||
147 | int grow = 0; | ||
148 | int err = 0; | ||
149 | u32 hash_idx; | ||
150 | |||
151 | if (memcmp(dst, dev->dev_addr, ETH_ALEN) == 0) | ||
152 | /* never add ourselves as neighbours */ | ||
153 | return -ENOTSUPP; | ||
154 | |||
155 | if (is_multicast_ether_addr(dst)) | ||
156 | return -ENOTSUPP; | ||
157 | |||
158 | if (atomic_add_unless(&sdata->u.sta.mpaths, 1, MESH_MAX_MPATHS) == 0) | ||
159 | return -ENOSPC; | ||
160 | |||
161 | read_lock(&pathtbl_resize_lock); | ||
162 | |||
163 | new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL); | ||
164 | if (!new_mpath) { | ||
165 | atomic_dec(&sdata->u.sta.mpaths); | ||
166 | err = -ENOMEM; | ||
167 | goto endadd2; | ||
168 | } | ||
169 | memcpy(new_mpath->dst, dst, ETH_ALEN); | ||
170 | new_mpath->dev = dev; | ||
171 | new_mpath->flags = 0; | ||
172 | skb_queue_head_init(&new_mpath->frame_queue); | ||
173 | new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); | ||
174 | new_node->mpath = new_mpath; | ||
175 | new_mpath->timer.data = (unsigned long) new_mpath; | ||
176 | new_mpath->timer.function = mesh_path_timer; | ||
177 | new_mpath->exp_time = jiffies; | ||
178 | spin_lock_init(&new_mpath->state_lock); | ||
179 | init_timer(&new_mpath->timer); | ||
180 | |||
181 | hash_idx = mesh_table_hash(dst, dev, mesh_paths); | ||
182 | bucket = &mesh_paths->hash_buckets[hash_idx]; | ||
183 | |||
184 | spin_lock(&mesh_paths->hashwlock[hash_idx]); | ||
185 | |||
186 | hlist_for_each_entry(node, n, bucket, list) { | ||
187 | mpath = node->mpath; | ||
188 | if (mpath->dev == dev && memcmp(dst, mpath->dst, ETH_ALEN) | ||
189 | == 0) { | ||
190 | err = -EEXIST; | ||
191 | atomic_dec(&sdata->u.sta.mpaths); | ||
192 | kfree(new_node); | ||
193 | kfree(new_mpath); | ||
194 | goto endadd; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | hlist_add_head_rcu(&new_node->list, bucket); | ||
199 | if (atomic_inc_return(&mesh_paths->entries) >= | ||
200 | mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1)) | ||
201 | grow = 1; | ||
202 | |||
203 | endadd: | ||
204 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); | ||
205 | endadd2: | ||
206 | read_unlock(&pathtbl_resize_lock); | ||
207 | if (!err && grow) { | ||
208 | struct mesh_table *oldtbl, *newtbl; | ||
209 | |||
210 | write_lock(&pathtbl_resize_lock); | ||
211 | oldtbl = mesh_paths; | ||
212 | newtbl = mesh_table_grow(mesh_paths); | ||
213 | if (!newtbl) { | ||
214 | write_unlock(&pathtbl_resize_lock); | ||
215 | return -ENOMEM; | ||
216 | } | ||
217 | rcu_assign_pointer(mesh_paths, newtbl); | ||
218 | synchronize_rcu(); | ||
219 | mesh_table_free(oldtbl, false); | ||
220 | write_unlock(&pathtbl_resize_lock); | ||
221 | } | ||
222 | return err; | ||
223 | } | ||
224 | |||
225 | |||
226 | /** | ||
227 | * mesh_plink_broken - deactivates paths and sends perr when a link breaks | ||
228 | * | ||
229 | * @sta: broken peer link | ||
230 | * | ||
231 | * This function must be called from the rate control algorithm if enough | ||
232 | * delivery errors suggest that a peer link is no longer usable. | ||
233 | */ | ||
234 | void mesh_plink_broken(struct sta_info *sta) | ||
235 | { | ||
236 | struct mesh_path *mpath; | ||
237 | struct mpath_node *node; | ||
238 | struct hlist_node *p; | ||
239 | struct net_device *dev = sta->sdata->dev; | ||
240 | int i; | ||
241 | |||
242 | rcu_read_lock(); | ||
243 | for_each_mesh_entry(mesh_paths, p, node, i) { | ||
244 | mpath = node->mpath; | ||
245 | spin_lock_bh(&mpath->state_lock); | ||
246 | if (mpath->next_hop == sta && | ||
247 | mpath->flags & MESH_PATH_ACTIVE && | ||
248 | !(mpath->flags & MESH_PATH_FIXED)) { | ||
249 | mpath->flags &= ~MESH_PATH_ACTIVE; | ||
250 | ++mpath->dsn; | ||
251 | spin_unlock_bh(&mpath->state_lock); | ||
252 | mesh_path_error_tx(mpath->dst, | ||
253 | cpu_to_le32(mpath->dsn), | ||
254 | dev->broadcast, dev); | ||
255 | } else | ||
256 | spin_unlock_bh(&mpath->state_lock); | ||
257 | } | ||
258 | rcu_read_unlock(); | ||
259 | } | ||
260 | EXPORT_SYMBOL(mesh_plink_broken); | ||
261 | |||
262 | /** | ||
263 | * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches | ||
264 | * | ||
265 | * @sta - mesh peer to match | ||
266 | * | ||
267 | * RCU notes: this function is called when a mesh plink transitions from | ||
268 | * PLINK_ESTAB to any other state, since PLINK_ESTAB state is the only one that | ||
269 | * allows path creation. This will happen before the sta can be freed (because | ||
270 | * sta_info_destroy() calls this) so any reader in a rcu read block will be | ||
271 | * protected against the plink disappearing. | ||
272 | */ | ||
273 | void mesh_path_flush_by_nexthop(struct sta_info *sta) | ||
274 | { | ||
275 | struct mesh_path *mpath; | ||
276 | struct mpath_node *node; | ||
277 | struct hlist_node *p; | ||
278 | int i; | ||
279 | |||
280 | for_each_mesh_entry(mesh_paths, p, node, i) { | ||
281 | mpath = node->mpath; | ||
282 | if (mpath->next_hop == sta) | ||
283 | mesh_path_del(mpath->dst, mpath->dev); | ||
284 | } | ||
285 | } | ||
286 | |||
287 | void mesh_path_flush(struct net_device *dev) | ||
288 | { | ||
289 | struct mesh_path *mpath; | ||
290 | struct mpath_node *node; | ||
291 | struct hlist_node *p; | ||
292 | int i; | ||
293 | |||
294 | for_each_mesh_entry(mesh_paths, p, node, i) { | ||
295 | mpath = node->mpath; | ||
296 | if (mpath->dev == dev) | ||
297 | mesh_path_del(mpath->dst, mpath->dev); | ||
298 | } | ||
299 | } | ||
300 | |||
301 | static void mesh_path_node_reclaim(struct rcu_head *rp) | ||
302 | { | ||
303 | struct mpath_node *node = container_of(rp, struct mpath_node, rcu); | ||
304 | struct ieee80211_sub_if_data *sdata = | ||
305 | IEEE80211_DEV_TO_SUB_IF(node->mpath->dev); | ||
306 | |||
307 | del_timer_sync(&node->mpath->timer); | ||
308 | atomic_dec(&sdata->u.sta.mpaths); | ||
309 | kfree(node->mpath); | ||
310 | kfree(node); | ||
311 | } | ||
312 | |||
313 | /** | ||
314 | * mesh_path_del - delete a mesh path from the table | ||
315 | * | ||
316 | * @addr: dst address (ETH_ALEN length) | ||
317 | * @dev: local interface | ||
318 | * | ||
319 | * Returns: 0 if succesful | ||
320 | */ | ||
321 | int mesh_path_del(u8 *addr, struct net_device *dev) | ||
322 | { | ||
323 | struct mesh_path *mpath; | ||
324 | struct mpath_node *node; | ||
325 | struct hlist_head *bucket; | ||
326 | struct hlist_node *n; | ||
327 | int hash_idx; | ||
328 | int err = 0; | ||
329 | |||
330 | read_lock(&pathtbl_resize_lock); | ||
331 | hash_idx = mesh_table_hash(addr, dev, mesh_paths); | ||
332 | bucket = &mesh_paths->hash_buckets[hash_idx]; | ||
333 | |||
334 | spin_lock(&mesh_paths->hashwlock[hash_idx]); | ||
335 | hlist_for_each_entry(node, n, bucket, list) { | ||
336 | mpath = node->mpath; | ||
337 | if (mpath->dev == dev && | ||
338 | memcmp(addr, mpath->dst, ETH_ALEN) == 0) { | ||
339 | spin_lock_bh(&mpath->state_lock); | ||
340 | mpath->flags |= MESH_PATH_RESOLVING; | ||
341 | hlist_del_rcu(&node->list); | ||
342 | call_rcu(&node->rcu, mesh_path_node_reclaim); | ||
343 | atomic_dec(&mesh_paths->entries); | ||
344 | spin_unlock_bh(&mpath->state_lock); | ||
345 | goto enddel; | ||
346 | } | ||
347 | } | ||
348 | |||
349 | err = -ENXIO; | ||
350 | enddel: | ||
351 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); | ||
352 | read_unlock(&pathtbl_resize_lock); | ||
353 | return err; | ||
354 | } | ||
355 | |||
356 | /** | ||
357 | * mesh_path_tx_pending - sends pending frames in a mesh path queue | ||
358 | * | ||
359 | * @mpath: mesh path to activate | ||
360 | * | ||
361 | * Locking: the state_lock of the mpath structure must NOT be held when calling | ||
362 | * this function. | ||
363 | */ | ||
364 | void mesh_path_tx_pending(struct mesh_path *mpath) | ||
365 | { | ||
366 | struct sk_buff *skb; | ||
367 | |||
368 | while ((skb = skb_dequeue(&mpath->frame_queue)) && | ||
369 | (mpath->flags & MESH_PATH_ACTIVE)) | ||
370 | dev_queue_xmit(skb); | ||
371 | } | ||
372 | |||
373 | /** | ||
374 | * mesh_path_discard_frame - discard a frame whose path could not be resolved | ||
375 | * | ||
376 | * @skb: frame to discard | ||
377 | * @dev: network device the frame was to be sent through | ||
378 | * | ||
379 | * If the frame was beign forwarded from another MP, a PERR frame will be sent | ||
380 | * to the precursor. | ||
381 | * | ||
382 | * Locking: the function must me called within a rcu_read_lock region | ||
383 | */ | ||
384 | void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev) | ||
385 | { | ||
386 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
387 | struct mesh_path *mpath; | ||
388 | u32 dsn = 0; | ||
389 | |||
390 | if (skb->pkt_type == PACKET_OTHERHOST) { | ||
391 | struct ieee80211s_hdr *prev_meshhdr; | ||
392 | int mshhdrlen; | ||
393 | u8 *ra, *da; | ||
394 | |||
395 | prev_meshhdr = ((struct ieee80211s_hdr *)skb->cb); | ||
396 | mshhdrlen = ieee80211_get_mesh_hdrlen(prev_meshhdr); | ||
397 | da = skb->data; | ||
398 | ra = MESH_PREQ(skb); | ||
399 | mpath = mesh_path_lookup(da, dev); | ||
400 | if (mpath) | ||
401 | dsn = ++mpath->dsn; | ||
402 | mesh_path_error_tx(skb->data, cpu_to_le32(dsn), ra, dev); | ||
403 | } | ||
404 | |||
405 | kfree_skb(skb); | ||
406 | sdata->u.sta.mshstats.dropped_frames_no_route++; | ||
407 | } | ||
408 | |||
409 | /** | ||
410 | * mesh_path_flush_pending - free the pending queue of a mesh path | ||
411 | * | ||
412 | * @mpath: mesh path whose queue has to be freed | ||
413 | * | ||
414 | * Locking: the function must me called withing a rcu_read_lock region | ||
415 | */ | ||
416 | void mesh_path_flush_pending(struct mesh_path *mpath) | ||
417 | { | ||
418 | struct ieee80211_sub_if_data *sdata; | ||
419 | struct sk_buff *skb; | ||
420 | |||
421 | sdata = IEEE80211_DEV_TO_SUB_IF(mpath->dev); | ||
422 | |||
423 | while ((skb = skb_dequeue(&mpath->frame_queue)) && | ||
424 | (mpath->flags & MESH_PATH_ACTIVE)) | ||
425 | mesh_path_discard_frame(skb, mpath->dev); | ||
426 | } | ||
427 | |||
428 | /** | ||
429 | * mesh_path_fix_nexthop - force a specific next hop for a mesh path | ||
430 | * | ||
431 | * @mpath: the mesh path to modify | ||
432 | * @next_hop: the next hop to force | ||
433 | * | ||
434 | * Locking: this function must be called holding mpath->state_lock | ||
435 | */ | ||
436 | void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop) | ||
437 | { | ||
438 | spin_lock_bh(&mpath->state_lock); | ||
439 | mesh_path_assign_nexthop(mpath, next_hop); | ||
440 | mpath->dsn = 0xffff; | ||
441 | mpath->metric = 0; | ||
442 | mpath->hop_count = 0; | ||
443 | mpath->exp_time = 0; | ||
444 | mpath->flags |= MESH_PATH_FIXED; | ||
445 | mesh_path_activate(mpath); | ||
446 | spin_unlock_bh(&mpath->state_lock); | ||
447 | mesh_path_tx_pending(mpath); | ||
448 | } | ||
449 | |||
450 | static void mesh_path_node_free(struct hlist_node *p, bool free_leafs) | ||
451 | { | ||
452 | struct mesh_path *mpath; | ||
453 | struct mpath_node *node = hlist_entry(p, struct mpath_node, list); | ||
454 | mpath = node->mpath; | ||
455 | hlist_del_rcu(p); | ||
456 | synchronize_rcu(); | ||
457 | if (free_leafs) | ||
458 | kfree(mpath); | ||
459 | kfree(node); | ||
460 | } | ||
461 | |||
462 | static void mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl) | ||
463 | { | ||
464 | struct mesh_path *mpath; | ||
465 | struct mpath_node *node, *new_node; | ||
466 | u32 hash_idx; | ||
467 | |||
468 | node = hlist_entry(p, struct mpath_node, list); | ||
469 | mpath = node->mpath; | ||
470 | new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); | ||
471 | new_node->mpath = mpath; | ||
472 | hash_idx = mesh_table_hash(mpath->dst, mpath->dev, newtbl); | ||
473 | hlist_add_head(&new_node->list, | ||
474 | &newtbl->hash_buckets[hash_idx]); | ||
475 | } | ||
476 | |||
477 | int mesh_pathtbl_init(void) | ||
478 | { | ||
479 | mesh_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER); | ||
480 | mesh_paths->free_node = &mesh_path_node_free; | ||
481 | mesh_paths->copy_node = &mesh_path_node_copy; | ||
482 | mesh_paths->mean_chain_len = MEAN_CHAIN_LEN; | ||
483 | if (!mesh_paths) | ||
484 | return -ENOMEM; | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | void mesh_path_expire(struct net_device *dev) | ||
489 | { | ||
490 | struct mesh_path *mpath; | ||
491 | struct mpath_node *node; | ||
492 | struct hlist_node *p; | ||
493 | int i; | ||
494 | |||
495 | read_lock(&pathtbl_resize_lock); | ||
496 | for_each_mesh_entry(mesh_paths, p, node, i) { | ||
497 | if (node->mpath->dev != dev) | ||
498 | continue; | ||
499 | mpath = node->mpath; | ||
500 | spin_lock_bh(&mpath->state_lock); | ||
501 | if ((!(mpath->flags & MESH_PATH_RESOLVING)) && | ||
502 | (!(mpath->flags & MESH_PATH_FIXED)) && | ||
503 | time_after(jiffies, | ||
504 | mpath->exp_time + MESH_PATH_EXPIRE)) { | ||
505 | spin_unlock_bh(&mpath->state_lock); | ||
506 | mesh_path_del(mpath->dst, mpath->dev); | ||
507 | } else | ||
508 | spin_unlock_bh(&mpath->state_lock); | ||
509 | } | ||
510 | read_unlock(&pathtbl_resize_lock); | ||
511 | } | ||
512 | |||
513 | void mesh_pathtbl_unregister(void) | ||
514 | { | ||
515 | mesh_table_free(mesh_paths, true); | ||
516 | } | ||
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c new file mode 100644 index 000000000000..18fe52436c47 --- /dev/null +++ b/net/mac80211/mesh_plink.c | |||
@@ -0,0 +1,761 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008 open80211s Ltd. | ||
3 | * Author: Luis Carlos Cobo <luisca@cozybit.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/random.h> | ||
11 | #include "ieee80211_i.h" | ||
12 | #include "ieee80211_rate.h" | ||
13 | #include "mesh.h" | ||
14 | |||
15 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | ||
16 | #define mpl_dbg(fmt, args...) printk(KERN_DEBUG fmt, ##args) | ||
17 | #else | ||
18 | #define mpl_dbg(fmt, args...) do { (void)(0); } while (0) | ||
19 | #endif | ||
20 | |||
21 | #define IEEE80211_FC(type, stype) cpu_to_le16(type | stype) | ||
22 | #define PLINK_GET_FRAME_SUBTYPE(p) (p) | ||
23 | #define PLINK_GET_LLID(p) (p + 1) | ||
24 | #define PLINK_GET_PLID(p) (p + 3) | ||
25 | |||
26 | #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ | ||
27 | jiffies + HZ * t / 1000)) | ||
28 | |||
29 | /* Peer link cancel reasons, all subject to ANA approval */ | ||
30 | #define MESH_LINK_CANCELLED 2 | ||
31 | #define MESH_MAX_NEIGHBORS 3 | ||
32 | #define MESH_CAPABILITY_POLICY_VIOLATION 4 | ||
33 | #define MESH_CLOSE_RCVD 5 | ||
34 | #define MESH_MAX_RETRIES 6 | ||
35 | #define MESH_CONFIRM_TIMEOUT 7 | ||
36 | #define MESH_SECURITY_ROLE_NEGOTIATION_DIFFERS 8 | ||
37 | #define MESH_SECURITY_AUTHENTICATION_IMPOSSIBLE 9 | ||
38 | #define MESH_SECURITY_FAILED_VERIFICATION 10 | ||
39 | |||
40 | #define dot11MeshMaxRetries(s) (s->u.sta.mshcfg.dot11MeshMaxRetries) | ||
41 | #define dot11MeshRetryTimeout(s) (s->u.sta.mshcfg.dot11MeshRetryTimeout) | ||
42 | #define dot11MeshConfirmTimeout(s) (s->u.sta.mshcfg.dot11MeshConfirmTimeout) | ||
43 | #define dot11MeshHoldingTimeout(s) (s->u.sta.mshcfg.dot11MeshHoldingTimeout) | ||
44 | #define dot11MeshMaxPeerLinks(s) (s->u.sta.mshcfg.dot11MeshMaxPeerLinks) | ||
45 | |||
46 | enum plink_frame_type { | ||
47 | PLINK_OPEN = 0, | ||
48 | PLINK_CONFIRM, | ||
49 | PLINK_CLOSE | ||
50 | }; | ||
51 | |||
52 | enum plink_event { | ||
53 | PLINK_UNDEFINED, | ||
54 | OPN_ACPT, | ||
55 | OPN_RJCT, | ||
56 | OPN_IGNR, | ||
57 | CNF_ACPT, | ||
58 | CNF_RJCT, | ||
59 | CNF_IGNR, | ||
60 | CLS_ACPT, | ||
61 | CLS_IGNR | ||
62 | }; | ||
63 | |||
64 | static inline | ||
65 | void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) | ||
66 | { | ||
67 | atomic_inc(&sdata->u.sta.mshstats.estab_plinks); | ||
68 | mesh_accept_plinks_update(sdata); | ||
69 | } | ||
70 | |||
71 | static inline | ||
72 | void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) | ||
73 | { | ||
74 | atomic_dec(&sdata->u.sta.mshstats.estab_plinks); | ||
75 | mesh_accept_plinks_update(sdata); | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * mesh_plink_fsm_restart - restart a mesh peer link finite state machine | ||
80 | * | ||
81 | * @sta: mes peer link to restart | ||
82 | * | ||
83 | * Locking: this function must be called holding sta->plink_lock | ||
84 | */ | ||
85 | static inline void mesh_plink_fsm_restart(struct sta_info *sta) | ||
86 | { | ||
87 | sta->plink_state = PLINK_LISTEN; | ||
88 | sta->llid = sta->plid = sta->reason = 0; | ||
89 | sta->plink_retries = 0; | ||
90 | } | ||
91 | |||
92 | static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | ||
93 | u8 *hw_addr, u64 rates) | ||
94 | { | ||
95 | struct ieee80211_local *local = sdata->local; | ||
96 | struct sta_info *sta; | ||
97 | |||
98 | if (local->num_sta >= MESH_MAX_PLINKS) | ||
99 | return NULL; | ||
100 | |||
101 | sta = sta_info_alloc(sdata, hw_addr, GFP_ATOMIC); | ||
102 | if (!sta) | ||
103 | return NULL; | ||
104 | |||
105 | sta->flags |= WLAN_STA_AUTHORIZED; | ||
106 | sta->supp_rates[local->hw.conf.channel->band] = rates; | ||
107 | |||
108 | return sta; | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * mesh_plink_deactivate - deactivate mesh peer link | ||
113 | * | ||
114 | * @sta: mesh peer link to deactivate | ||
115 | * | ||
116 | * All mesh paths with this peer as next hop will be flushed | ||
117 | * | ||
118 | * Locking: the caller must hold sta->plink_lock | ||
119 | */ | ||
120 | static void __mesh_plink_deactivate(struct sta_info *sta) | ||
121 | { | ||
122 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
123 | |||
124 | if (sta->plink_state == PLINK_ESTAB) | ||
125 | mesh_plink_dec_estab_count(sdata); | ||
126 | sta->plink_state = PLINK_BLOCKED; | ||
127 | mesh_path_flush_by_nexthop(sta); | ||
128 | } | ||
129 | |||
130 | /** | ||
131 | * __mesh_plink_deactivate - deactivate mesh peer link | ||
132 | * | ||
133 | * @sta: mesh peer link to deactivate | ||
134 | * | ||
135 | * All mesh paths with this peer as next hop will be flushed | ||
136 | */ | ||
137 | void mesh_plink_deactivate(struct sta_info *sta) | ||
138 | { | ||
139 | spin_lock_bh(&sta->plink_lock); | ||
140 | __mesh_plink_deactivate(sta); | ||
141 | spin_unlock_bh(&sta->plink_lock); | ||
142 | } | ||
143 | |||
144 | static int mesh_plink_frame_tx(struct net_device *dev, | ||
145 | enum plink_frame_type action, u8 *da, __le16 llid, __le16 plid, | ||
146 | __le16 reason) { | ||
147 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
148 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | ||
149 | struct ieee80211_mgmt *mgmt; | ||
150 | bool include_plid = false; | ||
151 | u8 *pos; | ||
152 | int ie_len; | ||
153 | |||
154 | if (!skb) | ||
155 | return -1; | ||
156 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
157 | /* 25 is the size of the common mgmt part (24) plus the size of the | ||
158 | * common action part (1) | ||
159 | */ | ||
160 | mgmt = (struct ieee80211_mgmt *) | ||
161 | skb_put(skb, 25 + sizeof(mgmt->u.action.u.plink_action)); | ||
162 | memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.plink_action)); | ||
163 | mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, | ||
164 | IEEE80211_STYPE_ACTION); | ||
165 | memcpy(mgmt->da, da, ETH_ALEN); | ||
166 | memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); | ||
167 | /* BSSID is left zeroed, wildcard value */ | ||
168 | mgmt->u.action.category = PLINK_CATEGORY; | ||
169 | mgmt->u.action.u.plink_action.action_code = action; | ||
170 | |||
171 | if (action == PLINK_CLOSE) | ||
172 | mgmt->u.action.u.plink_action.aux = reason; | ||
173 | else { | ||
174 | mgmt->u.action.u.plink_action.aux = cpu_to_le16(0x0); | ||
175 | if (action == PLINK_CONFIRM) { | ||
176 | pos = skb_put(skb, 4); | ||
177 | /* two-byte status code followed by two-byte AID */ | ||
178 | memset(pos, 0, 4); | ||
179 | } | ||
180 | mesh_mgmt_ies_add(skb, dev); | ||
181 | } | ||
182 | |||
183 | /* Add Peer Link Management element */ | ||
184 | switch (action) { | ||
185 | case PLINK_OPEN: | ||
186 | ie_len = 3; | ||
187 | break; | ||
188 | case PLINK_CONFIRM: | ||
189 | ie_len = 5; | ||
190 | include_plid = true; | ||
191 | break; | ||
192 | case PLINK_CLOSE: | ||
193 | default: | ||
194 | if (!plid) | ||
195 | ie_len = 5; | ||
196 | else { | ||
197 | ie_len = 7; | ||
198 | include_plid = true; | ||
199 | } | ||
200 | break; | ||
201 | } | ||
202 | |||
203 | pos = skb_put(skb, 2 + ie_len); | ||
204 | *pos++ = WLAN_EID_PEER_LINK; | ||
205 | *pos++ = ie_len; | ||
206 | *pos++ = action; | ||
207 | memcpy(pos, &llid, 2); | ||
208 | if (include_plid) { | ||
209 | pos += 2; | ||
210 | memcpy(pos, &plid, 2); | ||
211 | } | ||
212 | if (action == PLINK_CLOSE) { | ||
213 | pos += 2; | ||
214 | memcpy(pos, &reason, 2); | ||
215 | } | ||
216 | |||
217 | ieee80211_sta_tx(dev, skb, 0); | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, | ||
222 | bool peer_accepting_plinks) | ||
223 | { | ||
224 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
225 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
226 | struct sta_info *sta; | ||
227 | |||
228 | rcu_read_lock(); | ||
229 | |||
230 | sta = sta_info_get(local, hw_addr); | ||
231 | if (!sta) { | ||
232 | sta = mesh_plink_alloc(sdata, hw_addr, rates); | ||
233 | if (!sta) { | ||
234 | rcu_read_unlock(); | ||
235 | return; | ||
236 | } | ||
237 | if (sta_info_insert(sta)) { | ||
238 | sta_info_destroy(sta); | ||
239 | rcu_read_unlock(); | ||
240 | return; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | sta->last_rx = jiffies; | ||
245 | sta->supp_rates[local->hw.conf.channel->band] = rates; | ||
246 | if (peer_accepting_plinks && sta->plink_state == PLINK_LISTEN && | ||
247 | sdata->u.sta.accepting_plinks && | ||
248 | sdata->u.sta.mshcfg.auto_open_plinks) | ||
249 | mesh_plink_open(sta); | ||
250 | |||
251 | rcu_read_unlock(); | ||
252 | } | ||
253 | |||
254 | static void mesh_plink_timer(unsigned long data) | ||
255 | { | ||
256 | struct sta_info *sta; | ||
257 | __le16 llid, plid, reason; | ||
258 | struct net_device *dev = NULL; | ||
259 | struct ieee80211_sub_if_data *sdata; | ||
260 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | ||
261 | DECLARE_MAC_BUF(mac); | ||
262 | #endif | ||
263 | |||
264 | /* | ||
265 | * This STA is valid because sta_info_destroy() will | ||
266 | * del_timer_sync() this timer after having made sure | ||
267 | * it cannot be readded (by deleting the plink.) | ||
268 | */ | ||
269 | sta = (struct sta_info *) data; | ||
270 | |||
271 | spin_lock_bh(&sta->plink_lock); | ||
272 | if (sta->ignore_plink_timer) { | ||
273 | sta->ignore_plink_timer = false; | ||
274 | spin_unlock_bh(&sta->plink_lock); | ||
275 | return; | ||
276 | } | ||
277 | mpl_dbg("Mesh plink timer for %s fired on state %d\n", | ||
278 | print_mac(mac, sta->addr), sta->plink_state); | ||
279 | reason = 0; | ||
280 | llid = sta->llid; | ||
281 | plid = sta->plid; | ||
282 | sdata = sta->sdata; | ||
283 | dev = sdata->dev; | ||
284 | |||
285 | switch (sta->plink_state) { | ||
286 | case PLINK_OPN_RCVD: | ||
287 | case PLINK_OPN_SNT: | ||
288 | /* retry timer */ | ||
289 | if (sta->plink_retries < dot11MeshMaxRetries(sdata)) { | ||
290 | u32 rand; | ||
291 | mpl_dbg("Mesh plink for %s (retry, timeout): %d %d\n", | ||
292 | print_mac(mac, sta->addr), | ||
293 | sta->plink_retries, sta->plink_timeout); | ||
294 | get_random_bytes(&rand, sizeof(u32)); | ||
295 | sta->plink_timeout = sta->plink_timeout + | ||
296 | rand % sta->plink_timeout; | ||
297 | ++sta->plink_retries; | ||
298 | mod_plink_timer(sta, sta->plink_timeout); | ||
299 | spin_unlock_bh(&sta->plink_lock); | ||
300 | mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid, | ||
301 | 0, 0); | ||
302 | break; | ||
303 | } | ||
304 | reason = cpu_to_le16(MESH_MAX_RETRIES); | ||
305 | /* fall through on else */ | ||
306 | case PLINK_CNF_RCVD: | ||
307 | /* confirm timer */ | ||
308 | if (!reason) | ||
309 | reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); | ||
310 | sta->plink_state = PLINK_HOLDING; | ||
311 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | ||
312 | spin_unlock_bh(&sta->plink_lock); | ||
313 | mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, | ||
314 | reason); | ||
315 | break; | ||
316 | case PLINK_HOLDING: | ||
317 | /* holding timer */ | ||
318 | del_timer(&sta->plink_timer); | ||
319 | mesh_plink_fsm_restart(sta); | ||
320 | spin_unlock_bh(&sta->plink_lock); | ||
321 | break; | ||
322 | default: | ||
323 | spin_unlock_bh(&sta->plink_lock); | ||
324 | break; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) | ||
329 | { | ||
330 | sta->plink_timer.expires = jiffies + (HZ * timeout / 1000); | ||
331 | sta->plink_timer.data = (unsigned long) sta; | ||
332 | sta->plink_timer.function = mesh_plink_timer; | ||
333 | sta->plink_timeout = timeout; | ||
334 | add_timer(&sta->plink_timer); | ||
335 | } | ||
336 | |||
337 | int mesh_plink_open(struct sta_info *sta) | ||
338 | { | ||
339 | __le16 llid; | ||
340 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
341 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | ||
342 | DECLARE_MAC_BUF(mac); | ||
343 | #endif | ||
344 | |||
345 | spin_lock_bh(&sta->plink_lock); | ||
346 | get_random_bytes(&llid, 2); | ||
347 | sta->llid = llid; | ||
348 | if (sta->plink_state != PLINK_LISTEN) { | ||
349 | spin_unlock_bh(&sta->plink_lock); | ||
350 | return -EBUSY; | ||
351 | } | ||
352 | sta->plink_state = PLINK_OPN_SNT; | ||
353 | mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); | ||
354 | spin_unlock_bh(&sta->plink_lock); | ||
355 | mpl_dbg("Mesh plink: starting establishment with %s\n", | ||
356 | print_mac(mac, sta->addr)); | ||
357 | |||
358 | return mesh_plink_frame_tx(sdata->dev, PLINK_OPEN, | ||
359 | sta->addr, llid, 0, 0); | ||
360 | } | ||
361 | |||
362 | void mesh_plink_block(struct sta_info *sta) | ||
363 | { | ||
364 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | ||
365 | DECLARE_MAC_BUF(mac); | ||
366 | #endif | ||
367 | |||
368 | spin_lock_bh(&sta->plink_lock); | ||
369 | __mesh_plink_deactivate(sta); | ||
370 | sta->plink_state = PLINK_BLOCKED; | ||
371 | spin_unlock_bh(&sta->plink_lock); | ||
372 | } | ||
373 | |||
374 | int mesh_plink_close(struct sta_info *sta) | ||
375 | { | ||
376 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
377 | __le16 llid, plid, reason; | ||
378 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | ||
379 | DECLARE_MAC_BUF(mac); | ||
380 | #endif | ||
381 | |||
382 | mpl_dbg("Mesh plink: closing link with %s\n", | ||
383 | print_mac(mac, sta->addr)); | ||
384 | spin_lock_bh(&sta->plink_lock); | ||
385 | sta->reason = cpu_to_le16(MESH_LINK_CANCELLED); | ||
386 | reason = sta->reason; | ||
387 | |||
388 | if (sta->plink_state == PLINK_LISTEN || | ||
389 | sta->plink_state == PLINK_BLOCKED) { | ||
390 | mesh_plink_fsm_restart(sta); | ||
391 | spin_unlock_bh(&sta->plink_lock); | ||
392 | return 0; | ||
393 | } else if (sta->plink_state == PLINK_ESTAB) { | ||
394 | __mesh_plink_deactivate(sta); | ||
395 | /* The timer should not be running */ | ||
396 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | ||
397 | } else if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) | ||
398 | sta->ignore_plink_timer = true; | ||
399 | |||
400 | sta->plink_state = PLINK_HOLDING; | ||
401 | llid = sta->llid; | ||
402 | plid = sta->plid; | ||
403 | spin_unlock_bh(&sta->plink_lock); | ||
404 | mesh_plink_frame_tx(sta->sdata->dev, PLINK_CLOSE, sta->addr, llid, | ||
405 | plid, reason); | ||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | ||
410 | size_t len, struct ieee80211_rx_status *rx_status) | ||
411 | { | ||
412 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
413 | struct ieee80211_local *local = sdata->local; | ||
414 | struct ieee802_11_elems elems; | ||
415 | struct sta_info *sta; | ||
416 | enum plink_event event; | ||
417 | enum plink_frame_type ftype; | ||
418 | size_t baselen; | ||
419 | u8 ie_len; | ||
420 | u8 *baseaddr; | ||
421 | __le16 plid, llid, reason; | ||
422 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | ||
423 | DECLARE_MAC_BUF(mac); | ||
424 | #endif | ||
425 | |||
426 | if (is_multicast_ether_addr(mgmt->da)) { | ||
427 | mpl_dbg("Mesh plink: ignore frame from multicast address"); | ||
428 | return; | ||
429 | } | ||
430 | |||
431 | baseaddr = mgmt->u.action.u.plink_action.variable; | ||
432 | baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt; | ||
433 | if (mgmt->u.action.u.plink_action.action_code == PLINK_CONFIRM) { | ||
434 | baseaddr += 4; | ||
435 | baselen -= 4; | ||
436 | } | ||
437 | ieee802_11_parse_elems(baseaddr, len - baselen, &elems); | ||
438 | if (!elems.peer_link) { | ||
439 | mpl_dbg("Mesh plink: missing necessary peer link ie\n"); | ||
440 | return; | ||
441 | } | ||
442 | |||
443 | ftype = *((u8 *)PLINK_GET_FRAME_SUBTYPE(elems.peer_link)); | ||
444 | ie_len = elems.peer_link_len; | ||
445 | if ((ftype == PLINK_OPEN && ie_len != 3) || | ||
446 | (ftype == PLINK_CONFIRM && ie_len != 5) || | ||
447 | (ftype == PLINK_CLOSE && ie_len != 5 && ie_len != 7)) { | ||
448 | mpl_dbg("Mesh plink: incorrect plink ie length\n"); | ||
449 | return; | ||
450 | } | ||
451 | |||
452 | if (ftype != PLINK_CLOSE && (!elems.mesh_id || !elems.mesh_config)) { | ||
453 | mpl_dbg("Mesh plink: missing necessary ie\n"); | ||
454 | return; | ||
455 | } | ||
456 | /* Note the lines below are correct, the llid in the frame is the plid | ||
457 | * from the point of view of this host. | ||
458 | */ | ||
459 | memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2); | ||
460 | if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 7)) | ||
461 | memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); | ||
462 | |||
463 | rcu_read_lock(); | ||
464 | |||
465 | sta = sta_info_get(local, mgmt->sa); | ||
466 | if (!sta && ftype != PLINK_OPEN) { | ||
467 | mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); | ||
468 | rcu_read_unlock(); | ||
469 | return; | ||
470 | } | ||
471 | |||
472 | if (sta && sta->plink_state == PLINK_BLOCKED) { | ||
473 | rcu_read_unlock(); | ||
474 | return; | ||
475 | } | ||
476 | |||
477 | /* Now we will figure out the appropriate event... */ | ||
478 | event = PLINK_UNDEFINED; | ||
479 | if (ftype != PLINK_CLOSE && (!mesh_matches_local(&elems, dev))) { | ||
480 | switch (ftype) { | ||
481 | case PLINK_OPEN: | ||
482 | event = OPN_RJCT; | ||
483 | break; | ||
484 | case PLINK_CONFIRM: | ||
485 | event = CNF_RJCT; | ||
486 | break; | ||
487 | case PLINK_CLOSE: | ||
488 | /* avoid warning */ | ||
489 | break; | ||
490 | } | ||
491 | spin_lock_bh(&sta->plink_lock); | ||
492 | } else if (!sta) { | ||
493 | /* ftype == PLINK_OPEN */ | ||
494 | u64 rates; | ||
495 | if (!mesh_plink_free_count(sdata)) { | ||
496 | mpl_dbg("Mesh plink error: no more free plinks\n"); | ||
497 | rcu_read_unlock(); | ||
498 | return; | ||
499 | } | ||
500 | |||
501 | rates = ieee80211_sta_get_rates(local, &elems, rx_status->band); | ||
502 | sta = mesh_plink_alloc(sdata, mgmt->sa, rates); | ||
503 | if (!sta) { | ||
504 | mpl_dbg("Mesh plink error: plink table full\n"); | ||
505 | rcu_read_unlock(); | ||
506 | return; | ||
507 | } | ||
508 | if (sta_info_insert(sta)) { | ||
509 | sta_info_destroy(sta); | ||
510 | rcu_read_unlock(); | ||
511 | return; | ||
512 | } | ||
513 | event = OPN_ACPT; | ||
514 | spin_lock_bh(&sta->plink_lock); | ||
515 | } else { | ||
516 | spin_lock_bh(&sta->plink_lock); | ||
517 | switch (ftype) { | ||
518 | case PLINK_OPEN: | ||
519 | if (!mesh_plink_free_count(sdata) || | ||
520 | (sta->plid && sta->plid != plid)) | ||
521 | event = OPN_IGNR; | ||
522 | else | ||
523 | event = OPN_ACPT; | ||
524 | break; | ||
525 | case PLINK_CONFIRM: | ||
526 | if (!mesh_plink_free_count(sdata) || | ||
527 | (sta->llid != llid || sta->plid != plid)) | ||
528 | event = CNF_IGNR; | ||
529 | else | ||
530 | event = CNF_ACPT; | ||
531 | break; | ||
532 | case PLINK_CLOSE: | ||
533 | if (sta->plink_state == PLINK_ESTAB) | ||
534 | /* Do not check for llid or plid. This does not | ||
535 | * follow the standard but since multiple plinks | ||
536 | * per sta are not supported, it is necessary in | ||
537 | * order to avoid a livelock when MP A sees an | ||
538 | * establish peer link to MP B but MP B does not | ||
539 | * see it. This can be caused by a timeout in | ||
540 | * B's peer link establishment or B beign | ||
541 | * restarted. | ||
542 | */ | ||
543 | event = CLS_ACPT; | ||
544 | else if (sta->plid != plid) | ||
545 | event = CLS_IGNR; | ||
546 | else if (ie_len == 7 && sta->llid != llid) | ||
547 | event = CLS_IGNR; | ||
548 | else | ||
549 | event = CLS_ACPT; | ||
550 | break; | ||
551 | default: | ||
552 | mpl_dbg("Mesh plink: unknown frame subtype\n"); | ||
553 | spin_unlock_bh(&sta->plink_lock); | ||
554 | rcu_read_unlock(); | ||
555 | return; | ||
556 | } | ||
557 | } | ||
558 | |||
559 | mpl_dbg("Mesh plink (peer, state, llid, plid, event): %s %d %d %d %d\n", | ||
560 | print_mac(mac, mgmt->sa), sta->plink_state, | ||
561 | le16_to_cpu(sta->llid), le16_to_cpu(sta->plid), | ||
562 | event); | ||
563 | reason = 0; | ||
564 | switch (sta->plink_state) { | ||
565 | /* spin_unlock as soon as state is updated at each case */ | ||
566 | case PLINK_LISTEN: | ||
567 | switch (event) { | ||
568 | case CLS_ACPT: | ||
569 | mesh_plink_fsm_restart(sta); | ||
570 | spin_unlock_bh(&sta->plink_lock); | ||
571 | break; | ||
572 | case OPN_ACPT: | ||
573 | sta->plink_state = PLINK_OPN_RCVD; | ||
574 | sta->plid = plid; | ||
575 | get_random_bytes(&llid, 2); | ||
576 | sta->llid = llid; | ||
577 | mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); | ||
578 | spin_unlock_bh(&sta->plink_lock); | ||
579 | mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid, | ||
580 | 0, 0); | ||
581 | mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, | ||
582 | llid, plid, 0); | ||
583 | break; | ||
584 | default: | ||
585 | spin_unlock_bh(&sta->plink_lock); | ||
586 | break; | ||
587 | } | ||
588 | break; | ||
589 | |||
590 | case PLINK_OPN_SNT: | ||
591 | switch (event) { | ||
592 | case OPN_RJCT: | ||
593 | case CNF_RJCT: | ||
594 | reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION); | ||
595 | case CLS_ACPT: | ||
596 | if (!reason) | ||
597 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | ||
598 | sta->reason = reason; | ||
599 | sta->plink_state = PLINK_HOLDING; | ||
600 | if (!mod_plink_timer(sta, | ||
601 | dot11MeshHoldingTimeout(sdata))) | ||
602 | sta->ignore_plink_timer = true; | ||
603 | |||
604 | llid = sta->llid; | ||
605 | spin_unlock_bh(&sta->plink_lock); | ||
606 | mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, | ||
607 | plid, reason); | ||
608 | break; | ||
609 | case OPN_ACPT: | ||
610 | /* retry timer is left untouched */ | ||
611 | sta->plink_state = PLINK_OPN_RCVD; | ||
612 | sta->plid = plid; | ||
613 | llid = sta->llid; | ||
614 | spin_unlock_bh(&sta->plink_lock); | ||
615 | mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, | ||
616 | plid, 0); | ||
617 | break; | ||
618 | case CNF_ACPT: | ||
619 | sta->plink_state = PLINK_CNF_RCVD; | ||
620 | if (!mod_plink_timer(sta, | ||
621 | dot11MeshConfirmTimeout(sdata))) | ||
622 | sta->ignore_plink_timer = true; | ||
623 | |||
624 | spin_unlock_bh(&sta->plink_lock); | ||
625 | break; | ||
626 | default: | ||
627 | spin_unlock_bh(&sta->plink_lock); | ||
628 | break; | ||
629 | } | ||
630 | break; | ||
631 | |||
632 | case PLINK_OPN_RCVD: | ||
633 | switch (event) { | ||
634 | case OPN_RJCT: | ||
635 | case CNF_RJCT: | ||
636 | reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION); | ||
637 | case CLS_ACPT: | ||
638 | if (!reason) | ||
639 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | ||
640 | sta->reason = reason; | ||
641 | sta->plink_state = PLINK_HOLDING; | ||
642 | if (!mod_plink_timer(sta, | ||
643 | dot11MeshHoldingTimeout(sdata))) | ||
644 | sta->ignore_plink_timer = true; | ||
645 | |||
646 | llid = sta->llid; | ||
647 | spin_unlock_bh(&sta->plink_lock); | ||
648 | mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, | ||
649 | plid, reason); | ||
650 | break; | ||
651 | case OPN_ACPT: | ||
652 | llid = sta->llid; | ||
653 | spin_unlock_bh(&sta->plink_lock); | ||
654 | mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, | ||
655 | plid, 0); | ||
656 | break; | ||
657 | case CNF_ACPT: | ||
658 | del_timer(&sta->plink_timer); | ||
659 | sta->plink_state = PLINK_ESTAB; | ||
660 | mesh_plink_inc_estab_count(sdata); | ||
661 | spin_unlock_bh(&sta->plink_lock); | ||
662 | mpl_dbg("Mesh plink with %s ESTABLISHED\n", | ||
663 | print_mac(mac, sta->addr)); | ||
664 | break; | ||
665 | default: | ||
666 | spin_unlock_bh(&sta->plink_lock); | ||
667 | break; | ||
668 | } | ||
669 | break; | ||
670 | |||
671 | case PLINK_CNF_RCVD: | ||
672 | switch (event) { | ||
673 | case OPN_RJCT: | ||
674 | case CNF_RJCT: | ||
675 | reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION); | ||
676 | case CLS_ACPT: | ||
677 | if (!reason) | ||
678 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | ||
679 | sta->reason = reason; | ||
680 | sta->plink_state = PLINK_HOLDING; | ||
681 | if (!mod_plink_timer(sta, | ||
682 | dot11MeshHoldingTimeout(sdata))) | ||
683 | sta->ignore_plink_timer = true; | ||
684 | |||
685 | llid = sta->llid; | ||
686 | spin_unlock_bh(&sta->plink_lock); | ||
687 | mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, | ||
688 | plid, reason); | ||
689 | break; | ||
690 | case OPN_ACPT: | ||
691 | del_timer(&sta->plink_timer); | ||
692 | sta->plink_state = PLINK_ESTAB; | ||
693 | mesh_plink_inc_estab_count(sdata); | ||
694 | spin_unlock_bh(&sta->plink_lock); | ||
695 | mpl_dbg("Mesh plink with %s ESTABLISHED\n", | ||
696 | print_mac(mac, sta->addr)); | ||
697 | mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, | ||
698 | plid, 0); | ||
699 | break; | ||
700 | default: | ||
701 | spin_unlock_bh(&sta->plink_lock); | ||
702 | break; | ||
703 | } | ||
704 | break; | ||
705 | |||
706 | case PLINK_ESTAB: | ||
707 | switch (event) { | ||
708 | case CLS_ACPT: | ||
709 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | ||
710 | sta->reason = reason; | ||
711 | __mesh_plink_deactivate(sta); | ||
712 | sta->plink_state = PLINK_HOLDING; | ||
713 | llid = sta->llid; | ||
714 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | ||
715 | spin_unlock_bh(&sta->plink_lock); | ||
716 | mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, | ||
717 | plid, reason); | ||
718 | break; | ||
719 | case OPN_ACPT: | ||
720 | llid = sta->llid; | ||
721 | spin_unlock_bh(&sta->plink_lock); | ||
722 | mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, | ||
723 | plid, 0); | ||
724 | break; | ||
725 | default: | ||
726 | spin_unlock_bh(&sta->plink_lock); | ||
727 | break; | ||
728 | } | ||
729 | break; | ||
730 | case PLINK_HOLDING: | ||
731 | switch (event) { | ||
732 | case CLS_ACPT: | ||
733 | if (del_timer(&sta->plink_timer)) | ||
734 | sta->ignore_plink_timer = 1; | ||
735 | mesh_plink_fsm_restart(sta); | ||
736 | spin_unlock_bh(&sta->plink_lock); | ||
737 | break; | ||
738 | case OPN_ACPT: | ||
739 | case CNF_ACPT: | ||
740 | case OPN_RJCT: | ||
741 | case CNF_RJCT: | ||
742 | llid = sta->llid; | ||
743 | reason = sta->reason; | ||
744 | spin_unlock_bh(&sta->plink_lock); | ||
745 | mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, | ||
746 | plid, reason); | ||
747 | break; | ||
748 | default: | ||
749 | spin_unlock_bh(&sta->plink_lock); | ||
750 | } | ||
751 | break; | ||
752 | default: | ||
753 | /* should not get here, PLINK_BLOCKED is dealt with at the | ||
754 | * beggining of the function | ||
755 | */ | ||
756 | spin_unlock_bh(&sta->plink_lock); | ||
757 | break; | ||
758 | } | ||
759 | |||
760 | rcu_read_unlock(); | ||
761 | } | ||
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 9762803e4876..a1993161de99 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #include <linux/debugfs.h> | 15 | #include <linux/debugfs.h> |
16 | #include <net/mac80211.h> | 16 | #include <net/mac80211.h> |
17 | #include "ieee80211_rate.h" | 17 | #include "ieee80211_rate.h" |
18 | 18 | #include "mesh.h" | |
19 | #include "rc80211_pid.h" | 19 | #include "rc80211_pid.h" |
20 | 20 | ||
21 | 21 | ||
@@ -77,7 +77,7 @@ static void rate_control_pid_adjust_rate(struct ieee80211_local *local, | |||
77 | int cur_sorted, new_sorted, probe, tmp, n_bitrates, band; | 77 | int cur_sorted, new_sorted, probe, tmp, n_bitrates, band; |
78 | int cur = sta->txrate_idx; | 78 | int cur = sta->txrate_idx; |
79 | 79 | ||
80 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 80 | sdata = sta->sdata; |
81 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 81 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
82 | band = sband->band; | 82 | band = sband->band; |
83 | n_bitrates = sband->n_bitrates; | 83 | n_bitrates = sband->n_bitrates; |
@@ -148,6 +148,9 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, | |||
148 | struct ieee80211_local *local, | 148 | struct ieee80211_local *local, |
149 | struct sta_info *sta) | 149 | struct sta_info *sta) |
150 | { | 150 | { |
151 | #ifdef CONFIG_MAC80211_MESH | ||
152 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
153 | #endif | ||
151 | struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv; | 154 | struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv; |
152 | struct rc_pid_rateinfo *rinfo = pinfo->rinfo; | 155 | struct rc_pid_rateinfo *rinfo = pinfo->rinfo; |
153 | struct ieee80211_supported_band *sband; | 156 | struct ieee80211_supported_band *sband; |
@@ -178,7 +181,14 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, | |||
178 | pf = spinfo->last_pf; | 181 | pf = spinfo->last_pf; |
179 | else { | 182 | else { |
180 | pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit; | 183 | pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit; |
184 | #ifdef CONFIG_MAC80211_MESH | ||
185 | if (pf == 100 && | ||
186 | sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) | ||
187 | mesh_plink_broken(sta); | ||
188 | #endif | ||
181 | pf <<= RC_PID_ARITH_SHIFT; | 189 | pf <<= RC_PID_ARITH_SHIFT; |
190 | sta->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9) | ||
191 | >> RC_PID_ARITH_SHIFT; | ||
182 | } | 192 | } |
183 | 193 | ||
184 | spinfo->tx_num_xmit = 0; | 194 | spinfo->tx_num_xmit = 0; |
@@ -239,23 +249,25 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, | |||
239 | unsigned long period; | 249 | unsigned long period; |
240 | struct ieee80211_supported_band *sband; | 250 | struct ieee80211_supported_band *sband; |
241 | 251 | ||
252 | rcu_read_lock(); | ||
253 | |||
242 | sta = sta_info_get(local, hdr->addr1); | 254 | sta = sta_info_get(local, hdr->addr1); |
243 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 255 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
244 | 256 | ||
245 | if (!sta) | 257 | if (!sta) |
246 | return; | 258 | goto unlock; |
247 | 259 | ||
248 | /* Don't update the state if we're not controlling the rate. */ | 260 | /* Don't update the state if we're not controlling the rate. */ |
249 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 261 | sdata = sta->sdata; |
250 | if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { | 262 | if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { |
251 | sta->txrate_idx = sdata->bss->max_ratectrl_rateidx; | 263 | sta->txrate_idx = sdata->bss->max_ratectrl_rateidx; |
252 | return; | 264 | goto unlock; |
253 | } | 265 | } |
254 | 266 | ||
255 | /* Ignore all frames that were sent with a different rate than the rate | 267 | /* Ignore all frames that were sent with a different rate than the rate |
256 | * we currently advise mac80211 to use. */ | 268 | * we currently advise mac80211 to use. */ |
257 | if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx]) | 269 | if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx]) |
258 | goto ignore; | 270 | goto unlock; |
259 | 271 | ||
260 | spinfo = sta->rate_ctrl_priv; | 272 | spinfo = sta->rate_ctrl_priv; |
261 | spinfo->tx_num_xmit++; | 273 | spinfo->tx_num_xmit++; |
@@ -293,8 +305,8 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, | |||
293 | if (time_after(jiffies, spinfo->last_sample + period)) | 305 | if (time_after(jiffies, spinfo->last_sample + period)) |
294 | rate_control_pid_sample(pinfo, local, sta); | 306 | rate_control_pid_sample(pinfo, local, sta); |
295 | 307 | ||
296 | ignore: | 308 | unlock: |
297 | sta_info_put(sta); | 309 | rcu_read_unlock(); |
298 | } | 310 | } |
299 | 311 | ||
300 | static void rate_control_pid_get_rate(void *priv, struct net_device *dev, | 312 | static void rate_control_pid_get_rate(void *priv, struct net_device *dev, |
@@ -309,6 +321,8 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, | |||
309 | int rateidx; | 321 | int rateidx; |
310 | u16 fc; | 322 | u16 fc; |
311 | 323 | ||
324 | rcu_read_lock(); | ||
325 | |||
312 | sta = sta_info_get(local, hdr->addr1); | 326 | sta = sta_info_get(local, hdr->addr1); |
313 | 327 | ||
314 | /* Send management frames and broadcast/multicast data using lowest | 328 | /* Send management frames and broadcast/multicast data using lowest |
@@ -317,8 +331,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, | |||
317 | if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || | 331 | if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || |
318 | is_multicast_ether_addr(hdr->addr1) || !sta) { | 332 | is_multicast_ether_addr(hdr->addr1) || !sta) { |
319 | sel->rate = rate_lowest(local, sband, sta); | 333 | sel->rate = rate_lowest(local, sband, sta); |
320 | if (sta) | 334 | rcu_read_unlock(); |
321 | sta_info_put(sta); | ||
322 | return; | 335 | return; |
323 | } | 336 | } |
324 | 337 | ||
@@ -334,7 +347,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, | |||
334 | 347 | ||
335 | sta->last_txrate_idx = rateidx; | 348 | sta->last_txrate_idx = rateidx; |
336 | 349 | ||
337 | sta_info_put(sta); | 350 | rcu_read_unlock(); |
338 | 351 | ||
339 | sel->rate = &sband->bitrates[rateidx]; | 352 | sel->rate = &sband->bitrates[rateidx]; |
340 | 353 | ||
@@ -357,6 +370,7 @@ static void rate_control_pid_rate_init(void *priv, void *priv_sta, | |||
357 | 370 | ||
358 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 371 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
359 | sta->txrate_idx = rate_lowest_index(local, sband, sta); | 372 | sta->txrate_idx = rate_lowest_index(local, sband, sta); |
373 | sta->fail_avg = 0; | ||
360 | } | 374 | } |
361 | 375 | ||
362 | static void *rate_control_pid_alloc(struct ieee80211_local *local) | 376 | static void *rate_control_pid_alloc(struct ieee80211_local *local) |
diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c index bcc541d4b95c..4f72fdca7f12 100644 --- a/net/mac80211/rc80211_simple.c +++ b/net/mac80211/rc80211_simple.c | |||
@@ -40,7 +40,7 @@ static void rate_control_rate_inc(struct ieee80211_local *local, | |||
40 | int i = sta->txrate_idx; | 40 | int i = sta->txrate_idx; |
41 | int maxrate; | 41 | int maxrate; |
42 | 42 | ||
43 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 43 | sdata = sta->sdata; |
44 | if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { | 44 | if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { |
45 | /* forced unicast rate - do not change STA rate */ | 45 | /* forced unicast rate - do not change STA rate */ |
46 | return; | 46 | return; |
@@ -70,7 +70,7 @@ static void rate_control_rate_dec(struct ieee80211_local *local, | |||
70 | struct ieee80211_supported_band *sband; | 70 | struct ieee80211_supported_band *sband; |
71 | int i = sta->txrate_idx; | 71 | int i = sta->txrate_idx; |
72 | 72 | ||
73 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 73 | sdata = sta->sdata; |
74 | if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { | 74 | if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { |
75 | /* forced unicast rate - do not change STA rate */ | 75 | /* forced unicast rate - do not change STA rate */ |
76 | return; | 76 | return; |
@@ -118,10 +118,12 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, | |||
118 | struct sta_info *sta; | 118 | struct sta_info *sta; |
119 | struct sta_rate_control *srctrl; | 119 | struct sta_rate_control *srctrl; |
120 | 120 | ||
121 | rcu_read_lock(); | ||
122 | |||
121 | sta = sta_info_get(local, hdr->addr1); | 123 | sta = sta_info_get(local, hdr->addr1); |
122 | 124 | ||
123 | if (!sta) | 125 | if (!sta) |
124 | return; | 126 | goto unlock; |
125 | 127 | ||
126 | srctrl = sta->rate_ctrl_priv; | 128 | srctrl = sta->rate_ctrl_priv; |
127 | srctrl->tx_num_xmit++; | 129 | srctrl->tx_num_xmit++; |
@@ -191,7 +193,8 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, | |||
191 | } | 193 | } |
192 | } | 194 | } |
193 | 195 | ||
194 | sta_info_put(sta); | 196 | unlock: |
197 | rcu_read_unlock(); | ||
195 | } | 198 | } |
196 | 199 | ||
197 | 200 | ||
@@ -208,6 +211,8 @@ rate_control_simple_get_rate(void *priv, struct net_device *dev, | |||
208 | int rateidx; | 211 | int rateidx; |
209 | u16 fc; | 212 | u16 fc; |
210 | 213 | ||
214 | rcu_read_lock(); | ||
215 | |||
211 | sta = sta_info_get(local, hdr->addr1); | 216 | sta = sta_info_get(local, hdr->addr1); |
212 | 217 | ||
213 | /* Send management frames and broadcast/multicast data using lowest | 218 | /* Send management frames and broadcast/multicast data using lowest |
@@ -216,8 +221,7 @@ rate_control_simple_get_rate(void *priv, struct net_device *dev, | |||
216 | if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || | 221 | if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || |
217 | is_multicast_ether_addr(hdr->addr1) || !sta) { | 222 | is_multicast_ether_addr(hdr->addr1) || !sta) { |
218 | sel->rate = rate_lowest(local, sband, sta); | 223 | sel->rate = rate_lowest(local, sband, sta); |
219 | if (sta) | 224 | rcu_read_unlock(); |
220 | sta_info_put(sta); | ||
221 | return; | 225 | return; |
222 | } | 226 | } |
223 | 227 | ||
@@ -233,7 +237,7 @@ rate_control_simple_get_rate(void *priv, struct net_device *dev, | |||
233 | 237 | ||
234 | sta->last_txrate_idx = rateidx; | 238 | sta->last_txrate_idx = rateidx; |
235 | 239 | ||
236 | sta_info_put(sta); | 240 | rcu_read_unlock(); |
237 | 241 | ||
238 | sel->rate = &sband->bitrates[rateidx]; | 242 | sel->rate = &sband->bitrates[rateidx]; |
239 | } | 243 | } |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 48574f6c0e74..644d2774469d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -20,6 +20,7 @@ | |||
20 | 20 | ||
21 | #include "ieee80211_i.h" | 21 | #include "ieee80211_i.h" |
22 | #include "ieee80211_led.h" | 22 | #include "ieee80211_led.h" |
23 | #include "mesh.h" | ||
23 | #include "wep.h" | 24 | #include "wep.h" |
24 | #include "wpa.h" | 25 | #include "wpa.h" |
25 | #include "tkip.h" | 26 | #include "tkip.h" |
@@ -250,7 +251,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
250 | } | 251 | } |
251 | 252 | ||
252 | 253 | ||
253 | static void ieee80211_parse_qos(struct ieee80211_txrx_data *rx) | 254 | static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) |
254 | { | 255 | { |
255 | u8 *data = rx->skb->data; | 256 | u8 *data = rx->skb->data; |
256 | int tid; | 257 | int tid; |
@@ -261,9 +262,9 @@ static void ieee80211_parse_qos(struct ieee80211_txrx_data *rx) | |||
261 | /* frame has qos control */ | 262 | /* frame has qos control */ |
262 | tid = qc[0] & QOS_CONTROL_TID_MASK; | 263 | tid = qc[0] & QOS_CONTROL_TID_MASK; |
263 | if (qc[0] & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) | 264 | if (qc[0] & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) |
264 | rx->flags |= IEEE80211_TXRXD_RX_AMSDU; | 265 | rx->flags |= IEEE80211_RX_AMSDU; |
265 | else | 266 | else |
266 | rx->flags &= ~IEEE80211_TXRXD_RX_AMSDU; | 267 | rx->flags &= ~IEEE80211_RX_AMSDU; |
267 | } else { | 268 | } else { |
268 | if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) { | 269 | if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) { |
269 | /* Separate TID for management frames */ | 270 | /* Separate TID for management frames */ |
@@ -279,13 +280,13 @@ static void ieee80211_parse_qos(struct ieee80211_txrx_data *rx) | |||
279 | if (rx->sta) | 280 | if (rx->sta) |
280 | I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]); | 281 | I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]); |
281 | 282 | ||
282 | rx->u.rx.queue = tid; | 283 | rx->queue = tid; |
283 | /* Set skb->priority to 1d tag if highest order bit of TID is not set. | 284 | /* Set skb->priority to 1d tag if highest order bit of TID is not set. |
284 | * For now, set skb->priority to 0 for other cases. */ | 285 | * For now, set skb->priority to 0 for other cases. */ |
285 | rx->skb->priority = (tid > 7) ? 0 : tid; | 286 | rx->skb->priority = (tid > 7) ? 0 : tid; |
286 | } | 287 | } |
287 | 288 | ||
288 | static void ieee80211_verify_ip_alignment(struct ieee80211_txrx_data *rx) | 289 | static void ieee80211_verify_ip_alignment(struct ieee80211_rx_data *rx) |
289 | { | 290 | { |
290 | #ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT | 291 | #ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT |
291 | int hdrlen; | 292 | int hdrlen; |
@@ -313,7 +314,7 @@ static void ieee80211_verify_ip_alignment(struct ieee80211_txrx_data *rx) | |||
313 | * to move the 802.11 header further back in that case. | 314 | * to move the 802.11 header further back in that case. |
314 | */ | 315 | */ |
315 | hdrlen = ieee80211_get_hdrlen(rx->fc); | 316 | hdrlen = ieee80211_get_hdrlen(rx->fc); |
316 | if (rx->flags & IEEE80211_TXRXD_RX_AMSDU) | 317 | if (rx->flags & IEEE80211_RX_AMSDU) |
317 | hdrlen += ETH_HLEN; | 318 | hdrlen += ETH_HLEN; |
318 | WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3); | 319 | WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3); |
319 | #endif | 320 | #endif |
@@ -356,32 +357,32 @@ static u32 ieee80211_rx_load_stats(struct ieee80211_local *local, | |||
356 | /* rx handlers */ | 357 | /* rx handlers */ |
357 | 358 | ||
358 | static ieee80211_rx_result | 359 | static ieee80211_rx_result |
359 | ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx) | 360 | ieee80211_rx_h_if_stats(struct ieee80211_rx_data *rx) |
360 | { | 361 | { |
361 | if (rx->sta) | 362 | if (rx->sta) |
362 | rx->sta->channel_use_raw += rx->u.rx.load; | 363 | rx->sta->channel_use_raw += rx->load; |
363 | rx->sdata->channel_use_raw += rx->u.rx.load; | 364 | rx->sdata->channel_use_raw += rx->load; |
364 | return RX_CONTINUE; | 365 | return RX_CONTINUE; |
365 | } | 366 | } |
366 | 367 | ||
367 | static ieee80211_rx_result | 368 | static ieee80211_rx_result |
368 | ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) | 369 | ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) |
369 | { | 370 | { |
370 | struct ieee80211_local *local = rx->local; | 371 | struct ieee80211_local *local = rx->local; |
371 | struct sk_buff *skb = rx->skb; | 372 | struct sk_buff *skb = rx->skb; |
372 | 373 | ||
373 | if (unlikely(local->sta_hw_scanning)) | 374 | if (unlikely(local->sta_hw_scanning)) |
374 | return ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status); | 375 | return ieee80211_sta_rx_scan(rx->dev, skb, rx->status); |
375 | 376 | ||
376 | if (unlikely(local->sta_sw_scanning)) { | 377 | if (unlikely(local->sta_sw_scanning)) { |
377 | /* drop all the other packets during a software scan anyway */ | 378 | /* drop all the other packets during a software scan anyway */ |
378 | if (ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status) | 379 | if (ieee80211_sta_rx_scan(rx->dev, skb, rx->status) |
379 | != RX_QUEUED) | 380 | != RX_QUEUED) |
380 | dev_kfree_skb(skb); | 381 | dev_kfree_skb(skb); |
381 | return RX_QUEUED; | 382 | return RX_QUEUED; |
382 | } | 383 | } |
383 | 384 | ||
384 | if (unlikely(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) { | 385 | if (unlikely(rx->flags & IEEE80211_RX_IN_SCAN)) { |
385 | /* scanning finished during invoking of handlers */ | 386 | /* scanning finished during invoking of handlers */ |
386 | I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); | 387 | I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); |
387 | return RX_DROP_UNUSABLE; | 388 | return RX_DROP_UNUSABLE; |
@@ -391,23 +392,75 @@ ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) | |||
391 | } | 392 | } |
392 | 393 | ||
393 | static ieee80211_rx_result | 394 | static ieee80211_rx_result |
394 | ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) | 395 | ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) |
396 | { | ||
397 | int hdrlen = ieee80211_get_hdrlen(rx->fc); | ||
398 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; | ||
399 | |||
400 | #define msh_h_get(h, l) ((struct ieee80211s_hdr *) ((u8 *)h + l)) | ||
401 | |||
402 | if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { | ||
403 | if (!((rx->fc & IEEE80211_FCTL_FROMDS) && | ||
404 | (rx->fc & IEEE80211_FCTL_TODS))) | ||
405 | return RX_DROP_MONITOR; | ||
406 | if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0) | ||
407 | return RX_DROP_MONITOR; | ||
408 | } | ||
409 | |||
410 | /* If there is not an established peer link and this is not a peer link | ||
411 | * establisment frame, beacon or probe, drop the frame. | ||
412 | */ | ||
413 | |||
414 | if (!rx->sta || sta_plink_state(rx->sta) != PLINK_ESTAB) { | ||
415 | struct ieee80211_mgmt *mgmt; | ||
416 | |||
417 | if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) | ||
418 | return RX_DROP_MONITOR; | ||
419 | |||
420 | switch (rx->fc & IEEE80211_FCTL_STYPE) { | ||
421 | case IEEE80211_STYPE_ACTION: | ||
422 | mgmt = (struct ieee80211_mgmt *)hdr; | ||
423 | if (mgmt->u.action.category != PLINK_CATEGORY) | ||
424 | return RX_DROP_MONITOR; | ||
425 | /* fall through on else */ | ||
426 | case IEEE80211_STYPE_PROBE_REQ: | ||
427 | case IEEE80211_STYPE_PROBE_RESP: | ||
428 | case IEEE80211_STYPE_BEACON: | ||
429 | return RX_CONTINUE; | ||
430 | break; | ||
431 | default: | ||
432 | return RX_DROP_MONITOR; | ||
433 | } | ||
434 | |||
435 | } else if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && | ||
436 | is_broadcast_ether_addr(hdr->addr1) && | ||
437 | mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->dev)) | ||
438 | return RX_DROP_MONITOR; | ||
439 | #undef msh_h_get | ||
440 | |||
441 | return RX_CONTINUE; | ||
442 | } | ||
443 | |||
444 | |||
445 | static ieee80211_rx_result | ||
446 | ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | ||
395 | { | 447 | { |
396 | struct ieee80211_hdr *hdr; | 448 | struct ieee80211_hdr *hdr; |
449 | |||
397 | hdr = (struct ieee80211_hdr *) rx->skb->data; | 450 | hdr = (struct ieee80211_hdr *) rx->skb->data; |
398 | 451 | ||
399 | /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ | 452 | /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ |
400 | if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) { | 453 | if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) { |
401 | if (unlikely(rx->fc & IEEE80211_FCTL_RETRY && | 454 | if (unlikely(rx->fc & IEEE80211_FCTL_RETRY && |
402 | rx->sta->last_seq_ctrl[rx->u.rx.queue] == | 455 | rx->sta->last_seq_ctrl[rx->queue] == |
403 | hdr->seq_ctrl)) { | 456 | hdr->seq_ctrl)) { |
404 | if (rx->flags & IEEE80211_TXRXD_RXRA_MATCH) { | 457 | if (rx->flags & IEEE80211_RX_RA_MATCH) { |
405 | rx->local->dot11FrameDuplicateCount++; | 458 | rx->local->dot11FrameDuplicateCount++; |
406 | rx->sta->num_duplicates++; | 459 | rx->sta->num_duplicates++; |
407 | } | 460 | } |
408 | return RX_DROP_MONITOR; | 461 | return RX_DROP_MONITOR; |
409 | } else | 462 | } else |
410 | rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl; | 463 | rx->sta->last_seq_ctrl[rx->queue] = hdr->seq_ctrl; |
411 | } | 464 | } |
412 | 465 | ||
413 | if (unlikely(rx->skb->len < 16)) { | 466 | if (unlikely(rx->skb->len < 16)) { |
@@ -423,6 +476,10 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) | |||
423 | * deauth/disassoc frames when needed. In addition, hostapd is | 476 | * deauth/disassoc frames when needed. In addition, hostapd is |
424 | * responsible for filtering on both auth and assoc states. | 477 | * responsible for filtering on both auth and assoc states. |
425 | */ | 478 | */ |
479 | |||
480 | if (ieee80211_vif_is_mesh(&rx->sdata->vif)) | ||
481 | return ieee80211_rx_mesh_check(rx); | ||
482 | |||
426 | if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA || | 483 | if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA || |
427 | ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL && | 484 | ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL && |
428 | (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) && | 485 | (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) && |
@@ -431,7 +488,7 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) | |||
431 | if ((!(rx->fc & IEEE80211_FCTL_FROMDS) && | 488 | if ((!(rx->fc & IEEE80211_FCTL_FROMDS) && |
432 | !(rx->fc & IEEE80211_FCTL_TODS) && | 489 | !(rx->fc & IEEE80211_FCTL_TODS) && |
433 | (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) | 490 | (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) |
434 | || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { | 491 | || !(rx->flags & IEEE80211_RX_RA_MATCH)) { |
435 | /* Drop IBSS frames and frames for other hosts | 492 | /* Drop IBSS frames and frames for other hosts |
436 | * silently. */ | 493 | * silently. */ |
437 | return RX_DROP_MONITOR; | 494 | return RX_DROP_MONITOR; |
@@ -445,7 +502,7 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) | |||
445 | 502 | ||
446 | 503 | ||
447 | static ieee80211_rx_result | 504 | static ieee80211_rx_result |
448 | ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) | 505 | ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) |
449 | { | 506 | { |
450 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; | 507 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; |
451 | int keyidx; | 508 | int keyidx; |
@@ -486,7 +543,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) | |||
486 | * No point in finding a key and decrypting if the frame is neither | 543 | * No point in finding a key and decrypting if the frame is neither |
487 | * addressed to us nor a multicast frame. | 544 | * addressed to us nor a multicast frame. |
488 | */ | 545 | */ |
489 | if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) | 546 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) |
490 | return RX_CONTINUE; | 547 | return RX_CONTINUE; |
491 | 548 | ||
492 | if (rx->sta) | 549 | if (rx->sta) |
@@ -504,8 +561,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) | |||
504 | * we somehow allow the driver to tell us which key | 561 | * we somehow allow the driver to tell us which key |
505 | * the hardware used if this flag is set? | 562 | * the hardware used if this flag is set? |
506 | */ | 563 | */ |
507 | if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && | 564 | if ((rx->status->flag & RX_FLAG_DECRYPTED) && |
508 | (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) | 565 | (rx->status->flag & RX_FLAG_IV_STRIPPED)) |
509 | return RX_CONTINUE; | 566 | return RX_CONTINUE; |
510 | 567 | ||
511 | hdrlen = ieee80211_get_hdrlen(rx->fc); | 568 | hdrlen = ieee80211_get_hdrlen(rx->fc); |
@@ -546,8 +603,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) | |||
546 | /* Check for weak IVs if possible */ | 603 | /* Check for weak IVs if possible */ |
547 | if (rx->sta && rx->key->conf.alg == ALG_WEP && | 604 | if (rx->sta && rx->key->conf.alg == ALG_WEP && |
548 | ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && | 605 | ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && |
549 | (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) || | 606 | (!(rx->status->flag & RX_FLAG_IV_STRIPPED) || |
550 | !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) && | 607 | !(rx->status->flag & RX_FLAG_DECRYPTED)) && |
551 | ieee80211_wep_is_weak_iv(rx->skb, rx->key)) | 608 | ieee80211_wep_is_weak_iv(rx->skb, rx->key)) |
552 | rx->sta->wep_weak_iv_count++; | 609 | rx->sta->wep_weak_iv_count++; |
553 | 610 | ||
@@ -564,7 +621,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) | |||
564 | } | 621 | } |
565 | 622 | ||
566 | /* either the frame has been decrypted or will be dropped */ | 623 | /* either the frame has been decrypted or will be dropped */ |
567 | rx->u.rx.status->flag |= RX_FLAG_DECRYPTED; | 624 | rx->status->flag |= RX_FLAG_DECRYPTED; |
568 | 625 | ||
569 | return result; | 626 | return result; |
570 | } | 627 | } |
@@ -574,7 +631,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) | |||
574 | struct ieee80211_sub_if_data *sdata; | 631 | struct ieee80211_sub_if_data *sdata; |
575 | DECLARE_MAC_BUF(mac); | 632 | DECLARE_MAC_BUF(mac); |
576 | 633 | ||
577 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 634 | sdata = sta->sdata; |
578 | 635 | ||
579 | if (sdata->bss) | 636 | if (sdata->bss) |
580 | atomic_inc(&sdata->bss->num_sta_ps); | 637 | atomic_inc(&sdata->bss->num_sta_ps); |
@@ -595,7 +652,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) | |||
595 | struct ieee80211_tx_packet_data *pkt_data; | 652 | struct ieee80211_tx_packet_data *pkt_data; |
596 | DECLARE_MAC_BUF(mac); | 653 | DECLARE_MAC_BUF(mac); |
597 | 654 | ||
598 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 655 | sdata = sta->sdata; |
599 | 656 | ||
600 | if (sdata->bss) | 657 | if (sdata->bss) |
601 | atomic_dec(&sdata->bss->num_sta_ps); | 658 | atomic_dec(&sdata->bss->num_sta_ps); |
@@ -634,7 +691,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) | |||
634 | } | 691 | } |
635 | 692 | ||
636 | static ieee80211_rx_result | 693 | static ieee80211_rx_result |
637 | ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) | 694 | ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) |
638 | { | 695 | { |
639 | struct sta_info *sta = rx->sta; | 696 | struct sta_info *sta = rx->sta; |
640 | struct net_device *dev = rx->dev; | 697 | struct net_device *dev = rx->dev; |
@@ -657,24 +714,26 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) | |||
657 | /* Update last_rx only for unicast frames in order to prevent | 714 | /* Update last_rx only for unicast frames in order to prevent |
658 | * the Probe Request frames (the only broadcast frames from a | 715 | * the Probe Request frames (the only broadcast frames from a |
659 | * STA in infrastructure mode) from keeping a connection alive. | 716 | * STA in infrastructure mode) from keeping a connection alive. |
717 | * Mesh beacons will update last_rx when if they are found to | ||
718 | * match the current local configuration when processed. | ||
660 | */ | 719 | */ |
661 | sta->last_rx = jiffies; | 720 | sta->last_rx = jiffies; |
662 | } | 721 | } |
663 | 722 | ||
664 | if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) | 723 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) |
665 | return RX_CONTINUE; | 724 | return RX_CONTINUE; |
666 | 725 | ||
667 | sta->rx_fragments++; | 726 | sta->rx_fragments++; |
668 | sta->rx_bytes += rx->skb->len; | 727 | sta->rx_bytes += rx->skb->len; |
669 | sta->last_rssi = rx->u.rx.status->ssi; | 728 | sta->last_rssi = rx->status->ssi; |
670 | sta->last_signal = rx->u.rx.status->signal; | 729 | sta->last_signal = rx->status->signal; |
671 | sta->last_noise = rx->u.rx.status->noise; | 730 | sta->last_noise = rx->status->noise; |
672 | 731 | ||
673 | if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) { | 732 | if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) { |
674 | /* Change STA power saving mode only in the end of a frame | 733 | /* Change STA power saving mode only in the end of a frame |
675 | * exchange sequence */ | 734 | * exchange sequence */ |
676 | if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM)) | 735 | if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM)) |
677 | rx->u.rx.sent_ps_buffered += ap_sta_ps_end(dev, sta); | 736 | rx->sent_ps_buffered += ap_sta_ps_end(dev, sta); |
678 | else if (!(sta->flags & WLAN_STA_PS) && | 737 | else if (!(sta->flags & WLAN_STA_PS) && |
679 | (rx->fc & IEEE80211_FCTL_PM)) | 738 | (rx->fc & IEEE80211_FCTL_PM)) |
680 | ap_sta_ps_start(dev, sta); | 739 | ap_sta_ps_start(dev, sta); |
@@ -779,7 +838,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, | |||
779 | } | 838 | } |
780 | 839 | ||
781 | static ieee80211_rx_result | 840 | static ieee80211_rx_result |
782 | ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) | 841 | ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) |
783 | { | 842 | { |
784 | struct ieee80211_hdr *hdr; | 843 | struct ieee80211_hdr *hdr; |
785 | u16 sc; | 844 | u16 sc; |
@@ -805,14 +864,14 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) | |||
805 | if (frag == 0) { | 864 | if (frag == 0) { |
806 | /* This is the first fragment of a new frame. */ | 865 | /* This is the first fragment of a new frame. */ |
807 | entry = ieee80211_reassemble_add(rx->sdata, frag, seq, | 866 | entry = ieee80211_reassemble_add(rx->sdata, frag, seq, |
808 | rx->u.rx.queue, &(rx->skb)); | 867 | rx->queue, &(rx->skb)); |
809 | if (rx->key && rx->key->conf.alg == ALG_CCMP && | 868 | if (rx->key && rx->key->conf.alg == ALG_CCMP && |
810 | (rx->fc & IEEE80211_FCTL_PROTECTED)) { | 869 | (rx->fc & IEEE80211_FCTL_PROTECTED)) { |
811 | /* Store CCMP PN so that we can verify that the next | 870 | /* Store CCMP PN so that we can verify that the next |
812 | * fragment has a sequential PN value. */ | 871 | * fragment has a sequential PN value. */ |
813 | entry->ccmp = 1; | 872 | entry->ccmp = 1; |
814 | memcpy(entry->last_pn, | 873 | memcpy(entry->last_pn, |
815 | rx->key->u.ccmp.rx_pn[rx->u.rx.queue], | 874 | rx->key->u.ccmp.rx_pn[rx->queue], |
816 | CCMP_PN_LEN); | 875 | CCMP_PN_LEN); |
817 | } | 876 | } |
818 | return RX_QUEUED; | 877 | return RX_QUEUED; |
@@ -822,7 +881,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) | |||
822 | * fragment cache. Add this fragment to the end of the pending entry. | 881 | * fragment cache. Add this fragment to the end of the pending entry. |
823 | */ | 882 | */ |
824 | entry = ieee80211_reassemble_find(rx->sdata, rx->fc, frag, seq, | 883 | entry = ieee80211_reassemble_find(rx->sdata, rx->fc, frag, seq, |
825 | rx->u.rx.queue, hdr); | 884 | rx->queue, hdr); |
826 | if (!entry) { | 885 | if (!entry) { |
827 | I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); | 886 | I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); |
828 | return RX_DROP_MONITOR; | 887 | return RX_DROP_MONITOR; |
@@ -841,7 +900,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) | |||
841 | if (pn[i]) | 900 | if (pn[i]) |
842 | break; | 901 | break; |
843 | } | 902 | } |
844 | rpn = rx->key->u.ccmp.rx_pn[rx->u.rx.queue]; | 903 | rpn = rx->key->u.ccmp.rx_pn[rx->queue]; |
845 | if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) { | 904 | if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) { |
846 | if (net_ratelimit()) | 905 | if (net_ratelimit()) |
847 | printk(KERN_DEBUG "%s: defrag: CCMP PN not " | 906 | printk(KERN_DEBUG "%s: defrag: CCMP PN not " |
@@ -882,7 +941,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) | |||
882 | } | 941 | } |
883 | 942 | ||
884 | /* Complete frame has been reassembled - process it now */ | 943 | /* Complete frame has been reassembled - process it now */ |
885 | rx->flags |= IEEE80211_TXRXD_FRAGMENTED; | 944 | rx->flags |= IEEE80211_RX_FRAGMENTED; |
886 | 945 | ||
887 | out: | 946 | out: |
888 | if (rx->sta) | 947 | if (rx->sta) |
@@ -895,7 +954,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) | |||
895 | } | 954 | } |
896 | 955 | ||
897 | static ieee80211_rx_result | 956 | static ieee80211_rx_result |
898 | ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) | 957 | ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) |
899 | { | 958 | { |
900 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); | 959 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); |
901 | struct sk_buff *skb; | 960 | struct sk_buff *skb; |
@@ -905,7 +964,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) | |||
905 | if (likely(!rx->sta || | 964 | if (likely(!rx->sta || |
906 | (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL || | 965 | (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL || |
907 | (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL || | 966 | (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL || |
908 | !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))) | 967 | !(rx->flags & IEEE80211_RX_RA_MATCH))) |
909 | return RX_CONTINUE; | 968 | return RX_CONTINUE; |
910 | 969 | ||
911 | if ((sdata->vif.type != IEEE80211_IF_TYPE_AP) && | 970 | if ((sdata->vif.type != IEEE80211_IF_TYPE_AP) && |
@@ -949,7 +1008,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) | |||
949 | if (no_pending_pkts) | 1008 | if (no_pending_pkts) |
950 | sta_info_clear_tim_bit(rx->sta); | 1009 | sta_info_clear_tim_bit(rx->sta); |
951 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 1010 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
952 | } else if (!rx->u.rx.sent_ps_buffered) { | 1011 | } else if (!rx->sent_ps_buffered) { |
953 | /* | 1012 | /* |
954 | * FIXME: This can be the result of a race condition between | 1013 | * FIXME: This can be the result of a race condition between |
955 | * us expiring a frame and the station polling for it. | 1014 | * us expiring a frame and the station polling for it. |
@@ -970,7 +1029,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) | |||
970 | } | 1029 | } |
971 | 1030 | ||
972 | static ieee80211_rx_result | 1031 | static ieee80211_rx_result |
973 | ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) | 1032 | ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx) |
974 | { | 1033 | { |
975 | u16 fc = rx->fc; | 1034 | u16 fc = rx->fc; |
976 | u8 *data = rx->skb->data; | 1035 | u8 *data = rx->skb->data; |
@@ -990,7 +1049,7 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) | |||
990 | } | 1049 | } |
991 | 1050 | ||
992 | static int | 1051 | static int |
993 | ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx) | 1052 | ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) |
994 | { | 1053 | { |
995 | if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) { | 1054 | if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) { |
996 | #ifdef CONFIG_MAC80211_DEBUG | 1055 | #ifdef CONFIG_MAC80211_DEBUG |
@@ -1005,13 +1064,13 @@ ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx) | |||
1005 | } | 1064 | } |
1006 | 1065 | ||
1007 | static int | 1066 | static int |
1008 | ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx) | 1067 | ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx) |
1009 | { | 1068 | { |
1010 | /* | 1069 | /* |
1011 | * Pass through unencrypted frames if the hardware has | 1070 | * Pass through unencrypted frames if the hardware has |
1012 | * decrypted them already. | 1071 | * decrypted them already. |
1013 | */ | 1072 | */ |
1014 | if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) | 1073 | if (rx->status->flag & RX_FLAG_DECRYPTED) |
1015 | return 0; | 1074 | return 0; |
1016 | 1075 | ||
1017 | /* Drop unencrypted frames if key is set. */ | 1076 | /* Drop unencrypted frames if key is set. */ |
@@ -1028,7 +1087,7 @@ ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx) | |||
1028 | } | 1087 | } |
1029 | 1088 | ||
1030 | static int | 1089 | static int |
1031 | ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) | 1090 | ieee80211_data_to_8023(struct ieee80211_rx_data *rx) |
1032 | { | 1091 | { |
1033 | struct net_device *dev = rx->dev; | 1092 | struct net_device *dev = rx->dev; |
1034 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; | 1093 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; |
@@ -1050,6 +1109,21 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) | |||
1050 | 1109 | ||
1051 | hdrlen = ieee80211_get_hdrlen(fc); | 1110 | hdrlen = ieee80211_get_hdrlen(fc); |
1052 | 1111 | ||
1112 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
1113 | int meshhdrlen = ieee80211_get_mesh_hdrlen( | ||
1114 | (struct ieee80211s_hdr *) (skb->data + hdrlen)); | ||
1115 | /* Copy on cb: | ||
1116 | * - mesh header: to be used for mesh forwarding | ||
1117 | * decision. It will also be used as mesh header template at | ||
1118 | * tx.c:ieee80211_subif_start_xmit() if interface | ||
1119 | * type is mesh and skb->pkt_type == PACKET_OTHERHOST | ||
1120 | * - ta: to be used if a RERR needs to be sent. | ||
1121 | */ | ||
1122 | memcpy(skb->cb, skb->data + hdrlen, meshhdrlen); | ||
1123 | memcpy(MESH_PREQ(skb), hdr->addr2, ETH_ALEN); | ||
1124 | hdrlen += meshhdrlen; | ||
1125 | } | ||
1126 | |||
1053 | /* convert IEEE 802.11 header + possible LLC headers into Ethernet | 1127 | /* convert IEEE 802.11 header + possible LLC headers into Ethernet |
1054 | * header | 1128 | * header |
1055 | * IEEE 802.11 address fields: | 1129 | * IEEE 802.11 address fields: |
@@ -1083,9 +1157,10 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) | |||
1083 | memcpy(dst, hdr->addr3, ETH_ALEN); | 1157 | memcpy(dst, hdr->addr3, ETH_ALEN); |
1084 | memcpy(src, hdr->addr4, ETH_ALEN); | 1158 | memcpy(src, hdr->addr4, ETH_ALEN); |
1085 | 1159 | ||
1086 | if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS)) { | 1160 | if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS && |
1087 | if (net_ratelimit()) | 1161 | sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)) { |
1088 | printk(KERN_DEBUG "%s: dropped FromDS&ToDS " | 1162 | if (net_ratelimit()) |
1163 | printk(KERN_DEBUG "%s: dropped FromDS&ToDS " | ||
1089 | "frame (RA=%s TA=%s DA=%s SA=%s)\n", | 1164 | "frame (RA=%s TA=%s DA=%s SA=%s)\n", |
1090 | rx->dev->name, | 1165 | rx->dev->name, |
1091 | print_mac(mac, hdr->addr1), | 1166 | print_mac(mac, hdr->addr1), |
@@ -1160,7 +1235,7 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) | |||
1160 | /* | 1235 | /* |
1161 | * requires that rx->skb is a frame with ethernet header | 1236 | * requires that rx->skb is a frame with ethernet header |
1162 | */ | 1237 | */ |
1163 | static bool ieee80211_frame_allowed(struct ieee80211_txrx_data *rx) | 1238 | static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx) |
1164 | { | 1239 | { |
1165 | static const u8 pae_group_addr[ETH_ALEN] | 1240 | static const u8 pae_group_addr[ETH_ALEN] |
1166 | = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 }; | 1241 | = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 }; |
@@ -1186,7 +1261,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_txrx_data *rx) | |||
1186 | * requires that rx->skb is a frame with ethernet header | 1261 | * requires that rx->skb is a frame with ethernet header |
1187 | */ | 1262 | */ |
1188 | static void | 1263 | static void |
1189 | ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) | 1264 | ieee80211_deliver_skb(struct ieee80211_rx_data *rx) |
1190 | { | 1265 | { |
1191 | struct net_device *dev = rx->dev; | 1266 | struct net_device *dev = rx->dev; |
1192 | struct ieee80211_local *local = rx->local; | 1267 | struct ieee80211_local *local = rx->local; |
@@ -1200,7 +1275,7 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) | |||
1200 | 1275 | ||
1201 | if (local->bridge_packets && (sdata->vif.type == IEEE80211_IF_TYPE_AP || | 1276 | if (local->bridge_packets && (sdata->vif.type == IEEE80211_IF_TYPE_AP || |
1202 | sdata->vif.type == IEEE80211_IF_TYPE_VLAN) && | 1277 | sdata->vif.type == IEEE80211_IF_TYPE_VLAN) && |
1203 | (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { | 1278 | (rx->flags & IEEE80211_RX_RA_MATCH)) { |
1204 | if (is_multicast_ether_addr(ehdr->h_dest)) { | 1279 | if (is_multicast_ether_addr(ehdr->h_dest)) { |
1205 | /* | 1280 | /* |
1206 | * send multicast frames both to higher layers in | 1281 | * send multicast frames both to higher layers in |
@@ -1212,7 +1287,7 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) | |||
1212 | "multicast frame\n", dev->name); | 1287 | "multicast frame\n", dev->name); |
1213 | } else { | 1288 | } else { |
1214 | dsta = sta_info_get(local, skb->data); | 1289 | dsta = sta_info_get(local, skb->data); |
1215 | if (dsta && dsta->dev == dev) { | 1290 | if (dsta && dsta->sdata->dev == dev) { |
1216 | /* | 1291 | /* |
1217 | * The destination station is associated to | 1292 | * The destination station is associated to |
1218 | * this AP (in this VLAN), so send the frame | 1293 | * this AP (in this VLAN), so send the frame |
@@ -1222,8 +1297,38 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) | |||
1222 | xmit_skb = skb; | 1297 | xmit_skb = skb; |
1223 | skb = NULL; | 1298 | skb = NULL; |
1224 | } | 1299 | } |
1225 | if (dsta) | 1300 | } |
1226 | sta_info_put(dsta); | 1301 | } |
1302 | |||
1303 | /* Mesh forwarding */ | ||
1304 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
1305 | u8 *mesh_ttl = &((struct ieee80211s_hdr *)skb->cb)->ttl; | ||
1306 | (*mesh_ttl)--; | ||
1307 | |||
1308 | if (is_multicast_ether_addr(skb->data)) { | ||
1309 | if (*mesh_ttl > 0) { | ||
1310 | xmit_skb = skb_copy(skb, GFP_ATOMIC); | ||
1311 | if (!xmit_skb && net_ratelimit()) | ||
1312 | printk(KERN_DEBUG "%s: failed to clone " | ||
1313 | "multicast frame\n", dev->name); | ||
1314 | else | ||
1315 | xmit_skb->pkt_type = PACKET_OTHERHOST; | ||
1316 | } else | ||
1317 | IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.sta, | ||
1318 | dropped_frames_ttl); | ||
1319 | } else if (skb->pkt_type != PACKET_OTHERHOST && | ||
1320 | compare_ether_addr(dev->dev_addr, skb->data) != 0) { | ||
1321 | if (*mesh_ttl == 0) { | ||
1322 | IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.sta, | ||
1323 | dropped_frames_ttl); | ||
1324 | dev_kfree_skb(skb); | ||
1325 | skb = NULL; | ||
1326 | } else { | ||
1327 | xmit_skb = skb; | ||
1328 | xmit_skb->pkt_type = PACKET_OTHERHOST; | ||
1329 | if (!(dev->flags & IFF_PROMISC)) | ||
1330 | skb = NULL; | ||
1331 | } | ||
1227 | } | 1332 | } |
1228 | } | 1333 | } |
1229 | 1334 | ||
@@ -1244,7 +1349,7 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) | |||
1244 | } | 1349 | } |
1245 | 1350 | ||
1246 | static ieee80211_rx_result | 1351 | static ieee80211_rx_result |
1247 | ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) | 1352 | ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) |
1248 | { | 1353 | { |
1249 | struct net_device *dev = rx->dev; | 1354 | struct net_device *dev = rx->dev; |
1250 | struct ieee80211_local *local = rx->local; | 1355 | struct ieee80211_local *local = rx->local; |
@@ -1264,7 +1369,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) | |||
1264 | if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) | 1369 | if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) |
1265 | return RX_DROP_MONITOR; | 1370 | return RX_DROP_MONITOR; |
1266 | 1371 | ||
1267 | if (!(rx->flags & IEEE80211_TXRXD_RX_AMSDU)) | 1372 | if (!(rx->flags & IEEE80211_RX_AMSDU)) |
1268 | return RX_CONTINUE; | 1373 | return RX_CONTINUE; |
1269 | 1374 | ||
1270 | err = ieee80211_data_to_8023(rx); | 1375 | err = ieee80211_data_to_8023(rx); |
@@ -1361,7 +1466,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) | |||
1361 | } | 1466 | } |
1362 | 1467 | ||
1363 | static ieee80211_rx_result | 1468 | static ieee80211_rx_result |
1364 | ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) | 1469 | ieee80211_rx_h_data(struct ieee80211_rx_data *rx) |
1365 | { | 1470 | { |
1366 | struct net_device *dev = rx->dev; | 1471 | struct net_device *dev = rx->dev; |
1367 | u16 fc; | 1472 | u16 fc; |
@@ -1392,7 +1497,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) | |||
1392 | } | 1497 | } |
1393 | 1498 | ||
1394 | static ieee80211_rx_result | 1499 | static ieee80211_rx_result |
1395 | ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx) | 1500 | ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) |
1396 | { | 1501 | { |
1397 | struct ieee80211_local *local = rx->local; | 1502 | struct ieee80211_local *local = rx->local; |
1398 | struct ieee80211_hw *hw = &local->hw; | 1503 | struct ieee80211_hw *hw = &local->hw; |
@@ -1435,18 +1540,19 @@ ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx) | |||
1435 | } | 1540 | } |
1436 | 1541 | ||
1437 | static ieee80211_rx_result | 1542 | static ieee80211_rx_result |
1438 | ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) | 1543 | ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) |
1439 | { | 1544 | { |
1440 | struct ieee80211_sub_if_data *sdata; | 1545 | struct ieee80211_sub_if_data *sdata; |
1441 | 1546 | ||
1442 | if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) | 1547 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) |
1443 | return RX_DROP_MONITOR; | 1548 | return RX_DROP_MONITOR; |
1444 | 1549 | ||
1445 | sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); | 1550 | sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); |
1446 | if ((sdata->vif.type == IEEE80211_IF_TYPE_STA || | 1551 | if ((sdata->vif.type == IEEE80211_IF_TYPE_STA || |
1447 | sdata->vif.type == IEEE80211_IF_TYPE_IBSS) && | 1552 | sdata->vif.type == IEEE80211_IF_TYPE_IBSS || |
1553 | sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) && | ||
1448 | !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) | 1554 | !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) |
1449 | ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); | 1555 | ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->status); |
1450 | else | 1556 | else |
1451 | return RX_DROP_MONITOR; | 1557 | return RX_DROP_MONITOR; |
1452 | 1558 | ||
@@ -1455,7 +1561,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) | |||
1455 | 1561 | ||
1456 | static void ieee80211_rx_michael_mic_report(struct net_device *dev, | 1562 | static void ieee80211_rx_michael_mic_report(struct net_device *dev, |
1457 | struct ieee80211_hdr *hdr, | 1563 | struct ieee80211_hdr *hdr, |
1458 | struct ieee80211_txrx_data *rx) | 1564 | struct ieee80211_rx_data *rx) |
1459 | { | 1565 | { |
1460 | int keyidx, hdrlen; | 1566 | int keyidx, hdrlen; |
1461 | DECLARE_MAC_BUF(mac); | 1567 | DECLARE_MAC_BUF(mac); |
@@ -1525,7 +1631,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, | |||
1525 | rx->skb = NULL; | 1631 | rx->skb = NULL; |
1526 | } | 1632 | } |
1527 | 1633 | ||
1528 | static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx) | 1634 | /* TODO: use IEEE80211_RX_FRAGMENTED */ |
1635 | static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx) | ||
1529 | { | 1636 | { |
1530 | struct ieee80211_sub_if_data *sdata; | 1637 | struct ieee80211_sub_if_data *sdata; |
1531 | struct ieee80211_local *local = rx->local; | 1638 | struct ieee80211_local *local = rx->local; |
@@ -1538,9 +1645,9 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx) | |||
1538 | } __attribute__ ((packed)) *rthdr; | 1645 | } __attribute__ ((packed)) *rthdr; |
1539 | struct sk_buff *skb = rx->skb, *skb2; | 1646 | struct sk_buff *skb = rx->skb, *skb2; |
1540 | struct net_device *prev_dev = NULL; | 1647 | struct net_device *prev_dev = NULL; |
1541 | struct ieee80211_rx_status *status = rx->u.rx.status; | 1648 | struct ieee80211_rx_status *status = rx->status; |
1542 | 1649 | ||
1543 | if (rx->flags & IEEE80211_TXRXD_RX_CMNTR_REPORTED) | 1650 | if (rx->flags & IEEE80211_RX_CMNTR_REPORTED) |
1544 | goto out_free_skb; | 1651 | goto out_free_skb; |
1545 | 1652 | ||
1546 | if (skb_headroom(skb) < sizeof(*rthdr) && | 1653 | if (skb_headroom(skb) < sizeof(*rthdr) && |
@@ -1555,7 +1662,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx) | |||
1555 | (1 << IEEE80211_RADIOTAP_RATE) | | 1662 | (1 << IEEE80211_RADIOTAP_RATE) | |
1556 | (1 << IEEE80211_RADIOTAP_CHANNEL)); | 1663 | (1 << IEEE80211_RADIOTAP_CHANNEL)); |
1557 | 1664 | ||
1558 | rthdr->rate = rx->u.rx.rate->bitrate / 5; | 1665 | rthdr->rate = rx->rate->bitrate / 5; |
1559 | rthdr->chan_freq = cpu_to_le16(status->freq); | 1666 | rthdr->chan_freq = cpu_to_le16(status->freq); |
1560 | 1667 | ||
1561 | if (status->band == IEEE80211_BAND_5GHZ) | 1668 | if (status->band == IEEE80211_BAND_5GHZ) |
@@ -1598,14 +1705,14 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx) | |||
1598 | } else | 1705 | } else |
1599 | goto out_free_skb; | 1706 | goto out_free_skb; |
1600 | 1707 | ||
1601 | rx->flags |= IEEE80211_TXRXD_RX_CMNTR_REPORTED; | 1708 | rx->flags |= IEEE80211_RX_CMNTR_REPORTED; |
1602 | return; | 1709 | return; |
1603 | 1710 | ||
1604 | out_free_skb: | 1711 | out_free_skb: |
1605 | dev_kfree_skb(skb); | 1712 | dev_kfree_skb(skb); |
1606 | } | 1713 | } |
1607 | 1714 | ||
1608 | typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_txrx_data *); | 1715 | typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_rx_data *); |
1609 | static ieee80211_rx_handler ieee80211_rx_handlers[] = | 1716 | static ieee80211_rx_handler ieee80211_rx_handlers[] = |
1610 | { | 1717 | { |
1611 | ieee80211_rx_h_if_stats, | 1718 | ieee80211_rx_h_if_stats, |
@@ -1629,7 +1736,7 @@ static ieee80211_rx_handler ieee80211_rx_handlers[] = | |||
1629 | }; | 1736 | }; |
1630 | 1737 | ||
1631 | static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, | 1738 | static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, |
1632 | struct ieee80211_txrx_data *rx, | 1739 | struct ieee80211_rx_data *rx, |
1633 | struct sk_buff *skb) | 1740 | struct sk_buff *skb) |
1634 | { | 1741 | { |
1635 | ieee80211_rx_handler *handler; | 1742 | ieee80211_rx_handler *handler; |
@@ -1672,7 +1779,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, | |||
1672 | /* main receive path */ | 1779 | /* main receive path */ |
1673 | 1780 | ||
1674 | static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | 1781 | static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, |
1675 | u8 *bssid, struct ieee80211_txrx_data *rx, | 1782 | u8 *bssid, struct ieee80211_rx_data *rx, |
1676 | struct ieee80211_hdr *hdr) | 1783 | struct ieee80211_hdr *hdr) |
1677 | { | 1784 | { |
1678 | int multicast = is_multicast_ether_addr(hdr->addr1); | 1785 | int multicast = is_multicast_ether_addr(hdr->addr1); |
@@ -1682,15 +1789,15 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
1682 | if (!bssid) | 1789 | if (!bssid) |
1683 | return 0; | 1790 | return 0; |
1684 | if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { | 1791 | if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { |
1685 | if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) | 1792 | if (!(rx->flags & IEEE80211_RX_IN_SCAN)) |
1686 | return 0; | 1793 | return 0; |
1687 | rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; | 1794 | rx->flags &= ~IEEE80211_RX_RA_MATCH; |
1688 | } else if (!multicast && | 1795 | } else if (!multicast && |
1689 | compare_ether_addr(sdata->dev->dev_addr, | 1796 | compare_ether_addr(sdata->dev->dev_addr, |
1690 | hdr->addr1) != 0) { | 1797 | hdr->addr1) != 0) { |
1691 | if (!(sdata->dev->flags & IFF_PROMISC)) | 1798 | if (!(sdata->dev->flags & IFF_PROMISC)) |
1692 | return 0; | 1799 | return 0; |
1693 | rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; | 1800 | rx->flags &= ~IEEE80211_RX_RA_MATCH; |
1694 | } | 1801 | } |
1695 | break; | 1802 | break; |
1696 | case IEEE80211_IF_TYPE_IBSS: | 1803 | case IEEE80211_IF_TYPE_IBSS: |
@@ -1700,19 +1807,29 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
1700 | (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) | 1807 | (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) |
1701 | return 1; | 1808 | return 1; |
1702 | else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { | 1809 | else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { |
1703 | if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) | 1810 | if (!(rx->flags & IEEE80211_RX_IN_SCAN)) |
1704 | return 0; | 1811 | return 0; |
1705 | rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; | 1812 | rx->flags &= ~IEEE80211_RX_RA_MATCH; |
1706 | } else if (!multicast && | 1813 | } else if (!multicast && |
1707 | compare_ether_addr(sdata->dev->dev_addr, | 1814 | compare_ether_addr(sdata->dev->dev_addr, |
1708 | hdr->addr1) != 0) { | 1815 | hdr->addr1) != 0) { |
1709 | if (!(sdata->dev->flags & IFF_PROMISC)) | 1816 | if (!(sdata->dev->flags & IFF_PROMISC)) |
1710 | return 0; | 1817 | return 0; |
1711 | rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; | 1818 | rx->flags &= ~IEEE80211_RX_RA_MATCH; |
1712 | } else if (!rx->sta) | 1819 | } else if (!rx->sta) |
1713 | rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb, | 1820 | rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb, |
1714 | bssid, hdr->addr2); | 1821 | bssid, hdr->addr2); |
1715 | break; | 1822 | break; |
1823 | case IEEE80211_IF_TYPE_MESH_POINT: | ||
1824 | if (!multicast && | ||
1825 | compare_ether_addr(sdata->dev->dev_addr, | ||
1826 | hdr->addr1) != 0) { | ||
1827 | if (!(sdata->dev->flags & IFF_PROMISC)) | ||
1828 | return 0; | ||
1829 | |||
1830 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | ||
1831 | } | ||
1832 | break; | ||
1716 | case IEEE80211_IF_TYPE_VLAN: | 1833 | case IEEE80211_IF_TYPE_VLAN: |
1717 | case IEEE80211_IF_TYPE_AP: | 1834 | case IEEE80211_IF_TYPE_AP: |
1718 | if (!bssid) { | 1835 | if (!bssid) { |
@@ -1721,12 +1838,12 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
1721 | return 0; | 1838 | return 0; |
1722 | } else if (!ieee80211_bssid_match(bssid, | 1839 | } else if (!ieee80211_bssid_match(bssid, |
1723 | sdata->dev->dev_addr)) { | 1840 | sdata->dev->dev_addr)) { |
1724 | if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) | 1841 | if (!(rx->flags & IEEE80211_RX_IN_SCAN)) |
1725 | return 0; | 1842 | return 0; |
1726 | rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; | 1843 | rx->flags &= ~IEEE80211_RX_RA_MATCH; |
1727 | } | 1844 | } |
1728 | if (sdata->dev == sdata->local->mdev && | 1845 | if (sdata->dev == sdata->local->mdev && |
1729 | !(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) | 1846 | !(rx->flags & IEEE80211_RX_IN_SCAN)) |
1730 | /* do not receive anything via | 1847 | /* do not receive anything via |
1731 | * master device when not scanning */ | 1848 | * master device when not scanning */ |
1732 | return 0; | 1849 | return 0; |
@@ -1763,7 +1880,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
1763 | struct ieee80211_local *local = hw_to_local(hw); | 1880 | struct ieee80211_local *local = hw_to_local(hw); |
1764 | struct ieee80211_sub_if_data *sdata; | 1881 | struct ieee80211_sub_if_data *sdata; |
1765 | struct ieee80211_hdr *hdr; | 1882 | struct ieee80211_hdr *hdr; |
1766 | struct ieee80211_txrx_data rx; | 1883 | struct ieee80211_rx_data rx; |
1767 | u16 type; | 1884 | u16 type; |
1768 | int prepares; | 1885 | int prepares; |
1769 | struct ieee80211_sub_if_data *prev = NULL; | 1886 | struct ieee80211_sub_if_data *prev = NULL; |
@@ -1775,9 +1892,9 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
1775 | rx.skb = skb; | 1892 | rx.skb = skb; |
1776 | rx.local = local; | 1893 | rx.local = local; |
1777 | 1894 | ||
1778 | rx.u.rx.status = status; | 1895 | rx.status = status; |
1779 | rx.u.rx.load = load; | 1896 | rx.load = load; |
1780 | rx.u.rx.rate = rate; | 1897 | rx.rate = rate; |
1781 | rx.fc = le16_to_cpu(hdr->frame_control); | 1898 | rx.fc = le16_to_cpu(hdr->frame_control); |
1782 | type = rx.fc & IEEE80211_FCTL_FTYPE; | 1899 | type = rx.fc & IEEE80211_FCTL_FTYPE; |
1783 | 1900 | ||
@@ -1786,17 +1903,17 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
1786 | 1903 | ||
1787 | rx.sta = sta_info_get(local, hdr->addr2); | 1904 | rx.sta = sta_info_get(local, hdr->addr2); |
1788 | if (rx.sta) { | 1905 | if (rx.sta) { |
1789 | rx.dev = rx.sta->dev; | 1906 | rx.sdata = rx.sta->sdata; |
1790 | rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); | 1907 | rx.dev = rx.sta->sdata->dev; |
1791 | } | 1908 | } |
1792 | 1909 | ||
1793 | if ((status->flag & RX_FLAG_MMIC_ERROR)) { | 1910 | if ((status->flag & RX_FLAG_MMIC_ERROR)) { |
1794 | ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx); | 1911 | ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx); |
1795 | goto end; | 1912 | return; |
1796 | } | 1913 | } |
1797 | 1914 | ||
1798 | if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning)) | 1915 | if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning)) |
1799 | rx.flags |= IEEE80211_TXRXD_RXIN_SCAN; | 1916 | rx.flags |= IEEE80211_RX_IN_SCAN; |
1800 | 1917 | ||
1801 | ieee80211_parse_qos(&rx); | 1918 | ieee80211_parse_qos(&rx); |
1802 | ieee80211_verify_ip_alignment(&rx); | 1919 | ieee80211_verify_ip_alignment(&rx); |
@@ -1811,7 +1928,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
1811 | continue; | 1928 | continue; |
1812 | 1929 | ||
1813 | bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type); | 1930 | bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type); |
1814 | rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; | 1931 | rx.flags |= IEEE80211_RX_RA_MATCH; |
1815 | prepares = prepare_for_handlers(sdata, bssid, &rx, hdr); | 1932 | prepares = prepare_for_handlers(sdata, bssid, &rx, hdr); |
1816 | 1933 | ||
1817 | if (!prepares) | 1934 | if (!prepares) |
@@ -1851,10 +1968,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
1851 | ieee80211_invoke_rx_handlers(prev, &rx, skb); | 1968 | ieee80211_invoke_rx_handlers(prev, &rx, skb); |
1852 | } else | 1969 | } else |
1853 | dev_kfree_skb(skb); | 1970 | dev_kfree_skb(skb); |
1854 | |||
1855 | end: | ||
1856 | if (rx.sta) | ||
1857 | sta_info_put(rx.sta); | ||
1858 | } | 1971 | } |
1859 | 1972 | ||
1860 | #define SEQ_MODULO 0x1000 | 1973 | #define SEQ_MODULO 0x1000 |
@@ -2031,7 +2144,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, | |||
2031 | /* if this mpdu is fragmented - terminate rx aggregation session */ | 2144 | /* if this mpdu is fragmented - terminate rx aggregation session */ |
2032 | sc = le16_to_cpu(hdr->seq_ctrl); | 2145 | sc = le16_to_cpu(hdr->seq_ctrl); |
2033 | if (sc & IEEE80211_SCTL_FRAG) { | 2146 | if (sc & IEEE80211_SCTL_FRAG) { |
2034 | ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr, | 2147 | ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr, |
2035 | tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); | 2148 | tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); |
2036 | ret = 1; | 2149 | ret = 1; |
2037 | goto end_reorder; | 2150 | goto end_reorder; |
@@ -2041,9 +2154,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, | |||
2041 | mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; | 2154 | mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; |
2042 | ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, | 2155 | ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, |
2043 | mpdu_seq_num, 0); | 2156 | mpdu_seq_num, 0); |
2044 | end_reorder: | 2157 | end_reorder: |
2045 | if (sta) | ||
2046 | sta_info_put(sta); | ||
2047 | return ret; | 2158 | return ret; |
2048 | } | 2159 | } |
2049 | 2160 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index e384e6632d97..3b84c16cf054 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -15,21 +15,52 @@ | |||
15 | #include <linux/skbuff.h> | 15 | #include <linux/skbuff.h> |
16 | #include <linux/if_arp.h> | 16 | #include <linux/if_arp.h> |
17 | #include <linux/timer.h> | 17 | #include <linux/timer.h> |
18 | #include <linux/rtnetlink.h> | ||
18 | 19 | ||
19 | #include <net/mac80211.h> | 20 | #include <net/mac80211.h> |
20 | #include "ieee80211_i.h" | 21 | #include "ieee80211_i.h" |
21 | #include "ieee80211_rate.h" | 22 | #include "ieee80211_rate.h" |
22 | #include "sta_info.h" | 23 | #include "sta_info.h" |
23 | #include "debugfs_sta.h" | 24 | #include "debugfs_sta.h" |
25 | #include "mesh.h" | ||
24 | 26 | ||
25 | /* Caller must hold local->sta_lock */ | 27 | /** |
26 | static void sta_info_hash_add(struct ieee80211_local *local, | 28 | * DOC: STA information lifetime rules |
27 | struct sta_info *sta) | 29 | * |
28 | { | 30 | * STA info structures (&struct sta_info) are managed in a hash table |
29 | sta->hnext = local->sta_hash[STA_HASH(sta->addr)]; | 31 | * for faster lookup and a list for iteration. They are managed using |
30 | local->sta_hash[STA_HASH(sta->addr)] = sta; | 32 | * RCU, i.e. access to the list and hash table is protected by RCU. |
31 | } | 33 | * |
32 | 34 | * Upon allocating a STA info structure with sta_info_alloc(), the caller owns | |
35 | * that structure. It must then either destroy it using sta_info_destroy() | ||
36 | * (which is pretty useless) or insert it into the hash table using | ||
37 | * sta_info_insert() which demotes the reference from ownership to a regular | ||
38 | * RCU-protected reference; if the function is called without protection by an | ||
39 | * RCU critical section the reference is instantly invalidated. | ||
40 | * | ||
41 | * Because there are debugfs entries for each station, and adding those | ||
42 | * must be able to sleep, it is also possible to "pin" a station entry, | ||
43 | * that means it can be removed from the hash table but not be freed. | ||
44 | * See the comment in __sta_info_unlink() for more information. | ||
45 | * | ||
46 | * In order to remove a STA info structure, the caller needs to first | ||
47 | * unlink it (sta_info_unlink()) from the list and hash tables and | ||
48 | * then wait for an RCU synchronisation before it can be freed. Due to | ||
49 | * the pinning and the possibility of multiple callers trying to remove | ||
50 | * the same STA info at the same time, sta_info_unlink() can clear the | ||
51 | * STA info pointer it is passed to indicate that the STA info is owned | ||
52 | * by somebody else now. | ||
53 | * | ||
54 | * If sta_info_unlink() did not clear the pointer then the caller owns | ||
55 | * the STA info structure now and is responsible of destroying it with | ||
56 | * a call to sta_info_destroy(), not before RCU synchronisation, of | ||
57 | * course. Note that sta_info_destroy() must be protected by the RTNL. | ||
58 | * | ||
59 | * In all other cases, there is no concept of ownership on a STA entry, | ||
60 | * each structure is owned by the global hash table/list until it is | ||
61 | * removed. All users of the structure need to be RCU protected so that | ||
62 | * the structure won't be freed before they are done using it. | ||
63 | */ | ||
33 | 64 | ||
34 | /* Caller must hold local->sta_lock */ | 65 | /* Caller must hold local->sta_lock */ |
35 | static int sta_info_hash_del(struct ieee80211_local *local, | 66 | static int sta_info_hash_del(struct ieee80211_local *local, |
@@ -41,109 +72,152 @@ static int sta_info_hash_del(struct ieee80211_local *local, | |||
41 | if (!s) | 72 | if (!s) |
42 | return -ENOENT; | 73 | return -ENOENT; |
43 | if (s == sta) { | 74 | if (s == sta) { |
44 | local->sta_hash[STA_HASH(sta->addr)] = s->hnext; | 75 | rcu_assign_pointer(local->sta_hash[STA_HASH(sta->addr)], |
76 | s->hnext); | ||
45 | return 0; | 77 | return 0; |
46 | } | 78 | } |
47 | 79 | ||
48 | while (s->hnext && s->hnext != sta) | 80 | while (s->hnext && s->hnext != sta) |
49 | s = s->hnext; | 81 | s = s->hnext; |
50 | if (s->hnext) { | 82 | if (s->hnext) { |
51 | s->hnext = sta->hnext; | 83 | rcu_assign_pointer(s->hnext, sta->hnext); |
52 | return 0; | 84 | return 0; |
53 | } | 85 | } |
54 | 86 | ||
55 | return -ENOENT; | 87 | return -ENOENT; |
56 | } | 88 | } |
57 | 89 | ||
58 | /* must hold local->sta_lock */ | 90 | /* protected by RCU */ |
59 | static struct sta_info *__sta_info_find(struct ieee80211_local *local, | 91 | static struct sta_info *__sta_info_find(struct ieee80211_local *local, |
60 | u8 *addr) | 92 | u8 *addr) |
61 | { | 93 | { |
62 | struct sta_info *sta; | 94 | struct sta_info *sta; |
63 | 95 | ||
64 | sta = local->sta_hash[STA_HASH(addr)]; | 96 | sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]); |
65 | while (sta) { | 97 | while (sta) { |
66 | if (compare_ether_addr(sta->addr, addr) == 0) | 98 | if (compare_ether_addr(sta->addr, addr) == 0) |
67 | break; | 99 | break; |
68 | sta = sta->hnext; | 100 | sta = rcu_dereference(sta->hnext); |
69 | } | 101 | } |
70 | return sta; | 102 | return sta; |
71 | } | 103 | } |
72 | 104 | ||
73 | struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) | 105 | struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) |
74 | { | 106 | { |
75 | struct sta_info *sta; | 107 | return __sta_info_find(local, addr); |
76 | |||
77 | read_lock_bh(&local->sta_lock); | ||
78 | sta = __sta_info_find(local, addr); | ||
79 | if (sta) | ||
80 | __sta_info_get(sta); | ||
81 | read_unlock_bh(&local->sta_lock); | ||
82 | |||
83 | return sta; | ||
84 | } | 108 | } |
85 | EXPORT_SYMBOL(sta_info_get); | 109 | EXPORT_SYMBOL(sta_info_get); |
86 | 110 | ||
111 | struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, | ||
112 | struct net_device *dev) | ||
113 | { | ||
114 | struct sta_info *sta; | ||
115 | int i = 0; | ||
116 | |||
117 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
118 | if (dev && dev != sta->sdata->dev) | ||
119 | continue; | ||
120 | if (i < idx) { | ||
121 | ++i; | ||
122 | continue; | ||
123 | } | ||
124 | return sta; | ||
125 | } | ||
126 | |||
127 | return NULL; | ||
128 | } | ||
87 | 129 | ||
88 | static void sta_info_release(struct kref *kref) | 130 | void sta_info_destroy(struct sta_info *sta) |
89 | { | 131 | { |
90 | struct sta_info *sta = container_of(kref, struct sta_info, kref); | ||
91 | struct ieee80211_local *local = sta->local; | 132 | struct ieee80211_local *local = sta->local; |
92 | struct sk_buff *skb; | 133 | struct sk_buff *skb; |
93 | int i; | 134 | int i; |
135 | DECLARE_MAC_BUF(mbuf); | ||
136 | |||
137 | if (!sta) | ||
138 | return; | ||
139 | |||
140 | ASSERT_RTNL(); | ||
141 | might_sleep(); | ||
142 | |||
143 | rate_control_remove_sta_debugfs(sta); | ||
144 | ieee80211_sta_debugfs_remove(sta); | ||
145 | |||
146 | #ifdef CONFIG_MAC80211_MESH | ||
147 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
148 | mesh_plink_deactivate(sta); | ||
149 | #endif | ||
150 | |||
151 | /* | ||
152 | * NOTE: This will call synchronize_rcu() internally to | ||
153 | * make sure no key references can be in use. We rely on | ||
154 | * that here for the mesh code! | ||
155 | */ | ||
156 | ieee80211_key_free(sta->key); | ||
157 | WARN_ON(sta->key); | ||
158 | |||
159 | #ifdef CONFIG_MAC80211_MESH | ||
160 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
161 | del_timer_sync(&sta->plink_timer); | ||
162 | #endif | ||
94 | 163 | ||
95 | /* free sta structure; it has already been removed from | ||
96 | * hash table etc. external structures. Make sure that all | ||
97 | * buffered frames are release (one might have been added | ||
98 | * after sta_info_free() was called). */ | ||
99 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { | 164 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { |
100 | local->total_ps_buffered--; | 165 | local->total_ps_buffered--; |
101 | dev_kfree_skb_any(skb); | 166 | dev_kfree_skb_any(skb); |
102 | } | 167 | } |
103 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { | 168 | |
169 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) | ||
104 | dev_kfree_skb_any(skb); | 170 | dev_kfree_skb_any(skb); |
105 | } | 171 | |
106 | for (i = 0; i < STA_TID_NUM; i++) { | 172 | for (i = 0; i < STA_TID_NUM; i++) { |
107 | del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer); | 173 | del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer); |
108 | del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); | 174 | del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); |
109 | } | 175 | } |
110 | rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); | 176 | rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); |
111 | rate_control_put(sta->rate_ctrl); | 177 | rate_control_put(sta->rate_ctrl); |
178 | |||
179 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
180 | printk(KERN_DEBUG "%s: Destroyed STA %s\n", | ||
181 | wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->addr)); | ||
182 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
183 | |||
112 | kfree(sta); | 184 | kfree(sta); |
113 | } | 185 | } |
114 | 186 | ||
115 | 187 | ||
116 | void sta_info_put(struct sta_info *sta) | 188 | /* Caller must hold local->sta_lock */ |
189 | static void sta_info_hash_add(struct ieee80211_local *local, | ||
190 | struct sta_info *sta) | ||
117 | { | 191 | { |
118 | kref_put(&sta->kref, sta_info_release); | 192 | sta->hnext = local->sta_hash[STA_HASH(sta->addr)]; |
193 | rcu_assign_pointer(local->sta_hash[STA_HASH(sta->addr)], sta); | ||
119 | } | 194 | } |
120 | EXPORT_SYMBOL(sta_info_put); | ||
121 | 195 | ||
122 | 196 | struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |
123 | struct sta_info *sta_info_add(struct ieee80211_local *local, | 197 | u8 *addr, gfp_t gfp) |
124 | struct net_device *dev, u8 *addr, gfp_t gfp) | ||
125 | { | 198 | { |
199 | struct ieee80211_local *local = sdata->local; | ||
126 | struct sta_info *sta; | 200 | struct sta_info *sta; |
127 | int i; | 201 | int i; |
128 | DECLARE_MAC_BUF(mac); | 202 | DECLARE_MAC_BUF(mbuf); |
129 | 203 | ||
130 | sta = kzalloc(sizeof(*sta), gfp); | 204 | sta = kzalloc(sizeof(*sta), gfp); |
131 | if (!sta) | 205 | if (!sta) |
132 | return ERR_PTR(-ENOMEM); | 206 | return NULL; |
133 | 207 | ||
134 | kref_init(&sta->kref); | 208 | memcpy(sta->addr, addr, ETH_ALEN); |
209 | sta->local = local; | ||
210 | sta->sdata = sdata; | ||
135 | 211 | ||
136 | sta->rate_ctrl = rate_control_get(local->rate_ctrl); | 212 | sta->rate_ctrl = rate_control_get(local->rate_ctrl); |
137 | sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp); | 213 | sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, |
214 | gfp); | ||
138 | if (!sta->rate_ctrl_priv) { | 215 | if (!sta->rate_ctrl_priv) { |
139 | rate_control_put(sta->rate_ctrl); | 216 | rate_control_put(sta->rate_ctrl); |
140 | kfree(sta); | 217 | kfree(sta); |
141 | return ERR_PTR(-ENOMEM); | 218 | return NULL; |
142 | } | 219 | } |
143 | 220 | ||
144 | memcpy(sta->addr, addr, ETH_ALEN); | ||
145 | sta->local = local; | ||
146 | sta->dev = dev; | ||
147 | spin_lock_init(&sta->ampdu_mlme.ampdu_rx); | 221 | spin_lock_init(&sta->ampdu_mlme.ampdu_rx); |
148 | spin_lock_init(&sta->ampdu_mlme.ampdu_tx); | 222 | spin_lock_init(&sta->ampdu_mlme.ampdu_tx); |
149 | for (i = 0; i < STA_TID_NUM; i++) { | 223 | for (i = 0; i < STA_TID_NUM; i++) { |
@@ -168,35 +242,68 @@ struct sta_info *sta_info_add(struct ieee80211_local *local, | |||
168 | } | 242 | } |
169 | skb_queue_head_init(&sta->ps_tx_buf); | 243 | skb_queue_head_init(&sta->ps_tx_buf); |
170 | skb_queue_head_init(&sta->tx_filtered); | 244 | skb_queue_head_init(&sta->tx_filtered); |
171 | write_lock_bh(&local->sta_lock); | 245 | |
172 | /* mark sta as used (by caller) */ | 246 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
173 | __sta_info_get(sta); | 247 | printk(KERN_DEBUG "%s: Allocated STA %s\n", |
248 | wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->addr)); | ||
249 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
250 | |||
251 | #ifdef CONFIG_MAC80211_MESH | ||
252 | sta->plink_state = PLINK_LISTEN; | ||
253 | spin_lock_init(&sta->plink_lock); | ||
254 | init_timer(&sta->plink_timer); | ||
255 | #endif | ||
256 | |||
257 | return sta; | ||
258 | } | ||
259 | |||
260 | int sta_info_insert(struct sta_info *sta) | ||
261 | { | ||
262 | struct ieee80211_local *local = sta->local; | ||
263 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
264 | unsigned long flags; | ||
265 | DECLARE_MAC_BUF(mac); | ||
266 | |||
267 | /* | ||
268 | * Can't be a WARN_ON because it can be triggered through a race: | ||
269 | * something inserts a STA (on one CPU) without holding the RTNL | ||
270 | * and another CPU turns off the net device. | ||
271 | */ | ||
272 | if (unlikely(!netif_running(sdata->dev))) | ||
273 | return -ENETDOWN; | ||
274 | |||
275 | if (WARN_ON(compare_ether_addr(sta->addr, sdata->dev->dev_addr) == 0)) | ||
276 | return -EINVAL; | ||
277 | |||
278 | if (WARN_ON(is_multicast_ether_addr(sta->addr))) | ||
279 | return -EINVAL; | ||
280 | |||
281 | spin_lock_irqsave(&local->sta_lock, flags); | ||
174 | /* check if STA exists already */ | 282 | /* check if STA exists already */ |
175 | if (__sta_info_find(local, addr)) { | 283 | if (__sta_info_find(local, sta->addr)) { |
176 | write_unlock_bh(&local->sta_lock); | 284 | spin_unlock_irqrestore(&local->sta_lock, flags); |
177 | sta_info_put(sta); | 285 | return -EEXIST; |
178 | return ERR_PTR(-EEXIST); | ||
179 | } | 286 | } |
180 | list_add(&sta->list, &local->sta_list); | 287 | list_add(&sta->list, &local->sta_list); |
181 | local->num_sta++; | 288 | local->num_sta++; |
182 | sta_info_hash_add(local, sta); | 289 | sta_info_hash_add(local, sta); |
183 | if (local->ops->sta_notify) { | ||
184 | struct ieee80211_sub_if_data *sdata; | ||
185 | 290 | ||
186 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 291 | /* notify driver */ |
292 | if (local->ops->sta_notify) { | ||
187 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) | 293 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) |
188 | sdata = sdata->u.vlan.ap; | 294 | sdata = sdata->u.vlan.ap; |
189 | 295 | ||
190 | local->ops->sta_notify(local_to_hw(local), &sdata->vif, | 296 | local->ops->sta_notify(local_to_hw(local), &sdata->vif, |
191 | STA_NOTIFY_ADD, addr); | 297 | STA_NOTIFY_ADD, sta->addr); |
192 | } | 298 | } |
193 | write_unlock_bh(&local->sta_lock); | ||
194 | 299 | ||
195 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 300 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
196 | printk(KERN_DEBUG "%s: Added STA %s\n", | 301 | printk(KERN_DEBUG "%s: Inserted STA %s\n", |
197 | wiphy_name(local->hw.wiphy), print_mac(mac, addr)); | 302 | wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr)); |
198 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 303 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
199 | 304 | ||
305 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
306 | |||
200 | #ifdef CONFIG_MAC80211_DEBUGFS | 307 | #ifdef CONFIG_MAC80211_DEBUGFS |
201 | /* debugfs entry adding might sleep, so schedule process | 308 | /* debugfs entry adding might sleep, so schedule process |
202 | * context task for adding entry for STAs that do not yet | 309 | * context task for adding entry for STAs that do not yet |
@@ -204,7 +311,10 @@ struct sta_info *sta_info_add(struct ieee80211_local *local, | |||
204 | queue_work(local->hw.workqueue, &local->sta_debugfs_add); | 311 | queue_work(local->hw.workqueue, &local->sta_debugfs_add); |
205 | #endif | 312 | #endif |
206 | 313 | ||
207 | return sta; | 314 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
315 | mesh_accept_plinks_update(sdata); | ||
316 | |||
317 | return 0; | ||
208 | } | 318 | } |
209 | 319 | ||
210 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) | 320 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) |
@@ -230,19 +340,20 @@ static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss, | |||
230 | { | 340 | { |
231 | if (bss) | 341 | if (bss) |
232 | __bss_tim_set(bss, sta->aid); | 342 | __bss_tim_set(bss, sta->aid); |
233 | if (sta->local->ops->set_tim) | 343 | if (sta->local->ops->set_tim) { |
344 | sta->local->tim_in_locked_section = true; | ||
234 | sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1); | 345 | sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1); |
346 | sta->local->tim_in_locked_section = false; | ||
347 | } | ||
235 | } | 348 | } |
236 | 349 | ||
237 | void sta_info_set_tim_bit(struct sta_info *sta) | 350 | void sta_info_set_tim_bit(struct sta_info *sta) |
238 | { | 351 | { |
239 | struct ieee80211_sub_if_data *sdata; | 352 | unsigned long flags; |
240 | |||
241 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | ||
242 | 353 | ||
243 | read_lock_bh(&sta->local->sta_lock); | 354 | spin_lock_irqsave(&sta->local->sta_lock, flags); |
244 | __sta_info_set_tim_bit(sdata->bss, sta); | 355 | __sta_info_set_tim_bit(sta->sdata->bss, sta); |
245 | read_unlock_bh(&sta->local->sta_lock); | 356 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); |
246 | } | 357 | } |
247 | 358 | ||
248 | static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, | 359 | static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, |
@@ -250,88 +361,135 @@ static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, | |||
250 | { | 361 | { |
251 | if (bss) | 362 | if (bss) |
252 | __bss_tim_clear(bss, sta->aid); | 363 | __bss_tim_clear(bss, sta->aid); |
253 | if (sta->local->ops->set_tim) | 364 | if (sta->local->ops->set_tim) { |
365 | sta->local->tim_in_locked_section = true; | ||
254 | sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0); | 366 | sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0); |
367 | sta->local->tim_in_locked_section = false; | ||
368 | } | ||
255 | } | 369 | } |
256 | 370 | ||
257 | void sta_info_clear_tim_bit(struct sta_info *sta) | 371 | void sta_info_clear_tim_bit(struct sta_info *sta) |
258 | { | 372 | { |
259 | struct ieee80211_sub_if_data *sdata; | 373 | unsigned long flags; |
260 | 374 | ||
261 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 375 | spin_lock_irqsave(&sta->local->sta_lock, flags); |
376 | __sta_info_clear_tim_bit(sta->sdata->bss, sta); | ||
377 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); | ||
378 | } | ||
262 | 379 | ||
263 | read_lock_bh(&sta->local->sta_lock); | 380 | /* |
264 | __sta_info_clear_tim_bit(sdata->bss, sta); | 381 | * See comment in __sta_info_unlink, |
265 | read_unlock_bh(&sta->local->sta_lock); | 382 | * caller must hold local->sta_lock. |
383 | */ | ||
384 | static void __sta_info_pin(struct sta_info *sta) | ||
385 | { | ||
386 | WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_NORMAL); | ||
387 | sta->pin_status = STA_INFO_PIN_STAT_PINNED; | ||
266 | } | 388 | } |
267 | 389 | ||
268 | /* Caller must hold local->sta_lock */ | 390 | /* |
269 | void sta_info_remove(struct sta_info *sta) | 391 | * See comment in __sta_info_unlink, returns sta if it |
392 | * needs to be destroyed. | ||
393 | */ | ||
394 | static struct sta_info *__sta_info_unpin(struct sta_info *sta) | ||
270 | { | 395 | { |
271 | struct ieee80211_local *local = sta->local; | 396 | struct sta_info *ret = NULL; |
272 | struct ieee80211_sub_if_data *sdata; | 397 | unsigned long flags; |
273 | 398 | ||
274 | /* don't do anything if we've been removed already */ | 399 | spin_lock_irqsave(&sta->local->sta_lock, flags); |
275 | if (sta_info_hash_del(local, sta)) | 400 | WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_DESTROY && |
276 | return; | 401 | sta->pin_status != STA_INFO_PIN_STAT_PINNED); |
402 | if (sta->pin_status == STA_INFO_PIN_STAT_DESTROY) | ||
403 | ret = sta; | ||
404 | sta->pin_status = STA_INFO_PIN_STAT_NORMAL; | ||
405 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); | ||
277 | 406 | ||
278 | list_del(&sta->list); | 407 | return ret; |
279 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | ||
280 | if (sta->flags & WLAN_STA_PS) { | ||
281 | sta->flags &= ~WLAN_STA_PS; | ||
282 | if (sdata->bss) | ||
283 | atomic_dec(&sdata->bss->num_sta_ps); | ||
284 | __sta_info_clear_tim_bit(sdata->bss, sta); | ||
285 | } | ||
286 | local->num_sta--; | ||
287 | } | 408 | } |
288 | 409 | ||
289 | void sta_info_free(struct sta_info *sta) | 410 | static void __sta_info_unlink(struct sta_info **sta) |
290 | { | 411 | { |
291 | struct sk_buff *skb; | 412 | struct ieee80211_local *local = (*sta)->local; |
292 | struct ieee80211_local *local = sta->local; | 413 | struct ieee80211_sub_if_data *sdata = (*sta)->sdata; |
293 | DECLARE_MAC_BUF(mac); | 414 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
415 | DECLARE_MAC_BUF(mbuf); | ||
416 | #endif | ||
417 | /* | ||
418 | * pull caller's reference if we're already gone. | ||
419 | */ | ||
420 | if (sta_info_hash_del(local, *sta)) { | ||
421 | *sta = NULL; | ||
422 | return; | ||
423 | } | ||
294 | 424 | ||
295 | might_sleep(); | 425 | /* |
426 | * Also pull caller's reference if the STA is pinned by the | ||
427 | * task that is adding the debugfs entries. In that case, we | ||
428 | * leave the STA "to be freed". | ||
429 | * | ||
430 | * The rules are not trivial, but not too complex either: | ||
431 | * (1) pin_status is only modified under the sta_lock | ||
432 | * (2) sta_info_debugfs_add_work() will set the status | ||
433 | * to PINNED when it found an item that needs a new | ||
434 | * debugfs directory created. In that case, that item | ||
435 | * must not be freed although all *RCU* users are done | ||
436 | * with it. Hence, we tell the caller of _unlink() | ||
437 | * that the item is already gone (as can happen when | ||
438 | * two tasks try to unlink/destroy at the same time) | ||
439 | * (3) We set the pin_status to DESTROY here when we | ||
440 | * find such an item. | ||
441 | * (4) sta_info_debugfs_add_work() will reset the pin_status | ||
442 | * from PINNED to NORMAL when it is done with the item, | ||
443 | * but will check for DESTROY before resetting it in | ||
444 | * which case it will free the item. | ||
445 | */ | ||
446 | if ((*sta)->pin_status == STA_INFO_PIN_STAT_PINNED) { | ||
447 | (*sta)->pin_status = STA_INFO_PIN_STAT_DESTROY; | ||
448 | *sta = NULL; | ||
449 | return; | ||
450 | } | ||
296 | 451 | ||
297 | write_lock_bh(&local->sta_lock); | 452 | list_del(&(*sta)->list); |
298 | sta_info_remove(sta); | ||
299 | write_unlock_bh(&local->sta_lock); | ||
300 | 453 | ||
301 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { | 454 | if ((*sta)->flags & WLAN_STA_PS) { |
302 | local->total_ps_buffered--; | 455 | (*sta)->flags &= ~WLAN_STA_PS; |
303 | dev_kfree_skb(skb); | 456 | if (sdata->bss) |
304 | } | 457 | atomic_dec(&sdata->bss->num_sta_ps); |
305 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { | 458 | __sta_info_clear_tim_bit(sdata->bss, *sta); |
306 | dev_kfree_skb(skb); | ||
307 | } | 459 | } |
308 | 460 | ||
309 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 461 | local->num_sta--; |
310 | printk(KERN_DEBUG "%s: Removed STA %s\n", | ||
311 | wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr)); | ||
312 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
313 | |||
314 | ieee80211_key_free(sta->key); | ||
315 | WARN_ON(sta->key); | ||
316 | 462 | ||
317 | if (local->ops->sta_notify) { | 463 | if (local->ops->sta_notify) { |
318 | struct ieee80211_sub_if_data *sdata; | ||
319 | |||
320 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | ||
321 | |||
322 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) | 464 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) |
323 | sdata = sdata->u.vlan.ap; | 465 | sdata = sdata->u.vlan.ap; |
324 | 466 | ||
325 | local->ops->sta_notify(local_to_hw(local), &sdata->vif, | 467 | local->ops->sta_notify(local_to_hw(local), &sdata->vif, |
326 | STA_NOTIFY_REMOVE, sta->addr); | 468 | STA_NOTIFY_REMOVE, (*sta)->addr); |
327 | } | 469 | } |
328 | 470 | ||
329 | rate_control_remove_sta_debugfs(sta); | 471 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
330 | ieee80211_sta_debugfs_remove(sta); | 472 | mesh_accept_plinks_update(sdata); |
473 | #ifdef CONFIG_MAC80211_MESH | ||
474 | del_timer(&(*sta)->plink_timer); | ||
475 | #endif | ||
476 | } | ||
331 | 477 | ||
332 | sta_info_put(sta); | 478 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
479 | printk(KERN_DEBUG "%s: Removed STA %s\n", | ||
480 | wiphy_name(local->hw.wiphy), print_mac(mbuf, (*sta)->addr)); | ||
481 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
333 | } | 482 | } |
334 | 483 | ||
484 | void sta_info_unlink(struct sta_info **sta) | ||
485 | { | ||
486 | struct ieee80211_local *local = (*sta)->local; | ||
487 | unsigned long flags; | ||
488 | |||
489 | spin_lock_irqsave(&local->sta_lock, flags); | ||
490 | __sta_info_unlink(sta); | ||
491 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
492 | } | ||
335 | 493 | ||
336 | static inline int sta_info_buffer_expired(struct ieee80211_local *local, | 494 | static inline int sta_info_buffer_expired(struct ieee80211_local *local, |
337 | struct sta_info *sta, | 495 | struct sta_info *sta, |
@@ -377,7 +535,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
377 | if (!skb) | 535 | if (!skb) |
378 | break; | 536 | break; |
379 | 537 | ||
380 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 538 | sdata = sta->sdata; |
381 | local->total_ps_buffered--; | 539 | local->total_ps_buffered--; |
382 | printk(KERN_DEBUG "Buffered frame expired (STA " | 540 | printk(KERN_DEBUG "Buffered frame expired (STA " |
383 | "%s)\n", print_mac(mac, sta->addr)); | 541 | "%s)\n", print_mac(mac, sta->addr)); |
@@ -394,13 +552,10 @@ static void sta_info_cleanup(unsigned long data) | |||
394 | struct ieee80211_local *local = (struct ieee80211_local *) data; | 552 | struct ieee80211_local *local = (struct ieee80211_local *) data; |
395 | struct sta_info *sta; | 553 | struct sta_info *sta; |
396 | 554 | ||
397 | read_lock_bh(&local->sta_lock); | 555 | rcu_read_lock(); |
398 | list_for_each_entry(sta, &local->sta_list, list) { | 556 | list_for_each_entry_rcu(sta, &local->sta_list, list) |
399 | __sta_info_get(sta); | ||
400 | sta_info_cleanup_expire_buffered(local, sta); | 557 | sta_info_cleanup_expire_buffered(local, sta); |
401 | sta_info_put(sta); | 558 | rcu_read_unlock(); |
402 | } | ||
403 | read_unlock_bh(&local->sta_lock); | ||
404 | 559 | ||
405 | local->sta_cleanup.expires = | 560 | local->sta_cleanup.expires = |
406 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 561 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); |
@@ -408,37 +563,45 @@ static void sta_info_cleanup(unsigned long data) | |||
408 | } | 563 | } |
409 | 564 | ||
410 | #ifdef CONFIG_MAC80211_DEBUGFS | 565 | #ifdef CONFIG_MAC80211_DEBUGFS |
411 | static void sta_info_debugfs_add_task(struct work_struct *work) | 566 | static void sta_info_debugfs_add_work(struct work_struct *work) |
412 | { | 567 | { |
413 | struct ieee80211_local *local = | 568 | struct ieee80211_local *local = |
414 | container_of(work, struct ieee80211_local, sta_debugfs_add); | 569 | container_of(work, struct ieee80211_local, sta_debugfs_add); |
415 | struct sta_info *sta, *tmp; | 570 | struct sta_info *sta, *tmp; |
571 | unsigned long flags; | ||
416 | 572 | ||
417 | while (1) { | 573 | while (1) { |
418 | sta = NULL; | 574 | sta = NULL; |
419 | read_lock_bh(&local->sta_lock); | 575 | |
576 | spin_lock_irqsave(&local->sta_lock, flags); | ||
420 | list_for_each_entry(tmp, &local->sta_list, list) { | 577 | list_for_each_entry(tmp, &local->sta_list, list) { |
421 | if (!tmp->debugfs.dir) { | 578 | if (!tmp->debugfs.dir) { |
422 | sta = tmp; | 579 | sta = tmp; |
423 | __sta_info_get(sta); | 580 | __sta_info_pin(sta); |
424 | break; | 581 | break; |
425 | } | 582 | } |
426 | } | 583 | } |
427 | read_unlock_bh(&local->sta_lock); | 584 | spin_unlock_irqrestore(&local->sta_lock, flags); |
428 | 585 | ||
429 | if (!sta) | 586 | if (!sta) |
430 | break; | 587 | break; |
431 | 588 | ||
432 | ieee80211_sta_debugfs_add(sta); | 589 | ieee80211_sta_debugfs_add(sta); |
433 | rate_control_add_sta_debugfs(sta); | 590 | rate_control_add_sta_debugfs(sta); |
434 | sta_info_put(sta); | 591 | |
592 | sta = __sta_info_unpin(sta); | ||
593 | |||
594 | if (sta) { | ||
595 | synchronize_rcu(); | ||
596 | sta_info_destroy(sta); | ||
597 | } | ||
435 | } | 598 | } |
436 | } | 599 | } |
437 | #endif | 600 | #endif |
438 | 601 | ||
439 | void sta_info_init(struct ieee80211_local *local) | 602 | void sta_info_init(struct ieee80211_local *local) |
440 | { | 603 | { |
441 | rwlock_init(&local->sta_lock); | 604 | spin_lock_init(&local->sta_lock); |
442 | INIT_LIST_HEAD(&local->sta_list); | 605 | INIT_LIST_HEAD(&local->sta_list); |
443 | 606 | ||
444 | setup_timer(&local->sta_cleanup, sta_info_cleanup, | 607 | setup_timer(&local->sta_cleanup, sta_info_cleanup, |
@@ -447,7 +610,7 @@ void sta_info_init(struct ieee80211_local *local) | |||
447 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 610 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); |
448 | 611 | ||
449 | #ifdef CONFIG_MAC80211_DEBUGFS | 612 | #ifdef CONFIG_MAC80211_DEBUGFS |
450 | INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_task); | 613 | INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_work); |
451 | #endif | 614 | #endif |
452 | } | 615 | } |
453 | 616 | ||
@@ -465,25 +628,38 @@ void sta_info_stop(struct ieee80211_local *local) | |||
465 | 628 | ||
466 | /** | 629 | /** |
467 | * sta_info_flush - flush matching STA entries from the STA table | 630 | * sta_info_flush - flush matching STA entries from the STA table |
631 | * | ||
632 | * Returns the number of removed STA entries. | ||
633 | * | ||
468 | * @local: local interface data | 634 | * @local: local interface data |
469 | * @dev: matching rule for the net device (sta->dev) or %NULL to match all STAs | 635 | * @sdata: matching rule for the net device (sta->dev) or %NULL to match all STAs |
470 | */ | 636 | */ |
471 | void sta_info_flush(struct ieee80211_local *local, struct net_device *dev) | 637 | int sta_info_flush(struct ieee80211_local *local, |
638 | struct ieee80211_sub_if_data *sdata) | ||
472 | { | 639 | { |
473 | struct sta_info *sta, *tmp; | 640 | struct sta_info *sta, *tmp; |
474 | LIST_HEAD(tmp_list); | 641 | LIST_HEAD(tmp_list); |
642 | int ret = 0; | ||
643 | unsigned long flags; | ||
475 | 644 | ||
476 | write_lock_bh(&local->sta_lock); | 645 | might_sleep(); |
477 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) | ||
478 | if (!dev || dev == sta->dev) { | ||
479 | __sta_info_get(sta); | ||
480 | sta_info_remove(sta); | ||
481 | list_add_tail(&sta->list, &tmp_list); | ||
482 | } | ||
483 | write_unlock_bh(&local->sta_lock); | ||
484 | 646 | ||
485 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) { | 647 | spin_lock_irqsave(&local->sta_lock, flags); |
486 | sta_info_free(sta); | 648 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { |
487 | sta_info_put(sta); | 649 | if (!sdata || sdata == sta->sdata) { |
650 | __sta_info_unlink(&sta); | ||
651 | if (sta) { | ||
652 | list_add_tail(&sta->list, &tmp_list); | ||
653 | ret++; | ||
654 | } | ||
655 | } | ||
488 | } | 656 | } |
657 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
658 | |||
659 | synchronize_rcu(); | ||
660 | |||
661 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) | ||
662 | sta_info_destroy(sta); | ||
663 | |||
664 | return ret; | ||
489 | } | 665 | } |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 86eed40ada78..f166c8039f2b 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <linux/list.h> | 12 | #include <linux/list.h> |
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | #include <linux/if_ether.h> | 14 | #include <linux/if_ether.h> |
15 | #include <linux/kref.h> | ||
16 | #include "ieee80211_key.h" | 15 | #include "ieee80211_key.h" |
17 | 16 | ||
18 | /** | 17 | /** |
@@ -108,6 +107,29 @@ struct tid_ampdu_rx { | |||
108 | }; | 107 | }; |
109 | 108 | ||
110 | /** | 109 | /** |
110 | * enum plink_state - state of a mesh peer link finite state machine | ||
111 | * | ||
112 | * @PLINK_LISTEN: initial state, considered the implicit state of non existant | ||
113 | * mesh peer links | ||
114 | * @PLINK_OPN_SNT: mesh plink open frame has been sent to this mesh peer | ||
115 | * @PLINK_OPN_RCVD: mesh plink open frame has been received from this mesh peer | ||
116 | * @PLINK_CNF_RCVD: mesh plink confirm frame has been received from this mesh | ||
117 | * peer | ||
118 | * @PLINK_ESTAB: mesh peer link is established | ||
119 | * @PLINK_HOLDING: mesh peer link is being closed or cancelled | ||
120 | * @PLINK_BLOCKED: all frames transmitted from this mesh plink are discarded | ||
121 | */ | ||
122 | enum plink_state { | ||
123 | PLINK_LISTEN, | ||
124 | PLINK_OPN_SNT, | ||
125 | PLINK_OPN_RCVD, | ||
126 | PLINK_CNF_RCVD, | ||
127 | PLINK_ESTAB, | ||
128 | PLINK_HOLDING, | ||
129 | PLINK_BLOCKED | ||
130 | }; | ||
131 | |||
132 | /** | ||
111 | * struct sta_ampdu_mlme - STA aggregation information. | 133 | * struct sta_ampdu_mlme - STA aggregation information. |
112 | * | 134 | * |
113 | * @tid_rx: aggregation info for Rx per TID | 135 | * @tid_rx: aggregation info for Rx per TID |
@@ -124,75 +146,132 @@ struct sta_ampdu_mlme { | |||
124 | u8 dialog_token_allocator; | 146 | u8 dialog_token_allocator; |
125 | }; | 147 | }; |
126 | 148 | ||
149 | |||
150 | /* see __sta_info_unlink */ | ||
151 | #define STA_INFO_PIN_STAT_NORMAL 0 | ||
152 | #define STA_INFO_PIN_STAT_PINNED 1 | ||
153 | #define STA_INFO_PIN_STAT_DESTROY 2 | ||
154 | |||
155 | /** | ||
156 | * struct sta_info - STA information | ||
157 | * | ||
158 | * This structure collects information about a station that | ||
159 | * mac80211 is communicating with. | ||
160 | * | ||
161 | * @list: global linked list entry | ||
162 | * @hnext: hash table linked list pointer | ||
163 | * @local: pointer to the global information | ||
164 | * @addr: MAC address of this STA | ||
165 | * @aid: STA's unique AID (1..2007, 0 = not assigned yet), | ||
166 | * only used in AP (and IBSS?) mode | ||
167 | * @flags: STA flags, see &enum ieee80211_sta_info_flags | ||
168 | * @ps_tx_buf: buffer of frames to transmit to this station | ||
169 | * when it leaves power saving state | ||
170 | * @tx_filtered: buffer of frames we already tried to transmit | ||
171 | * but were filtered by hardware due to STA having entered | ||
172 | * power saving state | ||
173 | * @rx_packets: Number of MSDUs received from this STA | ||
174 | * @rx_bytes: Number of bytes received from this STA | ||
175 | * @supp_rates: Bitmap of supported rates (per band) | ||
176 | * @ht_info: HT capabilities of this STA | ||
177 | */ | ||
127 | struct sta_info { | 178 | struct sta_info { |
128 | struct kref kref; | 179 | /* General information, mostly static */ |
129 | struct list_head list; | 180 | struct list_head list; |
130 | struct sta_info *hnext; /* next entry in hash table list */ | 181 | struct sta_info *hnext; |
131 | |||
132 | struct ieee80211_local *local; | 182 | struct ieee80211_local *local; |
133 | 183 | struct ieee80211_sub_if_data *sdata; | |
134 | u8 addr[ETH_ALEN]; | ||
135 | u16 aid; /* STA's unique AID (1..2007), 0 = not yet assigned */ | ||
136 | u32 flags; /* WLAN_STA_ */ | ||
137 | |||
138 | struct sk_buff_head ps_tx_buf; /* buffer of TX frames for station in | ||
139 | * power saving state */ | ||
140 | struct sk_buff_head tx_filtered; /* buffer of TX frames that were | ||
141 | * already given to low-level driver, | ||
142 | * but were filtered */ | ||
143 | unsigned long rx_packets, tx_packets; /* number of RX/TX MSDUs */ | ||
144 | unsigned long rx_bytes, tx_bytes; | ||
145 | unsigned long tx_retry_failed, tx_retry_count; | ||
146 | unsigned long tx_filtered_count; | ||
147 | |||
148 | unsigned int wep_weak_iv_count; /* number of RX frames with weak IV */ | ||
149 | |||
150 | unsigned long last_rx; | ||
151 | /* bitmap of supported rates per band */ | ||
152 | u64 supp_rates[IEEE80211_NUM_BANDS]; | ||
153 | int txrate_idx; | ||
154 | /* last rates used to send a frame to this STA */ | ||
155 | int last_txrate_idx, last_nonerp_txrate_idx; | ||
156 | |||
157 | struct net_device *dev; /* which net device is this station associated | ||
158 | * to */ | ||
159 | |||
160 | struct ieee80211_key *key; | 184 | struct ieee80211_key *key; |
161 | |||
162 | u32 tx_num_consecutive_failures; | ||
163 | u32 tx_num_mpdu_ok; | ||
164 | u32 tx_num_mpdu_fail; | ||
165 | |||
166 | struct rate_control_ref *rate_ctrl; | 185 | struct rate_control_ref *rate_ctrl; |
167 | void *rate_ctrl_priv; | 186 | void *rate_ctrl_priv; |
187 | struct ieee80211_ht_info ht_info; | ||
188 | u64 supp_rates[IEEE80211_NUM_BANDS]; | ||
189 | u8 addr[ETH_ALEN]; | ||
190 | u16 aid; | ||
191 | u16 listen_interval; | ||
168 | 192 | ||
169 | /* last received seq/frag number from this STA (per RX queue) */ | 193 | /* |
170 | __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; | 194 | * for use by the internal lifetime management, |
195 | * see __sta_info_unlink | ||
196 | */ | ||
197 | u8 pin_status; | ||
198 | |||
199 | /* frequently updated information, needs locking? */ | ||
200 | u32 flags; | ||
201 | |||
202 | /* | ||
203 | * STA powersave frame queues, no more than the internal | ||
204 | * locking required. | ||
205 | */ | ||
206 | struct sk_buff_head ps_tx_buf; | ||
207 | struct sk_buff_head tx_filtered; | ||
208 | |||
209 | /* Updated from RX path only, no locking requirements */ | ||
210 | unsigned long rx_packets, rx_bytes; | ||
211 | unsigned long wep_weak_iv_count; | ||
212 | unsigned long last_rx; | ||
171 | unsigned long num_duplicates; /* number of duplicate frames received | 213 | unsigned long num_duplicates; /* number of duplicate frames received |
172 | * from this STA */ | 214 | * from this STA */ |
173 | unsigned long tx_fragments; /* number of transmitted MPDUs */ | ||
174 | unsigned long rx_fragments; /* number of received MPDUs */ | 215 | unsigned long rx_fragments; /* number of received MPDUs */ |
175 | unsigned long rx_dropped; /* number of dropped MPDUs from this STA */ | 216 | unsigned long rx_dropped; /* number of dropped MPDUs from this STA */ |
176 | |||
177 | int last_rssi; /* RSSI of last received frame from this STA */ | 217 | int last_rssi; /* RSSI of last received frame from this STA */ |
178 | int last_signal; /* signal of last received frame from this STA */ | 218 | int last_signal; /* signal of last received frame from this STA */ |
179 | int last_noise; /* noise of last received frame from this STA */ | 219 | int last_noise; /* noise of last received frame from this STA */ |
180 | int channel_use; | 220 | /* last received seq/frag number from this STA (per RX queue) */ |
181 | int channel_use_raw; | 221 | __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; |
182 | |||
183 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | 222 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS |
184 | unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES]; | 223 | unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES]; |
224 | #endif | ||
225 | |||
226 | /* Updated from TX status path only, no locking requirements */ | ||
227 | unsigned long tx_filtered_count; | ||
228 | unsigned long tx_retry_failed, tx_retry_count; | ||
229 | /* TODO: update in generic code not rate control? */ | ||
230 | u32 tx_num_consecutive_failures; | ||
231 | u32 tx_num_mpdu_ok; | ||
232 | u32 tx_num_mpdu_fail; | ||
233 | /* moving percentage of failed MSDUs */ | ||
234 | unsigned int fail_avg; | ||
235 | |||
236 | /* Updated from TX path only, no locking requirements */ | ||
237 | unsigned long tx_packets; /* number of RX/TX MSDUs */ | ||
238 | unsigned long tx_bytes; | ||
239 | unsigned long tx_fragments; /* number of transmitted MPDUs */ | ||
240 | int txrate_idx; | ||
241 | int last_txrate_idx; | ||
242 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | ||
185 | unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES]; | 243 | unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES]; |
186 | #endif /* CONFIG_MAC80211_DEBUG_COUNTERS */ | 244 | #endif |
187 | 245 | ||
188 | u16 listen_interval; | 246 | /* Debug counters, no locking doesn't matter */ |
247 | int channel_use; | ||
248 | int channel_use_raw; | ||
189 | 249 | ||
190 | struct ieee80211_ht_info ht_info; /* 802.11n HT capabilities | 250 | /* |
191 | of this STA */ | 251 | * Aggregation information, comes with own locking. |
252 | */ | ||
192 | struct sta_ampdu_mlme ampdu_mlme; | 253 | struct sta_ampdu_mlme ampdu_mlme; |
193 | u8 timer_to_tid[STA_TID_NUM]; /* convert timer id to tid */ | 254 | u8 timer_to_tid[STA_TID_NUM]; /* identity mapping to ID timers */ |
194 | u8 tid_to_tx_q[STA_TID_NUM]; /* map tid to tx queue */ | 255 | u8 tid_to_tx_q[STA_TID_NUM]; /* map tid to tx queue */ |
195 | 256 | ||
257 | #ifdef CONFIG_MAC80211_MESH | ||
258 | /* | ||
259 | * Mesh peer link attributes | ||
260 | * TODO: move to a sub-structure that is referenced with pointer? | ||
261 | */ | ||
262 | __le16 llid; /* Local link ID */ | ||
263 | __le16 plid; /* Peer link ID */ | ||
264 | __le16 reason; /* Cancel reason on PLINK_HOLDING state */ | ||
265 | u8 plink_retries; /* Retries in establishment */ | ||
266 | bool ignore_plink_timer; | ||
267 | enum plink_state plink_state; | ||
268 | u32 plink_timeout; | ||
269 | struct timer_list plink_timer; | ||
270 | spinlock_t plink_lock; /* For peer_state reads / updates and other | ||
271 | updates in the structure. Ensures robust | ||
272 | transitions for the peerlink FSM */ | ||
273 | #endif | ||
274 | |||
196 | #ifdef CONFIG_MAC80211_DEBUGFS | 275 | #ifdef CONFIG_MAC80211_DEBUGFS |
197 | struct sta_info_debugfsdentries { | 276 | struct sta_info_debugfsdentries { |
198 | struct dentry *dir; | 277 | struct dentry *dir; |
@@ -209,6 +288,14 @@ struct sta_info { | |||
209 | #endif | 288 | #endif |
210 | }; | 289 | }; |
211 | 290 | ||
291 | static inline enum plink_state sta_plink_state(struct sta_info *sta) | ||
292 | { | ||
293 | #ifdef CONFIG_MAC80211_MESH | ||
294 | return sta->plink_state; | ||
295 | #endif | ||
296 | return PLINK_LISTEN; | ||
297 | } | ||
298 | |||
212 | 299 | ||
213 | /* Maximum number of concurrently registered stations */ | 300 | /* Maximum number of concurrently registered stations */ |
214 | #define MAX_STA_COUNT 2007 | 301 | #define MAX_STA_COUNT 2007 |
@@ -228,23 +315,44 @@ struct sta_info { | |||
228 | */ | 315 | */ |
229 | #define STA_INFO_CLEANUP_INTERVAL (10 * HZ) | 316 | #define STA_INFO_CLEANUP_INTERVAL (10 * HZ) |
230 | 317 | ||
231 | static inline void __sta_info_get(struct sta_info *sta) | 318 | /* |
232 | { | 319 | * Get a STA info, must have be under RCU read lock. |
233 | kref_get(&sta->kref); | 320 | */ |
234 | } | 321 | struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr); |
322 | /* | ||
323 | * Get STA info by index, BROKEN! | ||
324 | */ | ||
325 | struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, | ||
326 | struct net_device *dev); | ||
327 | /* | ||
328 | * Create a new STA info, caller owns returned structure | ||
329 | * until sta_info_insert(). | ||
330 | */ | ||
331 | struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | ||
332 | u8 *addr, gfp_t gfp); | ||
333 | /* | ||
334 | * Insert STA info into hash table/list, returns zero or a | ||
335 | * -EEXIST if (if the same MAC address is already present). | ||
336 | * | ||
337 | * Calling this without RCU protection makes the caller | ||
338 | * relinquish its reference to @sta. | ||
339 | */ | ||
340 | int sta_info_insert(struct sta_info *sta); | ||
341 | /* | ||
342 | * Unlink a STA info from the hash table/list. | ||
343 | * This can NULL the STA pointer if somebody else | ||
344 | * has already unlinked it. | ||
345 | */ | ||
346 | void sta_info_unlink(struct sta_info **sta); | ||
347 | |||
348 | void sta_info_destroy(struct sta_info *sta); | ||
349 | void sta_info_set_tim_bit(struct sta_info *sta); | ||
350 | void sta_info_clear_tim_bit(struct sta_info *sta); | ||
235 | 351 | ||
236 | struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr); | ||
237 | void sta_info_put(struct sta_info *sta); | ||
238 | struct sta_info *sta_info_add(struct ieee80211_local *local, | ||
239 | struct net_device *dev, u8 *addr, gfp_t gfp); | ||
240 | void sta_info_remove(struct sta_info *sta); | ||
241 | void sta_info_free(struct sta_info *sta); | ||
242 | void sta_info_init(struct ieee80211_local *local); | 352 | void sta_info_init(struct ieee80211_local *local); |
243 | int sta_info_start(struct ieee80211_local *local); | 353 | int sta_info_start(struct ieee80211_local *local); |
244 | void sta_info_stop(struct ieee80211_local *local); | 354 | void sta_info_stop(struct ieee80211_local *local); |
245 | void sta_info_flush(struct ieee80211_local *local, struct net_device *dev); | 355 | int sta_info_flush(struct ieee80211_local *local, |
246 | 356 | struct ieee80211_sub_if_data *sdata); | |
247 | void sta_info_set_tim_bit(struct sta_info *sta); | ||
248 | void sta_info_clear_tim_bit(struct sta_info *sta); | ||
249 | 357 | ||
250 | #endif /* STA_INFO_H */ | 358 | #endif /* STA_INFO_H */ |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1cd58e01f1ee..80f4343a3007 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | #include "ieee80211_i.h" | 27 | #include "ieee80211_i.h" |
28 | #include "ieee80211_led.h" | 28 | #include "ieee80211_led.h" |
29 | #include "mesh.h" | ||
29 | #include "wep.h" | 30 | #include "wep.h" |
30 | #include "wpa.h" | 31 | #include "wpa.h" |
31 | #include "wme.h" | 32 | #include "wme.h" |
@@ -86,11 +87,11 @@ static inline void ieee80211_dump_frame(const char *ifname, const char *title, | |||
86 | } | 87 | } |
87 | #endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ | 88 | #endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ |
88 | 89 | ||
89 | static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, | 90 | static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, |
90 | int next_frag_len) | 91 | int next_frag_len) |
91 | { | 92 | { |
92 | int rate, mrate, erp, dur, i; | 93 | int rate, mrate, erp, dur, i; |
93 | struct ieee80211_rate *txrate = tx->u.tx.rate; | 94 | struct ieee80211_rate *txrate = tx->rate; |
94 | struct ieee80211_local *local = tx->local; | 95 | struct ieee80211_local *local = tx->local; |
95 | struct ieee80211_supported_band *sband; | 96 | struct ieee80211_supported_band *sband; |
96 | 97 | ||
@@ -233,7 +234,7 @@ static int inline is_ieee80211_device(struct net_device *dev, | |||
233 | /* tx handlers */ | 234 | /* tx handlers */ |
234 | 235 | ||
235 | static ieee80211_tx_result | 236 | static ieee80211_tx_result |
236 | ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) | 237 | ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) |
237 | { | 238 | { |
238 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 239 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
239 | struct sk_buff *skb = tx->skb; | 240 | struct sk_buff *skb = tx->skb; |
@@ -241,7 +242,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) | |||
241 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 242 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
242 | u32 sta_flags; | 243 | u32 sta_flags; |
243 | 244 | ||
244 | if (unlikely(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) | 245 | if (unlikely(tx->flags & IEEE80211_TX_INJECTED)) |
245 | return TX_CONTINUE; | 246 | return TX_CONTINUE; |
246 | 247 | ||
247 | if (unlikely(tx->local->sta_sw_scanning) && | 248 | if (unlikely(tx->local->sta_sw_scanning) && |
@@ -249,12 +250,15 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) | |||
249 | (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) | 250 | (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) |
250 | return TX_DROP; | 251 | return TX_DROP; |
251 | 252 | ||
252 | if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED) | 253 | if (tx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) |
254 | return TX_CONTINUE; | ||
255 | |||
256 | if (tx->flags & IEEE80211_TX_PS_BUFFERED) | ||
253 | return TX_CONTINUE; | 257 | return TX_CONTINUE; |
254 | 258 | ||
255 | sta_flags = tx->sta ? tx->sta->flags : 0; | 259 | sta_flags = tx->sta ? tx->sta->flags : 0; |
256 | 260 | ||
257 | if (likely(tx->flags & IEEE80211_TXRXD_TXUNICAST)) { | 261 | if (likely(tx->flags & IEEE80211_TX_UNICAST)) { |
258 | if (unlikely(!(sta_flags & WLAN_STA_ASSOC) && | 262 | if (unlikely(!(sta_flags & WLAN_STA_ASSOC) && |
259 | tx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS && | 263 | tx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS && |
260 | (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { | 264 | (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { |
@@ -284,7 +288,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) | |||
284 | } | 288 | } |
285 | 289 | ||
286 | static ieee80211_tx_result | 290 | static ieee80211_tx_result |
287 | ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx) | 291 | ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) |
288 | { | 292 | { |
289 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; | 293 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; |
290 | 294 | ||
@@ -323,10 +327,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) | |||
323 | } | 327 | } |
324 | total += skb_queue_len(&ap->ps_bc_buf); | 328 | total += skb_queue_len(&ap->ps_bc_buf); |
325 | } | 329 | } |
326 | rcu_read_unlock(); | ||
327 | 330 | ||
328 | read_lock_bh(&local->sta_lock); | 331 | list_for_each_entry_rcu(sta, &local->sta_list, list) { |
329 | list_for_each_entry(sta, &local->sta_list, list) { | ||
330 | skb = skb_dequeue(&sta->ps_tx_buf); | 332 | skb = skb_dequeue(&sta->ps_tx_buf); |
331 | if (skb) { | 333 | if (skb) { |
332 | purged++; | 334 | purged++; |
@@ -334,7 +336,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) | |||
334 | } | 336 | } |
335 | total += skb_queue_len(&sta->ps_tx_buf); | 337 | total += skb_queue_len(&sta->ps_tx_buf); |
336 | } | 338 | } |
337 | read_unlock_bh(&local->sta_lock); | 339 | |
340 | rcu_read_unlock(); | ||
338 | 341 | ||
339 | local->total_ps_buffered = total; | 342 | local->total_ps_buffered = total; |
340 | printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", | 343 | printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", |
@@ -342,7 +345,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) | |||
342 | } | 345 | } |
343 | 346 | ||
344 | static ieee80211_tx_result | 347 | static ieee80211_tx_result |
345 | ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) | 348 | ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) |
346 | { | 349 | { |
347 | /* | 350 | /* |
348 | * broadcast/multicast frame | 351 | * broadcast/multicast frame |
@@ -379,13 +382,13 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) | |||
379 | } | 382 | } |
380 | 383 | ||
381 | /* buffered in hardware */ | 384 | /* buffered in hardware */ |
382 | tx->u.tx.control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM; | 385 | tx->control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM; |
383 | 386 | ||
384 | return TX_CONTINUE; | 387 | return TX_CONTINUE; |
385 | } | 388 | } |
386 | 389 | ||
387 | static ieee80211_tx_result | 390 | static ieee80211_tx_result |
388 | ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) | 391 | ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) |
389 | { | 392 | { |
390 | struct sta_info *sta = tx->sta; | 393 | struct sta_info *sta = tx->sta; |
391 | DECLARE_MAC_BUF(mac); | 394 | DECLARE_MAC_BUF(mac); |
@@ -439,32 +442,32 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) | |||
439 | } | 442 | } |
440 | 443 | ||
441 | static ieee80211_tx_result | 444 | static ieee80211_tx_result |
442 | ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) | 445 | ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx) |
443 | { | 446 | { |
444 | if (unlikely(tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED)) | 447 | if (unlikely(tx->flags & IEEE80211_TX_PS_BUFFERED)) |
445 | return TX_CONTINUE; | 448 | return TX_CONTINUE; |
446 | 449 | ||
447 | if (tx->flags & IEEE80211_TXRXD_TXUNICAST) | 450 | if (tx->flags & IEEE80211_TX_UNICAST) |
448 | return ieee80211_tx_h_unicast_ps_buf(tx); | 451 | return ieee80211_tx_h_unicast_ps_buf(tx); |
449 | else | 452 | else |
450 | return ieee80211_tx_h_multicast_ps_buf(tx); | 453 | return ieee80211_tx_h_multicast_ps_buf(tx); |
451 | } | 454 | } |
452 | 455 | ||
453 | static ieee80211_tx_result | 456 | static ieee80211_tx_result |
454 | ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) | 457 | ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) |
455 | { | 458 | { |
456 | struct ieee80211_key *key; | 459 | struct ieee80211_key *key; |
457 | u16 fc = tx->fc; | 460 | u16 fc = tx->fc; |
458 | 461 | ||
459 | if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) | 462 | if (unlikely(tx->control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) |
460 | tx->key = NULL; | 463 | tx->key = NULL; |
461 | else if (tx->sta && (key = rcu_dereference(tx->sta->key))) | 464 | else if (tx->sta && (key = rcu_dereference(tx->sta->key))) |
462 | tx->key = key; | 465 | tx->key = key; |
463 | else if ((key = rcu_dereference(tx->sdata->default_key))) | 466 | else if ((key = rcu_dereference(tx->sdata->default_key))) |
464 | tx->key = key; | 467 | tx->key = key; |
465 | else if (tx->sdata->drop_unencrypted && | 468 | else if (tx->sdata->drop_unencrypted && |
466 | !(tx->u.tx.control->flags & IEEE80211_TXCTL_EAPOL_FRAME) && | 469 | !(tx->control->flags & IEEE80211_TXCTL_EAPOL_FRAME) && |
467 | !(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) { | 470 | !(tx->flags & IEEE80211_TX_INJECTED)) { |
468 | I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); | 471 | I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); |
469 | return TX_DROP; | 472 | return TX_DROP; |
470 | } else | 473 | } else |
@@ -493,13 +496,13 @@ ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) | |||
493 | } | 496 | } |
494 | 497 | ||
495 | if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) | 498 | if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) |
496 | tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; | 499 | tx->control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; |
497 | 500 | ||
498 | return TX_CONTINUE; | 501 | return TX_CONTINUE; |
499 | } | 502 | } |
500 | 503 | ||
501 | static ieee80211_tx_result | 504 | static ieee80211_tx_result |
502 | ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) | 505 | ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) |
503 | { | 506 | { |
504 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; | 507 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; |
505 | size_t hdrlen, per_fragm, num_fragm, payload_len, left; | 508 | size_t hdrlen, per_fragm, num_fragm, payload_len, left; |
@@ -509,7 +512,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) | |||
509 | u8 *pos; | 512 | u8 *pos; |
510 | int frag_threshold = tx->local->fragmentation_threshold; | 513 | int frag_threshold = tx->local->fragmentation_threshold; |
511 | 514 | ||
512 | if (!(tx->flags & IEEE80211_TXRXD_FRAGMENTED)) | 515 | if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) |
513 | return TX_CONTINUE; | 516 | return TX_CONTINUE; |
514 | 517 | ||
515 | first = tx->skb; | 518 | first = tx->skb; |
@@ -561,8 +564,8 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) | |||
561 | } | 564 | } |
562 | skb_trim(first, hdrlen + per_fragm); | 565 | skb_trim(first, hdrlen + per_fragm); |
563 | 566 | ||
564 | tx->u.tx.num_extra_frag = num_fragm - 1; | 567 | tx->num_extra_frag = num_fragm - 1; |
565 | tx->u.tx.extra_frag = frags; | 568 | tx->extra_frag = frags; |
566 | 569 | ||
567 | return TX_CONTINUE; | 570 | return TX_CONTINUE; |
568 | 571 | ||
@@ -579,7 +582,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) | |||
579 | } | 582 | } |
580 | 583 | ||
581 | static ieee80211_tx_result | 584 | static ieee80211_tx_result |
582 | ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx) | 585 | ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) |
583 | { | 586 | { |
584 | if (!tx->key) | 587 | if (!tx->key) |
585 | return TX_CONTINUE; | 588 | return TX_CONTINUE; |
@@ -599,56 +602,56 @@ ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx) | |||
599 | } | 602 | } |
600 | 603 | ||
601 | static ieee80211_tx_result | 604 | static ieee80211_tx_result |
602 | ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) | 605 | ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) |
603 | { | 606 | { |
604 | struct rate_selection rsel; | 607 | struct rate_selection rsel; |
605 | struct ieee80211_supported_band *sband; | 608 | struct ieee80211_supported_band *sband; |
606 | 609 | ||
607 | sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; | 610 | sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; |
608 | 611 | ||
609 | if (likely(!tx->u.tx.rate)) { | 612 | if (likely(!tx->rate)) { |
610 | rate_control_get_rate(tx->dev, sband, tx->skb, &rsel); | 613 | rate_control_get_rate(tx->dev, sband, tx->skb, &rsel); |
611 | tx->u.tx.rate = rsel.rate; | 614 | tx->rate = rsel.rate; |
612 | if (unlikely(rsel.probe)) { | 615 | if (unlikely(rsel.probe)) { |
613 | tx->u.tx.control->flags |= | 616 | tx->control->flags |= |
614 | IEEE80211_TXCTL_RATE_CTRL_PROBE; | 617 | IEEE80211_TXCTL_RATE_CTRL_PROBE; |
615 | tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; | 618 | tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; |
616 | tx->u.tx.control->alt_retry_rate = tx->u.tx.rate; | 619 | tx->control->alt_retry_rate = tx->rate; |
617 | tx->u.tx.rate = rsel.probe; | 620 | tx->rate = rsel.probe; |
618 | } else | 621 | } else |
619 | tx->u.tx.control->alt_retry_rate = NULL; | 622 | tx->control->alt_retry_rate = NULL; |
620 | 623 | ||
621 | if (!tx->u.tx.rate) | 624 | if (!tx->rate) |
622 | return TX_DROP; | 625 | return TX_DROP; |
623 | } else | 626 | } else |
624 | tx->u.tx.control->alt_retry_rate = NULL; | 627 | tx->control->alt_retry_rate = NULL; |
625 | 628 | ||
626 | if (tx->sdata->bss_conf.use_cts_prot && | 629 | if (tx->sdata->bss_conf.use_cts_prot && |
627 | (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && rsel.nonerp) { | 630 | (tx->flags & IEEE80211_TX_FRAGMENTED) && rsel.nonerp) { |
628 | tx->u.tx.last_frag_rate = tx->u.tx.rate; | 631 | tx->last_frag_rate = tx->rate; |
629 | if (rsel.probe) | 632 | if (rsel.probe) |
630 | tx->flags &= ~IEEE80211_TXRXD_TXPROBE_LAST_FRAG; | 633 | tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG; |
631 | else | 634 | else |
632 | tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; | 635 | tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; |
633 | tx->u.tx.rate = rsel.nonerp; | 636 | tx->rate = rsel.nonerp; |
634 | tx->u.tx.control->tx_rate = rsel.nonerp; | 637 | tx->control->tx_rate = rsel.nonerp; |
635 | tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; | 638 | tx->control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; |
636 | } else { | 639 | } else { |
637 | tx->u.tx.last_frag_rate = tx->u.tx.rate; | 640 | tx->last_frag_rate = tx->rate; |
638 | tx->u.tx.control->tx_rate = tx->u.tx.rate; | 641 | tx->control->tx_rate = tx->rate; |
639 | } | 642 | } |
640 | tx->u.tx.control->tx_rate = tx->u.tx.rate; | 643 | tx->control->tx_rate = tx->rate; |
641 | 644 | ||
642 | return TX_CONTINUE; | 645 | return TX_CONTINUE; |
643 | } | 646 | } |
644 | 647 | ||
645 | static ieee80211_tx_result | 648 | static ieee80211_tx_result |
646 | ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) | 649 | ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) |
647 | { | 650 | { |
648 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; | 651 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; |
649 | u16 fc = le16_to_cpu(hdr->frame_control); | 652 | u16 fc = le16_to_cpu(hdr->frame_control); |
650 | u16 dur; | 653 | u16 dur; |
651 | struct ieee80211_tx_control *control = tx->u.tx.control; | 654 | struct ieee80211_tx_control *control = tx->control; |
652 | 655 | ||
653 | if (!control->retry_limit) { | 656 | if (!control->retry_limit) { |
654 | if (!is_multicast_ether_addr(hdr->addr1)) { | 657 | if (!is_multicast_ether_addr(hdr->addr1)) { |
@@ -670,7 +673,7 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) | |||
670 | } | 673 | } |
671 | } | 674 | } |
672 | 675 | ||
673 | if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) { | 676 | if (tx->flags & IEEE80211_TX_FRAGMENTED) { |
674 | /* Do not use multiple retry rates when sending fragmented | 677 | /* Do not use multiple retry rates when sending fragmented |
675 | * frames. | 678 | * frames. |
676 | * TODO: The last fragment could still use multiple retry | 679 | * TODO: The last fragment could still use multiple retry |
@@ -682,8 +685,8 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) | |||
682 | * there are associated non-ERP stations and RTS/CTS is not configured | 685 | * there are associated non-ERP stations and RTS/CTS is not configured |
683 | * for the frame. */ | 686 | * for the frame. */ |
684 | if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) && | 687 | if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) && |
685 | (tx->u.tx.rate->flags & IEEE80211_RATE_ERP_G) && | 688 | (tx->rate->flags & IEEE80211_RATE_ERP_G) && |
686 | (tx->flags & IEEE80211_TXRXD_TXUNICAST) && | 689 | (tx->flags & IEEE80211_TX_UNICAST) && |
687 | tx->sdata->bss_conf.use_cts_prot && | 690 | tx->sdata->bss_conf.use_cts_prot && |
688 | !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) | 691 | !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) |
689 | control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; | 692 | control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; |
@@ -692,18 +695,18 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) | |||
692 | * short preambles at the selected rate and short preambles are | 695 | * short preambles at the selected rate and short preambles are |
693 | * available on the network at the current point in time. */ | 696 | * available on the network at the current point in time. */ |
694 | if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && | 697 | if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && |
695 | (tx->u.tx.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && | 698 | (tx->rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && |
696 | tx->sdata->bss_conf.use_short_preamble && | 699 | tx->sdata->bss_conf.use_short_preamble && |
697 | (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { | 700 | (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { |
698 | tx->u.tx.control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; | 701 | tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; |
699 | } | 702 | } |
700 | 703 | ||
701 | /* Setup duration field for the first fragment of the frame. Duration | 704 | /* Setup duration field for the first fragment of the frame. Duration |
702 | * for remaining fragments will be updated when they are being sent | 705 | * for remaining fragments will be updated when they are being sent |
703 | * to low-level driver in ieee80211_tx(). */ | 706 | * to low-level driver in ieee80211_tx(). */ |
704 | dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1), | 707 | dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1), |
705 | (tx->flags & IEEE80211_TXRXD_FRAGMENTED) ? | 708 | (tx->flags & IEEE80211_TX_FRAGMENTED) ? |
706 | tx->u.tx.extra_frag[0]->len : 0); | 709 | tx->extra_frag[0]->len : 0); |
707 | hdr->duration_id = cpu_to_le16(dur); | 710 | hdr->duration_id = cpu_to_le16(dur); |
708 | 711 | ||
709 | if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || | 712 | if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || |
@@ -719,7 +722,7 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) | |||
719 | control->alt_retry_rate = NULL; | 722 | control->alt_retry_rate = NULL; |
720 | 723 | ||
721 | /* Use min(data rate, max base rate) as CTS/RTS rate */ | 724 | /* Use min(data rate, max base rate) as CTS/RTS rate */ |
722 | rate = tx->u.tx.rate; | 725 | rate = tx->rate; |
723 | baserate = NULL; | 726 | baserate = NULL; |
724 | 727 | ||
725 | for (idx = 0; idx < sband->n_bitrates; idx++) { | 728 | for (idx = 0; idx < sband->n_bitrates; idx++) { |
@@ -741,12 +744,12 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) | |||
741 | tx->sta->tx_packets++; | 744 | tx->sta->tx_packets++; |
742 | tx->sta->tx_fragments++; | 745 | tx->sta->tx_fragments++; |
743 | tx->sta->tx_bytes += tx->skb->len; | 746 | tx->sta->tx_bytes += tx->skb->len; |
744 | if (tx->u.tx.extra_frag) { | 747 | if (tx->extra_frag) { |
745 | int i; | 748 | int i; |
746 | tx->sta->tx_fragments += tx->u.tx.num_extra_frag; | 749 | tx->sta->tx_fragments += tx->num_extra_frag; |
747 | for (i = 0; i < tx->u.tx.num_extra_frag; i++) { | 750 | for (i = 0; i < tx->num_extra_frag; i++) { |
748 | tx->sta->tx_bytes += | 751 | tx->sta->tx_bytes += |
749 | tx->u.tx.extra_frag[i]->len; | 752 | tx->extra_frag[i]->len; |
750 | } | 753 | } |
751 | } | 754 | } |
752 | } | 755 | } |
@@ -755,13 +758,13 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) | |||
755 | } | 758 | } |
756 | 759 | ||
757 | static ieee80211_tx_result | 760 | static ieee80211_tx_result |
758 | ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) | 761 | ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx) |
759 | { | 762 | { |
760 | struct ieee80211_local *local = tx->local; | 763 | struct ieee80211_local *local = tx->local; |
761 | struct sk_buff *skb = tx->skb; | 764 | struct sk_buff *skb = tx->skb; |
762 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 765 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
763 | u32 load = 0, hdrtime; | 766 | u32 load = 0, hdrtime; |
764 | struct ieee80211_rate *rate = tx->u.tx.rate; | 767 | struct ieee80211_rate *rate = tx->rate; |
765 | 768 | ||
766 | /* TODO: this could be part of tx_status handling, so that the number | 769 | /* TODO: this could be part of tx_status handling, so that the number |
767 | * of retries would be known; TX rate should in that case be stored | 770 | * of retries would be known; TX rate should in that case be stored |
@@ -772,8 +775,8 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) | |||
772 | /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, | 775 | /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, |
773 | * 1 usec = 1/8 * (1080 / 10) = 13.5 */ | 776 | * 1 usec = 1/8 * (1080 / 10) = 13.5 */ |
774 | 777 | ||
775 | if (tx->u.tx.channel->band == IEEE80211_BAND_5GHZ || | 778 | if (tx->channel->band == IEEE80211_BAND_5GHZ || |
776 | (tx->u.tx.channel->band == IEEE80211_BAND_2GHZ && | 779 | (tx->channel->band == IEEE80211_BAND_2GHZ && |
777 | rate->flags & IEEE80211_RATE_ERP_G)) | 780 | rate->flags & IEEE80211_RATE_ERP_G)) |
778 | hdrtime = CHAN_UTIL_HDR_SHORT; | 781 | hdrtime = CHAN_UTIL_HDR_SHORT; |
779 | else | 782 | else |
@@ -783,20 +786,20 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) | |||
783 | if (!is_multicast_ether_addr(hdr->addr1)) | 786 | if (!is_multicast_ether_addr(hdr->addr1)) |
784 | load += hdrtime; | 787 | load += hdrtime; |
785 | 788 | ||
786 | if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_RTS_CTS) | 789 | if (tx->control->flags & IEEE80211_TXCTL_USE_RTS_CTS) |
787 | load += 2 * hdrtime; | 790 | load += 2 * hdrtime; |
788 | else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) | 791 | else if (tx->control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) |
789 | load += hdrtime; | 792 | load += hdrtime; |
790 | 793 | ||
791 | /* TODO: optimise again */ | 794 | /* TODO: optimise again */ |
792 | load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; | 795 | load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; |
793 | 796 | ||
794 | if (tx->u.tx.extra_frag) { | 797 | if (tx->extra_frag) { |
795 | int i; | 798 | int i; |
796 | for (i = 0; i < tx->u.tx.num_extra_frag; i++) { | 799 | for (i = 0; i < tx->num_extra_frag; i++) { |
797 | load += 2 * hdrtime; | 800 | load += 2 * hdrtime; |
798 | load += tx->u.tx.extra_frag[i]->len * | 801 | load += tx->extra_frag[i]->len * |
799 | tx->u.tx.rate->bitrate; | 802 | tx->rate->bitrate; |
800 | } | 803 | } |
801 | } | 804 | } |
802 | 805 | ||
@@ -811,7 +814,7 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) | |||
811 | } | 814 | } |
812 | 815 | ||
813 | 816 | ||
814 | typedef ieee80211_tx_result (*ieee80211_tx_handler)(struct ieee80211_txrx_data *); | 817 | typedef ieee80211_tx_result (*ieee80211_tx_handler)(struct ieee80211_tx_data *); |
815 | static ieee80211_tx_handler ieee80211_tx_handlers[] = | 818 | static ieee80211_tx_handler ieee80211_tx_handlers[] = |
816 | { | 819 | { |
817 | ieee80211_tx_h_check_assoc, | 820 | ieee80211_tx_h_check_assoc, |
@@ -834,7 +837,7 @@ static ieee80211_tx_handler ieee80211_tx_handlers[] = | |||
834 | * with Radiotap Header -- only called for monitor mode interface | 837 | * with Radiotap Header -- only called for monitor mode interface |
835 | */ | 838 | */ |
836 | static ieee80211_tx_result | 839 | static ieee80211_tx_result |
837 | __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, | 840 | __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, |
838 | struct sk_buff *skb) | 841 | struct sk_buff *skb) |
839 | { | 842 | { |
840 | /* | 843 | /* |
@@ -850,13 +853,13 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, | |||
850 | (struct ieee80211_radiotap_header *) skb->data; | 853 | (struct ieee80211_radiotap_header *) skb->data; |
851 | struct ieee80211_supported_band *sband; | 854 | struct ieee80211_supported_band *sband; |
852 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); | 855 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); |
853 | struct ieee80211_tx_control *control = tx->u.tx.control; | 856 | struct ieee80211_tx_control *control = tx->control; |
854 | 857 | ||
855 | sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; | 858 | sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; |
856 | 859 | ||
857 | control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; | 860 | control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; |
858 | tx->flags |= IEEE80211_TXRXD_TX_INJECTED; | 861 | tx->flags |= IEEE80211_TX_INJECTED; |
859 | tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; | 862 | tx->flags &= ~IEEE80211_TX_FRAGMENTED; |
860 | 863 | ||
861 | /* | 864 | /* |
862 | * for every radiotap entry that is present | 865 | * for every radiotap entry that is present |
@@ -892,7 +895,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, | |||
892 | r = &sband->bitrates[i]; | 895 | r = &sband->bitrates[i]; |
893 | 896 | ||
894 | if (r->bitrate == target_rate) { | 897 | if (r->bitrate == target_rate) { |
895 | tx->u.tx.rate = r; | 898 | tx->rate = r; |
896 | break; | 899 | break; |
897 | } | 900 | } |
898 | } | 901 | } |
@@ -930,7 +933,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, | |||
930 | control->flags &= | 933 | control->flags &= |
931 | ~IEEE80211_TXCTL_DO_NOT_ENCRYPT; | 934 | ~IEEE80211_TXCTL_DO_NOT_ENCRYPT; |
932 | if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) | 935 | if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) |
933 | tx->flags |= IEEE80211_TXRXD_FRAGMENTED; | 936 | tx->flags |= IEEE80211_TX_FRAGMENTED; |
934 | break; | 937 | break; |
935 | 938 | ||
936 | /* | 939 | /* |
@@ -961,7 +964,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, | |||
961 | * initialises @tx | 964 | * initialises @tx |
962 | */ | 965 | */ |
963 | static ieee80211_tx_result | 966 | static ieee80211_tx_result |
964 | __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, | 967 | __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, |
965 | struct sk_buff *skb, | 968 | struct sk_buff *skb, |
966 | struct net_device *dev, | 969 | struct net_device *dev, |
967 | struct ieee80211_tx_control *control) | 970 | struct ieee80211_tx_control *control) |
@@ -977,12 +980,12 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, | |||
977 | tx->dev = dev; /* use original interface */ | 980 | tx->dev = dev; /* use original interface */ |
978 | tx->local = local; | 981 | tx->local = local; |
979 | tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 982 | tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
980 | tx->u.tx.control = control; | 983 | tx->control = control; |
981 | /* | 984 | /* |
982 | * Set this flag (used below to indicate "automatic fragmentation"), | 985 | * Set this flag (used below to indicate "automatic fragmentation"), |
983 | * it will be cleared/left by radiotap as desired. | 986 | * it will be cleared/left by radiotap as desired. |
984 | */ | 987 | */ |
985 | tx->flags |= IEEE80211_TXRXD_FRAGMENTED; | 988 | tx->flags |= IEEE80211_TX_FRAGMENTED; |
986 | 989 | ||
987 | /* process and remove the injection radiotap header */ | 990 | /* process and remove the injection radiotap header */ |
988 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 991 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
@@ -1003,20 +1006,20 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, | |||
1003 | tx->fc = le16_to_cpu(hdr->frame_control); | 1006 | tx->fc = le16_to_cpu(hdr->frame_control); |
1004 | 1007 | ||
1005 | if (is_multicast_ether_addr(hdr->addr1)) { | 1008 | if (is_multicast_ether_addr(hdr->addr1)) { |
1006 | tx->flags &= ~IEEE80211_TXRXD_TXUNICAST; | 1009 | tx->flags &= ~IEEE80211_TX_UNICAST; |
1007 | control->flags |= IEEE80211_TXCTL_NO_ACK; | 1010 | control->flags |= IEEE80211_TXCTL_NO_ACK; |
1008 | } else { | 1011 | } else { |
1009 | tx->flags |= IEEE80211_TXRXD_TXUNICAST; | 1012 | tx->flags |= IEEE80211_TX_UNICAST; |
1010 | control->flags &= ~IEEE80211_TXCTL_NO_ACK; | 1013 | control->flags &= ~IEEE80211_TXCTL_NO_ACK; |
1011 | } | 1014 | } |
1012 | 1015 | ||
1013 | if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) { | 1016 | if (tx->flags & IEEE80211_TX_FRAGMENTED) { |
1014 | if ((tx->flags & IEEE80211_TXRXD_TXUNICAST) && | 1017 | if ((tx->flags & IEEE80211_TX_UNICAST) && |
1015 | skb->len + FCS_LEN > local->fragmentation_threshold && | 1018 | skb->len + FCS_LEN > local->fragmentation_threshold && |
1016 | !local->ops->set_frag_threshold) | 1019 | !local->ops->set_frag_threshold) |
1017 | tx->flags |= IEEE80211_TXRXD_FRAGMENTED; | 1020 | tx->flags |= IEEE80211_TX_FRAGMENTED; |
1018 | else | 1021 | else |
1019 | tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; | 1022 | tx->flags &= ~IEEE80211_TX_FRAGMENTED; |
1020 | } | 1023 | } |
1021 | 1024 | ||
1022 | if (!tx->sta) | 1025 | if (!tx->sta) |
@@ -1039,7 +1042,7 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, | |||
1039 | /* | 1042 | /* |
1040 | * NB: @tx is uninitialised when passed in here | 1043 | * NB: @tx is uninitialised when passed in here |
1041 | */ | 1044 | */ |
1042 | static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, | 1045 | static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx, |
1043 | struct sk_buff *skb, | 1046 | struct sk_buff *skb, |
1044 | struct net_device *mdev, | 1047 | struct net_device *mdev, |
1045 | struct ieee80211_tx_control *control) | 1048 | struct ieee80211_tx_control *control) |
@@ -1062,9 +1065,9 @@ static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, | |||
1062 | } | 1065 | } |
1063 | 1066 | ||
1064 | static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, | 1067 | static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, |
1065 | struct ieee80211_txrx_data *tx) | 1068 | struct ieee80211_tx_data *tx) |
1066 | { | 1069 | { |
1067 | struct ieee80211_tx_control *control = tx->u.tx.control; | 1070 | struct ieee80211_tx_control *control = tx->control; |
1068 | int ret, i; | 1071 | int ret, i; |
1069 | 1072 | ||
1070 | if (!ieee80211_qdisc_installed(local->mdev) && | 1073 | if (!ieee80211_qdisc_installed(local->mdev) && |
@@ -1081,20 +1084,20 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, | |||
1081 | local->mdev->trans_start = jiffies; | 1084 | local->mdev->trans_start = jiffies; |
1082 | ieee80211_led_tx(local, 1); | 1085 | ieee80211_led_tx(local, 1); |
1083 | } | 1086 | } |
1084 | if (tx->u.tx.extra_frag) { | 1087 | if (tx->extra_frag) { |
1085 | control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | | 1088 | control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | |
1086 | IEEE80211_TXCTL_USE_CTS_PROTECT | | 1089 | IEEE80211_TXCTL_USE_CTS_PROTECT | |
1087 | IEEE80211_TXCTL_CLEAR_PS_FILT | | 1090 | IEEE80211_TXCTL_CLEAR_PS_FILT | |
1088 | IEEE80211_TXCTL_FIRST_FRAGMENT); | 1091 | IEEE80211_TXCTL_FIRST_FRAGMENT); |
1089 | for (i = 0; i < tx->u.tx.num_extra_frag; i++) { | 1092 | for (i = 0; i < tx->num_extra_frag; i++) { |
1090 | if (!tx->u.tx.extra_frag[i]) | 1093 | if (!tx->extra_frag[i]) |
1091 | continue; | 1094 | continue; |
1092 | if (__ieee80211_queue_stopped(local, control->queue)) | 1095 | if (__ieee80211_queue_stopped(local, control->queue)) |
1093 | return IEEE80211_TX_FRAG_AGAIN; | 1096 | return IEEE80211_TX_FRAG_AGAIN; |
1094 | if (i == tx->u.tx.num_extra_frag) { | 1097 | if (i == tx->num_extra_frag) { |
1095 | control->tx_rate = tx->u.tx.last_frag_rate; | 1098 | control->tx_rate = tx->last_frag_rate; |
1096 | 1099 | ||
1097 | if (tx->flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG) | 1100 | if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG) |
1098 | control->flags |= | 1101 | control->flags |= |
1099 | IEEE80211_TXCTL_RATE_CTRL_PROBE; | 1102 | IEEE80211_TXCTL_RATE_CTRL_PROBE; |
1100 | else | 1103 | else |
@@ -1104,18 +1107,18 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, | |||
1104 | 1107 | ||
1105 | ieee80211_dump_frame(wiphy_name(local->hw.wiphy), | 1108 | ieee80211_dump_frame(wiphy_name(local->hw.wiphy), |
1106 | "TX to low-level driver", | 1109 | "TX to low-level driver", |
1107 | tx->u.tx.extra_frag[i]); | 1110 | tx->extra_frag[i]); |
1108 | ret = local->ops->tx(local_to_hw(local), | 1111 | ret = local->ops->tx(local_to_hw(local), |
1109 | tx->u.tx.extra_frag[i], | 1112 | tx->extra_frag[i], |
1110 | control); | 1113 | control); |
1111 | if (ret) | 1114 | if (ret) |
1112 | return IEEE80211_TX_FRAG_AGAIN; | 1115 | return IEEE80211_TX_FRAG_AGAIN; |
1113 | local->mdev->trans_start = jiffies; | 1116 | local->mdev->trans_start = jiffies; |
1114 | ieee80211_led_tx(local, 1); | 1117 | ieee80211_led_tx(local, 1); |
1115 | tx->u.tx.extra_frag[i] = NULL; | 1118 | tx->extra_frag[i] = NULL; |
1116 | } | 1119 | } |
1117 | kfree(tx->u.tx.extra_frag); | 1120 | kfree(tx->extra_frag); |
1118 | tx->u.tx.extra_frag = NULL; | 1121 | tx->extra_frag = NULL; |
1119 | } | 1122 | } |
1120 | return IEEE80211_TX_OK; | 1123 | return IEEE80211_TX_OK; |
1121 | } | 1124 | } |
@@ -1126,7 +1129,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, | |||
1126 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1129 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1127 | struct sta_info *sta; | 1130 | struct sta_info *sta; |
1128 | ieee80211_tx_handler *handler; | 1131 | ieee80211_tx_handler *handler; |
1129 | struct ieee80211_txrx_data tx; | 1132 | struct ieee80211_tx_data tx; |
1130 | ieee80211_tx_result res = TX_DROP, res_prepare; | 1133 | ieee80211_tx_result res = TX_DROP, res_prepare; |
1131 | int ret, i; | 1134 | int ret, i; |
1132 | 1135 | ||
@@ -1137,22 +1140,19 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, | |||
1137 | return 0; | 1140 | return 0; |
1138 | } | 1141 | } |
1139 | 1142 | ||
1143 | rcu_read_lock(); | ||
1144 | |||
1140 | /* initialises tx */ | 1145 | /* initialises tx */ |
1141 | res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); | 1146 | res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); |
1142 | 1147 | ||
1143 | if (res_prepare == TX_DROP) { | 1148 | if (res_prepare == TX_DROP) { |
1144 | dev_kfree_skb(skb); | 1149 | dev_kfree_skb(skb); |
1150 | rcu_read_unlock(); | ||
1145 | return 0; | 1151 | return 0; |
1146 | } | 1152 | } |
1147 | 1153 | ||
1148 | /* | ||
1149 | * key references are protected using RCU and this requires that | ||
1150 | * we are in a read-site RCU section during receive processing | ||
1151 | */ | ||
1152 | rcu_read_lock(); | ||
1153 | |||
1154 | sta = tx.sta; | 1154 | sta = tx.sta; |
1155 | tx.u.tx.channel = local->hw.conf.channel; | 1155 | tx.channel = local->hw.conf.channel; |
1156 | 1156 | ||
1157 | for (handler = ieee80211_tx_handlers; *handler != NULL; | 1157 | for (handler = ieee80211_tx_handlers; *handler != NULL; |
1158 | handler++) { | 1158 | handler++) { |
@@ -1163,9 +1163,6 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, | |||
1163 | 1163 | ||
1164 | skb = tx.skb; /* handlers are allowed to change skb */ | 1164 | skb = tx.skb; /* handlers are allowed to change skb */ |
1165 | 1165 | ||
1166 | if (sta) | ||
1167 | sta_info_put(sta); | ||
1168 | |||
1169 | if (unlikely(res == TX_DROP)) { | 1166 | if (unlikely(res == TX_DROP)) { |
1170 | I802_DEBUG_INC(local->tx_handlers_drop); | 1167 | I802_DEBUG_INC(local->tx_handlers_drop); |
1171 | goto drop; | 1168 | goto drop; |
@@ -1177,18 +1174,18 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, | |||
1177 | return 0; | 1174 | return 0; |
1178 | } | 1175 | } |
1179 | 1176 | ||
1180 | if (tx.u.tx.extra_frag) { | 1177 | if (tx.extra_frag) { |
1181 | for (i = 0; i < tx.u.tx.num_extra_frag; i++) { | 1178 | for (i = 0; i < tx.num_extra_frag; i++) { |
1182 | int next_len, dur; | 1179 | int next_len, dur; |
1183 | struct ieee80211_hdr *hdr = | 1180 | struct ieee80211_hdr *hdr = |
1184 | (struct ieee80211_hdr *) | 1181 | (struct ieee80211_hdr *) |
1185 | tx.u.tx.extra_frag[i]->data; | 1182 | tx.extra_frag[i]->data; |
1186 | 1183 | ||
1187 | if (i + 1 < tx.u.tx.num_extra_frag) { | 1184 | if (i + 1 < tx.num_extra_frag) { |
1188 | next_len = tx.u.tx.extra_frag[i + 1]->len; | 1185 | next_len = tx.extra_frag[i + 1]->len; |
1189 | } else { | 1186 | } else { |
1190 | next_len = 0; | 1187 | next_len = 0; |
1191 | tx.u.tx.rate = tx.u.tx.last_frag_rate; | 1188 | tx.rate = tx.last_frag_rate; |
1192 | } | 1189 | } |
1193 | dur = ieee80211_duration(&tx, 0, next_len); | 1190 | dur = ieee80211_duration(&tx, 0, next_len); |
1194 | hdr->duration_id = cpu_to_le16(dur); | 1191 | hdr->duration_id = cpu_to_le16(dur); |
@@ -1223,11 +1220,11 @@ retry: | |||
1223 | memcpy(&store->control, control, | 1220 | memcpy(&store->control, control, |
1224 | sizeof(struct ieee80211_tx_control)); | 1221 | sizeof(struct ieee80211_tx_control)); |
1225 | store->skb = skb; | 1222 | store->skb = skb; |
1226 | store->extra_frag = tx.u.tx.extra_frag; | 1223 | store->extra_frag = tx.extra_frag; |
1227 | store->num_extra_frag = tx.u.tx.num_extra_frag; | 1224 | store->num_extra_frag = tx.num_extra_frag; |
1228 | store->last_frag_rate = tx.u.tx.last_frag_rate; | 1225 | store->last_frag_rate = tx.last_frag_rate; |
1229 | store->last_frag_rate_ctrl_probe = | 1226 | store->last_frag_rate_ctrl_probe = |
1230 | !!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG); | 1227 | !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG); |
1231 | } | 1228 | } |
1232 | rcu_read_unlock(); | 1229 | rcu_read_unlock(); |
1233 | return 0; | 1230 | return 0; |
@@ -1235,10 +1232,10 @@ retry: | |||
1235 | drop: | 1232 | drop: |
1236 | if (skb) | 1233 | if (skb) |
1237 | dev_kfree_skb(skb); | 1234 | dev_kfree_skb(skb); |
1238 | for (i = 0; i < tx.u.tx.num_extra_frag; i++) | 1235 | for (i = 0; i < tx.num_extra_frag; i++) |
1239 | if (tx.u.tx.extra_frag[i]) | 1236 | if (tx.extra_frag[i]) |
1240 | dev_kfree_skb(tx.u.tx.extra_frag[i]); | 1237 | dev_kfree_skb(tx.extra_frag[i]); |
1241 | kfree(tx.u.tx.extra_frag); | 1238 | kfree(tx.extra_frag); |
1242 | rcu_read_unlock(); | 1239 | rcu_read_unlock(); |
1243 | return 0; | 1240 | return 0; |
1244 | } | 1241 | } |
@@ -1384,8 +1381,9 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1384 | struct ieee80211_tx_packet_data *pkt_data; | 1381 | struct ieee80211_tx_packet_data *pkt_data; |
1385 | struct ieee80211_sub_if_data *sdata; | 1382 | struct ieee80211_sub_if_data *sdata; |
1386 | int ret = 1, head_need; | 1383 | int ret = 1, head_need; |
1387 | u16 ethertype, hdrlen, fc; | 1384 | u16 ethertype, hdrlen, meshhdrlen = 0, fc; |
1388 | struct ieee80211_hdr hdr; | 1385 | struct ieee80211_hdr hdr; |
1386 | struct ieee80211s_hdr mesh_hdr; | ||
1389 | const u8 *encaps_data; | 1387 | const u8 *encaps_data; |
1390 | int encaps_len, skip_header_bytes; | 1388 | int encaps_len, skip_header_bytes; |
1391 | int nh_pos, h_pos; | 1389 | int nh_pos, h_pos; |
@@ -1427,6 +1425,37 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1427 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | 1425 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); |
1428 | hdrlen = 30; | 1426 | hdrlen = 30; |
1429 | break; | 1427 | break; |
1428 | #ifdef CONFIG_MAC80211_MESH | ||
1429 | case IEEE80211_IF_TYPE_MESH_POINT: | ||
1430 | fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; | ||
1431 | /* RA TA DA SA */ | ||
1432 | if (is_multicast_ether_addr(skb->data)) | ||
1433 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | ||
1434 | else if (mesh_nexthop_lookup(hdr.addr1, skb, dev)) | ||
1435 | return 0; | ||
1436 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | ||
1437 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | ||
1438 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | ||
1439 | if (skb->pkt_type == PACKET_OTHERHOST) { | ||
1440 | /* Forwarded frame, keep mesh ttl and seqnum */ | ||
1441 | struct ieee80211s_hdr *prev_meshhdr; | ||
1442 | prev_meshhdr = ((struct ieee80211s_hdr *)skb->cb); | ||
1443 | meshhdrlen = ieee80211_get_mesh_hdrlen(prev_meshhdr); | ||
1444 | memcpy(&mesh_hdr, prev_meshhdr, meshhdrlen); | ||
1445 | sdata->u.sta.mshstats.fwded_frames++; | ||
1446 | } else { | ||
1447 | if (!sdata->u.sta.mshcfg.dot11MeshTTL) { | ||
1448 | /* Do not send frames with mesh_ttl == 0 */ | ||
1449 | sdata->u.sta.mshstats.dropped_frames_ttl++; | ||
1450 | ret = 0; | ||
1451 | goto fail; | ||
1452 | } | ||
1453 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, | ||
1454 | sdata); | ||
1455 | } | ||
1456 | hdrlen = 30; | ||
1457 | break; | ||
1458 | #endif | ||
1430 | case IEEE80211_IF_TYPE_STA: | 1459 | case IEEE80211_IF_TYPE_STA: |
1431 | fc |= IEEE80211_FCTL_TODS; | 1460 | fc |= IEEE80211_FCTL_TODS; |
1432 | /* BSSID SA DA */ | 1461 | /* BSSID SA DA */ |
@@ -1453,11 +1482,11 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1453 | * in AP mode) | 1482 | * in AP mode) |
1454 | */ | 1483 | */ |
1455 | if (!is_multicast_ether_addr(hdr.addr1)) { | 1484 | if (!is_multicast_ether_addr(hdr.addr1)) { |
1485 | rcu_read_lock(); | ||
1456 | sta = sta_info_get(local, hdr.addr1); | 1486 | sta = sta_info_get(local, hdr.addr1); |
1457 | if (sta) { | 1487 | if (sta) |
1458 | sta_flags = sta->flags; | 1488 | sta_flags = sta->flags; |
1459 | sta_info_put(sta); | 1489 | rcu_read_unlock(); |
1460 | } | ||
1461 | } | 1490 | } |
1462 | 1491 | ||
1463 | /* receiver is QoS enabled, use a QoS type frame */ | 1492 | /* receiver is QoS enabled, use a QoS type frame */ |
@@ -1471,8 +1500,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1471 | * EAPOL frames from the local station. | 1500 | * EAPOL frames from the local station. |
1472 | */ | 1501 | */ |
1473 | if (unlikely(!is_multicast_ether_addr(hdr.addr1) && | 1502 | if (unlikely(!is_multicast_ether_addr(hdr.addr1) && |
1474 | !(sta_flags & WLAN_STA_AUTHORIZED) && | 1503 | !(sta_flags & WLAN_STA_AUTHORIZED) && |
1475 | !(ethertype == ETH_P_PAE && | 1504 | !(ethertype == ETH_P_PAE && |
1476 | compare_ether_addr(dev->dev_addr, | 1505 | compare_ether_addr(dev->dev_addr, |
1477 | skb->data + ETH_ALEN) == 0))) { | 1506 | skb->data + ETH_ALEN) == 0))) { |
1478 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1507 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
@@ -1525,7 +1554,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1525 | * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and | 1554 | * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and |
1526 | * alloc_skb() (net/core/skbuff.c) | 1555 | * alloc_skb() (net/core/skbuff.c) |
1527 | */ | 1556 | */ |
1528 | head_need = hdrlen + encaps_len + local->tx_headroom; | 1557 | head_need = hdrlen + encaps_len + meshhdrlen + local->tx_headroom; |
1529 | head_need -= skb_headroom(skb); | 1558 | head_need -= skb_headroom(skb); |
1530 | 1559 | ||
1531 | /* We are going to modify skb data, so make a copy of it if happens to | 1560 | /* We are going to modify skb data, so make a copy of it if happens to |
@@ -1559,6 +1588,12 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1559 | h_pos += encaps_len; | 1588 | h_pos += encaps_len; |
1560 | } | 1589 | } |
1561 | 1590 | ||
1591 | if (meshhdrlen > 0) { | ||
1592 | memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen); | ||
1593 | nh_pos += meshhdrlen; | ||
1594 | h_pos += meshhdrlen; | ||
1595 | } | ||
1596 | |||
1562 | if (fc & IEEE80211_STYPE_QOS_DATA) { | 1597 | if (fc & IEEE80211_STYPE_QOS_DATA) { |
1563 | __le16 *qos_control; | 1598 | __le16 *qos_control; |
1564 | 1599 | ||
@@ -1628,7 +1663,7 @@ void ieee80211_tx_pending(unsigned long data) | |||
1628 | struct ieee80211_local *local = (struct ieee80211_local *)data; | 1663 | struct ieee80211_local *local = (struct ieee80211_local *)data; |
1629 | struct net_device *dev = local->mdev; | 1664 | struct net_device *dev = local->mdev; |
1630 | struct ieee80211_tx_stored_packet *store; | 1665 | struct ieee80211_tx_stored_packet *store; |
1631 | struct ieee80211_txrx_data tx; | 1666 | struct ieee80211_tx_data tx; |
1632 | int i, ret, reschedule = 0; | 1667 | int i, ret, reschedule = 0; |
1633 | 1668 | ||
1634 | netif_tx_lock_bh(dev); | 1669 | netif_tx_lock_bh(dev); |
@@ -1640,13 +1675,13 @@ void ieee80211_tx_pending(unsigned long data) | |||
1640 | continue; | 1675 | continue; |
1641 | } | 1676 | } |
1642 | store = &local->pending_packet[i]; | 1677 | store = &local->pending_packet[i]; |
1643 | tx.u.tx.control = &store->control; | 1678 | tx.control = &store->control; |
1644 | tx.u.tx.extra_frag = store->extra_frag; | 1679 | tx.extra_frag = store->extra_frag; |
1645 | tx.u.tx.num_extra_frag = store->num_extra_frag; | 1680 | tx.num_extra_frag = store->num_extra_frag; |
1646 | tx.u.tx.last_frag_rate = store->last_frag_rate; | 1681 | tx.last_frag_rate = store->last_frag_rate; |
1647 | tx.flags = 0; | 1682 | tx.flags = 0; |
1648 | if (store->last_frag_rate_ctrl_probe) | 1683 | if (store->last_frag_rate_ctrl_probe) |
1649 | tx.flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; | 1684 | tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG; |
1650 | ret = __ieee80211_tx(local, store->skb, &tx); | 1685 | ret = __ieee80211_tx(local, store->skb, &tx); |
1651 | if (ret) { | 1686 | if (ret) { |
1652 | if (ret == IEEE80211_TX_FRAG_AGAIN) | 1687 | if (ret == IEEE80211_TX_FRAG_AGAIN) |
@@ -1680,7 +1715,6 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, | |||
1680 | 1715 | ||
1681 | /* Generate bitmap for TIM only if there are any STAs in power save | 1716 | /* Generate bitmap for TIM only if there are any STAs in power save |
1682 | * mode. */ | 1717 | * mode. */ |
1683 | read_lock_bh(&local->sta_lock); | ||
1684 | if (atomic_read(&bss->num_sta_ps) > 0) | 1718 | if (atomic_read(&bss->num_sta_ps) > 0) |
1685 | /* in the hope that this is faster than | 1719 | /* in the hope that this is faster than |
1686 | * checking byte-for-byte */ | 1720 | * checking byte-for-byte */ |
@@ -1731,7 +1765,6 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, | |||
1731 | *pos++ = aid0; /* Bitmap control */ | 1765 | *pos++ = aid0; /* Bitmap control */ |
1732 | *pos++ = 0; /* Part Virt Bitmap */ | 1766 | *pos++ = 0; /* Part Virt Bitmap */ |
1733 | } | 1767 | } |
1734 | read_unlock_bh(&local->sta_lock); | ||
1735 | } | 1768 | } |
1736 | 1769 | ||
1737 | struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | 1770 | struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, |
@@ -1746,6 +1779,10 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1746 | struct rate_selection rsel; | 1779 | struct rate_selection rsel; |
1747 | struct beacon_data *beacon; | 1780 | struct beacon_data *beacon; |
1748 | struct ieee80211_supported_band *sband; | 1781 | struct ieee80211_supported_band *sband; |
1782 | struct ieee80211_mgmt *mgmt; | ||
1783 | int *num_beacons; | ||
1784 | bool err = true; | ||
1785 | u8 *pos; | ||
1749 | 1786 | ||
1750 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1787 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1751 | 1788 | ||
@@ -1753,11 +1790,84 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1753 | 1790 | ||
1754 | sdata = vif_to_sdata(vif); | 1791 | sdata = vif_to_sdata(vif); |
1755 | bdev = sdata->dev; | 1792 | bdev = sdata->dev; |
1756 | ap = &sdata->u.ap; | ||
1757 | 1793 | ||
1758 | beacon = rcu_dereference(ap->beacon); | 1794 | if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { |
1795 | ap = &sdata->u.ap; | ||
1796 | beacon = rcu_dereference(ap->beacon); | ||
1797 | if (ap && beacon) { | ||
1798 | /* | ||
1799 | * headroom, head length, | ||
1800 | * tail length and maximum TIM length | ||
1801 | */ | ||
1802 | skb = dev_alloc_skb(local->tx_headroom + | ||
1803 | beacon->head_len + | ||
1804 | beacon->tail_len + 256); | ||
1805 | if (!skb) | ||
1806 | goto out; | ||
1807 | |||
1808 | skb_reserve(skb, local->tx_headroom); | ||
1809 | memcpy(skb_put(skb, beacon->head_len), beacon->head, | ||
1810 | beacon->head_len); | ||
1811 | |||
1812 | ieee80211_include_sequence(sdata, | ||
1813 | (struct ieee80211_hdr *)skb->data); | ||
1814 | |||
1815 | /* | ||
1816 | * Not very nice, but we want to allow the driver to call | ||
1817 | * ieee80211_beacon_get() as a response to the set_tim() | ||
1818 | * callback. That, however, is already invoked under the | ||
1819 | * sta_lock to guarantee consistent and race-free update | ||
1820 | * of the tim bitmap in mac80211 and the driver. | ||
1821 | */ | ||
1822 | if (local->tim_in_locked_section) { | ||
1823 | ieee80211_beacon_add_tim(local, ap, skb, beacon); | ||
1824 | } else { | ||
1825 | unsigned long flags; | ||
1826 | |||
1827 | spin_lock_irqsave(&local->sta_lock, flags); | ||
1828 | ieee80211_beacon_add_tim(local, ap, skb, beacon); | ||
1829 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
1830 | } | ||
1831 | |||
1832 | if (beacon->tail) | ||
1833 | memcpy(skb_put(skb, beacon->tail_len), | ||
1834 | beacon->tail, beacon->tail_len); | ||
1835 | |||
1836 | num_beacons = &ap->num_beacons; | ||
1837 | |||
1838 | err = false; | ||
1839 | } | ||
1840 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
1841 | /* headroom, head length, tail length and maximum TIM length */ | ||
1842 | skb = dev_alloc_skb(local->tx_headroom + 400); | ||
1843 | if (!skb) | ||
1844 | goto out; | ||
1845 | |||
1846 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1847 | mgmt = (struct ieee80211_mgmt *) | ||
1848 | skb_put(skb, 24 + sizeof(mgmt->u.beacon)); | ||
1849 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); | ||
1850 | mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, | ||
1851 | IEEE80211_STYPE_BEACON); | ||
1852 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
1853 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
1854 | /* BSSID is left zeroed, wildcard value */ | ||
1855 | mgmt->u.beacon.beacon_int = | ||
1856 | cpu_to_le16(local->hw.conf.beacon_int); | ||
1857 | mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ | ||
1759 | 1858 | ||
1760 | if (!ap || sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon) { | 1859 | pos = skb_put(skb, 2); |
1860 | *pos++ = WLAN_EID_SSID; | ||
1861 | *pos++ = 0x0; | ||
1862 | |||
1863 | mesh_mgmt_ies_add(skb, sdata->dev); | ||
1864 | |||
1865 | num_beacons = &sdata->u.sta.num_beacons; | ||
1866 | |||
1867 | err = false; | ||
1868 | } | ||
1869 | |||
1870 | if (err) { | ||
1761 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1871 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1762 | if (net_ratelimit()) | 1872 | if (net_ratelimit()) |
1763 | printk(KERN_DEBUG "no beacon data avail for %s\n", | 1873 | printk(KERN_DEBUG "no beacon data avail for %s\n", |
@@ -1767,24 +1877,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1767 | goto out; | 1877 | goto out; |
1768 | } | 1878 | } |
1769 | 1879 | ||
1770 | /* headroom, head length, tail length and maximum TIM length */ | ||
1771 | skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + | ||
1772 | beacon->tail_len + 256); | ||
1773 | if (!skb) | ||
1774 | goto out; | ||
1775 | |||
1776 | skb_reserve(skb, local->tx_headroom); | ||
1777 | memcpy(skb_put(skb, beacon->head_len), beacon->head, | ||
1778 | beacon->head_len); | ||
1779 | |||
1780 | ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); | ||
1781 | |||
1782 | ieee80211_beacon_add_tim(local, ap, skb, beacon); | ||
1783 | |||
1784 | if (beacon->tail) | ||
1785 | memcpy(skb_put(skb, beacon->tail_len), beacon->tail, | ||
1786 | beacon->tail_len); | ||
1787 | |||
1788 | if (control) { | 1880 | if (control) { |
1789 | rate_control_get_rate(local->mdev, sband, skb, &rsel); | 1881 | rate_control_get_rate(local->mdev, sband, skb, &rsel); |
1790 | if (!rsel.rate) { | 1882 | if (!rsel.rate) { |
@@ -1808,10 +1900,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1808 | control->retry_limit = 1; | 1900 | control->retry_limit = 1; |
1809 | control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; | 1901 | control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; |
1810 | } | 1902 | } |
1811 | 1903 | (*num_beacons)++; | |
1812 | ap->num_beacons++; | 1904 | out: |
1813 | |||
1814 | out: | ||
1815 | rcu_read_unlock(); | 1905 | rcu_read_unlock(); |
1816 | return skb; | 1906 | return skb; |
1817 | } | 1907 | } |
@@ -1859,7 +1949,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
1859 | struct sk_buff *skb; | 1949 | struct sk_buff *skb; |
1860 | struct sta_info *sta; | 1950 | struct sta_info *sta; |
1861 | ieee80211_tx_handler *handler; | 1951 | ieee80211_tx_handler *handler; |
1862 | struct ieee80211_txrx_data tx; | 1952 | struct ieee80211_tx_data tx; |
1863 | ieee80211_tx_result res = TX_DROP; | 1953 | ieee80211_tx_result res = TX_DROP; |
1864 | struct net_device *bdev; | 1954 | struct net_device *bdev; |
1865 | struct ieee80211_sub_if_data *sdata; | 1955 | struct ieee80211_sub_if_data *sdata; |
@@ -1881,7 +1971,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
1881 | rcu_read_unlock(); | 1971 | rcu_read_unlock(); |
1882 | return NULL; | 1972 | return NULL; |
1883 | } | 1973 | } |
1884 | rcu_read_unlock(); | ||
1885 | 1974 | ||
1886 | if (bss->dtim_count != 0) | 1975 | if (bss->dtim_count != 0) |
1887 | return NULL; /* send buffered bc/mc only after DTIM beacon */ | 1976 | return NULL; /* send buffered bc/mc only after DTIM beacon */ |
@@ -1907,8 +1996,8 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
1907 | dev_kfree_skb_any(skb); | 1996 | dev_kfree_skb_any(skb); |
1908 | } | 1997 | } |
1909 | sta = tx.sta; | 1998 | sta = tx.sta; |
1910 | tx.flags |= IEEE80211_TXRXD_TXPS_BUFFERED; | 1999 | tx.flags |= IEEE80211_TX_PS_BUFFERED; |
1911 | tx.u.tx.channel = local->hw.conf.channel; | 2000 | tx.channel = local->hw.conf.channel; |
1912 | 2001 | ||
1913 | for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { | 2002 | for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { |
1914 | res = (*handler)(&tx); | 2003 | res = (*handler)(&tx); |
@@ -1926,8 +2015,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
1926 | skb = NULL; | 2015 | skb = NULL; |
1927 | } | 2016 | } |
1928 | 2017 | ||
1929 | if (sta) | 2018 | rcu_read_unlock(); |
1930 | sta_info_put(sta); | ||
1931 | 2019 | ||
1932 | return skb; | 2020 | return skb; |
1933 | } | 2021 | } |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index f64804fed0a9..57c404f3f6d0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | #include "ieee80211_i.h" | 27 | #include "ieee80211_i.h" |
28 | #include "ieee80211_rate.h" | 28 | #include "ieee80211_rate.h" |
29 | #include "mesh.h" | ||
29 | #include "wme.h" | 30 | #include "wme.h" |
30 | 31 | ||
31 | /* privid for wiphys to determine whether they belong to us or not */ | 32 | /* privid for wiphys to determine whether they belong to us or not */ |
@@ -146,17 +147,35 @@ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) | |||
146 | } | 147 | } |
147 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); | 148 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); |
148 | 149 | ||
149 | void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) | 150 | int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) |
151 | { | ||
152 | int ae = meshhdr->flags & IEEE80211S_FLAGS_AE; | ||
153 | /* 7.1.3.5a.2 */ | ||
154 | switch (ae) { | ||
155 | case 0: | ||
156 | return 5; | ||
157 | case 1: | ||
158 | return 11; | ||
159 | case 2: | ||
160 | return 17; | ||
161 | case 3: | ||
162 | return 23; | ||
163 | default: | ||
164 | return 5; | ||
165 | } | ||
166 | } | ||
167 | |||
168 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) | ||
150 | { | 169 | { |
151 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; | 170 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; |
152 | 171 | ||
153 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | 172 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); |
154 | if (tx->u.tx.extra_frag) { | 173 | if (tx->extra_frag) { |
155 | struct ieee80211_hdr *fhdr; | 174 | struct ieee80211_hdr *fhdr; |
156 | int i; | 175 | int i; |
157 | for (i = 0; i < tx->u.tx.num_extra_frag; i++) { | 176 | for (i = 0; i < tx->num_extra_frag; i++) { |
158 | fhdr = (struct ieee80211_hdr *) | 177 | fhdr = (struct ieee80211_hdr *) |
159 | tx->u.tx.extra_frag[i]->data; | 178 | tx->extra_frag[i]->data; |
160 | fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | 179 | fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); |
161 | } | 180 | } |
162 | } | 181 | } |
@@ -382,6 +401,7 @@ void ieee80211_iterate_active_interfaces( | |||
382 | case IEEE80211_IF_TYPE_STA: | 401 | case IEEE80211_IF_TYPE_STA: |
383 | case IEEE80211_IF_TYPE_IBSS: | 402 | case IEEE80211_IF_TYPE_IBSS: |
384 | case IEEE80211_IF_TYPE_WDS: | 403 | case IEEE80211_IF_TYPE_WDS: |
404 | case IEEE80211_IF_TYPE_MESH_POINT: | ||
385 | break; | 405 | break; |
386 | } | 406 | } |
387 | if (sdata->dev == local->mdev) | 407 | if (sdata->dev == local->mdev) |
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index a33ef5cfa9ad..affcecd78c10 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c | |||
@@ -306,14 +306,14 @@ u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) | |||
306 | } | 306 | } |
307 | 307 | ||
308 | ieee80211_rx_result | 308 | ieee80211_rx_result |
309 | ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) | 309 | ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) |
310 | { | 310 | { |
311 | if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && | 311 | if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && |
312 | ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || | 312 | ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || |
313 | (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) | 313 | (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) |
314 | return RX_CONTINUE; | 314 | return RX_CONTINUE; |
315 | 315 | ||
316 | if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { | 316 | if (!(rx->status->flag & RX_FLAG_DECRYPTED)) { |
317 | if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { | 317 | if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { |
318 | #ifdef CONFIG_MAC80211_DEBUG | 318 | #ifdef CONFIG_MAC80211_DEBUG |
319 | if (net_ratelimit()) | 319 | if (net_ratelimit()) |
@@ -322,7 +322,7 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) | |||
322 | #endif /* CONFIG_MAC80211_DEBUG */ | 322 | #endif /* CONFIG_MAC80211_DEBUG */ |
323 | return RX_DROP_UNUSABLE; | 323 | return RX_DROP_UNUSABLE; |
324 | } | 324 | } |
325 | } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) { | 325 | } else if (!(rx->status->flag & RX_FLAG_IV_STRIPPED)) { |
326 | ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); | 326 | ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); |
327 | /* remove ICV */ | 327 | /* remove ICV */ |
328 | skb_trim(rx->skb, rx->skb->len - 4); | 328 | skb_trim(rx->skb, rx->skb->len - 4); |
@@ -331,13 +331,13 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) | |||
331 | return RX_CONTINUE; | 331 | return RX_CONTINUE; |
332 | } | 332 | } |
333 | 333 | ||
334 | static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) | 334 | static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) |
335 | { | 335 | { |
336 | if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { | 336 | if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { |
337 | if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) | 337 | if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) |
338 | return -1; | 338 | return -1; |
339 | } else { | 339 | } else { |
340 | tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; | 340 | tx->control->key_idx = tx->key->conf.hw_key_idx; |
341 | if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { | 341 | if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { |
342 | if (!ieee80211_wep_add_iv(tx->local, skb, tx->key)) | 342 | if (!ieee80211_wep_add_iv(tx->local, skb, tx->key)) |
343 | return -1; | 343 | return -1; |
@@ -347,21 +347,21 @@ static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) | |||
347 | } | 347 | } |
348 | 348 | ||
349 | ieee80211_tx_result | 349 | ieee80211_tx_result |
350 | ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx) | 350 | ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx) |
351 | { | 351 | { |
352 | tx->u.tx.control->iv_len = WEP_IV_LEN; | 352 | tx->control->iv_len = WEP_IV_LEN; |
353 | tx->u.tx.control->icv_len = WEP_ICV_LEN; | 353 | tx->control->icv_len = WEP_ICV_LEN; |
354 | ieee80211_tx_set_iswep(tx); | 354 | ieee80211_tx_set_protected(tx); |
355 | 355 | ||
356 | if (wep_encrypt_skb(tx, tx->skb) < 0) { | 356 | if (wep_encrypt_skb(tx, tx->skb) < 0) { |
357 | I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); | 357 | I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); |
358 | return TX_DROP; | 358 | return TX_DROP; |
359 | } | 359 | } |
360 | 360 | ||
361 | if (tx->u.tx.extra_frag) { | 361 | if (tx->extra_frag) { |
362 | int i; | 362 | int i; |
363 | for (i = 0; i < tx->u.tx.num_extra_frag; i++) { | 363 | for (i = 0; i < tx->num_extra_frag; i++) { |
364 | if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) { | 364 | if (wep_encrypt_skb(tx, tx->extra_frag[i]) < 0) { |
365 | I802_DEBUG_INC(tx->local-> | 365 | I802_DEBUG_INC(tx->local-> |
366 | tx_handlers_drop_wep); | 366 | tx_handlers_drop_wep); |
367 | return TX_DROP; | 367 | return TX_DROP; |
diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index 43aef50cd0d6..9f723938b63f 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h | |||
@@ -29,8 +29,8 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, | |||
29 | u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); | 29 | u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); |
30 | 30 | ||
31 | ieee80211_rx_result | 31 | ieee80211_rx_result |
32 | ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx); | 32 | ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx); |
33 | ieee80211_tx_result | 33 | ieee80211_tx_result |
34 | ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx); | 34 | ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx); |
35 | 35 | ||
36 | #endif /* WEP_H */ | 36 | #endif /* WEP_H */ |
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 8cc036decc82..4e94e4026e78 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -153,6 +153,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) | |||
153 | 153 | ||
154 | if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { | 154 | if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { |
155 | queue = pkt_data->queue; | 155 | queue = pkt_data->queue; |
156 | rcu_read_lock(); | ||
156 | sta = sta_info_get(local, hdr->addr1); | 157 | sta = sta_info_get(local, hdr->addr1); |
157 | tid = skb->priority & QOS_CONTROL_TAG1D_MASK; | 158 | tid = skb->priority & QOS_CONTROL_TAG1D_MASK; |
158 | if (sta) { | 159 | if (sta) { |
@@ -164,8 +165,8 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) | |||
164 | } else { | 165 | } else { |
165 | pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; | 166 | pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; |
166 | } | 167 | } |
167 | sta_info_put(sta); | ||
168 | } | 168 | } |
169 | rcu_read_unlock(); | ||
169 | skb_queue_tail(&q->requeued[queue], skb); | 170 | skb_queue_tail(&q->requeued[queue], skb); |
170 | qd->q.qlen++; | 171 | qd->q.qlen++; |
171 | return 0; | 172 | return 0; |
@@ -187,6 +188,8 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) | |||
187 | p++; | 188 | p++; |
188 | *p = 0; | 189 | *p = 0; |
189 | 190 | ||
191 | rcu_read_lock(); | ||
192 | |||
190 | sta = sta_info_get(local, hdr->addr1); | 193 | sta = sta_info_get(local, hdr->addr1); |
191 | if (sta) { | 194 | if (sta) { |
192 | int ampdu_queue = sta->tid_to_tx_q[tid]; | 195 | int ampdu_queue = sta->tid_to_tx_q[tid]; |
@@ -197,8 +200,9 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) | |||
197 | } else { | 200 | } else { |
198 | pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; | 201 | pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; |
199 | } | 202 | } |
200 | sta_info_put(sta); | ||
201 | } | 203 | } |
204 | |||
205 | rcu_read_unlock(); | ||
202 | } | 206 | } |
203 | 207 | ||
204 | if (unlikely(queue >= local->hw.queues)) { | 208 | if (unlikely(queue >= local->hw.queues)) { |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index b35e51c6ce0c..df0b7341efc8 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -71,7 +71,7 @@ static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da, | |||
71 | 71 | ||
72 | 72 | ||
73 | ieee80211_tx_result | 73 | ieee80211_tx_result |
74 | ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) | 74 | ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) |
75 | { | 75 | { |
76 | u8 *data, *sa, *da, *key, *mic, qos_tid; | 76 | u8 *data, *sa, *da, *key, *mic, qos_tid; |
77 | size_t data_len; | 77 | size_t data_len; |
@@ -90,7 +90,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) | |||
90 | return TX_DROP; | 90 | return TX_DROP; |
91 | 91 | ||
92 | if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && | 92 | if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && |
93 | !(tx->flags & IEEE80211_TXRXD_FRAGMENTED) && | 93 | !(tx->flags & IEEE80211_TX_FRAGMENTED) && |
94 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) && | 94 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) && |
95 | !wpa_test) { | 95 | !wpa_test) { |
96 | /* hwaccel - with no need for preallocated room for Michael MIC | 96 | /* hwaccel - with no need for preallocated room for Michael MIC |
@@ -124,7 +124,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) | |||
124 | 124 | ||
125 | 125 | ||
126 | ieee80211_rx_result | 126 | ieee80211_rx_result |
127 | ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) | 127 | ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) |
128 | { | 128 | { |
129 | u8 *data, *sa, *da, *key = NULL, qos_tid; | 129 | u8 *data, *sa, *da, *key = NULL, qos_tid; |
130 | size_t data_len; | 130 | size_t data_len; |
@@ -139,7 +139,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) | |||
139 | /* | 139 | /* |
140 | * No way to verify the MIC if the hardware stripped it | 140 | * No way to verify the MIC if the hardware stripped it |
141 | */ | 141 | */ |
142 | if (rx->u.rx.status->flag & RX_FLAG_MMIC_STRIPPED) | 142 | if (rx->status->flag & RX_FLAG_MMIC_STRIPPED) |
143 | return RX_CONTINUE; | 143 | return RX_CONTINUE; |
144 | 144 | ||
145 | if (!rx->key || rx->key->conf.alg != ALG_TKIP || | 145 | if (!rx->key || rx->key->conf.alg != ALG_TKIP || |
@@ -161,7 +161,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) | |||
161 | ALG_TKIP_TEMP_AUTH_TX_MIC_KEY]; | 161 | ALG_TKIP_TEMP_AUTH_TX_MIC_KEY]; |
162 | michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); | 162 | michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); |
163 | if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) { | 163 | if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) { |
164 | if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) | 164 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) |
165 | return RX_DROP_UNUSABLE; | 165 | return RX_DROP_UNUSABLE; |
166 | 166 | ||
167 | printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from " | 167 | printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from " |
@@ -176,14 +176,14 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) | |||
176 | skb_trim(skb, skb->len - MICHAEL_MIC_LEN); | 176 | skb_trim(skb, skb->len - MICHAEL_MIC_LEN); |
177 | 177 | ||
178 | /* update IV in key information to be able to detect replays */ | 178 | /* update IV in key information to be able to detect replays */ |
179 | rx->key->u.tkip.iv32_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv32; | 179 | rx->key->u.tkip.iv32_rx[rx->queue] = rx->tkip_iv32; |
180 | rx->key->u.tkip.iv16_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv16; | 180 | rx->key->u.tkip.iv16_rx[rx->queue] = rx->tkip_iv16; |
181 | 181 | ||
182 | return RX_CONTINUE; | 182 | return RX_CONTINUE; |
183 | } | 183 | } |
184 | 184 | ||
185 | 185 | ||
186 | static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, | 186 | static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, |
187 | struct sk_buff *skb, int test) | 187 | struct sk_buff *skb, int test) |
188 | { | 188 | { |
189 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 189 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
@@ -228,7 +228,7 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, | |||
228 | 0x7f), | 228 | 0x7f), |
229 | (u8) key->u.tkip.iv16); | 229 | (u8) key->u.tkip.iv16); |
230 | 230 | ||
231 | tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; | 231 | tx->control->key_idx = tx->key->conf.hw_key_idx; |
232 | return 0; | 232 | return 0; |
233 | } | 233 | } |
234 | 234 | ||
@@ -243,30 +243,30 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, | |||
243 | 243 | ||
244 | 244 | ||
245 | ieee80211_tx_result | 245 | ieee80211_tx_result |
246 | ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx) | 246 | ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx) |
247 | { | 247 | { |
248 | struct sk_buff *skb = tx->skb; | 248 | struct sk_buff *skb = tx->skb; |
249 | int wpa_test = 0, test = 0; | 249 | int wpa_test = 0, test = 0; |
250 | 250 | ||
251 | tx->u.tx.control->icv_len = TKIP_ICV_LEN; | 251 | tx->control->icv_len = TKIP_ICV_LEN; |
252 | tx->u.tx.control->iv_len = TKIP_IV_LEN; | 252 | tx->control->iv_len = TKIP_IV_LEN; |
253 | ieee80211_tx_set_iswep(tx); | 253 | ieee80211_tx_set_protected(tx); |
254 | 254 | ||
255 | if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && | 255 | if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && |
256 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && | 256 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && |
257 | !wpa_test) { | 257 | !wpa_test) { |
258 | /* hwaccel - with no need for preallocated room for IV/ICV */ | 258 | /* hwaccel - with no need for preallocated room for IV/ICV */ |
259 | tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; | 259 | tx->control->key_idx = tx->key->conf.hw_key_idx; |
260 | return TX_CONTINUE; | 260 | return TX_CONTINUE; |
261 | } | 261 | } |
262 | 262 | ||
263 | if (tkip_encrypt_skb(tx, skb, test) < 0) | 263 | if (tkip_encrypt_skb(tx, skb, test) < 0) |
264 | return TX_DROP; | 264 | return TX_DROP; |
265 | 265 | ||
266 | if (tx->u.tx.extra_frag) { | 266 | if (tx->extra_frag) { |
267 | int i; | 267 | int i; |
268 | for (i = 0; i < tx->u.tx.num_extra_frag; i++) { | 268 | for (i = 0; i < tx->num_extra_frag; i++) { |
269 | if (tkip_encrypt_skb(tx, tx->u.tx.extra_frag[i], test) | 269 | if (tkip_encrypt_skb(tx, tx->extra_frag[i], test) |
270 | < 0) | 270 | < 0) |
271 | return TX_DROP; | 271 | return TX_DROP; |
272 | } | 272 | } |
@@ -277,7 +277,7 @@ ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx) | |||
277 | 277 | ||
278 | 278 | ||
279 | ieee80211_rx_result | 279 | ieee80211_rx_result |
280 | ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) | 280 | ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) |
281 | { | 281 | { |
282 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; | 282 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; |
283 | u16 fc; | 283 | u16 fc; |
@@ -295,8 +295,8 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) | |||
295 | if (!rx->sta || skb->len - hdrlen < 12) | 295 | if (!rx->sta || skb->len - hdrlen < 12) |
296 | return RX_DROP_UNUSABLE; | 296 | return RX_DROP_UNUSABLE; |
297 | 297 | ||
298 | if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) { | 298 | if (rx->status->flag & RX_FLAG_DECRYPTED) { |
299 | if (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) { | 299 | if (rx->status->flag & RX_FLAG_IV_STRIPPED) { |
300 | /* | 300 | /* |
301 | * Hardware took care of all processing, including | 301 | * Hardware took care of all processing, including |
302 | * replay protection, and stripped the ICV/IV so | 302 | * replay protection, and stripped the ICV/IV so |
@@ -312,9 +312,9 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) | |||
312 | res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm, | 312 | res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm, |
313 | key, skb->data + hdrlen, | 313 | key, skb->data + hdrlen, |
314 | skb->len - hdrlen, rx->sta->addr, | 314 | skb->len - hdrlen, rx->sta->addr, |
315 | hwaccel, rx->u.rx.queue, | 315 | hwaccel, rx->queue, |
316 | &rx->u.rx.tkip_iv32, | 316 | &rx->tkip_iv32, |
317 | &rx->u.rx.tkip_iv16); | 317 | &rx->tkip_iv16); |
318 | if (res != TKIP_DECRYPT_OK || wpa_test) { | 318 | if (res != TKIP_DECRYPT_OK || wpa_test) { |
319 | #ifdef CONFIG_MAC80211_DEBUG | 319 | #ifdef CONFIG_MAC80211_DEBUG |
320 | if (net_ratelimit()) | 320 | if (net_ratelimit()) |
@@ -429,7 +429,7 @@ static inline int ccmp_hdr2pn(u8 *pn, u8 *hdr) | |||
429 | } | 429 | } |
430 | 430 | ||
431 | 431 | ||
432 | static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, | 432 | static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, |
433 | struct sk_buff *skb, int test) | 433 | struct sk_buff *skb, int test) |
434 | { | 434 | { |
435 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 435 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
@@ -478,7 +478,7 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, | |||
478 | 478 | ||
479 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { | 479 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { |
480 | /* hwaccel - with preallocated room for CCMP header */ | 480 | /* hwaccel - with preallocated room for CCMP header */ |
481 | tx->u.tx.control->key_idx = key->conf.hw_key_idx; | 481 | tx->control->key_idx = key->conf.hw_key_idx; |
482 | return 0; | 482 | return 0; |
483 | } | 483 | } |
484 | 484 | ||
@@ -492,30 +492,30 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, | |||
492 | 492 | ||
493 | 493 | ||
494 | ieee80211_tx_result | 494 | ieee80211_tx_result |
495 | ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx) | 495 | ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx) |
496 | { | 496 | { |
497 | struct sk_buff *skb = tx->skb; | 497 | struct sk_buff *skb = tx->skb; |
498 | int test = 0; | 498 | int test = 0; |
499 | 499 | ||
500 | tx->u.tx.control->icv_len = CCMP_MIC_LEN; | 500 | tx->control->icv_len = CCMP_MIC_LEN; |
501 | tx->u.tx.control->iv_len = CCMP_HDR_LEN; | 501 | tx->control->iv_len = CCMP_HDR_LEN; |
502 | ieee80211_tx_set_iswep(tx); | 502 | ieee80211_tx_set_protected(tx); |
503 | 503 | ||
504 | if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && | 504 | if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && |
505 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { | 505 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { |
506 | /* hwaccel - with no need for preallocated room for CCMP " | 506 | /* hwaccel - with no need for preallocated room for CCMP " |
507 | * header or MIC fields */ | 507 | * header or MIC fields */ |
508 | tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; | 508 | tx->control->key_idx = tx->key->conf.hw_key_idx; |
509 | return TX_CONTINUE; | 509 | return TX_CONTINUE; |
510 | } | 510 | } |
511 | 511 | ||
512 | if (ccmp_encrypt_skb(tx, skb, test) < 0) | 512 | if (ccmp_encrypt_skb(tx, skb, test) < 0) |
513 | return TX_DROP; | 513 | return TX_DROP; |
514 | 514 | ||
515 | if (tx->u.tx.extra_frag) { | 515 | if (tx->extra_frag) { |
516 | int i; | 516 | int i; |
517 | for (i = 0; i < tx->u.tx.num_extra_frag; i++) { | 517 | for (i = 0; i < tx->num_extra_frag; i++) { |
518 | if (ccmp_encrypt_skb(tx, tx->u.tx.extra_frag[i], test) | 518 | if (ccmp_encrypt_skb(tx, tx->extra_frag[i], test) |
519 | < 0) | 519 | < 0) |
520 | return TX_DROP; | 520 | return TX_DROP; |
521 | } | 521 | } |
@@ -526,7 +526,7 @@ ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx) | |||
526 | 526 | ||
527 | 527 | ||
528 | ieee80211_rx_result | 528 | ieee80211_rx_result |
529 | ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) | 529 | ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) |
530 | { | 530 | { |
531 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; | 531 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; |
532 | u16 fc; | 532 | u16 fc; |
@@ -547,15 +547,15 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) | |||
547 | if (!rx->sta || data_len < 0) | 547 | if (!rx->sta || data_len < 0) |
548 | return RX_DROP_UNUSABLE; | 548 | return RX_DROP_UNUSABLE; |
549 | 549 | ||
550 | if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && | 550 | if ((rx->status->flag & RX_FLAG_DECRYPTED) && |
551 | (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) | 551 | (rx->status->flag & RX_FLAG_IV_STRIPPED)) |
552 | return RX_CONTINUE; | 552 | return RX_CONTINUE; |
553 | 553 | ||
554 | (void) ccmp_hdr2pn(pn, skb->data + hdrlen); | 554 | (void) ccmp_hdr2pn(pn, skb->data + hdrlen); |
555 | 555 | ||
556 | if (memcmp(pn, key->u.ccmp.rx_pn[rx->u.rx.queue], CCMP_PN_LEN) <= 0) { | 556 | if (memcmp(pn, key->u.ccmp.rx_pn[rx->queue], CCMP_PN_LEN) <= 0) { |
557 | #ifdef CONFIG_MAC80211_DEBUG | 557 | #ifdef CONFIG_MAC80211_DEBUG |
558 | u8 *ppn = key->u.ccmp.rx_pn[rx->u.rx.queue]; | 558 | u8 *ppn = key->u.ccmp.rx_pn[rx->queue]; |
559 | 559 | ||
560 | printk(KERN_DEBUG "%s: CCMP replay detected for RX frame from " | 560 | printk(KERN_DEBUG "%s: CCMP replay detected for RX frame from " |
561 | "%s (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN " | 561 | "%s (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN " |
@@ -568,7 +568,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) | |||
568 | return RX_DROP_UNUSABLE; | 568 | return RX_DROP_UNUSABLE; |
569 | } | 569 | } |
570 | 570 | ||
571 | if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { | 571 | if (!(rx->status->flag & RX_FLAG_DECRYPTED)) { |
572 | /* hardware didn't decrypt/verify MIC */ | 572 | /* hardware didn't decrypt/verify MIC */ |
573 | u8 *scratch, *b_0, *aad; | 573 | u8 *scratch, *b_0, *aad; |
574 | 574 | ||
@@ -593,7 +593,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) | |||
593 | } | 593 | } |
594 | } | 594 | } |
595 | 595 | ||
596 | memcpy(key->u.ccmp.rx_pn[rx->u.rx.queue], pn, CCMP_PN_LEN); | 596 | memcpy(key->u.ccmp.rx_pn[rx->queue], pn, CCMP_PN_LEN); |
597 | 597 | ||
598 | /* Remove CCMP header and MIC */ | 598 | /* Remove CCMP header and MIC */ |
599 | skb_trim(skb, skb->len - CCMP_MIC_LEN); | 599 | skb_trim(skb, skb->len - CCMP_MIC_LEN); |
diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index 16e4dba4aa70..d42d221d8a1d 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h | |||
@@ -14,18 +14,18 @@ | |||
14 | #include "ieee80211_i.h" | 14 | #include "ieee80211_i.h" |
15 | 15 | ||
16 | ieee80211_tx_result | 16 | ieee80211_tx_result |
17 | ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx); | 17 | ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx); |
18 | ieee80211_rx_result | 18 | ieee80211_rx_result |
19 | ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx); | 19 | ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx); |
20 | 20 | ||
21 | ieee80211_tx_result | 21 | ieee80211_tx_result |
22 | ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx); | 22 | ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx); |
23 | ieee80211_rx_result | 23 | ieee80211_rx_result |
24 | ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx); | 24 | ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx); |
25 | 25 | ||
26 | ieee80211_tx_result | 26 | ieee80211_tx_result |
27 | ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx); | 27 | ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx); |
28 | ieee80211_rx_result | 28 | ieee80211_rx_result |
29 | ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx); | 29 | ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx); |
30 | 30 | ||
31 | #endif /* WPA_H */ | 31 | #endif /* WPA_H */ |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5b3474798b8d..64a7460af734 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -81,8 +81,12 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
81 | [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, | 81 | [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, |
82 | [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, | 82 | [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, |
83 | .len = NL80211_MAX_SUPP_RATES }, | 83 | .len = NL80211_MAX_SUPP_RATES }, |
84 | [NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 }, | ||
84 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, | 85 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, |
85 | [NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED }, | 86 | [NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED }, |
87 | [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, | ||
88 | .len = IEEE80211_MAX_MESH_ID_LEN }, | ||
89 | [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, | ||
86 | }; | 90 | }; |
87 | 91 | ||
88 | /* message building helper */ | 92 | /* message building helper */ |
@@ -369,11 +373,14 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) | |||
369 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | 373 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) |
370 | { | 374 | { |
371 | struct cfg80211_registered_device *drv; | 375 | struct cfg80211_registered_device *drv; |
376 | struct vif_params params; | ||
372 | int err, ifindex; | 377 | int err, ifindex; |
373 | enum nl80211_iftype type; | 378 | enum nl80211_iftype type; |
374 | struct net_device *dev; | 379 | struct net_device *dev; |
375 | u32 flags; | 380 | u32 flags; |
376 | 381 | ||
382 | memset(¶ms, 0, sizeof(params)); | ||
383 | |||
377 | if (info->attrs[NL80211_ATTR_IFTYPE]) { | 384 | if (info->attrs[NL80211_ATTR_IFTYPE]) { |
378 | type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | 385 | type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); |
379 | if (type > NL80211_IFTYPE_MAX) | 386 | if (type > NL80211_IFTYPE_MAX) |
@@ -392,12 +399,18 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
392 | goto unlock; | 399 | goto unlock; |
393 | } | 400 | } |
394 | 401 | ||
402 | if (type == NL80211_IFTYPE_MESH_POINT && | ||
403 | info->attrs[NL80211_ATTR_MESH_ID]) { | ||
404 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | ||
405 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | ||
406 | } | ||
407 | |||
395 | rtnl_lock(); | 408 | rtnl_lock(); |
396 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 409 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
397 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | 410 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, |
398 | &flags); | 411 | &flags); |
399 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, | 412 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, |
400 | type, err ? NULL : &flags); | 413 | type, err ? NULL : &flags, ¶ms); |
401 | rtnl_unlock(); | 414 | rtnl_unlock(); |
402 | 415 | ||
403 | unlock: | 416 | unlock: |
@@ -408,10 +421,13 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
408 | static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | 421 | static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) |
409 | { | 422 | { |
410 | struct cfg80211_registered_device *drv; | 423 | struct cfg80211_registered_device *drv; |
424 | struct vif_params params; | ||
411 | int err; | 425 | int err; |
412 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; | 426 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
413 | u32 flags; | 427 | u32 flags; |
414 | 428 | ||
429 | memset(¶ms, 0, sizeof(params)); | ||
430 | |||
415 | if (!info->attrs[NL80211_ATTR_IFNAME]) | 431 | if (!info->attrs[NL80211_ATTR_IFNAME]) |
416 | return -EINVAL; | 432 | return -EINVAL; |
417 | 433 | ||
@@ -430,15 +446,22 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
430 | goto unlock; | 446 | goto unlock; |
431 | } | 447 | } |
432 | 448 | ||
449 | if (type == NL80211_IFTYPE_MESH_POINT && | ||
450 | info->attrs[NL80211_ATTR_MESH_ID]) { | ||
451 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | ||
452 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | ||
453 | } | ||
454 | |||
433 | rtnl_lock(); | 455 | rtnl_lock(); |
434 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 456 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
435 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | 457 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, |
436 | &flags); | 458 | &flags); |
437 | err = drv->ops->add_virtual_intf(&drv->wiphy, | 459 | err = drv->ops->add_virtual_intf(&drv->wiphy, |
438 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 460 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
439 | type, err ? NULL : &flags); | 461 | type, err ? NULL : &flags, ¶ms); |
440 | rtnl_unlock(); | 462 | rtnl_unlock(); |
441 | 463 | ||
464 | |||
442 | unlock: | 465 | unlock: |
443 | cfg80211_put_dev(drv); | 466 | cfg80211_put_dev(drv); |
444 | return err; | 467 | return err; |
@@ -866,10 +889,10 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags) | |||
866 | 889 | ||
867 | static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | 890 | static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, |
868 | int flags, struct net_device *dev, | 891 | int flags, struct net_device *dev, |
869 | u8 *mac_addr, struct station_stats *stats) | 892 | u8 *mac_addr, struct station_info *sinfo) |
870 | { | 893 | { |
871 | void *hdr; | 894 | void *hdr; |
872 | struct nlattr *statsattr; | 895 | struct nlattr *sinfoattr; |
873 | 896 | ||
874 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); | 897 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); |
875 | if (!hdr) | 898 | if (!hdr) |
@@ -878,20 +901,29 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
878 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 901 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
879 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | 902 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
880 | 903 | ||
881 | statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS); | 904 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); |
882 | if (!statsattr) | 905 | if (!sinfoattr) |
883 | goto nla_put_failure; | 906 | goto nla_put_failure; |
884 | if (stats->filled & STATION_STAT_INACTIVE_TIME) | 907 | if (sinfo->filled & STATION_INFO_INACTIVE_TIME) |
885 | NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME, | 908 | NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME, |
886 | stats->inactive_time); | 909 | sinfo->inactive_time); |
887 | if (stats->filled & STATION_STAT_RX_BYTES) | 910 | if (sinfo->filled & STATION_INFO_RX_BYTES) |
888 | NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES, | 911 | NLA_PUT_U32(msg, NL80211_STA_INFO_RX_BYTES, |
889 | stats->rx_bytes); | 912 | sinfo->rx_bytes); |
890 | if (stats->filled & STATION_STAT_TX_BYTES) | 913 | if (sinfo->filled & STATION_INFO_TX_BYTES) |
891 | NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES, | 914 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_BYTES, |
892 | stats->tx_bytes); | 915 | sinfo->tx_bytes); |
893 | 916 | if (sinfo->filled & STATION_INFO_LLID) | |
894 | nla_nest_end(msg, statsattr); | 917 | NLA_PUT_U16(msg, NL80211_STA_INFO_LLID, |
918 | sinfo->llid); | ||
919 | if (sinfo->filled & STATION_INFO_PLID) | ||
920 | NLA_PUT_U16(msg, NL80211_STA_INFO_PLID, | ||
921 | sinfo->plid); | ||
922 | if (sinfo->filled & STATION_INFO_PLINK_STATE) | ||
923 | NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE, | ||
924 | sinfo->plink_state); | ||
925 | |||
926 | nla_nest_end(msg, sinfoattr); | ||
895 | 927 | ||
896 | return genlmsg_end(msg, hdr); | 928 | return genlmsg_end(msg, hdr); |
897 | 929 | ||
@@ -899,17 +931,80 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
899 | return genlmsg_cancel(msg, hdr); | 931 | return genlmsg_cancel(msg, hdr); |
900 | } | 932 | } |
901 | 933 | ||
934 | static int nl80211_dump_station(struct sk_buff *skb, | ||
935 | struct netlink_callback *cb) | ||
936 | { | ||
937 | int wp_idx = 0; | ||
938 | int if_idx = 0; | ||
939 | int sta_idx = cb->args[2]; | ||
940 | int wp_start = cb->args[0]; | ||
941 | int if_start = cb->args[1]; | ||
942 | struct station_info sinfo; | ||
943 | struct cfg80211_registered_device *dev; | ||
944 | struct wireless_dev *wdev; | ||
945 | u8 mac_addr[ETH_ALEN]; | ||
946 | int err; | ||
947 | int exit = 0; | ||
948 | |||
949 | /* TODO: filter by device */ | ||
950 | mutex_lock(&cfg80211_drv_mutex); | ||
951 | list_for_each_entry(dev, &cfg80211_drv_list, list) { | ||
952 | if (exit) | ||
953 | break; | ||
954 | if (++wp_idx < wp_start) | ||
955 | continue; | ||
956 | if_idx = 0; | ||
957 | |||
958 | mutex_lock(&dev->devlist_mtx); | ||
959 | list_for_each_entry(wdev, &dev->netdev_list, list) { | ||
960 | if (exit) | ||
961 | break; | ||
962 | if (++if_idx < if_start) | ||
963 | continue; | ||
964 | if (!dev->ops->dump_station) | ||
965 | continue; | ||
966 | |||
967 | for (;; ++sta_idx) { | ||
968 | rtnl_lock(); | ||
969 | err = dev->ops->dump_station(&dev->wiphy, | ||
970 | wdev->netdev, sta_idx, mac_addr, | ||
971 | &sinfo); | ||
972 | rtnl_unlock(); | ||
973 | if (err) { | ||
974 | sta_idx = 0; | ||
975 | break; | ||
976 | } | ||
977 | if (nl80211_send_station(skb, | ||
978 | NETLINK_CB(cb->skb).pid, | ||
979 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
980 | wdev->netdev, mac_addr, | ||
981 | &sinfo) < 0) { | ||
982 | exit = 1; | ||
983 | break; | ||
984 | } | ||
985 | } | ||
986 | } | ||
987 | mutex_unlock(&dev->devlist_mtx); | ||
988 | } | ||
989 | mutex_unlock(&cfg80211_drv_mutex); | ||
990 | |||
991 | cb->args[0] = wp_idx; | ||
992 | cb->args[1] = if_idx; | ||
993 | cb->args[2] = sta_idx; | ||
994 | |||
995 | return skb->len; | ||
996 | } | ||
902 | 997 | ||
903 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | 998 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) |
904 | { | 999 | { |
905 | struct cfg80211_registered_device *drv; | 1000 | struct cfg80211_registered_device *drv; |
906 | int err; | 1001 | int err; |
907 | struct net_device *dev; | 1002 | struct net_device *dev; |
908 | struct station_stats stats; | 1003 | struct station_info sinfo; |
909 | struct sk_buff *msg; | 1004 | struct sk_buff *msg; |
910 | u8 *mac_addr = NULL; | 1005 | u8 *mac_addr = NULL; |
911 | 1006 | ||
912 | memset(&stats, 0, sizeof(stats)); | 1007 | memset(&sinfo, 0, sizeof(sinfo)); |
913 | 1008 | ||
914 | if (!info->attrs[NL80211_ATTR_MAC]) | 1009 | if (!info->attrs[NL80211_ATTR_MAC]) |
915 | return -EINVAL; | 1010 | return -EINVAL; |
@@ -926,15 +1021,18 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
926 | } | 1021 | } |
927 | 1022 | ||
928 | rtnl_lock(); | 1023 | rtnl_lock(); |
929 | err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats); | 1024 | err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo); |
930 | rtnl_unlock(); | 1025 | rtnl_unlock(); |
931 | 1026 | ||
1027 | if (err) | ||
1028 | goto out; | ||
1029 | |||
932 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 1030 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
933 | if (!msg) | 1031 | if (!msg) |
934 | goto out; | 1032 | goto out; |
935 | 1033 | ||
936 | if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, | 1034 | if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, |
937 | dev, mac_addr, &stats) < 0) | 1035 | dev, mac_addr, &sinfo) < 0) |
938 | goto out_free; | 1036 | goto out_free; |
939 | 1037 | ||
940 | err = genlmsg_unicast(msg, info->snd_pid); | 1038 | err = genlmsg_unicast(msg, info->snd_pid); |
@@ -1005,6 +1103,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
1005 | ¶ms.station_flags)) | 1103 | ¶ms.station_flags)) |
1006 | return -EINVAL; | 1104 | return -EINVAL; |
1007 | 1105 | ||
1106 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) | ||
1107 | params.plink_action = | ||
1108 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | ||
1109 | |||
1008 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 1110 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); |
1009 | if (err) | 1111 | if (err) |
1010 | return err; | 1112 | return err; |
@@ -1119,6 +1221,273 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | |||
1119 | return err; | 1221 | return err; |
1120 | } | 1222 | } |
1121 | 1223 | ||
1224 | static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, | ||
1225 | int flags, struct net_device *dev, | ||
1226 | u8 *dst, u8 *next_hop, | ||
1227 | struct mpath_info *pinfo) | ||
1228 | { | ||
1229 | void *hdr; | ||
1230 | struct nlattr *pinfoattr; | ||
1231 | |||
1232 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); | ||
1233 | if (!hdr) | ||
1234 | return -1; | ||
1235 | |||
1236 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | ||
1237 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); | ||
1238 | NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); | ||
1239 | |||
1240 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); | ||
1241 | if (!pinfoattr) | ||
1242 | goto nla_put_failure; | ||
1243 | if (pinfo->filled & MPATH_INFO_FRAME_QLEN) | ||
1244 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, | ||
1245 | pinfo->frame_qlen); | ||
1246 | if (pinfo->filled & MPATH_INFO_DSN) | ||
1247 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_DSN, | ||
1248 | pinfo->dsn); | ||
1249 | if (pinfo->filled & MPATH_INFO_METRIC) | ||
1250 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, | ||
1251 | pinfo->metric); | ||
1252 | if (pinfo->filled & MPATH_INFO_EXPTIME) | ||
1253 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_EXPTIME, | ||
1254 | pinfo->exptime); | ||
1255 | if (pinfo->filled & MPATH_INFO_FLAGS) | ||
1256 | NLA_PUT_U8(msg, NL80211_MPATH_INFO_FLAGS, | ||
1257 | pinfo->flags); | ||
1258 | if (pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) | ||
1259 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, | ||
1260 | pinfo->discovery_timeout); | ||
1261 | if (pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) | ||
1262 | NLA_PUT_U8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES, | ||
1263 | pinfo->discovery_retries); | ||
1264 | |||
1265 | nla_nest_end(msg, pinfoattr); | ||
1266 | |||
1267 | return genlmsg_end(msg, hdr); | ||
1268 | |||
1269 | nla_put_failure: | ||
1270 | return genlmsg_cancel(msg, hdr); | ||
1271 | } | ||
1272 | |||
1273 | static int nl80211_dump_mpath(struct sk_buff *skb, | ||
1274 | struct netlink_callback *cb) | ||
1275 | { | ||
1276 | int wp_idx = 0; | ||
1277 | int if_idx = 0; | ||
1278 | int sta_idx = cb->args[2]; | ||
1279 | int wp_start = cb->args[0]; | ||
1280 | int if_start = cb->args[1]; | ||
1281 | struct mpath_info pinfo; | ||
1282 | struct cfg80211_registered_device *dev; | ||
1283 | struct wireless_dev *wdev; | ||
1284 | u8 dst[ETH_ALEN]; | ||
1285 | u8 next_hop[ETH_ALEN]; | ||
1286 | int err; | ||
1287 | int exit = 0; | ||
1288 | |||
1289 | /* TODO: filter by device */ | ||
1290 | mutex_lock(&cfg80211_drv_mutex); | ||
1291 | list_for_each_entry(dev, &cfg80211_drv_list, list) { | ||
1292 | if (exit) | ||
1293 | break; | ||
1294 | if (++wp_idx < wp_start) | ||
1295 | continue; | ||
1296 | if_idx = 0; | ||
1297 | |||
1298 | mutex_lock(&dev->devlist_mtx); | ||
1299 | list_for_each_entry(wdev, &dev->netdev_list, list) { | ||
1300 | if (exit) | ||
1301 | break; | ||
1302 | if (++if_idx < if_start) | ||
1303 | continue; | ||
1304 | if (!dev->ops->dump_mpath) | ||
1305 | continue; | ||
1306 | |||
1307 | for (;; ++sta_idx) { | ||
1308 | rtnl_lock(); | ||
1309 | err = dev->ops->dump_mpath(&dev->wiphy, | ||
1310 | wdev->netdev, sta_idx, dst, | ||
1311 | next_hop, &pinfo); | ||
1312 | rtnl_unlock(); | ||
1313 | if (err) { | ||
1314 | sta_idx = 0; | ||
1315 | break; | ||
1316 | } | ||
1317 | if (nl80211_send_mpath(skb, | ||
1318 | NETLINK_CB(cb->skb).pid, | ||
1319 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
1320 | wdev->netdev, dst, next_hop, | ||
1321 | &pinfo) < 0) { | ||
1322 | exit = 1; | ||
1323 | break; | ||
1324 | } | ||
1325 | } | ||
1326 | } | ||
1327 | mutex_unlock(&dev->devlist_mtx); | ||
1328 | } | ||
1329 | mutex_unlock(&cfg80211_drv_mutex); | ||
1330 | |||
1331 | cb->args[0] = wp_idx; | ||
1332 | cb->args[1] = if_idx; | ||
1333 | cb->args[2] = sta_idx; | ||
1334 | |||
1335 | return skb->len; | ||
1336 | } | ||
1337 | |||
1338 | static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | ||
1339 | { | ||
1340 | struct cfg80211_registered_device *drv; | ||
1341 | int err; | ||
1342 | struct net_device *dev; | ||
1343 | struct mpath_info pinfo; | ||
1344 | struct sk_buff *msg; | ||
1345 | u8 *dst = NULL; | ||
1346 | u8 next_hop[ETH_ALEN]; | ||
1347 | |||
1348 | memset(&pinfo, 0, sizeof(pinfo)); | ||
1349 | |||
1350 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
1351 | return -EINVAL; | ||
1352 | |||
1353 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
1354 | |||
1355 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
1356 | if (err) | ||
1357 | return err; | ||
1358 | |||
1359 | if (!drv->ops->get_mpath) { | ||
1360 | err = -EOPNOTSUPP; | ||
1361 | goto out; | ||
1362 | } | ||
1363 | |||
1364 | rtnl_lock(); | ||
1365 | err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo); | ||
1366 | rtnl_unlock(); | ||
1367 | |||
1368 | if (err) | ||
1369 | goto out; | ||
1370 | |||
1371 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
1372 | if (!msg) | ||
1373 | goto out; | ||
1374 | |||
1375 | if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, | ||
1376 | dev, dst, next_hop, &pinfo) < 0) | ||
1377 | goto out_free; | ||
1378 | |||
1379 | err = genlmsg_unicast(msg, info->snd_pid); | ||
1380 | goto out; | ||
1381 | |||
1382 | out_free: | ||
1383 | nlmsg_free(msg); | ||
1384 | |||
1385 | out: | ||
1386 | cfg80211_put_dev(drv); | ||
1387 | dev_put(dev); | ||
1388 | return err; | ||
1389 | } | ||
1390 | |||
1391 | static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) | ||
1392 | { | ||
1393 | struct cfg80211_registered_device *drv; | ||
1394 | int err; | ||
1395 | struct net_device *dev; | ||
1396 | u8 *dst = NULL; | ||
1397 | u8 *next_hop = NULL; | ||
1398 | |||
1399 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
1400 | return -EINVAL; | ||
1401 | |||
1402 | if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) | ||
1403 | return -EINVAL; | ||
1404 | |||
1405 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
1406 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | ||
1407 | |||
1408 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
1409 | if (err) | ||
1410 | return err; | ||
1411 | |||
1412 | if (!drv->ops->change_mpath) { | ||
1413 | err = -EOPNOTSUPP; | ||
1414 | goto out; | ||
1415 | } | ||
1416 | |||
1417 | rtnl_lock(); | ||
1418 | err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop); | ||
1419 | rtnl_unlock(); | ||
1420 | |||
1421 | out: | ||
1422 | cfg80211_put_dev(drv); | ||
1423 | dev_put(dev); | ||
1424 | return err; | ||
1425 | } | ||
1426 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | ||
1427 | { | ||
1428 | struct cfg80211_registered_device *drv; | ||
1429 | int err; | ||
1430 | struct net_device *dev; | ||
1431 | u8 *dst = NULL; | ||
1432 | u8 *next_hop = NULL; | ||
1433 | |||
1434 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
1435 | return -EINVAL; | ||
1436 | |||
1437 | if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) | ||
1438 | return -EINVAL; | ||
1439 | |||
1440 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
1441 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | ||
1442 | |||
1443 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
1444 | if (err) | ||
1445 | return err; | ||
1446 | |||
1447 | if (!drv->ops->add_mpath) { | ||
1448 | err = -EOPNOTSUPP; | ||
1449 | goto out; | ||
1450 | } | ||
1451 | |||
1452 | rtnl_lock(); | ||
1453 | err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop); | ||
1454 | rtnl_unlock(); | ||
1455 | |||
1456 | out: | ||
1457 | cfg80211_put_dev(drv); | ||
1458 | dev_put(dev); | ||
1459 | return err; | ||
1460 | } | ||
1461 | |||
1462 | static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) | ||
1463 | { | ||
1464 | struct cfg80211_registered_device *drv; | ||
1465 | int err; | ||
1466 | struct net_device *dev; | ||
1467 | u8 *dst = NULL; | ||
1468 | |||
1469 | if (info->attrs[NL80211_ATTR_MAC]) | ||
1470 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
1471 | |||
1472 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
1473 | if (err) | ||
1474 | return err; | ||
1475 | |||
1476 | if (!drv->ops->del_mpath) { | ||
1477 | err = -EOPNOTSUPP; | ||
1478 | goto out; | ||
1479 | } | ||
1480 | |||
1481 | rtnl_lock(); | ||
1482 | err = drv->ops->del_mpath(&drv->wiphy, dev, dst); | ||
1483 | rtnl_unlock(); | ||
1484 | |||
1485 | out: | ||
1486 | cfg80211_put_dev(drv); | ||
1487 | dev_put(dev); | ||
1488 | return err; | ||
1489 | } | ||
1490 | |||
1122 | static struct genl_ops nl80211_ops[] = { | 1491 | static struct genl_ops nl80211_ops[] = { |
1123 | { | 1492 | { |
1124 | .cmd = NL80211_CMD_GET_WIPHY, | 1493 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -1203,7 +1572,7 @@ static struct genl_ops nl80211_ops[] = { | |||
1203 | { | 1572 | { |
1204 | .cmd = NL80211_CMD_GET_STATION, | 1573 | .cmd = NL80211_CMD_GET_STATION, |
1205 | .doit = nl80211_get_station, | 1574 | .doit = nl80211_get_station, |
1206 | /* TODO: implement dumpit */ | 1575 | .dumpit = nl80211_dump_station, |
1207 | .policy = nl80211_policy, | 1576 | .policy = nl80211_policy, |
1208 | .flags = GENL_ADMIN_PERM, | 1577 | .flags = GENL_ADMIN_PERM, |
1209 | }, | 1578 | }, |
@@ -1225,6 +1594,31 @@ static struct genl_ops nl80211_ops[] = { | |||
1225 | .policy = nl80211_policy, | 1594 | .policy = nl80211_policy, |
1226 | .flags = GENL_ADMIN_PERM, | 1595 | .flags = GENL_ADMIN_PERM, |
1227 | }, | 1596 | }, |
1597 | { | ||
1598 | .cmd = NL80211_CMD_GET_MPATH, | ||
1599 | .doit = nl80211_get_mpath, | ||
1600 | .dumpit = nl80211_dump_mpath, | ||
1601 | .policy = nl80211_policy, | ||
1602 | .flags = GENL_ADMIN_PERM, | ||
1603 | }, | ||
1604 | { | ||
1605 | .cmd = NL80211_CMD_SET_MPATH, | ||
1606 | .doit = nl80211_set_mpath, | ||
1607 | .policy = nl80211_policy, | ||
1608 | .flags = GENL_ADMIN_PERM, | ||
1609 | }, | ||
1610 | { | ||
1611 | .cmd = NL80211_CMD_NEW_MPATH, | ||
1612 | .doit = nl80211_new_mpath, | ||
1613 | .policy = nl80211_policy, | ||
1614 | .flags = GENL_ADMIN_PERM, | ||
1615 | }, | ||
1616 | { | ||
1617 | .cmd = NL80211_CMD_DEL_MPATH, | ||
1618 | .doit = nl80211_del_mpath, | ||
1619 | .policy = nl80211_policy, | ||
1620 | .flags = GENL_ADMIN_PERM, | ||
1621 | }, | ||
1228 | }; | 1622 | }; |
1229 | 1623 | ||
1230 | /* multicast groups */ | 1624 | /* multicast groups */ |