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