linux/drivers/staging/wlan-ng/cfg80211.c
<<
>>
Prefs
   1/* cfg80211 Interface for prism2_usb module */
   2
   3
   4/* Prism2 channel/frequency/bitrate declarations */
   5static const struct ieee80211_channel prism2_channels[] = {
   6        { .center_freq = 2412 },
   7        { .center_freq = 2417 },
   8        { .center_freq = 2422 },
   9        { .center_freq = 2427 },
  10        { .center_freq = 2432 },
  11        { .center_freq = 2437 },
  12        { .center_freq = 2442 },
  13        { .center_freq = 2447 },
  14        { .center_freq = 2452 },
  15        { .center_freq = 2457 },
  16        { .center_freq = 2462 },
  17        { .center_freq = 2467 },
  18        { .center_freq = 2472 },
  19        { .center_freq = 2484 },
  20};
  21
  22static const struct ieee80211_rate prism2_rates[] = {
  23        { .bitrate = 10 },
  24        { .bitrate = 20 },
  25        { .bitrate = 55 },
  26        { .bitrate = 110 }
  27};
  28
  29#define PRISM2_NUM_CIPHER_SUITES 2
  30static const u32 prism2_cipher_suites[PRISM2_NUM_CIPHER_SUITES] = {
  31        WLAN_CIPHER_SUITE_WEP40,
  32        WLAN_CIPHER_SUITE_WEP104
  33};
  34
  35
  36/* prism2 device private data */
  37struct prism2_wiphy_private {
  38        wlandevice_t *wlandev;
  39
  40        struct ieee80211_supported_band band;
  41        struct ieee80211_channel channels[ARRAY_SIZE(prism2_channels)];
  42        struct ieee80211_rate rates[ARRAY_SIZE(prism2_rates)];
  43
  44        struct cfg80211_scan_request *scan_request;
  45};
  46
  47static const void * const prism2_wiphy_privid = &prism2_wiphy_privid;
  48
  49
  50/* Helper Functions */
  51static int prism2_result2err(int prism2_result)
  52{
  53        int err = 0;
  54
  55        switch (prism2_result) {
  56        case P80211ENUM_resultcode_invalid_parameters:
  57                err = -EINVAL;
  58                break;
  59        case P80211ENUM_resultcode_implementation_failure:
  60                err = -EIO;
  61                break;
  62        case P80211ENUM_resultcode_not_supported:
  63                err = -EOPNOTSUPP;
  64                break;
  65        default:
  66                err = 0;
  67                break;
  68        }
  69
  70        return err;
  71}
  72
  73static int prism2_domibset_uint32(wlandevice_t *wlandev, u32 did, u32 data)
  74{
  75        struct p80211msg_dot11req_mibset msg;
  76        p80211item_uint32_t *mibitem = (p80211item_uint32_t *) &msg.mibattribute.data;
  77
  78        msg.msgcode = DIDmsg_dot11req_mibset;
  79        mibitem->did = did;
  80        mibitem->data = data;
  81
  82        return p80211req_dorequest(wlandev, (u8 *) &msg);
  83}
  84
  85static int prism2_domibset_pstr32(wlandevice_t *wlandev,
  86                                  u32 did, u8 len, u8 *data)
  87{
  88        struct p80211msg_dot11req_mibset msg;
  89        p80211item_pstr32_t *mibitem = (p80211item_pstr32_t *) &msg.mibattribute.data;
  90
  91        msg.msgcode = DIDmsg_dot11req_mibset;
  92        mibitem->did = did;
  93        mibitem->data.len = len;
  94        memcpy(mibitem->data.data, data, len);
  95
  96        return p80211req_dorequest(wlandev, (u8 *) &msg);
  97}
  98
  99
 100/* The interface functions, called by the cfg80211 layer */
 101int prism2_change_virtual_intf(struct wiphy *wiphy,
 102                               struct net_device *dev,
 103                               enum nl80211_iftype type, u32 *flags,
 104                               struct vif_params *params)
 105{
 106        wlandevice_t *wlandev = dev->ml_priv;
 107        u32 data;
 108        int result;
 109        int err = 0;
 110
 111        switch (type) {
 112        case NL80211_IFTYPE_ADHOC:
 113                if (wlandev->macmode == WLAN_MACMODE_IBSS_STA)
 114                        goto exit;
 115                wlandev->macmode = WLAN_MACMODE_IBSS_STA;
 116                data = 0;
 117                break;
 118        case NL80211_IFTYPE_STATION:
 119                if (wlandev->macmode == WLAN_MACMODE_ESS_STA)
 120                        goto exit;
 121                wlandev->macmode = WLAN_MACMODE_ESS_STA;
 122                data = 1;
 123                break;
 124        default:
 125                printk(KERN_WARNING "Operation mode: %d not support\n", type);
 126                return -EOPNOTSUPP;
 127        }
 128
 129        /* Set Operation mode to the PORT TYPE RID */
 130        result = prism2_domibset_uint32(wlandev,
 131                                        DIDmib_p2_p2Static_p2CnfPortType,
 132                                        data);
 133
 134        if (result)
 135                err = -EFAULT;
 136
 137        dev->ieee80211_ptr->iftype = type;
 138
 139exit:
 140        return err;
 141}
 142
 143int prism2_add_key(struct wiphy *wiphy, struct net_device *dev,
 144                   u8 key_index, bool pairwise, const u8 *mac_addr,
 145                   struct key_params *params)
 146{
 147        wlandevice_t *wlandev = dev->ml_priv;
 148        u32 did;
 149
 150        int err = 0;
 151        int result = 0;
 152
 153        switch (params->cipher) {
 154        case WLAN_CIPHER_SUITE_WEP40:
 155        case WLAN_CIPHER_SUITE_WEP104:
 156                result = prism2_domibset_uint32(wlandev,
 157                                                DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
 158                                                key_index);
 159                if (result)
 160                        goto exit;
 161
 162                /* send key to driver */
 163                switch (key_index) {
 164                case 0:
 165                        did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
 166                        break;
 167
 168                case 1:
 169                        did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
 170                        break;
 171
 172                case 2:
 173                        did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
 174                        break;
 175
 176                case 3:
 177                        did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
 178                        break;
 179
 180                default:
 181                        err = -EINVAL;
 182                        goto exit;
 183                }
 184
 185                result = prism2_domibset_pstr32(wlandev, did, params->key_len, params->key);
 186                if (result)
 187                        goto exit;
 188                break;
 189
 190        default:
 191                pr_debug("Unsupported cipher suite\n");
 192                result = 1;
 193        }
 194
 195exit:
 196        if (result)
 197                err = -EFAULT;
 198
 199        return err;
 200}
 201
 202int prism2_get_key(struct wiphy *wiphy, struct net_device *dev,
 203                   u8 key_index, bool pairwise, const u8 *mac_addr, void *cookie,
 204                   void (*callback)(void *cookie, struct key_params*))
 205{
 206        wlandevice_t *wlandev = dev->ml_priv;
 207        struct key_params params;
 208        int len;
 209
 210        if (key_index >= NUM_WEPKEYS)
 211                return -EINVAL;
 212
 213        len = wlandev->wep_keylens[key_index];
 214        memset(&params, 0, sizeof(params));
 215
 216        if (len == 13)
 217                params.cipher = WLAN_CIPHER_SUITE_WEP104;
 218        else if (len == 5)
 219                params.cipher = WLAN_CIPHER_SUITE_WEP104;
 220        else
 221                return -ENOENT;
 222        params.key_len = len;
 223        params.key = wlandev->wep_keys[key_index];
 224        params.seq_len = 0;
 225
 226        callback(cookie, &params);
 227
 228        return 0;
 229}
 230
 231int prism2_del_key(struct wiphy *wiphy, struct net_device *dev,
 232                   u8 key_index, bool pairwise, const u8 *mac_addr)
 233{
 234        wlandevice_t *wlandev = dev->ml_priv;
 235        u32 did;
 236        int err = 0;
 237        int result = 0;
 238
 239        /* There is no direct way in the hardware (AFAIK) of removing
 240           a key, so we will cheat by setting the key to a bogus value */
 241        /* send key to driver */
 242        switch (key_index) {
 243        case 0:
 244                did =
 245                    DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
 246                break;
 247
 248        case 1:
 249                did =
 250                    DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
 251                break;
 252
 253        case 2:
 254                did =
 255                    DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
 256                break;
 257
 258        case 3:
 259                did =
 260                    DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
 261                break;
 262
 263        default:
 264                err = -EINVAL;
 265                goto exit;
 266        }
 267
 268        result = prism2_domibset_pstr32(wlandev, did, 13, "0000000000000");
 269
 270exit:
 271        if (result)
 272                err = -EFAULT;
 273
 274        return err;
 275}
 276
 277int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev,
 278                           u8 key_index, bool unicast, bool multicast)
 279{
 280        wlandevice_t *wlandev = dev->ml_priv;
 281
 282        int err = 0;
 283        int result = 0;
 284
 285        result = prism2_domibset_uint32(wlandev,
 286                DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
 287                key_index);
 288
 289        if (result)
 290                err = -EFAULT;
 291
 292        return err;
 293}
 294
 295
 296int prism2_get_station(struct wiphy *wiphy, struct net_device *dev,
 297                       u8 *mac, struct station_info *sinfo)
 298{
 299        wlandevice_t *wlandev = dev->ml_priv;
 300        struct p80211msg_lnxreq_commsquality quality;
 301        int result;
 302
 303        memset(sinfo, 0, sizeof(*sinfo));
 304
 305        if ((wlandev == NULL) || (wlandev->msdstate != WLAN_MSD_RUNNING))
 306                return -EOPNOTSUPP;
 307
 308        /* build request message */
 309        quality.msgcode = DIDmsg_lnxreq_commsquality;
 310        quality.dbm.data = P80211ENUM_truth_true;
 311        quality.dbm.status = P80211ENUM_msgitem_status_data_ok;
 312
 313        /* send message to nsd */
 314        if (wlandev->mlmerequest == NULL)
 315                return -EOPNOTSUPP;
 316
 317        result = wlandev->mlmerequest(wlandev, (struct p80211msg *) &quality);
 318
 319
 320        if (result == 0) {
 321                sinfo->txrate.legacy = quality.txrate.data;
 322                sinfo->filled |= STATION_INFO_TX_BITRATE;
 323                sinfo->signal = quality.level.data;
 324                sinfo->filled |= STATION_INFO_SIGNAL;
 325        }
 326
 327        return result;
 328}
 329
 330int prism2_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
 331{
 332        struct net_device *dev;
 333        struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
 334        wlandevice_t *wlandev;
 335        struct p80211msg_dot11req_scan msg1;
 336        struct p80211msg_dot11req_scan_results msg2;
 337        struct cfg80211_bss *bss;
 338        int result;
 339        int err = 0;
 340        int numbss = 0;
 341        int i = 0;
 342        u8 ie_buf[46];
 343        int ie_len;
 344
 345        if (!request)
 346                return -EINVAL;
 347
 348        dev = request->wdev->netdev;
 349        wlandev = dev->ml_priv;
 350
 351        if (priv->scan_request && priv->scan_request != request)
 352                return -EBUSY;
 353
 354        if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
 355                printk(KERN_ERR "Can't scan in AP mode\n");
 356                return -EOPNOTSUPP;
 357        }
 358
 359        priv->scan_request = request;
 360
 361        memset(&msg1, 0x00, sizeof(struct p80211msg_dot11req_scan));
 362        msg1.msgcode = DIDmsg_dot11req_scan;
 363        msg1.bsstype.data = P80211ENUM_bsstype_any;
 364
 365        memset(&msg1.bssid.data.data, 0xFF, sizeof(msg1.bssid.data.data));
 366        msg1.bssid.data.len = 6;
 367
 368        if (request->n_ssids > 0) {
 369                msg1.scantype.data = P80211ENUM_scantype_active;
 370                msg1.ssid.data.len = request->ssids->ssid_len;
 371                memcpy(msg1.ssid.data.data,
 372                        request->ssids->ssid, request->ssids->ssid_len);
 373        } else {
 374                msg1.scantype.data = 0;
 375        }
 376        msg1.probedelay.data = 0;
 377
 378        for (i = 0;
 379                (i < request->n_channels) && i < ARRAY_SIZE(prism2_channels);
 380                i++)
 381                msg1.channellist.data.data[i] =
 382                        ieee80211_frequency_to_channel(request->channels[i]->center_freq);
 383        msg1.channellist.data.len = request->n_channels;
 384
 385        msg1.maxchanneltime.data = 250;
 386        msg1.minchanneltime.data = 200;
 387
 388        result = p80211req_dorequest(wlandev, (u8 *) &msg1);
 389        if (result) {
 390                err = prism2_result2err(msg1.resultcode.data);
 391                goto exit;
 392        }
 393        /* Now retrieve scan results */
 394        numbss = msg1.numbss.data;
 395
 396        for (i = 0; i < numbss; i++) {
 397                memset(&msg2, 0, sizeof(msg2));
 398                msg2.msgcode = DIDmsg_dot11req_scan_results;
 399                msg2.bssindex.data = i;
 400
 401                result = p80211req_dorequest(wlandev, (u8 *) &msg2);
 402                if ((result != 0) ||
 403                    (msg2.resultcode.data != P80211ENUM_resultcode_success)) {
 404                        break;
 405                }
 406
 407                ie_buf[0] = WLAN_EID_SSID;
 408                ie_buf[1] = msg2.ssid.data.len;
 409                ie_len = ie_buf[1] + 2;
 410                memcpy(&ie_buf[2], &(msg2.ssid.data.data), msg2.ssid.data.len);
 411                bss = cfg80211_inform_bss(wiphy,
 412                        ieee80211_get_channel(wiphy, ieee80211_dsss_chan_to_freq(msg2.dschannel.data)),
 413                        (const u8 *) &(msg2.bssid.data.data),
 414                        msg2.timestamp.data, msg2.capinfo.data,
 415                        msg2.beaconperiod.data,
 416                        ie_buf,
 417                        ie_len,
 418                        (msg2.signal.data - 65536) * 100, /* Conversion to signed type */
 419                        GFP_KERNEL
 420                );
 421
 422                if (!bss) {
 423                        err = -ENOMEM;
 424                        goto exit;
 425                }
 426
 427                cfg80211_put_bss(wiphy, bss);
 428        }
 429
 430        if (result)
 431                err = prism2_result2err(msg2.resultcode.data);
 432
 433exit:
 434        cfg80211_scan_done(request, err ? 1 : 0);
 435        priv->scan_request = NULL;
 436        return err;
 437}
 438
 439int prism2_set_wiphy_params(struct wiphy *wiphy, u32 changed)
 440{
 441        struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
 442        wlandevice_t *wlandev = priv->wlandev;
 443        u32 data;
 444        int result;
 445        int err = 0;
 446
 447        if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
 448                if (wiphy->rts_threshold == -1)
 449                        data = 2347;
 450                else
 451                        data = wiphy->rts_threshold;
 452
 453                result = prism2_domibset_uint32(wlandev,
 454                                                DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold,
 455                                                data);
 456                if (result) {
 457                        err = -EFAULT;
 458                        goto exit;
 459                }
 460        }
 461
 462        if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
 463                if (wiphy->frag_threshold == -1)
 464                        data = 2346;
 465                else
 466                        data = wiphy->frag_threshold;
 467
 468                result = prism2_domibset_uint32(wlandev,
 469                                                DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold,
 470                                                data);
 471                if (result) {
 472                        err = -EFAULT;
 473                        goto exit;
 474                }
 475        }
 476
 477exit:
 478        return err;
 479}
 480
 481int prism2_connect(struct wiphy *wiphy, struct net_device *dev,
 482                   struct cfg80211_connect_params *sme)
 483{
 484        wlandevice_t *wlandev = dev->ml_priv;
 485        struct ieee80211_channel *channel = sme->channel;
 486        struct p80211msg_lnxreq_autojoin msg_join;
 487        u32 did;
 488        int length = sme->ssid_len;
 489        int chan = -1;
 490        int is_wep = (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) ||
 491            (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104);
 492        int result;
 493        int err = 0;
 494
 495        /* Set the channel */
 496        if (channel) {
 497                chan = ieee80211_frequency_to_channel(channel->center_freq);
 498                result = prism2_domibset_uint32(wlandev,
 499                                                DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel,
 500                                                chan);
 501                if (result)
 502                        goto exit;
 503        }
 504
 505        /* Set the authorization */
 506        if ((sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) ||
 507                ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && !is_wep))
 508                        msg_join.authtype.data = P80211ENUM_authalg_opensystem;
 509        else if ((sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) ||
 510                ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && is_wep))
 511                        msg_join.authtype.data = P80211ENUM_authalg_sharedkey;
 512        else
 513                printk(KERN_WARNING
 514                        "Unhandled authorisation type for connect (%d)\n",
 515                        sme->auth_type);
 516
 517        /* Set the encryption - we only support wep */
 518        if (is_wep) {
 519                if (sme->key) {
 520                        result = prism2_domibset_uint32(wlandev,
 521                                DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
 522                                sme->key_idx);
 523                        if (result)
 524                                goto exit;
 525
 526                        /* send key to driver */
 527                        switch (sme->key_idx) {
 528                        case 0:
 529                                did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
 530                                break;
 531
 532                        case 1:
 533                                did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
 534                                break;
 535
 536                        case 2:
 537                                did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
 538                                break;
 539
 540                        case 3:
 541                                did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
 542                                break;
 543
 544                        default:
 545                                err = -EINVAL;
 546                                goto exit;
 547                        }
 548
 549                        result = prism2_domibset_pstr32(wlandev,
 550                                                        did, sme->key_len,
 551                                                        (u8 *)sme->key);
 552                        if (result)
 553                                goto exit;
 554
 555                }
 556
 557                /* Assume we should set privacy invoked and exclude unencrypted
 558                   We could possibly use sme->privacy here, but the assumption
 559                   seems reasonable anyway */
 560                result = prism2_domibset_uint32(wlandev,
 561                                                DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
 562                                                P80211ENUM_truth_true);
 563                if (result)
 564                        goto exit;
 565
 566                result = prism2_domibset_uint32(wlandev,
 567                                                DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
 568                                                P80211ENUM_truth_true);
 569                if (result)
 570                        goto exit;
 571
 572        } else {
 573                /* Assume we should unset privacy invoked
 574                   and exclude unencrypted */
 575                result = prism2_domibset_uint32(wlandev,
 576                                                DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
 577                                                P80211ENUM_truth_false);
 578                if (result)
 579                        goto exit;
 580
 581                result = prism2_domibset_uint32(wlandev,
 582                                                DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
 583                                                P80211ENUM_truth_false);
 584                if (result)
 585                        goto exit;
 586
 587        }
 588
 589        /* Now do the actual join. Note there is no way that I can
 590           see to request a specific bssid */
 591        msg_join.msgcode = DIDmsg_lnxreq_autojoin;
 592
 593        memcpy(msg_join.ssid.data.data, sme->ssid, length);
 594        msg_join.ssid.data.len = length;
 595
 596        result = p80211req_dorequest(wlandev, (u8 *) &msg_join);
 597
 598exit:
 599        if (result)
 600                err = -EFAULT;
 601
 602        return err;
 603}
 604
 605int prism2_disconnect(struct wiphy *wiphy, struct net_device *dev,
 606                      u16 reason_code)
 607{
 608        wlandevice_t *wlandev = dev->ml_priv;
 609        struct p80211msg_lnxreq_autojoin msg_join;
 610        int result;
 611        int err = 0;
 612
 613
 614        /* Do a join, with a bogus ssid. Thats the only way I can think of */
 615        msg_join.msgcode = DIDmsg_lnxreq_autojoin;
 616
 617        memcpy(msg_join.ssid.data.data, "---", 3);
 618        msg_join.ssid.data.len = 3;
 619
 620        result = p80211req_dorequest(wlandev, (u8 *) &msg_join);
 621
 622        if (result)
 623                err = -EFAULT;
 624
 625        return err;
 626}
 627
 628
 629int prism2_join_ibss(struct wiphy *wiphy, struct net_device *dev,
 630                     struct cfg80211_ibss_params *params)
 631{
 632        return -EOPNOTSUPP;
 633}
 634
 635int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
 636{
 637        return -EOPNOTSUPP;
 638}
 639
 640
 641int prism2_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
 642                        enum nl80211_tx_power_setting type, int mbm)
 643{
 644        struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
 645        wlandevice_t *wlandev = priv->wlandev;
 646        u32 data;
 647        int result;
 648        int err = 0;
 649
 650        if (type == NL80211_TX_POWER_AUTOMATIC)
 651                data = 30;
 652        else
 653                data = MBM_TO_DBM(mbm);
 654
 655        result = prism2_domibset_uint32(wlandev,
 656                DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel,
 657                data);
 658
 659        if (result) {
 660                err = -EFAULT;
 661                goto exit;
 662        }
 663
 664exit:
 665        return err;
 666}
 667
 668int prism2_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
 669                        int *dbm)
 670{
 671        struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
 672        wlandevice_t *wlandev = priv->wlandev;
 673        struct p80211msg_dot11req_mibget msg;
 674        p80211item_uint32_t *mibitem;
 675        int result;
 676        int err = 0;
 677
 678        mibitem = (p80211item_uint32_t *) &msg.mibattribute.data;
 679        msg.msgcode = DIDmsg_dot11req_mibget;
 680        mibitem->did =
 681            DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
 682
 683        result = p80211req_dorequest(wlandev, (u8 *) &msg);
 684
 685        if (result) {
 686                err = -EFAULT;
 687                goto exit;
 688        }
 689
 690        *dbm = mibitem->data;
 691
 692exit:
 693        return err;
 694}
 695
 696
 697
 698
 699/* Interface callback functions, passing data back up to the cfg80211 layer */
 700void prism2_connect_result(wlandevice_t *wlandev, u8 failed)
 701{
 702        u16 status = failed ?
 703                     WLAN_STATUS_UNSPECIFIED_FAILURE : WLAN_STATUS_SUCCESS;
 704
 705        cfg80211_connect_result(wlandev->netdev, wlandev->bssid,
 706                                NULL, 0, NULL, 0, status, GFP_KERNEL);
 707}
 708
 709void prism2_disconnected(wlandevice_t *wlandev)
 710{
 711        cfg80211_disconnected(wlandev->netdev, 0, NULL,
 712                0, GFP_KERNEL);
 713}
 714
 715void prism2_roamed(wlandevice_t *wlandev)
 716{
 717        cfg80211_roamed(wlandev->netdev, NULL, wlandev->bssid,
 718                NULL, 0, NULL, 0, GFP_KERNEL);
 719}
 720
 721
 722/* Structures for declaring wiphy interface */
 723static const struct cfg80211_ops prism2_usb_cfg_ops = {
 724        .change_virtual_intf = prism2_change_virtual_intf,
 725        .add_key = prism2_add_key,
 726        .get_key = prism2_get_key,
 727        .del_key = prism2_del_key,
 728        .set_default_key = prism2_set_default_key,
 729        .get_station = prism2_get_station,
 730        .scan = prism2_scan,
 731        .set_wiphy_params = prism2_set_wiphy_params,
 732        .connect = prism2_connect,
 733        .disconnect = prism2_disconnect,
 734        .join_ibss = prism2_join_ibss,
 735        .leave_ibss = prism2_leave_ibss,
 736        .set_tx_power = prism2_set_tx_power,
 737        .get_tx_power = prism2_get_tx_power,
 738};
 739
 740
 741/* Functions to create/free wiphy interface */
 742struct wiphy *wlan_create_wiphy(struct device *dev, wlandevice_t *wlandev)
 743{
 744        struct wiphy *wiphy;
 745        struct prism2_wiphy_private *priv;
 746
 747        wiphy = wiphy_new(&prism2_usb_cfg_ops, sizeof(*priv));
 748        if (!wiphy)
 749                return NULL;
 750
 751        priv = wiphy_priv(wiphy);
 752        priv->wlandev = wlandev;
 753        memcpy(priv->channels, prism2_channels, sizeof(prism2_channels));
 754        memcpy(priv->rates, prism2_rates, sizeof(prism2_rates));
 755        priv->band.channels = priv->channels;
 756        priv->band.n_channels = ARRAY_SIZE(prism2_channels);
 757        priv->band.bitrates = priv->rates;
 758        priv->band.n_bitrates = ARRAY_SIZE(prism2_rates);
 759        priv->band.band = IEEE80211_BAND_2GHZ;
 760        priv->band.ht_cap.ht_supported = false;
 761        wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
 762
 763        set_wiphy_dev(wiphy, dev);
 764        wiphy->privid = prism2_wiphy_privid;
 765        wiphy->max_scan_ssids = 1;
 766        wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
 767                                 | BIT(NL80211_IFTYPE_ADHOC);
 768        wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
 769        wiphy->n_cipher_suites = PRISM2_NUM_CIPHER_SUITES;
 770        wiphy->cipher_suites = prism2_cipher_suites;
 771
 772        if (wiphy_register(wiphy) < 0)
 773                return NULL;
 774
 775        return wiphy;
 776}
 777
 778
 779void wlan_free_wiphy(struct wiphy *wiphy)
 780{
 781        wiphy_unregister(wiphy);
 782        wiphy_free(wiphy);
 783}
 784