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