Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* cfg80211 Interface for prism2_usb module */
0003 #include "hfa384x.h"
0004 #include "prism2mgmt.h"
0005 
0006 /* Prism2 channel/frequency/bitrate declarations */
0007 static const struct ieee80211_channel prism2_channels[] = {
0008     { .center_freq = 2412 },
0009     { .center_freq = 2417 },
0010     { .center_freq = 2422 },
0011     { .center_freq = 2427 },
0012     { .center_freq = 2432 },
0013     { .center_freq = 2437 },
0014     { .center_freq = 2442 },
0015     { .center_freq = 2447 },
0016     { .center_freq = 2452 },
0017     { .center_freq = 2457 },
0018     { .center_freq = 2462 },
0019     { .center_freq = 2467 },
0020     { .center_freq = 2472 },
0021     { .center_freq = 2484 },
0022 };
0023 
0024 static const struct ieee80211_rate prism2_rates[] = {
0025     { .bitrate = 10 },
0026     { .bitrate = 20 },
0027     { .bitrate = 55 },
0028     { .bitrate = 110 }
0029 };
0030 
0031 #define PRISM2_NUM_CIPHER_SUITES 2
0032 static const u32 prism2_cipher_suites[PRISM2_NUM_CIPHER_SUITES] = {
0033     WLAN_CIPHER_SUITE_WEP40,
0034     WLAN_CIPHER_SUITE_WEP104
0035 };
0036 
0037 /* prism2 device private data */
0038 struct prism2_wiphy_private {
0039     struct wlandevice *wlandev;
0040 
0041     struct ieee80211_supported_band band;
0042     struct ieee80211_channel channels[ARRAY_SIZE(prism2_channels)];
0043     struct ieee80211_rate rates[ARRAY_SIZE(prism2_rates)];
0044 
0045     struct cfg80211_scan_request *scan_request;
0046 };
0047 
0048 static const void * const prism2_wiphy_privid = &prism2_wiphy_privid;
0049 
0050 /* Helper Functions */
0051 static int prism2_result2err(int prism2_result)
0052 {
0053     int err = 0;
0054 
0055     switch (prism2_result) {
0056     case P80211ENUM_resultcode_invalid_parameters:
0057         err = -EINVAL;
0058         break;
0059     case P80211ENUM_resultcode_implementation_failure:
0060         err = -EIO;
0061         break;
0062     case P80211ENUM_resultcode_not_supported:
0063         err = -EOPNOTSUPP;
0064         break;
0065     default:
0066         err = 0;
0067         break;
0068     }
0069 
0070     return err;
0071 }
0072 
0073 static int prism2_domibset_uint32(struct wlandevice *wlandev,
0074                   u32 did, u32 data)
0075 {
0076     struct p80211msg_dot11req_mibset msg;
0077     struct p80211item_uint32 *mibitem =
0078             (struct p80211item_uint32 *)&msg.mibattribute.data;
0079 
0080     msg.msgcode = DIDMSG_DOT11REQ_MIBSET;
0081     mibitem->did = did;
0082     mibitem->data = data;
0083 
0084     return p80211req_dorequest(wlandev, (u8 *)&msg);
0085 }
0086 
0087 static int prism2_domibset_pstr32(struct wlandevice *wlandev,
0088                   u32 did, u8 len, const u8 *data)
0089 {
0090     struct p80211msg_dot11req_mibset msg;
0091     struct p80211item_pstr32 *mibitem =
0092             (struct p80211item_pstr32 *)&msg.mibattribute.data;
0093 
0094     msg.msgcode = DIDMSG_DOT11REQ_MIBSET;
0095     mibitem->did = did;
0096     mibitem->data.len = len;
0097     memcpy(mibitem->data.data, data, len);
0098 
0099     return p80211req_dorequest(wlandev, (u8 *)&msg);
0100 }
0101 
0102 /* The interface functions, called by the cfg80211 layer */
0103 static int prism2_change_virtual_intf(struct wiphy *wiphy,
0104                       struct net_device *dev,
0105                       enum nl80211_iftype type,
0106                       struct vif_params *params)
0107 {
0108     struct wlandevice *wlandev = dev->ml_priv;
0109     u32 data;
0110     int result;
0111     int err = 0;
0112 
0113     switch (type) {
0114     case NL80211_IFTYPE_ADHOC:
0115         if (wlandev->macmode == WLAN_MACMODE_IBSS_STA)
0116             goto exit;
0117         wlandev->macmode = WLAN_MACMODE_IBSS_STA;
0118         data = 0;
0119         break;
0120     case NL80211_IFTYPE_STATION:
0121         if (wlandev->macmode == WLAN_MACMODE_ESS_STA)
0122             goto exit;
0123         wlandev->macmode = WLAN_MACMODE_ESS_STA;
0124         data = 1;
0125         break;
0126     default:
0127         netdev_warn(dev, "Operation mode: %d not support\n", type);
0128         return -EOPNOTSUPP;
0129     }
0130 
0131     /* Set Operation mode to the PORT TYPE RID */
0132     result = prism2_domibset_uint32(wlandev,
0133                     DIDMIB_P2_STATIC_CNFPORTTYPE,
0134                     data);
0135 
0136     if (result)
0137         err = -EFAULT;
0138 
0139     dev->ieee80211_ptr->iftype = type;
0140 
0141 exit:
0142     return err;
0143 }
0144 
0145 static int prism2_add_key(struct wiphy *wiphy, struct net_device *dev,
0146               u8 key_index, bool pairwise, const u8 *mac_addr,
0147               struct key_params *params)
0148 {
0149     struct wlandevice *wlandev = dev->ml_priv;
0150     u32 did;
0151 
0152     if (key_index >= NUM_WEPKEYS)
0153         return -EINVAL;
0154 
0155     if (params->cipher != WLAN_CIPHER_SUITE_WEP40 &&
0156         params->cipher != WLAN_CIPHER_SUITE_WEP104) {
0157         pr_debug("Unsupported cipher suite\n");
0158         return -EFAULT;
0159     }
0160 
0161     if (prism2_domibset_uint32(wlandev,
0162                    DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
0163                    key_index))
0164         return -EFAULT;
0165 
0166     /* send key to driver */
0167     did = didmib_dot11smt_wepdefaultkeystable_key(key_index + 1);
0168 
0169     if (prism2_domibset_pstr32(wlandev, did, params->key_len, params->key))
0170         return -EFAULT;
0171     return 0;
0172 }
0173 
0174 static int prism2_get_key(struct wiphy *wiphy, struct net_device *dev,
0175               u8 key_index, bool pairwise,
0176               const u8 *mac_addr, void *cookie,
0177               void (*callback)(void *cookie, struct key_params*))
0178 {
0179     struct wlandevice *wlandev = dev->ml_priv;
0180     struct key_params params;
0181     int len;
0182 
0183     if (key_index >= NUM_WEPKEYS)
0184         return -EINVAL;
0185 
0186     len = wlandev->wep_keylens[key_index];
0187     memset(&params, 0, sizeof(params));
0188 
0189     if (len == 13)
0190         params.cipher = WLAN_CIPHER_SUITE_WEP104;
0191     else if (len == 5)
0192         params.cipher = WLAN_CIPHER_SUITE_WEP104;
0193     else
0194         return -ENOENT;
0195     params.key_len = len;
0196     params.key = wlandev->wep_keys[key_index];
0197     params.seq_len = 0;
0198 
0199     callback(cookie, &params);
0200 
0201     return 0;
0202 }
0203 
0204 static int prism2_del_key(struct wiphy *wiphy, struct net_device *dev,
0205               u8 key_index, bool pairwise, const u8 *mac_addr)
0206 {
0207     struct wlandevice *wlandev = dev->ml_priv;
0208     u32 did;
0209     int err = 0;
0210     int result = 0;
0211 
0212     /* There is no direct way in the hardware (AFAIK) of removing
0213      * a key, so we will cheat by setting the key to a bogus value
0214      */
0215 
0216     if (key_index >= NUM_WEPKEYS)
0217         return -EINVAL;
0218 
0219     /* send key to driver */
0220     did = didmib_dot11smt_wepdefaultkeystable_key(key_index + 1);
0221     result = prism2_domibset_pstr32(wlandev, did, 13, "0000000000000");
0222 
0223     if (result)
0224         err = -EFAULT;
0225 
0226     return err;
0227 }
0228 
0229 static int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev,
0230                   u8 key_index, bool unicast, bool multicast)
0231 {
0232     struct wlandevice *wlandev = dev->ml_priv;
0233 
0234     return  prism2_domibset_uint32(wlandev,
0235                        DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
0236                        key_index);
0237 }
0238 
0239 static int prism2_get_station(struct wiphy *wiphy, struct net_device *dev,
0240                   const u8 *mac, struct station_info *sinfo)
0241 {
0242     struct wlandevice *wlandev = dev->ml_priv;
0243     struct p80211msg_lnxreq_commsquality quality;
0244     int result;
0245 
0246     memset(sinfo, 0, sizeof(*sinfo));
0247 
0248     if (!wlandev || (wlandev->msdstate != WLAN_MSD_RUNNING))
0249         return -EOPNOTSUPP;
0250 
0251     /* build request message */
0252     quality.msgcode = DIDMSG_LNXREQ_COMMSQUALITY;
0253     quality.dbm.data = P80211ENUM_truth_true;
0254     quality.dbm.status = P80211ENUM_msgitem_status_data_ok;
0255 
0256     /* send message to nsd */
0257     if (!wlandev->mlmerequest)
0258         return -EOPNOTSUPP;
0259 
0260     result = wlandev->mlmerequest(wlandev, (struct p80211msg *)&quality);
0261 
0262     if (result == 0) {
0263         sinfo->txrate.legacy = quality.txrate.data;
0264         sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
0265         sinfo->signal = quality.level.data;
0266         sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
0267     }
0268 
0269     return result;
0270 }
0271 
0272 static int prism2_scan(struct wiphy *wiphy,
0273                struct cfg80211_scan_request *request)
0274 {
0275     struct net_device *dev;
0276     struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
0277     struct wlandevice *wlandev;
0278     struct p80211msg_dot11req_scan msg1;
0279     struct p80211msg_dot11req_scan_results *msg2;
0280     struct cfg80211_bss *bss;
0281     struct cfg80211_scan_info info = {};
0282 
0283     int result;
0284     int err = 0;
0285     int numbss = 0;
0286     int i = 0;
0287     u8 ie_buf[46];
0288     int ie_len;
0289 
0290     if (!request)
0291         return -EINVAL;
0292 
0293     dev = request->wdev->netdev;
0294     wlandev = dev->ml_priv;
0295 
0296     if (priv->scan_request && priv->scan_request != request)
0297         return -EBUSY;
0298 
0299     if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
0300         netdev_err(dev, "Can't scan in AP mode\n");
0301         return -EOPNOTSUPP;
0302     }
0303 
0304     msg2 = kzalloc(sizeof(*msg2), GFP_KERNEL);
0305     if (!msg2)
0306         return -ENOMEM;
0307 
0308     priv->scan_request = request;
0309 
0310     memset(&msg1, 0x00, sizeof(msg1));
0311     msg1.msgcode = DIDMSG_DOT11REQ_SCAN;
0312     msg1.bsstype.data = P80211ENUM_bsstype_any;
0313 
0314     memset(&msg1.bssid.data.data, 0xFF, sizeof(msg1.bssid.data.data));
0315     msg1.bssid.data.len = 6;
0316 
0317     if (request->n_ssids > 0) {
0318         msg1.scantype.data = P80211ENUM_scantype_active;
0319         msg1.ssid.data.len = request->ssids->ssid_len;
0320         memcpy(msg1.ssid.data.data,
0321                request->ssids->ssid, request->ssids->ssid_len);
0322     } else {
0323         msg1.scantype.data = 0;
0324     }
0325     msg1.probedelay.data = 0;
0326 
0327     for (i = 0;
0328         (i < request->n_channels) && i < ARRAY_SIZE(prism2_channels);
0329         i++)
0330         msg1.channellist.data.data[i] =
0331             ieee80211_frequency_to_channel(request->channels[i]->center_freq);
0332     msg1.channellist.data.len = request->n_channels;
0333 
0334     msg1.maxchanneltime.data = 250;
0335     msg1.minchanneltime.data = 200;
0336 
0337     result = p80211req_dorequest(wlandev, (u8 *)&msg1);
0338     if (result) {
0339         err = prism2_result2err(msg1.resultcode.data);
0340         goto exit;
0341     }
0342     /* Now retrieve scan results */
0343     numbss = msg1.numbss.data;
0344 
0345     for (i = 0; i < numbss; i++) {
0346         int freq;
0347 
0348         msg2->msgcode = DIDMSG_DOT11REQ_SCAN_RESULTS;
0349         msg2->bssindex.data = i;
0350 
0351         result = p80211req_dorequest(wlandev, (u8 *)&msg2);
0352         if ((result != 0) ||
0353             (msg2->resultcode.data != P80211ENUM_resultcode_success)) {
0354             break;
0355         }
0356 
0357         ie_buf[0] = WLAN_EID_SSID;
0358         ie_buf[1] = msg2->ssid.data.len;
0359         ie_len = ie_buf[1] + 2;
0360         memcpy(&ie_buf[2], &msg2->ssid.data.data, msg2->ssid.data.len);
0361         freq = ieee80211_channel_to_frequency(msg2->dschannel.data,
0362                               NL80211_BAND_2GHZ);
0363         bss = cfg80211_inform_bss(wiphy,
0364                       ieee80211_get_channel(wiphy, freq),
0365                       CFG80211_BSS_FTYPE_UNKNOWN,
0366                       (const u8 *)&msg2->bssid.data.data,
0367                       msg2->timestamp.data, msg2->capinfo.data,
0368                       msg2->beaconperiod.data,
0369                       ie_buf,
0370                       ie_len,
0371                       (msg2->signal.data - 65536) * 100, /* Conversion to signed type */
0372                       GFP_KERNEL);
0373 
0374         if (!bss) {
0375             err = -ENOMEM;
0376             goto exit;
0377         }
0378 
0379         cfg80211_put_bss(wiphy, bss);
0380     }
0381 
0382     if (result)
0383         err = prism2_result2err(msg2->resultcode.data);
0384 
0385 exit:
0386     info.aborted = !!(err);
0387     cfg80211_scan_done(request, &info);
0388     priv->scan_request = NULL;
0389     kfree(msg2);
0390     return err;
0391 }
0392 
0393 static int prism2_set_wiphy_params(struct wiphy *wiphy, u32 changed)
0394 {
0395     struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
0396     struct wlandevice *wlandev = priv->wlandev;
0397     u32 data;
0398     int result;
0399     int err = 0;
0400 
0401     if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
0402         if (wiphy->rts_threshold == -1)
0403             data = 2347;
0404         else
0405             data = wiphy->rts_threshold;
0406 
0407         result = prism2_domibset_uint32(wlandev,
0408                         DIDMIB_DOT11MAC_OPERATIONTABLE_RTSTHRESHOLD,
0409                         data);
0410         if (result) {
0411             err = -EFAULT;
0412             goto exit;
0413         }
0414     }
0415 
0416     if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
0417         if (wiphy->frag_threshold == -1)
0418             data = 2346;
0419         else
0420             data = wiphy->frag_threshold;
0421 
0422         result = prism2_domibset_uint32(wlandev,
0423                         DIDMIB_DOT11MAC_OPERATIONTABLE_FRAGMENTATIONTHRESHOLD,
0424                         data);
0425         if (result) {
0426             err = -EFAULT;
0427             goto exit;
0428         }
0429     }
0430 
0431 exit:
0432     return err;
0433 }
0434 
0435 static int prism2_connect(struct wiphy *wiphy, struct net_device *dev,
0436               struct cfg80211_connect_params *sme)
0437 {
0438     struct wlandevice *wlandev = dev->ml_priv;
0439     struct ieee80211_channel *channel = sme->channel;
0440     struct p80211msg_lnxreq_autojoin msg_join;
0441     u32 did;
0442     int length = sme->ssid_len;
0443     int chan = -1;
0444     int is_wep = (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) ||
0445         (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104);
0446     int result;
0447     int err = 0;
0448 
0449     /* Set the channel */
0450     if (channel) {
0451         chan = ieee80211_frequency_to_channel(channel->center_freq);
0452         result = prism2_domibset_uint32(wlandev,
0453                         DIDMIB_DOT11PHY_DSSSTABLE_CURRENTCHANNEL,
0454                         chan);
0455         if (result)
0456             goto exit;
0457     }
0458 
0459     /* Set the authorization */
0460     if ((sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) ||
0461         ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && !is_wep))
0462         msg_join.authtype.data = P80211ENUM_authalg_opensystem;
0463     else if ((sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) ||
0464          ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && is_wep))
0465         msg_join.authtype.data = P80211ENUM_authalg_sharedkey;
0466     else
0467         netdev_warn(dev,
0468                 "Unhandled authorisation type for connect (%d)\n",
0469                 sme->auth_type);
0470 
0471     /* Set the encryption - we only support wep */
0472     if (is_wep) {
0473         if (sme->key) {
0474             if (sme->key_idx >= NUM_WEPKEYS)
0475                 return -EINVAL;
0476 
0477             result = prism2_domibset_uint32(wlandev,
0478                             DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
0479                 sme->key_idx);
0480             if (result)
0481                 goto exit;
0482 
0483             /* send key to driver */
0484             did = didmib_dot11smt_wepdefaultkeystable_key(sme->key_idx + 1);
0485             result = prism2_domibset_pstr32(wlandev,
0486                             did, sme->key_len,
0487                             (u8 *)sme->key);
0488             if (result)
0489                 goto exit;
0490         }
0491 
0492         /* Assume we should set privacy invoked and exclude unencrypted
0493          * We could possible use sme->privacy here, but the assumption
0494          * seems reasonable anyways
0495          */
0496         result = prism2_domibset_uint32(wlandev,
0497                         DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED,
0498                         P80211ENUM_truth_true);
0499         if (result)
0500             goto exit;
0501 
0502         result = prism2_domibset_uint32(wlandev,
0503                         DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED,
0504                         P80211ENUM_truth_true);
0505         if (result)
0506             goto exit;
0507 
0508     } else {
0509         /* Assume we should unset privacy invoked
0510          * and exclude unencrypted
0511          */
0512         result = prism2_domibset_uint32(wlandev,
0513                         DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED,
0514                         P80211ENUM_truth_false);
0515         if (result)
0516             goto exit;
0517 
0518         result = prism2_domibset_uint32(wlandev,
0519                         DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED,
0520                         P80211ENUM_truth_false);
0521         if (result)
0522             goto exit;
0523     }
0524 
0525     /* Now do the actual join. Note there is no way that I can
0526      * see to request a specific bssid
0527      */
0528     msg_join.msgcode = DIDMSG_LNXREQ_AUTOJOIN;
0529 
0530     memcpy(msg_join.ssid.data.data, sme->ssid, length);
0531     msg_join.ssid.data.len = length;
0532 
0533     result = p80211req_dorequest(wlandev, (u8 *)&msg_join);
0534 
0535 exit:
0536     if (result)
0537         err = -EFAULT;
0538 
0539     return err;
0540 }
0541 
0542 static int prism2_disconnect(struct wiphy *wiphy, struct net_device *dev,
0543                  u16 reason_code)
0544 {
0545     struct wlandevice *wlandev = dev->ml_priv;
0546     struct p80211msg_lnxreq_autojoin msg_join;
0547     int result;
0548     int err = 0;
0549 
0550     /* Do a join, with a bogus ssid. Thats the only way I can think of */
0551     msg_join.msgcode = DIDMSG_LNXREQ_AUTOJOIN;
0552 
0553     memcpy(msg_join.ssid.data.data, "---", 3);
0554     msg_join.ssid.data.len = 3;
0555 
0556     result = p80211req_dorequest(wlandev, (u8 *)&msg_join);
0557 
0558     if (result)
0559         err = -EFAULT;
0560 
0561     return err;
0562 }
0563 
0564 static int prism2_join_ibss(struct wiphy *wiphy, struct net_device *dev,
0565                 struct cfg80211_ibss_params *params)
0566 {
0567     return -EOPNOTSUPP;
0568 }
0569 
0570 static int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
0571 {
0572     return -EOPNOTSUPP;
0573 }
0574 
0575 static int prism2_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
0576                    enum nl80211_tx_power_setting type, int mbm)
0577 {
0578     struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
0579     struct wlandevice *wlandev = priv->wlandev;
0580     u32 data;
0581     int result;
0582     int err = 0;
0583 
0584     if (type == NL80211_TX_POWER_AUTOMATIC)
0585         data = 30;
0586     else
0587         data = MBM_TO_DBM(mbm);
0588 
0589     result = prism2_domibset_uint32(wlandev,
0590                     DIDMIB_DOT11PHY_TXPOWERTABLE_CURRENTTXPOWERLEVEL,
0591         data);
0592 
0593     if (result) {
0594         err = -EFAULT;
0595         goto exit;
0596     }
0597 
0598 exit:
0599     return err;
0600 }
0601 
0602 static int prism2_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
0603                    int *dbm)
0604 {
0605     struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
0606     struct wlandevice *wlandev = priv->wlandev;
0607     struct p80211msg_dot11req_mibget msg;
0608     struct p80211item_uint32 *mibitem;
0609     int result;
0610     int err = 0;
0611 
0612     mibitem = (struct p80211item_uint32 *)&msg.mibattribute.data;
0613     msg.msgcode = DIDMSG_DOT11REQ_MIBGET;
0614     mibitem->did = DIDMIB_DOT11PHY_TXPOWERTABLE_CURRENTTXPOWERLEVEL;
0615 
0616     result = p80211req_dorequest(wlandev, (u8 *)&msg);
0617 
0618     if (result) {
0619         err = -EFAULT;
0620         goto exit;
0621     }
0622 
0623     *dbm = mibitem->data;
0624 
0625 exit:
0626     return err;
0627 }
0628 
0629 /* Interface callback functions, passing data back up to the cfg80211 layer */
0630 void prism2_connect_result(struct wlandevice *wlandev, u8 failed)
0631 {
0632     u16 status = failed ?
0633              WLAN_STATUS_UNSPECIFIED_FAILURE : WLAN_STATUS_SUCCESS;
0634 
0635     cfg80211_connect_result(wlandev->netdev, wlandev->bssid,
0636                 NULL, 0, NULL, 0, status, GFP_KERNEL);
0637 }
0638 
0639 void prism2_disconnected(struct wlandevice *wlandev)
0640 {
0641     cfg80211_disconnected(wlandev->netdev, 0, NULL,
0642                   0, false, GFP_KERNEL);
0643 }
0644 
0645 void prism2_roamed(struct wlandevice *wlandev)
0646 {
0647     struct cfg80211_roam_info roam_info = {
0648         .links[0].bssid = wlandev->bssid,
0649     };
0650 
0651     cfg80211_roamed(wlandev->netdev, &roam_info, GFP_KERNEL);
0652 }
0653 
0654 /* Structures for declaring wiphy interface */
0655 static const struct cfg80211_ops prism2_usb_cfg_ops = {
0656     .change_virtual_intf = prism2_change_virtual_intf,
0657     .add_key = prism2_add_key,
0658     .get_key = prism2_get_key,
0659     .del_key = prism2_del_key,
0660     .set_default_key = prism2_set_default_key,
0661     .get_station = prism2_get_station,
0662     .scan = prism2_scan,
0663     .set_wiphy_params = prism2_set_wiphy_params,
0664     .connect = prism2_connect,
0665     .disconnect = prism2_disconnect,
0666     .join_ibss = prism2_join_ibss,
0667     .leave_ibss = prism2_leave_ibss,
0668     .set_tx_power = prism2_set_tx_power,
0669     .get_tx_power = prism2_get_tx_power,
0670 };
0671 
0672 /* Functions to create/free wiphy interface */
0673 static struct wiphy *wlan_create_wiphy(struct device *dev,
0674                        struct wlandevice *wlandev)
0675 {
0676     struct wiphy *wiphy;
0677     struct prism2_wiphy_private *priv;
0678 
0679     wiphy = wiphy_new(&prism2_usb_cfg_ops, sizeof(*priv));
0680     if (!wiphy)
0681         return NULL;
0682 
0683     priv = wiphy_priv(wiphy);
0684     priv->wlandev = wlandev;
0685     memcpy(priv->channels, prism2_channels, sizeof(prism2_channels));
0686     memcpy(priv->rates, prism2_rates, sizeof(prism2_rates));
0687     priv->band.channels = priv->channels;
0688     priv->band.n_channels = ARRAY_SIZE(prism2_channels);
0689     priv->band.bitrates = priv->rates;
0690     priv->band.n_bitrates = ARRAY_SIZE(prism2_rates);
0691     priv->band.band = NL80211_BAND_2GHZ;
0692     priv->band.ht_cap.ht_supported = false;
0693     wiphy->bands[NL80211_BAND_2GHZ] = &priv->band;
0694 
0695     set_wiphy_dev(wiphy, dev);
0696     wiphy->privid = prism2_wiphy_privid;
0697     wiphy->max_scan_ssids = 1;
0698     wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
0699                  | BIT(NL80211_IFTYPE_ADHOC);
0700     wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
0701     wiphy->n_cipher_suites = PRISM2_NUM_CIPHER_SUITES;
0702     wiphy->cipher_suites = prism2_cipher_suites;
0703 
0704     if (wiphy_register(wiphy) < 0) {
0705         wiphy_free(wiphy);
0706         return NULL;
0707     }
0708 
0709     return wiphy;
0710 }
0711 
0712 static void wlan_free_wiphy(struct wiphy *wiphy)
0713 {
0714     wiphy_unregister(wiphy);
0715     wiphy_free(wiphy);
0716 }