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)
 366                        return -ENOMEM;
 367                new_crypt->ops = try_then_request_module(ieee80211_get_crypto_ops("WEP"),
 368                                                         "ieee80211_crypt_wep");
 369                if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
 370                        new_crypt->priv = new_crypt->ops->init(key);
 371
 372                if (!new_crypt->ops || !new_crypt->priv) {
 373                        kfree(new_crypt);
 374                        new_crypt = NULL;
 375
 376                        printk(KERN_WARNING "%s: could not initialize WEP: "
 377                               "load module ieee80211_crypt_wep\n",
 378                               dev->name);
 379                        return -EOPNOTSUPP;
 380                }
 381                *crypt = new_crypt;
 382        }
 383
 384        /* If a new key was provided, set it up */
 385        if (erq->length > 0) {
 386                len = erq->length <= 5 ? 5 : 13;
 387                memcpy(sec.keys[key], keybuf, erq->length);
 388                if (len > erq->length)
 389                        memset(sec.keys[key] + erq->length, 0,
 390                               len - erq->length);
 391                IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
 392                                   key, escape_essid(sec.keys[key], len),
 393                                   erq->length, len);
 394                sec.key_sizes[key] = len;
 395                (*crypt)->ops->set_key(sec.keys[key], len, NULL,
 396                                       (*crypt)->priv);
 397                sec.flags |= (1 << key);
 398                /* This ensures a key will be activated if no key is
 399                 * explicitely set */
 400                if (key == sec.active_key)
 401                        sec.flags |= SEC_ACTIVE_KEY;
 402                ieee->tx_keyidx = key;
 403
 404        } else {
 405                len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
 406                                             NULL, (*crypt)->priv);
 407                if (len == 0) {
 408                        /* Set a default key of all 0 */
 409                        printk("Setting key %d to all zero.\n",
 410                                           key);
 411
 412                        IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
 413                                           key);
 414                        memset(sec.keys[key], 0, 13);
 415                        (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
 416                                               (*crypt)->priv);
 417                        sec.key_sizes[key] = 13;
 418                        sec.flags |= (1 << key);
 419                }
 420
 421                /* No key data - just set the default TX key index */
 422                if (key_provided) {
 423                        IEEE80211_DEBUG_WX(
 424                                "Setting key %d to default Tx key.\n", key);
 425                        ieee->tx_keyidx = key;
 426                        sec.active_key = key;
 427                        sec.flags |= SEC_ACTIVE_KEY;
 428                }
 429        }
 430
 431 done:
 432        ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
 433        ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
 434        sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
 435        sec.flags |= SEC_AUTH_MODE;
 436        IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
 437                           "OPEN" : "SHARED KEY");
 438
 439        /* For now we just support WEP, so only set that security level...
 440         * TODO: When WPA is added this is one place that needs to change */
 441        sec.flags |= SEC_LEVEL;
 442        sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
 443
 444        if (ieee->set_security)
 445                ieee->set_security(dev, &sec);
 446
 447        /* Do not reset port if card is in Managed mode since resetting will
 448         * generate new IEEE 802.11 authentication which may end up in looping
 449         * with IEEE 802.1X.  If your hardware requires a reset after WEP
 450         * configuration (for example... Prism2), implement the reset_port in
 451         * the callbacks structures used to initialize the 802.11 stack. */
 452        if (ieee->reset_on_keychange &&
 453            ieee->iw_mode != IW_MODE_INFRA &&
 454            ieee->reset_port && ieee->reset_port(dev)) {
 455                printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
 456                return -EINVAL;
 457        }
 458        return 0;
 459}
 460EXPORT_SYMBOL(ieee80211_wx_set_encode);
 461
 462int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
 463                            struct iw_request_info *info,
 464                            union iwreq_data *wrqu, char *keybuf)
 465{
 466        struct iw_point *erq = &(wrqu->encoding);
 467        int len, key;
 468        struct ieee80211_crypt_data *crypt;
 469
 470        IEEE80211_DEBUG_WX("GET_ENCODE\n");
 471
 472        if(ieee->iw_mode == IW_MODE_MONITOR)
 473                return -1;
 474
 475        key = erq->flags & IW_ENCODE_INDEX;
 476        if (key) {
 477                if (key > WEP_KEYS)
 478                        return -EINVAL;
 479                key--;
 480        } else
 481                key = ieee->tx_keyidx;
 482
 483        crypt = ieee->crypt[key];
 484        erq->flags = key + 1;
 485
 486        if (crypt == NULL || crypt->ops == NULL) {
 487                erq->length = 0;
 488                erq->flags |= IW_ENCODE_DISABLED;
 489                return 0;
 490        }
 491        len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
 492        erq->length = (len >= 0 ? len : 0);
 493
 494        erq->flags |= IW_ENCODE_ENABLED;
 495
 496        if (ieee->open_wep)
 497                erq->flags |= IW_ENCODE_OPEN;
 498        else
 499                erq->flags |= IW_ENCODE_RESTRICTED;
 500
 501        return 0;
 502}
 503EXPORT_SYMBOL(ieee80211_wx_get_encode);
 504
 505int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
 506                               struct iw_request_info *info,
 507                               union iwreq_data *wrqu, char *extra)
 508{
 509        int ret = 0;
 510        struct net_device *dev = ieee->dev;
 511        struct iw_point *encoding = &wrqu->encoding;
 512        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 513        int i, idx;
 514        int group_key = 0;
 515        const char *alg, *module;
 516        struct ieee80211_crypto_ops *ops;
 517        struct ieee80211_crypt_data **crypt;
 518
 519        struct ieee80211_security sec = {
 520                .flags = 0,
 521        };
 522        idx = encoding->flags & IW_ENCODE_INDEX;
 523        if (idx) {
 524                if (idx < 1 || idx > WEP_KEYS)
 525                        return -EINVAL;
 526                idx--;
 527        } else
 528                idx = ieee->tx_keyidx;
 529
 530        if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
 531
 532                crypt = &ieee->crypt[idx];
 533
 534                group_key = 1;
 535        } else {
 536                /* some Cisco APs use idx>0 for unicast in dynamic WEP */
 537                if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
 538                        return -EINVAL;
 539                if (ieee->iw_mode == IW_MODE_INFRA)
 540
 541                        crypt = &ieee->crypt[idx];
 542
 543                else
 544                        return -EINVAL;
 545        }
 546
 547        sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT;
 548        if ((encoding->flags & IW_ENCODE_DISABLED) ||
 549            ext->alg == IW_ENCODE_ALG_NONE) {
 550                if (*crypt)
 551                        ieee80211_crypt_delayed_deinit(ieee, crypt);
 552
 553                for (i = 0; i < WEP_KEYS; i++)
 554
 555                        if (ieee->crypt[i] != NULL)
 556
 557                                break;
 558
 559                if (i == WEP_KEYS) {
 560                        sec.enabled = 0;
 561                      //  sec.encrypt = 0;
 562                        sec.level = SEC_LEVEL_0;
 563                        sec.flags |= SEC_LEVEL;
 564                }
 565                goto done;
 566        }
 567
 568        sec.enabled = 1;
 569    //    sec.encrypt = 1;
 570        switch (ext->alg) {
 571        case IW_ENCODE_ALG_WEP:
 572                alg = "WEP";
 573                module = "ieee80211_crypt_wep";
 574                break;
 575        case IW_ENCODE_ALG_TKIP:
 576                alg = "TKIP";
 577                module = "ieee80211_crypt_tkip";
 578                break;
 579        case IW_ENCODE_ALG_CCMP:
 580                alg = "CCMP";
 581                module = "ieee80211_crypt_ccmp";
 582                break;
 583        default:
 584                IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
 585                                   dev->name, ext->alg);
 586                ret = -EINVAL;
 587                goto done;
 588        }
 589        printk("alg name:%s\n",alg);
 590
 591        ops = try_then_request_module(ieee80211_get_crypto_ops(alg), module);
 592        if (!ops) {
 593                IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
 594                                   dev->name, ext->alg);
 595                printk("========>unknown crypto alg %d\n", ext->alg);
 596                ret = -EINVAL;
 597                goto done;
 598        }
 599
 600        if (*crypt == NULL || (*crypt)->ops != ops) {
 601                struct ieee80211_crypt_data *new_crypt;
 602
 603                ieee80211_crypt_delayed_deinit(ieee, crypt);
 604
 605                new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
 606                if (!new_crypt) {
 607                        ret = -ENOMEM;
 608                        goto done;
 609                }
 610                new_crypt->ops = ops;
 611                if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
 612                        new_crypt->priv = new_crypt->ops->init(idx);
 613                if (new_crypt->priv == NULL) {
 614                        kfree(new_crypt);
 615                        ret = -EINVAL;
 616                        goto done;
 617                }
 618                *crypt = new_crypt;
 619        }
 620
 621        if (ext->key_len > 0 && (*crypt)->ops->set_key &&
 622            (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
 623                                   (*crypt)->priv) < 0) {
 624                IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
 625                printk("key setting failed\n");
 626                ret = -EINVAL;
 627                goto done;
 628        }
 629 //skip_host_crypt:
 630        if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
 631                ieee->tx_keyidx = idx;
 632                sec.active_key = idx;
 633                sec.flags |= SEC_ACTIVE_KEY;
 634        }
 635
 636        if (ext->alg != IW_ENCODE_ALG_NONE) {
 637                //memcpy(sec.keys[idx], ext->key, ext->key_len);
 638                sec.key_sizes[idx] = ext->key_len;
 639                sec.flags |= (1 << idx);
 640                if (ext->alg == IW_ENCODE_ALG_WEP) {
 641                      //  sec.encode_alg[idx] = SEC_ALG_WEP;
 642                        sec.flags |= SEC_LEVEL;
 643                        sec.level = SEC_LEVEL_1;
 644                } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
 645                      //  sec.encode_alg[idx] = SEC_ALG_TKIP;
 646                        sec.flags |= SEC_LEVEL;
 647                        sec.level = SEC_LEVEL_2;
 648                } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
 649                       // sec.encode_alg[idx] = SEC_ALG_CCMP;
 650                        sec.flags |= SEC_LEVEL;
 651                        sec.level = SEC_LEVEL_3;
 652                }
 653                /* Don't set sec level for group keys. */
 654                if (group_key)
 655                        sec.flags &= ~SEC_LEVEL;
 656        }
 657done:
 658        if (ieee->set_security)
 659                ieee->set_security(ieee->dev, &sec);
 660
 661        if (ieee->reset_on_keychange &&
 662            ieee->iw_mode != IW_MODE_INFRA &&
 663            ieee->reset_port && ieee->reset_port(dev)) {
 664                IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
 665                return -EINVAL;
 666        }
 667        return ret;
 668}
 669EXPORT_SYMBOL(ieee80211_wx_set_encode_ext);
 670
 671int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee,
 672                               struct iw_request_info *info,
 673                               union iwreq_data *wrqu, char *extra)
 674{
 675        struct iw_point *encoding = &wrqu->encoding;
 676        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 677        struct ieee80211_crypt_data *crypt;
 678        int idx, max_key_len;
 679
 680        max_key_len = encoding->length - sizeof(*ext);
 681        if (max_key_len < 0)
 682                return -EINVAL;
 683
 684        idx = encoding->flags & IW_ENCODE_INDEX;
 685        if (idx) {
 686                if (idx < 1 || idx > WEP_KEYS)
 687                        return -EINVAL;
 688                idx--;
 689        } else
 690                idx = ieee->tx_keyidx;
 691
 692        if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
 693            ext->alg != IW_ENCODE_ALG_WEP)
 694                if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
 695                        return -EINVAL;
 696
 697        crypt = ieee->crypt[idx];
 698        encoding->flags = idx + 1;
 699        memset(ext, 0, sizeof(*ext));
 700
 701        if (crypt == NULL || crypt->ops == NULL ) {
 702                ext->alg = IW_ENCODE_ALG_NONE;
 703                ext->key_len = 0;
 704                encoding->flags |= IW_ENCODE_DISABLED;
 705        } else {
 706                if (strcmp(crypt->ops->name, "WEP") == 0 )
 707                        ext->alg = IW_ENCODE_ALG_WEP;
 708                else if (strcmp(crypt->ops->name, "TKIP"))
 709                        ext->alg = IW_ENCODE_ALG_TKIP;
 710                else if (strcmp(crypt->ops->name, "CCMP"))
 711                        ext->alg = IW_ENCODE_ALG_CCMP;
 712                else
 713                        return -EINVAL;
 714                ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv);
 715                encoding->flags |= IW_ENCODE_ENABLED;
 716                if (ext->key_len &&
 717                    (ext->alg == IW_ENCODE_ALG_TKIP ||
 718                     ext->alg == IW_ENCODE_ALG_CCMP))
 719                        ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
 720        }
 721
 722        return 0;
 723}
 724EXPORT_SYMBOL(ieee80211_wx_get_encode_ext);
 725
 726int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
 727                               struct iw_request_info *info,
 728                               union iwreq_data *wrqu, char *extra)
 729{
 730        struct iw_mlme *mlme = (struct iw_mlme *) extra;
 731        switch (mlme->cmd) {
 732        case IW_MLME_DEAUTH:
 733        case IW_MLME_DISASSOC:
 734                ieee80211_disassociate(ieee);
 735                break;
 736        default:
 737                return -EOPNOTSUPP;
 738        }
 739        return 0;
 740}
 741EXPORT_SYMBOL(ieee80211_wx_set_mlme);
 742
 743int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
 744                               struct iw_request_info *info,
 745                               struct iw_param *data, char *extra)
 746{
 747        switch (data->flags & IW_AUTH_INDEX) {
 748        case IW_AUTH_WPA_VERSION:
 749             /*need to support wpa2 here*/
 750                break;
 751        case IW_AUTH_CIPHER_PAIRWISE:
 752        case IW_AUTH_CIPHER_GROUP:
 753        case IW_AUTH_KEY_MGMT:
 754                /*
 755 *                  * Host AP driver does not use these parameters and allows
 756 *                                   * wpa_supplicant to control them internally.
 757 *                                                    */
 758                break;
 759        case IW_AUTH_TKIP_COUNTERMEASURES:
 760                ieee->tkip_countermeasures = data->value;
 761                break;
 762        case IW_AUTH_DROP_UNENCRYPTED:
 763                ieee->drop_unencrypted = data->value;
 764                break;
 765
 766        case IW_AUTH_80211_AUTH_ALG:
 767                //printk("======>%s():data->value is %d\n",__func__,data->value);
 768        //      ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0;
 769                if(data->value & IW_AUTH_ALG_SHARED_KEY){
 770                        ieee->open_wep = 0;
 771                        ieee->auth_mode = 1;
 772                }
 773                else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){
 774                        ieee->open_wep = 1;
 775                        ieee->auth_mode = 0;
 776                }
 777                else if(data->value & IW_AUTH_ALG_LEAP){
 778                        ieee->open_wep = 1;
 779                        ieee->auth_mode = 2;
 780                }
 781                else
 782                        return -EINVAL;
 783                break;
 784
 785        case IW_AUTH_WPA_ENABLED:
 786                ieee->wpa_enabled = (data->value)?1:0;
 787                break;
 788
 789        case IW_AUTH_RX_UNENCRYPTED_EAPOL:
 790                ieee->ieee802_1x = data->value;
 791                break;
 792        case IW_AUTH_PRIVACY_INVOKED:
 793                ieee->privacy_invoked = data->value;
 794                break;
 795        default:
 796                return -EOPNOTSUPP;
 797        }
 798        return 0;
 799}
 800EXPORT_SYMBOL(ieee80211_wx_set_auth);
 801
 802int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
 803{
 804        u8 *buf;
 805
 806        if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
 807        {
 808        //      printk("return error out, len:%d\n", len);
 809        return -EINVAL;
 810        }
 811
 812
 813        if (len)
 814        {
 815                if (len != ie[1]+2)
 816                {
 817                        printk("len:%zu, ie:%d\n", len, ie[1]);
 818                        return -EINVAL;
 819                }
 820                buf = kmemdup(ie, len, GFP_KERNEL);
 821                if (buf == NULL)
 822                        return -ENOMEM;
 823                kfree(ieee->wpa_ie);
 824                ieee->wpa_ie = buf;
 825                ieee->wpa_ie_len = len;
 826        }
 827        else{
 828                kfree(ieee->wpa_ie);
 829                ieee->wpa_ie = NULL;
 830                ieee->wpa_ie_len = 0;
 831        }
 832        return 0;
 833}
 834EXPORT_SYMBOL(ieee80211_wx_set_gen_ie);
 835