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