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