linux/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c
<<
>>
Prefs
   1/******************************************************************************
   2
   3  Copyright(c) 2004 Intel Corporation. All rights reserved.
   4
   5  Portions of this file are based on the WEP enablement code provided by the
   6  Host AP project hostap-drivers v0.1.3
   7  Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
   8  <jkmaline@cc.hut.fi>
   9  Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
  10
  11  This program is free software; you can redistribute it and/or modify it
  12  under the terms of version 2 of the GNU General Public License as
  13  published by the Free Software Foundation.
  14
  15  This program is distributed in the hope that it will be useful, but WITHOUT
  16  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  17  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  18  more details.
  19
  20  You should have received a copy of the GNU General Public License along with
  21  this program; if not, write to the Free Software Foundation, Inc., 59
  22  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  23
  24  The full GNU General Public License is included in this distribution in the
  25  file called LICENSE.
  26
  27  Contact Information:
  28  James P. Ketrenos <ipw2100-admin@linux.intel.com>
  29  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  30
  31******************************************************************************/
  32#include <linux/wireless.h>
  33#include <linux/version.h>
  34#include <linux/kmod.h>
  35#include <linux/module.h>
  36
  37#include "ieee80211.h"
  38#if 0
  39static const char *ieee80211_modes[] = {
  40        "?", "a", "b", "ab", "g", "ag", "bg", "abg"
  41};
  42#endif
  43struct modes_unit {
  44        char *mode_string;
  45        int mode_size;
  46};
  47struct modes_unit ieee80211_modes[] = {
  48        {"a",1},
  49        {"b",1},
  50        {"g",1},
  51        {"?",1},
  52        {"N-24G",5},
  53        {"N-5G",4},
  54};
  55
  56#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
  57static inline char *
  58iwe_stream_add_event_rsl(char *     stream,         /* Stream of events */
  59                     char *     ends,           /* End of stream */
  60                     struct iw_event *iwe,      /* Payload */
  61                     int        event_len)      /* Real size of payload */
  62{
  63        /* Check if it's possible */
  64        if((stream + event_len) < ends) {
  65                iwe->len = event_len;
  66                ndelay(1);   //new
  67                memcpy(stream, (char *) iwe, event_len);
  68                stream += event_len;
  69        }
  70        return stream;
  71}
  72#else
  73#define iwe_stream_add_event_rsl iwe_stream_add_event
  74#endif
  75
  76#define MAX_CUSTOM_LEN 64
  77static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
  78                                           char *start, char *stop,
  79                                           struct ieee80211_network *network,
  80                                           struct iw_request_info *info)
  81{
  82        char custom[MAX_CUSTOM_LEN];
  83        char proto_name[IFNAMSIZ];
  84        char *pname = proto_name;
  85        char *p;
  86        struct iw_event iwe;
  87        int i, j;
  88        u16 max_rate, rate;
  89        static u8       EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33};
  90
  91        /* First entry *MUST* be the AP MAC address */
  92        iwe.cmd = SIOCGIWAP;
  93        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
  94        memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
  95#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
  96        start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_ADDR_LEN);
  97#else
  98        start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_ADDR_LEN);
  99#endif
 100        /* Remaining entries will be displayed in the order we provide them */
 101
 102        /* Add the ESSID */
 103        iwe.cmd = SIOCGIWESSID;
 104        iwe.u.data.flags = 1;
 105//      if (network->flags & NETWORK_EMPTY_ESSID) {
 106        if (network->ssid_len == 0) {
 107                iwe.u.data.length = sizeof("<hidden>");
 108#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 109                start = iwe_stream_add_point(info, start, stop, &iwe, "<hidden>");
 110#else
 111                start = iwe_stream_add_point(start, stop, &iwe, "<hidden>");
 112#endif
 113        } else {
 114                iwe.u.data.length = min(network->ssid_len, (u8)32);
 115#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 116                start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
 117#else
 118                start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
 119#endif
 120        }
 121        /* Add the protocol name */
 122        iwe.cmd = SIOCGIWNAME;
 123        for(i=0; i<(sizeof(ieee80211_modes)/sizeof(ieee80211_modes[0])); i++) {
 124                if(network->mode&(1<<i)) {
 125                        sprintf(pname,ieee80211_modes[i].mode_string,ieee80211_modes[i].mode_size);
 126                        pname +=ieee80211_modes[i].mode_size;
 127                }
 128        }
 129        *pname = '\0';
 130        snprintf(iwe.u.name, IFNAMSIZ, "IEEE802.11%s", proto_name);
 131#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 132        start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_CHAR_LEN);
 133#else
 134        start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_CHAR_LEN);
 135#endif
 136        /* Add mode */
 137        iwe.cmd = SIOCGIWMODE;
 138        if (network->capability &
 139            (WLAN_CAPABILITY_BSS | WLAN_CAPABILITY_IBSS)) {
 140                if (network->capability & WLAN_CAPABILITY_BSS)
 141                        iwe.u.mode = IW_MODE_MASTER;
 142                else
 143                        iwe.u.mode = IW_MODE_ADHOC;
 144#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 145                start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_UINT_LEN);
 146#else
 147                start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_UINT_LEN);
 148#endif
 149        }
 150
 151        /* Add frequency/channel */
 152        iwe.cmd = SIOCGIWFREQ;
 153/*      iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
 154        iwe.u.freq.e = 3; */
 155        iwe.u.freq.m = network->channel;
 156        iwe.u.freq.e = 0;
 157        iwe.u.freq.i = 0;
 158#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 159        start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_FREQ_LEN);
 160#else
 161        start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_FREQ_LEN);
 162#endif
 163        /* Add encryption capability */
 164        iwe.cmd = SIOCGIWENCODE;
 165        if (network->capability & WLAN_CAPABILITY_PRIVACY)
 166                iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
 167        else
 168                iwe.u.data.flags = IW_ENCODE_DISABLED;
 169        iwe.u.data.length = 0;
 170#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 171        start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
 172#else
 173        start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
 174#endif
 175        /* Add basic and extended rates */
 176        max_rate = 0;
 177        p = custom;
 178        p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
 179        for (i = 0, j = 0; i < network->rates_len; ) {
 180                if (j < network->rates_ex_len &&
 181                    ((network->rates_ex[j] & 0x7F) <
 182                     (network->rates[i] & 0x7F)))
 183                        rate = network->rates_ex[j++] & 0x7F;
 184                else
 185                        rate = network->rates[i++] & 0x7F;
 186                if (rate > max_rate)
 187                        max_rate = rate;
 188                p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
 189                              "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
 190        }
 191        for (; j < network->rates_ex_len; j++) {
 192                rate = network->rates_ex[j] & 0x7F;
 193                p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
 194                              "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
 195                if (rate > max_rate)
 196                        max_rate = rate;
 197        }
 198
 199        if (network->mode >= IEEE_N_24G)//add N rate here;
 200        {
 201                PHT_CAPABILITY_ELE ht_cap = NULL;
 202                bool is40M = false, isShortGI = false;
 203                u8 max_mcs = 0;
 204                if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4))
 205                        ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[4];
 206                else
 207                        ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[0];
 208                is40M = (ht_cap->ChlWidth)?1:0;
 209                isShortGI = (ht_cap->ChlWidth)?
 210                                                ((ht_cap->ShortGI40Mhz)?1:0):
 211                                                ((ht_cap->ShortGI20Mhz)?1:0);
 212
 213                max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS, MCS_FILTER_ALL);
 214                rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs&0x7f];
 215                if (rate > max_rate)
 216                        max_rate = rate;
 217        }
 218#if 0
 219        printk("max rate:%d ===basic rate:\n", max_rate);
 220        for (i=0;i<network->rates_len;i++)
 221                printk(" %x", network->rates[i]);
 222        printk("\n=======extend rate\n");
 223        for (i=0; i<network->rates_ex_len; i++)
 224                printk(" %x", network->rates_ex[i]);
 225        printk("\n");
 226#endif
 227        iwe.cmd = SIOCGIWRATE;
 228        iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
 229        iwe.u.bitrate.value = max_rate * 500000;
 230#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 231        start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
 232                                     IW_EV_PARAM_LEN);
 233#else
 234        start = iwe_stream_add_event_rsl(start, stop, &iwe,
 235                                     IW_EV_PARAM_LEN);
 236#endif
 237        iwe.cmd = IWEVCUSTOM;
 238        iwe.u.data.length = p - custom;
 239        if (iwe.u.data.length)
 240#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 241        start = iwe_stream_add_point(info, start, stop, &iwe, custom);
 242#else
 243        start = iwe_stream_add_point(start, stop, &iwe, custom);
 244#endif
 245        /* Add quality statistics */
 246        /* TODO: Fix these values... */
 247        iwe.cmd = IWEVQUAL;
 248        iwe.u.qual.qual = network->stats.signal;
 249        iwe.u.qual.level = network->stats.rssi;
 250        iwe.u.qual.noise = network->stats.noise;
 251        iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK;
 252        if (!(network->stats.mask & IEEE80211_STATMASK_RSSI))
 253                iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
 254        if (!(network->stats.mask & IEEE80211_STATMASK_NOISE))
 255                iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
 256        if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL))
 257                iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
 258        iwe.u.qual.updated = 7;
 259#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 260        start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_QUAL_LEN);
 261#else
 262        start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_QUAL_LEN);
 263#endif
 264        iwe.cmd = IWEVCUSTOM;
 265        p = custom;
 266
 267        iwe.u.data.length = p - custom;
 268        if (iwe.u.data.length)
 269#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 270            start = iwe_stream_add_point(info, start, stop, &iwe, custom);
 271#else
 272            start = iwe_stream_add_point(start, stop, &iwe, custom);
 273#endif
 274#if (WIRELESS_EXT < 18)
 275        if (ieee->wpa_enabled && network->wpa_ie_len){
 276                char buf[MAX_WPA_IE_LEN * 2 + 30];
 277        //      printk("WPA IE\n");
 278                u8 *p = buf;
 279                p += sprintf(p, "wpa_ie=");
 280                for (i = 0; i < network->wpa_ie_len; i++) {
 281                        p += sprintf(p, "%02x", network->wpa_ie[i]);
 282                }
 283
 284                memset(&iwe, 0, sizeof(iwe));
 285                iwe.cmd = IWEVCUSTOM;
 286                iwe.u.data.length = strlen(buf);
 287#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 288                start = iwe_stream_add_point(info, start, stop, &iwe, buf);
 289#else
 290                start = iwe_stream_add_point(start, stop, &iwe, buf);
 291#endif
 292        }
 293
 294        if (ieee->wpa_enabled && network->rsn_ie_len){
 295                char buf[MAX_WPA_IE_LEN * 2 + 30];
 296
 297                u8 *p = buf;
 298                p += sprintf(p, "rsn_ie=");
 299                for (i = 0; i < network->rsn_ie_len; i++) {
 300                        p += sprintf(p, "%02x", network->rsn_ie[i]);
 301                }
 302
 303                memset(&iwe, 0, sizeof(iwe));
 304                iwe.cmd = IWEVCUSTOM;
 305                iwe.u.data.length = strlen(buf);
 306#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 307                start = iwe_stream_add_point(info, start, stop, &iwe, buf);
 308#else
 309                start = iwe_stream_add_point(start, stop, &iwe, buf);
 310#endif
 311        }
 312#else
 313        memset(&iwe, 0, sizeof(iwe));
 314        if (network->wpa_ie_len)
 315        {
 316                char buf[MAX_WPA_IE_LEN];
 317                memcpy(buf, network->wpa_ie, network->wpa_ie_len);
 318                iwe.cmd = IWEVGENIE;
 319                iwe.u.data.length = network->wpa_ie_len;
 320#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 321                start = iwe_stream_add_point(info, start, stop, &iwe, buf);
 322#else
 323                start = iwe_stream_add_point(start, stop, &iwe, buf);
 324#endif
 325        }
 326        memset(&iwe, 0, sizeof(iwe));
 327        if (network->rsn_ie_len)
 328        {
 329                char buf[MAX_WPA_IE_LEN];
 330                memcpy(buf, network->rsn_ie, network->rsn_ie_len);
 331                iwe.cmd = IWEVGENIE;
 332                iwe.u.data.length = network->rsn_ie_len;
 333#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 334                start = iwe_stream_add_point(info, start, stop, &iwe, buf);
 335#else
 336                start = iwe_stream_add_point(start, stop, &iwe, buf);
 337#endif
 338        }
 339#endif
 340
 341
 342        /* Add EXTRA: Age to display seconds since last beacon/probe response
 343         * for given network. */
 344        iwe.cmd = IWEVCUSTOM;
 345        p = custom;
 346        p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
 347                      " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100));
 348        iwe.u.data.length = p - custom;
 349        if (iwe.u.data.length)
 350#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 351            start = iwe_stream_add_point(info, start, stop, &iwe, custom);
 352#else
 353            start = iwe_stream_add_point(start, stop, &iwe, custom);
 354#endif
 355
 356        return start;
 357}
 358
 359int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
 360                          struct iw_request_info *info,
 361                          union iwreq_data *wrqu, char *extra)
 362{
 363        struct ieee80211_network *network;
 364        unsigned long flags;
 365
 366        char *ev = extra;
 367//      char *stop = ev + IW_SCAN_MAX_DATA;
 368        char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA;
 369        //char *stop = ev + IW_SCAN_MAX_DATA;
 370        int i = 0;
 371        int err = 0;
 372        IEEE80211_DEBUG_WX("Getting scan\n");
 373        down(&ieee->wx_sem);
 374        spin_lock_irqsave(&ieee->lock, flags);
 375
 376        list_for_each_entry(network, &ieee->network_list, list) {
 377                i++;
 378                if((stop-ev)<200)
 379                {
 380                        err = -E2BIG;
 381                        break;
 382                                                                                                }
 383                if (ieee->scan_age == 0 ||
 384                    time_after(network->last_scanned + ieee->scan_age, jiffies))
 385                        ev = rtl819x_translate_scan(ieee, ev, stop, network, info);
 386                else
 387                        IEEE80211_DEBUG_SCAN(
 388                                "Not showing network '%s ("
 389                                MAC_FMT ")' due to age (%lums).\n",
 390                                escape_essid(network->ssid,
 391                                             network->ssid_len),
 392                                MAC_ARG(network->bssid),
 393                                (jiffies - network->last_scanned) / (HZ / 100));
 394        }
 395
 396        spin_unlock_irqrestore(&ieee->lock, flags);
 397        up(&ieee->wx_sem);
 398        wrqu->data.length = ev -  extra;
 399        wrqu->data.flags = 0;
 400
 401        IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
 402
 403        return err;
 404}
 405
 406int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
 407                            struct iw_request_info *info,
 408                            union iwreq_data *wrqu, char *keybuf)
 409{
 410        struct iw_point *erq = &(wrqu->encoding);
 411        struct net_device *dev = ieee->dev;
 412        struct ieee80211_security sec = {
 413                .flags = 0
 414        };
 415        int i, key, key_provided, len;
 416        struct ieee80211_crypt_data **crypt;
 417
 418        IEEE80211_DEBUG_WX("SET_ENCODE\n");
 419
 420        key = erq->flags & IW_ENCODE_INDEX;
 421        if (key) {
 422                if (key > WEP_KEYS)
 423                        return -EINVAL;
 424                key--;
 425                key_provided = 1;
 426        } else {
 427                key_provided = 0;
 428                key = ieee->tx_keyidx;
 429        }
 430
 431        IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
 432                           "provided" : "default");
 433        crypt = &ieee->crypt[key];
 434
 435        if (erq->flags & IW_ENCODE_DISABLED) {
 436                if (key_provided && *crypt) {
 437                        IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
 438                                           key);
 439                        ieee80211_crypt_delayed_deinit(ieee, crypt);
 440                } else
 441                        IEEE80211_DEBUG_WX("Disabling encryption.\n");
 442
 443                /* Check all the keys to see if any are still configured,
 444                 * and if no key index was provided, de-init them all */
 445                for (i = 0; i < WEP_KEYS; i++) {
 446                        if (ieee->crypt[i] != NULL) {
 447                                if (key_provided)
 448                                        break;
 449                                ieee80211_crypt_delayed_deinit(
 450                                        ieee, &ieee->crypt[i]);
 451                        }
 452                }
 453
 454                if (i == WEP_KEYS) {
 455                        sec.enabled = 0;
 456                        sec.level = SEC_LEVEL_0;
 457                        sec.flags |= SEC_ENABLED | SEC_LEVEL;
 458                }
 459
 460                goto done;
 461        }
 462
 463
 464
 465        sec.enabled = 1;
 466        sec.flags |= SEC_ENABLED;
 467
 468        if (*crypt != NULL && (*crypt)->ops != NULL &&
 469            strcmp((*crypt)->ops->name, "WEP") != 0) {
 470                /* changing to use WEP; deinit previously used algorithm
 471                 * on this key */
 472                ieee80211_crypt_delayed_deinit(ieee, crypt);
 473        }
 474
 475        if (*crypt == NULL) {
 476                struct ieee80211_crypt_data *new_crypt;
 477
 478                /* take WEP into use */
 479                new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
 480                                    GFP_KERNEL);
 481                if (new_crypt == NULL)
 482                        return -ENOMEM;
 483                memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
 484                new_crypt->ops = ieee80211_get_crypto_ops("WEP");
 485                if (!new_crypt->ops)
 486                        new_crypt->ops = ieee80211_get_crypto_ops("WEP");
 487                if (new_crypt->ops)
 488                        new_crypt->priv = new_crypt->ops->init(key);
 489
 490                if (!new_crypt->ops || !new_crypt->priv) {
 491                        kfree(new_crypt);
 492                        new_crypt = NULL;
 493
 494                        printk(KERN_WARNING "%s: could not initialize WEP: "
 495                               "load module ieee80211_crypt_wep\n",
 496                               dev->name);
 497                        return -EOPNOTSUPP;
 498                }
 499                *crypt = new_crypt;
 500        }
 501
 502        /* If a new key was provided, set it up */
 503        if (erq->length > 0) {
 504                len = erq->length <= 5 ? 5 : 13;
 505                memcpy(sec.keys[key], keybuf, erq->length);
 506                if (len > erq->length)
 507                        memset(sec.keys[key] + erq->length, 0,
 508                               len - erq->length);
 509                IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
 510                                   key, escape_essid(sec.keys[key], len),
 511                                   erq->length, len);
 512                sec.key_sizes[key] = len;
 513                (*crypt)->ops->set_key(sec.keys[key], len, NULL,
 514                                       (*crypt)->priv);
 515                sec.flags |= (1 << key);
 516                /* This ensures a key will be activated if no key is
 517                 * explicitely set */
 518                if (key == sec.active_key)
 519                        sec.flags |= SEC_ACTIVE_KEY;
 520                ieee->tx_keyidx = key;
 521
 522        } else {
 523                len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
 524                                             NULL, (*crypt)->priv);
 525                if (len == 0) {
 526                        /* Set a default key of all 0 */
 527                        printk("Setting key %d to all zero.\n",
 528                                           key);
 529
 530                        IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
 531                                           key);
 532                        memset(sec.keys[key], 0, 13);
 533                        (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
 534                                               (*crypt)->priv);
 535                        sec.key_sizes[key] = 13;
 536                        sec.flags |= (1 << key);
 537                }
 538
 539                /* No key data - just set the default TX key index */
 540                if (key_provided) {
 541                        IEEE80211_DEBUG_WX(
 542                                "Setting key %d to default Tx key.\n", key);
 543                        ieee->tx_keyidx = key;
 544                        sec.active_key = key;
 545                        sec.flags |= SEC_ACTIVE_KEY;
 546                }
 547        }
 548
 549 done:
 550        ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
 551        ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
 552        sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
 553        sec.flags |= SEC_AUTH_MODE;
 554        IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
 555                           "OPEN" : "SHARED KEY");
 556
 557        /* For now we just support WEP, so only set that security level...
 558         * TODO: When WPA is added this is one place that needs to change */
 559        sec.flags |= SEC_LEVEL;
 560        sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
 561
 562        if (ieee->set_security)
 563                ieee->set_security(dev, &sec);
 564
 565        /* Do not reset port if card is in Managed mode since resetting will
 566         * generate new IEEE 802.11 authentication which may end up in looping
 567         * with IEEE 802.1X.  If your hardware requires a reset after WEP
 568         * configuration (for example... Prism2), implement the reset_port in
 569         * the callbacks structures used to initialize the 802.11 stack. */
 570        if (ieee->reset_on_keychange &&
 571            ieee->iw_mode != IW_MODE_INFRA &&
 572            ieee->reset_port && ieee->reset_port(dev)) {
 573                printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
 574                return -EINVAL;
 575        }
 576        return 0;
 577}
 578
 579int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
 580                            struct iw_request_info *info,
 581                            union iwreq_data *wrqu, char *keybuf)
 582{
 583        struct iw_point *erq = &(wrqu->encoding);
 584        int len, key;
 585        struct ieee80211_crypt_data *crypt;
 586
 587        IEEE80211_DEBUG_WX("GET_ENCODE\n");
 588
 589        if(ieee->iw_mode == IW_MODE_MONITOR)
 590                return -1;
 591
 592        key = erq->flags & IW_ENCODE_INDEX;
 593        if (key) {
 594                if (key > WEP_KEYS)
 595                        return -EINVAL;
 596                key--;
 597        } else
 598                key = ieee->tx_keyidx;
 599
 600        crypt = ieee->crypt[key];
 601        erq->flags = key + 1;
 602
 603        if (crypt == NULL || crypt->ops == NULL) {
 604                erq->length = 0;
 605                erq->flags |= IW_ENCODE_DISABLED;
 606                return 0;
 607        }
 608#if 0
 609        if (strcmp(crypt->ops->name, "WEP") != 0) {
 610                /* only WEP is supported with wireless extensions, so just
 611                 * report that encryption is used */
 612                erq->length = 0;
 613                erq->flags |= IW_ENCODE_ENABLED;
 614                return 0;
 615        }
 616#endif
 617        len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
 618        erq->length = (len >= 0 ? len : 0);
 619
 620        erq->flags |= IW_ENCODE_ENABLED;
 621
 622        if (ieee->open_wep)
 623                erq->flags |= IW_ENCODE_OPEN;
 624        else
 625                erq->flags |= IW_ENCODE_RESTRICTED;
 626
 627        return 0;
 628}
 629#if (WIRELESS_EXT >= 18)
 630int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
 631                               struct iw_request_info *info,
 632                               union iwreq_data *wrqu, char *extra)
 633{
 634        int ret = 0;
 635#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
 636        struct net_device *dev = ieee->dev;
 637        struct iw_point *encoding = &wrqu->encoding;
 638        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 639        int i, idx;
 640        int group_key = 0;
 641        const char *alg;
 642        struct ieee80211_crypto_ops *ops;
 643        struct ieee80211_crypt_data **crypt;
 644
 645        struct ieee80211_security sec = {
 646                .flags = 0,
 647        };
 648        //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg);
 649        idx = encoding->flags & IW_ENCODE_INDEX;
 650        if (idx) {
 651                if (idx < 1 || idx > WEP_KEYS)
 652                        return -EINVAL;
 653                idx--;
 654        } else
 655                idx = ieee->tx_keyidx;
 656
 657        if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
 658
 659                crypt = &ieee->crypt[idx];
 660
 661                group_key = 1;
 662        } else {
 663                /* some Cisco APs use idx>0 for unicast in dynamic WEP */
 664                //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg);
 665                if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
 666                        return -EINVAL;
 667                if (ieee->iw_mode == IW_MODE_INFRA)
 668
 669                        crypt = &ieee->crypt[idx];
 670
 671                else
 672                        return -EINVAL;
 673        }
 674
 675        sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT;
 676        if ((encoding->flags & IW_ENCODE_DISABLED) ||
 677            ext->alg == IW_ENCODE_ALG_NONE) {
 678                if (*crypt)
 679                        ieee80211_crypt_delayed_deinit(ieee, crypt);
 680
 681                for (i = 0; i < WEP_KEYS; i++)
 682
 683                        if (ieee->crypt[i] != NULL)
 684
 685                                break;
 686
 687                if (i == WEP_KEYS) {
 688                        sec.enabled = 0;
 689                      //  sec.encrypt = 0;
 690                        sec.level = SEC_LEVEL_0;
 691                        sec.flags |= SEC_LEVEL;
 692                }
 693                //printk("disabled: flag:%x\n", encoding->flags);
 694                goto done;
 695        }
 696
 697        sec.enabled = 1;
 698    //    sec.encrypt = 1;
 699#if 0
 700        if (group_key ? !ieee->host_mc_decrypt :
 701            !(ieee->host_encrypt || ieee->host_decrypt ||
 702              ieee->host_encrypt_msdu))
 703                goto skip_host_crypt;
 704#endif
 705        switch (ext->alg) {
 706        case IW_ENCODE_ALG_WEP:
 707                alg = "WEP";
 708                break;
 709        case IW_ENCODE_ALG_TKIP:
 710                alg = "TKIP";
 711                break;
 712        case IW_ENCODE_ALG_CCMP:
 713                alg = "CCMP";
 714                break;
 715        default:
 716                IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
 717                                   dev->name, ext->alg);
 718                ret = -EINVAL;
 719                goto done;
 720        }
 721        printk("alg name:%s\n",alg);
 722
 723         ops = ieee80211_get_crypto_ops(alg);
 724        if (ops == NULL)
 725                ops = ieee80211_get_crypto_ops(alg);
 726        if (ops == NULL) {
 727                IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
 728                                   dev->name, ext->alg);
 729                printk("========>unknown crypto alg %d\n", ext->alg);
 730                ret = -EINVAL;
 731                goto done;
 732        }
 733
 734        if (*crypt == NULL || (*crypt)->ops != ops) {
 735                struct ieee80211_crypt_data *new_crypt;
 736
 737                ieee80211_crypt_delayed_deinit(ieee, crypt);
 738
 739#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
 740                new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
 741#else
 742                new_crypt = kmalloc(sizeof(*new_crypt), GFP_KERNEL);
 743                memset(new_crypt,0,sizeof(*new_crypt));
 744#endif
 745                if (new_crypt == NULL) {
 746                        ret = -ENOMEM;
 747                        goto done;
 748                }
 749                new_crypt->ops = ops;
 750                if (new_crypt->ops)
 751                        new_crypt->priv = new_crypt->ops->init(idx);
 752                if (new_crypt->priv == NULL) {
 753                        kfree(new_crypt);
 754                        ret = -EINVAL;
 755                        goto done;
 756                }
 757                *crypt = new_crypt;
 758
 759        }
 760
 761        if (ext->key_len > 0 && (*crypt)->ops->set_key &&
 762            (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
 763                                   (*crypt)->priv) < 0) {
 764                IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
 765                printk("key setting failed\n");
 766                ret = -EINVAL;
 767                goto done;
 768        }
 769#if 1
 770 //skip_host_crypt:
 771        //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags);
 772        if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
 773                ieee->tx_keyidx = idx;
 774                sec.active_key = idx;
 775                sec.flags |= SEC_ACTIVE_KEY;
 776        }
 777
 778        if (ext->alg != IW_ENCODE_ALG_NONE) {
 779                //memcpy(sec.keys[idx], ext->key, ext->key_len);
 780                sec.key_sizes[idx] = ext->key_len;
 781                sec.flags |= (1 << idx);
 782                if (ext->alg == IW_ENCODE_ALG_WEP) {
 783                      //  sec.encode_alg[idx] = SEC_ALG_WEP;
 784                        sec.flags |= SEC_LEVEL;
 785                        sec.level = SEC_LEVEL_1;
 786                } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
 787                      //  sec.encode_alg[idx] = SEC_ALG_TKIP;
 788                        sec.flags |= SEC_LEVEL;
 789                        sec.level = SEC_LEVEL_2;
 790                } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
 791                       // sec.encode_alg[idx] = SEC_ALG_CCMP;
 792                        sec.flags |= SEC_LEVEL;
 793                        sec.level = SEC_LEVEL_3;
 794                }
 795                /* Don't set sec level for group keys. */
 796                if (group_key)
 797                        sec.flags &= ~SEC_LEVEL;
 798        }
 799#endif
 800done:
 801        if (ieee->set_security)
 802                ieee->set_security(ieee->dev, &sec);
 803
 804         if (ieee->reset_on_keychange &&
 805            ieee->iw_mode != IW_MODE_INFRA &&
 806            ieee->reset_port && ieee->reset_port(dev)) {
 807                IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
 808                return -EINVAL;
 809        }
 810#endif
 811        return ret;
 812}
 813
 814int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee,
 815                               struct iw_request_info *info,
 816                               union iwreq_data *wrqu, char *extra)
 817{
 818        struct iw_point *encoding = &wrqu->encoding;
 819        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 820        struct ieee80211_crypt_data *crypt;
 821        int idx, max_key_len;
 822
 823        max_key_len = encoding->length - sizeof(*ext);
 824        if (max_key_len < 0)
 825                return -EINVAL;
 826
 827        idx = encoding->flags & IW_ENCODE_INDEX;
 828        if (idx) {
 829                if (idx < 1 || idx > WEP_KEYS)
 830                        return -EINVAL;
 831                idx--;
 832        } else
 833                idx = ieee->tx_keyidx;
 834
 835        if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
 836            ext->alg != IW_ENCODE_ALG_WEP)
 837                if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
 838                        return -EINVAL;
 839
 840        crypt = ieee->crypt[idx];
 841        encoding->flags = idx + 1;
 842        memset(ext, 0, sizeof(*ext));
 843
 844        if (crypt == NULL || crypt->ops == NULL ) {
 845                ext->alg = IW_ENCODE_ALG_NONE;
 846                ext->key_len = 0;
 847                encoding->flags |= IW_ENCODE_DISABLED;
 848        } else {
 849                if (strcmp(crypt->ops->name, "WEP") == 0 )
 850                        ext->alg = IW_ENCODE_ALG_WEP;
 851                else if (strcmp(crypt->ops->name, "TKIP"))
 852                        ext->alg = IW_ENCODE_ALG_TKIP;
 853                else if (strcmp(crypt->ops->name, "CCMP"))
 854                        ext->alg = IW_ENCODE_ALG_CCMP;
 855                else
 856                        return -EINVAL;
 857                ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv);
 858                encoding->flags |= IW_ENCODE_ENABLED;
 859                if (ext->key_len &&
 860                    (ext->alg == IW_ENCODE_ALG_TKIP ||
 861                     ext->alg == IW_ENCODE_ALG_CCMP))
 862                        ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
 863
 864        }
 865
 866        return 0;
 867}
 868
 869int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
 870                               struct iw_request_info *info,
 871                               union iwreq_data *wrqu, char *extra)
 872{
 873#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
 874        struct iw_mlme *mlme = (struct iw_mlme *) extra;
 875        switch (mlme->cmd) {
 876        case IW_MLME_DEAUTH:
 877        case IW_MLME_DISASSOC:
 878                ieee80211_disassociate(ieee);
 879                break;
 880         default:
 881                return -EOPNOTSUPP;
 882        }
 883#endif
 884        return 0;
 885}
 886
 887int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
 888                               struct iw_request_info *info,
 889                               struct iw_param *data, char *extra)
 890{
 891#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
 892        switch (data->flags & IW_AUTH_INDEX) {
 893        case IW_AUTH_WPA_VERSION:
 894             /*need to support wpa2 here*/
 895                //printk("wpa version:%x\n", data->value);
 896                break;
 897        case IW_AUTH_CIPHER_PAIRWISE:
 898        case IW_AUTH_CIPHER_GROUP:
 899        case IW_AUTH_KEY_MGMT:
 900                /*
 901 *                  * Host AP driver does not use these parameters and allows
 902 *                                   * wpa_supplicant to control them internally.
 903 *                                                    */
 904                break;
 905        case IW_AUTH_TKIP_COUNTERMEASURES:
 906                ieee->tkip_countermeasures = data->value;
 907                break;
 908        case IW_AUTH_DROP_UNENCRYPTED:
 909                ieee->drop_unencrypted = data->value;
 910                break;
 911
 912        case IW_AUTH_80211_AUTH_ALG:
 913                //printk("======>%s():data->value is %d\n",__FUNCTION__,data->value);
 914        //      ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0;
 915                if(data->value & IW_AUTH_ALG_SHARED_KEY){
 916                        ieee->open_wep = 0;
 917                        ieee->auth_mode = 1;
 918                }
 919                else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){
 920                        ieee->open_wep = 1;
 921                        ieee->auth_mode = 0;
 922                }
 923                else if(data->value & IW_AUTH_ALG_LEAP){
 924                        ieee->open_wep = 1;
 925                        ieee->auth_mode = 2;
 926                        //printk("hahahaa:LEAP\n");
 927                }
 928                else
 929                        return -EINVAL;
 930                //printk("open_wep:%d\n", ieee->open_wep);
 931                break;
 932
 933#if 1
 934        case IW_AUTH_WPA_ENABLED:
 935                ieee->wpa_enabled = (data->value)?1:0;
 936                //printk("enalbe wpa:%d\n", ieee->wpa_enabled);
 937                break;
 938
 939#endif
 940        case IW_AUTH_RX_UNENCRYPTED_EAPOL:
 941                ieee->ieee802_1x = data->value;
 942                break;
 943        case IW_AUTH_PRIVACY_INVOKED:
 944                ieee->privacy_invoked = data->value;
 945                break;
 946        default:
 947                return -EOPNOTSUPP;
 948        }
 949#endif
 950        return 0;
 951}
 952#endif
 953#if 1
 954int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
 955{
 956#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
 957#if 0
 958        printk("====>%s()\n", __FUNCTION__);
 959        {
 960                int i;
 961                for (i=0; i<len; i++)
 962                printk("%2x ", ie[i]&0xff);
 963                printk("\n");
 964        }
 965#endif
 966        u8 *buf;
 967
 968        if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
 969        {
 970        //      printk("return error out, len:%d\n", len);
 971        return -EINVAL;
 972        }
 973
 974
 975        if (len)
 976        {
 977                if (len != ie[1]+2)
 978                {
 979                        printk("len:%d, ie:%d\n", len, ie[1]);
 980                        return -EINVAL;
 981                }
 982                buf = kmalloc(len, GFP_KERNEL);
 983                if (buf == NULL)
 984                        return -ENOMEM;
 985                memcpy(buf, ie, len);
 986                kfree(ieee->wpa_ie);
 987                ieee->wpa_ie = buf;
 988                ieee->wpa_ie_len = len;
 989        }
 990        else{
 991                if (ieee->wpa_ie)
 992                kfree(ieee->wpa_ie);
 993                ieee->wpa_ie = NULL;
 994                ieee->wpa_ie_len = 0;
 995        }
 996#endif
 997        return 0;
 998
 999}
1000#endif
1001
1002#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1003//EXPORT_SYMBOL(ieee80211_wx_set_gen_ie);
1004#if (WIRELESS_EXT >= 18)
1005//EXPORT_SYMBOL(ieee80211_wx_set_mlme);
1006//EXPORT_SYMBOL(ieee80211_wx_set_auth);
1007//EXPORT_SYMBOL(ieee80211_wx_set_encode_ext);
1008//EXPORT_SYMBOL(ieee80211_wx_get_encode_ext);
1009#endif
1010//EXPORT_SYMBOL(ieee80211_wx_get_scan);
1011//EXPORT_SYMBOL(ieee80211_wx_set_encode);
1012//EXPORT_SYMBOL(ieee80211_wx_get_encode);
1013#else
1014//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_gen_ie);
1015//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_mlme);
1016//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_auth);
1017//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_encode_ext);
1018//EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_scan);
1019//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_encode);
1020//EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_encode);
1021#endif
1022