/* * Copyright (C) 2015 Freie Universität Berlin * * 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. */ /** * @{ * @ingroup net_gnrc_netapi * @file * @brief This file contains a number of helper functions that provide * some shortcuts for some always repeating code snippets when * servicing the netapi interface * * @author Hauke Petersen * @} */ #include "mbox.h" #include "msg.h" #include "net/gnrc/netreg.h" #include "net/gnrc/pktbuf.h" #include "net/gnrc/netapi.h" #define ENABLE_DEBUG (0) #include "debug.h" /** * @brief Unified function for getting and setting netapi options * * @param[in] pid PID of the targeted thread * @param[in] type specify if option is to be set or get * @param[in] opt option to set or get * @param[in] data data to set or pointer to buffer for reading options * @param[in] data_len size of the given buffer * * @return the value from the received ACK message */ static inline int _get_set(kernel_pid_t pid, uint16_t type, netopt_t opt, uint16_t context, void *data, size_t data_len) { msg_t cmd; msg_t ack; gnrc_netapi_opt_t o; /* set netapi's option struct */ o.opt = opt; o.context = context; o.data = data; o.data_len = data_len; /* set outgoing message's fields */ cmd.type = type; cmd.content.ptr = (void *)&o; /* trigger the netapi */ msg_send_receive(&cmd, &ack, pid); assert(ack.type == GNRC_NETAPI_MSG_TYPE_ACK); /* return the ACK message's value */ return (int)ack.content.value; } static inline int _snd_rcv(kernel_pid_t pid, uint16_t type, gnrc_pktsnip_t *pkt) { msg_t msg; /* set the outgoing message's fields */ msg.type = type; msg.content.ptr = (void *)pkt; /* send message */ int ret = msg_try_send(&msg, pid); if (ret < 1) { DEBUG("gnrc_netapi: dropped message to %" PRIkernel_pid " (%s)\n", pid, (ret == 0) ? "receiver queue is full" : "invalid receiver"); } return ret; } #ifdef MODULE_GNRC_NETAPI_MBOX static inline int _snd_rcv_mbox(mbox_t *mbox, uint16_t type, gnrc_pktsnip_t *pkt) { msg_t msg; /* set the outgoing message's fields */ msg.type = type; msg.content.ptr = (void *)pkt; /* send message */ int ret = mbox_try_put(mbox, &msg); if (ret < 1) { DEBUG("gnrc_netapi: dropped message to %p (was full)\n", mbox); } return ret; } #endif int gnrc_netapi_dispatch(gnrc_nettype_t type, uint32_t demux_ctx, uint16_t cmd, gnrc_pktsnip_t *pkt) { int numof = gnrc_netreg_num(type, demux_ctx); if (numof != 0) { gnrc_netreg_entry_t *sendto = gnrc_netreg_lookup(type, demux_ctx); gnrc_pktbuf_hold(pkt, numof - 1); while (sendto) { #if defined(MODULE_GNRC_NETAPI_MBOX) || defined(MODULE_GNRC_NETAPI_CALLBACKS) int release = 0; switch (sendto->type) { case GNRC_NETREG_TYPE_DEFAULT: if (_snd_rcv(sendto->target.pid, cmd, pkt) < 1) { /* unable to dispatch packet */ release = 1; } break; #ifdef MODULE_GNRC_NETAPI_MBOX case GNRC_NETREG_TYPE_MBOX: if (_snd_rcv_mbox(sendto->target.mbox, cmd, pkt) < 1) { /* unable to dispatch packet */ release = 1; } break; #endif #ifdef MODULE_GNRC_NETAPI_CALLBACKS case GNRC_NETREG_TYPE_CB: sendto->target.cbd->cb(cmd, pkt, sendto->target.cbd->ctx); break; #endif default: /* unknown dispatch type */ release = 1; break; } if (release) { gnrc_pktbuf_release(pkt); } #else if (_snd_rcv(sendto->target.pid, cmd, pkt) < 1) { /* unable to dispatch packet */ gnrc_pktbuf_release(pkt); } #endif sendto = gnrc_netreg_getnext(sendto); } } return numof; } int gnrc_netapi_send(kernel_pid_t pid, gnrc_pktsnip_t *pkt) { return _snd_rcv(pid, GNRC_NETAPI_MSG_TYPE_SND, pkt); } int gnrc_netapi_receive(kernel_pid_t pid, gnrc_pktsnip_t *pkt) { return _snd_rcv(pid, GNRC_NETAPI_MSG_TYPE_RCV, pkt); } int gnrc_netapi_get(kernel_pid_t pid, netopt_t opt, uint16_t context, void *data, size_t data_len) { return _get_set(pid, GNRC_NETAPI_MSG_TYPE_GET, opt, context, data, data_len); } int gnrc_netapi_set(kernel_pid_t pid, netopt_t opt, uint16_t context, void *data, size_t data_len) { return _get_set(pid, GNRC_NETAPI_MSG_TYPE_SET, opt, context, data, data_len); }