/*
 * 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;
}
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;
}