summaryrefslogtreecommitdiff
path: root/drivers/staging/wlags49_h2/wl_wext.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/wlags49_h2/wl_wext.c')
-rw-r--r--drivers/staging/wlags49_h2/wl_wext.c3987
1 files changed, 3987 insertions, 0 deletions
diff --git a/drivers/staging/wlags49_h2/wl_wext.c b/drivers/staging/wlags49_h2/wl_wext.c
new file mode 100644
index 00000000..c731ff2a
--- /dev/null
+++ b/drivers/staging/wlags49_h2/wl_wext.c
@@ -0,0 +1,3987 @@
+/*******************************************************************************
+ * Agere Systems Inc.
+ * Wireless device driver for Linux (wlags49).
+ *
+ * Copyright (c) 1998-2003 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ * Initially developed by TriplePoint, Inc.
+ * http://www.triplepoint.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2003 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ * include files
+ ******************************************************************************/
+#include <wl_version.h>
+
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <asm/uaccess.h>
+
+#include <debug.h>
+#include <hcf.h>
+#include <hcfdef.h>
+
+#include <wl_if.h>
+#include <wl_internal.h>
+#include <wl_util.h>
+#include <wl_main.h>
+#include <wl_wext.h>
+#include <wl_priv.h>
+
+/*******************************************************************************
+ * global definitions
+ ******************************************************************************/
+#if DBG
+extern dbg_info_t *DbgInfo;
+#endif // DBG
+
+
+/* Set up the LTV to program the appropriate key */
+static int hermes_set_tkip_keys(ltv_t *ltv, u16 key_idx, u8 *addr,
+ int set_tx, u8 *seq, u8 *key, size_t key_len)
+{
+ int ret = -EINVAL;
+ int buf_idx = 0;
+ hcf_8 tsc[IW_ENCODE_SEQ_MAX_SIZE] =
+ { 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 };
+
+ DBG_ENTER(DbgInfo);
+
+ /*
+ * Check the key index here; if 0, load as Pairwise Key, otherwise,
+ * load as a group key. Note that for the Hermes, the RIDs for
+ * group/pairwise keys are different from each other and different
+ * than the default WEP keys as well.
+ */
+ switch (key_idx) {
+ case 0:
+ ltv->len = 28;
+ ltv->typ = CFG_ADD_TKIP_MAPPED_KEY;
+
+ /* Load the BSSID */
+ memcpy(&ltv->u.u8[buf_idx], addr, ETH_ALEN);
+ buf_idx += ETH_ALEN;
+
+ /* Load the TKIP key */
+ memcpy(&ltv->u.u8[buf_idx], &key[0], 16);
+ buf_idx += 16;
+
+ /* Load the TSC */
+ memcpy(&ltv->u.u8[buf_idx], tsc, IW_ENCODE_SEQ_MAX_SIZE);
+ buf_idx += IW_ENCODE_SEQ_MAX_SIZE;
+
+ /* Load the RSC */
+ memcpy(&ltv->u.u8[buf_idx], seq, IW_ENCODE_SEQ_MAX_SIZE);
+ buf_idx += IW_ENCODE_SEQ_MAX_SIZE;
+
+ /* Load the TxMIC key */
+ memcpy(&ltv->u.u8[buf_idx], &key[16], 8);
+ buf_idx += 8;
+
+ /* Load the RxMIC key */
+ memcpy(&ltv->u.u8[buf_idx], &key[24], 8);
+
+ ret = 0;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ ltv->len = 26;
+ ltv->typ = CFG_ADD_TKIP_DEFAULT_KEY;
+
+ /* Load the key Index */
+
+ /* If this is a Tx Key, set bit 8000 */
+ if (set_tx)
+ key_idx |= 0x8000;
+ ltv->u.u16[buf_idx] = cpu_to_le16(key_idx);
+ buf_idx += 2;
+
+ /* Load the RSC */
+ memcpy(&ltv->u.u8[buf_idx], seq, IW_ENCODE_SEQ_MAX_SIZE);
+ buf_idx += IW_ENCODE_SEQ_MAX_SIZE;
+
+ /* Load the TKIP, TxMIC, and RxMIC keys in one shot, because in
+ CFG_ADD_TKIP_DEFAULT_KEY they are back-to-back */
+ memcpy(&ltv->u.u8[buf_idx], key, key_len);
+ buf_idx += key_len;
+
+ /* Load the TSC */
+ memcpy(&ltv->u.u8[buf_idx], tsc, IW_ENCODE_SEQ_MAX_SIZE);
+
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+
+ DBG_LEAVE(DbgInfo);
+ return ret;
+}
+
+/* Set up the LTV to clear the appropriate key */
+static int hermes_clear_tkip_keys(ltv_t *ltv, u16 key_idx, u8 *addr)
+{
+ int ret;
+
+ switch (key_idx) {
+ case 0:
+ if (!is_broadcast_ether_addr(addr)) {
+ ltv->len = 7;
+ ltv->typ = CFG_REMOVE_TKIP_MAPPED_KEY;
+ memcpy(&ltv->u.u8[0], addr, ETH_ALEN);
+ ret = 0;
+ }
+ break;
+ case 1:
+ case 2:
+ case 3:
+ /* Clear the Group TKIP keys by index */
+ ltv->len = 2;
+ ltv->typ = CFG_REMOVE_TKIP_DEFAULT_KEY;
+ ltv->u.u16[0] = cpu_to_le16(key_idx);
+
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/* Set the WEP keys in the wl_private structure */
+static int hermes_set_wep_keys(struct wl_private *lp, u16 key_idx,
+ u8 *key, size_t key_len,
+ bool enable, bool set_tx)
+{
+ hcf_8 encryption_state = lp->EnableEncryption;
+ int tk = lp->TransmitKeyID - 1; /* current key */
+ int ret = 0;
+
+ /* Is encryption supported? */
+ if (!wl_has_wep(&(lp->hcfCtx))) {
+ DBG_WARNING(DbgInfo, "WEP not supported on this device\n");
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ DBG_NOTICE(DbgInfo, "pointer: %p, length: %d\n",
+ key, key_len);
+
+ /* Check the size of the key */
+ switch (key_len) {
+ case MIN_KEY_SIZE:
+ case MAX_KEY_SIZE:
+
+ /* Check the index */
+ if ((key_idx < 0) || (key_idx >= MAX_KEYS))
+ key_idx = tk;
+
+ /* Cleanup */
+ memset(lp->DefaultKeys.key[key_idx].key, 0, MAX_KEY_SIZE);
+
+ /* Copy the key in the driver */
+ memcpy(lp->DefaultKeys.key[key_idx].key, key, key_len);
+
+ /* Set the length */
+ lp->DefaultKeys.key[key_idx].len = key_len;
+
+ DBG_NOTICE(DbgInfo, "encoding.length: %d\n", key_len);
+ DBG_NOTICE(DbgInfo, "set key: %s(%d) [%d]\n",
+ lp->DefaultKeys.key[key_idx].key,
+ lp->DefaultKeys.key[key_idx].len, key_idx);
+
+ /* Enable WEP (if possible) */
+ if ((key_idx == tk) && (lp->DefaultKeys.key[tk].len > 0))
+ lp->EnableEncryption = 1;
+
+ break;
+
+ case 0:
+ /* Do we want to just set the current transmit key? */
+ if (set_tx && (key_idx >= 0) && (key_idx < MAX_KEYS)) {
+ DBG_NOTICE(DbgInfo, "index: %d; len: %d\n", key_idx,
+ lp->DefaultKeys.key[key_idx].len);
+
+ if (lp->DefaultKeys.key[key_idx].len > 0) {
+ lp->TransmitKeyID = key_idx + 1;
+ lp->EnableEncryption = 1;
+ } else {
+ DBG_WARNING(DbgInfo, "Problem setting the current TxKey\n");
+ ret = -EINVAL;
+ }
+ }
+ break;
+
+ default:
+ DBG_WARNING(DbgInfo, "Invalid Key length\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Read the flags */
+ if (enable) {
+ lp->EnableEncryption = 1;
+ lp->wext_enc = IW_ENCODE_ALG_WEP;
+ } else {
+ lp->EnableEncryption = 0; /* disable encryption */
+ lp->wext_enc = IW_ENCODE_ALG_NONE;
+ }
+
+ DBG_TRACE(DbgInfo, "encryption_state : %d\n", encryption_state);
+ DBG_TRACE(DbgInfo, "lp->EnableEncryption : %d\n", lp->EnableEncryption);
+ DBG_TRACE(DbgInfo, "erq->length : %d\n", key_len);
+
+ /* Write the changes to the card */
+ if (ret == 0) {
+ DBG_NOTICE(DbgInfo, "encrypt: %d, ID: %d\n", lp->EnableEncryption,
+ lp->TransmitKeyID);
+
+ if (lp->EnableEncryption == encryption_state) {
+ if (key_len != 0) {
+ /* Dynamic WEP key update */
+ wl_set_wep_keys(lp);
+ }
+ } else {
+ /* To switch encryption on/off, soft reset is
+ * required */
+ wl_apply(lp);
+ }
+ }
+
+out:
+ return ret;
+}
+
+/*******************************************************************************
+ * wireless_commit()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Commit
+ * protocol used.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+static int wireless_commit(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *rqu, char *extra)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+ /*------------------------------------------------------------------------*/
+
+ DBG_FUNC( "wireless_commit" );
+ DBG_ENTER(DbgInfo);
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ wl_apply(lp);
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_commit
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_get_protocol()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Returns a vendor-defined string that should identify the wireless
+ * protocol used.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+static int wireless_get_protocol(struct net_device *dev, struct iw_request_info *info, char *name, char *extra)
+{
+ DBG_FUNC( "wireless_get_protocol" );
+ DBG_ENTER( DbgInfo );
+
+ /* Originally, the driver was placing the string "Wireless" here. However,
+ the wireless extensions (/linux/wireless.h) indicate this string should
+ describe the wireless protocol. */
+
+ strcpy(name, "IEEE 802.11b");
+
+ DBG_LEAVE(DbgInfo);
+ return 0;
+} // wireless_get_protocol
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_set_frequency()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Sets the frequency (channel) on which the card should Tx/Rx.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_set_frequency(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int channel = 0;
+ int ret = 0;
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wireless_set_frequency" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if( !capable( CAP_NET_ADMIN )) {
+ ret = -EPERM;
+ DBG_LEAVE( DbgInfo );
+ return ret;
+ }
+
+
+ /* If frequency specified, look up channel */
+ if( freq->e == 1 ) {
+ int f = freq->m / 100000;
+ channel = wl_get_chan_from_freq( f );
+ }
+
+
+ /* Channel specified */
+ if( freq->e == 0 ) {
+ channel = freq->m;
+ }
+
+
+ /* If the channel is an 802.11a channel, set Bit 8 */
+ if( channel > 14 ) {
+ channel = channel | 0x100;
+ }
+
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ lp->Channel = channel;
+
+
+ /* Commit the adapter parameters */
+ wl_apply( lp );
+
+ /* Send an event that channel/freq has been set */
+ wl_wext_event_freq( lp->dev );
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_set_frequency
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_get_frequency()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Gets the frequency (channel) on which the card is Tx/Rx.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+static int wireless_get_frequency(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra)
+
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = -1;
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wireless_get_frequency" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ lp->ltvRecord.len = 2;
+ lp->ltvRecord.typ = CFG_CUR_CHANNEL;
+
+ ret = hcf_get_info( &(lp->hcfCtx), (LTVP)&( lp->ltvRecord ));
+ if( ret == HCF_SUCCESS ) {
+ hcf_16 channel = CNV_LITTLE_TO_INT( lp->ltvRecord.u.u16[0] );
+
+ freq->m = wl_get_freq_from_chan( channel ) * 100000;
+ freq->e = 1;
+ }
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+ ret = (ret == HCF_SUCCESS ? 0 : -EFAULT);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_get_frequency
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_get_range()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * This function is used to provide misc info and statistics about the
+ * wireless device.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_get_range(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ struct iw_range *range = (struct iw_range *) extra;
+ int ret = 0;
+ int status = -1;
+ int count;
+ __u16 *pTxRate;
+ int retries = 0;
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wireless_get_range" );
+ DBG_ENTER( DbgInfo );
+
+ /* Set range information */
+ data->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ /* Set range information */
+ memset( range, 0, sizeof( struct iw_range ));
+
+retry:
+ /* Get the current transmit rate from the adapter */
+ lp->ltvRecord.len = 1 + (sizeof(*pTxRate) / sizeof(hcf_16));
+ lp->ltvRecord.typ = CFG_CUR_TX_RATE;
+
+ status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
+ if( status != HCF_SUCCESS ) {
+ /* Recovery action: reset and retry up to 10 times */
+ DBG_TRACE( DbgInfo, "Get CFG_CUR_TX_RATE failed: 0x%x\n", status );
+
+ if (retries < 10) {
+ retries++;
+
+ /* Holding the lock too long, makes a gap to allow other processes */
+ wl_unlock(lp, &flags);
+ wl_lock( lp, &flags );
+
+ status = wl_reset( dev );
+ if ( status != HCF_SUCCESS ) {
+ DBG_TRACE( DbgInfo, "reset failed: 0x%x\n", status );
+
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+
+ /* Holding the lock too long, makes a gap to allow other processes */
+ wl_unlock(lp, &flags);
+ wl_lock( lp, &flags );
+
+ goto retry;
+
+ } else {
+ DBG_TRACE( DbgInfo, "Get CFG_CUR_TX_RATE failed: %d retries\n", retries );
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+ }
+
+ /* Holding the lock too long, makes a gap to allow other processes */
+ wl_unlock(lp, &flags);
+ wl_lock( lp, &flags );
+
+ pTxRate = (__u16 *)&( lp->ltvRecord.u.u32 );
+
+ range->throughput = CNV_LITTLE_TO_INT( *pTxRate ) * MEGABIT;
+
+ if (retries > 0) {
+ DBG_TRACE( DbgInfo, "Get CFG_CUR_TX_RATE succes: %d retries\n", retries );
+ }
+
+ // NWID - NOT SUPPORTED
+
+
+ /* Channel/Frequency Info */
+ range->num_channels = RADIO_CHANNELS;
+
+
+ /* Signal Level Thresholds */
+ range->sensitivity = RADIO_SENSITIVITY_LEVELS;
+
+
+ /* Link quality */
+ range->max_qual.qual = (u_char)HCF_MAX_COMM_QUALITY;
+
+ /* If the value returned in /proc/net/wireless is greater than the maximum range,
+ iwconfig assumes that the value is in dBm. Because an unsigned char is used,
+ it requires a bit of contorsion... */
+
+ range->max_qual.level = (u_char)( dbm( HCF_MIN_SIGNAL_LEVEL ) - 1 );
+ range->max_qual.noise = (u_char)( dbm( HCF_MIN_NOISE_LEVEL ) - 1 );
+
+
+ /* Set available rates */
+ range->num_bitrates = 0;
+
+ lp->ltvRecord.len = 6;
+ lp->ltvRecord.typ = CFG_SUPPORTED_DATA_RATES;
+
+ status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
+ if( status == HCF_SUCCESS ) {
+ for( count = 0; count < MAX_RATES; count++ )
+ if( lp->ltvRecord.u.u8[count+2] != 0 ) {
+ range->bitrate[count] = lp->ltvRecord.u.u8[count+2] * MEGABIT / 2;
+ range->num_bitrates++;
+ }
+ } else {
+ DBG_TRACE( DbgInfo, "CFG_SUPPORTED_DATA_RATES: 0x%x\n", status );
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+
+ /* RTS Threshold info */
+ range->min_rts = MIN_RTS_BYTES;
+ range->max_rts = MAX_RTS_BYTES;
+
+ // Frag Threshold info - NOT SUPPORTED
+
+ // Power Management info - NOT SUPPORTED
+
+ /* Encryption */
+
+ /* Holding the lock too long, makes a gap to allow other processes */
+ wl_unlock(lp, &flags);
+ wl_lock( lp, &flags );
+
+ /* Is WEP supported? */
+
+ if( wl_has_wep( &( lp->hcfCtx ))) {
+ /* WEP: RC4 40 bits */
+ range->encoding_size[0] = MIN_KEY_SIZE;
+
+ /* RC4 ~128 bits */
+ range->encoding_size[1] = MAX_KEY_SIZE;
+ range->num_encoding_sizes = 2;
+ range->max_encoding_tokens = MAX_KEYS;
+ }
+
+ /* Tx Power Info */
+ range->txpower_capa = IW_TXPOW_MWATT;
+ range->num_txpower = 1;
+ range->txpower[0] = RADIO_TX_POWER_MWATT;
+
+ /* Wireless Extension Info */
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = WIRELESS_SUPPORT;
+
+ // Retry Limits and Lifetime - NOT SUPPORTED
+
+ /* Holding the lock too long, makes a gap to allow other processes */
+ wl_unlock(lp, &flags);
+ wl_lock( lp, &flags );
+
+ DBG_TRACE( DbgInfo, "calling wl_wireless_stats\n" );
+ wl_wireless_stats( lp->dev );
+ range->avg_qual = lp->wstats.qual;
+ DBG_TRACE( DbgInfo, "wl_wireless_stats done\n" );
+
+ /* Event capability (kernel + driver) */
+ IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
+ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
+ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
+ IW_EVENT_CAPA_SET(range->event_capa, IWEVREGISTERED);
+ IW_EVENT_CAPA_SET(range->event_capa, IWEVEXPIRED);
+ IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE);
+ IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCREQIE);
+ IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCRESPIE);
+
+ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP;
+ range->scan_capa = IW_SCAN_CAPA_NONE;
+
+out_unlock:
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+ DBG_LEAVE(DbgInfo);
+ return ret;
+} // wireless_get_range
+/*============================================================================*/
+
+
+/*******************************************************************************
+ * wireless_get_bssid()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Gets the BSSID the wireless device is currently associated with.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_get_bssid(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+#if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
+ int status = -1;
+#endif /* (HCF_TYPE) & HCF_TYPE_STA */
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wireless_get_bssid" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ ap_addr->sa_family = ARPHRD_ETHER;
+
+ /* Assume AP mode here, which means the BSSID is our own MAC address. In
+ STA mode, this address will be overwritten with the actual BSSID using
+ the code below. */
+ memcpy(&ap_addr->sa_data, lp->dev->dev_addr, ETH_ALEN);
+
+
+#if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
+ //;?should we return an error status in AP mode
+
+ if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_STA ) {
+ /* Get Current BSSID */
+ lp->ltvRecord.typ = CFG_CUR_BSSID;
+ lp->ltvRecord.len = 4;
+ status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
+
+ if( status == HCF_SUCCESS ) {
+ /* Copy info into sockaddr struct */
+ memcpy(&ap_addr->sa_data, lp->ltvRecord.u.u8, ETH_ALEN);
+ } else {
+ ret = -EFAULT;
+ }
+ }
+
+#endif // (HCF_TYPE) & HCF_TYPE_STA
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE(DbgInfo);
+ return ret;
+} // wireless_get_bssid
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_get_ap_list()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Gets the results of a network scan.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ * NOTE: SIOCGIWAPLIST has been deprecated by SIOCSIWSCAN. This function
+ * implements SIOCGIWAPLIST only to provide backwards compatibility. For
+ * all systems using WIRELESS_EXT v14 and higher, use SIOCSIWSCAN!
+ *
+ ******************************************************************************/
+static int wireless_get_ap_list (struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret;
+ int num_aps = -1;
+ int sec_count = 0;
+ hcf_32 count;
+ struct sockaddr *hwa = NULL;
+ struct iw_quality *qual = NULL;
+#ifdef WARP
+ ScanResult *p = &lp->scan_results;
+#else
+ ProbeResult *p = &lp->probe_results;
+#endif // WARP
+ /*------------------------------------------------------------------------*/
+
+ DBG_FUNC( "wireless_get_ap_list" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ /* Set the completion state to FALSE */
+ lp->scan_results.scan_complete = FALSE;
+ lp->probe_results.scan_complete = FALSE;
+ /* Channels to scan */
+ lp->ltvRecord.len = 2;
+ lp->ltvRecord.typ = CFG_SCAN_CHANNELS_2GHZ;
+ lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0x7FFF );
+ ret = hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
+ DBG_TRACE( DbgInfo, "CFG_SCAN_CHANNELS_2GHZ result: 0x%x\n", ret );
+
+ /* Set the SCAN_SSID to "ANY". Using this RID for scan prevents the need to
+ disassociate from the network we are currently on */
+ lp->ltvRecord.len = 2;
+ lp->ltvRecord.typ = CFG_SCAN_SSID;
+ lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0 );
+ ret = hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
+ DBG_TRACE( DbgInfo, "CFG_SCAN_SSID to 'any' ret: 0x%x\n", ret );
+
+ /* Initiate the scan */
+#ifdef WARP
+ ret = hcf_action( &( lp->hcfCtx ), MDD_ACT_SCAN );
+#else
+ ret = hcf_action( &( lp->hcfCtx ), HCF_ACT_ACS_SCAN );
+#endif // WARP
+
+ wl_act_int_on( lp );
+
+ //;? unlock? what about the access to lp below? is it broken?
+ wl_unlock(lp, &flags);
+
+ if( ret == HCF_SUCCESS ) {
+ DBG_TRACE( DbgInfo, "SUCCESSFULLY INITIATED SCAN...\n" );
+ while( (*p).scan_complete == FALSE && ret == HCF_SUCCESS ) {
+ DBG_TRACE( DbgInfo, "Waiting for scan results...\n" );
+ /* Abort the scan if we've waited for more than MAX_SCAN_TIME_SEC */
+ if( sec_count++ > MAX_SCAN_TIME_SEC ) {
+ ret = -EIO;
+ } else {
+ /* Wait for 1 sec in 10ms intervals, scheduling the kernel to do
+ other things in the meantime, This prevents system lockups by
+ giving some time back to the kernel */
+ for( count = 0; count < 100; count ++ ) {
+ mdelay( 10 );
+ schedule( );
+ }
+ }
+ }
+
+ rmb();
+
+ if ( ret != HCF_SUCCESS ) {
+ DBG_ERROR( DbgInfo, "timeout waiting for scan results\n" );
+ } else {
+ num_aps = (*p)/*lp->probe_results*/.num_aps;
+ if (num_aps > IW_MAX_AP) {
+ num_aps = IW_MAX_AP;
+ }
+ data->length = num_aps;
+ hwa = (struct sockaddr *)extra;
+ qual = (struct iw_quality *) extra +
+ ( sizeof( struct sockaddr ) * num_aps );
+
+ /* This flag is used to tell the user if we provide quality
+ information. Since we provide signal/noise levels but no
+ quality info on a scan, this is set to 0. Setting to 1 and
+ providing a quality of 0 produces weird results. If we ever
+ provide quality (or can calculate it), this can be changed */
+ data->flags = 0;
+
+ for( count = 0; count < num_aps; count++ ) {
+#ifdef WARP
+ memcpy( hwa[count].sa_data,
+ (*p)/*lp->scan_results*/.APTable[count].bssid, ETH_ALEN );
+#else //;?why use BSSID and bssid as names in seemingly very comparable situations
+ DBG_PRINT("BSSID: %pM\n",
+ (*p).ProbeTable[count].BSSID);
+ memcpy( hwa[count].sa_data,
+ (*p)/*lp->probe_results*/.ProbeTable[count].BSSID, ETH_ALEN );
+#endif // WARP
+ }
+ /* Once the data is copied to the wireless struct, invalidate the
+ scan result to initiate a rescan on the next request */
+ (*p)/*lp->probe_results*/.scan_complete = FALSE;
+ /* Send the wireless event that the scan has completed, just in case
+ it's needed */
+ wl_wext_event_scan_complete( lp->dev );
+ }
+ }
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_get_ap_list
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_set_sensitivity()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Sets the sensitivity (distance between APs) of the wireless card.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_set_sensitivity(struct net_device *dev, struct iw_request_info *info, struct iw_param *sens, char *extra)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+ int dens = sens->value;
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wireless_set_sensitivity" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if(( dens < 1 ) || ( dens > 3 )) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ lp->DistanceBetweenAPs = dens;
+ wl_apply( lp );
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_set_sensitivity
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_get_sensitivity()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Gets the sensitivity (distance between APs) of the wireless card.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_get_sensitivity(struct net_device *dev, struct iw_request_info *info, struct iw_param *sens, char *extra)
+{
+ struct wl_private *lp = wl_priv(dev);
+ int ret = 0;
+ /*------------------------------------------------------------------------*/
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wireless_get_sensitivity" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* not worth locking ... */
+ sens->value = lp->DistanceBetweenAPs;
+ sens->fixed = 0; /* auto */
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_get_sensitivity
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_set_essid()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Sets the ESSID (network name) that the wireless device should associate
+ * with.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_set_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+
+ DBG_FUNC( "wireless_set_essid" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (data->flags != 0 && data->length > HCF_MAX_NAME_LEN + 1) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ memset( lp->NetworkName, 0, sizeof( lp->NetworkName ));
+
+ /* data->flags is zero to ask for "any" */
+ if( data->flags == 0 ) {
+ /* Need this because in STAP build PARM_DEFAULT_SSID is "LinuxAP"
+ * ;?but there ain't no STAP anymore*/
+ if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_STA ) {
+ strcpy( lp->NetworkName, "ANY" );
+ } else {
+ //strcpy( lp->NetworkName, "ANY" );
+ strcpy( lp->NetworkName, PARM_DEFAULT_SSID );
+ }
+ } else {
+ memcpy( lp->NetworkName, ssid, data->length );
+ }
+
+ DBG_NOTICE( DbgInfo, "set NetworkName: %s\n", ssid );
+
+ /* Commit the adapter parameters */
+ wl_apply( lp );
+
+ /* Send an event that ESSID has been set */
+ wl_wext_event_essid( lp->dev );
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_set_essid
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_get_essid()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Gets the ESSID (network name) that the wireless device is associated
+ * with.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_get_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *essid)
+
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+ int status = -1;
+ wvName_t *pName;
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wireless_get_essid" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ /* Get the desired network name */
+ lp->ltvRecord.len = 1 + ( sizeof( *pName ) / sizeof( hcf_16 ));
+
+
+#if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
+ //;?should we return an error status in AP mode
+
+ lp->ltvRecord.typ = CFG_DESIRED_SSID;
+
+#endif
+
+
+#if 1 //;? (HCF_TYPE) & HCF_TYPE_AP
+ //;?should we restore this to allow smaller memory footprint
+
+ if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) {
+ lp->ltvRecord.typ = CFG_CNF_OWN_SSID;
+ }
+
+#endif // HCF_AP
+
+
+ status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
+ if( status == HCF_SUCCESS ) {
+ pName = (wvName_t *)&( lp->ltvRecord.u.u32 );
+
+ /* Endian translate the string length */
+ pName->length = CNV_LITTLE_TO_INT( pName->length );
+
+ /* Copy the information into the user buffer */
+ data->length = pName->length;
+
+ if( pName->length < HCF_MAX_NAME_LEN ) {
+ pName->name[pName->length] = '\0';
+ }
+
+ data->flags = 1;
+
+
+#if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
+ //;?should we return an error status in AP mode
+
+ /* if desired is null ("any"), return current or "any" */
+ if( pName->name[0] == '\0' ) {
+ /* Get the current network name */
+ lp->ltvRecord.len = 1 + ( sizeof(*pName ) / sizeof( hcf_16 ));
+ lp->ltvRecord.typ = CFG_CUR_SSID;
+
+ status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
+
+ if( status == HCF_SUCCESS ) {
+ pName = (wvName_t *)&( lp->ltvRecord.u.u32 );
+
+ /* Endian translate the string length */
+ pName->length = CNV_LITTLE_TO_INT( pName->length );
+
+ /* Copy the information into the user buffer */
+ data->length = pName->length;
+ data->flags = 1;
+ } else {
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+ }
+
+#endif // HCF_STA
+
+ if (pName->length > IW_ESSID_MAX_SIZE) {
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+
+ memcpy(essid, pName->name, pName->length);
+ } else {
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+
+out_unlock:
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_get_essid
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_set_encode()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Sets the encryption keys and status (enable or disable).
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_set_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *keybuf)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int key_idx = (erq->flags & IW_ENCODE_INDEX) - 1;
+ int ret = 0;
+ bool enable = true;
+
+ DBG_ENTER(DbgInfo);
+
+ if (lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (erq->flags & IW_ENCODE_DISABLED)
+ enable = false;
+
+ wl_lock(lp, &flags);
+
+ wl_act_int_off(lp);
+
+ ret = hermes_set_wep_keys(lp, key_idx, keybuf, erq->length,
+ enable, true);
+
+ /* Send an event that Encryption has been set */
+ if (ret == 0)
+ wl_wext_event_encode(dev);
+
+ wl_act_int_on(lp);
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE(DbgInfo);
+ return ret;
+}
+
+/*******************************************************************************
+ * wireless_get_encode()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Gets the encryption keys and status.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_get_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *key)
+
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+ int index;
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wireless_get_encode" );
+ DBG_ENTER( DbgInfo );
+ DBG_NOTICE(DbgInfo, "GIWENCODE: encrypt: %d, ID: %d\n", lp->EnableEncryption, lp->TransmitKeyID);
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* Only super-user can see WEP key */
+ if( !capable( CAP_NET_ADMIN )) {
+ ret = -EPERM;
+ DBG_LEAVE( DbgInfo );
+ return ret;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ /* Is it supported? */
+ if( !wl_has_wep( &( lp->hcfCtx ))) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+
+ /* Basic checking */
+ index = (erq->flags & IW_ENCODE_INDEX ) - 1;
+
+
+ /* Set the flags */
+ erq->flags = 0;
+
+ if( lp->EnableEncryption == 0 ) {
+ erq->flags |= IW_ENCODE_DISABLED;
+ }
+
+ /* Which key do we want */
+ if(( index < 0 ) || ( index >= MAX_KEYS )) {
+ index = lp->TransmitKeyID - 1;
+ }
+
+ erq->flags |= index + 1;
+
+ /* Copy the key to the user buffer */
+ erq->length = lp->DefaultKeys.key[index].len;
+
+ memcpy(key, lp->DefaultKeys.key[index].key, erq->length);
+
+out_unlock:
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_get_encode
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_set_nickname()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Sets the nickname, or station name, of the wireless device.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_set_nickname(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *nickname)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wireless_set_nickname" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+#if 0 //;? Needed, was present in original code but not in 7.18 Linux 2.6 kernel version
+ if( !capable(CAP_NET_ADMIN )) {
+ ret = -EPERM;
+ DBG_LEAVE( DbgInfo );
+ return ret;
+ }
+#endif
+
+ /* Validate the new value */
+ if(data->length > HCF_MAX_NAME_LEN) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ memset( lp->StationName, 0, sizeof( lp->StationName ));
+
+ memcpy( lp->StationName, nickname, data->length );
+
+ /* Commit the adapter parameters */
+ wl_apply( lp );
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_set_nickname
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_get_nickname()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Gets the nickname, or station name, of the wireless device.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_get_nickname(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *nickname)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+ int status = -1;
+ wvName_t *pName;
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wireless_get_nickname" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ /* Get the current station name */
+ lp->ltvRecord.len = 1 + ( sizeof( *pName ) / sizeof( hcf_16 ));
+ lp->ltvRecord.typ = CFG_CNF_OWN_NAME;
+
+ status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
+
+ if( status == HCF_SUCCESS ) {
+ pName = (wvName_t *)&( lp->ltvRecord.u.u32 );
+
+ /* Endian translate the length */
+ pName->length = CNV_LITTLE_TO_INT( pName->length );
+
+ if ( pName->length > IW_ESSID_MAX_SIZE ) {
+ ret = -EFAULT;
+ } else {
+ /* Copy the information into the user buffer */
+ data->length = pName->length;
+ memcpy(nickname, pName->name, pName->length);
+ }
+ } else {
+ ret = -EFAULT;
+ }
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE(DbgInfo);
+ return ret;
+} // wireless_get_nickname
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_set_porttype()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Sets the port type of the wireless device.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_set_porttype(struct net_device *dev, struct iw_request_info *info, __u32 *mode, char *extra)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+ hcf_16 portType;
+ hcf_16 createIBSS;
+ /*------------------------------------------------------------------------*/
+
+ DBG_FUNC( "wireless_set_porttype" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ /* Validate the new value */
+ switch( *mode ) {
+ case IW_MODE_ADHOC:
+
+ /* When user requests ad-hoc, set IBSS mode! */
+ portType = 1;
+ createIBSS = 1;
+
+ lp->DownloadFirmware = WVLAN_DRV_MODE_STA; //1;
+
+ break;
+
+
+ case IW_MODE_AUTO:
+ case IW_MODE_INFRA:
+
+ /* Both automatic and infrastructure set port to BSS/STA mode */
+ portType = 1;
+ createIBSS = 0;
+
+ lp->DownloadFirmware = WVLAN_DRV_MODE_STA; //1;
+
+ break;
+
+
+#if 0 //;? (HCF_TYPE) & HCF_TYPE_AP
+
+ case IW_MODE_MASTER:
+
+ /* Set BSS/AP mode */
+ portType = 1;
+
+ lp->CreateIBSS = 0;
+ lp->DownloadFirmware = WVLAN_DRV_MODE_AP; //2;
+
+ break;
+
+#endif /* (HCF_TYPE) & HCF_TYPE_AP */
+
+
+ default:
+
+ portType = 0;
+ createIBSS = 0;
+ ret = -EINVAL;
+ }
+
+ if( portType != 0 ) {
+ /* Only do something if there is a mode change */
+ if( ( lp->PortType != portType ) || (lp->CreateIBSS != createIBSS)) {
+ lp->PortType = portType;
+ lp->CreateIBSS = createIBSS;
+
+ /* Commit the adapter parameters */
+ wl_go( lp );
+
+ /* Send an event that mode has been set */
+ wl_wext_event_mode( lp->dev );
+ }
+ }
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_set_porttype
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_get_porttype()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Gets the port type of the wireless device.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_get_porttype(struct net_device *dev, struct iw_request_info *info, __u32 *mode, char *extra)
+
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+ int status = -1;
+ hcf_16 *pPortType;
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wireless_get_porttype" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ /* Get the current port type */
+ lp->ltvRecord.len = 1 + ( sizeof( *pPortType ) / sizeof( hcf_16 ));
+ lp->ltvRecord.typ = CFG_CNF_PORT_TYPE;
+
+ status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
+
+ if( status == HCF_SUCCESS ) {
+ pPortType = (hcf_16 *)&( lp->ltvRecord.u.u32 );
+
+ *pPortType = CNV_LITTLE_TO_INT( *pPortType );
+
+ switch( *pPortType ) {
+ case 1:
+
+#if 0
+#if (HCF_TYPE) & HCF_TYPE_AP
+
+ if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) {
+ *mode = IW_MODE_MASTER;
+ } else {
+ *mode = IW_MODE_INFRA;
+ }
+
+#else
+
+ *mode = IW_MODE_INFRA;
+
+#endif /* (HCF_TYPE) & HCF_TYPE_AP */
+#endif
+
+ if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) {
+ *mode = IW_MODE_MASTER;
+ } else {
+ if( lp->CreateIBSS ) {
+ *mode = IW_MODE_ADHOC;
+ } else {
+ *mode = IW_MODE_INFRA;
+ }
+ }
+
+ break;
+
+
+ case 3:
+ *mode = IW_MODE_ADHOC;
+ break;
+
+ default:
+ ret = -EFAULT;
+ break;
+ }
+ } else {
+ ret = -EFAULT;
+ }
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_get_porttype
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_set_power()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Sets the power management settings of the wireless device.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_set_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *wrq, char *extra)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wireless_set_power" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ DBG_PRINT( "THIS CORRUPTS PMEnabled ;?!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" );
+
+#if 0 //;? Needed, was present in original code but not in 7.18 Linux 2.6 kernel version
+ if( !capable( CAP_NET_ADMIN )) {
+ ret = -EPERM;
+
+ DBG_LEAVE( DbgInfo );
+ return ret;
+ }
+#endif
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ /* Set the power management state based on the 'disabled' value */
+ if( wrq->disabled ) {
+ lp->PMEnabled = 0;
+ } else {
+ lp->PMEnabled = 1;
+ }
+
+ /* Commit the adapter parameters */
+ wl_apply( lp );
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_set_power
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_get_power()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Gets the power management settings of the wireless device.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_get_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra)
+
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+ /*------------------------------------------------------------------------*/
+ DBG_FUNC( "wireless_get_power" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ DBG_PRINT( "THIS IS PROBABLY AN OVER-SIMPLIFICATION ;?!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" );
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ rrq->flags = 0;
+ rrq->value = 0;
+
+ if( lp->PMEnabled ) {
+ rrq->disabled = 0;
+ } else {
+ rrq->disabled = 1;
+ }
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_get_power
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_get_tx_power()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Gets the transmit power of the wireless device's radio.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_get_tx_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+ /*------------------------------------------------------------------------*/
+ DBG_FUNC( "wireless_get_tx_power" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+#ifdef USE_POWER_DBM
+ rrq->value = RADIO_TX_POWER_DBM;
+ rrq->flags = IW_TXPOW_DBM;
+#else
+ rrq->value = RADIO_TX_POWER_MWATT;
+ rrq->flags = IW_TXPOW_MWATT;
+#endif
+ rrq->fixed = 1;
+ rrq->disabled = 0;
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_get_tx_power
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_set_rts_threshold()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Sets the RTS threshold for the wireless card.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_set_rts_threshold (struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra)
+{
+ int ret = 0;
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int rthr = rts->value;
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wireless_set_rts_threshold" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if(rts->fixed == 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if( rts->disabled ) {
+ rthr = 2347;
+ }
+
+ if(( rthr < 256 ) || ( rthr > 2347 )) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ lp->RTSThreshold = rthr;
+
+ wl_apply( lp );
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_set_rts_threshold
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_get_rts_threshold()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Gets the RTS threshold for the wireless card.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_get_rts_threshold (struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra)
+{
+ int ret = 0;
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ /*------------------------------------------------------------------------*/
+
+ DBG_FUNC( "wireless_get_rts_threshold" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ rts->value = lp->RTSThreshold;
+
+ rts->disabled = ( rts->value == 2347 );
+
+ rts->fixed = 1;
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_get_rts_threshold
+/*============================================================================*/
+
+
+
+
+
+/*******************************************************************************
+ * wireless_set_rate()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Set the default data rate setting used by the wireless device.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_set_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+#ifdef WARP
+ int status = -1;
+ int index = 0;
+#endif // WARP
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wireless_set_rate" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+#ifdef WARP
+
+ /* Determine if the card is operating in the 2.4 or 5.0 GHz band; check
+ if Bit 9 is set in the current channel RID */
+ lp->ltvRecord.len = 2;
+ lp->ltvRecord.typ = CFG_CUR_CHANNEL;
+
+ status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
+
+ if( status == HCF_SUCCESS ) {
+ index = ( CNV_LITTLE_TO_INT( lp->ltvRecord.u.u16[0] ) & 0x100 ) ? 1 : 0;
+
+ DBG_PRINT( "Index: %d\n", index );
+ } else {
+ DBG_ERROR( DbgInfo, "Could not determine radio frequency\n" );
+ DBG_LEAVE( DbgInfo );
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ if( rrq->value > 0 &&
+ rrq->value <= 1 * MEGABIT ) {
+ lp->TxRateControl[index] = 0x0001;
+ }
+ else if( rrq->value > 1 * MEGABIT &&
+ rrq->value <= 2 * MEGABIT ) {
+ if( rrq->fixed == 1 ) {
+ lp->TxRateControl[index] = 0x0002;
+ } else {
+ lp->TxRateControl[index] = 0x0003;
+ }
+ }
+ else if( rrq->value > 2 * MEGABIT &&
+ rrq->value <= 5 * MEGABIT ) {
+ if( rrq->fixed == 1 ) {
+ lp->TxRateControl[index] = 0x0004;
+ } else {
+ lp->TxRateControl[index] = 0x0007;
+ }
+ }
+ else if( rrq->value > 5 * MEGABIT &&
+ rrq->value <= 6 * MEGABIT ) {
+ if( rrq->fixed == 1 ) {
+ lp->TxRateControl[index] = 0x0010;
+ } else {
+ lp->TxRateControl[index] = 0x0017;
+ }
+ }
+ else if( rrq->value > 6 * MEGABIT &&
+ rrq->value <= 9 * MEGABIT ) {
+ if( rrq->fixed == 1 ) {
+ lp->TxRateControl[index] = 0x0020;
+ } else {
+ lp->TxRateControl[index] = 0x0037;
+ }
+ }
+ else if( rrq->value > 9 * MEGABIT &&
+ rrq->value <= 11 * MEGABIT ) {
+ if( rrq->fixed == 1 ) {
+ lp->TxRateControl[index] = 0x0008;
+ } else {
+ lp->TxRateControl[index] = 0x003F;
+ }
+ }
+ else if( rrq->value > 11 * MEGABIT &&
+ rrq->value <= 12 * MEGABIT ) {
+ if( rrq->fixed == 1 ) {
+ lp->TxRateControl[index] = 0x0040;
+ } else {
+ lp->TxRateControl[index] = 0x007F;
+ }
+ }
+ else if( rrq->value > 12 * MEGABIT &&
+ rrq->value <= 18 * MEGABIT ) {
+ if( rrq->fixed == 1 ) {
+ lp->TxRateControl[index] = 0x0080;
+ } else {
+ lp->TxRateControl[index] = 0x00FF;
+ }
+ }
+ else if( rrq->value > 18 * MEGABIT &&
+ rrq->value <= 24 * MEGABIT ) {
+ if( rrq->fixed == 1 ) {
+ lp->TxRateControl[index] = 0x0100;
+ } else {
+ lp->TxRateControl[index] = 0x01FF;
+ }
+ }
+ else if( rrq->value > 24 * MEGABIT &&
+ rrq->value <= 36 * MEGABIT ) {
+ if( rrq->fixed == 1 ) {
+ lp->TxRateControl[index] = 0x0200;
+ } else {
+ lp->TxRateControl[index] = 0x03FF;
+ }
+ }
+ else if( rrq->value > 36 * MEGABIT &&
+ rrq->value <= 48 * MEGABIT ) {
+ if( rrq->fixed == 1 ) {
+ lp->TxRateControl[index] = 0x0400;
+ } else {
+ lp->TxRateControl[index] = 0x07FF;
+ }
+ }
+ else if( rrq->value > 48 * MEGABIT &&
+ rrq->value <= 54 * MEGABIT ) {
+ if( rrq->fixed == 1 ) {
+ lp->TxRateControl[index] = 0x0800;
+ } else {
+ lp->TxRateControl[index] = 0x0FFF;
+ }
+ }
+ else if( rrq->fixed == 0 ) {
+ /* In this case, the user has not specified a bitrate, only the "auto"
+ moniker. So, set to all supported rates */
+ lp->TxRateControl[index] = PARM_MAX_TX_RATE;
+ } else {
+ rrq->value = 0;
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+
+#else
+
+ if( rrq->value > 0 &&
+ rrq->value <= 1 * MEGABIT ) {
+ lp->TxRateControl[0] = 1;
+ }
+ else if( rrq->value > 1 * MEGABIT &&
+ rrq->value <= 2 * MEGABIT ) {
+ if( rrq->fixed ) {
+ lp->TxRateControl[0] = 2;
+ } else {
+ lp->TxRateControl[0] = 6;
+ }
+ }
+ else if( rrq->value > 2 * MEGABIT &&
+ rrq->value <= 5 * MEGABIT ) {
+ if( rrq->fixed ) {
+ lp->TxRateControl[0] = 4;
+ } else {
+ lp->TxRateControl[0] = 7;
+ }
+ }
+ else if( rrq->value > 5 * MEGABIT &&
+ rrq->value <= 11 * MEGABIT ) {
+ if( rrq->fixed) {
+ lp->TxRateControl[0] = 5;
+ } else {
+ lp->TxRateControl[0] = 3;
+ }
+ }
+ else if( rrq->fixed == 0 ) {
+ /* In this case, the user has not specified a bitrate, only the "auto"
+ moniker. So, set the rate to 11Mb auto */
+ lp->TxRateControl[0] = 3;
+ } else {
+ rrq->value = 0;
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+#endif // WARP
+
+
+ /* Commit the adapter parameters */
+ wl_apply( lp );
+
+out_unlock:
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_set_rate
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_get_rate()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Get the default data rate setting used by the wireless device.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_get_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra)
+
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+ int status = -1;
+ hcf_16 txRate;
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wireless_get_rate" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ /* Get the current transmit rate from the adapter */
+ lp->ltvRecord.len = 1 + ( sizeof(txRate)/sizeof(hcf_16));
+ lp->ltvRecord.typ = CFG_CUR_TX_RATE;
+
+ status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
+
+ if( status == HCF_SUCCESS ) {
+#ifdef WARP
+
+ txRate = CNV_LITTLE_TO_INT( lp->ltvRecord.u.u16[0] );
+
+ if( txRate & 0x0001 ) {
+ txRate = 1;
+ }
+ else if( txRate & 0x0002 ) {
+ txRate = 2;
+ }
+ else if( txRate & 0x0004 ) {
+ txRate = 5;
+ }
+ else if( txRate & 0x0008 ) {
+ txRate = 11;
+ }
+ else if( txRate & 0x00010 ) {
+ txRate = 6;
+ }
+ else if( txRate & 0x00020 ) {
+ txRate = 9;
+ }
+ else if( txRate & 0x00040 ) {
+ txRate = 12;
+ }
+ else if( txRate & 0x00080 ) {
+ txRate = 18;
+ }
+ else if( txRate & 0x00100 ) {
+ txRate = 24;
+ }
+ else if( txRate & 0x00200 ) {
+ txRate = 36;
+ }
+ else if( txRate & 0x00400 ) {
+ txRate = 48;
+ }
+ else if( txRate & 0x00800 ) {
+ txRate = 54;
+ }
+
+#else
+
+ txRate = (hcf_16)CNV_LITTLE_TO_LONG( lp->ltvRecord.u.u32[0] );
+
+#endif // WARP
+
+ rrq->value = txRate * MEGABIT;
+ } else {
+ rrq->value = 0;
+ ret = -EFAULT;
+ }
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_get_rate
+/*============================================================================*/
+
+
+
+
+#if 0 //;? Not used anymore
+/*******************************************************************************
+ * wireless_get_private_interface()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Returns the Linux Wireless Extensions' compatible private interface of
+ * the driver.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+int wireless_get_private_interface( struct iwreq *wrq, struct wl_private *lp )
+{
+ int ret = 0;
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wireless_get_private_interface" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if( wrq->u.data.pointer != NULL ) {
+ struct iw_priv_args priv[] =
+ {
+ { SIOCSIWNETNAME, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, 0, "snetwork_name" },
+ { SIOCGIWNETNAME, 0, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, "gnetwork_name" },
+ { SIOCSIWSTANAME, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, 0, "sstation_name" },
+ { SIOCGIWSTANAME, 0, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, "gstation_name" },
+ { SIOCSIWPORTTYPE, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "sport_type" },
+ { SIOCGIWPORTTYPE, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "gport_type" },
+ };
+
+ /* Verify the user buffer */
+ ret = verify_area( VERIFY_WRITE, wrq->u.data.pointer, sizeof( priv ));
+
+ if( ret != 0 ) {
+ DBG_LEAVE( DbgInfo );
+ return ret;
+ }
+
+ /* Copy the data into the user's buffer */
+ wrq->u.data.length = NELEM( priv );
+ copy_to_user( wrq->u.data.pointer, &priv, sizeof( priv ));
+ }
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_get_private_interface
+/*============================================================================*/
+#endif
+
+
+
+/*******************************************************************************
+ * wireless_set_scan()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Instructs the driver to initiate a network scan.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_set_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+ int status = -1;
+ int retries = 0;
+ /*------------------------------------------------------------------------*/
+
+ //;? Note: shows results as trace, returns always 0 unless BUSY
+
+ DBG_FUNC( "wireless_set_scan" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ /*
+ * This looks like a nice place to test if the HCF is still
+ * communicating with the card. It seems that sometimes BAP_1
+ * gets corrupted. By looking at the comments in HCF the
+ * cause is still a mystery. Okay, the communication to the
+ * card is dead, reset the card to revive.
+ */
+ if((lp->hcfCtx.IFB_CardStat & CARD_STAT_DEFUNCT) != 0)
+ {
+ DBG_TRACE( DbgInfo, "CARD is in DEFUNCT mode, reset it to bring it back to life\n" );
+ wl_reset( dev );
+ }
+
+retry:
+ /* Set the completion state to FALSE */
+ lp->probe_results.scan_complete = FALSE;
+
+
+ /* Channels to scan */
+#ifdef WARP
+ lp->ltvRecord.len = 5;
+ lp->ltvRecord.typ = CFG_SCAN_CHANNEL;
+ lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0x3FFF ); // 2.4 GHz Band
+ lp->ltvRecord.u.u16[1] = CNV_INT_TO_LITTLE( 0xFFFF ); // 5.0 GHz Band
+ lp->ltvRecord.u.u16[2] = CNV_INT_TO_LITTLE( 0xFFFF ); // ..
+ lp->ltvRecord.u.u16[3] = CNV_INT_TO_LITTLE( 0x0007 ); // ..
+#else
+ lp->ltvRecord.len = 2;
+ lp->ltvRecord.typ = CFG_SCAN_CHANNEL;
+ lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0x7FFF );
+#endif // WARP
+
+ status = hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
+
+ DBG_TRACE( DbgInfo, "CFG_SCAN_CHANNEL result : 0x%x\n", status );
+
+ // Holding the lock too long, makes a gap to allow other processes
+ wl_unlock(lp, &flags);
+ wl_lock( lp, &flags );
+
+ if( status != HCF_SUCCESS ) {
+ //Recovery
+ retries++;
+ if(retries <= 10) {
+ DBG_TRACE( DbgInfo, "Reset card to recover, attempt: %d\n", retries );
+ wl_reset( dev );
+
+ // Holding the lock too long, makes a gap to allow other processes
+ wl_unlock(lp, &flags);
+ wl_lock( lp, &flags );
+
+ goto retry;
+ }
+ }
+
+ /* Set the SCAN_SSID to "ANY". Using this RID for scan prevents the need to
+ disassociate from the network we are currently on */
+ lp->ltvRecord.len = 18;
+ lp->ltvRecord.typ = CFG_SCAN_SSID;
+ lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0 );
+ lp->ltvRecord.u.u16[1] = CNV_INT_TO_LITTLE( 0 );
+
+ status = hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
+
+ // Holding the lock too long, makes a gap to allow other processes
+ wl_unlock(lp, &flags);
+ wl_lock( lp, &flags );
+
+ DBG_TRACE( DbgInfo, "CFG_SCAN_SSID to 'any' status: 0x%x\n", status );
+
+ /* Initiate the scan */
+ /* NOTE: Using HCF_ACT_SCAN has been removed, as using HCF_ACT_ACS_SCAN to
+ retrieve probe response must always be used to support WPA */
+ status = hcf_action( &( lp->hcfCtx ), HCF_ACT_ACS_SCAN );
+
+ if( status == HCF_SUCCESS ) {
+ DBG_TRACE( DbgInfo, "SUCCESSFULLY INITIATED SCAN...\n" );
+ } else {
+ DBG_TRACE( DbgInfo, "INITIATE SCAN FAILED...\n" );
+ }
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE(DbgInfo);
+ return ret;
+} // wireless_set_scan
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wireless_get_scan()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Instructs the driver to gather and return the results of a network scan.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+static int wireless_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+ int count;
+ char *buf;
+ char *buf_end;
+ struct iw_event iwe;
+ PROBE_RESP *probe_resp;
+ hcf_8 msg[512];
+ hcf_8 *wpa_ie;
+ hcf_16 wpa_ie_len;
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wireless_get_scan" );
+ DBG_ENTER( DbgInfo );
+
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ /* If the scan is not done, tell the calling process to try again later */
+ if( !lp->probe_results.scan_complete ) {
+ ret = -EAGAIN;
+ goto out_unlock;
+ }
+
+ DBG_TRACE( DbgInfo, "SCAN COMPLETE, Num of APs: %d\n",
+ lp->probe_results.num_aps );
+
+ buf = extra;
+ buf_end = extra + IW_SCAN_MAX_DATA;
+
+ for( count = 0; count < lp->probe_results.num_aps; count++ ) {
+ /* Reference the probe response from the table */
+ probe_resp = (PROBE_RESP *)&lp->probe_results.ProbeTable[count];
+
+
+ /* First entry MUST be the MAC address */
+ memset( &iwe, 0, sizeof( iwe ));
+
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy( iwe.u.ap_addr.sa_data, probe_resp->BSSID, ETH_ALEN);
+ iwe.len = IW_EV_ADDR_LEN;
+
+ buf = iwe_stream_add_event(info, buf, buf_end,
+ &iwe, IW_EV_ADDR_LEN);
+
+ /* Use the mode to indicate if it's a station or AP */
+ /* Won't always be an AP if in IBSS mode */
+ memset( &iwe, 0, sizeof( iwe ));
+
+ iwe.cmd = SIOCGIWMODE;
+
+ if( probe_resp->capability & CAPABILITY_IBSS ) {
+ iwe.u.mode = IW_MODE_INFRA;
+ } else {
+ iwe.u.mode = IW_MODE_MASTER;
+ }
+
+ iwe.len = IW_EV_UINT_LEN;
+
+ buf = iwe_stream_add_event(info, buf, buf_end,
+ &iwe, IW_EV_UINT_LEN);
+
+ /* Any quality information */
+ memset(&iwe, 0, sizeof(iwe));
+
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.level = dbm(probe_resp->signal);
+ iwe.u.qual.noise = dbm(probe_resp->silence);
+ iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
+ iwe.u.qual.updated = lp->probe_results.scan_complete | IW_QUAL_DBM;
+ iwe.len = IW_EV_QUAL_LEN;
+
+ buf = iwe_stream_add_event(info, buf, buf_end,
+ &iwe, IW_EV_QUAL_LEN);
+
+
+ /* ESSID information */
+ if( probe_resp->rawData[1] > 0 ) {
+ memset( &iwe, 0, sizeof( iwe ));
+
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.length = probe_resp->rawData[1];
+ iwe.u.data.flags = 1;
+
+ buf = iwe_stream_add_point(info, buf, buf_end,
+ &iwe, &probe_resp->rawData[2]);
+ }
+
+
+ /* Encryption Information */
+ memset( &iwe, 0, sizeof( iwe ));
+
+ iwe.cmd = SIOCGIWENCODE;
+ iwe.u.data.length = 0;
+
+ /* Check the capabilities field of the Probe Response to see if
+ 'privacy' is supported on the AP in question */
+ if( probe_resp->capability & CAPABILITY_PRIVACY ) {
+ iwe.u.data.flags |= IW_ENCODE_ENABLED;
+ } else {
+ iwe.u.data.flags |= IW_ENCODE_DISABLED;
+ }
+
+ buf = iwe_stream_add_point(info, buf, buf_end, &iwe, NULL);
+
+
+ /* Frequency Info */
+ memset( &iwe, 0, sizeof( iwe ));
+
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.len = IW_EV_FREQ_LEN;
+ iwe.u.freq.m = wl_parse_ds_ie( probe_resp );
+ iwe.u.freq.e = 0;
+
+ buf = iwe_stream_add_event(info, buf, buf_end,
+ &iwe, IW_EV_FREQ_LEN);
+
+
+ /* Custom info (Beacon Interval) */
+ memset( &iwe, 0, sizeof( iwe ));
+ memset( msg, 0, sizeof( msg ));
+
+ iwe.cmd = IWEVCUSTOM;
+ sprintf( msg, "beacon_interval=%d", probe_resp->beaconInterval );
+ iwe.u.data.length = strlen( msg );
+
+ buf = iwe_stream_add_point(info, buf, buf_end, &iwe, msg);
+
+
+ /* WPA-IE */
+ wpa_ie = NULL;
+ wpa_ie_len = 0;
+
+ wpa_ie = wl_parse_wpa_ie( probe_resp, &wpa_ie_len );
+ if( wpa_ie != NULL ) {
+ memset(&iwe, 0, sizeof(iwe));
+
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = wpa_ie_len;
+
+ buf = iwe_stream_add_point(info, buf, buf_end,
+ &iwe, wpa_ie);
+ }
+
+ /* Add other custom info in formatted string format as needed... */
+ }
+
+ data->length = buf - extra;
+
+out_unlock:
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_get_scan
+/*============================================================================*/
+
+#if DBG
+static const char * const auth_names[] = {
+ "IW_AUTH_WPA_VERSION",
+ "IW_AUTH_CIPHER_PAIRWISE",
+ "IW_AUTH_CIPHER_GROUP",
+ "IW_AUTH_KEY_MGMT",
+ "IW_AUTH_TKIP_COUNTERMEASURES",
+ "IW_AUTH_DROP_UNENCRYPTED",
+ "IW_AUTH_80211_AUTH_ALG",
+ "IW_AUTH_WPA_ENABLED",
+ "IW_AUTH_RX_UNENCRYPTED_EAPOL",
+ "IW_AUTH_ROAMING_CONTROL",
+ "IW_AUTH_PRIVACY_INVOKED",
+ "IW_AUTH_CIPHER_GROUP_MGMT",
+ "IW_AUTH_MFP",
+ "Unsupported"
+};
+#endif
+
+static int wireless_set_auth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *data, char *extra)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ ltv_t ltv;
+ int ret;
+ int iwa_idx = data->flags & IW_AUTH_INDEX;
+ int iwa_val = data->value;
+
+ DBG_FUNC( "wireless_set_auth" );
+ DBG_ENTER( DbgInfo );
+
+ if (lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+ if (iwa_idx > IW_AUTH_MFP)
+ iwa_idx = IW_AUTH_MFP + 1;
+ DBG_TRACE(DbgInfo, "%s\n", auth_names[iwa_idx]);
+ switch (iwa_idx) {
+ case IW_AUTH_WPA_VERSION:
+ /* We do support WPA */
+ if ((iwa_val == IW_AUTH_WPA_VERSION_WPA) ||
+ (iwa_val == IW_AUTH_WPA_VERSION_DISABLED))
+ ret = 0;
+ else
+ ret = -EINVAL;
+ break;
+
+ case IW_AUTH_WPA_ENABLED:
+ DBG_TRACE(DbgInfo, "val = %d\n", iwa_val);
+ if (iwa_val)
+ lp->EnableEncryption = 2;
+ else
+ lp->EnableEncryption = 0;
+
+ /* Write straight to the card */
+ ltv.len = 2;
+ ltv.typ = CFG_CNF_ENCRYPTION;
+ ltv.u.u16[0] = cpu_to_le16(lp->EnableEncryption);
+ ret = hcf_put_info(&lp->hcfCtx, (LTVP)&ltv);
+
+ break;
+
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+
+ /* Immediately disable card */
+ lp->driverEnable = !iwa_val;
+ if (lp->driverEnable)
+ hcf_cntl(&(lp->hcfCtx), HCF_CNTL_ENABLE | HCF_PORT_0);
+ else
+ hcf_cntl(&(lp->hcfCtx), HCF_CNTL_DISABLE | HCF_PORT_0);
+ ret = 0;
+ break;
+
+ case IW_AUTH_MFP:
+ /* Management Frame Protection not supported.
+ * Only fail if set to required.
+ */
+ if (iwa_val == IW_AUTH_MFP_REQUIRED)
+ ret = -EINVAL;
+ else
+ ret = 0;
+ break;
+
+ case IW_AUTH_KEY_MGMT:
+
+ /* Record required management suite.
+ * Will take effect on next commit */
+ if (iwa_val != 0)
+ lp->AuthKeyMgmtSuite = 4;
+ else
+ lp->AuthKeyMgmtSuite = 0;
+
+ ret = -EINPROGRESS;
+ break;
+
+ case IW_AUTH_80211_AUTH_ALG:
+
+ /* Just record whether open or shared is required.
+ * Will take effect on next commit */
+ ret = -EINPROGRESS;
+
+ if (iwa_val & IW_AUTH_ALG_SHARED_KEY)
+ lp->authentication = 1;
+ else if (iwa_val & IW_AUTH_ALG_OPEN_SYSTEM)
+ lp->authentication = 0;
+ else
+ ret = -EINVAL;
+ break;
+
+ case IW_AUTH_DROP_UNENCRYPTED:
+ /* Only needed for AP */
+ lp->ExcludeUnencrypted = iwa_val;
+ ret = -EINPROGRESS;
+ break;
+
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ /* Not used. May need to do something with
+ * CIPHER_PAIRWISE and CIPHER_GROUP*/
+ ret = -EINPROGRESS;
+ break;
+
+ default:
+ DBG_TRACE(DbgInfo, "IW_AUTH_?? (%d) unknown\n", iwa_idx);
+ /* return an error */
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE( DbgInfo );
+ return ret;
+} // wireless_set_auth
+/*============================================================================*/
+
+
+static void flush_tx(struct wl_private *lp)
+{
+ ltv_t ltv;
+ int count;
+
+ /*
+ * Make sure that there is no data queued up in the firmware
+ * before setting the TKIP keys. If this check is not
+ * performed, some data may be sent out with incorrect MIC
+ * and cause synchronization errors with the AP
+ */
+ /* Check every 1ms for 100ms */
+ for (count = 0; count < 100; count++) {
+ udelay(1000);
+
+ ltv.len = 2;
+ ltv.typ = 0xFD91; /* This RID not defined in HCF yet!!! */
+ ltv.u.u16[0] = 0;
+
+ hcf_get_info(&(lp->hcfCtx), (LTVP)&ltv);
+
+ if (ltv.u.u16[0] == 0)
+ break;
+ }
+
+ if (count >= 100)
+ DBG_TRACE(DbgInfo, "Timed out waiting for TxQ flush!\n");
+
+}
+
+static int wireless_set_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *keybuf)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret;
+ int key_idx = (erq->flags & IW_ENCODE_INDEX) - 1;
+ ltv_t ltv;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)keybuf;
+ bool enable = true;
+ bool set_tx = false;
+
+ DBG_ENTER(DbgInfo);
+
+ if (lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (erq->flags & IW_ENCODE_DISABLED) {
+ ext->alg = IW_ENCODE_ALG_NONE;
+ enable = false;
+ }
+
+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
+ set_tx = true;
+
+ wl_lock(lp, &flags);
+
+ wl_act_int_off(lp);
+
+ memset(&ltv, 0, sizeof(ltv));
+
+ switch (ext->alg) {
+ case IW_ENCODE_ALG_TKIP:
+ DBG_TRACE(DbgInfo, "IW_ENCODE_ALG_TKIP: key(%d)\n", key_idx);
+
+ if (sizeof(ext->rx_seq) != 8) {
+ DBG_TRACE(DbgInfo, "rx_seq size mismatch\n");
+ DBG_LEAVE(DbgInfo);
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ ret = hermes_set_tkip_keys(&ltv, key_idx, ext->addr.sa_data,
+ set_tx,
+ ext->rx_seq, ext->key, ext->key_len);
+
+ if (ret != 0) {
+ DBG_TRACE(DbgInfo, "hermes_set_tkip_keys returned != 0, key not set\n");
+ goto out_unlock;
+ }
+
+ flush_tx(lp);
+
+ lp->wext_enc = IW_ENCODE_ALG_TKIP;
+
+ /* Write the key */
+ ret = hcf_put_info(&(lp->hcfCtx), (LTVP)&ltv);
+ break;
+
+ case IW_ENCODE_ALG_WEP:
+ DBG_TRACE(DbgInfo, "IW_ENCODE_ALG_WEP: key(%d)\n", key_idx);
+
+ if (erq->flags & IW_ENCODE_RESTRICTED) {
+ DBG_WARNING(DbgInfo, "IW_ENCODE_RESTRICTED invalid\n");
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ ret = hermes_set_wep_keys(lp, key_idx, ext->key, ext->key_len,
+ enable, set_tx);
+
+ break;
+
+ case IW_ENCODE_ALG_CCMP:
+ DBG_TRACE(DbgInfo, "IW_ENCODE_ALG_CCMP: key(%d)\n", key_idx);
+ ret = -EOPNOTSUPP;
+ break;
+
+ case IW_ENCODE_ALG_NONE:
+ DBG_TRACE(DbgInfo, "IW_ENCODE_ALG_NONE: key(%d)\n", key_idx);
+
+ if (lp->wext_enc == IW_ENCODE_ALG_TKIP) {
+ ret = hermes_clear_tkip_keys(&ltv, key_idx,
+ ext->addr.sa_data);
+ flush_tx(lp);
+ lp->wext_enc = IW_ENCODE_ALG_NONE;
+ ret = hcf_put_info(&(lp->hcfCtx), (LTVP)&ltv);
+
+ } else if (lp->wext_enc == IW_ENCODE_ALG_WEP) {
+ ret = hermes_set_wep_keys(lp, key_idx,
+ ext->key, ext->key_len,
+ false, false);
+ } else {
+ ret = 0;
+ }
+
+ break;
+
+ default:
+ DBG_TRACE( DbgInfo, "IW_ENCODE_??: key(%d)\n", key_idx);
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+out_unlock:
+
+ wl_act_int_on(lp);
+
+ wl_unlock(lp, &flags);
+
+out:
+ DBG_LEAVE(DbgInfo);
+ return ret;
+}
+/*============================================================================*/
+
+
+
+static int wireless_set_genie(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+
+{
+ int ret = 0;
+
+ DBG_ENTER(DbgInfo);
+
+ /* We can't write this to the card, but apparently this
+ * operation needs to succeed */
+ ret = 0;
+
+ DBG_LEAVE(DbgInfo);
+ return ret;
+}
+/*============================================================================*/
+
+
+/*******************************************************************************
+ * wl_wireless_stats()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Return the current device wireless statistics.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+struct iw_statistics * wl_wireless_stats( struct net_device *dev )
+{
+ struct iw_statistics *pStats;
+ struct wl_private *lp = wl_priv(dev);
+ /*------------------------------------------------------------------------*/
+
+
+ DBG_FUNC( "wl_wireless_stats" );
+ DBG_ENTER(DbgInfo);
+ DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
+
+ pStats = NULL;
+
+ /* Initialize the statistics */
+ pStats = &( lp->wstats );
+ pStats->qual.updated = 0x00;
+
+ if( !( lp->flags & WVLAN2_UIL_BUSY ))
+ {
+ CFG_COMMS_QUALITY_STRCT *pQual;
+ CFG_HERMES_TALLIES_STRCT tallies;
+ int status;
+
+ /* Update driver status */
+ pStats->status = 0;
+
+ /* Get the current link quality information */
+ lp->ltvRecord.len = 1 + ( sizeof( *pQual ) / sizeof( hcf_16 ));
+ lp->ltvRecord.typ = CFG_COMMS_QUALITY;
+ status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
+
+ if( status == HCF_SUCCESS ) {
+ pQual = (CFG_COMMS_QUALITY_STRCT *)&( lp->ltvRecord );
+
+ pStats->qual.qual = (u_char) CNV_LITTLE_TO_INT( pQual->coms_qual );
+ pStats->qual.level = (u_char) dbm( CNV_LITTLE_TO_INT( pQual->signal_lvl ));
+ pStats->qual.noise = (u_char) dbm( CNV_LITTLE_TO_INT( pQual->noise_lvl ));
+
+ pStats->qual.updated |= (IW_QUAL_QUAL_UPDATED |
+ IW_QUAL_LEVEL_UPDATED |
+ IW_QUAL_NOISE_UPDATED |
+ IW_QUAL_DBM);
+ } else {
+ memset( &( pStats->qual ), 0, sizeof( pStats->qual ));
+ }
+
+ /* Get the current tallies from the adapter */
+ /* Only possible when the device is open */
+ if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ if( wl_get_tallies( lp, &tallies ) == 0 ) {
+ /* No endian translation is needed here, as CFG_TALLIES is an
+ MSF RID; all processing is done on the host, not the card! */
+ pStats->discard.nwid = 0L;
+ pStats->discard.code = tallies.RxWEPUndecryptable;
+ pStats->discard.misc = tallies.TxDiscards +
+ tallies.RxFCSErrors +
+ //tallies.RxDiscardsNoBuffer +
+ tallies.TxDiscardsWrongSA;
+ //;? Extra taken over from Linux driver based on 7.18 version
+ pStats->discard.retries = tallies.TxRetryLimitExceeded;
+ pStats->discard.fragment = tallies.RxMsgInBadMsgFragments;
+ } else {
+ memset( &( pStats->discard ), 0, sizeof( pStats->discard ));
+ }
+ } else {
+ memset( &( pStats->discard ), 0, sizeof( pStats->discard ));
+ }
+ }
+
+ DBG_LEAVE( DbgInfo );
+ return pStats;
+} // wl_wireless_stats
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_get_wireless_stats()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Return the current device wireless statistics. This function calls
+ * wl_wireless_stats, but acquires spinlocks first as it can be called
+ * directly by the network layer.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+struct iw_statistics * wl_get_wireless_stats( struct net_device *dev )
+{
+ unsigned long flags;
+ struct wl_private *lp = wl_priv(dev);
+ struct iw_statistics *pStats = NULL;
+ /*------------------------------------------------------------------------*/
+
+ DBG_FUNC( "wl_get_wireless_stats" );
+ DBG_ENTER(DbgInfo);
+
+ wl_lock( lp, &flags );
+
+ wl_act_int_off( lp );
+
+#ifdef USE_RTS
+ if( lp->useRTS == 1 ) {
+ DBG_TRACE( DbgInfo, "Skipping wireless stats, in RTS mode\n" );
+ } else
+#endif
+ {
+ pStats = wl_wireless_stats( dev );
+ }
+ wl_act_int_on( lp );
+
+ wl_unlock(lp, &flags);
+
+ DBG_LEAVE( DbgInfo );
+ return pStats;
+} // wl_get_wireless_stats
+
+
+/*******************************************************************************
+ * wl_spy_gather()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * Gather wireless spy statistics.
+ *
+ * PARAMETERS:
+ *
+ * wrq - the wireless request buffer
+ * lp - the device's private adapter structure
+ *
+ * RETURNS:
+ *
+ * 0 on success
+ * errno value otherwise
+ *
+ ******************************************************************************/
+inline void wl_spy_gather( struct net_device *dev, u_char *mac )
+{
+ struct iw_quality wstats;
+ int status;
+ u_char stats[2];
+ DESC_STRCT desc[1];
+ struct wl_private *lp = wl_priv(dev);
+ /*------------------------------------------------------------------------*/
+
+ /* shortcut */
+ if (!lp->spy_data.spy_number) {
+ return;
+ }
+
+ /* Gather wireless spy statistics: for each packet, compare the source
+ address with out list, and if match, get the stats. */
+ memset( stats, 0, sizeof(stats));
+ memset( desc, 0, sizeof(DESC_STRCT));
+
+ desc[0].buf_addr = stats;
+ desc[0].BUF_SIZE = sizeof(stats);
+ desc[0].next_desc_addr = 0; // terminate list
+
+ status = hcf_rcv_msg( &( lp->hcfCtx ), &desc[0], 0 );
+
+ if( status == HCF_SUCCESS ) {
+ wstats.level = (u_char) dbm(stats[1]);
+ wstats.noise = (u_char) dbm(stats[0]);
+ wstats.qual = wstats.level > wstats.noise ? wstats.level - wstats.noise : 0;
+
+ wstats.updated = (IW_QUAL_QUAL_UPDATED |
+ IW_QUAL_LEVEL_UPDATED |
+ IW_QUAL_NOISE_UPDATED |
+ IW_QUAL_DBM);
+
+ wireless_spy_update( dev, mac, &wstats );
+ }
+} // wl_spy_gather
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_wext_event_freq()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * This function is used to send an event that the channel/freq
+ * configuration for a specific device has changed.
+ *
+ *
+ * PARAMETERS:
+ *
+ * dev - the network device for which this event is to be issued
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void wl_wext_event_freq( struct net_device *dev )
+{
+ union iwreq_data wrqu;
+ struct wl_private *lp = wl_priv(dev);
+ /*------------------------------------------------------------------------*/
+
+
+ memset( &wrqu, 0, sizeof( wrqu ));
+
+ wrqu.freq.m = lp->Channel;
+ wrqu.freq.e = 0;
+
+ wireless_send_event( dev, SIOCSIWFREQ, &wrqu, NULL );
+
+ return;
+} // wl_wext_event_freq
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_wext_event_mode()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * This function is used to send an event that the mode of operation
+ * for a specific device has changed.
+ *
+ *
+ * PARAMETERS:
+ *
+ * dev - the network device for which this event is to be issued
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void wl_wext_event_mode( struct net_device *dev )
+{
+ union iwreq_data wrqu;
+ struct wl_private *lp = wl_priv(dev);
+ /*------------------------------------------------------------------------*/
+
+
+ memset( &wrqu, 0, sizeof( wrqu ));
+
+ if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_STA ) {
+ wrqu.mode = IW_MODE_INFRA;
+ } else {
+ wrqu.mode = IW_MODE_MASTER;
+ }
+
+ wireless_send_event( dev, SIOCSIWMODE, &wrqu, NULL );
+
+ return;
+} // wl_wext_event_mode
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_wext_event_essid()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * This function is used to send an event that the ESSID configuration for
+ * a specific device has changed.
+ *
+ *
+ * PARAMETERS:
+ *
+ * dev - the network device for which this event is to be issued
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void wl_wext_event_essid( struct net_device *dev )
+{
+ union iwreq_data wrqu;
+ struct wl_private *lp = wl_priv(dev);
+ /*------------------------------------------------------------------------*/
+
+
+ memset( &wrqu, 0, sizeof( wrqu ));
+
+ /* Fill out the buffer. Note that the buffer doesn't actually contain the
+ ESSID, but a pointer to the contents. In addition, the 'extra' field of
+ the call to wireless_send_event() must also point to where the ESSID
+ lives */
+ wrqu.essid.length = strlen( lp->NetworkName );
+ wrqu.essid.pointer = (caddr_t)lp->NetworkName;
+ wrqu.essid.flags = 1;
+
+ wireless_send_event( dev, SIOCSIWESSID, &wrqu, lp->NetworkName );
+
+ return;
+} // wl_wext_event_essid
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_wext_event_encode()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * This function is used to send an event that the encryption configuration
+ * for a specific device has changed.
+ *
+ *
+ * PARAMETERS:
+ *
+ * dev - the network device for which this event is to be issued
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void wl_wext_event_encode( struct net_device *dev )
+{
+ union iwreq_data wrqu;
+ struct wl_private *lp = wl_priv(dev);
+ int index = 0;
+ /*------------------------------------------------------------------------*/
+
+
+ memset( &wrqu, 0, sizeof( wrqu ));
+
+ if( lp->EnableEncryption == 0 ) {
+ wrqu.encoding.flags = IW_ENCODE_DISABLED;
+ } else {
+ wrqu.encoding.flags |= lp->TransmitKeyID;
+
+ index = lp->TransmitKeyID - 1;
+
+ /* Only set IW_ENCODE_RESTRICTED/OPEN flag using lp->ExcludeUnencrypted
+ if we're in AP mode */
+#if 1 //;? (HCF_TYPE) & HCF_TYPE_AP
+ //;?should we restore this to allow smaller memory footprint
+
+ if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) {
+ if( lp->ExcludeUnencrypted ) {
+ wrqu.encoding.flags |= IW_ENCODE_RESTRICTED;
+ } else {
+ wrqu.encoding.flags |= IW_ENCODE_OPEN;
+ }
+ }
+
+#endif // HCF_TYPE_AP
+
+ /* Only provide the key if permissions allow */
+ if( capable( CAP_NET_ADMIN )) {
+ wrqu.encoding.pointer = (caddr_t)lp->DefaultKeys.key[index].key;
+ wrqu.encoding.length = lp->DefaultKeys.key[index].len;
+ } else {
+ wrqu.encoding.flags |= IW_ENCODE_NOKEY;
+ }
+ }
+
+ wireless_send_event( dev, SIOCSIWENCODE, &wrqu,
+ lp->DefaultKeys.key[index].key );
+
+ return;
+} // wl_wext_event_encode
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_wext_event_ap()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * This function is used to send an event that the device has been
+ * associated to a new AP.
+ *
+ *
+ * PARAMETERS:
+ *
+ * dev - the network device for which this event is to be issued
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void wl_wext_event_ap( struct net_device *dev )
+{
+ union iwreq_data wrqu;
+ struct wl_private *lp = wl_priv(dev);
+ int status;
+ /*------------------------------------------------------------------------*/
+
+
+ /* Retrieve the WPA-IEs used by the firmware and send an event. We must send
+ this event BEFORE sending the association event, as there are timing
+ issues with the hostap supplicant. The supplicant will attempt to process
+ an EAPOL-Key frame from an AP before receiving this information, which
+ is required for a proper processed frame. */
+ wl_wext_event_assoc_ie( dev );
+
+ /* Get the BSSID */
+ lp->ltvRecord.typ = CFG_CUR_BSSID;
+ lp->ltvRecord.len = 4;
+
+ status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
+ if( status == HCF_SUCCESS ) {
+ memset( &wrqu, 0, sizeof( wrqu ));
+
+ memcpy( wrqu.addr.sa_data, lp->ltvRecord.u.u8, ETH_ALEN );
+
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+
+ wireless_send_event( dev, SIOCGIWAP, &wrqu, NULL );
+ }
+
+ return;
+} // wl_wext_event_ap
+/*============================================================================*/
+
+
+
+/*******************************************************************************
+ * wl_wext_event_scan_complete()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * This function is used to send an event that a request for a network scan
+ * has completed.
+ *
+ *
+ * PARAMETERS:
+ *
+ * dev - the network device for which this event is to be issued
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void wl_wext_event_scan_complete( struct net_device *dev )
+{
+ union iwreq_data wrqu;
+ /*------------------------------------------------------------------------*/
+
+
+ memset( &wrqu, 0, sizeof( wrqu ));
+
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event( dev, SIOCGIWSCAN, &wrqu, NULL );
+
+ return;
+} // wl_wext_event_scan_complete
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_wext_event_new_sta()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * This function is used to send an event that an AP has registered a new
+ * station.
+ *
+ *
+ * PARAMETERS:
+ *
+ * dev - the network device for which this event is to be issued
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void wl_wext_event_new_sta( struct net_device *dev )
+{
+ union iwreq_data wrqu;
+ /*------------------------------------------------------------------------*/
+
+
+ memset( &wrqu, 0, sizeof( wrqu ));
+
+ /* Send the station's mac address here */
+ memcpy( wrqu.addr.sa_data, dev->dev_addr, ETH_ALEN );
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event( dev, IWEVREGISTERED, &wrqu, NULL );
+
+ return;
+} // wl_wext_event_new_sta
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_wext_event_expired_sta()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * This function is used to send an event that an AP has deregistered a
+ * station.
+ *
+ *
+ * PARAMETERS:
+ *
+ * dev - the network device for which this event is to be issued
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void wl_wext_event_expired_sta( struct net_device *dev )
+{
+ union iwreq_data wrqu;
+ /*------------------------------------------------------------------------*/
+
+
+ memset( &wrqu, 0, sizeof( wrqu ));
+
+ memcpy( wrqu.addr.sa_data, dev->dev_addr, ETH_ALEN );
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event( dev, IWEVEXPIRED, &wrqu, NULL );
+
+ return;
+} // wl_wext_event_expired_sta
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_wext_event_mic_failed()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * This function is used to send an event that MIC calculations failed.
+ *
+ *
+ * PARAMETERS:
+ *
+ * dev - the network device for which this event is to be issued
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void wl_wext_event_mic_failed( struct net_device *dev )
+{
+ union iwreq_data wrqu;
+ struct wl_private *lp = wl_priv(dev);
+ struct iw_michaelmicfailure wxmic;
+ int key_idx;
+ char *addr1;
+ char *addr2;
+ WVLAN_RX_WMP_HDR *hdr;
+ /*------------------------------------------------------------------------*/
+
+
+ key_idx = lp->lookAheadBuf[HFS_STAT+1] >> 3;
+ key_idx &= 0x03;
+
+ /* Cast the lookahead buffer into a RFS format */
+ hdr = (WVLAN_RX_WMP_HDR *)&lp->lookAheadBuf[HFS_STAT];
+
+ /* Cast the addresses to byte buffers, as in the above RFS they are word
+ length */
+ addr1 = (char *)hdr->address1;
+ addr2 = (char *)hdr->address2;
+
+ DBG_PRINT( "MIC FAIL - KEY USED : %d, STATUS : 0x%04x\n", key_idx,
+ hdr->status );
+
+ memset(&wrqu, 0, sizeof(wrqu));
+ memset(&wxmic, 0, sizeof(wxmic));
+
+ wxmic.flags = key_idx & IW_MICFAILURE_KEY_ID;
+ wxmic.flags |= (addr1[0] & 1) ?
+ IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE;
+ wxmic.src_addr.sa_family = ARPHRD_ETHER;
+ memcpy(wxmic.src_addr.sa_data, addr2, ETH_ALEN);
+
+ wrqu.data.length = sizeof(wxmic);
+ wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&wxmic);
+
+ return;
+} // wl_wext_event_mic_failed
+/*============================================================================*/
+
+
+
+
+/*******************************************************************************
+ * wl_wext_event_assoc_ie()
+ *******************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * This function is used to send an event containing the WPA-IE generated
+ * by the firmware in an association request.
+ *
+ *
+ * PARAMETERS:
+ *
+ * dev - the network device for which this event is to be issued
+ *
+ * RETURNS:
+ *
+ * N/A
+ *
+ ******************************************************************************/
+void wl_wext_event_assoc_ie( struct net_device *dev )
+{
+ union iwreq_data wrqu;
+ struct wl_private *lp = wl_priv(dev);
+ int status;
+ PROBE_RESP data;
+ hcf_16 length;
+ hcf_8 *wpa_ie;
+ /*------------------------------------------------------------------------*/
+
+
+ memset( &wrqu, 0, sizeof( wrqu ));
+
+ /* Retrieve the Association Request IE */
+ lp->ltvRecord.len = 45;
+ lp->ltvRecord.typ = CFG_CUR_ASSOC_REQ_INFO;
+
+ status = hcf_get_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
+ if( status == HCF_SUCCESS )
+ {
+ length = 0;
+ memcpy( &data.rawData, &( lp->ltvRecord.u.u8[1] ), 88 );
+ wpa_ie = wl_parse_wpa_ie( &data, &length );
+
+ if( length != 0 )
+ {
+ wrqu.data.length = wpa_ie[1] + 2;
+ wireless_send_event(dev, IWEVASSOCREQIE,
+ &wrqu, wpa_ie);
+
+ /* This bit is a hack. We send the respie
+ * event at the same time */
+ wireless_send_event(dev, IWEVASSOCRESPIE,
+ &wrqu, wpa_ie);
+ }
+ }
+
+ return;
+} // wl_wext_event_assoc_ie
+/*============================================================================*/
+/* Structures to export the Wireless Handlers */
+
+static const iw_handler wl_handler[] =
+{
+ IW_HANDLER(SIOCSIWCOMMIT, (iw_handler) wireless_commit),
+ IW_HANDLER(SIOCGIWNAME, (iw_handler) wireless_get_protocol),
+ IW_HANDLER(SIOCSIWFREQ, (iw_handler) wireless_set_frequency),
+ IW_HANDLER(SIOCGIWFREQ, (iw_handler) wireless_get_frequency),
+ IW_HANDLER(SIOCSIWMODE, (iw_handler) wireless_set_porttype),
+ IW_HANDLER(SIOCGIWMODE, (iw_handler) wireless_get_porttype),
+ IW_HANDLER(SIOCSIWSENS, (iw_handler) wireless_set_sensitivity),
+ IW_HANDLER(SIOCGIWSENS, (iw_handler) wireless_get_sensitivity),
+ IW_HANDLER(SIOCGIWRANGE, (iw_handler) wireless_get_range),
+ IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
+ IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
+#if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
+ IW_HANDLER(SIOCGIWAP, (iw_handler) wireless_get_bssid),
+#endif
+ IW_HANDLER(SIOCGIWAPLIST, (iw_handler) wireless_get_ap_list),
+ IW_HANDLER(SIOCSIWSCAN, (iw_handler) wireless_set_scan),
+ IW_HANDLER(SIOCGIWSCAN, (iw_handler) wireless_get_scan),
+ IW_HANDLER(SIOCSIWESSID, (iw_handler) wireless_set_essid),
+ IW_HANDLER(SIOCGIWESSID, (iw_handler) wireless_get_essid),
+ IW_HANDLER(SIOCSIWNICKN, (iw_handler) wireless_set_nickname),
+ IW_HANDLER(SIOCGIWNICKN, (iw_handler) wireless_get_nickname),
+ IW_HANDLER(SIOCSIWRATE, (iw_handler) wireless_set_rate),
+ IW_HANDLER(SIOCGIWRATE, (iw_handler) wireless_get_rate),
+ IW_HANDLER(SIOCSIWRTS, (iw_handler) wireless_set_rts_threshold),
+ IW_HANDLER(SIOCGIWRTS, (iw_handler) wireless_get_rts_threshold),
+ IW_HANDLER(SIOCGIWTXPOW, (iw_handler) wireless_get_tx_power),
+ IW_HANDLER(SIOCSIWENCODE, (iw_handler) wireless_set_encode),
+ IW_HANDLER(SIOCGIWENCODE, (iw_handler) wireless_get_encode),
+ IW_HANDLER(SIOCSIWPOWER, (iw_handler) wireless_set_power),
+ IW_HANDLER(SIOCGIWPOWER, (iw_handler) wireless_get_power),
+ IW_HANDLER(SIOCSIWGENIE, (iw_handler) wireless_set_genie),
+ IW_HANDLER(SIOCSIWAUTH, (iw_handler) wireless_set_auth),
+ IW_HANDLER(SIOCSIWENCODEEXT, (iw_handler) wireless_set_encodeext),
+};
+
+static const iw_handler wl_private_handler[] =
+{ /* SIOCIWFIRSTPRIV + */
+ wvlan_set_netname, /* 0: SIOCSIWNETNAME */
+ wvlan_get_netname, /* 1: SIOCGIWNETNAME */
+ wvlan_set_station_nickname, /* 2: SIOCSIWSTANAME */
+ wvlan_get_station_nickname, /* 3: SIOCGIWSTANAME */
+#if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
+ wvlan_set_porttype, /* 4: SIOCSIWPORTTYPE */
+ wvlan_get_porttype, /* 5: SIOCGIWPORTTYPE */
+#endif
+};
+
+struct iw_priv_args wl_priv_args[] = {
+ {SIOCSIWNETNAME, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, 0, "snetwork_name" },
+ {SIOCGIWNETNAME, 0, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, "gnetwork_name" },
+ {SIOCSIWSTANAME, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, 0, "sstation_name" },
+ {SIOCGIWSTANAME, 0, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, "gstation_name" },
+#if 1 //;? #if (HCF_TYPE) & HCF_TYPE_STA
+ {SIOCSIWPORTTYPE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "sport_type" },
+ {SIOCGIWPORTTYPE, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gport_type" },
+#endif
+};
+
+const struct iw_handler_def wl_iw_handler_def =
+{
+ .num_private = sizeof(wl_private_handler) / sizeof(iw_handler),
+ .private = (iw_handler *) wl_private_handler,
+ .private_args = (struct iw_priv_args *) wl_priv_args,
+ .num_private_args = sizeof(wl_priv_args) / sizeof(struct iw_priv_args),
+ .num_standard = sizeof(wl_handler) / sizeof(iw_handler),
+ .standard = (iw_handler *) wl_handler,
+ .get_wireless_stats = wl_get_wireless_stats,
+};