/* Cesar project {{{ * * Copyright (C) 2008 Spidcom * * <<>> * * }}} */ /** * \file cp/msg/src/msg.c * \brief MSG functions. * \ingroup cp_msg * */ #include "common/std.h" #include "common/defs/spidcom.h" #include "lib/swap.h" #include "lib/crc.h" #include "lib/rnd.h" #include "lib/trace.h" #include "common/defs/homeplugAV.h" #include "common/defs/ethernet.h" #include "cp/cp.h" #include "cp/msg/msg.h" #include "cp/cl_interf/cl_interf.h" #include "cp/sta/mgr/sta_mgr.h" #include "cp/sta/mgr/sta_own_data.h" #include "cp/secu/defs.h" #include "cp/fsm/forward.h" #include "cp/sta/core/core.h" #include "cp/msg/inc/msg.h" #include "cp/inc/context.h" #include "cp/inc/trace.h" #include "cp/msg/inc/allowed_mme.h" #if CONFIG_CP_EOC #include "config/cp/msg/eoc/multi/sta/mme.h" #include "config/cp/msg/eoc.h" #endif /* CONFIG_CP_EOC */ #include /** * Name of the event when there is no event. */ #define NO_EVENT NB /** * Handy macro to fill the allowed MMEs table. * \param mmtype the MMType of the MME. It must corresponds to the suffix of * the CP FSM event name! * \param min_sta_status the status of our STA we at least need to have * (i.e.: associated) to allow this MME. See cp_msg_mme_sta_status_t. * \param encrypted true if the MME must be encrypted. * \param from_h1 true if the MME must come from the H1. * \param cp_fsm_event the CP FSM event to generate, or NO_EVENT if no event * need to be generated. */ #define CP_MSG_MME_ALLOWED_ENTRY(mmtype, min_sta_status, encrypted, from_h1, \ cp_fsm_event) \ { \ mmtype, \ PASTE (CP_MSG_MME_, min_sta_status), \ PASTE (CP_MSG_MME_, encrypted), \ PASTE (CP_MSG_MME_, from_h1), \ PASTE (CP_FSM_EVENT_TYPE_, cp_fsm_event), \ trace_do (# mmtype) \ } cp_msg_mme_allowed_t cp_msg_mme_allowed[] = { CP_MSG_MME_ALLOWED_ENTRY (CC_CCO_APPOINT_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_YES, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_CCO_APPOINT_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_YES, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_CCO_APPOINT_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_BACKUP_APPOINT_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_BACKUP_APPOINT_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_LINK_INFO_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_YES, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_LINK_INFO_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_LINK_INFO_IND, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_LINK_INFO_RSP, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_HANDOVER_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, CC_HANDOVER_REQ), CP_MSG_MME_ALLOWED_ENTRY (CC_HANDOVER_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, CC_HANDOVER_CNF), CP_MSG_MME_ALLOWED_ENTRY (CC_HANDOVER_INFO_IND, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, CC_HANDOVER_INFO_IND), CP_MSG_MME_ALLOWED_ENTRY (CC_HANDOVER_INFO_RSP, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, CC_HANDOVER_INFO_RSP), CP_MSG_MME_ALLOWED_ENTRY (CC_DISCOVER_LIST_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_YES, CC_DISCOVER_LIST_REQ), CP_MSG_MME_ALLOWED_ENTRY (CC_DISCOVER_LIST_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_DISCOVER_LIST_IND, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_LINK_NEW_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_LINK_NEW_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_LINK_MOD_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_LINK_MOD_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_LINK_SQZ_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_LINK_SQZ_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_LINK_REL_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_LINK_REL_IND, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_DETECT_REPORT_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_DETECT_REPORT_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), #if CONFIG_CP_EOC CP_MSG_MME_ALLOWED_ENTRY (CC_WHO_RU_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, CC_WHO_RU_REQ), CP_MSG_MME_ALLOWED_ENTRY (CC_WHO_RU_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, CC_WHO_RU_CNF), #if CONFIG_CP_MSG_EOC_MULTI_STA_MME CP_MSG_MME_ALLOWED_ENTRY (CC_ASSOC_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, MULTI_STA_MME), #else CP_MSG_MME_ALLOWED_ENTRY (CC_ASSOC_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, CC_ASSOC_REQ), #endif /* CONFIG_CP_MSG_EOC_MULTI_STA_MME */ #else /* CONFIG_CP_EOC */ CP_MSG_MME_ALLOWED_ENTRY (CC_WHO_RU_REQ, STA_ASSOC, NEK_ENC_NO, FROM_H1_YES, CC_WHO_RU_REQ), CP_MSG_MME_ALLOWED_ENTRY (CC_WHO_RU_CNF, STA_ASSOC, NEK_ENC_NO, FROM_H1_NO, CC_WHO_RU_CNF), CP_MSG_MME_ALLOWED_ENTRY (CC_ASSOC_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, CC_ASSOC_REQ), #endif /* CONFIG_CP_EOC */ CP_MSG_MME_ALLOWED_ENTRY (CC_ASSOC_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, CC_ASSOC_CNF), CP_MSG_MME_ALLOWED_ENTRY (CC_LEAVE_REQ, STA_ASSOC, NEK_ENC_NO, FROM_H1_NO, CC_LEAVE_REQ), CP_MSG_MME_ALLOWED_ENTRY (CC_LEAVE_CNF, STA_ASSOC, NEK_ENC_NO, FROM_H1_NO, CC_LEAVE_CNF), CP_MSG_MME_ALLOWED_ENTRY (CC_LEAVE_IND, STA_ASSOC, NEK_ENC_NO, FROM_H1_NO, CC_LEAVE_IND), CP_MSG_MME_ALLOWED_ENTRY (CC_LEAVE_RSP, STA_ASSOC, NEK_ENC_NO, FROM_H1_NO, CC_LEAVE_RSP), CP_MSG_MME_ALLOWED_ENTRY (CC_SET_TEI_MAP_REQ, STA_ASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_SET_TEI_MAP_IND, STA_ASSOC, NEK_ENC_NO, FROM_H1_NO, CC_SET_TEI_MAP_IND), CP_MSG_MME_ALLOWED_ENTRY (CC_RELAY_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, CC_RELAY_REQ), CP_MSG_MME_ALLOWED_ENTRY (CC_RELAY_IND, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, CC_RELAY_IND), CP_MSG_MME_ALLOWED_ENTRY (CC_BEACON_RELIABILITY_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_BEACON_RELIABILITY_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_ALLOC_MOVE_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_ALLOC_MOVE_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_ACCESS_NEW_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_ACCESS_NEW_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_ACCESS_NEW_IND, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_ACCESS_NEW_RSP, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_ACCESS_REL_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_ACCESS_REL_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_ACCESS_REL_IND, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_ACCESS_REL_RSP, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_DCPPC_IND, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_DCPPC_RSP, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_HP1_DET_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_HP1_DET_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CC_BLE_UPDATE_IND, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CP_PROXY_APPOINT_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CP_PROXY_APPOINT_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (PH_PROXY_APPOINT_IND, STA_AUTH, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CP_PROXY_WAKE_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (NN_INL_REQ, STA_AUTH, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (NN_INL_CNF, STA_AUTH, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (NN_NEW_NET_REQ, STA_AUTH, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (NN_NEW_NET_CNF, STA_AUTH, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (NN_NEW_NET_IND, STA_AUTH, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (NN_ADD_ALLOC_REQ, STA_AUTH, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (NN_ADD_ALLOC_CNF, STA_AUTH, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (NN_ADD_ALLOC_IND, STA_AUTH, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (NN_REL_ALLOC_REQ, STA_AUTH, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (NN_REL_ALLOC_CNF, STA_AUTH, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (NN_REL_NET_IND, STA_AUTH, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_UNASSOCIATED_STA_IND, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, CM_UNASSOCIATED_STA_IND), CP_MSG_MME_ALLOWED_ENTRY (CM_ENCRYPTED_PAYLOAD_IND, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_ENCRYPTED_PAYLOAD_RSP, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_SET_KEY_REQ, STA_ASSOC, NEK_ENC_YES, FROM_H1_YES, CM_SET_KEY_REQ), CP_MSG_MME_ALLOWED_ENTRY (CM_SET_KEY_CNF, STA_ASSOC, NEK_ENC_YES, FROM_H1_YES, CM_SET_KEY_CNF), #if CONFIG_CP_EOC #if CONFIG_CP_MSG_EOC_MULTI_STA_MME CP_MSG_MME_ALLOWED_ENTRY (CM_GET_KEY_REQ, STA_ASSOC, NEK_ENC_NO, FROM_H1_YES, MULTI_STA_MME), #else CP_MSG_MME_ALLOWED_ENTRY (CM_GET_KEY_REQ, STA_ASSOC, NEK_ENC_NO, FROM_H1_YES, CM_GET_KEY_REQ), #endif /* CONFIG_CP_MSG_EOC_MULTI_STA_MME */ #else /* CONFIG_CP_EOC */ CP_MSG_MME_ALLOWED_ENTRY (CM_GET_KEY_REQ, STA_ASSOC, NEK_ENC_NO, FROM_H1_YES, CM_GET_KEY_REQ), #endif /* CONFIG_CP_EOC */ CP_MSG_MME_ALLOWED_ENTRY (CM_GET_KEY_CNF, STA_ASSOC, NEK_ENC_NO, FROM_H1_YES, CM_GET_KEY_CNF), CP_MSG_MME_ALLOWED_ENTRY (CM_SC_JOIN_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, CM_SC_JOIN_REQ), CP_MSG_MME_ALLOWED_ENTRY (CM_SC_JOIN_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, CM_SC_JOIN_CNF), CP_MSG_MME_ALLOWED_ENTRY (CM_CHAN_EST_IND, STA_ASSOC, NEK_ENC_NO, FROM_H1_NO, CM_CHAN_EST_IND), CP_MSG_MME_ALLOWED_ENTRY (CM_TM_UPDATE_IND, STA_ASSOC, NEK_ENC_NO, FROM_H1_NO, CM_TM_UPDATE_IND), CP_MSG_MME_ALLOWED_ENTRY (CM_AMP_MAP_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_YES, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_AMP_MAP_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_BRG_INFO_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_YES, CM_BRG_INFO_REQ), CP_MSG_MME_ALLOWED_ENTRY (CM_BRG_INFO_CNF, STA_AUTH, NEK_ENC_NO, FROM_H1_NO, CM_BRG_INFO_CNF), CP_MSG_MME_ALLOWED_ENTRY (CM_CONN_NEW_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_CONN_NEW_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_CONN_REL_IND, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_CONN_REL_RSP, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_CONN_MOD_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_CONN_MOD_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_CONN_INFO_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_YES, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_CONN_INFO_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_STA_CAP_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, CM_STA_CAP_REQ), CP_MSG_MME_ALLOWED_ENTRY (CM_STA_CAP_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_NW_INFO_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_YES, CM_NW_INFO_REQ), CP_MSG_MME_ALLOWED_ENTRY (CM_NW_INFO_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_GET_BEACON_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_YES, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_GET_BEACON_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_HFID_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, CM_HFID_REQ), CP_MSG_MME_ALLOWED_ENTRY (CM_HFID_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, CM_HFID_CNF), CP_MSG_MME_ALLOWED_ENTRY (CM_MME_ERROR_IND, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, CM_MME_ERROR_IND), CP_MSG_MME_ALLOWED_ENTRY (CM_NW_STATS_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_YES, CM_NW_STATS_REQ), CP_MSG_MME_ALLOWED_ENTRY (CM_NW_STATS_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (CM_LINK_STATS_REQ, STA_AUTH, NEK_ENC_YES, FROM_H1_YES, CM_LINK_STATS_REQ), CP_MSG_MME_ALLOWED_ENTRY (CM_LINK_STATS_CNF, STA_AUTH, NEK_ENC_YES, FROM_H1_NO, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_GET_VERSION_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_GET_VERSION_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_RESET_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_RESET_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_GET_NVRAM_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_GET_NVRAM_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_GET_LOOPBACK_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_GET_LOOPBACK_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_SET_LOOPBACK_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_SET_LOOPBACK_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_GET_TONEMASK_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_GET_TONEMASK_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_GET_ETH_PHY_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_GET_ETH_PHY_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_ETH_STATS_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_ETH_STATS_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_GET_STATUS_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, NO_EVENT), // CP_MSG_MME_ALLOWED_ENTRY (VS_GET_STATUS_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (VS_GET_TONEMAP_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_GET_TONEMAP_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_GET_TONEMAP_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (VS_GET_SNR_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_GET_SNR_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_GET_SNR_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (VS_GET_SPECTRUM_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_GET_SPECTRUM_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_GET_SPECTRUM_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (VS_GET_LINK_STATS_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_GET_LINK_STATS_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_GET_LINK_STATS_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (VS_GET_AMP_MAP_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_GET_AMP_MAP_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_GET_AMP_MAP_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (VS_GET_STATS_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_GET_STATS_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_GET_STATS_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (VS_GET_CE_STATS_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_GET_CE_STATS_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_GET_CE_STATS_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), #if CONFIG_CP_EOC CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_GET_TOPO_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_EOC_GET_TOPO_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_GET_TOPO_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_CCO_SET_WL_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_EOC_CCO_SET_WL_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_CCO_SET_WL_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_CCO_GET_WL_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_EOC_CCO_GET_WL_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_CCO_GET_WL_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_CCO_SET_OUT_LEV_IND, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, VS_EOC_CCO_SET_OUT_LEV_IND), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_CCO_SET_SERVICES_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_EOC_CCO_SET_SERVICES_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_CCO_SET_SERVICES_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_CCO_GET_SERVICES_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_EOC_CCO_GET_SERVICES_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_CCO_GET_SERVICES_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_SET_PORTS_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_EOC_SET_PORTS_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_SET_PORTS_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_CCO_GET_PORTS_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_EOC_CCO_GET_PORTS_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_CCO_GET_PORTS_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_GET_INFO_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_EOC_GET_INFO_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_GET_INFO_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_DIAGNOSTIC_INFO_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_EOC_DIAGNOSTIC_INFO_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_DIAGNOSTIC_INFO_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_GET_REAL_TIME_STATISTICS_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_EOC_GET_REAL_TIME_STATISTICS_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_EOC_GET_REAL_TIME_STATISTICS_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), #endif /* CONFIG_CP_EOC */ CP_MSG_MME_ALLOWED_ENTRY (VS_GET_PB_STATS_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_GET_PB_STATS_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_GET_PB_STATS_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (VS_GET_MACTOTEI_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, VS_GET_MACTOTEI_REQ), CP_MSG_MME_ALLOWED_ENTRY (VS_GET_MACTOTEI_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (IMAC_GET_DISCOVER_LIST_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, IMAC_GET_DISCOVER_LIST_REQ), CP_MSG_MME_ALLOWED_ENTRY (IMAC_GET_DISCOVER_LIST_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_MAC_ADDR_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_SET_MAC_ADDR_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_MAC_ADDR_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_CCO_PREF_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_SET_CCO_PREF_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_CCO_PREF_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_WAS_CCO_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_SET_WAS_CCO_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_WAS_CCO_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_NPW_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_SET_NPW_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_NPW_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_DPW_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_SET_DPW_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_DPW_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_SL_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_SET_SL_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_SL_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_M_STA_HFID_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_SET_M_STA_HFID_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_M_STA_HFID_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_U_STA_HFID_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_SET_U_STA_HFID_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_U_STA_HFID_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_U_STA_HFID_IND, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_AVLN_HFID_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_SET_AVLN_HFID_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_AVLN_HFID_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_AVLN_HFID_IND, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_TONEMASK_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_SET_TONEMASK_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_TONEMASK_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_MAC_START_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_MAC_START_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_MAC_START_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_MAC_STOP_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_MAC_STOP_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_MAC_STOP_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SC_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_SC_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SC_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_STATUS_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_STATUS_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_STATUS_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_STATUS_IND, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_KEY_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_SET_KEY_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_KEY_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_KEY_IND, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_GET_KEY_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_GET_KEY_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_GET_KEY_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_DAK_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_SET_DAK_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_DAK_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_CONFIG_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_STA_SET_CONFIG_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_STA_SET_CONFIG_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_MCAST_SET_LIST_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_MCAST_SET_LIST_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_MCAST_SET_LIST_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), #if CONFIG_CP_EOC CP_MSG_MME_ALLOWED_ENTRY (DRV_EOC_STA_SET_SLAVE_CONFIG_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_EOC_STA_SET_SLAVE_CONFIG_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_EOC_STA_SET_SLAVE_CONFIG_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), CP_MSG_MME_ALLOWED_ENTRY (DRV_EOC_STA_SET_EOC_CONFIG_REQ, STA_UNASSOC, NEK_ENC_NO, FROM_H1_YES, DRV_EOC_STA_SET_EOC_CONFIG_REQ), CP_MSG_MME_ALLOWED_ENTRY (DRV_EOC_STA_SET_EOC_CONFIG_CNF, STA_UNASSOC, NEK_ENC_NO, FROM_H1_NO, NO_EVENT), #endif /* CONFIG_CP_EOC */ }; uint cp_msg_mme_allowed_count = COUNT (cp_msg_mme_allowed); /** Enum type for allowed MME error code. */ enum cp_msg_allowed_mme_t { /** MME Allowed. */ CP_MSG_ALLOWED_MME_OK, /** MME is not handled by CP. */ CP_MSG_ALLOWED_MME_NOT_HANDLED, /** MME not allowed to be received from the PHY. */ CP_MSG_ALLOWED_MME_PHY_NOT_ALLOWED, /** MME not allowed to be received from H1. */ CP_MSG_ALLOWED_MME_H1_NOT_ALLOWED, /** Station status is not sufficient, MME require a high level status * (Associated or Authenticated) and the station does not respect it. */ CP_MSG_ALLOWED_MME_STA_STATUS_NOK, /** The OUI embedded in the MME is not from SPiDCOM. */ CP_MSG_ALLOWED_MME_SPC_OUI_WRONG, /** Bad encryption key used, the STA is unable to decrypt it. */ CP_MSG_ALLOWED_MME_ENC_BAD, CP_MSG_ALLOWED_MME_NB }; /** * Increase the FMSN value for the next fragmented MME transaction. * \param ctx the module context. * * \warn fmsn with value 0 is forbidden. */ PRIVATE void cp_msg_mme_fmsn_increase (cp_msg_t *ctx) { /* fmsn is u8 */ ctx->fmsn = (ctx->fmsn + 1); if (ctx->fmsn == 0) ctx->fmsn = 1; } /** * Compute the header length of the MME fragmented or not. * \param msg the MME to send. * \return the header length. */ static inline uint cp_msg_mme_header_length (cp_mme_peer_t *peer, mmtype_t mmtype) { uint header_length = 0; dbg_assert (peer); header_length = HPAV_MME_HEADER; header_length += ETH_GET_VLANTAG_SIZE (peer->eth_type); /* If it's a Vendor Specific MME, so we have a OUI field added * See Page 576 of HomePlugAV spec , version 1.1, may 21 2007.*/ if (HPAV_MMTYPE_IS_VS (mmtype)) header_length += OUI_SIZE; return header_length; } /** * Compute the current length of the MME fragmented or not. * \param msg the MME to send. * \return the length. */ static inline uint cp_msg_mme_length (cp_mme_tx_t *mme) { uint mme_length; uint p_capability; uint h_size; dbg_assert (mme); h_size = cp_msg_mme_header_length (&mme->peer, mme->mmtype); if (HPAV_MMTYPE_IS_VS (mme->mmtype)) p_capability = HPAV_VS_MME_PAYLOAD_MAX; else p_capability = HPAV_MME_PAYLOAD_MAX_SIZE; mme_length = bitstream_bytes_processed (&mme->bitstream); dbg_assert (mme_length >= h_size); mme_length -= h_size; mme_length %= p_capability; mme_length += h_size; return mme_length; } /** Pad the MME to reach the minimal length. */ static void cp_msg_mme_pad (cp_t *ctx, cp_mme_tx_t *msg) { uint length; dbg_assert (ctx); dbg_assert (msg); for (length = cp_msg_mme_length (msg); length < ETH_PACKET_MIN_SIZE; length ++) { bitstream_write (&msg->bitstream, 0, 8); } } /** * Provide the key using the PEKS to select it. * \param ctx the module context. * \param peks the peks to use. * \return the key to encrypt or decrypt. * * If the peks points to an invalid value the function asserts. * PEKS_SPC_NOT_EMBEDDED is considered as a wrong value and causes an assert. */ static inline cp_key_t cp_msg_peks_key_get (cp_t *ctx, cp_mme_peks_t peks) { dbg_assert (ctx); dbg_assert (peks < CP_MME_PEKS_NONE); if (peks == CP_MME_PEKS_NMK) return cp_sta_own_data_get_nmk (ctx); else if ((peks >= CP_MME_PEKS_TEK_MIN) && (peks <= CP_MME_PEKS_TEK_MAX)) return cp_sta_own_data_get_tek (ctx); else if (peks == CP_MME_PEKS_DAK) return cp_sta_own_data_get_dak (ctx); else dbg_assert_default (); } #if CONFIG_CP_EOC #if CONFIG_CP_MSG_EOC_MULTI_STA_MME /** * Provide the key for the peer using the PEKS to select it. * \param ctx the module context. * \param peer the peer to communicate with. * \param peks the peks to use. * \return the key to encrypt or decrypt. * * If the peks points to an invalid value the function asserts. * PEKS_SPC_NOT_EMBEDDED is considered as a wrong value and causes an assert. */ static inline cp_key_t cp_msg_peer_peks_key_get (cp_t *ctx, cp_mme_peer_t peer, cp_mme_peks_t peks) { dbg_assert (ctx); dbg_assert (peks < CP_MME_PEKS_NONE); if (peks == CP_MME_PEKS_NMK) return cp_sta_own_data_get_nmk (ctx); else if ((peks >= CP_MME_PEKS_TEK_MIN) && (peks <= CP_MME_PEKS_TEK_MAX)) return cp_sta_own_data_get_tek (ctx); else if (peks == CP_MME_PEKS_DAK) { cp_key_t key = {{0, 0, 0, 0}}; cp_sta_t *dest = cp_sta_mgr_sta_get_from_mac (ctx, peer.mac); if (dest) { key = dest->multi_sta.dak; slab_release (dest); } return key; } else dbg_assert_default (); } #endif #endif void cp_msg_init (cp_t *ctx) { dbg_assert (ctx); slab_cache_init (&ctx->msg.mme_tx_slab_cache, "MME TX", sizeof (cp_mme_tx_t), (slab_object_destructor_t) cp_msg_mme_tx_destructor); slab_cache_init (&ctx->msg.mme_rx_slab_cache, "MME RX", sizeof (cp_mme_rx_t), (slab_object_destructor_t) cp_msg_mme_rx_destructor); ctx->msg.fmsn = 1; } void cp_msg_uninit (cp_t *ctx) { dbg_assert (ctx); slab_cache_uninit (&ctx->msg.mme_tx_slab_cache); slab_cache_uninit (&ctx->msg.mme_rx_slab_cache); } /** * Read the header of the encrypted MME. * \param ctx the module context. * \param mme the MME handler. * \return true on success. * * This function will verify if the encrypted payload is received as relayed * one, if it is the case it will check if the TEI is broadcast, if not it * will return false. */ PRIVATE bool cp_msg_dispatch__read_enc_header (cp_t *ctx, cp_mme_rx_t *mme) { /* If the MMe as been relayed the TEI shall be Broadcast one. */ if ((mme->relay.ftei != MAC_TEI_BCAST) && (mme->relay.mac_fa != 0x0)) { return false; } /* The MMe has not been relayed. */ else { return cp_msg_mme_read_header_enc (ctx, mme); } } /** * Verify if the MME is allowed to be sent by the peer station. * \param ctx the ctx module. * \param mme the mme context. * \param status_min the minimum status required to continue with the MME. * \param type the variable to store the FSM event type. * \return value code. */ static enum cp_msg_allowed_mme_t cp_msg_dispatch__allowed_mme (cp_t *ctx, cp_mme_rx_t *mme, enum cp_msg_mme_sta_status_t *status_min, cp_fsm_event_type_t *type) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (status_min); uint i; DICHOTOMY_SEARCH (0, cp_msg_mme_allowed_count, i, mme->mmtype <= cp_msg_mme_allowed[i].mmtype); if ((i < cp_msg_mme_allowed_count) && (mme->mmtype == cp_msg_mme_allowed[i].mmtype)) { *status_min = cp_msg_mme_allowed[i].min_sta_status; *type = cp_msg_mme_allowed[i].fsm_event; /* First case, MME comes from the PLC. */ if (mme->peer.tei != MAC_TEI_FOREIGN) { if ((cp_msg_mme_allowed[i].nek_encrypted <= mme->encrypt) && ((mme->encrypt == CP_MME_RX_NOT_ENCRYPTED) || (mme->encrypt == CP_MME_RX_SOFT_ENCRYPTED) || ((mme->encrypt == CP_MME_RX_NEK_ENCRYPTED) && (MAC_TEI_IS_STA(mme->peer.tei))))) return CP_MSG_ALLOWED_MME_OK; else return CP_MSG_ALLOWED_MME_PHY_NOT_ALLOWED; } /* Second case, MME comes from the H1. */ else if (mme->peer.tei == MAC_TEI_FOREIGN) { if (cp_msg_mme_allowed[i].from_h1) return CP_MSG_ALLOWED_MME_OK; else return CP_MSG_ALLOWED_MME_H1_NOT_ALLOWED; } } return CP_MSG_ALLOWED_MME_NOT_HANDLED; } /** * Has for job to verify the if our station have the minimal required status * to handle the MMe. * \param ctx the ctx module. * \param mme the mme context. * \param type the event FSM event type. * \return code value on cp_msg_allowed_mme_t type. */ static enum cp_msg_allowed_mme_t cp_msg_dispatch__allowed_mme_testing (cp_t *ctx, cp_mme_rx_t *mme, cp_fsm_event_type_t *type) { enum cp_msg_allowed_mme_t ok; enum cp_msg_mme_sta_status_t status_min; enum cp_msg_mme_sta_status_t sta_own_current_status; dbg_assert (ctx); dbg_assert (mme); dbg_assert (type); ok = cp_msg_dispatch__allowed_mme (ctx, mme, &status_min, type); if (ok == CP_MSG_ALLOWED_MME_OK && (mme->peer.tei != MAC_TEI_FOREIGN)) { if (cp_sta_own_data_get_authenticated_status (ctx)) sta_own_current_status = CP_MSG_MME_STA_AUTH; else if (cp_sta_own_data_get_tei (ctx)) sta_own_current_status = CP_MSG_MME_STA_ASSOC; else sta_own_current_status = CP_MSG_MME_STA_UNASSOC; ok = (sta_own_current_status >= status_min) ? CP_MSG_ALLOWED_MME_OK: CP_MSG_ALLOWED_MME_STA_STATUS_NOK; } return ok; } void cp_msg_dispatch (cp_t *ctx, cp_mme_rx_t *mme) { cp_fsm_event_t *event; cp_fsm_event_type_t type; enum cp_msg_allowed_mme_t ok; dbg_assert (ctx); dbg_assert (mme); cp_sta_core_checkpoint (ctx); /* If the MME is a vendor specific. */ if (mme->mmtype >= VS_MIN && mme->mmtype <= VS_MAX) { uint oui = bitstream_read (&mme->bitstream, OUI_SIZE_BITS); if (oui == SPC_OUI) ok = cp_msg_dispatch__allowed_mme_testing (ctx, mme, &type); else ok = CP_MSG_ALLOWED_MME_SPC_OUI_WRONG; } else ok = cp_msg_dispatch__allowed_mme_testing (ctx, mme, &type); if (ok == CP_MSG_ALLOWED_MME_OK) { /* If the MME is embedded in a CM_ENCRYPTED_PAYLOAD, it should * continue reading the MME to reach the embedded MME. By the same way * if the embedded MME is encrypted it decrypts it. */ if (mme->mmtype == CM_ENCRYPTED_PAYLOAD_IND) { if (cp_msg_dispatch__read_enc_header (ctx, mme)) { /* Test if the embedded MME is allowed to be received. */ mme->encrypt = CP_MME_RX_SOFT_ENCRYPTED; ok = cp_msg_dispatch__allowed_mme_testing (ctx, mme, &type); } else ok = CP_MSG_ALLOWED_MME_ENC_BAD; } if (ok == CP_MSG_ALLOWED_MME_OK && type < CP_FSM_EVENT_TYPE_NB) { CP_TRACE (MSG_DISPATCH, phy_date (), mme->mmtype, mme->peer.tei); event = cp_fsm_event_mme_new (ctx, type, mme); cp_fsm_post (ctx, event); } else { if (type == CP_FSM_EVENT_TYPE_NB && ok != CP_MSG_ALLOWED_MME_ENC_BAD) ok = CP_MSG_ALLOWED_MME_NOT_HANDLED; CP_TRACE (MSG_DISPATCH_DROP, phy_date (), mme->mmtype, mme->peer.tei, ok); } } else CP_TRACE (MSG_DISPATCH_DROP, phy_date (), mme->mmtype, mme->peer.tei, ok); slab_release (mme); } cp_mme_tx_t * cp_msg_mme_init (cp_t *ctx, cp_mme_peer_t *peer, mmtype_t mmtype, uint mme_payload_length) { cp_mme_tx_t *mme; uint p_capability; uint nf_mi; dbg_assert (ctx); dbg_assert (peer); /* Fragmentation Management Information – * 4 bits are Number of Fragments (NF_MI) of the MMENTRY * 0x00 = MMENTRY is not Fragmented * 0x01 = MMENTRY is Fragmented into two parts * 0x02 = MMENTRY is Fragmented into three parts, and so on **/ if (HPAV_MMTYPE_IS_VS(mmtype)) p_capability = HPAV_VS_MME_PAYLOAD_MAX; else p_capability = HPAV_MME_PAYLOAD_MAX_SIZE; nf_mi = mme_payload_length / p_capability; dbg_assert (nf_mi < HPAV_MME_FRAG_MAX); if (nf_mi == 0) mme = cp_msg_mme_init_not_frag (ctx, peer, mmtype); else { mme = cp_msg_mme_init_frag (ctx, peer, mmtype, nf_mi); dbg_assert (mme); bitstream_init_buffer_cb ( &mme->bitstream, (bitstream_buffer_cb_t) cp_msg_mme_tx_change_buffer, mme); } return mme; } cp_mme_tx_t * cp_msg_mme_init_not_frag (cp_t *ctx, cp_mme_peer_t *peer, mmtype_t mmtype) { cp_mme_tx_t *msg; uint eth_packet_size = ETH_PACKET_GET_MAX_SIZE (peer->eth_type); dbg_assert (ctx); dbg_assert (peer); // Allocate the new message. msg = cp_msg_mme_tx_init (ctx); dbg_assert (msg); // Get a buffer. msg->p_mme = cp_cl_interf_get_buffer_tx (ctx); msg->peer = *peer; msg->peks = CP_MME_PEKS_SPC_NOT_EMBEDDED; msg->mmtype = mmtype; msg->final_peer = *peer; // Initialise the bitstream context and fill the MME header. bitstream_write_init (&msg->bitstream, msg->p_mme, eth_packet_size); cp_msg_mme_write_frag_header (ctx, msg, &msg->bitstream, mmtype); return msg; } cp_mme_tx_t * cp_msg_mme_init_encrypted (cp_t *ctx, cp_mme_peer_t *peer, mmtype_t mmtype, cp_mme_peks_t peks, const cp_secu_protocol_run_t *prun) { cp_mme_tx_t *msg; uint eth_packet_size = ETH_PACKET_GET_MAX_SIZE (peer->eth_type); uint i; dbg_assert (ctx); dbg_assert (peer); dbg_assert (prun); dbg_assert (peks < CP_MME_PEKS_NB); // Initialise the message context. msg = cp_msg_mme_tx_init (ctx); dbg_assert (msg); // Get a buffer msg->p_mme = cp_cl_interf_get_buffer_tx (ctx); msg->peer = *peer; msg->peks = peks; msg->prun = *prun; msg->mmtype = mmtype; // Initialise the bitstream context and fill the MME header. bitstream_write_init (&msg->bitstream, msg->p_mme, eth_packet_size); cp_msg_mme_write_frag_header (ctx, msg, &msg->bitstream, CM_ENCRYPTED_PAYLOAD_IND); bitstream_write (&msg->bitstream, msg->peks, 8); // AVLN status. u8 status = CP_MSG_AVLN_STATUS_NB; if (cp_sta_own_data_get_cco_status (ctx)) status = CP_MSG_AVLN_STATUS_CCO; else if (!cp_sta_own_data_get_tei (ctx)) status = CP_MSG_AVLN_STATUS_UNASSOC_CCO_0 + CP_CCO_LEVEL; else if (cp_sta_own_data_get_pco_status(ctx) && cp_sta_own_data_get_tei(ctx)) status = CP_MSG_AVLN_STATUS_ASSOC_PCO; else if (!cp_sta_own_data_get_pco_status(ctx) && cp_sta_own_data_get_tei(ctx)) status = CP_MSG_AVLN_STATUS_ASSOC_NOT_PCO; dbg_assert (status < CP_MSG_AVLN_STATUS_NB); bitstream_write (&msg->bitstream, status, 8); bitstream_write (&msg->bitstream, msg->prun.pid, 8); bitstream_write (&msg->bitstream, msg->prun.prn, 16); bitstream_write (&msg->bitstream, msg->prun.pmn, 8); // IV or UUID. for (i = 0; i< 4; i++) { msg->iv_uuid.key[i] = lib_rnd32 (&ctx->rnd); bitstream_write (&msg->bitstream, msg->iv_uuid.key[i], 32); } // Length of the MME TO be patch at the end. bitstream_write (&msg->bitstream, 0, 16); // RFLen msg->rf_len = lib_rnd32 (&ctx->rnd) % 0xF; for (i = 0; i < msg->rf_len; i++) { bitstream_write (&msg->bitstream, lib_rnd32 (&ctx->rnd) & 0xff, 8); } // Compute the payload offset. msg->payload_offset = bitstream_bytes_processed (&msg->bitstream); // The payload cp_msg_mme_write_frag_header (ctx, msg, &msg->bitstream, mmtype); return msg; } /** * Fill the MME with the relay header and data. * \param ctx the ctx module. * \param bs the bitstream. * \param dpeer the destination peer. * \param final_peer the final destination peer. * \param fmi_nbFrag the number of fragments. * \param fmi_nb the fragment number. * \param fmi_fmsn the transaction number. */ PRIVATE void cp_msg_mme_write_relay_header (cp_t *ctx, bitstream_t *bs, cp_mme_peer_t dpeer, cp_mme_peer_t final_peer, uint fmi_nbFrag, uint fmi_nb, uint fmi_fmsn) { dbg_assert (ctx); dbg_assert (bs); dbg_assert (MAC_IS_VALID (dpeer.mac)); dbg_assert (MAC_TEI_IS_STA (dpeer.tei)); dbg_assert (MAC_IS_VALID (final_peer.mac)); dbg_assert (MAC_TEI_IS_STA (final_peer.tei)); /* Store the CC Relay data in the MME. */ bitstream_write_large (bs, dpeer.mac, BYTES_SIZE_TO_BITS (ETH_MAC_ADDRESS_SIZE)); bitstream_write_large (bs, cp_sta_own_data_get_mac_address (ctx), BYTES_SIZE_TO_BITS (ETH_MAC_ADDRESS_SIZE)); switch (dpeer.eth_type) { case HPAV_MTYPE_MME: /* Nothing to add */ break; case ETH_TYPE_VLAN: bitstream_write (bs, ETH_TYPE_VLAN, BYTES_SIZE_TO_BITS (ETH_TYPE_SIZE)); bitstream_write (bs, dpeer.vlan_tci, 16); break; default: /* Not managed */ dbg_assert_default (); break; } bitstream_write (bs, HPAV_MTYPE_MME, BYTES_SIZE_TO_BITS (HPAV_MTYPE_SIZE)); bitstream_write (bs, HPAV_MMV, BYTES_SIZE_TO_BITS (HPAV_MMV_SIZE)); bitstream_write (bs, CC_RELAY_REQ, BYTES_SIZE_TO_BITS (HPAV_MMTYPE_SIZE)); bitstream_write (bs, fmi_nbFrag, 4); bitstream_write (bs, fmi_nb, 4); bitstream_write (bs, fmi_fmsn, 8); /* Store the beginning of the CC RELAY MME.*/ bitstream_write_large (bs, final_peer.mac, BYTES_SIZE_TO_BITS (ETH_MAC_ADDRESS_SIZE)); bitstream_write (bs, final_peer.tei, 8); bitstream_write (bs, 0, 16); } /** * Fill the MME header with the relay data if the destination peer is hidden. * \param ctx the ctx module. * \param bs the bitstream. * \param msg the msg MME. */ PRIVATE void cp_msg_mme_write_relay (cp_t *ctx, bitstream_t *bs, cp_mme_tx_t *msg) { dbg_assert (ctx); dbg_assert (bs); dbg_assert (msg); msg->final_peer.mac = msg->peer.mac; msg->final_peer.tei = msg->peer.tei; msg->final_peer.eth_type = msg->peer.eth_type; msg->final_peer.vlan_tci = msg->peer.vlan_tci; /* If the our station is associated.*/ if (cp_sta_own_data_get_tei (ctx) != MAC_TEI_UNASSOCIATED && MAC_IS_VALID(msg->peer.mac)) { cp_sta_t *fdest; /* Try to get the final station. */ fdest = cp_sta_mgr_sta_get_from_mac (ctx, msg->peer.mac); /* If the final station is hidden, get the proxy one. */ if (fdest && MAC_TEI_IS_STA(fdest->pco) && (cp_sta_get_visible_status (fdest) == CP_STA_VISIBLE_STATE_HIDDEN)) { cp_sta_t *fdestpco; cp_net_t *our_net; our_net = cp_sta_mgr_get_our_avln (ctx); fdestpco = cp_sta_mgr_sta_get_assoc (ctx, our_net, fdest->pco); if (fdestpco) { msg->relay = true; cp_sta_get_peer (fdestpco, &msg->peer); cp_msg_mme_write_relay_header (ctx, bs, msg->peer, msg->final_peer, msg->fmi_nbfrag, msg->fmi_nb, msg->fmi_fmsn); slab_release (fdestpco); } } if (fdest) slab_release (fdest); } } void cp_msg_mme_write_frag_header (cp_t *ctx, cp_mme_tx_t *msg, bitstream_t *bs, mmtype_t mmtype) { dbg_assert (ctx); dbg_assert (msg); dbg_assert (bs); if (msg->relay) { cp_msg_mme_write_relay_header (ctx, bs, msg->peer, msg->final_peer, msg->fmi_nbfrag, msg->fmi_nb, msg->fmi_fmsn); } else { cp_msg_mme_write_relay (ctx, bs, msg); } bitstream_write_large (bs, msg->final_peer.mac, BYTES_SIZE_TO_BITS (ETH_MAC_ADDRESS_SIZE)); bitstream_write_large (bs, cp_sta_own_data_get_mac_address (ctx), BYTES_SIZE_TO_BITS (ETH_MAC_ADDRESS_SIZE)); if (ETH_IS_VLANTAG (msg->final_peer.eth_type)) { bitstream_write (bs, msg->final_peer.eth_type, BYTES_SIZE_TO_BITS (ETH_TYPE_SIZE)); bitstream_write (bs, msg->final_peer.vlan_tci, 16); } bitstream_write (bs, HPAV_MTYPE_MME, BYTES_SIZE_TO_BITS (HPAV_MTYPE_SIZE)); bitstream_write (bs, HPAV_MMV, BYTES_SIZE_TO_BITS (HPAV_MMV_SIZE)); bitstream_write (bs, mmtype, BYTES_SIZE_TO_BITS (HPAV_MMTYPE_SIZE)); bitstream_write (bs, msg->fmi_nbfrag, 4); bitstream_write (bs, msg->fmi_nb, 4); bitstream_write (bs, msg->fmi_fmsn, 8); if (mmtype >= VS_MIN && mmtype <= VS_MAX) bitstream_write (bs, SPC_OUI, OUI_SIZE_BITS); } cp_mme_tx_t * cp_msg_mme_init_frag (cp_t *ctx, cp_mme_peer_t *peer, mmtype_t mmtype, uint fmi_nbFrag) { cp_mme_tx_t *msg; uint eth_packet_size = ETH_PACKET_GET_MAX_SIZE (peer->eth_type); dbg_assert (ctx); dbg_assert (peer); dbg_assert (fmi_nbFrag < HPAV_MME_FRAG_MAX); // Allocate the new message. msg = cp_msg_mme_tx_init (ctx); dbg_assert (msg); // Get a buffer. msg->p_mme = cp_cl_interf_get_buffer_tx (ctx); msg->peer = *peer; msg->final_peer = *peer; msg->peks = CP_MME_PEKS_SPC_NOT_EMBEDDED; msg->fmi_nbfrag = fmi_nbFrag; msg->fmi_nb = 0; msg->fmi_fmsn = ctx->msg.fmsn; msg->mmtype = mmtype; cp_msg_mme_fmsn_increase (&ctx->msg); // Initialise the bitstream context and fill the MME header. bitstream_write_init (&msg->bitstream, msg->p_mme, eth_packet_size); cp_msg_mme_write_frag_header (ctx, msg, &msg->bitstream, mmtype); return msg; } /** * Finalise and send a MME. * \param ctx control plane context * \param mme MME handle * * If the MME is encapsulated, write any pending footer, then send the * message. */ void cp_msg_mme_send (cp_t *ctx, cp_mme_tx_t *mme) { dbg_assert (ctx); dbg_assert (mme); cp_sta_core_checkpoint (ctx); /* If length is filled, MME is ended yet. */ if (mme->length) { /* Nothing to do. */ } /* Ends the MME. See HPAV table 11-77. * PEKS is use to determine if the MME is embedded and the function should * end the encrypted payload mme before sending it. */ else if ((mme->peks != CP_MME_PEKS_SPC_NOT_EMBEDDED) && (mme->prun.pid != 0x4)) { crc_t crc; cp_secu_aes_t aes; uint crc_value; u32 enc_tab[256]; uint padding_len; uint i; uint enc_length; uint crc_pos; cp_key_t key; crc.width = 32; crc.generator = HPAV_CRC32_GENERATOR; crc.init = HPAV_CRC32_INIT; crc.refin = true; crc.refout = true; crc.xorout = 0xffffffff; crc.reg_init = 0; crc.table.t32 = enc_tab; crc_init(&crc); /* Patch the length of the MME in the header. * 22 Bytes in after the head of the encrypted payload to reach the * length field. * + The MME header. */ mme->length = (bitstream_bytes_processed (&mme->bitstream) - mme->payload_offset); bitstream_direct_write (mme->p_mme, BYTES_SIZE_TO_BITS ( HPAV_MME_HEADER + ETH_GET_VLANTAG_SIZE (mme->peer.eth_type) + 22), mme->length, 16); /* Store the CRC. */ crc_pos = bitstream_written_bits (&mme->bitstream); bitstream_write (&mme->bitstream, 0, BYTES_SIZE_TO_BITS (CP_MSG_CM_ENC_PLAYLOAD_CRC_SIZE)); /* PID. */ bitstream_write (&mme->bitstream, mme->prun.pid, BYTES_SIZE_TO_BITS (CP_SECU_PID_SIZE)); /* PRN. */ bitstream_write (&mme->bitstream, mme->prun.prn, BYTES_SIZE_TO_BITS (CP_SECU_PRN_SIZE)); /* PMN. */ bitstream_write (&mme->bitstream, mme->prun.pmn, BYTES_SIZE_TO_BITS (CP_SECU_PMN_SIZE)); /* Padding. crc_value variable used as Padding. */ padding_len = 16 - ((mme->length + mme->rf_len + CP_MSG_ENCRYPTED_DATA_FOOTER_SIZE) % 16); for ( i = 0; i < padding_len; i++) bitstream_write (&mme->bitstream, 0, 8); /* RF Len. */ bitstream_write (&mme->bitstream, mme->rf_len, 8); /* Finalise the bitstream. */ cp_msg_mme_pad (ctx, mme); dbg_check (bitstream_finalise (&mme->bitstream) % 8 == 0); /* Compute the CRC. */ crc_value = crc_compute_begin (&crc); crc_value = crc_compute_continue_block_le (&crc, crc_value, mme->p_mme + mme->payload_offset, mme->length); crc_value = crc_compute_end (&crc, crc_value); bitstream_direct_write ( mme->p_mme, crc_pos, crc_value, BYTES_SIZE_TO_BITS (CP_MSG_CM_ENC_PLAYLOAD_CRC_SIZE)); /* Select the key indexed by the PEKS to encrypted the embedded MME. */ if (mme->peks != CP_MME_PEKS_NONE) { #if CONFIG_CP_EOC && CONFIG_CP_MSG_EOC_MULTI_STA_MME key = cp_msg_peer_peks_key_get (ctx, mme->peer, mme->peks); #else key = cp_msg_peks_key_get (ctx, mme->peks); #endif /* CONFIG_CP_EOC */ /* AES encryption. */ enc_length = mme->length + mme->rf_len + CP_MSG_ENCRYPTED_DATA_FOOTER_SIZE + padding_len; cp_secu_aes_set_encrypt_key (&aes, key); cp_secu_aes_cbc_encrypt (ctx, &aes, mme->iv_uuid.key, (u32*) (mme->p_mme + mme->payload_offset - mme->rf_len), (u32*) (mme->p_mme + mme->payload_offset - mme->rf_len), enc_length); } mme->length = bitstream_bytes_processed (&mme->bitstream); } else { /* Finalise the bitstream. */ cp_msg_mme_pad (ctx, mme); dbg_check (bitstream_finalise (&mme->bitstream) % 8 == 0); mme->length = cp_msg_mme_length (mme); } if (mme->relay) cp_msg_cc_relay_req_send_finalise (ctx, mme); /* Add a trace. */ CP_TRACE (MSG_SEND, phy_date (), mme->mmtype, mme->peer.tei); /* Send the MME. */ cp_sta_core_checkpoint (ctx); cp_cl_interf_mme_send (ctx, mme); /* Release the MME. */ slab_release (mme); } bool cp_msg_mme_read_header_initialised (cp_mme_rx_t *mme, uint *fmi) { uint mtype; dbg_assert (mme); dbg_assert (fmi); bitstream_access (&mme->bitstream, &mme->peer.mac, BYTES_SIZE_TO_BITS (ETH_MAC_ADDRESS_SIZE)); bitstream_access (&mme->bitstream, &mme->peer.eth_type, BYTES_SIZE_TO_BITS (ETH_TYPE_SIZE)); if (ETH_IS_VLANTAG (mme->peer.eth_type)) { bitstream_access (&mme->bitstream, &mme->peer.vlan_tci, 16); bitstream_access (&mme->bitstream, &mtype, BYTES_SIZE_TO_BITS (HPAV_MTYPE_SIZE)); } else { mme->peer.vlan_tci = 0; mtype = mme->peer.eth_type; } bitstream_access (&mme->bitstream, &mme->mmv, 8); bitstream_access (&mme->bitstream, &mme->mmtype, 16); bitstream_access (&mme->bitstream, fmi, 16); // Verify some data. if ((mme->mmv != HPAV_MMV1) || (mtype != HPAV_MTYPE_MME)) { return false; } return true; } cp_mme_rx_t * cp_msg_mme_read_header (cp_t *ctx, u8 *mme, uint length, cp_tei_t tei, uint *fmi) { cp_mme_rx_t *mme_rx; u16 eth_type; bool ok; dbg_assert (ctx); dbg_assert (mme); dbg_assert (fmi); eth_type = bitstream_direct_read ( mme + ETH_TYPE_OFFSET, 0, BYTES_SIZE_TO_BITS (ETH_TYPE_SIZE)); if (length >= (HPAV_MME_HEADER + ETH_GET_VLANTAG_SIZE(eth_type))) { mme_rx = cp_msg_mme_rx_init (ctx, mme, length, tei); bitstream_init (&mme_rx->bitstream, mme + ETH_MAC_ADDRESS_SIZE, length - ETH_MAC_ADDRESS_SIZE, BITSTREAM_READ); if (cp_msg_mme_read_error (ctx, mme_rx)) { ok = cp_msg_mme_read_header_initialised (mme_rx, fmi); } else ok = false; if (ok == false) { slab_release (mme_rx); mme_rx = NULL; } } else { if (tei == MAC_TEI_FOREIGN) bufmgr_give_back (ctx->bufmgr, mme); else bufmgr_keep_buffer (ctx->bufmgr, mme); mme_rx = NULL; } return mme_rx; } /** * Check the CRC and the pid, prn, pnm of the Encrypted MME to verify if it is * not corrupted. * \param ctx the module context. * \param mme the MMe. * \param mm_offset the MME enrypted position in the encrypted MME. */ static bool cp_msg_mme_read_header_enc_check_data (cp_t *ctx, cp_mme_rx_t *mme, uint mm_offset) { u32 crc = 0; u32 enc_tab[256]; bool output = false; crc_t crc_ctx; dbg_assert (ctx); dbg_assert (mme); if (mme->prun.pid != CP_SECU_PID_HLE) { memset (enc_tab, 0, sizeof (enc_tab)); /* Compute the CRC. */ crc_ctx.width = 32; crc_ctx.generator = HPAV_CRC32_GENERATOR; crc_ctx.init = HPAV_CRC32_INIT; crc_ctx.refin = true; crc_ctx.refout = true; crc_ctx.xorout = 0xffffffff; crc_ctx.reg_init = 0; crc_ctx.table.t32 = enc_tab; crc_init(&crc_ctx); crc = crc_compute_begin (&crc_ctx); crc = crc_compute_continue_block_le (&crc_ctx, crc, mme->p_mme + mm_offset, mme->length); crc = crc_compute_end (&crc_ctx, crc); if (crc == bitstream_direct_read (mme->p_mme, (mm_offset + mme->length) * 8, 32)) { uint pid; uint prn; uint pmn; pid = bitstream_direct_read (mme->p_mme, (mm_offset + mme->length + 4) * 8, 8); prn = bitstream_direct_read (mme->p_mme, (mm_offset + mme->length + 5) * 8, 16); pmn = bitstream_direct_read (mme->p_mme, (mm_offset + mme->length + 7) * 8, 8); if ((pid != mme->prun.pid) || (prn != mme->prun.prn) || (pmn != mme->prun.pmn)) output = false; else output = true; } else output = false; } else output = true; return output; } bool cp_msg_mme_read_header_enc (cp_t *ctx, cp_mme_rx_t *mme) { uint i; uint enc_length; uint full_length; uint payload_offset; uint rf_len; uint avln_status; uint data; cp_key_t key; mac_t oda = 0; mac_t osa = 0; uint mtype = 0; uint mmv = 0; cp_secu_aes_t aes; bool output = false; dbg_assert (ctx); dbg_assert (mme); full_length = mme->length; if (cp_msg_mme_read_error (ctx, mme)) { // Continue reading the MME. bitstream_access (&mme->bitstream, &mme->peks, BYTES_SIZE_TO_BITS (CP_MSG_CM_ENC_PLAYLOAD_PEKS_SIZE)); // AVLN STATUS. bitstream_access (&mme->bitstream, &avln_status, BYTES_SIZE_TO_BITS (CP_MSG_CM_ENC_PLAYLOAD_AVLN_STATUS_SIZE)); bitstream_access (&mme->bitstream, &mme->prun.pid, BYTES_SIZE_TO_BITS (CP_SECU_PID_SIZE)); bitstream_access (&mme->bitstream, &mme->prun.prn, BYTES_SIZE_TO_BITS (CP_SECU_PRN_SIZE)); bitstream_access (&mme->bitstream, &mme->prun.pmn, BYTES_SIZE_TO_BITS (CP_SECU_PMN_SIZE)); // IV. for ( i = 0; i < 4; i++) { bitstream_access (&mme->bitstream, &mme->iv_uuid.key[i], 32); } // Len of the payload. bitstream_access (&mme->bitstream, &mme->length, 16); // Decrypt the buffer. /* Compute a first payload offset position. The RF is still in * contained in this length because the RF length is encrypted. */ payload_offset = CP_MSG_ENCRYPTED_DATA_HEADER_SIZE + HPAV_MME_HEADER + ETH_GET_VLANTAG_SIZE (mme->peer.eth_type); enc_length = full_length - payload_offset; /* Select the key to decrypt the embedded MME. */ if (mme->peks != CP_MME_PEKS_NONE) { #if CONFIG_CP_EOC && CONFIG_CP_MSG_EOC_MULTI_STA_MME key = cp_msg_peer_peks_key_get (ctx, mme->peer, mme->peks); #else key = cp_msg_peks_key_get (ctx, mme->peks); #endif /* CONFIG_CP_MSG_EOC_MULTI_STA_MME */ cp_secu_aes_set_decrypt_key (&aes, key); cp_secu_aes_cbc_decrypt (ctx, &aes, mme->iv_uuid.key, (u32 *) (mme->p_mme + payload_offset), (u32 *) (mme->p_mme + payload_offset), enc_length); } /* The length provided in the mme->length corresponds to the full * size of the MME (header included). The RF length is setted to the * length - 1 bytes. */ rf_len = bitstream_direct_read (mme->p_mme + full_length - 1, 0, 8); if (rf_len < CP_MSG_CM_ENC_PLAYLOAD_RF_LEN_MAX_SIZE) { // RF. for (i = 0; i < rf_len; i++) bitstream_access (&mme->bitstream, &data, 8); // Finalise the bitstream. bitstream_finalise (&mme->bitstream); payload_offset += rf_len; if (cp_msg_mme_read_header_enc_check_data (ctx, mme, payload_offset)) { u16 vlan_tci = 0; u16 eth_type; bitstream_read_init (&mme->bitstream, mme->p_mme + payload_offset, mme->length); /* Payload. */ bitstream_access (&mme->bitstream, &oda, 48); bitstream_access (&mme->bitstream, &osa, 48); bitstream_access (&mme->bitstream, ð_type, BYTES_SIZE_TO_BITS (ETH_TYPE_SIZE)); if (ETH_IS_VLANTAG (eth_type)) { bitstream_access (&mme->bitstream, &vlan_tci, 16); bitstream_access (&mme->bitstream, &mtype, BYTES_SIZE_TO_BITS (HPAV_MTYPE_SIZE)); } else { vlan_tci = 0; mtype = eth_type; } bitstream_access (&mme->bitstream, &mmv, 8); // MMTYPE. bitstream_access (&mme->bitstream, &mme->mmtype, 16); // FMI bitstream_access (&mme->bitstream, &data, 16); if ((mmv != HPAV_MMV1) || (mtype != HPAV_MTYPE_MME) || (oda != cp_sta_own_data_get_mac_address (ctx)) || (osa != mme->peer.mac) || (eth_type != mme->peer.eth_type) || (vlan_tci != mme->peer.vlan_tci) || ((avln_status > CP_MSG_AVLN_STATUS_ASSOC_PCO) && (avln_status < CP_MSG_AVLN_STATUS_CCO)) || (avln_status >= CP_MSG_AVLN_STATUS_NB) || (mme->prun.pid >= CP_SECU_NB) || (rf_len > 15)) output = false; else output = true; } else output = false; } else output = false; } else output = false; return output; } void cp_msg_mme_rx_change_buffer (cp_mme_rx_t *msg) { cp_sta_reassembly_ctx_blk_t *current; dbg_assert (msg); dbg_assert (msg->p_frag); dbg_assert (msg->p_frag_current); dbg_assert (msg->p_frag_current->next); // Change the current pointer to the next one. msg->p_frag_current = msg->p_frag_current->next; current = (cp_sta_reassembly_ctx_blk_t *) msg->p_frag_current; bitstream_set_buffer (&msg->bitstream, current->data, current->length); } void cp_msg_mme_tx_change_buffer (bitstream_t *bs, cp_mme_tx_t *mme) { dbg_assert (mme); uint eth_packet_size = ETH_PACKET_GET_MAX_SIZE (mme->peer.eth_type); // Compute fragment size. mme->length = eth_packet_size; // Finalise the MME. slab_addref (mme); cp_msg_mme_send (mme->cp, mme); // Initialise the header of the new buffer. mme->p_mme = cp_cl_interf_get_buffer_tx (mme->cp); bitstream_t header_bs; bitstream_write_init (&header_bs, mme->p_mme, eth_packet_size); mme->fmi_nb++; cp_msg_mme_write_frag_header (mme->cp, mme, &header_bs, mme->mmtype); uint offset = bitstream_finalise (&header_bs); dbg_assert (offset % 8 == 0); offset /= 8; // Set new buffer. bitstream_set_buffer (bs, mme->p_mme + offset, eth_packet_size - offset); /* The last mme must call the bitstream_finalize in cp_msg_mme_send * function. Fix when we have fragmented messages. */ mme->length = 0; } void cp_msg_mme_read_error_process (bitstream_t *ctx, void *user_data) { cp_mme_rx_t *mme = user_data; dbg_assert (ctx); dbg_assert (user_data); if (mme->p_frag_current && mme->p_frag_current->next) cp_msg_mme_rx_change_buffer (mme); else longjmp(mme->jump_env, -1); }