Linux Audio

Check our new training course

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