/*
 * IOCTL request handler to change Ad-Hoc channel.
 *
 * This function allocates the IOCTL request buffer, fills it
 * with requisite parameters and calls the IOCTL handler.
 *
 * The function follows the following steps to perform the change -
 *      - Get current IBSS information
 *      - Get current channel
 *      - If no change is required, return
 *      - If not connected, change channel and return
 *      - If connected,
 *          - Disconnect
 *          - Change channel
 *          - Perform specific SSID scan with same SSID
 *          - Start/Join the IBSS
 */
int
mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
{
	int ret;
	struct mwifiex_bss_info bss_info;
	struct mwifiex_ssid_bssid ssid_bssid;
	u16 curr_chan = 0;

	memset(&bss_info, 0, sizeof(bss_info));

	/* Get BSS information */
	if (mwifiex_get_bss_info(priv, &bss_info))
		return -1;

	/* Get current channel */
	ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_GET,
					     &curr_chan);

	if (curr_chan == channel) {
		ret = 0;
		goto done;
	}
	dev_dbg(priv->adapter->dev, "cmd: updating channel from %d to %d\n",
			curr_chan, channel);

	if (!bss_info.media_connected) {
		ret = 0;
		goto done;
	}

	/* Do disonnect */
	memset(&ssid_bssid, 0, ETH_ALEN);
	ret = mwifiex_deauthenticate(priv, ssid_bssid.bssid);

	ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_SET,
					     (u16 *) &channel);

	/* Do specific SSID scanning */
	if (mwifiex_request_scan(priv, &bss_info.ssid)) {
		ret = -1;
		goto done;
	}
	/* Start/Join Adhoc network */
	memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
	memcpy(&ssid_bssid.ssid, &bss_info.ssid,
	       sizeof(struct mwifiex_802_11_ssid));

	ret = mwifiex_bss_start(priv, &ssid_bssid);
done:
	return ret;
}
Esempio n. 2
0
/*
 * This function connects with a BSS.
 *
 * This function handles both Infra and Ad-Hoc modes. It also performs
 * validity checking on the provided parameters, disconnects from the
 * current BSS (if any), sets up the association/scan parameters,
 * including security settings, and performs specific SSID scan before
 * trying to connect.
 *
 * For Infra mode, the function returns failure if the specified SSID
 * is not found in scan table. However, for Ad-Hoc mode, it can create
 * the IBSS if it does not exist. On successful completion in either case,
 * the function notifies the CFG802.11 subsystem of the new BSS connection,
 * otherwise the kernel will panic.
 */
static int
mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
		       u8 *bssid, int mode, struct ieee80211_channel *channel,
		       struct cfg80211_connect_params *sme, bool privacy)
{
	struct mwifiex_802_11_ssid req_ssid;
	struct mwifiex_ssid_bssid ssid_bssid;
	int ret, auth_type = 0;

	memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid));
	memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));

	req_ssid.ssid_len = ssid_len;
	if (ssid_len > IEEE80211_MAX_SSID_LEN) {
		dev_err(priv->adapter->dev, "invalid SSID - aborting\n");
		return -EINVAL;
	}

	memcpy(req_ssid.ssid, ssid, ssid_len);
	if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) {
		dev_err(priv->adapter->dev, "invalid SSID - aborting\n");
		return -EINVAL;
	}

	/* disconnect before try to associate */
	mwifiex_deauthenticate(priv, NULL);

	if (channel)
		ret = mwifiex_set_rf_channel(priv, channel,
				mwifiex_channels_to_cfg80211_channel_type
				(priv->adapter->chan_offset));

	ret = mwifiex_set_encode(priv, NULL, 0, 0, 1);	/* Disable keys */

	if (mode == NL80211_IFTYPE_ADHOC) {
		/* "privacy" is set only for ad-hoc mode */
		if (privacy) {
			/*
			 * Keep WLAN_CIPHER_SUITE_WEP104 for now so that
			 * the firmware can find a matching network from the
			 * scan. The cfg80211 does not give us the encryption
			 * mode at this stage so just setting it to WEP here.
			 */
			priv->sec_info.encryption_mode =
					WLAN_CIPHER_SUITE_WEP104;
			priv->sec_info.authentication_mode =
					NL80211_AUTHTYPE_OPEN_SYSTEM;
		}

		goto done;
	}

	/* Now handle infra mode. "sme" is valid for infra mode only */
	if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC
			|| sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM)
		auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
	else if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
		auth_type = NL80211_AUTHTYPE_SHARED_KEY;

	if (sme->crypto.n_ciphers_pairwise) {
		priv->sec_info.encryption_mode =
						sme->crypto.ciphers_pairwise[0];
		priv->sec_info.authentication_mode = auth_type;
	}

	if (sme->crypto.cipher_group) {
		priv->sec_info.encryption_mode = sme->crypto.cipher_group;
		priv->sec_info.authentication_mode = auth_type;
	}
	if (sme->ie)
		ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len);

	if (sme->key) {
		if (mwifiex_is_alg_wep(priv->sec_info.encryption_mode)) {
			dev_dbg(priv->adapter->dev,
				"info: setting wep encryption"
				" with key len %d\n", sme->key_len);
			ret = mwifiex_set_encode(priv, sme->key, sme->key_len,
							sme->key_idx, 0);
		}
	}
