1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2cb3126e6SKarl Relton /* cfg80211 Interface for prism2_usb module */
36eaf0788STair Rzayev #include "hfa384x.h"
46eaf0788STair Rzayev #include "prism2mgmt.h"
5cb3126e6SKarl Relton 
6d34602deSJustin P. Mattock /* Prism2 channel/frequency/bitrate declarations */
7cb3126e6SKarl Relton static const struct ieee80211_channel prism2_channels[] = {
8cb3126e6SKarl Relton 	{ .center_freq = 2412 },
9cb3126e6SKarl Relton 	{ .center_freq = 2417 },
10cb3126e6SKarl Relton 	{ .center_freq = 2422 },
11cb3126e6SKarl Relton 	{ .center_freq = 2427 },
12cb3126e6SKarl Relton 	{ .center_freq = 2432 },
13cb3126e6SKarl Relton 	{ .center_freq = 2437 },
14cb3126e6SKarl Relton 	{ .center_freq = 2442 },
15cb3126e6SKarl Relton 	{ .center_freq = 2447 },
16cb3126e6SKarl Relton 	{ .center_freq = 2452 },
17cb3126e6SKarl Relton 	{ .center_freq = 2457 },
18cb3126e6SKarl Relton 	{ .center_freq = 2462 },
19cb3126e6SKarl Relton 	{ .center_freq = 2467 },
20cb3126e6SKarl Relton 	{ .center_freq = 2472 },
21cb3126e6SKarl Relton 	{ .center_freq = 2484 },
22cb3126e6SKarl Relton };
23cb3126e6SKarl Relton 
24cb3126e6SKarl Relton static const struct ieee80211_rate prism2_rates[] = {
25cb3126e6SKarl Relton 	{ .bitrate = 10 },
26cb3126e6SKarl Relton 	{ .bitrate = 20 },
27cb3126e6SKarl Relton 	{ .bitrate = 55 },
28cb3126e6SKarl Relton 	{ .bitrate = 110 }
29cb3126e6SKarl Relton };
30cb3126e6SKarl Relton 
31cb3126e6SKarl Relton #define PRISM2_NUM_CIPHER_SUITES 2
32cb3126e6SKarl Relton static const u32 prism2_cipher_suites[PRISM2_NUM_CIPHER_SUITES] = {
33cb3126e6SKarl Relton 	WLAN_CIPHER_SUITE_WEP40,
34cb3126e6SKarl Relton 	WLAN_CIPHER_SUITE_WEP104
35cb3126e6SKarl Relton };
36cb3126e6SKarl Relton 
37cb3126e6SKarl Relton /* prism2 device private data */
38cb3126e6SKarl Relton struct prism2_wiphy_private {
39c9573a8dSsayli karnik 	struct wlandevice *wlandev;
40cb3126e6SKarl Relton 
41cb3126e6SKarl Relton 	struct ieee80211_supported_band band;
42cb3126e6SKarl Relton 	struct ieee80211_channel channels[ARRAY_SIZE(prism2_channels)];
43cb3126e6SKarl Relton 	struct ieee80211_rate rates[ARRAY_SIZE(prism2_rates)];
44cb3126e6SKarl Relton 
45cb3126e6SKarl Relton 	struct cfg80211_scan_request *scan_request;
46cb3126e6SKarl Relton };
47cb3126e6SKarl Relton 
48cb3126e6SKarl Relton static const void * const prism2_wiphy_privid = &prism2_wiphy_privid;
49cb3126e6SKarl Relton 
50cb3126e6SKarl Relton /* Helper Functions */
51cb3126e6SKarl Relton static int prism2_result2err(int prism2_result)
52cb3126e6SKarl Relton {
53cb3126e6SKarl Relton 	int err = 0;
54cb3126e6SKarl Relton 
55cb3126e6SKarl Relton 	switch (prism2_result) {
56cb3126e6SKarl Relton 	case P80211ENUM_resultcode_invalid_parameters:
57cb3126e6SKarl Relton 		err = -EINVAL;
58cb3126e6SKarl Relton 		break;
59cb3126e6SKarl Relton 	case P80211ENUM_resultcode_implementation_failure:
60cb3126e6SKarl Relton 		err = -EIO;
61cb3126e6SKarl Relton 		break;
62cb3126e6SKarl Relton 	case P80211ENUM_resultcode_not_supported:
63cb3126e6SKarl Relton 		err = -EOPNOTSUPP;
64cb3126e6SKarl Relton 		break;
65cb3126e6SKarl Relton 	default:
66cb3126e6SKarl Relton 		err = 0;
67cb3126e6SKarl Relton 		break;
68cb3126e6SKarl Relton 	}
69cb3126e6SKarl Relton 
70cb3126e6SKarl Relton 	return err;
71cb3126e6SKarl Relton }
72cb3126e6SKarl Relton 
73c2f4dd43SK Hodges static int prism2_domibset_uint32(struct wlandevice *wlandev,
74c2f4dd43SK Hodges 				  u32 did, u32 data)
75cb3126e6SKarl Relton {
76b6bb56e6SEdgardo Hames 	struct p80211msg_dot11req_mibset msg;
77b26b2325SSergio Paracuellos 	struct p80211item_uint32 *mibitem =
78b26b2325SSergio Paracuellos 			(struct p80211item_uint32 *)&msg.mibattribute.data;
79cb3126e6SKarl Relton 
80e409d2bcSTim Collier 	msg.msgcode = DIDMSG_DOT11REQ_MIBSET;
81cb3126e6SKarl Relton 	mibitem->did = did;
82cb3126e6SKarl Relton 	mibitem->data = data;
83cb3126e6SKarl Relton 
84cb3126e6SKarl Relton 	return p80211req_dorequest(wlandev, (u8 *)&msg);
85cb3126e6SKarl Relton }
86cb3126e6SKarl Relton 
87c9573a8dSsayli karnik static int prism2_domibset_pstr32(struct wlandevice *wlandev,
88c1e5f471SJohannes Berg 				  u32 did, u8 len, const u8 *data)
89cb3126e6SKarl Relton {
90b6bb56e6SEdgardo Hames 	struct p80211msg_dot11req_mibset msg;
916a50b5afSSergio Paracuellos 	struct p80211item_pstr32 *mibitem =
926a50b5afSSergio Paracuellos 			(struct p80211item_pstr32 *)&msg.mibattribute.data;
93cb3126e6SKarl Relton 
94e409d2bcSTim Collier 	msg.msgcode = DIDMSG_DOT11REQ_MIBSET;
95cb3126e6SKarl Relton 	mibitem->did = did;
96cb3126e6SKarl Relton 	mibitem->data.len = len;
97cb3126e6SKarl Relton 	memcpy(mibitem->data.data, data, len);
98cb3126e6SKarl Relton 
99cb3126e6SKarl Relton 	return p80211req_dorequest(wlandev, (u8 *)&msg);
100cb3126e6SKarl Relton }
101cb3126e6SKarl Relton 
102cb3126e6SKarl Relton /* The interface functions, called by the cfg80211 layer */
10355da06ebSTeodora Baluta static int prism2_change_virtual_intf(struct wiphy *wiphy,
104cb3126e6SKarl Relton 				      struct net_device *dev,
105818a986eSJohannes Berg 				      enum nl80211_iftype type,
106cb3126e6SKarl Relton 				      struct vif_params *params)
107cb3126e6SKarl Relton {
108c9573a8dSsayli karnik 	struct wlandevice *wlandev = dev->ml_priv;
109cb3126e6SKarl Relton 	u32 data;
110cb3126e6SKarl Relton 	int result;
111cb3126e6SKarl Relton 	int err = 0;
112cb3126e6SKarl Relton 
113cb3126e6SKarl Relton 	switch (type) {
114cb3126e6SKarl Relton 	case NL80211_IFTYPE_ADHOC:
1158dd82ebeSEdgardo Hames 		if (wlandev->macmode == WLAN_MACMODE_IBSS_STA)
1168dd82ebeSEdgardo Hames 			goto exit;
117cb3126e6SKarl Relton 		wlandev->macmode = WLAN_MACMODE_IBSS_STA;
118cb3126e6SKarl Relton 		data = 0;
119cb3126e6SKarl Relton 		break;
120cb3126e6SKarl Relton 	case NL80211_IFTYPE_STATION:
1218dd82ebeSEdgardo Hames 		if (wlandev->macmode == WLAN_MACMODE_ESS_STA)
1228dd82ebeSEdgardo Hames 			goto exit;
123cb3126e6SKarl Relton 		wlandev->macmode = WLAN_MACMODE_ESS_STA;
124cb3126e6SKarl Relton 		data = 1;
125cb3126e6SKarl Relton 		break;
126cb3126e6SKarl Relton 	default:
127eed88971SAvinash Kumar 		netdev_warn(dev, "Operation mode: %d not support\n", type);
128cb3126e6SKarl Relton 		return -EOPNOTSUPP;
129cb3126e6SKarl Relton 	}
130cb3126e6SKarl Relton 
131cb3126e6SKarl Relton 	/* Set Operation mode to the PORT TYPE RID */
1328aac4d44SDevendra Naga 	result = prism2_domibset_uint32(wlandev,
133a4857d8bSTim Collier 					DIDMIB_P2_STATIC_CNFPORTTYPE,
1348aac4d44SDevendra Naga 					data);
135cb3126e6SKarl Relton 
136cb3126e6SKarl Relton 	if (result)
137cb3126e6SKarl Relton 		err = -EFAULT;
138cb3126e6SKarl Relton 
139cb3126e6SKarl Relton 	dev->ieee80211_ptr->iftype = type;
140cb3126e6SKarl Relton 
141cb3126e6SKarl Relton exit:
142cb3126e6SKarl Relton 	return err;
143cb3126e6SKarl Relton }
144cb3126e6SKarl Relton 
14555da06ebSTeodora Baluta static int prism2_add_key(struct wiphy *wiphy, struct net_device *dev,
14634a488c1SBen Hutchings 			  u8 key_index, bool pairwise, const u8 *mac_addr,
1478dd82ebeSEdgardo Hames 			  struct key_params *params)
1488dd82ebeSEdgardo Hames {
149c9573a8dSsayli karnik 	struct wlandevice *wlandev = dev->ml_priv;
150cb3126e6SKarl Relton 	u32 did;
151cb3126e6SKarl Relton 
1520ca6d8e7SClaudiu Beznea 	if (key_index >= NUM_WEPKEYS)
1530ca6d8e7SClaudiu Beznea 		return -EINVAL;
1540ca6d8e7SClaudiu Beznea 
1556b142341SChris Opperman 	if (params->cipher != WLAN_CIPHER_SUITE_WEP40 &&
1566b142341SChris Opperman 	    params->cipher != WLAN_CIPHER_SUITE_WEP104) {
1576b142341SChris Opperman 		pr_debug("Unsupported cipher suite\n");
1586b142341SChris Opperman 		return -EFAULT;
1596b142341SChris Opperman 	}
1606b142341SChris Opperman 
1616b142341SChris Opperman 	if (prism2_domibset_uint32(wlandev,
162eeeeacd8STim Collier 				   DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
1636b142341SChris Opperman 				   key_index))
1646b142341SChris Opperman 		return -EFAULT;
165cb3126e6SKarl Relton 
166cb3126e6SKarl Relton 	/* send key to driver */
167ce0f34e4STim Collier 	did = didmib_dot11smt_wepdefaultkeystable_key(key_index + 1);
168cb3126e6SKarl Relton 
1696b142341SChris Opperman 	if (prism2_domibset_pstr32(wlandev, did, params->key_len, params->key))
1706b142341SChris Opperman 		return -EFAULT;
1716b142341SChris Opperman 	return 0;
172cb3126e6SKarl Relton }
173cb3126e6SKarl Relton 
17455da06ebSTeodora Baluta static int prism2_get_key(struct wiphy *wiphy, struct net_device *dev,
17555da06ebSTeodora Baluta 			  u8 key_index, bool pairwise,
17655da06ebSTeodora Baluta 			  const u8 *mac_addr, void *cookie,
1778dd82ebeSEdgardo Hames 			  void (*callback)(void *cookie, struct key_params*))
1788dd82ebeSEdgardo Hames {
179c9573a8dSsayli karnik 	struct wlandevice *wlandev = dev->ml_priv;
180cb3126e6SKarl Relton 	struct key_params params;
181cb3126e6SKarl Relton 	int len;
182cb3126e6SKarl Relton 
1838dd82ebeSEdgardo Hames 	if (key_index >= NUM_WEPKEYS)
1848dd82ebeSEdgardo Hames 		return -EINVAL;
185cb3126e6SKarl Relton 
186cb3126e6SKarl Relton 	len = wlandev->wep_keylens[key_index];
187cb3126e6SKarl Relton 	memset(&params, 0, sizeof(params));
188cb3126e6SKarl Relton 
1898dd82ebeSEdgardo Hames 	if (len == 13)
190cb3126e6SKarl Relton 		params.cipher = WLAN_CIPHER_SUITE_WEP104;
1918dd82ebeSEdgardo Hames 	else if (len == 5)
192cb3126e6SKarl Relton 		params.cipher = WLAN_CIPHER_SUITE_WEP104;
1938dd82ebeSEdgardo Hames 	else
1948dd82ebeSEdgardo Hames 		return -ENOENT;
195cb3126e6SKarl Relton 	params.key_len = len;
196cb3126e6SKarl Relton 	params.key = wlandev->wep_keys[key_index];
197aff3ea4eSKarl Relton 	params.seq_len = 0;
198cb3126e6SKarl Relton 
199cb3126e6SKarl Relton 	callback(cookie, &params);
2008dd82ebeSEdgardo Hames 
201cb3126e6SKarl Relton 	return 0;
202cb3126e6SKarl Relton }
203cb3126e6SKarl Relton 
20455da06ebSTeodora Baluta static int prism2_del_key(struct wiphy *wiphy, struct net_device *dev,
20534a488c1SBen Hutchings 			  u8 key_index, bool pairwise, const u8 *mac_addr)
2068dd82ebeSEdgardo Hames {
207c9573a8dSsayli karnik 	struct wlandevice *wlandev = dev->ml_priv;
208cb3126e6SKarl Relton 	u32 did;
209cb3126e6SKarl Relton 	int err = 0;
210cb3126e6SKarl Relton 	int result = 0;
211cb3126e6SKarl Relton 
212cb3126e6SKarl Relton 	/* There is no direct way in the hardware (AFAIK) of removing
21335028fe1SGavin O'Leary 	 * a key, so we will cheat by setting the key to a bogus value
21435028fe1SGavin O'Leary 	 */
21535028fe1SGavin O'Leary 
2160ca6d8e7SClaudiu Beznea 	if (key_index >= NUM_WEPKEYS)
2170ca6d8e7SClaudiu Beznea 		return -EINVAL;
2180ca6d8e7SClaudiu Beznea 
219cb3126e6SKarl Relton 	/* send key to driver */
220ce0f34e4STim Collier 	did = didmib_dot11smt_wepdefaultkeystable_key(key_index + 1);
221cb3126e6SKarl Relton 	result = prism2_domibset_pstr32(wlandev, did, 13, "0000000000000");
222cb3126e6SKarl Relton 
2238dd82ebeSEdgardo Hames 	if (result)
2248dd82ebeSEdgardo Hames 		err = -EFAULT;
225cb3126e6SKarl Relton 
226cb3126e6SKarl Relton 	return err;
227cb3126e6SKarl Relton }
228cb3126e6SKarl Relton 
22955da06ebSTeodora Baluta static int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev,
2309005fcd8SHarry Wei 				  u8 key_index, bool unicast, bool multicast)
2318dd82ebeSEdgardo Hames {
232c9573a8dSsayli karnik 	struct wlandevice *wlandev = dev->ml_priv;
233cb3126e6SKarl Relton 
234f0f74b45SHariprasad Kelam 	return  prism2_domibset_uint32(wlandev,
235eeeeacd8STim Collier 				       DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
236cb3126e6SKarl Relton 				       key_index);
237cb3126e6SKarl Relton }
238cb3126e6SKarl Relton 
23955da06ebSTeodora Baluta static int prism2_get_station(struct wiphy *wiphy, struct net_device *dev,
2403b3a0162SJohannes Berg 			      const u8 *mac, struct station_info *sinfo)
2418dd82ebeSEdgardo Hames {
242c9573a8dSsayli karnik 	struct wlandevice *wlandev = dev->ml_priv;
243b6bb56e6SEdgardo Hames 	struct p80211msg_lnxreq_commsquality quality;
244cb3126e6SKarl Relton 	int result;
245cb3126e6SKarl Relton 
246cb3126e6SKarl Relton 	memset(sinfo, 0, sizeof(*sinfo));
247cb3126e6SKarl Relton 
248e52f2149SSandhya Bankar 	if (!wlandev || (wlandev->msdstate != WLAN_MSD_RUNNING))
249cb3126e6SKarl Relton 		return -EOPNOTSUPP;
250cb3126e6SKarl Relton 
251cb3126e6SKarl Relton 	/* build request message */
2523b6ee123STim Collier 	quality.msgcode = DIDMSG_LNXREQ_COMMSQUALITY;
253cb3126e6SKarl Relton 	quality.dbm.data = P80211ENUM_truth_true;
254cb3126e6SKarl Relton 	quality.dbm.status = P80211ENUM_msgitem_status_data_ok;
255cb3126e6SKarl Relton 
256cb3126e6SKarl Relton 	/* send message to nsd */
257e52f2149SSandhya Bankar 	if (!wlandev->mlmerequest)
258cb3126e6SKarl Relton 		return -EOPNOTSUPP;
259cb3126e6SKarl Relton 
2603d049431SEdgardo Hames 	result = wlandev->mlmerequest(wlandev, (struct p80211msg *)&quality);
261cb3126e6SKarl Relton 
262cb3126e6SKarl Relton 	if (result == 0) {
263cb3126e6SKarl Relton 		sinfo->txrate.legacy = quality.txrate.data;
2645c6a5eb3SOmer Efrat 		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
265cb3126e6SKarl Relton 		sinfo->signal = quality.level.data;
2665c6a5eb3SOmer Efrat 		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
267cb3126e6SKarl Relton 	}
268cb3126e6SKarl Relton 
269cb3126e6SKarl Relton 	return result;
270cb3126e6SKarl Relton }
271cb3126e6SKarl Relton 
272bb1da756SHimangi Saraogi static int prism2_scan(struct wiphy *wiphy,
273bb1da756SHimangi Saraogi 		       struct cfg80211_scan_request *request)
274cb3126e6SKarl Relton {
2755d5d7c3bSEmil Goode 	struct net_device *dev;
276cb3126e6SKarl Relton 	struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
277c9573a8dSsayli karnik 	struct wlandevice *wlandev;
278b6bb56e6SEdgardo Hames 	struct p80211msg_dot11req_scan msg1;
279ea82ff74SLee Jones 	struct p80211msg_dot11req_scan_results *msg2;
28019f798adSKrzysztof Wilczynski 	struct cfg80211_bss *bss;
2811d76250bSAvraham Stern 	struct cfg80211_scan_info info = {};
2821d76250bSAvraham Stern 
283cb3126e6SKarl Relton 	int result;
284cb3126e6SKarl Relton 	int err = 0;
285cb3126e6SKarl Relton 	int numbss = 0;
286cb3126e6SKarl Relton 	int i = 0;
287cb3126e6SKarl Relton 	u8 ie_buf[46];
288cb3126e6SKarl Relton 	int ie_len;
289cb3126e6SKarl Relton 
290cb3126e6SKarl Relton 	if (!request)
291cb3126e6SKarl Relton 		return -EINVAL;
292cb3126e6SKarl Relton 
2935d5d7c3bSEmil Goode 	dev = request->wdev->netdev;
2945d5d7c3bSEmil Goode 	wlandev = dev->ml_priv;
2955d5d7c3bSEmil Goode 
296cb3126e6SKarl Relton 	if (priv->scan_request && priv->scan_request != request)
297cb3126e6SKarl Relton 		return -EBUSY;
298cb3126e6SKarl Relton 
299cb3126e6SKarl Relton 	if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
300eed88971SAvinash Kumar 		netdev_err(dev, "Can't scan in AP mode\n");
301cb3126e6SKarl Relton 		return -EOPNOTSUPP;
302cb3126e6SKarl Relton 	}
303cb3126e6SKarl Relton 
304ea82ff74SLee Jones 	msg2 = kzalloc(sizeof(*msg2), GFP_KERNEL);
305ea82ff74SLee Jones 	if (!msg2)
306ea82ff74SLee Jones 		return -ENOMEM;
307ea82ff74SLee Jones 
308cb3126e6SKarl Relton 	priv->scan_request = request;
309cb3126e6SKarl Relton 
31089e13b45SSergio Paracuellos 	memset(&msg1, 0x00, sizeof(msg1));
3111ffaa906STim Collier 	msg1.msgcode = DIDMSG_DOT11REQ_SCAN;
312cb3126e6SKarl Relton 	msg1.bsstype.data = P80211ENUM_bsstype_any;
313cb3126e6SKarl Relton 
314625aeb3aSDan Carpenter 	memset(&msg1.bssid.data.data, 0xFF, sizeof(msg1.bssid.data.data));
315cb3126e6SKarl Relton 	msg1.bssid.data.len = 6;
316cb3126e6SKarl Relton 
317cb3126e6SKarl Relton 	if (request->n_ssids > 0) {
318cb3126e6SKarl Relton 		msg1.scantype.data = P80211ENUM_scantype_active;
319cb3126e6SKarl Relton 		msg1.ssid.data.len = request->ssids->ssid_len;
3208aac4d44SDevendra Naga 		memcpy(msg1.ssid.data.data,
3218aac4d44SDevendra Naga 		       request->ssids->ssid, request->ssids->ssid_len);
322cb3126e6SKarl Relton 	} else {
323cb3126e6SKarl Relton 		msg1.scantype.data = 0;
324cb3126e6SKarl Relton 	}
325cb3126e6SKarl Relton 	msg1.probedelay.data = 0;
326cb3126e6SKarl Relton 
327cb3126e6SKarl Relton 	for (i = 0;
328cb3126e6SKarl Relton 		(i < request->n_channels) && i < ARRAY_SIZE(prism2_channels);
329cb3126e6SKarl Relton 		i++)
330cb3126e6SKarl Relton 		msg1.channellist.data.data[i] =
331*00bb97ddSAlaa Mohamed 			ieee80211_frequency_to_channel(request->channels[i]->center_freq);
332cb3126e6SKarl Relton 	msg1.channellist.data.len = request->n_channels;
333cb3126e6SKarl Relton 
334cb3126e6SKarl Relton 	msg1.maxchanneltime.data = 250;
335cb3126e6SKarl Relton 	msg1.minchanneltime.data = 200;
336cb3126e6SKarl Relton 
337cb3126e6SKarl Relton 	result = p80211req_dorequest(wlandev, (u8 *)&msg1);
338cb3126e6SKarl Relton 	if (result) {
339cb3126e6SKarl Relton 		err = prism2_result2err(msg1.resultcode.data);
340cb3126e6SKarl Relton 		goto exit;
341cb3126e6SKarl Relton 	}
342cb3126e6SKarl Relton 	/* Now retrieve scan results */
343cb3126e6SKarl Relton 	numbss = msg1.numbss.data;
344cb3126e6SKarl Relton 
345cb3126e6SKarl Relton 	for (i = 0; i < numbss; i++) {
3464e5e9d7cSZhao, Gang 		int freq;
3474e5e9d7cSZhao, Gang 
348ea82ff74SLee Jones 		msg2->msgcode = DIDMSG_DOT11REQ_SCAN_RESULTS;
349ea82ff74SLee Jones 		msg2->bssindex.data = i;
350cb3126e6SKarl Relton 
351cb3126e6SKarl Relton 		result = p80211req_dorequest(wlandev, (u8 *)&msg2);
352cb3126e6SKarl Relton 		if ((result != 0) ||
353ea82ff74SLee Jones 		    (msg2->resultcode.data != P80211ENUM_resultcode_success)) {
354cb3126e6SKarl Relton 			break;
355cb3126e6SKarl Relton 		}
356cb3126e6SKarl Relton 
357cb3126e6SKarl Relton 		ie_buf[0] = WLAN_EID_SSID;
358ea82ff74SLee Jones 		ie_buf[1] = msg2->ssid.data.len;
359cb3126e6SKarl Relton 		ie_len = ie_buf[1] + 2;
360ea82ff74SLee Jones 		memcpy(&ie_buf[2], &msg2->ssid.data.data, msg2->ssid.data.len);
361ea82ff74SLee Jones 		freq = ieee80211_channel_to_frequency(msg2->dschannel.data,
36257fbcce3SJohannes Berg 						      NL80211_BAND_2GHZ);
36319f798adSKrzysztof Wilczynski 		bss = cfg80211_inform_bss(wiphy,
3644e5e9d7cSZhao, Gang 					  ieee80211_get_channel(wiphy, freq),
3655bc8c1f2SJohannes Berg 					  CFG80211_BSS_FTYPE_UNKNOWN,
366ea82ff74SLee Jones 					  (const u8 *)&msg2->bssid.data.data,
367ea82ff74SLee Jones 					  msg2->timestamp.data, msg2->capinfo.data,
368ea82ff74SLee Jones 					  msg2->beaconperiod.data,
369cb3126e6SKarl Relton 					  ie_buf,
370cb3126e6SKarl Relton 					  ie_len,
371ea82ff74SLee Jones 					  (msg2->signal.data - 65536) * 100, /* Conversion to signed type */
37215d25ed7SSumera Priyadarsini 					  GFP_KERNEL);
37319f798adSKrzysztof Wilczynski 
37419f798adSKrzysztof Wilczynski 		if (!bss) {
37519f798adSKrzysztof Wilczynski 			err = -ENOMEM;
37619f798adSKrzysztof Wilczynski 			goto exit;
37719f798adSKrzysztof Wilczynski 		}
37819f798adSKrzysztof Wilczynski 
3795b112d3dSJohannes Berg 		cfg80211_put_bss(wiphy, bss);
380cb3126e6SKarl Relton 	}
381cb3126e6SKarl Relton 
3828dd82ebeSEdgardo Hames 	if (result)
383ea82ff74SLee Jones 		err = prism2_result2err(msg2->resultcode.data);
384cb3126e6SKarl Relton 
385cb3126e6SKarl Relton exit:
3861d76250bSAvraham Stern 	info.aborted = !!(err);
3871d76250bSAvraham Stern 	cfg80211_scan_done(request, &info);
388cb3126e6SKarl Relton 	priv->scan_request = NULL;
389ea82ff74SLee Jones 	kfree(msg2);
390cb3126e6SKarl Relton 	return err;
391cb3126e6SKarl Relton }
392cb3126e6SKarl Relton 
39355da06ebSTeodora Baluta static int prism2_set_wiphy_params(struct wiphy *wiphy, u32 changed)
3948dd82ebeSEdgardo Hames {
395cb3126e6SKarl Relton 	struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
396c9573a8dSsayli karnik 	struct wlandevice *wlandev = priv->wlandev;
397cb3126e6SKarl Relton 	u32 data;
398cb3126e6SKarl Relton 	int result;
399cb3126e6SKarl Relton 	int err = 0;
400cb3126e6SKarl Relton 
401cb3126e6SKarl Relton 	if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
402cb3126e6SKarl Relton 		if (wiphy->rts_threshold == -1)
403cb3126e6SKarl Relton 			data = 2347;
404cb3126e6SKarl Relton 		else
405cb3126e6SKarl Relton 			data = wiphy->rts_threshold;
406cb3126e6SKarl Relton 
4078dd82ebeSEdgardo Hames 		result = prism2_domibset_uint32(wlandev,
408334e5e68STim Collier 						DIDMIB_DOT11MAC_OPERATIONTABLE_RTSTHRESHOLD,
409cb3126e6SKarl Relton 						data);
410cb3126e6SKarl Relton 		if (result) {
411cb3126e6SKarl Relton 			err = -EFAULT;
412cb3126e6SKarl Relton 			goto exit;
413cb3126e6SKarl Relton 		}
414cb3126e6SKarl Relton 	}
415cb3126e6SKarl Relton 
416cb3126e6SKarl Relton 	if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
417cb3126e6SKarl Relton 		if (wiphy->frag_threshold == -1)
418cb3126e6SKarl Relton 			data = 2346;
419cb3126e6SKarl Relton 		else
420cb3126e6SKarl Relton 			data = wiphy->frag_threshold;
421cb3126e6SKarl Relton 
4228dd82ebeSEdgardo Hames 		result = prism2_domibset_uint32(wlandev,
42304bbfc2aSTim Collier 						DIDMIB_DOT11MAC_OPERATIONTABLE_FRAGMENTATIONTHRESHOLD,
424cb3126e6SKarl Relton 						data);
425cb3126e6SKarl Relton 		if (result) {
426cb3126e6SKarl Relton 			err = -EFAULT;
427cb3126e6SKarl Relton 			goto exit;
428cb3126e6SKarl Relton 		}
429cb3126e6SKarl Relton 	}
430cb3126e6SKarl Relton 
431cb3126e6SKarl Relton exit:
432cb3126e6SKarl Relton 	return err;
433cb3126e6SKarl Relton }
434cb3126e6SKarl Relton 
43555da06ebSTeodora Baluta static int prism2_connect(struct wiphy *wiphy, struct net_device *dev,
4368dd82ebeSEdgardo Hames 			  struct cfg80211_connect_params *sme)
4378dd82ebeSEdgardo Hames {
438c9573a8dSsayli karnik 	struct wlandevice *wlandev = dev->ml_priv;
439cb3126e6SKarl Relton 	struct ieee80211_channel *channel = sme->channel;
440b6bb56e6SEdgardo Hames 	struct p80211msg_lnxreq_autojoin msg_join;
441cb3126e6SKarl Relton 	u32 did;
442cb3126e6SKarl Relton 	int length = sme->ssid_len;
443cb3126e6SKarl Relton 	int chan = -1;
444cb3126e6SKarl Relton 	int is_wep = (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) ||
445cb3126e6SKarl Relton 	    (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104);
446cb3126e6SKarl Relton 	int result;
447cb3126e6SKarl Relton 	int err = 0;
448cb3126e6SKarl Relton 
449cb3126e6SKarl Relton 	/* Set the channel */
450cb3126e6SKarl Relton 	if (channel) {
451cb3126e6SKarl Relton 		chan = ieee80211_frequency_to_channel(channel->center_freq);
4528dd82ebeSEdgardo Hames 		result = prism2_domibset_uint32(wlandev,
45393d5a1dcSTim Collier 						DIDMIB_DOT11PHY_DSSSTABLE_CURRENTCHANNEL,
454cb3126e6SKarl Relton 						chan);
4558dd82ebeSEdgardo Hames 		if (result)
4568dd82ebeSEdgardo Hames 			goto exit;
457cb3126e6SKarl Relton 	}
458cb3126e6SKarl Relton 
459d34602deSJustin P. Mattock 	/* Set the authorization */
460cb3126e6SKarl Relton 	if ((sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) ||
461cb3126e6SKarl Relton 	    ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && !is_wep))
462cb3126e6SKarl Relton 		msg_join.authtype.data = P80211ENUM_authalg_opensystem;
463cb3126e6SKarl Relton 	else if ((sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) ||
464cb3126e6SKarl Relton 		 ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && is_wep))
465cb3126e6SKarl Relton 		msg_join.authtype.data = P80211ENUM_authalg_sharedkey;
4668dd82ebeSEdgardo Hames 	else
467eed88971SAvinash Kumar 		netdev_warn(dev,
4688dd82ebeSEdgardo Hames 			    "Unhandled authorisation type for connect (%d)\n",
4698dd82ebeSEdgardo Hames 			    sme->auth_type);
470cb3126e6SKarl Relton 
471cb3126e6SKarl Relton 	/* Set the encryption - we only support wep */
472cb3126e6SKarl Relton 	if (is_wep) {
473cb3126e6SKarl Relton 		if (sme->key) {
474153c5d81SColin Ian King 			if (sme->key_idx >= NUM_WEPKEYS)
475153c5d81SColin Ian King 				return -EINVAL;
4760ca6d8e7SClaudiu Beznea 
477cb3126e6SKarl Relton 			result = prism2_domibset_uint32(wlandev,
478eeeeacd8STim Collier 				DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
479cb3126e6SKarl Relton 				sme->key_idx);
4808dd82ebeSEdgardo Hames 			if (result)
4818dd82ebeSEdgardo Hames 				goto exit;
482cb3126e6SKarl Relton 
483cb3126e6SKarl Relton 			/* send key to driver */
484*00bb97ddSAlaa Mohamed 			did = didmib_dot11smt_wepdefaultkeystable_key(sme->key_idx + 1);
4858aac4d44SDevendra Naga 			result = prism2_domibset_pstr32(wlandev,
4868aac4d44SDevendra Naga 							did, sme->key_len,
4878aac4d44SDevendra Naga 							(u8 *)sme->key);
4888dd82ebeSEdgardo Hames 			if (result)
4898dd82ebeSEdgardo Hames 				goto exit;
490cb3126e6SKarl Relton 		}
491cb3126e6SKarl Relton 
492cb3126e6SKarl Relton 		/* Assume we should set privacy invoked and exclude unencrypted
49335028fe1SGavin O'Leary 		 * We could possible use sme->privacy here, but the assumption
49435028fe1SGavin O'Leary 		 * seems reasonable anyways
49535028fe1SGavin O'Leary 		 */
4968dd82ebeSEdgardo Hames 		result = prism2_domibset_uint32(wlandev,
497184fcaa1STim Collier 						DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED,
498cb3126e6SKarl Relton 						P80211ENUM_truth_true);
4998dd82ebeSEdgardo Hames 		if (result)
5008dd82ebeSEdgardo Hames 			goto exit;
5018dd82ebeSEdgardo Hames 
5028dd82ebeSEdgardo Hames 		result = prism2_domibset_uint32(wlandev,
5032ddc995dSTim Collier 						DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED,
504cb3126e6SKarl Relton 						P80211ENUM_truth_true);
5058dd82ebeSEdgardo Hames 		if (result)
5068dd82ebeSEdgardo Hames 			goto exit;
507cb3126e6SKarl Relton 
508cb3126e6SKarl Relton 	} else {
5098dd82ebeSEdgardo Hames 		/* Assume we should unset privacy invoked
51035028fe1SGavin O'Leary 		 * and exclude unencrypted
51135028fe1SGavin O'Leary 		 */
5128dd82ebeSEdgardo Hames 		result = prism2_domibset_uint32(wlandev,
513184fcaa1STim Collier 						DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED,
514cb3126e6SKarl Relton 						P80211ENUM_truth_false);
5158dd82ebeSEdgardo Hames 		if (result)
5168dd82ebeSEdgardo Hames 			goto exit;
5178dd82ebeSEdgardo Hames 
5188dd82ebeSEdgardo Hames 		result = prism2_domibset_uint32(wlandev,
5192ddc995dSTim Collier 						DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED,
520cb3126e6SKarl Relton 						P80211ENUM_truth_false);
5218dd82ebeSEdgardo Hames 		if (result)
5228dd82ebeSEdgardo Hames 			goto exit;
523cb3126e6SKarl Relton 	}
524cb3126e6SKarl Relton 
525cb3126e6SKarl Relton 	/* Now do the actual join. Note there is no way that I can
5264f9de774SGavin O'Leary 	 * see to request a specific bssid
5274f9de774SGavin O'Leary 	 */
528b1f1118bSTim Collier 	msg_join.msgcode = DIDMSG_LNXREQ_AUTOJOIN;
529cb3126e6SKarl Relton 
530cb3126e6SKarl Relton 	memcpy(msg_join.ssid.data.data, sme->ssid, length);
531cb3126e6SKarl Relton 	msg_join.ssid.data.len = length;
532cb3126e6SKarl Relton 
533cb3126e6SKarl Relton 	result = p80211req_dorequest(wlandev, (u8 *)&msg_join);
534cb3126e6SKarl Relton 
535cb3126e6SKarl Relton exit:
5368dd82ebeSEdgardo Hames 	if (result)
5378dd82ebeSEdgardo Hames 		err = -EFAULT;
538cb3126e6SKarl Relton 
539cb3126e6SKarl Relton 	return err;
540cb3126e6SKarl Relton }
541cb3126e6SKarl Relton 
54255da06ebSTeodora Baluta static int prism2_disconnect(struct wiphy *wiphy, struct net_device *dev,
5438dd82ebeSEdgardo Hames 			     u16 reason_code)
5448dd82ebeSEdgardo Hames {
545c9573a8dSsayli karnik 	struct wlandevice *wlandev = dev->ml_priv;
546b6bb56e6SEdgardo Hames 	struct p80211msg_lnxreq_autojoin msg_join;
547cb3126e6SKarl Relton 	int result;
548cb3126e6SKarl Relton 	int err = 0;
549cb3126e6SKarl Relton 
550cb3126e6SKarl Relton 	/* Do a join, with a bogus ssid. Thats the only way I can think of */
551b1f1118bSTim Collier 	msg_join.msgcode = DIDMSG_LNXREQ_AUTOJOIN;
552cb3126e6SKarl Relton 
553cb3126e6SKarl Relton 	memcpy(msg_join.ssid.data.data, "---", 3);
554cb3126e6SKarl Relton 	msg_join.ssid.data.len = 3;
555cb3126e6SKarl Relton 
556cb3126e6SKarl Relton 	result = p80211req_dorequest(wlandev, (u8 *)&msg_join);
557cb3126e6SKarl Relton 
5588dd82ebeSEdgardo Hames 	if (result)
5598dd82ebeSEdgardo Hames 		err = -EFAULT;
560cb3126e6SKarl Relton 
561cb3126e6SKarl Relton 	return err;
562cb3126e6SKarl Relton }
563cb3126e6SKarl Relton 
56455da06ebSTeodora Baluta static int prism2_join_ibss(struct wiphy *wiphy, struct net_device *dev,
5658dd82ebeSEdgardo Hames 			    struct cfg80211_ibss_params *params)
5668dd82ebeSEdgardo Hames {
567cb3126e6SKarl Relton 	return -EOPNOTSUPP;
568cb3126e6SKarl Relton }
569cb3126e6SKarl Relton 
57055da06ebSTeodora Baluta static int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
5718dd82ebeSEdgardo Hames {
572cb3126e6SKarl Relton 	return -EOPNOTSUPP;
573cb3126e6SKarl Relton }
574cb3126e6SKarl Relton 
57555da06ebSTeodora Baluta static int prism2_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
5765f3b361aSEmil Goode 			       enum nl80211_tx_power_setting type, int mbm)
5778dd82ebeSEdgardo Hames {
578cb3126e6SKarl Relton 	struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
579c9573a8dSsayli karnik 	struct wlandevice *wlandev = priv->wlandev;
580cb3126e6SKarl Relton 	u32 data;
581cb3126e6SKarl Relton 	int result;
582cb3126e6SKarl Relton 	int err = 0;
583cb3126e6SKarl Relton 
5849015e499SChristoph Fritz 	if (type == NL80211_TX_POWER_AUTOMATIC)
585cb3126e6SKarl Relton 		data = 30;
586cb3126e6SKarl Relton 	else
5879015e499SChristoph Fritz 		data = MBM_TO_DBM(mbm);
588cb3126e6SKarl Relton 
589cb3126e6SKarl Relton 	result = prism2_domibset_uint32(wlandev,
590c9a89f4eSTim Collier 		DIDMIB_DOT11PHY_TXPOWERTABLE_CURRENTTXPOWERLEVEL,
591cb3126e6SKarl Relton 		data);
592cb3126e6SKarl Relton 
593cb3126e6SKarl Relton 	if (result) {
594cb3126e6SKarl Relton 		err = -EFAULT;
595cb3126e6SKarl Relton 		goto exit;
596cb3126e6SKarl Relton 	}
597cb3126e6SKarl Relton 
598cb3126e6SKarl Relton exit:
599cb3126e6SKarl Relton 	return err;
600cb3126e6SKarl Relton }
601cb3126e6SKarl Relton 
60255da06ebSTeodora Baluta static int prism2_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
6035f3b361aSEmil Goode 			       int *dbm)
6048dd82ebeSEdgardo Hames {
605cb3126e6SKarl Relton 	struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
606c9573a8dSsayli karnik 	struct wlandevice *wlandev = priv->wlandev;
607b6bb56e6SEdgardo Hames 	struct p80211msg_dot11req_mibget msg;
608b26b2325SSergio Paracuellos 	struct p80211item_uint32 *mibitem;
609cb3126e6SKarl Relton 	int result;
610cb3126e6SKarl Relton 	int err = 0;
611cb3126e6SKarl Relton 
612b26b2325SSergio Paracuellos 	mibitem = (struct p80211item_uint32 *)&msg.mibattribute.data;
61308ac8573STim Collier 	msg.msgcode = DIDMSG_DOT11REQ_MIBGET;
61404950c3fSTim Collier 	mibitem->did = DIDMIB_DOT11PHY_TXPOWERTABLE_CURRENTTXPOWERLEVEL;
615cb3126e6SKarl Relton 
616cb3126e6SKarl Relton 	result = p80211req_dorequest(wlandev, (u8 *)&msg);
617cb3126e6SKarl Relton 
618cb3126e6SKarl Relton 	if (result) {
619cb3126e6SKarl Relton 		err = -EFAULT;
620cb3126e6SKarl Relton 		goto exit;
621cb3126e6SKarl Relton 	}
622cb3126e6SKarl Relton 
623cb3126e6SKarl Relton 	*dbm = mibitem->data;
624cb3126e6SKarl Relton 
625cb3126e6SKarl Relton exit:
626cb3126e6SKarl Relton 	return err;
627cb3126e6SKarl Relton }
628cb3126e6SKarl Relton 
629cb3126e6SKarl Relton /* Interface callback functions, passing data back up to the cfg80211 layer */
630c9573a8dSsayli karnik void prism2_connect_result(struct wlandevice *wlandev, u8 failed)
6318dd82ebeSEdgardo Hames {
6328aac4d44SDevendra Naga 	u16 status = failed ?
6338aac4d44SDevendra Naga 		     WLAN_STATUS_UNSPECIFIED_FAILURE : WLAN_STATUS_SUCCESS;
634cb3126e6SKarl Relton 
635cb3126e6SKarl Relton 	cfg80211_connect_result(wlandev->netdev, wlandev->bssid,
6368dd82ebeSEdgardo Hames 				NULL, 0, NULL, 0, status, GFP_KERNEL);
637cb3126e6SKarl Relton }
638cb3126e6SKarl Relton 
639c9573a8dSsayli karnik void prism2_disconnected(struct wlandevice *wlandev)
6408dd82ebeSEdgardo Hames {
641cb3126e6SKarl Relton 	cfg80211_disconnected(wlandev->netdev, 0, NULL,
64280279fb7SJohannes Berg 			      0, false, GFP_KERNEL);
643cb3126e6SKarl Relton }
644cb3126e6SKarl Relton 
645c9573a8dSsayli karnik void prism2_roamed(struct wlandevice *wlandev)
6468dd82ebeSEdgardo Hames {
64729ce6ecbSAvraham Stern 	struct cfg80211_roam_info roam_info = {
64829ce6ecbSAvraham Stern 		.bssid = wlandev->bssid,
64929ce6ecbSAvraham Stern 	};
65029ce6ecbSAvraham Stern 
65129ce6ecbSAvraham Stern 	cfg80211_roamed(wlandev->netdev, &roam_info, GFP_KERNEL);
652cb3126e6SKarl Relton }
653cb3126e6SKarl Relton 
654cb3126e6SKarl Relton /* Structures for declaring wiphy interface */
655cb3126e6SKarl Relton static const struct cfg80211_ops prism2_usb_cfg_ops = {
656cb3126e6SKarl Relton 	.change_virtual_intf = prism2_change_virtual_intf,
657cb3126e6SKarl Relton 	.add_key = prism2_add_key,
658cb3126e6SKarl Relton 	.get_key = prism2_get_key,
659cb3126e6SKarl Relton 	.del_key = prism2_del_key,
660cb3126e6SKarl Relton 	.set_default_key = prism2_set_default_key,
661cb3126e6SKarl Relton 	.get_station = prism2_get_station,
662cb3126e6SKarl Relton 	.scan = prism2_scan,
663cb3126e6SKarl Relton 	.set_wiphy_params = prism2_set_wiphy_params,
664cb3126e6SKarl Relton 	.connect = prism2_connect,
665cb3126e6SKarl Relton 	.disconnect = prism2_disconnect,
666cb3126e6SKarl Relton 	.join_ibss = prism2_join_ibss,
667cb3126e6SKarl Relton 	.leave_ibss = prism2_leave_ibss,
668cb3126e6SKarl Relton 	.set_tx_power = prism2_set_tx_power,
669cb3126e6SKarl Relton 	.get_tx_power = prism2_get_tx_power,
670cb3126e6SKarl Relton };
671cb3126e6SKarl Relton 
672cb3126e6SKarl Relton /* Functions to create/free wiphy interface */
673285376ffSTim Collier static struct wiphy *wlan_create_wiphy(struct device *dev,
674285376ffSTim Collier 				       struct wlandevice *wlandev)
675cb3126e6SKarl Relton {
676cb3126e6SKarl Relton 	struct wiphy *wiphy;
677cb3126e6SKarl Relton 	struct prism2_wiphy_private *priv;
6788aac4d44SDevendra Naga 
6798aac4d44SDevendra Naga 	wiphy = wiphy_new(&prism2_usb_cfg_ops, sizeof(*priv));
680cb3126e6SKarl Relton 	if (!wiphy)
681cb3126e6SKarl Relton 		return NULL;
682cb3126e6SKarl Relton 
683cb3126e6SKarl Relton 	priv = wiphy_priv(wiphy);
684cb3126e6SKarl Relton 	priv->wlandev = wlandev;
685cb3126e6SKarl Relton 	memcpy(priv->channels, prism2_channels, sizeof(prism2_channels));
686cb3126e6SKarl Relton 	memcpy(priv->rates, prism2_rates, sizeof(prism2_rates));
687cb3126e6SKarl Relton 	priv->band.channels = priv->channels;
688cb3126e6SKarl Relton 	priv->band.n_channels = ARRAY_SIZE(prism2_channels);
689cb3126e6SKarl Relton 	priv->band.bitrates = priv->rates;
690cb3126e6SKarl Relton 	priv->band.n_bitrates = ARRAY_SIZE(prism2_rates);
69157fbcce3SJohannes Berg 	priv->band.band = NL80211_BAND_2GHZ;
692aff3ea4eSKarl Relton 	priv->band.ht_cap.ht_supported = false;
69357fbcce3SJohannes Berg 	wiphy->bands[NL80211_BAND_2GHZ] = &priv->band;
694cb3126e6SKarl Relton 
695cb3126e6SKarl Relton 	set_wiphy_dev(wiphy, dev);
696cb3126e6SKarl Relton 	wiphy->privid = prism2_wiphy_privid;
697cb3126e6SKarl Relton 	wiphy->max_scan_ssids = 1;
6988dd82ebeSEdgardo Hames 	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
6998dd82ebeSEdgardo Hames 				 | BIT(NL80211_IFTYPE_ADHOC);
700cb3126e6SKarl Relton 	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
701cb3126e6SKarl Relton 	wiphy->n_cipher_suites = PRISM2_NUM_CIPHER_SUITES;
702cb3126e6SKarl Relton 	wiphy->cipher_suites = prism2_cipher_suites;
703cb3126e6SKarl Relton 
704f96b36c7SClaudiu Beznea 	if (wiphy_register(wiphy) < 0) {
705f96b36c7SClaudiu Beznea 		wiphy_free(wiphy);
706cb3126e6SKarl Relton 		return NULL;
707f96b36c7SClaudiu Beznea 	}
708cb3126e6SKarl Relton 
709cb3126e6SKarl Relton 	return wiphy;
710cb3126e6SKarl Relton }
711cb3126e6SKarl Relton 
71236d9c250STugce Sirin static void wlan_free_wiphy(struct wiphy *wiphy)
713cb3126e6SKarl Relton {
714cb3126e6SKarl Relton 	wiphy_unregister(wiphy);
715cb3126e6SKarl Relton 	wiphy_free(wiphy);
716cb3126e6SKarl Relton }
717