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};
  42struct 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#if (WIRELESS_EXT < 18)
 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#else
 228        memset(&iwe, 0, sizeof(iwe));
 229        if (network->wpa_ie_len)
 230        {
 231                char buf[MAX_WPA_IE_LEN];
 232                memcpy(buf, network->wpa_ie, network->wpa_ie_len);
 233                iwe.cmd = IWEVGENIE;
 234                iwe.u.data.length = network->wpa_ie_len;
 235                start = iwe_stream_add_point(info, start, stop, &iwe, buf);
 236        }
 237        memset(&iwe, 0, sizeof(iwe));
 238        if (network->rsn_ie_len)
 239        {
 240                char buf[MAX_WPA_IE_LEN];
 241                memcpy(buf, network->rsn_ie, network->rsn_ie_len);
 242                iwe.cmd = IWEVGENIE;
 243                iwe.u.data.length = network->rsn_ie_len;
 244                start = iwe_stream_add_point(info, start, stop, &iwe, buf);
 245        }
 246#endif
 247
 248
 249        /* Add EXTRA: Age to display seconds since last beacon/probe response
 250         * for given network. */
 251        iwe.cmd = IWEVCUSTOM;
 252        p = custom;
 253        p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
 254                      " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100));
 255        iwe.u.data.length = p - custom;
 256        if (iwe.u.data.length)
 257            start = iwe_stream_add_point(info, start, stop, &iwe, custom);
 258
 259        return start;
 260}
 261
 262int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
 263                          struct iw_request_info *info,
 264                          union iwreq_data *wrqu, char *extra)
 265{
 266        struct ieee80211_network *network;
 267        unsigned long flags;
 268
 269        char *ev = extra;
 270//      char *stop = ev + IW_SCAN_MAX_DATA;
 271        char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA;
 272        //char *stop = ev + IW_SCAN_MAX_DATA;
 273        int i = 0;
 274        int err = 0;
 275        IEEE80211_DEBUG_WX("Getting scan\n");
 276        down(&ieee->wx_sem);
 277        spin_lock_irqsave(&ieee->lock, flags);
 278
 279        list_for_each_entry(network, &ieee->network_list, list) {
 280                i++;
 281                if((stop-ev)<200)
 282                {
 283                        err = -E2BIG;
 284                        break;
 285                                                                                                }
 286                if (ieee->scan_age == 0 ||
 287                    time_after(network->last_scanned + ieee->scan_age, jiffies))
 288                        ev = rtl819x_translate_scan(ieee, ev, stop, network, info);
 289                else
 290                        IEEE80211_DEBUG_SCAN(
 291                                "Not showing network '%s ("
 292                                "%pM)' due to age (%lums).\n",
 293                                escape_essid(network->ssid,
 294                                             network->ssid_len),
 295                                network->bssid,
 296                                (jiffies - network->last_scanned) / (HZ / 100));
 297        }
 298
 299        spin_unlock_irqrestore(&ieee->lock, flags);
 300        up(&ieee->wx_sem);
 301        wrqu->data.length = ev -  extra;
 302        wrqu->data.flags = 0;
 303
 304        IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
 305
 306        return err;
 307}
 308
 309int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
 310                            struct iw_request_info *info,
 311                            union iwreq_data *wrqu, char *keybuf)
 312{
 313        struct iw_point *erq = &(wrqu->encoding);
 314        struct net_device *dev = ieee->dev;
 315        struct ieee80211_security sec = {
 316                .flags = 0
 317        };
 318        int i, key, key_provided, len;
 319        struct ieee80211_crypt_data **crypt;
 320
 321        IEEE80211_DEBUG_WX("SET_ENCODE\n");
 322
 323        key = erq->flags & IW_ENCODE_INDEX;
 324        if (key) {
 325                if (key > WEP_KEYS)
 326                        return -EINVAL;
 327                key--;
 328                key_provided = 1;
 329        } else {
 330                key_provided = 0;
 331                key = ieee->tx_keyidx;
 332        }
 333
 334        IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
 335                           "provided" : "default");
 336        crypt = &ieee->crypt[key];
 337
 338        if (erq->flags & IW_ENCODE_DISABLED) {
 339                if (key_provided && *crypt) {
 340                        IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
 341                                           key);
 342                        ieee80211_crypt_delayed_deinit(ieee, crypt);
 343                } else
 344                        IEEE80211_DEBUG_WX("Disabling encryption.\n");
 345
 346                /* Check all the keys to see if any are still configured,
 347                 * and if no key index was provided, de-init them all */
 348                for (i = 0; i < WEP_KEYS; i++) {
 349                        if (ieee->crypt[i] != NULL) {
 350                                if (key_provided)
 351                                        break;
 352                                ieee80211_crypt_delayed_deinit(
 353                                        ieee, &ieee->crypt[i]);
 354                        }
 355                }
 356
 357                if (i == WEP_KEYS) {
 358                        sec.enabled = 0;
 359                        sec.level = SEC_LEVEL_0;
 360                        sec.flags |= SEC_ENABLED | SEC_LEVEL;
 361                }
 362
 363                goto done;
 364        }
 365
 366
 367
 368        sec.enabled = 1;
 369        sec.flags |= SEC_ENABLED;
 370
 371        if (*crypt != NULL && (*crypt)->ops != NULL &&
 372            strcmp((*crypt)->ops->name, "WEP") != 0) {
 373                /* changing to use WEP; deinit previously used algorithm
 374                 * on this key */
 375                ieee80211_crypt_delayed_deinit(ieee, crypt);
 376        }
 377
 378        if (*crypt == NULL) {
 379                struct ieee80211_crypt_data *new_crypt;
 380
 381                /* take WEP into use */
 382                new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
 383                                    GFP_KERNEL);
 384                if (new_crypt == NULL)
 385                        return -ENOMEM;
 386                new_crypt->ops = ieee80211_get_crypto_ops("WEP");
 387                if (!new_crypt->ops) {
 388                        request_module("ieee80211_crypt_wep");
 389                        new_crypt->ops = ieee80211_get_crypto_ops("WEP");
 390                }
 391                if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
 392                        new_crypt->priv = new_crypt->ops->init(key);
 393
 394                if (!new_crypt->ops || !new_crypt->priv) {
 395                        kfree(new_crypt);
 396                        new_crypt = NULL;
 397
 398                        printk(KERN_WARNING "%s: could not initialize WEP: "
 399                               "load module ieee80211_crypt_wep\n",
 400                               dev->name);
 401                        return -EOPNOTSUPP;
 402                }
 403                *crypt = new_crypt;
 404        }
 405
 406        /* If a new key was provided, set it up */
 407        if (erq->length > 0) {
 408                len = erq->length <= 5 ? 5 : 13;
 409                memcpy(sec.keys[key], keybuf, erq->length);
 410                if (len > erq->length)
 411                        memset(sec.keys[key] + erq->length, 0,
 412                               len - erq->length);
 413                IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
 414                                   key, escape_essid(sec.keys[key], len),
 415                                   erq->length, len);
 416                sec.key_sizes[key] = len;
 417                (*crypt)->ops->set_key(sec.keys[key], len, NULL,
 418                                       (*crypt)->priv);
 419                sec.flags |= (1 << key);
 420                /* This ensures a key will be activated if no key is
 421                 * explicitely set */
 422                if (key == sec.active_key)
 423                        sec.flags |= SEC_ACTIVE_KEY;
 424                ieee->tx_keyidx = key;
 425
 426        } else {
 427                len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
 428                                             NULL, (*crypt)->priv);
 429                if (len == 0) {
 430                        /* Set a default key of all 0 */
 431                        printk("Setting key %d to all zero.\n",
 432                                           key);
 433
 434                        IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
 435                                           key);
 436                        memset(sec.keys[key], 0, 13);
 437                        (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
 438                                               (*crypt)->priv);
 439                        sec.key_sizes[key] = 13;
 440                        sec.flags |= (1 << key);
 441                }
 442
 443                /* No key data - just set the default TX key index */
 444                if (key_provided) {
 445                        IEEE80211_DEBUG_WX(
 446                                "Setting key %d to default Tx key.\n", key);
 447                        ieee->tx_keyidx = key;
 448                        sec.active_key = key;
 449                        sec.flags |= SEC_ACTIVE_KEY;
 450                }
 451        }
 452
 453 done:
 454        ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
 455        ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
 456        sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
 457        sec.flags |= SEC_AUTH_MODE;
 458        IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
 459                           "OPEN" : "SHARED KEY");
 460
 461        /* For now we just support WEP, so only set that security level...
 462         * TODO: When WPA is added this is one place that needs to change */
 463        sec.flags |= SEC_LEVEL;
 464        sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
 465
 466        if (ieee->set_security)
 467                ieee->set_security(dev, &sec);
 468
 469        /* Do not reset port if card is in Managed mode since resetting will
 470         * generate new IEEE 802.11 authentication which may end up in looping
 471         * with IEEE 802.1X.  If your hardware requires a reset after WEP
 472         * configuration (for example... Prism2), implement the reset_port in
 473         * the callbacks structures used to initialize the 802.11 stack. */
 474        if (ieee->reset_on_keychange &&
 475            ieee->iw_mode != IW_MODE_INFRA &&
 476            ieee->reset_port && ieee->reset_port(dev)) {
 477                printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
 478                return -EINVAL;
 479        }
 480        return 0;
 481}
 482
 483int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
 484                            struct iw_request_info *info,
 485                            union iwreq_data *wrqu, char *keybuf)
 486{
 487        struct iw_point *erq = &(wrqu->encoding);
 488        int len, key;
 489        struct ieee80211_crypt_data *crypt;
 490
 491        IEEE80211_DEBUG_WX("GET_ENCODE\n");
 492
 493        if(ieee->iw_mode == IW_MODE_MONITOR)
 494                return -1;
 495
 496        key = erq->flags & IW_ENCODE_INDEX;
 497        if (key) {
 498                if (key > WEP_KEYS)
 499                        return -EINVAL;
 500                key--;
 501        } else
 502                key = ieee->tx_keyidx;
 503
 504        crypt = ieee->crypt[key];
 505        erq->flags = key + 1;
 506
 507        if (crypt == NULL || crypt->ops == NULL) {
 508                erq->length = 0;
 509                erq->flags |= IW_ENCODE_DISABLED;
 510                return 0;
 511        }
 512        len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
 513        erq->length = (len >= 0 ? len : 0);
 514
 515        erq->flags |= IW_ENCODE_ENABLED;
 516
 517        if (ieee->open_wep)
 518                erq->flags |= IW_ENCODE_OPEN;
 519        else
 520                erq->flags |= IW_ENCODE_RESTRICTED;
 521
 522        return 0;
 523}
 524#if (WIRELESS_EXT >= 18)
 525int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
 526                               struct iw_request_info *info,
 527                               union iwreq_data *wrqu, char *extra)
 528{
 529        int ret = 0;
 530        struct net_device *dev = ieee->dev;
 531        struct iw_point *encoding = &wrqu->encoding;
 532        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 533        int i, idx;
 534        int group_key = 0;
 535        const char *alg, *module;
 536        struct ieee80211_crypto_ops *ops;
 537        struct ieee80211_crypt_data **crypt;
 538
 539        struct ieee80211_security sec = {
 540                .flags = 0,
 541        };
 542        //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg);
 543        idx = encoding->flags & IW_ENCODE_INDEX;
 544        if (idx) {
 545                if (idx < 1 || idx > WEP_KEYS)
 546                        return -EINVAL;
 547                idx--;
 548        } else
 549                idx = ieee->tx_keyidx;
 550
 551        if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
 552
 553                crypt = &ieee->crypt[idx];
 554
 555                group_key = 1;
 556        } else {
 557                /* some Cisco APs use idx>0 for unicast in dynamic WEP */
 558                //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg);
 559                if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
 560                        return -EINVAL;
 561                if (ieee->iw_mode == IW_MODE_INFRA)
 562
 563                        crypt = &ieee->crypt[idx];
 564
 565                else
 566                        return -EINVAL;
 567        }
 568
 569        sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT;
 570        if ((encoding->flags & IW_ENCODE_DISABLED) ||
 571            ext->alg == IW_ENCODE_ALG_NONE) {
 572                if (*crypt)
 573                        ieee80211_crypt_delayed_deinit(ieee, crypt);
 574
 575                for (i = 0; i < WEP_KEYS; i++)
 576
 577                        if (ieee->crypt[i] != NULL)
 578
 579                                break;
 580
 581                if (i == WEP_KEYS) {
 582                        sec.enabled = 0;
 583                      //  sec.encrypt = 0;
 584                        sec.level = SEC_LEVEL_0;
 585                        sec.flags |= SEC_LEVEL;
 586                }
 587                //printk("disabled: flag:%x\n", encoding->flags);
 588                goto done;
 589        }
 590
 591        sec.enabled = 1;
 592    //    sec.encrypt = 1;
 593        switch (ext->alg) {
 594        case IW_ENCODE_ALG_WEP:
 595                alg = "WEP";
 596                module = "ieee80211_crypt_wep";
 597                break;
 598        case IW_ENCODE_ALG_TKIP:
 599                alg = "TKIP";
 600                module = "ieee80211_crypt_tkip";
 601                break;
 602        case IW_ENCODE_ALG_CCMP:
 603                alg = "CCMP";
 604                module = "ieee80211_crypt_ccmp";
 605                break;
 606        default:
 607                IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
 608                                   dev->name, ext->alg);
 609                ret = -EINVAL;
 610                goto done;
 611        }
 612        printk("alg name:%s\n",alg);
 613
 614         ops = ieee80211_get_crypto_ops(alg);
 615        if (ops == NULL) {
 616                request_module(module);
 617                ops = ieee80211_get_crypto_ops(alg);
 618        }
 619        if (ops == NULL) {
 620                IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
 621                                   dev->name, ext->alg);
 622                printk("========>unknown crypto alg %d\n", ext->alg);
 623                ret = -EINVAL;
 624                goto done;
 625        }
 626
 627        if (*crypt == NULL || (*crypt)->ops != ops) {
 628                struct ieee80211_crypt_data *new_crypt;
 629
 630                ieee80211_crypt_delayed_deinit(ieee, crypt);
 631
 632                new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
 633                if (new_crypt == NULL) {
 634                        ret = -ENOMEM;
 635                        goto done;
 636                }
 637                new_crypt->ops = ops;
 638                if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
 639                        new_crypt->priv = new_crypt->ops->init(idx);
 640                if (new_crypt->priv == NULL) {
 641                        kfree(new_crypt);
 642                        ret = -EINVAL;
 643                        goto done;
 644                }
 645                *crypt = new_crypt;
 646
 647        }
 648
 649        if (ext->key_len > 0 && (*crypt)->ops->set_key &&
 650            (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
 651                                   (*crypt)->priv) < 0) {
 652                IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
 653                printk("key setting failed\n");
 654                ret = -EINVAL;
 655                goto done;
 656        }
 657 //skip_host_crypt:
 658        //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags);
 659        if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
 660                ieee->tx_keyidx = idx;
 661                sec.active_key = idx;
 662                sec.flags |= SEC_ACTIVE_KEY;
 663        }
 664
 665        if (ext->alg != IW_ENCODE_ALG_NONE) {
 666                //memcpy(sec.keys[idx], ext->key, ext->key_len);
 667                sec.key_sizes[idx] = ext->key_len;
 668                sec.flags |= (1 << idx);
 669                if (ext->alg == IW_ENCODE_ALG_WEP) {
 670                      //  sec.encode_alg[idx] = SEC_ALG_WEP;
 671                        sec.flags |= SEC_LEVEL;
 672                        sec.level = SEC_LEVEL_1;
 673                } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
 674                      //  sec.encode_alg[idx] = SEC_ALG_TKIP;
 675                        sec.flags |= SEC_LEVEL;
 676                        sec.level = SEC_LEVEL_2;
 677                } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
 678                       // sec.encode_alg[idx] = SEC_ALG_CCMP;
 679                        sec.flags |= SEC_LEVEL;
 680                        sec.level = SEC_LEVEL_3;
 681                }
 682                /* Don't set sec level for group keys. */
 683                if (group_key)
 684                        sec.flags &= ~SEC_LEVEL;
 685        }
 686done:
 687        if (ieee->set_security)
 688                ieee->set_security(ieee->dev, &sec);
 689
 690         if (ieee->reset_on_keychange &&
 691            ieee->iw_mode != IW_MODE_INFRA &&
 692            ieee->reset_port && ieee->reset_port(dev)) {
 693                IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
 694                return -EINVAL;
 695        }
 696        return ret;
 697}
 698
 699int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee,
 700                               struct iw_request_info *info,
 701                               union iwreq_data *wrqu, char *extra)
 702{
 703        struct iw_point *encoding = &wrqu->encoding;
 704        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 705        struct ieee80211_crypt_data *crypt;
 706        int idx, max_key_len;
 707
 708        max_key_len = encoding->length - sizeof(*ext);
 709        if (max_key_len < 0)
 710                return -EINVAL;
 711
 712        idx = encoding->flags & IW_ENCODE_INDEX;
 713        if (idx) {
 714                if (idx < 1 || idx > WEP_KEYS)
 715                        return -EINVAL;
 716                idx--;
 717        } else
 718                idx = ieee->tx_keyidx;
 719
 720        if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
 721            ext->alg != IW_ENCODE_ALG_WEP)
 722                if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
 723                        return -EINVAL;
 724
 725        crypt = ieee->crypt[idx];
 726        encoding->flags = idx + 1;
 727        memset(ext, 0, sizeof(*ext));
 728
 729        if (crypt == NULL || crypt->ops == NULL ) {
 730                ext->alg = IW_ENCODE_ALG_NONE;
 731                ext->key_len = 0;
 732                encoding->flags |= IW_ENCODE_DISABLED;
 733        } else {
 734                if (strcmp(crypt->ops->name, "WEP") == 0 )
 735                        ext->alg = IW_ENCODE_ALG_WEP;
 736                else if (strcmp(crypt->ops->name, "TKIP"))
 737                        ext->alg = IW_ENCODE_ALG_TKIP;
 738                else if (strcmp(crypt->ops->name, "CCMP"))
 739                        ext->alg = IW_ENCODE_ALG_CCMP;
 740                else
 741                        return -EINVAL;
 742                ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv);
 743                encoding->flags |= IW_ENCODE_ENABLED;
 744                if (ext->key_len &&
 745                    (ext->alg == IW_ENCODE_ALG_TKIP ||
 746                     ext->alg == IW_ENCODE_ALG_CCMP))
 747                        ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
 748
 749        }
 750
 751        return 0;
 752}
 753
 754int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
 755                               struct iw_request_info *info,
 756                               union iwreq_data *wrqu, char *extra)
 757{
 758        struct iw_mlme *mlme = (struct iw_mlme *) extra;
 759        switch (mlme->cmd) {
 760        case IW_MLME_DEAUTH:
 761        case IW_MLME_DISASSOC:
 762                ieee80211_disassociate(ieee);
 763                break;
 764        default:
 765                return -EOPNOTSUPP;
 766        }
 767        return 0;
 768}
 769
 770int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
 771                               struct iw_request_info *info,
 772                               struct iw_param *data, char *extra)
 773{
 774        switch (data->flags & IW_AUTH_INDEX) {
 775        case IW_AUTH_WPA_VERSION:
 776             /*need to support wpa2 here*/
 777                //printk("wpa version:%x\n", data->value);
 778                break;
 779        case IW_AUTH_CIPHER_PAIRWISE:
 780        case IW_AUTH_CIPHER_GROUP:
 781        case IW_AUTH_KEY_MGMT:
 782                /*
 783 *                  * Host AP driver does not use these parameters and allows
 784 *                                   * wpa_supplicant to control them internally.
 785 *                                                    */
 786                break;
 787        case IW_AUTH_TKIP_COUNTERMEASURES:
 788                ieee->tkip_countermeasures = data->value;
 789                break;
 790        case IW_AUTH_DROP_UNENCRYPTED:
 791                ieee->drop_unencrypted = data->value;
 792                break;
 793
 794        case IW_AUTH_80211_AUTH_ALG:
 795                //printk("======>%s():data->value is %d\n",__FUNCTION__,data->value);
 796        //      ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0;
 797                if(data->value & IW_AUTH_ALG_SHARED_KEY){
 798                        ieee->open_wep = 0;
 799                        ieee->auth_mode = 1;
 800                }
 801                else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){
 802                        ieee->open_wep = 1;
 803                        ieee->auth_mode = 0;
 804                }
 805                else if(data->value & IW_AUTH_ALG_LEAP){
 806                        ieee->open_wep = 1;
 807                        ieee->auth_mode = 2;
 808                        //printk("hahahaa:LEAP\n");
 809                }
 810                else
 811                        return -EINVAL;
 812                //printk("open_wep:%d\n", ieee->open_wep);
 813                break;
 814
 815        case IW_AUTH_WPA_ENABLED:
 816                ieee->wpa_enabled = (data->value)?1:0;
 817                //printk("enalbe wpa:%d\n", ieee->wpa_enabled);
 818                break;
 819
 820        case IW_AUTH_RX_UNENCRYPTED_EAPOL:
 821                ieee->ieee802_1x = data->value;
 822                break;
 823        case IW_AUTH_PRIVACY_INVOKED:
 824                ieee->privacy_invoked = data->value;
 825                break;
 826        default:
 827                return -EOPNOTSUPP;
 828        }
 829        return 0;
 830}
 831#endif
 832int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
 833{
 834        u8 *buf;
 835
 836        if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
 837        {
 838        //      printk("return error out, len:%d\n", len);
 839        return -EINVAL;
 840        }
 841
 842
 843        if (len)
 844        {
 845                if (len != ie[1]+2)
 846                {
 847                        printk("len:%zu, ie:%d\n", len, ie[1]);
 848                        return -EINVAL;
 849                }
 850                buf = kmemdup(ie, len, GFP_KERNEL);
 851                if (buf == NULL)
 852                        return -ENOMEM;
 853                kfree(ieee->wpa_ie);
 854                ieee->wpa_ie = buf;
 855                ieee->wpa_ie_len = len;
 856        }
 857        else{
 858                kfree(ieee->wpa_ie);
 859                ieee->wpa_ie = NULL;
 860                ieee->wpa_ie_len = 0;
 861        }
 862        return 0;
 863
 864}
 865
 866EXPORT_SYMBOL(ieee80211_wx_set_gen_ie);
 867#if (WIRELESS_EXT >= 18)
 868EXPORT_SYMBOL(ieee80211_wx_set_mlme);
 869EXPORT_SYMBOL(ieee80211_wx_set_auth);
 870EXPORT_SYMBOL(ieee80211_wx_set_encode_ext);
 871EXPORT_SYMBOL(ieee80211_wx_get_encode_ext);
 872#endif
 873EXPORT_SYMBOL(ieee80211_wx_get_scan);
 874EXPORT_SYMBOL(ieee80211_wx_set_encode);
 875EXPORT_SYMBOL(ieee80211_wx_get_encode);
 876