diff --git a/Makefile.dep b/Makefile.dep index 48fa8002dd36943544aae314277bcfd9552098be..a7531a3231f852f5c356c92edaad7ed9a6d0ccaf 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -184,6 +184,13 @@ ifneq (,$(filter ng_udp,$(USEMODULE))) USEMODULE += ng_inet_csum endif +ifneq (,$(filter ng_nettest,$(USEMODULE))) + USEMODULE += ng_netapi + USEMODULE += ng_netreg + USEMODULE += ng_netif + USEMODULE += ng_pktbuf +endif + ifneq (,$(filter ng_netbase,$(USEMODULE))) USEMODULE += ng_netapi USEMODULE += ng_netreg diff --git a/sys/Makefile b/sys/Makefile index e815e4cb87fcfb78b75d1d85346c25ad0f587f5b..35fb3f01680bf919623bab56b3be726132cd16f7 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -107,6 +107,9 @@ endif ifneq (,$(filter ng_netreg,$(USEMODULE))) DIRS += net/crosslayer/ng_netreg endif +ifneq (,$(filter ng_nettest,$(USEMODULE))) + DIRS += net/crosslayer/ng_nettest +endif ifneq (,$(filter ng_nomac,$(USEMODULE))) DIRS += net/link_layer/ng_nomac endif diff --git a/sys/include/net/ng_nettest.h b/sys/include/net/ng_nettest.h new file mode 100644 index 0000000000000000000000000000000000000000..05f837066b5a8f4e404a200d2426bc5870c27592 --- /dev/null +++ b/sys/include/net/ng_nettest.h @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup net_ng_nettest NETAPI test framework + * @ingroup net_ng_netapi + * @brief This provides a framework to test the @ref net_ng_netapi IPC + * calls. + * @{ + * + * @file + * @brief Definitions for the @ref net_ng_netapi test framework + * + * @author Martine Lenders <mlenders@inf.fu-berlin.de> + */ +#ifndef NG_NETTEST_H_ +#define NG_NETTEST_H_ + +#include <stdint.h> +#include <stdlib.h> + +#include "kernel_types.h" +#include "net/ng_netapi.h" +#include "net/ng_netconf.h" +#include "net/ng_nettype.h" +#include "net/ng_pkt.h" +#include "thread.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Timeout for tests in microseconds + */ +#ifndef NG_NETTEST_TIMEOUT +#define NG_NETTEST_TIMEOUT (1000) +#endif + +/** + * @brief Default stack size to use for the nettest thread + */ +#ifndef NG_NETTEST_STACK_SIZE +#define NG_NETTEST_STACK_SIZE (THREAD_STACKSIZE_DEFAULT) +#endif + +/** + * @brief Default priority for the nettest thread + */ +#ifndef NG_NETTEST_PRIO +#define NG_NETTEST_PRIO (THREAD_PRIORITY_MAIN) +#endif + +/** + * @brief Default message queue size to use for the nettest thread. + */ +#ifndef NG_NETTEST_MSG_QUEUE_SIZE +#define NG_NETTEST_MSG_QUEUE_SIZE (8U) +#endif + + +/** + * @brief Type for get/set callbacks. + * + * @param[in] context (Optional) context for the option. + * Compare ng_netapi_opt_t::context. + * @param[in,out] data Data to set or buffer to read into. + * Compare ng_netapi_opt_t::data. + * @param[in] data_len Size of the data / the buffer. + * Compare ng_netapi_opt_t::data_len + * + * @return The value for the @ref NG_NETAPI_MSG_TYPE_ACK message. + */ +typedef int (*ng_nettest_opt_cb_t)(uint16_t context, void *data, uint16_t data_len); + +/** + * @brief Option callback list element. + */ +typedef struct { + ng_nettest_opt_cb_t get; /**< getter for an option */ + ng_nettest_opt_cb_t set; /**< setter for an option */ +} ng_nettest_opt_cbs_t; + +/** + * @brief Result type for tests. + */ +typedef enum { + NG_NETTEST_SUCCESS = 0, /**< test was successful */ + NG_NETTEST_FAIL, /**< test failed */ + NG_NETTEST_TIMED_OUT, /**< test timed out */ + NG_NETTEST_WRONG_MSG, /**< wrong message type received */ + NG_NETTEST_WRONG_SENDER, /**< wrong message type received */ +} ng_nettest_res_t; + +/** + * @brief Registers a getter for an option. + * + * @details Overrides previous registrations. + * + * @param[in] opt The option to register the getter for. + * @param[in] cb An option getter. NULL to delete. + */ +void ng_nettest_register_get(ng_netconf_opt_t opt, ng_nettest_opt_cb_t cb); + +/** + * @brief Registers a setter for an option. + * + * @details Overrides previous registrations. + * + * @param[in] opt The option to register the setter for. + * @param[in] cb An option setter. NULL to delete. + */ +void ng_nettest_register_set(ng_netconf_opt_t opt, ng_nettest_opt_cb_t cb); + +/** + * @brief Test @ref NG_NETAPI_MSG_TYPE_SND command to @p pid. + * + * @details This registered the nettest thread to (@p exp_type, @p exp_demux_ctx) + * and checks if @p exp_pkts of @p exp_out were received from @p exp_senders. + * If no message was received after @ref NG_NETTEST_TIMEOUT microseconds, while + * there are still packets expected, the function will return NG_NETTEST_TIMED_OUT. + * + * @param[in] pid The thread you want to test the + * @ref NG_NETAPI_MSG_TYPE_SND command for. + * @param[in] in The packet you want to send through @p pid. + * @param[in] exp_pkts The number of packets expected to be received. + * @param[in] exp_senders The PID the resulting packet should be coming from. + * Must be of dimension @p exp_pkts. + * @param[in] exp_out The expected packet from @p exp_sender. + * Must be of dimension @p exp_pkts. + * @param[in] exp_type The expected receiver type for the + * @ref NG_NETAPI_MSG_TYPE_SND command. + * @param[in] exp_demux_ctx The expected receiver demux type for the + * @ref NG_NETAPI_MSG_TYPE_SND command. + * + * @return @see ng_nettest_res_t + */ +ng_nettest_res_t ng_nettest_send(kernel_pid_t pid, ng_pktsnip_t *in, + unsigned int exp_pkts, kernel_pid_t exp_senders[], + ng_pktsnip_t *exp_out[], ng_nettype_t exp_type, + uint32_t exp_demux_ctx); + +/** + * @brief Test @ref NG_NETAPI_MSG_TYPE_SND command to @p pid with the receiving + * thread being an interface. + * + * @details This registered the nettest thread as an interface and checks ifx + * @p exp_pkts of @p exp_out were received from @p exp_senders. If no message + * was received after @ref NG_NETTEST_TIMEOUT microseconds, while there are + * still packets expected, the function will return NG_NETTEST_TIMED_OUT. + * + * @param[in] pid The thread you want to test the + * @ref NG_NETAPI_MSG_TYPE_SND command for. + * @param[in] in The packet you want to send through @p pid. + * @param[in] exp_pkts The number of packets expected to be received. + * @param[in] exp_senders The PID the resulting packet should be coming from. + * Must be of dimension @p exp_pkts. + * @param[in] exp_out The expected packet from @p exp_sender. + * Must be of dimension @p exp_pkts. + * + * @return @see ng_nettest_res_t + */ +ng_nettest_res_t ng_nettest_send_iface(kernel_pid_t pid, ng_pktsnip_t *in, + unsigned int exp_pkts, + kernel_pid_t exp_senders[], + ng_pktsnip_t *exp_out[]); + +/** + * @brief Test @ref NG_NETAPI_MSG_TYPE_RCV command to @p pid. + * + * @details This registered the nettest thread to (@p exp_type, @p exp_demux_ctx) + * and checks if @p exp_pkts of @p exp_out were received from @p exp_senders. + * If no message was received after @ref NG_NETTEST_TIMEOUT microseconds, while + * there are still packets expected, the function will return NG_NETTEST_TIMED_OUT. + * + * @param[in] pid The thread you want to test the + * @ref NG_NETAPI_MSG_TYPE_RCV command for. + * @param[in] in The packet you want to send through @p pid. + * @param[in] exp_pkts The number of packets expected to be received. + * @param[in] exp_senders The PID the resulting packet should be coming from. + * Must be of dimension @p exp_pkts. + * @param[in] exp_out The expected packet from @p exp_sender. + * Must be of dimension @p exp_pkts. + * @param[in] exp_type The expected receiver type for the + * @ref NG_NETAPI_MSG_TYPE_RCV command. + * @param[in] exp_demux_ctx The expected receiver demux type for the + * @ref NG_NETAPI_MSG_TYPE_RCV command. + * + * @return @see ng_nettest_res_t + */ +ng_nettest_res_t ng_nettest_receive(kernel_pid_t pid, ng_pktsnip_t *in, + unsigned int exp_pkts, kernel_pid_t exp_senders[], + ng_pktsnip_t *exp_out[], ng_nettype_t exp_type, + uint32_t exp_demux_ctx); + +/** + * @brief Test @ref NG_NETAPI_MSG_TYPE_GET command to @p pid. + * + * @param[in] pid The thread you want to test the + * @ref NG_NETAPI_MSG_TYPE_GET command for. + * @param[in] opt The option you want to test. + * @param[in] context The context for the option. + * @param[in] data The data pointer for the @ref NG_NETAPI_MSG_TYPE_GET + * command. + * @param[in] data_len The maximum length for @p data. + * @param[in] exp_data The expected value for the returned data. May be + * NULL if @p exp_res < 0 + * @param[in] exp_res The expected return value for the + * @ref NG_NETAPI_MSG_TYPE_GET command. + * + * @return @see ng_nettest_res_t + */ +ng_nettest_res_t ng_nettest_get(kernel_pid_t pid, ng_netconf_opt_t opt, + uint16_t context, void *data, size_t data_len, + void *exp_data, int exp_res); + +/** + * @brief Test @ref NG_NETAPI_MSG_TYPE_SET command to @p pid. + * + * @param[in] pid The thread you want to test the + * @ref NG_NETAPI_MSG_TYPE_SET command for. + * @param[in] opt The option you want to test. + * @param[in] context The context for the option. + * @param[in] data The data pointer for the @ref NG_NETAPI_MSG_TYPE_SET + * command. + * @param[in] data_len The maximum length for @p data. + * @param[in] exp_res The expected return value for the + * @ref NG_NETAPI_MSG_TYPE_SET command. + * + * @return @see ng_nettest_res_t + */ +ng_nettest_res_t ng_nettest_set(kernel_pid_t pid, ng_netconf_opt_t opt, + uint16_t context, void *data, size_t data_len, + int exp_res); + +/** + * @brief Initializes the @ref net_ng_nettest module. + * + * @return The PID to the nettest thread, on success. + * @return a negative errno on error. + * @return -EOVERFLOW, if there are too many threads running already + */ +int ng_nettest_init(void); + +/** + * @brief Resets ng_nettest_opt_cbs_t list. + */ +void ng_nettest_reset(void); + +#ifdef __cplusplus +} +#endif + +#endif /* NG_NETTEST_H_ */ +/** @} */ diff --git a/sys/net/crosslayer/ng_nettest/Makefile b/sys/net/crosslayer/ng_nettest/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..48422e909a47d7cd428d10fa73825060ccc8d8c2 --- /dev/null +++ b/sys/net/crosslayer/ng_nettest/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/crosslayer/ng_nettest/ng_nettest.c b/sys/net/crosslayer/ng_nettest/ng_nettest.c new file mode 100644 index 0000000000000000000000000000000000000000..2fcf19fb6d3ede79a55f839adc1ec523cf07c4b3 --- /dev/null +++ b/sys/net/crosslayer/ng_nettest/ng_nettest.c @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * + * @file + */ + +#include <errno.h> +#include <string.h> + +#include "msg.h" +#include "mutex.h" +#include "net/ng_netapi.h" +#include "net/ng_netif.h" +#include "net/ng_netconf.h" +#include "net/ng_netreg.h" +#include "net/ng_pktbuf.h" +#include "timex.h" +#include "thread.h" +#include "vtimer.h" + +#include "net/ng_nettest.h" + +static ng_nettest_opt_cbs_t _opt_cbs[NETCONF_OPT_NUMOF]; +static mutex_t _mutex = MUTEX_INIT; +static kernel_pid_t _pid = KERNEL_PID_UNDEF; +static char _stack[NG_NETTEST_STACK_SIZE]; + +static void *_event_loop(void *arg); + +void ng_nettest_register_get(ng_netconf_opt_t opt, ng_nettest_opt_cb_t cb) +{ + mutex_lock(&_mutex); + _opt_cbs[opt].get = cb; + mutex_unlock(&_mutex); +} + +void ng_nettest_register_set(ng_netconf_opt_t opt, ng_nettest_opt_cb_t cb) +{ + mutex_lock(&_mutex); + _opt_cbs[opt].set = cb; + mutex_unlock(&_mutex); +} + +static ng_nettest_res_t _pkt_test(uint16_t cmd_type, kernel_pid_t pid, ng_pktsnip_t *in, + unsigned int exp_pkts, kernel_pid_t exp_senders[], + ng_pktsnip_t *exp_out[]) +{ + msg_t msg; + timex_t t = { 0, NG_NETTEST_TIMEOUT }; + ng_nettest_res_t res = NG_NETTEST_SUCCESS; + + msg.type = cmd_type; + msg.content.ptr = (char *)in; + + msg_send(&msg, pid); + + for (unsigned int i = 0; i < exp_pkts; i++) { + ng_pktsnip_t *out; + + if ((vtimer_msg_receive_timeout(&msg, t) < 0) && res == NG_NETTEST_SUCCESS) { + res = NG_NETTEST_TIMED_OUT; + } + + if (msg.type != NG_NETAPI_MSG_TYPE_SND && (res == NG_NETTEST_SUCCESS)) { + res = NG_NETTEST_WRONG_MSG; + } + + if (msg.sender_pid != exp_senders[i] && (res == NG_NETTEST_SUCCESS)) { + res = NG_NETTEST_WRONG_SENDER; + } + + out = (ng_pktsnip_t *)msg.content.ptr; + + if ((out == NULL) && (res == NG_NETTEST_SUCCESS)) { + res = NG_NETTEST_FAIL; + } + + while (out) { + if ((res == NG_NETTEST_SUCCESS) && + ((out->users != exp_out[i]->users) || + (out->size != exp_out[i]->size) || + (out->type != exp_out[i]->type) || + (memcmp(out->data, exp_out[i]->data, out->size) != 0))) { + res = NG_NETTEST_FAIL; + } + + out = out->next; + } + + ng_pktbuf_release((ng_pktsnip_t *)msg.content.ptr); + } + + return res; +} + +ng_nettest_res_t ng_nettest_send(kernel_pid_t pid, ng_pktsnip_t *in, + unsigned int exp_pkts, kernel_pid_t exp_senders[], + ng_pktsnip_t *exp_out[], ng_nettype_t exp_type, + uint32_t exp_demux_ctx) +{ + ng_netreg_entry_t reg_entry = { NULL, exp_demux_ctx, thread_getpid() }; + ng_nettest_res_t res; + + ng_netreg_register(exp_type, ®_entry); + + res = _pkt_test(NG_NETAPI_MSG_TYPE_SND, pid, in, exp_pkts, exp_senders, + exp_out); + + ng_netreg_unregister(exp_type, ®_entry); + + return res; +} + +ng_nettest_res_t ng_nettest_send_iface(kernel_pid_t pid, ng_pktsnip_t *in, + unsigned int exp_pkts, + kernel_pid_t exp_senders[], + ng_pktsnip_t *exp_out[]) +{ + ng_nettest_res_t res; + + ng_netif_add(thread_getpid()); + + res = _pkt_test(NG_NETAPI_MSG_TYPE_SND, pid, in, exp_pkts, exp_senders, + exp_out); + + ng_netif_remove(thread_getpid()); + + return res; +} + +ng_nettest_res_t ng_nettest_receive(kernel_pid_t pid, ng_pktsnip_t *in, + unsigned int exp_pkts, kernel_pid_t exp_senders[], + ng_pktsnip_t *exp_out[], ng_nettype_t exp_type, + uint32_t exp_demux_ctx) +{ + ng_netreg_entry_t reg_entry = { NULL, exp_demux_ctx, thread_getpid() }; + ng_nettest_res_t res; + + ng_netreg_register(exp_type, ®_entry); + + res = _pkt_test(NG_NETAPI_MSG_TYPE_RCV, pid, in, exp_pkts, exp_senders, + exp_out); + + ng_netreg_unregister(exp_type, ®_entry); + + return res; +} + +ng_nettest_res_t ng_nettest_get(kernel_pid_t pid, ng_netconf_opt_t opt, + uint16_t context, void *data, size_t data_len, + void *exp_data, int exp_res) +{ + if ((exp_res != ng_netapi_get(pid, opt, context, data, data_len)) || + ((exp_res > 0) && (memcpy(exp_data, data, exp_res)))) { + return NG_NETTEST_FAIL; + } + + return NG_NETTEST_SUCCESS; +} + +ng_nettest_res_t ng_nettest_set(kernel_pid_t pid, ng_netconf_opt_t opt, + uint16_t context, void *data, size_t data_len, + int exp_res) +{ + if (exp_res != ng_netapi_get(pid, opt, context, data, data_len)) { + return NG_NETTEST_FAIL; + } + + return NG_NETTEST_SUCCESS; +} + +int ng_nettest_init(void) +{ + if (_pid <= KERNEL_PID_UNDEF) { + _pid = thread_create(_stack, sizeof(_stack), NG_NETTEST_PRIO, + CREATE_STACKTEST, _event_loop, NULL, "nettest"); + } + + return _pid; +} + +void ng_nettest_reset(void) +{ + for (int i = 0; i < NETCONF_OPT_NUMOF; i++) { + _opt_cbs[i].get = NULL; + _opt_cbs[i].set = NULL; + } +} + +static inline uint32_t _get_set_opt(ng_nettest_opt_cb_t cb, uint16_t context, + void *data, uint16_t data_len) +{ + int res; + + mutex_lock(&_mutex); + if (cb != NULL) { + res = cb(context, data, data_len); + } + else { + res = -ENOTSUP; + } + mutex_unlock(&_mutex); + return (uint32_t)res; +} + +static void *_event_loop(void *arg) +{ + msg_t reply, msg_queue[NG_NETTEST_MSG_QUEUE_SIZE]; + + (void)arg; + msg_init_queue(msg_queue, NG_NETTEST_MSG_QUEUE_SIZE); + reply.type = NG_NETAPI_MSG_TYPE_ACK; + + while (1) { + msg_t msg; + ng_netapi_opt_t *opt; + + msg_receive(&msg); + + switch (msg.type) { + case NG_NETAPI_MSG_TYPE_GET: + opt = (ng_netapi_opt_t *)msg.content.ptr; + reply.content.value = _get_set_opt(_opt_cbs[opt->opt].get, + opt->context, opt->data, + opt->data_len); + break; + + case NG_NETAPI_MSG_TYPE_SET: + opt = (ng_netapi_opt_t *)msg.content.ptr; + reply.content.value = _get_set_opt(_opt_cbs[opt->opt].set, + opt->context, opt->data, + opt->data_len); + break; + } + + msg_reply(&msg, &reply); + } + + return NULL; +} + +/** @} */