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