/* Cesar project {{{ * * Copyright (C) 2008 Spidcom * * <<>> * * }}} */ /** * \file cp/msg/src/msg_cc.c * \brief CC family MME. * \ingroup cp_msg */ #include "common/std.h" #include "common/defs/homeplugAV.h" #include "common/defs/ethernet.h" #include "lib/slab.h" #include "cp/cp.h" #include "cp/cl_interf/cl_interf.h" #include "cp/msg/msg.h" #include "cp/msg/inc/msg.h" #include "cp/sta/mgr/net.h" #include "cp/msg/inc/msg_cc.h" /** * Send a CC_WHO_RU.REQ. * \param ctx control plane context * \param peer peer information * \param nid NID of the requested AVLN */ void cp_msg_cc_who_ru_req_send (cp_t *ctx, cp_mme_peer_t *peer, cp_nid_t nid) { cp_mme_tx_t *msg; dbg_assert (ctx); dbg_assert (peer); dbg_assert (HPAV_NID_IS_VALID (nid)); msg = cp_msg_mme_init (ctx, peer, CC_WHO_RU_REQ); dbg_check (msg); bitstream_access (&msg->bitstream, &nid, 56); cp_msg_mme_send (ctx, msg); } /** * Receive a CC_WHO_RU.REQ. * \param ctx control plane context * \param mme MME handle * \param nid received NID of the requested AVLN * \return true on success */ bool cp_msg_cc_who_ru_req_receive (cp_t *ctx, cp_mme_rx_t *mme, cp_nid_t *nid) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (nid); if (cp_msg_mme_read_error (ctx, mme)) { bitstream_access (&mme->bitstream, nid, 56); if (!HPAV_NID_IS_VALID (*nid) || (!cp_msg_mme_read_end_check (ctx, mme))) return false; return true; } return false; } /** * Send a CC_WHO_RU.CNF. * \param ctx control plane context * \param peer peer information * \param data MME data to send */ void cp_msg_cc_who_ru_cnf_send (cp_t *ctx, cp_mme_peer_t *peer, const cp_msg_cc_who_ru_cnf_t *data) { cp_mme_tx_t *msg; int i; dbg_assert (ctx); dbg_assert (peer); dbg_assert (data); dbg_assert (HPAV_NID_IS_VALID (data->nid)); dbg_assert (data->cco_mac); msg = cp_msg_mme_init (ctx, peer, CC_WHO_RU_CNF); dbg_check (msg); bitstream_access (&msg->bitstream, &data->nid, 56); bitstream_access (&msg->bitstream, (mac_t *) &data->cco_mac, 48); int length = strlen (data->avln_hfid); bitstream_access_buf (&msg->bitstream, (u8*) data->avln_hfid, length); for (i = 0; i < CP_HFID_SIZE - length; i++) bitstream_write (&msg->bitstream, 0, 8); cp_msg_mme_send (ctx, msg); } /** * Receive a CC_WHO_RU.CNF. * \param ctx control plane context * \param mme MME handle * \param data received MME data * \return true on success */ bool cp_msg_cc_who_ru_cnf_receive (cp_t *ctx, cp_mme_rx_t *mme, cp_msg_cc_who_ru_cnf_t *data) { uint i; dbg_assert (ctx); dbg_assert (mme); dbg_assert (data); if (cp_msg_mme_read_error (ctx, mme)) { data->nid = bitstream_read_large (&mme->bitstream, 56); data->cco_mac = bitstream_read_large (&mme->bitstream, 48); if (!HPAV_NID_IS_VALID (data->nid) || (!MAC_IS_VALID (data->cco_mac))) return false; for (i = 0; i < CP_HFID_SIZE; i++) { bitstream_access (&mme->bitstream, &data->avln_hfid[i], 8); if (!ASCII_IS_VALID (data->avln_hfid[i])) break; } if ((i != CP_HFID_SIZE) || (!cp_msg_mme_read_end_check (ctx, mme))) return false; return true; } return false; } /** * Send a CC_ASSOC.REQ. * \param ctx control plane context * \param peer peer information * \param data MME data to send */ void cp_msg_cc_assoc_req_send (cp_t *ctx, cp_mme_peer_t *peer, const cp_msg_cc_assoc_req_t *data) { cp_mme_tx_t *msg; dbg_assert (ctx); dbg_assert (peer); dbg_assert (data); dbg_assert ((data->request_type < CP_MSG_CC_ASSOC_REQ_TYPE_NB) || (data->cco_cap < 4) || (data->proxy_cap < 2)); msg = cp_msg_mme_init (ctx, peer, CC_ASSOC_REQ); dbg_check (msg); bitstream_access (&msg->bitstream, &data->request_type, 8); bitstream_access (&msg->bitstream, &data->nid, 56); bitstream_access (&msg->bitstream, &data->cco_cap, 8); bitstream_access (&msg->bitstream, &data->proxy_cap, 8); cp_msg_mme_send (ctx, msg); } /** * Receive a CC_ASSOC.REQ. * \param ctx control plane context * \param mme MME handle * \param data received MME data * \return true on success */ bool cp_msg_cc_assoc_req_receive (cp_t *ctx, cp_mme_rx_t *mme, cp_msg_cc_assoc_req_t *data) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (data); if (cp_msg_mme_read_error (ctx, mme)) { data->request_type = bitstream_read (&mme->bitstream, 8); data->nid = bitstream_read_large (&mme->bitstream, 56); data->cco_cap = bitstream_read (&mme->bitstream, 8); data->proxy_cap = bitstream_read (&mme->bitstream, 8); if ((data->request_type >= CP_MSG_CC_ASSOC_REQ_TYPE_NB) || !HPAV_NID_IS_VALID (data->nid) || (data->cco_cap > CP_CCO_LEVEL_MAX) || (data->proxy_cap > CP_PCO_CAP_MAX) || (!cp_msg_mme_read_end_check (ctx, mme))) { return false; } return true; } return false; } /** * Send a CC_ASSOC.CNF. * \param ctx control plane context * \param peer peer information * \param data MME data to send */ void cp_msg_cc_assoc_cnf_send (cp_t *ctx, cp_mme_peer_t *peer, const cp_msg_cc_assoc_cnf_t *data) { cp_mme_tx_t *msg; dbg_assert (ctx); dbg_assert (peer); dbg_assert (data); dbg_assert ((data->result < CP_MSG_CC_ASSOC_CNF_RESULT_NB) || data->nid || data->sta_tei || data->lease_time_min); msg = cp_msg_mme_init (ctx, peer, CC_ASSOC_CNF); dbg_check (msg); bitstream_access (&msg->bitstream, &data->result, 8); bitstream_access (&msg->bitstream, &data->nid, 56); bitstream_access (&msg->bitstream, &data->snid, 8); bitstream_access (&msg->bitstream, &data->sta_tei, 8); bitstream_access (&msg->bitstream, &data->lease_time_min, 16); cp_msg_mme_send (ctx, msg); } /** * Receive a CC_ASSOC.CNF. * \param ctx control plane context * \param mme MME handle * \param data received MME data * \return true on success */ bool cp_msg_cc_assoc_cnf_receive (cp_t *ctx, cp_mme_rx_t *mme, cp_msg_cc_assoc_cnf_t *data) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (data); if (cp_msg_mme_read_error (ctx, mme)) { data->result = bitstream_read (&mme->bitstream, 8); data->nid = bitstream_read_large (&mme->bitstream, 56); data->snid = bitstream_read (&mme->bitstream, 8); data->sta_tei = bitstream_read (&mme->bitstream, 8); data->lease_time_min = bitstream_read (&mme->bitstream, 16); /* Verify. */ if (!HPAV_NID_IS_VALID (data->nid) || (data->result >= CP_MSG_CC_ASSOC_CNF_RESULT_NB) || (!MAC_TEI_IS_STA (data->sta_tei)) || (data->lease_time_min == 0) || (!cp_msg_mme_read_end_check (ctx, mme))) { return false; } return true; } return false; } /** * Send a CC_LEAVE.REQ. * \param ctx control plane context * \param peer peer information * \param reason reason for the disassociation */ void cp_msg_cc_leave_req_send (cp_t *ctx, cp_mme_peer_t *peer, enum cp_msg_cc_leave_req_reason_t reason) { cp_mme_tx_t *msg; dbg_assert (ctx); dbg_assert (peer); dbg_assert (reason < CP_MSG_CC_LEAVE_IND_REASON_NB); msg = cp_msg_mme_init (ctx, peer, CC_LEAVE_REQ); dbg_check (msg); bitstream_access (&msg->bitstream, &reason, 8); cp_msg_mme_send (ctx, msg); } /** * Receive a CC_LEAVE.REQ. * \param ctx control plane context * \param mme MME handle * \param reason received reason for the disassociation * \return true on success */ bool cp_msg_cc_leave_req_receive (cp_t *ctx, cp_mme_rx_t *mme, enum cp_msg_cc_leave_req_reason_t *reason) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (reason); if (cp_msg_mme_read_error (ctx, mme)) { bitstream_access (&mme->bitstream, reason, 8); if ((*reason >= CP_MSG_CC_LEAVE_REQ_REASON_NB) || (!cp_msg_mme_read_end_check (ctx, mme))) return false; return true; } return false; } /** * Send a CC_LEAVE.CNF. * \param ctx control plane context * \param peer peer information */ void cp_msg_cc_leave_cnf_send (cp_t *ctx, cp_mme_peer_t *peer) { cp_mme_tx_t *msg; dbg_assert (ctx); dbg_assert (peer); msg = cp_msg_mme_init (ctx, peer, CC_LEAVE_CNF); dbg_check (msg); cp_msg_mme_send (ctx, msg); } /** * Receive a CC_LEAVE.CNF. * \param ctx control plane context * \param mme MME handle * \return true on success */ bool cp_msg_cc_leave_cnf_receive (cp_t *ctx, cp_mme_rx_t *mme) { dbg_assert (ctx); dbg_assert (mme); return (!cp_msg_mme_read_end_check (ctx, mme)); } /** * Send a CC_LEAVE.IND. * \param ctx control plane context * \param peer peer information * \param reason reason for the disassociation * \param nid NID */ void cp_msg_cc_leave_ind_send (cp_t *ctx, cp_mme_peer_t *peer, enum cp_msg_cc_leave_ind_reason_t reason, cp_nid_t nid) { cp_mme_tx_t *msg; dbg_assert (ctx); dbg_assert (peer); dbg_assert (reason < CP_MSG_CC_LEAVE_IND_REASON_NB); dbg_assert (HPAV_NID_IS_VALID (nid)); msg = cp_msg_mme_init (ctx, peer, CC_LEAVE_IND); dbg_check (msg); bitstream_access (&msg->bitstream, &reason, 8); bitstream_access (&msg->bitstream, &nid, 56); cp_msg_mme_send (ctx, msg); } /** * Receive a CC_LEAVE.IND. * \param ctx control plane context * \param mme MME handle * \param reason received reason for the disassociation * \param nid received NID * \return true on success */ bool cp_msg_cc_leave_ind_receive (cp_t *ctx, cp_mme_rx_t *mme, enum cp_msg_cc_leave_ind_reason_t *reason, cp_nid_t *nid) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (reason); dbg_assert (nid); if (cp_msg_mme_read_error (ctx, mme)) { bitstream_access (&mme->bitstream, reason, 8); bitstream_access (&mme->bitstream, nid, 56); if (!HPAV_NID_IS_VALID (*nid) || (*reason >= CP_MSG_CC_LEAVE_IND_REASON_NB) || (!cp_msg_mme_read_end_check (ctx, mme))) { return false; } return true; } return false; } /** * Send a CC_LEAVE.RSP. * \param ctx control plane context * \param peer peer information */ void cp_msg_cc_leave_rsp_send (cp_t *ctx, cp_mme_peer_t *peer) { cp_mme_tx_t *msg; dbg_assert (ctx); dbg_assert (peer); msg = cp_msg_mme_init (ctx, peer, CC_LEAVE_RSP); dbg_check (msg); cp_msg_mme_send (ctx, msg); } /** * Receive a CC_LEAVE.RSP. * \param ctx control plane context * \param mme MME handle * \return true on success */ bool cp_msg_cc_leave_rsp_receive (cp_t *ctx, cp_mme_rx_t *mme) { dbg_assert (ctx); dbg_assert (mme); return true; } /** * Send a CC_SET_TEI_MAP.REQ. * \param ctx control plane context * \param peer peer information */ void cp_msg_cc_set_tei_map_req_send (cp_t *ctx, cp_mme_peer_t *peer) { cp_mme_tx_t *msg; dbg_assert (ctx); dbg_assert (peer); msg = cp_msg_mme_init (ctx, peer, CC_SET_TEI_MAP_REQ); dbg_check (msg); cp_msg_mme_send (ctx, msg); } /** * Receive a CC_SET_TEI_MAP.REQ. * \param ctx control plane context * \param mme MME handle * \return true on success */ bool cp_msg_cc_set_tei_map_req_receive (cp_t *ctx, cp_mme_rx_t *mme) { dbg_assert (ctx); dbg_assert (mme); return true; } /** * Begin a CC_SET_TEI_MAP.IND construction. * \param ctx control plane context * \param peer peer information * \param mode update, add or delete * \param sta_nb number of stations sent * \return the MME being constructed */ cp_mme_tx_t * cp_msg_cc_set_tei_map_ind_send_begin ( cp_t *ctx, cp_mme_peer_t *peer, enum cp_msg_cc_set_tei_map_ind_mode_t mode, uint sta_nb) { cp_mme_tx_t *msg; dbg_assert (ctx); dbg_assert (peer); dbg_assert (mode < CP_MSG_CC_SET_TEI_MAP_IND_MODE_NB); dbg_assert (sta_nb); if (sta_nb * 8 > (peer->vlan_tag ? HPAV_MME_PAYLOAD_MAX_SIZE_WITH_VLAN : HPAV_MME_PAYLOAD_MAX_SIZE) - 2) { msg = cp_msg_mme_init_frag (ctx, peer, CC_SET_TEI_MAP_IND, 1, 0); bitstream_init_buffer_cb ( &msg->bitstream, (bitstream_buffer_cb_t) cp_msg_mme_tx_change_buffer, msg); } else msg = cp_msg_mme_init (ctx, peer, CC_SET_TEI_MAP_IND); dbg_check (msg); bitstream_access (&msg->bitstream, &mode, 8); bitstream_access (&msg->bitstream, &sta_nb, 8); return msg; } /** * Write a station to a CC_SET_TEI_MAP.IND being constructed. * \param ctx control plane context * \param mme MME being constructed * \param tei STA TEI * \param mac STA mac address * \param status STA status */ void cp_msg_cc_set_tei_map_ind_send_sta ( cp_t *ctx, cp_mme_tx_t *mme, cp_tei_t tei, mac_t mac, enum cp_msg_cc_set_tei_map_ind_status_t status) { dbg_assert (mme); dbg_assert (tei); dbg_assert (mac); dbg_assert (status < CP_MSG_CC_SET_TEI_MAP_IND_STATUS_NB); bitstream_access (&mme->bitstream, &tei, 8); bitstream_access (&mme->bitstream, &mac, 48); bitstream_access (&mme->bitstream, &status, 8); } /** * Finalise and send a CC_SET_TEI_MAP.IND message. * \param ctx control plane context * \param mme MME being constructed */ void cp_msg_cc_set_tei_map_ind_send_end (cp_t *ctx, cp_mme_tx_t *mme) { dbg_assert (ctx); dbg_assert (mme); mme->length = 0; cp_msg_mme_send (ctx, mme); } /** * Begin a CC_SET_TEI_MAP.IND reception. * \param ctx control plane context * \param mme MME handle * \param mode received mode: update, add or delete * \param sta_nb received number of STA * \return true on success */ bool cp_msg_cc_set_tei_map_ind_receive_begin ( cp_t *ctx, cp_mme_rx_t *mme, enum cp_msg_cc_set_tei_map_ind_mode_t *mode, uint *sta_nb) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (mode); dbg_assert (sta_nb); if (cp_msg_mme_read_error (ctx, mme)) { bitstream_access (&mme->bitstream, mode, 8); bitstream_access (&mme->bitstream, sta_nb, 8); if (*mode >= CP_MSG_CC_SET_TEI_MAP_IND_MODE_NB) return false; return true; } return false; } bool cp_msg_cc_set_tei_map_ind_receive_sta ( cp_t *ctx, cp_mme_rx_t *mme, cp_tei_t *tei, mac_t *mac, enum cp_msg_cc_set_tei_map_ind_status_t *status) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (tei); dbg_assert (mac); dbg_assert (status); if (cp_msg_mme_read_error (ctx, mme)) { *tei = bitstream_read (&mme->bitstream, 8); *mac = bitstream_read_large (&mme->bitstream, 48); *status = bitstream_read (&mme->bitstream, 8); if ((*status >= CP_MSG_CC_SET_TEI_MAP_IND_STATUS_NB) || (!MAC_TEI_IS_STA(*tei)) || (!MAC_IS_VALID(*mac)) || (*status >= CP_MSG_CC_SET_TEI_MAP_IND_STATUS_NB)) return false; return true; } return false; } bool cp_msg_cc_set_tei_map_ind_receive_end (cp_t *ctx, cp_mme_rx_t *mme) { dbg_assert (ctx); dbg_assert (mme); return (cp_msg_mme_read_end_check (ctx, mme)); } /** * Write the header of a CC_RELAY MME. * \param ctx the module context. * \param peer the peer information. * \param mmtype the MMType of the MME CC_RELAY_REQ or CC_RELAY_IND. * \param prun if the MME shall be encrypted. * \param peks the Payload encryption key select. * \param fda the final destination mac address. * \param ftei the final TEI. */ static cp_mme_tx_t * cp_msg_cc_relay_send_begin (cp_t *ctx, cp_mme_peer_t *peer, cp_mmtype_t mmtype, const cp_secu_protocol_run_t *prun, cp_mme_peks_t peks, mac_t fda, cp_tei_t ftei) { cp_mme_tx_t * msg; dbg_assert (ctx); dbg_assert (peer); dbg_assert (fda); dbg_assert (((mmtype == CC_RELAY_REQ) && (ftei != MAC_TEI_UNASSOCIATED)) || (mmtype == CC_RELAY_IND)); dbg_assert ((mmtype != CC_RELAY_REQ) || (mmtype != CC_RELAY_IND)); // Get a TX buffer. if (peks == CP_MME_PEKS_SPC_NOT_EMBEDDED) msg = cp_msg_mme_init (ctx, peer, mmtype); else msg = cp_msg_mme_init_encrypted (ctx, peer, mmtype, peks, prun); // Fill the data of the MME. bitstream_access (&msg->bitstream, &fda, 48); // Fill the TEI of the final destination station. bitstream_access (&msg->bitstream, &ftei, 8); // Go forward inserting a zero length MME payload length. bitstream_write (&msg->bitstream, 0, 16); return msg; } cp_mme_tx_t * cp_msg_cc_relay_req_send_begin (cp_t *ctx, cp_mme_peer_t *peer, const cp_secu_protocol_run_t *prun, cp_mme_peks_t peks, mac_t fda, cp_tei_t ftei) { return cp_msg_cc_relay_send_begin (ctx, peer, CC_RELAY_REQ, prun, peks, fda, ftei); } /** * Finalise the MME CC_RELAY.IND. * \param ctx the module context. * \param msg the MME REQ received. * \param osa the original source mac address. * \param stei the source TEI of the station which sent the cc_relay_req. * \param length the length of the payload. * * Patch the Length of the MME payload in the MSG CC_RELAY.REQ MME. */ void cp_msg_cc_relay_ind_send (cp_t *ctx, cp_mme_rx_t *msg, mac_t osa, cp_tei_t stei, uint length) { cp_mme_tx_t *mme; cp_mme_peer_t peer; dbg_assert (ctx); dbg_assert (msg); dbg_assert (osa); dbg_assert (length); peer.mac = msg->relay.mac_fa; peer.tei = msg->relay.ftei; peer.vlan_tag = msg->peer.vlan_tag; mme = cp_msg_mme_init (ctx, &peer, CC_RELAY_IND); dbg_assert (mme); bitstream_write_large (&mme->bitstream, osa, 48); bitstream_access (&mme->bitstream, &stei, 8); bitstream_access (&mme->bitstream, &length, 16); bitstream_copy_buf (&mme->bitstream, &msg->bitstream, length); cp_msg_mme_send (ctx, mme); } void cp_msg_cc_relay_req_send_finalise (cp_t *ctx, cp_mme_tx_t *msg) { uint length; uint offset; dbg_assert (ctx); dbg_assert (msg); if (msg->peer.vlan_tag) { offset = (HPAV_MME_HEADER_LEN_WITH_VLAN + 7) * 8; length = msg->length - HPAV_MME_HEADER_LEN_WITH_VLAN - 9; } else { offset = (HPAV_MME_HEADER + 7) * 8; length = msg->length - HPAV_MME_HEADER - 9; } bitstream_direct_write (msg->p_mme, offset, length, 16); } /** * Receive a CC_RELAY.* * \param ctx the control plane context. * \param msg the MME context. * \param length the MME payload length contained. * \return true on success * * Initialise the Relay MME. */ bool cp_msg_cc_relay_req_receive (cp_t *ctx, cp_mme_rx_t *msg, uint *length, uint *mmtype) { uint length_computed; uint mme_header_len; dbg_assert (ctx); dbg_assert (msg); dbg_assert (length); dbg_assert (mmtype); if (cp_msg_mme_read_error (ctx, msg)) { // Read the FDA. bitstream_access (&msg->bitstream, &msg->relay.mac_fa, 48); bitstream_access (&msg->bitstream, &msg->relay.ftei, 8); bitstream_access (&msg->bitstream, length, 16); mme_header_len = msg->peer.vlan_tag ? HPAV_MME_HEADER_LEN_WITH_VLAN : HPAV_MME_HEADER; length_computed = msg->length - mme_header_len - 9; *mmtype = bitstream_direct_read (msg->p_mme + 2*mme_header_len + 5, 0, 16); if ((*length != length_computed) || (msg->relay.mac_fa == 0)) { return false; } return true; } return false; } bool cp_msg_cc_relay_ind_receive (cp_t *ctx, cp_mme_rx_t *msg, uint *length) { uint length_computed; uint mme_header_len; dbg_assert (ctx); dbg_assert (msg); dbg_assert (length); if (cp_msg_mme_read_error (ctx, msg)) { // Read the FDA. bitstream_access (&msg->bitstream, &msg->peer.mac, 48); bitstream_access (&msg->bitstream, &msg->peer.tei, 8); bitstream_access (&msg->bitstream, length, 16); mme_header_len = msg->peer.vlan_tag ? HPAV_MME_HEADER_LEN_WITH_VLAN : HPAV_MME_HEADER; length_computed = msg->length - mme_header_len - 9; if ((*length > ETH_PACKET_MAX_SIZE) || (*length != length_computed)) { return false; } return true; } return false; } bool cp_msg_cc_relay_read_payload_header (cp_t *ctx, cp_mme_rx_t *msg) { uint fmi; dbg_assert (ctx); dbg_assert (msg); return cp_msg_mme_read_header_initialised (msg, &fmi, msg->peer.vlan_tag); } /** * Send a CC_DISCOVER_LIST.REQ * \param ctx the control plane context. */ void cp_msg_cc_discover_list_req_send (cp_t *ctx, cp_mme_peer_t *peer) { cp_mme_tx_t *mme; dbg_assert (ctx); dbg_assert (peer); mme = cp_msg_mme_init (ctx, peer, CC_DISCOVER_LIST_REQ); dbg_assert (mme); cp_msg_mme_send (ctx, mme); } /** * Receive a CC_DISCOVER_LIST.REQ * \param ctx the control plane context. * \param msg the MME context. * \return true if the MME is correct, false otherwise. */ bool cp_msg_cc_discover_list_req_receive (cp_t *ctx, cp_mme_rx_t *msg) { return cp_msg_mme_read_end_check (ctx, msg); } /** Read or store the number of station from/to the MME. * \param stream the bitstream context. * \param nb_sta the number of station variable to read/store. */ static void cp_msg_cc_discover_list_cnf_nb_sta (bitstream_t *stream, uint *nb_sta) { dbg_assert (stream); dbg_assert (nb_sta); bitstream_access (stream, nb_sta, 8); } /** Read or store the number of networks from/to the MME. * \param stream the bitstream context. * \param nb_net the number of networks variable to read/store. */ static void cp_msg_cc_discover_list_cnf_nb_net (bitstream_t *stream, uint *nb_net) { dbg_assert (stream); dbg_assert (nb_net); bitstream_access (stream, nb_net, 8); } /** * Send a CC_DISCOVER_LIST.CNF * \param ctx the control plane context. * \param peer the peer info. * \param nb_sta the number of discovered stations. * \param nb_net the number of discovered networks. * \param disc_ctx the discover context use to fill the MME. * \return the message context. */ cp_mme_tx_t * cp_msg_cc_discover_list_cnf_send_begin (cp_t *ctx, cp_mme_peer_t *peer, uint nb_sta, uint nb_net, cp_msg_cc_discover_list_ctx_t *disc_ctx) { cp_mme_tx_t *mme; uint mme_length; uint nb_sta_length; uint nb_net_length; dbg_assert (ctx); dbg_assert (peer); dbg_assert (disc_ctx); /* Fill the discover list context. */ disc_ctx->nb_stations = nb_sta; disc_ctx->nb_networks = nb_net; /* Compute the MMe length. */ nb_sta_length = 1 + nb_sta * 12; // see Table 11-193. nb_net_length = 1 + nb_net * 13; // see Table 11-193. mme_length = (peer->vlan_tag ? HPAV_MME_HEADER_LEN_WITH_VLAN : HPAV_MME_HEADER) + nb_sta_length + nb_net_length; if (mme_length <= ETH_PACKET_MAX_SIZE) mme = cp_msg_mme_init (ctx, peer, CC_DISCOVER_LIST_CNF); else { uint nbFrag; nbFrag = mme_length / ETH_PACKET_MAX_SIZE; mme = cp_msg_mme_init_frag ( ctx, peer, CC_DISCOVER_LIST_CNF, nbFrag, 0); bitstream_init_buffer_cb ( &mme->bitstream, (bitstream_buffer_cb_t) cp_msg_mme_tx_change_buffer, mme); } return mme; } /** * Send a CC_DISCOVER_LIST.CNF * \param ctx the control plane context. * \param mme the MME message. * \param disc_ctx the discover context use to fill the MME. */ void cp_msg_cc_discover_list_cnf_send_stations_begin (cp_t *ctx, cp_mme_tx_t *mme, cp_msg_cc_discover_list_ctx_t *disc_ctx) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (disc_ctx); cp_msg_cc_discover_list_cnf_nb_sta (&mme->bitstream, &disc_ctx->nb_stations); } /** * Add a station to the MME. * \param ctx the control plane context. * \param mme the MME message. * \param data the data to store in the MME. */ void cp_msg_cc_discover_list_cnf_send_station (cp_t *ctx, cp_mme_tx_t *mme, const cp_msg_cc_discover_list_sta_t *data) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (data); bitstream_write_large (&mme->bitstream, data->mac_addr, 48); bitstream_write (&mme->bitstream, data->tei, 8); bitstream_write (&mme->bitstream, data->same_network, 8); bitstream_write (&mme->bitstream, data->snid, 4); bitstream_write (&mme->bitstream, data->access, 4); bitstream_write (&mme->bitstream, 0, 1); bitstream_write (&mme->bitstream, data->cco_cap, 2); bitstream_write (&mme->bitstream, data->proxy_cap, 1); bitstream_write (&mme->bitstream, data->backup_cco_cap, 1); bitstream_write (&mme->bitstream, data->cco_status, 1); bitstream_write (&mme->bitstream, data->pco_status, 1); bitstream_write (&mme->bitstream, data->backup_cco_status, 1); bitstream_write (&mme->bitstream, data->signal_level, 8); bitstream_write (&mme->bitstream, data->average_ble, 8); } /** * Store the number of discovered networks in the MME. * \param ctx the control plane context. * \param mme the MME message. * \param disc_ctx the discover context use to fill the MME. */ void cp_msg_cc_discover_list_cnf_send_net_begin (cp_t *ctx, cp_mme_tx_t *mme, cp_msg_cc_discover_list_ctx_t *disc_ctx) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (disc_ctx); cp_msg_cc_discover_list_cnf_nb_net (&mme->bitstream, &disc_ctx->nb_networks); } /** * Add a station to the MME. * \param ctx the control plane context. * \param mme the MME message. * \param data the data to store in the MME. */ void cp_msg_cc_discover_list_cnf_send_net (cp_t *ctx, cp_mme_tx_t *mme, const cp_msg_cc_discover_list_net_t *data) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (data); bitstream_write_large (&mme->bitstream, data->nid, 56); bitstream_write (&mme->bitstream, data->snid, 4); bitstream_write (&mme->bitstream, data->access, 4); bitstream_write (&mme->bitstream, data->hm, 8); bitstream_write (&mme->bitstream, data->numslots, 8); bitstream_write (&mme->bitstream, data->coordinated_status, 8); bitstream_write (&mme->bitstream, data->offset, 16); } /** * Send a CC_DISCOVER_LIST.CNF * \param ctx the control plane context. * \param mme the MME to send. */ void cp_msg_cc_discover_list_cnf_send_end (cp_t *ctx, cp_mme_tx_t *mme) { dbg_assert (ctx); dbg_assert (mme); cp_msg_mme_send (ctx, mme); } /** * Begin a CC_DISCOVER_LIST.CNF reception. * \param ctx control plane context * \param mme MME handle * \return true on success */ bool cp_msg_cc_discover_list_cnf_receive_begin (cp_t *ctx, cp_mme_rx_t *mme) { dbg_assert (ctx); dbg_assert (mme); return true; } /** * Receive a CC_DISCOVER_LIST.CNF * \param ctx the control plane context. * \param msg the MME payload. * \param nb_sta The number of discovered station done by the source * station. * \return true on success. */ bool cp_msg_cc_discover_list_cnf_recv_begin_sta (cp_t *ctx, cp_mme_rx_t *msg, uint *nb_sta) { dbg_assert (ctx); dbg_assert (msg); dbg_assert (nb_sta); if (cp_msg_mme_read_error (ctx, msg)) { cp_msg_cc_discover_list_cnf_nb_sta (&msg->bitstream, nb_sta); return true; } return false; } bool cp_msg_cc_discover_list_cnf_recv_station (cp_t *ctx, cp_mme_rx_t *mme, cp_msg_cc_discover_list_sta_t *data) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (data); if (cp_msg_mme_read_error (ctx, mme)) { uint rsvd; data->mac_addr = bitstream_read_large (&mme->bitstream, 48); data->tei = bitstream_read (&mme->bitstream, 8); data->same_network = bitstream_read (&mme->bitstream, 8); data->snid = bitstream_read (&mme->bitstream, 4); data->access = bitstream_read (&mme->bitstream, 4); rsvd = bitstream_read (&mme->bitstream, 1); data->cco_cap = bitstream_read (&mme->bitstream, 2); data->proxy_cap = bitstream_read (&mme->bitstream, 1); data->backup_cco_cap = bitstream_read (&mme->bitstream, 1); data->cco_status = bitstream_read (&mme->bitstream, 1); data->pco_status = bitstream_read (&mme->bitstream, 1); data->backup_cco_status = bitstream_read (&mme->bitstream, 1); data->signal_level = bitstream_read (&mme->bitstream, 8); data->average_ble = bitstream_read (&mme->bitstream, 8); if ((!MAC_IS_VALID (data->mac_addr)) || (!MAC_TEI_IS_STA (data->tei)) || (data->same_network >= CC_DISCOVER_LIST_NET_NB) || (data->access >= HPAV_ACCESS_NB) || (data->cco_cap > CP_CCO_LEVEL_MAX) || (data->proxy_cap > CP_PCO_CAP_MAX) || (data->backup_cco_cap > CP_BACKUP_CCO_CAP_MAX) || !(CP_MSG_CC_DISCOVER_LIST_SIGNAL_LEVEL_IS_VALID( data->signal_level))) return false; return true; } return false; } bool cp_msg_cc_discover_list_cnf_recv_begin_net (cp_t *ctx, cp_mme_rx_t *msg, uint *nb_net) { dbg_assert (ctx); dbg_assert (msg); dbg_assert (nb_net); if (cp_msg_mme_read_error (ctx, msg)) { cp_msg_cc_discover_list_cnf_nb_net (&msg->bitstream, nb_net); return true; } return false; } bool cp_msg_cc_discover_list_cnf_recv_network (cp_t *ctx, cp_mme_rx_t *mme, cp_msg_cc_discover_list_net_t *data) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (data); if (cp_msg_mme_read_error (ctx, mme)) { data->nid = bitstream_read_large (&mme->bitstream, 56); data->snid = bitstream_read (&mme->bitstream, 4); data->access = bitstream_read (&mme->bitstream, 4); data->hm = bitstream_read (&mme->bitstream, 8); data->numslots = bitstream_read (&mme->bitstream, 8); data->coordinated_status = bitstream_read (&mme->bitstream, 8); data->offset = bitstream_read (&mme->bitstream, 16); if ((!HPAV_NID_IS_VALID (data->nid)) || (data->access >= HPAV_ACCESS_NB) || (data->hm >= MAC_COEXISTENCE_NB) || (data->numslots > HPAV_BEACON_NUMSLOTS_MAX) || (data->coordinated_status >= CC_DISCOVER_LIST_CCORD_NB)) return false; return true; } return false; } bool cp_msg_cc_discover_list_cnf_recv_end (cp_t *ctx, cp_mme_rx_t *mme) { dbg_assert (ctx); dbg_assert (mme); return cp_msg_mme_read_end_check (ctx, mme); } void cp_msg_cc_handover_req_send (cp_t *ctx, cp_mme_peer_t *peer, cp_msg_cc_handover_req_soft_hard_t soft_hard, cp_msg_cc_handover_req_reason_t reason) { cp_mme_tx_t *mme; dbg_assert (ctx); dbg_assert (peer); dbg_assert (soft_hard < CP_MSG_CC_HANDOVER_REQ_NB); dbg_assert (reason < CP_MSG_CC_HANDOVER_REQ_REASON_NB); mme = cp_msg_mme_init (ctx, peer, CC_HANDOVER_REQ); dbg_assert (mme); bitstream_write (&mme->bitstream, soft_hard, 8); bitstream_write (&mme->bitstream, reason, 8); cp_msg_mme_send (ctx, mme); } bool cp_msg_cc_handover_req_receive (cp_t *ctx, cp_mme_rx_t *mme, cp_msg_cc_handover_req_soft_hard_t *soft_hard, cp_msg_cc_handover_req_reason_t *reason) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (soft_hard); dbg_assert (reason); if (cp_msg_mme_read_error (ctx, mme)) { *soft_hard = bitstream_read (&mme->bitstream, 8); *reason = bitstream_read (&mme->bitstream, 8); bitstream_finalise (&mme->bitstream); if ((*soft_hard >= CP_MSG_CC_HANDOVER_REQ_NB) || (*reason >= CP_MSG_CC_HANDOVER_REQ_REASON_NB) || (!cp_msg_mme_read_end_check (ctx, mme))) return false; return true; } return false; } void cp_msg_cc_handover_cnf_send (cp_t *ctx, cp_mme_peer_t *peer, cp_msg_cc_handover_cnf_result_t result) { cp_mme_tx_t *mme; dbg_assert (ctx); dbg_assert (peer); dbg_assert (result < CP_MSG_CC_HANDOVER_CNF_RESULT_NB); mme = cp_msg_mme_init (ctx, peer, CC_HANDOVER_CNF); dbg_assert (mme); bitstream_write (&mme->bitstream, result, 8); cp_msg_mme_send (ctx, mme); } bool cp_msg_cc_handover_cnf_receive (cp_t *ctx, cp_mme_rx_t *mme, cp_msg_cc_handover_cnf_result_t *result) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (result); if (cp_msg_mme_read_error (ctx, mme)) { *result= bitstream_read (&mme->bitstream, 8); bitstream_finalise (&mme->bitstream); if ((*result >= CP_MSG_CC_HANDOVER_CNF_RESULT_NB) || (!cp_msg_mme_read_end_check (ctx, mme))) return false; return true; } return false; } cp_mme_tx_t * cp_msg_cc_handover_info_ind_send_begin (cp_t *ctx, cp_mme_peer_t *peer, cp_msg_cc_handover_info_ind_rsc_t rsc, cp_tei_t bcco, uint num_sta) { cp_mme_tx_t *mme; dbg_assert (ctx); dbg_assert (peer); dbg_assert (rsc < CP_MSG_CC_HANDOVER_INFO_IND_RSC_NB); /* 166 stations maximum in the MME. * With Vlan, 1518 - 23 = 1495 bytes. * The station data are 9 bytes long. * (1495 - 3) / 9 = 165.77 bytes. * Without Vlan, 1518 - 19 = 1499. * (1499 - 3) / 9 = 166.22 bytes. */ if (((peer->vlan_tag) && (num_sta < 165)) || (num_sta < 166)) mme = cp_msg_mme_init (ctx, peer, CC_HANDOVER_INFO_IND); else { mme = cp_msg_mme_init_frag (ctx, peer, CC_HANDOVER_INFO_IND, 1, 0); bitstream_init_buffer_cb ( &mme->bitstream, (bitstream_buffer_cb_t) cp_msg_mme_tx_change_buffer, mme); } dbg_assert (mme); bitstream_write (&mme->bitstream, rsc, 8); bitstream_write (&mme->bitstream, bcco, 8); bitstream_write (&mme->bitstream, num_sta, 8); return mme; } void cp_msg_cc_handover_info_ind_send (cp_t *ctx, cp_mme_tx_t *mme, cp_tei_t tei, mac_t mac_addr, uint status, cp_tei_t ptei) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (MAC_TEI_IS_STA (tei)); dbg_assert ((mac_addr > 0) && (mac_addr < MAC_BROADCAST)); bitstream_write (&mme->bitstream, tei, 8); bitstream_write_large (&mme->bitstream, mac_addr, 48); bitstream_write (&mme->bitstream, status, 8); bitstream_write (&mme->bitstream, ptei, 8); } void cp_msg_cc_handover_info_ind_send_end (cp_t *ctx, cp_mme_tx_t *mme) { dbg_assert (ctx); dbg_assert (mme); mme->length = 0; cp_msg_mme_send (ctx, mme); } bool cp_msg_cc_handover_info_ind_receive_begin (cp_t *ctx, cp_mme_rx_t *mme, cp_msg_cc_handover_info_ind_rsc_t *rsc, cp_tei_t *bcco, uint *num_sta) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (rsc); dbg_assert (bcco); dbg_assert (num_sta); if (cp_msg_mme_read_error (ctx, mme)) { *rsc = bitstream_read (&mme->bitstream, 8); *bcco = bitstream_read (&mme->bitstream, 8); *num_sta = bitstream_read (&mme->bitstream, 8); if ((*rsc >= CP_MSG_CC_HANDOVER_INFO_IND_RSC_NB) || (*bcco > MAC_TEI_STA_MAX)) return false; return true; } return false; } bool cp_msg_cc_handover_info_ind_receive (cp_t *ctx, cp_mme_rx_t *mme, cp_tei_t *tei, mac_t *mac_addr, uint *status, cp_tei_t *ptei) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (tei); dbg_assert (mac_addr); dbg_assert (status); dbg_assert (ptei); if (cp_msg_mme_read_error (ctx, mme)) { *tei = bitstream_read (&mme->bitstream, 8); *mac_addr = bitstream_read_large (&mme->bitstream, 48); *status = bitstream_read (&mme->bitstream, 8); *ptei = bitstream_read (&mme->bitstream, 8); if ((!MAC_TEI_IS_STA (*tei)) || (*mac_addr == 0) || (*mac_addr == MAC_BROADCAST) || (*status > CP_NET_STA_NB) || (*ptei > MAC_TEI_STA_MAX)) return false; return true; } return false; } bool cp_msg_cc_handover_info_ind_receive_end (cp_t *ctx, cp_mme_rx_t *mme) { dbg_assert (ctx); dbg_assert (mme); return (cp_msg_mme_read_end_check (ctx, mme)); } void cp_msg_cc_handover_info_rsp_send (cp_t *ctx, cp_mme_peer_t *peer) { cp_mme_tx_t *mme; dbg_assert (ctx); dbg_assert (peer); mme = cp_msg_mme_init (ctx, peer, CC_HANDOVER_INFO_RSP); dbg_assert (mme); cp_msg_mme_send (ctx, mme); } bool cp_msg_cc_handover_info_rsp_receive (cp_t *ctx, cp_mme_rx_t *mme) { uint i; dbg_assert (ctx); dbg_assert (mme); for (i = 0; i < bitstream_available_bits (&mme->bitstream) / 8; i++) if (bitstream_read (&mme->bitstream, 8) != 0) return false; return true; } void cp_msg_cc_cco_appoint_req_send (cp_t *ctx, cp_mme_peer_t *peer, cp_msg_cc_cco_appoint_req_rt_t req_type, mac_t mac_addr) { cp_mme_tx_t *mme; dbg_assert (ctx); dbg_assert (req_type < CP_MSG_CC_CCO_APPOINT_REQ_RT_NB); dbg_assert ((((req_type == 0x0) || (req_type == 0x2)) && MAC_IS_VALID (mac_addr)) || ((req_type == 0x1) && (mac_addr == MAC_ZERO))); mme = cp_msg_mme_init (ctx, peer, CC_CCO_APPOINT_REQ); dbg_assert (mme); bitstream_write (&mme->bitstream, req_type, 8); bitstream_write_large (&mme->bitstream, mac_addr, 48); cp_msg_mme_send (ctx, mme); } bool cp_msg_cc_cco_appoint_req_receive (cp_t *ctx, cp_mme_rx_t *mme, cp_msg_cc_cco_appoint_req_rt_t *req_type, mac_t *mac_addr) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (req_type); dbg_assert (mac_addr); if (cp_msg_mme_read_error (ctx, mme)) { *req_type = bitstream_read (&mme->bitstream, 8); *mac_addr = bitstream_read_large (&mme->bitstream, 48); if (((*req_type < CP_MSG_CC_CCO_APPOINT_REQ_RT_NB) && (((*req_type == 0x0) && MAC_IS_VALID (*mac_addr)) || ((*req_type == 0x1) && (*mac_addr == MAC_ZERO)) || ((*req_type == 0x2) && MAC_IS_VALID (*mac_addr)))) || (!cp_msg_mme_read_end_check (ctx, mme))) return true; } return false; } void cp_msg_cc_cco_appoint_cnf_send (cp_t *ctx, cp_mme_peer_t *peer, cp_msg_cc_cco_appoint_cnf_res_t result) { cp_mme_tx_t *mme; dbg_assert (ctx); dbg_assert (peer); dbg_assert (result < CP_MSG_CC_CCO_APPOINT_CNF_RES_NB); mme = cp_msg_mme_init (ctx, peer, CC_CCO_APPOINT_CNF); dbg_assert (mme); bitstream_write (&mme->bitstream, result, 8); cp_msg_mme_send (ctx, mme); } bool cp_msg_cc_cco_appoint_cnf_receive (cp_t *ctx, cp_mme_rx_t *mme, cp_msg_cc_cco_appoint_cnf_res_t *result) { dbg_assert (ctx); dbg_assert (mme); dbg_assert (result); if (cp_msg_mme_read_error (ctx, mme)) { *result = bitstream_read (&mme->bitstream, 8); if ((*result >= CP_MSG_CC_CCO_APPOINT_CNF_RES_NB) || (!cp_msg_mme_read_end_check (ctx, mme))) return false; return true; } return false; }