3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-11-25 17:59:25 +01:00

ap: Make station removal safer

Replace instances of the ap_del_station() +
ap_sta_free()/ap_remove_sta() with calls to ap_station_disconnect to
make sure we consistently remove the station from the ap->sta_states
queue before using ap_del_station().  ap_del_station() may generate an
event to the ap.h API user (e.g. P2P) and this may end up tearing down
the AP completely.

For that scenario we also don't want ap_sta_free() to access sta->ap so
we make sure ap_del_station() performs these cleanup steps so that
ap_sta_free() has nothing to do that accesses sta->ap.
This commit is contained in:
Andrew Zaborowski 2021-08-07 04:10:42 +02:00 committed by Denis Kenzior
parent 97a34e6b4a
commit 2af0166970

View File

@ -251,6 +251,11 @@ static void ap_del_station(struct sta_state *sta, uint16_t reason,
sta->rsna = false; sta->rsna = false;
} }
if (sta->assoc_resp_cmd_id) {
l_genl_family_cancel(ap->nl80211, sta->assoc_resp_cmd_id);
sta->assoc_resp_cmd_id = 0;
}
if (sta->gtk_query_cmd_id) { if (sta->gtk_query_cmd_id) {
l_genl_family_cancel(ap->nl80211, sta->gtk_query_cmd_id); l_genl_family_cancel(ap->nl80211, sta->gtk_query_cmd_id);
sta->gtk_query_cmd_id = 0; sta->gtk_query_cmd_id = 0;
@ -258,6 +263,10 @@ static void ap_del_station(struct sta_state *sta, uint16_t reason,
ap_stop_handshake(sta); ap_stop_handshake(sta);
/*
* If the event handler tears the AP down, we've made sure above that
* a subsequent ap_sta_free(sta) has no need to access sta->ap.
*/
if (send_event) if (send_event)
ap->ops->handle_event(AP_EVENT_STATION_REMOVED, &event_data, ap->ops->handle_event(AP_EVENT_STATION_REMOVED, &event_data,
ap->user_data); ap->user_data);
@ -2004,7 +2013,6 @@ static void ap_deauth_cb(const struct mmpdu_header *hdr, const void *body,
size_t body_len, int rssi, void *user_data) size_t body_len, int rssi, void *user_data)
{ {
struct ap_state *ap = user_data; struct ap_state *ap = user_data;
struct sta_state *sta;
const struct mmpdu_deauthentication *deauth = body; const struct mmpdu_deauthentication *deauth = body;
const uint8_t *bssid = netdev_get_address(ap->netdev); const uint8_t *bssid = netdev_get_address(ap->netdev);
@ -2016,14 +2024,8 @@ static void ap_deauth_cb(const struct mmpdu_header *hdr, const void *body,
memcmp(hdr->address_3, bssid, 6)) memcmp(hdr->address_3, bssid, 6))
return; return;
sta = l_queue_remove_if(ap->sta_states, ap_sta_match_addr, ap_station_disconnect(ap, hdr->address_2,
hdr->address_2); L_LE16_TO_CPU(deauth->reason_code));
if (!sta)
return;
ap_del_station(sta, L_LE16_TO_CPU(deauth->reason_code), false);
ap_sta_free(sta);
} }
static void do_debug(const char *str, void *user_data) static void do_debug(const char *str, void *user_data)
@ -2339,7 +2341,6 @@ cleanup:
static void ap_handle_del_station(struct ap_state *ap, struct l_genl_msg *msg) static void ap_handle_del_station(struct ap_state *ap, struct l_genl_msg *msg)
{ {
struct sta_state *sta;
struct l_genl_attr attr; struct l_genl_attr attr;
uint16_t type; uint16_t type;
uint16_t len; uint16_t len;
@ -2366,12 +2367,7 @@ static void ap_handle_del_station(struct ap_state *ap, struct l_genl_msg *msg)
} }
} }
sta = l_queue_find(ap->sta_states, ap_sta_match_addr, mac); ap_station_disconnect(ap, mac, reason);
if (!sta)
return;
ap_del_station(sta, reason, true);
ap_remove_sta(sta);
} }
static void ap_mlme_notify(struct l_genl_msg *msg, void *user_data) static void ap_mlme_notify(struct l_genl_msg *msg, void *user_data)