/* Cesar project {{{ * * Copyright (C) 2008 Spidcom * * <<>> * * }}} */ /** * \file cp/sta/action/src/bridge.c * \brief STA action, bridge table related implementations. * \ingroup cp_sta_action * * Bridge table request and reception implementations. */ #include "common/std.h" #include "cp/mme.h" // cp_mme_rx_t #include "cp/msg/msg.h" // to include cp/msg/inc/msg_cm.h #include "cp/msg/inc/msg_cm.h" // cp_msg_cm_brg_info_cnf_receive_* #include "cp/sta/mgr/sta_mgr.h" // cp_sta_mgr_get_our_avln #include "cp/sta/mgr/sta.h" // cp_sta_get_peer #include "cp/sta/mgr/net.h" // cp_net_sta_get_* #include "cl/cl_mactotei.h" // cl_mactotei_* #include "cp/inc/context.h" // cp_t #include "cl/bridge_table.h" // bridge_table_* #include "lib/utils.h" // less_mod2p32 #include "cp/sta/action/bridge.h" /** * Send a CM_BRG_INFO.CNF with the local bridge table of the CL. * \param ctx the CP context. * \param peer_dst the destination peer of the MME to send. */ static void cp_sta_action_send_cm_brg_info_cnf (cp_t *ctx, cp_mme_peer_t *peer_dst) { /* Check parameters. */ dbg_assert (ctx); dbg_assert (peer_dst); /* We are always doing bridging function. */ const uint bsf = 1; /* Number of entry in the bridge table. */ uint nbda = bridge_table_size (ctx->cl); /* Limit size of the message. */ if (nbda >= 0xff) nbda = 0xff; /* Create the reply message (CM_BRG_INFO.CNF). */ cp_mme_tx_t * reply = cp_msg_cm_brg_info_cnf_send_begin (ctx, peer_dst, bsf, nbda, cp_sta_own_data_get_tei (ctx)); /* Add one by one each entry of the bridge table. */ uint count; for (count = 0; count < nbda; count++) { cp_msg_cm_brg_info_cnf_send (ctx, reply, bridge_table_get_entry (ctx->cl, count)); } /* Send the reply. */ cp_msg_cm_brg_info_cnf_send_end (ctx, reply); } void cp_sta_action_bridge_init (cp_t *ctx) { /* Check parameter. */ dbg_assert (ctx); /* Bridge table default expiration values. */ ctx->sta_action.bridge.min_time_send_new_s = 5; ctx->sta_action.bridge.wait_time_without_update_s = 90; /* For bridge table update. In fact this variable should be set to * wait_time_without_update_s in order to emit the bridge table when the * station starts, but we prefer to wait at least min_time_send_new_s, * even for the first update. So, we set it to 0. */ ctx->sta_action.bridge.cycle_count_since_last_emission = 0; } void cp_sta_action_process_cm_brg_info_cnf (cp_t *ctx, cp_mme_rx_t *mme) { /* Check parameters. */ dbg_assert (ctx); dbg_assert (mme); /* Start decoding the message. */ uint bsf, nbda; if (cp_msg_cm_brg_info_cnf_receive_begin (ctx, mme, &bsf, &nbda)) { bool error = 0; /* Peer must be able to bridge and have a table with at least one * entry. */ if ((bsf == 1) && (nbda > 0)) { /* Create a new table. */ cl_mactotei_blk_t *new_table = cl_mactotei_new (); /* Copy entries except the old ones. */ cl_mactotei_copy_except_tag (ctx->cl, new_table, mme->peer.tei); /* Copy also the multicast group if exist */ cl_mactotei_copy_tei_and_tag (ctx->cl, new_table, MAC_TEI_BCAST, mme->peer.tei); /* Add new entries. */ uint count; mac_t bda; for (count = 0; count < nbda; count++) { /* Get bridged destination address. */ if (!cp_msg_cm_brg_info_cnf_receive (ctx, mme, &bda) || mac_is_multicast (bda)) { /* Error in get or multicast/broadcast MAC address. */ error = 1; break; } /* Add bridged destination address. */ cl_mactotei_addr_add (new_table, bda, mme->peer.tei, mme->peer.tei); } /* Error? */ if (error == 1) { /* Cancel the creation of the new MAC to TEI table, and keep * using the old one. */ cl_mactotei_cancel (new_table); } else { /* Use new MAC to TEI table. */ cl_mactotei_use_table (ctx->cl, new_table); cl_update_igmp_groups (ctx->cl); } } /* End MME decoding if there are no error. */ if (error == 0) cp_msg_cm_brg_info_cnf_receive_end (ctx, mme); } } void cp_sta_action_process_cm_brg_info_req (cp_t *ctx, cp_mme_rx_t *mme) { /* Check parameters. */ dbg_assert (ctx); dbg_assert (mme); /* Check if the message is correct. */ if (cp_msg_cm_brg_info_req_receive (ctx, mme)) { /* Reply to peer with the local bridge table. */ cp_sta_action_send_cm_brg_info_cnf (ctx, &mme->peer); } } void cp_sta_action_update_bridge_table (cp_t *ctx) { /* Check parameter. */ dbg_assert (ctx); /* Flag to know if the bridge table has been updated (modified) and need * to be sent. */ static bool new_table_to_send = false; /* If we are not over the wait_time_without_update_s value, we increments * the cycle_count_since_last_emission. */ if (ctx->sta_action.bridge.cycle_count_since_last_emission <= ctx->sta_action.bridge.wait_time_without_update_s) ctx->sta_action.bridge.cycle_count_since_last_emission++; /* Update bridge table. */ bool update = bridge_table_update (ctx->cl); /* Update flag if needed. */ if (!new_table_to_send) new_table_to_send = update; /* Send the bridge table with a CM_BRG_INFO.CNF if: * - the table is not empty and (date can not be checked or last emission * is more than wait_time_without_update_s) * or * - a new table has not been sent yet (we must wait at least * min_time_send_new_s if date are valid). */ if ( ((bridge_table_size (ctx->cl) > 0) && (ctx->sta_action.bridge.cycle_count_since_last_emission >= ctx->sta_action.bridge.wait_time_without_update_s)) || (new_table_to_send && (ctx->sta_action.bridge.cycle_count_since_last_emission >= ctx->sta_action.bridge.min_time_send_new_s)) ) { /* Sent the local bridge table in mutli-unicast if we are * authenticated. */ if (cp_sta_own_data_get_authenticated_status (ctx)) { cp_mme_peer_t peer = CP_MME_PEER_ALL_STA; cp_sta_action_send_cm_brg_info_cnf (ctx, &peer); /* Reset cycle counter since last emission. */ ctx->sta_action.bridge.cycle_count_since_last_emission = 0; /* Reset flag for new table to send. */ new_table_to_send = false; } } } void cp_sta_action_bridge_first_com (cp_t *ctx, cp_net_t *net, cp_sta_t *sta) { /* Check parameter. */ dbg_assert (sta); /* ctx & net not directly used. */ /* Get peer. */ cp_mme_peer_t peer; cp_sta_get_peer (sta, &peer); /* Send MME. */ cp_sta_action_send_cm_brg_info_cnf (ctx, &peer); }