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        int err = 0;
 235        int result = 0;
 236
 237        result = prism2_domibset_uint32(wlandev,
 238                DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
 239                key_index);
 240
 241        if (result)
 242                err = -EFAULT;
 243
 244        return err;
 245}
 246
 247static int prism2_get_station(struct wiphy *wiphy, struct net_device *dev,
 248                              const u8 *mac, struct station_info *sinfo)
 249{
 250        struct wlandevice *wlandev = dev->ml_priv;
 251        struct p80211msg_lnxreq_commsquality quality;
 252        int result;
 253
 254        memset(sinfo, 0, sizeof(*sinfo));
 255
 256        if (!wlandev || (wlandev->msdstate != WLAN_MSD_RUNNING))
 257                return -EOPNOTSUPP;
 258
 259        /* build request message */
 260        quality.msgcode = DIDMSG_LNXREQ_COMMSQUALITY;
 261        quality.dbm.data = P80211ENUM_truth_true;
 262        quality.dbm.status = P80211ENUM_msgitem_status_data_ok;
 263
 264        /* send message to nsd */
 265        if (!wlandev->mlmerequest)
 266                return -EOPNOTSUPP;
 267
 268        result = wlandev->mlmerequest(wlandev, (struct p80211msg *)&quality);
 269
 270        if (result == 0) {
 271                sinfo->txrate.legacy = quality.txrate.data;
 272                sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
 273                sinfo->signal = quality.level.data;
 274                sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
 275        }
 276
 277        return result;
 278}
 279
 280static int prism2_scan(struct wiphy *wiphy,
 281                       struct cfg80211_scan_request *request)
 282{
 283        struct net_device *dev;
 284        struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
 285        struct wlandevice *wlandev;
 286        struct p80211msg_dot11req_scan msg1;
 287        struct p80211msg_dot11req_scan_results msg2;
 288        struct cfg80211_bss *bss;
 289        struct cfg80211_scan_info info = {};
 290
 291        int result;
 292        int err = 0;
 293        int numbss = 0;
 294        int i = 0;
 295        u8 ie_buf[46];
 296        int ie_len;
 297
 298        if (!request)
 299                return -EINVAL;
 300
 301        dev = request->wdev->netdev;
 302        wlandev = dev->ml_priv;
 303
 304        if (priv->scan_request && priv->scan_request != request)
 305                return -EBUSY;
 306
 307        if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
 308                netdev_err(dev, "Can't scan in AP mode\n");
 309                return -EOPNOTSUPP;
 310        }
 311
 312        priv->scan_request = request;
 313
 314        memset(&msg1, 0x00, sizeof(msg1));
 315        msg1.msgcode = DIDMSG_DOT11REQ_SCAN;
 316        msg1.bsstype.data = P80211ENUM_bsstype_any;
 317
 318        memset(&msg1.bssid.data.data, 0xFF, sizeof(msg1.bssid.data.data));
 319        msg1.bssid.data.len = 6;
 320
 321        if (request->n_ssids > 0) {
 322                msg1.scantype.data = P80211ENUM_scantype_active;
 323                msg1.ssid.data.len = request->ssids->ssid_len;
 324                memcpy(msg1.ssid.data.data,
 325                       request->ssids->ssid, request->ssids->ssid_len);
 326        } else {
 327                msg1.scantype.data = 0;
 328        }
 329        msg1.probedelay.data = 0;
 330
 331        for (i = 0;
 332                (i < request->n_channels) && i < ARRAY_SIZE(prism2_channels);
 333                i++)
 334                msg1.channellist.data.data[i] =
 335                        ieee80211_frequency_to_channel(
 336                                request->channels[i]->center_freq);
 337        msg1.channellist.data.len = request->n_channels;
 338
 339        msg1.maxchanneltime.data = 250;
 340        msg1.minchanneltime.data = 200;
 341
 342        result = p80211req_dorequest(wlandev, (u8 *)&msg1);
 343        if (result) {
 344                err = prism2_result2err(msg1.resultcode.data);
 345                goto exit;
 346        }
 347        /* Now retrieve scan results */
 348        numbss = msg1.numbss.data;
 349
 350        for (i = 0; i < numbss; i++) {
 351                int freq;
 352
 353                memset(&msg2, 0, sizeof(msg2));
 354                msg2.msgcode = DIDMSG_DOT11REQ_SCAN_RESULTS;
 355                msg2.bssindex.data = i;
 356
 357                result = p80211req_dorequest(wlandev, (u8 *)&msg2);
 358                if ((result != 0) ||
 359                    (msg2.resultcode.data != P80211ENUM_resultcode_success)) {
 360                        break;
 361                }
 362
 363                ie_buf[0] = WLAN_EID_SSID;
 364                ie_buf[1] = msg2.ssid.data.len;
 365                ie_len = ie_buf[1] + 2;
 366                memcpy(&ie_buf[2], &msg2.ssid.data.data, msg2.ssid.data.len);
 367                freq = ieee80211_channel_to_frequency(msg2.dschannel.data,
 368                                                      NL80211_BAND_2GHZ);
 369                bss = cfg80211_inform_bss(wiphy,
 370                        ieee80211_get_channel(wiphy, freq),
 371                        CFG80211_BSS_FTYPE_UNKNOWN,
 372                        (const u8 *)&msg2.bssid.data.data,
 373                        msg2.timestamp.data, msg2.capinfo.data,
 374                        msg2.beaconperiod.data,
 375                        ie_buf,
 376                        ie_len,
 377                        (msg2.signal.data - 65536) * 100, /* Conversion to signed type */
 378                        GFP_KERNEL
 379                );
 380
 381                if (!bss) {
 382                        err = -ENOMEM;
 383                        goto exit;
 384                }
 385
 386                cfg80211_put_bss(wiphy, bss);
 387        }
 388
 389        if (result)
 390                err = prism2_result2err(msg2.resultcode.data);
 391
 392exit:
 393        info.aborted = !!(err);
 394        cfg80211_scan_done(request, &info);
 395        priv->scan_request = NULL;
 396        return err;
 397}
 398
 399static int prism2_set_wiphy_params(struct wiphy *wiphy, u32 changed)
 400{
 401        struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
 402        struct wlandevice *wlandev = priv->wlandev;
 403        u32 data;
 404        int result;
 405        int err = 0;
 406
 407        if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
 408                if (wiphy->rts_threshold == -1)
 409                        data = 2347;
 410                else
 411                        data = wiphy->rts_threshold;
 412
 413                result = prism2_domibset_uint32(wlandev,
 414                                                DIDMIB_DOT11MAC_OPERATIONTABLE_RTSTHRESHOLD,
 415                                                data);
 416                if (result) {
 417                        err = -EFAULT;
 418                        goto exit;
 419                }
 420        }
 421
 422        if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
 423                if (wiphy->frag_threshold == -1)
 424                        data = 2346;
 425                else
 426                        data = wiphy->frag_threshold;
 427
 428                result = prism2_domibset_uint32(wlandev,
 429                                                DIDMIB_DOT11MAC_OPERATIONTABLE_FRAGMENTATIONTHRESHOLD,
 430                                                data);
 431                if (result) {
 432                        err = -EFAULT;
 433                        goto exit;
 434                }
 435        }
 436
 437exit:
 438        return err;
 439}
 440
 441static int prism2_connect(struct wiphy *wiphy, struct net_device *dev,
 442                          struct cfg80211_connect_params *sme)
 443{
 444        struct wlandevice *wlandev = dev->ml_priv;
 445        struct ieee80211_channel *channel = sme->channel;
 446        struct p80211msg_lnxreq_autojoin msg_join;
 447        u32 did;
 448        int length = sme->ssid_len;
 449        int chan = -1;
 450        int is_wep = (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) ||
 451            (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104);
 452        int result;
 453        int err = 0;
 454
 455        /* Set the channel */
 456        if (channel) {
 457                chan = ieee80211_frequency_to_channel(channel->center_freq);
 458                result = prism2_domibset_uint32(wlandev,
 459                                                DIDMIB_DOT11PHY_DSSSTABLE_CURRENTCHANNEL,
 460                                                chan);
 461                if (result)
 462                        goto exit;
 463        }
 464
 465        /* Set the authorization */
 466        if ((sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) ||
 467            ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && !is_wep))
 468                msg_join.authtype.data = P80211ENUM_authalg_opensystem;
 469        else if ((sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) ||
 470                 ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && is_wep))
 471                msg_join.authtype.data = P80211ENUM_authalg_sharedkey;
 472        else
 473                netdev_warn(dev,
 474                            "Unhandled authorisation type for connect (%d)\n",
 475                            sme->auth_type);
 476
 477        /* Set the encryption - we only support wep */
 478        if (is_wep) {
 479                if (sme->key) {
 480                        if (sme->key_idx >= NUM_WEPKEYS) {
 481                                err = -EINVAL;
 482                                goto exit;
 483                        }
 484
 485                        result = prism2_domibset_uint32(wlandev,
 486                                DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
 487                                sme->key_idx);
 488                        if (result)
 489                                goto exit;
 490
 491                        /* send key to driver */
 492                        did = didmib_dot11smt_wepdefaultkeystable_key(
 493                                        sme->key_idx + 1);
 494                        result = prism2_domibset_pstr32(wlandev,
 495                                                        did, sme->key_len,
 496                                                        (u8 *)sme->key);
 497                        if (result)
 498                                goto exit;
 499                }
 500
 501                /* Assume we should set privacy invoked and exclude unencrypted
 502                 * We could possible use sme->privacy here, but the assumption
 503                 * seems reasonable anyways
 504                 */
 505                result = prism2_domibset_uint32(wlandev,
 506                                                DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED,
 507                                                P80211ENUM_truth_true);
 508                if (result)
 509                        goto exit;
 510
 511                result = prism2_domibset_uint32(wlandev,
 512                                                DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED,
 513                                                P80211ENUM_truth_true);
 514                if (result)
 515                        goto exit;
 516
 517        } else {
 518                /* Assume we should unset privacy invoked
 519                 * and exclude unencrypted
 520                 */
 521                result = prism2_domibset_uint32(wlandev,
 522                                                DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED,
 523                                                P80211ENUM_truth_false);
 524                if (result)
 525                        goto exit;
 526
 527                result = prism2_domibset_uint32(wlandev,
 528                                                DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED,
 529                                                P80211ENUM_truth_false);
 530                if (result)
 531                        goto exit;
 532        }
 533
 534        /* Now do the actual join. Note there is no way that I can
 535         * see to request a specific bssid
 536         */
 537        msg_join.msgcode = DIDMSG_LNXREQ_AUTOJOIN;
 538
 539        memcpy(msg_join.ssid.data.data, sme->ssid, length);
 540        msg_join.ssid.data.len = length;
 541
 542        result = p80211req_dorequest(wlandev, (u8 *)&msg_join);
 543
 544exit:
 545        if (result)
 546                err = -EFAULT;
 547
 548        return err;
 549}
 550
 551static int prism2_disconnect(struct wiphy *wiphy, struct net_device *dev,
 552                             u16 reason_code)
 553{
 554        struct wlandevice *wlandev = dev->ml_priv;
 555        struct p80211msg_lnxreq_autojoin msg_join;
 556        int result;
 557        int err = 0;
 558
 559        /* Do a join, with a bogus ssid. Thats the only way I can think of */
 560        msg_join.msgcode = DIDMSG_LNXREQ_AUTOJOIN;
 561
 562        memcpy(msg_join.ssid.data.data, "---", 3);
 563        msg_join.ssid.data.len = 3;
 564
 565        result = p80211req_dorequest(wlandev, (u8 *)&msg_join);
 566
 567        if (result)
 568                err = -EFAULT;
 569
 570        return err;
 571}
 572
 573static int prism2_join_ibss(struct wiphy *wiphy, struct net_device *dev,
 574                            struct cfg80211_ibss_params *params)
 575{
 576        return -EOPNOTSUPP;
 577}
 578
 579static int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
 580{
 581        return -EOPNOTSUPP;
 582}
 583
 584static int prism2_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
 585                               enum nl80211_tx_power_setting type, int mbm)
 586{
 587        struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
 588        struct wlandevice *wlandev = priv->wlandev;
 589        u32 data;
 590        int result;
 591        int err = 0;
 592
 593        if (type == NL80211_TX_POWER_AUTOMATIC)
 594                data = 30;
 595        else
 596                data = MBM_TO_DBM(mbm);
 597
 598        result = prism2_domibset_uint32(wlandev,
 599                DIDMIB_DOT11PHY_TXPOWERTABLE_CURRENTTXPOWERLEVEL,
 600                data);
 601
 602        if (result) {
 603                err = -EFAULT;
 604                goto exit;
 605        }
 606
 607exit:
 608        return err;
 609}
 610
 611static int prism2_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
 612                               int *dbm)
 613{
 614        struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
 615        struct wlandevice *wlandev = priv->wlandev;
 616        struct p80211msg_dot11req_mibget msg;
 617        struct p80211item_uint32 *mibitem;
 618        int result;
 619        int err = 0;
 620
 621        mibitem = (struct p80211item_uint32 *)&msg.mibattribute.data;
 622        msg.msgcode = DIDMSG_DOT11REQ_MIBGET;
 623        mibitem->did = DIDMIB_DOT11PHY_TXPOWERTABLE_CURRENTTXPOWERLEVEL;
 624
 625        result = p80211req_dorequest(wlandev, (u8 *)&msg);
 626
 627        if (result) {
 628                err = -EFAULT;
 629                goto exit;
 630        }
 631
 632        *dbm = mibitem->data;
 633
 634exit:
 635        return err;
 636}
 637
 638/* Interface callback functions, passing data back up to the cfg80211 layer */
 639void prism2_connect_result(struct wlandevice *wlandev, u8 failed)
 640{
 641        u16 status = failed ?
 642                     WLAN_STATUS_UNSPECIFIED_FAILURE : WLAN_STATUS_SUCCESS;
 643
 644        cfg80211_connect_result(wlandev->netdev, wlandev->bssid,
 645                                NULL, 0, NULL, 0, status, GFP_KERNEL);
 646}
 647
 648void prism2_disconnected(struct wlandevice *wlandev)
 649{
 650        cfg80211_disconnected(wlandev->netdev, 0, NULL,
 651                              0, false, GFP_KERNEL);
 652}
 653
 654void prism2_roamed(struct wlandevice *wlandev)
 655{
 656        struct cfg80211_roam_info roam_info = {
 657                .bssid = wlandev->bssid,
 658        };
 659
 660        cfg80211_roamed(wlandev->netdev, &roam_info, GFP_KERNEL);
 661}
 662
 663/* Structures for declaring wiphy interface */
 664static const struct cfg80211_ops prism2_usb_cfg_ops = {
 665        .change_virtual_intf = prism2_change_virtual_intf,
 666        .add_key = prism2_add_key,
 667        .get_key = prism2_get_key,
 668        .del_key = prism2_del_key,
 669        .set_default_key = prism2_set_default_key,
 670        .get_station = prism2_get_station,
 671        .scan = prism2_scan,
 672        .set_wiphy_params = prism2_set_wiphy_params,
 673        .connect = prism2_connect,
 674        .disconnect = prism2_disconnect,
 675        .join_ibss = prism2_join_ibss,
 676        .leave_ibss = prism2_leave_ibss,
 677        .set_tx_power = prism2_set_tx_power,
 678        .get_tx_power = prism2_get_tx_power,
 679};
 680
 681/* Functions to create/free wiphy interface */
 682static struct wiphy *wlan_create_wiphy(struct device *dev,
 683                                       struct wlandevice *wlandev)
 684{
 685        struct wiphy *wiphy;
 686        struct prism2_wiphy_private *priv;
 687
 688        wiphy = wiphy_new(&prism2_usb_cfg_ops, sizeof(*priv));
 689        if (!wiphy)
 690                return NULL;
 691
 692        priv = wiphy_priv(wiphy);
 693        priv->wlandev = wlandev;
 694        memcpy(priv->channels, prism2_channels, sizeof(prism2_channels));
 695        memcpy(priv->rates, prism2_rates, sizeof(prism2_rates));
 696        priv->band.channels = priv->channels;
 697        priv->band.n_channels = ARRAY_SIZE(prism2_channels);
 698        priv->band.bitrates = priv->rates;
 699        priv->band.n_bitrates = ARRAY_SIZE(prism2_rates);
 700        priv->band.band = NL80211_BAND_2GHZ;
 701        priv->band.ht_cap.ht_supported = false;
 702        wiphy->bands[NL80211_BAND_2GHZ] = &priv->band;
 703
 704        set_wiphy_dev(wiphy, dev);
 705        wiphy->privid = prism2_wiphy_privid;
 706        wiphy->max_scan_ssids = 1;
 707        wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
 708                                 | BIT(NL80211_IFTYPE_ADHOC);
 709        wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
 710        wiphy->n_cipher_suites = PRISM2_NUM_CIPHER_SUITES;
 711        wiphy->cipher_suites = prism2_cipher_suites;
 712
 713        if (wiphy_register(wiphy) < 0) {
 714                wiphy_free(wiphy);
 715                return NULL;
 716        }
 717
 718        return wiphy;
 719}
 720
 721static void wlan_free_wiphy(struct wiphy *wiphy)
 722{
 723        wiphy_unregister(wiphy);
 724        wiphy_free(wiphy);
 725}
 726