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