lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:   Thu, 23 Nov 2017 02:29:06 +0100
From:   ishraq.i.ashraf@...il.com
To:     gregkh@...uxfoundation.org
Cc:     himanshujha199640@...il.com, goudapatilk@...il.com,
        insafonov@...il.com, devel@...verdev.osuosl.org,
        linux-kernel@...r.kernel.org,
        Ishraq Ibne Ashraf <ishraq.i.ashraf@...il.com>
Subject: [PATCH] staging: rtl8188eu: Fix private WEXT IOCTL calls

From: Ishraq Ibne Ashraf <ishraq.i.ashraf@...il.com>

Commit 8bfb36766064 ("wireless: wext: remove ndo_do_ioctl fallback") breaks private WEXT
IOCTL calls of this driver as these are not invoked through ndo_do_ioctl
interface anymore. As a result hostapd stops working with this driver. In
this patch this problem is solved by implementing equivalent private IOCTL
functions of the existing ones which are accessed via iw_handler_def
interface.

Signed-off-by: Ishraq Ibne Ashraf <ishraq.i.ashraf@...il.com>
---
 drivers/staging/rtl8188eu/os_dep/ioctl_linux.c | 1042 ++++++++++++++++++++++++
 1 file changed, 1042 insertions(+)

diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
index c0664dc..7503751 100644
--- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
@@ -3061,6 +3061,1046 @@ static iw_handler rtw_handlers[] = {
 	NULL,					/*---hole---*/
 };
 
