/* Cesar project {{{ * * Copyright (C) 2008 Spidcom * * <<>> * * }}} */ /** * \file cp/beacon/src/beacon.c * \brief Beacon Module. * \ingroup cp_beacon * * The beacon module is responsible for : * - When the station acts as CCo: * - Create the central beacon. * - Get the discover info from the others stations. */ #include "common/std.h" #include "lib/fixed.h" #include "lib/slist.h" #include "lib/stats.h" #include "string.h" #include "hal/arch/arch.h" #include "cp/defs.h" #include "cp/cp.h" #include "cp/fsm/fsm.h" #include "cp/beacon/beacon.h" #include "cp/cco/bw/bw.h" #include "mac/common/timings.h" #include "mac/common/ntb.h" #include "cp/beacon/inc/beacon.h" #include "cp/beacon/discover.h" #include "cp/inc/context.h" #include "cp/inc/trace.h" #include "hal/gpio/gpio.h" #include "bsu/beacon/beacon.h" #include "bsu/bsu.h" /** Default interval between SPOC updates. */ #define CP_BEACON_SPOC_UPDATE_INTERVAL_DEFAULT_MS 0 /** Timer expires. * \param ctx the CP context. */ static void cp_beacon_timer_expires (cp_t *ctx) { dbg_assert (ctx); // Post an event in the FSM beacon timer expires. cp_fsm_post_urgent_new_event (ctx, bare, BEACON_TIMER_EXPIRES); } /** * Get the next beacon shared memory to update. * \param ctx the control plane context. * \return a pointer on the next slot. */ static bsu_beacon_t * cp_get_next_beacon_shared_memory (cp_t *ctx) { bsu_beacon_t *next_beacon_shared_memory = &ctx->beacon.shared_mem[ctx->beacon.shared_mem_slot_id]; ctx->beacon.shared_mem_slot_id++; ctx->beacon.shared_mem_slot_id %= CP_SHARED_MEM_SLOT_NB; return next_beacon_shared_memory; } /** * Fill the discover info beacon entry. * \param ctx the module context. * \param beacon the beacon to fill. */ static void cp_beacon_fill_discover_info (cp_t *ctx, bsu_beacon_bmi_discover_info_t *discover) { cp_sta_own_data_t *sta = cp_sta_mgr_get_sta_own_data (ctx); bitstream_t stream; bitstream_write_init (&stream, &discover->info_data, 4); bitstream_write (&stream, 0, 1); bitstream_write (&stream, CP_CCO_LEVEL, 2); bitstream_write (&stream, CP_PCO_CAP, 1); bitstream_write (&stream, CP_BACKUP_CCO_CAP, 1); bitstream_write (&stream, cp_sta_own_data_get_cco_status (ctx), 1); bitstream_write (&stream, cp_sta_own_data_get_pco_status (ctx), 1); bitstream_write (&stream, false, 1); bitstream_write (&stream, cp_sta_mgr_get_num_discovered_stas (ctx), 8); bitstream_write (&stream, cp_sta_mgr_get_num_discovered_net (ctx), 8); bitstream_write (&stream, cp_sta_own_data_get_authenticated_status (ctx), 1); bitstream_write (&stream, sta->cco_prefered, 1); bitstream_write (&stream, 0, 6); bitstream_finalise (&stream); u32 last = bitstream_direct_read (&ctx->beacon.discover_info_last, 1, 31); u32 new = bitstream_direct_read (&discover->info_data, 1, 31); /* Updated ? */ bitstream_direct_write (&discover->info_data, 0, new != last, 1); ctx->beacon.discover_info_last = discover->info_data; discover->present = true; } static void cp_beacon_clk_sync_call_spoc (cp_t *ctx, u32 fe) { dbg_assert (ctx); phy_spoc_coeff_t *coeff = blk_alloc (); coeff->part2 = blk_alloc(); phy_spoc_compute_all (fe, coeff); pbproc_spoc_coeff_set (ctx->pbproc, coeff); } bsu_beacon_t * cp_beacon_fill_share_memory (cp_t *ctx) { bsu_beacon_t *beacon; cp_sta_own_data_t *sta; cp_net_t *net = NULL; uint nb, ns; beacon = cp_get_next_beacon_shared_memory (ctx); dbg_assert (beacon); beacon->beacon_period_start_date = bsu_aclf_beacon_period_start_date_next (ctx->bsu_aclf); sta = cp_sta_mgr_get_sta_own_data (ctx); if (cp_sta_own_data_get_tei (ctx)) net = cp_sta_mgr_get_our_avln (ctx); beacon->vf.nid = cp_sta_own_data_get_nid (ctx); beacon->vf.hm = sta->hybrid_mode; beacon->vf.ncnr = CP_BEACON_NON_COORDINATED_NETWORK; beacon->vf.npsm = CP_BEACON_NPSM_NOT_ACTIVE; beacon->vf.numslots = 1; beacon->vf.slotusage = cp_sta_mgr_get_slot_usage (ctx); beacon->vf.slotid = net == NULL ? 0 : cp_net_get_slot_id (ctx, net); beacon->vf.aclsss = 0; beacon->vf.hoip = ctx->beacon.hoip.hoip_flag; beacon->vf.rtsbf = false; beacon->vf.nm = BSU_BEACON_NM_CSMA_ONLY; beacon->vf.ccocap = CP_CCO_LEVEL; /* regions. */ cp_cco_region_alloc_t *region; for (nb = 0, region = cp_cco_region_alloc_get_first (ctx, &ctx->region.region_list); region; region = cp_cco_region_alloc_get_next (ctx, &ctx->region.region_list, region), nb++) { beacon->bmis.region.region[nb].rt = region->type; beacon->bmis.region.region[nb].end_time_atu = region->end_time_atu; } beacon->bmis.region.nb = nb; /* Store the persistent schedules. */ uint sched_id = 0; cp_cco_bw_alloc_t *sched; for (nb = 0; nb < 8; nb++) { for (ns = 0, sched = cp_cco_bw_alloc_get_first_persistent (ctx, &ctx->bw.alloc_list, nb); sched; sched = cp_cco_bw_alloc_get_next_persistent (ctx, &ctx->bw.alloc_list, sched), ns++) { dbg_assert (sched_id < BSU_BEACON_BMI_PERSISTENT_SCHEDULE_MAX); beacon->bmis.ps.ps[sched_id].sais[ns].stpf = sched->stpf; beacon->bmis.ps.ps[sched_id].sais[ns].glid = sched->glid; beacon->bmis.ps.ps[sched_id].sais[ns].start_time_atu = sched->start_time_atu; beacon->bmis.ps.ps[sched_id].sais[ns].end_time_atu = sched->end_time_atu; if (ns == 0) { beacon->bmis.ps.ps[sched_id].pscd = sched->pscd; beacon->bmis.ps.ps[sched_id].cscd = sched->cscd; } } if (ns) { beacon->bmis.ps.ps[sched_id].ns = ns; sched_id++; } } beacon->bmis.ps.nb = sched_id; /* Store the not persistent schedules. */ for (ns = 0, sched = cp_cco_bw_alloc_get_first_with_persistence (ctx, &ctx->bw.alloc_list, CP_CCO_BW_ALLOC_PERSISTENCE_NOT_PERSISTENT); sched; sched = cp_cco_bw_alloc_get_next_with_persistence (ctx, &ctx->bw.alloc_list, sched), ns++) { dbg_assert (ns < BSU_BEACON_BMIS_SCHEDULES_SAI_MAX); beacon->bmis.nps.sais[ns].stpf = sched->stpf; beacon->bmis.nps.sais[ns].glid = sched->glid; beacon->bmis.nps.sais[ns].start_time_atu = sched->start_time_atu; beacon->bmis.nps.sais[ns].end_time_atu = sched->end_time_atu; } beacon->bmis.nps.ns = ns; uint tei; if (cp_sta_own_data_get_cco_status (ctx) && cp_beacon_discover_need_to_request (ctx, &tei)) { beacon->bmis.discover.present = true; beacon->bmis.discover.tei = tei; } else beacon->bmis.discover.present = false; cp_beacon_fill_discover_info (ctx, &beacon->bmis.discover_info); /* If the EKS countdown is not 0. */ if (ctx->beacon.eks.kccd) { beacon->bmis.eks.present = true; beacon->bmis.eks.kccd = ctx->beacon.eks.kccd; beacon->bmis.eks.kbc = ctx->beacon.eks.kbc; beacon->bmis.eks.new_eks = ctx->beacon.eks.new_eks; } else beacon->bmis.eks.present = false; /* If the handover countdown is not 0. */ if (ctx->beacon.hoip.hoipcd) { beacon->bmis.handover.present = true; beacon->bmis.handover.hcd = ctx->beacon.hoip.hoipcd; beacon->bmis.handover.tei = ctx->beacon.hoip.cco; } else beacon->bmis.handover.present = false; /* If the hybrid mode countdown is not 0. */ if (ctx->beacon.hm.hmcd) { beacon->bmis.change_hm.present = true; beacon->bmis.change_hm.hmccd = ctx->beacon.hm.hmcd; beacon->bmis.change_hm.newhm = ctx->beacon.hm.hm; } else beacon->bmis.change_hm.present = false; /* If the snid countdown is not 0. */ if (ctx->beacon.snids.snidcd) { beacon->bmis.change_snid.present = true; beacon->bmis.change_snid.snidccd = ctx->beacon.snids.snidcd; beacon->bmis.change_snid.new_snid = ctx->beacon.snids.snid; } else beacon->bmis.change_snid.present = false; beacon->bmis.bpsto.present = (beacon->vf.nm == BSU_BEACON_NM_CSMA_ONLY); beacon->bmis.relocation.present = false; beacon->bmis.aclsc.present = false; beacon->bmis.cns.present = false; beacon->bmis.mac_address_present.present = true; return beacon; } /** * The beacon received from the AVLN. * \param ctx the module context. * \param beacon The beacon received. * * Add the beacon to the list of received beacon, and raise the flag * beacon received in STA_CORE */ void cp_beacon_receive (void *ul, pb_beacon_t * beacon, bsu_params_t *params) { cp_t *ctx = (cp_t *) ul; dbg_assert (ul); dbg_assert (beacon); dbg_assert (params); interface_beacon (ctx->interface, beacon, params); if (params->direction == BSU_BEACON_DIRECTION_FROM_PLC) { beacon->next = NULL; slist_push_back (ctx->beacon.list., beacon, bare); cp_sta_core_signal_recv_beacon_event (ctx); } else { /* The station is CCo, release the beacon. */ blk_release_desc ((blk_t*) beacon); } } /** * Set the sai in the schedule. */ static inline void cp_beacon_set_sai_in_sched (cp_cco_bw_alloc_t *sched, bsu_beacon_sai_t* sai) { sched->end_time_atu = sai->end_time_atu; sched->glid = sai->glid | 0x80; sched->stpf = sai->stpf; } /** * Add the allocation of the beacon to the bandwidth manager. * \param ctx the Module context. * \param unpack the unpack structure. * \param bts the beacon time stamp. * \param btos the array of beacon time offset. */ static void cp_beacon_sta_compute_schedules (cp_t *ctx, bsu_beacon_t *beacon_data) { dbg_assert (ctx); dbg_assert (beacon_data); uint i, j; /** Organize the schedules contained in beacon_data as a set. */ set_t set_schedules; cp_cco_bw_alloc_t *sched; set_init (&set_schedules, cp_cco_bw_alloc_less); for (i = 0; i < beacon_data->bmis.nps.ns; i++) { sched = cp_cco_bw_alloc_init(ctx); cp_beacon_set_sai_in_sched (sched, &beacon_data->bmis.nps.sais[i]); if (sched->stpf) sched->start_time_atu = beacon_data->bmis.nps.sais[i].start_time_atu; cp_cco_bw_alloc_add (ctx, &set_schedules, sched); slab_release (sched); } for (i = 0; i < beacon_data->bmis.ps.nb; i++) { for (j = 0; j < beacon_data->bmis.ps.ps[i].ns; j++) { sched = cp_cco_bw_alloc_init(ctx); sched->cscd = beacon_data->bmis.ps.ps[i].cscd; sched->pscd = beacon_data->bmis.ps.ps[i].pscd; cp_beacon_set_sai_in_sched (sched, &beacon_data->bmis.ps.ps[i].sais[j]); if (sched->stpf) sched->start_time_atu = beacon_data->bmis.ps.ps[i].sais[j].start_time_atu; cp_cco_bw_alloc_add (ctx, &set_schedules, sched); slab_release (sched); } } /** Organize the regions contained in beacon_data as a set. */ cp_cco_region_alloc_t *region; set_t set_regions; set_init (&set_regions, cp_cco_region_alloc_less); for (i = 0; i < beacon_data->bmis.region.nb; i++) { region = cp_cco_region_alloc_init (ctx); region->type = beacon_data->bmis.region.region[i].rt; region->end_time_atu = beacon_data->bmis.region.region[i].end_time_atu; cp_cco_region_alloc_add (ctx, &set_regions, region); slab_release (region); } cp_cco_bw_allocation_list_swap (ctx, &set_schedules); cp_cco_region_allocation_list_swap (ctx, &set_regions); } /** * Update the station in the station manager with the data contained in the * beacon. * \param ctx the module context. * \param beacon_data the beacon data. * \param net the network corresponding to the beacon. * \param type the beacon type. * \param tei the Source TEI present in the beacon. * \param mac_address the Source MAC Address if present in beacon. * return the control plane station. */ static cp_sta_t * cp_beacon_update_sta_peer (cp_t *ctx, bsu_beacon_t *beacon_data, cp_net_t *net, bsu_beacon_type_t type, cp_tei_t tei, mac_t mac_address) { cp_sta_t *sta; mac_t mac; dbg_assert (ctx); dbg_assert (beacon_data); dbg_assert (net); /** Handle the absence of Mac address bentry in the Central beacon. */ mac = beacon_data->bmis.mac_address_present.present ? mac_address : MAC_BROADCAST; sta = cp_sta_mgr_sta_add (ctx, net, tei, mac); dbg_assert (sta); /* Is the station UCCo. */ if ((type == CP_BEACON_DISCOVER_BEACON) && (tei == MAC_TEI_UNASSOCIATED)) { cp_net_set_ucco (ctx, net, sta); } else if (type == CP_BEACON_CENTRAL_BEACON) { cp_net_set_cco (ctx, net, tei); cp_sta_set_authenticated (ctx, sta, true); } else if (type == CP_BEACON_PROXY_BEACON) { cp_net_set_pco (ctx, net, tei); cp_sta_set_authenticated (ctx, sta, true); } if (beacon_data->bmis.discover_info.present) { cp_beacon_discover_info_t info_data = *(cp_beacon_discover_info_t*) &beacon_data->bmis.discover_info.info_data; sta->is_backup_cco = info_data.backup_cco_status; sta->cco_cap = info_data.cco_cap; sta->pco_cap = info_data.proxy_net_cap; sta->backup_cco_cap = info_data.backup_cco_cap; sta->numDisSta = info_data.num_dis_sta; sta->numDisNet = info_data.num_dis_net; if (info_data.cco_status) cp_net_set_cco (ctx, net, tei); if (info_data.pco_status) cp_net_set_pco (ctx, net, tei); cp_sta_set_authenticated (ctx, sta, info_data.authentication); } return sta; } /** * Countdown decrement and process the necessary data. * \param ctx the CP context. */ static void cp_beacon_countdowns (cp_t *ctx) { dbg_assert (ctx); // TODO DM: is this test really usefull? if (less_mod2p32 (ctx->beacon.countdown_limit_date, phy_date ())) { u32 intervals; /** Check the interval: * We want to know how many beacon period elapsed. */ u32 bp = bsu_aclf_beacon_period_tck (ctx->bsu_aclf); dbg_assert (bp); bsu_aclf_beacon_period_start_date (ctx->bsu_aclf, &intervals, 1); intervals = (intervals + bp/2 - ctx->beacon.last_countdown_date) / bp; /** We missed too many beacon period we shouldn't be associated * anymore. */ if (intervals > CP_MAX_NO_BEACON + 1) { return; } ctx->beacon.last_countdown_date = ctx->beacon.countdown_limit_date; /** Update the countdown limit for next time. */ ctx->beacon.countdown_limit_date = bsu_aclf_beacon_period_start_date_next (ctx->bsu_aclf); /* Snid... */ if (ctx->beacon.snids.snidcd) { if (ctx->beacon.snids.snidcd <= intervals) { ctx->beacon.snids.snidcd = 0; cp_sta_own_data_set_snid (ctx, ctx->beacon.snids.snid); } else ctx->beacon.snids.snidcd -= intervals; } /* Hybrid mode... */ if (ctx->beacon.hm.hmcd) { if (ctx->beacon.hm.hmcd <= intervals) { cp_sta_own_data_t *own = cp_sta_mgr_get_sta_own_data (ctx); ctx->beacon.hm.hmcd = 0; own->hybrid_mode = ctx->beacon.hm.hm; } else ctx->beacon.hm.hmcd -= intervals; } /* Handover in progress... */ if (ctx->beacon.hoip.hoipcd) { if (ctx->beacon.hoip.hoipcd <= intervals) { cp_sta_t *sta; cp_net_t *net; ctx->beacon.hoip.hoipcd = 0; net = cp_sta_mgr_get_our_avln (ctx); if (cp_sta_own_data_get_tei (ctx) == ctx->beacon.hoip.cco) { cp_fsm_post_new_event (ctx, bare, HOIP_EXPIRED); } else { sta = cp_sta_mgr_sta_get_assoc (ctx, net, ctx->beacon.hoip.cco); cp_net_set_cco (ctx, net, ctx->beacon.hoip.cco); cp_fsm_post_new_event (ctx, sta, HOIP_EXPIRED, net, sta); } } else ctx->beacon.hoip.hoipcd -= intervals; } /* EKS ... */ if (ctx->beacon.eks.kccd) { if (ctx->beacon.eks.kccd <= intervals) ctx->beacon.eks.kccd = 0; else ctx->beacon.eks.kccd -= intervals; } } } /** * Initialise the beacon module. * \param ctx the module context. */ void cp_beacon_init (cp_t *ctx) { dbg_assert (ctx); // Initialise the beacon module. memset (&ctx->beacon, 0, sizeof (cp_beacon_t)); slist_init (ctx->beacon.list., bare); // Initialise the instance of the leon timer. hal_timer_instance_init (ctx->hal_timer, &ctx->beacon.leon_timer, ctx, (hal_timer_instance_cb_t)cp_beacon_timer_expires); // Initialise the mem_share_slot_id so that the next slot is 0. ctx->beacon.shared_mem_slot_id = CP_SHARED_MEM_SLOT_NB - 1; /* Setup beacon indicator. */ GPIO_SETUP (LED_BEACON_TX_RX, GPIO_DIRECTION_OUT); GPIO_SET (LED_BEACON_TX_RX, 0); bsu_init_beacon_cb (cp_beacon_receive, ctx); /* Store the current date for SPOC update coefficients. */ ctx->beacon.spoc_update_date = phy_date (); /* Initialise tunable parameters. */ ctx->beacon.spoc_update_interval_ms = CP_BEACON_SPOC_UPDATE_INTERVAL_DEFAULT_MS; lib_stats_set_stat_value_notype ("SPOC_UPDATE_INTERVAL_MS", &ctx->beacon.spoc_update_interval_ms, LIB_STATS_ACCESS_WRITE_ONLY, LIB_STATS_DEBUG); } /** * Uninitialise the beacon module. * \param ctx the module context. */ void cp_beacon_uninit (cp_t *ctx) { cp_beacon_deactivate (ctx); hal_timer_instance_uninit (ctx->hal_timer, &ctx->beacon.leon_timer); } static bsu_beacon_t* cp_beacon_update_beacon_data (cp_t *ctx, bool cco) { cp_beacon_countdowns (ctx); /** Generate the beacon and send. */ bsu_beacon_t *beacon = cp_beacon_fill_share_memory (ctx); /** Program the timer to awake and send another central beacon. */ cp_beacon_reconfigure_timer (ctx, cco); GPIO_TOGGLE (LED_BEACON_TX_RX); return beacon; } void cp_beacon_sta_update_beacon_data (cp_t *ctx) { dbg_assert (ctx); bsu_beacon_t *beacon = cp_beacon_update_beacon_data (ctx, false); bsu_update (beacon, BSU_UPDATE_STA_TYPE_STA); } void cp_beacon_cco_update_beacon_data (cp_t *ctx) { dbg_assert (ctx); bsu_beacon_t *beacon = cp_beacon_update_beacon_data (ctx, true); bsu_update (beacon, BSU_UPDATE_STA_TYPE_CCO); } void cp_beacon_ucco_update_beacon_data (cp_t *ctx) { dbg_assert (ctx); bsu_beacon_t *beacon = cp_beacon_update_beacon_data (ctx, true); bsu_update (beacon, BSU_UPDATE_STA_TYPE_UCCO); } void cp_beacon_poweron_init (cp_t *ctx) { dbg_assert (ctx); ctx->beacon.countdown_limit_date = ctx->beacon.last_countdown_date = phy_date (); /* Generate the beacon and send. */ bsu_beacon_t *beacon = cp_beacon_fill_share_memory (ctx); bsu_update (beacon, BSU_UPDATE_STA_TYPE_STA); GPIO_TOGGLE (LED_BEACON_TX_RX); } /** * Process the first beacon in the received list. * \param ctx the control plane context. */ void cp_beacon_get_and_process_beacon (cp_t *ctx) { dbg_assert (ctx); pb_beacon_t *pb_beacon; cp_net_t *net; cp_sta_t *sta; u64 nid; u8 snid; cp_sta_own_data_t *own; bsu_beacon_t beacon_data; bsu_beacon_type_t type; cp_tei_t tei = 0; mac_t mac_address; memset (&beacon_data, 0, sizeof (bsu_beacon_t)); /** check the countdowns. */ cp_beacon_countdowns (ctx); arch_dsr_lock (); pb_beacon = slist_pop_front (ctx->beacon.list., bare); arch_dsr_unlock (); bsu_params_t *bsu_params = &((cp_beacon_payload_t*)pb_beacon->data)->bsu_params; snid = bsu_params->rx_parameters.snid; u8 btei; if (!bsu_beacon_read (pb_beacon, &beacon_data, &type, &btei, &mac_address)) { /* The beacon contains some strange values. */ CP_TRACE (BEACON_UNPACK_ERROR, phy_date (), beacon_data.vf.nid, snid, tei, type, bsu_params->rx_parameters.bts); blk_release_desc ((blk_t *)pb_beacon); return; } tei = btei; /** Beacon received ok. */ GPIO_TOGGLE (LED_BEACON_TX_RX); nid = beacon_data.vf.nid; CP_TRACE_VERBOSE (BEACON_BEACON_PROCESS, phy_date(), nid, snid, tei, type, bsu_params->rx_parameters.bts); /** Add network and station info to local data. */ net = cp_sta_mgr_add_avln (ctx, snid, nid); net->hm = beacon_data.vf.hm; net->avln_num_slots = beacon_data.vf.numslots; cp_net_set_access (ctx, net, bsu_params->rx_parameters.access); cp_net_set_slot_id_and_usage (ctx, net, beacon_data.vf.slotid, beacon_data.vf.slotusage); dbg_assert (tei == MAC_TEI_UNASSOCIATED || MAC_TEI_IS_STA (tei)); sta = cp_beacon_update_sta_peer (ctx, &beacon_data, net, type, tei, mac_address); /** Our station is associated and the beacon is from our CCo. */ own = cp_sta_mgr_get_sta_own_data (ctx); if (cp_sta_own_data_get_tei (ctx) && (type == CP_BEACON_CENTRAL_BEACON) && (nid == own->nid_track) && (tei == own->tei_track) && (snid == cp_sta_own_data_get_snid (ctx))) { /* Update the countdowns. */ if (beacon_data.bmis.change_snid.present) { ctx->beacon.snids.snidcd = beacon_data.bmis.change_snid.snidccd; ctx->beacon.snids.snid = beacon_data.bmis.change_snid.new_snid; } if (beacon_data.bmis.change_hm.present) { ctx->beacon.hm.hmcd = beacon_data.bmis.change_hm.hmccd; ctx->beacon.hm.hm = beacon_data.bmis.change_hm.newhm; } if (beacon_data.bmis.handover.present) { ctx->beacon.hoip.hoipcd = beacon_data.bmis.handover.hcd; ctx->beacon.hoip.cco = beacon_data.bmis.handover.tei; } if (beacon_data.bmis.eks.present) { ctx->beacon.eks.kccd = beacon_data.bmis.eks.kccd; ctx->beacon.eks.kbc = beacon_data.bmis.eks.kbc; ctx->beacon.eks.new_eks = beacon_data.bmis.eks.new_eks; } if (ctx->beacon.spoc_update_interval_ms && less_mod2p32 (ctx->beacon.spoc_update_date, phy_date ())) { cp_beacon_clk_sync_call_spoc (ctx, bsu_params->frequency_error); ctx->beacon.spoc_update_date = phy_date () + MAC_MS_TO_TCK (ctx->beacon.spoc_update_interval_ms); } /** Update the schedules. */ cp_beacon_sta_compute_schedules (ctx, &beacon_data); 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) && type == CP_BEACON_DISCOVER_BEACON && nid == cp_sta_own_data_get_nid (ctx) && snid == cp_sta_own_data_get_snid (ctx)) { bool updated = bitstream_direct_read ( &beacon_data.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_tei (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. */ cp_fsm_post_new_event (ctx, beacon, BEACON, (cp_beacon_desc_t*)pb_beacon, net, sta); /** Release the beacon. */ blk_release_desc ((blk_t *)pb_beacon); /** Release the station provided the function which processed the beacon. * cp_beacon_process_central_proxy or cp_beacon_process_discover. */ slab_release (sta); } /** * Process a tracked network using the central beacon or the proxy beacon. * \param ctx the CP module context. * \param beacon the beacon received and tracked. */ void cp_beacon_process_tracked_avln (cp_t *ctx, cp_beacon_desc_t *beacon_desc, cp_net_t *net) { bsu_beacon_t beacon_data; bsu_beacon_type_t type; mac_t mac_address; cp_sta_own_data_t *own; dbg_assert (ctx); dbg_assert (beacon_desc); dbg_assert (net); memset (&beacon_data, 0, sizeof (bsu_beacon_t)); bsu_params_t *bsu_params = &beacon_desc->payload->bsu_params; u8 btei; bsu_beacon_read ((pb_beacon_t*)beacon_desc, &beacon_data, &type, &btei, &mac_address); own = cp_sta_mgr_get_sta_own_data (ctx); own->hybrid_mode = beacon_data.vf.hm; ctx->beacon.spoc_update_interval_ms = phy_date (); bsu_track_avln (beacon_data.vf.nid, bsu_params->rx_parameters.snid, btei, own->hybrid_mode); // Program the timer. cp_beacon_reconfigure_timer (ctx, false); } /** * Function to call once the beacon has not been received. * \param ctx the module context. * * The beacon timer has expired and this function had been called by the FSM. */ void cp_beacon_beacon_not_received (cp_t *ctx) { dbg_assert (ctx); cp_beacon_countdowns (ctx); cp_fsm_post_new_event (ctx, bare, BEACON_NOT_RECEIVED); /* Update the discover info for the BSU. */ 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); } /** * Set the nek in the beacon module. * \param ctx the CP context. * \param eks the eks tu use. * \param nek the nek key. * \param now indicate if the nek shall be use right now. */ void cp_beacon_change_nek (cp_t *ctx, uint eks, cp_key_t nek, bool now) { cp_key_t rnek; uint i,index; dbg_assert (ctx); dbg_assert (ctx->mac_config); if (now) index = bsu_nek_index_current (); else { index = bsu_nek_index_next (); ctx->beacon.eks.kccd = CP_BEACON_COUNTDOWN_EKS; ctx->beacon.eks.kbc = BSU_BEACON_EKS_KBC_NEK; ctx->beacon.eks.new_eks = eks; } cp_secu_pbb_dec_gen (nek, &rnek); ctx->mac_config->nek[index].eks = MAC_EKS_CLEAR; arch_reorder_barrier (); for (i = 0; i < COUNT(nek.key); i++) { ctx->mac_config->nek[index].nek_enc[i] = nek.key[i]; ctx->mac_config->nek[index].nek_dec[i] = rnek.key[i]; } arch_reorder_barrier (); ctx->mac_config->nek[index].eks = eks; } /** * Deactivate the Beacon module. * \param ctx the CP context. */ void cp_beacon_deactivate (cp_t *ctx) { pb_beacon_t *beacon; dbg_assert (ctx); /* Stop the hal timer. */ hal_timer_instance_cancel (ctx->hal_timer, &ctx->beacon.leon_timer); /* Release pending beacons. */ while (!slist_empty (ctx->beacon.list., bare)) { beacon = slist_pop_front (ctx->beacon.list., bare); blk_release_desc ((blk_t *) beacon); } cp_beacon_discover_uninit (ctx); } void cp_beacon_change_snid (cp_t *ctx, cp_snid_t snid) { dbg_assert (ctx); dbg_assert (cp_sta_own_data_get_cco_status (ctx)); if (!ctx->beacon.snids.snidcd) { ctx->beacon.snids.snid = snid; ctx->beacon.snids.snidcd = CP_BEACON_COUNTDOWN_SNID; } } void cp_beacon_change_hm (cp_t *ctx, uint hybrid_mode) { dbg_assert (ctx); dbg_assert (cp_sta_own_data_get_cco_status (ctx)); if (!ctx->beacon.hm.hmcd) { ctx->beacon.hm.hm = hybrid_mode; ctx->beacon.hm.hmcd = CP_BEACON_COUNTDOWN_HM; } } void cp_beacon_handover (cp_t *ctx, cp_tei_t cco) { dbg_assert (ctx); if (!ctx->beacon.hoip.hoipcd) { ctx->beacon.hoip.cco = cco; ctx->beacon.hoip.hoipcd = CP_BEACON_COUNTDOWN_HOIP; } } void cp_beacon_handover_hoipflag (cp_t *ctx, enum cp_beacon_hoip_e flag) { dbg_assert (ctx); dbg_assert (flag < CP_BEACON_HOIP_MAX); ctx->beacon.hoip.hoip_flag = flag; } void cp_beacon_reconfigure_timer (cp_t *ctx, bool cco) { dbg_assert (ctx); u32 date; if (cco) date = bsu_aclf_beacon_period_start_date_next (ctx->bsu_aclf) + bsu_aclf_beacon_period_tck (ctx->bsu_aclf) - CP_TIMER_OFFSET_CCO; else date = bsu_aclf_beacon_period_start_date_next (ctx->bsu_aclf) + CP_TIMER_OFFSET_STA; // Program the timer. hal_timer_instance_cancel (ctx->hal_timer, &ctx->beacon.leon_timer); hal_timer_instance_program (ctx->hal_timer, &ctx->beacon.leon_timer, date); } /** * Check if another countdown is currently active. * \param ctx the module context. * \return true if another countdown is active, false otherwise. */ bool cp_beacon_any_countdown_active (cp_t *ctx) { dbg_assert (ctx); return ((ctx->beacon.snids.snidcd) || (ctx->beacon.hm.hmcd) || (ctx->beacon.hoip.hoipcd)); }