]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
nl80211: Use nl80211 control port for receiving EAPOL frames
authorMarkus Theil <markus.theil@tu-ilmenau.de>
Sat, 11 Apr 2020 10:25:22 +0000 (12:25 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 19 Apr 2020 13:49:03 +0000 (16:49 +0300)
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>
src/drivers/driver_nl80211.c
src/drivers/driver_nl80211.h
src/drivers/driver_nl80211_scan.c

index 228385457b6a2a55401b4ac0101645d454453406..c72dda381a8b5ce5784ae08ec2ccfa8ffd153a21 100644 (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));
index 6e6c872476218a40e683f8585cc5062e077ac672..538d40364b34605edb3aef9d1fa997b3702592b8 100644 (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,
index 04f6bb8790ca6a87e48a94540c85bc8c5f13d937..17e8b2c2eea4a5c8175146eb967a1d4ef28d6b50 100644 (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));
        }
 }