done:
	/* Do specific SSID scanning */
	if (mwifiex_request_scan(priv, &req_ssid)) {
		dev_err(priv->adapter->dev, "scan error\n");
		return -EFAULT;
	}


	memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(struct mwifiex_802_11_ssid));

	if (mode != NL80211_IFTYPE_ADHOC) {
		if (mwifiex_find_best_bss(priv, &ssid_bssid))
			return -EFAULT;
		/* Inform the BSS information to kernel, otherwise
		 * kernel will give a panic after successful assoc */
		if (mwifiex_inform_bss_from_scan_result(priv, &req_ssid))
			return -EFAULT;
	}

	dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n",
	       (char *) req_ssid.ssid, ssid_bssid.bssid);

	memcpy(&priv->cfg_bssid, ssid_bssid.bssid, 6);

	/* Connect to BSS by ESSID */
	memset(&ssid_bssid.bssid, 0, ETH_ALEN);

	if (!netif_queue_stopped(priv->netdev))
		netif_stop_queue(priv->netdev);

	if (mwifiex_bss_start(priv, &ssid_bssid))
		return -EFAULT;

	if (mode == NL80211_IFTYPE_ADHOC) {
		/* Inform the BSS information to kernel, otherwise
		 * kernel will give a panic after successful assoc */
		if (mwifiex_cfg80211_inform_ibss_bss(priv))
			return -EFAULT;
	}

	return ret;
}
Esempio n. 3
0
/*
 * This function connects with a BSS.
 *
 * This function handles both Infra and Ad-Hoc modes. It also performs
 * validity checking on the provided parameters, disconnects from the
 * current BSS (if any), sets up the association/scan parameters,
 * including security settings, and performs specific SSID scan before
 * trying to connect.
 *
 * For Infra mode, the function returns failure if the specified SSID
 * is not found in scan table. However, for Ad-Hoc mode, it can create
 * the IBSS if it does not exist. On successful completion in either case,
 * the function notifies the CFG802.11 subsystem of the new BSS connection.
 */
static int
mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
		       u8 *bssid, int mode, struct ieee80211_channel *channel,
		       struct cfg80211_connect_params *sme, bool privacy)
{
	struct cfg80211_ssid req_ssid;
	int ret, auth_type = 0;
	struct cfg80211_bss *bss = NULL;
	u8 is_scanning_required = 0;

	memset(&req_ssid, 0, sizeof(struct cfg80211_ssid));

	req_ssid.ssid_len = ssid_len;
	if (ssid_len > IEEE80211_MAX_SSID_LEN) {
		dev_err(priv->adapter->dev, "invalid SSID - aborting\n");
		return -EINVAL;
	}

	memcpy(req_ssid.ssid, ssid, ssid_len);
	if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) {
		dev_err(priv->adapter->dev, "invalid SSID - aborting\n");
		return -EINVAL;
	}

	/* disconnect before try to associate */
	mwifiex_deauthenticate(priv, NULL);

	if (channel)
		ret = mwifiex_set_rf_channel(priv, channel,
						priv->adapter->channel_type);

	/* As this is new association, clear locally stored
	 * keys and security related flags */
	priv->sec_info.wpa_enabled = false;
	priv->sec_info.wpa2_enabled = false;
	priv->wep_key_curr_index = 0;
	priv->sec_info.encryption_mode = 0;
	priv->sec_info.is_authtype_auto = 0;
	ret = mwifiex_set_encode(priv, NULL, 0, 0, NULL, 1);

	if (mode == NL80211_IFTYPE_ADHOC) {
		/* "privacy" is set only for ad-hoc mode */
		if (privacy) {
			/*
			 * Keep WLAN_CIPHER_SUITE_WEP104 for now so that
			 * the firmware can find a matching network from the
			 * scan. The cfg80211 does not give us the encryption
			 * mode at this stage so just setting it to WEP here.
			 */
			priv->sec_info.encryption_mode =
					WLAN_CIPHER_SUITE_WEP104;
			priv->sec_info.authentication_mode =
					NL80211_AUTHTYPE_OPEN_SYSTEM;
		}

		goto done;
	}

	/* Now handle infra mode. "sme" is valid for infra mode only */
	if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
		auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
		priv->sec_info.is_authtype_auto = 1;
	} else {
		auth_type = sme->auth_type;
	}

	if (sme->crypto.n_ciphers_pairwise) {
		priv->sec_info.encryption_mode =
						sme->crypto.ciphers_pairwise[0];
		priv->sec_info.authentication_mode = auth_type;
	}

	if (sme->crypto.cipher_group) {
		priv->sec_info.encryption_mode = sme->crypto.cipher_group;
		priv->sec_info.authentication_mode = auth_type;
	}
	if (sme->ie)
		ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len);

	if (sme->key) {
		if (mwifiex_is_alg_wep(priv->sec_info.encryption_mode)) {
			dev_dbg(priv->adapter->dev,
				"info: setting wep encryption"
				" with key len %d\n", sme->key_len);
			priv->wep_key_curr_index = sme->key_idx;
			ret = mwifiex_set_encode(priv, sme->key, sme->key_len,
						 sme->key_idx, NULL, 0);
		}
	}
