/* Cesar project {{{ * * Copyright (C) 2010 Spidcom * * <<>> * * }}} */ /** * \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; } }