1 // SPDX-License-Identifier: GPL-2.0 2 /****************************************************************************** 3 * rtl871x_ioctl_set.c 4 * 5 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. 6 * Linux device driver for RTL8192SU 7 * 8 * Modifications for inclusion into the Linux staging tree are 9 * Copyright(c) 2010 Larry Finger. All rights reserved. 10 * 11 * Contact information: 12 * WLAN FAE <wlanfae@realtek.com> 13 * Larry Finger <Larry.Finger@lwfinger.net> 14 * 15 ******************************************************************************/ 16 17 #define _RTL871X_IOCTL_SET_C_ 18 19 #include "osdep_service.h" 20 #include "drv_types.h" 21 #include "rtl871x_ioctl_set.h" 22 #include "usb_osintf.h" 23 #include "usb_ops.h" 24 25 static u8 validate_ssid(struct ndis_802_11_ssid *ssid) 26 { 27 u8 i; 28 29 if (ssid->SsidLength > 32) 30 return false; 31 for (i = 0; i < ssid->SsidLength; i++) { 32 /* wifi, printable ascii code must be supported */ 33 if (!((ssid->Ssid[i] >= 0x20) && (ssid->Ssid[i] <= 0x7e))) 34 return false; 35 } 36 return true; 37 } 38 39 static u8 do_join(struct _adapter *padapter) 40 { 41 struct list_head *plist, *phead; 42 u8 *pibss = NULL; 43 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); 44 struct __queue *queue = &(pmlmepriv->scanned_queue); 45 int ret; 46 47 phead = &queue->queue; 48 plist = phead->next; 49 pmlmepriv->cur_network.join_res = -2; 50 pmlmepriv->fw_state |= _FW_UNDER_LINKING; 51 pmlmepriv->pscanned = plist; 52 pmlmepriv->to_join = true; 53 54 /* adhoc mode will start with an empty queue, but skip checking */ 55 if (!check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) && 56 list_empty(&queue->queue)) { 57 if (pmlmepriv->fw_state & _FW_UNDER_LINKING) 58 pmlmepriv->fw_state ^= _FW_UNDER_LINKING; 59 /* when set_ssid/set_bssid for do_join(), but scanning queue 60 * is empty we try to issue sitesurvey firstly 61 */ 62 if (!pmlmepriv->sitesurveyctrl.traffic_busy) 63 r8712_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid); 64 return true; 65 } 66 67 ret = r8712_select_and_join_from_scan(pmlmepriv); 68 if (!ret) { 69 mod_timer(&pmlmepriv->assoc_timer, 70 jiffies + msecs_to_jiffies(MAX_JOIN_TIMEOUT)); 71 } else { 72 if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { 73 /* submit r8712_createbss_cmd to change to an 74 * ADHOC_MASTER pmlmepriv->lock has been 75 * acquired by caller... 76 */ 77 struct wlan_bssid_ex *pdev_network = 78 &padapter->registrypriv.dev_network; 79 pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; 80 pibss = padapter->registrypriv.dev_network.MacAddress; 81 memcpy(&pdev_network->Ssid, 82 &pmlmepriv->assoc_ssid, 83 sizeof(struct ndis_802_11_ssid)); 84 r8712_update_registrypriv_dev_network(padapter); 85 r8712_generate_random_ibss(pibss); 86 if (r8712_createbss_cmd(padapter)) 87 return false; 88 pmlmepriv->to_join = false; 89 } else { 90 /* can't associate ; reset under-linking */ 91 if (pmlmepriv->fw_state & _FW_UNDER_LINKING) 92 pmlmepriv->fw_state ^= 93 _FW_UNDER_LINKING; 94 /* when set_ssid/set_bssid for do_join(), but 95 * there are no desired bss in scanning queue 96 * we try to issue sitesurvey first 97 */ 98 if (!pmlmepriv->sitesurveyctrl.traffic_busy) 99 r8712_sitesurvey_cmd(padapter, 100 &pmlmepriv->assoc_ssid); 101 } 102 } 103 return true; 104 } 105 106 u8 r8712_set_802_11_bssid(struct _adapter *padapter, u8 *bssid) 107 { 108 unsigned long irqL; 109 u8 status = true; 110 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 111 112 if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) { 113 status = false; 114 return status; 115 } 116 spin_lock_irqsave(&pmlmepriv->lock, irqL); 117 if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | 118 _FW_UNDER_LINKING)) { 119 status = check_fwstate(pmlmepriv, _FW_UNDER_LINKING); 120 goto _Abort_Set_BSSID; 121 } 122 if (check_fwstate(pmlmepriv, 123 _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) { 124 if (!memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, 125 ETH_ALEN)) { 126 if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE)) 127 /* driver is in 128 * WIFI_ADHOC_MASTER_STATE 129 */ 130 goto _Abort_Set_BSSID; 131 } else { 132 r8712_disassoc_cmd(padapter); 133 if (check_fwstate(pmlmepriv, _FW_LINKED)) 134 r8712_ind_disconnect(padapter); 135 r8712_free_assoc_resources(padapter); 136 if ((check_fwstate(pmlmepriv, 137 WIFI_ADHOC_MASTER_STATE))) { 138 _clr_fwstate_(pmlmepriv, 139 WIFI_ADHOC_MASTER_STATE); 140 set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); 141 } 142 } 143 } 144 memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN); 145 pmlmepriv->assoc_by_bssid = true; 146 status = do_join(padapter); 147 goto done; 148 _Abort_Set_BSSID: 149 done: 150 spin_unlock_irqrestore(&pmlmepriv->lock, irqL); 151 return status; 152 } 153 154 void r8712_set_802_11_ssid(struct _adapter *padapter, 155 struct ndis_802_11_ssid *ssid) 156 { 157 unsigned long irqL; 158 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 159 struct wlan_network *pnetwork = &pmlmepriv->cur_network; 160 161 if (!padapter->hw_init_completed) 162 return; 163 spin_lock_irqsave(&pmlmepriv->lock, irqL); 164 if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING)) { 165 check_fwstate(pmlmepriv, _FW_UNDER_LINKING); 166 goto _Abort_Set_SSID; 167 } 168 if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) { 169 if ((pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength) && 170 (!memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, 171 ssid->SsidLength))) { 172 if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { 173 if (!r8712_is_same_ibss(padapter, 174 pnetwork)) { 175 /* if in WIFI_ADHOC_MASTER_STATE or 176 * WIFI_ADHOC_STATE, create bss or 177 * rejoin again 178 */ 179 r8712_disassoc_cmd(padapter); 180 if (check_fwstate(pmlmepriv, 181 _FW_LINKED)) 182 r8712_ind_disconnect(padapter); 183 r8712_free_assoc_resources(padapter); 184 if (check_fwstate(pmlmepriv, 185 WIFI_ADHOC_MASTER_STATE)) { 186 _clr_fwstate_(pmlmepriv, 187 WIFI_ADHOC_MASTER_STATE); 188 set_fwstate(pmlmepriv, 189 WIFI_ADHOC_STATE); 190 } 191 } else { 192 /* driver is in 193 * WIFI_ADHOC_MASTER_STATE 194 */ 195 goto _Abort_Set_SSID; 196 } 197 } 198 } else { 199 r8712_disassoc_cmd(padapter); 200 if (check_fwstate(pmlmepriv, _FW_LINKED)) 201 r8712_ind_disconnect(padapter); 202 r8712_free_assoc_resources(padapter); 203 if (check_fwstate(pmlmepriv, 204 WIFI_ADHOC_MASTER_STATE)) { 205 _clr_fwstate_(pmlmepriv, 206 WIFI_ADHOC_MASTER_STATE); 207 set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); 208 } 209 } 210 } 211 if (padapter->securitypriv.btkip_countermeasure) 212 goto _Abort_Set_SSID; 213 if (!validate_ssid(ssid)) 214 goto _Abort_Set_SSID; 215 memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct ndis_802_11_ssid)); 216 pmlmepriv->assoc_by_bssid = false; 217 do_join(padapter); 218 goto done; 219 _Abort_Set_SSID: 220 done: 221 spin_unlock_irqrestore(&pmlmepriv->lock, irqL); 222 } 223 224 void r8712_set_802_11_infrastructure_mode(struct _adapter *padapter, 225 enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype) 226 { 227 unsigned long irqL; 228 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 229 struct wlan_network *cur_network = &pmlmepriv->cur_network; 230 enum NDIS_802_11_NETWORK_INFRASTRUCTURE *pold_state = 231 &(cur_network->network.InfrastructureMode); 232 233 if (*pold_state != networktype) { 234 spin_lock_irqsave(&pmlmepriv->lock, irqL); 235 if (check_fwstate(pmlmepriv, _FW_LINKED) || 236 (*pold_state == Ndis802_11IBSS)) 237 r8712_disassoc_cmd(padapter); 238 if (check_fwstate(pmlmepriv, 239 _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) 240 r8712_free_assoc_resources(padapter); 241 if (check_fwstate(pmlmepriv, _FW_LINKED) || 242 (*pold_state == Ndis802_11Infrastructure) || 243 (*pold_state == Ndis802_11IBSS)) { 244 /* will clr Linked_state before this function, 245 * we must have checked whether issue dis-assoc_cmd or 246 * not 247 */ 248 r8712_ind_disconnect(padapter); 249 } 250 *pold_state = networktype; 251 /* clear WIFI_STATION_STATE; WIFI_AP_STATE; WIFI_ADHOC_STATE; 252 * WIFI_ADHOC_MASTER_STATE 253 */ 254 _clr_fwstate_(pmlmepriv, WIFI_STATION_STATE | WIFI_AP_STATE | 255 WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE); 256 switch (networktype) { 257 case Ndis802_11IBSS: 258 set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); 259 break; 260 case Ndis802_11Infrastructure: 261 set_fwstate(pmlmepriv, WIFI_STATION_STATE); 262 break; 263 case Ndis802_11APMode: 264 set_fwstate(pmlmepriv, WIFI_AP_STATE); 265 break; 266 case Ndis802_11AutoUnknown: 267 case Ndis802_11InfrastructureMax: 268 break; 269 } 270 spin_unlock_irqrestore(&pmlmepriv->lock, irqL); 271 } 272 } 273 274 u8 r8712_set_802_11_disassociate(struct _adapter *padapter) 275 { 276 unsigned long irqL; 277 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 278 279 spin_lock_irqsave(&pmlmepriv->lock, irqL); 280 if (check_fwstate(pmlmepriv, _FW_LINKED)) { 281 r8712_disassoc_cmd(padapter); 282 r8712_ind_disconnect(padapter); 283 r8712_free_assoc_resources(padapter); 284 } 285 spin_unlock_irqrestore(&pmlmepriv->lock, irqL); 286 return true; 287 } 288 289 u8 r8712_set_802_11_bssid_list_scan(struct _adapter *padapter) 290 { 291 struct mlme_priv *pmlmepriv = NULL; 292 unsigned long irqL; 293 u8 ret = true; 294 295 if (!padapter) 296 return false; 297 pmlmepriv = &padapter->mlmepriv; 298 if (!padapter->hw_init_completed) 299 return false; 300 spin_lock_irqsave(&pmlmepriv->lock, irqL); 301 if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) || 302 pmlmepriv->sitesurveyctrl.traffic_busy) { 303 /* Scan or linking is in progress, do nothing. */ 304 ret = (u8)check_fwstate(pmlmepriv, _FW_UNDER_SURVEY); 305 } else { 306 r8712_free_network_queue(padapter); 307 ret = r8712_sitesurvey_cmd(padapter, NULL); 308 } 309 spin_unlock_irqrestore(&pmlmepriv->lock, irqL); 310 return ret; 311 } 312 313 u8 r8712_set_802_11_authentication_mode(struct _adapter *padapter, 314 enum NDIS_802_11_AUTHENTICATION_MODE authmode) 315 { 316 struct security_priv *psecuritypriv = &padapter->securitypriv; 317 u8 ret; 318 319 psecuritypriv->ndisauthtype = authmode; 320 if (psecuritypriv->ndisauthtype > 3) 321 psecuritypriv->AuthAlgrthm = 2; /* 802.1x */ 322 if (r8712_set_auth(padapter, psecuritypriv)) 323 ret = false; 324 else 325 ret = true; 326 return ret; 327 } 328 329 int r8712_set_802_11_add_wep(struct _adapter *padapter, 330 struct NDIS_802_11_WEP *wep) 331 { 332 sint keyid; 333 struct security_priv *psecuritypriv = &padapter->securitypriv; 334 335 keyid = wep->KeyIndex & 0x3fffffff; 336 if (keyid >= WEP_KEYS) 337 return -EINVAL; 338 switch (wep->KeyLength) { 339 case 5: 340 psecuritypriv->PrivacyAlgrthm = _WEP40_; 341 break; 342 case 13: 343 psecuritypriv->PrivacyAlgrthm = _WEP104_; 344 break; 345 default: 346 psecuritypriv->PrivacyAlgrthm = _NO_PRIVACY_; 347 break; 348 } 349 memcpy(psecuritypriv->DefKey[keyid].skey, &wep->KeyMaterial, 350 wep->KeyLength); 351 psecuritypriv->DefKeylen[keyid] = wep->KeyLength; 352 psecuritypriv->PrivacyKeyIndex = keyid; 353 return r8712_set_key(padapter, psecuritypriv, keyid); 354 } 355