summaryrefslogtreecommitdiff
path: root/cesar/cp/beacon/src/beacons.c
diff options
context:
space:
mode:
Diffstat (limited to 'cesar/cp/beacon/src/beacons.c')
-rw-r--r--cesar/cp/beacon/src/beacons.c1047
1 files changed, 1047 insertions, 0 deletions
diff --git a/cesar/cp/beacon/src/beacons.c b/cesar/cp/beacon/src/beacons.c
new file mode 100644
index 0000000000..e8e802a3e7
--- /dev/null
+++ b/cesar/cp/beacon/src/beacons.c
@@ -0,0 +1,1047 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2008 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file cp/beacon/src/beacons.c
+ * \brief CP beacon modules
+ * \ingroup cp_beacon
+ *
+ */
+#include "common/std.h"
+
+#include "lib/bitstream.h"
+#include "lib/read_word.h"
+
+#include "cp/beacon/beacons.h"
+#include "hal/phy/phy.h"
+
+#include "mac/ca/ca.h"
+#include "mac/common/ntb.h"
+#include "mac/common/timings.h"
+
+#include "hal/timer/timer.h"
+
+#include "cp/beacon/inc/beacons.h"
+#include "cp/beacon/inc/bentry.h"
+#include "cp/beacon/inc/beacons_ctx.h"
+#include "cp/beacon/inc/trace.h"
+#include "cp/beacon/inc/beacons_work.h"
+
+#define CP_BEACON_WORD_SIZE 32
+
+static cp_beacon_t cp_beacon_global;
+
+/**
+ * Init the beacons module.
+ *
+ * \param interface the inteface context.
+ * \param phy the phy context.
+ * \param sta the station context.
+ * \param secu the control plane security layer context.
+ * \param ca the Channel Access context.
+ * \param mac_store mac_store.
+ * \param pbproc pbproc.
+ * \param cco the cco context.
+ * \param timer the hal timer context to program the instance.
+ * \param user_data the CP user_data to be provided with the call back.
+ * \param cb the function to call back when the module is awake by the
+ * timer.
+ * \return the beacon context.
+ */
+cp_beacon_t *
+cp_beacon_init(interface_t *interface, phy_t *phy, cp_sta_t *sta,
+ cp_secu_t *secu, ca_t *ca,
+ pbproc_t *pbproc, mac_store_t *mac_store, cp_cco_t *cco,
+ hal_timer_t *timer, void *user_data, cp_beacon_timer_cb_t cb)
+{
+ cp_beacon_t *ctx;
+
+ dbg_assert(interface);
+ dbg_assert(phy);
+ dbg_assert(sta);
+
+ /* Laranjeiro 03/04/2008
+ * removed the test on secu, shall not be use actually in the beacons
+ * until the new version of the CP is not ready.
+ */
+ //dbg_assert(secu);
+ dbg_assert(ca);
+ dbg_assert(mac_store);
+ dbg_assert(pbproc);
+ dbg_assert(cco);
+ dbg_assert(timer);
+ dbg_assert(cb);
+
+
+ ctx = &cp_beacon_global;
+ ctx->interface = interface;
+ ctx->phy = phy;
+ ctx->sta = sta;
+ ctx->secu = secu;
+ ctx->ca = ca;
+ ctx->mac_store = mac_store;
+ ctx->pbproc = pbproc;
+ ctx->cco = cco;
+
+ ctx->cp_user_data = user_data;
+ ctx->cp_cb = cb;
+
+ // Add trace
+ cp_beacon_trace_init(ctx);
+ CP_BEACON_TRACE (INIT, mac_ntb());
+
+ // init all the context.
+ ctx->schedule_index = 0;
+ ctx->hm = 0x2;
+
+ // verify the AC line frequence.
+ ctx->pwl.date_ntb[0] = 0;
+ ctx->pwl.date_ntb[1] = 0;
+ ctx->pwl.detection = 0;
+ ctx->pwl.bp_ntb = 0;
+ ctx->pwl.pwzc_ntb = 0;
+
+ // Initialise the instance timer.
+ ctx->timer = timer;
+ hal_timer_instance_init (ctx->timer, &ctx->instance, ctx,
+ (hal_timer_instance_cb_t) cp_beacon_timer_it);
+
+ // init cbeacon
+ cp_beacon_init_beacons (ctx, &ctx->cbeacon);
+ // init dbeacon
+ cp_beacon_init_beacons (ctx, &ctx->dbeacon);
+
+ return ctx;
+}
+
+/**
+ * Uninit the beacon module
+ *
+ * \param ctx the beacon module.
+ */
+void
+cp_beacon_uninit(cp_beacon_t *ctx)
+{
+ dbg_assert(ctx);
+
+ cp_beacon_uninit_beacons (ctx, &ctx->cbeacon);
+ cp_beacon_uninit_beacons (ctx, &ctx->dbeacon);
+
+ // Cancel the timer instance.
+ if (hal_timer_instance_get_status (&ctx->instance))
+ hal_timer_instance_cancel (ctx->timer, &ctx->instance);
+
+ CP_BEACON_TRACE (UNINIT, mac_ntb());
+ cp_beacon_trace_uninit(ctx);
+}
+
+/**
+ * Initialize the sub module for the discover, central and proxy beacons.
+ * The beacon_ctx corresponds to the each part contained in the ctx.
+ *
+ * \param ctx the becon module context.
+ * \param beacon_ctx the central, discover or proxy context.
+ */
+void
+cp_beacon_init_beacons (cp_beacon_t *ctx, cp_beacon_common_t *beacon_ctx)
+{
+ uint i;
+
+ dbg_assert (ctx);
+ dbg_assert (beacon_ctx);
+
+ beacon_ctx->mfs = NULL;
+ beacon_ctx->bto_bpsto.bpsto = 0;
+ beacon_ctx->beacon_nb = 0;
+ beacon_ctx->per_ntb = 0;
+ beacon_ctx->last_beacon = NULL;
+ beacon_ctx->mfs = NULL;
+ beacon_ctx->last_bp.start_date = 0;
+ beacon_ctx->last_bp.schedule_index = 0;
+
+ // initialize the central beacon data.
+ ctx->cbeacon.beacon_nb = 0;
+ for (i = 0; i < 4; i++)
+ {
+ beacon_ctx->btse_ntb[i] = 0;
+ beacon_ctx->bto_bpsto.bto[i] = 0;
+ beacon_ctx->bp_tau[i] = 0;
+ }
+}
+
+/**
+ * Uninit the sub beacon modules.
+ *
+ * \param ctx the beacon module context
+ * \param beacon_ctx the beacon context to uninit.
+ */
+void
+cp_beacon_uninit_beacons (cp_beacon_t *ctx, cp_beacon_common_t *beacon_ctx)
+{
+ dbg_assert (ctx);
+ dbg_assert (beacon_ctx);
+
+ if (beacon_ctx->last_beacon != NULL)
+ {
+ blk_release_desc ((blk_t *) beacon_ctx->last_beacon);
+ }
+
+
+ if (beacon_ctx->mfs)
+ {
+ dbg_assert (ctx->mac_store);
+ mac_store_mfs_remove (ctx->mac_store, (mfs_t *)
+ beacon_ctx->mfs);
+
+ // Remove the MFS from the CA
+ ca_mfs_remove (ctx->ca, beacon_ctx->mfs);
+
+ // Release the mfs.
+ blk_release (beacon_ctx->mfs);
+ }
+}
+
+/**
+ * Create the default schedule for the CA to be able to listen the PWL on the
+ * POND procedure.
+ * This will create four beacon periods of a duration corresponding to
+ * CP_BEACON_DEFAULT_SCHEDULE_TIME / 4.
+ *
+ * \param ctx the cp beacon context
+ */
+void
+cp_beacon_create_default_schedule (cp_beacon_t *ctx)
+{
+ ca_beacon_period_t bp[3];
+ ca_schedule_t *sched;
+ uint i;
+
+ dbg_assert (ctx);
+ dbg_assert (ctx->ca);
+ dbg_assert (ctx->pbproc);
+ dbg_assert (ctx->cco);
+
+ /**
+ * When the STA get out off the POND sequence this function can be called
+ * once again even if a discover beacon has been received. To desallow the
+ * STA to modify the correct schedules for the CA, it shall verify if a
+ * beacon as been received. If its true, it return from this function.
+ * Otherwise no beacon had been received.
+ * This comment is only correct if the STA is not a CCo, otherwise, this
+ * function shall be called each time a discover beacon is being prepared
+ * to be sent.
+ */
+ if (ctx->cbeacon.last_beacon
+ || (ctx->dbeacon.last_beacon && cp_cco_get_cco_status(ctx->cco)))
+ {
+ return;
+ }
+
+
+ // Get the schedule 0
+ if (ctx->pbproc_activated == false)
+ {
+ sched = ca_alloc_get_schedule (ctx->ca, 0);
+ sched->coexistence_mode = ctx->hm;
+ sched->nek_switch = 0; //TODO
+ sched->allocations_nb = 1;
+ sched->allocations[0].end_offset_tck = 0xFFFFFF;
+ sched->allocations[0].glid = 0xFF;
+
+ ctx->schedule_index ++;
+ }
+
+ bp[0].start_date = mac_ntb ();
+ bp[0].schedule_index = 0;
+ for (i = 1; i < 3; i++)
+ {
+ bp[i].start_date = bp[i-1].start_date + 0xFFFFFF;
+ bp[i].schedule_index = 0;
+ }
+
+ // add the schedule to the CA.
+ ca_alloc_update_beacon_periods (ctx->ca, bp, 3);
+
+ // Program the timer to be awake
+ ctx->awake_time = 3 * CP_BEACON_DEFAULT_BP_WIDTH;
+
+ CP_BEACON_TRACE (DEFAULT_SCHED, mac_ntb());
+}
+
+/**
+ * Compute the AC line frequency from the PRATIC register
+ *
+ * \param ctx beacons module context
+ */
+void
+cp_beacon_acl_frequency_detection (cp_beacon_t *ctx)
+{
+ uint bp_width_ntb;
+
+ dbg_assert (ctx);
+ dbg_assert (ctx->phy);
+
+ if (ctx->pwl.detection == 0)
+ {
+ ctx->pwl.date_ntb[1] = phy_clock_get_zero_cross_captured_date(ctx->phy);
+ ctx->pwl.detection ++;
+ }
+ else if (ctx->pwl.detection == 1)
+ {
+ ctx->pwl.date_ntb[0] = phy_clock_get_zero_cross_captured_date(ctx->phy);
+ ctx->pwl.detection ++;
+ }
+
+ if (ctx->pwl.detection == 2)
+ {
+ // compute the becon period.
+ bp_width_ntb = (ctx->pwl.date_ntb[0] - ctx->pwl.date_ntb[1] + 5000) % 250000;
+
+ if (bp_width_ntb > 6000)
+ {
+ ctx->pwl.bp_ntb = 833333;
+ ctx->pwl.pwzc_ntb = 208333;
+ ctx->awake_time = 425000; // 17 ms.
+ }
+ else
+ {
+ ctx->pwl.bp_ntb = 1000000;
+ ctx->pwl.pwzc_ntb = 250000;
+ ctx->awake_time = 525000; // 21 ms.
+ }
+
+ CP_BEACON_TRACE (FREQ, mac_ntb(), ctx->pwl.bp_ntb, ctx->pwl.date_ntb[1],
+ ctx->pwl.date_ntb[0]);
+ }
+}
+
+/**
+ * Compute the next BTS, the four next BTOs and the BP in Time Allocation
+ * Unit to provide the data to the generated beacon.
+ *
+ * \param ctx the beacon context.
+ * \param common the common part of the beacons structure.
+ */
+void
+cp_beacon_estimate_bts_bto_bp (cp_beacon_t *ctx, cp_beacon_common_t *common)
+{
+ uint i;
+ uint btse;
+ uint per;
+
+ dbg_assert (ctx);
+ dbg_assert (common);
+
+ if (common->beacon_nb == 0)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ common->btse_ntb[i] = mac_ntb() + //ctx->pwl.date_ntb[0] +
+ i*ctx->pwl.bp_ntb;
+ common->bp_tau[i] = MAC_TCK_TO_ATU(ctx->pwl.bp_ntb);
+ }
+
+ common->per_ntb = cp_beacon_pwl_period(ctx);
+ return;
+ }
+
+ per = cp_beacon_pwl_period (ctx);
+ per = (uint) ((int)common->per_ntb + (((int)per - (int)common->per_ntb) >>
+ CP_BEACON_K));
+
+ btse = (uint) ((int)common->btse_ntb[3] + (int)per +
+ (((int)ctx->pwl.date_ntb[0] - ((int)common->btse_ntb[4]
+ + (int)per)) >> CP_BEACON_K));
+
+ for (i = 0; i < 3; i++)
+ {
+ common->btse_ntb[i] = common->btse_ntb[i+1];
+ common->bto_bpsto.bto[i] = common->bto_bpsto.bto[i+1];
+ common->bp_tau[i] = common->bp_tau[i+1];
+ }
+
+ common->per_ntb = per;
+
+ common->btse_ntb[3] += per;
+ common->bp_tau[3] = MAC_TCK_TO_ATU(per);
+ common->bto_bpsto.bto[4] = per - ctx->pwl.bp_ntb;
+
+ CP_BEACON_TRACE (ESTIMATION, mac_ntb(), btse, per, common->bto_bpsto.bto[0],
+ common->bto_bpsto.bto[1], common->bto_bpsto.bto[2],
+ common->bto_bpsto.bto[3]);
+}
+
+/**
+ * Compute the beacon period using the beacon period thereotic calculated
+ * during the pw frequency detection.
+ *
+ * \param ctx the beacon period context.
+ */
+uint
+cp_beacon_pwl_period (cp_beacon_t *ctx)
+{
+ uint per_ntb;
+ uint diff_ntb;
+
+ dbg_assert (ctx);
+ dbg_assert (ctx->pwl.bp_ntb);
+
+ ctx->pwl.date_ntb[1] = ctx->pwl.date_ntb[0];
+ ctx->pwl.date_ntb[0] = phy_clock_get_zero_cross_captured_date (ctx->phy);
+
+ diff_ntb = (ctx->pwl.date_ntb[0] - ctx->pwl.date_ntb[1]) % ctx->pwl.bp_ntb + 10000;
+ per_ntb = (4-(diff_ntb / ctx->pwl.pwzc_ntb)) * ctx->pwl.pwzc_ntb + diff_ntb - 10000;
+
+ CP_BEACON_TRACE (PWL_PER, mac_ntb(), ctx->pwl.date_ntb[1],
+ ctx->pwl.date_ntb[0], per_ntb);
+
+ return per_ntb;
+}
+
+/**
+ * Process the received beacon or countdown the counters if the beacon as
+ * not been received.
+ *
+ * \param ctx the beacon context.
+ * \param beacon the beacon received.
+ */
+void
+cp_beacon_process (cp_beacon_t *ctx, cp_beacon_desc_t *beacon)
+{
+ dbg_assert (ctx);
+
+ // TODO program the timer.
+
+ if (beacon)
+ {
+ cp_beacon_process_beacon (ctx, beacon);
+ }
+ else
+ {
+ /** Non persistent Preview schedule countdown. */
+ if (ctx->bentries_data.pscd)
+ {
+ ctx->bentries_data.pscd --;
+ // TODO Call the function to release the schedule.
+ }
+
+ /** Non persistent current schedule countdown. */
+ if (ctx->bentries_data.cscd)
+ {
+ ctx->bentries_data.cscd --;
+ // TODO call the right function
+ }
+
+ /** Key change countdown. */
+ if (ctx->bentries_data.kccd)
+ {
+ ctx->bentries_data.kccd --;
+ // TODO call the right function
+ }
+
+ /** Handover countdown. */
+ if (ctx->bentries_data.hcd)
+ {
+ ctx->bentries_data.hcd --;
+ // TODO call the right function
+ }
+
+ /** Relocation countdown. */
+ if (ctx->bentries_data.rcd)
+ {
+ ctx->bentries_data.rcd --;
+ // TODO call the right function
+ }
+
+ /** AC line countdown. */
+ if (ctx->bentries_data.aclcd)
+ {
+ ctx->bentries_data.aclcd --;
+ // TODO call the right function
+ }
+
+ /** Change numslot. */
+ if (ctx->bentries_data.nsccd)
+ {
+ ctx->bentries_data.nsccd --;
+ // TODO call the right function
+ }
+
+ /** Change Hibryd mode countdown. */
+ if (ctx->bentries_data.hmccd)
+ {
+ ctx->bentries_data.hmccd --;
+ // TODO call the right function
+ }
+
+ /** Change snid countdown. */
+ if(ctx->bentries_data.sccd)
+ {
+ ctx->bentries_data.sccd --;
+ // TODO call the right function
+ }
+ }
+}
+
+/**
+ * Process the received beacon
+ *
+ * \param ctx the beacon context.
+ * \param beacon the beacon received.
+ */
+void
+cp_beacon_process_beacon (cp_beacon_t *ctx, cp_beacon_desc_t *beacon)
+{
+ uint nbe;
+ u8 *bentry;
+ u8 *bentry_data;
+ cp_beacon_desc_alloc_t sched;
+ ca_beacon_period_t beacon_period[4];
+ uint i;
+ uint bpsto;
+ cp_beacon_common_t *common;
+ cp_beacon_work_beacon_t beacon_work;
+ bitstream_t bitstream;
+
+ dbg_assert (ctx);
+ dbg_assert (ctx->ca);
+ dbg_assert (ctx->sta);
+ dbg_assert (beacon);
+
+
+ // Keep the mac address of the source STA which emits the beacon to store
+ // it in the STA list.
+ mac_t mac = 0x0;
+ uint stei;
+
+ dbg_assert (ctx);
+ dbg_assert (beacon);
+
+ beacon_work.nid_msb = read_u32_from_word ((u8 *) &beacon->nid_msb);
+
+ bitstream_init (&bitstream, beacon->payload->beacon_mpdu_payload, 64,
+ BITSTREAM_READ);
+ bitstream_access (&bitstream, &beacon_work.nid_lsb, 22);
+ bitstream_access (&bitstream, &beacon_work.hm, 2);
+ bitstream_access (&bitstream, &beacon_work.stei, 8);
+ bitstream_access (&bitstream, &beacon_work.bt, 3);
+ beacon_work.bt = CP_BEACON_WORK_MASK_BT (beacon_work.bt);
+
+ bitstream_access (&bitstream, &beacon_work.ncnr, 1);
+ bitstream_access (&bitstream, &beacon_work.npsm, 1);
+ bitstream_access (&bitstream, &beacon_work.num_slots, 3);
+ beacon_work.num_slots =
+ CP_BEACON_WORK_MASK_NUM_SLOTS(beacon_work.num_slots);
+
+ bitstream_access (&bitstream, &beacon_work.slot_usage, 8);
+ bitstream_access (&bitstream, &beacon_work.slot_id, 3);
+ beacon_work.slot_id = CP_BEACON_WORK_MASK_SLOT_ID(beacon_work.slot_id);
+
+ bitstream_access (&bitstream, &beacon_work.aclss, 3);
+ beacon_work.aclss = CP_BEACON_WORK_MASK_ACLSS(beacon_work.aclss);
+
+ bitstream_access (&bitstream, &beacon_work.hoip, 1);
+ bitstream_access (&bitstream, &beacon_work.rtsbf, 1);
+ bitstream_access (&bitstream, &beacon_work.nm, 2);
+ beacon_work.nm = CP_BEACON_WORK_MASK_NM(beacon_work.nm);
+
+ bitstream_access (&bitstream, &beacon_work.cco_cap, 2);
+ beacon_work.cco_cap = CP_BEACON_WORK_MASK_CCO_CAP(beacon_work.cco_cap);
+ bitstream_finalise (&bitstream);
+
+ switch (beacon_work.bt)
+ {
+ case CP_BEACON_CENTRAL_BEACON:
+ common = &ctx->cbeacon;
+ break;
+ case CP_BEACON_DISCOVER_BEACON:
+ common = &ctx->dbeacon;
+ break;
+ default:
+ dbg_assert (false);
+ }
+
+ // Create a schedule.
+ sched.next_alloc = 0;
+
+ // Store the hybrid mode.
+ ctx->hm = beacon_work.hm;
+ cp_cco_set_ncnr (ctx->cco, beacon_work.ncnr);
+ cp_cco_set_npsm(ctx->cco, beacon_work.npsm);
+ cp_cco_set_numslots(ctx->cco, beacon_work.num_slots);
+ cp_cco_set_slotusage(ctx->cco, beacon_work.slot_usage);
+ cp_cco_set_aclss(ctx->cco, beacon_work.aclss);
+ cp_station_set_hoip(ctx->sta, beacon_work.hoip);
+
+ cp_station_set_rtsbf(ctx->sta, beacon_work.rtsbf);
+ cp_cco_set_nm(ctx->cco, beacon_work.nm);
+
+ // Store the coexistence mode
+ sched.ca_sched = ca_alloc_get_schedule (ctx->ca, ctx->schedule_index);
+ sched.ca_sched->coexistence_mode = ctx->hm;
+ sched.ca_sched->nek_switch = 0; //TODO
+
+ bentry = beacon->payload->bmis;
+ for (nbe = beacon->payload->nbe; nbe; nbe --)
+ {
+ // access direct to the bentry payload instead of providing the header
+ // of the bentry to the processing functions.
+ bentry_data = bentry + 2;
+ switch (read_u8_from_word(bentry))
+ {
+ case CP_BENTRY_PERSISTENT_SCHEDULE:
+ bentry = cp_bentry_persistent_schedule_process (ctx, bentry_data,
+ &sched);
+ break;
+ case CP_BENTRY_NON_PERSISTENT_SCHEDULE:
+ bentry = cp_bentry_non_persistent_schedule_process (ctx, bentry_data, &sched);
+ break;
+ case CP_BENTRY_REGIONS:
+ bentry = cp_bentry_regions_process (ctx, bentry_data);
+ break;
+ case CP_BENTRY_MAC_ADDRESS:
+ bentry = cp_bentry_mac_address_process (ctx, bentry_data, &mac);
+ break;
+ case CP_BENTRY_DISCOVER:
+ bentry = cp_bentry_discover_process (ctx, bentry_data,
+ beacon);
+ break;
+ case CP_BENTRY_DISCOVER_INFO:
+ bentry = cp_bentry_discover_info_process (ctx, bentry_data);
+ break;
+ case CP_BENTRY_BEACON_PERIOD_START_OFFSET:
+ bentry = cp_bentry_bpsto_process (ctx, bentry_data, &bpsto);
+ break;
+ case CP_BENTRY_ENCRYPTION_KEY_CHANGE:
+ bentry = cp_bentry_encryption_key_change_process (ctx, bentry_data);
+ break;
+ case CP_BENTRY_CCO_HANDOVER:
+ bentry = cp_bentry_handover_process (ctx, bentry_data);
+ break;
+ case CP_BENTRY_BEACON_RELOCATION:
+ bentry = cp_bentry_beacon_relocation_process (ctx, bentry_data);
+ break;
+ case CP_BENTRY_AC_LINE_SYNC_COUNTDOWN:
+ bentry = cp_bentry_ac_line_sync_countdown_process (ctx, bentry_data);
+ break;
+ case CP_BENTRY_CHANGE_NUMSLOTS:
+ bentry = cp_bentry_change_num_slots_process (ctx, bentry_data);
+ break;
+ case CP_BENTRY_CHANGE_HM:
+ bentry = cp_bentry_change_hm_process (ctx, bentry_data);
+ break;
+ case CP_BENTRY_CHANGE_SNID:
+ bentry = cp_bentry_change_snid_process (ctx, bentry_data);
+ break;
+ case CP_BENTRY_VENDOR:
+ bentry = cp_bentry_vendor_specific_process (ctx, bentry_data);
+ break;
+ default:
+ dbg_assert (*bentry > CP_BENTRY_CHANGE_SNID && *bentry < CP_BENTRY_VENDOR);
+ }
+ }
+
+ // Store the beacon in the cp_beacon context.
+ if (common->last_beacon != NULL)
+ {
+ blk_release_desc ((blk_t *) common->last_beacon);
+ }
+ common->last_beacon = beacon;
+
+ if (beacon_work.bt == CP_BEACON_CENTRAL_BEACON)
+ {
+ // Fill the end of the beacon period with an empty allocation.
+ if (sched.ca_sched->allocations[sched.next_alloc].end_offset_tck <
+ ctx->pwl.bp_ntb)
+ {
+ sched.ca_sched->allocations[sched.next_alloc].glid = MAC_LID_SPC_HOLE;
+ sched.ca_sched->allocations[sched.next_alloc].end_offset_tck =
+ ctx->pwl.bp_ntb;
+ sched.ca_sched->allocations_nb++;
+ sched.next_alloc ++;
+ }
+
+ beacon_period[0] = common->last_bp;
+ // ADD the schedule to the CA.
+ for (i = 1; i < 4; i++)
+ {
+ beacon_period[i].start_date = ctx->pwl.bp_ntb * i
+ + beacon->payload->fc.preamble_date
+ + beacon->payload->fc.bto[i]
+ - bpsto;
+ beacon_period[i].schedule_index = ctx->schedule_index;
+ }
+ common->last_bp = beacon_period[1];
+
+ ca_alloc_update_beacon_periods (ctx->ca, beacon_period, 4);
+ ctx->schedule_index ++;
+
+ CP_BEACON_TRACE (UPDATE_SCHED, mac_ntb(), beacon_work.bt,
+ beacon_period[0].start_date,
+ beacon_period[1].start_date,
+ beacon_period[2].start_date);
+ }
+
+ // Store the mac address and the tei of the CCo in the sta list if still
+ // not present.
+ if (stei && mac)
+ {
+ // TODO: Shall the stei and mac be provide to complete the network
+ // list ?
+ }
+
+ // increment the beacon number.
+ common->beacon_nb ++;
+
+ CP_BEACON_TRACE (BEACON_PROCESS, mac_ntb(), beacon_work.bt,
+ beacon->payload->fc.bts, beacon->payload->fc.bto[0],
+ beacon->payload->fc.bto[1], beacon->payload->fc.bto[2],
+ beacon->payload->fc.bto[3]);
+}
+
+/**
+ * Send a beacon when the STA is acting as a CCo.
+ *
+ * \param ctx the beacon module context
+ * \param beacon_type beacon type
+ */
+void
+cp_beacon_cco_send_beacon (cp_beacon_t *ctx, uint beacon_type)
+{
+ cp_beacon_desc_t *beacon;
+ cp_beacon_common_t *common;
+
+ dbg_assert (ctx);
+#if 0
+ dbg_assert (cp_cco_get_cco_status(ctx->cco));
+#endif
+
+ beacon = (cp_beacon_desc_t *) blk_alloc_desc();
+
+ // To keep the beacon in memroy for a future use
+ blk_addref_desc ((blk_t *) beacon);
+
+ switch (beacon_type)
+ {
+ case CP_BEACON_CENTRAL_BEACON:
+ common = &ctx->cbeacon;
+ cp_beacon_cco_beacon_central_generate (ctx, beacon);
+ break;
+ case CP_BEACON_DISCOVER_BEACON:
+ common = &ctx->dbeacon;
+ cp_beacon_cco_beacon_discover_generate (ctx, beacon);
+ break;
+ }
+
+ // Keep the beacon in the context.
+ if (common->last_beacon)
+ {
+ // release the previous one.
+ blk_release_desc ((blk_t *) common->last_beacon);
+ }
+ // Add the new one.
+ common->last_beacon = beacon;
+
+ cp_beacon_send_beacon (ctx, beacon, beacon_type);
+}
+
+/**
+ * Fill the payload of the beacon when the STA is accting as CCo or UCCo.
+ * Can be use for
+ * - the Central beacon when acting as a CCo
+ * - the discover beacon when acting as a UCCo.
+ *
+ *
+ * \param ctx the beacon module context
+ * \param beacon the beacon to fill.
+ * \param beacon_type the beacon type, central, discover or proxy.
+ */
+void
+cp_beacon_xcco_fill_common_part (cp_beacon_t *ctx, cp_beacon_desc_t *beacon,
+ uint beacon_type)
+{
+ bitstream_t bitstream;
+ u64 nid;
+ cp_beacon_work_beacon_t data;
+
+ dbg_assert (ctx);
+ dbg_assert (ctx->sta);
+ dbg_assert (ctx->cco);
+ dbg_assert (beacon);
+ dbg_assert (beacon_type < 3);
+
+ // Beacon payload
+ nid = cp_station_get_nid (ctx->sta);
+
+ data.nid_msb = nid >> 22;
+ data.nid_lsb = nid & 0x7FFFFF;
+ data.hm = ctx->hm;
+ data.stei = cp_station_get_tei (ctx->sta);
+ data.bt = beacon_type;
+ data.ncnr = cp_cco_get_ncnr (ctx->cco);
+ data.npsm = cp_cco_get_npsm (ctx->cco);
+ data.num_slots = cp_cco_get_numslots (ctx->cco);
+ data.slot_usage = cp_cco_get_slotusage(ctx->cco);
+ data.slot_id = cp_cco_get_slot_id (ctx->cco);
+ data.aclss = cp_cco_get_aclss (ctx->cco);
+ data.hoip = cp_station_get_hoip (ctx->sta);
+ data.rtsbf = cp_station_get_rtsbf (ctx->sta);
+ data.nm = cp_cco_get_nm (ctx->cco);
+ data.cco_cap = cp_cco_get_cco_cap (ctx->cco);
+
+ beacon->nid_msb = data.nid_msb;
+
+ bitstream_init (&bitstream, beacon->payload->beacon_mpdu_payload, CP_BEACON_WORD_SIZE,
+ BITSTREAM_WRITE);
+ bitstream_access (&bitstream, &data.nid_lsb, 22);
+ bitstream_access (&bitstream, &data.hm, 2);
+ bitstream_access (&bitstream, &data.stei, 8);
+ bitstream_finalise (&bitstream);
+
+ bitstream_init (&bitstream, beacon->payload->beacon_mpdu_payload + sizeof(uint), CP_BEACON_WORD_SIZE,
+ BITSTREAM_WRITE);
+ bitstream_access (&bitstream, &data.bt, 3);
+ bitstream_access (&bitstream, &data.ncnr, 1);
+ bitstream_access (&bitstream, &data.npsm, 1);
+ bitstream_access (&bitstream, &data.num_slots, 3);
+ bitstream_access (&bitstream, &data.slot_usage, 8);
+ bitstream_access (&bitstream, &data.slot_id, 3);
+ bitstream_access (&bitstream, &data.aclss, 3);
+ bitstream_access (&bitstream, &data.hoip, 1);
+ bitstream_access (&bitstream, &data.rtsbf, 1);
+ bitstream_access (&bitstream, &data.nm, 2);
+ bitstream_access (&bitstream, &data.cco_cap, 2);
+ bitstream_finalise (&bitstream);
+
+}
+
+/**
+ * Generate the central beacon.
+ *
+ * \param ctx the beacon context.
+ * \param beacon the beacon received.
+ */
+void
+cp_beacon_cco_beacon_central_generate (cp_beacon_t *ctx,
+ cp_beacon_desc_t *beacon)
+{
+ u8 *bentry;
+ cp_beacon_desc_alloc_t sched;
+ ca_beacon_period_t beacon_period[3];
+ uint i;
+ uint estimated_date;
+
+ dbg_assert (ctx);
+ dbg_assert (ctx->sta);
+ dbg_assert (ctx->cco);
+ dbg_assert (beacon);
+
+ cp_beacon_estimate_bts_bto_bp (ctx, &ctx->cbeacon);
+
+ // Store the coexistence mode
+ sched.next_alloc = 0;
+ sched.ca_sched = ca_alloc_get_schedule (ctx->ca, ctx->schedule_index);
+ sched.ca_sched->coexistence_mode = ctx->hm;
+ sched.ca_sched->nek_switch = 0; //TODO
+
+ beacon->payload->fc.bts = ctx->cbeacon.btse_ntb[0];
+ *beacon->payload->fc.bto = *ctx->cbeacon.bto_bpsto.bto;
+
+ // Beacon payload
+ cp_beacon_xcco_fill_common_part (ctx, beacon, CP_BEACON_CENTRAL_BEACON);
+ beacon->payload->nbe = 4;
+
+ // Bentries.
+ bentry = cp_bentry_bpsto (ctx, &ctx->cbeacon, beacon->payload->bmis);
+ bentry = cp_bentry_mac_address (ctx, bentry);
+ bentry = cp_bentry_regions (ctx, bentry);
+ bentry = cp_bentry_persistent_schedule (ctx, bentry, &sched);
+
+ // Fill the end of the beacon period with an empty allocation.
+ if (sched.ca_sched->allocations[sched.next_alloc].end_offset_tck <
+ ctx->cbeacon.per_ntb)
+ {
+ sched.next_alloc ++;
+ sched.ca_sched->allocations[sched.next_alloc].glid = MAC_LID_SPC_HOLE;
+ sched.ca_sched->allocations[sched.next_alloc].end_offset_tck =
+ ctx->cbeacon.per_ntb;
+ sched.ca_sched->allocations_nb++;
+ }
+
+ estimated_date = MAC_NTB_TO_DATE (beacon->payload->fc.bts);
+ if (ctx->cbeacon.beacon_nb)
+ {
+ // Program the timer for the next beacon period to generate the next
+ // central beacon.
+ hal_timer_instance_program (ctx->timer, &ctx->instance, mac_ntb()
+ + ctx->cbeacon.per_ntb);
+ }
+ else
+ {
+ // Program the timer for the next beacon period to generate the next
+ // central beacon.
+ hal_timer_instance_program (ctx->timer, &ctx->instance, mac_ntb()
+ + 3*ctx->pwl.pwzc_ntb);
+ }
+
+ beacon_period[0] = ctx->cbeacon.last_bp;
+ // ADD the schedule to the CA.
+ for (i = 1; i < 3 ; i++)
+ {
+ // The 3500 ticks are present to allow the CA to make an aifs before
+ // the new beacon period.
+ beacon_period[i].start_date = ctx->cbeacon.per_ntb * (i-1)
+ + estimated_date + beacon->payload->fc.bto[i] + 3500;
+ beacon_period[i].schedule_index = ctx->schedule_index;
+ }
+
+ ca_alloc_update_beacon_periods (ctx->ca, beacon_period, 3);
+
+ // Store the net last bp in the context.
+ ctx->cbeacon.last_bp = beacon_period[1];
+ ctx->schedule_index ++;
+
+ CP_BEACON_TRACE (UPDATE_SCHED, mac_ntb(), CP_BEACON_CENTRAL_BEACON,
+ beacon_period[0].start_date,
+ beacon_period[1].start_date,
+ beacon_period[2].start_date);
+}
+
+/**
+ * Generate the beacon.
+ *
+ * \param ctx the beacon context.
+ * \parma common the beacon central or discover context.
+ * \param beacon the central beacon to fill
+ */
+void
+cp_beacon_cco_beacon_discover_generate (cp_beacon_t *ctx,
+ cp_beacon_desc_t *beacon)
+{
+ u8 *bentry;
+
+ dbg_assert (ctx);
+ dbg_assert (ctx->sta);
+ dbg_assert (ctx->cco);
+ dbg_assert (beacon);
+
+ beacon->payload->fc.bts = mac_ntb();
+ *beacon->payload->fc.bto = *ctx->dbeacon.bto_bpsto.bto;
+
+ // Beacon payload
+ cp_beacon_xcco_fill_common_part (ctx, beacon, CP_BEACON_DISCOVER_BEACON);
+
+ beacon->payload->nbe = 5;
+
+ // Bentries.
+ bentry = cp_bentry_bpsto (ctx, &ctx->dbeacon, beacon->payload->bmis);
+ bentry = cp_bentry_mac_address (ctx, bentry);
+ bentry = cp_bentry_regions (ctx, bentry);
+ bentry = cp_bentry_default_schedule (ctx, bentry);
+ bentry = cp_bentry_discover_info (ctx, bentry);
+}
+
+/**
+ * Send the beacon over the PWL.
+ * TODO Implement the proxy beacon part
+ *
+ * \param ctx the cp beacon context
+ * \param beacon the beacon to send
+ * \param beacon_type the beacon type.
+ */
+void
+cp_beacon_send_beacon (cp_beacon_t *ctx, cp_beacon_desc_t *beacon,
+ uint beacon_type)
+{
+ mfs_tx_t *mfs_beacon;
+ bool added;
+ cp_beacon_common_t *common;
+ mac_t mac;
+
+ dbg_assert (ctx);
+ dbg_assert (beacon);
+
+ /* Create the MFS
+ * see http://pessac/cesar/trac/wiki/SoftMacBeacons#BeaconMFS
+ * for more details.
+ */
+ dbg_assert (ctx->mac_store);
+ switch (beacon_type)
+ {
+ case CP_BEACON_CENTRAL_BEACON:
+ mfs_beacon = mac_store_mfs_add_tx (ctx->mac_store, true, false,
+ MAC_LID_SPC_CENTRAL, 0xff, &added);
+ ctx->cbeacon.mfs = mfs_beacon;
+ mfs_beacon->cap = 0x3;
+ common = &ctx->cbeacon;
+ break;
+ case CP_BEACON_DISCOVER_BEACON:
+ mfs_beacon = mac_store_mfs_add_tx (ctx->mac_store, true, false,
+ MAC_LID_DISCOVER, 0xff, &added);
+ ctx->dbeacon.mfs = mfs_beacon;
+ mfs_beacon->cap = 0x2;
+ common = &ctx->dbeacon;
+ break;
+ default:
+ dbg_assert (false);
+ }
+
+ dbg_assert (mfs_beacon);
+
+ if (added)
+ {
+ mfs_beacon->beacon = true;
+ mfs_beacon->common.ats = false;
+
+ // Add the mfs to the CA
+ ca_mfs_add (ctx->ca, mfs_beacon);
+ }
+
+ dbg_assert (ctx->pbproc);
+ dbg_assert (common);
+
+ if (beacon_type == CP_BEACON_CENTRAL_BEACON && common->beacon_nb
+ > 0)
+ {
+ ca_mfs_hold (ctx->ca, mfs_beacon);
+ }
+
+ dbg_assert (ctx->interface);
+ dbg_assert (ctx->sta);
+ cp_station_get_mac_address (ctx->sta, (u8 *) &mac);
+ interface_beacon_prepare (ctx->interface, (pb_beacon_t *)
+ beacon, mac, mfs_beacon, &common->bto_bpsto);
+
+ /*
+ pbproc_mfs_beacon_prepare (ctx->pbproc, mfs_beacon, (pb_beacon_t *) beacon,
+ &common->bto_bpsto);
+
+ ca_mfs_update (ctx->ca, mfs_beacon);
+ */
+
+ CP_BEACON_TRACE (SEND_BEACON, mac_ntb(), common->btse_ntb[0],
+ beacon_type);
+
+ common->beacon_nb ++;
+ if (!added)
+ blk_release (mfs_beacon);
+}
+
+/**
+ * Function call by the timer when the timer expires.
+ *
+ * \param ctx the beacon context.
+ */
+void
+cp_beacon_timer_it (cp_beacon_t *ctx)
+{
+ dbg_assert (ctx);
+ dbg_assert (ctx->cp_cb);
+
+ (*ctx->cp_cb) (ctx->cp_user_data);
+}
+