summaryrefslogtreecommitdiff
path: root/cesar/cp/eoc/multi_sta/action/src/multi_sta_action.c
diff options
context:
space:
mode:
Diffstat (limited to 'cesar/cp/eoc/multi_sta/action/src/multi_sta_action.c')
-rw-r--r--cesar/cp/eoc/multi_sta/action/src/multi_sta_action.c441
1 files changed, 441 insertions, 0 deletions
diff --git a/cesar/cp/eoc/multi_sta/action/src/multi_sta_action.c b/cesar/cp/eoc/multi_sta/action/src/multi_sta_action.c
new file mode 100644
index 0000000000..1fd85ca269
--- /dev/null
+++ b/cesar/cp/eoc/multi_sta/action/src/multi_sta_action.c
@@ -0,0 +1,441 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2009 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file cp/eoc/multi_sta/action/src/multi_sta_action.c
+ * \brief multi_sta Action functions.
+ * \ingroup cp_multista_action
+ *
+ */
+
+#include "common/std.h"
+
+/* Private headers. */
+#include "cp/inc/context.h"
+ /* TODO: "cl_eoc_mactotei_entry_insert" should not be called.
+ * It's a private function.*/
+#include "cl/inc/context.h"
+#include "cp/eoc/multi_sta_fsm/inc/tables.h"
+#include "cp/eoc/inc/dbg_print.h"
+
+/* Public headers. */
+#include "cp/eoc/cco/action/vs_eoc_master.h"
+#include "cp/eoc/multi_sta/action/multi_sta_action.h"
+#include "cp/eoc/multi_sta_fsm/fsm.h"
+
+/* Config headers. */
+#include "config/cp/eoc/multi/sta/wl/allowed.h"
+#include "config/cl/eoc.h"
+
+
+/**
+ * manage association of a station.
+ * \param ctx the module context.
+ * \param assoc_req CM_ASSOC.REQ MME msg having being received
+ */
+
+#define _BRANCH(state, event, to) \
+ ((CP_EOC_MULTI_STA_FSM_STATE_ ## state) << 16 \
+ | (CP_EOC_MULTI_STA_FSM_EVENT_TYPE_ ## event) << 8 \
+ | (CP_EOC_MULTI_STA_FSM_STATE_ ## to))
+
+static void
+cp_eoc_multi_sta_action__assoc_req_common (cp_t *ctx, cp_mme_rx_t *mme)
+{
+ cp_eoc_multi_sta_fsm_event_t event;
+ cp_net_t *net;
+ cp_tei_t tei = MAC_TEI_UNASSOCIATED;
+ cp_msg_cc_assoc_cnf_t cnf;
+ cp_sta_t *sta;
+ bool added;
+ mfs_tx_t *mfs;
+
+ dbg_assert (ctx);
+ dbg_assert (mme);
+
+ /* Add the station to the AVLN. */
+ net = cp_sta_mgr_get_our_avln (ctx);
+
+ cnf.nid = cp_net_get_nid (ctx, net);
+ cnf.snid = cp_net_get_snid (ctx, net);
+
+ sta = cp_sta_mgr_sta_get_from_mac (ctx, mme->peer.mac);
+
+#if CONFIG_CP_EOC_MULTI_STA_WL_ALLOWED
+ cp_sta_own_data_t *own = cp_sta_mgr_get_sta_own_data (ctx);
+
+ /* The station already exists get the TEI. */
+ if (sta)
+ tei = cp_sta_get_tei (sta);
+
+ /* Check the White List restriction. */
+ if ((MAC_TEI_IS_STA (tei)) && (sta->multi_sta.allowed == true)
+ && (sta->multi_sta.to_leave == false))
+ {
+ cnf.result = ctx->cco_action.wl_accept_all ?
+ CP_MSG_CC_ASSOC_CNF_RESULT_SUCCESS_WL_ACCEPT_ALL
+ : CP_MSG_CC_ASSOC_CNF_RESULT_SUCCESS;
+ cnf.lease_time_min = CP_LEASE_ASSOC_MIN;
+ }
+ else
+ {
+ cnf.result = ctx->cco_action.wl_complete ?
+ CP_MSG_CC_ASSOC_CNF_RESULT_FAILURE_PERMANANT_RESSOURCE_EXHAUSTION :
+ CP_MSG_CC_ASSOC_CNF_RESULT_FAILURE_TEMPORARY_RESSOURCE_EXHAUSTION;
+ own->num_bad_assoc_failure ++;
+ }
+#else
+ /* The station already exists get the TEI. */
+ if (sta)
+ tei = cp_sta_get_tei (sta);
+
+ if (MAC_TEI_IS_STA (tei))
+ {
+ cnf.result = CP_MSG_CC_ASSOC_CNF_RESULT_SUCCESS;
+ cnf.lease_time_min = CP_LEASE_ASSOC_MIN;
+ }
+ else
+ {
+ cnf.result = ctx->cco_action.wl_complete ?
+ CP_MSG_CC_ASSOC_CNF_RESULT_FAILURE_PERMANANT_RESSOURCE_EXHAUSTION :
+ CP_MSG_CC_ASSOC_CNF_RESULT_FAILURE_TEMPORARY_RESSOURCE_EXHAUSTION;
+ }
+#endif /* CONFIG_CP_EOC_MULTI_STA_WL_ALLOWED */
+
+ /* Send the answer. */
+ cnf.sta_tei = tei;
+
+ /* find and change properly */
+ mme->peer.tei = MAC_TEI_BCAST;
+
+#if CONFIG_CP_EOC_MULTI_STA_WL_ALLOWED
+ /* Check allowed field. */
+ if ((MAC_TEI_IS_STA (tei)) && (sta->multi_sta.allowed == true))
+ {
+ if (sta->multi_sta.to_leave == false)
+ {
+ CP_TRACE (MULTI_STA_ASSOC, TRACE_U64 (mme->peer.mac), tei);
+ cp_msg_cc_assoc_cnf_send (ctx, &mme->peer, &cnf);
+
+ mfs = mac_store_mfs_add_tx (
+ ctx->mac_store, false, true, MAC_LID_NONE, tei, &added);
+ if (added)
+ sar_mfs_add (ctx->sar, (mfs_t *)mfs);
+ if (mfs)
+ blk_release (mfs);
+
+ /* Branch */
+ cp_eoc_multi_sta_fsm_event_t *e = &event;
+ cp_eoc_multi_sta_fsm_event_new (
+ ctx, CP_EOC_MULTI_STA_FSM_EVENT_TYPE_CC_ASSOC_REQ, e);
+
+ sta->fsm.handled_event = e;
+
+ /*sta in the white list*/
+ if (sta->fsm.state == CP_EOC_MULTI_STA_FSM_STATE_disconnected)
+ {
+ cp_eoc_multi_sta_fsm_branch_ (
+ ctx,
+ _BRANCH (disconnected, CC_ASSOC_REQ, associated),
+ sta);
+ sta->associated_date_ms = cp_sta_core_get_date_ms (ctx);
+ DBG_PRINT_2 ("sta: dsc->asc, tei=%d", tei);
+ }
+ else if (sta->fsm.state
+ == CP_EOC_MULTI_STA_FSM_STATE_unassociated)
+ {
+ cp_eoc_multi_sta_fsm_branch_ (
+ ctx,
+ _BRANCH (unassociated, CC_ASSOC_REQ, associated),
+ sta);
+ sta->associated_date_ms = cp_sta_core_get_date_ms (ctx);
+ DBG_PRINT_2 ("sta: una->asc, tei=%d", tei);
+ }
+
+ slab_release (sta);
+ }
+ }
+ /* Sta not registered or not in the white list. */
+ else
+ {
+ cp_eoc_multi_sta_fsm_event_t *e = &event;
+ cp_eoc_multi_sta_fsm_event_new (
+ ctx, CP_EOC_MULTI_STA_FSM_EVENT_TYPE_CC_ASSOC_REQ, e);
+ sta->fsm.handled_event = e;
+ cp_msg_cc_assoc_cnf_send (ctx, &mme->peer, &cnf);
+ if (sta->fsm.state == CP_EOC_MULTI_STA_FSM_STATE_disconnected)
+ {
+ cp_eoc_multi_sta_fsm_branch_ (
+ ctx,
+ _BRANCH (disconnected, CC_ASSOC_REQ, unassociated),
+ sta);
+ DBG_PRINT_2 ("sta: dsc->una, tei=%d", tei);
+ }
+ else if (sta->fsm.state
+ == CP_EOC_MULTI_STA_FSM_STATE_unassociated)
+ {
+ DBG_PRINT_2 ("sta: una, tei=%d", tei);
+ sta->fsm.handled_event = NULL;
+ }
+
+ slab_release (sta);
+ }
+#else
+ if (tei)
+ {
+ cp_sta_mgr_commit_to_dataplane (ctx);
+ /* Update the last request date in the sta. */
+ CP_TRACE (MULTI_STA_ASSOC, TRACE_U64 (mme->peer.mac), tei);
+ cp_msg_cc_assoc_cnf_send (ctx, &mme->peer, &cnf);
+
+ mfs = mac_store_mfs_add_tx (ctx->mac_store, false, true,
+ MAC_LID_NONE, tei, &added);
+ if (added)
+ sar_mfs_add (ctx->sar, (mfs_t *)mfs);
+ if (mfs)
+ blk_release (mfs);
+ /* Branch. */
+ cp_eoc_multi_sta_fsm_event_t *e = &event;
+ cp_eoc_multi_sta_fsm_event_new (
+ ctx, CP_EOC_MULTI_STA_FSM_EVENT_TYPE_CC_ASSOC_REQ, e);
+
+ sta->fsm.handled_event = e;
+
+ /* Sta in the white list. */
+ cp_eoc_multi_sta_fsm_branch_ (
+ ctx, _BRANCH (disconnected, CC_ASSOC_REQ, associated), sta);
+ slab_release (sta);
+
+ }
+ /* Check allowed field as well for WL implementation. */
+ if (!tei)
+ {
+ sta = cp_sta_mgr_sta_add (ctx, net, 0, mme->peer.mac);
+
+ cp_eoc_multi_sta_fsm_event_t *e = &event;
+ cp_eoc_multi_sta_fsm_event_new (
+ ctx, CP_EOC_MULTI_STA_FSM_EVENT_TYPE_CC_ASSOC_REQ, e);
+
+ sta->fsm.handled_event = e;
+
+ /* Sta not in the white list. */
+ cp_eoc_multi_sta_fsm_branch_
+ (ctx, _BRANCH (disconnected, CC_ASSOC_REQ, unassociated), sta);
+
+ slab_release (sta);
+ }
+#endif /* CONFIG_CP_EOC_MULTI_STA_WL_ALLOWED */
+}
+
+void
+cp_eoc_multi_sta_action__assoc_req (cp_t *ctx, cp_mme_rx_t *mme)
+{
+ cp_msg_cc_assoc_req_t assoc;
+
+ dbg_assert_ptr (ctx);
+ dbg_assert_ptr (mme);
+
+ cp_sta_t *sta;
+ cp_tei_t tei = MAC_TEI_UNASSOCIATED;
+
+ /* TODO take in consideration request type, is it new or renew*/
+ if (cp_msg_cc_assoc_req_receive (ctx, mme, &assoc))
+ {
+ cp_eoc_multi_sta_action__assoc_req_common (ctx, mme);
+ }
+ else
+ {
+ sta = cp_sta_mgr_sta_get_from_mac (ctx, mme->peer.mac);
+ tei = cp_sta_get_tei (sta);
+ sta->fsm.handled_event = NULL;
+ DBG_PRINT_2 ("wrong assoc_req, tei=%d", tei);
+ slab_release (sta);
+ }
+}
+
+void
+cp_eoc_multi_sta_action__get_key_req (cp_t *ctx, cp_mme_rx_t *mme)
+{
+ cp_eoc_cco_action__cco__cm_get_key_req_pid0 (ctx, mme);
+}
+
+void
+cp_eoc_cco_action__cco__cm_get_key_req_pid0 (
+ cp_t *ctx, cp_mme_rx_t * get_key_req)
+{
+ cp_eoc_multi_sta_fsm_event_t event;
+ cp_msg_cm_get_key_req_t req;
+ cp_msg_cm_get_key_cnf_t cnf;
+ cp_net_t *net = NULL;
+ cp_sta_t *sta = NULL;
+ bool added, acceptable = false;
+ mfs_tx_t *mfs;
+
+ dbg_assert (ctx);
+ dbg_assert (get_key_req);
+
+ if (cp_msg_cm_get_key_req_receive (ctx, get_key_req, &req)
+ && cp_secu_protocol_check (NULL, &get_key_req->prun,
+ CP_SECU_PROTOCOL_RUN_CHECK_RESULT_NEW)
+ && MAC_TEI_IS_STA (get_key_req->peer.tei))
+ acceptable = true;
+
+ /* Get the data in the payload of the mme. */
+ if (acceptable)
+ {
+ if (req.key_type == CP_MSG_KEY_NEK)
+ {
+ /* Get the network. */
+ net = cp_sta_mgr_get_our_avln (ctx);
+ /* Get the station. */
+ sta = cp_sta_mgr_sta_get_assoc (ctx, net, get_key_req->peer.tei);
+
+ if (sta)
+ {
+ cnf.result = CP_MSG_CM_GET_KEY_CNF_RESULT_KEY_GRANTED;
+ cp_sta_set_assoc_confirmed (ctx, sta, true);
+ sta->fsm.handled_event = NULL;
+
+ /* All keys granted. */
+ uint i;
+
+ mac_nek_t *nek = bsu_nek_get_current (ctx->bsu);
+ cnf.eks = nek->eks;
+ for (i = 0; i < COUNT (nek->nek_enc); i++)
+ cnf.key.key[i] = nek->nek_enc[i];
+
+ for (i = 0; i < MAC_CAP_NB; i++)
+ {
+ mfs = mac_store_mfs_add_tx (
+ ctx->mac_store, false, false, MAC_LLID_MIN + i,
+ get_key_req->peer.tei, &added);
+ if (added)
+ sar_mfs_add (ctx->sar, (mfs_t *)mfs);
+ if (mfs)
+ {
+ mfs->cap = i;
+ blk_release (mfs);
+ }
+ }
+
+ /* Send the TEI map: Not needed in EoC. */
+ slab_release (sta);
+ }
+ else
+ {
+ cnf.result = CP_MSG_CM_GET_KEY_CNF_RESULT_REQUEST_REFUSED;
+
+ sta = cp_sta_mgr_sta_get_from_mac (ctx,
+ get_key_req->peer.mac);
+ if (sta)
+ {
+ sta->fsm.handled_event = NULL;
+ DBG_PRINT_2 ("not auth, all keys not granted, tei=%d",
+ get_key_req->peer.tei);
+ slab_release (sta);
+ }
+ }
+ cp_secu_protocol_next (&get_key_req->prun, &ctx->rnd, false);
+ } /* Use it to ack previous neck key. */
+ else if (req.key_type == CP_MSG_KEY_TEK)
+ {
+ uint i;
+
+ mac_nek_t *nek = bsu_nek_get_current (ctx->bsu);
+ cnf.eks = nek->eks;
+ for (i = 0; i < COUNT (nek->nek_enc); i++)
+ cnf.key.key[i] = nek->nek_enc[i];
+
+ /* Get the network. */
+ net = cp_sta_mgr_get_our_avln (ctx);
+ /* Get the station. */
+ sta = cp_sta_mgr_sta_get_assoc (ctx, net, get_key_req->peer.tei);
+
+ if (sta)
+ {
+ cnf.result = CP_MSG_CM_GET_KEY_CNF_RESULT_KEY_GRANTED;
+ cp_sta_set_authenticated (ctx, sta, true);
+
+ cp_eoc_multi_sta_fsm_event_t *e = &event;
+ cp_eoc_multi_sta_fsm_event_new (
+ ctx, CP_EOC_MULTI_STA_FSM_EVENT_TYPE_CC_GET_KEY_REQ, e);
+
+ sta->fsm.handled_event = e;
+
+ /* all keys granted*/
+ cp_eoc_multi_sta_fsm_branch_ (
+ ctx,
+ _BRANCH (associated, CC_GET_KEY_REQ, authenticated),
+ sta);
+
+ sta->authenticated_to_unassociated = true;
+#if CONFIG_CL_EOC_ROUTE
+ arch_dsr_lock ();
+ added = cl_eoc_mactotei_entry_insert (
+ ctx->cl, get_key_req->peer.mac, get_key_req->peer.tei);
+ arch_dsr_unlock ();
+ dbg_assert (added);
+#endif
+ slab_release (sta);
+ }
+ cp_secu_protocol_next (&get_key_req->prun, &ctx->rnd, true);
+ }
+ }
+ /* Refuse the request. */
+ else
+ {
+ cnf.result = CP_MSG_CM_GET_KEY_CNF_RESULT_REQUEST_REFUSED;
+
+ sta = cp_sta_mgr_sta_get_from_mac (ctx, get_key_req->peer.mac);
+ if (sta)
+ {
+ sta->fsm.handled_event = NULL;
+ DBG_PRINT_2 ("not auth, all keys not granted, tei=%d",
+ get_key_req->peer.tei);
+ slab_release (sta);
+ }
+ }
+
+ /* Send message to peer. Mark station authenticated. */
+ cnf.key_type = req.key_type;
+ cnf.nid = req.nid;
+ cp_msg_cm_get_key_cnf_send (ctx, &get_key_req->peer, get_key_req->peks,
+ &get_key_req->prun, &cnf);
+
+ if ((req.key_type == CP_MSG_KEY_TEK)
+ && (cnf.result == CP_MSG_CM_GET_KEY_CNF_RESULT_KEY_GRANTED))
+ {
+ cp_eoc_cco_action_vs__cco__vs_set_out_lev_ind (
+ ctx, &get_key_req->peer);
+ DBG_PRINT_2 ("sta: auth, tei=%d", get_key_req->peer.tei);
+ cp_sta_own_data_t *own = cp_sta_mgr_get_sta_own_data (ctx);
+ own->num_good_assoc_auth ++;
+ }
+}
+
+void
+cp_eoc_multi_sta_action_put_sta_unassociated (cp_t *ctx, cp_sta_t *station)
+{
+ dbg_assert (ctx);
+ dbg_assert (station);
+
+ station->fsm.state = CP_EOC_MULTI_STA_FSM_STATE_unassociated;
+}
+
+cp_tei_t
+cp_eoc_multi_sta_action_compute_tei (cp_t *ctx)
+{
+ static uint tei = MAC_TEI_STA_MIN_EOC - 1;
+
+ tei ++;
+ if (tei <= MAC_TEI_STA_MAX)
+ return tei;
+ else
+ return MAC_TEI_UNASSOCIATED;
+}
+
+#undef _BRANCH