diff options
author | Larry Finger <Larry.Finger@lwfinger.net> | 2010-08-20 15:15:30 (GMT) |
---|---|---|
committer | Larry Finger <Larry.Finger@lwfinger.net> | 2010-08-20 15:15:30 (GMT) |
commit | 2865d42c78a9121caad52cb02d1fbb7f5cdbc4ef (patch) | |
tree | 430b79f753b0e1cec6379b9a4208a716c914ac65 /drivers/staging/rtl8712/rtl871x_ioctl_set.c | |
parent | 763008c4357b73c8d18396dfd8d79dc58fa3f99d (diff) | |
download | linux-fsl-qoriq-2865d42c78a9121caad52cb02d1fbb7f5cdbc4ef.tar.xz |
staging: r8712u: Add the new driver to the mainline kernel
This code is for a completely new version of the Realtek 8192 USB devices
such as the D-Link DWA-130. The Realtek code, which was originally for
Linux, Windows XP and Windows CE, has been stripped of all code not needed
for Linux. In addition, only one additional configuration variable, which
enables AP mode, remains.
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Florian Schilhabel <florian.c.schilhabel@googlemail.com>
Tested-by: Frederic Leroy <fredo@starox.org>
Diffstat (limited to 'drivers/staging/rtl8712/rtl871x_ioctl_set.c')
-rw-r--r-- | drivers/staging/rtl8712/rtl871x_ioctl_set.c | 379 |
1 files changed, 379 insertions, 0 deletions
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_set.c b/drivers/staging/rtl8712/rtl871x_ioctl_set.c new file mode 100644 index 0000000..8b1451d --- /dev/null +++ b/drivers/staging/rtl8712/rtl871x_ioctl_set.c @@ -0,0 +1,379 @@ +/****************************************************************************** + * rtl871x_ioctl_set.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RTL871X_IOCTL_SET_C_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "rtl871x_ioctl_set.h" +#include "usb_osintf.h" +#include "usb_ops.h" + +#define IS_MAC_ADDRESS_BROADCAST(addr) \ +( \ + ((addr[0] == 0xff) && (addr[1] == 0xff) && \ + (addr[2] == 0xff) && (addr[3] == 0xff) && \ + (addr[4] == 0xff) && (addr[5] == 0xff)) ? true : false \ +) + +static u8 validate_ssid(struct ndis_802_11_ssid *ssid) +{ + u8 i; + + if (ssid->SsidLength > 32) + return false; + for (i = 0; i < ssid->SsidLength; i++) { + /* wifi, printable ascii code must be supported */ + if (!((ssid->Ssid[i] >= 0x20) && (ssid->Ssid[i] <= 0x7e))) + return false; + } + return true; +} + +static u8 do_join(struct _adapter *padapter) +{ + struct list_head *plist, *phead; + u8 *pibss = NULL; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct __queue *queue = &(pmlmepriv->scanned_queue); + + phead = get_list_head(queue); + plist = get_next(phead); + pmlmepriv->cur_network.join_res = -2; + pmlmepriv->fw_state |= _FW_UNDER_LINKING; + pmlmepriv->pscanned = plist; + pmlmepriv->to_join = true; + if (_queue_empty(queue) == true) { + if (pmlmepriv->fw_state & _FW_UNDER_LINKING) + pmlmepriv->fw_state ^= _FW_UNDER_LINKING; + /* when set_ssid/set_bssid for do_join(), but scanning queue + * is empty we try to issue sitesurvey firstly + */ + if (pmlmepriv->sitesurveyctrl.traffic_busy == false) + r8712_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid); + return true; + } else { + int ret; + + ret = r8712_select_and_join_from_scan(pmlmepriv); + if (ret == _SUCCESS) + _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); + else { + if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { + /* submit r8712_createbss_cmd to change to an + * ADHOC_MASTER pmlmepriv->lock has been + * acquired by caller... + */ + struct wlan_bssid_ex *pdev_network = + &(padapter->registrypriv.dev_network); + pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; + pibss = padapter->registrypriv.dev_network. + MacAddress; + memset(&pdev_network->Ssid, 0, + sizeof(struct ndis_802_11_ssid)); + memcpy(&pdev_network->Ssid, + &pmlmepriv->assoc_ssid, + sizeof(struct ndis_802_11_ssid)); + r8712_update_registrypriv_dev_network(padapter); + r8712_generate_random_ibss(pibss); + if (r8712_createbss_cmd(padapter) != _SUCCESS) + return false; + pmlmepriv->to_join = false; + } else { + /* can't associate ; reset under-linking */ + if (pmlmepriv->fw_state & _FW_UNDER_LINKING) + pmlmepriv->fw_state ^= + _FW_UNDER_LINKING; + /* when set_ssid/set_bssid for do_join(), but + * there are no desired bss in scanning queue + * we try to issue sitesurvey first + */ + if (!pmlmepriv->sitesurveyctrl.traffic_busy) + r8712_sitesurvey_cmd(padapter, + &pmlmepriv->assoc_ssid); + } + } + } + return true; +} + +u8 r8712_set_802_11_bssid(struct _adapter *padapter, u8 *bssid) +{ + unsigned long irqL; + u8 status = true; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if ((bssid[0] == 0x00 && bssid[1] == 0x00 && bssid[2] == 0x00 && + bssid[3] == 0x00 && bssid[4] == 0x00 && bssid[5] == 0x00) || + (bssid[0] == 0xFF && bssid[1] == 0xFF && bssid[2] == 0xFF && + bssid[3] == 0xFF && bssid[4] == 0xFF && bssid[5] == 0xFF)) { + status = false; + return status; + } + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | + _FW_UNDER_LINKING) == true) { + status = check_fwstate(pmlmepriv, _FW_UNDER_LINKING); + goto _Abort_Set_BSSID; + } + if (check_fwstate(pmlmepriv, + _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true) { + if (!memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, + ETH_ALEN)) { + if (check_fwstate(pmlmepriv, + WIFI_STATION_STATE) == false) + goto _Abort_Set_BSSID; /* driver is in + * WIFI_ADHOC_MASTER_STATE */ + } else { + r8712_disassoc_cmd(padapter); + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + r8712_ind_disconnect(padapter); + r8712_free_assoc_resources(padapter); + if ((check_fwstate(pmlmepriv, + WIFI_ADHOC_MASTER_STATE))) { + _clr_fwstate_(pmlmepriv, + WIFI_ADHOC_MASTER_STATE); + set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); + } + } + } + memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN); + pmlmepriv->assoc_by_bssid = true; + status = do_join(padapter); + goto done; +_Abort_Set_BSSID: +done: + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); + return status; +} + +void r8712_set_802_11_ssid(struct _adapter *padapter, + struct ndis_802_11_ssid *ssid) +{ + unsigned long irqL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *pnetwork = &pmlmepriv->cur_network; + + if (padapter->hw_init_completed == false) + return; + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) { + check_fwstate(pmlmepriv, _FW_UNDER_LINKING); + goto _Abort_Set_SSID; + } + if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) { + if ((pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength) && + (!memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, + ssid->SsidLength))) { + if ((check_fwstate(pmlmepriv, + WIFI_STATION_STATE) == false)) { + if (r8712_is_same_ibss(padapter, + pnetwork) == false) { + /* if in WIFI_ADHOC_MASTER_STATE or + * WIFI_ADHOC_STATE, create bss or + * rejoin again + */ + r8712_disassoc_cmd(padapter); + if (check_fwstate(pmlmepriv, + _FW_LINKED) == true) + r8712_ind_disconnect(padapter); + r8712_free_assoc_resources(padapter); + if (check_fwstate(pmlmepriv, + WIFI_ADHOC_MASTER_STATE)) { + _clr_fwstate_(pmlmepriv, + WIFI_ADHOC_MASTER_STATE); + set_fwstate(pmlmepriv, + WIFI_ADHOC_STATE); + } + } else + goto _Abort_Set_SSID; /* driver is in + * WIFI_ADHOC_MASTER_STATE */ + } + } else { + r8712_disassoc_cmd(padapter); + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + r8712_ind_disconnect(padapter); + r8712_free_assoc_resources(padapter); + if (check_fwstate(pmlmepriv, + WIFI_ADHOC_MASTER_STATE) == true) { + _clr_fwstate_(pmlmepriv, + WIFI_ADHOC_MASTER_STATE); + set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); + } + } + } + if (padapter->securitypriv.btkip_countermeasure == true) + goto _Abort_Set_SSID; + if (validate_ssid(ssid) == false) + goto _Abort_Set_SSID; + memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct ndis_802_11_ssid)); + pmlmepriv->assoc_by_bssid = false; + do_join(padapter); + goto done; +_Abort_Set_SSID: +done: + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); +} + +u8 r8712_set_802_11_infrastructure_mode(struct _adapter *padapter, + enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype) +{ + unsigned long irqL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *cur_network = &pmlmepriv->cur_network; + enum NDIS_802_11_NETWORK_INFRASTRUCTURE *pold_state = + &(cur_network->network.InfrastructureMode); + + if (*pold_state != networktype) { + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) || + (*pold_state == Ndis802_11IBSS)) + r8712_disassoc_cmd(padapter); + if (check_fwstate(pmlmepriv, + _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true) + r8712_free_assoc_resources(padapter); + if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) || + (*pold_state == Ndis802_11Infrastructure) || + (*pold_state == Ndis802_11IBSS)) { + /* will clr Linked_state before this function, + * we must have chked whether issue dis-assoc_cmd or + * not */ + r8712_ind_disconnect(padapter); + } + *pold_state = networktype; + /* clear WIFI_STATION_STATE; WIFI_AP_STATE; WIFI_ADHOC_STATE; + * WIFI_ADHOC_MASTER_STATE */ + _clr_fwstate_(pmlmepriv, WIFI_STATION_STATE | WIFI_AP_STATE | + WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE | + WIFI_AP_STATE); + switch (networktype) { + case Ndis802_11IBSS: + set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); + break; + case Ndis802_11Infrastructure: + set_fwstate(pmlmepriv, WIFI_STATION_STATE); + break; + case Ndis802_11APMode: + set_fwstate(pmlmepriv, WIFI_AP_STATE); + break; + case Ndis802_11AutoUnknown: + case Ndis802_11InfrastructureMax: + break; + } + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); + } + return true; +} + +u8 r8712_set_802_11_disassociate(struct _adapter *padapter) +{ + unsigned long irqL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + r8712_disassoc_cmd(padapter); + r8712_ind_disconnect(padapter); + r8712_free_assoc_resources(padapter); + } + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); + return true; +} + +u8 r8712_set_802_11_bssid_list_scan(struct _adapter *padapter) +{ + struct mlme_priv *pmlmepriv = NULL; + unsigned long irqL; + u8 ret = true; + + if (padapter == NULL) + return false; + pmlmepriv = &padapter->mlmepriv; + if (padapter->hw_init_completed == false) + return false; + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) || + (pmlmepriv->sitesurveyctrl.traffic_busy == true)) { + /* Scan or linking is in progress, do nothing. */ + ret = (u8)check_fwstate(pmlmepriv, _FW_UNDER_SURVEY); + } else { + r8712_free_network_queue(padapter); + ret = r8712_sitesurvey_cmd(padapter, NULL); + } + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); + return ret; +} + +u8 r8712_set_802_11_authentication_mode(struct _adapter *padapter, + enum NDIS_802_11_AUTHENTICATION_MODE authmode) +{ + struct security_priv *psecuritypriv = &padapter->securitypriv; + u8 ret; + + psecuritypriv->ndisauthtype = authmode; + if (psecuritypriv->ndisauthtype > 3) + psecuritypriv->AuthAlgrthm = 2; /* 802.1x */ + if (r8712_set_auth(padapter, psecuritypriv) == _SUCCESS) + ret = true; + else + ret = false; + return ret; +} + +u8 r8712_set_802_11_add_wep(struct _adapter *padapter, + struct NDIS_802_11_WEP *wep) +{ + u8 bdefaultkey; + u8 btransmitkey; + sint keyid; + struct security_priv *psecuritypriv = &padapter->securitypriv; + + bdefaultkey = (wep->KeyIndex & 0x40000000) > 0 ? false : true; + btransmitkey = (wep->KeyIndex & 0x80000000) > 0 ? true : false; + keyid = wep->KeyIndex & 0x3fffffff; + if (keyid >= WEP_KEYS) + return false; + switch (wep->KeyLength) { + case 5: + psecuritypriv->PrivacyAlgrthm = _WEP40_; + break; + case 13: + psecuritypriv->PrivacyAlgrthm = _WEP104_; + break; + default: + psecuritypriv->PrivacyAlgrthm = _NO_PRIVACY_; + break; + } + memcpy(psecuritypriv->DefKey[keyid].skey, &wep->KeyMaterial, + wep->KeyLength); + psecuritypriv->DefKeylen[keyid] = wep->KeyLength; + psecuritypriv->PrivacyKeyIndex = keyid; + if (r8712_set_key(padapter, psecuritypriv, keyid) == _FAIL) + return false; + return _SUCCESS; +} |