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