summaryrefslogtreecommitdiff
path: root/cesar/mac/common/src/store.c
diff options
context:
space:
mode:
Diffstat (limited to 'cesar/mac/common/src/store.c')
-rw-r--r--cesar/mac/common/src/store.c523
1 files changed, 523 insertions, 0 deletions
diff --git a/cesar/mac/common/src/store.c b/cesar/mac/common/src/store.c
new file mode 100644
index 0000000000..93be2948c8
--- /dev/null
+++ b/cesar/mac/common/src/store.c
@@ -0,0 +1,523 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file mac/common/src/store.c
+ * \brief MFS and STA store, store pointers to MFS and STA information.
+ * \ingroup mac_common
+ */
+#include "common/std.h"
+#include "mac/common/store.h"
+
+#include "hal/arch/arch.h"
+#include "mac/common/defs.h"
+#include "lib/blk.h"
+
+/** Define index into MFS tables tables. */
+enum mac_store_kind_t
+{
+ MAC_STORE_KIND_TXRX_MASK = 1,
+ MAC_STORE_KIND_RX = 0,
+ MAC_STORE_KIND_TX = 1,
+ MAC_STORE_KIND_BCAST_MASK = 2,
+ MAC_STORE_KIND_RX_BCAST = 2,
+ MAC_STORE_KIND_STA_NB = 3,
+ MAC_STORE_KIND_TX_BCAST = 3
+};
+typedef enum mac_store_kind_t mac_store_kind_t;
+
+/** Find MFS for any traffic from and to a peer. MFS for non associated STA
+ * are not recorded here (actually, they are recorded nowhere). */
+struct mac_store_sta_t
+{
+ /** Other information about a STA. */
+ sta_t sta;
+ /** PLID MFS for this STA. */
+ mfs_t *plid[MAC_STORE_KIND_STA_NB][MAC_PLID_NB];
+ /** MME MFS for this STA. */
+ mfs_t *mme[MAC_STORE_KIND_STA_NB];
+ /** LLID MFS for RX from this STA. Only allocated when really needed, the
+ * first four pointers are not used. */
+ mfs_t **rx_llid;
+};
+typedef struct mac_store_sta_t mac_store_sta_t;
+
+/** MFS store context. */
+struct mac_store_t
+{
+ /* PLID MFS for broadcast TX from us. */
+ mfs_t *bcast_tx_plid[MAC_PLID_NB];
+ /* MME MFS for broadcast TX from us. */
+ mfs_t *bcast_tx_mme;
+ /** LLID MFS for TX and GLID MFS for TX/RX table.
+ * - 0x00-0x03: unused
+ * - 0x04-0x7f: TX LLID
+ * - 0x80-0xf7: TX/RX GLID
+ * - 0xf8-0xfd: unused & discover and central beacons */
+ mfs_t *lglid[MAC_LID_BEACON_MAX + 1];
+ /** Peers, indexed by TEI. */
+ mac_store_sta_t *sta[MAC_TEI_STA_MAX + 1];
+};
+/* Forward declaration in mac/common/store.h. */
+
+/** Global mac store context. */
+mac_store_t mac_store_global_context;
+
+mac_store_t *
+mac_store_init (void)
+{
+ uint i;
+ dbg_assert (BLK_SIZE == (MAC_LLID_MAX + 1) * sizeof (mfs_t *));
+ mac_store_t *ctx = &mac_store_global_context;
+ for (i = 0; i < COUNT (ctx->bcast_tx_plid); i++)
+ ctx->bcast_tx_plid[i] = NULL;
+ ctx->bcast_tx_mme = NULL;
+ for (i = 0; i < COUNT (ctx->lglid); i++)
+ ctx->lglid[i] = NULL;
+ for (i = 0; i < COUNT (ctx->sta); i++)
+ ctx->sta[i] = NULL;
+ return ctx;
+}
+
+void
+mac_store_uninit (mac_store_t *ctx)
+{
+ uint i;
+ for (i = 0; i < COUNT (ctx->bcast_tx_plid); i++)
+ dbg_assert (ctx->bcast_tx_plid[i] == NULL);
+ dbg_assert (ctx->bcast_tx_mme == NULL);
+ for (i = 0; i < COUNT (ctx->lglid); i++)
+ dbg_assert (ctx->lglid[i] == NULL);
+ for (i = 0; i < COUNT (ctx->sta); i++)
+ dbg_assert (ctx->sta[i] == NULL);
+}
+
+/**
+ * Factorise code to find a MFS.
+ * \param ctx store context
+ * \param tx true for a TX MFS
+ * \param bcast true for a broadcast MFS
+ * \param mme true for a MME MFS
+ * \param lid link id
+ * \param tei peer terminal equipment id
+ * \param add true if a MFS is being added
+ * \return pointer to an MFS pointer or NULL if no STA or no LLID table or
+ * GLID slot used
+ */
+static inline mfs_t **
+mac_store_mfs_slot_get (mac_store_t *ctx, bool tx, bool bcast, bool mme,
+ uint lid, uint tei, bool add __FL)
+{
+ dbg_assert (ctx);
+ dbg_assert ((mme && lid == MAC_LID_NONE)
+ || (!mme && (MAC_LID_IS_XLID (lid)
+ || lid == MAC_LID_DISCOVER
+ || lid == MAC_LID_SPC_CENTRAL)));
+ dbg_assert (((MAC_LID_IS_GLID (lid) /* Needed when tei is unknown. */
+ || lid == MAC_LID_DISCOVER
+ || lid == MAC_LID_SPC_CENTRAL) && tei == 0)
+ || (bcast && tx && tei == MAC_TEI_BCAST)
+ || (!(bcast && tx) && MAC_TEI_IS_STA (tei)));
+ if (!mme && (lid >= MAC_GLID_MIN))
+ {
+ /* GLID table contains TX and RX MFS, check it is the requested
+ * type. */
+ if (ctx->lglid[lid] && ctx->lglid[lid]->common.tx != tx)
+ {
+ dbg_assert (!add);
+ return NULL;
+ }
+ else
+ return &ctx->lglid[lid];
+ }
+ else if (!mme && (tx && lid >= MAC_LLID_MIN))
+ return &ctx->lglid[lid];
+ else if (tx && bcast && !mme && MAC_LID_IS_PLID (lid))
+ return &ctx->bcast_tx_plid[lid];
+ else if (tx && bcast && mme)
+ return &ctx->bcast_tx_mme;
+ else
+ {
+ /* Here, we need a STA. */
+ if (add)
+ mac_store_sta_add_ (ctx, tei __fl);
+ mac_store_sta_t *sta = ctx->sta[tei];
+ if (!sta)
+ return NULL;
+ else
+ {
+ if (!mme && lid >= MAC_LLID_MIN)
+ {
+ dbg_assert (!tx && lid <= MAC_LLID_MAX);
+ if (!sta->rx_llid)
+ {
+ if (add)
+ {
+ /* Allocate a new table. */
+ sta->rx_llid = blk_alloc_zero_ (_fl);
+ return &sta->rx_llid[lid];
+ }
+ else
+ return NULL;
+ }
+ else
+ return &sta->rx_llid[lid];
+ }
+ else
+ {
+ mac_store_kind_t kind = (tx ? MAC_STORE_KIND_TXRX_MASK : 0)
+ | (bcast ? MAC_STORE_KIND_BCAST_MASK : 0);
+ if (mme)
+ return &sta->mme[kind];
+ else
+ {
+ dbg_assert (lid <= MAC_PLID_MAX);
+ return &sta->plid[kind][lid];
+ }
+ }
+ }
+ }
+}
+
+mfs_t *
+mac_store_mfs_get_ (mac_store_t *ctx, bool tx, bool bcast, bool mme, uint lid,
+ uint tei __FL)
+{
+ mfs_t *mfs = NULL;
+ dbg_assert (ctx);
+ arch_dsr_lock ();
+ mfs_t **slot = mac_store_mfs_slot_get (ctx, tx, bcast, mme, lid, tei,
+ false __fl);
+ if (slot && *slot)
+ {
+ mfs = *slot;
+ blk_addref_ (mfs __fl);
+ }
+ arch_dsr_unlock ();
+ return mfs;
+}
+
+mfs_t *
+mac_store_mfs_add_ (mac_store_t *ctx, bool tx, bool bcast, bool mme, uint lid,
+ uint tei, bool *added __FL)
+{
+ mfs_t *mfs;
+ dbg_assert (ctx);
+ dbg_assert (added);
+ arch_dsr_lock ();
+ mfs_t **slot = mac_store_mfs_slot_get (ctx, tx, bcast, mme, lid, tei,
+ true __fl);
+ dbg_assert (slot);
+ *added = false;
+ if (!*slot)
+ {
+ mfs = blk_alloc_ (_fl);
+ if (!tx)
+ mfs_rx_init (&mfs->rx, bcast, mme, lid, tei);
+ else
+ mfs_tx_init (&mfs->tx, bcast, mme, lid, tei);
+ arch_reorder_barrier ();
+ *slot = mfs;
+ *added = true;
+ }
+ else
+ {
+ mfs = *slot;
+ }
+ blk_addref_ (mfs __fl);
+ arch_dsr_unlock ();
+ return mfs;
+}
+
+void
+mac_store_mfs_alias_ (mac_store_t *ctx, mfs_t *mfs, uint glid __FL)
+{
+ dbg_assert (ctx);
+ dbg_assert (mfs);
+ dbg_assert (MAC_LID_IS_GLID (glid));
+ dbg_assert (MAC_LID_IS_LLID (mfs->common.lid));
+ dbg_assert (mfs->common.lid_alias == MAC_LID_NONE);
+ /* Add the MFS to the GLID slot. */
+ dbg_assert (ctx->lglid[glid] == NULL);
+ arch_dsr_lock ();
+ blk_addref_ (mfs __fl);
+ ctx->lglid[glid] = mfs;
+ /* Modify the MFS. */
+ mfs->common.lid_alias = mfs->common.lid;
+ mfs->common.lid = glid;
+ arch_dsr_unlock ();
+}
+
+void
+mac_store_mfs_remove_ (mac_store_t *ctx, mfs_t *mfs __FL)
+{
+ dbg_assert (ctx);
+ dbg_assert (mfs);
+ arch_dsr_lock ();
+ bool alias = mfs->common.lid_alias != MAC_LID_NONE;
+ /* Remove alias first. */
+ uint lid = alias ? mfs->common.lid_alias : mfs->common.lid;
+ mfs_t **slot =
+ mac_store_mfs_slot_get (ctx, mfs->common.tx, mfs->common.bcast,
+ mfs->common.mme, lid,
+ mfs->common.tei, false __fl);
+ if (slot && *slot)
+ {
+ /* Order is important. The code could be interrupted... */
+ dbg_assert (*slot == mfs);
+ arch_reorder_barrier (); /* ...here... */
+ *slot = NULL;
+ arch_reorder_barrier (); /* ...or here... */
+ blk_release_ (mfs __fl);
+ }
+ /* Now remove actual GLID if aliased. */
+ if (alias)
+ {
+ dbg_assert (MAC_LID_IS_LLID (lid));
+ dbg_assert (MAC_LID_IS_GLID (mfs->common.lid));
+ slot = &ctx->lglid[mfs->common.lid];
+ dbg_assert (*slot == mfs);
+ arch_reorder_barrier ();
+ *slot = NULL;
+ arch_reorder_barrier ();
+ blk_release_ (mfs __fl);
+ }
+ arch_dsr_unlock ();
+}
+
+/**
+ * Helper for the travel functions.
+ * \param ctx store context
+ * \param mfs MFS to travel or NULL
+ * \param travel callback function
+ * \param user user data
+ *
+ * Will unlock DSR.
+ */
+void
+mac_store_mfs_travel_mfs_and_unlock (mac_store_t *ctx, mfs_t *mfs,
+ mac_store_travel_t travel, void *user)
+{
+ if (mfs)
+ {
+ blk_addref (mfs);
+ arch_dsr_unlock ();
+ travel (ctx, mfs, user);
+ blk_release (mfs);
+ }
+ else
+ arch_dsr_unlock ();
+}
+
+void
+mac_store_mfs_travel (mac_store_t *ctx, mac_store_travel_t travel,
+ void *user)
+{
+ /* Will unlock DSR between each MFS fetch to reduce DSR latency. */
+ int i;
+ dbg_assert (ctx);
+ dbg_assert (travel);
+ /* First travel local MFS. */
+ for (i = 0; i < MAC_PLID_NB; i++)
+ {
+ arch_dsr_lock ();
+ mac_store_mfs_travel_mfs_and_unlock (ctx, ctx->bcast_tx_plid[i],
+ travel, user);
+ }
+ arch_dsr_lock ();
+ mac_store_mfs_travel_mfs_and_unlock (ctx, ctx->bcast_tx_mme, travel,
+ user);
+ for (i = MAC_LLID_MIN; i < MAC_LID_NB; i++)
+ {
+ arch_dsr_lock ();
+ mac_store_mfs_travel_mfs_and_unlock (ctx, ctx->lglid[i], travel,
+ user);
+ }
+ /* Do not forget beacon MFS. */
+ arch_dsr_lock ();
+ mac_store_mfs_travel_mfs_and_unlock (ctx, ctx->lglid[MAC_LID_DISCOVER],
+ travel, user);
+ arch_dsr_lock ();
+ mac_store_mfs_travel_mfs_and_unlock (ctx, ctx->lglid[MAC_LID_SPC_CENTRAL],
+ travel, user);
+ /* Now travel by TEI. */
+ for (i = MAC_TEI_STA_MIN; i <= MAC_TEI_STA_MAX; i++)
+ mac_store_mfs_travel_by_tei (ctx, i, travel, user);
+}
+
+void
+mac_store_mfs_travel_by_tei (mac_store_t *ctx, uint tei,
+ mac_store_travel_t travel, void *user)
+{
+ uint i, j;
+ mac_store_sta_t *sta;
+ dbg_assert (ctx);
+ dbg_assert (MAC_TEI_IS_STA (tei));
+ dbg_assert (travel);
+ arch_dsr_lock ();
+ sta = ctx->sta[tei];
+ if (!sta)
+ {
+ arch_dsr_unlock ();
+ }
+ else
+ {
+ /* Ensure we do not lose the STA. */
+ blk_addref (sta);
+ arch_dsr_unlock ();
+ /* Travel MFS. */
+ for (i = 0; i < MAC_STORE_KIND_STA_NB; i++)
+ {
+ for (j = 0; j < MAC_PLID_NB; j++)
+ {
+ arch_dsr_lock ();
+ mac_store_mfs_travel_mfs_and_unlock (ctx, sta->plid[i][j],
+ travel, user);
+ }
+ arch_dsr_lock ();
+ mac_store_mfs_travel_mfs_and_unlock (ctx, sta->mme[i], travel,
+ user);
+ }
+ for (i = MAC_LLID_MIN; i <= MAC_LLID_MAX; i++)
+ {
+ arch_dsr_lock ();
+ /* Do this test at each loop step as the scheduler is unlocked
+ * between each step. */
+ if (!sta->rx_llid)
+ {
+ arch_dsr_unlock ();
+ break;
+ }
+ mac_store_mfs_travel_mfs_and_unlock (ctx, sta->rx_llid[i],
+ travel, user);
+ }
+ blk_release (sta);
+ }
+}
+
+sta_t *
+mac_store_sta_get_ (mac_store_t *ctx, uint tei __FL)
+{
+ dbg_assert (ctx);
+ dbg_assert (MAC_TEI_IS_STA (tei));
+ arch_dsr_lock ();
+ mac_store_sta_t *sta = ctx->sta[tei];
+ if (sta)
+ {
+ blk_addref_ (sta __fl);
+ arch_dsr_unlock ();
+ return &sta->sta;
+ }
+ else
+ {
+ arch_dsr_unlock ();
+ return NULL;
+ }
+}
+
+void
+mac_store_sta_add_ (mac_store_t *ctx, uint tei __FL)
+{
+ mac_store_sta_t *sta;
+ uint i, j;
+ dbg_assert (ctx);
+ dbg_assert (MAC_TEI_IS_STA (tei));
+ /* If the DSR lock time need to be decreased, the STA could be
+ * initialised, then existence be checked again. */
+ arch_dsr_lock ();
+ if (!ctx->sta[tei])
+ {
+ sta = blk_new_ ((blk_destructor_t) sta_uninit __fl);
+ sta_init (&sta->sta, tei);
+ /* Clear the new STA tables. */
+ for (i = 0; i < COUNT (sta->plid); i++)
+ {
+ for (j = 0; j < COUNT (sta->plid[i]); j++)
+ {
+ sta->plid[i][j] = NULL;
+ }
+ sta->mme[i] = NULL;
+ }
+ sta->rx_llid = NULL;
+ /* Done, ready to be used (order is important). */
+ arch_reorder_barrier ();
+ ctx->sta[tei] = sta;
+ }
+ arch_dsr_unlock ();
+}
+
+bool
+mac_store_sta_remove_ (mac_store_t *ctx, uint tei __FL)
+{
+ mac_store_sta_t *sta;
+ uint i, j;
+ dbg_assert (ctx);
+ dbg_assert (MAC_TEI_IS_STA (tei));
+ dbg_assert (ctx->sta[tei] != NULL);
+ arch_dsr_lock ();
+ /* Order is important! */
+ sta = ctx->sta[tei];
+ arch_reorder_barrier ();
+ /* Check the MFS are freed. */
+ bool ok = true;
+ for (i = 0; ok && i < COUNT (sta->plid); i++)
+ {
+ for (j = 0; ok && j < COUNT (sta->plid[i]); j++)
+ if (sta->plid[i][j])
+ ok = false;
+ if (sta->mme[i])
+ ok = false;
+ }
+ if (ok && sta->rx_llid)
+ {
+ for (i = 0; ok && i < MAC_LLID_MAX; i++)
+ if (sta->rx_llid[i])
+ ok = false;
+ }
+ if (ok)
+ {
+ /* Can no longer be accessed by interrupts, order is important. */
+ arch_reorder_barrier ();
+ ctx->sta[tei] = NULL;
+ arch_reorder_barrier ();
+ /* Free the LLID table. If someone owns a reference, this is not the
+ * store and it does not care about rx_llid. */
+ if (sta->rx_llid)
+ blk_release_ (sta->rx_llid __fl);
+ /* Release the STA information. */
+ blk_release_ (sta __fl);
+ }
+ arch_dsr_unlock ();
+ return ok;
+}
+
+int
+mac_store_get_free_tx_llid (mac_store_t *ctx)
+{
+ int i;
+ dbg_assert (ctx);
+ for (i = MAC_LLID_MIN; i <= MAC_LLID_MAX; i++)
+ {
+ if (ctx->lglid[i] == NULL)
+ return i;
+ }
+ return -1;
+}
+
+int
+mac_store_get_free_tei (mac_store_t *ctx)
+{
+ int i;
+ dbg_assert (ctx);
+ for (i = MAC_TEI_STA_MIN; i <= MAC_TEI_STA_MAX; i++)
+ {
+ if (ctx->sta[i] == NULL)
+ return i;
+ }
+ return -1;
+}
+