PLINK_UNDEFINED,
OPN_ACPT,
OPN_RJCT,
- OPN_IGNR,
CNF_ACPT,
CNF_RJCT,
- CNF_IGNR,
CLS_ACPT,
- CLS_IGNR
+ REQ_RJCT
};
static const char * const mplstate[] = {
[0] = "UNINITIALIZED",
- [PLINK_LISTEN] = "LISTEN",
- [PLINK_OPEN_SENT] = "OPEN_SENT",
- [PLINK_OPEN_RCVD] = "OPEN_RCVD",
+ [PLINK_IDLE] = "IDLE",
+ [PLINK_OPN_SNT] = "OPN_SNT",
+ [PLINK_OPN_RCVD] = "OPN_RCVD",
[PLINK_CNF_RCVD] = "CNF_RCVD",
[PLINK_ESTAB] = "ESTAB",
[PLINK_HOLDING] = "HOLDING",
[PLINK_UNDEFINED] = "UNDEFINED",
[OPN_ACPT] = "OPN_ACPT",
[OPN_RJCT] = "OPN_RJCT",
- [OPN_IGNR] = "OPN_IGNR",
[CNF_ACPT] = "CNF_ACPT",
[CNF_RJCT] = "CNF_RJCT",
- [CNF_IGNR] = "CNF_IGNR",
[CLS_ACPT] = "CLS_ACPT",
- [CLS_IGNR] = "CLS_IGNR"
+ [REQ_RJCT] = "REQ_RJCT",
};
sta->my_lid = llid;
sta->peer_lid = 0;
+ sta->peer_aid = 0;
/*
* We do not use wpa_mesh_set_plink_state() here because there is no
* entry in kernel yet.
*/
- sta->plink_state = PLINK_LISTEN;
+ sta->plink_state = PLINK_IDLE;
}
/* TODO: Add Connected to Mesh Gate/AS subfields */
wpabuf_put_u8(buf, info);
/* always forwarding & accepting plinks for now */
- wpabuf_put_u8(buf, 0x1 | 0x8);
+ wpabuf_put_u8(buf, MESH_CAP_ACCEPT_ADDITIONAL_PEER |
+ MESH_CAP_FORWARDING);
} else { /* Peer closing frame */
/* IE: Mesh ID */
wpabuf_put_u8(buf, WLAN_EID_MESH_ID);
os_memset(¶ms, 0, sizeof(params));
params.addr = sta->addr;
params.plink_state = state;
+ params.peer_aid = sta->peer_aid;
params.set = 1;
ret = wpa_drv_sta_add(wpa_s, ¶ms);
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
switch (sta->plink_state) {
- case PLINK_OPEN_RCVD:
- case PLINK_OPEN_SENT:
+ case PLINK_OPN_RCVD:
+ case PLINK_OPN_SNT:
/* retry timer */
if (sta->mpm_retries < conf->dot11MeshMaxRetries) {
eloop_register_timeout(
return -1;
}
- if ((PLINK_OPEN_SENT <= sta->plink_state &&
+ if ((PLINK_OPN_SNT <= sta->plink_state &&
sta->plink_state <= PLINK_ESTAB) ||
(sta->sae && sta->sae->state > SAE_NOTHING)) {
wpa_msg(wpa_s, MSG_INFO,
}
if (conf->security == MESH_CONF_SEC_NONE) {
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
} else {
mesh_rsn_auth_sae_sta(wpa_s, sta);
os_memcpy(hapd->mesh_required_peer, addr, ETH_ALEN);
if (!sta->my_lid)
mesh_mpm_init_link(wpa_s, sta);
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
}
/*
struct sta_info *sta;
int ret;
+ if (elems->mesh_config_len >= 7 &&
+ !(elems->mesh_config[6] & MESH_CAP_ACCEPT_ADDITIONAL_PEER)) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "mesh: Ignore a crowded peer " MACSTR,
+ MAC2STR(addr));
+ return NULL;
+ }
+
sta = ap_get_sta(data, addr);
if (!sta) {
sta = ap_sta_add(data, addr);
params.addr = addr;
params.plink_state = sta->plink_state;
params.aid = sta->aid;
+ params.peer_aid = sta->peer_aid;
params.listen_interval = 100;
params.ht_capabilities = sta->ht_capabilities;
params.vht_capabilities = sta->vht_capabilities;
}
if (conf->security == MESH_CONF_SEC_NONE) {
- if (sta->plink_state < PLINK_OPEN_SENT ||
+ if (sta->plink_state < PLINK_OPN_SNT ||
sta->plink_state > PLINK_ESTAB)
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
} else {
mesh_rsn_auth_sae_sta(wpa_s, sta);
}
MAC2STR(sta->addr));
if (conf->security & MESH_CONF_SEC_AMPE) {
- wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 0, 0,
- seq, sizeof(seq), sta->mtk, sizeof(sta->mtk));
- wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 1, 0,
- seq, sizeof(seq),
- sta->mgtk, sizeof(sta->mgtk));
- wpa_drv_set_key(wpa_s, WPA_ALG_IGTK, sta->addr, 4, 0,
- seq, sizeof(seq),
- sta->mgtk, sizeof(sta->mgtk));
-
- wpa_hexdump_key(MSG_DEBUG, "mtk:", sta->mtk, sizeof(sta->mtk));
- wpa_hexdump_key(MSG_DEBUG, "mgtk:",
- sta->mgtk, sizeof(sta->mgtk));
+ wpa_hexdump_key(MSG_DEBUG, "mesh: MTK", sta->mtk, sta->mtk_len);
+ wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->pairwise_cipher),
+ sta->addr, 0, 0, seq, sizeof(seq),
+ sta->mtk, sta->mtk_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK Key RSC",
+ sta->mgtk_rsc, sizeof(sta->mgtk_rsc));
+ wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK",
+ sta->mgtk, sta->mgtk_len);
+ wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->group_cipher),
+ sta->addr, sta->mgtk_key_id, 0,
+ sta->mgtk_rsc, sizeof(sta->mgtk_rsc),
+ sta->mgtk, sta->mgtk_len);
+
+ if (sta->igtk_len) {
+ wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK Key RSC",
+ sta->igtk_rsc, sizeof(sta->igtk_rsc));
+ wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK",
+ sta->igtk, sta->igtk_len);
+ wpa_drv_set_key(
+ wpa_s,
+ wpa_cipher_to_alg(conf->mgmt_group_cipher),
+ sta->addr, sta->igtk_key_id, 0,
+ sta->igtk_rsc, sizeof(sta->igtk_rsc),
+ sta->igtk, sta->igtk_len);
+ }
}
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_ESTAB);
static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
- enum plink_event event)
+ enum plink_event event, u16 reason)
{
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
struct mesh_conf *conf = wpa_s->ifmsh->mconf;
- u16 reason = 0;
wpa_msg(wpa_s, MSG_DEBUG, "MPM " MACSTR " state %s event %s",
MAC2STR(sta->addr), mplstate[sta->plink_state],
mplevent[event]);
switch (sta->plink_state) {
- case PLINK_LISTEN:
+ case PLINK_IDLE:
switch (event) {
case CLS_ACPT:
mesh_mpm_fsm_restart(wpa_s, sta);
break;
case OPN_ACPT:
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_RCVD);
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_RCVD);
mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM,
0);
break;
+ case REQ_RJCT:
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CLOSE, reason);
+ break;
default:
break;
}
break;
- case PLINK_OPEN_SENT:
+ case PLINK_OPN_SNT:
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
/* fall-through */
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
break;
case OPN_ACPT:
/* retry timer is left untouched */
- wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPEN_RCVD);
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPN_RCVD);
mesh_mpm_send_plink_action(wpa_s, sta,
PLINK_CONFIRM, 0);
break;
break;
}
break;
- case PLINK_OPEN_RCVD:
+ case PLINK_OPN_RCVD:
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
/* fall-through */
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
/* fall-through */
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
break;
case PLINK_ESTAB:
switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
- reason = WLAN_REASON_MESH_CLOSE_RCVD;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CLOSE_RCVD;
eloop_register_timeout(
conf->dot11MeshHoldingTimeout / 1000,
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
struct sta_info *sta;
- u16 plid = 0, llid = 0;
+ u16 plid = 0, llid = 0, aid = 0;
enum plink_event event;
struct ieee802_11_elems elems;
struct mesh_peer_mgmt_ie peer_mgmt_ie;
const u8 *ies;
size_t ie_len;
int ret;
+ u16 reason = 0;
if (mgmt->u.action.category != WLAN_ACTION_SELF_PROTECTED)
return;
ie_len -= 2;
}
if (action_field == PLINK_CONFIRM) {
- wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", WPA_GET_LE16(ies));
+ aid = WPA_GET_LE16(ies);
+ wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", aid);
ies += 2; /* aid */
ie_len -= 2;
}
llid = WPA_GET_LE16(peer_mgmt_ie.plid);
wpa_printf(MSG_DEBUG, "MPM: plid=0x%x llid=0x%x", plid, llid);
+ if (action_field == PLINK_CLOSE)
+ wpa_printf(MSG_DEBUG, "MPM: close reason=%u",
+ WPA_GET_LE16(peer_mgmt_ie.reason));
+
sta = ap_get_sta(hapd, mgmt->sa);
/*
if (!sta->my_lid)
mesh_mpm_init_link(wpa_s, sta);
- if ((mconf->security & MESH_CONF_SEC_AMPE) &&
- mesh_rsn_process_ampe(wpa_s, sta, &elems,
- &mgmt->u.action.category,
- peer_mgmt_ie.chosen_pmk,
- ies, ie_len)) {
- wpa_printf(MSG_DEBUG, "MPM: RSN process rejected frame");
- return;
+ if (mconf->security & MESH_CONF_SEC_AMPE) {
+ int res;
+
+ res = mesh_rsn_process_ampe(wpa_s, sta, &elems,
+ &mgmt->u.action.category,
+ peer_mgmt_ie.chosen_pmk,
+ ies, ie_len);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: RSN process rejected frame (res=%d)",
+ res);
+ if (action_field == PLINK_OPEN && res == -2) {
+ /* AES-SIV decryption failed */
+ mesh_mpm_fsm(wpa_s, sta, OPN_RJCT,
+ WLAN_REASON_MESH_INVALID_GTK);
+ }
+ return;
+ }
}
if (sta->plink_state == PLINK_BLOCKED) {
switch (action_field) {
case PLINK_OPEN:
if (plink_free_count(hapd) == 0) {
- event = OPN_IGNR;
+ event = REQ_RJCT;
+ reason = WLAN_REASON_MESH_MAX_PEERS;
wpa_printf(MSG_INFO,
"MPM: Peer link num over quota(%d)",
hapd->max_plinks);
} else if (sta->peer_lid && sta->peer_lid != plid) {
- event = OPN_IGNR;
+ wpa_printf(MSG_DEBUG,
+ "MPM: peer_lid mismatch: 0x%x != 0x%x",
+ sta->peer_lid, plid);
+ return; /* no FSM event */
} else {
sta->peer_lid = plid;
event = OPN_ACPT;
break;
case PLINK_CONFIRM:
if (plink_free_count(hapd) == 0) {
- event = CNF_IGNR;
+ event = REQ_RJCT;
+ reason = WLAN_REASON_MESH_MAX_PEERS;
wpa_printf(MSG_INFO,
"MPM: Peer link num over quota(%d)",
hapd->max_plinks);
} else if (sta->my_lid != llid ||
(sta->peer_lid && sta->peer_lid != plid)) {
- event = CNF_IGNR;
+ wpa_printf(MSG_DEBUG,
+ "MPM: lid mismatch: my_lid: 0x%x != 0x%x or peer_lid: 0x%x != 0x%x",
+ sta->my_lid, llid, sta->peer_lid, plid);
+ return; /* no FSM event */
} else {
if (!sta->peer_lid)
sta->peer_lid = plid;
+ sta->peer_aid = aid;
event = CNF_ACPT;
}
break;
* restarted.
*/
event = CLS_ACPT;
- else if (sta->peer_lid != plid)
- event = CLS_IGNR;
- else if (peer_mgmt_ie.plid && sta->my_lid != llid)
- event = CLS_IGNR;
- else
+ else if (sta->peer_lid != plid) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: peer_lid mismatch: 0x%x != 0x%x",
+ sta->peer_lid, plid);
+ return; /* no FSM event */
+ } else if (peer_mgmt_ie.plid && sta->my_lid != llid) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: my_lid mismatch: 0x%x != 0x%x",
+ sta->my_lid, llid);
+ return; /* no FSM event */
+ } else {
event = CLS_ACPT;
+ }
break;
default:
/*
*/
return;
}
- mesh_mpm_fsm(wpa_s, sta, event);
+ mesh_mpm_fsm(wpa_s, sta, event, reason);
}