static void fsm_step(struct candidate *cand, enum plink_event event) { struct ampe_config *aconf = cand->conf; unsigned short reason = 0; uint32_t changed = 0; switch (cand->link_state) { case PLINK_LISTEN: switch (event) { case CLS_ACPT: fsm_restart(cand); break; case OPN_ACPT: cand->timeout = aconf->retry_timeout_ms; cand->t2 = srv_add_timeout(srvctx, SRV_MSEC(cand->timeout), plink_timer, cand); plink_frame_tx(cand, PLINK_OPEN, 0); plink_frame_tx(cand, PLINK_CONFIRM, 0); break; default: break; } break; case PLINK_OPN_SNT: switch (event) { case OPN_RJCT: case CNF_RJCT: reason = htole16(MESH_CAPABILITY_POLICY_VIOLATION); case CLS_ACPT: if (!reason) reason = htole16(MESH_CLOSE_RCVD); cand->reason = reason; set_link_state(cand, PLINK_HOLDING); cand->timeout = aconf->holding_timeout_ms; cand->t2 = srv_add_timeout(srvctx, SRV_MSEC(cand->timeout), plink_timer, cand); plink_frame_tx(cand, PLINK_CLOSE, reason); break; case OPN_ACPT: /* retry timer is left untouched */ set_link_state(cand, PLINK_OPN_RCVD); plink_frame_tx(cand, PLINK_CONFIRM, 0); break; case CNF_ACPT: set_link_state(cand, PLINK_CNF_RCVD); cand->timeout = aconf->confirm_timeout_ms; cand->t2 = srv_add_timeout(srvctx, SRV_MSEC(cand->timeout), plink_timer, cand); break; default: break; } break; case PLINK_OPN_RCVD: switch (event) { case OPN_RJCT: case CNF_RJCT: reason = htole16(MESH_CAPABILITY_POLICY_VIOLATION); case CLS_ACPT: if (!reason) reason = htole16(MESH_CLOSE_RCVD); cand->reason = reason; set_link_state(cand, PLINK_HOLDING); cand->timeout = aconf->holding_timeout_ms; cand->t2 = srv_add_timeout(srvctx, SRV_MSEC(cand->timeout), plink_timer, cand); plink_frame_tx(cand, PLINK_CLOSE, reason); break; case OPN_ACPT: plink_frame_tx(cand, PLINK_CONFIRM, 0); break; case CNF_ACPT: //del_timer(&cand->plink_timer); set_link_state(cand, PLINK_ESTAB); //mesh_plink_inc_estab_count(sdata); //ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); derive_mtk(cand); estab_peer_link(cand->peer_mac, cand->mtk, sizeof(cand->mtk), cand->mgtk, sizeof(cand->mgtk), cand->mgtk_expiration, cand->sup_rates, cand->sup_rates_len, cand->cookie); changed |= mesh_set_ht_op_mode(cand->conf->mesh); sae_debug(AMPE_DEBUG_FSM, "mesh plink with " MACSTR " established\n", MAC2STR(cand->peer_mac)); break; default: break; } break; case PLINK_CNF_RCVD: switch (event) { case OPN_RJCT: case CNF_RJCT: reason = htole16(MESH_CAPABILITY_POLICY_VIOLATION); case CLS_ACPT: if (!reason) reason = htole16(MESH_CLOSE_RCVD); cand->reason = reason; set_link_state(cand, PLINK_HOLDING); cand->timeout = aconf->holding_timeout_ms; cand->t2 = srv_add_timeout(srvctx, SRV_MSEC(cand->timeout), plink_timer, cand); plink_frame_tx(cand, PLINK_CLOSE, reason); break; case OPN_ACPT: set_link_state(cand, PLINK_ESTAB); estab_peer_link(cand->peer_mac, cand->mtk, sizeof(cand->mtk), cand->mgtk, sizeof(cand->mgtk), cand->mgtk_expiration, cand->sup_rates, cand->sup_rates_len, cand->cookie); changed |= mesh_set_ht_op_mode(cand->conf->mesh); //TODO: update the number of available peer "slots" in mesh config //mesh_plink_inc_estab_count(sdata); //ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); sae_debug(AMPE_DEBUG_FSM, "Mesh plink with " MACSTR " ESTABLISHED\n", MAC2STR(cand->peer_mac)); plink_frame_tx(cand, PLINK_CONFIRM, 0); break; default: break; } break; case PLINK_ESTAB: switch (event) { case CLS_ACPT: reason = htole16(MESH_CLOSE_RCVD); cand->reason = reason; set_link_state(cand, PLINK_HOLDING); cand->timeout = aconf->holding_timeout_ms; cand->t2 = srv_add_timeout(srvctx, SRV_MSEC(cand->timeout), plink_timer, cand); changed |= mesh_set_ht_op_mode(cand->conf->mesh); //TODO: update the number of available peer "slots" in mesh config //if (deactivated) // ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); plink_frame_tx(cand, PLINK_CLOSE, reason); break; case OPN_ACPT: plink_frame_tx(cand, PLINK_CONFIRM, 0); break; default: break; } break; case PLINK_HOLDING: switch (event) { case CLS_ACPT: //if (del_timer(&cand->plink_timer)) // cand->ignore_plink_timer = 1; fsm_restart(cand); break; case OPN_ACPT: case CNF_ACPT: case OPN_RJCT: case CNF_RJCT: reason = cand->reason; plink_frame_tx(cand, PLINK_CLOSE, reason); break; default: break; } break; default: sae_debug(AMPE_DEBUG_FSM, "Unsupported event transition %d", event); break; } if (changed) meshd_set_mesh_conf(cand->conf->mesh, changed); }
static void fsm_step(struct candidate *cand, enum plink_event event) { struct ampe_config *aconf = cand->conf; unsigned short reason = 0; uint32_t changed = 0; switch (cand->link_state) { case PLINK_LISTEN: switch (event) { case CLS_ACPT: fsm_restart(cand); break; case OPN_ACPT: cand->timeout = aconf->retry_timeout_ms; cb->evl->rem_timeout(cand->t2); cand->t2 = cb->evl->add_timeout(SRV_MSEC(cand->timeout), plink_timer, cand); set_link_state(cand, PLINK_OPN_RCVD); plink_frame_tx(cand, PLINK_OPEN, 0); plink_frame_tx(cand, PLINK_CONFIRM, 0); break; default: break; } break; case PLINK_OPN_SNT: switch (event) { case OPN_RJCT: case CNF_RJCT: case REQ_RJCT: reason = MESH_CAPABILITY_POLICY_VIOLATION; /* no break */ case CLS_ACPT: if (!reason) reason = MESH_CLOSE_RCVD; set_link_state(cand, PLINK_HOLDING); cand->timeout = aconf->holding_timeout_ms; cb->evl->rem_timeout(cand->t2); cand->t2 = cb->evl->add_timeout(SRV_MSEC(cand->timeout), plink_timer, cand); plink_frame_tx(cand, PLINK_CLOSE, reason); break; case OPN_ACPT: /* retry timer is left untouched */ set_link_state(cand, PLINK_OPN_RCVD); plink_frame_tx(cand, PLINK_CONFIRM, 0); break; case CNF_ACPT: set_link_state(cand, PLINK_CNF_RCVD); cand->timeout = aconf->confirm_timeout_ms; cb->evl->rem_timeout(cand->t2); cand->t2 = cb->evl->add_timeout(SRV_MSEC(cand->timeout), plink_timer, cand); break; default: break; } break; case PLINK_OPN_RCVD: switch (event) { case OPN_RJCT: case CNF_RJCT: case REQ_RJCT: reason = MESH_CAPABILITY_POLICY_VIOLATION; /* no break */ case CLS_ACPT: if (!reason) reason = MESH_CLOSE_RCVD; set_link_state(cand, PLINK_HOLDING); cand->timeout = aconf->holding_timeout_ms; cb->evl->rem_timeout(cand->t2); cand->t2 = cb->evl->add_timeout(SRV_MSEC(cand->timeout), plink_timer, cand); plink_frame_tx(cand, PLINK_CLOSE, reason); break; case OPN_ACPT: plink_frame_tx(cand, PLINK_CONFIRM, 0); break; case CNF_ACPT: changed |= do_estab_peer_link(cand); break; default: break; } break; case PLINK_CNF_RCVD: switch (event) { case OPN_RJCT: case CNF_RJCT: case REQ_RJCT: reason = MESH_CAPABILITY_POLICY_VIOLATION; /* no break */ case CLS_ACPT: if (!reason) reason = MESH_CLOSE_RCVD; set_link_state(cand, PLINK_HOLDING); cand->timeout = aconf->holding_timeout_ms; cb->evl->rem_timeout(cand->t2); cand->t2 = cb->evl->add_timeout(SRV_MSEC(cand->timeout), plink_timer, cand); plink_frame_tx(cand, PLINK_CLOSE, reason); break; case OPN_ACPT: changed |= do_estab_peer_link(cand); plink_frame_tx(cand, PLINK_CONFIRM, 0); break; default: break; } break; case PLINK_ESTAB: switch (event) { case OPN_RJCT: case CNF_RJCT: case REQ_RJCT: reason = MESH_CAPABILITY_POLICY_VIOLATION; case CLS_ACPT: if (!reason) reason = MESH_CLOSE_RCVD; set_link_state(cand, PLINK_HOLDING); cand->timeout = aconf->holding_timeout_ms; cb->evl->rem_timeout(cand->t2); cand->t2 = cb->evl->add_timeout(SRV_MSEC(cand->timeout), plink_timer, cand); changed |= mesh_set_ht_op_mode(cand->conf->mesh); plink_frame_tx(cand, PLINK_CLOSE, reason); break; case OPN_ACPT: plink_frame_tx(cand, PLINK_CONFIRM, 0); break; default: break; } break; case PLINK_HOLDING: switch (event) { case CLS_ACPT: fsm_restart(cand); break; case OPN_ACPT: case CNF_ACPT: case OPN_RJCT: case CNF_RJCT: case REQ_RJCT: plink_frame_tx(cand, PLINK_CLOSE, reason); break; default: break; } break; default: sae_debug(AMPE_DEBUG_FSM, "Unsupported event transition %d", event); break; } if (changed) cb->meshd_set_mesh_conf(cand->conf->mesh, changed); }
static void plink_timer(timerid id, void *data) { __le16 reason; struct candidate *cand; cand = (struct candidate *)data; assert(cand); sae_debug(AMPE_DEBUG_FSM, "Mesh plink timer for " MACSTR " fired on state %s\n", MAC2STR(cand->peer_mac), mplstates[(cand->link_state > PLINK_BLOCKED) ? PLINK_UNDEFINED : cand->link_state]); reason = 0; switch (cand->link_state) { case PLINK_OPN_RCVD: case PLINK_OPN_SNT: /* retry timer */ sae_debug(AMPE_DEBUG_FSM, "Mesh plink:retries %d of %d\n", cand->retries, cand->conf->max_retries); if (cand->retries < cand->conf->max_retries) { unsigned int rand; sae_debug(AMPE_DEBUG_FSM, "Mesh plink for " MACSTR " (retry, timeout): %d %d\n", MAC2STR(cand->peer_mac), cand->retries, cand->timeout); RAND_bytes((unsigned char *) &rand, sizeof(rand)); if (!cand->timeout) { cand->timeout = cand->conf->retry_timeout_ms; sae_debug(AMPE_DEBUG_ERR, "WARN: cand " MACSTR " had a timeout of 0ms. Reset to %d\n", MAC2STR(cand->peer_mac),cand->timeout); } cand->timeout += rand % cand->timeout; ++cand->retries; cand->t2 = srv_add_timeout(srvctx, SRV_MSEC(cand->timeout), plink_timer, cand); plink_frame_tx(cand, PLINK_OPEN, 0); break; } reason = htole16(MESH_MAX_RETRIES); /* fall through on else */ case PLINK_CNF_RCVD: /* confirm timer */ if (!reason) reason = htole16(MESH_CONFIRM_TIMEOUT); set_link_state(cand, PLINK_HOLDING); cand->t2 = srv_add_timeout(srvctx, SRV_MSEC(cand->conf->holding_timeout_ms), plink_timer, cand); plink_frame_tx(cand, PLINK_CLOSE, reason); break; case PLINK_HOLDING: /* holding timer */ fsm_restart(cand); break; case PLINK_ESTAB: /* nothing to do */ break; default: sae_debug(AMPE_DEBUG_FSM, "Timeout for peer " MACSTR " in state %d\n", MAC2STR(cand->peer_mac), cand->link_state); break; } }
static void plink_timer(void *data) { le16 reason; struct candidate *cand; cand = (struct candidate *)data; assert(cand); sae_debug( AMPE_DEBUG_FSM, "Mesh plink timer for " MACSTR " fired on state %s\n", MAC2STR(cand->peer_mac), mpl_states[(cand->link_state > PLINK_BLOCKED) ? PLINK_UNDEFINED : cand->link_state]); reason = 0; switch (cand->link_state) { case PLINK_OPN_RCVD: case PLINK_OPN_SNT: /* retry timer */ sae_debug( AMPE_DEBUG_FSM, "Mesh plink:retries %d of %d\n", cand->retries, cand->conf->max_retries); if (cand->retries < cand->conf->max_retries) { cand->timeout = cand->conf->retry_timeout_ms; sae_debug( AMPE_DEBUG_FSM, "Mesh plink for " MACSTR " (retry, timeout): %d %d\n", MAC2STR(cand->peer_mac), cand->retries, cand->timeout); ++cand->retries; cb->evl->rem_timeout(cand->t2); cand->t2 = cb->evl->add_timeout(SRV_MSEC(cand->timeout), plink_timer, cand); plink_frame_tx(cand, PLINK_OPEN, 0); break; } reason = MESH_MAX_RETRIES; /* no break / fall through on else */ case PLINK_CNF_RCVD: /* confirm timer */ if (!reason) reason = MESH_CONFIRM_TIMEOUT; set_link_state(cand, PLINK_HOLDING); cb->evl->rem_timeout(cand->t2); cand->t2 = cb->evl->add_timeout( SRV_MSEC(cand->conf->holding_timeout_ms), plink_timer, cand); plink_frame_tx(cand, PLINK_CLOSE, reason); break; case PLINK_HOLDING: /* holding timer */ fsm_restart(cand); break; case PLINK_ESTAB: /* nothing to do */ break; default: sae_debug( AMPE_DEBUG_FSM, "Timeout for peer " MACSTR " in state %d\n", MAC2STR(cand->peer_mac), cand->link_state); break; } }