Commit | Line | Data |
---|---|---|
68c0bdff HG |
1 | /******************************************************************************* |
2 | * Agere Systems Inc. | |
3 | * Wireless device driver for Linux (wlags49). | |
4 | * | |
5 | * Copyright (c) 1998-2003 Agere Systems Inc. | |
6 | * All rights reserved. | |
7 | * http://www.agere.com | |
8 | * | |
9 | * Initially developed by TriplePoint, Inc. | |
10 | * http://www.triplepoint.com | |
11 | * | |
12 | *------------------------------------------------------------------------------ | |
13 | * | |
14 | * SOFTWARE LICENSE | |
15 | * | |
16 | * This software is provided subject to the following terms and conditions, | |
17 | * which you should read carefully before using the software. Using this | |
18 | * software indicates your acceptance of these terms and conditions. If you do | |
19 | * not agree with these terms and conditions, do not use the software. | |
20 | * | |
d36b6910 | 21 | * Copyright © 2003 Agere Systems Inc. |
68c0bdff HG |
22 | * All rights reserved. |
23 | * | |
24 | * Redistribution and use in source or binary forms, with or without | |
25 | * modifications, are permitted provided that the following conditions are met: | |
26 | * | |
27 | * . Redistributions of source code must retain the above copyright notice, this | |
28 | * list of conditions and the following Disclaimer as comments in the code as | |
29 | * well as in the documentation and/or other materials provided with the | |
30 | * distribution. | |
31 | * | |
32 | * . Redistributions in binary form must reproduce the above copyright notice, | |
33 | * this list of conditions and the following Disclaimer in the documentation | |
34 | * and/or other materials provided with the distribution. | |
35 | * | |
36 | * . Neither the name of Agere Systems Inc. nor the names of the contributors | |
37 | * may be used to endorse or promote products derived from this software | |
38 | * without specific prior written permission. | |
39 | * | |
40 | * Disclaimer | |
41 | * | |
d36b6910 | 42 | * THIS SOFTWARE IS PROVIDED \93AS IS\94 AND ANY EXPRESS OR IMPLIED WARRANTIES, |
68c0bdff HG |
43 | * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF |
44 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY | |
45 | * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN | |
46 | * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY | |
47 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
48 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
49 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
50 | * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT | |
51 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
52 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | |
53 | * DAMAGE. | |
54 | * | |
55 | ******************************************************************************/ | |
56 | ||
68c0bdff HG |
57 | /******************************************************************************* |
58 | * include files | |
59 | ******************************************************************************/ | |
60 | #include <wl_version.h> | |
61 | ||
62 | #include <linux/if_arp.h> | |
63 | #include <linux/ioport.h> | |
64 | #include <linux/delay.h> | |
4f19b38f | 65 | #include <linux/etherdevice.h> |
68c0bdff HG |
66 | #include <asm/uaccess.h> |
67 | ||
68 | #include <debug.h> | |
69 | #include <hcf.h> | |
70 | #include <hcfdef.h> | |
71 | ||
72 | #include <wl_if.h> | |
73 | #include <wl_internal.h> | |
74 | #include <wl_util.h> | |
75 | #include <wl_main.h> | |
76 | #include <wl_wext.h> | |
77 | #include <wl_priv.h> | |
78 | ||
05df482e DK |
79 | /* Set up the LTV to program the appropriate key */ |
80 | static int hermes_set_tkip_keys(ltv_t *ltv, u16 key_idx, u8 *addr, | |
81 | int set_tx, u8 *seq, u8 *key, size_t key_len) | |
82 | { | |
83 | int ret = -EINVAL; | |
84 | int buf_idx = 0; | |
85 | hcf_8 tsc[IW_ENCODE_SEQ_MAX_SIZE] = | |
86 | { 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 }; | |
87 | ||
05df482e DK |
88 | /* |
89 | * Check the key index here; if 0, load as Pairwise Key, otherwise, | |
90 | * load as a group key. Note that for the Hermes, the RIDs for | |
91 | * group/pairwise keys are different from each other and different | |
92 | * than the default WEP keys as well. | |
93 | */ | |
94 | switch (key_idx) { | |
95 | case 0: | |
96 | ltv->len = 28; | |
97 | ltv->typ = CFG_ADD_TKIP_MAPPED_KEY; | |
98 | ||
99 | /* Load the BSSID */ | |
100 | memcpy(<v->u.u8[buf_idx], addr, ETH_ALEN); | |
101 | buf_idx += ETH_ALEN; | |
102 | ||
103 | /* Load the TKIP key */ | |
104 | memcpy(<v->u.u8[buf_idx], &key[0], 16); | |
105 | buf_idx += 16; | |
106 | ||
107 | /* Load the TSC */ | |
108 | memcpy(<v->u.u8[buf_idx], tsc, IW_ENCODE_SEQ_MAX_SIZE); | |
109 | buf_idx += IW_ENCODE_SEQ_MAX_SIZE; | |
110 | ||
111 | /* Load the RSC */ | |
112 | memcpy(<v->u.u8[buf_idx], seq, IW_ENCODE_SEQ_MAX_SIZE); | |
113 | buf_idx += IW_ENCODE_SEQ_MAX_SIZE; | |
114 | ||
115 | /* Load the TxMIC key */ | |
116 | memcpy(<v->u.u8[buf_idx], &key[16], 8); | |
117 | buf_idx += 8; | |
118 | ||
119 | /* Load the RxMIC key */ | |
120 | memcpy(<v->u.u8[buf_idx], &key[24], 8); | |
121 | ||
122 | ret = 0; | |
123 | break; | |
124 | case 1: | |
125 | case 2: | |
126 | case 3: | |
127 | ltv->len = 26; | |
128 | ltv->typ = CFG_ADD_TKIP_DEFAULT_KEY; | |
129 | ||
130 | /* Load the key Index */ | |
131 | ||
132 | /* If this is a Tx Key, set bit 8000 */ | |
133 | if (set_tx) | |
134 | key_idx |= 0x8000; | |
135 | ltv->u.u16[buf_idx] = cpu_to_le16(key_idx); | |
136 | buf_idx += 2; | |
137 | ||
138 | /* Load the RSC */ | |
139 | memcpy(<v->u.u8[buf_idx], seq, IW_ENCODE_SEQ_MAX_SIZE); | |
140 | buf_idx += IW_ENCODE_SEQ_MAX_SIZE; | |
141 | ||
142 | /* Load the TKIP, TxMIC, and RxMIC keys in one shot, because in | |
143 | CFG_ADD_TKIP_DEFAULT_KEY they are back-to-back */ | |
144 | memcpy(<v->u.u8[buf_idx], key, key_len); | |
145 | buf_idx += key_len; | |
146 | ||
147 | /* Load the TSC */ | |
148 | memcpy(<v->u.u8[buf_idx], tsc, IW_ENCODE_SEQ_MAX_SIZE); | |
149 | ||
150 | ret = 0; | |
151 | break; | |
152 | default: | |
153 | break; | |
154 | } | |
155 | ||
05df482e DK |
156 | return ret; |
157 | } | |
158 | ||
159 | /* Set up the LTV to clear the appropriate key */ | |
160 | static int hermes_clear_tkip_keys(ltv_t *ltv, u16 key_idx, u8 *addr) | |
161 | { | |
162 | int ret; | |
163 | ||
164 | switch (key_idx) { | |
165 | case 0: | |
4f19b38f | 166 | if (!is_broadcast_ether_addr(addr)) { |
05df482e DK |
167 | ltv->len = 7; |
168 | ltv->typ = CFG_REMOVE_TKIP_MAPPED_KEY; | |
169 | memcpy(<v->u.u8[0], addr, ETH_ALEN); | |
170 | ret = 0; | |
171 | } | |
172 | break; | |
173 | case 1: | |
174 | case 2: | |
175 | case 3: | |
176 | /* Clear the Group TKIP keys by index */ | |
177 | ltv->len = 2; | |
178 | ltv->typ = CFG_REMOVE_TKIP_DEFAULT_KEY; | |
179 | ltv->u.u16[0] = cpu_to_le16(key_idx); | |
180 | ||
181 | ret = 0; | |
182 | break; | |
183 | default: | |
184 | break; | |
185 | } | |
186 | ||
187 | return ret; | |
188 | } | |
189 | ||
190 | /* Set the WEP keys in the wl_private structure */ | |
191 | static int hermes_set_wep_keys(struct wl_private *lp, u16 key_idx, | |
192 | u8 *key, size_t key_len, | |
193 | bool enable, bool set_tx) | |
194 | { | |
195 | hcf_8 encryption_state = lp->EnableEncryption; | |
196 | int tk = lp->TransmitKeyID - 1; /* current key */ | |
197 | int ret = 0; | |
198 | ||
199 | /* Is encryption supported? */ | |
200 | if (!wl_has_wep(&(lp->hcfCtx))) { | |
201 | DBG_WARNING(DbgInfo, "WEP not supported on this device\n"); | |
202 | ret = -EOPNOTSUPP; | |
203 | goto out; | |
204 | } | |
205 | ||
206 | DBG_NOTICE(DbgInfo, "pointer: %p, length: %d\n", | |
207 | key, key_len); | |
208 | ||
209 | /* Check the size of the key */ | |
210 | switch (key_len) { | |
211 | case MIN_KEY_SIZE: | |
212 | case MAX_KEY_SIZE: | |
213 | ||
214 | /* Check the index */ | |
215 | if ((key_idx < 0) || (key_idx >= MAX_KEYS)) | |
216 | key_idx = tk; | |
217 | ||
218 | /* Cleanup */ | |
219 | memset(lp->DefaultKeys.key[key_idx].key, 0, MAX_KEY_SIZE); | |
220 | ||
221 | /* Copy the key in the driver */ | |
222 | memcpy(lp->DefaultKeys.key[key_idx].key, key, key_len); | |
223 | ||
224 | /* Set the length */ | |
225 | lp->DefaultKeys.key[key_idx].len = key_len; | |
226 | ||
227 | DBG_NOTICE(DbgInfo, "encoding.length: %d\n", key_len); | |
228 | DBG_NOTICE(DbgInfo, "set key: %s(%d) [%d]\n", | |
229 | lp->DefaultKeys.key[key_idx].key, | |
230 | lp->DefaultKeys.key[key_idx].len, key_idx); | |
231 | ||
232 | /* Enable WEP (if possible) */ | |
233 | if ((key_idx == tk) && (lp->DefaultKeys.key[tk].len > 0)) | |
234 | lp->EnableEncryption = 1; | |
235 | ||
236 | break; | |
237 | ||
238 | case 0: | |
239 | /* Do we want to just set the current transmit key? */ | |
240 | if (set_tx && (key_idx >= 0) && (key_idx < MAX_KEYS)) { | |
241 | DBG_NOTICE(DbgInfo, "index: %d; len: %d\n", key_idx, | |
242 | lp->DefaultKeys.key[key_idx].len); | |
243 | ||
244 | if (lp->DefaultKeys.key[key_idx].len > 0) { | |
245 | lp->TransmitKeyID = key_idx + 1; | |
246 | lp->EnableEncryption = 1; | |
247 | } else { | |
248 | DBG_WARNING(DbgInfo, "Problem setting the current TxKey\n"); | |
249 | ret = -EINVAL; | |
250 | } | |
251 | } | |
252 | break; | |
253 | ||
254 | default: | |
255 | DBG_WARNING(DbgInfo, "Invalid Key length\n"); | |
256 | ret = -EINVAL; | |
257 | goto out; | |
258 | } | |
68c0bdff | 259 | |
05df482e DK |
260 | /* Read the flags */ |
261 | if (enable) { | |
262 | lp->EnableEncryption = 1; | |
263 | lp->wext_enc = IW_ENCODE_ALG_WEP; | |
264 | } else { | |
265 | lp->EnableEncryption = 0; /* disable encryption */ | |
266 | lp->wext_enc = IW_ENCODE_ALG_NONE; | |
267 | } | |
268 | ||
269 | DBG_TRACE(DbgInfo, "encryption_state : %d\n", encryption_state); | |
270 | DBG_TRACE(DbgInfo, "lp->EnableEncryption : %d\n", lp->EnableEncryption); | |
271 | DBG_TRACE(DbgInfo, "erq->length : %d\n", key_len); | |
272 | ||
273 | /* Write the changes to the card */ | |
274 | if (ret == 0) { | |
275 | DBG_NOTICE(DbgInfo, "encrypt: %d, ID: %d\n", lp->EnableEncryption, | |
276 | lp->TransmitKeyID); | |
277 | ||
278 | if (lp->EnableEncryption == encryption_state) { | |
279 | if (key_len != 0) { | |
280 | /* Dynamic WEP key update */ | |
281 | wl_set_wep_keys(lp); | |
282 | } | |
283 | } else { | |
284 | /* To switch encryption on/off, soft reset is | |
285 | * required */ | |
286 | wl_apply(lp); | |
287 | } | |
288 | } | |
289 | ||
290 | out: | |
291 | return ret; | |
292 | } | |
68c0bdff HG |
293 | |
294 | /******************************************************************************* | |
295 | * wireless_commit() | |
296 | ******************************************************************************* | |
297 | * | |
298 | * DESCRIPTION: | |
299 | * | |
300 | * Commit | |
301 | * protocol used. | |
302 | * | |
303 | * PARAMETERS: | |
304 | * | |
305 | * wrq - the wireless request buffer | |
306 | * | |
307 | * RETURNS: | |
308 | * | |
309 | * N/A | |
310 | * | |
311 | ******************************************************************************/ | |
312 | static int wireless_commit(struct net_device *dev, | |
313 | struct iw_request_info *info, | |
314 | union iwreq_data *rqu, char *extra) | |
315 | { | |
316 | struct wl_private *lp = wl_priv(dev); | |
317 | unsigned long flags; | |
318 | int ret = 0; | |
68c0bdff HG |
319 | |
320 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
321 | ret = -EBUSY; | |
322 | goto out; | |
323 | } | |
324 | ||
325 | wl_lock( lp, &flags ); | |
326 | ||
327 | wl_act_int_off( lp ); | |
328 | ||
329 | wl_apply(lp); | |
330 | ||
331 | wl_act_int_on( lp ); | |
332 | ||
333 | wl_unlock(lp, &flags); | |
334 | ||
335 | out: | |
68c0bdff HG |
336 | return ret; |
337 | } // wireless_commit | |
338 | /*============================================================================*/ | |
339 | ||
340 | ||
341 | ||
342 | ||
343 | /******************************************************************************* | |
344 | * wireless_get_protocol() | |
345 | ******************************************************************************* | |
346 | * | |
347 | * DESCRIPTION: | |
348 | * | |
349 | * Returns a vendor-defined string that should identify the wireless | |
350 | * protocol used. | |
351 | * | |
352 | * PARAMETERS: | |
353 | * | |
354 | * wrq - the wireless request buffer | |
355 | * | |
356 | * RETURNS: | |
357 | * | |
358 | * N/A | |
359 | * | |
360 | ******************************************************************************/ | |
361 | static int wireless_get_protocol(struct net_device *dev, struct iw_request_info *info, char *name, char *extra) | |
362 | { | |
68c0bdff HG |
363 | /* Originally, the driver was placing the string "Wireless" here. However, |
364 | the wireless extensions (/linux/wireless.h) indicate this string should | |
365 | describe the wireless protocol. */ | |
366 | ||
367 | strcpy(name, "IEEE 802.11b"); | |
368 | ||
68c0bdff HG |
369 | return 0; |
370 | } // wireless_get_protocol | |
371 | /*============================================================================*/ | |
372 | ||
373 | ||
374 | ||
375 | ||
376 | /******************************************************************************* | |
377 | * wireless_set_frequency() | |
378 | ******************************************************************************* | |
379 | * | |
380 | * DESCRIPTION: | |
381 | * | |
382 | * Sets the frequency (channel) on which the card should Tx/Rx. | |
383 | * | |
384 | * PARAMETERS: | |
385 | * | |
386 | * wrq - the wireless request buffer | |
387 | * lp - the device's private adapter structure | |
388 | * | |
389 | * RETURNS: | |
390 | * | |
391 | * 0 on success | |
392 | * errno value otherwise | |
393 | * | |
394 | ******************************************************************************/ | |
395 | static int wireless_set_frequency(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) | |
396 | { | |
397 | struct wl_private *lp = wl_priv(dev); | |
398 | unsigned long flags; | |
399 | int channel = 0; | |
400 | int ret = 0; | |
68c0bdff HG |
401 | |
402 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
403 | ret = -EBUSY; | |
404 | goto out; | |
405 | } | |
406 | ||
407 | if( !capable( CAP_NET_ADMIN )) { | |
408 | ret = -EPERM; | |
68c0bdff HG |
409 | return ret; |
410 | } | |
411 | ||
412 | ||
413 | /* If frequency specified, look up channel */ | |
414 | if( freq->e == 1 ) { | |
415 | int f = freq->m / 100000; | |
416 | channel = wl_get_chan_from_freq( f ); | |
417 | } | |
418 | ||
419 | ||
420 | /* Channel specified */ | |
421 | if( freq->e == 0 ) { | |
422 | channel = freq->m; | |
423 | } | |
424 | ||
425 | ||
426 | /* If the channel is an 802.11a channel, set Bit 8 */ | |
427 | if( channel > 14 ) { | |
428 | channel = channel | 0x100; | |
429 | } | |
430 | ||
431 | ||
432 | wl_lock( lp, &flags ); | |
433 | ||
434 | wl_act_int_off( lp ); | |
435 | ||
436 | lp->Channel = channel; | |
437 | ||
438 | ||
439 | /* Commit the adapter parameters */ | |
440 | wl_apply( lp ); | |
441 | ||
442 | /* Send an event that channel/freq has been set */ | |
443 | wl_wext_event_freq( lp->dev ); | |
444 | ||
445 | wl_act_int_on( lp ); | |
446 | ||
447 | wl_unlock(lp, &flags); | |
448 | ||
449 | out: | |
68c0bdff HG |
450 | return ret; |
451 | } // wireless_set_frequency | |
452 | /*============================================================================*/ | |
453 | ||
454 | ||
455 | ||
456 | ||
457 | /******************************************************************************* | |
458 | * wireless_get_frequency() | |
459 | ******************************************************************************* | |
460 | * | |
461 | * DESCRIPTION: | |
462 | * | |
463 | * Gets the frequency (channel) on which the card is Tx/Rx. | |
464 | * | |
465 | * PARAMETERS: | |
466 | * | |
467 | * wrq - the wireless request buffer | |
468 | * lp - the device's private adapter structure | |
469 | * | |
470 | * RETURNS: | |
471 | * | |
472 | * N/A | |
473 | * | |
474 | ******************************************************************************/ | |
475 | static int wireless_get_frequency(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) | |
476 | ||
477 | { | |
478 | struct wl_private *lp = wl_priv(dev); | |
479 | unsigned long flags; | |
480 | int ret = -1; | |
68c0bdff HG |
481 | |
482 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
483 | ret = -EBUSY; | |
484 | goto out; | |
485 | } | |
486 | ||
487 | wl_lock( lp, &flags ); | |
488 | ||
489 | wl_act_int_off( lp ); | |
490 | ||
491 | lp->ltvRecord.len = 2; | |
492 | lp->ltvRecord.typ = CFG_CUR_CHANNEL; | |
493 | ||
494 | ret = hcf_get_info( &(lp->hcfCtx), (LTVP)&( lp->ltvRecord )); | |
495 | if( ret == HCF_SUCCESS ) { | |
496 | hcf_16 channel = CNV_LITTLE_TO_INT( lp->ltvRecord.u.u16[0] ); | |
497 | ||
68c0bdff HG |
498 | freq->m = wl_get_freq_from_chan( channel ) * 100000; |
499 | freq->e = 1; | |
68c0bdff HG |
500 | } |
501 | ||
502 | wl_act_int_on( lp ); | |
503 | ||
504 | wl_unlock(lp, &flags); | |
505 | ||
506 | ret = (ret == HCF_SUCCESS ? 0 : -EFAULT); | |
507 | ||
508 | out: | |
68c0bdff HG |
509 | return ret; |
510 | } // wireless_get_frequency | |
511 | /*============================================================================*/ | |
512 | ||
513 | ||
514 | ||
515 | ||
516 | /******************************************************************************* | |
517 | * wireless_get_range() | |
518 | ******************************************************************************* | |
519 | * | |
520 | * DESCRIPTION: | |
521 | * | |
522 | * This function is used to provide misc info and statistics about the | |
523 | * wireless device. | |
524 | * | |
525 | * PARAMETERS: | |
526 | * | |
527 | * wrq - the wireless request buffer | |
528 | * lp - the device's private adapter structure | |
529 | * | |
530 | * RETURNS: | |
531 | * | |
532 | * 0 on success | |
533 | * errno value otherwise | |
534 | * | |
535 | ******************************************************************************/ | |
536 | static int wireless_get_range(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) | |
537 | { | |
538 | struct wl_private *lp = wl_priv(dev); | |
539 | unsigned long flags; | |
540 | struct iw_range *range = (struct iw_range *) extra; | |
541 | int ret = 0; | |
542 | int status = -1; | |
543 | int count; | |
544 | __u16 *pTxRate; | |
545 | int retries = 0; | |
68c0bdff HG |
546 | |
547 | /* Set range information */ | |
548 | data->length = sizeof(struct iw_range); | |
549 | memset(range, 0, sizeof(struct iw_range)); | |
550 | ||
551 | wl_lock( lp, &flags ); | |
552 | ||
553 | wl_act_int_off( lp ); | |
554 | ||
555 | /* Set range information */ | |
556 | memset( range, 0, sizeof( struct iw_range )); | |
557 | ||
558 | retry: | |
559 | /* Get the current transmit rate from the adapter */ | |
560 | lp->ltvRecord.len = 1 + (sizeof(*pTxRate) / sizeof(hcf_16)); | |
561 | lp->ltvRecord.typ = CFG_CUR_TX_RATE; | |
562 | ||
563 | status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); | |
564 | if( status != HCF_SUCCESS ) { | |
565 | /* Recovery action: reset and retry up to 10 times */ | |
566 | DBG_TRACE( DbgInfo, "Get CFG_CUR_TX_RATE failed: 0x%x\n", status ); | |
567 | ||
568 | if (retries < 10) { | |
569 | retries++; | |
570 | ||
86f9150c | 571 | /* Holding the lock too long, makes a gap to allow other processes */ |
68c0bdff HG |
572 | wl_unlock(lp, &flags); |
573 | wl_lock( lp, &flags ); | |
574 | ||
575 | status = wl_reset( dev ); | |
576 | if ( status != HCF_SUCCESS ) { | |
577 | DBG_TRACE( DbgInfo, "reset failed: 0x%x\n", status ); | |
578 | ||
579 | ret = -EFAULT; | |
580 | goto out_unlock; | |
581 | } | |
582 | ||
86f9150c | 583 | /* Holding the lock too long, makes a gap to allow other processes */ |
68c0bdff HG |
584 | wl_unlock(lp, &flags); |
585 | wl_lock( lp, &flags ); | |
586 | ||
587 | goto retry; | |
588 | ||
589 | } else { | |
590 | DBG_TRACE( DbgInfo, "Get CFG_CUR_TX_RATE failed: %d retries\n", retries ); | |
591 | ret = -EFAULT; | |
592 | goto out_unlock; | |
593 | } | |
594 | } | |
595 | ||
86f9150c | 596 | /* Holding the lock too long, makes a gap to allow other processes */ |
68c0bdff HG |
597 | wl_unlock(lp, &flags); |
598 | wl_lock( lp, &flags ); | |
599 | ||
600 | pTxRate = (__u16 *)&( lp->ltvRecord.u.u32 ); | |
601 | ||
602 | range->throughput = CNV_LITTLE_TO_INT( *pTxRate ) * MEGABIT; | |
603 | ||
604 | if (retries > 0) { | |
605 | DBG_TRACE( DbgInfo, "Get CFG_CUR_TX_RATE succes: %d retries\n", retries ); | |
606 | } | |
607 | ||
608 | // NWID - NOT SUPPORTED | |
609 | ||
610 | ||
611 | /* Channel/Frequency Info */ | |
612 | range->num_channels = RADIO_CHANNELS; | |
613 | ||
614 | ||
615 | /* Signal Level Thresholds */ | |
616 | range->sensitivity = RADIO_SENSITIVITY_LEVELS; | |
617 | ||
618 | ||
619 | /* Link quality */ | |
68c0bdff HG |
620 | range->max_qual.qual = (u_char)HCF_MAX_COMM_QUALITY; |
621 | ||
622 | /* If the value returned in /proc/net/wireless is greater than the maximum range, | |
623 | iwconfig assumes that the value is in dBm. Because an unsigned char is used, | |
624 | it requires a bit of contorsion... */ | |
625 | ||
626 | range->max_qual.level = (u_char)( dbm( HCF_MIN_SIGNAL_LEVEL ) - 1 ); | |
627 | range->max_qual.noise = (u_char)( dbm( HCF_MIN_NOISE_LEVEL ) - 1 ); | |
68c0bdff HG |
628 | |
629 | ||
630 | /* Set available rates */ | |
631 | range->num_bitrates = 0; | |
632 | ||
633 | lp->ltvRecord.len = 6; | |
634 | lp->ltvRecord.typ = CFG_SUPPORTED_DATA_RATES; | |
635 | ||
636 | status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); | |
637 | if( status == HCF_SUCCESS ) { | |
638 | for( count = 0; count < MAX_RATES; count++ ) | |
639 | if( lp->ltvRecord.u.u8[count+2] != 0 ) { | |
640 | range->bitrate[count] = lp->ltvRecord.u.u8[count+2] * MEGABIT / 2; | |
641 | range->num_bitrates++; | |
642 | } | |
643 | } else { | |
644 | DBG_TRACE( DbgInfo, "CFG_SUPPORTED_DATA_RATES: 0x%x\n", status ); | |
645 | ret = -EFAULT; | |
646 | goto out_unlock; | |
647 | } | |
648 | ||
649 | /* RTS Threshold info */ | |
650 | range->min_rts = MIN_RTS_BYTES; | |
651 | range->max_rts = MAX_RTS_BYTES; | |
652 | ||
653 | // Frag Threshold info - NOT SUPPORTED | |
654 | ||
655 | // Power Management info - NOT SUPPORTED | |
656 | ||
657 | /* Encryption */ | |
658 | ||
86f9150c | 659 | /* Holding the lock too long, makes a gap to allow other processes */ |
68c0bdff HG |
660 | wl_unlock(lp, &flags); |
661 | wl_lock( lp, &flags ); | |
662 | ||
663 | /* Is WEP supported? */ | |
664 | ||
665 | if( wl_has_wep( &( lp->hcfCtx ))) { | |
666 | /* WEP: RC4 40 bits */ | |
667 | range->encoding_size[0] = MIN_KEY_SIZE; | |
668 | ||
669 | /* RC4 ~128 bits */ | |
670 | range->encoding_size[1] = MAX_KEY_SIZE; | |
671 | range->num_encoding_sizes = 2; | |
672 | range->max_encoding_tokens = MAX_KEYS; | |
673 | } | |
674 | ||
68c0bdff HG |
675 | /* Tx Power Info */ |
676 | range->txpower_capa = IW_TXPOW_MWATT; | |
677 | range->num_txpower = 1; | |
678 | range->txpower[0] = RADIO_TX_POWER_MWATT; | |
679 | ||
68c0bdff HG |
680 | /* Wireless Extension Info */ |
681 | range->we_version_compiled = WIRELESS_EXT; | |
682 | range->we_version_source = WIRELESS_SUPPORT; | |
683 | ||
684 | // Retry Limits and Lifetime - NOT SUPPORTED | |
685 | ||
86f9150c | 686 | /* Holding the lock too long, makes a gap to allow other processes */ |
68c0bdff HG |
687 | wl_unlock(lp, &flags); |
688 | wl_lock( lp, &flags ); | |
689 | ||
690 | DBG_TRACE( DbgInfo, "calling wl_wireless_stats\n" ); | |
691 | wl_wireless_stats( lp->dev ); | |
692 | range->avg_qual = lp->wstats.qual; | |
693 | DBG_TRACE( DbgInfo, "wl_wireless_stats done\n" ); | |
694 | ||
68c0bdff | 695 | /* Event capability (kernel + driver) */ |
87063460 DK |
696 | IW_EVENT_CAPA_SET_KERNEL(range->event_capa); |
697 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); | |
698 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); | |
699 | IW_EVENT_CAPA_SET(range->event_capa, IWEVREGISTERED); | |
700 | IW_EVENT_CAPA_SET(range->event_capa, IWEVEXPIRED); | |
701 | IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE); | |
702 | IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCREQIE); | |
703 | IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCRESPIE); | |
68c0bdff HG |
704 | |
705 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP; | |
87063460 | 706 | range->scan_capa = IW_SCAN_CAPA_NONE; |
68c0bdff HG |
707 | |
708 | out_unlock: | |
709 | wl_act_int_on( lp ); | |
710 | ||
711 | wl_unlock(lp, &flags); | |
712 | ||
68c0bdff HG |
713 | return ret; |
714 | } // wireless_get_range | |
715 | /*============================================================================*/ | |
716 | ||
717 | ||
718 | /******************************************************************************* | |
719 | * wireless_get_bssid() | |
720 | ******************************************************************************* | |
721 | * | |
722 | * DESCRIPTION: | |
723 | * | |
724 | * Gets the BSSID the wireless device is currently associated with. | |
725 | * | |
726 | * PARAMETERS: | |
727 | * | |
728 | * wrq - the wireless request buffer | |
729 | * lp - the device's private adapter structure | |
730 | * | |
731 | * RETURNS: | |
732 | * | |
733 | * 0 on success | |
734 | * errno value otherwise | |
735 | * | |
736 | ******************************************************************************/ | |
737 | static int wireless_get_bssid(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) | |
738 | { | |
739 | struct wl_private *lp = wl_priv(dev); | |
740 | unsigned long flags; | |
741 | int ret = 0; | |
742 | #if 1 //;? (HCF_TYPE) & HCF_TYPE_STA | |
743 | int status = -1; | |
744 | #endif /* (HCF_TYPE) & HCF_TYPE_STA */ | |
68c0bdff HG |
745 | |
746 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
747 | ret = -EBUSY; | |
748 | goto out; | |
749 | } | |
750 | ||
751 | wl_lock( lp, &flags ); | |
752 | ||
753 | wl_act_int_off( lp ); | |
754 | ||
68c0bdff HG |
755 | ap_addr->sa_family = ARPHRD_ETHER; |
756 | ||
757 | /* Assume AP mode here, which means the BSSID is our own MAC address. In | |
758 | STA mode, this address will be overwritten with the actual BSSID using | |
759 | the code below. */ | |
760 | memcpy(&ap_addr->sa_data, lp->dev->dev_addr, ETH_ALEN); | |
761 | ||
762 | ||
763 | #if 1 //;? (HCF_TYPE) & HCF_TYPE_STA | |
764 | //;?should we return an error status in AP mode | |
765 | ||
766 | if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_STA ) { | |
767 | /* Get Current BSSID */ | |
768 | lp->ltvRecord.typ = CFG_CUR_BSSID; | |
769 | lp->ltvRecord.len = 4; | |
770 | status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); | |
771 | ||
772 | if( status == HCF_SUCCESS ) { | |
773 | /* Copy info into sockaddr struct */ | |
774 | memcpy(&ap_addr->sa_data, lp->ltvRecord.u.u8, ETH_ALEN); | |
775 | } else { | |
776 | ret = -EFAULT; | |
777 | } | |
778 | } | |
779 | ||
780 | #endif // (HCF_TYPE) & HCF_TYPE_STA | |
781 | ||
782 | wl_act_int_on( lp ); | |
783 | ||
784 | wl_unlock(lp, &flags); | |
785 | ||
786 | out: | |
68c0bdff HG |
787 | return ret; |
788 | } // wireless_get_bssid | |
789 | /*============================================================================*/ | |
790 | ||
791 | ||
792 | ||
793 | ||
794 | /******************************************************************************* | |
795 | * wireless_get_ap_list() | |
796 | ******************************************************************************* | |
797 | * | |
798 | * DESCRIPTION: | |
799 | * | |
800 | * Gets the results of a network scan. | |
801 | * | |
802 | * PARAMETERS: | |
803 | * | |
804 | * wrq - the wireless request buffer | |
805 | * lp - the device's private adapter structure | |
806 | * | |
807 | * RETURNS: | |
808 | * | |
809 | * 0 on success | |
810 | * errno value otherwise | |
811 | * | |
812 | * NOTE: SIOCGIWAPLIST has been deprecated by SIOCSIWSCAN. This function | |
813 | * implements SIOCGIWAPLIST only to provide backwards compatibility. For | |
814 | * all systems using WIRELESS_EXT v14 and higher, use SIOCSIWSCAN! | |
815 | * | |
816 | ******************************************************************************/ | |
817 | static int wireless_get_ap_list (struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) | |
818 | { | |
819 | struct wl_private *lp = wl_priv(dev); | |
820 | unsigned long flags; | |
821 | int ret; | |
822 | int num_aps = -1; | |
823 | int sec_count = 0; | |
824 | hcf_32 count; | |
825 | struct sockaddr *hwa = NULL; | |
826 | struct iw_quality *qual = NULL; | |
827 | #ifdef WARP | |
828 | ScanResult *p = &lp->scan_results; | |
829 | #else | |
830 | ProbeResult *p = &lp->probe_results; | |
831 | #endif // WARP | |
68c0bdff HG |
832 | |
833 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
834 | ret = -EBUSY; | |
835 | goto out; | |
836 | } | |
837 | ||
838 | wl_lock( lp, &flags ); | |
839 | ||
840 | wl_act_int_off( lp ); | |
841 | ||
842 | /* Set the completion state to FALSE */ | |
843 | lp->scan_results.scan_complete = FALSE; | |
844 | lp->probe_results.scan_complete = FALSE; | |
845 | /* Channels to scan */ | |
846 | lp->ltvRecord.len = 2; | |
847 | lp->ltvRecord.typ = CFG_SCAN_CHANNELS_2GHZ; | |
848 | lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0x7FFF ); | |
849 | ret = hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); | |
850 | DBG_TRACE( DbgInfo, "CFG_SCAN_CHANNELS_2GHZ result: 0x%x\n", ret ); | |
851 | ||
852 | /* Set the SCAN_SSID to "ANY". Using this RID for scan prevents the need to | |
853 | disassociate from the network we are currently on */ | |
854 | lp->ltvRecord.len = 2; | |
855 | lp->ltvRecord.typ = CFG_SCAN_SSID; | |
856 | lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0 ); | |
857 | ret = hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); | |
858 | DBG_TRACE( DbgInfo, "CFG_SCAN_SSID to 'any' ret: 0x%x\n", ret ); | |
859 | ||
860 | /* Initiate the scan */ | |
861 | #ifdef WARP | |
862 | ret = hcf_action( &( lp->hcfCtx ), MDD_ACT_SCAN ); | |
863 | #else | |
864 | ret = hcf_action( &( lp->hcfCtx ), HCF_ACT_ACS_SCAN ); | |
865 | #endif // WARP | |
866 | ||
867 | wl_act_int_on( lp ); | |
868 | ||
869 | //;? unlock? what about the access to lp below? is it broken? | |
870 | wl_unlock(lp, &flags); | |
871 | ||
872 | if( ret == HCF_SUCCESS ) { | |
873 | DBG_TRACE( DbgInfo, "SUCCESSFULLY INITIATED SCAN...\n" ); | |
874 | while( (*p).scan_complete == FALSE && ret == HCF_SUCCESS ) { | |
875 | DBG_TRACE( DbgInfo, "Waiting for scan results...\n" ); | |
876 | /* Abort the scan if we've waited for more than MAX_SCAN_TIME_SEC */ | |
877 | if( sec_count++ > MAX_SCAN_TIME_SEC ) { | |
878 | ret = -EIO; | |
879 | } else { | |
880 | /* Wait for 1 sec in 10ms intervals, scheduling the kernel to do | |
881 | other things in the meantime, This prevents system lockups by | |
882 | giving some time back to the kernel */ | |
883 | for( count = 0; count < 100; count ++ ) { | |
884 | mdelay( 10 ); | |
885 | schedule( ); | |
886 | } | |
887 | } | |
888 | } | |
889 | ||
890 | rmb(); | |
891 | ||
892 | if ( ret != HCF_SUCCESS ) { | |
893 | DBG_ERROR( DbgInfo, "timeout waiting for scan results\n" ); | |
894 | } else { | |
895 | num_aps = (*p)/*lp->probe_results*/.num_aps; | |
896 | if (num_aps > IW_MAX_AP) { | |
897 | num_aps = IW_MAX_AP; | |
898 | } | |
899 | data->length = num_aps; | |
900 | hwa = (struct sockaddr *)extra; | |
901 | qual = (struct iw_quality *) extra + | |
902 | ( sizeof( struct sockaddr ) * num_aps ); | |
903 | ||
904 | /* This flag is used to tell the user if we provide quality | |
905 | information. Since we provide signal/noise levels but no | |
906 | quality info on a scan, this is set to 0. Setting to 1 and | |
907 | providing a quality of 0 produces weird results. If we ever | |
908 | provide quality (or can calculate it), this can be changed */ | |
909 | data->flags = 0; | |
910 | ||
911 | for( count = 0; count < num_aps; count++ ) { | |
912 | #ifdef WARP | |
913 | memcpy( hwa[count].sa_data, | |
914 | (*p)/*lp->scan_results*/.APTable[count].bssid, ETH_ALEN ); | |
915 | #else //;?why use BSSID and bssid as names in seemingly very comparable situations | |
2b6d83d6 AS |
916 | DBG_PRINT("BSSID: %pM\n", |
917 | (*p).ProbeTable[count].BSSID); | |
68c0bdff HG |
918 | memcpy( hwa[count].sa_data, |
919 | (*p)/*lp->probe_results*/.ProbeTable[count].BSSID, ETH_ALEN ); | |
920 | #endif // WARP | |
921 | } | |
922 | /* Once the data is copied to the wireless struct, invalidate the | |
923 | scan result to initiate a rescan on the next request */ | |
924 | (*p)/*lp->probe_results*/.scan_complete = FALSE; | |
925 | /* Send the wireless event that the scan has completed, just in case | |
926 | it's needed */ | |
927 | wl_wext_event_scan_complete( lp->dev ); | |
928 | } | |
929 | } | |
930 | out: | |
68c0bdff HG |
931 | return ret; |
932 | } // wireless_get_ap_list | |
933 | /*============================================================================*/ | |
934 | ||
935 | ||
936 | ||
937 | ||
938 | /******************************************************************************* | |
939 | * wireless_set_sensitivity() | |
940 | ******************************************************************************* | |
941 | * | |
942 | * DESCRIPTION: | |
943 | * | |
944 | * Sets the sensitivity (distance between APs) of the wireless card. | |
945 | * | |
946 | * PARAMETERS: | |
947 | * | |
948 | * wrq - the wireless request buffer | |
949 | * lp - the device's private adapter structure | |
950 | * | |
951 | * RETURNS: | |
952 | * | |
953 | * 0 on success | |
954 | * errno value otherwise | |
955 | * | |
956 | ******************************************************************************/ | |
957 | static int wireless_set_sensitivity(struct net_device *dev, struct iw_request_info *info, struct iw_param *sens, char *extra) | |
958 | { | |
959 | struct wl_private *lp = wl_priv(dev); | |
960 | unsigned long flags; | |
961 | int ret = 0; | |
962 | int dens = sens->value; | |
68c0bdff HG |
963 | |
964 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
965 | ret = -EBUSY; | |
966 | goto out; | |
967 | } | |
968 | ||
969 | if(( dens < 1 ) || ( dens > 3 )) { | |
970 | ret = -EINVAL; | |
971 | goto out; | |
972 | } | |
973 | ||
974 | wl_lock( lp, &flags ); | |
975 | ||
976 | wl_act_int_off( lp ); | |
977 | ||
978 | lp->DistanceBetweenAPs = dens; | |
979 | wl_apply( lp ); | |
980 | ||
981 | wl_act_int_on( lp ); | |
982 | ||
983 | wl_unlock(lp, &flags); | |
984 | ||
985 | out: | |
68c0bdff HG |
986 | return ret; |
987 | } // wireless_set_sensitivity | |
988 | /*============================================================================*/ | |
989 | ||
990 | ||
991 | ||
992 | ||
993 | /******************************************************************************* | |
994 | * wireless_get_sensitivity() | |
995 | ******************************************************************************* | |
996 | * | |
997 | * DESCRIPTION: | |
998 | * | |
999 | * Gets the sensitivity (distance between APs) of the wireless card. | |
1000 | * | |
1001 | * PARAMETERS: | |
1002 | * | |
1003 | * wrq - the wireless request buffer | |
1004 | * lp - the device's private adapter structure | |
1005 | * | |
1006 | * RETURNS: | |
1007 | * | |
1008 | * 0 on success | |
1009 | * errno value otherwise | |
1010 | * | |
1011 | ******************************************************************************/ | |
1012 | static int wireless_get_sensitivity(struct net_device *dev, struct iw_request_info *info, struct iw_param *sens, char *extra) | |
1013 | { | |
1014 | struct wl_private *lp = wl_priv(dev); | |
1015 | int ret = 0; | |
68c0bdff HG |
1016 | |
1017 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
1018 | ret = -EBUSY; | |
1019 | goto out; | |
1020 | } | |
1021 | ||
1022 | /* not worth locking ... */ | |
1023 | sens->value = lp->DistanceBetweenAPs; | |
1024 | sens->fixed = 0; /* auto */ | |
1025 | out: | |
68c0bdff HG |
1026 | return ret; |
1027 | } // wireless_get_sensitivity | |
1028 | /*============================================================================*/ | |
1029 | ||
1030 | ||
1031 | ||
1032 | ||
1033 | /******************************************************************************* | |
1034 | * wireless_set_essid() | |
1035 | ******************************************************************************* | |
1036 | * | |
1037 | * DESCRIPTION: | |
1038 | * | |
1039 | * Sets the ESSID (network name) that the wireless device should associate | |
1040 | * with. | |
1041 | * | |
1042 | * PARAMETERS: | |
1043 | * | |
1044 | * wrq - the wireless request buffer | |
1045 | * lp - the device's private adapter structure | |
1046 | * | |
1047 | * RETURNS: | |
1048 | * | |
1049 | * 0 on success | |
1050 | * errno value otherwise | |
1051 | * | |
1052 | ******************************************************************************/ | |
1053 | static int wireless_set_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid) | |
1054 | { | |
1055 | struct wl_private *lp = wl_priv(dev); | |
1056 | unsigned long flags; | |
1057 | int ret = 0; | |
1058 | ||
68c0bdff HG |
1059 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { |
1060 | ret = -EBUSY; | |
1061 | goto out; | |
1062 | } | |
1063 | ||
6b89db36 | 1064 | if (data->flags != 0 && data->length > HCF_MAX_NAME_LEN) { |
68c0bdff HG |
1065 | ret = -EINVAL; |
1066 | goto out; | |
1067 | } | |
1068 | ||
1069 | wl_lock( lp, &flags ); | |
1070 | ||
1071 | wl_act_int_off( lp ); | |
1072 | ||
1073 | memset( lp->NetworkName, 0, sizeof( lp->NetworkName )); | |
1074 | ||
1075 | /* data->flags is zero to ask for "any" */ | |
1076 | if( data->flags == 0 ) { | |
1077 | /* Need this because in STAP build PARM_DEFAULT_SSID is "LinuxAP" | |
1078 | * ;?but there ain't no STAP anymore*/ | |
1079 | if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_STA ) { | |
1080 | strcpy( lp->NetworkName, "ANY" ); | |
1081 | } else { | |
1082 | //strcpy( lp->NetworkName, "ANY" ); | |
1083 | strcpy( lp->NetworkName, PARM_DEFAULT_SSID ); | |
1084 | } | |
1085 | } else { | |
1086 | memcpy( lp->NetworkName, ssid, data->length ); | |
1087 | } | |
1088 | ||
1089 | DBG_NOTICE( DbgInfo, "set NetworkName: %s\n", ssid ); | |
1090 | ||
1091 | /* Commit the adapter parameters */ | |
1092 | wl_apply( lp ); | |
1093 | ||
1094 | /* Send an event that ESSID has been set */ | |
1095 | wl_wext_event_essid( lp->dev ); | |
1096 | ||
1097 | wl_act_int_on( lp ); | |
1098 | ||
1099 | wl_unlock(lp, &flags); | |
1100 | ||
1101 | out: | |
68c0bdff HG |
1102 | return ret; |
1103 | } // wireless_set_essid | |
1104 | /*============================================================================*/ | |
1105 | ||
1106 | ||
1107 | ||
1108 | ||
1109 | /******************************************************************************* | |
1110 | * wireless_get_essid() | |
1111 | ******************************************************************************* | |
1112 | * | |
1113 | * DESCRIPTION: | |
1114 | * | |
1115 | * Gets the ESSID (network name) that the wireless device is associated | |
1116 | * with. | |
1117 | * | |
1118 | * PARAMETERS: | |
1119 | * | |
1120 | * wrq - the wireless request buffer | |
1121 | * lp - the device's private adapter structure | |
1122 | * | |
1123 | * RETURNS: | |
1124 | * | |
1125 | * 0 on success | |
1126 | * errno value otherwise | |
1127 | * | |
1128 | ******************************************************************************/ | |
1129 | static int wireless_get_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *essid) | |
1130 | ||
1131 | { | |
1132 | struct wl_private *lp = wl_priv(dev); | |
1133 | unsigned long flags; | |
1134 | int ret = 0; | |
1135 | int status = -1; | |
1136 | wvName_t *pName; | |
68c0bdff HG |
1137 | |
1138 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
1139 | ret = -EBUSY; | |
1140 | goto out; | |
1141 | } | |
1142 | ||
1143 | wl_lock( lp, &flags ); | |
1144 | ||
1145 | wl_act_int_off( lp ); | |
1146 | ||
1147 | /* Get the desired network name */ | |
1148 | lp->ltvRecord.len = 1 + ( sizeof( *pName ) / sizeof( hcf_16 )); | |
1149 | ||
1150 | ||
1151 | #if 1 //;? (HCF_TYPE) & HCF_TYPE_STA | |
1152 | //;?should we return an error status in AP mode | |
1153 | ||
1154 | lp->ltvRecord.typ = CFG_DESIRED_SSID; | |
1155 | ||
1156 | #endif | |
1157 | ||
1158 | ||
1159 | #if 1 //;? (HCF_TYPE) & HCF_TYPE_AP | |
1160 | //;?should we restore this to allow smaller memory footprint | |
1161 | ||
1162 | if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) { | |
1163 | lp->ltvRecord.typ = CFG_CNF_OWN_SSID; | |
1164 | } | |
1165 | ||
1166 | #endif // HCF_AP | |
1167 | ||
1168 | ||
1169 | status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); | |
1170 | if( status == HCF_SUCCESS ) { | |
1171 | pName = (wvName_t *)&( lp->ltvRecord.u.u32 ); | |
1172 | ||
1173 | /* Endian translate the string length */ | |
1174 | pName->length = CNV_LITTLE_TO_INT( pName->length ); | |
1175 | ||
1176 | /* Copy the information into the user buffer */ | |
1177 | data->length = pName->length; | |
1178 | ||
68c0bdff HG |
1179 | if( pName->length < HCF_MAX_NAME_LEN ) { |
1180 | pName->name[pName->length] = '\0'; | |
1181 | } | |
1182 | ||
1183 | data->flags = 1; | |
1184 | ||
1185 | ||
1186 | #if 1 //;? (HCF_TYPE) & HCF_TYPE_STA | |
1187 | //;?should we return an error status in AP mode | |
68c0bdff HG |
1188 | |
1189 | /* if desired is null ("any"), return current or "any" */ | |
1190 | if( pName->name[0] == '\0' ) { | |
1191 | /* Get the current network name */ | |
1192 | lp->ltvRecord.len = 1 + ( sizeof(*pName ) / sizeof( hcf_16 )); | |
1193 | lp->ltvRecord.typ = CFG_CUR_SSID; | |
1194 | ||
1195 | status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); | |
1196 | ||
1197 | if( status == HCF_SUCCESS ) { | |
1198 | pName = (wvName_t *)&( lp->ltvRecord.u.u32 ); | |
1199 | ||
1200 | /* Endian translate the string length */ | |
1201 | pName->length = CNV_LITTLE_TO_INT( pName->length ); | |
1202 | ||
1203 | /* Copy the information into the user buffer */ | |
e7751b63 | 1204 | data->length = pName->length; |
68c0bdff HG |
1205 | data->flags = 1; |
1206 | } else { | |
1207 | ret = -EFAULT; | |
1208 | goto out_unlock; | |
1209 | } | |
1210 | } | |
1211 | ||
68c0bdff HG |
1212 | #endif // HCF_STA |
1213 | ||
68c0bdff HG |
1214 | if (pName->length > IW_ESSID_MAX_SIZE) { |
1215 | ret = -EFAULT; | |
1216 | goto out_unlock; | |
1217 | } | |
1218 | ||
1219 | memcpy(essid, pName->name, pName->length); | |
1220 | } else { | |
1221 | ret = -EFAULT; | |
1222 | goto out_unlock; | |
1223 | } | |
1224 | ||
1225 | out_unlock: | |
1226 | wl_act_int_on( lp ); | |
1227 | ||
1228 | wl_unlock(lp, &flags); | |
1229 | ||
1230 | out: | |
68c0bdff HG |
1231 | return ret; |
1232 | } // wireless_get_essid | |
1233 | /*============================================================================*/ | |
1234 | ||
1235 | ||
1236 | ||
1237 | ||
1238 | /******************************************************************************* | |
1239 | * wireless_set_encode() | |
1240 | ******************************************************************************* | |
1241 | * | |
1242 | * DESCRIPTION: | |
1243 | * | |
1244 | * Sets the encryption keys and status (enable or disable). | |
1245 | * | |
1246 | * PARAMETERS: | |
1247 | * | |
1248 | * wrq - the wireless request buffer | |
1249 | * lp - the device's private adapter structure | |
1250 | * | |
1251 | * RETURNS: | |
1252 | * | |
1253 | * 0 on success | |
1254 | * errno value otherwise | |
1255 | * | |
1256 | ******************************************************************************/ | |
1257 | static int wireless_set_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *keybuf) | |
1258 | { | |
1259 | struct wl_private *lp = wl_priv(dev); | |
1260 | unsigned long flags; | |
05df482e DK |
1261 | int key_idx = (erq->flags & IW_ENCODE_INDEX) - 1; |
1262 | int ret = 0; | |
1263 | bool enable = true; | |
68c0bdff | 1264 | |
05df482e | 1265 | if (lp->portState == WVLAN_PORT_STATE_DISABLED) { |
68c0bdff HG |
1266 | ret = -EBUSY; |
1267 | goto out; | |
1268 | } | |
1269 | ||
05df482e DK |
1270 | if (erq->flags & IW_ENCODE_DISABLED) |
1271 | enable = false; | |
68c0bdff | 1272 | |
05df482e | 1273 | wl_lock(lp, &flags); |
68c0bdff | 1274 | |
05df482e | 1275 | wl_act_int_off(lp); |
68c0bdff | 1276 | |
05df482e DK |
1277 | ret = hermes_set_wep_keys(lp, key_idx, keybuf, erq->length, |
1278 | enable, true); | |
68c0bdff HG |
1279 | |
1280 | /* Send an event that Encryption has been set */ | |
05df482e DK |
1281 | if (ret == 0) |
1282 | wl_wext_event_encode(dev); | |
68c0bdff | 1283 | |
05df482e | 1284 | wl_act_int_on(lp); |
68c0bdff HG |
1285 | |
1286 | wl_unlock(lp, &flags); | |
1287 | ||
1288 | out: | |
68c0bdff | 1289 | return ret; |
05df482e | 1290 | } |
68c0bdff HG |
1291 | |
1292 | /******************************************************************************* | |
1293 | * wireless_get_encode() | |
1294 | ******************************************************************************* | |
1295 | * | |
1296 | * DESCRIPTION: | |
1297 | * | |
1298 | * Gets the encryption keys and status. | |
1299 | * | |
1300 | * PARAMETERS: | |
1301 | * | |
1302 | * wrq - the wireless request buffer | |
1303 | * lp - the device's private adapter structure | |
1304 | * | |
1305 | * RETURNS: | |
1306 | * | |
1307 | * 0 on success | |
1308 | * errno value otherwise | |
1309 | * | |
1310 | ******************************************************************************/ | |
1311 | static int wireless_get_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *key) | |
1312 | ||
1313 | { | |
1314 | struct wl_private *lp = wl_priv(dev); | |
1315 | unsigned long flags; | |
1316 | int ret = 0; | |
1317 | int index; | |
68c0bdff | 1318 | |
68c0bdff HG |
1319 | DBG_NOTICE(DbgInfo, "GIWENCODE: encrypt: %d, ID: %d\n", lp->EnableEncryption, lp->TransmitKeyID); |
1320 | ||
1321 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
1322 | ret = -EBUSY; | |
1323 | goto out; | |
1324 | } | |
1325 | ||
1326 | /* Only super-user can see WEP key */ | |
1327 | if( !capable( CAP_NET_ADMIN )) { | |
1328 | ret = -EPERM; | |
68c0bdff HG |
1329 | return ret; |
1330 | } | |
1331 | ||
1332 | wl_lock( lp, &flags ); | |
1333 | ||
1334 | wl_act_int_off( lp ); | |
1335 | ||
1336 | /* Is it supported? */ | |
1337 | if( !wl_has_wep( &( lp->hcfCtx ))) { | |
1338 | ret = -EOPNOTSUPP; | |
1339 | goto out_unlock; | |
1340 | } | |
1341 | ||
1342 | /* Basic checking */ | |
1343 | index = (erq->flags & IW_ENCODE_INDEX ) - 1; | |
1344 | ||
1345 | ||
1346 | /* Set the flags */ | |
1347 | erq->flags = 0; | |
1348 | ||
1349 | if( lp->EnableEncryption == 0 ) { | |
1350 | erq->flags |= IW_ENCODE_DISABLED; | |
1351 | } | |
1352 | ||
1353 | /* Which key do we want */ | |
1354 | if(( index < 0 ) || ( index >= MAX_KEYS )) { | |
1355 | index = lp->TransmitKeyID - 1; | |
1356 | } | |
1357 | ||
1358 | erq->flags |= index + 1; | |
1359 | ||
1360 | /* Copy the key to the user buffer */ | |
1361 | erq->length = lp->DefaultKeys.key[index].len; | |
1362 | ||
1363 | memcpy(key, lp->DefaultKeys.key[index].key, erq->length); | |
1364 | ||
1365 | out_unlock: | |
1366 | ||
1367 | wl_act_int_on( lp ); | |
1368 | ||
1369 | wl_unlock(lp, &flags); | |
1370 | ||
1371 | out: | |
68c0bdff HG |
1372 | return ret; |
1373 | } // wireless_get_encode | |
1374 | /*============================================================================*/ | |
1375 | ||
1376 | ||
1377 | ||
1378 | ||
1379 | /******************************************************************************* | |
1380 | * wireless_set_nickname() | |
1381 | ******************************************************************************* | |
1382 | * | |
1383 | * DESCRIPTION: | |
1384 | * | |
1385 | * Sets the nickname, or station name, of the wireless device. | |
1386 | * | |
1387 | * PARAMETERS: | |
1388 | * | |
1389 | * wrq - the wireless request buffer | |
1390 | * lp - the device's private adapter structure | |
1391 | * | |
1392 | * RETURNS: | |
1393 | * | |
1394 | * 0 on success | |
1395 | * errno value otherwise | |
1396 | * | |
1397 | ******************************************************************************/ | |
1398 | static int wireless_set_nickname(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *nickname) | |
1399 | { | |
1400 | struct wl_private *lp = wl_priv(dev); | |
1401 | unsigned long flags; | |
1402 | int ret = 0; | |
68c0bdff HG |
1403 | |
1404 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
1405 | ret = -EBUSY; | |
1406 | goto out; | |
1407 | } | |
1408 | ||
1409 | #if 0 //;? Needed, was present in original code but not in 7.18 Linux 2.6 kernel version | |
1410 | if( !capable(CAP_NET_ADMIN )) { | |
1411 | ret = -EPERM; | |
68c0bdff HG |
1412 | return ret; |
1413 | } | |
1414 | #endif | |
1415 | ||
1416 | /* Validate the new value */ | |
1417 | if(data->length > HCF_MAX_NAME_LEN) { | |
1418 | ret = -EINVAL; | |
1419 | goto out; | |
1420 | } | |
1421 | ||
1422 | wl_lock( lp, &flags ); | |
1423 | ||
1424 | wl_act_int_off( lp ); | |
1425 | ||
1426 | memset( lp->StationName, 0, sizeof( lp->StationName )); | |
1427 | ||
1428 | memcpy( lp->StationName, nickname, data->length ); | |
1429 | ||
1430 | /* Commit the adapter parameters */ | |
1431 | wl_apply( lp ); | |
1432 | ||
1433 | wl_act_int_on( lp ); | |
1434 | ||
1435 | wl_unlock(lp, &flags); | |
1436 | ||
1437 | out: | |
68c0bdff HG |
1438 | return ret; |
1439 | } // wireless_set_nickname | |
1440 | /*============================================================================*/ | |
1441 | ||
1442 | ||
1443 | ||
1444 | ||
1445 | /******************************************************************************* | |
1446 | * wireless_get_nickname() | |
1447 | ******************************************************************************* | |
1448 | * | |
1449 | * DESCRIPTION: | |
1450 | * | |
1451 | * Gets the nickname, or station name, of the wireless device. | |
1452 | * | |
1453 | * PARAMETERS: | |
1454 | * | |
1455 | * wrq - the wireless request buffer | |
1456 | * lp - the device's private adapter structure | |
1457 | * | |
1458 | * RETURNS: | |
1459 | * | |
1460 | * 0 on success | |
1461 | * errno value otherwise | |
1462 | * | |
1463 | ******************************************************************************/ | |
1464 | static int wireless_get_nickname(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *nickname) | |
1465 | { | |
1466 | struct wl_private *lp = wl_priv(dev); | |
1467 | unsigned long flags; | |
1468 | int ret = 0; | |
1469 | int status = -1; | |
1470 | wvName_t *pName; | |
68c0bdff HG |
1471 | |
1472 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
1473 | ret = -EBUSY; | |
1474 | goto out; | |
1475 | } | |
1476 | ||
1477 | wl_lock( lp, &flags ); | |
1478 | ||
1479 | wl_act_int_off( lp ); | |
1480 | ||
1481 | /* Get the current station name */ | |
1482 | lp->ltvRecord.len = 1 + ( sizeof( *pName ) / sizeof( hcf_16 )); | |
1483 | lp->ltvRecord.typ = CFG_CNF_OWN_NAME; | |
1484 | ||
1485 | status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); | |
1486 | ||
1487 | if( status == HCF_SUCCESS ) { | |
1488 | pName = (wvName_t *)&( lp->ltvRecord.u.u32 ); | |
1489 | ||
1490 | /* Endian translate the length */ | |
1491 | pName->length = CNV_LITTLE_TO_INT( pName->length ); | |
1492 | ||
1493 | if ( pName->length > IW_ESSID_MAX_SIZE ) { | |
1494 | ret = -EFAULT; | |
1495 | } else { | |
1496 | /* Copy the information into the user buffer */ | |
1497 | data->length = pName->length; | |
1498 | memcpy(nickname, pName->name, pName->length); | |
1499 | } | |
1500 | } else { | |
1501 | ret = -EFAULT; | |
1502 | } | |
1503 | ||
1504 | wl_act_int_on( lp ); | |
1505 | ||
1506 | wl_unlock(lp, &flags); | |
1507 | ||
1508 | out: | |
68c0bdff HG |
1509 | return ret; |
1510 | } // wireless_get_nickname | |
1511 | /*============================================================================*/ | |
1512 | ||
1513 | ||
1514 | ||
1515 | ||
1516 | /******************************************************************************* | |
1517 | * wireless_set_porttype() | |
1518 | ******************************************************************************* | |
1519 | * | |
1520 | * DESCRIPTION: | |
1521 | * | |
1522 | * Sets the port type of the wireless device. | |
1523 | * | |
1524 | * PARAMETERS: | |
1525 | * | |
1526 | * wrq - the wireless request buffer | |
1527 | * lp - the device's private adapter structure | |
1528 | * | |
1529 | * RETURNS: | |
1530 | * | |
1531 | * 0 on success | |
1532 | * errno value otherwise | |
1533 | * | |
1534 | ******************************************************************************/ | |
1535 | static int wireless_set_porttype(struct net_device *dev, struct iw_request_info *info, __u32 *mode, char *extra) | |
1536 | { | |
1537 | struct wl_private *lp = wl_priv(dev); | |
1538 | unsigned long flags; | |
1539 | int ret = 0; | |
1540 | hcf_16 portType; | |
1541 | hcf_16 createIBSS; | |
68c0bdff HG |
1542 | |
1543 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
1544 | ret = -EBUSY; | |
1545 | goto out; | |
1546 | } | |
1547 | ||
1548 | wl_lock( lp, &flags ); | |
1549 | ||
1550 | wl_act_int_off( lp ); | |
1551 | ||
1552 | /* Validate the new value */ | |
1553 | switch( *mode ) { | |
1554 | case IW_MODE_ADHOC: | |
1555 | ||
1556 | /* When user requests ad-hoc, set IBSS mode! */ | |
1557 | portType = 1; | |
1558 | createIBSS = 1; | |
1559 | ||
1560 | lp->DownloadFirmware = WVLAN_DRV_MODE_STA; //1; | |
1561 | ||
1562 | break; | |
1563 | ||
1564 | ||
1565 | case IW_MODE_AUTO: | |
1566 | case IW_MODE_INFRA: | |
1567 | ||
1568 | /* Both automatic and infrastructure set port to BSS/STA mode */ | |
1569 | portType = 1; | |
1570 | createIBSS = 0; | |
1571 | ||
1572 | lp->DownloadFirmware = WVLAN_DRV_MODE_STA; //1; | |
1573 | ||
1574 | break; | |
1575 | ||
1576 | ||
1577 | #if 0 //;? (HCF_TYPE) & HCF_TYPE_AP | |
1578 | ||
1579 | case IW_MODE_MASTER: | |
1580 | ||
1581 | /* Set BSS/AP mode */ | |
1582 | portType = 1; | |
1583 | ||
1584 | lp->CreateIBSS = 0; | |
1585 | lp->DownloadFirmware = WVLAN_DRV_MODE_AP; //2; | |
1586 | ||
1587 | break; | |
1588 | ||
1589 | #endif /* (HCF_TYPE) & HCF_TYPE_AP */ | |
1590 | ||
1591 | ||
1592 | default: | |
1593 | ||
1594 | portType = 0; | |
1595 | createIBSS = 0; | |
1596 | ret = -EINVAL; | |
1597 | } | |
1598 | ||
1599 | if( portType != 0 ) { | |
1600 | /* Only do something if there is a mode change */ | |
1601 | if( ( lp->PortType != portType ) || (lp->CreateIBSS != createIBSS)) { | |
1602 | lp->PortType = portType; | |
1603 | lp->CreateIBSS = createIBSS; | |
1604 | ||
1605 | /* Commit the adapter parameters */ | |
1606 | wl_go( lp ); | |
1607 | ||
1608 | /* Send an event that mode has been set */ | |
1609 | wl_wext_event_mode( lp->dev ); | |
1610 | } | |
1611 | } | |
1612 | ||
1613 | wl_act_int_on( lp ); | |
1614 | ||
1615 | wl_unlock(lp, &flags); | |
1616 | ||
1617 | out: | |
68c0bdff HG |
1618 | return ret; |
1619 | } // wireless_set_porttype | |
1620 | /*============================================================================*/ | |
1621 | ||
1622 | ||
1623 | ||
1624 | ||
1625 | /******************************************************************************* | |
1626 | * wireless_get_porttype() | |
1627 | ******************************************************************************* | |
1628 | * | |
1629 | * DESCRIPTION: | |
1630 | * | |
1631 | * Gets the port type of the wireless device. | |
1632 | * | |
1633 | * PARAMETERS: | |
1634 | * | |
1635 | * wrq - the wireless request buffer | |
1636 | * lp - the device's private adapter structure | |
1637 | * | |
1638 | * RETURNS: | |
1639 | * | |
1640 | * 0 on success | |
1641 | * errno value otherwise | |
1642 | * | |
1643 | ******************************************************************************/ | |
1644 | static int wireless_get_porttype(struct net_device *dev, struct iw_request_info *info, __u32 *mode, char *extra) | |
1645 | ||
1646 | { | |
1647 | struct wl_private *lp = wl_priv(dev); | |
1648 | unsigned long flags; | |
1649 | int ret = 0; | |
1650 | int status = -1; | |
1651 | hcf_16 *pPortType; | |
68c0bdff HG |
1652 | |
1653 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
1654 | ret = -EBUSY; | |
1655 | goto out; | |
1656 | } | |
1657 | ||
1658 | wl_lock( lp, &flags ); | |
1659 | ||
1660 | wl_act_int_off( lp ); | |
1661 | ||
1662 | /* Get the current port type */ | |
1663 | lp->ltvRecord.len = 1 + ( sizeof( *pPortType ) / sizeof( hcf_16 )); | |
1664 | lp->ltvRecord.typ = CFG_CNF_PORT_TYPE; | |
1665 | ||
1666 | status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); | |
1667 | ||
1668 | if( status == HCF_SUCCESS ) { | |
1669 | pPortType = (hcf_16 *)&( lp->ltvRecord.u.u32 ); | |
1670 | ||
1671 | *pPortType = CNV_LITTLE_TO_INT( *pPortType ); | |
1672 | ||
1673 | switch( *pPortType ) { | |
1674 | case 1: | |
1675 | ||
1676 | #if 0 | |
1677 | #if (HCF_TYPE) & HCF_TYPE_AP | |
1678 | ||
1679 | if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) { | |
1680 | *mode = IW_MODE_MASTER; | |
1681 | } else { | |
1682 | *mode = IW_MODE_INFRA; | |
1683 | } | |
1684 | ||
1685 | #else | |
1686 | ||
1687 | *mode = IW_MODE_INFRA; | |
1688 | ||
1689 | #endif /* (HCF_TYPE) & HCF_TYPE_AP */ | |
1690 | #endif | |
1691 | ||
1692 | if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) { | |
1693 | *mode = IW_MODE_MASTER; | |
1694 | } else { | |
1695 | if( lp->CreateIBSS ) { | |
1696 | *mode = IW_MODE_ADHOC; | |
1697 | } else { | |
1698 | *mode = IW_MODE_INFRA; | |
1699 | } | |
1700 | } | |
1701 | ||
1702 | break; | |
1703 | ||
1704 | ||
1705 | case 3: | |
1706 | *mode = IW_MODE_ADHOC; | |
1707 | break; | |
1708 | ||
1709 | default: | |
1710 | ret = -EFAULT; | |
1711 | break; | |
1712 | } | |
1713 | } else { | |
1714 | ret = -EFAULT; | |
1715 | } | |
1716 | ||
1717 | wl_act_int_on( lp ); | |
1718 | ||
1719 | wl_unlock(lp, &flags); | |
1720 | ||
1721 | out: | |
68c0bdff HG |
1722 | return ret; |
1723 | } // wireless_get_porttype | |
1724 | /*============================================================================*/ | |
1725 | ||
1726 | ||
1727 | ||
1728 | ||
1729 | /******************************************************************************* | |
1730 | * wireless_set_power() | |
1731 | ******************************************************************************* | |
1732 | * | |
1733 | * DESCRIPTION: | |
1734 | * | |
1735 | * Sets the power management settings of the wireless device. | |
1736 | * | |
1737 | * PARAMETERS: | |
1738 | * | |
1739 | * wrq - the wireless request buffer | |
1740 | * lp - the device's private adapter structure | |
1741 | * | |
1742 | * RETURNS: | |
1743 | * | |
1744 | * 0 on success | |
1745 | * errno value otherwise | |
1746 | * | |
1747 | ******************************************************************************/ | |
1748 | static int wireless_set_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *wrq, char *extra) | |
1749 | { | |
1750 | struct wl_private *lp = wl_priv(dev); | |
1751 | unsigned long flags; | |
1752 | int ret = 0; | |
68c0bdff HG |
1753 | |
1754 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
1755 | ret = -EBUSY; | |
1756 | goto out; | |
1757 | } | |
1758 | ||
1759 | DBG_PRINT( "THIS CORRUPTS PMEnabled ;?!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" ); | |
1760 | ||
1761 | #if 0 //;? Needed, was present in original code but not in 7.18 Linux 2.6 kernel version | |
1762 | if( !capable( CAP_NET_ADMIN )) { | |
1763 | ret = -EPERM; | |
68c0bdff HG |
1764 | return ret; |
1765 | } | |
1766 | #endif | |
1767 | ||
1768 | wl_lock( lp, &flags ); | |
1769 | ||
1770 | wl_act_int_off( lp ); | |
1771 | ||
1772 | /* Set the power management state based on the 'disabled' value */ | |
1773 | if( wrq->disabled ) { | |
1774 | lp->PMEnabled = 0; | |
1775 | } else { | |
1776 | lp->PMEnabled = 1; | |
1777 | } | |
1778 | ||
1779 | /* Commit the adapter parameters */ | |
1780 | wl_apply( lp ); | |
1781 | ||
1782 | wl_act_int_on( lp ); | |
1783 | ||
1784 | wl_unlock(lp, &flags); | |
1785 | ||
1786 | out: | |
68c0bdff HG |
1787 | return ret; |
1788 | } // wireless_set_power | |
1789 | /*============================================================================*/ | |
1790 | ||
1791 | ||
1792 | ||
1793 | ||
1794 | /******************************************************************************* | |
1795 | * wireless_get_power() | |
1796 | ******************************************************************************* | |
1797 | * | |
1798 | * DESCRIPTION: | |
1799 | * | |
1800 | * Gets the power management settings of the wireless device. | |
1801 | * | |
1802 | * PARAMETERS: | |
1803 | * | |
1804 | * wrq - the wireless request buffer | |
1805 | * lp - the device's private adapter structure | |
1806 | * | |
1807 | * RETURNS: | |
1808 | * | |
1809 | * 0 on success | |
1810 | * errno value otherwise | |
1811 | * | |
1812 | ******************************************************************************/ | |
1813 | static int wireless_get_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) | |
1814 | ||
1815 | { | |
1816 | struct wl_private *lp = wl_priv(dev); | |
1817 | unsigned long flags; | |
1818 | int ret = 0; | |
68c0bdff HG |
1819 | |
1820 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
1821 | ret = -EBUSY; | |
1822 | goto out; | |
1823 | } | |
1824 | ||
1825 | DBG_PRINT( "THIS IS PROBABLY AN OVER-SIMPLIFICATION ;?!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" ); | |
1826 | ||
1827 | wl_lock( lp, &flags ); | |
1828 | ||
1829 | wl_act_int_off( lp ); | |
1830 | ||
1831 | rrq->flags = 0; | |
1832 | rrq->value = 0; | |
1833 | ||
1834 | if( lp->PMEnabled ) { | |
1835 | rrq->disabled = 0; | |
1836 | } else { | |
1837 | rrq->disabled = 1; | |
1838 | } | |
1839 | ||
1840 | wl_act_int_on( lp ); | |
1841 | ||
1842 | wl_unlock(lp, &flags); | |
1843 | ||
1844 | out: | |
68c0bdff HG |
1845 | return ret; |
1846 | } // wireless_get_power | |
1847 | /*============================================================================*/ | |
1848 | ||
1849 | ||
1850 | ||
1851 | ||
1852 | /******************************************************************************* | |
1853 | * wireless_get_tx_power() | |
1854 | ******************************************************************************* | |
1855 | * | |
1856 | * DESCRIPTION: | |
1857 | * | |
1858 | * Gets the transmit power of the wireless device's radio. | |
1859 | * | |
1860 | * PARAMETERS: | |
1861 | * | |
1862 | * wrq - the wireless request buffer | |
1863 | * lp - the device's private adapter structure | |
1864 | * | |
1865 | * RETURNS: | |
1866 | * | |
1867 | * 0 on success | |
1868 | * errno value otherwise | |
1869 | * | |
1870 | ******************************************************************************/ | |
1871 | static int wireless_get_tx_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) | |
1872 | { | |
1873 | struct wl_private *lp = wl_priv(dev); | |
1874 | unsigned long flags; | |
1875 | int ret = 0; | |
68c0bdff HG |
1876 | |
1877 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
1878 | ret = -EBUSY; | |
1879 | goto out; | |
1880 | } | |
1881 | ||
1882 | wl_lock( lp, &flags ); | |
1883 | ||
1884 | wl_act_int_off( lp ); | |
1885 | ||
1886 | #ifdef USE_POWER_DBM | |
1887 | rrq->value = RADIO_TX_POWER_DBM; | |
1888 | rrq->flags = IW_TXPOW_DBM; | |
1889 | #else | |
1890 | rrq->value = RADIO_TX_POWER_MWATT; | |
1891 | rrq->flags = IW_TXPOW_MWATT; | |
1892 | #endif | |
1893 | rrq->fixed = 1; | |
1894 | rrq->disabled = 0; | |
1895 | ||
1896 | wl_act_int_on( lp ); | |
1897 | ||
1898 | wl_unlock(lp, &flags); | |
1899 | ||
1900 | out: | |
68c0bdff HG |
1901 | return ret; |
1902 | } // wireless_get_tx_power | |
1903 | /*============================================================================*/ | |
1904 | ||
1905 | ||
1906 | ||
1907 | ||
1908 | /******************************************************************************* | |
1909 | * wireless_set_rts_threshold() | |
1910 | ******************************************************************************* | |
1911 | * | |
1912 | * DESCRIPTION: | |
1913 | * | |
1914 | * Sets the RTS threshold for the wireless card. | |
1915 | * | |
1916 | * PARAMETERS: | |
1917 | * | |
1918 | * wrq - the wireless request buffer | |
1919 | * lp - the device's private adapter structure | |
1920 | * | |
1921 | * RETURNS: | |
1922 | * | |
1923 | * 0 on success | |
1924 | * errno value otherwise | |
1925 | * | |
1926 | ******************************************************************************/ | |
1927 | static int wireless_set_rts_threshold (struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) | |
1928 | { | |
1929 | int ret = 0; | |
1930 | struct wl_private *lp = wl_priv(dev); | |
1931 | unsigned long flags; | |
1932 | int rthr = rts->value; | |
68c0bdff HG |
1933 | |
1934 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
1935 | ret = -EBUSY; | |
1936 | goto out; | |
1937 | } | |
1938 | ||
1939 | if(rts->fixed == 0) { | |
1940 | ret = -EINVAL; | |
1941 | goto out; | |
1942 | } | |
1943 | ||
68c0bdff HG |
1944 | if( rts->disabled ) { |
1945 | rthr = 2347; | |
1946 | } | |
68c0bdff HG |
1947 | |
1948 | if(( rthr < 256 ) || ( rthr > 2347 )) { | |
1949 | ret = -EINVAL; | |
1950 | goto out; | |
1951 | } | |
1952 | ||
1953 | wl_lock( lp, &flags ); | |
1954 | ||
1955 | wl_act_int_off( lp ); | |
1956 | ||
1957 | lp->RTSThreshold = rthr; | |
1958 | ||
1959 | wl_apply( lp ); | |
1960 | ||
1961 | wl_act_int_on( lp ); | |
1962 | ||
1963 | wl_unlock(lp, &flags); | |
1964 | ||
1965 | out: | |
68c0bdff HG |
1966 | return ret; |
1967 | } // wireless_set_rts_threshold | |
1968 | /*============================================================================*/ | |
1969 | ||
1970 | ||
1971 | ||
1972 | ||
1973 | /******************************************************************************* | |
1974 | * wireless_get_rts_threshold() | |
1975 | ******************************************************************************* | |
1976 | * | |
1977 | * DESCRIPTION: | |
1978 | * | |
1979 | * Gets the RTS threshold for the wireless card. | |
1980 | * | |
1981 | * PARAMETERS: | |
1982 | * | |
1983 | * wrq - the wireless request buffer | |
1984 | * lp - the device's private adapter structure | |
1985 | * | |
1986 | * RETURNS: | |
1987 | * | |
1988 | * 0 on success | |
1989 | * errno value otherwise | |
1990 | * | |
1991 | ******************************************************************************/ | |
1992 | static int wireless_get_rts_threshold (struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) | |
1993 | { | |
1994 | int ret = 0; | |
1995 | struct wl_private *lp = wl_priv(dev); | |
1996 | unsigned long flags; | |
68c0bdff HG |
1997 | |
1998 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
1999 | ret = -EBUSY; | |
2000 | goto out; | |
2001 | } | |
2002 | ||
2003 | wl_lock( lp, &flags ); | |
2004 | ||
2005 | wl_act_int_off( lp ); | |
2006 | ||
2007 | rts->value = lp->RTSThreshold; | |
2008 | ||
68c0bdff HG |
2009 | rts->disabled = ( rts->value == 2347 ); |
2010 | ||
68c0bdff HG |
2011 | rts->fixed = 1; |
2012 | ||
2013 | wl_act_int_on( lp ); | |
2014 | ||
2015 | wl_unlock(lp, &flags); | |
2016 | ||
2017 | out: | |
68c0bdff HG |
2018 | return ret; |
2019 | } // wireless_get_rts_threshold | |
2020 | /*============================================================================*/ | |
2021 | ||
2022 | ||
2023 | ||
2024 | ||
2025 | ||
2026 | /******************************************************************************* | |
2027 | * wireless_set_rate() | |
2028 | ******************************************************************************* | |
2029 | * | |
2030 | * DESCRIPTION: | |
2031 | * | |
2032 | * Set the default data rate setting used by the wireless device. | |
2033 | * | |
2034 | * PARAMETERS: | |
2035 | * | |
2036 | * wrq - the wireless request buffer | |
2037 | * lp - the device's private adapter structure | |
2038 | * | |
2039 | * RETURNS: | |
2040 | * | |
2041 | * 0 on success | |
2042 | * errno value otherwise | |
2043 | * | |
2044 | ******************************************************************************/ | |
2045 | static int wireless_set_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) | |
2046 | { | |
2047 | struct wl_private *lp = wl_priv(dev); | |
2048 | unsigned long flags; | |
2049 | int ret = 0; | |
2050 | #ifdef WARP | |
2051 | int status = -1; | |
2052 | int index = 0; | |
2053 | #endif // WARP | |
68c0bdff HG |
2054 | |
2055 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
2056 | ret = -EBUSY; | |
2057 | goto out; | |
2058 | } | |
2059 | ||
2060 | wl_lock( lp, &flags ); | |
2061 | ||
2062 | wl_act_int_off( lp ); | |
2063 | ||
2064 | #ifdef WARP | |
2065 | ||
2066 | /* Determine if the card is operating in the 2.4 or 5.0 GHz band; check | |
2067 | if Bit 9 is set in the current channel RID */ | |
2068 | lp->ltvRecord.len = 2; | |
2069 | lp->ltvRecord.typ = CFG_CUR_CHANNEL; | |
2070 | ||
2071 | status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); | |
2072 | ||
2073 | if( status == HCF_SUCCESS ) { | |
2074 | index = ( CNV_LITTLE_TO_INT( lp->ltvRecord.u.u16[0] ) & 0x100 ) ? 1 : 0; | |
2075 | ||
2076 | DBG_PRINT( "Index: %d\n", index ); | |
2077 | } else { | |
2078 | DBG_ERROR( DbgInfo, "Could not determine radio frequency\n" ); | |
68c0bdff HG |
2079 | ret = -EINVAL; |
2080 | goto out_unlock; | |
2081 | } | |
2082 | ||
2083 | if( rrq->value > 0 && | |
2084 | rrq->value <= 1 * MEGABIT ) { | |
2085 | lp->TxRateControl[index] = 0x0001; | |
2086 | } | |
2087 | else if( rrq->value > 1 * MEGABIT && | |
2088 | rrq->value <= 2 * MEGABIT ) { | |
2089 | if( rrq->fixed == 1 ) { | |
2090 | lp->TxRateControl[index] = 0x0002; | |
2091 | } else { | |
2092 | lp->TxRateControl[index] = 0x0003; | |
2093 | } | |
2094 | } | |
2095 | else if( rrq->value > 2 * MEGABIT && | |
2096 | rrq->value <= 5 * MEGABIT ) { | |
2097 | if( rrq->fixed == 1 ) { | |
2098 | lp->TxRateControl[index] = 0x0004; | |
2099 | } else { | |
2100 | lp->TxRateControl[index] = 0x0007; | |
2101 | } | |
2102 | } | |
2103 | else if( rrq->value > 5 * MEGABIT && | |
2104 | rrq->value <= 6 * MEGABIT ) { | |
2105 | if( rrq->fixed == 1 ) { | |
2106 | lp->TxRateControl[index] = 0x0010; | |
2107 | } else { | |
2108 | lp->TxRateControl[index] = 0x0017; | |
2109 | } | |
2110 | } | |
2111 | else if( rrq->value > 6 * MEGABIT && | |
2112 | rrq->value <= 9 * MEGABIT ) { | |
2113 | if( rrq->fixed == 1 ) { | |
2114 | lp->TxRateControl[index] = 0x0020; | |
2115 | } else { | |
2116 | lp->TxRateControl[index] = 0x0037; | |
2117 | } | |
2118 | } | |
2119 | else if( rrq->value > 9 * MEGABIT && | |
2120 | rrq->value <= 11 * MEGABIT ) { | |
2121 | if( rrq->fixed == 1 ) { | |
2122 | lp->TxRateControl[index] = 0x0008; | |
2123 | } else { | |
2124 | lp->TxRateControl[index] = 0x003F; | |
2125 | } | |
2126 | } | |
2127 | else if( rrq->value > 11 * MEGABIT && | |
2128 | rrq->value <= 12 * MEGABIT ) { | |
2129 | if( rrq->fixed == 1 ) { | |
2130 | lp->TxRateControl[index] = 0x0040; | |
2131 | } else { | |
2132 | lp->TxRateControl[index] = 0x007F; | |
2133 | } | |
2134 | } | |
2135 | else if( rrq->value > 12 * MEGABIT && | |
2136 | rrq->value <= 18 * MEGABIT ) { | |
2137 | if( rrq->fixed == 1 ) { | |
2138 | lp->TxRateControl[index] = 0x0080; | |
2139 | } else { | |
2140 | lp->TxRateControl[index] = 0x00FF; | |
2141 | } | |
2142 | } | |
2143 | else if( rrq->value > 18 * MEGABIT && | |
2144 | rrq->value <= 24 * MEGABIT ) { | |
2145 | if( rrq->fixed == 1 ) { | |
2146 | lp->TxRateControl[index] = 0x0100; | |
2147 | } else { | |
2148 | lp->TxRateControl[index] = 0x01FF; | |
2149 | } | |
2150 | } | |
2151 | else if( rrq->value > 24 * MEGABIT && | |
2152 | rrq->value <= 36 * MEGABIT ) { | |
2153 | if( rrq->fixed == 1 ) { | |
2154 | lp->TxRateControl[index] = 0x0200; | |
2155 | } else { | |
2156 | lp->TxRateControl[index] = 0x03FF; | |
2157 | } | |
2158 | } | |
2159 | else if( rrq->value > 36 * MEGABIT && | |
2160 | rrq->value <= 48 * MEGABIT ) { | |
2161 | if( rrq->fixed == 1 ) { | |
2162 | lp->TxRateControl[index] = 0x0400; | |
2163 | } else { | |
2164 | lp->TxRateControl[index] = 0x07FF; | |
2165 | } | |
2166 | } | |
2167 | else if( rrq->value > 48 * MEGABIT && | |
2168 | rrq->value <= 54 * MEGABIT ) { | |
2169 | if( rrq->fixed == 1 ) { | |
2170 | lp->TxRateControl[index] = 0x0800; | |
2171 | } else { | |
2172 | lp->TxRateControl[index] = 0x0FFF; | |
2173 | } | |
2174 | } | |
2175 | else if( rrq->fixed == 0 ) { | |
2176 | /* In this case, the user has not specified a bitrate, only the "auto" | |
2177 | moniker. So, set to all supported rates */ | |
2178 | lp->TxRateControl[index] = PARM_MAX_TX_RATE; | |
2179 | } else { | |
2180 | rrq->value = 0; | |
2181 | ret = -EINVAL; | |
2182 | goto out_unlock; | |
2183 | } | |
2184 | ||
2185 | ||
2186 | #else | |
2187 | ||
2188 | if( rrq->value > 0 && | |
2189 | rrq->value <= 1 * MEGABIT ) { | |
2190 | lp->TxRateControl[0] = 1; | |
2191 | } | |
2192 | else if( rrq->value > 1 * MEGABIT && | |
2193 | rrq->value <= 2 * MEGABIT ) { | |
2194 | if( rrq->fixed ) { | |
2195 | lp->TxRateControl[0] = 2; | |
2196 | } else { | |
2197 | lp->TxRateControl[0] = 6; | |
2198 | } | |
2199 | } | |
2200 | else if( rrq->value > 2 * MEGABIT && | |
2201 | rrq->value <= 5 * MEGABIT ) { | |
2202 | if( rrq->fixed ) { | |
2203 | lp->TxRateControl[0] = 4; | |
2204 | } else { | |
2205 | lp->TxRateControl[0] = 7; | |
2206 | } | |
2207 | } | |
2208 | else if( rrq->value > 5 * MEGABIT && | |
2209 | rrq->value <= 11 * MEGABIT ) { | |
2210 | if( rrq->fixed) { | |
2211 | lp->TxRateControl[0] = 5; | |
2212 | } else { | |
2213 | lp->TxRateControl[0] = 3; | |
2214 | } | |
2215 | } | |
2216 | else if( rrq->fixed == 0 ) { | |
2217 | /* In this case, the user has not specified a bitrate, only the "auto" | |
2218 | moniker. So, set the rate to 11Mb auto */ | |
2219 | lp->TxRateControl[0] = 3; | |
2220 | } else { | |
2221 | rrq->value = 0; | |
2222 | ret = -EINVAL; | |
2223 | goto out_unlock; | |
2224 | } | |
2225 | ||
2226 | #endif // WARP | |
2227 | ||
2228 | ||
2229 | /* Commit the adapter parameters */ | |
2230 | wl_apply( lp ); | |
2231 | ||
2232 | out_unlock: | |
2233 | ||
2234 | wl_act_int_on( lp ); | |
2235 | ||
2236 | wl_unlock(lp, &flags); | |
2237 | ||
2238 | out: | |
68c0bdff HG |
2239 | return ret; |
2240 | } // wireless_set_rate | |
2241 | /*============================================================================*/ | |
2242 | ||
2243 | ||
2244 | ||
2245 | ||
2246 | /******************************************************************************* | |
2247 | * wireless_get_rate() | |
2248 | ******************************************************************************* | |
2249 | * | |
2250 | * DESCRIPTION: | |
2251 | * | |
2252 | * Get the default data rate setting used by the wireless device. | |
2253 | * | |
2254 | * PARAMETERS: | |
2255 | * | |
2256 | * wrq - the wireless request buffer | |
2257 | * lp - the device's private adapter structure | |
2258 | * | |
2259 | * RETURNS: | |
2260 | * | |
2261 | * 0 on success | |
2262 | * errno value otherwise | |
2263 | * | |
2264 | ******************************************************************************/ | |
2265 | static int wireless_get_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) | |
2266 | ||
2267 | { | |
2268 | struct wl_private *lp = wl_priv(dev); | |
2269 | unsigned long flags; | |
2270 | int ret = 0; | |
2271 | int status = -1; | |
2272 | hcf_16 txRate; | |
68c0bdff HG |
2273 | |
2274 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
2275 | ret = -EBUSY; | |
2276 | goto out; | |
2277 | } | |
2278 | ||
2279 | wl_lock( lp, &flags ); | |
2280 | ||
2281 | wl_act_int_off( lp ); | |
2282 | ||
2283 | /* Get the current transmit rate from the adapter */ | |
2284 | lp->ltvRecord.len = 1 + ( sizeof(txRate)/sizeof(hcf_16)); | |
2285 | lp->ltvRecord.typ = CFG_CUR_TX_RATE; | |
2286 | ||
2287 | status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); | |
2288 | ||
2289 | if( status == HCF_SUCCESS ) { | |
2290 | #ifdef WARP | |
2291 | ||
2292 | txRate = CNV_LITTLE_TO_INT( lp->ltvRecord.u.u16[0] ); | |
2293 | ||
2294 | if( txRate & 0x0001 ) { | |
2295 | txRate = 1; | |
2296 | } | |
2297 | else if( txRate & 0x0002 ) { | |
2298 | txRate = 2; | |
2299 | } | |
2300 | else if( txRate & 0x0004 ) { | |
2301 | txRate = 5; | |
2302 | } | |
2303 | else if( txRate & 0x0008 ) { | |
2304 | txRate = 11; | |
2305 | } | |
2306 | else if( txRate & 0x00010 ) { | |
2307 | txRate = 6; | |
2308 | } | |
2309 | else if( txRate & 0x00020 ) { | |
2310 | txRate = 9; | |
2311 | } | |
2312 | else if( txRate & 0x00040 ) { | |
2313 | txRate = 12; | |
2314 | } | |
2315 | else if( txRate & 0x00080 ) { | |
2316 | txRate = 18; | |
2317 | } | |
2318 | else if( txRate & 0x00100 ) { | |
2319 | txRate = 24; | |
2320 | } | |
2321 | else if( txRate & 0x00200 ) { | |
2322 | txRate = 36; | |
2323 | } | |
2324 | else if( txRate & 0x00400 ) { | |
2325 | txRate = 48; | |
2326 | } | |
2327 | else if( txRate & 0x00800 ) { | |
2328 | txRate = 54; | |
2329 | } | |
2330 | ||
2331 | #else | |
2332 | ||
2333 | txRate = (hcf_16)CNV_LITTLE_TO_LONG( lp->ltvRecord.u.u32[0] ); | |
2334 | ||
2335 | #endif // WARP | |
2336 | ||
2337 | rrq->value = txRate * MEGABIT; | |
2338 | } else { | |
2339 | rrq->value = 0; | |
2340 | ret = -EFAULT; | |
2341 | } | |
2342 | ||
2343 | wl_act_int_on( lp ); | |
2344 | ||
2345 | wl_unlock(lp, &flags); | |
2346 | ||
2347 | out: | |
68c0bdff HG |
2348 | return ret; |
2349 | } // wireless_get_rate | |
2350 | /*============================================================================*/ | |
2351 | ||
2352 | ||
2353 | ||
2354 | ||
2355 | #if 0 //;? Not used anymore | |
2356 | /******************************************************************************* | |
2357 | * wireless_get_private_interface() | |
2358 | ******************************************************************************* | |
2359 | * | |
2360 | * DESCRIPTION: | |
2361 | * | |
2362 | * Returns the Linux Wireless Extensions' compatible private interface of | |
2363 | * the driver. | |
2364 | * | |
2365 | * PARAMETERS: | |
2366 | * | |
2367 | * wrq - the wireless request buffer | |
2368 | * lp - the device's private adapter structure | |
2369 | * | |
2370 | * RETURNS: | |
2371 | * | |
2372 | * 0 on success | |
2373 | * errno value otherwise | |
2374 | * | |
2375 | ******************************************************************************/ | |
2376 | int wireless_get_private_interface( struct iwreq *wrq, struct wl_private *lp ) | |
2377 | { | |
2378 | int ret = 0; | |
68c0bdff HG |
2379 | |
2380 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
2381 | ret = -EBUSY; | |
2382 | goto out; | |
2383 | } | |
2384 | ||
2385 | if( wrq->u.data.pointer != NULL ) { | |
2386 | struct iw_priv_args priv[] = | |
2387 | { | |
2388 | { SIOCSIWNETNAME, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, 0, "snetwork_name" }, | |
2389 | { SIOCGIWNETNAME, 0, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, "gnetwork_name" }, | |
2390 | { SIOCSIWSTANAME, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, 0, "sstation_name" }, | |
2391 | { SIOCGIWSTANAME, 0, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, "gstation_name" }, | |
2392 | { SIOCSIWPORTTYPE, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "sport_type" }, | |
2393 | { SIOCGIWPORTTYPE, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "gport_type" }, | |
2394 | }; | |
2395 | ||
2396 | /* Verify the user buffer */ | |
2397 | ret = verify_area( VERIFY_WRITE, wrq->u.data.pointer, sizeof( priv )); | |
2398 | ||
3c319c96 | 2399 | if( ret != 0 ) |
68c0bdff | 2400 | return ret; |
68c0bdff HG |
2401 | |
2402 | /* Copy the data into the user's buffer */ | |
2403 | wrq->u.data.length = NELEM( priv ); | |
2404 | copy_to_user( wrq->u.data.pointer, &priv, sizeof( priv )); | |
2405 | } | |
2406 | ||
2407 | out: | |
68c0bdff HG |
2408 | return ret; |
2409 | } // wireless_get_private_interface | |
2410 | /*============================================================================*/ | |
2411 | #endif | |
2412 | ||
2413 | ||
2414 | ||
68c0bdff HG |
2415 | /******************************************************************************* |
2416 | * wireless_set_scan() | |
2417 | ******************************************************************************* | |
2418 | * | |
2419 | * DESCRIPTION: | |
2420 | * | |
2421 | * Instructs the driver to initiate a network scan. | |
2422 | * | |
2423 | * PARAMETERS: | |
2424 | * | |
2425 | * wrq - the wireless request buffer | |
2426 | * lp - the device's private adapter structure | |
2427 | * | |
2428 | * RETURNS: | |
2429 | * | |
2430 | * 0 on success | |
2431 | * errno value otherwise | |
2432 | * | |
2433 | ******************************************************************************/ | |
2434 | static int wireless_set_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) | |
2435 | { | |
2436 | struct wl_private *lp = wl_priv(dev); | |
2437 | unsigned long flags; | |
2438 | int ret = 0; | |
2439 | int status = -1; | |
2440 | int retries = 0; | |
68c0bdff | 2441 | |
cb154c18 | 2442 | //;? Note: shows results as trace, returns always 0 unless BUSY |
68c0bdff | 2443 | |
68c0bdff HG |
2444 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { |
2445 | ret = -EBUSY; | |
2446 | goto out; | |
2447 | } | |
2448 | ||
2449 | wl_lock( lp, &flags ); | |
2450 | ||
2451 | wl_act_int_off( lp ); | |
2452 | ||
2453 | /* | |
2454 | * This looks like a nice place to test if the HCF is still | |
2455 | * communicating with the card. It seems that sometimes BAP_1 | |
2456 | * gets corrupted. By looking at the comments in HCF the | |
25985edc | 2457 | * cause is still a mystery. Okay, the communication to the |
68c0bdff HG |
2458 | * card is dead, reset the card to revive. |
2459 | */ | |
2460 | if((lp->hcfCtx.IFB_CardStat & CARD_STAT_DEFUNCT) != 0) | |
2461 | { | |
2462 | DBG_TRACE( DbgInfo, "CARD is in DEFUNCT mode, reset it to bring it back to life\n" ); | |
2463 | wl_reset( dev ); | |
2464 | } | |
2465 | ||
2466 | retry: | |
2467 | /* Set the completion state to FALSE */ | |
2468 | lp->probe_results.scan_complete = FALSE; | |
2469 | ||
2470 | ||
2471 | /* Channels to scan */ | |
2472 | #ifdef WARP | |
2473 | lp->ltvRecord.len = 5; | |
2474 | lp->ltvRecord.typ = CFG_SCAN_CHANNEL; | |
2475 | lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0x3FFF ); // 2.4 GHz Band | |
2476 | lp->ltvRecord.u.u16[1] = CNV_INT_TO_LITTLE( 0xFFFF ); // 5.0 GHz Band | |
2477 | lp->ltvRecord.u.u16[2] = CNV_INT_TO_LITTLE( 0xFFFF ); // .. | |
2478 | lp->ltvRecord.u.u16[3] = CNV_INT_TO_LITTLE( 0x0007 ); // .. | |
2479 | #else | |
2480 | lp->ltvRecord.len = 2; | |
2481 | lp->ltvRecord.typ = CFG_SCAN_CHANNEL; | |
2482 | lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0x7FFF ); | |
2483 | #endif // WARP | |
2484 | ||
2485 | status = hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); | |
2486 | ||
2487 | DBG_TRACE( DbgInfo, "CFG_SCAN_CHANNEL result : 0x%x\n", status ); | |
2488 | ||
86f9150c | 2489 | // Holding the lock too long, makes a gap to allow other processes |
68c0bdff HG |
2490 | wl_unlock(lp, &flags); |
2491 | wl_lock( lp, &flags ); | |
2492 | ||
2493 | if( status != HCF_SUCCESS ) { | |
2494 | //Recovery | |
2495 | retries++; | |
2496 | if(retries <= 10) { | |
2497 | DBG_TRACE( DbgInfo, "Reset card to recover, attempt: %d\n", retries ); | |
2498 | wl_reset( dev ); | |
2499 | ||
86f9150c | 2500 | // Holding the lock too long, makes a gap to allow other processes |
68c0bdff HG |
2501 | wl_unlock(lp, &flags); |
2502 | wl_lock( lp, &flags ); | |
2503 | ||
2504 | goto retry; | |
2505 | } | |
2506 | } | |
2507 | ||
2508 | /* Set the SCAN_SSID to "ANY". Using this RID for scan prevents the need to | |
2509 | disassociate from the network we are currently on */ | |
2510 | lp->ltvRecord.len = 18; | |
2511 | lp->ltvRecord.typ = CFG_SCAN_SSID; | |
2512 | lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0 ); | |
2513 | lp->ltvRecord.u.u16[1] = CNV_INT_TO_LITTLE( 0 ); | |
2514 | ||
2515 | status = hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); | |
2516 | ||
86f9150c | 2517 | // Holding the lock too long, makes a gap to allow other processes |
68c0bdff HG |
2518 | wl_unlock(lp, &flags); |
2519 | wl_lock( lp, &flags ); | |
2520 | ||
2521 | DBG_TRACE( DbgInfo, "CFG_SCAN_SSID to 'any' status: 0x%x\n", status ); | |
2522 | ||
2523 | /* Initiate the scan */ | |
2524 | /* NOTE: Using HCF_ACT_SCAN has been removed, as using HCF_ACT_ACS_SCAN to | |
86f9150c | 2525 | retrieve probe response must always be used to support WPA */ |
68c0bdff HG |
2526 | status = hcf_action( &( lp->hcfCtx ), HCF_ACT_ACS_SCAN ); |
2527 | ||
2528 | if( status == HCF_SUCCESS ) { | |
2529 | DBG_TRACE( DbgInfo, "SUCCESSFULLY INITIATED SCAN...\n" ); | |
2530 | } else { | |
2531 | DBG_TRACE( DbgInfo, "INITIATE SCAN FAILED...\n" ); | |
2532 | } | |
2533 | ||
2534 | wl_act_int_on( lp ); | |
2535 | ||
2536 | wl_unlock(lp, &flags); | |
2537 | ||
2538 | out: | |
68c0bdff HG |
2539 | return ret; |
2540 | } // wireless_set_scan | |
2541 | /*============================================================================*/ | |
2542 | ||
2543 | ||
2544 | ||
2545 | ||
2546 | /******************************************************************************* | |
2547 | * wireless_get_scan() | |
2548 | ******************************************************************************* | |
2549 | * | |
2550 | * DESCRIPTION: | |
2551 | * | |
2552 | * Instructs the driver to gather and return the results of a network scan. | |
2553 | * | |
2554 | * PARAMETERS: | |
2555 | * | |
2556 | * wrq - the wireless request buffer | |
2557 | * lp - the device's private adapter structure | |
2558 | * | |
2559 | * RETURNS: | |
2560 | * | |
2561 | * 0 on success | |
2562 | * errno value otherwise | |
2563 | * | |
2564 | ******************************************************************************/ | |
2565 | static int wireless_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) | |
2566 | { | |
2567 | struct wl_private *lp = wl_priv(dev); | |
2568 | unsigned long flags; | |
2569 | int ret = 0; | |
2570 | int count; | |
2571 | char *buf; | |
2572 | char *buf_end; | |
2573 | struct iw_event iwe; | |
2574 | PROBE_RESP *probe_resp; | |
2575 | hcf_8 msg[512]; | |
2576 | hcf_8 *wpa_ie; | |
2577 | hcf_16 wpa_ie_len; | |
68c0bdff HG |
2578 | |
2579 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
2580 | ret = -EBUSY; | |
2581 | goto out; | |
2582 | } | |
2583 | ||
2584 | wl_lock( lp, &flags ); | |
2585 | ||
2586 | wl_act_int_off( lp ); | |
2587 | ||
2588 | /* If the scan is not done, tell the calling process to try again later */ | |
2589 | if( !lp->probe_results.scan_complete ) { | |
2590 | ret = -EAGAIN; | |
2591 | goto out_unlock; | |
2592 | } | |
2593 | ||
2594 | DBG_TRACE( DbgInfo, "SCAN COMPLETE, Num of APs: %d\n", | |
2595 | lp->probe_results.num_aps ); | |
2596 | ||
2597 | buf = extra; | |
2598 | buf_end = extra + IW_SCAN_MAX_DATA; | |
2599 | ||
2600 | for( count = 0; count < lp->probe_results.num_aps; count++ ) { | |
2601 | /* Reference the probe response from the table */ | |
2602 | probe_resp = (PROBE_RESP *)&lp->probe_results.ProbeTable[count]; | |
2603 | ||
2604 | ||
2605 | /* First entry MUST be the MAC address */ | |
2606 | memset( &iwe, 0, sizeof( iwe )); | |
2607 | ||
2608 | iwe.cmd = SIOCGIWAP; | |
2609 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | |
2610 | memcpy( iwe.u.ap_addr.sa_data, probe_resp->BSSID, ETH_ALEN); | |
2611 | iwe.len = IW_EV_ADDR_LEN; | |
2612 | ||
25b20463 DK |
2613 | buf = iwe_stream_add_event(info, buf, buf_end, |
2614 | &iwe, IW_EV_ADDR_LEN); | |
68c0bdff HG |
2615 | |
2616 | /* Use the mode to indicate if it's a station or AP */ | |
2617 | /* Won't always be an AP if in IBSS mode */ | |
2618 | memset( &iwe, 0, sizeof( iwe )); | |
2619 | ||
2620 | iwe.cmd = SIOCGIWMODE; | |
2621 | ||
2622 | if( probe_resp->capability & CAPABILITY_IBSS ) { | |
2623 | iwe.u.mode = IW_MODE_INFRA; | |
2624 | } else { | |
2625 | iwe.u.mode = IW_MODE_MASTER; | |
2626 | } | |
2627 | ||
2628 | iwe.len = IW_EV_UINT_LEN; | |
2629 | ||
25b20463 DK |
2630 | buf = iwe_stream_add_event(info, buf, buf_end, |
2631 | &iwe, IW_EV_UINT_LEN); | |
68c0bdff HG |
2632 | |
2633 | /* Any quality information */ | |
2634 | memset(&iwe, 0, sizeof(iwe)); | |
2635 | ||
2636 | iwe.cmd = IWEVQUAL; | |
2637 | iwe.u.qual.level = dbm(probe_resp->signal); | |
2638 | iwe.u.qual.noise = dbm(probe_resp->silence); | |
2639 | iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; | |
e81589a7 | 2640 | iwe.u.qual.updated = lp->probe_results.scan_complete | IW_QUAL_DBM; |
68c0bdff HG |
2641 | iwe.len = IW_EV_QUAL_LEN; |
2642 | ||
25b20463 DK |
2643 | buf = iwe_stream_add_event(info, buf, buf_end, |
2644 | &iwe, IW_EV_QUAL_LEN); | |
68c0bdff HG |
2645 | |
2646 | ||
2647 | /* ESSID information */ | |
2648 | if( probe_resp->rawData[1] > 0 ) { | |
2649 | memset( &iwe, 0, sizeof( iwe )); | |
2650 | ||
2651 | iwe.cmd = SIOCGIWESSID; | |
2652 | iwe.u.data.length = probe_resp->rawData[1]; | |
2653 | iwe.u.data.flags = 1; | |
2654 | ||
25b20463 DK |
2655 | buf = iwe_stream_add_point(info, buf, buf_end, |
2656 | &iwe, &probe_resp->rawData[2]); | |
68c0bdff HG |
2657 | } |
2658 | ||
2659 | ||
2660 | /* Encryption Information */ | |
2661 | memset( &iwe, 0, sizeof( iwe )); | |
2662 | ||
2663 | iwe.cmd = SIOCGIWENCODE; | |
2664 | iwe.u.data.length = 0; | |
2665 | ||
2666 | /* Check the capabilities field of the Probe Response to see if | |
2667 | 'privacy' is supported on the AP in question */ | |
2668 | if( probe_resp->capability & CAPABILITY_PRIVACY ) { | |
2669 | iwe.u.data.flags |= IW_ENCODE_ENABLED; | |
2670 | } else { | |
2671 | iwe.u.data.flags |= IW_ENCODE_DISABLED; | |
2672 | } | |
2673 | ||
25b20463 | 2674 | buf = iwe_stream_add_point(info, buf, buf_end, &iwe, NULL); |
68c0bdff HG |
2675 | |
2676 | ||
2677 | /* Frequency Info */ | |
2678 | memset( &iwe, 0, sizeof( iwe )); | |
2679 | ||
2680 | iwe.cmd = SIOCGIWFREQ; | |
2681 | iwe.len = IW_EV_FREQ_LEN; | |
2682 | iwe.u.freq.m = wl_parse_ds_ie( probe_resp ); | |
2683 | iwe.u.freq.e = 0; | |
2684 | ||
25b20463 DK |
2685 | buf = iwe_stream_add_event(info, buf, buf_end, |
2686 | &iwe, IW_EV_FREQ_LEN); | |
68c0bdff HG |
2687 | |
2688 | ||
68c0bdff HG |
2689 | /* Custom info (Beacon Interval) */ |
2690 | memset( &iwe, 0, sizeof( iwe )); | |
2691 | memset( msg, 0, sizeof( msg )); | |
2692 | ||
2693 | iwe.cmd = IWEVCUSTOM; | |
2694 | sprintf( msg, "beacon_interval=%d", probe_resp->beaconInterval ); | |
2695 | iwe.u.data.length = strlen( msg ); | |
2696 | ||
25b20463 | 2697 | buf = iwe_stream_add_point(info, buf, buf_end, &iwe, msg); |
68c0bdff HG |
2698 | |
2699 | ||
68da1056 | 2700 | /* WPA-IE */ |
68c0bdff HG |
2701 | wpa_ie = NULL; |
2702 | wpa_ie_len = 0; | |
2703 | ||
2704 | wpa_ie = wl_parse_wpa_ie( probe_resp, &wpa_ie_len ); | |
2705 | if( wpa_ie != NULL ) { | |
68da1056 | 2706 | memset(&iwe, 0, sizeof(iwe)); |
68c0bdff | 2707 | |
68da1056 DK |
2708 | iwe.cmd = IWEVGENIE; |
2709 | iwe.u.data.length = wpa_ie_len; | |
68c0bdff | 2710 | |
25b20463 | 2711 | buf = iwe_stream_add_point(info, buf, buf_end, |
68da1056 | 2712 | &iwe, wpa_ie); |
68c0bdff HG |
2713 | } |
2714 | ||
2715 | /* Add other custom info in formatted string format as needed... */ | |
68c0bdff HG |
2716 | } |
2717 | ||
2718 | data->length = buf - extra; | |
2719 | ||
2720 | out_unlock: | |
2721 | ||
2722 | wl_act_int_on( lp ); | |
2723 | ||
2724 | wl_unlock(lp, &flags); | |
2725 | ||
2726 | out: | |
68c0bdff HG |
2727 | return ret; |
2728 | } // wireless_get_scan | |
2729 | /*============================================================================*/ | |
2730 | ||
9ef02300 DK |
2731 | #if DBG |
2732 | static const char * const auth_names[] = { | |
2733 | "IW_AUTH_WPA_VERSION", | |
2734 | "IW_AUTH_CIPHER_PAIRWISE", | |
2735 | "IW_AUTH_CIPHER_GROUP", | |
2736 | "IW_AUTH_KEY_MGMT", | |
2737 | "IW_AUTH_TKIP_COUNTERMEASURES", | |
2738 | "IW_AUTH_DROP_UNENCRYPTED", | |
2739 | "IW_AUTH_80211_AUTH_ALG", | |
2740 | "IW_AUTH_WPA_ENABLED", | |
2741 | "IW_AUTH_RX_UNENCRYPTED_EAPOL", | |
2742 | "IW_AUTH_ROAMING_CONTROL", | |
2743 | "IW_AUTH_PRIVACY_INVOKED", | |
2744 | "IW_AUTH_CIPHER_GROUP_MGMT", | |
2745 | "IW_AUTH_MFP", | |
2746 | "Unsupported" | |
2747 | }; | |
2748 | #endif | |
68c0bdff | 2749 | |
68c0bdff HG |
2750 | static int wireless_set_auth(struct net_device *dev, |
2751 | struct iw_request_info *info, | |
2752 | struct iw_param *data, char *extra) | |
2753 | { | |
2754 | struct wl_private *lp = wl_priv(dev); | |
2755 | unsigned long flags; | |
9ef02300 DK |
2756 | ltv_t ltv; |
2757 | int ret; | |
2758 | int iwa_idx = data->flags & IW_AUTH_INDEX; | |
2759 | int iwa_val = data->value; | |
68c0bdff | 2760 | |
9ef02300 | 2761 | if (lp->portState == WVLAN_PORT_STATE_DISABLED) { |
68c0bdff HG |
2762 | ret = -EBUSY; |
2763 | goto out; | |
2764 | } | |
2765 | ||
2766 | wl_lock( lp, &flags ); | |
2767 | ||
2768 | wl_act_int_off( lp ); | |
2769 | ||
9ef02300 DK |
2770 | if (iwa_idx > IW_AUTH_MFP) |
2771 | iwa_idx = IW_AUTH_MFP + 1; | |
2772 | DBG_TRACE(DbgInfo, "%s\n", auth_names[iwa_idx]); | |
68c0bdff | 2773 | switch (iwa_idx) { |
9ef02300 DK |
2774 | case IW_AUTH_WPA_VERSION: |
2775 | /* We do support WPA */ | |
2776 | if ((iwa_val == IW_AUTH_WPA_VERSION_WPA) || | |
2777 | (iwa_val == IW_AUTH_WPA_VERSION_DISABLED)) | |
68c0bdff | 2778 | ret = 0; |
9ef02300 DK |
2779 | else |
2780 | ret = -EINVAL; | |
2781 | break; | |
68c0bdff | 2782 | |
9ef02300 DK |
2783 | case IW_AUTH_WPA_ENABLED: |
2784 | DBG_TRACE(DbgInfo, "val = %d\n", iwa_val); | |
2785 | if (iwa_val) | |
2786 | lp->EnableEncryption = 2; | |
2787 | else | |
2788 | lp->EnableEncryption = 0; | |
68c0bdff | 2789 | |
9ef02300 DK |
2790 | /* Write straight to the card */ |
2791 | ltv.len = 2; | |
2792 | ltv.typ = CFG_CNF_ENCRYPTION; | |
2793 | ltv.u.u16[0] = cpu_to_le16(lp->EnableEncryption); | |
2794 | ret = hcf_put_info(&lp->hcfCtx, (LTVP)<v); | |
68c0bdff | 2795 | |
9ef02300 | 2796 | break; |
68c0bdff | 2797 | |
9ef02300 | 2798 | case IW_AUTH_TKIP_COUNTERMEASURES: |
68c0bdff | 2799 | |
9ef02300 DK |
2800 | /* Immediately disable card */ |
2801 | lp->driverEnable = !iwa_val; | |
2802 | if (lp->driverEnable) | |
2803 | hcf_cntl(&(lp->hcfCtx), HCF_CNTL_ENABLE | HCF_PORT_0); | |
2804 | else | |
2805 | hcf_cntl(&(lp->hcfCtx), HCF_CNTL_DISABLE | HCF_PORT_0); | |
2806 | ret = 0; | |
2807 | break; | |
68c0bdff | 2808 | |
9ef02300 DK |
2809 | case IW_AUTH_MFP: |
2810 | /* Management Frame Protection not supported. | |
2811 | * Only fail if set to required. | |
2812 | */ | |
2813 | if (iwa_val == IW_AUTH_MFP_REQUIRED) | |
68c0bdff | 2814 | ret = -EINVAL; |
9ef02300 DK |
2815 | else |
2816 | ret = 0; | |
2817 | break; | |
68c0bdff | 2818 | |
9ef02300 | 2819 | case IW_AUTH_KEY_MGMT: |
68c0bdff | 2820 | |
9ef02300 DK |
2821 | /* Record required management suite. |
2822 | * Will take effect on next commit */ | |
2823 | if (iwa_val != 0) | |
2824 | lp->AuthKeyMgmtSuite = 4; | |
2825 | else | |
2826 | lp->AuthKeyMgmtSuite = 0; | |
68c0bdff | 2827 | |
9ef02300 DK |
2828 | ret = -EINPROGRESS; |
2829 | break; | |
68c0bdff | 2830 | |
9ef02300 DK |
2831 | case IW_AUTH_80211_AUTH_ALG: |
2832 | ||
2833 | /* Just record whether open or shared is required. | |
2834 | * Will take effect on next commit */ | |
2835 | ret = -EINPROGRESS; | |
2836 | ||
2837 | if (iwa_val & IW_AUTH_ALG_SHARED_KEY) | |
2838 | lp->authentication = 1; | |
2839 | else if (iwa_val & IW_AUTH_ALG_OPEN_SYSTEM) | |
2840 | lp->authentication = 0; | |
2841 | else | |
68c0bdff | 2842 | ret = -EINVAL; |
9ef02300 DK |
2843 | break; |
2844 | ||
2845 | case IW_AUTH_DROP_UNENCRYPTED: | |
2846 | /* Only needed for AP */ | |
2847 | lp->ExcludeUnencrypted = iwa_val; | |
2848 | ret = -EINPROGRESS; | |
2849 | break; | |
2850 | ||
2851 | case IW_AUTH_CIPHER_PAIRWISE: | |
2852 | case IW_AUTH_CIPHER_GROUP: | |
2853 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | |
2854 | case IW_AUTH_ROAMING_CONTROL: | |
2855 | case IW_AUTH_PRIVACY_INVOKED: | |
2856 | /* Not used. May need to do something with | |
2857 | * CIPHER_PAIRWISE and CIPHER_GROUP*/ | |
2858 | ret = -EINPROGRESS; | |
2859 | break; | |
2860 | ||
2861 | default: | |
2862 | DBG_TRACE(DbgInfo, "IW_AUTH_?? (%d) unknown\n", iwa_idx); | |
2863 | /* return an error */ | |
2864 | ret = -EOPNOTSUPP; | |
2865 | break; | |
68c0bdff HG |
2866 | } |
2867 | ||
2868 | wl_act_int_on( lp ); | |
2869 | ||
2870 | wl_unlock(lp, &flags); | |
2871 | ||
2872 | out: | |
68c0bdff HG |
2873 | return ret; |
2874 | } // wireless_set_auth | |
2875 | /*============================================================================*/ | |
2876 | ||
2877 | ||
05df482e | 2878 | static void flush_tx(struct wl_private *lp) |
68c0bdff | 2879 | { |
05df482e DK |
2880 | ltv_t ltv; |
2881 | int count; | |
68c0bdff HG |
2882 | |
2883 | /* | |
05df482e DK |
2884 | * Make sure that there is no data queued up in the firmware |
2885 | * before setting the TKIP keys. If this check is not | |
2886 | * performed, some data may be sent out with incorrect MIC | |
86f9150c | 2887 | * and cause synchronization errors with the AP |
05df482e DK |
2888 | */ |
2889 | /* Check every 1ms for 100ms */ | |
2890 | for (count = 0; count < 100; count++) { | |
2891 | udelay(1000); | |
2892 | ||
2893 | ltv.len = 2; | |
2894 | ltv.typ = 0xFD91; /* This RID not defined in HCF yet!!! */ | |
2895 | ltv.u.u16[0] = 0; | |
2896 | ||
2897 | hcf_get_info(&(lp->hcfCtx), (LTVP)<v); | |
2898 | ||
2899 | if (ltv.u.u16[0] == 0) | |
2900 | break; | |
2901 | } | |
68c0bdff | 2902 | |
05df482e DK |
2903 | if (count >= 100) |
2904 | DBG_TRACE(DbgInfo, "Timed out waiting for TxQ flush!\n"); | |
68c0bdff | 2905 | |
05df482e | 2906 | } |
68c0bdff | 2907 | |
05df482e DK |
2908 | static int wireless_set_encodeext(struct net_device *dev, |
2909 | struct iw_request_info *info, | |
2910 | struct iw_point *erq, char *keybuf) | |
2911 | { | |
2912 | struct wl_private *lp = wl_priv(dev); | |
2913 | unsigned long flags; | |
2914 | int ret; | |
2915 | int key_idx = (erq->flags & IW_ENCODE_INDEX) - 1; | |
2916 | ltv_t ltv; | |
2917 | struct iw_encode_ext *ext = (struct iw_encode_ext *)keybuf; | |
2918 | bool enable = true; | |
2919 | bool set_tx = false; | |
68c0bdff | 2920 | |
05df482e DK |
2921 | if (lp->portState == WVLAN_PORT_STATE_DISABLED) { |
2922 | ret = -EBUSY; | |
2923 | goto out; | |
2924 | } | |
68c0bdff | 2925 | |
05df482e DK |
2926 | if (erq->flags & IW_ENCODE_DISABLED) { |
2927 | ext->alg = IW_ENCODE_ALG_NONE; | |
2928 | enable = false; | |
2929 | } | |
68c0bdff | 2930 | |
05df482e DK |
2931 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) |
2932 | set_tx = true; | |
68c0bdff | 2933 | |
05df482e | 2934 | wl_lock(lp, &flags); |
68c0bdff | 2935 | |
05df482e | 2936 | wl_act_int_off(lp); |
68c0bdff | 2937 | |
05df482e | 2938 | memset(<v, 0, sizeof(ltv)); |
68c0bdff | 2939 | |
05df482e DK |
2940 | switch (ext->alg) { |
2941 | case IW_ENCODE_ALG_TKIP: | |
2942 | DBG_TRACE(DbgInfo, "IW_ENCODE_ALG_TKIP: key(%d)\n", key_idx); | |
68c0bdff | 2943 | |
05df482e DK |
2944 | if (sizeof(ext->rx_seq) != 8) { |
2945 | DBG_TRACE(DbgInfo, "rx_seq size mismatch\n"); | |
05df482e DK |
2946 | ret = -EINVAL; |
2947 | goto out_unlock; | |
2948 | } | |
68c0bdff | 2949 | |
05df482e DK |
2950 | ret = hermes_set_tkip_keys(<v, key_idx, ext->addr.sa_data, |
2951 | set_tx, | |
2952 | ext->rx_seq, ext->key, ext->key_len); | |
68c0bdff | 2953 | |
05df482e DK |
2954 | if (ret != 0) { |
2955 | DBG_TRACE(DbgInfo, "hermes_set_tkip_keys returned != 0, key not set\n"); | |
2956 | goto out_unlock; | |
2957 | } | |
68c0bdff | 2958 | |
05df482e | 2959 | flush_tx(lp); |
68c0bdff | 2960 | |
05df482e | 2961 | lp->wext_enc = IW_ENCODE_ALG_TKIP; |
68c0bdff | 2962 | |
05df482e DK |
2963 | /* Write the key */ |
2964 | ret = hcf_put_info(&(lp->hcfCtx), (LTVP)<v); | |
2965 | break; | |
68c0bdff | 2966 | |
05df482e DK |
2967 | case IW_ENCODE_ALG_WEP: |
2968 | DBG_TRACE(DbgInfo, "IW_ENCODE_ALG_WEP: key(%d)\n", key_idx); | |
2969 | ||
2970 | if (erq->flags & IW_ENCODE_RESTRICTED) { | |
2971 | DBG_WARNING(DbgInfo, "IW_ENCODE_RESTRICTED invalid\n"); | |
2972 | ret = -EINVAL; | |
2973 | goto out_unlock; | |
68c0bdff HG |
2974 | } |
2975 | ||
05df482e DK |
2976 | ret = hermes_set_wep_keys(lp, key_idx, ext->key, ext->key_len, |
2977 | enable, set_tx); | |
68c0bdff | 2978 | |
68c0bdff HG |
2979 | break; |
2980 | ||
2981 | case IW_ENCODE_ALG_CCMP: | |
05df482e DK |
2982 | DBG_TRACE(DbgInfo, "IW_ENCODE_ALG_CCMP: key(%d)\n", key_idx); |
2983 | ret = -EOPNOTSUPP; | |
68c0bdff HG |
2984 | break; |
2985 | ||
2986 | case IW_ENCODE_ALG_NONE: | |
05df482e DK |
2987 | DBG_TRACE(DbgInfo, "IW_ENCODE_ALG_NONE: key(%d)\n", key_idx); |
2988 | ||
2989 | if (lp->wext_enc == IW_ENCODE_ALG_TKIP) { | |
2990 | ret = hermes_clear_tkip_keys(<v, key_idx, | |
2991 | ext->addr.sa_data); | |
2992 | flush_tx(lp); | |
2993 | lp->wext_enc = IW_ENCODE_ALG_NONE; | |
2994 | ret = hcf_put_info(&(lp->hcfCtx), (LTVP)<v); | |
2995 | ||
2996 | } else if (lp->wext_enc == IW_ENCODE_ALG_WEP) { | |
2997 | ret = hermes_set_wep_keys(lp, key_idx, | |
2998 | ext->key, ext->key_len, | |
2999 | false, false); | |
3000 | } else { | |
68c0bdff | 3001 | ret = 0; |
68c0bdff | 3002 | } |
05df482e | 3003 | |
68c0bdff | 3004 | break; |
05df482e | 3005 | |
68c0bdff HG |
3006 | default: |
3007 | DBG_TRACE( DbgInfo, "IW_ENCODE_??: key(%d)\n", key_idx); | |
05df482e | 3008 | ret = -EOPNOTSUPP; |
68c0bdff HG |
3009 | break; |
3010 | } | |
3011 | ||
68c0bdff | 3012 | out_unlock: |
68c0bdff | 3013 | |
05df482e | 3014 | wl_act_int_on(lp); |
68c0bdff HG |
3015 | |
3016 | wl_unlock(lp, &flags); | |
3017 | ||
3018 | out: | |
68c0bdff | 3019 | return ret; |
05df482e | 3020 | } |
68c0bdff HG |
3021 | /*============================================================================*/ |
3022 | ||
3023 | ||
3024 | ||
729336b3 DK |
3025 | static int wireless_set_genie(struct net_device *dev, |
3026 | struct iw_request_info *info, | |
3027 | struct iw_point *data, char *extra) | |
68c0bdff HG |
3028 | |
3029 | { | |
68c0bdff | 3030 | int ret = 0; |
68c0bdff | 3031 | |
729336b3 DK |
3032 | /* We can't write this to the card, but apparently this |
3033 | * operation needs to succeed */ | |
3034 | ret = 0; | |
68c0bdff | 3035 | |
68c0bdff HG |
3036 | return ret; |
3037 | } | |
3038 | /*============================================================================*/ | |
3039 | ||
3040 | ||
68c0bdff HG |
3041 | /******************************************************************************* |
3042 | * wl_wireless_stats() | |
3043 | ******************************************************************************* | |
3044 | * | |
3045 | * DESCRIPTION: | |
3046 | * | |
3047 | * Return the current device wireless statistics. | |
3048 | * | |
3049 | * PARAMETERS: | |
3050 | * | |
3051 | * wrq - the wireless request buffer | |
3052 | * lp - the device's private adapter structure | |
3053 | * | |
3054 | * RETURNS: | |
3055 | * | |
3056 | * 0 on success | |
3057 | * errno value otherwise | |
3058 | * | |
3059 | ******************************************************************************/ | |
3060 | struct iw_statistics * wl_wireless_stats( struct net_device *dev ) | |
3061 | { | |
3062 | struct iw_statistics *pStats; | |
3063 | struct wl_private *lp = wl_priv(dev); | |
68c0bdff | 3064 | |
68c0bdff HG |
3065 | DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev); |
3066 | ||
3067 | pStats = NULL; | |
3068 | ||
3069 | /* Initialize the statistics */ | |
3070 | pStats = &( lp->wstats ); | |
3071 | pStats->qual.updated = 0x00; | |
3072 | ||
3073 | if( !( lp->flags & WVLAN2_UIL_BUSY )) | |
3074 | { | |
3075 | CFG_COMMS_QUALITY_STRCT *pQual; | |
3076 | CFG_HERMES_TALLIES_STRCT tallies; | |
3077 | int status; | |
3078 | ||
3079 | /* Update driver status */ | |
3080 | pStats->status = 0; | |
3081 | ||
3082 | /* Get the current link quality information */ | |
3083 | lp->ltvRecord.len = 1 + ( sizeof( *pQual ) / sizeof( hcf_16 )); | |
3084 | lp->ltvRecord.typ = CFG_COMMS_QUALITY; | |
68c0bdff HG |
3085 | status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); |
3086 | ||
3087 | if( status == HCF_SUCCESS ) { | |
3088 | pQual = (CFG_COMMS_QUALITY_STRCT *)&( lp->ltvRecord ); | |
3089 | ||
68c0bdff HG |
3090 | pStats->qual.qual = (u_char) CNV_LITTLE_TO_INT( pQual->coms_qual ); |
3091 | pStats->qual.level = (u_char) dbm( CNV_LITTLE_TO_INT( pQual->signal_lvl )); | |
3092 | pStats->qual.noise = (u_char) dbm( CNV_LITTLE_TO_INT( pQual->noise_lvl )); | |
e81589a7 HG |
3093 | |
3094 | pStats->qual.updated |= (IW_QUAL_QUAL_UPDATED | | |
3095 | IW_QUAL_LEVEL_UPDATED | | |
3096 | IW_QUAL_NOISE_UPDATED | | |
3097 | IW_QUAL_DBM); | |
68c0bdff HG |
3098 | } else { |
3099 | memset( &( pStats->qual ), 0, sizeof( pStats->qual )); | |
3100 | } | |
3101 | ||
3102 | /* Get the current tallies from the adapter */ | |
3103 | /* Only possible when the device is open */ | |
3104 | if(lp->portState == WVLAN_PORT_STATE_DISABLED) { | |
3105 | if( wl_get_tallies( lp, &tallies ) == 0 ) { | |
3106 | /* No endian translation is needed here, as CFG_TALLIES is an | |
3107 | MSF RID; all processing is done on the host, not the card! */ | |
3108 | pStats->discard.nwid = 0L; | |
3109 | pStats->discard.code = tallies.RxWEPUndecryptable; | |
3110 | pStats->discard.misc = tallies.TxDiscards + | |
3111 | tallies.RxFCSErrors + | |
3112 | //tallies.RxDiscardsNoBuffer + | |
3113 | tallies.TxDiscardsWrongSA; | |
3114 | //;? Extra taken over from Linux driver based on 7.18 version | |
3115 | pStats->discard.retries = tallies.TxRetryLimitExceeded; | |
3116 | pStats->discard.fragment = tallies.RxMsgInBadMsgFragments; | |
3117 | } else { | |
3118 | memset( &( pStats->discard ), 0, sizeof( pStats->discard )); | |
3119 | } | |
3120 | } else { | |
3121 | memset( &( pStats->discard ), 0, sizeof( pStats->discard )); | |
3122 | } | |
3123 | } | |
3124 | ||
68c0bdff HG |
3125 | return pStats; |
3126 | } // wl_wireless_stats | |
3127 | /*============================================================================*/ | |
3128 | ||
3129 | ||
3130 | ||
3131 | ||
3132 | /******************************************************************************* | |
3133 | * wl_get_wireless_stats() | |
3134 | ******************************************************************************* | |
3135 | * | |
3136 | * DESCRIPTION: | |
3137 | * | |
3138 | * Return the current device wireless statistics. This function calls | |
3139 | * wl_wireless_stats, but acquires spinlocks first as it can be called | |
3140 | * directly by the network layer. | |
3141 | * | |
3142 | * PARAMETERS: | |
3143 | * | |
3144 | * wrq - the wireless request buffer | |
3145 | * lp - the device's private adapter structure | |
3146 | * | |
3147 | * RETURNS: | |
3148 | * | |
3149 | * 0 on success | |
3150 | * errno value otherwise | |
3151 | * | |
3152 | ******************************************************************************/ | |
3153 | struct iw_statistics * wl_get_wireless_stats( struct net_device *dev ) | |
3154 | { | |
3155 | unsigned long flags; | |
3156 | struct wl_private *lp = wl_priv(dev); | |
3157 | struct iw_statistics *pStats = NULL; | |
68c0bdff HG |
3158 | |
3159 | wl_lock( lp, &flags ); | |
3160 | ||
3161 | wl_act_int_off( lp ); | |
3162 | ||
3163 | #ifdef USE_RTS | |
3164 | if( lp->useRTS == 1 ) { | |
3165 | DBG_TRACE( DbgInfo, "Skipping wireless stats, in RTS mode\n" ); | |
3166 | } else | |
3167 | #endif | |
3168 | { | |
3169 | pStats = wl_wireless_stats( dev ); | |
3170 | } | |
3171 | wl_act_int_on( lp ); | |
3172 | ||
3173 | wl_unlock(lp, &flags); | |
3174 | ||
68c0bdff HG |
3175 | return pStats; |
3176 | } // wl_get_wireless_stats | |
3177 | ||
3178 | ||
3179 | /******************************************************************************* | |
3180 | * wl_spy_gather() | |
3181 | ******************************************************************************* | |
3182 | * | |
3183 | * DESCRIPTION: | |
3184 | * | |
3185 | * Gather wireless spy statistics. | |
3186 | * | |
3187 | * PARAMETERS: | |
3188 | * | |
3189 | * wrq - the wireless request buffer | |
3190 | * lp - the device's private adapter structure | |
3191 | * | |
3192 | * RETURNS: | |
3193 | * | |
3194 | * 0 on success | |
3195 | * errno value otherwise | |
3196 | * | |
3197 | ******************************************************************************/ | |
3198 | inline void wl_spy_gather( struct net_device *dev, u_char *mac ) | |
3199 | { | |
3200 | struct iw_quality wstats; | |
3201 | int status; | |
3202 | u_char stats[2]; | |
3203 | DESC_STRCT desc[1]; | |
3204 | struct wl_private *lp = wl_priv(dev); | |
3205 | /*------------------------------------------------------------------------*/ | |
3206 | ||
3207 | /* shortcut */ | |
3208 | if (!lp->spy_data.spy_number) { | |
3209 | return; | |
3210 | } | |
3211 | ||
3212 | /* Gather wireless spy statistics: for each packet, compare the source | |
3213 | address with out list, and if match, get the stats. */ | |
3214 | memset( stats, 0, sizeof(stats)); | |
3215 | memset( desc, 0, sizeof(DESC_STRCT)); | |
3216 | ||
3217 | desc[0].buf_addr = stats; | |
3218 | desc[0].BUF_SIZE = sizeof(stats); | |
3219 | desc[0].next_desc_addr = 0; // terminate list | |
3220 | ||
3221 | status = hcf_rcv_msg( &( lp->hcfCtx ), &desc[0], 0 ); | |
3222 | ||
3223 | if( status == HCF_SUCCESS ) { | |
3224 | wstats.level = (u_char) dbm(stats[1]); | |
3225 | wstats.noise = (u_char) dbm(stats[0]); | |
3226 | wstats.qual = wstats.level > wstats.noise ? wstats.level - wstats.noise : 0; | |
3227 | ||
e81589a7 HG |
3228 | wstats.updated = (IW_QUAL_QUAL_UPDATED | |
3229 | IW_QUAL_LEVEL_UPDATED | | |
3230 | IW_QUAL_NOISE_UPDATED | | |
3231 | IW_QUAL_DBM); | |
68c0bdff HG |
3232 | |
3233 | wireless_spy_update( dev, mac, &wstats ); | |
3234 | } | |
3235 | } // wl_spy_gather | |
3236 | /*============================================================================*/ | |
3237 | ||
3238 | ||
3239 | ||
3240 | ||
3241 | /******************************************************************************* | |
3242 | * wl_wext_event_freq() | |
3243 | ******************************************************************************* | |
3244 | * | |
3245 | * DESCRIPTION: | |
3246 | * | |
3247 | * This function is used to send an event that the channel/freq | |
3248 | * configuration for a specific device has changed. | |
3249 | * | |
3250 | * | |
3251 | * PARAMETERS: | |
3252 | * | |
3253 | * dev - the network device for which this event is to be issued | |
3254 | * | |
3255 | * RETURNS: | |
3256 | * | |
3257 | * N/A | |
3258 | * | |
3259 | ******************************************************************************/ | |
3260 | void wl_wext_event_freq( struct net_device *dev ) | |
3261 | { | |
68c0bdff HG |
3262 | union iwreq_data wrqu; |
3263 | struct wl_private *lp = wl_priv(dev); | |
3264 | /*------------------------------------------------------------------------*/ | |
3265 | ||
3266 | ||
3267 | memset( &wrqu, 0, sizeof( wrqu )); | |
3268 | ||
3269 | wrqu.freq.m = lp->Channel; | |
3270 | wrqu.freq.e = 0; | |
3271 | ||
3272 | wireless_send_event( dev, SIOCSIWFREQ, &wrqu, NULL ); | |
68c0bdff HG |
3273 | |
3274 | return; | |
3275 | } // wl_wext_event_freq | |
3276 | /*============================================================================*/ | |
3277 | ||
3278 | ||
3279 | ||
3280 | ||
3281 | /******************************************************************************* | |
3282 | * wl_wext_event_mode() | |
3283 | ******************************************************************************* | |
3284 | * | |
3285 | * DESCRIPTION: | |
3286 | * | |
3287 | * This function is used to send an event that the mode of operation | |
3288 | * for a specific device has changed. | |
3289 | * | |
3290 | * | |
3291 | * PARAMETERS: | |
3292 | * | |
3293 | * dev - the network device for which this event is to be issued | |
3294 | * | |
3295 | * RETURNS: | |
3296 | * | |
3297 | * N/A | |
3298 | * | |
3299 | ******************************************************************************/ | |
3300 | void wl_wext_event_mode( struct net_device *dev ) | |
3301 | { | |
68c0bdff HG |
3302 | union iwreq_data wrqu; |
3303 | struct wl_private *lp = wl_priv(dev); | |
3304 | /*------------------------------------------------------------------------*/ | |
3305 | ||
3306 | ||
3307 | memset( &wrqu, 0, sizeof( wrqu )); | |
3308 | ||
3309 | if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_STA ) { | |
3310 | wrqu.mode = IW_MODE_INFRA; | |
3311 | } else { | |
3312 | wrqu.mode = IW_MODE_MASTER; | |
3313 | } | |
3314 | ||
3315 | wireless_send_event( dev, SIOCSIWMODE, &wrqu, NULL ); | |
68c0bdff HG |
3316 | |
3317 | return; | |
3318 | } // wl_wext_event_mode | |
3319 | /*============================================================================*/ | |
3320 | ||
3321 | ||
3322 | ||
3323 | ||
3324 | /******************************************************************************* | |
3325 | * wl_wext_event_essid() | |
3326 | ******************************************************************************* | |
3327 | * | |
3328 | * DESCRIPTION: | |
3329 | * | |
3330 | * This function is used to send an event that the ESSID configuration for | |
3331 | * a specific device has changed. | |
3332 | * | |
3333 | * | |
3334 | * PARAMETERS: | |
3335 | * | |
3336 | * dev - the network device for which this event is to be issued | |
3337 | * | |
3338 | * RETURNS: | |
3339 | * | |
3340 | * N/A | |
3341 | * | |
3342 | ******************************************************************************/ | |
3343 | void wl_wext_event_essid( struct net_device *dev ) | |
3344 | { | |
68c0bdff HG |
3345 | union iwreq_data wrqu; |
3346 | struct wl_private *lp = wl_priv(dev); | |
3347 | /*------------------------------------------------------------------------*/ | |
3348 | ||
3349 | ||
3350 | memset( &wrqu, 0, sizeof( wrqu )); | |
3351 | ||
3352 | /* Fill out the buffer. Note that the buffer doesn't actually contain the | |
3353 | ESSID, but a pointer to the contents. In addition, the 'extra' field of | |
3354 | the call to wireless_send_event() must also point to where the ESSID | |
3355 | lives */ | |
3356 | wrqu.essid.length = strlen( lp->NetworkName ); | |
3357 | wrqu.essid.pointer = (caddr_t)lp->NetworkName; | |
3358 | wrqu.essid.flags = 1; | |
3359 | ||
3360 | wireless_send_event( dev, SIOCSIWESSID, &wrqu, lp->NetworkName ); | |
68c0bdff HG |
3361 | |
3362 | return; | |
3363 | } // wl_wext_event_essid | |
3364 | /*============================================================================*/ | |
3365 | ||
3366 | ||
3367 | ||
3368 | ||
3369 | /******************************************************************************* | |
3370 | * wl_wext_event_encode() | |
3371 | ******************************************************************************* | |
3372 | * | |
3373 | * DESCRIPTION: | |
3374 | * | |
3375 | * This function is used to send an event that the encryption configuration | |
3376 | * for a specific device has changed. | |
3377 | * | |
3378 | * | |
3379 | * PARAMETERS: | |
3380 | * | |
3381 | * dev - the network device for which this event is to be issued | |
3382 | * | |
3383 | * RETURNS: | |
3384 | * | |
3385 | * N/A | |
3386 | * | |
3387 | ******************************************************************************/ | |
3388 | void wl_wext_event_encode( struct net_device *dev ) | |
3389 | { | |
68c0bdff HG |
3390 | union iwreq_data wrqu; |
3391 | struct wl_private *lp = wl_priv(dev); | |
3392 | int index = 0; | |
3393 | /*------------------------------------------------------------------------*/ | |
3394 | ||
3395 | ||
3396 | memset( &wrqu, 0, sizeof( wrqu )); | |
3397 | ||
3398 | if( lp->EnableEncryption == 0 ) { | |
3399 | wrqu.encoding.flags = IW_ENCODE_DISABLED; | |
3400 | } else { | |
3401 | wrqu.encoding.flags |= lp->TransmitKeyID; | |
3402 | ||
3403 | index = lp->TransmitKeyID - 1; | |
3404 | ||
3405 | /* Only set IW_ENCODE_RESTRICTED/OPEN flag using lp->ExcludeUnencrypted | |
3406 | if we're in AP mode */ | |
3407 | #if 1 //;? (HCF_TYPE) & HCF_TYPE_AP | |
3408 | //;?should we restore this to allow smaller memory footprint | |
3409 | ||
3410 | if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) { | |
3411 | if( lp->ExcludeUnencrypted ) { | |
3412 | wrqu.encoding.flags |= IW_ENCODE_RESTRICTED; | |
3413 | } else { | |
3414 | wrqu.encoding.flags |= IW_ENCODE_OPEN; | |
3415 | } | |
3416 | } | |
3417 | ||
3418 | #endif // HCF_TYPE_AP | |
3419 | ||
3420 | /* Only provide the key if permissions allow */ | |
3421 | if( capable( CAP_NET_ADMIN )) { | |
3422 | wrqu.encoding.pointer = (caddr_t)lp->DefaultKeys.key[index].key; | |
3423 | wrqu.encoding.length = lp->DefaultKeys.key[index].len; | |
3424 | } else { | |
3425 | wrqu.encoding.flags |= IW_ENCODE_NOKEY; | |
3426 | } | |
3427 | } | |
3428 | ||
3429 | wireless_send_event( dev, SIOCSIWENCODE, &wrqu, | |
3430 | lp->DefaultKeys.key[index].key ); | |
68c0bdff HG |
3431 | |
3432 | return; | |
3433 | } // wl_wext_event_encode | |
3434 | /*============================================================================*/ | |
3435 | ||
3436 | ||
3437 | ||
3438 | ||
3439 | /******************************************************************************* | |
3440 | * wl_wext_event_ap() | |
3441 | ******************************************************************************* | |
3442 | * | |
3443 | * DESCRIPTION: | |
3444 | * | |
3445 | * This function is used to send an event that the device has been | |
3446 | * associated to a new AP. | |
3447 | * | |
3448 | * | |
3449 | * PARAMETERS: | |
3450 | * | |
3451 | * dev - the network device for which this event is to be issued | |
3452 | * | |
3453 | * RETURNS: | |
3454 | * | |
3455 | * N/A | |
3456 | * | |
3457 | ******************************************************************************/ | |
3458 | void wl_wext_event_ap( struct net_device *dev ) | |
3459 | { | |
68c0bdff HG |
3460 | union iwreq_data wrqu; |
3461 | struct wl_private *lp = wl_priv(dev); | |
3462 | int status; | |
3463 | /*------------------------------------------------------------------------*/ | |
3464 | ||
3465 | ||
3466 | /* Retrieve the WPA-IEs used by the firmware and send an event. We must send | |
3467 | this event BEFORE sending the association event, as there are timing | |
3468 | issues with the hostap supplicant. The supplicant will attempt to process | |
3469 | an EAPOL-Key frame from an AP before receiving this information, which | |
86f9150c | 3470 | is required for a proper processed frame. */ |
68c0bdff HG |
3471 | wl_wext_event_assoc_ie( dev ); |
3472 | ||
3473 | /* Get the BSSID */ | |
3474 | lp->ltvRecord.typ = CFG_CUR_BSSID; | |
3475 | lp->ltvRecord.len = 4; | |
3476 | ||
3477 | status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); | |
3478 | if( status == HCF_SUCCESS ) { | |
3479 | memset( &wrqu, 0, sizeof( wrqu )); | |
3480 | ||
3481 | memcpy( wrqu.addr.sa_data, lp->ltvRecord.u.u8, ETH_ALEN ); | |
3482 | ||
3483 | wrqu.addr.sa_family = ARPHRD_ETHER; | |
3484 | ||
3485 | wireless_send_event( dev, SIOCGIWAP, &wrqu, NULL ); | |
3486 | } | |
3487 | ||
68c0bdff HG |
3488 | return; |
3489 | } // wl_wext_event_ap | |
3490 | /*============================================================================*/ | |
3491 | ||
3492 | ||
3493 | ||
3494 | /******************************************************************************* | |
3495 | * wl_wext_event_scan_complete() | |
3496 | ******************************************************************************* | |
3497 | * | |
3498 | * DESCRIPTION: | |
3499 | * | |
3500 | * This function is used to send an event that a request for a network scan | |
3501 | * has completed. | |
3502 | * | |
3503 | * | |
3504 | * PARAMETERS: | |
3505 | * | |
3506 | * dev - the network device for which this event is to be issued | |
3507 | * | |
3508 | * RETURNS: | |
3509 | * | |
3510 | * N/A | |
3511 | * | |
3512 | ******************************************************************************/ | |
3513 | void wl_wext_event_scan_complete( struct net_device *dev ) | |
3514 | { | |
68c0bdff HG |
3515 | union iwreq_data wrqu; |
3516 | /*------------------------------------------------------------------------*/ | |
3517 | ||
3518 | ||
3519 | memset( &wrqu, 0, sizeof( wrqu )); | |
3520 | ||
3521 | wrqu.addr.sa_family = ARPHRD_ETHER; | |
3522 | wireless_send_event( dev, SIOCGIWSCAN, &wrqu, NULL ); | |
68c0bdff HG |
3523 | |
3524 | return; | |
3525 | } // wl_wext_event_scan_complete | |
3526 | /*============================================================================*/ | |
3527 | ||
3528 | ||
3529 | ||
3530 | ||
3531 | /******************************************************************************* | |
3532 | * wl_wext_event_new_sta() | |
3533 | ******************************************************************************* | |
3534 | * | |
3535 | * DESCRIPTION: | |
3536 | * | |
3537 | * This function is used to send an event that an AP has registered a new | |
3538 | * station. | |
3539 | * | |
3540 | * | |
3541 | * PARAMETERS: | |
3542 | * | |
3543 | * dev - the network device for which this event is to be issued | |
3544 | * | |
3545 | * RETURNS: | |
3546 | * | |
3547 | * N/A | |
3548 | * | |
3549 | ******************************************************************************/ | |
3550 | void wl_wext_event_new_sta( struct net_device *dev ) | |
3551 | { | |
68c0bdff HG |
3552 | union iwreq_data wrqu; |
3553 | /*------------------------------------------------------------------------*/ | |
3554 | ||
3555 | ||
3556 | memset( &wrqu, 0, sizeof( wrqu )); | |
3557 | ||
3558 | /* Send the station's mac address here */ | |
3559 | memcpy( wrqu.addr.sa_data, dev->dev_addr, ETH_ALEN ); | |
3560 | wrqu.addr.sa_family = ARPHRD_ETHER; | |
3561 | wireless_send_event( dev, IWEVREGISTERED, &wrqu, NULL ); | |
68c0bdff HG |
3562 | |
3563 | return; | |
3564 | } // wl_wext_event_new_sta | |
3565 | /*============================================================================*/ | |
3566 | ||
3567 | ||
3568 | ||
3569 | ||
3570 | /******************************************************************************* | |
3571 | * wl_wext_event_expired_sta() | |
3572 | ******************************************************************************* | |
3573 | * | |
3574 | * DESCRIPTION: | |
3575 | * | |
3576 | * This function is used to send an event that an AP has deregistered a | |
3577 | * station. | |
3578 | * | |
3579 | * | |
3580 | * PARAMETERS: | |
3581 | * | |
3582 | * dev - the network device for which this event is to be issued | |
3583 | * | |
3584 | * RETURNS: | |
3585 | * | |
3586 | * N/A | |
3587 | * | |
3588 | ******************************************************************************/ | |
3589 | void wl_wext_event_expired_sta( struct net_device *dev ) | |
3590 | { | |
68c0bdff HG |
3591 | union iwreq_data wrqu; |
3592 | /*------------------------------------------------------------------------*/ | |
3593 | ||
3594 | ||
3595 | memset( &wrqu, 0, sizeof( wrqu )); | |
3596 | ||
3597 | memcpy( wrqu.addr.sa_data, dev->dev_addr, ETH_ALEN ); | |
3598 | wrqu.addr.sa_family = ARPHRD_ETHER; | |
3599 | wireless_send_event( dev, IWEVEXPIRED, &wrqu, NULL ); | |
68c0bdff HG |
3600 | |
3601 | return; | |
3602 | } // wl_wext_event_expired_sta | |
3603 | /*============================================================================*/ | |
3604 | ||
3605 | ||
3606 | ||
3607 | ||
3608 | /******************************************************************************* | |
3609 | * wl_wext_event_mic_failed() | |
3610 | ******************************************************************************* | |
3611 | * | |
3612 | * DESCRIPTION: | |
3613 | * | |
3614 | * This function is used to send an event that MIC calculations failed. | |
3615 | * | |
3616 | * | |
3617 | * PARAMETERS: | |
3618 | * | |
3619 | * dev - the network device for which this event is to be issued | |
3620 | * | |
3621 | * RETURNS: | |
3622 | * | |
3623 | * N/A | |
3624 | * | |
3625 | ******************************************************************************/ | |
3626 | void wl_wext_event_mic_failed( struct net_device *dev ) | |
3627 | { | |
68c0bdff HG |
3628 | union iwreq_data wrqu; |
3629 | struct wl_private *lp = wl_priv(dev); | |
a4f7b2e8 | 3630 | struct iw_michaelmicfailure wxmic; |
68c0bdff HG |
3631 | int key_idx; |
3632 | char *addr1; | |
3633 | char *addr2; | |
3634 | WVLAN_RX_WMP_HDR *hdr; | |
3635 | /*------------------------------------------------------------------------*/ | |
3636 | ||
3637 | ||
3638 | key_idx = lp->lookAheadBuf[HFS_STAT+1] >> 3; | |
3639 | key_idx &= 0x03; | |
3640 | ||
3641 | /* Cast the lookahead buffer into a RFS format */ | |
3642 | hdr = (WVLAN_RX_WMP_HDR *)&lp->lookAheadBuf[HFS_STAT]; | |
3643 | ||
3644 | /* Cast the addresses to byte buffers, as in the above RFS they are word | |
3645 | length */ | |
3646 | addr1 = (char *)hdr->address1; | |
3647 | addr2 = (char *)hdr->address2; | |
3648 | ||
3649 | DBG_PRINT( "MIC FAIL - KEY USED : %d, STATUS : 0x%04x\n", key_idx, | |
3650 | hdr->status ); | |
3651 | ||
a4f7b2e8 DK |
3652 | memset(&wrqu, 0, sizeof(wrqu)); |
3653 | memset(&wxmic, 0, sizeof(wxmic)); | |
68c0bdff | 3654 | |
a4f7b2e8 DK |
3655 | wxmic.flags = key_idx & IW_MICFAILURE_KEY_ID; |
3656 | wxmic.flags |= (addr1[0] & 1) ? | |
3657 | IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE; | |
3658 | wxmic.src_addr.sa_family = ARPHRD_ETHER; | |
3659 | memcpy(wxmic.src_addr.sa_data, addr2, ETH_ALEN); | |
68c0bdff | 3660 | |
a4f7b2e8 DK |
3661 | wrqu.data.length = sizeof(wxmic); |
3662 | wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&wxmic); | |
68c0bdff HG |
3663 | |
3664 | return; | |
3665 | } // wl_wext_event_mic_failed | |
3666 | /*============================================================================*/ | |
3667 | ||
3668 | ||
3669 | ||
3670 | ||
3671 | /******************************************************************************* | |
3672 | * wl_wext_event_assoc_ie() | |
3673 | ******************************************************************************* | |
3674 | * | |
3675 | * DESCRIPTION: | |
3676 | * | |
3677 | * This function is used to send an event containing the WPA-IE generated | |
3678 | * by the firmware in an association request. | |
3679 | * | |
3680 | * | |
3681 | * PARAMETERS: | |
3682 | * | |
3683 | * dev - the network device for which this event is to be issued | |
3684 | * | |
3685 | * RETURNS: | |
3686 | * | |
3687 | * N/A | |
3688 | * | |
3689 | ******************************************************************************/ | |
3690 | void wl_wext_event_assoc_ie( struct net_device *dev ) | |
3691 | { | |
68c0bdff HG |
3692 | union iwreq_data wrqu; |
3693 | struct wl_private *lp = wl_priv(dev); | |
3694 | int status; | |
3695 | PROBE_RESP data; | |
3696 | hcf_16 length; | |
3697 | hcf_8 *wpa_ie; | |
3698 | /*------------------------------------------------------------------------*/ | |
3699 | ||
3700 | ||
3701 | memset( &wrqu, 0, sizeof( wrqu )); | |
68c0bdff HG |
3702 | |
3703 | /* Retrieve the Association Request IE */ | |
3704 | lp->ltvRecord.len = 45; | |
3705 | lp->ltvRecord.typ = CFG_CUR_ASSOC_REQ_INFO; | |
3706 | ||
3707 | status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); | |
3708 | if( status == HCF_SUCCESS ) | |
3709 | { | |
3710 | length = 0; | |
3711 | memcpy( &data.rawData, &( lp->ltvRecord.u.u8[1] ), 88 ); | |
3712 | wpa_ie = wl_parse_wpa_ie( &data, &length ); | |
3713 | ||
68c0bdff HG |
3714 | if( length != 0 ) |
3715 | { | |
a4f7b2e8 DK |
3716 | wrqu.data.length = wpa_ie[1] + 2; |
3717 | wireless_send_event(dev, IWEVASSOCREQIE, | |
3718 | &wrqu, wpa_ie); | |
3719 | ||
3720 | /* This bit is a hack. We send the respie | |
3721 | * event at the same time */ | |
3722 | wireless_send_event(dev, IWEVASSOCRESPIE, | |
3723 | &wrqu, wpa_ie); | |
68c0bdff HG |
3724 | } |
3725 | } | |
68c0bdff HG |
3726 | |
3727 | return; | |
3728 | } // wl_wext_event_assoc_ie | |
3729 | /*============================================================================*/ | |
3730 | /* Structures to export the Wireless Handlers */ | |
3731 | ||
3732 | static const iw_handler wl_handler[] = | |
3733 | { | |
bc79be9b DK |
3734 | IW_HANDLER(SIOCSIWCOMMIT, (iw_handler) wireless_commit), |
3735 | IW_HANDLER(SIOCGIWNAME, (iw_handler) wireless_get_protocol), | |
3736 | IW_HANDLER(SIOCSIWFREQ, (iw_handler) wireless_set_frequency), | |
3737 | IW_HANDLER(SIOCGIWFREQ, (iw_handler) wireless_get_frequency), | |
3738 | IW_HANDLER(SIOCSIWMODE, (iw_handler) wireless_set_porttype), | |
3739 | IW_HANDLER(SIOCGIWMODE, (iw_handler) wireless_get_porttype), | |
3740 | IW_HANDLER(SIOCSIWSENS, (iw_handler) wireless_set_sensitivity), | |
3741 | IW_HANDLER(SIOCGIWSENS, (iw_handler) wireless_get_sensitivity), | |
3742 | IW_HANDLER(SIOCGIWRANGE, (iw_handler) wireless_get_range), | |
3743 | IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), | |
3744 | IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), | |
68c0bdff | 3745 | #if 1 //;? (HCF_TYPE) & HCF_TYPE_STA |
bc79be9b | 3746 | IW_HANDLER(SIOCGIWAP, (iw_handler) wireless_get_bssid), |
68c0bdff | 3747 | #endif |
bc79be9b DK |
3748 | IW_HANDLER(SIOCGIWAPLIST, (iw_handler) wireless_get_ap_list), |
3749 | IW_HANDLER(SIOCSIWSCAN, (iw_handler) wireless_set_scan), | |
3750 | IW_HANDLER(SIOCGIWSCAN, (iw_handler) wireless_get_scan), | |
3751 | IW_HANDLER(SIOCSIWESSID, (iw_handler) wireless_set_essid), | |
3752 | IW_HANDLER(SIOCGIWESSID, (iw_handler) wireless_get_essid), | |
3753 | IW_HANDLER(SIOCSIWNICKN, (iw_handler) wireless_set_nickname), | |
3754 | IW_HANDLER(SIOCGIWNICKN, (iw_handler) wireless_get_nickname), | |
3755 | IW_HANDLER(SIOCSIWRATE, (iw_handler) wireless_set_rate), | |
3756 | IW_HANDLER(SIOCGIWRATE, (iw_handler) wireless_get_rate), | |
3757 | IW_HANDLER(SIOCSIWRTS, (iw_handler) wireless_set_rts_threshold), | |
3758 | IW_HANDLER(SIOCGIWRTS, (iw_handler) wireless_get_rts_threshold), | |
3759 | IW_HANDLER(SIOCGIWTXPOW, (iw_handler) wireless_get_tx_power), | |
3760 | IW_HANDLER(SIOCSIWENCODE, (iw_handler) wireless_set_encode), | |
3761 | IW_HANDLER(SIOCGIWENCODE, (iw_handler) wireless_get_encode), | |
3762 | IW_HANDLER(SIOCSIWPOWER, (iw_handler) wireless_set_power), | |
3763 | IW_HANDLER(SIOCGIWPOWER, (iw_handler) wireless_get_power), | |
729336b3 | 3764 | IW_HANDLER(SIOCSIWGENIE, (iw_handler) wireless_set_genie), |
bc79be9b DK |
3765 | IW_HANDLER(SIOCSIWAUTH, (iw_handler) wireless_set_auth), |
3766 | IW_HANDLER(SIOCSIWENCODEEXT, (iw_handler) wireless_set_encodeext), | |
68c0bdff HG |
3767 | }; |
3768 | ||
3769 | static const iw_handler wl_private_handler[] = | |
3770 | { /* SIOCIWFIRSTPRIV + */ | |
3771 | wvlan_set_netname, /* 0: SIOCSIWNETNAME */ | |
3772 | wvlan_get_netname, /* 1: SIOCGIWNETNAME */ | |
3773 | wvlan_set_station_nickname, /* 2: SIOCSIWSTANAME */ | |
3774 | wvlan_get_station_nickname, /* 3: SIOCGIWSTANAME */ | |
3775 | #if 1 //;? (HCF_TYPE) & HCF_TYPE_STA | |
3776 | wvlan_set_porttype, /* 4: SIOCSIWPORTTYPE */ | |
3777 | wvlan_get_porttype, /* 5: SIOCGIWPORTTYPE */ | |
3778 | #endif | |
3779 | }; | |
3780 | ||
3781 | struct iw_priv_args wl_priv_args[] = { | |
3782 | {SIOCSIWNETNAME, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, 0, "snetwork_name" }, | |
3783 | {SIOCGIWNETNAME, 0, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, "gnetwork_name" }, | |
3784 | {SIOCSIWSTANAME, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, 0, "sstation_name" }, | |
3785 | {SIOCGIWSTANAME, 0, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, "gstation_name" }, | |
3786 | #if 1 //;? #if (HCF_TYPE) & HCF_TYPE_STA | |
3787 | {SIOCSIWPORTTYPE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "sport_type" }, | |
3788 | {SIOCGIWPORTTYPE, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gport_type" }, | |
3789 | #endif | |
3790 | }; | |
3791 | ||
3792 | const struct iw_handler_def wl_iw_handler_def = | |
3793 | { | |
3794 | .num_private = sizeof(wl_private_handler) / sizeof(iw_handler), | |
3795 | .private = (iw_handler *) wl_private_handler, | |
3796 | .private_args = (struct iw_priv_args *) wl_priv_args, | |
3797 | .num_private_args = sizeof(wl_priv_args) / sizeof(struct iw_priv_args), | |
3798 | .num_standard = sizeof(wl_handler) / sizeof(iw_handler), | |
3799 | .standard = (iw_handler *) wl_handler, | |
3800 | .get_wireless_stats = wl_get_wireless_stats, | |
3801 | }; |