+static int get_private_handler_ieee_param(struct adapter *padapter,
+	union iwreq_data *wrqu,
+	void *param)
+{
+	/*
+	 * This function is expected to be called in master mode, which allows no
+	 * power saving. So we just check hw_init_completed.
+	 */
+
+	if (!padapter->hw_init_completed)
+		return -EPERM;
+
+	if (!wrqu->data.pointer)
+		return -EINVAL;
+
+	/*
+	 * Since we don't allocate memory for param in this function, we assume
+	 * the caller of this function will properly allocate and deallocate memory
+	 * for param.
+	 */
+	if (copy_from_user(param, wrqu->data.pointer, wrqu->data.length))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int rtw_hostapd_sta_flush_pvt(struct net_device *dev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+	DBG_88E("%s\n", __func__);
+
+	flush_all_cam_entry(padapter); // Clear CAM.
+
+	return rtw_sta_flush(padapter);
+}
+
+static int rtw_add_sta_pvt(struct net_device *dev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	int ret = 0;
+	struct sta_info *psta = NULL;
+	struct ieee_param *param = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	param = (struct ieee_param *)rtw_malloc(wrqu->data.length);
+
+	if (!param) {
+		DBG_88E(" rtw_add_sta: ieee_param allocate fail !!!\n");
+
+		return -ENOMEM;
+	}
+
+	ret = get_private_handler_ieee_param(padapter, wrqu, param);
+
+	if (ret != 0) {
+		kfree(param);
+		DBG_88E(" rtw_add_sta: ieee_param get fail !!!\n");
+
+		return ret;
+	}
+
+	DBG_88E("rtw_add_sta(aid =%d) =%pM\n", param->u.add_sta.aid, (param->sta_addr));
+
+	if (!check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)))
+		return -EINVAL;
+
+	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+	      return -EINVAL;
+
+	psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+	if (psta) {
+		int flags = param->u.add_sta.flags;
+		psta->aid = param->u.add_sta.aid; // aid = 1~2007.
+
+		memcpy(psta->bssrateset, param->u.add_sta.tx_supp_rates, 16);
+
+		// Check WMM cap.
+		if (WLAN_STA_WME&flags)
+			psta->qos_option = 1;
+		else
+			psta->qos_option = 0;
+
+		if (pmlmepriv->qospriv.qos_option == 0)
+			psta->qos_option = 0;
+
+		// Check 802.11n HT cap.
+		if (WLAN_STA_HT&flags) {
+			psta->htpriv.ht_option = true;
+			psta->qos_option = 1;
+			memcpy(&psta->htpriv.ht_cap,
+			       &param->u.add_sta.ht_cap,
+			       sizeof(struct ieee80211_ht_cap));
+		} else {
+			psta->htpriv.ht_option = false;
+		}
+
+		if (pmlmepriv->htpriv.ht_option == false)
+			psta->htpriv.ht_option = false;
+
+		update_sta_info_apmode(padapter, psta);
+	} else {
+		ret = -ENOMEM;
+	}
+
+	if (ret == 0 && (copy_to_user(wrqu->data.pointer, param, wrqu->data.length)))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static int rtw_del_sta_pvt(struct net_device *dev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	int ret = 0;
+	struct sta_info *psta = NULL;
+	struct ieee_param *param = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	int updated = 0;
+
+	param = (struct ieee_param *)rtw_malloc(wrqu->data.length);
+
+	if (!param) {
+		DBG_88E(" rtw_del_sta: ieee_param allocate fail !!!\n");
+
+		return -ENOMEM;
+	}
+
+	ret = get_private_handler_ieee_param(padapter, wrqu, param);
+
+	if (ret != 0) {
+		kfree(param);
+		DBG_88E(" rtw_del_sta: ieee_param get fail !!!\n");
+
+		return ret;
+	}
+
+	DBG_88E("rtw_del_sta =%pM\n", (param->sta_addr));
+
+	if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true)
+		return -EINVAL;
+
+	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+	      return -EINVAL;
+
+	psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+	if (psta) {
+		spin_lock_bh(&pstapriv->asoc_list_lock);
+		if (!list_empty(&psta->asoc_list)) {
+			list_del_init(&psta->asoc_list);
+			pstapriv->asoc_list_cnt--;
+			updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING);
+		}
+		spin_unlock_bh(&pstapriv->asoc_list_lock);
+		associated_clients_update(padapter, updated);
+		psta = NULL;
+	} else {
+		DBG_88E("rtw_del_sta(), sta has already been removed or never been added\n");
+	}
+
+	if (ret == 0 && (copy_to_user(wrqu->data.pointer, param, wrqu->data.length)))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static int rtw_set_beacon_pvt(struct net_device *dev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	int ret = 0;
+	int len = 0;
+	unsigned char *pbuf = NULL;
+	struct ieee_param *param = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	param = (struct ieee_param *)rtw_malloc(wrqu->data.length);
+
+	if (!param) {
+		DBG_88E(" rtw_set_beacon: ieee_param allocate fail !!!\n");
+
+		return -ENOMEM;
+	}
+
+	ret = get_private_handler_ieee_param(padapter, wrqu, param);
+
+	if (ret != 0) {
+		kfree(param);
+		DBG_88E(" rtw_set_beacon: ieee_param get fail !!!\n");
+
+		return ret;
+	}
+
+	len = wrqu->data.length;
+	pbuf = param->u.bcn_ie.buf;
+
+	DBG_88E("%s, len =%d\n", __func__, len);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+		return -EINVAL;
+
+	memcpy(&pstapriv->max_num_sta, param->u.bcn_ie.reserved, 2);
+
+	if ((pstapriv->max_num_sta > NUM_STA) || (pstapriv->max_num_sta <= 0))
+		pstapriv->max_num_sta = NUM_STA;
+
+	if (rtw_check_beacon_data(padapter, pbuf,  (len-12-2)) == _SUCCESS) //  12 = Param header, 2 = Not packed.
+		ret = 0;
+	else
+		ret = -EINVAL;
+
+	if (ret == 0 && (copy_to_user(wrqu->data.pointer, param, wrqu->data.length)))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static int rtw_set_encryption_pvt(struct net_device *dev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	int ret = 0;
+	int param_len = 0;
+	struct ieee_param *param = NULL;
+	u32 wep_key_idx, wep_key_len, wep_total_len;
+	struct ndis_802_11_wep	 *pwep = NULL;
+	struct sta_info *psta = NULL, *pbcmc_sta = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct security_priv *psecuritypriv = &(padapter->securitypriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	param = (struct ieee_param *)rtw_malloc(wrqu->data.length);
+
+	if (!param) {
+		ret = -ENOMEM;
+		DBG_88E(" r871x_set_encryption: ieee_param allocate fail !!!\n");
+
+		goto exit;
+	}
+
+	ret = get_private_handler_ieee_param(padapter, wrqu, param);
+
+	if (ret != 0) {
+		kfree(param);
+		DBG_88E(" r871x_set_encryption: ieee_param get fail !!!\n");
+
+		goto exit;
+	}
+
+	param_len = wrqu->data.length;
+
+	DBG_88E("%s\n", __func__);
+	param->u.crypt.err = 0;
+	param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
+	if (param_len !=  sizeof(struct ieee_param) + param->u.crypt.key_len) {
+		ret =  -EINVAL;
+		goto exit;
+	}
+	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+		if (param->u.crypt.idx >= WEP_KEYS) {
+			ret = -EINVAL;
+			goto exit;
+		}
+	} else {
+		psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+		if (!psta) {
+			DBG_88E("rtw_set_encryption(), sta has already been removed or never been added\n");
+			goto exit;
+		}
+	}
+
+	if (strcmp(param->u.crypt.alg, "none") == 0 && (!psta)) {
+		// TODO: Clear default encryption keys.
+
+		DBG_88E("clear default encryption keys, keyid =%d\n", param->u.crypt.idx);
+		goto exit;
+	}
+	if (strcmp(param->u.crypt.alg, "WEP") == 0 && (!psta)) {
+		DBG_88E("r871x_set_encryption, crypt.alg = WEP\n");
+		wep_key_idx = param->u.crypt.idx;
+		wep_key_len = param->u.crypt.key_len;
+		DBG_88E("r871x_set_encryption, wep_key_idx=%d, len=%d\n", wep_key_idx, wep_key_len);
+		if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0)) {
+			ret = -EINVAL;
+			goto exit;
+		}
+
+		if (wep_key_len > 0) {
+			wep_key_len = wep_key_len <= 5 ? 5 : 13;
+			wep_total_len = wep_key_len + offsetof(struct ndis_802_11_wep, KeyMaterial);
+			pwep = (struct ndis_802_11_wep *)rtw_malloc(wep_total_len);
+			if (!pwep) {
+				DBG_88E(" r871x_set_encryption: pwep allocate fail !!!\n");
+				goto exit;
+			}
+
+			memset(pwep, 0, wep_total_len);
+
+			pwep->KeyLength = wep_key_len;
+			pwep->Length = wep_total_len;
+		}
+
+		pwep->KeyIndex = wep_key_idx;
+
+		memcpy(pwep->KeyMaterial,  param->u.crypt.key, pwep->KeyLength);
+
+		if (param->u.crypt.set_tx) {
+			DBG_88E("wep, set_tx = 1\n");
+
+			psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;
+			psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
+			psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+
+			if (pwep->KeyLength == 13) {
+				psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
+				psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+			}
+
+			psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx;
+
+			memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]),
+			       pwep->KeyMaterial,
+			       pwep->KeyLength);
+
+			psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength;
+
+			set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx);
+		} else {
+			DBG_88E("wep, set_tx = 0\n");
+
+			/*
+			 * Don't update "psecuritypriv->dot11PrivacyAlgrthm" and
+			 * "psecuritypriv->dot11PrivacyKeyIndex = keyid", but rtw_set_key()
+			 * can to cam.
+			 */
+
+			memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]),
+			       pwep->KeyMaterial,
+			       pwep->KeyLength);
+
+			psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength;
+
+			set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx);
+		}
+
+		goto exit;
+	}
+
+	if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) { //  Group key.
+		if (param->u.crypt.set_tx == 1) {
+			if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+				DBG_88E("%s, set group_key, WEP\n", __func__);
+
+				memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+				       param->u.crypt.key,
+				       min_t(u16, param->u.crypt.key_len,
+				       16));
+
+				psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+				if (param->u.crypt.key_len == 13)
+						psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+			} else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+				DBG_88E("%s, set group_key, TKIP\n", __func__);
+				psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
+				memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+				       param->u.crypt.key,
+				       min_t(u16, param->u.crypt.key_len,
+				       16));
+				// Set mic key.
+				memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey,
+				       &(param->u.crypt.key[16]),
+				       8);
+				memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey,
+				       &(param->u.crypt.key[24]),
+				       8);
+
+				psecuritypriv->busetkipkey = true;
+			} else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+				DBG_88E("%s, set group_key, CCMP\n", __func__);
+				psecuritypriv->dot118021XGrpPrivacy = _AES_;
+				memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+				       param->u.crypt.key,
+				       min_t(u16, param->u.crypt.key_len, 16));
+			} else {
+				DBG_88E("%s, set group_key, none\n", __func__);
+				psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+			}
+			psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx;
+			psecuritypriv->binstallGrpkey = true;
+			psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;
+			set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx);
+			pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
+			if (pbcmc_sta) {
+				pbcmc_sta->ieee8021x_blocked = false;
+				pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy; // rx will use bmc_sta's dot118021XPrivacy.
+			}
+		}
+		goto exit;
+	}
+
+	if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && psta) { // psk/802_1x.
+		if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+			if (param->u.crypt.set_tx == 1) {
+				memcpy(psta->dot118021x_UncstKey.skey,  param->u.crypt.key, min_t(u16, param->u.crypt.key_len, 16));
+
+				if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+					DBG_88E("%s, set pairwise key, WEP\n", __func__);
+
+					psta->dot118021XPrivacy = _WEP40_;
+					if (param->u.crypt.key_len == 13)
+						psta->dot118021XPrivacy = _WEP104_;
+				} else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+					DBG_88E("%s, set pairwise key, TKIP\n", __func__);
+
+					psta->dot118021XPrivacy = _TKIP_;
+
+					// Set mic key.
+					memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8);
+					memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8);
+
+					psecuritypriv->busetkipkey = true;
+				} else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+					DBG_88E("%s, set pairwise key, CCMP\n", __func__);
+
+					psta->dot118021XPrivacy = _AES_;
+				} else {
+					DBG_88E("%s, set pairwise key, none\n", __func__);
+
+					psta->dot118021XPrivacy = _NO_PRIVACY_;
+				}
+
+				set_pairwise_key(padapter, psta);
+
+				psta->ieee8021x_blocked = false;
+			} else { // Group key ?
+				if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+					memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+					       param->u.crypt.key,
+					       min_t(u16, param->u.crypt.key_len, 16));
+					psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+					if (param->u.crypt.key_len == 13)
+						psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+				} else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+					psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
+
+					memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+					       param->u.crypt.key,
+					       min_t(u16, param->u.crypt.key_len, 16));
+
+					// Set mic key.
+					memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey,
+					       &(param->u.crypt.key[16]), 8);
+					memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey,
+					       &(param->u.crypt.key[24]), 8);
+
+					psecuritypriv->busetkipkey = true;
+				} else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+					psecuritypriv->dot118021XGrpPrivacy = _AES_;
+
+					memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+					       param->u.crypt.key,
+					       min_t(u16, param->u.crypt.key_len, 16));
+				} else {
+					psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+				}
+
+				psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx;
+				psecuritypriv->binstallGrpkey = true;
+				psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;
+
+				set_group_key(padapter,
+					param->u.crypt.key,
+					psecuritypriv->dot118021XGrpPrivacy,
+					param->u.crypt.idx);
+
+				pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
+				if (pbcmc_sta) {
+					pbcmc_sta->ieee8021x_blocked = false;
+					pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy; // rx will use bmc_sta's dot118021XPrivacy.
+				}
+			}
+		}
+	}
+
+exit:
+
+	kfree(pwep);
+
+	if (ret == 0 && (copy_to_user(wrqu->data.pointer, param, wrqu->data.length)))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static int rtw_get_sta_wpaie_pvt(struct net_device *dev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	int ret = 0;
+	struct sta_info *psta = NULL;
+	struct ieee_param *param = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	param = (struct ieee_param *)rtw_malloc(wrqu->data.length);
+
+	if (!param) {
+		DBG_88E(" rtw_get_sta_wpaie: ieee_param allocate fail !!!\n");
+
+		return -ENOMEM;
+	}
+
+	ret = get_private_handler_ieee_param(padapter, wrqu, param);
+
+	if (ret != 0) {
+		kfree(param);
+		DBG_88E(" rtw_get_sta_wpaie: ieee_param get fail !!!\n");
+
+		return ret;
+	}
+
+	DBG_88E("rtw_get_sta_wpaie, sta_addr: %pM\n", (param->sta_addr));
+
+	if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true)
+		return -EINVAL;
+
+	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+	      return -EINVAL;
+
+	psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+	if (psta) {
+		if (psta->wpa_ie[0] == WLAN_EID_RSN ||
+		    psta->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC) {
+		      int wpa_ie_len;
+		      int copy_len;
+
+		      wpa_ie_len = psta->wpa_ie[1];
+		      copy_len = min_t(int, wpa_ie_len + 2, sizeof(psta->wpa_ie));
+		      param->u.wpa_ie.len = copy_len;
+		      memcpy(param->u.wpa_ie.reserved, psta->wpa_ie, copy_len);
+		} else {
+			DBG_88E("sta's wpa_ie is NONE\n");
+		}
+	} else {
+		ret = -1;
+	}
+
+	if (ret == 0 && (copy_to_user(wrqu->data.pointer, param, wrqu->data.length)))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static int rtw_set_wps_beacon_pvt(struct net_device *dev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	int ret = 0;
+	struct ieee_param *param = NULL;
+	unsigned char wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	int len, ie_len;
+
+	param = (struct ieee_param *)rtw_malloc(wrqu->data.length);
+
+	if (!param) {
+		DBG_88E(" rtw_set_wps_beacon: ieee_param allocate fail !!!\n");
+
+		return  -ENOMEM;
+	}
+
+	ret = get_private_handler_ieee_param(padapter, wrqu, param);
+
+	if (ret != 0) {
+		kfree(param);
+		DBG_88E(" rtw_set_wps_beacon: ieee_param get fail !!!\n");
+
+		return ret;
+	}
+
+	len = wrqu->data.length;
+
+	DBG_88E("%s, len =%d\n", __func__, len);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+		return -EINVAL;
+
+	ie_len = len-12-2; // 12 = Param header, 2 = Not packed.
+
+	kfree(pmlmepriv->wps_beacon_ie);
+	pmlmepriv->wps_beacon_ie = NULL;
+
+	if (ie_len > 0) {
+		pmlmepriv->wps_beacon_ie = rtw_malloc(ie_len);
+		pmlmepriv->wps_beacon_ie_len = ie_len;
+		if (!pmlmepriv->wps_beacon_ie) {
+			DBG_88E("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+			return -EINVAL;
+		}
+
+		memcpy(pmlmepriv->wps_beacon_ie, param->u.bcn_ie.buf, ie_len);
+		update_beacon(padapter, _VENDOR_SPECIFIC_IE_, wps_oui, true);
+
+		pmlmeext->bstart_bss = true;
+	}
+
+	if (ret == 0 && (copy_to_user(wrqu->data.pointer, param, wrqu->data.length)))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static int rtw_set_wps_probe_resp_pvt(struct net_device *dev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	int ret = 0;
+	struct ieee_param *param = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	int len, ie_len;
+
+	param = (struct ieee_param *)rtw_malloc(wrqu->data.length);
+
+	if (!param) {
+		DBG_88E(" rtw_set_wps_probe_resp: ieee_param allocate fail !!!\n");
+
+		return -ENOMEM;
+	}
+
+	ret = get_private_handler_ieee_param(padapter, wrqu, param);
+
+	if (ret != 0) {
+		kfree(param);
+		DBG_88E(" rtw_set_wps_probe_resp: ieee_param get fail !!!\n");
+
+		return ret;
+	}
+
+	len = wrqu->data.length;
+
+	DBG_88E("%s, len =%d\n", __func__, len);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+		return -EINVAL;
+
+	ie_len = len-12-2; // 12 = Param header, 2 = Not packed.
+
+	kfree(pmlmepriv->wps_probe_resp_ie);
+	pmlmepriv->wps_probe_resp_ie = NULL;
+
+	if (ie_len > 0) {
+		pmlmepriv->wps_probe_resp_ie = rtw_malloc(ie_len);
+		pmlmepriv->wps_probe_resp_ie_len = ie_len;
+		if (!pmlmepriv->wps_probe_resp_ie) {
+			DBG_88E("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+			return -EINVAL;
+		}
+		memcpy(pmlmepriv->wps_probe_resp_ie, param->u.bcn_ie.buf, ie_len);
+	}
+
+	if (ret == 0 && (copy_to_user(wrqu->data.pointer, param, wrqu->data.length)))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static int rtw_set_wps_assoc_resp_pvt(struct net_device *dev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	int ret = 0;
+	struct ieee_param *param = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	int len, ie_len;
+
+	param = (struct ieee_param *)rtw_malloc(wrqu->data.length);
+
+	if (!param) {
+		DBG_88E(" rtw_set_wps_assoc_resp: ieee_param allocate fail !!!\n");
+
+		return -ENOMEM;
+	}
+
+	ret = get_private_handler_ieee_param(padapter, wrqu, param);
+
+	if (ret != 0) {
+		kfree(param);
+		DBG_88E(" rtw_set_wps_assoc_resp: ieee_param get fail !!!\n");
+
+		return ret;
+	}
+
+	len = wrqu->data.length;
+
+	DBG_88E("%s, len =%d\n", __func__, len);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+		return -EINVAL;
+
+	ie_len = len-12-2; // 12 = Param header, 2 = Not packed.
+
+	kfree(pmlmepriv->wps_assoc_resp_ie);
+	pmlmepriv->wps_assoc_resp_ie = NULL;
+
+	if (ie_len > 0) {
+		pmlmepriv->wps_assoc_resp_ie = rtw_malloc(ie_len);
+		pmlmepriv->wps_assoc_resp_ie_len = ie_len;
+		if (!pmlmepriv->wps_assoc_resp_ie) {
+			DBG_88E("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+			return -EINVAL;
+		}
+
+		memcpy(pmlmepriv->wps_assoc_resp_ie, param->u.bcn_ie.buf, ie_len);
+	}
+
+	if (ret == 0 && (copy_to_user(wrqu->data.pointer, param, wrqu->data.length)))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static int rtw_set_hidden_ssid_pvt(struct net_device *dev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	int ret = 0;
+	struct ieee_param *param = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	u8 value;
+
+	param = (struct ieee_param *)rtw_malloc(wrqu->data.length);
+
+	if (!param) {
+		DBG_88E(" rtw_set_hidden_ssid: ieee_param allocate fail !!!\n");
+
+		return -ENOMEM;
+	}
+
+	ret = get_private_handler_ieee_param(padapter, wrqu, param);
+
+	if (ret != 0) {
+		kfree(param);
+		DBG_88E(" rtw_set_hidden_ssid: ieee_param get fail !!!\n");
+
+		return ret;
+	}
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+		return -EINVAL;
+
+	if (param->u.wpa_param.name != 0) // Dummy test.
+		DBG_88E("%s name(%u) != 0\n", __func__, param->u.wpa_param.name);
+	value = param->u.wpa_param.value;
+
+	// Use the same definition of hostapd's ignore_broadcast_ssid.
+	if (value != 1 && value != 2)
+		value = 0;
+	DBG_88E("%s value(%u)\n", __func__, value);
+	pmlmeinfo->hidden_ssid_mode = value;
+
+	if (ret == 0 && (copy_to_user(wrqu->data.pointer, param, wrqu->data.length)))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static int rtw_ioctl_get_sta_data_pvt(struct net_device *dev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	int ret = 0;
+	struct sta_info *psta = NULL;
+	struct sta_data *psta_data = NULL;
+	struct ieee_param_ex *param_ex = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	param_ex = (struct ieee_param_ex *)rtw_malloc(wrqu->data.length);
+
+	if (!param_ex) {
+		DBG_88E(" rtw_ioctl_get_sta_data: ieee_param_ex allocate fail !!!\n");
+
+		return -ENOMEM;
+	}
+
+	ret = get_private_handler_ieee_param(padapter, wrqu, param_ex);
+
+	if (ret != 0) {
+		kfree(param_ex);
+		DBG_88E(" rtw_ioctl_get_sta_data: ieee_param get fail !!!\n");
+
+		return ret;
+	}
+
+	psta_data = (struct sta_data *)param_ex->data;
+
+	DBG_88E("rtw_ioctl_get_sta_info, sta_addr: %pM\n", (param_ex->sta_addr));
+
+	if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true)
+		return -EINVAL;
+
+	if (param_ex->sta_addr[0] == 0xff && param_ex->sta_addr[1] == 0xff &&
+	    param_ex->sta_addr[2] == 0xff && param_ex->sta_addr[3] == 0xff &&
+	    param_ex->sta_addr[4] == 0xff && param_ex->sta_addr[5] == 0xff)
+	      return -EINVAL;
+
+	psta = rtw_get_stainfo(pstapriv, param_ex->sta_addr);
+	if (psta) {
+		psta_data->aid = (u16)psta->aid;
+		psta_data->capability = psta->capability;
+		psta_data->flags = psta->flags;
+
+		/*
+		nonerp_set : BIT(0)
+		no_short_slot_time_set : BIT(1)
+		no_short_preamble_set : BIT(2)
+		no_ht_gf_set : BIT(3)
+		no_ht_set : BIT(4)
+		ht_20mhz_set : BIT(5)
+		*/
+
+		psta_data->sta_set = \
+			((psta->nonerp_set) |
+			(psta->no_short_slot_time_set << 1) |
+			(psta->no_short_preamble_set << 2) |
+			(psta->no_ht_gf_set << 3) |
+			(psta->no_ht_set << 4) |
+			(psta->ht_20mhz_set << 5));
+		psta_data->tx_supp_rates_len =  psta->bssratelen;
+		memcpy(psta_data->tx_supp_rates, psta->bssrateset, psta->bssratelen);
+		memcpy(&psta_data->ht_cap,
+		       &psta->htpriv.ht_cap,
+		       sizeof(struct ieee80211_ht_cap));
+		psta_data->rx_pkts = psta->sta_stats.rx_data_pkts;
+		psta_data->rx_bytes = psta->sta_stats.rx_bytes;
+		psta_data->rx_drops = psta->sta_stats.rx_drops;
+		psta_data->tx_pkts = psta->sta_stats.tx_pkts;
+		psta_data->tx_bytes = psta->sta_stats.tx_bytes;
+		psta_data->tx_drops = psta->sta_stats.tx_drops;
+	} else {
+		ret = -1;
+	}
+
+	if (ret == 0 && (copy_to_user(wrqu->data.pointer, param_ex, wrqu->data.length)))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static int rtw_ioctl_set_macaddr_acl_pvt(struct net_device *dev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	int ret = 0;
+	struct ieee_param *param = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	param = (struct ieee_param *)rtw_malloc(wrqu->data.length);
+
+	if (!param) {
+		DBG_88E(" rtw_ioctl_set_macaddr_acl: ieee_param allocate fail !!!\n");
+
+		return -ENOMEM;
+	}
+
+	ret = get_private_handler_ieee_param(padapter, wrqu, param);
+
+	if (ret != 0) {
+		kfree(param);
+		DBG_88E(" rtw_ioctl_set_macaddr_acl: ieee_param get fail !!!\n");
+
+		return ret;
+	}
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+		return -EINVAL;
+
+	rtw_set_macaddr_acl(padapter, param->u.mlme.command);
+
+	if (ret == 0 && (copy_to_user(wrqu->data.pointer, param, wrqu->data.length)))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static int rtw_ioctl_acl_add_sta_pvt(struct net_device *dev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	int ret = 0;
+	struct ieee_param *param = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	param = (struct ieee_param *)rtw_malloc(wrqu->data.length);
+
+	if (!param) {
+		DBG_88E(" rtw_ioctl_acl_add_sta: ieee_param allocate fail !!!\n");
+
+		return -ENOMEM;
+	}
+
+	ret = get_private_handler_ieee_param(padapter, wrqu, param);
+
+	if (ret != 0) {
+		kfree(param);
+		DBG_88E(" rtw_ioctl_acl_add_sta: ieee_param get fail !!!\n");
+
+		return ret;
+	}
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+		return -EINVAL;
+
+	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+	      return -EINVAL;
+
+	ret = rtw_acl_add_sta(padapter, param->sta_addr);
+
+	if (ret == 0 && (copy_to_user(wrqu->data.pointer, param, wrqu->data.length)))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static int rtw_ioctl_acl_remove_sta_pvt(struct net_device *dev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	int ret = 0;
+	struct ieee_param *param = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	param = (struct ieee_param *)rtw_malloc(wrqu->data.length);
+
+	if (!param) {
+		DBG_88E(" rtw_ioctl_acl_remove_sta: ieee_param allocate fail !!!\n");
+
+		return -ENOMEM;
+	}
+
+	ret = get_private_handler_ieee_param(padapter, wrqu, param);
+
+	if (ret != 0) {
+		kfree(param);
+		DBG_88E(" rtw_ioctl_acl_remove_sta: ieee_param get fail !!!\n");
+
+		return ret;
+	}
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+		return -EINVAL;
+
+	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+	      return -EINVAL;
+
+	ret = rtw_acl_remove_sta(padapter, param->sta_addr);
+
+	if (ret == 0 && (copy_to_user(wrqu->data.pointer, param, wrqu->data.length)))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static iw_handler rtw_handlers_private[] = {
+	NULL,                          // Empty
+	rtw_hostapd_sta_flush_pvt,     // RTL871X_HOSTAPD_FLUSH
+	rtw_add_sta_pvt,               // RTL871X_HOSTAPD_ADD_STA
+	rtw_del_sta_pvt,               // RTL871X_HOSTAPD_REMOVE_STA
+	rtw_ioctl_get_sta_data_pvt,    // RTL871X_HOSTAPD_GET_INFO_STA
+	rtw_get_sta_wpaie_pvt,         // RTL871X_HOSTAPD_GET_WPAIE_STA
+	rtw_set_encryption_pvt,        // RTL871X_SET_ENCRYPTION
+	NULL,                          // RTL871X_GET_ENCRYPTION
+	NULL,                          // RTL871X_HOSTAPD_SET_FLAGS_STA
+	NULL,                          // RTL871X_HOSTAPD_GET_RID
+	NULL,                          // RTL871X_HOSTAPD_SET_RID
+	NULL,                          // RTL871X_HOSTAPD_SET_ASSOC_AP_ADDR
+	NULL,                          // RTL871X_HOSTAPD_SET_GENERIC_ELEMENT
+	NULL,                          // RTL871X_HOSTAPD_MLME
+	NULL,                          // RTL871X_HOSTAPD_SCAN_REQ
+	NULL,                          // RTL871X_HOSTAPD_STA_CLEAR_STATS
+	rtw_set_beacon_pvt,            // RTL871X_HOSTAPD_SET_BEACON
+	rtw_set_wps_beacon_pvt,        // RTL871X_HOSTAPD_SET_WPS_BEACON
+	rtw_set_wps_probe_resp_pvt,    // RTL871X_HOSTAPD_SET_WPS_PROBE_RESP
+	rtw_set_wps_assoc_resp_pvt,    // RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP
+	rtw_set_hidden_ssid_pvt,       // RTL871X_HOSTAPD_SET_HIDDEN_SSID
+	rtw_ioctl_set_macaddr_acl_pvt, // RTL871X_HOSTAPD_SET_MACADDR_ACL
+	rtw_ioctl_acl_add_sta_pvt,     // RTL871X_HOSTAPD_ACL_ADD_STA
+	rtw_ioctl_acl_remove_sta_pvt,  // RTL871X_HOSTAPD_ACL_REMOVE_STA
+};
+
 static struct iw_statistics *rtw_get_wireless_stats(struct net_device *dev)
 {
 	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
@@ -3089,6 +4129,8 @@ static struct iw_statistics *rtw_get_wireless_stats(struct net_device *dev)
 struct iw_handler_def rtw_handlers_def = {
 	.standard = rtw_handlers,
 	.num_standard = ARRAY_SIZE(rtw_handlers),
+	.private = rtw_handlers_private,
+	.num_private = ARRAY_SIZE(rtw_handlers_private),
 	.get_wireless_stats = rtw_get_wireless_stats,
 };
 
-- 
2.7.4

Powered by blists - more mailing lists