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