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