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