mesh: Add scan result for mesh network
[mech_eap.git] / wpa_supplicant / mesh.c
index efacf70..23108ba 100644 (file)
@@ -21,7 +21,9 @@
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
 #include "notify.h"
+#include "ap.h"
 #include "mesh_mpm.h"
+#include "mesh_rsn.h"
 #include "mesh.h"
 
 
@@ -30,6 +32,8 @@ static void wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s)
        wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
        wpa_s->ifmsh = NULL;
        wpa_s->current_ssid = NULL;
+       os_free(wpa_s->mesh_rsn);
+       wpa_s->mesh_rsn = NULL;
        /* TODO: leave mesh (stop beacon). This will happen on link down
         * anyway, so it's not urgent */
 }
@@ -118,6 +122,7 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
        int basic_rates_erp[] = { 10, 20, 55, 60, 110, 120, 240, -1 };
        static int default_groups[] = { 19, 20, 21, 25, 26, -1 };
        size_t len;
+       int rate_len;
 
        if (!wpa_s->conf->user_mpm) {
                /* not much for us to do here */
@@ -130,6 +135,7 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
        if (!ifmsh)
                return -ENOMEM;
 
+       ifmsh->drv_flags = wpa_s->drv_flags;
        ifmsh->num_bss = 1;
        ifmsh->bss = os_calloc(wpa_s->ifmsh->num_bss,
                               sizeof(struct hostapd_data *));
@@ -144,6 +150,7 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
        bss->driver = wpa_s->driver;
        bss->drv_priv = wpa_s->drv_priv;
        bss->iface = ifmsh;
+       bss->mesh_sta_free_cb = mesh_mpm_free_sta;
        wpa_s->assoc_freq = ssid->frequency;
        wpa_s->current_ssid = ssid;
 
@@ -180,19 +187,34 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
                goto out_free;
        }
 
-       /*
-        * XXX: Hack! This is so an MPM which correctly sets the ERP mandatory
-        * rates as BSSBasicRateSet doesn't reject us. We could add a new
-        * hw_mode HOSTAPD_MODE_IEEE80211G_ERP, but this is way easier. This
-        * also makes our BSSBasicRateSet advertised in Beacon frames match the
-        * one in peering frames, sigh.
-        */
-       if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
-               conf->basic_rates = os_malloc(sizeof(basic_rates_erp));
-               if (!conf->basic_rates)
+       if (ssid->mesh_basic_rates == NULL) {
+               /*
+                * XXX: Hack! This is so an MPM which correctly sets the ERP
+                * mandatory rates as BSSBasicRateSet doesn't reject us. We
+                * could add a new hw_mode HOSTAPD_MODE_IEEE80211G_ERP, but
+                * this is way easier. This also makes our BSSBasicRateSet
+                * advertised in beacons match the one in peering frames, sigh.
+                */
+               if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+                       conf->basic_rates = os_malloc(sizeof(basic_rates_erp));
+                       if (!conf->basic_rates)
+                               goto out_free;
+                       os_memcpy(conf->basic_rates, basic_rates_erp,
+                                 sizeof(basic_rates_erp));
+               }
+       } else {
+               rate_len = 0;
+               while (1) {
+                       if (ssid->mesh_basic_rates[rate_len] < 1)
+                               break;
+                       rate_len++;
+               }
+               conf->basic_rates = os_calloc(rate_len + 1, sizeof(int));
+               if (conf->basic_rates == NULL)
                        goto out_free;
-               os_memcpy(conf->basic_rates, basic_rates_erp,
-                         sizeof(basic_rates_erp));
+               os_memcpy(conf->basic_rates, ssid->mesh_basic_rates,
+                         rate_len * sizeof(int));
+               conf->basic_rates[rate_len] = -1;
        }
 
        if (hostapd_setup_interface(ifmsh)) {
@@ -231,8 +253,14 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
                len = os_strlen(ssid->passphrase);
                bss->conf->ssid.wpa_passphrase =
                        dup_binstr(ssid->passphrase, len);
+
+               wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, mconf);
+               if (!wpa_s->mesh_rsn)
+                       goto out_free;
        }
 
+       wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
+
        return 0;
 out_free:
        wpa_supplicant_mesh_deinit(wpa_s);
