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