summaryrefslogtreecommitdiff
path: root/cesar/cl
diff options
context:
space:
mode:
Diffstat (limited to 'cesar/cl')
-rw-r--r--cesar/cl/Config6
-rw-r--r--cesar/cl/Module5
-rw-r--r--cesar/cl/cl_eoc_mactotei.h159
-rw-r--r--cesar/cl/cl_mactotei.h23
-rw-r--r--cesar/cl/inc/context.h39
-rw-r--r--cesar/cl/inc/trace.h3
-rw-r--r--cesar/cl/mcast.h36
-rw-r--r--cesar/cl/src/bridge_table.c10
-rw-r--r--cesar/cl/src/cl.c72
-rw-r--r--cesar/cl/src/cl_eoc_mactotei.c328
-rw-r--r--cesar/cl/src/cl_mactotei.c2
-rw-r--r--cesar/cl/src/mcast.c60
-rw-r--r--cesar/cl/src/receive.c16
-rw-r--r--cesar/cl/src/send_data.c152
-rw-r--r--cesar/cl/src/trace.c8
-rw-r--r--cesar/cl/stub/Module5
-rw-r--r--cesar/cl/stub/src/cl_eoc_mactotei.c62
-rw-r--r--cesar/cl/stub/src/mcast.c26
-rw-r--r--cesar/cl/test/bridge_table/Makefile1
-rw-r--r--cesar/cl/test/data_rate/Makefile1
-rw-r--r--cesar/cl/test/functional/host-Config2
-rw-r--r--cesar/cl/test/functional/src/cl.c4
-rw-r--r--cesar/cl/test/utest/src/cl.c3
-rw-r--r--cesar/cl/test/utest/src/misc.c3
-rw-r--r--cesar/cl/test/utest_eoc/Config9
-rw-r--r--cesar/cl/test/utest_eoc/Makefile17
-rw-r--r--cesar/cl/test/utest_eoc/src/cl.c50
-rw-r--r--cesar/cl/test/utest_eoc/src/hle_tools.c37
-rw-r--r--cesar/cl/test/utest_eoc/src/mcast.c69
-rw-r--r--cesar/cl/test/utest_eoc/src/receive.c83
-rw-r--r--cesar/cl/test/utest_eoc/src/send.c261
-rw-r--r--cesar/cl/test/utest_eoc/src/test.c88
-rw-r--r--cesar/cl/test/utest_eoc/src/test_mactotei.c232
-rw-r--r--cesar/cl/test/utest_eoc/test.h124
34 files changed, 1929 insertions, 67 deletions
diff --git a/cesar/cl/Config b/cesar/cl/Config
index c91d7c649d..4439db01e0 100644
--- a/cesar/cl/Config
+++ b/cesar/cl/Config
@@ -1,5 +1,9 @@
+CONFIG_CL_EOC_CLASSIFY = n
CONFIG_GPIO_LED_CL_RX = n
CONFIG_GPIO_LED_CL_RX_GPIO = 0
CONFIG_GPIO_LED_CL_TX = n
CONFIG_GPIO_LED_CL_TX_GPIO = 0
-CONFIG_CL_DATA_RATE=n
+CONFIG_CL_EOC_ROUTE = n
+CONFIG_CL_DATA_RATE = n
+CONFIG_CL_MCAST = n
+CONFIG_CL_AV = y
diff --git a/cesar/cl/Module b/cesar/cl/Module
index 1623f040a3..2b5a906a19 100644
--- a/cesar/cl/Module
+++ b/cesar/cl/Module
@@ -1,7 +1,10 @@
SOURCES := cl.c cl_mactotei.c bridge_table.c data_rate.c brg_rx.c send_mme.c \
- send_data.c receive.c
+ send_data.c receive.c mcast.c
ifeq ($(CONFIG_TRACE),y)
SOURCES += trace.c
endif
+ifeq ($(CONFIG_CL_EOC_ROUTE),y)
+SOURCES += cl_eoc_mactotei.c
+endif
MODULES := cl/mbx
diff --git a/cesar/cl/cl_eoc_mactotei.h b/cesar/cl/cl_eoc_mactotei.h
new file mode 100644
index 0000000000..57bf74f8c7
--- /dev/null
+++ b/cesar/cl/cl_eoc_mactotei.h
@@ -0,0 +1,159 @@
+#ifndef CL_EOC_MACTOTEI_H_
+#define CL_EOC_MACTOTEI_H_
+
+/* Cesar project {{{
+ *
+ * Copyright (C) 2009 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file cl/cl_eoc_mactotei.h
+ * \brief MAC to TEI table interface between the CL and the CP.
+ * \ingroup cl
+ *
+ * The MAC to TEI table associate a MAC address to a TEI and a timestamp. The
+ * timestamp is used to know if the entry is obsolete entry or not.
+ */
+#include "lib/list.h"
+#include "mac/common/timings.h"
+
+#define MACTOTEI_NB_ENTRIES 512
+#define MACTOTEI_HASHSIZE 256
+#define MACTOTEI_HASHFUNC(mac) ((mac) >> 40)
+#define MAC_LIMITATION 9
+
+/** Duration after which the entry is obsolete (in seconds)*/
+#define MAX_ENTRY_AGE_SEC 1800
+#define MIN_ENTRY_AGE_SEC 60
+#define DEFAULT_ENTRY_AGE_SEC 300
+
+/** Single MAC to TEI entry contained in the table. Reserved entries do not age,
+ * they are reserved for multicast
+ */
+struct cl_eoc_mactotei_entry_t
+{
+ /** Station's TEI*/
+ uint tei;
+ /** MAC address of equipment behind TEI*/
+ mac_t mac_addr;
+ /** Entry's node in unique ageing list of all MAC adresses*/
+ list_node_t l_age;
+ /** Entry's node in hashing_list. */
+ list_node_t l_hash;
+ /** Time of creation or refresh of entry. */
+ uint timestamp;
+ /** Reserved entries do not age. */
+ bool reserved;
+};
+
+typedef struct cl_eoc_mactotei_entry_t cl_eoc_mactotei_entry_t;
+
+/** Entry used by the snapshot of the mactotei table. */
+struct cl_eoc_mactotei_snapshot_entry_t
+{
+ u64 mac:48;
+ u64 tei:16;
+};
+typedef struct cl_eoc_mactotei_snapshot_entry_t \
+ cl_eoc_mactotei_snapshot_entry_t;
+
+/** Table used to keep MAC to TEI mappings */
+struct cl_eoc_mactotei_table_t
+{
+ /** Unique ageing list. */
+ list_t ageing_list;
+ /** Hashing lists, take least significant byte of MAC address. */
+ list_t hashing_list[MACTOTEI_HASHSIZE];
+ /** Limited number of entries for each STA/CCo. */
+ cl_eoc_mactotei_entry_t cl_eoc_mtt_entries[MACTOTEI_NB_ENTRIES];
+ /** Duration after which entry is obsolete */
+ uint max_duration;
+ /** Current number mac addresses on STA side */
+ uint num_of_entries;
+ /** Number of allowed mac addresses on STA side */
+ uint max_entries;
+ /** STA's local time for entries expiration */
+ uint time_count;
+ /** Snapshot of valid (MAC address, TEI) in MAC to TEI table.*/
+ cl_eoc_mactotei_snapshot_entry_t mactotei_snapshot[MACTOTEI_NB_ENTRIES];
+};
+
+typedef struct cl_eoc_mactotei_table_t cl_eoc_mactotei_table_t;
+
+BEGIN_DECLS
+
+/** Find TEI to which to route packests according to MAC address.
+ * \param ctx CL context
+ * \param mac_addr MAC address of source
+ */
+uint
+cl_eoc_mactotei_find_tei (cl_t *ctx, mac_t mac_addr);
+
+/** Initialization of EoC mactotei table.
+ * \param ctx CL context
+ */
+void
+cl_eoc_mactotei_init (cl_t *ctx);
+
+/** Put new entry in mactotei table.
+ * \param ctx CL context
+ * \param mac_addr MAC address of new entry
+ * \param tei TEI of new entry
+*/
+bool
+cl_eoc_mactotei_entry_insert (cl_t *ctx, mac_t mac_addr, uint tei);
+
+/** Remove all entries associated with given TEI from ageing and hashing lists
+ * of cl_eoc_mactotei_table.
+ * \param ctx CL context
+ * \param tei TEI of the STA whose entries should be removed from the table
+*/
+void
+cl_eoc_mactotei_entry_remove (cl_t *ctx, uint tei);
+
+/** Set time during which entry will be valid.
+ * \param ctx CL context
+ * \param max_dur_sec maximum duration of entry in seconds
+ */
+void
+cl_eoc_mactotei_set_entry_duration (cl_t * ctx, uint max_dur_sec);
+
+/**
+ * Perform some periodic action
+ */
+void
+cl_eoc_mactotei_periodic_action (cl_t *ctx);
+
+/**
+ * Create a snapshot of the MAC to TEI entries.
+ * \param ctx CL context
+ * \return Number of entries in the created snapshot.
+ */
+uint
+cl_eoc_mactotei_snapshot_create (cl_t *ctx);
+
+/**
+ * Get a MAC address from the mactotei's snapshot
+ * \param ctx CL context
+ * \param index index of the MAC address to get
+ * \return the MAC address
+ */
+mac_t
+cl_eoc_mactotei_snapshot_get_mac (cl_t *ctx, uint index);
+
+/**
+ * Get a (MAC, TEI) from the mactotei's snapshot
+ * \param ctx CL context
+ * \param index index of the (MAC, TEI) to get
+ * \param[out] mac the MAC
+ * \param[out] tei the TEI
+ */
+void
+cl_eoc_mactotei_snapshot_get_mac_tei (cl_t *ctx, uint index, mac_t *mac,
+ uint *tei);
+
+END_DECLS
+
+#endif /*CL_EOC_MACTOTEI_H_*/
diff --git a/cesar/cl/cl_mactotei.h b/cesar/cl/cl_mactotei.h
index f6e416b588..d403861b45 100644
--- a/cesar/cl/cl_mactotei.h
+++ b/cesar/cl/cl_mactotei.h
@@ -39,8 +39,10 @@ typedef struct mac_lookup_block_header_t cl_mactotei_blk_t;
*/
struct cl_mactotei_entry_t
{
+ /** A MAC address*/
mac_t mac;
- u8 tei;
+ /** A TEI */
+ uint tei;
u8 tag;
};
typedef struct cl_mactotei_entry_t cl_mactotei_entry_t;
@@ -168,6 +170,25 @@ void
cl_mactotei_cancel (cl_mactotei_blk_t *table);
/**
+ * Add a temporary entry to the bridge table (if not already existing).
+ * \param cl the CL context.
+ * \param tei the TEI.
+ * \param mac the source MAC address.
+ */
+void
+cl_mactotei_add (cl_t *ctx, uint tei, mac_t mac);
+
+/**
+ * Get TEI associated to a given MAC address of a packet
+ * \param cl the CL context.
+ * \param mac the source MAC address of a packet
+ *
+ * This function is called every time CCo has to send_sack
+ */
+uint
+cl_mactotei_get_tei (cl_t *ctx, mac_t mac);
+
+/*
* This function will return the current amount of entry in the mactotei table
* (Used by VS_GET_MACTOTEI).
* \param ctx the CL context.
diff --git a/cesar/cl/inc/context.h b/cesar/cl/inc/context.h
index afc24cd739..a2c0a6bf32 100644
--- a/cesar/cl/inc/context.h
+++ b/cesar/cl/inc/context.h
@@ -20,6 +20,10 @@
#include "cl/brg_rx.h"
#include "cl/inc/bridge_table.h"
#include "cl/inc/trace.h"
+#include "config/cl/eoc.h"
+
+#include "cl/cl_eoc_mactotei.h"
+#include "common/defs/igmp.h"
#include "cl/mbx/inc/mbx.h"
/** Define the delay at the one the data inside the cl_data_send_link_t are
@@ -45,6 +49,32 @@ struct cl_data_send_link_t
};
typedef struct cl_data_send_link_t cl_data_send_link_t;
+/** Cl statistics structure. */
+struct cl_stat_t
+{
+ /** Received data frames. */
+ uint rx_data;
+ /** Received bytes count. */
+ uint rx_data_bytes;
+ /** Received multicast frames. */
+ uint rx_data_multicast;
+ /** Received mme frames. */
+ uint rx_mme;
+ /** Transmitted data frames. */
+ uint tx_data;
+ /** Transmitted data frames dropped, not auth. */
+ uint tx_data_drop_auth;
+ /** Transmitted data frames dropped, mfs overload. */
+ uint tx_data_drop_mfs;
+ /** Transmitted bytes count. */
+ uint tx_data_bytes;
+ /** Transmitted multicast frames. */
+ uint tx_data_multicast;
+ /** Transmitted mme frames. */
+ uint tx_mme;
+};
+typedef struct cl_stat_t cl_stat_t;
+
struct cl_t
{
/** The sar context use to send the MME or data. */
@@ -62,6 +92,13 @@ struct cl_t
/** mactotei table to send data over the PLC. */
cl_mactotei_table_t *mactotei;
+#if CONFIG_CL_EOC_ROUTE
+ /** Table for routing packages in EoC, maps MAC to TEI of STA on CCo side
+ * and limits number of MAC address behind STA
+ */
+ cl_eoc_mactotei_table_t cl_eoc_mactotei_table;
+#endif
+
/** The mac config */
mac_config_t *mac_config;
@@ -89,6 +126,8 @@ struct cl_t
lib_seq_check_t seq_check_rx_ctx;
lib_seq_check_t seq_check_tx_ctx;
#endif
+ /** Cl statistics. */
+ cl_stat_t stats;
};
#endif /* CL_INC_CONTEXT_H_ */
diff --git a/cesar/cl/inc/trace.h b/cesar/cl/inc/trace.h
index 8c9cb6a07f..bbe27c0c2f 100644
--- a/cesar/cl/inc/trace.h
+++ b/cesar/cl/inc/trace.h
@@ -43,12 +43,13 @@ enum
CL_TRACE_DATA_SEND,
CL_TRACE_DATA_SEND_DROP,
CL_TRACE_DATA_SEND_DONE,
- CL_TRACE_DATA_SEND_MULTI_FAILED,
CL_TRACE_DATA_RECV,
CL_TRACE_DATA_BUFFER_ADD,
CL_TRACE_BRIDGE_ADD,
+ CL_TRACE_MULTICAST_NOT_FOUND,
CL_TRACE_SEQ_CHECK_TX,
CL_TRACE_SEQ_CHECK_RX,
+ CL_TRACE_DATA_SEND_DROP_MFS,
};
BEGIN_DECLS
diff --git a/cesar/cl/mcast.h b/cesar/cl/mcast.h
new file mode 100644
index 0000000000..72a76e0b62
--- /dev/null
+++ b/cesar/cl/mcast.h
@@ -0,0 +1,36 @@
+#ifndef cesar_cl_mcast_h
+#define cesar_cl_mcast_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2011 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file cesar/cl/mcast.h
+ * \brief Multicast
+ * \ingroup cl
+ */
+#include "common/defs/igmp.h"
+
+BEGIN_DECLS
+
+/**
+ * Update the igmp groups based on the mactotei table.
+ * \param cl the CL context.
+ */
+void
+cl_update_igmp_groups (cl_t *ctx);
+
+/**
+ * Get the access to the igmp data in the cl context.
+ * \param cl the CL context.
+ * \return the pointer to the igmp data.
+ */
+igmp_groups_t *
+cl_get_igmp_groups (cl_t *cl);
+
+END_DECLS
+
+#endif /* cesar_cl_mcast_h */
diff --git a/cesar/cl/src/bridge_table.c b/cesar/cl/src/bridge_table.c
index 163919bd01..84937316d5 100644
--- a/cesar/cl/src/bridge_table.c
+++ b/cesar/cl/src/bridge_table.c
@@ -182,8 +182,11 @@ bridge_table_size (cl_t *ctx)
{
/* Check parameter. */
dbg_assert (ctx);
-
+#if !CONFIG_CL_EOC_ROUTE
return mac_lookup_entry_count (ctx->bridge_table.table);
+#else
+ return cl_eoc_mactotei_snapshot_create (ctx);
+#endif
}
mac_t
@@ -191,7 +194,10 @@ bridge_table_get_entry (cl_t *ctx, uint position)
{
/* Check parameters. */
dbg_assert (ctx);
+#if !CONFIG_CL_EOC_ROUTE
dbg_assert (position < bridge_table_size (ctx));
-
return mac_lookup_get_mac (ctx->bridge_table.table, position);
+#else
+ return cl_eoc_mactotei_snapshot_get_mac (ctx, position);
+#endif
}
diff --git a/cesar/cl/src/cl.c b/cesar/cl/src/cl.c
index f3aa688592..ba8d4d958a 100644
--- a/cesar/cl/src/cl.c
+++ b/cesar/cl/src/cl.c
@@ -15,6 +15,7 @@
#include "common/std.h"
#include "lib/seq_check.h"
+#include "lib/stats.h"
#include "hal/arch/arch.h"
#include "hal/gpio/gpio.h"
@@ -27,10 +28,39 @@
#include "cl/inc/trace.h"
#include "cl/inc/send.h"
#include "cl/inc/receive.h"
+
#include "config/cl.h"
+#include "config/cl/eoc.h"
+#include "config/mac/common.h"
+#include "config.h"
+
+#include <string.h>
static struct cl_t cl_global;
+/**
+ * Initialise CL stats.
+ * \param ctx cl context
+ */
+#if CONFIG_STATS
+static void
+cl_stats_init (cl_t *ctx)
+{
+ # define CL_STAT(s) \
+ lib_stats_set_stat_value_notype ("cl_" #s, &ctx->stats.s, \
+ LIB_STATS_ACCESS_READ_ONLY, \
+ LIB_STATS_DEBUG)
+ CL_STAT (rx_data);
+ CL_STAT (rx_data_multicast);
+ CL_STAT (rx_mme);
+ CL_STAT (tx_data);
+ CL_STAT (tx_data_drop_auth);
+ CL_STAT (tx_data_drop_mfs);
+ CL_STAT (tx_data_multicast);
+ CL_STAT (tx_mme);
+}
+#endif
+
cl_t *
cl_init (mac_store_t *mac_store, sar_t *sar, mac_config_t *mac_config,
ipmbox_t *ipmbox, bufmgr_t *bufmgr)
@@ -40,6 +70,7 @@ cl_init (mac_store_t *mac_store, sar_t *sar, mac_config_t *mac_config,
/* Check parameters. */
dbg_assert (mac_config);
+ memset (&cl_global, 0, sizeof (cl_t));
ctx = &cl_global;
/* Initialize MAC store. */
@@ -76,6 +107,11 @@ cl_init (mac_store_t *mac_store, sar_t *sar, mac_config_t *mac_config,
bridge_table_init (ctx);
ctx->brg_rx = NULL;
+#if CONFIG_CL_EOC_ROUTE
+ cl_eoc_mactotei_init (ctx);
+ ctx->groups.nb = 0;
+#endif
+
/* Initialize the data link. */
ctx->data_send_link.mfs = NULL;
@@ -87,6 +123,10 @@ cl_init (mac_store_t *mac_store, sar_t *sar, mac_config_t *mac_config,
lib_seq_check_init (
&ctx->seq_check_tx_ctx, CALLBACK (cl_lib_seq_check_tx_cb), ctx);
+#if CONFIG_STATS
+ /* Register statistics. */
+ cl_stats_init (ctx);
+#endif
/* Debug LEDs. */
GPIO_SETUP (LED_CL_RX, GPIO_DIRECTION_OUT);
GPIO_SET (LED_CL_RX, 0);
@@ -131,38 +171,6 @@ cl_data_send_link_clear (cl_t *ctx)
arch_dsr_unlock ();
}
-igmp_groups_t*
-cl_get_igmp_groups (cl_t *ctx)
-{
- dbg_assert (ctx);
-
- return &ctx->groups;
-}
-
-void
-cl_update_igmp_groups (cl_t *ctx)
-{
- dbg_assert (ctx);
- uint g;
- uint m;
- for (g = 0; g < ctx->groups.nb; g++)
- {
- uint tei = MAC_TEI_UNASSOCIATED;
- ctx->groups.nb_actual_members[g] = 0;
-
- for (m = 0; m < ctx->groups.nb_total_members[g]; m++)
- {
- tei = cl_mactotei_table_find_tei_from_mac (
- ctx, ctx->groups.member_mac[g][m]);
- if (MAC_TEI_IS_STA(tei))
- ctx->groups.member_tei[g][ctx->groups.nb_actual_members[g]++] =
- tei;
- }
- if (ctx->groups.nb_actual_members[g] == 0)
- ctx->groups.member_tei[g][0] = MAC_TEI_BCAST;
- }
-}
-
#if CONFIG_CL_DATA_RATE
void
cl_compute_datarate_on_sta_ (cl_t *ctx, mfs_t *mfs, uint length)
diff --git a/cesar/cl/src/cl_eoc_mactotei.c b/cesar/cl/src/cl_eoc_mactotei.c
new file mode 100644
index 0000000000..5d940c8b2a
--- /dev/null
+++ b/cesar/cl/src/cl_eoc_mactotei.c
@@ -0,0 +1,328 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2009 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file cl/src/cl_eoc_mactotei.c
+ * \brief MAC to TEI mapping for the Convergence Layer
+ * \ingroup cl
+ *
+ */
+#include "common/std.h"
+#include "cl/inc/context.h"
+#include "cl/cl_eoc_mactotei.h"
+#include "hal/arch/arch.h"
+#include "lib/stats.h"
+
+/** Keep local time updated for entry expiration purpose.
+ * \param ctx CL context
+ */
+PRIVATE void
+cl_eoc_time_update (cl_t *ctx)
+{
+ ctx->cl_eoc_mactotei_table.time_count++;
+}
+
+static inline uint
+cl_eoc_get_time (cl_t *ctx)
+{
+ return ctx->cl_eoc_mactotei_table.time_count;
+}
+
+static inline int
+cl_eoc_is_obsolete (cl_t *ctx, cl_eoc_mactotei_entry_t *entry, uint timestamp)
+{
+ if (ctx->mac_config->sta_mac_address == entry->mac_addr)
+ return 0;
+ else
+ return lesseq_mod2p32(entry->timestamp +
+ ctx->cl_eoc_mactotei_table.max_duration, timestamp);
+}
+
+/** Initialization of EoC mactotei table.
+ * \param ctx CL context
+ */
+void
+cl_eoc_mactotei_init (cl_t *ctx)
+{
+ cl_eoc_mactotei_table_t *mtt_table = &ctx->cl_eoc_mactotei_table;
+ cl_eoc_mactotei_entry_t *entry;
+ int i;
+
+ list_init (&mtt_table->ageing_list);
+ for (i = 0; i < MACTOTEI_HASHSIZE; i++)
+ list_init (&mtt_table->hashing_list[i]);
+ for (i = 0; i < MACTOTEI_NB_ENTRIES; i++)
+ {
+ entry = &mtt_table->cl_eoc_mtt_entries[i];
+ list_init_node (&entry->l_hash);
+ list_init_node (&entry->l_age);
+ entry->timestamp = i;
+ entry->reserved = 0;
+ entry->mac_addr = 0;
+ list_push_back (&mtt_table->ageing_list,&entry->l_age);
+ }
+ mtt_table->num_of_entries = 0;
+ mtt_table->time_count = 0;
+ mtt_table->max_entries = MAC_LIMITATION;
+ cl_eoc_mactotei_set_entry_duration (ctx, DEFAULT_ENTRY_AGE_SEC);
+
+ lib_stats_set_stat_value_notype ("MAC_LIMITATION",
+ &mtt_table->max_entries,
+ LIB_STATS_ACCESS_READ_WRITE,
+ LIB_STATS_DEBUG);
+}
+
+/** Search for an entry in eoc_mactotei table with the given mac address.
+ * \param ctx CL context
+ * \param mac_addr MAC address of the entry to be found in table
+ */
+cl_eoc_mactotei_entry_t *cl_eoc_mactotei_entry_find (cl_t *ctx, mac_t mac_addr)
+{
+
+ u8 index = MACTOTEI_HASHFUNC (mac_addr);
+ cl_eoc_mactotei_entry_t *entry = NULL;
+ list_node_t *list_node = NULL;
+
+ list_node = list_begin (&ctx->cl_eoc_mactotei_table.hashing_list[index]);
+
+ while (list_node != &ctx->cl_eoc_mactotei_table.hashing_list[index].nil)
+ {
+ if (list_node)
+ entry = PARENT_OF (cl_eoc_mactotei_entry_t, l_hash, list_node);
+ if (entry && (mac_addr == entry->mac_addr))
+ return entry;
+ list_node = list_next (list_node);
+ }
+
+ return NULL;
+}
+
+/** Find TEI to which to route packets according to MAC address.
+ * \param ctx CL context
+ * \param mac_addr MAC address to be mapped to TEI
+ */
+uint
+cl_eoc_mactotei_find_tei (cl_t *ctx, mac_t mac_addr)
+{
+ cl_eoc_mactotei_entry_t *entry = NULL;
+
+ entry = cl_eoc_mactotei_entry_find (ctx, mac_addr);
+ if (entry && !cl_eoc_is_obsolete (ctx, entry, cl_eoc_get_time (ctx)))
+ {
+ entry->timestamp = cl_eoc_get_time (ctx);
+ return entry->tei;
+ }
+
+ return MAC_TEI_UNASSOCIATED;
+}
+
+/** Put new MAC address in mactotei table.
+ * \param ctx CL context
+ * \param mac_addr MAC address of the packet
+ * \param tei TEI of the packet
+*/
+bool
+cl_eoc_mactotei_entry_insert (cl_t *ctx, mac_t mac_addr, uint tei)
+{
+ cl_eoc_mactotei_entry_t *entry = NULL;
+ cl_eoc_mactotei_entry_t *entry1 = NULL;
+ uint i;
+ list_node_t *list_node = NULL;
+
+ entry = cl_eoc_mactotei_entry_find (ctx, mac_addr);
+
+ if (!entry || cl_eoc_is_obsolete (ctx, entry, cl_eoc_get_time (ctx)))
+ {
+ /* Check if limit of MAC addresses is reached */
+ if (ctx->mac_config->tei == tei)
+ {
+ if (ctx->cl_eoc_mactotei_table.num_of_entries ==
+ ctx->cl_eoc_mactotei_table.max_entries)
+ {
+ ctx->cl_eoc_mactotei_table.num_of_entries = 0;
+ /* Count number of valid entries */
+ for (i = 0; i < MACTOTEI_HASHSIZE; i++)
+ {
+ list_node = list_begin (&ctx->cl_eoc_mactotei_table.hashing_list[i]);
+ while (list_node != &ctx->cl_eoc_mactotei_table.hashing_list[i].nil)
+ {
+ if (list_node)
+ entry1 = PARENT_OF (cl_eoc_mactotei_entry_t, l_hash,
+ list_node);
+ if ((entry1->tei == tei) &&
+ !cl_eoc_is_obsolete (ctx, entry1, cl_eoc_get_time (ctx)))
+ {
+ ctx->cl_eoc_mactotei_table.num_of_entries++;
+ }
+ if (ctx->cl_eoc_mactotei_table.num_of_entries ==
+ ctx->cl_eoc_mactotei_table.max_entries)
+ return false;
+ list_node = list_next (list_node);
+ }
+ }
+ }
+ ctx->cl_eoc_mactotei_table.num_of_entries++;
+ }
+ }
+
+ u8 index = MACTOTEI_HASHFUNC (mac_addr);
+ if (!entry)
+ {
+ list_node = list_next (&ctx->cl_eoc_mactotei_table.ageing_list.nil);
+ list_remove (&ctx->cl_eoc_mactotei_table.ageing_list, list_node);
+ entry = PARENT_OF (cl_eoc_mactotei_entry_t, l_age, list_node);
+ if (entry->mac_addr)
+ {
+ u8 index1 = MACTOTEI_HASHFUNC (entry->mac_addr);
+ list_remove (&ctx->cl_eoc_mactotei_table.hashing_list[index1],
+ &entry->l_hash);
+ }
+ }
+ else
+ {
+ list_remove (&ctx->cl_eoc_mactotei_table.hashing_list[index],
+ &entry->l_hash);
+ list_remove (&ctx->cl_eoc_mactotei_table.ageing_list, &entry->l_age);
+ }
+ entry->tei = tei;
+ entry->mac_addr = mac_addr;
+ entry->reserved = 0;
+ entry->timestamp = cl_eoc_get_time (ctx);
+ list_push_back (&ctx->cl_eoc_mactotei_table.ageing_list, &entry->l_age);
+ list_push_back (&ctx->cl_eoc_mactotei_table.hashing_list[index],
+ &entry->l_hash);
+ return true;
+}
+
+/** Remove all entries associated with given TEI from ageing and hashing lists
+ * of cl_eoc_mactotei_table
+ * \param ctx CL context
+ * \param tei TEI of the STA whose entries should be removed from the table
+*/
+void
+cl_eoc_mactotei_entry_remove (cl_t *ctx, uint tei)
+{
+ cl_eoc_mactotei_entry_t *entry = NULL;
+ list_node_t *list_node = NULL;
+
+ arch_dsr_lock ();
+ list_node = list_begin (&ctx->cl_eoc_mactotei_table.ageing_list);
+ while (list_node != &ctx->cl_eoc_mactotei_table.ageing_list.nil)
+ {
+ if (list_node)
+ entry = PARENT_OF (cl_eoc_mactotei_entry_t, l_age, list_node);
+ if (entry && (tei == entry->tei))
+ {
+ u8 index = MACTOTEI_HASHFUNC (entry->mac_addr);
+ list_remove (&ctx->cl_eoc_mactotei_table.hashing_list[index],
+ &entry->l_hash);
+ entry->tei = MAC_TEI_UNASSOCIATED;
+ entry->mac_addr = 0;
+ }
+ list_node = list_next (list_node);
+ }
+ arch_dsr_unlock ();
+}
+
+/** Set time during which entry will be valid
+ * \param ctx CL context
+ * \param max_dur_sec maximum duration of entry in seconds
+ */
+void
+cl_eoc_mactotei_set_entry_duration (cl_t * ctx, uint max_dur_sec)
+{
+ if ((max_dur_sec > MIN_ENTRY_AGE_SEC) && (max_dur_sec < MAX_ENTRY_AGE_SEC))
+ ctx->cl_eoc_mactotei_table.max_duration = max_dur_sec;
+}
+
+/**
+ * Remove obsolete/expired entries from the MAC to TEI
+ * \param ctx CL context
+ */
+PRIVATE void
+cl_eoc_mactotei_remove_obsolete (cl_t *ctx)
+{
+ list_node_t *list_node;
+
+ arch_dsr_lock ();
+ list_node = list_rbegin (&ctx->cl_eoc_mactotei_table.ageing_list);
+ while (list_node != &ctx->cl_eoc_mactotei_table.ageing_list.nil)
+ {
+ cl_eoc_mactotei_entry_t *entry
+ = PARENT_OF (cl_eoc_mactotei_entry_t, l_age, list_node);
+
+ if (!entry->mac_addr)
+ break;
+
+ if (cl_eoc_is_obsolete (ctx, entry, cl_eoc_get_time (ctx)))
+ {
+ /* Entry should be removed. */
+ u8 index = MACTOTEI_HASHFUNC (entry->mac_addr);
+ list_remove (&ctx->cl_eoc_mactotei_table.hashing_list[index],
+ &entry->l_hash);
+ entry->tei = MAC_TEI_UNASSOCIATED;
+ entry->mac_addr = 0;
+ }
+ list_node = list_prev (list_node);
+ }
+ arch_dsr_unlock ();
+}
+
+uint
+cl_eoc_mactotei_snapshot_create (cl_t *ctx)
+{
+ uint valid_entries_nb = 0;
+ list_node_t *list_node;
+ cl_eoc_mactotei_snapshot_entry_t *snapshot
+ = ctx->cl_eoc_mactotei_table.mactotei_snapshot;
+
+ arch_dsr_lock ();
+ list_node = list_rbegin (&ctx->cl_eoc_mactotei_table.ageing_list);
+ while (list_node != &ctx->cl_eoc_mactotei_table.ageing_list.nil)
+ {
+ cl_eoc_mactotei_entry_t *entry
+ = PARENT_OF (cl_eoc_mactotei_entry_t, l_age, list_node);
+
+ if (!entry->mac_addr)
+ break;
+
+ if (!cl_eoc_is_obsolete (ctx, entry, cl_eoc_get_time (ctx)))
+ {
+ snapshot[valid_entries_nb].mac = entry->mac_addr;
+ snapshot[valid_entries_nb].tei = entry->tei;
+ valid_entries_nb++;
+ }
+ list_node = list_prev (list_node);
+ }
+ arch_dsr_unlock ();
+
+ return valid_entries_nb;
+}
+
+mac_t
+cl_eoc_mactotei_snapshot_get_mac (cl_t *ctx, uint index)
+{
+ return ctx->cl_eoc_mactotei_table.mactotei_snapshot[index].mac;
+}
+
+void
+cl_eoc_mactotei_snapshot_get_mac_tei (cl_t *ctx, uint index, mac_t *mac,
+ uint *tei)
+{
+ cl_eoc_mactotei_snapshot_entry_t *snapshot_entry
+ = &ctx->cl_eoc_mactotei_table.mactotei_snapshot[index];
+ *mac = snapshot_entry->mac;
+ *tei = snapshot_entry->tei;
+}
+
+void
+cl_eoc_mactotei_periodic_action (cl_t *ctx)
+{
+ dbg_assert (ctx);
+ cl_eoc_time_update (ctx);
+ cl_eoc_mactotei_remove_obsolete (ctx);
+}
diff --git a/cesar/cl/src/cl_mactotei.c b/cesar/cl/src/cl_mactotei.c
index c30c05bd29..7fab9a3b72 100644
--- a/cesar/cl/src/cl_mactotei.c
+++ b/cesar/cl/src/cl_mactotei.c
@@ -17,6 +17,8 @@
#include "cl/cl_mactotei.h"
#include "cl/inc/context.h"
+#include "config/cl/eoc.h"
+
/**
* Set a TEI and a tag in an extra information field.
* \param tei TEI to set.
diff --git a/cesar/cl/src/mcast.c b/cesar/cl/src/mcast.c
new file mode 100644
index 0000000000..923d18044f
--- /dev/null
+++ b/cesar/cl/src/mcast.c
@@ -0,0 +1,60 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2011 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file cesar/cl/src/mcast.c
+ * \brief Multicast.
+ * \ingroup cl
+ */
+#include "common/std.h"
+#include "cl/cl.h"
+#include "cl/mcast.h"
+#include "config/cl/eoc/route.h"
+#include "cl/inc/context.h"
+
+igmp_groups_t*
+cl_get_igmp_groups (cl_t *ctx)
+{
+ dbg_assert (ctx);
+ return &ctx->groups;
+}
+
+void
+cl_update_igmp_groups (cl_t *ctx)
+{
+ dbg_assert (ctx);
+ uint g;
+ uint m;
+ for (g = 0; g < ctx->groups.nb; g++)
+ {
+ uint tei = MAC_TEI_UNASSOCIATED;
+ ctx->groups.nb_actual_members[g] = 0;
+
+ for (m = 0; m < ctx->groups.nb_total_members[g]; m++)
+# if CONFIG_CL_EOC_ROUTE
+ {
+ tei = cl_eoc_mactotei_find_tei (
+ ctx, ctx->groups.member_mac[g][m]);
+ if (MAC_TEI_IS_EOC_STA (tei))
+ ctx->groups.member_tei[g][ctx->groups.nb_actual_members[g]++] =
+ tei;
+ }
+ if (ctx->groups.nb_actual_members[g] == 0)
+ ctx->groups.member_tei[g][0] = MAC_TEI_UNASSOCIATED;
+#else
+ {
+ tei = cl_mactotei_table_find_tei_from_mac (
+ ctx, ctx->groups.member_mac[g][m]);
+ if (MAC_TEI_IS_STA(tei))
+ ctx->groups.member_tei[g][ctx->groups.nb_actual_members[g]++] =
+ tei;
+ }
+ if (ctx->groups.nb_actual_members[g] == 0)
+ ctx->groups.member_tei[g][0] = MAC_TEI_BCAST;
+#endif
+ }
+}
diff --git a/cesar/cl/src/receive.c b/cesar/cl/src/receive.c
index c06f175f59..3b38f10456 100644
--- a/cesar/cl/src/receive.c
+++ b/cesar/cl/src/receive.c
@@ -45,6 +45,9 @@ cl_sar_data_recv (cl_t *ctx, u8 *buffer, uint length, mfs_rx_t *mfs)
/* Check sequence number of throughput. */
lib_seq_check_packet (&ctx->seq_check_rx_ctx, buffer, length);
+ /* Increase bytes count. */
+ ctx->stats.rx_data_bytes += length;
+
mac_t smac, dmac;
bitstream_direct_read_macs (buffer, &dmac, &smac);
CL_TRACE (DATA_RECV, phy_date (), buffer, TRACE_U64 (dmac),
@@ -56,7 +59,19 @@ cl_sar_data_recv (cl_t *ctx, u8 *buffer, uint length, mfs_rx_t *mfs)
msg.buffer_addr = (u32) buffer;
ipmbox_tx_data (ctx->ipmbox, (u32 *) &msg, IPMBOX_MSG_DATA_WORDS);
+#if !CONFIG_CL_EOC_ROUTE
cl_brg_rx_add (ctx, smac, mfs->common.tei);
+#else
+ bool ok = true;
+ if (MAC_TEI_IS_EOC_CCO(ctx->mac_config->tei))
+ ok = cl_eoc_mactotei_entry_insert (ctx, smac, mfs->common.tei);
+ dbg_assert (ok);
+#endif
+
+ if (mac_is_multicast (dmac) && dmac != MAC_BROADCAST)
+ ctx->stats.rx_data_multicast++;
+ else
+ ctx->stats.rx_data++;
/* update data rate informations associated to the RX
* from the associated sta to the local sta */
@@ -72,6 +87,7 @@ cl_sar_mme_recv (cl_t *ctx, u8 *buffer, uint length, mfs_rx_t *mfs,
dbg_claim (ctx);
dbg_claim (mfs);
dbg_claim (buffer);
+ ctx->stats.rx_mme++;
(*ctx->mbx->cb) (ctx->mbx->user_data, mfs->common.tei,
buffer, length, encryption);
CL_TRACE (MME_RECV, phy_date (), length, buffer, true);
diff --git a/cesar/cl/src/send_data.c b/cesar/cl/src/send_data.c
index b2d3bcbd5c..dd6fd72b1f 100644
--- a/cesar/cl/src/send_data.c
+++ b/cesar/cl/src/send_data.c
@@ -67,7 +67,14 @@ cl_classifer_get_lid (cl_t *ctx, uint tei, uint tag,
*bcast = false;
*acs = false;
*drop = false;
+#if CONFIG_CL_EOC_CLASSIFY
+ if (MAC_TEI_IS_STA (tei))
+ lid = lid_table[tag] + MAC_LLID_MIN;
+ else
+ lid = 0;
+#else /* !CONFIG_CL_EOC_CLASSIFY */
lid = lid_table[tag];
+#endif /* !CONFIG_CL_EOC_CLASSIFY */
CL_TRACE (CLASSIFIER, phy_date (), tei, *bcast, *acs, *drop, lid);
/** TODO fill the classifier */
return lid;
@@ -81,21 +88,26 @@ cl_classifer_get_lid (cl_t *ctx, uint tei, uint tag,
* \param tag the tag for the classifier
* \param arrival_time_ntb the arrival time in NTB
* \param mcast the packet is multicast
+ * \param dmac the destination mac address
+ * \param smac the source mac address
*
* The callee is responsible to give back the buffer to the buffer manager.
+ * dmac and smac are used only in non mcast mode.
*/
static inline void
cl_data_send_sublayer (cl_t *ctx, u8 *buffer, uint length, uint tag,
- u32 arrival_time_ntb, u8 tei, bool mcast)
+ u32 arrival_time_ntb, u8 tei, bool mcast,
+ mac_t dmac, mac_t smac)
{
uint lid;
- bool bcast, acs, drop, added;
+ bool bcast, acs, drop;
mfs_tx_t *mfs;
/* Get some data from the classifier. */
lid = cl_classifer_get_lid (ctx, tei, tag, &bcast, &acs, &drop);
if (MAC_LID_IS_PLID (lid))
{
+ bool added;
/* Create the MFS if it does not exits. */
mfs = mac_store_mfs_add_tx (ctx->mac_store, bcast, false, lid,
tei, &added);
@@ -105,9 +117,14 @@ cl_data_send_sublayer (cl_t *ctx, u8 *buffer, uint length, uint tag,
else
{
/* try to get the mfs from the store. */
+#if !CONFIG_MAC_COMMON_EOC_MFS
mfs = mac_store_mfs_get_tx (ctx->mac_store, bcast, false, lid, tei);
+#else
+ mfs = mac_store_mfs_get_sta_tx_data_locked (ctx->mac_store, lid, tei);
+ if (mfs)
+ blk_addref (mfs);
+#endif
}
-
if (!drop && !acs && mfs)
{
sar_msdu_process (ctx->sar, buffer, length, mfs,
@@ -120,13 +137,12 @@ cl_data_send_sublayer (cl_t *ctx, u8 *buffer, uint length, uint tag,
mfs->common.bcast);
if (!mcast)
{
- mac_t dmac, smac;
- bitstream_direct_read_macs (buffer, &dmac, &smac);
ctx->data_send_link.mfs = mfs;
ctx->data_send_link.last_update_date_ntb = arrival_time_ntb;
ctx->data_send_link.dmac = dmac;
ctx->data_send_link.smac = smac;
ctx->data_send_link.tag = tag;
+ ctx->stats.tx_data++;
}
else
blk_release (mfs);
@@ -135,17 +151,14 @@ cl_data_send_sublayer (cl_t *ctx, u8 *buffer, uint length, uint tag,
{
if (mfs)
blk_release (mfs);
- if (mcast)
- CL_TRACE (DATA_SEND_MULTI_FAILED,
- phy_date (), ctx->mac_config->authenticated,
- buffer, length);
- else
- CL_TRACE (DATA_SEND_DROP,
- phy_date (), ctx->mac_config->authenticated,
- buffer, length);
+ ctx->stats.tx_data_drop_mfs++;
+ CL_TRACE (DATA_SEND_DROP,
+ phy_date (), ctx->mac_config->authenticated,
+ buffer, length, TRACE_U64 (dmac), TRACE_U64 (smac));
}
}
+#if CONFIG_CL_AV
/**
* Send multicast packet to a group.
* \param ctx the cl context
@@ -165,12 +178,13 @@ cl_av_data_send_multicast (cl_t *ctx, u8 *buffer, uint length, uint tag,
uint tei = ctx->groups.member_tei[group_id][i];
dbg_assert (MAC_TEI_IS_STA (tei));
cl_data_send_sublayer (ctx, buffer, length, tag, arrival_time_ntb,
- tei, true /* mcast */);
+ tei, true /* mcast */, 0, 0);
}
/* The buffer is no more used, be aware the SAR is polling the bridge
* DMA, that why it can release the buffer here. */
bufmgr_give_back (ctx->bufmgr, buffer);
}
+#endif /* !CONFIG_CL_AV */
/**
* Prepare the CL to send a Frame.
@@ -196,25 +210,47 @@ cl_data_send_prepare (cl_t *ctx, u8 *buffer, uint length, uint tag,
/* Add the source MAC address to the local bridge table if not our MAC
* address. */
dbg_claim (ctx->mac_config);
- if (ctx->mac_config->sta_mac_address != smac)
+ if (ctx->mac_config->sta_mac_address != smac && !CONFIG_CL_EOC_ROUTE)
bridge_table_add (ctx, smac);
/* Data are forbidden if not authenticated. */
if (!ctx->mac_config->authenticated)
{
CL_TRACE (DATA_SEND_DROP, phy_date (), ctx->mac_config->authenticated,
- buffer, length);
+ buffer, length, TRACE_U64 (dmac), TRACE_U64 (smac));
+ ctx->stats.tx_data_drop_auth++;
bufmgr_give_back (ctx->bufmgr, buffer);
return;
}
/* Get the TEI from the mactotei table. */
uint tei;
- uint group;
+#if CONFIG_CL_EOC_ROUTE
+ /* For STA, if tei is unassociated, or MAC limit is reached
+ * drop the packet */
+ if (MAC_TEI_IS_EOC_STA(ctx->mac_config->tei))
+ {
+ bool drop = false;
+ tei = MAC_TEI_CCO_DEF;
+ if (smac != ctx->mac_config->sta_mac_address)
+ drop = !cl_eoc_mactotei_entry_insert (ctx, smac,
+ ctx->mac_config->tei);
+ if (drop)
+ {
+ bufmgr_give_back (ctx->bufmgr, buffer);
+ return;
+ }
+ }
+ else
+ tei = cl_eoc_mactotei_find_tei (ctx, dmac);
+#else
+ uint group = 0;
tei = cl_mactotei_table_find_tei_and_tag_from_mac (ctx, dmac, &group);
+#endif
dbg_assert (tei != ctx->mac_config->tei);
- if (tei == MAC_TEI_BCAST)
+#if CONFIG_CL_AV
+ if (tei == MAC_TEI_BCAST && ctx->groups.nb)
{
if (ctx->groups.nb_actual_members[group] > 1)
{
@@ -225,17 +261,69 @@ cl_data_send_prepare (cl_t *ctx, u8 *buffer, uint length, uint tag,
else
tei = ctx->groups.member_tei[group][0];
}
+#endif /* !CONFIG_CL_AV */
+
/* If the TEI is not found the packet is send as broadcast. */
- if (tei == MAC_TEI_UNASSOCIATED)
- tei = MAC_TEI_BCAST;
cl_data_send_sublayer (ctx, buffer, length, tag, arrival_time_ntb,
- tei, false /* unicast */);
+ tei == MAC_TEI_UNASSOCIATED ? MAC_TEI_BCAST: tei,
+ false /* unicast */, dmac, smac);
/* SAR ends using the buffer it can be given back.
* BRGDMA is polled by the SAR thats why it the buffer can be given
* back to the buffer manager. */
bufmgr_give_back (ctx->bufmgr, buffer);
}
+/**
+ * Send multicast packet to a group if it exists.
+ * \param ctx the cl context
+ * \param buffer the buffer containing the data to send
+ * \param length the length of the data to send
+ * \param tag the tag to use
+ * \param arrival_time_ntb the arrival time
+ * \param dmac the destination mac address
+ * \param smac the source mac address
+ */
+void
+cl_eoc_data_send_multicast (cl_t *ctx, u8 *buffer, uint length, uint tag,
+ u32 arrival_time_ntb, mac_t dmac, mac_t smac)
+{
+ if (MAC_IS_GROUP (dmac) && dmac != MCAST_MAC_IGMP_GENERAL_QUERY)
+ {
+ uint i, group_idx = ctx->groups.nb, tei;
+ /* Get the group from the IGMP local table. */
+ for (i = 0; i < ctx->groups.nb; i++)
+ {
+ if (ctx->groups.group_mac[i] == dmac
+ && ctx->groups.nb_actual_members[i])
+ {
+ group_idx = i;
+ break;
+ }
+ }
+ if (group_idx < ctx->groups.nb)
+ {
+ for (i = 0; i < ctx->groups.nb_actual_members[group_idx]; i++)
+ {
+ tei = ctx->groups.member_tei[group_idx][i];
+ cl_data_send_sublayer (ctx, buffer, length, tag,
+ arrival_time_ntb,
+ tei, true /* multicast */, 0, 0);
+ }
+ }
+ /* If the group is found the function has already returned so at this
+ * point the packet must be dropped. */
+ CL_TRACE (MULTICAST_NOT_FOUND, TRACE_U64 (dmac));
+ bufmgr_give_back (ctx->bufmgr, buffer);
+ }
+ /* Not a group but the mac address is maybe a multicast packet outside the
+ * multicast video range (i.e Spanning tree, etc...). */
+ else
+ {
+ cl_data_send_prepare (
+ ctx, buffer, length, tag, arrival_time_ntb, dmac, smac);
+ }
+}
+
void ARCH_ILRAM_PRIO (3)
cl_data_send (cl_t *ctx, u8 *buffer, uint length, uint tag,
u32 arrival_time_ntb)
@@ -245,6 +333,8 @@ cl_data_send (cl_t *ctx, u8 *buffer, uint length, uint tag,
dbg_claim (buffer);
dbg_claim (length >= ETH_PACKET_MIN_SIZE_ALLOWED
&& length <= ETH_PACKET_MAX_SIZE);
+ /* Increase bytes count. */
+ ctx->stats.tx_data_bytes += length;
/* Check sequence number of throughput. */
lib_seq_check_packet (&ctx->seq_check_tx_ctx, buffer, length);
/* Get macs. */
@@ -263,8 +353,9 @@ cl_data_send (cl_t *ctx, u8 *buffer, uint length, uint tag,
ctx->data_send_link.mfs->common.tei,
ctx->data_send_link.mfs->common.lid,
ctx->data_send_link.mfs->common.bcast);
- sar_msdu_process (ctx->sar, buffer, length, ctx->data_send_link.mfs,
- arrival_time_ntb);
+ ctx->stats.tx_data++;
+ sar_msdu_process (ctx->sar, buffer, length,
+ ctx->data_send_link.mfs, arrival_time_ntb);
/* update data rate informations associated to the TX
* from the local sta to the associated sta */
cl_compute_datarate_on_sta (
@@ -282,7 +373,18 @@ cl_data_send (cl_t *ctx, u8 *buffer, uint length, uint tag,
blk_release (ctx->data_send_link.mfs);
ctx->data_send_link.mfs = NULL;
}
- cl_data_send_prepare (ctx, buffer, length, tag, arrival_time_ntb,
- dmac, smac);
+ if (mac_is_multicast (dmac))
+ {
+#if CONFIG_CL_MCAST
+ cl_eoc_data_send_multicast (
+ ctx, buffer, length, tag, arrival_time_ntb, dmac, smac);
+#endif
+ ctx->stats.tx_data_multicast++;
+ }
+#if CONFIG_CL_MCAST
+ else
+#endif
+ cl_data_send_prepare (
+ ctx, buffer, length, tag, arrival_time_ntb, dmac, smac);
}
}
diff --git a/cesar/cl/src/trace.c b/cesar/cl/src/trace.c
index d9386fa9f1..ef9ef32d49 100644
--- a/cesar/cl/src/trace.c
+++ b/cesar/cl/src/trace.c
@@ -46,16 +46,20 @@ cl_trace_init (cl_t *ctx)
TRACE_EVENT (CL_TRACE_MACTOTEI_FIND_TEI, "CL_MACTOTEI_FIND_TEI mac @ : %m, found %d, tei use : %x", TIMESTAMP),
TRACE_EVENT (CL_TRACE_CLASSIFIER, "CL_CLASSIFIER tei : %x, bcast %d, acs : %d, drop : %d, lid : %x", TIMESTAMP),
TRACE_EVENT (CL_TRACE_DATA_SEND, "CL_DATA_SEND buffer @ : %x, length : %d, tei : %x, lid : %x, bcast : %d", TIMESTAMP),
- TRACE_EVENT (CL_TRACE_DATA_SEND_DROP, "CL_DATA_SEND_DROP authenticated : %d, buffer @ : %x, length : %d", TIMESTAMP),
+ TRACE_EVENT (CL_TRACE_DATA_SEND_DROP, "CL_DATA_SEND_DROP"
+ "authenticated : %d, buffer @ : %x, length : %d,"
+ "dmac %m, smac : %m", TIMESTAMP),
TRACE_EVENT (CL_TRACE_DATA_SEND_DONE, "CL_DATA_SEND_DONE buffer @ : %x", TIMESTAMP),
- TRACE_EVENT (CL_TRACE_DATA_SEND_MULTI_FAILED, "Multiunicast data send failed drop : %d, acs : %d, mfs : %x, dtei : %x, group : %d", TIMESTAMP),
TRACE_EVENT (CL_TRACE_DATA_RECV, "CL_DATA_RECV buffer @ : %x, destination : %m, source : %m, length : %d", TIMESTAMP),
TRACE_EVENT (CL_TRACE_DATA_BUFFER_ADD, "CL_DATA_BUFFER_ADD buffer @ : %x", TIMESTAMP),
TRACE_EVENT (CL_TRACE_BRIDGE_ADD, "Bridging MAC %m"),
+ TRACE_EVENT (CL_TRACE_MULTICAST_NOT_FOUND, "Multicast group not found %m"),
TRACE_EVENT (CL_TRACE_SEQ_CHECK_RX, "[SeqCheck] input from PLC: "
"[%d][%d] expected=%x, actual=%x"),
TRACE_EVENT (CL_TRACE_SEQ_CHECK_TX, "[SeqCheck] input from Eth: "
"[%d][%d] expected=%x, actual=%x"),
+ TRACE_EVENT (CL_TRACE_DATA_SEND_DROP_MFS, "CL_DATA_SEND_DROP_MFS "
+ "tei : %d, lid : %d, buffer @ : %x, length : %d", TIMESTAMP),
};
dbg_assert (ctx);
trace_namespace_init (&namespace, event_ids, COUNT (event_ids));
diff --git a/cesar/cl/stub/Module b/cesar/cl/stub/Module
index 2ad195744b..20fad46b15 100644
--- a/cesar/cl/stub/Module
+++ b/cesar/cl/stub/Module
@@ -1 +1,4 @@
-SOURCES:=cl.c cl_mactotei.c bridge_table.c brg_rx.c
+SOURCES:=cl.c cl_mactotei.c bridge_table.c brg_rx.c mcast.c
+ifeq ($(CONFIG_CL_EOC_ROUTE),y)
+SOURCES += cl_eoc_mactotei.c
+endif
diff --git a/cesar/cl/stub/src/cl_eoc_mactotei.c b/cesar/cl/stub/src/cl_eoc_mactotei.c
new file mode 100644
index 0000000000..fadac7182f
--- /dev/null
+++ b/cesar/cl/stub/src/cl_eoc_mactotei.c
@@ -0,0 +1,62 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2009 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file cl/src/cl_eoc_mactotei.c
+ * \brief MAC to TEI mapping for the Convergence Layer
+ * \ingroup cl
+ *
+ */
+#include "common/std.h"
+#include "cl/inc/context.h"
+#include "cl/cl_eoc_mactotei.h"
+#include "hal/arch/arch.h"
+#include "lib/stats.h"
+
+bool
+cl_eoc_mactotei_entry_insert (cl_t *ctx, mac_t mac_addr, uint tei)
+ __attribute__((weak));
+
+bool
+cl_eoc_mactotei_entry_insert (cl_t *ctx, mac_t mac_addr, uint tei)
+{
+ return true;
+}
+
+uint
+cl_eoc_mactotei_find_tei (cl_t *ctx, mac_t mac_addr) __attribute__((weak));
+
+uint
+cl_eoc_mactotei_find_tei (cl_t *ctx, mac_t mac_addr)
+{ return MAC_TEI_UNASSOCIATED; }
+
+void
+cl_eoc_mactotei_entry_remove (cl_t *ctx, uint tei) __attribute__((weak));
+
+void
+cl_eoc_mactotei_entry_remove (cl_t *ctx, uint tei)
+{
+ dbg_assert (MAC_TEI_IS_STA (tei));
+}
+
+void
+cl_eoc_mactotei_periodic_action (cl_t *ctx)
+{
+ dbg_assert (ctx);
+}
+
+uint
+cl_eoc_mactotei_snapshot_create (cl_t *ctx)
+{
+ return 0;
+}
+
+void
+cl_eoc_mactotei_snapshot_get_mac_tei (cl_t *ctx, uint index, mac_t *mac,
+ uint *tei)
+{
+}
diff --git a/cesar/cl/stub/src/mcast.c b/cesar/cl/stub/src/mcast.c
new file mode 100644
index 0000000000..a3a4e99b05
--- /dev/null
+++ b/cesar/cl/stub/src/mcast.c
@@ -0,0 +1,26 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2011 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file cl/stub/src/mcast.c
+ * \brief Stub the mcast functions
+ * \ingroup cl
+ *
+ */
+#include "common/std.h"
+#include "cl/cl.h"
+#include "cl/mcast.h"
+
+igmp_groups_t*
+cl_get_igmp_groups (cl_t *ctx) __attribute__((weak));
+
+igmp_groups_t*
+cl_get_igmp_groups (cl_t *ctx)
+{
+ dbg_assert (ctx);
+ return NULL;
+};
diff --git a/cesar/cl/test/bridge_table/Makefile b/cesar/cl/test/bridge_table/Makefile
index 2a2de34cc1..53e865768c 100644
--- a/cesar/cl/test/bridge_table/Makefile
+++ b/cesar/cl/test/bridge_table/Makefile
@@ -4,6 +4,7 @@ HOST_PROGRAMS = test_bridge_table
test_bridge_table_SOURCES = test_bridge_table.c
test_bridge_table_MODULES = lib cl hal/ipmbox/stub
+test_bridge_table_CONFIG_MODULES = mac/common
# Overrides source of the cl module.
cl_MODULE_SOURCES = bridge_table.c
diff --git a/cesar/cl/test/data_rate/Makefile b/cesar/cl/test/data_rate/Makefile
index 3156b1d874..8cbb78f51e 100644
--- a/cesar/cl/test/data_rate/Makefile
+++ b/cesar/cl/test/data_rate/Makefile
@@ -7,6 +7,7 @@ INCLUDES = cl/test/data_rate/override
HOST_PROGRAMS = data_rate
data_rate_SOURCES = data_rate_test.c
data_rate_MODULES = lib cl hal/ipmbox/stub
+data_rate_CONFIG_MODULES = mac/common
# Overrides source of the cl module.
cl_MODULE_SOURCES = data_rate.c
diff --git a/cesar/cl/test/functional/host-Config b/cesar/cl/test/functional/host-Config
new file mode 100644
index 0000000000..fdbfb45e5a
--- /dev/null
+++ b/cesar/cl/test/functional/host-Config
@@ -0,0 +1,2 @@
+CONFIG_STATS = n
+CONFIG_BLK_NB = 2048
diff --git a/cesar/cl/test/functional/src/cl.c b/cesar/cl/test/functional/src/cl.c
index 636b6bb1a7..2945b6f5a2 100644
--- a/cesar/cl/test/functional/src/cl.c
+++ b/cesar/cl/test/functional/src/cl.c
@@ -64,6 +64,10 @@ cl_test_init (cl_test_t *test)
mac_ntb_init (&test->mac_config);
test->cl = cl_init (test->mac_store, (sar_t*) test, &test->mac_config,
(ipmbox_t*) test, INVALID_PTR);
+ /* Force blk initialization. */
+ pb_t *pb = blk_alloc ();
+ dbg_assert (pb);
+ blk_release (pb);
}
void
diff --git a/cesar/cl/test/utest/src/cl.c b/cesar/cl/test/utest/src/cl.c
index 031f8ea520..eafa5cd2fe 100644
--- a/cesar/cl/test/utest/src/cl.c
+++ b/cesar/cl/test/utest/src/cl.c
@@ -15,6 +15,7 @@
#include "lib/test.h"
#include "lib/blk.h"
#include "lib/trace.h"
+#include "lib/stats.h"
void
cl_test_suite_send (test_t test);
@@ -34,11 +35,13 @@ main (int argc, char **argv)
test_t test;
test_init (test, argc, argv);
trace_init ();
+ lib_stats_init();
cl_test_suite_send (test);
cl_test_suite_receive (test);
cl_test_suite_misc (test);
cl_test_brg_rx (test);
trace_uninit ();
+ lib_stats_uninit();
test_begin (test, "Memory")
{
test_fail_if (blk_check_memory() == false, "Memory not freed");
diff --git a/cesar/cl/test/utest/src/misc.c b/cesar/cl/test/utest/src/misc.c
index 0032ecaa73..ed86e7a0ad 100644
--- a/cesar/cl/test/utest/src/misc.c
+++ b/cesar/cl/test/utest/src/misc.c
@@ -14,8 +14,9 @@
#include "lib/test.h"
#include "cl/test/utest/test.h"
#include "cl/cl_mactotei.h"
-#include <stdio.h>
+#include "cl/mcast.h"
#include "cl/inc/context.h"
+#include <stdio.h>
uint
cl_classifer_get_lid (cl_t *ctx, uint tei, uint tag,
diff --git a/cesar/cl/test/utest_eoc/Config b/cesar/cl/test/utest_eoc/Config
new file mode 100644
index 0000000000..63734d7175
--- /dev/null
+++ b/cesar/cl/test/utest_eoc/Config
@@ -0,0 +1,9 @@
+CONFIG_TRACE = y
+CONFIG_MAC_COMMON_EOC_TEI = y
+CONFIG_CL_EOC_ROUTE = y
+CONFIG_MAC_COMMON_EOC_MFS = y
+CONFIG_MAC_COMMON_EOC_SCHED = y
+CONFIG_CL_EOC_CLASSIFY = y
+CONFIG_MAC_PBPROC_EOC_FC = y
+CONFIG_CL_MCAST = y
+
diff --git a/cesar/cl/test/utest_eoc/Makefile b/cesar/cl/test/utest_eoc/Makefile
new file mode 100644
index 0000000000..56ba1c605b
--- /dev/null
+++ b/cesar/cl/test/utest_eoc/Makefile
@@ -0,0 +1,17 @@
+BASE = ../../..
+
+DEFS = -DNO_PRIVATE
+HOST_PROGRAMS = test_cl test_cl_mactotei
+
+test_cl_SOURCES = cl.c test.c mcast.c hle_tools.c send.c receive.c
+test_cl_MODULES = lib cl mac/common \
+ mac/sar/stub bufmgr/stub hal/ipmbox/stub hle/tools
+test_cl_CONFIG_MODULES = mac/sar
+
+test_cl_mactotei_SOURCES = test_mactotei.c hle_tools.c
+test_cl_mactotei_MODULES = lib cl mac/common \
+ mac/sar/stub bufmgr/stub hal/ipmbox/stub
+
+hle_tools_MODULE_SOURCES =
+
+include $(BASE)/common/make/top.mk
diff --git a/cesar/cl/test/utest_eoc/src/cl.c b/cesar/cl/test/utest_eoc/src/cl.c
new file mode 100644
index 0000000000..ff315780d8
--- /dev/null
+++ b/cesar/cl/test/utest_eoc/src/cl.c
@@ -0,0 +1,50 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2011 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file cl/test/utest_eoc/src/cl.c
+ * \brief « brief description »
+ * \ingroup « module »
+ *
+ * « long description »
+ */
+#include "common/std.h"
+#include "lib/test.h"
+#include "lib/blk.h"
+#include "lib/trace.h"
+#include "lib/stats.h"
+
+void
+cl_test_suite_mcast (test_t test);
+
+void
+cl_test_suite_send (test_t test);
+
+void
+cl_test_suite_receive (test_t test);
+
+int
+main (int argc, char **argv)
+{
+ test_t test;
+ test_init (test, argc, argv);
+ trace_init ();
+ lib_stats_init ();
+ cl_test_suite_send (test);
+ cl_test_suite_mcast (test);
+ cl_test_suite_receive (test);
+ lib_stats_uninit ();
+ trace_uninit ();
+ test_begin (test, "Memory")
+ {
+ test_fail_if (blk_check_memory() == false, "Memory not freed");
+ }
+ test_end;
+ trace_uninit ();
+ test_result (test);
+ return test_nb_failed (test) == 0 ? 0 : 1;
+}
diff --git a/cesar/cl/test/utest_eoc/src/hle_tools.c b/cesar/cl/test/utest_eoc/src/hle_tools.c
new file mode 100644
index 0000000000..eba7086609
--- /dev/null
+++ b/cesar/cl/test/utest_eoc/src/hle_tools.c
@@ -0,0 +1,37 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file cl/test/utest_eoc/src/hle_tools.c
+ * \brief Stub hle tools.
+ * \ingroup cl
+ */
+#include "common/std.h"
+#include "hle/tools/tools.h"
+
+#include "cl/test/utest_eoc/test.h"
+#include "config/hle.h"
+
+hle_tools_t *
+hle_tools_init (ipmbox_t *ipmbox)
+{
+ static hle_tools_test_t hle_tools;
+ hle_tools.msg = NULL;
+ return (hle_tools_t *) &hle_tools;
+}
+
+void
+hle_tools_uninit (hle_tools_t *ctx)
+{
+}
+
+void
+hle_tools_msg_recv (hle_tools_t *ctx, const ipmbox_msg_mbx_t *msg)
+{
+ hle_tools_test_t *t = (hle_tools_test_t*) ctx;
+ t->msg = (ipmbox_msg_mbx_t*) msg;
+}
diff --git a/cesar/cl/test/utest_eoc/src/mcast.c b/cesar/cl/test/utest_eoc/src/mcast.c
new file mode 100644
index 0000000000..097b37c426
--- /dev/null
+++ b/cesar/cl/test/utest_eoc/src/mcast.c
@@ -0,0 +1,69 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2011 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file cl/test/utest_eoc/src/mcast.c
+ * \brief Multicast test.
+ * \ingroup cl
+ */
+#include "common/std.h"
+#include "lib/test.h"
+#include "cl/test/utest_eoc/test.h"
+#include "config/cl/eoc.h"
+#include "cl/inc/context.h"
+#include "cl/mcast.h"
+
+#if (!CONFIG_CL_EOC_ROUTE)
+# error (!CONFIG_CL_EOC_ROUTE)
+#endif
+
+void
+cl_test_case_mcast_master (test_t test)
+{
+ test_case_begin (test, "Master");
+ cl_test_t ctx;
+ cl_test_init (&ctx, 0x4354);
+ mac_t mac_group = MAC_ADDRESS (0x01, 0x00, 0x5E, 0x00, 0x00, 0x01);
+ mac_t mac_member = 0xe03708b65000ll;
+ test_begin (test, "No group")
+ {
+ igmp_groups_t *igmp = cl_get_igmp_groups (ctx.cl);
+ igmp->nb = 0;
+ cl_update_igmp_groups (ctx.cl);
+ test_fail_unless (igmp->nb == 0);
+ }
+ test_end;
+ test_begin (test, "Groups")
+ {
+ bool ok = false;
+ ok = cl_eoc_mactotei_entry_insert (ctx.cl, mac_member, 3);
+ test_fail_unless (ok);
+ /* Add a group. */
+ igmp_groups_t *igmp = cl_get_igmp_groups (ctx.cl);
+ igmp->nb = 1;
+ igmp->group_mac[0] = mac_group;
+ igmp->nb_total_members[0] = 1;
+ igmp->member_mac[0][0] = mac_member;
+ /* Update the igmp group. */
+ cl_update_igmp_groups (ctx.cl);
+ test_fail_unless (igmp->nb == 1);
+ test_fail_unless (igmp->group_mac[0]);
+ test_fail_unless (igmp->nb_total_members[0] == 1);
+ test_fail_unless (igmp->nb_actual_members[0] == 1);
+ test_fail_unless (igmp->member_mac[0][0] == mac_member);
+ test_fail_unless (igmp->member_tei[0][0] == 3);
+ }
+ test_end;
+ cl_test_uninit (&ctx);
+}
+
+void
+cl_test_suite_mcast (test_t test)
+{
+ test_suite_begin (test, "Multicast");
+ cl_test_case_mcast_master (test);
+}
diff --git a/cesar/cl/test/utest_eoc/src/receive.c b/cesar/cl/test/utest_eoc/src/receive.c
new file mode 100644
index 0000000000..eb2f70e96d
--- /dev/null
+++ b/cesar/cl/test/utest_eoc/src/receive.c
@@ -0,0 +1,83 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+
+/**
+ * \file cl/test/utest_eoc/src/receive.c
+ * \brief CL RX unit tests.
+ * \ingroup cl/test/utest_eoc
+ */
+
+#include <string.h>
+#include "common/std.h"
+#include "common/defs/ethernet.h"
+#include "lib/test.h"
+#include "cl/test/utest_eoc/test.h"
+#include "cl/inc/receive.h"
+#include "cl/inc/context.h"
+
+void
+test_case__cl_sar_data_recv (test_t test)
+{
+ test_case_begin (test, "Receive DATA");
+
+ u8 buffer[ETH_PACKET_MAX_SIZE];
+ cl_test_t t;
+ uint length = 500;
+ bool added = false;
+ uint j = 0;
+ uint rx_data = 0;
+ uint rx_data_bytes = 0;
+ uint rx_data_multicast = 0;
+ mac_t sta_mac [] = {0x123456789abcull, 0x23456789abceull,
+ 0x0100005E0001ull};
+ mfs_rx_t *mfs[COUNT(sta_mac)];
+ cl_test_init (&t, 0x9999432);
+
+ test_begin (test, "From SAR")
+ {
+ for (j = 0; j < COUNT (sta_mac); j++)
+ {
+ mfs[j] = mac_store_mfs_add_rx (t.mac_store, false, false,
+ MAC_LLID_MIN + 1, j + 100, &added);
+ dbg_assert (added);
+ cl_test_prepare_buffer (&t, buffer, length, sta_mac[j], 0);
+ rx_data_bytes = t.cl->stats.rx_data_bytes;
+ rx_data = t.cl->stats.rx_data;
+ cl_sar_data_recv (t.cl, buffer, length, mfs[j]);
+ test_fail_unless (t.cl->stats.rx_data_bytes
+ == rx_data_bytes + length);
+ if (!mac_is_multicast(sta_mac[j]))
+ {
+ test_fail_unless (t.cl->stats.rx_data == rx_data + 1);
+ test_fail_unless (t.cl->stats.rx_data_multicast
+ == rx_data_multicast);
+ }
+ else
+ {
+ test_fail_unless (t.cl->stats.rx_data == rx_data);
+ test_fail_unless (t.cl->stats.rx_data_multicast
+ == rx_data_multicast + 1);
+ }
+ test_fail_unless (t.pwl_recv.buffer == buffer);
+ test_fail_unless (t.pwl_recv.length == length);
+
+ mac_store_mfs_remove (t.mac_store, PARENT_OF (mfs_t, rx, mfs[j]));
+ blk_release (mfs [j]);
+ dbg_check (mac_store_sta_remove (t.mac_store, j + 100));
+ }
+ }
+ test_end;
+ cl_test_uninit (&t);
+}
+
+void
+cl_test_suite_receive (test_t test)
+{
+ test_suite_begin (test, "CL receive");
+ test_case__cl_sar_data_recv (test);
+}
diff --git a/cesar/cl/test/utest_eoc/src/send.c b/cesar/cl/test/utest_eoc/src/send.c
new file mode 100644
index 0000000000..58af73dd68
--- /dev/null
+++ b/cesar/cl/test/utest_eoc/src/send.c
@@ -0,0 +1,261 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file cl/test/utest_eoc/src/send.c
+ * \brief CL TX unit tests.
+ * \ingroup cl/test/utest_eoc
+ */
+#include <string.h>
+
+#include "common/std.h"
+#include "lib/test.h"
+
+#include "cl/test/utest_eoc/test.h"
+#include "cl/inc/send.h"
+#include "cl/inc/context.h"
+#include "lib/bitstream.h"
+
+uint
+cl_classifer_get_lid (cl_t *ctx, uint tei, uint tag,
+ bool *bcast, bool *acs,
+ bool *drop);
+
+void
+sar_msdu_process (sar_t *ctx, u8 *buffer, u16 length,
+ mfs_tx_t *mfs, u32 arrival_time_ntb)
+{
+ sar_test_t *t = (sar_test_t*) ctx;
+ dbg_assert (ctx);
+ dbg_assert (t->nb <= TEST_BUFFER_MAX_NB);
+
+ t->buffer[t->nb] = buffer;
+ t->length[t->nb] = length;
+ t->mfs[t->nb] = mfs;
+ t->nb++;
+}
+
+void
+cl_test_case__cl_data_send_prepare (test_t test)
+{
+ test_case_begin (test, "Data send");
+
+ u8 buffer [1024];
+ cl_test_t t;
+ cl_data_send_link_t expected;
+ mac_t sta_mac [] = {0x123456789abcull, 0x23456789abceull};
+ mfs_tx_t *mfs[COUNT(sta_mac)];
+ uint i, j;
+ uint start_time_ntb = 0;
+ uint tag = 0;
+ uint tx_data = 0;
+ uint tx_data_bytes = 0;
+ uint sar_nb = 0;
+ uint length = 123;
+ bool added = false;
+
+ cl_test_init (&t, 0x95490d);
+ cl_test_prepare_mactotei (&t, sta_mac, COUNT (sta_mac));
+
+ test_begin (test, "To SAR")
+ for (j = 0; j < COUNT (sta_mac); j++)
+ {
+ mfs[j] = mac_store_mfs_add_tx (t.mac_store, false, false,
+ MAC_LLID_MIN + 1, j + 100, &added);
+ dbg_assert (added);
+ t.sar.nb = 0;
+ cl_test_prepare_buffer (&t, buffer, length, sta_mac[j], 0);
+ expected.mfs = mfs[j];
+ expected.last_update_date_ntb = start_time_ntb;
+ expected.dmac = sta_mac[j];
+ for (i = start_time_ntb; i < 500000; i+= 100000)
+ {
+ if (i == MAC_MS_TO_TCK (CL_DATA_SEND_EXCEED_TIME_MS))
+ expected.last_update_date_ntb = i;
+ tx_data_bytes = t.cl->stats.tx_data_bytes;
+ tx_data = t.cl->stats.tx_data;
+ sar_nb = t.sar.nb;
+ cl_data_send (t.cl, buffer, length, tag, i);
+ test_fail_unless (t.cl->data_send_link.mfs == expected.mfs);
+ test_fail_unless (t.cl->data_send_link.last_update_date_ntb
+ == expected.last_update_date_ntb);
+ test_fail_unless (t.cl->stats.tx_data_bytes
+ == tx_data_bytes + length);
+ test_fail_unless (t.cl->stats.tx_data == tx_data + 1);
+ test_fail_unless (t.sar.nb == sar_nb + 1);
+ test_fail_unless (t.cl->data_send_link.dmac
+ == bitstream_direct_read_large (buffer, 0, 48));
+ }
+ mac_store_mfs_remove (t.mac_store, PARENT_OF (mfs_t, tx, mfs[j]));
+ blk_release (mfs [j]);
+ dbg_check (mac_store_sta_remove (t.mac_store, j + 100));
+ }
+ test_end;
+
+ cl_test_uninit (&t);
+}
+
+void
+cl_test_case__cl_data_send_mcast (test_t test)
+{
+ test_case_begin (test, "Multicast send");
+
+ u8 buffer [1024];
+ cl_test_t t;
+ mfs_tx_t *mfs_ref, *mfs_mcast[MCAST_GROUP_MAX_NB][MCAST_MEMBER_MAX_NB];
+ uint i, j;
+ uint start_time_ntb = 0;
+ uint tx_data_multicast = 0;
+ uint tx_data = 0;
+ uint tx_data_bytes = 0;
+ uint length = 123;
+ bool added = false;
+ bool bcast = false;
+ bool acs = false;
+ bool drop = false;
+
+ cl_test_init (&t, 0x95490d);
+
+ test_begin (test, "Multicast data.")
+ {
+ /** Prepare the groups and the mactotei table. */
+ for (j = 0; j < MCAST_GROUP_MAX_NB; j++)
+ {
+ t.cl->groups.group_mac[j] =
+ MAC_ADDRESS (0x01, 0x00, 0x5E, 0x00, j + 1, 0x01);
+ t.cl->groups.nb_actual_members[j] = j % (MCAST_MEMBER_MAX_NB + 1);
+ t.cl->groups.member_tei[j][0] = MAC_TEI_UNASSOCIATED;
+
+ for (i = 0; i < t.cl->groups.nb_actual_members[j]; i++)
+ {
+ t.cl->groups.member_tei[j][i]
+ = 100 + j * MCAST_MEMBER_MAX_NB + i;
+ mfs_mcast[j][i] = mac_store_mfs_add_tx (t.mac_store, false,
+ false, MAC_LLID_MIN + 1,
+ t.cl->groups.member_tei[j][i], &added);
+ dbg_assert (added);
+ }
+ cl_eoc_mactotei_entry_insert (t.cl, t.cl->groups.group_mac[j],
+ MAC_TEI_BCAST);
+ }
+ t.cl->groups.nb = MCAST_GROUP_MAX_NB;
+
+ for (j = 0; j < MCAST_GROUP_MAX_NB; j++)
+ {
+ cl_test_prepare_buffer (&t, buffer, length,
+ MAC_ADDRESS (0x01, 0x00, 0x5E, 0x00, j + 1, 0x01),
+ 0);
+
+ /** Send the multicast message */
+ t.sar.nb = 0;
+ tx_data_bytes = t.cl->stats.tx_data_bytes;
+ tx_data_multicast = t.cl->stats.tx_data_multicast;
+ tx_data = t.cl->stats.tx_data;
+
+ cl_data_send (t.cl, buffer, length, 0, start_time_ntb);
+
+ test_fail_unless (t.cl->stats.tx_data_bytes
+ == tx_data_bytes + length);
+ test_fail_unless (t.cl->stats.tx_data_multicast
+ == tx_data_multicast + 1);
+ test_fail_unless (t.cl->stats.tx_data == tx_data);
+
+ if (t.cl->groups.nb_actual_members[j] == 0)
+ {
+ test_fail_unless (t.sar.nb == 0);
+ }
+ else
+ {
+ test_fail_unless (t.sar.nb
+ == t.cl->groups.nb_actual_members[j]);
+
+ for (i = 0; i < t.cl->groups.nb_actual_members[j]; i++)
+ {
+ uint tei = 100 + j * MCAST_MEMBER_MAX_NB + i;
+ uint lid = cl_classifer_get_lid (t.cl, tei, 0, &bcast,
+ &acs, &drop);
+ mfs_ref = mac_store_mfs_get_tx (t.cl->mac_store, bcast,
+ false, lid, tei);
+
+ test_fail_unless (mfs_ref == t.sar.mfs[i]);
+ test_fail_unless (buffer == t.sar.buffer[i]);
+ test_fail_unless (mfs_ref->common.tei == tei);
+ test_fail_unless (bcast == false);
+
+ mac_store_mfs_remove (t.mac_store,
+ PARENT_OF (mfs_t, tx, mfs_ref));
+ blk_release (mfs_ref);
+ dbg_check (mac_store_sta_remove (t.mac_store, tei));
+ }
+ }
+ for (i = 0; i < t.cl->groups.nb_actual_members[j]; i++)
+ {
+ mac_store_mfs_remove (t.mac_store,
+ PARENT_OF (mfs_t, tx, mfs_mcast[j][i]));
+ blk_release (mfs_mcast[j][i]);
+ }
+ }
+ cl_mactotei_release_table (t.cl);
+ }
+ test_end;
+
+ test_begin (test, "Multicast not IGMP members")
+ {
+ /*
+ * From Wikipedia
+ * http://en.wikipedia.org/wiki/Multicast_address#Ethernet
+ *
+ * 01-00-0C-CC-CC-CC 0x0802 CDP, VTP
+ * 01-00-0C-CC-CC-CD 0x0802 Cisco Shared Spanning Tree Protocol Address
+ * 01-80-C2-00-00-00 0x0802 Spanning Tree Protocol IEEE 802.1D
+ * 01-80-C2-00-00-08 0x0802 Spanning Tree Protocol IEEE 802.1AD
+ * 01-80-C2-00-00-02 0x8809 Ethernet OAM Protocol IEEE 802.3ah
+ * 01-00-5E-xx-xx-xx 0x0800 IPv4 Multicast (RFC 1112)
+ */
+ mac_t mcast_mac_addr[] = {
+ MAC_ADDRESS (0x01, 0x00, 0x0C, 0xCC, 0xCC, 0xCC),
+ MAC_ADDRESS (0x01, 0x00, 0x0C, 0xCC, 0xCC, 0xCD),
+ MAC_ADDRESS (0x01, 0x80, 0xC2, 0x00, 0x00, 0x00),
+ MAC_ADDRESS (0x01, 0x80, 0xC2, 0x00, 0x00, 0x08),
+ MAC_ADDRESS (0x01, 0x80, 0xC2, 0x00, 0x00, 0x02),
+ MCAST_MAC_IGMP_GENERAL_QUERY,
+ };
+
+ uint i;
+ uint tag = 0;
+ for (i = 0; i < COUNT (mcast_mac_addr); i++)
+ {
+ mfs_t *mfs;
+ cl_test_prepare_buffer (&t, buffer, length, mcast_mac_addr[i],
+ tag);
+ cl_data_send (t.cl, buffer, length, tag, 0x0);
+ mfs = PARENT_OF_OR_NULL (mfs_t, tx, t.sar.mfs[0]);
+ test_fail_unless (mfs && mfs->common.bcast);
+ /* Release the MFS from:
+ * - the CL ("fast path") i.e. data_send_link,
+ * - the overridden SAR layer which contains a pointer to it,
+ * - the mac store which has initialised it.
+ */
+ t.cl->data_send_link.mfs = NULL;
+ t.sar.nb = 0;
+ t.sar.mfs[0] = NULL;
+ mac_store_mfs_remove (t.mac_store, mfs);
+ blk_release (mfs);
+ }
+ }
+ test_end;
+
+ cl_test_uninit (&t);
+}
+
+void
+cl_test_suite_send (test_t test)
+{
+ test_suite_begin (test, "CL send");
+ cl_test_case__cl_data_send_prepare (test);
+ cl_test_case__cl_data_send_mcast (test);
+}
diff --git a/cesar/cl/test/utest_eoc/src/test.c b/cesar/cl/test/utest_eoc/src/test.c
new file mode 100644
index 0000000000..57eb6ad58c
--- /dev/null
+++ b/cesar/cl/test/utest_eoc/src/test.c
@@ -0,0 +1,88 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2010 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file cl/test/utest_eoc/src/test.c
+ * \brief CL environment test.
+ * \ingroup cl
+ */
+#include "common/std.h"
+#include "lib/bitstream.h"
+#include "cl/test/utest_eoc/test.h"
+#include "mac/common/ntb.h"
+#include "cl/inc/context.h"
+#include <string.h>
+
+void
+ipmbox_tx_data (ipmbox_t *ctx, u32 *first_msg, uint length)
+{
+ dbg_assert (ctx);
+ cl_test_recv_t *test_ctx = (cl_test_recv_t*) ctx;
+ test_ctx->buffer = (u8 *) first_msg[1];
+ test_ctx->length = ipmbox_msg_get_data_length (first_msg[0]);
+}
+
+static int
+cl_trace_buffer_dbg_dump_callback (void *user, const char *text,
+ uint text_size)
+{
+ return 0;
+}
+
+void
+cl_test_init (cl_test_t *ctx, u32 seed)
+{
+ dbg_assert (ctx);
+ ctx->mac_store = mac_store_init ();
+ mac_config_init (&ctx->mac_config);
+ mac_ntb_init (&ctx->mac_config);
+ ctx->mac_config.authenticated = true;
+ ctx->mac_config.tei = MAC_TEI_CCO_DEF;
+ ctx->mac_config.sta_mac_address = 0xfeffffd71300ull;
+ ctx->cl = cl_init (ctx->mac_store, (sar_t*) &ctx->sar, &ctx->mac_config,
+ (ipmbox_t *) &ctx->pwl_recv, (bufmgr_t*) &ctx->bufmgr);
+ lib_rnd_init (&ctx->rnd, seed);
+}
+
+void
+cl_test_uninit (cl_test_t *ctx)
+{
+ dbg_assert (ctx);
+ trace_bundle_dump_all ("dbg", cl_trace_buffer_dbg_dump_callback, NULL);
+ cl_uninit (ctx->cl);
+ mac_store_uninit (ctx->mac_store);
+}
+
+void
+cl_test_prepare_mactotei (cl_test_t *ctx, mac_t *dmacs, uint nb)
+{
+ uint i;
+ dbg_assert (ctx);
+ for (i = 0; i < nb; i++)
+ {
+ dbg_assert (!mac_is_multicast (dmacs[i]));
+ cl_eoc_mactotei_entry_insert (ctx->cl, dmacs[i], i + 100);
+ }
+}
+
+void
+cl_test_prepare_buffer (cl_test_t *ctx, u8 *buffer, u16 length, mac_t dmac,
+ uint tag)
+{
+ u8 data;
+ u16 i;
+ bitstream_t stream;
+ dbg_assert (ctx);
+ data = lib_rnd32 (&ctx->rnd) & 0xff;
+ bitstream_write_init (&stream, buffer, length);
+ bitstream_write_large (&stream, dmac, 48);
+ bitstream_write_large (&stream, ctx->mac_config.sta_mac_address, 48);
+ bitstream_write (&stream, tag, 16);
+ for (i = 0; i < length - 14; i++)
+ bitstream_write (&stream, data, 8);
+ bitstream_finalise (&stream);
+}
diff --git a/cesar/cl/test/utest_eoc/src/test_mactotei.c b/cesar/cl/test/utest_eoc/src/test_mactotei.c
new file mode 100644
index 0000000000..fbdcf67f13
--- /dev/null
+++ b/cesar/cl/test/utest_eoc/src/test_mactotei.c
@@ -0,0 +1,232 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2009 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file cl/test/utest_eoc/src/test_mactotei.c
+ * \brief Unit test for EoC mactotei table in the CL module.
+ * \ingroup cl
+ *
+ * This suite tests functions used for creating, refreshing and finding entries
+ * of EoC mactotei table.
+ */
+#include "common/std.h"
+
+#include "lib/test.h"
+#include "lib/stats.h"
+#include "cl/inc/context.h"
+#include "cl/cl_eoc_mactotei.h"
+
+static cl_t cl;
+static mac_config_t mac_config;
+
+extern void cl_eoc_time_update (cl_t *ctx);
+extern cl_eoc_mactotei_entry_t *cl_eoc_mactotei_entry_find (cl_t *ctx,
+ mac_t mac_addr);
+extern void cl_eoc_mactotei_remove_obsolete (cl_t *ctx);
+
+void
+test_entries (test_t test)
+{
+ cl.mac_config = &mac_config;
+ list_node_t *list_node = NULL;
+ cl_eoc_mactotei_entry_t *entry;
+ uint i,tei;
+ bool ok;
+
+ lib_stats_init ();
+ test_case_begin (test, "MACtoTEI table");
+ test_begin (test, "Initialize")
+ {
+ cl_eoc_mactotei_init (&cl);
+ i = 0;
+ list_node = list_next (&cl.cl_eoc_mactotei_table.ageing_list.nil);
+ do
+ {
+ entry = PARENT_OF (cl_eoc_mactotei_entry_t, l_age, list_node);
+ test_fail_unless (entry->timestamp == i);
+ i++;
+ list_node = list_next (list_node);
+ } while (list_node != &cl.cl_eoc_mactotei_table.ageing_list.nil);
+ test_fail_unless (i == MACTOTEI_NB_ENTRIES);
+ }
+ test_end;
+
+ test_begin (test, "Fill table")
+ {
+ cl.mac_config->tei = 1;
+ ok = cl_eoc_mactotei_entry_insert (&cl, 0x0000112233445566ull, 4);
+ test_fail_if (!ok);
+ tei = cl_eoc_mactotei_find_tei (&cl, 0x0000112233445566ull);
+ test_fail_unless (tei == 4);
+ ok = cl_eoc_mactotei_entry_insert (&cl, 0x0000112233445577ull, 5);
+ test_fail_if (!ok);
+ ok = cl_eoc_mactotei_entry_insert (&cl, 0x0000112233445588ull, 10);
+ test_fail_if (!ok);
+ ok = cl_eoc_mactotei_entry_insert (&cl, 0x0000122233445513ull, 5);
+ test_fail_if (!ok);
+ ok = cl_eoc_mactotei_entry_insert (&cl, 0x0000112233445599ull, 21);
+ test_fail_if (!ok);
+ tei = cl_eoc_mactotei_find_tei (&cl, 0x0000112233445588ull);
+ test_fail_unless (tei == 10);
+ cl_eoc_mactotei_entry_remove (&cl, 5);
+ cl_eoc_mactotei_entry_remove (&cl, 21);
+ cl_eoc_mactotei_entry_remove (&cl, 35);
+ tei = cl_eoc_mactotei_find_tei (&cl, 0x0000112233445577ull);
+ test_fail_unless (tei == MAC_TEI_UNASSOCIATED);
+
+ u64 mac_addr = 0x0000112233445512ull;
+ for (i = 0; i < 5 * MACTOTEI_NB_ENTRIES; i++)
+ {
+ mac_addr -= 0x1000000;
+ ok = cl_eoc_mactotei_entry_insert (&cl, mac_addr,
+ i % MACTOTEI_NB_ENTRIES);
+ test_fail_if (!ok);
+ }
+ cl_eoc_mactotei_entry_remove (&cl, 12);
+ }
+ test_end;
+
+ test_begin (test, "Obsoleteness & refresh")
+ {
+ list_node = list_prev (&cl.cl_eoc_mactotei_table.ageing_list.nil);
+ entry = PARENT_OF (cl_eoc_mactotei_entry_t, l_age, list_node);
+
+ /* increment time to exceed max age duration */
+ for (i = 0; i < 1.1*(cl.cl_eoc_mactotei_table.max_duration); i++)
+ cl_eoc_time_update (&cl);
+
+ tei = cl_eoc_mactotei_find_tei (&cl, entry->mac_addr);
+ test_fail_if (tei != MAC_TEI_UNASSOCIATED);
+
+ ok = cl_eoc_mactotei_entry_insert (&cl, entry->mac_addr, 111);
+ tei = cl_eoc_mactotei_find_tei (&cl, entry->mac_addr);
+ test_fail_if (tei != 111);
+ ok = cl_eoc_mactotei_entry_insert (&cl, entry->mac_addr, 111);
+ test_fail_if (!ok);
+
+ for (i = 0; i < 1234; i++)
+ {
+ ok = cl_eoc_mactotei_entry_insert (&cl, entry->mac_addr, 111);
+ test_fail_if (!ok);
+ }
+ }
+ test_end;
+
+ test_begin (test, "Removal of obsolete entries")
+ {
+ cl.mac_config->tei = 3;
+ cl_eoc_mactotei_init (&cl);
+ cl_eoc_mactotei_entry_insert (&cl, 0x0000030001D713ull, 6);
+ cl_eoc_mactotei_entry_insert (&cl, 0x0000050001D713ull, 8);
+ for (i = 0; i < cl.cl_eoc_mactotei_table.max_duration; i++)
+ cl_eoc_time_update (&cl);
+ cl_eoc_mactotei_entry_insert (&cl, 0x0000060001D713ull, 9);
+ cl_eoc_mactotei_entry_insert (&cl, 0x0000070001D713ull, 10);
+
+ cl_eoc_mactotei_remove_obsolete (&cl);
+
+ /* cl_eoc_mactotei_find_tei() hides obsolete entries.
+ * So use cl_eoc_mactotei_entry_find() instead. */
+ entry = cl_eoc_mactotei_entry_find (&cl, 0x0000030001D713ull);
+ test_fail_if (entry != NULL);
+ entry = cl_eoc_mactotei_entry_find (&cl, 0x0000050001D713ull);
+ test_fail_if (entry != NULL);
+ entry = cl_eoc_mactotei_entry_find (&cl, 0x0000060001D713ull);
+ test_fail_if (entry == NULL || entry->tei != 9);
+ entry = cl_eoc_mactotei_entry_find (&cl, 0x0000070001D713ull);
+ test_fail_if (entry == NULL || entry->tei != 10);
+ }
+ test_end;
+
+ test_begin (test, "Limitation of entries")
+ {
+ cl.mac_config->tei = 5;
+ cl_eoc_mactotei_init (&cl);
+ u64 mac_addr = 0x0000112233445566ull;
+ for (i = 0; i < cl.cl_eoc_mactotei_table.max_entries; i++)
+ {
+ mac_addr += 0x123456789ull;
+ ok = cl_eoc_mactotei_entry_insert (&cl, mac_addr, 5);
+ test_fail_if (!ok);
+ }
+ /* no new addresses allowed from sta side, as source addresses */
+ ok = cl_eoc_mactotei_entry_insert (&cl, 0x0000132233445588ull, 5);
+ test_fail_if (ok);
+ /* new addresses allowed as destination addresses*/
+ ok = cl_eoc_mactotei_entry_insert (&cl, 0x0000132233445511ull, 1);
+ test_fail_unless (ok);
+ ok = cl_eoc_mactotei_entry_insert (&cl, 0x0000132233442511ull, 1);
+ test_fail_unless (ok);
+ test_fail_unless (cl.cl_eoc_mactotei_table.num_of_entries ==
+ cl.cl_eoc_mactotei_table.max_entries);
+
+ /* increment time to exceed max age duration */
+ for (i = 0; i < 1.1*(cl.cl_eoc_mactotei_table.max_duration); i++)
+ cl_eoc_time_update (&cl);
+ ok = cl_eoc_mactotei_entry_insert (&cl, 0x0000132233445588ull, 5);
+ test_fail_unless (ok);
+ test_fail_unless (cl.cl_eoc_mactotei_table.num_of_entries == 1);
+ }
+ test_end;
+
+ test_begin (test, "Bridge info")
+ {
+ uint nb_entry;
+ mac_t mac, mac_ref;
+ uint tei_ref;
+ cl_eoc_mactotei_init (&cl);
+ cl.mac_config->tei = 1;
+ ok = cl_eoc_mactotei_entry_insert (&cl, 0x0000112233445566ull, 4);
+ test_fail_if (!ok);
+ ok = cl_eoc_mactotei_entry_insert (&cl, 0x0000112233445577ull, 5);
+ test_fail_if (!ok);
+ for (i = 0; i < 0.9*(cl.cl_eoc_mactotei_table.max_duration); i++)
+ cl_eoc_time_update (&cl);
+ nb_entry = cl_eoc_mactotei_snapshot_create (&cl);
+ test_fail_unless (nb_entry == 2);
+ ok = cl_eoc_mactotei_entry_insert (&cl, 0x0000112233445512ull, 6);
+ test_fail_if (!ok);
+ nb_entry = cl_eoc_mactotei_snapshot_create (&cl);
+ test_fail_unless (nb_entry == 3);
+ for (i = 0; i < 0.3*(cl.cl_eoc_mactotei_table.max_duration); i++)
+ cl_eoc_time_update (&cl);
+ ok = cl_eoc_mactotei_entry_insert (&cl, 0x0000112233445513ull, 7);
+ test_fail_if (!ok);
+ ok = cl_eoc_mactotei_entry_insert (&cl, 0x0000112233445514ull, 8);
+ test_fail_if (!ok);
+ ok = cl_eoc_mactotei_entry_insert (&cl, 0x0000112233445515ull, 9);
+ test_fail_if (!ok);
+ nb_entry = cl_eoc_mactotei_snapshot_create (&cl);
+ test_fail_unless (nb_entry == 4);
+ mac_ref = 0x0000112233445515ull;
+ tei_ref = 9;
+ for (i = 0; i < nb_entry; i++)
+ {
+ mac = cl_eoc_mactotei_snapshot_get_mac (&cl, i);
+ test_fail_unless (mac == mac_ref - i);
+
+ uint tei = 0;
+ cl_eoc_mactotei_snapshot_get_mac_tei (&cl, i, &mac, &tei);
+ test_fail_if (mac != mac_ref - i);
+ test_fail_if (tei != tei_ref - i);
+ }
+ }
+ test_end;
+}
+
+int
+main (void)
+{
+ test_t test;
+ test_init (test, 0, NULL);
+
+ test_suite_begin (test, "Cl_EoC: MAC to Tei");
+ test_entries (test);
+
+ test_result (test);
+ return test_nb_failed (test) == 0 ? 0 : 1;
+}
diff --git a/cesar/cl/test/utest_eoc/test.h b/cesar/cl/test/utest_eoc/test.h
new file mode 100644
index 0000000000..6d4b94b78d
--- /dev/null
+++ b/cesar/cl/test/utest_eoc/test.h
@@ -0,0 +1,124 @@
+#ifndef cl_test_test_h
+#define cl_test_test_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file cl/test/utest_eoc/test.h
+ * \brief CL environment test.
+ * \ingroup cl
+ */
+#include "cl/cl.h"
+#include "lib/rnd.h"
+
+#include "common/ipmbox/msg.h"
+#include "cl/mbx/mbx.h"
+
+#define TEST_BUFFER_MAX_NB 4
+
+struct sar_test_t
+{
+ /** buffer received. */
+ u8 *buffer[TEST_BUFFER_MAX_NB];
+ /** MFS used for TX. */
+ mfs_tx_t *mfs[TEST_BUFFER_MAX_NB];
+ /** Data length. */
+ uint length[TEST_BUFFER_MAX_NB];
+ /** User data. */
+ void *ud[MCAST_MEMBER_MAX_NB];
+ /** Number of calls. */
+ uint nb;
+};
+typedef struct sar_test_t sar_test_t;
+
+struct cl_test_recv_t
+{
+ /** Source TEI. */
+ uint stei;
+ /** Buffer. */
+ u8 *buffer;
+ /** length */
+ uint length;
+ /** NEK Encrypted ?*/
+ bool nek_enc;
+};
+typedef struct cl_test_recv_t cl_test_recv_t;
+
+struct hle_tools_test_t
+{
+ ipmbox_msg_mbx_t *msg;
+};
+typedef struct hle_tools_test_t hle_tools_test_t;
+
+struct cl_test_t
+{
+ /** CL context. */
+ cl_t *cl;
+ /** Mac config context. */
+ mac_config_t mac_config;
+ /** Mac store context. */
+ mac_store_t *mac_store;
+ /** Random context. */
+ lib_rnd_t rnd;
+ /** SAR test context. */
+ sar_test_t sar;
+ /** PWL receive MME or DATA. */
+ cl_test_recv_t pwl_recv;
+ /** Ipmbox context. */
+ void *ipmbox;
+ /** Buffer manager context. */
+ void *bufmgr;
+ /** Hle tools stubbed context. */
+ hle_tools_test_t *hle_tools;
+ /** Mbox context. */
+ cl_mbx_t *mbx;
+};
+typedef struct cl_test_t cl_test_t;
+
+BEGIN_DECLS
+
+/**
+ * Initialise test context.
+ * \param ctx the test context.
+ * \param seed the seed to initialise the random generator.
+ */
+void
+cl_test_init (cl_test_t *ctx, u32 seed);
+
+/**
+ * Uninitialise the CL context.
+ * \param ctx the test context.
+ */
+void
+cl_test_uninit (cl_test_t *ctx);
+
+/**
+ * Prepare the mac to tei table of the CL.
+ * \param ctx the CL context.
+ * \param dmacs destination mac tables.
+ * \param nb the number of entries.
+ *
+ * First entry corresponds to TEI 1 and so on.
+ */
+void
+cl_test_prepare_mactotei (cl_test_t *ctx, mac_t *dmacs, uint nb);
+
+/**
+ * Prepare a buffer to be sent by the Cl.
+ * \param ctx the test context.
+ * \param buffer the buffer to use.
+ * \param length the MF length.
+ * \param dmac the destination mac address.
+ * \param tag the linux priority tag for the classifier.
+ */
+void
+cl_test_prepare_buffer (cl_test_t *ctx, u8 *buffer, u16 length, mac_t dmac,
+ uint tag);
+
+END_DECLS
+
+#endif /* cl_test_test_h */