diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 2d01280c0564..95e8484eb4f1 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -5899,6 +5899,17 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif); */ void ieee80211_connection_loss(struct ieee80211_vif *vif); +/** + * ieee80211_disconnect - request disconnection + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @reconnect: immediate reconnect is desired + * + * Request disconnection from the current network and, if enabled, send a + * hint to the higher layers that immediate reconnect is desired. + */ +void ieee80211_disconnect(struct ieee80211_vif *vif, bool reconnect); + /** * ieee80211_resume_disconnect - disconnect from AP after resume * diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index cde2e3f4fbcd..cd8275e4b2cd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -452,7 +452,9 @@ struct ieee80211_if_managed { unsigned long probe_timeout; int probe_send_count; bool nullfunc_failed; - bool connection_loss; + u8 connection_loss:1, + driver_disconnect:1, + reconnect:1; struct cfg80211_bss *associated; struct ieee80211_mgd_auth_data *auth_data; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5a2828dccfa5..3e124eee91d4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2732,7 +2732,7 @@ EXPORT_SYMBOL(ieee80211_ap_probereq_get); static void ieee80211_report_disconnect(struct ieee80211_sub_if_data *sdata, const u8 *buf, size_t len, bool tx, - u16 reason) + u16 reason, bool reconnect) { struct ieee80211_event event = { .type = MLME_EVENT, @@ -2741,7 +2741,7 @@ static void ieee80211_report_disconnect(struct ieee80211_sub_if_data *sdata, }; if (tx) - cfg80211_tx_mlme_mgmt(sdata->dev, buf, len, false); + cfg80211_tx_mlme_mgmt(sdata->dev, buf, len, reconnect); else cfg80211_rx_mlme_mgmt(sdata->dev, buf, len); @@ -2763,13 +2763,18 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) tx = !sdata->csa_block_tx; - /* AP is probably out of range (or not reachable for another reason) so - * remove the bss struct for that AP. - */ - cfg80211_unlink_bss(local->hw.wiphy, ifmgd->associated); + if (!ifmgd->driver_disconnect) { + /* + * AP is probably out of range (or not reachable for another + * reason) so remove the bss struct for that AP. + */ + cfg80211_unlink_bss(local->hw.wiphy, ifmgd->associated); + } ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, - WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, + ifmgd->driver_disconnect ? + WLAN_REASON_DEAUTH_LEAVING : + WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, tx, frame_buf); mutex_lock(&local->mtx); sdata->vif.csa_active = false; @@ -2782,7 +2787,9 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) mutex_unlock(&local->mtx); ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), tx, - WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); + WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, + ifmgd->reconnect); + ifmgd->reconnect = false; sdata_unlock(sdata); } @@ -2801,6 +2808,13 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work) sdata_info(sdata, "Connection to AP %pM lost\n", ifmgd->bssid); __ieee80211_disconnect(sdata); + ifmgd->connection_loss = false; + } else if (ifmgd->driver_disconnect) { + sdata_info(sdata, + "Driver requested disconnection from AP %pM\n", + ifmgd->bssid); + __ieee80211_disconnect(sdata); + ifmgd->driver_disconnect = false; } else { ieee80211_mgd_probe_ap(sdata, true); } @@ -2839,6 +2853,21 @@ void ieee80211_connection_loss(struct ieee80211_vif *vif) } EXPORT_SYMBOL(ieee80211_connection_loss); +void ieee80211_disconnect(struct ieee80211_vif *vif, bool reconnect) +{ + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_hw *hw = &sdata->local->hw; + + trace_api_disconnect(sdata, reconnect); + + if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) + return; + + sdata->u.mgd.driver_disconnect = true; + sdata->u.mgd.reconnect = reconnect; + ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); +} +EXPORT_SYMBOL(ieee80211_disconnect); static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, bool assoc) @@ -3142,7 +3171,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, ieee80211_set_disassoc(sdata, 0, 0, false, NULL); ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, - reason_code); + reason_code, false); return; } @@ -3191,7 +3220,8 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, ieee80211_set_disassoc(sdata, 0, 0, false, NULL); - ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code); + ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code, + false); } static void ieee80211_get_rates(struct ieee80211_supported_band *sband, @@ -4204,7 +4234,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, true, deauth_buf); ieee80211_report_disconnect(sdata, deauth_buf, sizeof(deauth_buf), true, - WLAN_REASON_DEAUTH_LEAVING); + WLAN_REASON_DEAUTH_LEAVING, + false); return; } @@ -4349,7 +4380,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, tx, frame_buf); ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, - reason); + reason, false); } static int ieee80211_auth(struct ieee80211_sub_if_data *sdata) @@ -5436,7 +5467,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, - WLAN_REASON_UNSPECIFIED); + WLAN_REASON_UNSPECIFIED, + false); } sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid); @@ -5508,7 +5540,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, - WLAN_REASON_UNSPECIFIED); + WLAN_REASON_UNSPECIFIED, + false); } if (ifmgd->auth_data && !ifmgd->auth_data->done) { @@ -5807,7 +5840,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, ieee80211_destroy_auth_data(sdata, false); ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, - req->reason_code); + req->reason_code, false); return 0; } @@ -5827,7 +5860,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, ieee80211_destroy_assoc_data(sdata, false, true); ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, - req->reason_code); + req->reason_code, false); return 0; } @@ -5842,7 +5875,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, req->reason_code, tx, frame_buf); ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, - req->reason_code); + req->reason_code, false); return 0; } @@ -5875,7 +5908,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, frame_buf); ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, - req->reason_code); + req->reason_code, false); return 0; } diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 89723907a094..601322e16957 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -2,7 +2,7 @@ /* * Portions of this file * Copyright(c) 2016-2017 Intel Deutschland GmbH -* Copyright (C) 2018 - 2019 Intel Corporation +* Copyright (C) 2018 - 2020 Intel Corporation */ #if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ) @@ -2086,6 +2086,27 @@ TRACE_EVENT(api_connection_loss, ) ); +TRACE_EVENT(api_disconnect, + TP_PROTO(struct ieee80211_sub_if_data *sdata, bool reconnect), + + TP_ARGS(sdata, reconnect), + + TP_STRUCT__entry( + VIF_ENTRY + __field(int, reconnect) + ), + + TP_fast_assign( + VIF_ASSIGN; + __entry->reconnect = reconnect; + ), + + TP_printk( + VIF_PR_FMT " reconnect:%d", + VIF_PR_ARG, __entry->reconnect + ) +); + TRACE_EVENT(api_cqm_rssi_notify, TP_PROTO(struct ieee80211_sub_if_data *sdata, enum nl80211_cqm_rssi_threshold_event rssi_event,