@@ -257,6 +285,19 @@ void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
 }
 
 
+void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
+                                    struct wpabuf **extra_ie)
+{
+       /* EID + 0-length (wildcard) mesh-id */
+       size_t ielen = 2;
+
+       if (wpabuf_resize(extra_ie, ielen) == 0) {
+               wpabuf_put_u8(*extra_ie, WLAN_EID_MESH_ID);
+               wpabuf_put_u8(*extra_ie, 0);
+       }
+}
+
+
 int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
                             struct wpa_ssid *ssid)
 {
@@ -274,6 +315,9 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
        params.meshid = ssid->ssid;
        params.meshid_len = ssid->ssid_len;
        params.freq = ssid->frequency;
+#ifdef CONFIG_IEEE80211N
+       params.ht_mode = ssid->mesh_ht_mode;
+#endif /* CONFIG_IEEE80211N */
 
        if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
                params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
@@ -331,3 +375,97 @@ int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s)
 
        return ret;
 }
+
+
+static int mesh_attr_text(const u8 *ies, size_t ies_len, char *buf, char *end)
+{
+       struct ieee802_11_elems elems;
+       char *mesh_id, *pos = buf;
+       u8 *bss_basic_rate_set;
+       int bss_basic_rate_set_len, ret, i;
+
+       if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) == ParseFailed)
+               return -1;
+
+       if (elems.mesh_id_len < 1)
+               return 0;
+
+       mesh_id = os_malloc(elems.mesh_id_len + 1);
+       if (mesh_id == NULL)
+               return -1;
+
+       os_memcpy(mesh_id, elems.mesh_id, elems.mesh_id_len);
+       mesh_id[elems.mesh_id_len] = '\0';
+       ret = os_snprintf(pos, end - pos, "mesh_id=%s\n", mesh_id);
+       os_free(mesh_id);
+       if (ret < 0 || ret >= end - pos)
+               return pos - buf;
+       pos += ret;
+
+       if (elems.mesh_config_len > 6) {
+               ret = os_snprintf(pos, end - pos,
+                                 "active_path_selection_protocol_id=0x%02x\n"
+                                 "active_path_selection_metric_id=0x%02x\n"
+                                 "congestion_control_mode_id=0x%02x\n"
+                                 "synchronization_method_id=0x%02x\n"
+                                 "authentication_protocol_id=0x%02x\n"
+                                 "mesh_formation_info=0x%02x\n"
+                                 "mesh_capability=0x%02x\n",
+                                 elems.mesh_config[0], elems.mesh_config[1],
+                                 elems.mesh_config[2], elems.mesh_config[3],
+                                 elems.mesh_config[4], elems.mesh_config[5],
+                                 elems.mesh_config[6]);
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
+
+       bss_basic_rate_set = os_malloc(elems.supp_rates_len +
+               elems.ext_supp_rates_len);
+       if (bss_basic_rate_set == NULL)
+               return -1;
+
+       bss_basic_rate_set_len = 0;
+       for (i = 0; i < elems.supp_rates_len; i++) {
+               if (elems.supp_rates[i] & 0x80) {
+                       bss_basic_rate_set[bss_basic_rate_set_len++] =
+                               (elems.supp_rates[i] & 0x7f) * 5;
+               }
+       }
+       for (i = 0; i < elems.ext_supp_rates_len; i++) {
+               if (elems.ext_supp_rates[i] & 0x80) {
+                       bss_basic_rate_set[bss_basic_rate_set_len++] =
+                               (elems.ext_supp_rates[i] & 0x7f) * 5;
+               }
+       }
+       if (bss_basic_rate_set_len > 0) {
+               ret = os_snprintf(pos, end - pos, "bss_basic_rate_set=%d",
+                                 bss_basic_rate_set[0]);
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+
+               for (i = 1; i < bss_basic_rate_set_len; i++) {
+                       ret = os_snprintf(pos, end - pos, " %d",
+                                         bss_basic_rate_set[i]);
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+               }
+
+               ret = os_snprintf(pos, end - pos, "\n");
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
+       os_free(bss_basic_rate_set);
+
+       return pos - buf;
+}
+
+
+int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
+                              char *end)
+{
+       return mesh_attr_text(ies, ies_len, buf, end);
+}