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(&params, 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, &params);
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(&params, 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, &params);
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(&params, 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, &params);
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