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 */
prism2_result2err(int prism2_result)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
prism2_domibset_uint32(struct wlandevice * wlandev,u32 did,u32 data)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
prism2_domibset_pstr32(struct wlandevice * wlandev,u32 did,u8 len,const u8 * data)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 */
prism2_change_virtual_intf(struct wiphy * wiphy,struct net_device * dev,enum nl80211_iftype type,struct vif_params * params)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
prism2_add_key(struct wiphy * wiphy,struct net_device * dev,int link_id,u8 key_index,bool pairwise,const u8 * mac_addr,struct key_params * params)14555da06ebSTeodora Baluta static int prism2_add_key(struct wiphy *wiphy, struct net_device *dev,
146*e7a7b84eSVeerendranath Jakkam int link_id, u8 key_index, bool pairwise,
147*e7a7b84eSVeerendranath Jakkam const u8 *mac_addr, 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
prism2_get_key(struct wiphy * wiphy,struct net_device * dev,int link_id,u8 key_index,bool pairwise,const u8 * mac_addr,void * cookie,void (* callback)(void * cookie,struct key_params *))17455da06ebSTeodora Baluta static int prism2_get_key(struct wiphy *wiphy, struct net_device *dev,
175*e7a7b84eSVeerendranath Jakkam int link_id, 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(¶ms, 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, ¶ms);
2008dd82ebeSEdgardo Hames
201cb3126e6SKarl Relton return 0;
202cb3126e6SKarl Relton }
203cb3126e6SKarl Relton
prism2_del_key(struct wiphy * wiphy,struct net_device * dev,int link_id,u8 key_index,bool pairwise,const u8 * mac_addr)20455da06ebSTeodora Baluta static int prism2_del_key(struct wiphy *wiphy, struct net_device *dev,
205*e7a7b84eSVeerendranath Jakkam int link_id, u8 key_index, bool pairwise,
206*e7a7b84eSVeerendranath Jakkam const u8 *mac_addr)
2078dd82ebeSEdgardo Hames {
208c9573a8dSsayli karnik struct wlandevice *wlandev = dev->ml_priv;
209cb3126e6SKarl Relton u32 did;
210cb3126e6SKarl Relton int err = 0;
211cb3126e6SKarl Relton int result = 0;
212cb3126e6SKarl Relton
213cb3126e6SKarl Relton /* There is no direct way in the hardware (AFAIK) of removing
21435028fe1SGavin O'Leary * a key, so we will cheat by setting the key to a bogus value
21535028fe1SGavin O'Leary */
21635028fe1SGavin O'Leary
2170ca6d8e7SClaudiu Beznea if (key_index >= NUM_WEPKEYS)
2180ca6d8e7SClaudiu Beznea return -EINVAL;
2190ca6d8e7SClaudiu Beznea
220cb3126e6SKarl Relton /* send key to driver */
221ce0f34e4STim Collier did = didmib_dot11smt_wepdefaultkeystable_key(key_index + 1);
222cb3126e6SKarl Relton result = prism2_domibset_pstr32(wlandev, did, 13, "0000000000000");
223cb3126e6SKarl Relton
2248dd82ebeSEdgardo Hames if (result)
2258dd82ebeSEdgardo Hames err = -EFAULT;
226cb3126e6SKarl Relton
227cb3126e6SKarl Relton return err;
228cb3126e6SKarl Relton }
229cb3126e6SKarl Relton
prism2_set_default_key(struct wiphy * wiphy,struct net_device * dev,int link_id,u8 key_index,bool unicast,bool multicast)23055da06ebSTeodora Baluta static int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev,
231*e7a7b84eSVeerendranath Jakkam int link_id, u8 key_index, bool unicast,
232*e7a7b84eSVeerendranath Jakkam bool multicast)
2338dd82ebeSEdgardo Hames {
234c9573a8dSsayli karnik struct wlandevice *wlandev = dev->ml_priv;
235cb3126e6SKarl Relton
236f0f74b45SHariprasad Kelam return prism2_domibset_uint32(wlandev,
237eeeeacd8STim Collier DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
238cb3126e6SKarl Relton key_index);
239cb3126e6SKarl Relton }
240cb3126e6SKarl Relton
prism2_get_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_info * sinfo)24155da06ebSTeodora Baluta static int prism2_get_station(struct wiphy *wiphy, struct net_device *dev,
2423b3a0162SJohannes Berg const u8 *mac, struct station_info *sinfo)
2438dd82ebeSEdgardo Hames {
244c9573a8dSsayli karnik struct wlandevice *wlandev = dev->ml_priv;
245b6bb56e6SEdgardo Hames struct p80211msg_lnxreq_commsquality quality;
246cb3126e6SKarl Relton int result;
247cb3126e6SKarl Relton
248cb3126e6SKarl Relton memset(sinfo, 0, sizeof(*sinfo));
249cb3126e6SKarl Relton
250e52f2149SSandhya Bankar if (!wlandev || (wlandev->msdstate != WLAN_MSD_RUNNING))
251cb3126e6SKarl Relton return -EOPNOTSUPP;
252cb3126e6SKarl Relton
253cb3126e6SKarl Relton /* build request message */
2543b6ee123STim Collier quality.msgcode = DIDMSG_LNXREQ_COMMSQUALITY;
255cb3126e6SKarl Relton quality.dbm.data = P80211ENUM_truth_true;
256cb3126e6SKarl Relton quality.dbm.status = P80211ENUM_msgitem_status_data_ok;
257cb3126e6SKarl Relton
258cb3126e6SKarl Relton /* send message to nsd */
259e52f2149SSandhya Bankar if (!wlandev->mlmerequest)
260cb3126e6SKarl Relton return -EOPNOTSUPP;
261cb3126e6SKarl Relton
2623d049431SEdgardo Hames result = wlandev->mlmerequest(wlandev, (struct p80211msg *)&quality);
263cb3126e6SKarl Relton
264cb3126e6SKarl Relton if (result == 0) {
265cb3126e6SKarl Relton sinfo->txrate.legacy = quality.txrate.data;
2665c6a5eb3SOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
267cb3126e6SKarl Relton sinfo->signal = quality.level.data;
2685c6a5eb3SOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
269cb3126e6SKarl Relton }
270cb3126e6SKarl Relton
271cb3126e6SKarl Relton return result;
272cb3126e6SKarl Relton }
273cb3126e6SKarl Relton
prism2_scan(struct wiphy * wiphy,struct cfg80211_scan_request * request)274bb1da756SHimangi Saraogi static int prism2_scan(struct wiphy *wiphy,
275bb1da756SHimangi Saraogi struct cfg80211_scan_request *request)
276cb3126e6SKarl Relton {
2775d5d7c3bSEmil Goode struct net_device *dev;
278cb3126e6SKarl Relton struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
279c9573a8dSsayli karnik struct wlandevice *wlandev;
280b6bb56e6SEdgardo Hames struct p80211msg_dot11req_scan msg1;
281ea82ff74SLee Jones struct p80211msg_dot11req_scan_results *msg2;
28219f798adSKrzysztof Wilczynski struct cfg80211_bss *bss;
2831d76250bSAvraham Stern struct cfg80211_scan_info info = {};
2841d76250bSAvraham Stern
285cb3126e6SKarl Relton int result;
286cb3126e6SKarl Relton int err = 0;
287cb3126e6SKarl Relton int numbss = 0;
288cb3126e6SKarl Relton int i = 0;
289cb3126e6SKarl Relton u8 ie_buf[46];
290cb3126e6SKarl Relton int ie_len;
291cb3126e6SKarl Relton
292cb3126e6SKarl Relton if (!request)
293cb3126e6SKarl Relton return -EINVAL;
294cb3126e6SKarl Relton
2955d5d7c3bSEmil Goode dev = request->wdev->netdev;
2965d5d7c3bSEmil Goode wlandev = dev->ml_priv;
2975d5d7c3bSEmil Goode
298cb3126e6SKarl Relton if (priv->scan_request && priv->scan_request != request)
299cb3126e6SKarl Relton return -EBUSY;
300cb3126e6SKarl Relton
301cb3126e6SKarl Relton if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
302eed88971SAvinash Kumar netdev_err(dev, "Can't scan in AP mode\n");
303cb3126e6SKarl Relton return -EOPNOTSUPP;
304cb3126e6SKarl Relton }
305cb3126e6SKarl Relton
306ea82ff74SLee Jones msg2 = kzalloc(sizeof(*msg2), GFP_KERNEL);
307ea82ff74SLee Jones if (!msg2)
308ea82ff74SLee Jones return -ENOMEM;
309ea82ff74SLee Jones
310cb3126e6SKarl Relton priv->scan_request = request;
311cb3126e6SKarl Relton
31289e13b45SSergio Paracuellos memset(&msg1, 0x00, sizeof(msg1));
3131ffaa906STim Collier msg1.msgcode = DIDMSG_DOT11REQ_SCAN;
314cb3126e6SKarl Relton msg1.bsstype.data = P80211ENUM_bsstype_any;
315cb3126e6SKarl Relton
316625aeb3aSDan Carpenter memset(&msg1.bssid.data.data, 0xFF, sizeof(msg1.bssid.data.data));
317cb3126e6SKarl Relton msg1.bssid.data.len = 6;
318cb3126e6SKarl Relton
319cb3126e6SKarl Relton if (request->n_ssids > 0) {
320cb3126e6SKarl Relton msg1.scantype.data = P80211ENUM_scantype_active;
321cb3126e6SKarl Relton msg1.ssid.data.len = request->ssids->ssid_len;
3228aac4d44SDevendra Naga memcpy(msg1.ssid.data.data,
3238aac4d44SDevendra Naga request->ssids->ssid, request->ssids->ssid_len);
324cb3126e6SKarl Relton } else {
325cb3126e6SKarl Relton msg1.scantype.data = 0;
326cb3126e6SKarl Relton }
327cb3126e6SKarl Relton msg1.probedelay.data = 0;
328cb3126e6SKarl Relton
329cb3126e6SKarl Relton for (i = 0;
330cb3126e6SKarl Relton (i < request->n_channels) && i < ARRAY_SIZE(prism2_channels);
331cb3126e6SKarl Relton i++)
332cb3126e6SKarl Relton msg1.channellist.data.data[i] =
33300bb97ddSAlaa Mohamed ieee80211_frequency_to_channel(request->channels[i]->center_freq);
334cb3126e6SKarl Relton msg1.channellist.data.len = request->n_channels;
335cb3126e6SKarl Relton
336cb3126e6SKarl Relton msg1.maxchanneltime.data = 250;
337cb3126e6SKarl Relton msg1.minchanneltime.data = 200;
338cb3126e6SKarl Relton
339cb3126e6SKarl Relton result = p80211req_dorequest(wlandev, (u8 *)&msg1);
340cb3126e6SKarl Relton if (result) {
341cb3126e6SKarl Relton err = prism2_result2err(msg1.resultcode.data);
342cb3126e6SKarl Relton goto exit;
343cb3126e6SKarl Relton }
344cb3126e6SKarl Relton /* Now retrieve scan results */
345cb3126e6SKarl Relton numbss = msg1.numbss.data;
346cb3126e6SKarl Relton
347cb3126e6SKarl Relton for (i = 0; i < numbss; i++) {
3484e5e9d7cSZhao, Gang int freq;
3494e5e9d7cSZhao, Gang
350ea82ff74SLee Jones msg2->msgcode = DIDMSG_DOT11REQ_SCAN_RESULTS;
351ea82ff74SLee Jones msg2->bssindex.data = i;
352cb3126e6SKarl Relton
353cb3126e6SKarl Relton result = p80211req_dorequest(wlandev, (u8 *)&msg2);
354cb3126e6SKarl Relton if ((result != 0) ||
355ea82ff74SLee Jones (msg2->resultcode.data != P80211ENUM_resultcode_success)) {
356cb3126e6SKarl Relton break;
357cb3126e6SKarl Relton }
358cb3126e6SKarl Relton
359cb3126e6SKarl Relton ie_buf[0] = WLAN_EID_SSID;
360ea82ff74SLee Jones ie_buf[1] = msg2->ssid.data.len;
361cb3126e6SKarl Relton ie_len = ie_buf[1] + 2;
362ea82ff74SLee Jones memcpy(&ie_buf[2], &msg2->ssid.data.data, msg2->ssid.data.len);
363ea82ff74SLee Jones freq = ieee80211_channel_to_frequency(msg2->dschannel.data,
36457fbcce3SJohannes Berg NL80211_BAND_2GHZ);
36519f798adSKrzysztof Wilczynski bss = cfg80211_inform_bss(wiphy,
3664e5e9d7cSZhao, Gang ieee80211_get_channel(wiphy, freq),
3675bc8c1f2SJohannes Berg CFG80211_BSS_FTYPE_UNKNOWN,
368ea82ff74SLee Jones (const u8 *)&msg2->bssid.data.data,
369ea82ff74SLee Jones msg2->timestamp.data, msg2->capinfo.data,
370ea82ff74SLee Jones msg2->beaconperiod.data,
371cb3126e6SKarl Relton ie_buf,
372cb3126e6SKarl Relton ie_len,
373ea82ff74SLee Jones (msg2->signal.data - 65536) * 100, /* Conversion to signed type */
37415d25ed7SSumera Priyadarsini GFP_KERNEL);
37519f798adSKrzysztof Wilczynski
37619f798adSKrzysztof Wilczynski if (!bss) {
37719f798adSKrzysztof Wilczynski err = -ENOMEM;
37819f798adSKrzysztof Wilczynski goto exit;
37919f798adSKrzysztof Wilczynski }
38019f798adSKrzysztof Wilczynski
3815b112d3dSJohannes Berg cfg80211_put_bss(wiphy, bss);
382cb3126e6SKarl Relton }
383cb3126e6SKarl Relton
3848dd82ebeSEdgardo Hames if (result)
385ea82ff74SLee Jones err = prism2_result2err(msg2->resultcode.data);
386cb3126e6SKarl Relton
387cb3126e6SKarl Relton exit:
3881d76250bSAvraham Stern info.aborted = !!(err);
3891d76250bSAvraham Stern cfg80211_scan_done(request, &info);
390cb3126e6SKarl Relton priv->scan_request = NULL;
391ea82ff74SLee Jones kfree(msg2);
392cb3126e6SKarl Relton return err;
393cb3126e6SKarl Relton }
394cb3126e6SKarl Relton
prism2_set_wiphy_params(struct wiphy * wiphy,u32 changed)39555da06ebSTeodora Baluta static int prism2_set_wiphy_params(struct wiphy *wiphy, u32 changed)
3968dd82ebeSEdgardo Hames {
397cb3126e6SKarl Relton struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
398c9573a8dSsayli karnik struct wlandevice *wlandev = priv->wlandev;
399cb3126e6SKarl Relton u32 data;
400cb3126e6SKarl Relton int result;
401cb3126e6SKarl Relton int err = 0;
402cb3126e6SKarl Relton
403cb3126e6SKarl Relton if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
404cb3126e6SKarl Relton if (wiphy->rts_threshold == -1)
405cb3126e6SKarl Relton data = 2347;
406cb3126e6SKarl Relton else
407cb3126e6SKarl Relton data = wiphy->rts_threshold;
408cb3126e6SKarl Relton
4098dd82ebeSEdgardo Hames result = prism2_domibset_uint32(wlandev,
410334e5e68STim Collier DIDMIB_DOT11MAC_OPERATIONTABLE_RTSTHRESHOLD,
411cb3126e6SKarl Relton data);
412cb3126e6SKarl Relton if (result) {
413cb3126e6SKarl Relton err = -EFAULT;
414cb3126e6SKarl Relton goto exit;
415cb3126e6SKarl Relton }
416cb3126e6SKarl Relton }
417cb3126e6SKarl Relton
418cb3126e6SKarl Relton if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
419cb3126e6SKarl Relton if (wiphy->frag_threshold == -1)
420cb3126e6SKarl Relton data = 2346;
421cb3126e6SKarl Relton else
422cb3126e6SKarl Relton data = wiphy->frag_threshold;
423cb3126e6SKarl Relton
4248dd82ebeSEdgardo Hames result = prism2_domibset_uint32(wlandev,
42504bbfc2aSTim Collier DIDMIB_DOT11MAC_OPERATIONTABLE_FRAGMENTATIONTHRESHOLD,
426cb3126e6SKarl Relton data);
427cb3126e6SKarl Relton if (result) {
428cb3126e6SKarl Relton err = -EFAULT;
429cb3126e6SKarl Relton goto exit;
430cb3126e6SKarl Relton }
431cb3126e6SKarl Relton }
432cb3126e6SKarl Relton
433cb3126e6SKarl Relton exit:
434cb3126e6SKarl Relton return err;
435cb3126e6SKarl Relton }
436cb3126e6SKarl Relton
prism2_connect(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_connect_params * sme)43755da06ebSTeodora Baluta static int prism2_connect(struct wiphy *wiphy, struct net_device *dev,
4388dd82ebeSEdgardo Hames struct cfg80211_connect_params *sme)
4398dd82ebeSEdgardo Hames {
440c9573a8dSsayli karnik struct wlandevice *wlandev = dev->ml_priv;
441cb3126e6SKarl Relton struct ieee80211_channel *channel = sme->channel;
442b6bb56e6SEdgardo Hames struct p80211msg_lnxreq_autojoin msg_join;
443cb3126e6SKarl Relton u32 did;
444cb3126e6SKarl Relton int length = sme->ssid_len;
445cb3126e6SKarl Relton int chan = -1;
446cb3126e6SKarl Relton int is_wep = (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) ||
447cb3126e6SKarl Relton (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104);
448cb3126e6SKarl Relton int result;
449cb3126e6SKarl Relton int err = 0;
450cb3126e6SKarl Relton
451cb3126e6SKarl Relton /* Set the channel */
452cb3126e6SKarl Relton if (channel) {
453cb3126e6SKarl Relton chan = ieee80211_frequency_to_channel(channel->center_freq);
4548dd82ebeSEdgardo Hames result = prism2_domibset_uint32(wlandev,
45593d5a1dcSTim Collier DIDMIB_DOT11PHY_DSSSTABLE_CURRENTCHANNEL,
456cb3126e6SKarl Relton chan);
4578dd82ebeSEdgardo Hames if (result)
4588dd82ebeSEdgardo Hames goto exit;
459cb3126e6SKarl Relton }
460cb3126e6SKarl Relton
461d34602deSJustin P. Mattock /* Set the authorization */
462cb3126e6SKarl Relton if ((sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) ||
463cb3126e6SKarl Relton ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && !is_wep))
464cb3126e6SKarl Relton msg_join.authtype.data = P80211ENUM_authalg_opensystem;
465cb3126e6SKarl Relton else if ((sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) ||
466cb3126e6SKarl Relton ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && is_wep))
467cb3126e6SKarl Relton msg_join.authtype.data = P80211ENUM_authalg_sharedkey;
4688dd82ebeSEdgardo Hames else
469eed88971SAvinash Kumar netdev_warn(dev,
4708dd82ebeSEdgardo Hames "Unhandled authorisation type for connect (%d)\n",
4718dd82ebeSEdgardo Hames sme->auth_type);
472cb3126e6SKarl Relton
473cb3126e6SKarl Relton /* Set the encryption - we only support wep */
474cb3126e6SKarl Relton if (is_wep) {
475cb3126e6SKarl Relton if (sme->key) {
476153c5d81SColin Ian King if (sme->key_idx >= NUM_WEPKEYS)
477153c5d81SColin Ian King return -EINVAL;
4780ca6d8e7SClaudiu Beznea
479cb3126e6SKarl Relton result = prism2_domibset_uint32(wlandev,
480eeeeacd8STim Collier DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
481cb3126e6SKarl Relton sme->key_idx);
4828dd82ebeSEdgardo Hames if (result)
4838dd82ebeSEdgardo Hames goto exit;
484cb3126e6SKarl Relton
485cb3126e6SKarl Relton /* send key to driver */
48600bb97ddSAlaa Mohamed did = didmib_dot11smt_wepdefaultkeystable_key(sme->key_idx + 1);
4878aac4d44SDevendra Naga result = prism2_domibset_pstr32(wlandev,
4888aac4d44SDevendra Naga did, sme->key_len,
4898aac4d44SDevendra Naga (u8 *)sme->key);
4908dd82ebeSEdgardo Hames if (result)
4918dd82ebeSEdgardo Hames goto exit;
492cb3126e6SKarl Relton }
493cb3126e6SKarl Relton
494cb3126e6SKarl Relton /* Assume we should set privacy invoked and exclude unencrypted
49535028fe1SGavin O'Leary * We could possible use sme->privacy here, but the assumption
49635028fe1SGavin O'Leary * seems reasonable anyways
49735028fe1SGavin O'Leary */
4988dd82ebeSEdgardo Hames result = prism2_domibset_uint32(wlandev,
499184fcaa1STim Collier DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED,
500cb3126e6SKarl Relton P80211ENUM_truth_true);
5018dd82ebeSEdgardo Hames if (result)
5028dd82ebeSEdgardo Hames goto exit;
5038dd82ebeSEdgardo Hames
5048dd82ebeSEdgardo Hames result = prism2_domibset_uint32(wlandev,
5052ddc995dSTim Collier DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED,
506cb3126e6SKarl Relton P80211ENUM_truth_true);
5078dd82ebeSEdgardo Hames if (result)
5088dd82ebeSEdgardo Hames goto exit;
509cb3126e6SKarl Relton
510cb3126e6SKarl Relton } else {
5118dd82ebeSEdgardo Hames /* Assume we should unset privacy invoked
51235028fe1SGavin O'Leary * and exclude unencrypted
51335028fe1SGavin O'Leary */
5148dd82ebeSEdgardo Hames result = prism2_domibset_uint32(wlandev,
515184fcaa1STim Collier DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED,
516cb3126e6SKarl Relton P80211ENUM_truth_false);
5178dd82ebeSEdgardo Hames if (result)
5188dd82ebeSEdgardo Hames goto exit;
5198dd82ebeSEdgardo Hames
5208dd82ebeSEdgardo Hames result = prism2_domibset_uint32(wlandev,
5212ddc995dSTim Collier DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED,
522cb3126e6SKarl Relton P80211ENUM_truth_false);
5238dd82ebeSEdgardo Hames if (result)
5248dd82ebeSEdgardo Hames goto exit;
525cb3126e6SKarl Relton }
526cb3126e6SKarl Relton
527cb3126e6SKarl Relton /* Now do the actual join. Note there is no way that I can
5284f9de774SGavin O'Leary * see to request a specific bssid
5294f9de774SGavin O'Leary */
530b1f1118bSTim Collier msg_join.msgcode = DIDMSG_LNXREQ_AUTOJOIN;
531cb3126e6SKarl Relton
532cb3126e6SKarl Relton memcpy(msg_join.ssid.data.data, sme->ssid, length);
533cb3126e6SKarl Relton msg_join.ssid.data.len = length;
534cb3126e6SKarl Relton
535cb3126e6SKarl Relton result = p80211req_dorequest(wlandev, (u8 *)&msg_join);
536cb3126e6SKarl Relton
537cb3126e6SKarl Relton exit:
5388dd82ebeSEdgardo Hames if (result)
5398dd82ebeSEdgardo Hames err = -EFAULT;
540cb3126e6SKarl Relton
541cb3126e6SKarl Relton return err;
542cb3126e6SKarl Relton }
543cb3126e6SKarl Relton
prism2_disconnect(struct wiphy * wiphy,struct net_device * dev,u16 reason_code)54455da06ebSTeodora Baluta static int prism2_disconnect(struct wiphy *wiphy, struct net_device *dev,
5458dd82ebeSEdgardo Hames u16 reason_code)
5468dd82ebeSEdgardo Hames {
547c9573a8dSsayli karnik struct wlandevice *wlandev = dev->ml_priv;
548b6bb56e6SEdgardo Hames struct p80211msg_lnxreq_autojoin msg_join;
549cb3126e6SKarl Relton int result;
550cb3126e6SKarl Relton int err = 0;
551cb3126e6SKarl Relton
552cb3126e6SKarl Relton /* Do a join, with a bogus ssid. Thats the only way I can think of */
553b1f1118bSTim Collier msg_join.msgcode = DIDMSG_LNXREQ_AUTOJOIN;
554cb3126e6SKarl Relton
555cb3126e6SKarl Relton memcpy(msg_join.ssid.data.data, "---", 3);
556cb3126e6SKarl Relton msg_join.ssid.data.len = 3;
557cb3126e6SKarl Relton
558cb3126e6SKarl Relton result = p80211req_dorequest(wlandev, (u8 *)&msg_join);
559cb3126e6SKarl Relton
5608dd82ebeSEdgardo Hames if (result)
5618dd82ebeSEdgardo Hames err = -EFAULT;
562cb3126e6SKarl Relton
563cb3126e6SKarl Relton return err;
564cb3126e6SKarl Relton }
565cb3126e6SKarl Relton
prism2_join_ibss(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_ibss_params * params)56655da06ebSTeodora Baluta static int prism2_join_ibss(struct wiphy *wiphy, struct net_device *dev,
5678dd82ebeSEdgardo Hames struct cfg80211_ibss_params *params)
5688dd82ebeSEdgardo Hames {
569cb3126e6SKarl Relton return -EOPNOTSUPP;
570cb3126e6SKarl Relton }
571cb3126e6SKarl Relton
prism2_leave_ibss(struct wiphy * wiphy,struct net_device * dev)57255da06ebSTeodora Baluta static int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
5738dd82ebeSEdgardo Hames {
574cb3126e6SKarl Relton return -EOPNOTSUPP;
575cb3126e6SKarl Relton }
576cb3126e6SKarl Relton
prism2_set_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,enum nl80211_tx_power_setting type,int mbm)57755da06ebSTeodora Baluta static int prism2_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
5785f3b361aSEmil Goode enum nl80211_tx_power_setting type, int mbm)
5798dd82ebeSEdgardo Hames {
580cb3126e6SKarl Relton struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
581c9573a8dSsayli karnik struct wlandevice *wlandev = priv->wlandev;
582cb3126e6SKarl Relton u32 data;
583cb3126e6SKarl Relton int result;
584cb3126e6SKarl Relton int err = 0;
585cb3126e6SKarl Relton
5869015e499SChristoph Fritz if (type == NL80211_TX_POWER_AUTOMATIC)
587cb3126e6SKarl Relton data = 30;
588cb3126e6SKarl Relton else
5899015e499SChristoph Fritz data = MBM_TO_DBM(mbm);
590cb3126e6SKarl Relton
591cb3126e6SKarl Relton result = prism2_domibset_uint32(wlandev,
592c9a89f4eSTim Collier DIDMIB_DOT11PHY_TXPOWERTABLE_CURRENTTXPOWERLEVEL,
593cb3126e6SKarl Relton data);
594cb3126e6SKarl Relton
595cb3126e6SKarl Relton if (result) {
596cb3126e6SKarl Relton err = -EFAULT;
597cb3126e6SKarl Relton goto exit;
598cb3126e6SKarl Relton }
599cb3126e6SKarl Relton
600cb3126e6SKarl Relton exit:
601cb3126e6SKarl Relton return err;
602cb3126e6SKarl Relton }
603cb3126e6SKarl Relton
prism2_get_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,int * dbm)60455da06ebSTeodora Baluta static int prism2_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
6055f3b361aSEmil Goode int *dbm)
6068dd82ebeSEdgardo Hames {
607cb3126e6SKarl Relton struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
608c9573a8dSsayli karnik struct wlandevice *wlandev = priv->wlandev;
609b6bb56e6SEdgardo Hames struct p80211msg_dot11req_mibget msg;
610b26b2325SSergio Paracuellos struct p80211item_uint32 *mibitem;
611cb3126e6SKarl Relton int result;
612cb3126e6SKarl Relton int err = 0;
613cb3126e6SKarl Relton
614b26b2325SSergio Paracuellos mibitem = (struct p80211item_uint32 *)&msg.mibattribute.data;
61508ac8573STim Collier msg.msgcode = DIDMSG_DOT11REQ_MIBGET;
61604950c3fSTim Collier mibitem->did = DIDMIB_DOT11PHY_TXPOWERTABLE_CURRENTTXPOWERLEVEL;
617cb3126e6SKarl Relton
618cb3126e6SKarl Relton result = p80211req_dorequest(wlandev, (u8 *)&msg);
619cb3126e6SKarl Relton
620cb3126e6SKarl Relton if (result) {
621cb3126e6SKarl Relton err = -EFAULT;
622cb3126e6SKarl Relton goto exit;
623cb3126e6SKarl Relton }
624cb3126e6SKarl Relton
625cb3126e6SKarl Relton *dbm = mibitem->data;
626cb3126e6SKarl Relton
627cb3126e6SKarl Relton exit:
628cb3126e6SKarl Relton return err;
629cb3126e6SKarl Relton }
630cb3126e6SKarl Relton
631cb3126e6SKarl Relton /* Interface callback functions, passing data back up to the cfg80211 layer */
prism2_connect_result(struct wlandevice * wlandev,u8 failed)632c9573a8dSsayli karnik void prism2_connect_result(struct wlandevice *wlandev, u8 failed)
6338dd82ebeSEdgardo Hames {
6348aac4d44SDevendra Naga u16 status = failed ?
6358aac4d44SDevendra Naga WLAN_STATUS_UNSPECIFIED_FAILURE : WLAN_STATUS_SUCCESS;
636cb3126e6SKarl Relton
637cb3126e6SKarl Relton cfg80211_connect_result(wlandev->netdev, wlandev->bssid,
6388dd82ebeSEdgardo Hames NULL, 0, NULL, 0, status, GFP_KERNEL);
639cb3126e6SKarl Relton }
640cb3126e6SKarl Relton
prism2_disconnected(struct wlandevice * wlandev)641c9573a8dSsayli karnik void prism2_disconnected(struct wlandevice *wlandev)
6428dd82ebeSEdgardo Hames {
643cb3126e6SKarl Relton cfg80211_disconnected(wlandev->netdev, 0, NULL,
64480279fb7SJohannes Berg 0, false, GFP_KERNEL);
645cb3126e6SKarl Relton }
646cb3126e6SKarl Relton
prism2_roamed(struct wlandevice * wlandev)647c9573a8dSsayli karnik void prism2_roamed(struct wlandevice *wlandev)
6488dd82ebeSEdgardo Hames {
64929ce6ecbSAvraham Stern struct cfg80211_roam_info roam_info = {
650efbabc11SVeerendranath Jakkam .links[0].bssid = wlandev->bssid,
65129ce6ecbSAvraham Stern };
65229ce6ecbSAvraham Stern
65329ce6ecbSAvraham Stern cfg80211_roamed(wlandev->netdev, &roam_info, GFP_KERNEL);
654cb3126e6SKarl Relton }
655cb3126e6SKarl Relton
656cb3126e6SKarl Relton /* Structures for declaring wiphy interface */
657cb3126e6SKarl Relton static const struct cfg80211_ops prism2_usb_cfg_ops = {
658cb3126e6SKarl Relton .change_virtual_intf = prism2_change_virtual_intf,
659cb3126e6SKarl Relton .add_key = prism2_add_key,
660cb3126e6SKarl Relton .get_key = prism2_get_key,
661cb3126e6SKarl Relton .del_key = prism2_del_key,
662cb3126e6SKarl Relton .set_default_key = prism2_set_default_key,
663cb3126e6SKarl Relton .get_station = prism2_get_station,
664cb3126e6SKarl Relton .scan = prism2_scan,
665cb3126e6SKarl Relton .set_wiphy_params = prism2_set_wiphy_params,
666cb3126e6SKarl Relton .connect = prism2_connect,
667cb3126e6SKarl Relton .disconnect = prism2_disconnect,
668cb3126e6SKarl Relton .join_ibss = prism2_join_ibss,
669cb3126e6SKarl Relton .leave_ibss = prism2_leave_ibss,
670cb3126e6SKarl Relton .set_tx_power = prism2_set_tx_power,
671cb3126e6SKarl Relton .get_tx_power = prism2_get_tx_power,
672cb3126e6SKarl Relton };
673cb3126e6SKarl Relton
674cb3126e6SKarl Relton /* Functions to create/free wiphy interface */
wlan_create_wiphy(struct device * dev,struct wlandevice * wlandev)675285376ffSTim Collier static struct wiphy *wlan_create_wiphy(struct device *dev,
676285376ffSTim Collier struct wlandevice *wlandev)
677cb3126e6SKarl Relton {
678cb3126e6SKarl Relton struct wiphy *wiphy;
679cb3126e6SKarl Relton struct prism2_wiphy_private *priv;
6808aac4d44SDevendra Naga
6818aac4d44SDevendra Naga wiphy = wiphy_new(&prism2_usb_cfg_ops, sizeof(*priv));
682cb3126e6SKarl Relton if (!wiphy)
683cb3126e6SKarl Relton return NULL;
684cb3126e6SKarl Relton
685cb3126e6SKarl Relton priv = wiphy_priv(wiphy);
686cb3126e6SKarl Relton priv->wlandev = wlandev;
687cb3126e6SKarl Relton memcpy(priv->channels, prism2_channels, sizeof(prism2_channels));
688cb3126e6SKarl Relton memcpy(priv->rates, prism2_rates, sizeof(prism2_rates));
689cb3126e6SKarl Relton priv->band.channels = priv->channels;
690cb3126e6SKarl Relton priv->band.n_channels = ARRAY_SIZE(prism2_channels);
691cb3126e6SKarl Relton priv->band.bitrates = priv->rates;
692cb3126e6SKarl Relton priv->band.n_bitrates = ARRAY_SIZE(prism2_rates);
69357fbcce3SJohannes Berg priv->band.band = NL80211_BAND_2GHZ;
694aff3ea4eSKarl Relton priv->band.ht_cap.ht_supported = false;
69557fbcce3SJohannes Berg wiphy->bands[NL80211_BAND_2GHZ] = &priv->band;
696cb3126e6SKarl Relton
697cb3126e6SKarl Relton set_wiphy_dev(wiphy, dev);
698cb3126e6SKarl Relton wiphy->privid = prism2_wiphy_privid;
699cb3126e6SKarl Relton wiphy->max_scan_ssids = 1;
7008dd82ebeSEdgardo Hames wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
7018dd82ebeSEdgardo Hames | BIT(NL80211_IFTYPE_ADHOC);
702cb3126e6SKarl Relton wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
703cb3126e6SKarl Relton wiphy->n_cipher_suites = PRISM2_NUM_CIPHER_SUITES;
704cb3126e6SKarl Relton wiphy->cipher_suites = prism2_cipher_suites;
705cb3126e6SKarl Relton
706f96b36c7SClaudiu Beznea if (wiphy_register(wiphy) < 0) {
707f96b36c7SClaudiu Beznea wiphy_free(wiphy);
708cb3126e6SKarl Relton return NULL;
709f96b36c7SClaudiu Beznea }
710cb3126e6SKarl Relton
711cb3126e6SKarl Relton return wiphy;
712cb3126e6SKarl Relton }
713cb3126e6SKarl Relton
wlan_free_wiphy(struct wiphy * wiphy)71436d9c250STugce Sirin static void wlan_free_wiphy(struct wiphy *wiphy)
715cb3126e6SKarl Relton {
716cb3126e6SKarl Relton wiphy_unregister(wiphy);
717cb3126e6SKarl Relton wiphy_free(wiphy);
718cb3126e6SKarl Relton }
719