/* Cesar project {{{ * * Copyright (C) 2009 Spidcom * * <<>> * * }}} */ /** * \file cp/av/sta/action/src/handover.c * \brief Handover functions. * \ingroup cp_av_sta_action * */ #include "common/std.h" #include "cp/sta/mgr/sta_mgr.h" #include "cp/sta/core/core.h" #include "cp/msg/msg.h" #include "cp/fsm/fsm.h" #include "cp/defs.h" #include "cp/inc/context.h" #include "cp/cco/action/cco_action.h" #include "cp/sta/action/inc/context.h" #include "cp/av/sta/action/handover.h" #include "cp/av/sta/action/assoc.h" #include "cp/av/beacon/beacon.h" #include "cp/av/cco/action/cco_action.h" void cp_av_sta_action_handover__handover (cp_t *ctx, cp_mme_rx_t *mme) { cp_net_t *net; cp_sta_t *sta; dbg_assert (ctx); dbg_assert (mme); net = cp_sta_mgr_get_our_avln (ctx); sta = cp_sta_mgr_sta_add (ctx, net, mme->peer.tei, mme->peer.mac); cp_sta_set_authenticated (ctx, sta, true); cp_net_set_cco (ctx, net, mme->peer.tei); slab_release (sta); cp_fsm_trigger_new_event (ctx, mme, STA_HANDOVER_START, mme); } void cp_av_sta_action_handover__start (cp_t *ctx, cp_mme_rx_t *mme) { cp_msg_cc_handover_req_soft_hard_t soft_hard = 0; cp_msg_cc_handover_req_reason_t reason = 0; cp_msg_cc_handover_cnf_result_t result = 0; cp_sta_own_data_t *own = NULL; dbg_assert (ctx); dbg_assert (mme); if (cp_msg_cc_handover_req_receive (ctx, mme, &soft_hard, &reason)) { if ((soft_hard == CP_MSG_CC_HANDOVER_REQ_HANDOVER_SOFT) && (CP_CCO_LEVEL == 0)) { result = CP_MSG_CC_HANDOVER_CNF_RESULT_REJECT_SOFT_HANDOVER; } else if (soft_hard == CP_MSG_CC_HANDOVER_REQ_HANDOVER_HARD) { /* Store in the context. */ switch (reason) { case CP_MSG_CC_HANDOVER_REQ_REASON_CCO_LEAVING: ctx->handover.reason = CP_HANDOVER_REASON_CCO_LEAVING; break; case CP_MSG_CC_HANDOVER_REQ_REASON_USER_APPOINT: ctx->handover.reason = CP_HANDOVER_REASON_USER_APPOINT; break; case CP_MSG_CC_HANDOVER_REQ_REASON_CCO_SELECTION: ctx->handover.reason = CP_HANDOVER_REASON_CCO_SELECTION; break; default: dbg_assert_default (); } /* Go to the handover hard branch. */ result = CP_MSG_CC_HANDOVER_CNF_RESULT_ACCEPT; if (reason != CP_MSG_CC_HANDOVER_REQ_REASON_USER_APPOINT) { cp_fsm_event_t *event; cp_fsm_branch (ctx, STA_HANDOVER_IDLE, STA_HANDOVER_START, hard); /* Program the timer for the timeout. */ event = cp_fsm_event_bare_new (ctx, CP_FSM_EVENT_TYPE_HANDOVER_TIMEOUT); cp_sta_core_gen_timed_event (ctx, &ctx->handover.handover_timeout, event, CP_TIMEOUT_MS); } else { own = cp_sta_mgr_get_sta_own_data (ctx); own->cco_prefered = true; } } cp_msg_cc_handover_cnf_send (ctx, &mme->peer, result); } else { cp_msg_cc_handover_cnf_send (ctx, &mme->peer, CP_MSG_CC_HANDOVER_CNF_RESULT_REJECT_ANY_HANDOVER); } } void cp_av_sta_action_handover__handover_info_ind_receive (cp_t *ctx, cp_mme_rx_t *mme) { cp_msg_cc_handover_info_ind_rsc_t rsc; cp_tei_t bcco; uint num_sta; bool res; dbg_assert (ctx); dbg_assert (mme); cp_sta_core_stop_timed_or_cyclic_event (ctx, &ctx->handover.handover_timeout); res = cp_msg_cc_handover_info_ind_receive_begin (ctx, mme, &rsc, &bcco, &num_sta); if (res && (rsc == CP_MSG_CC_HANDOVER_INFO_IND_RSC_HOIP)) { cp_tei_t tei; mac_t mac_addr; uint status; cp_tei_t ptei; cp_sta_t *sta; cp_net_t *net; net = cp_sta_mgr_get_our_avln (ctx); /* TODO: Store the backup CCO. */ for (; num_sta; num_sta --) { res = cp_msg_cc_handover_info_ind_receive (ctx, mme, &tei, &mac_addr, &status, &ptei); if (res) { sta = cp_sta_mgr_sta_add (ctx, net, tei, mac_addr); cp_sta_set_authenticated (ctx, sta, status); sta->pco = ptei; sta->tei_lease_date_ms = cp_sta_core_get_date_ms (ctx) + MAC_SEC_TO_MS ( ctx->cco_action.tei_lease_association_min * 60); cp_av_cco_action_tei_in_use (ctx, tei); slab_release (sta); } } res = cp_msg_cc_handover_info_ind_receive_end (ctx, mme); if (res) { cp_av_cco_action_tei_in_use (ctx, cp_sta_own_data_get_tei (ctx)); /* Send the confirmation. */ cp_msg_cc_handover_info_rsp_send (ctx, &mme->peer); } } } void cp_av_sta_action_handover__handover_ended (cp_t *ctx) { cp_net_t *net; cp_sta_t *old_cco; dbg_assert (ctx); net = cp_sta_mgr_get_our_avln (ctx); old_cco = cp_net_get_cco (ctx, net); cp_net_set_cco (ctx, net, MAC_TEI_UNASSOCIATED); /* Reset the handover flag in the central beacon. */ cp_av_beacon_handover_hoipflag (ctx, CP_BEACON_HOIP_FALSE); cp_av_cco_action_cco__assoc_start (ctx); /* Stop the lease timer. */ cp_sta_core_stop_timed_or_cyclic_event (ctx, &ctx->sta_action.assoc.lease_timer); if (ctx->handover.reason == CP_HANDOVER_REASON_CCO_LEAVING) { cp_av_cco_action_cco_sta_leave_send_tei_map (ctx, old_cco); cp_sta_mgr_release_station (ctx, cp_sta_get_tei (old_cco)); } cp_fsm_trigger_new_event (ctx, bare, HANDOVER_SUCCESS); slab_release (old_cco); } void cp_av_sta_action_handover__sta_handover (cp_t *ctx, cp_net_t *net, cp_sta_t *sta) { dbg_assert (ctx); dbg_assert (net); if (sta) { cp_beacon_update_tracking (ctx, sta); cp_av_sta_action_assoc__authenticated__renew (ctx); } } void cp_av_sta_action_handover__failure (cp_t *ctx) { dbg_assert (ctx); /* cancel the timer. */ cp_sta_core_stop_timed_or_cyclic_event (ctx, &ctx->handover.handover_timeout); cp_fsm_trigger_new_event (ctx, bare, HANDOVER_FAILURE); }