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