158391efdSNathan Chancellor // SPDX-License-Identifier: GPL-2.0
2554c0a3aSHans de Goede /******************************************************************************
3554c0a3aSHans de Goede *
4554c0a3aSHans de Goede * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
5554c0a3aSHans de Goede *
6554c0a3aSHans de Goede ******************************************************************************/
7554c0a3aSHans de Goede
82dcce8edSArushi Singhal #include <linux/etherdevice.h>
9554c0a3aSHans de Goede #include <drv_types.h>
10554c0a3aSHans de Goede #include <rtw_debug.h>
11554c0a3aSHans de Goede #include <rtw_mp.h>
127d6a6e7bSNishka Dasgupta #include <hal_btcoex.h>
13554c0a3aSHans de Goede #include <linux/jiffies.h>
1460db8d10SJérémy Lefaure #include <linux/kernel.h>
15554c0a3aSHans de Goede
16f85ac230STeo Dacquet #define RTL_IOCTL_WPA_SUPPLICANT (SIOCIWFIRSTPRIV + 30)
17554c0a3aSHans de Goede
wpa_set_auth_algs(struct net_device * dev,u32 value)18554c0a3aSHans de Goede static int wpa_set_auth_algs(struct net_device *dev, u32 value)
19554c0a3aSHans de Goede {
2042a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
21554c0a3aSHans de Goede int ret = 0;
22554c0a3aSHans de Goede
23b658acbfSFabio Aiuto if ((value & IW_AUTH_ALG_SHARED_KEY) && (value & IW_AUTH_ALG_OPEN_SYSTEM)) {
24554c0a3aSHans de Goede padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
25554c0a3aSHans de Goede padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch;
26554c0a3aSHans de Goede padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
27b658acbfSFabio Aiuto } else if (value & IW_AUTH_ALG_SHARED_KEY) {
28554c0a3aSHans de Goede padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
29554c0a3aSHans de Goede
30554c0a3aSHans de Goede padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared;
31554c0a3aSHans de Goede padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared;
32b658acbfSFabio Aiuto } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
33554c0a3aSHans de Goede /* padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; */
34f85ac230STeo Dacquet if (padapter->securitypriv.ndisauthtype < Ndis802_11AuthModeWPAPSK) {
35554c0a3aSHans de Goede padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
36554c0a3aSHans de Goede padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
37554c0a3aSHans de Goede }
38f85ac230STeo Dacquet } else {
39554c0a3aSHans de Goede ret = -EINVAL;
40554c0a3aSHans de Goede }
41554c0a3aSHans de Goede
42554c0a3aSHans de Goede return ret;
43554c0a3aSHans de Goede }
44554c0a3aSHans de Goede
wpa_set_encryption(struct net_device * dev,struct ieee_param * param,u32 param_len)45554c0a3aSHans de Goede static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len)
46554c0a3aSHans de Goede {
47554c0a3aSHans de Goede int ret = 0;
4805cbcc41SHans de Goede u8 max_idx;
49554c0a3aSHans de Goede u32 wep_key_idx, wep_key_len, wep_total_len;
50554c0a3aSHans de Goede struct ndis_802_11_wep *pwep = NULL;
5142a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
52554c0a3aSHans de Goede struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
53554c0a3aSHans de Goede struct security_priv *psecuritypriv = &padapter->securitypriv;
54554c0a3aSHans de Goede
55554c0a3aSHans de Goede param->u.crypt.err = 0;
56554c0a3aSHans de Goede param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
57554c0a3aSHans de Goede
58f85ac230STeo Dacquet if (param_len < (u32)((u8 *)param->u.crypt.key - (u8 *)param) + param->u.crypt.key_len) {
59554c0a3aSHans de Goede ret = -EINVAL;
60554c0a3aSHans de Goede goto exit;
61554c0a3aSHans de Goede }
62554c0a3aSHans de Goede
6305cbcc41SHans de Goede if (param->sta_addr[0] != 0xff || param->sta_addr[1] != 0xff ||
6405cbcc41SHans de Goede param->sta_addr[2] != 0xff || param->sta_addr[3] != 0xff ||
6505cbcc41SHans de Goede param->sta_addr[4] != 0xff || param->sta_addr[5] != 0xff) {
66554c0a3aSHans de Goede ret = -EINVAL;
67554c0a3aSHans de Goede goto exit;
68554c0a3aSHans de Goede }
6905cbcc41SHans de Goede
7005cbcc41SHans de Goede if (strcmp(param->u.crypt.alg, "WEP") == 0)
7105cbcc41SHans de Goede max_idx = WEP_KEYS - 1;
7205cbcc41SHans de Goede else
7305cbcc41SHans de Goede max_idx = BIP_MAX_KEYID;
7405cbcc41SHans de Goede
7505cbcc41SHans de Goede if (param->u.crypt.idx > max_idx) {
7605cbcc41SHans de Goede netdev_err(dev, "Error crypt.idx %d > %d\n", param->u.crypt.idx, max_idx);
77554c0a3aSHans de Goede ret = -EINVAL;
78554c0a3aSHans de Goede goto exit;
79554c0a3aSHans de Goede }
80554c0a3aSHans de Goede
81f85ac230STeo Dacquet if (strcmp(param->u.crypt.alg, "WEP") == 0) {
82554c0a3aSHans de Goede padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
83554c0a3aSHans de Goede padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
84554c0a3aSHans de Goede padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_;
85554c0a3aSHans de Goede
86554c0a3aSHans de Goede wep_key_idx = param->u.crypt.idx;
87554c0a3aSHans de Goede wep_key_len = param->u.crypt.key_len;
88554c0a3aSHans de Goede
89f85ac230STeo Dacquet if (wep_key_len > 0) {
90554c0a3aSHans de Goede wep_key_len = wep_key_len <= 5 ? 5 : 13;
91f133717eSFabio Aiuto wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, key_material);
9267ea0a2aSKees Cook /* Allocate a full structure to avoid potentially running off the end. */
9367ea0a2aSKees Cook pwep = kzalloc(sizeof(*pwep), GFP_KERNEL);
94eb64c6f6SChristophe JAILLET if (!pwep) {
95eb64c6f6SChristophe JAILLET ret = -ENOMEM;
96554c0a3aSHans de Goede goto exit;
97eb64c6f6SChristophe JAILLET }
98554c0a3aSHans de Goede
99f133717eSFabio Aiuto pwep->key_length = wep_key_len;
100f133717eSFabio Aiuto pwep->length = wep_total_len;
101554c0a3aSHans de Goede
102f85ac230STeo Dacquet if (wep_key_len == 13) {
103554c0a3aSHans de Goede padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_;
104554c0a3aSHans de Goede padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_;
105554c0a3aSHans de Goede }
106f85ac230STeo Dacquet } else {
107554c0a3aSHans de Goede ret = -EINVAL;
108554c0a3aSHans de Goede goto exit;
109554c0a3aSHans de Goede }
110554c0a3aSHans de Goede
111f133717eSFabio Aiuto pwep->key_index = wep_key_idx;
112f133717eSFabio Aiuto pwep->key_index |= 0x80000000;
113554c0a3aSHans de Goede
114f133717eSFabio Aiuto memcpy(pwep->key_material, param->u.crypt.key, pwep->key_length);
115554c0a3aSHans de Goede
116f85ac230STeo Dacquet if (param->u.crypt.set_tx) {
117554c0a3aSHans de Goede if (rtw_set_802_11_add_wep(padapter, pwep) == (u8)_FAIL)
118554c0a3aSHans de Goede ret = -EOPNOTSUPP;
119f85ac230STeo Dacquet } else {
120554c0a3aSHans de Goede /* don't update "psecuritypriv->dot11PrivacyAlgrthm" and */
121554c0a3aSHans de Goede /* psecuritypriv->dot11PrivacyKeyIndex =keyid", but can rtw_set_key to fw/cam */
122554c0a3aSHans de Goede
123554c0a3aSHans de Goede if (wep_key_idx >= WEP_KEYS) {
124554c0a3aSHans de Goede ret = -EOPNOTSUPP;
125554c0a3aSHans de Goede goto exit;
126554c0a3aSHans de Goede }
127554c0a3aSHans de Goede
128722a3291SFranziska Naepelt memcpy(&psecuritypriv->dot11DefKey[wep_key_idx].skey[0], pwep->key_material, pwep->key_length);
129f133717eSFabio Aiuto psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->key_length;
130554c0a3aSHans de Goede rtw_set_key(padapter, psecuritypriv, wep_key_idx, 0, true);
131554c0a3aSHans de Goede }
132554c0a3aSHans de Goede
133554c0a3aSHans de Goede goto exit;
134554c0a3aSHans de Goede }
135554c0a3aSHans de Goede
136f85ac230STeo Dacquet if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { /* 802_1x */
137554c0a3aSHans de Goede struct sta_info *psta, *pbcmc_sta;
138554c0a3aSHans de Goede struct sta_priv *pstapriv = &padapter->stapriv;
139554c0a3aSHans de Goede
140f85ac230STeo Dacquet if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE) == true) { /* sta mode */
141554c0a3aSHans de Goede psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv));
142cd1f1450SMichael Straube if (!psta) {
143554c0a3aSHans de Goede /* DEBUG_ERR(("Set wpa_set_encryption: Obtain Sta_info fail\n")); */
144f85ac230STeo Dacquet } else {
145554c0a3aSHans de Goede /* Jeff: don't disable ieee8021x_blocked while clearing key */
146554c0a3aSHans de Goede if (strcmp(param->u.crypt.alg, "none") != 0)
147554c0a3aSHans de Goede psta->ieee8021x_blocked = false;
148554c0a3aSHans de Goede
149554c0a3aSHans de Goede if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) ||
150f85ac230STeo Dacquet (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) {
151554c0a3aSHans de Goede psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
152554c0a3aSHans de Goede }
153554c0a3aSHans de Goede
154f85ac230STeo Dacquet if (param->u.crypt.set_tx == 1) { /* pairwise key */
155554c0a3aSHans de Goede memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
156554c0a3aSHans de Goede
157f85ac230STeo Dacquet if (strcmp(param->u.crypt.alg, "TKIP") == 0) { /* set mic key */
158554c0a3aSHans de Goede /* DEBUG_ERR(("\nset key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */
159722a3291SFranziska Naepelt memcpy(psta->dot11tkiptxmickey.skey, ¶m->u.crypt.key[16], 8);
160722a3291SFranziska Naepelt memcpy(psta->dot11tkiprxmickey.skey, ¶m->u.crypt.key[24], 8);
161554c0a3aSHans de Goede
162554c0a3aSHans de Goede padapter->securitypriv.busetkipkey = false;
163554c0a3aSHans de Goede /* _set_timer(&padapter->securitypriv.tkip_timer, 50); */
164554c0a3aSHans de Goede }
165554c0a3aSHans de Goede
166554c0a3aSHans de Goede rtw_setstakey_cmd(padapter, psta, true, true);
167f85ac230STeo Dacquet } else { /* group key */
168f85ac230STeo Dacquet if (strcmp(param->u.crypt.alg, "TKIP") == 0 || strcmp(param->u.crypt.alg, "CCMP") == 0) {
169554c0a3aSHans de Goede memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
170554c0a3aSHans de Goede /* only TKIP group key need to install this */
171f85ac230STeo Dacquet if (param->u.crypt.key_len > 16) {
172722a3291SFranziska Naepelt memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey, ¶m->u.crypt.key[16], 8);
173722a3291SFranziska Naepelt memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey, ¶m->u.crypt.key[24], 8);
174554c0a3aSHans de Goede }
175554c0a3aSHans de Goede padapter->securitypriv.binstallGrpkey = true;
176554c0a3aSHans de Goede
177554c0a3aSHans de Goede padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx;
178554c0a3aSHans de Goede
179554c0a3aSHans de Goede rtw_set_key(padapter, &padapter->securitypriv, param->u.crypt.idx, 1, true);
180f85ac230STeo Dacquet } else if (strcmp(param->u.crypt.alg, "BIP") == 0) {
181554c0a3aSHans de Goede /* printk("BIP key_len =%d , index =%d @@@@@@@@@@@@@@@@@@\n", param->u.crypt.key_len, param->u.crypt.idx); */
182554c0a3aSHans de Goede /* save the IGTK key, length 16 bytes */
183554c0a3aSHans de Goede memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
184554c0a3aSHans de Goede /*printk("IGTK key below:\n");
185554c0a3aSHans de Goede for (no = 0;no<16;no++)
186554c0a3aSHans de Goede printk(" %02x ", padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey[no]);
187554c0a3aSHans de Goede printk("\n");*/
188554c0a3aSHans de Goede padapter->securitypriv.dot11wBIPKeyid = param->u.crypt.idx;
189554c0a3aSHans de Goede padapter->securitypriv.binstallBIPkey = true;
190554c0a3aSHans de Goede }
191554c0a3aSHans de Goede }
192554c0a3aSHans de Goede }
193554c0a3aSHans de Goede
194554c0a3aSHans de Goede pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
195cd1f1450SMichael Straube if (!pbcmc_sta) {
196554c0a3aSHans de Goede /* DEBUG_ERR(("Set OID_802_11_ADD_KEY: bcmc stainfo is null\n")); */
197f85ac230STeo Dacquet } else {
198554c0a3aSHans de Goede /* Jeff: don't disable ieee8021x_blocked while clearing key */
199554c0a3aSHans de Goede if (strcmp(param->u.crypt.alg, "none") != 0)
200554c0a3aSHans de Goede pbcmc_sta->ieee8021x_blocked = false;
201554c0a3aSHans de Goede
202554c0a3aSHans de Goede if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) ||
203f85ac230STeo Dacquet (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) {
204554c0a3aSHans de Goede pbcmc_sta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
205554c0a3aSHans de Goede }
206554c0a3aSHans de Goede }
207f85ac230STeo Dacquet } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
208f85ac230STeo Dacquet /* adhoc mode */
209554c0a3aSHans de Goede }
210554c0a3aSHans de Goede }
211554c0a3aSHans de Goede
212554c0a3aSHans de Goede exit:
213554c0a3aSHans de Goede
214428715baSAmitoj Kaur Chawla kfree(pwep);
215554c0a3aSHans de Goede return ret;
216554c0a3aSHans de Goede }
217554c0a3aSHans de Goede
rtw_set_wpa_ie(struct adapter * padapter,char * pie,unsigned short ielen)218554c0a3aSHans de Goede static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ielen)
219554c0a3aSHans de Goede {
220288f9acaSNishka Dasgupta u8 *buf = NULL;
221554c0a3aSHans de Goede int group_cipher = 0, pairwise_cipher = 0;
222554c0a3aSHans de Goede int ret = 0;
223554c0a3aSHans de Goede u8 null_addr[] = {0, 0, 0, 0, 0, 0};
224554c0a3aSHans de Goede
225cd1f1450SMichael Straube if (ielen > MAX_WPA_IE_LEN || !pie) {
226554c0a3aSHans de Goede _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
227cd1f1450SMichael Straube if (!pie)
228554c0a3aSHans de Goede return ret;
229554c0a3aSHans de Goede else
230554c0a3aSHans de Goede return -EINVAL;
231554c0a3aSHans de Goede }
232554c0a3aSHans de Goede
233f85ac230STeo Dacquet if (ielen) {
234554c0a3aSHans de Goede buf = rtw_zmalloc(ielen);
235cd1f1450SMichael Straube if (!buf) {
236554c0a3aSHans de Goede ret = -ENOMEM;
237554c0a3aSHans de Goede goto exit;
238554c0a3aSHans de Goede }
239554c0a3aSHans de Goede
240554c0a3aSHans de Goede memcpy(buf, pie, ielen);
241554c0a3aSHans de Goede
242554c0a3aSHans de Goede if (ielen < RSN_HEADER_LEN) {
243554c0a3aSHans de Goede ret = -1;
244554c0a3aSHans de Goede goto exit;
245554c0a3aSHans de Goede }
246554c0a3aSHans de Goede
247f85ac230STeo Dacquet if (rtw_parse_wpa_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
248554c0a3aSHans de Goede padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
249554c0a3aSHans de Goede padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK;
250554c0a3aSHans de Goede memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen);
251554c0a3aSHans de Goede }
252554c0a3aSHans de Goede
253f85ac230STeo Dacquet if (rtw_parse_wpa2_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
254554c0a3aSHans de Goede padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
255554c0a3aSHans de Goede padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK;
256554c0a3aSHans de Goede memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen);
257554c0a3aSHans de Goede }
258554c0a3aSHans de Goede
259554c0a3aSHans de Goede if (group_cipher == 0)
260554c0a3aSHans de Goede group_cipher = WPA_CIPHER_NONE;
261554c0a3aSHans de Goede if (pairwise_cipher == 0)
262554c0a3aSHans de Goede pairwise_cipher = WPA_CIPHER_NONE;
263554c0a3aSHans de Goede
264f85ac230STeo Dacquet switch (group_cipher) {
265554c0a3aSHans de Goede case WPA_CIPHER_NONE:
266554c0a3aSHans de Goede padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
267554c0a3aSHans de Goede padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
268554c0a3aSHans de Goede break;
269554c0a3aSHans de Goede case WPA_CIPHER_WEP40:
270554c0a3aSHans de Goede padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_;
271554c0a3aSHans de Goede padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
272554c0a3aSHans de Goede break;
273554c0a3aSHans de Goede case WPA_CIPHER_TKIP:
274554c0a3aSHans de Goede padapter->securitypriv.dot118021XGrpPrivacy = _TKIP_;
275554c0a3aSHans de Goede padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
276554c0a3aSHans de Goede break;
277554c0a3aSHans de Goede case WPA_CIPHER_CCMP:
278554c0a3aSHans de Goede padapter->securitypriv.dot118021XGrpPrivacy = _AES_;
279554c0a3aSHans de Goede padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
280554c0a3aSHans de Goede break;
281554c0a3aSHans de Goede case WPA_CIPHER_WEP104:
282554c0a3aSHans de Goede padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_;
283554c0a3aSHans de Goede padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
284554c0a3aSHans de Goede break;
285554c0a3aSHans de Goede }
286554c0a3aSHans de Goede
287f85ac230STeo Dacquet switch (pairwise_cipher) {
288554c0a3aSHans de Goede case WPA_CIPHER_NONE:
289554c0a3aSHans de Goede padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
290554c0a3aSHans de Goede padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
291554c0a3aSHans de Goede break;
292554c0a3aSHans de Goede case WPA_CIPHER_WEP40:
293554c0a3aSHans de Goede padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
294554c0a3aSHans de Goede padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
295554c0a3aSHans de Goede break;
296554c0a3aSHans de Goede case WPA_CIPHER_TKIP:
297554c0a3aSHans de Goede padapter->securitypriv.dot11PrivacyAlgrthm = _TKIP_;
298554c0a3aSHans de Goede padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
299554c0a3aSHans de Goede break;
300554c0a3aSHans de Goede case WPA_CIPHER_CCMP:
301554c0a3aSHans de Goede padapter->securitypriv.dot11PrivacyAlgrthm = _AES_;
302554c0a3aSHans de Goede padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
303554c0a3aSHans de Goede break;
304554c0a3aSHans de Goede case WPA_CIPHER_WEP104:
305554c0a3aSHans de Goede padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_;
306554c0a3aSHans de Goede padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
307554c0a3aSHans de Goede break;
308554c0a3aSHans de Goede }
309554c0a3aSHans de Goede
310554c0a3aSHans de Goede _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
311554c0a3aSHans de Goede {/* set wps_ie */
312554c0a3aSHans de Goede u16 cnt = 0;
313554c0a3aSHans de Goede u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
314554c0a3aSHans de Goede
315f85ac230STeo Dacquet while (cnt < ielen) {
316554c0a3aSHans de Goede eid = buf[cnt];
317554c0a3aSHans de Goede
318b05cc3a9SRoss Schmidt if ((eid == WLAN_EID_VENDOR_SPECIFIC) && (!memcmp(&buf[cnt + 2], wps_oui, 4))) {
319554c0a3aSHans de Goede padapter->securitypriv.wps_ie_len = ((buf[cnt + 1] + 2) < MAX_WPS_IE_LEN) ? (buf[cnt + 1] + 2) : MAX_WPS_IE_LEN;
320554c0a3aSHans de Goede
321554c0a3aSHans de Goede memcpy(padapter->securitypriv.wps_ie, &buf[cnt], padapter->securitypriv.wps_ie_len);
322554c0a3aSHans de Goede
323554c0a3aSHans de Goede set_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS);
324554c0a3aSHans de Goede
325554c0a3aSHans de Goede cnt += buf[cnt + 1] + 2;
326554c0a3aSHans de Goede
327554c0a3aSHans de Goede break;
328554c0a3aSHans de Goede } else {
329554c0a3aSHans de Goede cnt += buf[cnt + 1] + 2; /* goto next */
330554c0a3aSHans de Goede }
331554c0a3aSHans de Goede }
332554c0a3aSHans de Goede }
333554c0a3aSHans de Goede }
334554c0a3aSHans de Goede
335554c0a3aSHans de Goede /* TKIP and AES disallow multicast packets until installing group key */
336105bc6b9SFabio Aiuto if (padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_ ||
337105bc6b9SFabio Aiuto padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_WTMIC_ ||
338105bc6b9SFabio Aiuto padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)
339554c0a3aSHans de Goede /* WPS open need to enable multicast */
340554c0a3aSHans de Goede /* check_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS) == true) */
341554c0a3aSHans de Goede rtw_hal_set_hwreg(padapter, HW_VAR_OFF_RCR_AM, null_addr);
342554c0a3aSHans de Goede
343554c0a3aSHans de Goede exit:
344554c0a3aSHans de Goede
3457ad61a38SAishwarya Pant kfree(buf);
346554c0a3aSHans de Goede
347554c0a3aSHans de Goede return ret;
348554c0a3aSHans de Goede }
349554c0a3aSHans de Goede
wpa_set_param(struct net_device * dev,u8 name,u32 value)350554c0a3aSHans de Goede static int wpa_set_param(struct net_device *dev, u8 name, u32 value)
351554c0a3aSHans de Goede {
352554c0a3aSHans de Goede uint ret = 0;
35342a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
354554c0a3aSHans de Goede
355554c0a3aSHans de Goede switch (name) {
356554c0a3aSHans de Goede case IEEE_PARAM_WPA_ENABLED:
357554c0a3aSHans de Goede
358554c0a3aSHans de Goede padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; /* 802.1x */
359554c0a3aSHans de Goede
360554c0a3aSHans de Goede /* ret = ieee80211_wpa_enable(ieee, value); */
361554c0a3aSHans de Goede
362f85ac230STeo Dacquet switch ((value) & 0xff) {
363554c0a3aSHans de Goede case 1: /* WPA */
364554c0a3aSHans de Goede padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK; /* WPA_PSK */
365554c0a3aSHans de Goede padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
366554c0a3aSHans de Goede break;
367554c0a3aSHans de Goede case 2: /* WPA2 */
368554c0a3aSHans de Goede padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK; /* WPA2_PSK */
369554c0a3aSHans de Goede padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
370554c0a3aSHans de Goede break;
371554c0a3aSHans de Goede }
372554c0a3aSHans de Goede
373554c0a3aSHans de Goede break;
374554c0a3aSHans de Goede
375554c0a3aSHans de Goede case IEEE_PARAM_TKIP_COUNTERMEASURES:
376554c0a3aSHans de Goede /* ieee->tkip_countermeasures =value; */
377554c0a3aSHans de Goede break;
378554c0a3aSHans de Goede
379554c0a3aSHans de Goede case IEEE_PARAM_DROP_UNENCRYPTED:
380554c0a3aSHans de Goede {
381554c0a3aSHans de Goede /* HACK:
382554c0a3aSHans de Goede *
383554c0a3aSHans de Goede * wpa_supplicant calls set_wpa_enabled when the driver
384554c0a3aSHans de Goede * is loaded and unloaded, regardless of if WPA is being
385554c0a3aSHans de Goede * used. No other calls are made which can be used to
386554c0a3aSHans de Goede * determine if encryption will be used or not prior to
387554c0a3aSHans de Goede * association being expected. If encryption is not being
388554c0a3aSHans de Goede * used, drop_unencrypted is set to false, else true -- we
389554c0a3aSHans de Goede * can use this to determine if the CAP_PRIVACY_ON bit should
390554c0a3aSHans de Goede * be set.
391554c0a3aSHans de Goede */
392554c0a3aSHans de Goede break;
393554c0a3aSHans de Goede }
394554c0a3aSHans de Goede case IEEE_PARAM_PRIVACY_INVOKED:
395554c0a3aSHans de Goede
396554c0a3aSHans de Goede /* ieee->privacy_invoked =value; */
397554c0a3aSHans de Goede
398554c0a3aSHans de Goede break;
399554c0a3aSHans de Goede
400554c0a3aSHans de Goede case IEEE_PARAM_AUTH_ALGS:
401554c0a3aSHans de Goede
402554c0a3aSHans de Goede ret = wpa_set_auth_algs(dev, value);
403554c0a3aSHans de Goede
404554c0a3aSHans de Goede break;
405554c0a3aSHans de Goede
406554c0a3aSHans de Goede case IEEE_PARAM_IEEE_802_1X:
407554c0a3aSHans de Goede
408554c0a3aSHans de Goede /* ieee->ieee802_1x =value; */
409554c0a3aSHans de Goede
410554c0a3aSHans de Goede break;
411554c0a3aSHans de Goede
412554c0a3aSHans de Goede case IEEE_PARAM_WPAX_SELECT:
413554c0a3aSHans de Goede
414554c0a3aSHans de Goede /* added for WPA2 mixed mode */
415554c0a3aSHans de Goede /*
416554c0a3aSHans de Goede spin_lock_irqsave(&ieee->wpax_suitlist_lock, flags);
417554c0a3aSHans de Goede ieee->wpax_type_set = 1;
418554c0a3aSHans de Goede ieee->wpax_type_notify = value;
419554c0a3aSHans de Goede spin_unlock_irqrestore(&ieee->wpax_suitlist_lock, flags);
420554c0a3aSHans de Goede */
421554c0a3aSHans de Goede
422554c0a3aSHans de Goede break;
423554c0a3aSHans de Goede
424554c0a3aSHans de Goede default:
425554c0a3aSHans de Goede
426554c0a3aSHans de Goede ret = -EOPNOTSUPP;
427554c0a3aSHans de Goede
428554c0a3aSHans de Goede break;
429554c0a3aSHans de Goede }
430554c0a3aSHans de Goede
431554c0a3aSHans de Goede return ret;
432554c0a3aSHans de Goede }
433554c0a3aSHans de Goede
wpa_mlme(struct net_device * dev,u32 command,u32 reason)434554c0a3aSHans de Goede static int wpa_mlme(struct net_device *dev, u32 command, u32 reason)
435554c0a3aSHans de Goede {
436554c0a3aSHans de Goede int ret = 0;
43742a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
438554c0a3aSHans de Goede
439f85ac230STeo Dacquet switch (command) {
440554c0a3aSHans de Goede case IEEE_MLME_STA_DEAUTH:
441554c0a3aSHans de Goede
442554c0a3aSHans de Goede if (!rtw_set_802_11_disassociate(padapter))
443554c0a3aSHans de Goede ret = -1;
444554c0a3aSHans de Goede
445554c0a3aSHans de Goede break;
446554c0a3aSHans de Goede
447554c0a3aSHans de Goede case IEEE_MLME_STA_DISASSOC:
448554c0a3aSHans de Goede
449554c0a3aSHans de Goede if (!rtw_set_802_11_disassociate(padapter))
450554c0a3aSHans de Goede ret = -1;
451554c0a3aSHans de Goede
452554c0a3aSHans de Goede break;
453554c0a3aSHans de Goede
454554c0a3aSHans de Goede default:
455554c0a3aSHans de Goede ret = -EOPNOTSUPP;
456554c0a3aSHans de Goede break;
457554c0a3aSHans de Goede }
458554c0a3aSHans de Goede
459554c0a3aSHans de Goede return ret;
460554c0a3aSHans de Goede }
461554c0a3aSHans de Goede
wpa_supplicant_ioctl(struct net_device * dev,struct iw_point * p)462554c0a3aSHans de Goede static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p)
463554c0a3aSHans de Goede {
464554c0a3aSHans de Goede struct ieee_param *param;
465554c0a3aSHans de Goede uint ret = 0;
466554c0a3aSHans de Goede
467554c0a3aSHans de Goede /* down(&ieee->wx_sem); */
468554c0a3aSHans de Goede
4699a4556bdSLarry Finger if (!p->pointer || p->length != sizeof(struct ieee_param))
4709a4556bdSLarry Finger return -EINVAL;
471554c0a3aSHans de Goede
4722ef2b7c2SJoe Perches param = rtw_malloc(p->length);
473cd1f1450SMichael Straube if (!param)
4749a4556bdSLarry Finger return -ENOMEM;
475554c0a3aSHans de Goede
476f85ac230STeo Dacquet if (copy_from_user(param, p->pointer, p->length)) {
477428715baSAmitoj Kaur Chawla kfree(param);
4789a4556bdSLarry Finger return -EFAULT;
479554c0a3aSHans de Goede }
480554c0a3aSHans de Goede
481554c0a3aSHans de Goede switch (param->cmd) {
482554c0a3aSHans de Goede case IEEE_CMD_SET_WPA_PARAM:
483554c0a3aSHans de Goede ret = wpa_set_param(dev, param->u.wpa_param.name, param->u.wpa_param.value);
484554c0a3aSHans de Goede break;
485554c0a3aSHans de Goede
486554c0a3aSHans de Goede case IEEE_CMD_SET_WPA_IE:
487554c0a3aSHans de Goede /* ret = wpa_set_wpa_ie(dev, param, p->length); */
48842a18f09SIvan Safonov ret = rtw_set_wpa_ie(rtw_netdev_priv(dev), (char *)param->u.wpa_ie.data, (u16)param->u.wpa_ie.len);
489554c0a3aSHans de Goede break;
490554c0a3aSHans de Goede
491554c0a3aSHans de Goede case IEEE_CMD_SET_ENCRYPTION:
492554c0a3aSHans de Goede ret = wpa_set_encryption(dev, param, p->length);
493554c0a3aSHans de Goede break;
494554c0a3aSHans de Goede
495554c0a3aSHans de Goede case IEEE_CMD_MLME:
496554c0a3aSHans de Goede ret = wpa_mlme(dev, param->u.mlme.command, param->u.mlme.reason_code);
497554c0a3aSHans de Goede break;
498554c0a3aSHans de Goede
499554c0a3aSHans de Goede default:
500554c0a3aSHans de Goede ret = -EOPNOTSUPP;
501554c0a3aSHans de Goede break;
502554c0a3aSHans de Goede }
503554c0a3aSHans de Goede
504554c0a3aSHans de Goede if (ret == 0 && copy_to_user(p->pointer, param, p->length))
505554c0a3aSHans de Goede ret = -EFAULT;
506554c0a3aSHans de Goede
507428715baSAmitoj Kaur Chawla kfree(param);
508554c0a3aSHans de Goede
509554c0a3aSHans de Goede /* up(&ieee->wx_sem); */
510554c0a3aSHans de Goede return ret;
511554c0a3aSHans de Goede }
512554c0a3aSHans de Goede
rtw_set_encryption(struct net_device * dev,struct ieee_param * param,u32 param_len)513554c0a3aSHans de Goede static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len)
514554c0a3aSHans de Goede {
515554c0a3aSHans de Goede int ret = 0;
516554c0a3aSHans de Goede u32 wep_key_idx, wep_key_len, wep_total_len;
517554c0a3aSHans de Goede struct ndis_802_11_wep *pwep = NULL;
518554c0a3aSHans de Goede struct sta_info *psta = NULL, *pbcmc_sta = NULL;
51942a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
520554c0a3aSHans de Goede struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
521722a3291SFranziska Naepelt struct security_priv *psecuritypriv = &padapter->securitypriv;
522554c0a3aSHans de Goede struct sta_priv *pstapriv = &padapter->stapriv;
52314b6cff5SArnd Bergmann char *txkey = padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey;
52414b6cff5SArnd Bergmann char *rxkey = padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey;
52514b6cff5SArnd Bergmann char *grpkey = psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey;
526554c0a3aSHans de Goede
527554c0a3aSHans de Goede param->u.crypt.err = 0;
528554c0a3aSHans de Goede param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
529554c0a3aSHans de Goede
530554c0a3aSHans de Goede /* sizeof(struct ieee_param) = 64 bytes; */
531554c0a3aSHans de Goede /* if (param_len != (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) */
532f85ac230STeo Dacquet if (param_len != sizeof(struct ieee_param) + param->u.crypt.key_len) {
533554c0a3aSHans de Goede ret = -EINVAL;
534554c0a3aSHans de Goede goto exit;
535554c0a3aSHans de Goede }
536554c0a3aSHans de Goede
537554c0a3aSHans de Goede if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
538554c0a3aSHans de Goede param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
539f85ac230STeo Dacquet param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
540f85ac230STeo Dacquet if (param->u.crypt.idx >= WEP_KEYS) {
541554c0a3aSHans de Goede ret = -EINVAL;
542554c0a3aSHans de Goede goto exit;
543554c0a3aSHans de Goede }
544f85ac230STeo Dacquet } else {
545554c0a3aSHans de Goede psta = rtw_get_stainfo(pstapriv, param->sta_addr);
546709c8e49SFabio Aiuto if (!psta)
547554c0a3aSHans de Goede /* ret = -EINVAL; */
548554c0a3aSHans de Goede goto exit;
549554c0a3aSHans de Goede }
550554c0a3aSHans de Goede
551cd1f1450SMichael Straube if (strcmp(param->u.crypt.alg, "none") == 0 && !psta) {
552554c0a3aSHans de Goede /* todo:clear default encryption keys */
553554c0a3aSHans de Goede
554554c0a3aSHans de Goede psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
555554c0a3aSHans de Goede psecuritypriv->ndisencryptstatus = Ndis802_11EncryptionDisabled;
556554c0a3aSHans de Goede psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
557554c0a3aSHans de Goede psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
558554c0a3aSHans de Goede
559554c0a3aSHans de Goede goto exit;
560554c0a3aSHans de Goede }
561554c0a3aSHans de Goede
562cd1f1450SMichael Straube if (strcmp(param->u.crypt.alg, "WEP") == 0 && !psta) {
563554c0a3aSHans de Goede wep_key_idx = param->u.crypt.idx;
564554c0a3aSHans de Goede wep_key_len = param->u.crypt.key_len;
565554c0a3aSHans de Goede
566f85ac230STeo Dacquet if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0)) {
567554c0a3aSHans de Goede ret = -EINVAL;
568554c0a3aSHans de Goede goto exit;
569554c0a3aSHans de Goede }
570554c0a3aSHans de Goede
571f85ac230STeo Dacquet if (wep_key_len > 0) {
572554c0a3aSHans de Goede wep_key_len = wep_key_len <= 5 ? 5 : 13;
573f133717eSFabio Aiuto wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, key_material);
57467ea0a2aSKees Cook /* Allocate a full structure to avoid potentially running off the end. */
57567ea0a2aSKees Cook pwep = kzalloc(sizeof(*pwep), GFP_KERNEL);
576e427bdd8SFabio Aiuto if (!pwep)
577554c0a3aSHans de Goede goto exit;
578554c0a3aSHans de Goede
579f133717eSFabio Aiuto pwep->key_length = wep_key_len;
580f133717eSFabio Aiuto pwep->length = wep_total_len;
581554c0a3aSHans de Goede }
582554c0a3aSHans de Goede
583f133717eSFabio Aiuto pwep->key_index = wep_key_idx;
584554c0a3aSHans de Goede
585f133717eSFabio Aiuto memcpy(pwep->key_material, param->u.crypt.key, pwep->key_length);
586554c0a3aSHans de Goede
587f85ac230STeo Dacquet if (param->u.crypt.set_tx) {
588554c0a3aSHans de Goede psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
589554c0a3aSHans de Goede psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;
590554c0a3aSHans de Goede psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
591554c0a3aSHans de Goede psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
592554c0a3aSHans de Goede
593f133717eSFabio Aiuto if (pwep->key_length == 13) {
594554c0a3aSHans de Goede psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
595554c0a3aSHans de Goede psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
596554c0a3aSHans de Goede }
597554c0a3aSHans de Goede
598554c0a3aSHans de Goede psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx;
599554c0a3aSHans de Goede
600722a3291SFranziska Naepelt memcpy(&psecuritypriv->dot11DefKey[wep_key_idx].skey[0], pwep->key_material, pwep->key_length);
601554c0a3aSHans de Goede
602f133717eSFabio Aiuto psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->key_length;
603554c0a3aSHans de Goede
604f133717eSFabio Aiuto rtw_ap_set_wep_key(padapter, pwep->key_material, pwep->key_length, wep_key_idx, 1);
605f85ac230STeo Dacquet } else {
606554c0a3aSHans de Goede /* don't update "psecuritypriv->dot11PrivacyAlgrthm" and */
607554c0a3aSHans de Goede /* psecuritypriv->dot11PrivacyKeyIndex =keyid", but can rtw_set_key to cam */
608554c0a3aSHans de Goede
609722a3291SFranziska Naepelt memcpy(&psecuritypriv->dot11DefKey[wep_key_idx].skey[0], pwep->key_material, pwep->key_length);
610554c0a3aSHans de Goede
611f133717eSFabio Aiuto psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->key_length;
612554c0a3aSHans de Goede
613f133717eSFabio Aiuto rtw_ap_set_wep_key(padapter, pwep->key_material, pwep->key_length, wep_key_idx, 0);
614554c0a3aSHans de Goede }
615554c0a3aSHans de Goede
616554c0a3aSHans de Goede goto exit;
617554c0a3aSHans de Goede }
618554c0a3aSHans de Goede
619f85ac230STeo Dacquet if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) { /* group key */
620f85ac230STeo Dacquet if (param->u.crypt.set_tx == 1) {
621f85ac230STeo Dacquet if (strcmp(param->u.crypt.alg, "WEP") == 0) {
62214b6cff5SArnd Bergmann memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
623554c0a3aSHans de Goede
624554c0a3aSHans de Goede psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
625554c0a3aSHans de Goede if (param->u.crypt.key_len == 13)
626554c0a3aSHans de Goede psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
627554c0a3aSHans de Goede
628f85ac230STeo Dacquet } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
629554c0a3aSHans de Goede psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
630554c0a3aSHans de Goede
63114b6cff5SArnd Bergmann memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
632554c0a3aSHans de Goede
633554c0a3aSHans de Goede /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */
634554c0a3aSHans de Goede /* set mic key */
635722a3291SFranziska Naepelt memcpy(txkey, ¶m->u.crypt.key[16], 8);
636722a3291SFranziska Naepelt memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, ¶m->u.crypt.key[24], 8);
637554c0a3aSHans de Goede
638554c0a3aSHans de Goede psecuritypriv->busetkipkey = true;
639554c0a3aSHans de Goede
6404762c171SFranziska Naepelt } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
641554c0a3aSHans de Goede psecuritypriv->dot118021XGrpPrivacy = _AES_;
642554c0a3aSHans de Goede
64314b6cff5SArnd Bergmann memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
644f85ac230STeo Dacquet } else {
645554c0a3aSHans de Goede psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
646554c0a3aSHans de Goede }
647554c0a3aSHans de Goede
648554c0a3aSHans de Goede psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx;
649554c0a3aSHans de Goede
650554c0a3aSHans de Goede psecuritypriv->binstallGrpkey = true;
651554c0a3aSHans de Goede
652554c0a3aSHans de Goede psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;/* */
653554c0a3aSHans de Goede
654554c0a3aSHans de Goede rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx);
655554c0a3aSHans de Goede
656554c0a3aSHans de Goede pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
657f85ac230STeo Dacquet if (pbcmc_sta) {
658554c0a3aSHans de Goede pbcmc_sta->ieee8021x_blocked = false;
659554c0a3aSHans de Goede pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;/* rx will use bmc_sta's dot118021XPrivacy */
660554c0a3aSHans de Goede }
661554c0a3aSHans de Goede }
662554c0a3aSHans de Goede
663554c0a3aSHans de Goede goto exit;
664554c0a3aSHans de Goede }
665554c0a3aSHans de Goede
666f85ac230STeo Dacquet if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && psta) { /* psk/802_1x */
667f85ac230STeo Dacquet if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
668f85ac230STeo Dacquet if (param->u.crypt.set_tx == 1) {
669554c0a3aSHans de Goede memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
670554c0a3aSHans de Goede
671f85ac230STeo Dacquet if (strcmp(param->u.crypt.alg, "WEP") == 0) {
672554c0a3aSHans de Goede psta->dot118021XPrivacy = _WEP40_;
673554c0a3aSHans de Goede if (param->u.crypt.key_len == 13)
674554c0a3aSHans de Goede psta->dot118021XPrivacy = _WEP104_;
675f85ac230STeo Dacquet } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
676554c0a3aSHans de Goede psta->dot118021XPrivacy = _TKIP_;
677554c0a3aSHans de Goede
678554c0a3aSHans de Goede /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */
679554c0a3aSHans de Goede /* set mic key */
680722a3291SFranziska Naepelt memcpy(psta->dot11tkiptxmickey.skey, ¶m->u.crypt.key[16], 8);
681722a3291SFranziska Naepelt memcpy(psta->dot11tkiprxmickey.skey, ¶m->u.crypt.key[24], 8);
682554c0a3aSHans de Goede
683554c0a3aSHans de Goede psecuritypriv->busetkipkey = true;
684554c0a3aSHans de Goede
685f85ac230STeo Dacquet } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
686554c0a3aSHans de Goede psta->dot118021XPrivacy = _AES_;
687f85ac230STeo Dacquet } else {
688554c0a3aSHans de Goede psta->dot118021XPrivacy = _NO_PRIVACY_;
689554c0a3aSHans de Goede }
690554c0a3aSHans de Goede
691554c0a3aSHans de Goede rtw_ap_set_pairwise_key(padapter, psta);
692554c0a3aSHans de Goede
693554c0a3aSHans de Goede psta->ieee8021x_blocked = false;
694554c0a3aSHans de Goede
695f85ac230STeo Dacquet } else { /* group key??? */
696f85ac230STeo Dacquet if (strcmp(param->u.crypt.alg, "WEP") == 0) {
69714b6cff5SArnd Bergmann memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
698554c0a3aSHans de Goede
699554c0a3aSHans de Goede psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
700554c0a3aSHans de Goede if (param->u.crypt.key_len == 13)
701554c0a3aSHans de Goede psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
702f85ac230STeo Dacquet } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
703554c0a3aSHans de Goede psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
704554c0a3aSHans de Goede
70514b6cff5SArnd Bergmann memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
706554c0a3aSHans de Goede
707554c0a3aSHans de Goede /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */
708554c0a3aSHans de Goede /* set mic key */
709722a3291SFranziska Naepelt memcpy(txkey, ¶m->u.crypt.key[16], 8);
710722a3291SFranziska Naepelt memcpy(rxkey, ¶m->u.crypt.key[24], 8);
711554c0a3aSHans de Goede
712554c0a3aSHans de Goede psecuritypriv->busetkipkey = true;
713554c0a3aSHans de Goede
714f85ac230STeo Dacquet } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
715554c0a3aSHans de Goede psecuritypriv->dot118021XGrpPrivacy = _AES_;
716554c0a3aSHans de Goede
71714b6cff5SArnd Bergmann memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
718f85ac230STeo Dacquet } else {
719554c0a3aSHans de Goede psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
720554c0a3aSHans de Goede }
721554c0a3aSHans de Goede
722554c0a3aSHans de Goede psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx;
723554c0a3aSHans de Goede
724554c0a3aSHans de Goede psecuritypriv->binstallGrpkey = true;
725554c0a3aSHans de Goede
726554c0a3aSHans de Goede psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;/* */
727554c0a3aSHans de Goede
728554c0a3aSHans de Goede rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx);
729554c0a3aSHans de Goede
730554c0a3aSHans de Goede pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
731f85ac230STeo Dacquet if (pbcmc_sta) {
732554c0a3aSHans de Goede pbcmc_sta->ieee8021x_blocked = false;
733554c0a3aSHans de Goede pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;/* rx will use bmc_sta's dot118021XPrivacy */
734554c0a3aSHans de Goede }
735554c0a3aSHans de Goede }
736554c0a3aSHans de Goede }
737554c0a3aSHans de Goede }
738554c0a3aSHans de Goede
739554c0a3aSHans de Goede exit:
740428715baSAmitoj Kaur Chawla kfree(pwep);
741554c0a3aSHans de Goede
742554c0a3aSHans de Goede return ret;
743554c0a3aSHans de Goede }
744554c0a3aSHans de Goede
rtw_set_beacon(struct net_device * dev,struct ieee_param * param,int len)745554c0a3aSHans de Goede static int rtw_set_beacon(struct net_device *dev, struct ieee_param *param, int len)
746554c0a3aSHans de Goede {
747554c0a3aSHans de Goede int ret = 0;
74842a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
749722a3291SFranziska Naepelt struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
750554c0a3aSHans de Goede struct sta_priv *pstapriv = &padapter->stapriv;
751554c0a3aSHans de Goede unsigned char *pbuf = param->u.bcn_ie.buf;
752554c0a3aSHans de Goede
753554c0a3aSHans de Goede if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
754554c0a3aSHans de Goede return -EINVAL;
755554c0a3aSHans de Goede
756554c0a3aSHans de Goede memcpy(&pstapriv->max_num_sta, param->u.bcn_ie.reserved, 2);
757554c0a3aSHans de Goede
758554c0a3aSHans de Goede if ((pstapriv->max_num_sta > NUM_STA) || (pstapriv->max_num_sta <= 0))
759554c0a3aSHans de Goede pstapriv->max_num_sta = NUM_STA;
760554c0a3aSHans de Goede
761554c0a3aSHans de Goede if (rtw_check_beacon_data(padapter, pbuf, (len - 12 - 2)) == _SUCCESS)/* 12 = param header, 2:no packed */
762554c0a3aSHans de Goede ret = 0;
763554c0a3aSHans de Goede else
764554c0a3aSHans de Goede ret = -EINVAL;
765554c0a3aSHans de Goede
766554c0a3aSHans de Goede return ret;
767554c0a3aSHans de Goede }
768554c0a3aSHans de Goede
rtw_hostapd_sta_flush(struct net_device * dev)769371ec021SHariprasad Kelam static void rtw_hostapd_sta_flush(struct net_device *dev)
770554c0a3aSHans de Goede {
771554c0a3aSHans de Goede /* _irqL irqL; */
772554c0a3aSHans de Goede /* struct list_head *phead, *plist; */
773554c0a3aSHans de Goede /* struct sta_info *psta = NULL; */
77442a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
775554c0a3aSHans de Goede /* struct sta_priv *pstapriv = &padapter->stapriv; */
776554c0a3aSHans de Goede
777554c0a3aSHans de Goede flush_all_cam_entry(padapter); /* clear CAM */
778554c0a3aSHans de Goede
779371ec021SHariprasad Kelam rtw_sta_flush(padapter);
780554c0a3aSHans de Goede }
781554c0a3aSHans de Goede
rtw_add_sta(struct net_device * dev,struct ieee_param * param)782554c0a3aSHans de Goede static int rtw_add_sta(struct net_device *dev, struct ieee_param *param)
783554c0a3aSHans de Goede {
784554c0a3aSHans de Goede int ret = 0;
785554c0a3aSHans de Goede struct sta_info *psta = NULL;
78642a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
787722a3291SFranziska Naepelt struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
788554c0a3aSHans de Goede struct sta_priv *pstapriv = &padapter->stapriv;
789554c0a3aSHans de Goede
790554c0a3aSHans de Goede if (check_fwstate(pmlmepriv, (_FW_LINKED | WIFI_AP_STATE)) != true)
791554c0a3aSHans de Goede return -EINVAL;
792554c0a3aSHans de Goede
793554c0a3aSHans de Goede if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
794554c0a3aSHans de Goede param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
795f85ac230STeo Dacquet param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
796554c0a3aSHans de Goede return -EINVAL;
797554c0a3aSHans de Goede }
798554c0a3aSHans de Goede
799554c0a3aSHans de Goede /*
800554c0a3aSHans de Goede psta = rtw_get_stainfo(pstapriv, param->sta_addr);
801554c0a3aSHans de Goede if (psta)
802554c0a3aSHans de Goede {
803554c0a3aSHans de Goede rtw_free_stainfo(padapter, psta);
804554c0a3aSHans de Goede
805554c0a3aSHans de Goede psta = NULL;
806554c0a3aSHans de Goede }
807554c0a3aSHans de Goede */
808554c0a3aSHans de Goede /* psta = rtw_alloc_stainfo(pstapriv, param->sta_addr); */
809554c0a3aSHans de Goede psta = rtw_get_stainfo(pstapriv, param->sta_addr);
810f85ac230STeo Dacquet if (psta) {
811554c0a3aSHans de Goede int flags = param->u.add_sta.flags;
812554c0a3aSHans de Goede
813554c0a3aSHans de Goede psta->aid = param->u.add_sta.aid;/* aid = 1~2007 */
814554c0a3aSHans de Goede
815554c0a3aSHans de Goede memcpy(psta->bssrateset, param->u.add_sta.tx_supp_rates, 16);
816554c0a3aSHans de Goede
817554c0a3aSHans de Goede /* check wmm cap. */
818554c0a3aSHans de Goede if (WLAN_STA_WME & flags)
819554c0a3aSHans de Goede psta->qos_option = 1;
820554c0a3aSHans de Goede else
821554c0a3aSHans de Goede psta->qos_option = 0;
822554c0a3aSHans de Goede
823554c0a3aSHans de Goede if (pmlmepriv->qospriv.qos_option == 0)
824554c0a3aSHans de Goede psta->qos_option = 0;
825554c0a3aSHans de Goede
826554c0a3aSHans de Goede /* chec 802.11n ht cap. */
827f85ac230STeo Dacquet if (WLAN_STA_HT & flags) {
828554c0a3aSHans de Goede psta->htpriv.ht_option = true;
829554c0a3aSHans de Goede psta->qos_option = 1;
830c25d8a7dSRoss Schmidt memcpy((void *)&psta->htpriv.ht_cap, (void *)¶m->u.add_sta.ht_cap, sizeof(struct ieee80211_ht_cap));
831f85ac230STeo Dacquet } else {
832554c0a3aSHans de Goede psta->htpriv.ht_option = false;
833554c0a3aSHans de Goede }
834554c0a3aSHans de Goede
835*e1bfd974SFranziska Naepelt if (!pmlmepriv->htpriv.ht_option)
836554c0a3aSHans de Goede psta->htpriv.ht_option = false;
837554c0a3aSHans de Goede
838554c0a3aSHans de Goede update_sta_info_apmode(padapter, psta);
839554c0a3aSHans de Goede
840f85ac230STeo Dacquet } else {
841554c0a3aSHans de Goede ret = -ENOMEM;
842554c0a3aSHans de Goede }
843554c0a3aSHans de Goede
844554c0a3aSHans de Goede return ret;
845554c0a3aSHans de Goede }
846554c0a3aSHans de Goede
rtw_del_sta(struct net_device * dev,struct ieee_param * param)847554c0a3aSHans de Goede static int rtw_del_sta(struct net_device *dev, struct ieee_param *param)
848554c0a3aSHans de Goede {
849554c0a3aSHans de Goede int ret = 0;
850554c0a3aSHans de Goede struct sta_info *psta = NULL;
85142a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
852722a3291SFranziska Naepelt struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
853554c0a3aSHans de Goede struct sta_priv *pstapriv = &padapter->stapriv;
854554c0a3aSHans de Goede
855554c0a3aSHans de Goede if (check_fwstate(pmlmepriv, (_FW_LINKED | WIFI_AP_STATE)) != true)
856554c0a3aSHans de Goede return -EINVAL;
857554c0a3aSHans de Goede
858554c0a3aSHans de Goede if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
859554c0a3aSHans de Goede param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
860f85ac230STeo Dacquet param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
861554c0a3aSHans de Goede return -EINVAL;
862554c0a3aSHans de Goede }
863554c0a3aSHans de Goede
864554c0a3aSHans de Goede psta = rtw_get_stainfo(pstapriv, param->sta_addr);
865f85ac230STeo Dacquet if (psta) {
866554c0a3aSHans de Goede u8 updated = false;
867554c0a3aSHans de Goede
868554c0a3aSHans de Goede spin_lock_bh(&pstapriv->asoc_list_lock);
869f85ac230STeo Dacquet if (list_empty(&psta->asoc_list) == false) {
870554c0a3aSHans de Goede list_del_init(&psta->asoc_list);
871554c0a3aSHans de Goede pstapriv->asoc_list_cnt--;
872554c0a3aSHans de Goede updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING);
873554c0a3aSHans de Goede }
874554c0a3aSHans de Goede spin_unlock_bh(&pstapriv->asoc_list_lock);
875554c0a3aSHans de Goede
876554c0a3aSHans de Goede associated_clients_update(padapter, updated);
877554c0a3aSHans de Goede
878554c0a3aSHans de Goede psta = NULL;
879554c0a3aSHans de Goede }
880554c0a3aSHans de Goede
881554c0a3aSHans de Goede return ret;
882554c0a3aSHans de Goede }
883554c0a3aSHans de Goede
rtw_ioctl_get_sta_data(struct net_device * dev,struct ieee_param * param,int len)884554c0a3aSHans de Goede static int rtw_ioctl_get_sta_data(struct net_device *dev, struct ieee_param *param, int len)
885554c0a3aSHans de Goede {
886554c0a3aSHans de Goede int ret = 0;
887554c0a3aSHans de Goede struct sta_info *psta = NULL;
88842a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
889722a3291SFranziska Naepelt struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
890554c0a3aSHans de Goede struct sta_priv *pstapriv = &padapter->stapriv;
891554c0a3aSHans de Goede struct ieee_param_ex *param_ex = (struct ieee_param_ex *)param;
892554c0a3aSHans de Goede struct sta_data *psta_data = (struct sta_data *)param_ex->data;
893554c0a3aSHans de Goede
894554c0a3aSHans de Goede if (check_fwstate(pmlmepriv, (_FW_LINKED | WIFI_AP_STATE)) != true)
895554c0a3aSHans de Goede return -EINVAL;
896554c0a3aSHans de Goede
897554c0a3aSHans de Goede if (param_ex->sta_addr[0] == 0xff && param_ex->sta_addr[1] == 0xff &&
898554c0a3aSHans de Goede param_ex->sta_addr[2] == 0xff && param_ex->sta_addr[3] == 0xff &&
899f85ac230STeo Dacquet param_ex->sta_addr[4] == 0xff && param_ex->sta_addr[5] == 0xff) {
900554c0a3aSHans de Goede return -EINVAL;
901554c0a3aSHans de Goede }
902554c0a3aSHans de Goede
903554c0a3aSHans de Goede psta = rtw_get_stainfo(pstapriv, param_ex->sta_addr);
904f85ac230STeo Dacquet if (psta) {
905554c0a3aSHans de Goede psta_data->aid = (u16)psta->aid;
906554c0a3aSHans de Goede psta_data->capability = psta->capability;
907554c0a3aSHans de Goede psta_data->flags = psta->flags;
908554c0a3aSHans de Goede
909554c0a3aSHans de Goede /*
910554c0a3aSHans de Goede nonerp_set : BIT(0)
911554c0a3aSHans de Goede no_short_slot_time_set : BIT(1)
912554c0a3aSHans de Goede no_short_preamble_set : BIT(2)
913554c0a3aSHans de Goede no_ht_gf_set : BIT(3)
914554c0a3aSHans de Goede no_ht_set : BIT(4)
915554c0a3aSHans de Goede ht_20mhz_set : BIT(5)
916554c0a3aSHans de Goede */
917554c0a3aSHans de Goede
918554c0a3aSHans de Goede psta_data->sta_set = ((psta->nonerp_set) |
919554c0a3aSHans de Goede (psta->no_short_slot_time_set << 1) |
920554c0a3aSHans de Goede (psta->no_short_preamble_set << 2) |
921554c0a3aSHans de Goede (psta->no_ht_gf_set << 3) |
922554c0a3aSHans de Goede (psta->no_ht_set << 4) |
923554c0a3aSHans de Goede (psta->ht_20mhz_set << 5));
924554c0a3aSHans de Goede
925554c0a3aSHans de Goede psta_data->tx_supp_rates_len = psta->bssratelen;
926554c0a3aSHans de Goede memcpy(psta_data->tx_supp_rates, psta->bssrateset, psta->bssratelen);
927c25d8a7dSRoss Schmidt memcpy(&psta_data->ht_cap, &psta->htpriv.ht_cap, sizeof(struct ieee80211_ht_cap));
928554c0a3aSHans de Goede psta_data->rx_pkts = psta->sta_stats.rx_data_pkts;
929554c0a3aSHans de Goede psta_data->rx_bytes = psta->sta_stats.rx_bytes;
930554c0a3aSHans de Goede psta_data->rx_drops = psta->sta_stats.rx_drops;
931554c0a3aSHans de Goede
932554c0a3aSHans de Goede psta_data->tx_pkts = psta->sta_stats.tx_pkts;
933554c0a3aSHans de Goede psta_data->tx_bytes = psta->sta_stats.tx_bytes;
934554c0a3aSHans de Goede psta_data->tx_drops = psta->sta_stats.tx_drops;
935554c0a3aSHans de Goede
936f85ac230STeo Dacquet } else {
937554c0a3aSHans de Goede ret = -1;
938554c0a3aSHans de Goede }
939554c0a3aSHans de Goede
940554c0a3aSHans de Goede return ret;
941554c0a3aSHans de Goede }
942554c0a3aSHans de Goede
rtw_get_sta_wpaie(struct net_device * dev,struct ieee_param * param)943554c0a3aSHans de Goede static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param)
944554c0a3aSHans de Goede {
945554c0a3aSHans de Goede int ret = 0;
946554c0a3aSHans de Goede struct sta_info *psta = NULL;
94742a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
948722a3291SFranziska Naepelt struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
949554c0a3aSHans de Goede struct sta_priv *pstapriv = &padapter->stapriv;
950554c0a3aSHans de Goede
951554c0a3aSHans de Goede if (check_fwstate(pmlmepriv, (_FW_LINKED | WIFI_AP_STATE)) != true)
952554c0a3aSHans de Goede return -EINVAL;
953554c0a3aSHans de Goede
954554c0a3aSHans de Goede if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
955554c0a3aSHans de Goede param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
956f85ac230STeo Dacquet param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
957554c0a3aSHans de Goede return -EINVAL;
958554c0a3aSHans de Goede }
959554c0a3aSHans de Goede
960554c0a3aSHans de Goede psta = rtw_get_stainfo(pstapriv, param->sta_addr);
961f85ac230STeo Dacquet if (psta) {
962b05cc3a9SRoss Schmidt if ((psta->wpa_ie[0] == WLAN_EID_RSN) || (psta->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC)) {
963554c0a3aSHans de Goede int wpa_ie_len;
964554c0a3aSHans de Goede int copy_len;
965554c0a3aSHans de Goede
966554c0a3aSHans de Goede wpa_ie_len = psta->wpa_ie[1];
967554c0a3aSHans de Goede
968554c0a3aSHans de Goede copy_len = ((wpa_ie_len + 2) > sizeof(psta->wpa_ie)) ? (sizeof(psta->wpa_ie)) : (wpa_ie_len + 2);
969554c0a3aSHans de Goede
970554c0a3aSHans de Goede param->u.wpa_ie.len = copy_len;
971554c0a3aSHans de Goede
972554c0a3aSHans de Goede memcpy(param->u.wpa_ie.reserved, psta->wpa_ie, copy_len);
973554c0a3aSHans de Goede }
974f85ac230STeo Dacquet } else {
975554c0a3aSHans de Goede ret = -1;
976554c0a3aSHans de Goede }
977554c0a3aSHans de Goede
978554c0a3aSHans de Goede return ret;
979554c0a3aSHans de Goede }
980554c0a3aSHans de Goede
rtw_set_wps_beacon(struct net_device * dev,struct ieee_param * param,int len)981554c0a3aSHans de Goede static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param, int len)
982554c0a3aSHans de Goede {
983554c0a3aSHans de Goede int ret = 0;
984554c0a3aSHans de Goede unsigned char wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
98542a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
986722a3291SFranziska Naepelt struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
987722a3291SFranziska Naepelt struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
988554c0a3aSHans de Goede int ie_len;
989554c0a3aSHans de Goede
990554c0a3aSHans de Goede if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
991554c0a3aSHans de Goede return -EINVAL;
992554c0a3aSHans de Goede
993554c0a3aSHans de Goede ie_len = len - 12 - 2;/* 12 = param header, 2:no packed */
994554c0a3aSHans de Goede
995554c0a3aSHans de Goede kfree(pmlmepriv->wps_beacon_ie);
996554c0a3aSHans de Goede pmlmepriv->wps_beacon_ie = NULL;
997554c0a3aSHans de Goede
998f85ac230STeo Dacquet if (ie_len > 0) {
999554c0a3aSHans de Goede pmlmepriv->wps_beacon_ie = rtw_malloc(ie_len);
1000554c0a3aSHans de Goede pmlmepriv->wps_beacon_ie_len = ie_len;
1001e427bdd8SFabio Aiuto if (!pmlmepriv->wps_beacon_ie)
1002554c0a3aSHans de Goede return -EINVAL;
1003554c0a3aSHans de Goede
1004554c0a3aSHans de Goede memcpy(pmlmepriv->wps_beacon_ie, param->u.bcn_ie.buf, ie_len);
1005554c0a3aSHans de Goede
1006b05cc3a9SRoss Schmidt update_beacon(padapter, WLAN_EID_VENDOR_SPECIFIC, wps_oui, true);
1007554c0a3aSHans de Goede
1008554c0a3aSHans de Goede pmlmeext->bstart_bss = true;
1009554c0a3aSHans de Goede }
1010554c0a3aSHans de Goede
1011554c0a3aSHans de Goede return ret;
1012554c0a3aSHans de Goede }
1013554c0a3aSHans de Goede
rtw_set_wps_probe_resp(struct net_device * dev,struct ieee_param * param,int len)1014554c0a3aSHans de Goede static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *param, int len)
1015554c0a3aSHans de Goede {
1016554c0a3aSHans de Goede int ret = 0;
101742a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
1018722a3291SFranziska Naepelt struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1019554c0a3aSHans de Goede int ie_len;
1020554c0a3aSHans de Goede
1021554c0a3aSHans de Goede if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
1022554c0a3aSHans de Goede return -EINVAL;
1023554c0a3aSHans de Goede
1024554c0a3aSHans de Goede ie_len = len - 12 - 2;/* 12 = param header, 2:no packed */
1025554c0a3aSHans de Goede
1026554c0a3aSHans de Goede kfree(pmlmepriv->wps_probe_resp_ie);
1027554c0a3aSHans de Goede pmlmepriv->wps_probe_resp_ie = NULL;
1028554c0a3aSHans de Goede
1029f85ac230STeo Dacquet if (ie_len > 0) {
1030554c0a3aSHans de Goede pmlmepriv->wps_probe_resp_ie = rtw_malloc(ie_len);
1031554c0a3aSHans de Goede pmlmepriv->wps_probe_resp_ie_len = ie_len;
1032e427bdd8SFabio Aiuto if (!pmlmepriv->wps_probe_resp_ie)
1033554c0a3aSHans de Goede return -EINVAL;
1034709c8e49SFabio Aiuto
1035554c0a3aSHans de Goede memcpy(pmlmepriv->wps_probe_resp_ie, param->u.bcn_ie.buf, ie_len);
1036554c0a3aSHans de Goede }
1037554c0a3aSHans de Goede
1038554c0a3aSHans de Goede return ret;
1039554c0a3aSHans de Goede }
1040554c0a3aSHans de Goede
rtw_set_wps_assoc_resp(struct net_device * dev,struct ieee_param * param,int len)1041554c0a3aSHans de Goede static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *param, int len)
1042554c0a3aSHans de Goede {
1043554c0a3aSHans de Goede int ret = 0;
104442a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
1045722a3291SFranziska Naepelt struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1046554c0a3aSHans de Goede int ie_len;
1047554c0a3aSHans de Goede
1048554c0a3aSHans de Goede if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
1049554c0a3aSHans de Goede return -EINVAL;
1050554c0a3aSHans de Goede
1051554c0a3aSHans de Goede ie_len = len - 12 - 2;/* 12 = param header, 2:no packed */
1052554c0a3aSHans de Goede
1053554c0a3aSHans de Goede kfree(pmlmepriv->wps_assoc_resp_ie);
1054554c0a3aSHans de Goede pmlmepriv->wps_assoc_resp_ie = NULL;
1055554c0a3aSHans de Goede
1056f85ac230STeo Dacquet if (ie_len > 0) {
1057554c0a3aSHans de Goede pmlmepriv->wps_assoc_resp_ie = rtw_malloc(ie_len);
1058554c0a3aSHans de Goede pmlmepriv->wps_assoc_resp_ie_len = ie_len;
1059e427bdd8SFabio Aiuto if (!pmlmepriv->wps_assoc_resp_ie)
1060554c0a3aSHans de Goede return -EINVAL;
1061554c0a3aSHans de Goede
1062554c0a3aSHans de Goede memcpy(pmlmepriv->wps_assoc_resp_ie, param->u.bcn_ie.buf, ie_len);
1063554c0a3aSHans de Goede }
1064554c0a3aSHans de Goede
1065554c0a3aSHans de Goede return ret;
1066554c0a3aSHans de Goede }
1067554c0a3aSHans de Goede
rtw_set_hidden_ssid(struct net_device * dev,struct ieee_param * param,int len)1068554c0a3aSHans de Goede static int rtw_set_hidden_ssid(struct net_device *dev, struct ieee_param *param, int len)
1069554c0a3aSHans de Goede {
1070554c0a3aSHans de Goede int ret = 0;
107142a18f09SIvan Safonov struct adapter *adapter = rtw_netdev_priv(dev);
1072722a3291SFranziska Naepelt struct mlme_priv *mlmepriv = &adapter->mlmepriv;
1073722a3291SFranziska Naepelt struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
1074722a3291SFranziska Naepelt struct mlme_ext_info *mlmeinfo = &mlmeext->mlmext_info;
1075554c0a3aSHans de Goede int ie_len;
1076554c0a3aSHans de Goede u8 *ssid_ie;
1077554c0a3aSHans de Goede char ssid[NDIS_802_11_LENGTH_SSID + 1];
1078d495c550SMarco Cesati signed int ssid_len;
1079554c0a3aSHans de Goede u8 ignore_broadcast_ssid;
1080554c0a3aSHans de Goede
1081554c0a3aSHans de Goede if (check_fwstate(mlmepriv, WIFI_AP_STATE) != true)
1082554c0a3aSHans de Goede return -EPERM;
1083554c0a3aSHans de Goede
1084554c0a3aSHans de Goede if (param->u.bcn_ie.reserved[0] != 0xea)
1085554c0a3aSHans de Goede return -EINVAL;
1086554c0a3aSHans de Goede
1087554c0a3aSHans de Goede mlmeinfo->hidden_ssid_mode = ignore_broadcast_ssid = param->u.bcn_ie.reserved[1];
1088554c0a3aSHans de Goede
1089554c0a3aSHans de Goede ie_len = len - 12 - 2;/* 12 = param header, 2:no packed */
1090554c0a3aSHans de Goede ssid_ie = rtw_get_ie(param->u.bcn_ie.buf, WLAN_EID_SSID, &ssid_len, ie_len);
1091554c0a3aSHans de Goede
1092554c0a3aSHans de Goede if (ssid_ie && ssid_len > 0 && ssid_len <= NDIS_802_11_LENGTH_SSID) {
1093554c0a3aSHans de Goede struct wlan_bssid_ex *pbss_network = &mlmepriv->cur_network.network;
1094554c0a3aSHans de Goede struct wlan_bssid_ex *pbss_network_ext = &mlmeinfo->network;
1095554c0a3aSHans de Goede
1096554c0a3aSHans de Goede memcpy(ssid, ssid_ie + 2, ssid_len);
1097554c0a3aSHans de Goede ssid[ssid_len] = 0x0;
1098554c0a3aSHans de Goede
10996994aa43SFabio Aiuto memcpy(pbss_network->ssid.ssid, (void *)ssid, ssid_len);
11006994aa43SFabio Aiuto pbss_network->ssid.ssid_length = ssid_len;
11016994aa43SFabio Aiuto memcpy(pbss_network_ext->ssid.ssid, (void *)ssid, ssid_len);
11026994aa43SFabio Aiuto pbss_network_ext->ssid.ssid_length = ssid_len;
1103554c0a3aSHans de Goede }
1104554c0a3aSHans de Goede
1105554c0a3aSHans de Goede return ret;
1106554c0a3aSHans de Goede }
1107554c0a3aSHans de Goede
rtw_ioctl_acl_remove_sta(struct net_device * dev,struct ieee_param * param,int len)1108554c0a3aSHans de Goede static int rtw_ioctl_acl_remove_sta(struct net_device *dev, struct ieee_param *param, int len)
1109554c0a3aSHans de Goede {
111042a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
1111722a3291SFranziska Naepelt struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1112554c0a3aSHans de Goede
1113554c0a3aSHans de Goede if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
1114554c0a3aSHans de Goede return -EINVAL;
1115554c0a3aSHans de Goede
1116554c0a3aSHans de Goede if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
1117554c0a3aSHans de Goede param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
1118f85ac230STeo Dacquet param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
1119554c0a3aSHans de Goede return -EINVAL;
1120554c0a3aSHans de Goede }
1121554c0a3aSHans de Goede
11224769aae3SShobhit Kukreti rtw_acl_remove_sta(padapter, param->sta_addr);
11234769aae3SShobhit Kukreti return 0;
1124554c0a3aSHans de Goede }
1125554c0a3aSHans de Goede
rtw_ioctl_acl_add_sta(struct net_device * dev,struct ieee_param * param,int len)1126554c0a3aSHans de Goede static int rtw_ioctl_acl_add_sta(struct net_device *dev, struct ieee_param *param, int len)
1127554c0a3aSHans de Goede {
112842a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
1129722a3291SFranziska Naepelt struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1130554c0a3aSHans de Goede
1131554c0a3aSHans de Goede if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
1132554c0a3aSHans de Goede return -EINVAL;
1133554c0a3aSHans de Goede
1134554c0a3aSHans de Goede if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
1135554c0a3aSHans de Goede param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
1136f85ac230STeo Dacquet param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
1137554c0a3aSHans de Goede return -EINVAL;
1138554c0a3aSHans de Goede }
1139554c0a3aSHans de Goede
1140dedc1a73SHarsha Sharma return rtw_acl_add_sta(padapter, param->sta_addr);
1141554c0a3aSHans de Goede }
1142554c0a3aSHans de Goede
rtw_ioctl_set_macaddr_acl(struct net_device * dev,struct ieee_param * param,int len)1143554c0a3aSHans de Goede static int rtw_ioctl_set_macaddr_acl(struct net_device *dev, struct ieee_param *param, int len)
1144554c0a3aSHans de Goede {
1145554c0a3aSHans de Goede int ret = 0;
114642a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
1147722a3291SFranziska Naepelt struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1148554c0a3aSHans de Goede
1149554c0a3aSHans de Goede if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
1150554c0a3aSHans de Goede return -EINVAL;
1151554c0a3aSHans de Goede
1152554c0a3aSHans de Goede rtw_set_macaddr_acl(padapter, param->u.mlme.command);
1153554c0a3aSHans de Goede
1154554c0a3aSHans de Goede return ret;
1155554c0a3aSHans de Goede }
1156554c0a3aSHans de Goede
rtw_hostapd_ioctl(struct net_device * dev,struct iw_point * p)1157554c0a3aSHans de Goede static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p)
1158554c0a3aSHans de Goede {
1159554c0a3aSHans de Goede struct ieee_param *param;
1160554c0a3aSHans de Goede int ret = 0;
116142a18f09SIvan Safonov struct adapter *padapter = rtw_netdev_priv(dev);
1162554c0a3aSHans de Goede
1163554c0a3aSHans de Goede /*
1164554c0a3aSHans de Goede * this function is expect to call in master mode, which allows no power saving
1165554c0a3aSHans de Goede * so, we just check hw_init_completed
1166554c0a3aSHans de Goede */
1167554c0a3aSHans de Goede
11689a4556bdSLarry Finger if (!padapter->hw_init_completed)
11699a4556bdSLarry Finger return -EPERM;
1170554c0a3aSHans de Goede
11719a4556bdSLarry Finger if (!p->pointer || p->length != sizeof(*param))
11729a4556bdSLarry Finger return -EINVAL;
1173554c0a3aSHans de Goede
11742ef2b7c2SJoe Perches param = rtw_malloc(p->length);
1175cd1f1450SMichael Straube if (!param)
11769a4556bdSLarry Finger return -ENOMEM;
1177554c0a3aSHans de Goede
1178f85ac230STeo Dacquet if (copy_from_user(param, p->pointer, p->length)) {
1179428715baSAmitoj Kaur Chawla kfree(param);
11809a4556bdSLarry Finger return -EFAULT;
1181554c0a3aSHans de Goede }
1182554c0a3aSHans de Goede
1183f85ac230STeo Dacquet switch (param->cmd) {
1184554c0a3aSHans de Goede case RTL871X_HOSTAPD_FLUSH:
1185554c0a3aSHans de Goede
1186371ec021SHariprasad Kelam rtw_hostapd_sta_flush(dev);
1187554c0a3aSHans de Goede
1188554c0a3aSHans de Goede break;
1189554c0a3aSHans de Goede
1190554c0a3aSHans de Goede case RTL871X_HOSTAPD_ADD_STA:
1191554c0a3aSHans de Goede
1192554c0a3aSHans de Goede ret = rtw_add_sta(dev, param);
1193554c0a3aSHans de Goede
1194554c0a3aSHans de Goede break;
1195554c0a3aSHans de Goede
1196554c0a3aSHans de Goede case RTL871X_HOSTAPD_REMOVE_STA:
1197554c0a3aSHans de Goede
1198554c0a3aSHans de Goede ret = rtw_del_sta(dev, param);
1199554c0a3aSHans de Goede
1200554c0a3aSHans de Goede break;
1201554c0a3aSHans de Goede
1202554c0a3aSHans de Goede case RTL871X_HOSTAPD_SET_BEACON:
1203554c0a3aSHans de Goede
1204554c0a3aSHans de Goede ret = rtw_set_beacon(dev, param, p->length);
1205554c0a3aSHans de Goede
1206554c0a3aSHans de Goede break;
1207554c0a3aSHans de Goede
1208554c0a3aSHans de Goede case RTL871X_SET_ENCRYPTION:
1209554c0a3aSHans de Goede
1210554c0a3aSHans de Goede ret = rtw_set_encryption(dev, param, p->length);
1211554c0a3aSHans de Goede
1212554c0a3aSHans de Goede break;
1213554c0a3aSHans de Goede
1214554c0a3aSHans de Goede case RTL871X_HOSTAPD_GET_WPAIE_STA:
1215554c0a3aSHans de Goede
1216554c0a3aSHans de Goede ret = rtw_get_sta_wpaie(dev, param);
1217554c0a3aSHans de Goede
1218554c0a3aSHans de Goede break;
1219554c0a3aSHans de Goede
1220554c0a3aSHans de Goede case RTL871X_HOSTAPD_SET_WPS_BEACON:
1221554c0a3aSHans de Goede
1222554c0a3aSHans de Goede ret = rtw_set_wps_beacon(dev, param, p->length);
1223554c0a3aSHans de Goede
1224554c0a3aSHans de Goede break;
1225554c0a3aSHans de Goede
1226554c0a3aSHans de Goede case RTL871X_HOSTAPD_SET_WPS_PROBE_RESP:
1227554c0a3aSHans de Goede
1228554c0a3aSHans de Goede ret = rtw_set_wps_probe_resp(dev, param, p->length);
1229554c0a3aSHans de Goede
1230554c0a3aSHans de Goede break;
1231554c0a3aSHans de Goede
1232554c0a3aSHans de Goede case RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP:
1233554c0a3aSHans de Goede
1234554c0a3aSHans de Goede ret = rtw_set_wps_assoc_resp(dev, param, p->length);
1235554c0a3aSHans de Goede
1236554c0a3aSHans de Goede break;
1237554c0a3aSHans de Goede
1238554c0a3aSHans de Goede case RTL871X_HOSTAPD_SET_HIDDEN_SSID:
1239554c0a3aSHans de Goede
1240554c0a3aSHans de Goede ret = rtw_set_hidden_ssid(dev, param, p->length);
1241554c0a3aSHans de Goede
1242554c0a3aSHans de Goede break;
1243554c0a3aSHans de Goede
1244554c0a3aSHans de Goede case RTL871X_HOSTAPD_GET_INFO_STA:
1245554c0a3aSHans de Goede
1246554c0a3aSHans de Goede ret = rtw_ioctl_get_sta_data(dev, param, p->length);
1247554c0a3aSHans de Goede
1248554c0a3aSHans de Goede break;
1249554c0a3aSHans de Goede
1250554c0a3aSHans de Goede case RTL871X_HOSTAPD_SET_MACADDR_ACL:
1251554c0a3aSHans de Goede
1252554c0a3aSHans de Goede ret = rtw_ioctl_set_macaddr_acl(dev, param, p->length);
1253554c0a3aSHans de Goede
1254554c0a3aSHans de Goede break;
1255554c0a3aSHans de Goede
1256554c0a3aSHans de Goede case RTL871X_HOSTAPD_ACL_ADD_STA:
1257554c0a3aSHans de Goede
1258554c0a3aSHans de Goede ret = rtw_ioctl_acl_add_sta(dev, param, p->length);
1259554c0a3aSHans de Goede
1260554c0a3aSHans de Goede break;
1261554c0a3aSHans de Goede
1262554c0a3aSHans de Goede case RTL871X_HOSTAPD_ACL_REMOVE_STA:
1263554c0a3aSHans de Goede
1264554c0a3aSHans de Goede ret = rtw_ioctl_acl_remove_sta(dev, param, p->length);
1265554c0a3aSHans de Goede
1266554c0a3aSHans de Goede break;
1267554c0a3aSHans de Goede
1268554c0a3aSHans de Goede default:
1269554c0a3aSHans de Goede ret = -EOPNOTSUPP;
1270554c0a3aSHans de Goede break;
1271554c0a3aSHans de Goede }
1272554c0a3aSHans de Goede
1273554c0a3aSHans de Goede if (ret == 0 && copy_to_user(p->pointer, param, p->length))
1274554c0a3aSHans de Goede ret = -EFAULT;
1275554c0a3aSHans de Goede
1276428715baSAmitoj Kaur Chawla kfree(param);
1277554c0a3aSHans de Goede return ret;
1278554c0a3aSHans de Goede }
1279554c0a3aSHans de Goede
1280554c0a3aSHans de Goede /* copy from net/wireless/wext.c end */
1281554c0a3aSHans de Goede
rtw_ioctl(struct net_device * dev,struct ifreq * rq,int cmd)1282554c0a3aSHans de Goede int rtw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
1283554c0a3aSHans de Goede {
1284554c0a3aSHans de Goede struct iwreq *wrq = (struct iwreq *)rq;
1285554c0a3aSHans de Goede int ret = 0;
1286554c0a3aSHans de Goede
1287f85ac230STeo Dacquet switch (cmd) {
1288554c0a3aSHans de Goede case RTL_IOCTL_WPA_SUPPLICANT:
1289554c0a3aSHans de Goede ret = wpa_supplicant_ioctl(dev, &wrq->u.data);
1290554c0a3aSHans de Goede break;
1291554c0a3aSHans de Goede case RTL_IOCTL_HOSTAPD:
1292554c0a3aSHans de Goede ret = rtw_hostapd_ioctl(dev, &wrq->u.data);
1293554c0a3aSHans de Goede break;
1294554c0a3aSHans de Goede default:
1295554c0a3aSHans de Goede ret = -EOPNOTSUPP;
1296554c0a3aSHans de Goede break;
1297554c0a3aSHans de Goede }
1298554c0a3aSHans de Goede
1299554c0a3aSHans de Goede return ret;
1300554c0a3aSHans de Goede }
1301