1 /* cfg80211 Interface for prism2_usb module */
2 #include "hfa384x.h"
3 #include "prism2mgmt.h"
4 
5 /* Prism2 channel/frequency/bitrate declarations */
6 static 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 
23 static 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
31 static 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 */
37 struct 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 
47 static const void * const prism2_wiphy_privid = &prism2_wiphy_privid;
48 
49 /* Helper Functions */
50 static 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 
72 static 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 
85 static 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 */
101 static 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 
139 exit:
140 	return err;
141 }
142 
143 static 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 
196 exit:
197 	if (result)
198 		err = -EFAULT;
199 
200 	return err;
201 }
202 
203 static 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 
233 static 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 
272 exit:
273 	if (result)
274 		err = -EFAULT;
275 
276 	return err;
277 }
278 
279 static 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 
297 static 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 
330 static 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 
440 exit:
441 	cfg80211_scan_done(request, err ? 1 : 0);
442 	priv->scan_request = NULL;
443 	return err;
444 }
445 
446 static 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 
484 exit:
485 	return err;
486 }
487 
488 static 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 
605 exit:
606 	if (result)
607 		err = -EFAULT;
608 
609 	return err;
610 }
611 
612 static 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 
634 static int prism2_join_ibss(struct wiphy *wiphy, struct net_device *dev,
635 			    struct cfg80211_ibss_params *params)
636 {
637 	return -EOPNOTSUPP;
638 }
639 
640 static int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
641 {
642 	return -EOPNOTSUPP;
643 }
644 
645 static 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 
668 exit:
669 	return err;
670 }
671 
672 static 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 
696 exit:
697 	return err;
698 }
699 
700 /* Interface callback functions, passing data back up to the cfg80211 layer */
701 void 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 
710 void prism2_disconnected(wlandevice_t *wlandev)
711 {
712 	cfg80211_disconnected(wlandev->netdev, 0, NULL,
713 		0, false, GFP_KERNEL);
714 }
715 
716 void 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 */
723 static 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 */
741 static 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 
777 static void wlan_free_wiphy(struct wiphy *wiphy)
778 {
779 	wiphy_unregister(wiphy);
780 	wiphy_free(wiphy);
781 }
782