done:
	/*
	 * Scan entries are valid for some time (15 sec). So we can save one
	 * active scan time if we just try cfg80211_get_bss first. If it fails
	 * then request scan and cfg80211_get_bss() again for final output.
	 */
	while (1) {
		if (is_scanning_required) {
			/* Do specific SSID scanning */
			if (mwifiex_request_scan(priv, &req_ssid)) {
				dev_err(priv->adapter->dev, "scan error\n");
				return -EFAULT;
			}
		}

		/* Find the BSS we want using available scan results */
		if (mode == NL80211_IFTYPE_ADHOC)
			bss = cfg80211_get_bss(priv->wdev->wiphy, channel,
					       bssid, ssid, ssid_len,
					       WLAN_CAPABILITY_IBSS,
					       WLAN_CAPABILITY_IBSS);
		else
			bss = cfg80211_get_bss(priv->wdev->wiphy, channel,
					       bssid, ssid, ssid_len,
					       WLAN_CAPABILITY_ESS,
					       WLAN_CAPABILITY_ESS);

		if (!bss) {
			if (is_scanning_required) {
				dev_warn(priv->adapter->dev,
					 "assoc: requested bss not found in scan results\n");
				break;
			}
			is_scanning_required = 1;
		} else {
			dev_dbg(priv->adapter->dev,
				"info: trying to associate to '%s' bssid %pM\n",
				(char *) req_ssid.ssid, bss->bssid);
			memcpy(&priv->cfg_bssid, bss->bssid, ETH_ALEN);
			break;
		}
	}

	if (mwifiex_bss_start(priv, bss, &req_ssid))
		return -EFAULT;

	if (mode == NL80211_IFTYPE_ADHOC) {
		/* Inform the BSS information to kernel, otherwise
		 * kernel will give a panic after successful assoc */
		if (mwifiex_cfg80211_inform_ibss_bss(priv))
			return -EFAULT;
	}

	return ret;
}
int
mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, u16 channel)
{
	int ret;
	struct mwifiex_bss_info bss_info;
	struct mwifiex_ssid_bssid ssid_bssid;
	u16 curr_chan = 0;
	struct cfg80211_bss *bss = NULL;
	struct ieee80211_channel *chan;
	enum ieee80211_band band;

	memset(&bss_info, 0, sizeof(bss_info));

	
	if (mwifiex_get_bss_info(priv, &bss_info))
		return -1;

	
	ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_GET,
					     &curr_chan);

	if (curr_chan == channel) {
		ret = 0;
		goto done;
	}
	dev_dbg(priv->adapter->dev, "cmd: updating channel from %d to %d\n",
		curr_chan, channel);

	if (!bss_info.media_connected) {
		ret = 0;
		goto done;
	}

	
	memset(&ssid_bssid, 0, ETH_ALEN);
	ret = mwifiex_deauthenticate(priv, ssid_bssid.bssid);

	ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_SET,
					     &channel);

	
	if (mwifiex_request_scan(priv, &bss_info.ssid)) {
		ret = -1;
		goto done;
	}

	band = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
	chan = __ieee80211_get_channel(priv->wdev->wiphy,
				       ieee80211_channel_to_frequency(channel,
								      band));

	
	bss = cfg80211_get_bss(priv->wdev->wiphy, chan, bss_info.bssid,
			       bss_info.ssid.ssid, bss_info.ssid.ssid_len,
			       WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
	if (!bss)
		wiphy_warn(priv->wdev->wiphy, "assoc: bss %pM not in scan results\n",
			   bss_info.bssid);

	ret = mwifiex_bss_start(priv, bss, &bss_info.ssid);
done:
	return ret;
}