16c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/* 26c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * WPA Supplicant - Basic mesh peer management 36c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved. 46c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * 56c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * This software may be distributed under the terms of the BSD license. 66c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * See README for more details. 76c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */ 86c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 96c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "utils/includes.h" 106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "utils/common.h" 126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "utils/eloop.h" 136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "common/ieee802_11_defs.h" 146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "ap/hostapd.h" 156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "ap/sta_info.h" 166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "ap/ieee802_11.h" 176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "wpa_supplicant_i.h" 186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "driver_i.h" 196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "mesh_mpm.h" 206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "mesh_rsn.h" 216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstruct mesh_peer_mgmt_ie { 236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt const u8 *proto_id; 246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt const u8 *llid; 256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt const u8 *plid; 266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt const u8 *reason; 276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt const u8 *pmk; 286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}; 296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void plink_timer(void *eloop_ctx, void *user_data); 316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtenum plink_event { 346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt PLINK_UNDEFINED, 356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt OPN_ACPT, 366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt OPN_RJCT, 376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt OPN_IGNR, 386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt CNF_ACPT, 396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt CNF_RJCT, 406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt CNF_IGNR, 416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt CLS_ACPT, 426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt CLS_IGNR 436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}; 446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic const char * const mplstate[] = { 466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [PLINK_LISTEN] = "LISTEN", 476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [PLINK_OPEN_SENT] = "OPEN_SENT", 486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [PLINK_OPEN_RCVD] = "OPEN_RCVD", 496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [PLINK_CNF_RCVD] = "CNF_RCVD", 506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [PLINK_ESTAB] = "ESTAB", 516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [PLINK_HOLDING] = "HOLDING", 526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [PLINK_BLOCKED] = "BLOCKED" 536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}; 546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic const char * const mplevent[] = { 566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [PLINK_UNDEFINED] = "UNDEFINED", 576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [OPN_ACPT] = "OPN_ACPT", 586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [OPN_RJCT] = "OPN_RJCT", 596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [OPN_IGNR] = "OPN_IGNR", 606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [CNF_ACPT] = "CNF_ACPT", 616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [CNF_RJCT] = "CNF_RJCT", 626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [CNF_IGNR] = "CNF_IGNR", 636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [CLS_ACPT] = "CLS_ACPT", 646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [CLS_IGNR] = "CLS_IGNR" 656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}; 666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int mesh_mpm_parse_peer_mgmt(struct wpa_supplicant *wpa_s, 696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u8 action_field, 706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt const u8 *ie, size_t len, 716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct mesh_peer_mgmt_ie *mpm_ie) 726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_memset(mpm_ie, 0, sizeof(*mpm_ie)); 746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* remove optional PMK at end */ 766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (len >= 16) { 776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt len -= 16; 786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mpm_ie->pmk = ie + len - 16; 796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if ((action_field == PLINK_OPEN && len != 4) || 826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (action_field == PLINK_CONFIRM && len != 6) || 836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (action_field == PLINK_CLOSE && len != 6 && len != 8)) { 846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg(wpa_s, MSG_DEBUG, "MPM: Invalid peer mgmt ie"); 856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return -1; 866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* required fields */ 896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (len < 4) 906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return -1; 916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mpm_ie->proto_id = ie; 926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mpm_ie->llid = ie + 2; 936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ie += 4; 946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt len -= 4; 956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* close reason is always present at end for close */ 976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (action_field == PLINK_CLOSE) { 986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (len < 2) 996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return -1; 1006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mpm_ie->reason = ie + len - 2; 1016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt len -= 2; 1026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 1036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* plid, present for confirm, and possibly close */ 1056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (len) 1066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mpm_ie->plid = ie; 1076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 0; 1096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 1106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int plink_free_count(struct hostapd_data *hapd) 1136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 1146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (hapd->max_plinks > hapd->num_plinks) 1156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return hapd->max_plinks - hapd->num_plinks; 1166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 0; 1176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 1186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic u16 copy_supp_rates(struct wpa_supplicant *wpa_s, 1216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct sta_info *sta, 1226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct ieee802_11_elems *elems) 1236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 1246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!elems->supp_rates) { 1256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg(wpa_s, MSG_ERROR, "no supported rates from " MACSTR, 1266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt MAC2STR(sta->addr)); 1276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return WLAN_STATUS_UNSPECIFIED_FAILURE; 1286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 1296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (elems->supp_rates_len + elems->ext_supp_rates_len > 1316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sizeof(sta->supported_rates)) { 1326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg(wpa_s, MSG_ERROR, 1336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "Invalid supported rates element length " MACSTR 1346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt " %d+%d", MAC2STR(sta->addr), elems->supp_rates_len, 1356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt elems->ext_supp_rates_len); 1366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return WLAN_STATUS_UNSPECIFIED_FAILURE; 1376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 1386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->supported_rates_len = merge_byte_arrays( 1406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->supported_rates, sizeof(sta->supported_rates), 1416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt elems->supp_rates, elems->supp_rates_len, 1426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt elems->ext_supp_rates, elems->ext_supp_rates_len); 1436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return WLAN_STATUS_SUCCESS; 1456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 1466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/* return true if elems from a neighbor match this MBSS */ 1496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic Boolean matches_local(struct wpa_supplicant *wpa_s, 1506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct ieee802_11_elems *elems) 1516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 1526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct mesh_conf *mconf = wpa_s->ifmsh->mconf; 1536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (elems->mesh_config_len < 5) 1556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return FALSE; 1566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return (mconf->meshid_len == elems->mesh_id_len && 1586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_memcmp(mconf->meshid, elems->mesh_id, 1596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt elems->mesh_id_len) == 0 && 1606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mconf->mesh_pp_id == elems->mesh_config[0] && 1616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mconf->mesh_pm_id == elems->mesh_config[1] && 1626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mconf->mesh_cc_id == elems->mesh_config[2] && 1636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mconf->mesh_sp_id == elems->mesh_config[3] && 1646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mconf->mesh_auth_id == elems->mesh_config[4]); 1656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 1666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/* check if local link id is already used with another peer */ 1696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic Boolean llid_in_use(struct wpa_supplicant *wpa_s, u16 llid) 1706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 1716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct sta_info *sta; 1726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_data *hapd = wpa_s->ifmsh->bss[0]; 1736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt for (sta = hapd->sta_list; sta; sta = sta->next) { 1756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (sta->my_lid == llid) 1766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return TRUE; 1776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 1786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return FALSE; 1806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 1816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/* generate an llid for a link and set to initial state */ 1846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void mesh_mpm_init_link(struct wpa_supplicant *wpa_s, 1856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct sta_info *sta) 1866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 1876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u16 llid; 1886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt do { 1906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (os_get_random((u8 *) &llid, sizeof(llid)) < 0) 1916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt continue; 1926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } while (!llid || llid_in_use(wpa_s, llid)); 1936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->my_lid = llid; 1956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->peer_lid = 0; 196216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 197216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt /* 198216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * We do not use wpa_mesh_set_plink_state() here because there is no 199216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * entry in kernel yet. 200216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt */ 2016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->plink_state = PLINK_LISTEN; 2026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 2036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, 2066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct sta_info *sta, 2076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt enum plink_action_field type, 2086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u16 close_reason) 2096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 2106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct wpabuf *buf; 2116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_iface *ifmsh = wpa_s->ifmsh; 2126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_data *bss = ifmsh->bss[0]; 2136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct mesh_conf *conf = ifmsh->mconf; 2146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u8 supp_rates[2 + 2 + 32]; 2156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_IEEE80211N 2166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u8 ht_capa_oper[2 + 26 + 2 + 22]; 2176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_IEEE80211N */ 2186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u8 *pos, *cat; 2196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u8 ie_len, add_plid = 0; 2206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int ret; 2216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int ampe = conf->security & MESH_CONF_SEC_AMPE; 2226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt size_t buf_len; 2236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!sta) 2256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 2266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt buf_len = 2 + /* capability info */ 2286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2 + /* AID */ 2296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2 + 8 + /* supported rates */ 2306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2 + (32 - 8) + 2316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2 + 32 + /* mesh ID */ 2326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2 + 7 + /* mesh config */ 2336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2 + 23 + /* peering management */ 2346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2 + 96 + /* AMPE */ 2356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2 + 16; /* MIC */ 2366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_IEEE80211N 237ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) { 2386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt buf_len += 2 + 26 + /* HT capabilities */ 2396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2 + 22; /* HT operation */ 2406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 2416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_IEEE80211N */ 2426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt buf = wpabuf_alloc(buf_len); 2436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!buf) 2446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 2456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt cat = wpabuf_mhead_u8(buf); 2476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_u8(buf, WLAN_ACTION_SELF_PROTECTED); 2486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_u8(buf, type); 2496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (type != PLINK_CLOSE) { 2516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u8 info; 2526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* capability info */ 2546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_le16(buf, ampe ? IEEE80211_CAP_PRIVACY : 0); 2556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* aid */ 2576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (type == PLINK_CONFIRM) 2586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_le16(buf, sta->peer_lid); 2596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* IE: supp + ext. supp rates */ 2616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt pos = hostapd_eid_supp_rates(bss, supp_rates); 2626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt pos = hostapd_eid_ext_supp_rates(bss, pos); 2636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_data(buf, supp_rates, pos - supp_rates); 2646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* IE: Mesh ID */ 2666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_u8(buf, WLAN_EID_MESH_ID); 2676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_u8(buf, conf->meshid_len); 2686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_data(buf, conf->meshid, conf->meshid_len); 2696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* IE: mesh conf */ 2716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_u8(buf, WLAN_EID_MESH_CONFIG); 2726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_u8(buf, 7); 2736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_u8(buf, conf->mesh_pp_id); 2746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_u8(buf, conf->mesh_pm_id); 2756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_u8(buf, conf->mesh_cc_id); 2766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_u8(buf, conf->mesh_sp_id); 2776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_u8(buf, conf->mesh_auth_id); 2786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info = (bss->num_plinks > 63 ? 63 : bss->num_plinks) << 1; 2796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* TODO: Add Connected to Mesh Gate/AS subfields */ 2806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_u8(buf, info); 2816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* always forwarding & accepting plinks for now */ 2826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_u8(buf, 0x1 | 0x8); 2836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } else { /* Peer closing frame */ 2846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* IE: Mesh ID */ 2856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_u8(buf, WLAN_EID_MESH_ID); 2866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_u8(buf, conf->meshid_len); 2876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_data(buf, conf->meshid, conf->meshid_len); 2886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 2896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* IE: Mesh Peering Management element */ 2916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ie_len = 4; 2926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ampe) 2936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ie_len += PMKID_LEN; 2946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt switch (type) { 2956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case PLINK_OPEN: 2966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 2976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case PLINK_CONFIRM: 2986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ie_len += 2; 2996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt add_plid = 1; 3006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 3016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case PLINK_CLOSE: 3026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ie_len += 2; 3036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt add_plid = 1; 3046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ie_len += 2; /* reason code */ 3056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 3066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 3076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_u8(buf, WLAN_EID_PEER_MGMT); 3096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_u8(buf, ie_len); 3106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* peering protocol */ 3116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ampe) 3126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_le16(buf, 1); 3136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt else 3146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_le16(buf, 0); 3156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_le16(buf, sta->my_lid); 3166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (add_plid) 3176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_le16(buf, sta->peer_lid); 3186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (type == PLINK_CLOSE) 3196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_le16(buf, close_reason); 3206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ampe) { 3216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (sta->sae == NULL) { 3226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "Mesh MPM: no SAE session"); 3236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt goto fail; 3246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 3256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_rsn_get_pmkid(wpa_s->mesh_rsn, sta, 3266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put(buf, PMKID_LEN)); 3276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 3286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_IEEE80211N 330ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) { 3316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt pos = hostapd_eid_ht_capabilities(bss, ht_capa_oper); 3326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt pos = hostapd_eid_ht_operation(bss, pos); 3336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_put_data(buf, ht_capa_oper, pos - ht_capa_oper); 3346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 3356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_IEEE80211N */ 3366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ampe && mesh_rsn_protect_frame(wpa_s->mesh_rsn, sta, cat, buf)) { 3386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg(wpa_s, MSG_INFO, 3396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "Mesh MPM: failed to add AMPE and MIC IE"); 3406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt goto fail; 3416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 3426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, 3446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->addr, wpa_s->own_addr, wpa_s->own_addr, 3456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_head(buf), wpabuf_len(buf), 0); 3466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ret < 0) 3476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg(wpa_s, MSG_INFO, 3486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "Mesh MPM: failed to send peering frame"); 3496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail: 3516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_free(buf); 3526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 3536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/* configure peering state in ours and driver's station entry */ 356216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidtvoid wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s, 357216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt struct sta_info *sta, 358216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt enum mesh_plink_state state) 3596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 3606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_sta_add_params params; 3616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int ret; 3626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->plink_state = state; 3646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_memset(¶ms, 0, sizeof(params)); 3666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.addr = sta->addr; 3676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.plink_state = state; 3686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.set = 1; 3696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg(wpa_s, MSG_DEBUG, "MPM set " MACSTR " into %s", 3716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt MAC2STR(sta->addr), mplstate[state]); 3726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ret = wpa_drv_sta_add(wpa_s, ¶ms); 3736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ret) { 3746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg(wpa_s, MSG_ERROR, "Driver failed to set " MACSTR 3756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ": %d", MAC2STR(sta->addr), ret); 3766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 3776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 3786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void mesh_mpm_fsm_restart(struct wpa_supplicant *wpa_s, 3816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct sta_info *sta) 3826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 3836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_data *hapd = wpa_s->ifmsh->bss[0]; 3846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt eloop_cancel_timeout(plink_timer, wpa_s, sta); 3866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 387216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt ap_free_sta(hapd, sta); 3886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 3896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void plink_timer(void *eloop_ctx, void *user_data) 3926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 3936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct wpa_supplicant *wpa_s = eloop_ctx; 3946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct sta_info *sta = user_data; 3956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u16 reason = 0; 3966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct mesh_conf *conf = wpa_s->ifmsh->mconf; 3976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt switch (sta->plink_state) { 3996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case PLINK_OPEN_RCVD: 4006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case PLINK_OPEN_SENT: 4016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* retry timer */ 4026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (sta->mpm_retries < conf->dot11MeshMaxRetries) { 4036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt eloop_register_timeout( 4046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt conf->dot11MeshRetryTimeout / 1000, 4056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (conf->dot11MeshRetryTimeout % 1000) * 1000, 4066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt plink_timer, wpa_s, sta); 4076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_send_plink_action(wpa_s, sta, PLINK_OPEN, 0); 4086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->mpm_retries++; 4096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 4106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 4116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt reason = WLAN_REASON_MESH_MAX_RETRIES; 4126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* fall through on else */ 4136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case PLINK_CNF_RCVD: 4156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* confirm timer */ 4166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!reason) 4176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt reason = WLAN_REASON_MESH_CONFIRM_TIMEOUT; 418216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING); 4196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt eloop_register_timeout(conf->dot11MeshHoldingTimeout / 1000, 4206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (conf->dot11MeshHoldingTimeout % 1000) * 1000, 4216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt plink_timer, wpa_s, sta); 4226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason); 4236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 4246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case PLINK_HOLDING: 4256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* holding timer */ 4266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_fsm_restart(wpa_s, sta); 4276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 4286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt default: 4296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 4306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 4316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 4326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/* initiate peering with station */ 4356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void 4366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtmesh_mpm_plink_open(struct wpa_supplicant *wpa_s, struct sta_info *sta, 4376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt enum mesh_plink_state next_state) 4386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 4396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct mesh_conf *conf = wpa_s->ifmsh->mconf; 4406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt eloop_cancel_timeout(plink_timer, wpa_s, sta); 4426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt eloop_register_timeout(conf->dot11MeshRetryTimeout / 1000, 4436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (conf->dot11MeshRetryTimeout % 1000) * 1000, 4446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt plink_timer, wpa_s, sta); 4456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_send_plink_action(wpa_s, sta, PLINK_OPEN, 0); 4466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_mesh_set_plink_state(wpa_s, sta, next_state); 4476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 4486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint mesh_mpm_plink_close(struct hostapd_data *hapd, 4516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct sta_info *sta, void *ctx) 4526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 4536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct wpa_supplicant *wpa_s = ctx; 4546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int reason = WLAN_REASON_MESH_PEERING_CANCELLED; 4556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (sta) { 4576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING); 4586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason); 4596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "MPM closing plink sta=" MACSTR, 4606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt MAC2STR(sta->addr)); 4616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt eloop_cancel_timeout(plink_timer, wpa_s, sta); 4626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 0; 4636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 4646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 1; 4666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 4676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtvoid mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh) 4706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 4716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_data *hapd = ifmsh->bss[0]; 4726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* notify peers we're leaving */ 4746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ap_for_each_sta(hapd, mesh_mpm_plink_close, wpa_s); 4756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt hapd->num_plinks = 0; 4776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt hostapd_free_stas(hapd); 4786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 4796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/* for mesh_rsn to indicate this peer has completed authentication, and we're 4826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * ready to start AMPE */ 4836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtvoid mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr) 4846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 4856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_data *data = wpa_s->ifmsh->bss[0]; 4866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_sta_add_params params; 4876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct sta_info *sta; 4886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int ret; 4896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta = ap_get_sta(data, addr); 4916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!sta) { 4926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg(wpa_s, MSG_DEBUG, "no such mesh peer"); 4936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 4946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 4956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* TODO: Should do nothing if this STA is already authenticated, but 4976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * the AP code already sets this flag. */ 4986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->flags |= WLAN_STA_AUTH; 4996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 5006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_rsn_init_ampe_sta(wpa_s, sta); 5016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 5026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_memset(¶ms, 0, sizeof(params)); 5036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.addr = sta->addr; 5046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.flags = WPA_STA_AUTHENTICATED | WPA_STA_AUTHORIZED; 5056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.set = 1; 5066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 5076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg(wpa_s, MSG_DEBUG, "MPM authenticating " MACSTR, 5086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt MAC2STR(sta->addr)); 5096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ret = wpa_drv_sta_add(wpa_s, ¶ms); 5106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ret) { 5116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg(wpa_s, MSG_ERROR, 5126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "Driver failed to set " MACSTR ": %d", 5136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt MAC2STR(sta->addr), ret); 5146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 5156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 5166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!sta->my_lid) 5176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_init_link(wpa_s, sta); 5186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 5196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT); 5206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 5216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 522216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt/* 523216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * Initialize a sta_info structure for a peer and upload it into the driver 524216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * in preparation for beginning authentication or peering. This is done when a 525216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * Beacon (secure or open mesh) or a peering open frame (for open mesh) is 526216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * received from the peer for the first time. 527216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt */ 528216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidtstatic struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s, 529216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt const u8 *addr, 530216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt struct ieee802_11_elems *elems) 5316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 5326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_sta_add_params params; 5336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct mesh_conf *conf = wpa_s->ifmsh->mconf; 5346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_data *data = wpa_s->ifmsh->bss[0]; 5356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct sta_info *sta; 536216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt int ret; 5376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 5386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta = ap_get_sta(data, addr); 5396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!sta) { 5406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta = ap_sta_add(data, addr); 5416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!sta) 542216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt return NULL; 5436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 5446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 5456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* initialize sta */ 546216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt if (copy_supp_rates(wpa_s, sta, elems)) { 547216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt ap_free_sta(data, sta); 548216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt return NULL; 549216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt } 5506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 5516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_init_link(wpa_s, sta); 5526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 5536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_IEEE80211N 5549d9e60286e05ae45025b672636490bd12586138dDmitry Shmidt copy_sta_ht_capab(data, sta, elems->ht_capabilities); 5556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt update_ht_state(data, sta); 5566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_IEEE80211N */ 5576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 5586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* insert into driver */ 5596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_memset(¶ms, 0, sizeof(params)); 5606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.supp_rates = sta->supported_rates; 5616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.supp_rates_len = sta->supported_rates_len; 5626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.addr = addr; 5636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.plink_state = sta->plink_state; 5646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.aid = sta->peer_lid; 5656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.listen_interval = 100; 5666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.ht_capabilities = sta->ht_capabilities; 5676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.flags |= WPA_STA_WMM; 5686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.flags_mask |= WPA_STA_AUTHENTICATED; 5696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (conf->security == MESH_CONF_SEC_NONE) { 5706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.flags |= WPA_STA_AUTHORIZED; 5716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.flags |= WPA_STA_AUTHENTICATED; 5726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } else { 5736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->flags |= WLAN_STA_MFP; 5746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt params.flags |= WPA_STA_MFP; 5756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 5766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 5776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ret = wpa_drv_sta_add(wpa_s, ¶ms); 5786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ret) { 5796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg(wpa_s, MSG_ERROR, 5806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "Driver failed to insert " MACSTR ": %d", 5816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt MAC2STR(addr), ret); 582216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt ap_free_sta(data, sta); 583216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt return NULL; 5846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 5856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 586216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt return sta; 587216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt} 588216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 589216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 590216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidtvoid wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr, 591216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt struct ieee802_11_elems *elems) 592216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt{ 593216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt struct mesh_conf *conf = wpa_s->ifmsh->mconf; 594216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt struct hostapd_data *data = wpa_s->ifmsh->bss[0]; 595216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt struct sta_info *sta; 596216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt struct wpa_ssid *ssid = wpa_s->current_ssid; 597216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 598216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt sta = mesh_mpm_add_peer(wpa_s, addr, elems); 599216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt if (!sta) 600216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt return; 601216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 6026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ssid && ssid->no_auto_peer) { 6036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "will not initiate new peer link with " 6046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt MACSTR " because of no_auto_peer", MAC2STR(addr)); 6056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (data->mesh_pending_auth) { 6066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct os_reltime age; 6076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt const struct ieee80211_mgmt *mgmt; 6086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_frame_info fi; 6096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mgmt = wpabuf_head(data->mesh_pending_auth); 6116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_reltime_age(&data->mesh_pending_auth_time, &age); 6126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (age.sec < 2 && 6136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_memcmp(mgmt->sa, addr, ETH_ALEN) == 0) { 6146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, 6156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "mesh: Process pending Authentication frame from %u.%06u seconds ago", 6166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (unsigned int) age.sec, 6176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (unsigned int) age.usec); 6186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_memset(&fi, 0, sizeof(fi)); 6196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ieee802_11_mgmt( 6206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt data, 6216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_head(data->mesh_pending_auth), 6226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_len(data->mesh_pending_auth), 6236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt &fi); 6246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 6256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpabuf_free(data->mesh_pending_auth); 6266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt data->mesh_pending_auth = NULL; 6276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 6286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 6296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 6306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (conf->security == MESH_CONF_SEC_NONE) 6326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT); 6336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt else 6346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_rsn_auth_sae_sta(wpa_s, sta); 6356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 6366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtvoid mesh_mpm_mgmt_rx(struct wpa_supplicant *wpa_s, struct rx_mgmt *rx_mgmt) 6396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 6406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_frame_info fi; 6416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_memset(&fi, 0, sizeof(fi)); 6436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt fi.datarate = rx_mgmt->datarate; 6446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt fi.ssi_signal = rx_mgmt->ssi_signal; 6456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ieee802_11_mgmt(wpa_s->ifmsh->bss[0], rx_mgmt->frame, 6466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt rx_mgmt->frame_len, &fi); 6476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 6486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s, 6516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct sta_info *sta) 6526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 6536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_data *hapd = wpa_s->ifmsh->bss[0]; 6546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct mesh_conf *conf = wpa_s->ifmsh->mconf; 6556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u8 seq[6] = {}; 6566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "mesh plink with " MACSTR " established", 6586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt MAC2STR(sta->addr)); 6596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (conf->security & MESH_CONF_SEC_AMPE) { 6616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 0, 0, 6626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt seq, sizeof(seq), sta->mtk, sizeof(sta->mtk)); 6636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 1, 0, 6646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt seq, sizeof(seq), 6656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->mgtk, sizeof(sta->mgtk)); 6666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_drv_set_key(wpa_s, WPA_ALG_IGTK, sta->addr, 4, 0, 6676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt seq, sizeof(seq), 6686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->mgtk, sizeof(sta->mgtk)); 6696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "mtk:", sta->mtk, sizeof(sta->mtk)); 6716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "mgtk:", 6726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->mgtk, sizeof(sta->mgtk)); 6736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 6746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_mesh_set_plink_state(wpa_s, sta, PLINK_ESTAB); 6766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt hapd->num_plinks++; 6776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->flags |= WLAN_STA_ASSOC; 6796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt eloop_cancel_timeout(plink_timer, wpa_s, sta); 6816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* Send ctrl event */ 6836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR, 6846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt MAC2STR(sta->addr)); 6856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 6866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta, 6896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt enum plink_event event) 6906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 6916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_data *hapd = wpa_s->ifmsh->bss[0]; 6926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct mesh_conf *conf = wpa_s->ifmsh->mconf; 6936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u16 reason = 0; 6946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg(wpa_s, MSG_DEBUG, "MPM " MACSTR " state %s event %s", 6966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt MAC2STR(sta->addr), mplstate[sta->plink_state], 6976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mplevent[event]); 6986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt switch (sta->plink_state) { 7006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case PLINK_LISTEN: 7016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt switch (event) { 7026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case CLS_ACPT: 7036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_fsm_restart(wpa_s, sta); 7046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 7056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case OPN_ACPT: 7066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_RCVD); 7076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM, 7086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 0); 7096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 7106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt default: 7116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 7126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 7136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 7146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case PLINK_OPEN_SENT: 7156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt switch (event) { 7166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case OPN_RJCT: 7176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case CNF_RJCT: 7186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION; 7196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* fall-through */ 7206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case CLS_ACPT: 7216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING); 7226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!reason) 7236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt reason = WLAN_REASON_MESH_CLOSE_RCVD; 7246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt eloop_register_timeout( 7256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt conf->dot11MeshHoldingTimeout / 1000, 7266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (conf->dot11MeshHoldingTimeout % 1000) * 1000, 7276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt plink_timer, wpa_s, sta); 7286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_send_plink_action(wpa_s, sta, 7296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt PLINK_CLOSE, reason); 7306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 7316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case OPN_ACPT: 7326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* retry timer is left untouched */ 7336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPEN_RCVD); 7346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_send_plink_action(wpa_s, sta, 7356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt PLINK_CONFIRM, 0); 7366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 7376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case CNF_ACPT: 7386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_mesh_set_plink_state(wpa_s, sta, PLINK_CNF_RCVD); 7396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt eloop_register_timeout( 7406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt conf->dot11MeshConfirmTimeout / 1000, 7416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (conf->dot11MeshConfirmTimeout % 1000) * 1000, 7426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt plink_timer, wpa_s, sta); 7436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 7446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt default: 7456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 7466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 7476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 7486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case PLINK_OPEN_RCVD: 7496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt switch (event) { 7506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case OPN_RJCT: 7516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case CNF_RJCT: 7526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION; 7536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* fall-through */ 7546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case CLS_ACPT: 7556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING); 7566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!reason) 7576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt reason = WLAN_REASON_MESH_CLOSE_RCVD; 7586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt eloop_register_timeout( 7596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt conf->dot11MeshHoldingTimeout / 1000, 7606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (conf->dot11MeshHoldingTimeout % 1000) * 1000, 7616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt plink_timer, wpa_s, sta); 7626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->mpm_close_reason = reason; 7636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_send_plink_action(wpa_s, sta, 7646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt PLINK_CLOSE, reason); 7656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 7666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case OPN_ACPT: 7676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_send_plink_action(wpa_s, sta, 7686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt PLINK_CONFIRM, 0); 7696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 7706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case CNF_ACPT: 7716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (conf->security & MESH_CONF_SEC_AMPE) 7726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_rsn_derive_mtk(wpa_s, sta); 7736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_plink_estab(wpa_s, sta); 7746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 7756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt default: 7766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 7776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 7786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 7796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case PLINK_CNF_RCVD: 7806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt switch (event) { 7816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case OPN_RJCT: 7826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case CNF_RJCT: 7836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION; 7846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* fall-through */ 7856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case CLS_ACPT: 7866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING); 7876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!reason) 7886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt reason = WLAN_REASON_MESH_CLOSE_RCVD; 7896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt eloop_register_timeout( 7906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt conf->dot11MeshHoldingTimeout / 1000, 7916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (conf->dot11MeshHoldingTimeout % 1000) * 1000, 7926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt plink_timer, wpa_s, sta); 7936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->mpm_close_reason = reason; 7946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_send_plink_action(wpa_s, sta, 7956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt PLINK_CLOSE, reason); 7966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 7976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case OPN_ACPT: 7986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_plink_estab(wpa_s, sta); 7996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_send_plink_action(wpa_s, sta, 8006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt PLINK_CONFIRM, 0); 8016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 8026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt default: 8036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 8046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 8056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 8066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case PLINK_ESTAB: 8076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt switch (event) { 8086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case CLS_ACPT: 8096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING); 8106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt reason = WLAN_REASON_MESH_CLOSE_RCVD; 8116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt eloop_register_timeout( 8136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt conf->dot11MeshHoldingTimeout / 1000, 8146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (conf->dot11MeshHoldingTimeout % 1000) * 1000, 8156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt plink_timer, wpa_s, sta); 8166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->mpm_close_reason = reason; 8176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "mesh plink with " MACSTR 8196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt " closed with reason %d", 8206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt MAC2STR(sta->addr), reason); 8216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg_ctrl(wpa_s, MSG_INFO, 8236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt MESH_PEER_DISCONNECTED MACSTR, 8246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt MAC2STR(sta->addr)); 8256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt hapd->num_plinks--; 8276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_send_plink_action(wpa_s, sta, 8296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt PLINK_CLOSE, reason); 8306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 8316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case OPN_ACPT: 8326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_send_plink_action(wpa_s, sta, 8336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt PLINK_CONFIRM, 0); 8346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 8356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt default: 8366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 8376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 8386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 8396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case PLINK_HOLDING: 8406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt switch (event) { 8416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case CLS_ACPT: 8426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_fsm_restart(wpa_s, sta); 8436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 8446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case OPN_ACPT: 8456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case CNF_ACPT: 8466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case OPN_RJCT: 8476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case CNF_RJCT: 8486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt reason = sta->mpm_close_reason; 8496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_send_plink_action(wpa_s, sta, 8506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt PLINK_CLOSE, reason); 8516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 8526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt default: 8536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 8546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 8556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 8566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt default: 8576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_msg(wpa_s, MSG_DEBUG, 8586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "Unsupported MPM event %s for state %s", 8596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mplevent[event], mplstate[sta->plink_state]); 8606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 8616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 8626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 8636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtvoid mesh_mpm_action_rx(struct wpa_supplicant *wpa_s, 8666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt const struct ieee80211_mgmt *mgmt, size_t len) 8676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 8686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u8 action_field; 8696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_data *hapd = wpa_s->ifmsh->bss[0]; 8706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct mesh_conf *mconf = wpa_s->ifmsh->mconf; 8716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct sta_info *sta; 8726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u16 plid = 0, llid = 0; 8736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt enum plink_event event; 8746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct ieee802_11_elems elems; 8756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct mesh_peer_mgmt_ie peer_mgmt_ie; 8766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt const u8 *ies; 8776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt size_t ie_len; 8786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int ret; 8796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (mgmt->u.action.category != WLAN_ACTION_SELF_PROTECTED) 8816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 8826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt action_field = mgmt->u.action.u.slf_prot_action.action; 8846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (action_field != PLINK_OPEN && 8856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt action_field != PLINK_CONFIRM && 8866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt action_field != PLINK_CLOSE) 8876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 8886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ies = mgmt->u.action.u.slf_prot_action.variable; 8906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ie_len = (const u8 *) mgmt + len - 8916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mgmt->u.action.u.slf_prot_action.variable; 8926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* at least expect mesh id and peering mgmt */ 8946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ie_len < 2 + 2) { 8956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, 8966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "MPM: Ignore too short action frame %u ie_len %u", 8976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt action_field, (unsigned int) ie_len); 8986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 8996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 9006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "MPM: Received PLINK action %u", action_field); 9016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 9026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (action_field == PLINK_OPEN || action_field == PLINK_CONFIRM) { 9036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "MPM: Capability 0x%x", 9046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt WPA_GET_LE16(ies)); 9056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ies += 2; /* capability */ 9066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ie_len -= 2; 9076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 9086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (action_field == PLINK_CONFIRM) { 9096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", WPA_GET_LE16(ies)); 9106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ies += 2; /* aid */ 9116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ie_len -= 2; 9126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 9136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 9146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* check for mesh peering, mesh id and mesh config IEs */ 9156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed) { 9166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "MPM: Failed to parse PLINK IEs"); 9176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 9186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 9196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!elems.peer_mgmt) { 9206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, 9216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "MPM: No Mesh Peering Management element"); 9226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 9236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 9246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (action_field != PLINK_CLOSE) { 9256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!elems.mesh_id || !elems.mesh_config) { 9266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, 9276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "MPM: No Mesh ID or Mesh Configuration element"); 9286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 9296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 9306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 9316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!matches_local(wpa_s, &elems)) { 9326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, 9336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "MPM: Mesh ID or Mesh Configuration element do not match local MBSS"); 9346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 9356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 9366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 9376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 9386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ret = mesh_mpm_parse_peer_mgmt(wpa_s, action_field, 9396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt elems.peer_mgmt, 9406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt elems.peer_mgmt_len, 9416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt &peer_mgmt_ie); 9426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ret) { 9436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "MPM: Mesh parsing rejected frame"); 9446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 9456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 9466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 9476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* the sender's llid is our plid and vice-versa */ 9486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt plid = WPA_GET_LE16(peer_mgmt_ie.llid); 9496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (peer_mgmt_ie.plid) 9506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt llid = WPA_GET_LE16(peer_mgmt_ie.plid); 9516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "MPM: plid=0x%x llid=0x%x", plid, llid); 9526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 9536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta = ap_get_sta(hapd, mgmt->sa); 954216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 955216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt /* 956216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * If this is an open frame from an unknown STA, and this is an 957216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * open mesh, then go ahead and add the peer before proceeding. 958216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt */ 959216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt if (!sta && action_field == PLINK_OPEN && 960216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt !(mconf->security & MESH_CONF_SEC_AMPE)) 961216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt sta = mesh_mpm_add_peer(wpa_s, mgmt->sa, &elems); 962216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt 9636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!sta) { 9646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "MPM: No STA entry for peer"); 9656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 9666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 9676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 9686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_SAE 9696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* peer is in sae_accepted? */ 9706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (sta->sae && sta->sae->state != SAE_ACCEPTED) { 9716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "MPM: SAE not yet accepted for peer"); 9726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 9736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 9746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_SAE */ 9756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 9766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!sta->my_lid) 9776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_init_link(wpa_s, sta); 9786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 9796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if ((mconf->security & MESH_CONF_SEC_AMPE) && 9806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_rsn_process_ampe(wpa_s, sta, &elems, 9816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt &mgmt->u.action.category, 9826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ies, ie_len)) { 9836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "MPM: RSN process rejected frame"); 9846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 9856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 9866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 9876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (sta->plink_state == PLINK_BLOCKED) { 9886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "MPM: PLINK_BLOCKED"); 9896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 9906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 9916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 9926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* Now we will figure out the appropriate event... */ 9936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt switch (action_field) { 9946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case PLINK_OPEN: 9956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (plink_free_count(hapd) == 0) { 9966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt event = OPN_IGNR; 9976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_INFO, 9986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "MPM: Peer link num over quota(%d)", 9996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt hapd->max_plinks); 10006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } else if (sta->peer_lid && sta->peer_lid != plid) { 10016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt event = OPN_IGNR; 10026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } else { 10036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->peer_lid = plid; 10046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt event = OPN_ACPT; 10056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 10066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 10076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case PLINK_CONFIRM: 10086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (plink_free_count(hapd) == 0) { 10096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt event = CNF_IGNR; 10106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_INFO, 10116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "MPM: Peer link num over quota(%d)", 10126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt hapd->max_plinks); 10136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } else if (sta->my_lid != llid || 10146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (sta->peer_lid && sta->peer_lid != plid)) { 10156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt event = CNF_IGNR; 10166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } else { 10176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!sta->peer_lid) 10186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sta->peer_lid = plid; 10196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt event = CNF_ACPT; 10206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 10216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 10226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case PLINK_CLOSE: 10236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (sta->plink_state == PLINK_ESTAB) 10246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* Do not check for llid or plid. This does not 10256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * follow the standard but since multiple plinks 10266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * per cand are not supported, it is necessary in 10276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * order to avoid a livelock when MP A sees an 10286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * establish peer link to MP B but MP B does not 10296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * see it. This can be caused by a timeout in 10306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * B's peer link establishment or B being 10316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * restarted. 10326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */ 10336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt event = CLS_ACPT; 10346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt else if (sta->peer_lid != plid) 10356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt event = CLS_IGNR; 10366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt else if (peer_mgmt_ie.plid && sta->my_lid != llid) 10376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt event = CLS_IGNR; 10386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt else 10396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt event = CLS_ACPT; 10406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 10416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt default: 10426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* 10436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * This cannot be hit due to the action_field check above, but 10446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * compilers may not be able to figure that out and can warn 10456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * about uninitialized event below. 10466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */ 10476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 10486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 10496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mesh_mpm_fsm(wpa_s, sta, event); 10506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 10516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/* called by ap_free_sta */ 10546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtvoid mesh_mpm_free_sta(struct sta_info *sta) 10556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 10566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt eloop_cancel_timeout(plink_timer, ELOOP_ALL_CTX, sta); 10576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt eloop_cancel_timeout(mesh_auth_timer, ELOOP_ALL_CTX, sta); 10586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 1059