mesh: Create new station entry on popen frames
authorBob Copeland <me@bobcopeland.com>
Tue, 27 Jan 2015 13:17:59 +0000 (08:17 -0500)
committerJouni Malinen <j@w1.fi>
Wed, 28 Jan 2015 11:09:31 +0000 (13:09 +0200)
Currently, there is a race in open mesh networks where mesh STA A
receives a beacon from B and sends a peering open frame to initiate
peering. STA B, having not yet received a beacon from A and thus
created the corresponding station entry, will ignore all such open
frames. If the beacon interval is sufficiently long then peering
will not succeed as a result.

In fact B can simply create the station entry when the popen is
received, as is done in Linux's in-kernel MPM, avoiding the issue.

Signed-off-by: Bob Copeland <me@bobcopeland.com>
wpa_supplicant/mesh_mpm.c

index bc61da9..1d6f2be 100644 (file)
@@ -519,27 +519,34 @@ void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
        mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
 }
 
-
-void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
-                           struct ieee802_11_elems *elems)
+/*
+ * Initialize a sta_info structure for a peer and upload it into the driver
+ * in preparation for beginning authentication or peering. This is done when a
+ * Beacon (secure or open mesh) or a peering open frame (for open mesh) is
+ * received from the peer for the first time.
+ */
+static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
+                                          const u8 *addr,
+                                          struct ieee802_11_elems *elems)
 {
        struct hostapd_sta_add_params params;
        struct mesh_conf *conf = wpa_s->ifmsh->mconf;
        struct hostapd_data *data = wpa_s->ifmsh->bss[0];
        struct sta_info *sta;
-       struct wpa_ssid *ssid = wpa_s->current_ssid;
-       int ret = 0;
+       int ret;
 
        sta = ap_get_sta(data, addr);
        if (!sta) {
                sta = ap_sta_add(data, addr);
                if (!sta)
-                       return;
+                       return NULL;
        }
 
        /* initialize sta */
-       if (copy_supp_rates(wpa_s, sta, elems))
-               return;
+       if (copy_supp_rates(wpa_s, sta, elems)) {
+               ap_free_sta(data, sta);
+               return NULL;
+       }
 
        mesh_mpm_init_link(wpa_s, sta);
 
@@ -573,9 +580,26 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
                wpa_msg(wpa_s, MSG_ERROR,
                        "Driver failed to insert " MACSTR ": %d",
                        MAC2STR(addr), ret);
-               return;
+               ap_free_sta(data, sta);
+               return NULL;
        }
 
+       return sta;
+}
+
+
+void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+                           struct ieee802_11_elems *elems)
+{
+       struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+       struct hostapd_data *data = wpa_s->ifmsh->bss[0];
+       struct sta_info *sta;
+       struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+       sta = mesh_mpm_add_peer(wpa_s, addr, elems);
+       if (!sta)
+               return;
+
        if (ssid && ssid->no_auto_peer) {
                wpa_msg(wpa_s, MSG_INFO, "will not initiate new peer link with "
                        MACSTR " because of no_auto_peer", MAC2STR(addr));
@@ -928,6 +952,15 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
        wpa_printf(MSG_DEBUG, "MPM: plid=0x%x llid=0x%x", plid, llid);
 
        sta = ap_get_sta(hapd, mgmt->sa);
+
+       /*
+        * If this is an open frame from an unknown STA, and this is an
+        * open mesh, then go ahead and add the peer before proceeding.
+        */
+       if (!sta && action_field == PLINK_OPEN &&
+           !(mconf->security & MESH_CONF_SEC_AMPE))
+               sta = mesh_mpm_add_peer(wpa_s, mgmt->sa, &elems);
+
        if (!sta) {
                wpa_printf(MSG_DEBUG, "MPM: No STA entry for peer");
                return;