linux/drivers/staging/rtl8192u/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/kmod.h>
  34#include <linux/slab.h>
  35#include <linux/module.h>
  36
  37#include "ieee80211.h"
  38struct modes_unit {
  39        char *mode_string;
  40        int mode_size;
  41};
  42static struct modes_unit ieee80211_modes[] = {
  43        {"a", 1},
  44        {"b", 1},
  45        {"g", 1},
  46        {"?", 1},
  47        {"N-24G", 5},
  48        {"N-5G", 4},
  49};
  50
  51#define iwe_stream_add_event_rsl iwe_stream_add_event
  52
  53#define MAX_CUSTOM_LEN 64
  54static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
  55                                           char *start, char *stop,
  56                                           struct ieee80211_network *network,
  57                                           struct iw_request_info *info)
  58{
  59        char custom[MAX_CUSTOM_LEN];
  60        char proto_name[IFNAMSIZ];
  61        char *pname = proto_name;
  62        char *p;
  63        struct iw_event iwe;
  64        int i, j;
  65        u16 max_rate, rate;
  66        static u8       EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33};
  67
  68        /* First entry *MUST* be the AP MAC address */
  69        iwe.cmd = SIOCGIWAP;
  70        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
  71        memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
  72        start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_ADDR_LEN);
  73        /* Remaining entries will be displayed in the order we provide them */
  74
  75        /* Add the ESSID */
  76        iwe.cmd = SIOCGIWESSID;
  77        iwe.u.data.flags = 1;
  78//      if (network->flags & NETWORK_EMPTY_ESSID) {
  79        if (network->ssid_len == 0) {
  80                iwe.u.data.length = sizeof("<hidden>");
  81                start = iwe_stream_add_point(info, start, stop, &iwe, "<hidden>");
  82        } else {
  83                iwe.u.data.length = min(network->ssid_len, (u8)32);
  84                start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
  85        }
  86        /* Add the protocol name */
  87        iwe.cmd = SIOCGIWNAME;
  88        for(i=0; i<ARRAY_SIZE(ieee80211_modes); i++) {
  89                if(network->mode&(1<<i)) {
  90                        sprintf(pname,ieee80211_modes[i].mode_string,ieee80211_modes[i].mode_size);
  91                        pname +=ieee80211_modes[i].mode_size;
  92                }
  93        }
  94        *pname = '\0';
  95        snprintf(iwe.u.name, IFNAMSIZ, "IEEE802.11%s", proto_name);
  96        start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_CHAR_LEN);
  97        /* Add mode */
  98        iwe.cmd = SIOCGIWMODE;
  99        if (network->capability &
 100            (WLAN_CAPABILITY_BSS | WLAN_CAPABILITY_IBSS)) {
 101                if (network->capability & WLAN_CAPABILITY_BSS)
 102                        iwe.u.mode = IW_MODE_MASTER;
 103                else
 104                        iwe.u.mode = IW_MODE_ADHOC;
 105                start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_UINT_LEN);
 106        }
 107
 108        /* Add frequency/channel */
 109        iwe.cmd = SIOCGIWFREQ;
 110/*      iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
 111        iwe.u.freq.e = 3; */
 112        iwe.u.freq.m = network->channel;
 113        iwe.u.freq.e = 0;
 114        iwe.u.freq.i = 0;
 115        start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_FREQ_LEN);
 116        /* Add encryption capability */
 117        iwe.cmd = SIOCGIWENCODE;
 118        if (network->capability & WLAN_CAPABILITY_PRIVACY)
 119                iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
 120        else
 121                iwe.u.data.flags = IW_ENCODE_DISABLED;
 122        iwe.u.data.length = 0;
 123        start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
 124        /* Add basic and extended rates */
 125        max_rate = 0;
 126        p = custom;
 127        p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
 128        for (i = 0, j = 0; i < network->rates_len; ) {
 129                if (j < network->rates_ex_len &&
 130                    ((network->rates_ex[j] & 0x7F) <
 131                     (network->rates[i] & 0x7F)))
 132                        rate = network->rates_ex[j++] & 0x7F;
 133                else
 134                        rate = network->rates[i++] & 0x7F;
 135                if (rate > max_rate)
 136                        max_rate = rate;
 137                p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
 138                              "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
 139        }
 140        for (; j < network->rates_ex_len; j++) {
 141                rate = network->rates_ex[j] & 0x7F;
 142                p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
 143                              "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
 144                if (rate > max_rate)
 145                        max_rate = rate;
 146        }
 147
 148        if (network->mode >= IEEE_N_24G)//add N rate here;
 149        {
 150                PHT_CAPABILITY_ELE ht_cap = NULL;
 151                bool is40M = false, isShortGI = false;
 152                u8 max_mcs = 0;
 153                if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4))
 154                        ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[4];
 155                else
 156                        ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[0];
 157                is40M = (ht_cap->ChlWidth)?1:0;
 158                isShortGI = (ht_cap->ChlWidth)?
 159                                                ((ht_cap->ShortGI40Mhz)?1:0):
 160                                                ((ht_cap->ShortGI20Mhz)?1:0);
 161
 162                max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS, MCS_FILTER_ALL);
 163                rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs&0x7f];
 164                if (rate > max_rate)
 165                        max_rate = rate;
 166        }
 167        iwe.cmd = SIOCGIWRATE;
 168        iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
 169        iwe.u.bitrate.value = max_rate * 500000;
 170        start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
 171                                     IW_EV_PARAM_LEN);
 172        iwe.cmd = IWEVCUSTOM;
 173        iwe.u.data.length = p - custom;
 174        if (iwe.u.data.length)
 175                start = iwe_stream_add_point(info, start, stop, &iwe, custom);
 176        /* Add quality statistics */
 177        /* TODO: Fix these values... */
 178        iwe.cmd = IWEVQUAL;
 179        iwe.u.qual.qual = network->stats.signal;
 180        iwe.u.qual.level = network->stats.rssi;
 181        iwe.u.qual.noise = network->stats.noise;
 182        iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK;
 183        if (!(network->stats.mask & IEEE80211_STATMASK_RSSI))
 184                iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
 185        if (!(network->stats.mask & IEEE80211_STATMASK_NOISE))
 186                iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
 187        if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL))
 188                iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
 189        iwe.u.qual.updated = 7;
 190        start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_QUAL_LEN);
 191        iwe.cmd = IWEVCUSTOM;
 192        p = custom;
 193
 194        iwe.u.data.length = p - custom;
 195        if (iwe.u.data.length)
 196            start = iwe_stream_add_point(info, start, stop, &iwe, custom);
 197
 198        if (ieee->wpa_enabled && network->wpa_ie_len){
 199                char buf[MAX_WPA_IE_LEN * 2 + 30];
 200        //      printk("WPA IE\n");
 201                u8 *p = buf;
 202                p += sprintf(p, "wpa_ie=");
 203                for (i = 0; i < network->wpa_ie_len; i++) {
 204                        p += sprintf(p, "%02x", network->wpa_ie[i]);
 205                }
 206
 207                memset(&iwe, 0, sizeof(iwe));
 208                iwe.cmd = IWEVCUSTOM;
 209                iwe.u.data.length = strlen(buf);
 210                start = iwe_stream_add_point(info, start, stop, &iwe, buf);
 211        }
 212
 213        if (ieee->wpa_enabled && network->rsn_ie_len){
 214                char buf[MAX_WPA_IE_LEN * 2 + 30];
 215
 216                u8 *p = buf;
 217                p += sprintf(p, "rsn_ie=");
 218                for (i = 0; i < network->rsn_ie_len; i++) {
 219                        p += sprintf(p, "%02x", network->rsn_ie[i]);
 220                }
 221
 222                memset(&iwe, 0, sizeof(iwe));
 223                iwe.cmd = IWEVCUSTOM;
 224                iwe.u.data.length = strlen(buf);
 225                start = iwe_stream_add_point(info, start, stop, &iwe, buf);
 226        }
 227
 228
 229        /* Add EXTRA: Age to display seconds since last beacon/probe response
 230         * for given network. */
 231        iwe.cmd = IWEVCUSTOM;
 232        p = custom;
 233        p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
 234                      " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100));
 235        iwe.u.data.length = p - custom;
 236        if (iwe.u.data.length)
 237            start = iwe_stream_add_point(info, start, stop, &iwe, custom);
 238
 239        return start;
 240}
 241
 242int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
 243                          struct iw_request_info *info,
 244                          union iwreq_data *wrqu, char *extra)
 245{
 246        struct ieee80211_network *network;
 247        unsigned long flags;
 248
 249        char *ev = extra;
 250//      char *stop = ev + IW_SCAN_MAX_DATA;
 251        char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA;
 252        //char *stop = ev + IW_SCAN_MAX_DATA;
 253        int i = 0;
 254        int err = 0;
 255        IEEE80211_DEBUG_WX("Getting scan\n");
 256        mutex_lock(&ieee->wx_mutex);
 257        spin_lock_irqsave(&ieee->lock, flags);
 258
 259        list_for_each_entry(network, &ieee->network_list, list) {
 260                i++;
 261                if((stop-ev)<200)
 262                {
 263                        err = -E2BIG;
 264                        break;
 265                }
 266                if (ieee->scan_age == 0 ||
 267                    time_after(network->last_scanned + ieee->scan_age, jiffies))
 268                        ev = rtl819x_translate_scan(ieee, ev, stop, network, info);
 269                else
 270                        IEEE80211_DEBUG_SCAN(
 271                                "Not showing network '%s ("
 272                                "%pM)' due to age (%lums).\n",
 273                                escape_essid(network->ssid,
 274                                             network->ssid_len),
 275                                network->bssid,
 276                                (jiffies - network->last_scanned) / (HZ / 100));
 277        }
 278
 279        spin_unlock_irqrestore(&ieee->lock, flags);
 280        mutex_unlock(&ieee->wx_mutex);
 281        wrqu->data.length = ev -  extra;
 282        wrqu->data.flags = 0;
 283
 284        IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
 285
 286        return err;
 287}
 288EXPORT_SYMBOL(ieee80211_wx_get_scan);
 289
 290int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
 291                            struct iw_request_info *info,
 292                            union iwreq_data *wrqu, char *keybuf)
 293{
 294        struct iw_point *erq = &(wrqu->encoding);
 295        struct net_device *dev = ieee->dev;
 296        struct ieee80211_security sec = {
 297                .flags = 0
 298        };
 299        int i, key, key_provided, len;
 300        struct ieee80211_crypt_data **crypt;
 301
 302        IEEE80211_DEBUG_WX("SET_ENCODE\n");
 303
 304        key = erq->flags & IW_ENCODE_INDEX;
 305        if (key) {
 306                if (key > WEP_KEYS)
 307                        return -EINVAL;
 308                key--;
 309                key_provided = 1;
 310        } else {
 311                key_provided = 0;
 312                key = ieee->tx_keyidx;
 313        }
 314
 315        IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
 316                           "provided" : "default");
 317        crypt = &ieee->crypt[key];
 318
 319        if (erq->flags & IW_ENCODE_DISABLED) {
 320                if (key_provided && *crypt) {
 321                        IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
 322                                           key);
 323                        ieee80211_crypt_delayed_deinit(ieee, crypt);
 324                } else
 325                        IEEE80211_DEBUG_WX("Disabling encryption.\n");
 326
 327                /* Check all the keys to see if any are still configured,
 328                 * and if no key index was provided, de-init them all */
 329                for (i = 0; i < WEP_KEYS; i++) {
 330                        if (ieee->crypt[i] != NULL) {
 331                                if (key_provided)
 332                                        break;
 333                                ieee80211_crypt_delayed_deinit(
 334                                        ieee, &ieee->crypt[i]);
 335                        }
 336                }
 337
 338                if (i == WEP_KEYS) {
 339                        sec.enabled = 0;
 340                        sec.level = SEC_LEVEL_0;
 341                        sec.flags |= SEC_ENABLED | SEC_LEVEL;
 342                }
 343
 344                goto done;
 345        }
 346
 347
 348
 349        sec.enabled = 1;
 350        sec.flags |= SEC_ENABLED;
 351
 352        if (*crypt != NULL && (*crypt)->ops != NULL &&
 353            strcmp((*crypt)->ops->name, "WEP") != 0) {
 354                /* changing to use WEP; deinit previously used algorithm
 355                 * on this key */
 356                ieee80211_crypt_delayed_deinit(ieee, crypt);
 357        }
 358
 359        if (*crypt == NULL) {
 360                struct ieee80211_crypt_data *new_crypt;
 361
 362                /* take WEP into use */
 363                new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
 364                                    GFP_KERNEL);
 365                if (new_crypt == NULL)
 366                        return -ENOMEM;
 367                new_crypt->ops = ieee80211_get_crypto_ops("WEP");
 368                if (!new_crypt->ops) {
 369                        request_module("ieee80211_crypt_wep");
 370                        new_crypt->ops = ieee80211_get_crypto_ops("WEP");
 371                }
 372                if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
 373                        new_crypt->priv = new_crypt->ops->init(key);
 374
 375                if (!new_crypt->ops || !new_crypt->priv) {
 376                        kfree(new_crypt);
 377                        new_crypt = NULL;
 378
 379                        printk(KERN_WARNING "%s: could not initialize WEP: "
 380                               "load module ieee80211_crypt_wep\n",
 381                               dev->name);
 382                        return -EOPNOTSUPP;
 383                }
 384                *crypt = new_crypt;
 385        }
 386
 387        /* If a new key was provided, set it up */
 388        if (erq->length > 0) {
 389                len = erq->length <= 5 ? 5 : 13;
 390                memcpy(sec.keys[key], keybuf, erq->length);
 391                if (len > erq->length)
 392                        memset(sec.keys[key] + erq->length, 0,
 393                               len - erq->length);
 394                IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
 395                                   key, escape_essid(sec.keys[key], len),
 396                                   erq->length, len);
 397                sec.key_sizes[key] = len;
 398                (*crypt)->ops->set_key(sec.keys[key], len, NULL,
 399                                       (*crypt)->priv);
 400                sec.flags |= (1 << key);
 401                /* This ensures a key will be activated if no key is
 402                 * explicitely set */
 403                if (key == sec.active_key)
 404                        sec.flags |= SEC_ACTIVE_KEY;
 405                ieee->tx_keyidx = key;
 406
 407        } else {
 408                len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
 409                                             NULL, (*crypt)->priv);
 410                if (len == 0) {
 411                        /* Set a default key of all 0 */
 412                        printk("Setting key %d to all zero.\n",
 413                                           key);
 414
 415                        IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
 416                                           key);
 417                        memset(sec.keys[key], 0, 13);
 418                        (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
 419                                               (*crypt)->priv);
 420                        sec.key_sizes[key] = 13;
 421                        sec.flags |= (1 << key);
 422                }
 423
 424                /* No key data - just set the default TX key index */
 425                if (key_provided) {
 426                        IEEE80211_DEBUG_WX(
 427                                "Setting key %d to default Tx key.\n", key);
 428                        ieee->tx_keyidx = key;
 429                        sec.active_key = key;
 430                        sec.flags |= SEC_ACTIVE_KEY;
 431                }
 432        }
 433
 434 done:
 435        ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
 436        ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
 437        sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
 438        sec.flags |= SEC_AUTH_MODE;
 439        IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
 440                           "OPEN" : "SHARED KEY");
 441
 442        /* For now we just support WEP, so only set that security level...
 443         * TODO: When WPA is added this is one place that needs to change */
 444        sec.flags |= SEC_LEVEL;
 445        sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
 446
 447        if (ieee->set_security)
 448                ieee->set_security(dev, &sec);
 449
 450        /* Do not reset port if card is in Managed mode since resetting will
 451         * generate new IEEE 802.11 authentication which may end up in looping
 452         * with IEEE 802.1X.  If your hardware requires a reset after WEP
 453         * configuration (for example... Prism2), implement the reset_port in
 454         * the callbacks structures used to initialize the 802.11 stack. */
 455        if (ieee->reset_on_keychange &&
 456            ieee->iw_mode != IW_MODE_INFRA &&
 457            ieee->reset_port && ieee->reset_port(dev)) {
 458                printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
 459                return -EINVAL;
 460        }
 461        return 0;
 462}
 463EXPORT_SYMBOL(ieee80211_wx_set_encode);
 464
 465int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
 466                            struct iw_request_info *info,
 467                            union iwreq_data *wrqu, char *keybuf)
 468{
 469        struct iw_point *erq = &(wrqu->encoding);
 470        int len, key;
 471        struct ieee80211_crypt_data *crypt;
 472
 473        IEEE80211_DEBUG_WX("GET_ENCODE\n");
 474
 475        if(ieee->iw_mode == IW_MODE_MONITOR)
 476                return -1;
 477
 478        key = erq->flags & IW_ENCODE_INDEX;
 479        if (key) {
 480                if (key > WEP_KEYS)
 481                        return -EINVAL;
 482                key--;
 483        } else
 484                key = ieee->tx_keyidx;
 485
 486        crypt = ieee->crypt[key];
 487        erq->flags = key + 1;
 488
 489        if (crypt == NULL || crypt->ops == NULL) {
 490                erq->length = 0;
 491                erq->flags |= IW_ENCODE_DISABLED;
 492                return 0;
 493        }
 494        len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
 495        erq->length = (len >= 0 ? len : 0);
 496
 497        erq->flags |= IW_ENCODE_ENABLED;
 498
 499        if (ieee->open_wep)
 500                erq->flags |= IW_ENCODE_OPEN;
 501        else
 502                erq->flags |= IW_ENCODE_RESTRICTED;
 503
 504        return 0;
 505}
 506EXPORT_SYMBOL(ieee80211_wx_get_encode);
 507
 508int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
 509                               struct iw_request_info *info,
 510                               union iwreq_data *wrqu, char *extra)
 511{
 512        int ret = 0;
 513        struct net_device *dev = ieee->dev;
 514        struct iw_point *encoding = &wrqu->encoding;
 515        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 516        int i, idx;
 517        int group_key = 0;
 518        const char *alg, *module;
 519        struct ieee80211_crypto_ops *ops;
 520        struct ieee80211_crypt_data **crypt;
 521
 522        struct ieee80211_security sec = {
 523                .flags = 0,
 524        };
 525        idx = encoding->flags & IW_ENCODE_INDEX;
 526        if (idx) {
 527                if (idx < 1 || idx > WEP_KEYS)
 528                        return -EINVAL;
 529                idx--;
 530        } else
 531                idx = ieee->tx_keyidx;
 532
 533        if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
 534
 535                crypt = &ieee->crypt[idx];
 536
 537                group_key = 1;
 538        } else {
 539                /* some Cisco APs use idx>0 for unicast in dynamic WEP */
 540                if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
 541                        return -EINVAL;
 542                if (ieee->iw_mode == IW_MODE_INFRA)
 543
 544                        crypt = &ieee->crypt[idx];
 545
 546                else
 547                        return -EINVAL;
 548        }
 549
 550        sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT;
 551        if ((encoding->flags & IW_ENCODE_DISABLED) ||
 552            ext->alg == IW_ENCODE_ALG_NONE) {
 553                if (*crypt)
 554                        ieee80211_crypt_delayed_deinit(ieee, crypt);
 555
 556                for (i = 0; i < WEP_KEYS; i++)
 557
 558                        if (ieee->crypt[i] != NULL)
 559
 560                                break;
 561
 562                if (i == WEP_KEYS) {
 563                        sec.enabled = 0;
 564                      //  sec.encrypt = 0;
 565                        sec.level = SEC_LEVEL_0;
 566                        sec.flags |= SEC_LEVEL;
 567                }
 568                goto done;
 569        }
 570
 571        sec.enabled = 1;
 572    //    sec.encrypt = 1;
 573        switch (ext->alg) {
 574        case IW_ENCODE_ALG_WEP:
 575                alg = "WEP";
 576                module = "ieee80211_crypt_wep";
 577                break;
 578        case IW_ENCODE_ALG_TKIP:
 579                alg = "TKIP";
 580                module = "ieee80211_crypt_tkip";
 581                break;
 582        case IW_ENCODE_ALG_CCMP:
 583                alg = "CCMP";
 584                module = "ieee80211_crypt_ccmp";
 585                break;
 586        default:
 587                IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
 588                                   dev->name, ext->alg);
 589                ret = -EINVAL;
 590                goto done;
 591        }
 592        printk("alg name:%s\n",alg);
 593
 594         ops = ieee80211_get_crypto_ops(alg);
 595        if (ops == NULL) {
 596                request_module(module);
 597                ops = ieee80211_get_crypto_ops(alg);
 598        }
 599        if (ops == NULL) {
 600                IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
 601                                   dev->name, ext->alg);
 602                printk("========>unknown crypto alg %d\n", ext->alg);
 603                ret = -EINVAL;
 604                goto done;
 605        }
 606
 607        if (*crypt == NULL || (*crypt)->ops != ops) {
 608                struct ieee80211_crypt_data *new_crypt;
 609
 610                ieee80211_crypt_delayed_deinit(ieee, crypt);
 611
 612                new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
 613                if (new_crypt == NULL) {
 614                        ret = -ENOMEM;
 615                        goto done;
 616                }
 617                new_crypt->ops = ops;
 618                if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
 619                        new_crypt->priv = new_crypt->ops->init(idx);
 620                if (new_crypt->priv == NULL) {
 621                        kfree(new_crypt);
 622                        ret = -EINVAL;
 623                        goto done;
 624                }
 625                *crypt = new_crypt;
 626
 627        }
 628
 629        if (ext->key_len > 0 && (*crypt)->ops->set_key &&
 630            (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
 631                                   (*crypt)->priv) < 0) {
 632                IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
 633                printk("key setting failed\n");
 634                ret = -EINVAL;
 635                goto done;
 636        }
 637 //skip_host_crypt:
 638        if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
 639                ieee->tx_keyidx = idx;
 640                sec.active_key = idx;
 641                sec.flags |= SEC_ACTIVE_KEY;
 642        }
 643
 644        if (ext->alg != IW_ENCODE_ALG_NONE) {
 645                //memcpy(sec.keys[idx], ext->key, ext->key_len);
 646                sec.key_sizes[idx] = ext->key_len;
 647                sec.flags |= (1 << idx);
 648                if (ext->alg == IW_ENCODE_ALG_WEP) {
 649                      //  sec.encode_alg[idx] = SEC_ALG_WEP;
 650                        sec.flags |= SEC_LEVEL;
 651                        sec.level = SEC_LEVEL_1;
 652                } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
 653                      //  sec.encode_alg[idx] = SEC_ALG_TKIP;
 654                        sec.flags |= SEC_LEVEL;
 655                        sec.level = SEC_LEVEL_2;
 656                } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
 657                       // sec.encode_alg[idx] = SEC_ALG_CCMP;
 658                        sec.flags |= SEC_LEVEL;
 659                        sec.level = SEC_LEVEL_3;
 660                }
 661                /* Don't set sec level for group keys. */
 662                if (group_key)
 663                        sec.flags &= ~SEC_LEVEL;
 664        }
 665done:
 666        if (ieee->set_security)
 667                ieee->set_security(ieee->dev, &sec);
 668
 669         if (ieee->reset_on_keychange &&
 670            ieee->iw_mode != IW_MODE_INFRA &&
 671            ieee->reset_port && ieee->reset_port(dev)) {
 672                IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
 673                return -EINVAL;
 674        }
 675        return ret;
 676}
 677EXPORT_SYMBOL(ieee80211_wx_set_encode_ext);
 678
 679int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee,
 680                               struct iw_request_info *info,
 681                               union iwreq_data *wrqu, char *extra)
 682{
 683        struct iw_point *encoding = &wrqu->encoding;
 684        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 685        struct ieee80211_crypt_data *crypt;
 686        int idx, max_key_len;
 687
 688        max_key_len = encoding->length - sizeof(*ext);
 689        if (max_key_len < 0)
 690                return -EINVAL;
 691
 692        idx = encoding->flags & IW_ENCODE_INDEX;
 693        if (idx) {
 694                if (idx < 1 || idx > WEP_KEYS)
 695                        return -EINVAL;
 696                idx--;
 697        } else
 698                idx = ieee->tx_keyidx;
 699
 700        if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
 701            ext->alg != IW_ENCODE_ALG_WEP)
 702                if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
 703                        return -EINVAL;
 704
 705        crypt = ieee->crypt[idx];
 706        encoding->flags = idx + 1;
 707        memset(ext, 0, sizeof(*ext));
 708
 709        if (crypt == NULL || crypt->ops == NULL ) {
 710                ext->alg = IW_ENCODE_ALG_NONE;
 711                ext->key_len = 0;
 712                encoding->flags |= IW_ENCODE_DISABLED;
 713        } else {
 714                if (strcmp(crypt->ops->name, "WEP") == 0 )
 715                        ext->alg = IW_ENCODE_ALG_WEP;
 716                else if (strcmp(crypt->ops->name, "TKIP"))
 717                        ext->alg = IW_ENCODE_ALG_TKIP;
 718                else if (strcmp(crypt->ops->name, "CCMP"))
 719                        ext->alg = IW_ENCODE_ALG_CCMP;
 720                else
 721                        return -EINVAL;
 722                ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv);
 723                encoding->flags |= IW_ENCODE_ENABLED;
 724                if (ext->key_len &&
 725                    (ext->alg == IW_ENCODE_ALG_TKIP ||
 726                     ext->alg == IW_ENCODE_ALG_CCMP))
 727                        ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
 728
 729        }
 730
 731        return 0;
 732}
 733EXPORT_SYMBOL(ieee80211_wx_get_encode_ext);
 734
 735int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
 736                               struct iw_request_info *info,
 737                               union iwreq_data *wrqu, char *extra)
 738{
 739        struct iw_mlme *mlme = (struct iw_mlme *) extra;
 740        switch (mlme->cmd) {
 741        case IW_MLME_DEAUTH:
 742        case IW_MLME_DISASSOC:
 743                ieee80211_disassociate(ieee);
 744                break;
 745        default:
 746                return -EOPNOTSUPP;
 747        }
 748        return 0;
 749}
 750EXPORT_SYMBOL(ieee80211_wx_set_mlme);
 751
 752int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
 753                               struct iw_request_info *info,
 754                               struct iw_param *data, char *extra)
 755{
 756        switch (data->flags & IW_AUTH_INDEX) {
 757        case IW_AUTH_WPA_VERSION:
 758             /*need to support wpa2 here*/
 759                break;
 760        case IW_AUTH_CIPHER_PAIRWISE:
 761        case IW_AUTH_CIPHER_GROUP:
 762        case IW_AUTH_KEY_MGMT:
 763                /*
 764 *                  * Host AP driver does not use these parameters and allows
 765 *                                   * wpa_supplicant to control them internally.
 766 *                                                    */
 767                break;
 768        case IW_AUTH_TKIP_COUNTERMEASURES:
 769                ieee->tkip_countermeasures = data->value;
 770                break;
 771        case IW_AUTH_DROP_UNENCRYPTED:
 772                ieee->drop_unencrypted = data->value;
 773                break;
 774
 775        case IW_AUTH_80211_AUTH_ALG:
 776                //printk("======>%s():data->value is %d\n",__func__,data->value);
 777        //      ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0;
 778                if(data->value & IW_AUTH_ALG_SHARED_KEY){
 779                        ieee->open_wep = 0;
 780                        ieee->auth_mode = 1;
 781                }
 782                else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){
 783                        ieee->open_wep = 1;
 784                        ieee->auth_mode = 0;
 785                }
 786                else if(data->value & IW_AUTH_ALG_LEAP){
 787                        ieee->open_wep = 1;
 788                        ieee->auth_mode = 2;
 789                }
 790                else
 791                        return -EINVAL;
 792                break;
 793
 794        case IW_AUTH_WPA_ENABLED:
 795                ieee->wpa_enabled = (data->value)?1:0;
 796                break;
 797
 798        case IW_AUTH_RX_UNENCRYPTED_EAPOL:
 799                ieee->ieee802_1x = data->value;
 800                break;
 801        case IW_AUTH_PRIVACY_INVOKED:
 802                ieee->privacy_invoked = data->value;
 803                break;
 804        default:
 805                return -EOPNOTSUPP;
 806        }
 807        return 0;
 808}
 809EXPORT_SYMBOL(ieee80211_wx_set_auth);
 810
 811int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
 812{
 813        u8 *buf;
 814
 815        if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
 816        {
 817        //      printk("return error out, len:%d\n", len);
 818        return -EINVAL;
 819        }
 820
 821
 822        if (len)
 823        {
 824                if (len != ie[1]+2)
 825                {
 826                        printk("len:%zu, ie:%d\n", len, ie[1]);
 827                        return -EINVAL;
 828                }
 829                buf = kmemdup(ie, len, GFP_KERNEL);
 830                if (buf == NULL)
 831                        return -ENOMEM;
 832                kfree(ieee->wpa_ie);
 833                ieee->wpa_ie = buf;
 834                ieee->wpa_ie_len = len;
 835        }
 836        else{
 837                kfree(ieee->wpa_ie);
 838                ieee->wpa_ie = NULL;
 839                ieee->wpa_ie_len = 0;
 840        }
 841        return 0;
 842
 843}
 844EXPORT_SYMBOL(ieee80211_wx_set_gen_ie);
 845