/* Cesar project {{{ * * Copyright (C) 2008 Spidcom * * <<>> * * }}} */ /** * \file cp/sta/action/src/drv.c * \brief STA action, driver related definitions. * \ingroup cp_sta_action */ #include "common/std.h" #include "action.h" #include "cp/msg/msg.h" #include "cp/inc/context.h" #include "cp/fsm/fsm.h" #include "lib/stats.h" #include "common/defs/igmp.h" #include "cl/cl_mactotei.h" void cp_sta_action_drv__stopped__drv_sta_set_mac_addr_req (cp_t *ctx, cp_mme_rx_t *mme) { mac_t mac; bool ok = cp_msg_drv_sta_set_mac_addr_req_receive (ctx, mme, &mac); if (ok) cp_sta_own_data_set_mac_address (ctx, mac); cp_msg_drv_any_cnf_send (ctx, &mme->peer, DRV_STA_SET_MAC_ADDR_CNF, ok ? CP_MSG_DRV_RESULT_SUCCESS : CP_MSG_DRV_RESULT_FAILURE); } void cp_sta_action_drv__stopped__drv_sta_set_cco_pref_req (cp_t *ctx, cp_mme_rx_t *mme) { bool cco_pref; bool ok = cp_msg_drv_sta_set_cco_pref_req_receive (ctx, mme, &cco_pref); if (ok) { cp_sta_own_data_t *own = cp_sta_mgr_get_sta_own_data (ctx); own->cco_prefered = cco_pref; } cp_msg_drv_any_cnf_send (ctx, &mme->peer, DRV_STA_SET_CCO_PREF_CNF, ok ? CP_MSG_DRV_RESULT_SUCCESS : CP_MSG_DRV_RESULT_FAILURE); } void cp_sta_action_drv__stopped__drv_sta_set_was_cco_req (cp_t *ctx, cp_mme_rx_t *mme) { bool was_cco; bool ok = cp_msg_drv_sta_set_was_cco_req_receive (ctx, mme, &was_cco); if (ok) cp_sta_own_data_set_was_cco (ctx, was_cco); cp_msg_drv_any_cnf_send (ctx, &mme->peer, DRV_STA_SET_WAS_CCO_CNF, ok ? CP_MSG_DRV_RESULT_SUCCESS : CP_MSG_DRV_RESULT_FAILURE); } void cp_sta_action_drv__stopped__drv_sta_set_npw_req (cp_t *ctx, cp_mme_rx_t *mme) { char npw[CP_NPW_MAX_SIZE + 1]; bool ok = cp_msg_drv_sta_set_npw_req_receive (ctx, mme, npw); if (ok) { /* Compute NID from received information. */ cp_security_level_t sl; sl = cp_sta_own_data_get_security_level (ctx); cp_sta_own_data_set_npw (ctx, npw); cp_compute_nmk_and_nid_from_npw (ctx, npw, sl); } cp_msg_drv_any_cnf_send (ctx, &mme->peer, DRV_STA_SET_NPW_CNF, ok ? CP_MSG_DRV_RESULT_SUCCESS : CP_MSG_DRV_RESULT_FAILURE); } void cp_sta_action_drv__stopped__drv_sta_set_dpw_req (cp_t *ctx, cp_mme_rx_t *mme) { char dpw[CP_DPW_MAX_SIZE + 1]; bool ok = cp_msg_drv_sta_set_dpw_req_receive (ctx, mme, dpw); if (ok) cp_sta_own_data_set_dpw (ctx, dpw); cp_msg_drv_any_cnf_send (ctx, &mme->peer, DRV_STA_SET_DPW_CNF, ok ? CP_MSG_DRV_RESULT_SUCCESS : CP_MSG_DRV_RESULT_FAILURE); } void cp_sta_action_drv__stopped__drv_sta_set_sl_req (cp_t *ctx, cp_mme_rx_t *mme) { cp_security_level_t sl; bool ok = cp_msg_drv_sta_set_sl_req_receive (ctx, mme, &sl); if (ok) { /* Compute NID from received information. */ const char *npw; npw = cp_sta_own_data_get_npw (ctx); cp_sta_own_data_set_security_level (ctx, sl); cp_compute_nmk_and_nid_from_npw (ctx, npw, sl); } cp_msg_drv_any_cnf_send (ctx, &mme->peer, DRV_STA_SET_SL_CNF, ok ? CP_MSG_DRV_RESULT_SUCCESS : CP_MSG_DRV_RESULT_FAILURE); } void cp_sta_action_drv__stopped__drv_sta_set_nid_req (cp_t *ctx, cp_mme_rx_t *mme) { cp_nid_t nid; bool ok = cp_msg_drv_sta_set_nid_req_receive (ctx, mme, &nid); if (ok) cp_sta_own_data_set_nid (ctx, nid); cp_msg_drv_any_cnf_send (ctx, &mme->peer, DRV_STA_SET_NID_CNF, ok ? CP_MSG_DRV_RESULT_SUCCESS : CP_MSG_DRV_RESULT_FAILURE); } void cp_sta_action_drv__stopped__drv_sta_set_m_sta_hfid_req (cp_t *ctx, cp_mme_rx_t *mme) { char m_sta_hfid[CP_HFID_SIZE + 1]; bool ok = cp_msg_drv_sta_set_m_sta_hfid_req_receive (ctx, mme, m_sta_hfid); if (ok) cp_sta_own_data_set_hfid_manufacturer (ctx, m_sta_hfid); cp_msg_drv_any_cnf_send (ctx, &mme->peer, DRV_STA_SET_M_STA_HFID_CNF, ok ? CP_MSG_DRV_RESULT_SUCCESS : CP_MSG_DRV_RESULT_FAILURE); } void cp_sta_action_drv__stopped__drv_sta_set_u_sta_hfid_req (cp_t *ctx, cp_mme_rx_t *mme) { char u_sta_hfid[CP_HFID_SIZE + 1]; bool ok = cp_msg_drv_sta_set_u_sta_hfid_req_receive (ctx, mme, u_sta_hfid); if (ok) cp_sta_own_data_set_hfid_user (ctx, u_sta_hfid); cp_msg_drv_any_cnf_send (ctx, &mme->peer, DRV_STA_SET_U_STA_HFID_CNF, ok ? CP_MSG_DRV_RESULT_SUCCESS : CP_MSG_DRV_RESULT_FAILURE); } void cp_sta_action_drv__stopped__drv_sta_set_avln_hfid_req (cp_t *ctx, cp_mme_rx_t *mme) { char avln_hfid[CP_HFID_SIZE + 1]; bool ok = cp_msg_drv_sta_set_avln_hfid_req_receive (ctx, mme, avln_hfid); if (ok) cp_sta_own_data_set_hfid_avln (ctx, avln_hfid); cp_msg_drv_any_cnf_send (ctx, &mme->peer, DRV_STA_SET_AVLN_HFID_CNF, ok ? CP_MSG_DRV_RESULT_SUCCESS : CP_MSG_DRV_RESULT_FAILURE); } void cp_sta_action_drv__stopped__drv_sta_mac_start_req (cp_t *ctx, cp_mme_rx_t *mme) { bool ok = cp_msg_drv_sta_mac_start_req_receive (ctx, mme); if (ok) { /* Start power-on procedure. */ cp_sta_action_poweron_start (ctx); } cp_msg_drv_any_cnf_send (ctx, &mme->peer, DRV_STA_MAC_START_CNF, ok ? CP_MSG_DRV_RESULT_SUCCESS : CP_MSG_DRV_RESULT_FAILURE); } void cp_sta_action_drv__started__drv_sta_mac_stop_req (cp_t *ctx, cp_mme_rx_t *mme) { dbg_assert (ctx); dbg_assert (mme); bool ok = cp_msg_drv_sta_mac_stop_req_receive (ctx, mme); /* This come from the driver, it should be OK. */ dbg_assert (ok); /* Save driver address. */ ctx->sta_action.drv_peer = mme->peer; /* Stop station. */ cp_sta_action_poweron_stop (ctx); } void cp_sta_action_drv__stopping__stopped (cp_t *ctx) { dbg_assert (ctx); /* Signal the station is stopped. */ cp_msg_drv_any_cnf_send (ctx, &ctx->sta_action.drv_peer, DRV_STA_MAC_STOP_CNF, CP_MSG_DRV_RESULT_SUCCESS); } void cp_sta_action_drv__drv_sta_sc_common (cp_t *ctx, cp_mme_rx_t *mme, bool allow_sc_join, bool *sc_join) { /* Check parameters. */ dbg_assert (ctx); dbg_assert (mme); dbg_assert (sc_join); /* Check DRV MME. */ bool ok = cp_msg_drv_sta_sc_req_receive (ctx, mme, sc_join); /* This come from the driver, it should be OK. */ dbg_assert (ok); /* Send the driver MME reply. */ /* Failure if (nok or (sc_add and not allowed sc add)). */ cp_msg_drv_any_cnf_send (ctx, &mme->peer, DRV_STA_SC_CNF, (!ok || (*sc_join && !allow_sc_join)) ? CP_MSG_DRV_RESULT_FAILURE : CP_MSG_DRV_RESULT_SUCCESS); } void cp_sta_action_drv__stopped__drv_sta_set_dak_req (cp_t *ctx, cp_mme_rx_t *mme) { cp_key_t dak; dbg_assert (ctx); dbg_assert (mme); if (cp_msg_drv_sta_set_dak_req_receive (ctx, mme, &dak)) { cp_sta_own_data_set_dak (ctx, dak); cp_msg_drv_any_cnf_send (ctx, &mme->peer, DRV_STA_SET_DAK_CNF, CP_MSG_DRV_RESULT_SUCCESS); } else { cp_msg_drv_any_cnf_send (ctx, &mme->peer, DRV_STA_SET_DAK_CNF, CP_MSG_DRV_RESULT_FAILURE); } } void cp_sta_action_drv__drv_sta_get_key_req (cp_t *ctx, cp_mme_rx_t *mme) { cp_msg_drv_sta_get_key_t data; dbg_assert (ctx); dbg_assert (mme); memset (&data, 0, sizeof (cp_msg_drv_sta_get_key_t)); if (cp_msg_drv_sta_get_key_req_receive (ctx, mme)) { data.result = CP_MSG_DRV_RESULT_SUCCESS; data.nmk = cp_sta_own_data_get_nmk (ctx); data.nid = cp_sta_own_data_get_nid (ctx); data.sl = cp_sta_own_data_get_security_level (ctx); cp_msg_drv_sta_get_key_cnf_send (ctx, &mme->peer, &data); } else { data.result = CP_MSG_DRV_RESULT_FAILURE; cp_msg_drv_sta_get_key_cnf_send (ctx, &mme->peer, &data); } } /** * Fill the data structure corresponding the station's status. * \param ctx the control place context. * \param data the data structure corresponding to DRV_STA_STATUS.CNF fields * without the result. */ static void cp_sta_action_drv__drv_sta_status_common (cp_t *ctx, cp_msg_drv_sta_status_t *data) { dbg_assert (ctx); dbg_assert (data); if (cp_sta_own_data_get_cco_status (ctx)) { cp_net_t *net = cp_sta_mgr_get_our_avln (ctx); data->cco = CP_MSG_DRV_STA_STATUS_CCO_CCO; if (net->num_associated_stas) data->status = CP_MSG_DRV_STA_STATUS_STATUS_AUTH; else data->status = CP_MSG_DRV_STA_STATUS_STATUS_UNASSOC; } else if (cp_sta_own_data_get_tei (ctx) == MAC_TEI_UNASSOCIATED) { data->status = CP_MSG_DRV_STA_STATUS_STATUS_UNASSOC; data->cco = CP_MSG_DRV_STA_STATUS_CCO_STA; } else if (MAC_TEI_IS_STA(cp_sta_own_data_get_tei (ctx)) && !cp_sta_own_data_get_authenticated_status (ctx)) { data->status = CP_MSG_DRV_STA_STATUS_STATUS_ASSOC; data->cco = CP_MSG_DRV_STA_STATUS_CCO_STA; } else { data->status = CP_MSG_DRV_STA_STATUS_STATUS_AUTH; if (cp_sta_own_data_get_pco_status (ctx)) data->cco = CP_MSG_DRV_STA_STATUS_CCO_PCO; else if (cp_sta_own_data_get_cco_status (ctx)) data->cco = CP_MSG_DRV_STA_STATUS_CCO_CCO; else data->cco = CP_MSG_DRV_STA_STATUS_CCO_STA; } data->preferred_cco = false; /* TODO. */ data->backup_cco = false; /* TODO. */ data->simple_connect = cp_sta_own_data_get_sc (ctx); data->pwl_sync_frequency = ctx->bsu_aclf->frequency; } void cp_sta_action_drv__drv_sta_status_req (cp_t *ctx, cp_mme_rx_t *mme) { cp_msg_drv_sta_status_cnf_t data; dbg_assert (ctx); dbg_assert (mme); memset (&data, 0, sizeof (cp_msg_drv_sta_status_cnf_t)); if (cp_msg_drv_sta_status_req_receive (ctx, mme)) { data.result = CP_MSG_DRV_RESULT_SUCCESS; cp_sta_action_drv__drv_sta_status_common (ctx, &data.status); cp_msg_drv_sta_status_cnf_send (ctx, &mme->peer, &data); } else { data.result = CP_MSG_DRV_RESULT_FAILURE; cp_msg_drv_sta_status_cnf_send (ctx, &mme->peer, &data); } } void cp_sta_action_drv__drv_sta_status_ind_send (cp_t *ctx) { cp_msg_drv_sta_status_t data; cp_mme_peer_t peer; dbg_assert (ctx); peer = CP_MME_PEER (cp_sta_own_data_get_mac_address (ctx), MAC_TEI_FOREIGN); if (MAC_IS_VALID(peer.mac)) { cp_sta_action_drv__drv_sta_status_common (ctx, &data); cp_msg_drv_sta_status_ind_send (ctx, &peer, &data); } } void cp_sta_action_drv__drv_sta_set_config_req (cp_t *ctx, cp_mme_rx_t *mme) { /* Check parameter. */ dbg_assert (mme); char config[HPAV_MME_PAYLOAD_MAX_SIZE]; cp_msg_drv_result_t result = CP_MSG_DRV_RESULT_FAILURE; if (cp_msg_drv_sta_set_config_req_receive (ctx, mme, config)) { /* Correctly decoded, let's try to set it up. */ if (lib_stats_write_stats (config)) /* Success. */ result = CP_MSG_DRV_RESULT_SUCCESS; } cp_msg_drv_any_cnf_send (ctx, &mme->peer, DRV_STA_SET_CONFIG_CNF, result); } void cp_sta_action_drv__drv_mcast_set_list_req (cp_t *ctx, cp_mme_rx_t *mme) { /* Check parameters. */ dbg_assert (ctx); dbg_assert (mme); cp_msg_drv_result_t result = CP_MSG_DRV_RESULT_SUCCESS; igmp_groups_t *igmp_groups = NULL; igmp_groups = cl_get_igmp_groups (ctx->cl); if (cp_msg_drv_mcast_set_list_req_receive (ctx, mme, &igmp_groups->nb, igmp_groups->group_mac, igmp_groups->nb_total_members, igmp_groups->member_mac)) { /* Create a new table. */ cl_mactotei_blk_t *new_table = cl_mactotei_new (); /* Copy entries except the groups entries. */ cl_mactotei_copy_except_tei (ctx->cl, new_table, MAC_TEI_BCAST); /* Add new entries. */ uint g; for (g = 0; g < igmp_groups->nb; g++) { cl_mactotei_addr_add (new_table, igmp_groups->group_mac[g], MAC_TEI_BCAST, g); } /* Use new MAC to TEI table. */ cl_mactotei_use_table (ctx->cl, new_table); cl_update_igmp_groups (ctx->cl); } else result = CP_MSG_DRV_RESULT_FAILURE; cp_msg_drv_any_cnf_send (ctx, &mme->peer, DRV_MCAST_SET_LIST_CNF, result); }