Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 882a7c69 authored by Johannes Berg's avatar Johannes Berg
Browse files

mac80211: disconnect if channel switch fails



Disconnect from the AP if channel switching in the
driver failed or if the new channel is unavailable.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 30dd3edf
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -411,6 +411,7 @@ struct ieee80211_if_managed {
	struct work_struct monitor_work;
	struct work_struct monitor_work;
	struct work_struct chswitch_work;
	struct work_struct chswitch_work;
	struct work_struct beacon_connection_loss_work;
	struct work_struct beacon_connection_loss_work;
	struct work_struct csa_connection_drop_work;


	unsigned long beacon_timeout;
	unsigned long beacon_timeout;
	unsigned long probe_timeout;
	unsigned long probe_timeout;
+37 −18
Original line number Original line Diff line number Diff line
@@ -730,17 +730,14 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)


	trace_api_chswitch_done(sdata, success);
	trace_api_chswitch_done(sdata, success);
	if (!success) {
	if (!success) {
		/*
		sdata_info(sdata,
		 * If the channel switch was not successful, stay
			   "driver channel switch failed, disconnecting\n");
		 * around on the old channel. We currently lack
		ieee80211_queue_work(&sdata->local->hw,
		 * good handling of this situation, possibly we
				     &ifmgd->csa_connection_drop_work);
		 * should just drop the association.
	} else {
		 */
		sdata->local->csa_channel = sdata->local->oper_channel;
	}

		ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
		ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
	}
	}
}
EXPORT_SYMBOL(ieee80211_chswitch_done);
EXPORT_SYMBOL(ieee80211_chswitch_done);


static void ieee80211_chswitch_timer(unsigned long data)
static void ieee80211_chswitch_timer(unsigned long data)
@@ -784,8 +781,14 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
		return;
		return;


	new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
	new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
	if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED)
	if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) {
		sdata_info(sdata,
			   "AP %pM switches to unsupported channel (%d MHz), disconnecting\n",
			   ifmgd->associated->bssid, new_freq);
		ieee80211_queue_work(&sdata->local->hw,
				     &ifmgd->csa_connection_drop_work);
		return;
		return;
	}


	sdata->local->csa_channel = new_ch;
	sdata->local->csa_channel = new_ch;


@@ -1692,7 +1695,8 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
}
}
EXPORT_SYMBOL(ieee80211_ap_probereq_get);
EXPORT_SYMBOL(ieee80211_ap_probereq_get);


static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata,
				   bool transmit_frame)
{
{
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
	struct ieee80211_local *local = sdata->local;
	struct ieee80211_local *local = sdata->local;
@@ -1704,12 +1708,10 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
		return;
		return;
	}
	}


	sdata_info(sdata, "Connection to AP %pM lost\n",
		   ifmgd->associated->bssid);

	ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
	ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
			       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
			       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
			       false, frame_buf);
			       transmit_frame, frame_buf);
	ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
	mutex_unlock(&ifmgd->mtx);
	mutex_unlock(&ifmgd->mtx);


	/*
	/*
@@ -1739,11 +1741,25 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work)
		rcu_read_unlock();
		rcu_read_unlock();
	}
	}


	if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
	if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) {
		__ieee80211_connection_loss(sdata);
		sdata_info(sdata, "Connection to AP %pM lost\n",
	else
			   ifmgd->bssid);
		__ieee80211_disconnect(sdata, false);
	} else {
		ieee80211_mgd_probe_ap(sdata, true);
		ieee80211_mgd_probe_ap(sdata, true);
	}
	}
}

static void ieee80211_csa_connection_drop_work(struct work_struct *work)
{
	struct ieee80211_sub_if_data *sdata =
		container_of(work, struct ieee80211_sub_if_data,
			     u.mgd.csa_connection_drop_work);

	ieee80211_wake_queues_by_reason(&sdata->local->hw,
					IEEE80211_QUEUE_STOP_REASON_CSA);
	__ieee80211_disconnect(sdata, true);
}


void ieee80211_beacon_loss(struct ieee80211_vif *vif)
void ieee80211_beacon_loss(struct ieee80211_vif *vif)
{
{
@@ -2929,6 +2945,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)


	cancel_work_sync(&ifmgd->monitor_work);
	cancel_work_sync(&ifmgd->monitor_work);
	cancel_work_sync(&ifmgd->beacon_connection_loss_work);
	cancel_work_sync(&ifmgd->beacon_connection_loss_work);
	cancel_work_sync(&ifmgd->csa_connection_drop_work);
	if (del_timer_sync(&ifmgd->timer))
	if (del_timer_sync(&ifmgd->timer))
		set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
		set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);


@@ -2985,6 +3002,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
	INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
	INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
	INIT_WORK(&ifmgd->beacon_connection_loss_work,
	INIT_WORK(&ifmgd->beacon_connection_loss_work,
		  ieee80211_beacon_connection_loss_work);
		  ieee80211_beacon_connection_loss_work);
	INIT_WORK(&ifmgd->csa_connection_drop_work,
		  ieee80211_csa_connection_drop_work);
	INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work);
	INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work);
	setup_timer(&ifmgd->timer, ieee80211_sta_timer,
	setup_timer(&ifmgd->timer, ieee80211_sta_timer,
		    (unsigned long) sdata);
		    (unsigned long) sdata);