nl80211: Use nl80211 control port for receiving EAPOL frames

Use and/or set socker owner where necessary to allow EAPOL frames to be
received using the nl80211 control port. This is done when the driver
indicates support for the control port without previous hardcoded
reception of RSN preauth frames.

Use methods which set or use the connection owner nl_sock * where
necessary. Initial operations need to register with the SOCKET_OWNER
attribute set (e.g., connect for STA mode). Final operations need to use
the socket which holds the owner attribute (e.g., disconnect for STA
mode).

Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de>
This commit is contained in:
Markus Theil 2020-04-11 12:25:22 +02:00 committed by Jouni Malinen
parent 8609aa5ba3
commit 12ea7dee31
3 changed files with 77 additions and 26 deletions

View File

@ -438,6 +438,52 @@ int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
}
/* Use this method to mark that it is necessary to own the connection/interface
* for this operation.
* handle may be set to NULL, to get the same behavior as send_and_recv_msgs().
* set_owner can be used to mark this socket for receiving control port frames.
*/
static int send_and_recv_msgs_owner(struct wpa_driver_nl80211_data *drv,
struct nl_msg *msg,
struct nl_sock *handle, int set_owner,
int (*valid_handler)(struct nl_msg *,
void *),
void *valid_data)
{
/* Control port over nl80211 needs the flags and attributes below.
*
* The Linux kernel has initial checks for them (in nl80211.c) like:
* validate_pae_over_nl80211(...)
* or final checks like:
* dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid
*
* Final operations (e.g., disassociate) don't need to set these
* attributes, but they have to be performed on the socket, which has
* the connection owner property set in the kernel.
*/
if ((drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) &&
handle && set_owner &&
(nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_OVER_NL80211) ||
nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER) ||
nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_PREAUTH)))
return -1;
return send_and_recv(drv->global, handle ? handle : drv->global->nl,
msg, valid_handler, valid_data);
}
struct nl_sock * get_connect_handle(struct i802_bss *bss)
{
if ((bss->drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) ||
bss->use_nl_connect)
return bss->nl_connect;
return NULL;
}
struct family_data {
const char *group;
int id;
@ -3437,18 +3483,14 @@ static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
return nl80211_leave_ibss(drv, 1);
}
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
struct nl_sock *nl_connect = NULL;
if (bss->use_nl_connect)
nl_connect = bss->nl_connect;
return wpa_driver_nl80211_disconnect(drv, reason_code,
nl_connect);
get_connect_handle(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, NULL);
reason_code, 0, get_connect_handle(bss));
/*
* For locally generated deauthenticate, supplicant already generates a
* DEAUTH event, so ignore the event from NL80211.
@ -4432,7 +4474,8 @@ static int wpa_driver_nl80211_set_ap(void *priv,
}
#endif /* CONFIG_IEEE80211AX */
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 1,
NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
ret, strerror(-ret));
@ -5452,7 +5495,9 @@ 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(drv, msg, NULL, NULL);
ret = send_and_recv_msgs_owner(drv, msg,
get_connect_handle(drv->first_bss), 1,
NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
"(%s)", ret, strerror(-ret));
@ -5584,7 +5629,9 @@ retry:
if (ret < 0)
goto fail;
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
ret = send_and_recv_msgs_owner(drv, msg,
get_connect_handle(drv->first_bss), 1,
NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
@ -5985,12 +6032,8 @@ skip_auth_type:
if (ret)
goto fail;
if (nl_connect)
ret = send_and_recv(drv->global, nl_connect, msg,
NULL, (void *) -1);
else
ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
ret = send_and_recv_msgs_owner(drv, msg, nl_connect, 1, NULL,
(void *) -1);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
@ -6059,19 +6102,17 @@ static int wpa_driver_nl80211_associate(
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
enum nl80211_iftype nlmode = params->p2p ?
NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
struct nl_sock *nl_connect = NULL;
if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
return -1;
if (params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE) {
nl_connect = bss->nl_connect;
params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE)
bss->use_nl_connect = 1;
} else {
else
bss->use_nl_connect = 0;
}
return wpa_driver_nl80211_connect(drv, params, nl_connect);
return wpa_driver_nl80211_connect(drv, params,
get_connect_handle(bss));
}
nl80211_mark_disconnected(drv);
@ -6106,7 +6147,9 @@ static int wpa_driver_nl80211_associate(
goto fail;
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
ret = send_and_recv_msgs_owner(drv, msg,
get_connect_handle(drv->first_bss), 1,
NULL, NULL);
msg = NULL;
if (ret) {
wpa_dbg(drv->ctx, MSG_DEBUG,
@ -9502,7 +9545,12 @@ static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id,
if (nlmsg_append(msg, (void *) data, data_len, NLMSG_ALIGNTO) <
0)
goto fail;
ret = send_and_recv_msgs(drv, msg, cmd_reply_handler, buf);
/* This test vendor_cmd can be used with nl80211 commands that
* need the connect nl_sock, so use the owner-setting variant
* of send_and_recv_msgs(). */
ret = send_and_recv_msgs_owner(drv, msg,
get_connect_handle(bss), 0,
cmd_reply_handler, buf);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d",
ret);
@ -9957,7 +10005,8 @@ static int nl80211_join_mesh(struct i802_bss *bss,
if (nl80211_put_mesh_config(msg, &params->conf) < 0)
goto fail;
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 1,
NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
@ -10014,7 +10063,8 @@ 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(drv, msg, NULL, NULL);
ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 0,
NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
ret, strerror(-ret));

View File

@ -229,6 +229,7 @@ struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd);
int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg,
int (*valid_handler)(struct nl_msg *, void *),
void *valid_data);
struct nl_sock * get_connect_handle(struct i802_bss *bss);
int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
const char *ifname, enum nl80211_iftype iftype,
const u8 *addr, int wds,

View File

@ -872,7 +872,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,
NULL);
get_connect_handle(drv->first_bss));
}
}