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