From d0b3049c4fd2e5d1956055df7f61c503c683b22b Mon Sep 17 00:00:00 2001 From: NĂ©lio Laranjeiro Date: Wed, 9 Feb 2011 14:54:52 +0100 Subject: cesar/cp/beacon: carefully process same network beacons, refs #2235 When a STA or CCo receives a beacon from its NID and SNID it should be careful and check some other data before processing it. See the ticket for all details. --- cesar/cp/beacon/src/beacon.c | 311 +++++++++++++++++++++++++++---------------- 1 file changed, 197 insertions(+), 114 deletions(-) (limited to 'cesar/cp/beacon/src/beacon.c') diff --git a/cesar/cp/beacon/src/beacon.c b/cesar/cp/beacon/src/beacon.c index 7ee0e6cfaf..b69cf9c83d 100644 --- a/cesar/cp/beacon/src/beacon.c +++ b/cesar/cp/beacon/src/beacon.c @@ -610,6 +610,197 @@ cp_beacon_poweron_init (cp_t *ctx) GPIO_TOGGLE (LED_BEACON_TX_RX); } +/** + * Process the central beacon received. + * \param ctx the module context. + * \param beacon the beacon to process. + * \param net the network associated with the beacon. + * \return the station from the sta_mgr if the beacon has been processed. + */ +static cp_sta_t* +cp_beacon_process_beacon_central ( + cp_t *ctx, bsu_beacon_t *beacon, cp_net_t *net) +{ + cp_sta_t *sta = NULL; + mac_t cco_mac = beacon->bmis.mac_address.present ? + beacon->bmis.mac_address.mac_address : MAC_ZERO; + cp_sta_own_data_t *own = cp_sta_mgr_get_sta_own_data (ctx); + /* I Should follow instruction from the beacon only if I track it. */ + if (own->nid_track == beacon->vf.nid + && own->tei_track == beacon->vf.stei + && beacon->params.rx_parameters.snid + == cp_sta_own_data_get_snid (ctx) + && own->cco_mac_addr_track == cco_mac) + { + net->hm = beacon->vf.hm; + net->avln_num_slots = beacon->vf.numslots; + cp_net_set_access (ctx, net, beacon->params.rx_parameters.access); + cp_net_set_slot_id_and_usage (ctx, net, beacon->vf.slotid, + beacon->vf.slotusage); + sta = cp_beacon_update_sta_peer (ctx, beacon, net); + if (beacon->params.frequency_error_valid + && ctx->beacon.spoc_update_interval_ms + && less_mod2p32 ( + ctx->beacon.spoc_update_date, phy_date ())) + { + cp_beacon_clk_sync_call_spoc ( + ctx, beacon->params.frequency_error); + ctx->beacon.spoc_update_date = phy_date () + + MAC_MS_TO_TCK (ctx->beacon.spoc_update_interval_ms); + ctx->beacon.spoc_updated = true; + CP_TRACE_VERBOSE (SPOC, beacon->params.frequency_error); + } + /* I'm at least associated. */ + if (cp_sta_own_data_get_tei (ctx)) + { + /* Update the countdowns. */ + if (beacon->bmis.change_snid.present) + { + ctx->beacon.snids.snidcd + = beacon->bmis.change_snid.snidccd; + ctx->beacon.snids.snid + = beacon->bmis.change_snid.new_snid; + } + if (beacon->bmis.change_hm.present) + { + ctx->beacon.hm.hmcd = + beacon->bmis.change_hm.hmccd; + ctx->beacon.hm.hm = beacon->bmis.change_hm.newhm; + } + if (beacon->bmis.handover.present) + { + ctx->beacon.hoip.hoipcd = + beacon->bmis.handover.hcd; + ctx->beacon.hoip.cco = beacon->bmis.handover.tei; + } + if (beacon->bmis.eks.present) + { + ctx->beacon.eks.kccd = beacon->bmis.eks.kccd; + ctx->beacon.eks.kbc = beacon->bmis.eks.kbc; + ctx->beacon.eks.new_eks = + beacon->bmis.eks.new_eks; + } + /** Update the schedules. */ + cp_beacon_sta_compute_schedules (ctx, beacon); + bsu_beacon_bmi_discover_info_t discover; + cp_beacon_fill_discover_info (ctx, &discover); + bsu_update_discover_info (&discover); + /** Program the timer. */ + cp_beacon_reconfigure_timer (ctx, false); + } + } + /* I'm not associated or the beacon comes from another Network. */ + else if (!cp_sta_own_data_get_tei (ctx) + || (cp_sta_own_data_get_nid (ctx) != beacon->vf.nid + || (cp_sta_own_data_get_nid (ctx) == beacon->vf.nid + && cp_sta_own_data_get_snid (ctx) + != beacon->params.rx_parameters.snid))) + { + net->hm = beacon->vf.hm; + net->avln_num_slots = beacon->vf.numslots; + cp_net_set_access (ctx, net, beacon->params.rx_parameters.access); + cp_net_set_slot_id_and_usage (ctx, net, beacon->vf.slotid, + beacon->vf.slotusage); + sta = cp_beacon_update_sta_peer (ctx, beacon, net); + } + return sta; +} + +/** + * Process the discover beacon received. + * \param ctx the module context. + * \param beacon the beacon to process. + * \param net the network associated with the beacon. + * \return the station from the sta_mgr if the beacon has been processed. + */ +static cp_sta_t* +cp_beacon_process_beacon_discover ( + cp_t *ctx, bsu_beacon_t *beacon, cp_net_t *net) +{ + mac_t peer_mac = beacon->bmis.mac_address.present ? + beacon->bmis.mac_address.mac_address : MAC_ZERO; + cp_sta_t *sta = cp_sta_mgr_sta_get_from_mac (ctx, peer_mac); + /* The station exists in the station manager. */ + if (sta && cp_sta_get_tei (sta) == beacon->vf.stei) + { + sta = cp_beacon_update_sta_peer (ctx, beacon, net); + /* Discover beacons from our AVLN. */ + if (cp_sta_own_data_get_tei (ctx) + && cp_sta_mgr_get_our_avln (ctx) == net) + { + bool updated = bitstream_direct_read ( + &beacon->bmis.discover_info.info_data, 0, 1); + if (updated) + { + cp_fsm_event_t *event = cp_fsm_event_sta_new ( + ctx, CP_FSM_EVENT_TYPE_discover_info_updated, + net, sta); + cp_fsm_post (ctx, event); + } + } + /* This reference is return by the station update peer. */ + slab_release (sta); + } + /* Station does not exits, only the station from another AVLN should be + * added in the station manager. */ + else if (beacon->vf.nid != cp_sta_own_data_get_nid (ctx) + || (beacon->vf.nid == cp_sta_own_data_get_nid (ctx) + && beacon->params.rx_parameters.snid + != cp_sta_own_data_get_snid (ctx))) + { + sta = cp_beacon_update_sta_peer (ctx, beacon, net); + /* This reference is return by the station update peer. */ + slab_release (sta); + } + return sta; +} + +/** + * Process beacons. + * \param ctx the module context. + * \param beacon the beacon to process. + */ +static void +cp_beacon_process_beacon (cp_t *ctx, bsu_beacon_t *beacon) +{ + /** Add network and station info to local data. */ + cp_net_t *net = cp_sta_mgr_add_avln ( + ctx, beacon->params.rx_parameters.snid, beacon->vf.nid); + /** If no NET object available, do not process this beacon. + * This can happen on SNID conflict when some AVLN are powered on at + * the time, the SNID conflict will cause the CP to create a net + * object for each new tuple of {nid, snid}. STA mgr garbage should + * resolve the problem by removing the old AVLN but it takes its + * time. */ + if (net && MAC_TEI_IS_STA (beacon->vf.stei)) + { + cp_sta_t *sta = NULL; + if (beacon->vf.bt == BSU_BEACON_TYPE_CENTRAL) + sta = cp_beacon_process_beacon_central (ctx, beacon, net); + else if (beacon->vf.bt == BSU_BEACON_TYPE_DISCOVER) + sta = cp_beacon_process_beacon_discover (ctx, beacon, net); + /* Is the SNID in conflict. */ + if (cp_sta_own_data_get_cco_status (ctx)) + { + cp_net_t *our_net = cp_sta_mgr_get_our_avln (ctx); + if (our_net != net + && cp_net_get_snid (ctx, our_net) + == cp_net_get_snid (ctx, net) + && ctx->beacon.snids.snidcd == 0) + cp_fsm_post_new_event (ctx, bare, snid_conflict); + } + /* Raise the event in the FSM for station action. */ + if (sta + && (beacon->vf.bt == BSU_BEACON_TYPE_CENTRAL + || beacon->vf.bt == BSU_BEACON_TYPE_PROXY)) + cp_fsm_post_new_event ( + ctx, beacon, BEACON, beacon, net, sta); + /* Release my reference on the STA. */ + if (sta) + slab_release (sta); + } +} + /** * Process the first beacon in the received list. * \param ctx the control plane context. @@ -618,9 +809,6 @@ void cp_beacon_get_and_process_beacon (cp_t *ctx) { dbg_assert (ctx); - cp_net_t *net; - cp_sta_t *sta; - cp_sta_own_data_t *own; bsu_beacon_t *beacon; /** check the countdowns. */ cp_beacon_countdowns (ctx); @@ -637,117 +825,7 @@ cp_beacon_get_and_process_beacon (cp_t *ctx) BEACON_BEACON_PROCESS, phy_date(), beacon->vf.nid, beacon->params.rx_parameters.snid, beacon->vf.stei, beacon->vf.bt, beacon->params.rx_parameters.bts); - /** Add network and station info to local data. */ - net = cp_sta_mgr_add_avln ( - ctx, beacon->params.rx_parameters.snid, beacon->vf.nid); - /** If no NET object available, do not process this beacon. - * This can happen on SNID conflict when some AVLN are powered on at - * the time, the SNID conflict will cause the CP to create a net - * object for each new tuple of {nid, snid}. STA mgr garbage should - * resolve the problem by removing the old AVLN but it takes its - * time. */ - if (net) - { - net->hm = beacon->vf.hm; - net->avln_num_slots = beacon->vf.numslots; - cp_net_set_access (ctx, net, beacon->params.rx_parameters.access); - cp_net_set_slot_id_and_usage (ctx, net, beacon->vf.slotid, - beacon->vf.slotusage); - dbg_assert (beacon->vf.stei == MAC_TEI_UNASSOCIATED - || MAC_TEI_IS_STA (beacon->vf.stei)); - sta = cp_beacon_update_sta_peer (ctx, beacon, net); - /** Our station is associated and the beacon is from our CCo. */ - own = cp_sta_mgr_get_sta_own_data (ctx); - if (beacon->vf.bt == BSU_BEACON_TYPE_CENTRAL - && beacon->vf.nid == own->nid_track - && beacon->vf.stei == own->tei_track - && beacon->params.rx_parameters.snid - == cp_sta_own_data_get_snid (ctx)) - { - if (beacon->params.frequency_error_valid - && ctx->beacon.spoc_update_interval_ms - && less_mod2p32 ( - ctx->beacon.spoc_update_date, phy_date ())) - { - cp_beacon_clk_sync_call_spoc ( - ctx, beacon->params.frequency_error); - ctx->beacon.spoc_update_date = phy_date () - + MAC_MS_TO_TCK (ctx->beacon.spoc_update_interval_ms); - ctx->beacon.spoc_updated = true; - CP_TRACE_VERBOSE (SPOC, beacon->params.frequency_error); - } - if (cp_sta_own_data_get_tei (ctx)) - { - /* Update the countdowns. */ - if (beacon->bmis.change_snid.present) - { - ctx->beacon.snids.snidcd - = beacon->bmis.change_snid.snidccd; - ctx->beacon.snids.snid - = beacon->bmis.change_snid.new_snid; - } - if (beacon->bmis.change_hm.present) - { - ctx->beacon.hm.hmcd = - beacon->bmis.change_hm.hmccd; - ctx->beacon.hm.hm = beacon->bmis.change_hm.newhm; - } - if (beacon->bmis.handover.present) - { - ctx->beacon.hoip.hoipcd = - beacon->bmis.handover.hcd; - ctx->beacon.hoip.cco = beacon->bmis.handover.tei; - } - if (beacon->bmis.eks.present) - { - ctx->beacon.eks.kccd = beacon->bmis.eks.kccd; - ctx->beacon.eks.kbc = beacon->bmis.eks.kbc; - ctx->beacon.eks.new_eks = - beacon->bmis.eks.new_eks; - } - /** Update the schedules. */ - cp_beacon_sta_compute_schedules (ctx, beacon); - bsu_beacon_bmi_discover_info_t discover; - cp_beacon_fill_discover_info (ctx, &discover); - bsu_update_discover_info (&discover); - /** Program the timer. */ - cp_beacon_reconfigure_timer (ctx, false); - } - } - /* Discover beacons from our AVLN. */ - else if (cp_sta_own_data_get_tei (ctx) - && beacon->vf.bt == BSU_BEACON_TYPE_DISCOVER - && beacon->vf.nid == cp_sta_own_data_get_nid (ctx) - && beacon->params.rx_parameters.snid - == cp_sta_own_data_get_snid (ctx)) - { - bool updated = bitstream_direct_read ( - &beacon->bmis.discover_info.info_data, 0, 1); - if (updated) - { - cp_fsm_event_t *event = cp_fsm_event_sta_new ( - ctx, CP_FSM_EVENT_TYPE_discover_info_updated, - net, sta); - cp_fsm_post (ctx, event); - } - } - else if (cp_sta_own_data_get_cco_status (ctx)) - { - /* Is the SNID in conflict. */ - cp_net_t *our_net = cp_sta_mgr_get_our_avln (ctx); - if (our_net != net - && cp_net_get_snid (ctx, our_net) - == cp_net_get_snid (ctx, net) - && ctx->beacon.snids.snidcd == 0) - cp_fsm_post_new_event (ctx, bare, snid_conflict); - } - /** Raise the event in the FSM for station action. */ - if (beacon->vf.bt == BSU_BEACON_TYPE_CENTRAL - || beacon->vf.bt == BSU_BEACON_TYPE_PROXY) - cp_fsm_post_new_event ( - ctx, beacon, BEACON, beacon, net, sta); - slab_release (sta); - } + cp_beacon_process_beacon (ctx, beacon); /** Release the beacon. */ blk_release (beacon); } @@ -762,6 +840,10 @@ cp_beacon_process_tracked_avln (cp_t *ctx, bsu_beacon_t *beacon, dbg_assert (beacon); dbg_assert (net); own = cp_sta_mgr_get_sta_own_data (ctx); + own->nid_track = beacon->vf.nid; + own->tei_track = beacon->vf.stei; + own->cco_mac_addr_track = beacon->bmis.mac_address.present ? + beacon->bmis.mac_address.mac_address : MAC_ZERO; own->hybrid_mode = beacon->vf.hm; /* SPOC. */ ctx->beacon.spoc_update_date = phy_date (); @@ -785,6 +867,7 @@ cp_beacon_process_untracked_avln (cp_t *ctx) cp_sta_own_data_t *own = cp_sta_mgr_get_sta_own_data (ctx); own->nid_track = 0; own->tei_track = 0; + own->cco_mac_addr_track = MAC_ZERO; /* Reset SPOC. */ ctx->beacon.spoc_updated = false; cp_beacon_clk_sync_call_spoc (ctx, 0); -- cgit v1.2.3