From: Avraham Stern <avraham.stern@xxxxxxxxx> The nl_connect is initialized with the process_bss_event() handler. However, it is used several times with the default valid handler. As a result, if a message that is only valid for the process_bss_event() is received while the default handler is used, it will be dropped. This has been observed in a case where during the 4 way handshake, a beacon is received on the AP side, which triggers a beacon update, just before receiving the next EAPOL. When send_and_recv_msgs_owner() is called for sending the NL80211_CMD_SET_BEACON command, the NL80211_CMD_CONTROL_PORT_FRAME event is already pending. As a result, it is received with the default handler, which drops it. Since the EAPOL frame is dropped, the connection attempt fails. Fix it by using the process_bss_event() handler when the nl_connect handler is used. Signed-off-by: Avraham Stern <avraham.stern@xxxxxxxxx> --- src/drivers/driver_nl80211.c | 68 ++++++++++++++++--------------- src/drivers/driver_nl80211.h | 2 +- src/drivers/driver_nl80211_scan.c | 2 +- 3 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 6fb085446f..d8a911a6a4 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -530,6 +530,21 @@ static int send_and_recv_msgs_owner(struct wpa_driver_nl80211_data *drv, } +static int +send_and_recv_msgs_connect_handle(struct wpa_driver_nl80211_data *drv, + struct nl_msg *msg, struct i802_bss *bss) +{ + struct nl_sock *nl_connect = get_connect_handle(bss); + + if (nl_connect) + return send_and_recv_msgs_owner(drv, msg, nl_connect, 1, + process_bss_event, bss, NULL, + NULL); + else + return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); +} + + struct nl_sock * get_connect_handle(struct i802_bss *bss) { if ((bss->drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) || @@ -3541,10 +3556,11 @@ static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params, int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, const u8 *addr, int cmd, u16 reason_code, int local_state_change, - struct nl_sock *nl_connect) + struct i802_bss *bss) { int ret; struct nl_msg *msg; + struct nl_sock *nl_connect = get_connect_handle(bss); if (!(msg = nl80211_drv_msg(drv, 0, cmd)) || nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code) || @@ -3556,8 +3572,8 @@ int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, } if (nl_connect) - ret = send_and_recv(drv->global, nl_connect, msg, NULL, NULL, - NULL, NULL); + ret = send_and_recv(drv->global, nl_connect, msg, + process_bss_event, bss, NULL, NULL); else ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); if (ret) { @@ -3571,7 +3587,7 @@ int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv, u16 reason_code, - struct nl_sock *nl_connect) + struct i802_bss *bss) { int ret; int drv_associated = drv->associated; @@ -3580,7 +3596,7 @@ static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv, nl80211_mark_disconnected(drv); /* Disconnect command doesn't need BSSID - it uses cached value */ ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT, - reason_code, 0, nl_connect); + reason_code, 0, bss); /* * For locally generated disconnect, supplicant already generates a * DEAUTH event, so ignore the event from NL80211. @@ -3603,14 +3619,13 @@ static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss, return nl80211_leave_ibss(drv, 1); } if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) { - return wpa_driver_nl80211_disconnect(drv, reason_code, - get_connect_handle(bss)); + return wpa_driver_nl80211_disconnect(drv, reason_code, bss); } wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)", __func__, MAC2STR(addr), reason_code); nl80211_mark_disconnected(drv); ret = wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE, - reason_code, 0, get_connect_handle(bss)); + reason_code, 0, bss); /* * For locally generated deauthenticate, supplicant already generates a * DEAUTH event, so ignore the event from NL80211. @@ -4759,8 +4774,7 @@ static int wpa_driver_nl80211_set_ap(void *priv, goto fail; #endif /* CONFIG_FILS */ - ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 1, - NULL, NULL, NULL, NULL); + ret = send_and_recv_msgs_connect_handle(drv, msg, bss); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)", ret, strerror(-ret)); @@ -5814,9 +5828,7 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv, int ret; msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS); - ret = send_and_recv_msgs_owner(drv, msg, - get_connect_handle(drv->first_bss), 1, - NULL, NULL, NULL, NULL); + ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d " "(%s)", ret, strerror(-ret)); @@ -5948,9 +5960,7 @@ retry: if (ret < 0) goto fail; - ret = send_and_recv_msgs_owner(drv, msg, - get_connect_handle(drv->first_bss), 1, - NULL, NULL, NULL, NULL); + ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)", @@ -6286,7 +6296,7 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, static int wpa_driver_nl80211_try_connect( struct wpa_driver_nl80211_data *drv, struct wpa_driver_associate_params *params, - struct nl_sock *nl_connect) + struct i802_bss *bss) { struct nl_msg *msg; enum nl80211_auth_type type; @@ -6358,8 +6368,7 @@ skip_auth_type: if (ret) goto fail; - ret = send_and_recv_msgs_owner(drv, msg, nl_connect, 1, NULL, - (void *) -1, NULL, NULL); + ret = send_and_recv_msgs_connect_handle(drv, msg, bss); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d " @@ -6383,7 +6392,7 @@ fail: static int wpa_driver_nl80211_connect( struct wpa_driver_nl80211_data *drv, struct wpa_driver_associate_params *params, - struct nl_sock *nl_connect) + struct i802_bss *bss) { int ret; @@ -6393,7 +6402,7 @@ static int wpa_driver_nl80211_connect( else os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN); - ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect); + ret = wpa_driver_nl80211_try_connect(drv, params, bss); if (ret == -EALREADY) { /* * cfg80211 does not currently accept new connections if @@ -6404,9 +6413,9 @@ static int wpa_driver_nl80211_connect( "disconnecting before reassociation " "attempt"); if (wpa_driver_nl80211_disconnect( - drv, WLAN_REASON_PREV_AUTH_NOT_VALID, nl_connect)) + drv, WLAN_REASON_PREV_AUTH_NOT_VALID, bss)) return -1; - ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect); + ret = wpa_driver_nl80211_try_connect(drv, params, bss); } return ret; } @@ -6440,8 +6449,7 @@ static int wpa_driver_nl80211_associate( else bss->use_nl_connect = 0; - return wpa_driver_nl80211_connect(drv, params, - get_connect_handle(bss)); + return wpa_driver_nl80211_connect(drv, params, bss); } nl80211_mark_disconnected(drv); @@ -6476,9 +6484,7 @@ static int wpa_driver_nl80211_associate( goto fail; } - ret = send_and_recv_msgs_owner(drv, msg, - get_connect_handle(drv->first_bss), 1, - NULL, NULL, NULL, NULL); + ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss); msg = NULL; if (ret) { wpa_dbg(drv->ctx, MSG_DEBUG, @@ -10461,8 +10467,7 @@ static int nl80211_join_mesh(struct i802_bss *bss, if (nl80211_put_mesh_config(msg, ¶ms->conf) < 0) goto fail; - ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 1, - NULL, NULL, NULL, NULL); + ret = send_and_recv_msgs_connect_handle(drv, msg, bss); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)", @@ -10519,8 +10524,7 @@ static int wpa_driver_nl80211_leave_mesh(void *priv) wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex); msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_MESH); - ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 0, - NULL, NULL, NULL, NULL); + ret = send_and_recv_msgs_connect_handle(drv, msg, bss); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)", ret, strerror(-ret)); diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 940d82c87b..7b0caa2782 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -272,7 +272,7 @@ int wpa_driver_nl80211_set_mode(struct i802_bss *bss, int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, const u8 *addr, int cmd, u16 reason_code, int local_state_change, - struct nl_sock *nl_connect); + struct i802_bss *bss); int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv); void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv); diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c index 233175d19b..1316084805 100644 --- a/src/drivers/driver_nl80211_scan.c +++ b/src/drivers/driver_nl80211_scan.c @@ -870,7 +870,7 @@ static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv, wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE, WLAN_REASON_PREV_AUTH_NOT_VALID, 1, - get_connect_handle(drv->first_bss)); + drv->first_bss); } } -- 2.28.0 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap