/* Cesar project {{{ * * Copyright (C) 2008 Spidcom * * <<>> * * }}} */ /** * \file test_general/integration/interface-dp/src/station.c * \brief Station interface - DP. * \ingroup test_general * * Test the integration of the interface with the data plane. * The sniffer will be added to this test later. */ #include "common/std.h" #include "host/station.h" #include #include /** Library include. */ #include "lib/read_word.h" #include "lib/trace.h" #include "lib/circular_buffer.h" /** Data include. */ #include "mac/common/config.h" #include "mac/common/ntb.h" #include "mac/common/store.h" /** Layers include. */ #include "mac/sar/sar.h" #include "mac/pbproc/pbproc.h" #include "mac/ca/ca.h" #include "mac/sar/inc/trace.h" struct tei_node_t { list_node_t node; uint tei; }; typedef struct tei_node_t tei_node_t; /** station context. */ struct station_test_t { /** The mac config. */ mac_config_t mac_config; /** The mac store. */ mac_store_t *mac_store; // Layers /** Pbproc context. */ pbproc_t *pbproc; /** Sar context. */ sar_t *sar; /* Schedule index. */ uint sched_index; /* Pbproc activate. */ bool pbproc_activate; cyg_handle_t sched_handle; cyg_thread sched_thread; /** Used to memorize the list of TEI inserted in the mac_Store to remove it * in the future. */ list_t tei_list; }; typedef struct station_test_t station_test_t; u8 sched_stack [CYGNUM_HAL_STACK_SIZE_TYPICAL]; //---------------------------------------------------------------------------- /* Use to keep a list of rx params in the CE */ list_t ce_rx_params_list; struct ce_rx_params_node_t { list_node_t node; pbproc_rx_params_t *rx_params; }; typedef struct ce_rx_params_node_t ce_rx_params_node_t; static station_test_t station_test; /****************** CALL BACKS DEFINITION ****************/ /** * Call back called by the SAR each time a packet is segmented. * In this test it will only display a message. * The buffer is a static buffer not a allocated one it does not need to be * freed. * * \param user, User data * \param buffer the address of the buffer. */ void sar_segmentation_ul_done (void *user, u8* buffer) { printf ("******************************************\n"); printf (" sar Segmentation done\n \n"); printf ("******************************************\n"); } /** * Implementation of the sar_reassembly_done_cb_t call back. * Only used in this test. * The buffer and the mfs shall be release. * * \param user, User data * \param buffer the buffer address containing the data * \param length the data length * \param mfs the mfs used */ void sar_reassembly_ul_done (void *user, u8* buffer, uint length, mfs_rx_t *mfs, bool encrypted) { dbg_assert (buffer); dbg_assert (length >= 60 && length <= 1518); dbg_assert (mfs); printf ("******************************************\n"); printf (" sar Reassembly done\n \n"); printf ("******************************************\n"); free (buffer); } // ---------------------------- Station functions -------------------------- /** * Add a link to the STAtion i.e. will create a MFS * * \param ctx the station context. * \param type TX or RX link, it is a short 1 for TX 0 for RX. * \param bcast short indicating if the link is a broadcast link * \param mme short indicating if the link will be use to transmit MMEs * \param lid short indicating if it is a link identitier. * \param tei short the destination station. */ void station_test_link_add (station_test_t *ctx, uint type, uint bcast, uint mme, uint lid, uint tei) { bool added; mfs_t *mfs; dbg_assert (ctx); dbg_assert (ctx->mac_store); dbg_assert (ctx->sar); mfs = mac_store_mfs_add (ctx->mac_store, type, bcast, mme, lid, tei, &added); dbg_assert (added); // add the link to the sar. sar_mfs_add (ctx->sar, mfs); blk_release (mfs); } /** * Remove a link to the STAtion i.e. will create a MFS * * \param ctx the station context. * \param type TX or RX link, it is a short 1 for TX 0 for RX. * \param bcast short indicating if the link is a broadcast link * \param mme short indicating if the link will be use to transmit MMEs * \param lid short indicating if it is a link identitier. * \param tei short the destination station. */ void station_test_link_remove (station_test_t *ctx, uint type, uint bcast, uint mme, uint lid, uint tei) { mfs_t *mfs; pb_t *pb; dbg_assert (ctx); dbg_assert (ctx->mac_store); dbg_assert (ctx->sar); mfs = mac_store_mfs_get (ctx->mac_store, type, bcast, mme, lid, tei); if (mfs != NULL) { while (type && mfs->tx.head) { pb = mfs->tx.head; mfs->tx.head = mfs->tx.head->next; blk_release_desc ((blk_t *) pb); } while (!type && mfs->rx.head) { pb = mfs->rx.head; mfs->rx.head = mfs->rx.head->next; blk_release_desc ((blk_t *) pb); } // remove the MFS from the sar sar_mfs_remove (ctx->sar, mfs); blk_release (mfs); } } /** * Create a schedule for the Channel Access (beacon period) in CSMA only mode. * Shall always be used to send or receive data. * * \param int_sta the pbproc context * \param beacon_period_nb the quantity of beacon periods for the test. */ void create_schedule_csma_only (station_test_t *int_sta, uint beacon_period_nb) { pbproc_t *pbproc; dbg_assert (int_sta); pbproc = int_sta->pbproc; ca_beacon_period_t beacons_periods[beacon_period_nb]; uint i; dbg_assert (pbproc); dbg_assert (beacon_period_nb < CA_BEACON_PERIOD_NB); /* Get and fill the schedule */ ca_schedule_t *sched = ca_alloc_get_schedule (pbproc_get_ca (pbproc), int_sta->sched_index); sched->coexistence_mode = MAC_COEXISTENCE_SHARED_CSMA_HYBRID_MODE; sched->nek_switch = 0; //TODO sched->allocations_nb = 1; sched->allocations[0].end_offset_tck = 10000000; sched->allocations[0].glid = 0xff; /* Create a schedule for 14 beacon period */ for (i = 0; i < beacon_period_nb; i++) { beacons_periods[i].start_date = 1000000 * i + my_station.current_tick_tck; beacons_periods[i].schedule_index = int_sta->sched_index; } /* Use the new schedule */ ca_alloc_update_beacon_periods (pbproc_get_ca (pbproc), beacons_periods, beacon_period_nb); /* Activate the pbproc */ if (!int_sta->pbproc_activate) { pbproc_activate (pbproc, true); int_sta->pbproc_activate = true; } int_sta->sched_index++; } /** * Thread entry finction * * \param int_sta the sta context. */ void pbproc_sched (cyg_addrword_t int_sta) { station_test_t *station_test; station_test = (station_test_t *) int_sta; while (true) { create_schedule_csma_only (station_test, 14); station_test->sched_index ++; //create the second schedule. create_schedule_csma_only (station_test, 14); station_test->sched_index ++; //create the third schedule. create_schedule_csma_only (station_test, 14); station_test->sched_index ++; cyg_thread_delay (500); } } /** * Provides the Tei of the STA and the SNID * * \param ctx the station context * \param tei the tei of the station * \param snid the snid of the AVLN * \param beacon_period_auto generation automatic of the beacon period for * the CA scheduling * \param cco boolean informing if the sta is cco or not * \param authenticated boolean informing if the sta is authenticated or * not. */ void station_test_config (station_test_t *ctx, uint tei, uint snid, bool beacon_period_auto, mac_t mac_addr) { dbg_assert (ctx); ctx->mac_config.snid = snid; ctx->mac_config.tei = tei; if (mac_addr == 0) { ctx->mac_config.sta_mac_address = 0x123456789abcull; } else ctx->mac_config.sta_mac_address = mac_addr; if (beacon_period_auto) { // Create the Thread for the pbproc. cyg_thread_create (9, &pbproc_sched, (cyg_addrword_t) ctx, "Sched", sched_stack, CYGNUM_HAL_STACK_SIZE_TYPICAL, &ctx->sched_handle, &ctx->sched_thread); cyg_thread_resume (ctx->sched_handle); printf ("[STATION] PBproc Activated\n"); } } /** * Provides the TEI of all the station in the AVLN. * * \param ctx the station context. * \param tei the tei list of the stations * \param qte the quantity of TEIs in the list. */ void station_test_discover (station_test_t *ctx, uint *tei, uint qte) { tei_node_t *node; uint i; for (i = 0; i < qte; i++) { if (tei[i] != 0) { node = blk_alloc (); list_init_node (&node->node); node->tei = tei[i]; list_push (&ctx->tei_list, &node->node); mac_store_sta_add (ctx->mac_store, tei[i]); } } } // ---------------------------- Function calls ----------------------------- /** Creates a link in the STA. * * - dtei the tei of the station. * - fw forward link * - rw reverse link * - bcast broadcast. * * \param fcall the fcall context. * \param param the fcall param * \param msg the message * \param data anything */ int fc_add_mme_link (fcall_ctx_t *fcall, fcall_param_t **param, sci_msg_t **msg, void *data) { uint dtei = 0; uint fw = 0; uint rw = 0; uint bcast = 0; mfs_tx_t *mfs_tx; mfs_rx_t *mfs_rx; bool added; fcall_param_bind_short (*param, *msg, "dtei", &dtei); fcall_param_bind_short (*param, *msg, "fw", &fw); fcall_param_bind_short (*param, *msg, "rw", &rw); fcall_param_bind_short (*param, *msg, "bcast", &bcast); fcall_param_reset (*param); if (fw) { mfs_tx = mac_store_mfs_add_tx (station_test.mac_store, bcast, true, MAC_LID_NONE, dtei, &added); if (mfs_tx == NULL) return false; sar_mfs_add (station_test.sar, (mfs_t *) mfs_tx); blk_release (mfs_tx); } if (rw) { mfs_rx = mac_store_mfs_add_rx (station_test.mac_store, bcast, true, MAC_LID_NONE, dtei, &added); if (mfs_rx == NULL) return false; sar_mfs_add (station_test.sar, (mfs_t *) mfs_rx); blk_release (mfs_rx); } return true; } /** Initialise the station parameters data as the mac address the tei. * * - stei. * - mac_addr. * * \param fcall the fcall context. * \param param the fcall param * \param msg the message * \param data anything */ int fc_station_config (fcall_ctx_t *fcall, fcall_param_t **param, sci_msg_t **msg, void *data) { uint stei = 0; mac_t mac_address = 0; fcall_param_bind_short (*param, *msg, "stei", &stei); fcall_param_bind (*param, *msg, "mac_addr", sizeof(mac_t), &mac_address); station_test.mac_config.sta_mac_address = mac_address; station_test.mac_config.tei = stei; fcall_param_reset (*param); return true; } /** Prepare the station to work. * It will create default schedules for the Channel Access in CSMA-only mode * and activate the pbproc to start the communication with the others * stations. * * \param fcall the fcall context. * \param param the fcall param * \param msg the message * \param data anything */ int fc_station_start (fcall_ctx_t *fcall, fcall_param_t **param, sci_msg_t **msg, void *data) { ca_beacon_period_t beacons_periods[4]; uint i; /* Get and fill the schedule */ ca_schedule_t *sched = ca_alloc_get_schedule (pbproc_get_ca (station_test.pbproc),0); sched->coexistence_mode = MAC_COEXISTENCE_SHARED_CSMA_HYBRID_MODE; sched->nek_switch = 0; //TODO sched->allocations_nb = 1; sched->allocations[0].end_offset_tck = BITS_ONES (24); sched->allocations[0].glid = 0xff; /* Create a schedule for 14 beacon period */ for (i = 0; i < 4; i++) { beacons_periods[i].start_date = BITS_ONES(24) * i + my_station.current_tick_tck; beacons_periods[i].schedule_index = 0; } /* Use the new schedule */ ca_alloc_update_beacon_periods (pbproc_get_ca (station_test.pbproc), beacons_periods, 4); /* Only run this one !!! */ pbproc_activate (station_test.pbproc, true); return true; } /** * Add a link to the Station in order to receive or transmit data. * * - type TX or RX link, it is a short 1 for TX 0 for RX. * - bcast short indicating if the link is a broadcast link * - mme short indicating if the link will be use to transmit MMEs * - lid short indicating if it is a link identitier. * - tei short the destination station. * * \param fcall the fcall context. * \param param the fcall param * \param msg the message * \param data anything */ int fc_station_link_add (fcall_ctx_t *fcall, fcall_param_t **param, sci_msg_t **msg, void *data) { uint type; uint bcast; uint mme; uint lid; uint tei; type = 0; bcast = 0; mme = 0; lid = 0; tei = 0; fcall_param_bind_short (*param, *msg, "type", &type); fcall_param_bind_short (*param, *msg, "bcast", &bcast); fcall_param_bind_short (*param, *msg, "mme", &mme); fcall_param_bind_short (*param, *msg, "lid", &lid); fcall_param_bind_short (*param, *msg, "tei", &tei); if (type) printf ( "[STATION : %d] TX link added, bcast : %d, mme : %d, lid : %d, tei : %d\n", station_test.mac_config.tei, bcast, mme, lid, tei); else printf ( "[STATION : %d] RX link added, bcast : %d, mme : %d, lid : %d, tei : %d\n", station_test.mac_config.tei, bcast, mme, lid, tei); station_test_link_add (&station_test, type, bcast, mme, lid, tei); fcall_param_reset (*param); return true; } /** * Remove a link to the Station in order to receive or transmit data. * * - type TX or RX link, it is a short 1 for TX 0 for RX. * - bcast short indicating if the link is a broadcast link * - mme short indicating if the link will be use to transmit MMEs * - lid short indicating if it is a link identitier. * - tei short the destination station. * * \param fcall the fcall context. * \param param the fcall param * \param msg the message * \param data anything */ int fc_station_link_remove (fcall_ctx_t *fcall, fcall_param_t **param, sci_msg_t **msg, void *data) { uint type; uint bcast; uint mme; uint lid; uint tei; type = 0; bcast = 0; mme = 0; lid = 0; tei = 0; fcall_param_bind_short (*param, *msg, "type", &type); fcall_param_bind_short (*param, *msg, "bcast", &bcast); fcall_param_bind_short (*param, *msg, "mme", &mme); fcall_param_bind_short (*param, *msg, "lid", &lid); fcall_param_bind_short (*param, *msg, "tei", &tei); if (type) printf ( "[STATION : %d] TX link removed, bcast : %d, mme : %d, lid : %d, tei : %d\n", station_test.mac_config.tei, bcast, mme, lid, tei); else printf ( "[STATION : %d] RX link removed, bcast : %d, mme : %d, lid : %d, tei : %d\n", station_test.mac_config.tei, bcast, mme, lid, tei); station_test_link_remove (&station_test, type, bcast, mme, lid, tei); fcall_param_reset (*param); return true; } /** * Initialize the configuration of the STA. * The parameters we must provide are the TEI of the STA, the SNID and the * boolean to indicate the auto generation of the beacon periods. * * \param fcall the fcall context. * \param param the fcall param * \param msg the message * \param data anything */ int fc_station_init_config (fcall_ctx_t *fcall, fcall_param_t **param, sci_msg_t **msg, void *data) { uint tei; uint snid; uint beacon_period_auto; mac_t mac; tei = 0; snid = 0; beacon_period_auto = 0; fcall_param_bind_short (*param, *msg, "tei", &tei); fcall_param_bind_short (*param, *msg, "snid", &snid); fcall_param_bind_short (*param, *msg, "auto_sched", &beacon_period_auto); station_test_config (&station_test, tei, snid, beacon_period_auto, mac); fcall_param_reset (*param); return true; } /** * Add a data buffer to the SAR. * * \param fcall the fcall context. * \param param the fcall param * \param msg the message * \param data anything */ int fc_sar_data_buffer_add (fcall_ctx_t *fcall, fcall_param_t **param, sci_msg_t **msg, void *data) { u8 *buffer; buffer = (u8*) malloc (2048 * sizeof(u8)); sar_data_buffer_add (station_test.sar, buffer); fcall_param_reset (*param); return true; } /** * Add Msdu to send * * - lid the link to use * - tei the destination * - bcast if the link is a bcast link * - mme if it is a mme * - buffer the buffer containing a frame * - length the buffer length * * \param fcall the fcall context. * \param param the fcall param * \param msg the message * \param data anything */ int fc_sar_msdu_add (fcall_ctx_t *fcall, fcall_param_t **param, sci_msg_t **msg, void *data) { uint tei; uint lid; uint bcast; uint mme; uint length; u8 *buffer; mfs_tx_t *mfs; tei = 0; lid = 0; bcast = 0; mme = 0; length = 0; fcall_param_bind_short (*param, *msg, "tei", &tei); fcall_param_bind_short (*param, *msg, "lid", &lid); fcall_param_bind_short (*param, *msg, "bcast", &bcast); fcall_param_bind_short (*param, *msg, "mme", &mme); fcall_param_bind_short (*param, *msg, "length", &length); buffer = (u8 *) malloc (length * sizeof (length)); fcall_param_bind (*param, *msg, "buffer", length * sizeof(u8), buffer); mfs = mac_store_mfs_get_tx (station_test.mac_store, bcast, mme, lid, tei); dbg_assert (mfs); sar_msdu_add (station_test.sar, buffer, length, mac_ntb(), mfs); blk_release (mfs); fcall_param_reset (*param); return true; } /** * Provide to the STA using the parameters of the function call the station * use for the test. Each STA shall known the TEI of the others present in the * AVLN. * * The function call parameters must be * - qte the quantity of TEIs present in the paramters. One for each STA * without this one. * - tei The list of TEIs. * - mac the list of mac address. * * This will be use to add the STA's to the mac store, the STA will keep a * list of theses TEI to remove the STA during the uninit procedure. * * * \param fcall the fcall context. * \param param the fcall param * \param msg the message * \param data anything */ int fc_station_discover (fcall_ctx_t *fcall, fcall_param_t **param, sci_msg_t **msg, void *data) { uint tei[256]; mac_t macs[256]; uint qte; char val [2]; char id[5]; uint count; uint error; qte = 0; fcall_param_bind_short (*param, *msg, "qte", &qte); count = 0; error = 0; for (count = 0; count < qte; count ++) { tei[count] = 0; macs[count] = 0; sprintf (val, "%d", count); strcpy (id, "tei"); strcat (id, val); fcall_param_bind_short (*param, *msg, id, &tei[count]); } station_test_discover (&station_test, tei, qte); fcall_param_reset (*param); return true; } /** * print the sar traces for the tests. * if the trace_config == y the traces are printed to the stdio. * otherwise nothing is printed. * * \param fcall the fcall context. * \param param the fcall param * \param msg the message * \param data anything */ int fc_sar_print_trace (fcall_ctx_t *fcall, fcall_param_t **param, sci_msg_t **msg, void *data) { fcall_param_reset (*param); sar_trace_print (station_test.sar); return true; } // ---------------------------- Stub functions ---------------------------- /** * CE measurements. To be replace by the CE function to get the measurements * * Pb measurement RX callback for Channel estimation. * This call back will return one or two block in order to insert all the * measurements contained in each PB of the mpdu received. * Two cases can happen, the first the pb_nb is lesser than the blk capacity, * this callback will return only a blk pointed by the first and the last * pointer. * In the second case the quantity of PB are greater than one blk capacity, this * callback will return two blk (chained) the first pointed by the first pointer * and the last one by the last pointer. * * \param user User data * \param rx_params Frame control information to know date and tonemap used * \param number of pbs * \param first blk to insert the measurements. * \param last blk to insert the measurements. * \param chandata chan data measurements * * \return boolean to indicate if a block had been returned or not. */ bool ce_measurements (void *user, pbproc_rx_params_t *rx_params, uint pb_nb, blk_t **first, blk_t **last, pb_t *chandata, uint nb_chandata, uint *blk_offset) { ce_rx_params_node_t *ce_node; *first = NULL; *last = NULL; dbg_assert (rx_params); ce_node = blk_alloc (); list_init_node (&ce_node->node); list_push (&ce_rx_params_list, &ce_node->node); ce_node->rx_params = rx_params; rx_params->eks = 0x0; if (chandata) { blk_release (chandata); } return false; } /** * CP receives a new MME. * \param user_data the data registered by the actor in the init function. * \param mfs the mfs * \param buffer the buffer containing the MME. * \param length the MME length * \param mme_recv data use by the data plane. * \param encryption inform if the packet comes from the PWL if it had been * crypted or not. */ void cp_mme_recv (void *user_data, mfs_rx_t *mfs, u8 *buffer, uint length, void *mme_recv, bool encryption) { printf ("/*************************************************/\n"); printf ("/ STATION : %d Receive a MME **********/\n", station_test.mac_config.tei); printf ("/ MME length : %d **********/\n", length); printf ("/ MME encrypted : %d **********/\n", encryption); printf ("/*************************************************/\n"); } /** * CP receives a beacon. * \param user_data the data registered by the actor in the init function. * \param beacon the beacon freshly received. */ void cp_beacon_add (void *user_data, pb_beacon_t *beacon) { printf ("/*************************************************/\n"); printf ("/ STATION : %d Receive a beacon ********/\n", station_test.mac_config.tei); printf ("/*************************************************/\n"); // release the beacon. blk_release_desc ((blk_t *) beacon); } // ------------------------------------------------------------------------- /** Cesar init function as described in the wiki * http://pessac/cesar/trac/wiki/20071128Cesar#LEONcore */ void cesar_init (void) { // Initialise the trace system. trace_init (); // Initialise the mac_store. station_test.mac_store = mac_store_init (); // Initialise the mac config. mac_config_init (&station_test.mac_config); // Intialise the pbproc. station_test.pbproc = pbproc_init (&station_test.mac_config, station_test.mac_store); // Initialise the mac ntb. mac_ntb_init (pbproc_get_phy(station_test.pbproc), &station_test.mac_config); // Initialise the SAR. station_test.sar = sar_init (station_test.mac_store, station_test.pbproc, pbproc_get_ca (station_test.pbproc)); // init the variables of the station. station_test.pbproc_activate = false; station_test.sched_index = 0; } /* ---------------------- Main function -------------------*/ int cyg_user_start (void) { cesar_init (); station_log_set_level(&my_station, STATION_LOG_DEBUG); my_station.pipe_log_fd = 1; list_init (&ce_rx_params_list); fcall_register (my_station.fcall, "fc_station_link_add", &fc_station_link_add, NULL); fcall_register (my_station.fcall, "fc_station_link_remove", &fc_station_link_remove, NULL); fcall_register (my_station.fcall, "fc_station_init_config", &fc_station_init_config, NULL); fcall_register (my_station.fcall, "fc_sar_data_buffer_add", &fc_sar_data_buffer_add, NULL); fcall_register (my_station.fcall, "fc_sar_mme_buffer_add", &fc_sar_data_buffer_add, NULL); fcall_register (my_station.fcall, "fc_sar_msdu_add", &fc_sar_msdu_add, NULL); fcall_register (my_station.fcall, "fc_station_discover", &fc_station_discover, NULL); fcall_register (my_station.fcall, "fc_add_mme_link", &fc_add_mme_link , NULL); fcall_register (my_station.fcall, "fc_station_config", &fc_station_config, NULL); fcall_register (my_station.fcall, "fc_station_start", &fc_station_start, NULL); fcall_register (my_station.fcall, "fc_sar_print_trace", &fc_sar_print_trace, NULL); sar_init_data_context (station_test.sar, station_test.sar); sar_init_mme_context (station_test.sar, station_test.sar); sar_init_segmentation_data_cb (station_test.sar, sar_segmentation_ul_done); sar_init_reassembly_ul (station_test.sar, sar_reassembly_ul_done, true); sar_init_reassembly_ul (station_test.sar, sar_reassembly_ul_done, false); sar_init_measure_context (station_test.sar, &station_test.sar); sar_init_measurement_cb (station_test.sar, ce_measurements); return 0; }