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