cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cfg80211.c (17920B)


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