summaryrefslogtreecommitdiff
path: root/cesar/bsu/beacon/src
diff options
context:
space:
mode:
authorlaranjeiro2010-04-06 09:57:20 +0000
committerlaranjeiro2010-04-06 09:57:20 +0000
commitea35ceec611c968bc3ed8104885143eab966a3a6 (patch)
tree38147fcbd06645be23a22407ce87f7086f6255fe /cesar/bsu/beacon/src
parentf2c3183ced776bd5e3979410846a69f0f804bcb4 (diff)
cesar/beacon: add beacon library, closes #1424
git-svn-id: svn+ssh://pessac/svn/cesar/trunk@6874 017c9cb6-072f-447c-8318-d5b54f68fe89
Diffstat (limited to 'cesar/bsu/beacon/src')
-rw-r--r--cesar/bsu/beacon/src/beacon.c972
1 files changed, 972 insertions, 0 deletions
diff --git a/cesar/bsu/beacon/src/beacon.c b/cesar/bsu/beacon/src/beacon.c
new file mode 100644
index 0000000000..1192c81282
--- /dev/null
+++ b/cesar/bsu/beacon/src/beacon.c
@@ -0,0 +1,972 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2010 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file bsu/src/beacon.c
+ * \brief BSU bsu_beacon functions.
+ * \ingroup bsu
+ *
+ * Functions to read and write bsu_beacons.
+ */
+#include "common/std.h"
+#include "lib/bitstream.h"
+#include "bsu/beacon/beacon.h"
+#include "cp/defs.h"
+
+/** Define the bsu_beacon size in the data part of the block. The first part
+ * of the NID is stored in the block descriptor. */
+#define BSU_BEACON_SIZE 128
+
+/**
+ * Write the beacon variant fields.
+ * \param phy_beacon the beacon bloc.
+ * \param stream the bitstream context.
+ * \param mac_config the mac config object.
+ * \param beacon the data to use to write the beacon.
+ * \param type the beacon type.
+ */
+static void
+bsu_beacon_write_variant_fields (pb_beacon_t *phy_beacon,
+ bitstream_t *stream,
+ mac_config_t *mac_config,
+ bsu_beacon_t *beacon,
+ bsu_beacon_type_t type)
+{
+ phy_beacon->first_data_word = beacon->vf.nid;
+ bitstream_write (stream, beacon->vf.nid >> 32, 22);
+ bitstream_write (stream, beacon->vf.hm, 2);
+ bitstream_write (stream, mac_config->tei, 8);
+ bitstream_write (stream, type, 3);
+ bitstream_write (stream, beacon->vf.ncnr, 1);
+ bitstream_write (stream, beacon->vf.npsm, 1);
+ bitstream_write (stream, beacon->vf.numslots, 3);
+ bitstream_write (stream, beacon->vf.slotusage, 8);
+ bitstream_write (stream, beacon->vf.slotid, 3);
+ bitstream_write (stream, beacon->vf.aclsss, 3);
+ bitstream_write (stream, beacon->vf.hoip, 1);
+ bitstream_write (stream, beacon->vf.rtsbf, 1);
+ bitstream_write (stream, beacon->vf.nm, 2);
+ bitstream_write (stream, beacon->vf.ccocap, 2);
+ bitstream_write (stream, 0, 4);
+}
+
+/**
+ * Write the regions entries in the beacon.
+ * \param stream the bitstream context.
+ * \param region the region bentry.
+ */
+static void
+bsu_beacon_write_bmi_region (bitstream_t *stream,
+ bsu_beacon_bmi_region_t *region)
+{
+ uint nb;
+ dbg_assert (region->nb);
+ /* Store region header value. */
+ bitstream_write (stream, BSU_BEACON_ENTRY_HEADER_REGIONS, 8);
+ uint size = BSU_BEACON_ENTRY_SIZE_REGION (region->nb);
+ bitstream_write (stream, size, 8);
+ bitstream_write (stream, region->nb, 6);
+ bitstream_write (stream, 0, 2);
+ for (nb = 0; nb < region->nb; nb++)
+ {
+ bitstream_write (stream, region->region[nb].rt, 4);
+ bitstream_write (stream, region->region[nb].end_time_atu, 12);
+ }
+}
+
+/**
+ * Write SAI in the beacon.
+ * \param stream the bitstream context.
+ * \param sai the data to use to write the beacon.
+ */
+static void
+bsu_beacon_write_bmi_schedule_sai (bitstream_t *stream,
+ bsu_beacon_sai_t *sai)
+{
+ bitstream_write (stream, sai->stpf, 1);
+ bitstream_write (stream, sai->glid, 7);
+ if (sai->stpf)
+ bitstream_write (stream, sai->start_time_atu, 12);
+ bitstream_write (stream, sai->end_time_atu, 12);
+}
+
+/**
+ * Write Non persistent schedule in the beacon.
+ * \param stream the bitstream context.
+ * \param nps The uncompressed non persistent bsu_beacon entries to store.
+ * \param data the beginning of the beacon.
+ */
+static void
+bsu_beacon_write_bmi_non_persistent (bitstream_t *stream,
+ bsu_beacon_bmi_non_persistent_schedule_t *nps,
+ u8 *data)
+{
+ if (nps->ns)
+ {
+ u32 offset;
+ int nbsai = 0;
+ int nbnsai = 0;
+ uint ns = 0;
+ bitstream_write (stream,
+ BSU_BEACON_ENTRY_HEADER_NON_PERSISTENT_SCHEDULE, 8);
+ offset = bitstream_written_bits (stream);
+ /* Skip the length, it will be stored at the end. */
+ bitstream_write (stream, 0, 8);
+ /* Store the number of session. */
+ bitstream_write (stream, nps->ns, 6);
+ bitstream_write (stream, 0, 2);
+ /* Store the session. */
+ for (ns = 0; ns < nps->ns; ns++)
+ {
+ if (nps->sais[ns].stpf)
+ nbsai++;
+ else
+ nbnsai++;
+ bsu_beacon_write_bmi_schedule_sai (stream, &nps->sais[ns]);
+ }
+ /* Store the length. */
+ bitstream_direct_write (data, offset,
+ BSU_BEACON_ENTRY_SIZE_NON_PERSISTENT_SCHED (nbsai, nbnsai), 8);
+ }
+}
+
+/**
+ * Write a unique Persistent schedule in the beacon.
+ * \param stream the bitstream context.
+ * \param ps the persistent schedule beacon entry to store.
+ * \param data the beginning of the beacon.
+ */
+static void
+bsu_beacon_write_bmi_persistent__store (bitstream_t *stream,
+ bsu_beacon_bmi_persistent_schedule_desc_t *ps,
+ u8 *data)
+{
+ u32 offset;
+ int nbsai = 0;
+ int nbnsai = 0;
+ int ns = 0;
+ bitstream_write (stream,
+ BSU_BEACON_ENTRY_HEADER_PERSISTENT_SCHEDULE, 8);
+ offset = bitstream_written_bits (stream);
+ /* Skip the length, it will be stored at the end. */
+ bitstream_write (stream, 0, 8);
+ /* Store the countdowns. */
+ bitstream_write (stream, ps->pscd, 3);
+ bitstream_write (stream, ps->cscd, 3);
+ bitstream_write (stream, 0, 2);
+ bitstream_write (stream, ps->ns, 6);
+ bitstream_write (stream, 0, 2);
+ for (ns = 0; ns < ps->ns; ns++)
+ {
+ if (ps->sais[ns].stpf)
+ nbsai++;
+ else
+ nbnsai++;
+ bsu_beacon_write_bmi_schedule_sai (stream, &ps->sais[ns]);
+ }
+ /* Store the length. */
+ bitstream_direct_write (
+ data, offset, BSU_BEACON_ENTRY_SIZE_PERSISTENT_SCHED (nbsai, nbnsai),
+ 8);
+}
+
+/**
+ * Write Persistent schedule in the beacon.
+ * \param stream the bitstream context.
+ * \param ps The uncompressed persistent beacon entries to store.
+ * \param data the beginning of the beacon.
+ */
+static void
+bsu_beacon_write_bmi_persistent (bitstream_t *stream,
+ bsu_beacon_bmi_persistent_schedule_t *ps,
+ u8 *data)
+{
+ uint nb;
+ if (ps->nb)
+ for (nb = 0; nb < ps->nb; nb++)
+ bsu_beacon_write_bmi_persistent__store (stream, &ps->ps[nb],
+ data);
+}
+
+/**
+ * Write the discover beacon entry.
+ * \param stream the bitstream context.
+ * \param discover the discover beacon entry to write.
+ */
+static void
+bsu_beacon_write_bmi_discover (bitstream_t *stream,
+ bsu_beacon_bmi_discover_t *discover)
+{
+ if (discover->present)
+ {
+ bitstream_write (stream, BSU_BEACON_ENTRY_HEADER_DISCOVER, 8);
+ bitstream_write (stream, BSU_BEACON_ENTRY_SIZE_DISCOVER, 8);
+ bitstream_write (stream, discover->tei, 8);
+ }
+}
+
+/**
+ * Write the beacon period start time offset bentry.
+ * \param stream the bitstream context.
+ * \param bpsto the beacon period start time offset beacon entry.
+ * \return the offset in octets of the data position in the beacon.
+ */
+static u32
+bsu_beacon_write_bmi_bpsto (bitstream_t *stream,
+ bsu_beacon_bmi_bpsto_t *bpsto)
+{
+ u32 offset = 0;
+ if (bpsto->present)
+ {
+ bitstream_write (stream,
+ BSU_BEACON_ENTRY_HEADER_BEACON_PERIOD_START_TIME_OFFSET,
+ 8);
+ bitstream_write (stream, BSU_BEACON_ENTRY_SIZE_BPSTO, 8);
+ offset = bitstream_written_bits (stream) / 8;
+ bitstream_write (stream, 0, BSU_BEACON_ENTRY_SIZE_BPSTO * 8);
+ }
+ return offset;
+}
+
+/**
+ * Write the discover info beacon entry.
+ * \param beacon the data to use to write the beacon.
+ * \param discover_info the beacon entry to store.
+ */
+static void
+bsu_beacon_write_bmi_discover_info (
+ bitstream_t *stream, bsu_beacon_bmi_discover_info_t *discover_info)
+{
+ if (discover_info->present)
+ {
+ bitstream_write (stream, BSU_BEACON_ENTRY_HEADER_DISCOVERED_INFO, 8);
+ bitstream_write (stream, BSU_BEACON_ENTRY_SIZE_DISCOVER_INFO, 8);
+ bitstream_write (stream, discover_info->info_data, 32);
+ }
+}
+
+/**
+ * Write the encryption key change beacon entry.
+ * \param stream the bitstream context.
+ * \param eks the encryption key change beacon entry.
+ */
+static void
+bsu_beacon_write_bmi_eks (bitstream_t *stream, bsu_beacon_bmi_eks_t *eks)
+{
+ if (eks->present)
+ {
+ bitstream_write (stream,
+ BSU_BEACON_ENTRY_HEADER_ENCRYPTION_KEY_CHANGE,
+ 8);
+ bitstream_write (stream, BSU_BEACON_ENTRY_SIZE_EKC, 8);
+ bitstream_write (stream, eks->kccd, 6);
+ bitstream_write (stream, eks->kbc, 1);
+ bitstream_write (stream, 0, 1);
+ bitstream_write (stream, eks->new_eks, 4);
+ bitstream_write (stream, 0, 4);
+ }
+}
+
+/**
+ * Write the handover beacon entry.
+ * \param stream the bitstream context.
+ * \param handover the beacon entry to write.
+ */
+static void
+bsu_beacon_write_bmi_handover (bitstream_t *stream,
+ bsu_beacon_bmi_handover_t *handover)
+{
+ if (handover->present)
+ {
+ bitstream_write (stream, BSU_BEACON_ENTRY_HEADER_CCO_HANDOVER, 8);
+ bitstream_write (stream, BSU_BEACON_ENTRY_SIZE_HOIP, 8);
+ bitstream_write (stream, handover->hcd, 6);
+ bitstream_write (stream, 0, 2);
+ bitstream_write (stream, handover->tei, 8);
+ }
+}
+
+/**
+ * Write the bsu_beacon relocation entry.
+ * \param stream the bitstream context.
+ * \param relocation the beacon relocation entry data to write.
+ */
+static void
+bsu_beacon_write_bmi_relocation (bitstream_t *stream,
+ bsu_beacon_bmi_relocation_t *relocation)
+{
+ if (relocation->present)
+ {
+ bitstream_write (stream,
+ BSU_BEACON_ENTRY_HEADER_BEACON_RELOCATION,
+ 8);
+ bitstream_write (stream, BSU_BEACON_ENTRY_SIZE_RLO, 8);
+ bitstream_write (stream, relocation->rcd, 6);
+ bitstream_write (stream, relocation->rlt, 1);
+ bitstream_write (stream, relocation->lgf, 1);
+ bitstream_write (stream, relocation->rlo, 17);
+ bitstream_write (stream, relocation->rlslotid, 3);
+ bitstream_write (stream, 0, 4);
+ }
+}
+
+/**
+ * Write ACLSC beacon entry.
+ * \param stream the bitstream context.
+ * \param aclsc the beacon entry to store in the beacon.
+ */
+static void
+bsu_beacon_write_bmi_aclsc (bitstream_t *stream,
+ bsu_beacon_bmi_aclsc_t *aclsc)
+{
+ if (aclsc->present)
+ {
+ bitstream_write (stream,
+ BSU_BEACON_ENTRY_HEADER_AC_LINE_SYNC_COUNTDOWN,
+ 8);
+ bitstream_write (stream, BSU_BEACON_ENTRY_SIZE_ACL, 8);
+ bitstream_write (stream, aclsc->countdown, 6);
+ bitstream_write (stream, 0, 2);
+ bitstream_write (stream, aclsc->reason_code, 2);
+ bitstream_write (stream, 0, 6);
+ }
+}
+
+/**
+ * Write the change number of slots beacon entry.
+ * \param stream the bitstream context.
+ * \param cns the beacon entry to store in the beacon.
+ */
+static void
+bsu_beacon_write_bmi_change_num_slot (bitstream_t *stream,
+ bsu_beacon_bmi_change_num_slot_t *cns)
+{
+ if (cns->present)
+ {
+ bitstream_write (stream, BSU_BEACON_ENTRY_HEADER_CHANGE_NUMSLOTS, 8);
+ bitstream_write (stream, BSU_BEACON_ENTRY_SIZE_CHANGE_NUMSLOTS, 8);
+ bitstream_write (stream, cns->nsccd, 6);
+ bitstream_write (stream, 0, 2);
+ bitstream_write (stream, cns->newnumslot, 3);
+ bitstream_write (stream, 0, 5);
+ }
+}
+
+/**
+ * Write the change hybrid mode beacon entry.
+ * \param stream the bitstream context.
+ * \param hm the beacon entry to store in the beacon.
+ */
+static void
+bsu_beacon_write_bmi_change_hm (bitstream_t *stream,
+ bsu_beacon_bmi_change_hybrid_mode_t *hm)
+{
+ if (hm->present)
+ {
+ bitstream_write (stream, BSU_BEACON_ENTRY_HEADER_CHANGE_HM, 8);
+ bitstream_write (stream, BSU_BEACON_ENTRY_SIZE_CHANGE_HM, 8);
+ bitstream_write (stream, hm->hmccd, 6);
+ bitstream_write (stream, hm->newhm, 2);
+ }
+}
+
+/**
+ * Write the change snid beacon entry.
+ * \param stream the bitstream context.
+ * \param snid the beacon entry to store in the beacon.
+ */
+static void
+bsu_beacon_write_bmi_change_snid (bitstream_t *stream,
+ bsu_beacon_bmi_change_snid_t *snid)
+{
+ if (snid->present)
+ {
+ bitstream_write (stream, BSU_BEACON_ENTRY_HEADER_CHANGE_SNID, 8);
+ bitstream_write (stream, BSU_BEACON_ENTRY_SIZE_CHANGE_SNID, 8);
+ bitstream_write (stream, snid->snidccd, 4);
+ bitstream_write (stream, snid->new_snid, 4);
+ }
+}
+
+/**
+ * Write the Mac address beacon entry.
+ * \param stream the bitstream context.
+ * \param mac_config the mac config object.
+ * \param mac the beacon entry to store in the beacon.
+ */
+static void
+bsu_beacon_write_bmi_mac_address (bitstream_t *stream,
+ mac_config_t *mac_config,
+ bsu_beacon_bmi_mac_address_t *mac)
+{
+ if (mac->present)
+ {
+ bitstream_write (stream, BSU_BEACON_ENTRY_HEADER_MAC_ADDRESS, 8);
+ bitstream_write (stream, BSU_BEACON_ENTRY_SIZE_MAC_ADDRESS, 8);
+ bitstream_write_large (stream, mac_config->sta_mac_address, 48);
+ }
+}
+
+pb_beacon_t*
+bsu_beacon_write (bsu_beacon_t *beacon, bsu_beacon_type_t type,
+ mac_config_t *mac_config, pbproc_tx_beacon_params_t *params)
+{
+ bitstream_t stream;
+ pb_beacon_t *pbbeacon;
+ u32 offset;
+ dbg_assert (beacon);
+ dbg_assert (type < BSU_BEACON_TYPE_NB);
+ dbg_assert (mac_config);
+ dbg_assert (params);
+ /* Allocate the beacon. */
+ pbbeacon = (pb_beacon_t *) blk_alloc_desc ();
+ bitstream_write_init (&stream, pbbeacon->data, BSU_BEACON_SIZE);
+ bsu_beacon_write_variant_fields (
+ pbbeacon, &stream, mac_config, beacon, type);
+ bitstream_write (&stream, beacon->bmis.nbe, 8);
+ bsu_beacon_write_bmi_region (&stream, &beacon->bmis.region);
+ bsu_beacon_write_bmi_non_persistent (&stream, &beacon->bmis.nps,
+ pbbeacon->data);
+ bsu_beacon_write_bmi_persistent (&stream, &beacon->bmis.ps,
+ pbbeacon->data);
+ offset = bsu_beacon_write_bmi_bpsto (&stream,
+ &beacon->bmis.bpsto);
+ bsu_beacon_write_bmi_discover (&stream, &beacon->bmis.discover);
+ bsu_beacon_write_bmi_discover_info (&stream,
+ &beacon->bmis.discover_info);
+ bsu_beacon_write_bmi_eks (&stream, &beacon->bmis.eks);
+ bsu_beacon_write_bmi_handover (&stream, &beacon->bmis.handover);
+ bsu_beacon_write_bmi_relocation (&stream,
+ &beacon->bmis.relocation);
+ bsu_beacon_write_bmi_aclsc (&stream, &beacon->bmis.aclsc);
+ bsu_beacon_write_bmi_change_num_slot (&stream,
+ &beacon->bmis.cns);
+ bsu_beacon_write_bmi_change_hm (&stream,
+ &beacon->bmis.change_hm);
+ bsu_beacon_write_bmi_change_snid (&stream,
+ &beacon->bmis.change_snid);
+ bsu_beacon_write_bmi_mac_address (&stream, mac_config,
+ &beacon->bmis.mac_address_present);
+ bitstream_finalise (&stream);
+ params->bpsto = pbbeacon->data + offset;
+ return pbbeacon;
+}
+
+/**
+ * Read the beacon variant fields.
+ * \param phy_beacon the beacon received from the medium.
+ * \param stream the bitstream context.
+ * \param mac_config the mac config object.
+ * \param beacon the data to use to write the beacon.
+ * \param type the beacon type.
+ * \param tei the variable to store the TEI.
+ * \return true on success, false otherwise.
+ */
+static bool
+bsu_beacon_read_variant_fields (pb_beacon_t *phy_beacon,
+ bitstream_t *stream,
+ bsu_beacon_t *beacon,
+ bsu_beacon_type_t *type, u8 *tei)
+{
+ beacon->vf.nid = ((u64) bitstream_read (stream, 22)) << 32
+ | phy_beacon->first_data_word;
+ beacon->vf.hm = bitstream_read (stream, 2);
+ *tei = bitstream_read (stream, 8);
+ *type = bitstream_read (stream, 3);
+ beacon->vf.ncnr = bitstream_read (stream, 1);
+ beacon->vf.npsm = bitstream_read (stream, 1);
+ beacon->vf.numslots = bitstream_read (stream, 3);
+ beacon->vf.slotusage = bitstream_read (stream, 8);
+ beacon->vf.slotid = bitstream_read (stream, 3);
+ beacon->vf.aclsss = bitstream_read (stream, 3);
+ beacon->vf.hoip = bitstream_read (stream, 1);
+ beacon->vf.rtsbf = bitstream_read (stream, 1);
+ beacon->vf.nm = bitstream_read (stream, 2);
+ beacon->vf.ccocap = bitstream_read (stream, 2);
+ bitstream_skip (stream, 4);
+ if ((*type < BSU_BEACON_TYPE_NB)
+ && (beacon->vf.nm < BSU_BEACON_NM_NB)
+ && (beacon->vf.nid >> CP_NID_SIZE_BITS) == 0)
+ return true;
+ return false;
+}
+
+/**
+ * Read SAI in the beacon.
+ * \param stream the bitstream context.
+ * \param sai the schedule to fill.
+ */
+static void
+bsu_beacon_read_bmi_schedules_sai (bitstream_t *stream, bsu_beacon_sai_t *sai)
+{
+ sai->stpf = bitstream_read (stream, 1);
+ sai->glid = bitstream_read (stream, 7);
+ if (sai->stpf)
+ sai->start_time_atu = bitstream_read (stream, 12);
+ sai->end_time_atu = bitstream_read (stream, 12);
+}
+
+/**
+ * Read Non Persistent schedules from the beacon.
+ * \param stream the bitstream context.
+ * \param np the structure to store the schedules.
+ */
+static void
+bsu_beacon_read_bmi_non_persistent (
+ bitstream_t *stream, bsu_beacon_bmi_non_persistent_schedule_t *np)
+{
+ uint nb;
+ np->ns = bitstream_read (stream, 6);
+ bitstream_skip (stream, 2);
+ for (nb = 0; nb < np->ns; nb++)
+ bsu_beacon_read_bmi_schedules_sai (stream, &np->sais[nb]);
+}
+
+/**
+ * Read Persistent schedules from the beacon.
+ * \param stream the bitstream context.
+ * \param np the structure to store the schedules.
+ */
+static void
+bsu_beacon_read_bmi_persistent (
+ bitstream_t *stream, bsu_beacon_bmi_persistent_schedule_desc_t *p)
+{
+ uint nb;
+ p->pscd = bitstream_read (stream, 3);
+ p->cscd = bitstream_read (stream, 3);
+ bitstream_skip (stream, 2);
+ p->ns = bitstream_read (stream, 6);
+ bitstream_skip (stream, 2);
+ for (nb = 0; nb < p->ns; nb++)
+ bsu_beacon_read_bmi_schedules_sai (stream, &p->sais[nb]);
+}
+
+/**
+ * Read the beacon period start time offset beacon entry.
+ * \param ctx the module context.
+ * \param stream the bitstream context.
+ * \param bpsto the structure to store the BPSTO value.
+ */
+static void
+bsu_beacon_read_bmi_bpsto (bitstream_t *stream, bsu_beacon_bmi_bpsto_t *bpsto)
+{
+ bpsto->present = true;
+ bpsto->bpsto = bitstream_read (stream, 24);
+}
+
+void
+bsu_beacon_read_schedules (pb_beacon_t *beacon,
+ bsu_beacon_schedules_t *schedules)
+{
+ bitstream_t stream;
+ int i, nbe, nb_persistent = 0;
+ bsu_beacon_entry_header_t header;
+ uint length;
+ dbg_assert (beacon);
+ dbg_assert (schedules);
+ /* Initialise the bitstream context to read the beacon. */
+ bitstream_read_init (&stream, beacon->data, BSU_BEACON_SIZE);
+ /* Skip the NID. */
+ bitstream_skip (&stream, 22);
+ schedules->hm[0] = bitstream_read (&stream, 2);
+ /* Skip the end of variant fields. */
+ bitstream_skip (&stream, 40);
+ /* Read number of beacon entry. */
+ nbe = bitstream_read (&stream, 8);
+ for (i = 0; i < nbe; i++)
+ {
+ header = bitstream_read (&stream, 8);
+ length = bitstream_read (&stream, 8);
+ if (header == BSU_BEACON_ENTRY_HEADER_NON_PERSISTENT_SCHEDULE)
+ bsu_beacon_read_bmi_non_persistent (&stream, &schedules->nps);
+ else if (header == BSU_BEACON_ENTRY_HEADER_PERSISTENT_SCHEDULE)
+ bsu_beacon_read_bmi_persistent (&stream,
+ &schedules->ps.ps[nb_persistent++]);
+ else if (header ==
+ BSU_BEACON_ENTRY_HEADER_BEACON_PERIOD_START_TIME_OFFSET)
+ bsu_beacon_read_bmi_bpsto (&stream, &schedules->bpsto);
+ else
+ /* skip entry. */
+ bitstream_skip (&stream, length * 8);
+ }
+ bitstream_finalise (&stream);
+ schedules->ps.nb = nb_persistent;
+}
+
+/**
+ * Read the beacon entry header and length.
+ * \param stream the bitstream context.
+ * \param header the pointer to store the header.
+ * \param length the pointer to store the length.
+ * \return true on success, false otherwise.
+ */
+bool
+bsu_beacon_read_bmi_header (bitstream_t *bitstream, uint *header,
+ uint *length)
+{
+ *header = bitstream_read (bitstream, 8);
+ *length = bitstream_read (bitstream, 8);
+ if (BSU_BEACON_ENTRY_IS_BENTRY (*header))
+ return true;
+ return false;
+}
+
+/**
+ * Read the beacon region entry.
+ * \param bitstream the bitstream context.
+ * \param region the structure to store the data.
+ * \return true on success, false otherwise.
+ */
+static bool
+bsu_beacon_read_bmi_region (bitstream_t *bitstream,
+ bsu_beacon_bmi_region_t *region)
+{
+ uint i;
+ bool ok = true;
+ region->nb = bitstream_read (bitstream, 6);
+ dbg_assert (region->nb <= BSU_BEACON_BMI_REGION_NAX);
+ bitstream_skip (bitstream, 2);
+ for (i = 0; ok && i < region->nb; i++)
+ {
+ region->region[i].rt = bitstream_read (bitstream, 4);
+ region->region[i].end_time_atu = bitstream_read (bitstream, 12);
+ ok = region->region[i].rt < BSU_BEACON_REGION_NB;
+ }
+ return ok;
+}
+
+/**
+ * Read the beacon mac address entry.
+ * \param bitstream the bitstream context.
+ * \param mac_address to store data,
+ * \return true on success, false otherwise.
+ */
+static bool
+bsu_beacon_read_bmi_mac_address (bitstream_t *bitstream, mac_t *mac_address)
+{
+ *mac_address = bitstream_read_large (bitstream, 48);
+ return MAC_IS_VALID (*mac_address);
+}
+
+/**
+ * Read the beacon discover entry.
+ * \param bitstream the bitstream context.
+ * \param discover the discover structure to store the data.
+ */
+static void
+bsu_beacon_read_bmi_discover (bitstream_t *bitstream,
+ bsu_beacon_bmi_discover_t *discover)
+{
+ discover->tei = bitstream_read (bitstream, 8);
+ discover->present = MAC_TEI_IS_STA (discover->tei);
+}
+
+/**
+ * Read the beacon discover info entry.
+ * \param bitstream the bitstream context.
+ * \param info the info structure to store the data.
+ */
+static void
+bsu_beacon_read_bmi_discover_info (bitstream_t *bitstream,
+ bsu_beacon_bmi_discover_info_t *info)
+{
+ info->info_data = bitstream_read (bitstream, 32);
+ info->present = true;
+}
+
+/**
+ * Read the beacon handover entry.
+ * \param bitstream the bitstream context.
+ * \param handover the handover structure to store the data.
+ */
+static void
+bsu_beacon_read_bmi_handover (bitstream_t *bitstream,
+ bsu_beacon_bmi_handover_t *handover)
+{
+ handover->hcd = bitstream_read (bitstream, 6);
+ bitstream_skip (bitstream, 2);
+ handover->tei = bitstream_read (bitstream, 8);
+ handover->present = MAC_TEI_IS_STA (handover->tei);
+}
+
+/**
+ * Read the Change Hybrid mode.
+ * \param bitstream the bitstream context.
+ * \param hm the hybrid mode structure to store the data.
+ */
+static void
+bsu_beacon_read_bmi_change_hm (bitstream_t *bitstream,
+ bsu_beacon_bmi_change_hybrid_mode_t *hm)
+{
+ hm->present = true;
+ hm->hmccd = bitstream_read (bitstream, 6);
+ hm->newhm = bitstream_read (bitstream, 2);
+}
+
+/**
+ * Read the Change SNID.
+ * \param bitstream the bitstream context.
+ * \param snid the snid structure to store the data.
+ */
+static void
+bsu_beacon_read_bmi_change_snid (bitstream_t *bitstream,
+ bsu_beacon_bmi_change_snid_t *snid)
+{
+ snid->present = true;
+ snid->snidccd = bitstream_read (bitstream, 4);
+ snid->new_snid = bitstream_read (bitstream, 4);
+}
+
+/**
+ * Read the EKS bentry.
+ * \param bitstream the bitstream context.
+ * \param ekc the encryption key change structure to store the data.
+ */
+static void
+bsu_beacon_read_bmi_eks (bitstream_t *bitstream, bsu_beacon_bmi_eks_t *ekc)
+{
+ ekc->kccd = bitstream_read (bitstream, 6);
+ ekc->kbc = bitstream_read (bitstream, 1);
+ bitstream_skip (bitstream, 1);
+ ekc->new_eks = bitstream_read (bitstream, 4);
+ bitstream_skip (bitstream, 4);
+ ekc->present = (ekc->kbc < BSU_BEACON_EKS_KBC_NB);
+}
+
+/**
+ * Read the relocation bentry.
+ * \param bitstream the bitstream context.
+ * \param relocation the relocation structure to store the data.
+ */
+static void
+bsu_beacon_read_bmi_relocation (bitstream_t *stream,
+ bsu_beacon_bmi_relocation_t *relocation)
+{
+ relocation->present = true;
+ relocation->rcd = bitstream_read (stream, 6);
+ relocation->rlt = bitstream_read (stream, 1);
+ relocation->lgf = bitstream_read (stream, 1);
+ relocation->rlo = bitstream_read (stream, 17);
+ relocation->rlslotid = bitstream_read (stream, 3);
+ bitstream_skip (stream, 4);
+}
+
+/**
+ * Read the AC Line synchronisation bentry.
+ * \param bitstream the bitstream context.
+ * \param acl the acl structure to store the data.
+ */
+static void
+bsu_beacon_read_bmi_aslsc (bitstream_t *stream, bsu_beacon_bmi_aclsc_t *aclsc)
+{
+ aclsc->present = true;
+ aclsc->countdown = bitstream_read (stream, 6);
+ bitstream_skip (stream, 2);
+ aclsc->reason_code = bitstream_read (stream, 2);
+ bitstream_skip (stream, 6);
+}
+
+/**
+ * Read the change number of slots beacon entry.
+ * \param stream the bitstream context.
+ * \param cns the cns structure to store the data.
+ */
+static void
+bsu_beacon_read_bmi_change_num_slot (bitstream_t *stream,
+ bsu_beacon_bmi_change_num_slot_t *cns)
+{
+ cns->present = true;
+ cns->nsccd = bitstream_read (stream, 6);
+ bitstream_skip (stream, 2);
+ cns->newnumslot = bitstream_read (stream, 3);
+ bitstream_skip (stream, 5);
+}
+
+bool
+bsu_beacon_read (pb_beacon_t *pbbeacon, bsu_beacon_t *beacon,
+ bsu_beacon_type_t *type, u8 *tei, mac_t *mac_address)
+{
+ bitstream_t stream;
+ int nb_persistent = 0;
+ bsu_beacon_entry_header_t header;
+ uint nbe, length;
+ bool ok = false;
+ dbg_assert (pbbeacon);
+ dbg_assert (beacon);
+ /* If the CRC is false, stop all the data inside are corrupted. */
+ if (pbbeacon->phy_pb.pb_rx.pb_measurement.crc_error)
+ return false;
+ /* Initialise the data needed for the job. */
+ bitstream_read_init (&stream, pbbeacon->data, BSU_BEACON_SIZE);
+ ok = bsu_beacon_read_variant_fields (
+ pbbeacon, &stream, beacon, type, tei);
+ beacon->bmis.nbe = bitstream_read (&stream, 8);
+ // Processing beacon entries.
+ for (nbe = 0; ok && nbe < beacon->bmis.nbe; nbe++)
+ {
+ ok = bsu_beacon_read_bmi_header (&stream, &header, &length);
+ if (ok)
+ {
+ switch (header)
+ {
+ case BSU_BEACON_ENTRY_HEADER_REGIONS:
+ ok = bsu_beacon_read_bmi_region (
+ &stream, &beacon->bmis.region);
+ break;
+ case BSU_BEACON_ENTRY_HEADER_NON_PERSISTENT_SCHEDULE:
+ bsu_beacon_read_bmi_non_persistent (
+ &stream, &beacon->bmis.nps);
+ break;
+ case BSU_BEACON_ENTRY_HEADER_PERSISTENT_SCHEDULE:
+ bsu_beacon_read_bmi_persistent (
+ &stream, &beacon->bmis.ps.ps[nb_persistent++]);
+ break;
+ case BSU_BEACON_ENTRY_HEADER_MAC_ADDRESS:
+ ok = bsu_beacon_read_bmi_mac_address (&stream, mac_address);
+ beacon->bmis.mac_address_present.present = ok;
+ break;
+ case BSU_BEACON_ENTRY_HEADER_DISCOVER:
+ bsu_beacon_read_bmi_discover (
+ &stream, &beacon->bmis.discover);
+ break;
+ case BSU_BEACON_ENTRY_HEADER_DISCOVERED_INFO:
+ bsu_beacon_read_bmi_discover_info (
+ &stream, &beacon->bmis.discover_info);
+ break;
+ case BSU_BEACON_ENTRY_HEADER_BEACON_PERIOD_START_TIME_OFFSET:
+ bsu_beacon_read_bmi_bpsto (&stream, &beacon->bmis.bpsto);
+ break;
+ case BSU_BEACON_ENTRY_HEADER_CCO_HANDOVER:
+ bsu_beacon_read_bmi_handover (
+ &stream, &beacon->bmis.handover);
+ break;
+ case BSU_BEACON_ENTRY_HEADER_CHANGE_HM:
+ bsu_beacon_read_bmi_change_hm (
+ &stream, &beacon->bmis.change_hm);
+ break;
+ case BSU_BEACON_ENTRY_HEADER_CHANGE_SNID:
+ bsu_beacon_read_bmi_change_snid (
+ &stream, &beacon->bmis.change_snid);
+ break;
+ case BSU_BEACON_ENTRY_HEADER_ENCRYPTION_KEY_CHANGE:
+ bsu_beacon_read_bmi_eks (&stream, &beacon->bmis.eks);
+ break;
+ case BSU_BEACON_ENTRY_HEADER_BEACON_RELOCATION:
+ bsu_beacon_read_bmi_relocation (&stream,
+ &beacon->bmis.relocation);
+ break;
+ case BSU_BEACON_ENTRY_HEADER_AC_LINE_SYNC_COUNTDOWN:
+ bsu_beacon_read_bmi_aslsc (&stream, &beacon->bmis.aclsc);
+ break;
+ case BSU_BEACON_ENTRY_HEADER_CHANGE_NUMSLOTS:
+ bsu_beacon_read_bmi_change_num_slot (
+ &stream, &beacon->bmis.cns);
+ break;
+ case BSU_BEACON_ENTRY_HEADER_VENDOR:
+ default:
+ if (BYTES_SIZE_TO_BITS (length) <
+ bitstream_available_bits (&stream))
+ bitstream_skip (&stream, BYTES_SIZE_TO_BITS (length));
+ break;
+ }
+ }
+ }
+ bitstream_finalise (&stream);
+ beacon->bmis.ps.nb = nb_persistent;
+ /* If the beacon seams still ok check if the mandatory fields are
+ * present. */
+ if (ok
+ && !((*type == BSU_BEACON_TYPE_CENTRAL)
+ && (beacon->bmis.region.nb != 0)
+ && (beacon->bmis.nps.ns != 0 || beacon->bmis.ps.nb != 0)
+ && (((beacon->vf.nm == BSU_BEACON_NM_CSMA_ONLY)
+ && (beacon->bmis.bpsto.present == true))
+ || (beacon->vf.nm != BSU_BEACON_NM_CSMA_ONLY))
+ && (((beacon->vf.hoip == true)
+ && (beacon->bmis.handover.present == true))
+ || (beacon->vf.hoip == false)))
+ && !((*type == BSU_BEACON_TYPE_DISCOVER)
+ && (beacon->bmis.region.nb != 0)
+ && (beacon->bmis.mac_address_present.present == true)
+ && (beacon->bmis.discover_info.present == true)
+ && (beacon->bmis.bpsto.present == true))
+ && !((*type == BSU_BEACON_TYPE_PROXY)
+ && (beacon->bmis.bpsto.present == true)))
+ ok = false;
+ return ok;
+}
+
+void
+bsu_beacon_countdown (bsu_beacon_t *beacon)
+{
+ uint nb;
+ dbg_assert (beacon);
+ /* Parse persistent schedules and decrease the counter. */
+ for (nb = 0; nb < beacon->bmis.ps.nb; nb++)
+ {
+ /* Invalidate the persistent schedule if the current countdown is
+ * null. */
+ if (beacon->bmis.ps.ps[nb].pscd == 0
+ && beacon->bmis.ps.ps[nb].cscd == 0)
+ {
+ uint i;
+ beacon->bmis.ps.nb --;
+ /* move all the schedules after this one to this current position.
+ * */
+ for (i = nb; i < beacon->bmis.ps.nb; i++)
+ beacon->bmis.ps.ps[i] = beacon->bmis.ps.ps[i+1];
+ nb--;
+ }
+ /* Previous countdown. */
+ else if (beacon->bmis.ps.ps[nb].pscd)
+ beacon->bmis.ps.ps[nb].pscd--;
+ else if (beacon->bmis.ps.ps[nb].cscd)
+ beacon->bmis.ps.ps[nb].cscd--;
+ }
+ /* Encryption key change. */
+ if (beacon->bmis.eks.present)
+ {
+ beacon->bmis.eks.kccd --;
+ beacon->bmis.eks.present = beacon->bmis.eks.kccd;
+ }
+ /* CCo handover. */
+ if (beacon->bmis.handover.present)
+ {
+ beacon->bmis.handover.hcd --;
+ beacon->bmis.handover.present = beacon->bmis.handover.hcd;
+ }
+ /* Relocation beacon entry. */
+ if (beacon->bmis.relocation.present)
+ {
+ beacon->bmis.relocation.rcd --;
+ beacon->bmis.relocation.present = beacon->bmis.relocation.rcd;
+ }
+ /* AC Line synchronization beacon entry. */
+ if (beacon->bmis.aclsc.present)
+ {
+ beacon->bmis.aclsc.countdown --;
+ beacon->bmis.aclsc.present = beacon->bmis.aclsc.countdown;
+ }
+ /* Change num slots beacon entry. */
+ if (beacon->bmis.cns.present)
+ {
+ beacon->bmis.cns.nsccd --;
+ beacon->bmis.cns.present = beacon->bmis.cns.nsccd;
+ }
+ /* Change HM beacon entry. */
+ if (beacon->bmis.change_hm.present)
+ {
+ beacon->bmis.change_hm.hmccd --;
+ beacon->bmis.change_hm.present = beacon->bmis.change_hm.hmccd;
+ }
+ /* Change SNID beacon entry. */
+ if (beacon->bmis.change_snid.present)
+ {
+ beacon->bmis.change_snid.snidccd --;
+ beacon->bmis.change_snid.present = beacon->bmis.change_snid.snidccd;
+ }
+}