]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/mesh_mpm.c
mesh: Add mesh robust security network
[thirdparty/hostap.git] / wpa_supplicant / mesh_mpm.c
index 02bb32c43678b3c5e0c1377eb63ecd95969783cf..de6c3ebb9afd5d1db033546c62316f0220b51b5c 100644 (file)
@@ -17,6 +17,7 @@
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
 #include "mesh_mpm.h"
+#include "mesh_rsn.h"
 
 /* TODO make configurable */
 #define dot11MeshMaxRetries 10
@@ -212,7 +213,7 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
        struct hostapd_data *bss = ifmsh->bss[0];
        struct mesh_conf *conf = ifmsh->mconf;
        u8 supp_rates[2 + 2 + 32];
-       u8 *pos;
+       u8 *pos, *cat;
        u8 ie_len, add_plid = 0;
        int ret;
        int ampe = conf->security & MESH_CONF_SEC_AMPE;
@@ -234,6 +235,7 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
        if (!buf)
                return;
 
+       cat = wpabuf_mhead_u8(buf);
        wpabuf_put_u8(buf, WLAN_ACTION_SELF_PROTECTED);
        wpabuf_put_u8(buf, type);
 
@@ -303,9 +305,18 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
                wpabuf_put_le16(buf, sta->peer_lid);
        if (type == PLINK_CLOSE)
                wpabuf_put_le16(buf, close_reason);
+       if (ampe)
+               mesh_rsn_get_pmkid(wpa_s->mesh_rsn, sta,
+                                  wpabuf_put(buf, PMKID_LEN));
 
        /* TODO HT IEs */
 
+       if (ampe && mesh_rsn_protect_frame(wpa_s->mesh_rsn, sta, cat, buf)) {
+               wpa_msg(wpa_s, MSG_INFO,
+                       "Mesh MPM: failed to add AMPE and MIC IE");
+               goto fail;
+       }
+
        ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0,
                                  sta->addr, wpa_s->own_addr, wpa_s->own_addr,
                                  wpabuf_head(buf), wpabuf_len(buf), 0);
@@ -313,6 +324,7 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
                wpa_msg(wpa_s, MSG_INFO,
                        "Mesh MPM: failed to send peering frame");
 
+fail:
        wpabuf_free(buf);
 }
 
@@ -462,6 +474,8 @@ void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
         * the AP code already sets this flag. */
        sta->flags |= WLAN_STA_AUTH;
 
+       mesh_rsn_init_ampe_sta(wpa_s, sta);
+
        os_memset(&params, 0, sizeof(params));
        params.addr = sta->addr;
        params.flags = WPA_STA_AUTHENTICATED | WPA_STA_AUTHORIZED;
@@ -539,7 +553,10 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
                return;
        }
 
-       mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+       if (conf->security == MESH_CONF_SEC_NONE)
+               mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+       else
+               mesh_rsn_auth_sae_sta(wpa_s, sta);
 }
 
 
@@ -559,10 +576,27 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
                                 struct sta_info *sta)
 {
        struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+       struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+       u8 seq[6] = {};
 
        wpa_msg(wpa_s, MSG_INFO, "mesh plink with " MACSTR " established",
                MAC2STR(sta->addr));
 
+       if (conf->security & MESH_CONF_SEC_AMPE) {
+               wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 0, 0,
+                               seq, sizeof(seq), sta->mtk, sizeof(sta->mtk));
+               wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 1, 0,
+                               seq, sizeof(seq),
+                               sta->mgtk, sizeof(sta->mgtk));
+               wpa_drv_set_key(wpa_s, WPA_ALG_IGTK, sta->addr, 4, 0,
+                               seq, sizeof(seq),
+                               sta->mgtk, sizeof(sta->mgtk));
+
+               wpa_hexdump_key(MSG_DEBUG, "mtk:", sta->mtk, sizeof(sta->mtk));
+               wpa_hexdump_key(MSG_DEBUG, "mgtk:",
+                               sta->mgtk, sizeof(sta->mgtk));
+       }
+
        wpa_mesh_set_plink_state(wpa_s, sta, PLINK_ESTAB);
        hapd->num_plinks++;
 
@@ -580,6 +614,7 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
                         enum plink_event event)
 {
        struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+       struct mesh_conf *conf = wpa_s->ifmsh->mconf;
        u16 reason = 0;
 
        wpa_msg(wpa_s, MSG_DEBUG, "MPM " MACSTR " state %s event %s",
@@ -652,6 +687,8 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
                                                   PLINK_CONFIRM, 0);
                        break;
                case CNF_ACPT:
+                       if (conf->security & MESH_CONF_SEC_AMPE)
+                               mesh_rsn_derive_mtk(wpa_s, sta);
                        mesh_mpm_plink_estab(wpa_s, sta);
                        break;
                default:
@@ -745,6 +782,7 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
 {
        u8 action_field;
        struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+       struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
        struct sta_info *sta;
        u16 plid = 0, llid = 0;
        enum plink_event event;
@@ -804,9 +842,21 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
        if (!sta)
                return;
 
+#ifdef CONFIG_SAE
+       /* peer is in sae_accepted? */
+       if (sta->sae && sta->sae->state != SAE_ACCEPTED)
+               return;
+#endif /* CONFIG_SAE */
+
        if (!sta->my_lid)
                mesh_mpm_init_link(wpa_s, sta);
 
+       if (mconf->security & MESH_CONF_SEC_AMPE)
+               if (mesh_rsn_process_ampe(wpa_s, sta, &elems,
+                                         &mgmt->u.action.category,
+                                         ies, ie_len))
+                       return;
+
        if (sta->plink_state == PLINK_BLOCKED)
                return;