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