mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-18 09:52:45 +01:00
276ad5716a
A if `netdev_driver_t::confirm_send()` is provided, it provides the new netdev API. However, detecting the API at runtime and handling both API styles comes at a cost. This can be optimized in case only new or only old style netdevs are in use. To do so, this adds the pseudo modules `netdev_legacy_api` and `netdev_new_api`. As right now no netdev actually implements the new API, all netdevs pull in `netdev_legacy_api`. If `netdev_legacy_api` is in used but `netdev_new_api` is not, we can safely assume at compile time that only legacy netdevs are in use. Similar, if only `netdev_new_api` is used, only support for the new API is needed. Only when both are in use, run time checks are needed. This provides two helper function to check for a netif if the corresponding netdev implements the old or the new API. (With one being the inverse of the other.) They are suitable for constant folding when only new or only legacy devices are in use. Consequently, dead branches should be eliminated by the optimizer.
739 lines
25 KiB
C
739 lines
25 KiB
C
/*
|
|
* Copyright (C) 2017-20 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.
|
|
*/
|
|
|
|
/**
|
|
* @defgroup net_gnrc_netif Network interface API
|
|
* @ingroup net_gnrc
|
|
* @brief Abstraction layer for GNRC's network interfaces
|
|
*
|
|
* Network interfaces in the context of GNRC are threads for protocols that are
|
|
* below the network layer.
|
|
*
|
|
* ## Single interface optimizations
|
|
*
|
|
* If you only have one network interface on the board, you can select the
|
|
* `gnrc_netif_single` pseudo-module to enable further optimisations.
|
|
*
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief Definition for GNRC's network interfaces
|
|
*
|
|
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
|
*/
|
|
#ifndef NET_GNRC_NETIF_H
|
|
#define NET_GNRC_NETIF_H
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
|
|
#include "sched.h"
|
|
#include "msg.h"
|
|
#ifdef MODULE_GNRC_NETIF_BUS
|
|
#include "msg_bus.h"
|
|
#endif
|
|
#include "event.h"
|
|
#include "net/ipv6/addr.h"
|
|
#include "net/gnrc/netapi.h"
|
|
#include "net/gnrc/pkt.h"
|
|
#include "net/gnrc/netif/conf.h"
|
|
#if IS_USED(MODULE_GNRC_NETIF_LORAWAN)
|
|
#include "net/gnrc/netif/lorawan.h"
|
|
#endif
|
|
#if IS_USED(MODULE_GNRC_NETIF_6LO)
|
|
#include "net/gnrc/netif/6lo.h"
|
|
#endif
|
|
#if defined(MODULE_GNRC_NETIF_DEDUP) && (GNRC_NETIF_L2ADDR_MAXLEN > 0)
|
|
#include "net/gnrc/netif/dedup.h"
|
|
#endif
|
|
#include "net/gnrc/netif/flags.h"
|
|
#if IS_USED(MODULE_GNRC_NETIF_IPV6)
|
|
#include "net/gnrc/netif/ipv6.h"
|
|
#endif
|
|
#if IS_USED(MODULE_GNRC_NETIF_MAC)
|
|
#include "net/gnrc/netif/mac.h"
|
|
#endif
|
|
#if IS_USED(MODULE_GNRC_NETIF_PKTQ)
|
|
#include "net/gnrc/netif/pktq/type.h"
|
|
#endif
|
|
#include "net/l2util.h"
|
|
#include "net/ndp.h"
|
|
#include "net/netdev.h"
|
|
#include "net/netopt.h"
|
|
#ifdef MODULE_NETSTATS_L2
|
|
#include "net/netstats.h"
|
|
#endif
|
|
#include "rmutex.h"
|
|
#include "net/netif.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
* @brief Per-Interface Event Message Buses
|
|
*/
|
|
typedef enum {
|
|
#ifdef MODULE_GNRC_IPV6
|
|
GNRC_NETIF_BUS_IPV6, /**< provides @ref gnrc_ipv6_event_t
|
|
messages to subscribers */
|
|
#endif
|
|
GNRC_NETIF_BUS_NUMOF
|
|
} gnrc_netif_bus_t;
|
|
|
|
/**
|
|
* @brief Event types for GNRC_NETIF_BUS_IPV6 per-interface message bus
|
|
*/
|
|
typedef enum {
|
|
/**
|
|
* @brief Address becomes valid
|
|
*
|
|
* The event is generated when an address on the interface becomes valid.
|
|
* The message payload contains a pointer to the respective
|
|
* @ref ipv6_addr_t struct.
|
|
*
|
|
* @note If the address on the interface changed between sending
|
|
* the event and processing it, the pointer will point to the new address
|
|
* which might *not* be valid.
|
|
*/
|
|
GNRC_IPV6_EVENT_ADDR_VALID,
|
|
} gnrc_ipv6_event_t;
|
|
|
|
/**
|
|
* @brief Operations to an interface
|
|
*/
|
|
typedef struct gnrc_netif_ops gnrc_netif_ops_t;
|
|
|
|
/**
|
|
* @brief Representation of a network interface
|
|
*/
|
|
typedef struct {
|
|
netif_t netif; /**< network interface descriptor */
|
|
const gnrc_netif_ops_t *ops; /**< Operations of the network interface */
|
|
netdev_t *dev; /**< Network device of the network interface */
|
|
rmutex_t mutex; /**< Mutex of the interface */
|
|
#ifdef MODULE_NETSTATS_L2
|
|
netstats_t stats; /**< transceiver's statistics */
|
|
#endif
|
|
#if IS_USED(MODULE_GNRC_NETIF_LORAWAN) || defined(DOXYGEN)
|
|
gnrc_netif_lorawan_t lorawan; /**< LoRaWAN component */
|
|
#endif
|
|
#if IS_USED(MODULE_GNRC_NETIF_IPV6) || defined(DOXYGEN)
|
|
gnrc_netif_ipv6_t ipv6; /**< IPv6 component */
|
|
#endif
|
|
#if IS_USED(MODULE_GNRC_NETIF_MAC) || defined(DOXYGEN)
|
|
gnrc_netif_mac_t mac; /**< @ref net_gnrc_mac component */
|
|
#endif /* IS_USED(MODULE_GNRC_NETIF_MAC) || defined(DOXYGEN) */
|
|
#if IS_USED(MODULE_GNRC_NETIF_BUS) || DOXYGEN
|
|
msg_bus_t bus[GNRC_NETIF_BUS_NUMOF]; /**< Event Message Bus */
|
|
#endif
|
|
/**
|
|
* @brief Flags for the interface
|
|
*
|
|
* @see net_gnrc_netif_flags
|
|
*/
|
|
uint32_t flags;
|
|
/**
|
|
* @brief Event queue for asynchronous events
|
|
*/
|
|
event_queue_t evq;
|
|
/**
|
|
* @brief ISR event for the network device
|
|
*/
|
|
event_t event_isr;
|
|
#if (GNRC_NETIF_L2ADDR_MAXLEN > 0) || DOXYGEN
|
|
/**
|
|
* @brief The link-layer address currently used as the source address
|
|
* on this interface.
|
|
*
|
|
* @note Only available if @ref GNRC_NETIF_L2ADDR_MAXLEN > 0
|
|
*/
|
|
uint8_t l2addr[GNRC_NETIF_L2ADDR_MAXLEN];
|
|
|
|
/**
|
|
* @brief Length in bytes of gnrc_netif_t::l2addr
|
|
*
|
|
* @note Only available if @ref GNRC_NETIF_L2ADDR_MAXLEN > 0
|
|
*/
|
|
uint8_t l2addr_len;
|
|
#if defined(MODULE_GNRC_NETIF_DEDUP) || DOXYGEN
|
|
/**
|
|
* @brief Last received packet information
|
|
*
|
|
* @note Only available with @ref net_gnrc_netif_dedup.
|
|
*/
|
|
gnrc_netif_dedup_t last_pkt;
|
|
#endif
|
|
#endif
|
|
#if IS_USED(MODULE_GNRC_NETIF_6LO) || defined(DOXYGEN)
|
|
gnrc_netif_6lo_t sixlo; /**< 6Lo component */
|
|
#endif
|
|
#if IS_USED(MODULE_GNRC_NETIF_PKTQ) || defined(DOXYGEN)
|
|
/**
|
|
* @brief Packet queue for sending
|
|
*
|
|
* @note Only available with @ref net_gnrc_netif_pktq.
|
|
*/
|
|
gnrc_netif_pktq_t send_queue;
|
|
#endif
|
|
uint8_t cur_hl; /**< Current hop-limit for out-going packets */
|
|
uint8_t device_type; /**< Device type */
|
|
kernel_pid_t pid; /**< PID of the network interface's thread */
|
|
} gnrc_netif_t;
|
|
|
|
/**
|
|
* @brief Check if the device belonging to the given netif uses the legacy
|
|
* netdev API
|
|
*
|
|
* Check @ref netdev_driver_t::confirm_send for info about the old and new
|
|
* netdev API.
|
|
*
|
|
* netdevs using the legacy API have to depend on the (pseudo-)module
|
|
* netdev_legaqcy_api, netdevs using the new API have to depend on the
|
|
* (pseudo-)module netdev_new_api. If only one of the pseudo modules is used,
|
|
* this function can be constant folded. For boards mixing legacy and new API
|
|
* netdevs, this will check the flavor at runtime.
|
|
*
|
|
* @see netdev_driver_t::confirm_send
|
|
*/
|
|
static inline bool gnrc_netif_netdev_legacy_api(gnrc_netif_t *netif)
|
|
{
|
|
if (!IS_USED(MODULE_NETDEV_NEW_API) && !IS_USED(MODULE_NETDEV_LEGACY_API)) {
|
|
/* this should only happen for external netdevs or when no netdev is
|
|
* used (e.g. examples/gcoap can be used without any netdev, as still
|
|
* CoAP requests to ::1 can be send */
|
|
return true;
|
|
}
|
|
|
|
if (!IS_USED(MODULE_NETDEV_NEW_API)) {
|
|
return true;
|
|
}
|
|
|
|
if (!IS_USED(MODULE_NETDEV_LEGACY_API)) {
|
|
return false;
|
|
}
|
|
|
|
/* both legacy and new API netdevs in use, fall back to runtime test: */
|
|
return (netif->dev->driver->confirm_send == NULL);
|
|
}
|
|
|
|
/**
|
|
* @brief Check if the device belonging to the given netif uses the new
|
|
* netdev API
|
|
*
|
|
* @see gnrc_netif_netdev_legacy_api
|
|
*
|
|
* @see netdev_driver_t::confirm_send
|
|
*/
|
|
static inline bool gnrc_netif_netdev_new_api(gnrc_netif_t *netif)
|
|
{
|
|
return !gnrc_netif_netdev_legacy_api(netif);
|
|
}
|
|
|
|
/**
|
|
* @see gnrc_netif_ops_t
|
|
*/
|
|
struct gnrc_netif_ops {
|
|
/**
|
|
* @brief Initializes and registers network interface.
|
|
*
|
|
* @pre `netif != NULL`
|
|
*
|
|
* @param[in] netif The network interface.
|
|
*
|
|
* This function should init the device driver or MAC underlying MAC layer.
|
|
* This is called right before the interface's thread starts receiving
|
|
* messages. It is not necessary to lock the interface's mutex
|
|
* gnrc_netif_t::mutex, since it is already locked. Set to @ref
|
|
* gnrc_netif_default_init() if you do not need any special initialization.
|
|
* If you do need special initialization, it is recommended to call @ref
|
|
* gnrc_netif_default_init() at the start of the custom initialization
|
|
* function set here. This function MUST call @ref netif_register if the
|
|
* initialization is successful.
|
|
*
|
|
* @return 0 if the initialization of the device or MAC layer was
|
|
* successful
|
|
* @return negative errno on error.
|
|
*/
|
|
int (*init)(gnrc_netif_t *netif);
|
|
|
|
/**
|
|
* @brief Send a @ref net_gnrc_pkt "packet" over the network interface
|
|
*
|
|
* @pre `netif != NULL && pkt != NULL`
|
|
*
|
|
* @note The function re-formats the content of @p pkt to a format expected
|
|
* by the netdev_driver_t::send() method of gnrc_netif_t::dev and
|
|
* releases the packet before returning (so no additional release
|
|
* should be required after calling this method).
|
|
*
|
|
* @param[in] netif The network interface.
|
|
* @param[in] pkt A packet to send.
|
|
*
|
|
* @return The number of bytes actually sent on success
|
|
* @return -EBADMSG, if the @ref net_gnrc_netif_hdr in @p pkt is missing
|
|
* or is in an unexpected format.
|
|
* @return -ENOTSUP, if sending @p pkt in the given format isn't supported
|
|
* (e.g. empty payload with Ethernet).
|
|
* @return Any negative error code reported by gnrc_netif_t::dev.
|
|
*/
|
|
int (*send)(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt);
|
|
|
|
/**
|
|
* @brief Receives a @ref net_gnrc_pkt "packet" from the network interface
|
|
*
|
|
* @pre `netif != NULL`
|
|
*
|
|
* @note The function takes the bytes received via netdev_driver_t::recv()
|
|
* from gnrc_netif_t::dev and re-formats it to a
|
|
* @ref net_gnrc_pkt "packet" containing a @ref net_gnrc_netif_hdr
|
|
* and a payload header in receive order.
|
|
*
|
|
* @param[in] netif The network interface.
|
|
*
|
|
* @return The packet received. Contains the payload (with the type marked
|
|
* accordingly) and a @ref net_gnrc_netif_hdr in receive order.
|
|
* @return NULL, if @ref net_gnrc_pktbuf was full.
|
|
*/
|
|
gnrc_pktsnip_t *(*recv)(gnrc_netif_t *netif);
|
|
|
|
/**
|
|
* @brief Gets an option from the network interface
|
|
*
|
|
* Use gnrc_netif_get_from_netdev() to just get options from
|
|
* gnrc_netif_t::dev.
|
|
*
|
|
* @param[in] netif The network interface.
|
|
* @param[in] opt The option parameters.
|
|
*
|
|
* @return Number of bytes in @p data.
|
|
* @return -EOVERFLOW, if @p max_len is lesser than the required space.
|
|
* @return -ENOTSUP, if @p opt is not supported to be set.
|
|
* @return Any negative error code reported by gnrc_netif_t::dev.
|
|
*/
|
|
int (*get)(gnrc_netif_t *netif, gnrc_netapi_opt_t *opt);
|
|
|
|
/**
|
|
* @brief Sets an option from the network interface
|
|
*
|
|
* Use gnrc_netif_set_from_netdev() to just set options from
|
|
* gnrc_netif_t::dev.
|
|
*
|
|
* @param[in] netif The network interface.
|
|
* @param[in] opt The option parameters.
|
|
*
|
|
* @return Number of bytes written to gnrc_netif_t::dev.
|
|
* @return -EOVERFLOW, if @p data_len is greater than the allotted space in
|
|
* gnrc_netif_t::dev or gnrc_netif_t.
|
|
* @return -ENOTSUP, if @p opt is not supported to be set.
|
|
* @return Any negative error code reported by gnrc_netif_t::dev.
|
|
*/
|
|
int (*set)(gnrc_netif_t *netif, const gnrc_netapi_opt_t *opt);
|
|
|
|
/**
|
|
* @brief Message handler for network interface
|
|
*
|
|
* This message handler is used, when the network interface needs to handle
|
|
* message types beyond the ones defined in @ref net_gnrc_netapi "netapi".
|
|
* Leave NULL if this is not the case.
|
|
*
|
|
* @param[in] netif The network interface.
|
|
* @param[in] msg Message to be handled.
|
|
*/
|
|
void (*msg_handler)(gnrc_netif_t *netif, msg_t *msg);
|
|
};
|
|
|
|
/**
|
|
* @brief Initialize all available network interfaces.
|
|
* This function is called automatically if the auto_init_gnrc_netif
|
|
* module is used.
|
|
* If only the gnrc_netif_init module is used instead, you can call
|
|
* this function to manually set up the network interfaces at a later
|
|
* time.
|
|
*/
|
|
void gnrc_netif_init_devs(void);
|
|
|
|
/**
|
|
* @brief Creates a network interface
|
|
*
|
|
* @param[out] netif The interface. May not be `NULL`.
|
|
* @param[in] stack The stack for the network interface's thread.
|
|
* @param[in] stacksize Size of @p stack.
|
|
* @param[in] priority Priority for the network interface's thread.
|
|
* @param[in] name Name for the network interface. May be NULL.
|
|
* @param[in] dev Device for the interface.
|
|
* @param[in] ops Operations for the network interface.
|
|
*
|
|
* @note If @ref DEVELHELP is defined netif_params_t::name is used as the
|
|
* name of the network interface's thread.
|
|
*
|
|
* @return 0 on success
|
|
* @return negative number on error
|
|
*/
|
|
int gnrc_netif_create(gnrc_netif_t *netif, char *stack, int stacksize,
|
|
char priority, const char *name, netdev_t *dev,
|
|
const gnrc_netif_ops_t *ops);
|
|
|
|
/**
|
|
* @brief Get number of network interfaces actually allocated
|
|
*
|
|
* @return Number of network interfaces actually allocated
|
|
*/
|
|
unsigned gnrc_netif_numof(void);
|
|
|
|
/**
|
|
* @brief Check if there can only be one @ref gnrc_netif_t interface.
|
|
*
|
|
* > There can only be one!
|
|
*
|
|
* This function is used to allow compile time optimizations for
|
|
* single interface applications
|
|
*
|
|
* @return true, if there can only only one interface
|
|
* @return false, if there can be more than one interface
|
|
*/
|
|
static inline bool gnrc_netif_highlander(void)
|
|
{
|
|
return IS_USED(MODULE_GNRC_NETIF_SINGLE);
|
|
}
|
|
|
|
/**
|
|
* @brief Iterate over all network interfaces.
|
|
*
|
|
* @param[in] prev previous interface in iteration. NULL to start iteration.
|
|
*
|
|
* @return The next network interface after @p prev.
|
|
* @return NULL, if @p prev was the last network interface.
|
|
*/
|
|
gnrc_netif_t *gnrc_netif_iter(const gnrc_netif_t *prev);
|
|
|
|
/**
|
|
* @brief Get network interface by PID
|
|
*
|
|
* @param[in] pid A PID of a network interface.
|
|
*
|
|
* @return The network interface on success.
|
|
* @return NULL, if no network interface with PID exists.
|
|
*/
|
|
gnrc_netif_t *gnrc_netif_get_by_pid(kernel_pid_t pid);
|
|
|
|
/**
|
|
* @brief Gets the (unicast on anycast) IPv6 address of an interface (if IPv6
|
|
* is supported)
|
|
*
|
|
* @pre `netif != NULL`
|
|
* @pre `addrs != NULL`
|
|
* @pre `max_len >= sizeof(ipv6_addr_t)`
|
|
*
|
|
* @param[in] netif The interface. May not be `NULL`.
|
|
* @param[out] addrs Up to the first `max_len / sizeof(ipv6_addr_t)`
|
|
* addresses assigned to @p netif. May not be `NULL`
|
|
* @param[in] max_len Number of *bytes* available in @p addrs. Must be at
|
|
* least `sizeof(ipv6_addr_t)`. It is recommended to use
|
|
* @p CONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF `* sizeof(ipv6_addr_t)
|
|
* here (and have @p addrs of the according length).
|
|
*
|
|
* @return Size of the array of addresses in @p addrs on success.
|
|
* (number of addresses times `sizeof(ipv6_addr_t)`)
|
|
* May be 0 if no addresses are configured.
|
|
* @return -ENOTSUP, if @p netif doesn't support IPv6.
|
|
*/
|
|
static inline int gnrc_netif_ipv6_addrs_get(const gnrc_netif_t *netif,
|
|
ipv6_addr_t *addrs,
|
|
size_t max_len)
|
|
{
|
|
assert(netif != NULL);
|
|
assert(addrs != NULL);
|
|
assert(max_len >= sizeof(ipv6_addr_t));
|
|
return gnrc_netapi_get(netif->pid, NETOPT_IPV6_ADDR, 0, addrs, max_len);
|
|
}
|
|
|
|
/**
|
|
* @brief Adds an (unicast or anycast) IPv6 address to an interface (if IPv6
|
|
* is supported)
|
|
*
|
|
* @pre `netif != NULL`
|
|
* @pre `addr != NULL`
|
|
* @pre `(pfx_len > 0) && (pfx_len <= 128)`
|
|
*
|
|
* @param[in] netif The interface. May not be `NULL`.
|
|
* @param[in] addr The address to add to @p netif. May not be `NULL`.
|
|
* @param[in] pfx_len The prefix length of @p addr. Must be greater than 0 and
|
|
* lesser than or equal to 128.
|
|
* @param[in] flags [Flags](@ref net_gnrc_netif_ipv6_addrs_flags) for
|
|
* @p addr. Set @ref GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID
|
|
* to skip duplicate address detection (when activated).
|
|
*
|
|
* @return sizeof(ipv6_addr_t) on success.
|
|
* @return -ENOMEM, if no space is left on @p netif to add @p addr or its
|
|
* corresponding solicited-nodes multicast address.
|
|
* @return -ENOTSUP, if @p netif doesn't support IPv6.
|
|
*/
|
|
static inline int gnrc_netif_ipv6_addr_add(const gnrc_netif_t *netif,
|
|
const ipv6_addr_t *addr, unsigned pfx_len,
|
|
uint8_t flags)
|
|
{
|
|
assert(netif != NULL);
|
|
assert(addr != NULL);
|
|
assert((pfx_len > 0) && (pfx_len <= 128));
|
|
return gnrc_netapi_set(netif->pid, NETOPT_IPV6_ADDR,
|
|
((pfx_len << 8U) | flags), addr,
|
|
sizeof(ipv6_addr_t));
|
|
}
|
|
|
|
/**
|
|
* @brief Removes a (unicast or anycast) IPv6 address from an interface (if
|
|
* IPv6 is supported)
|
|
*
|
|
* @pre `netif != NULL`
|
|
* @pre `addr != NULL`
|
|
*
|
|
* @param[in] netif The interface. May not be `NULL`.
|
|
* @param[in] addr The address to remove from @p netif. May not be `NULL`.
|
|
*
|
|
* @return sizeof(ipv6_addr_t) on success.
|
|
* @return -ENOTSUP, if @p netif doesn't support IPv6.
|
|
*/
|
|
static inline int gnrc_netif_ipv6_addr_remove(const gnrc_netif_t *netif,
|
|
const ipv6_addr_t *addr)
|
|
{
|
|
assert(netif != NULL);
|
|
assert(addr != NULL);
|
|
return gnrc_netapi_set(netif->pid, NETOPT_IPV6_ADDR_REMOVE,
|
|
0, addr, sizeof(ipv6_addr_t));
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the IPv6 multicast groups an interface is joined to (if IPv6 is
|
|
* supported)
|
|
*
|
|
* @pre `netif != NULL`
|
|
* @pre `groups != NULL`
|
|
* @pre `max_len >= sizeof(ipv6_addr_t)`
|
|
*
|
|
* @param[in] netif The interface. May not be `NULL`.
|
|
* @param[out] groups Up to the first `max_len / 8` multicast groups @p netif
|
|
* is joined to. May not be `NULL`
|
|
* @param[in] max_len Number of *bytes* available in @p groups. Must be at
|
|
* least `sizeof(ipv6_addr_t)`. It is recommended to use
|
|
* @p GNRC_NETIF_IPV6_GROUPS_NUMOF `* sizeof(ipv6_addr_t)
|
|
* here (and have @p groups of the according length).
|
|
*
|
|
* @return Number of addresses in @p groups times `sizeof(ipv6_addr_t)` on
|
|
* success (including 0).
|
|
* @return -ENOTSUP, if @p netif doesn't support IPv6.
|
|
*/
|
|
static inline int gnrc_netif_ipv6_groups_get(const gnrc_netif_t *netif,
|
|
ipv6_addr_t *groups,
|
|
size_t max_len)
|
|
{
|
|
assert(netif != NULL);
|
|
assert(groups != NULL);
|
|
assert(max_len >= sizeof(ipv6_addr_t));
|
|
return gnrc_netapi_get(netif->pid, NETOPT_IPV6_GROUP, 0, groups, max_len);
|
|
}
|
|
|
|
/**
|
|
* @brief Joins an IPv6 multicast group on an interface (if IPv6 is supported)
|
|
*
|
|
* @pre `netif != NULL`
|
|
* @pre `group != NULL`
|
|
*
|
|
* @param[in] netif The interface.
|
|
* @param[in] group The address of the multicast group to join on @p netif.
|
|
* May not be `NULL`.
|
|
*
|
|
* @return sizeof(ipv6_addr_t) on success.
|
|
* @return -ENOMEM, if no space is left on @p netif to add @p group.
|
|
* @return -ENOTSUP, if @p netif doesn't support IPv6.
|
|
*/
|
|
static inline int gnrc_netif_ipv6_group_join(const gnrc_netif_t *netif,
|
|
ipv6_addr_t *group)
|
|
{
|
|
assert(netif != NULL);
|
|
assert(group != NULL);
|
|
return gnrc_netapi_set(netif->pid, NETOPT_IPV6_GROUP, 0, group,
|
|
sizeof(ipv6_addr_t));
|
|
}
|
|
|
|
/**
|
|
* @brief Leaves an IPv6 multicast group on an interface (if IPv6 is supported)
|
|
*
|
|
* @pre `netif != NULL`
|
|
* @pre `group != NULL`
|
|
*
|
|
* @param[in] netif The interface.
|
|
* @param[in] group The address of the multicast group to leave on @p netif.
|
|
* May not be `NULL`.
|
|
*
|
|
* @return sizeof(ipv6_addr_t) on success.
|
|
* @return -ENOTSUP, if @p netif doesn't support IPv6.
|
|
*/
|
|
static inline int gnrc_netif_ipv6_group_leave(const gnrc_netif_t *netif,
|
|
ipv6_addr_t *group)
|
|
{
|
|
assert(netif != NULL);
|
|
assert(group != NULL);
|
|
return gnrc_netapi_set(netif->pid, NETOPT_IPV6_GROUP_LEAVE, 0, group,
|
|
sizeof(ipv6_addr_t));
|
|
}
|
|
|
|
/**
|
|
* @brief Default operation for gnrc_netif_ops_t::init()
|
|
*
|
|
* @note Can also be used to be called *before* a custom operation. This
|
|
* function calls @ref netif_register internally.
|
|
*
|
|
* @param[in] netif The network interface.
|
|
*/
|
|
int gnrc_netif_default_init(gnrc_netif_t *netif);
|
|
|
|
/**
|
|
* @brief Default operation for gnrc_netif_ops_t::get()
|
|
*
|
|
* @note Can also be used to be called *after* a custom operation.
|
|
*
|
|
* @param[in] netif The network interface.
|
|
* @param[out] opt The option parameters.
|
|
*
|
|
* @return Return value of netdev_driver_t::get() of gnrc_netif_t::dev of
|
|
* @p netif.
|
|
*/
|
|
int gnrc_netif_get_from_netdev(gnrc_netif_t *netif, gnrc_netapi_opt_t *opt);
|
|
|
|
/**
|
|
* @brief Default operation for gnrc_netif_ops_t::set()
|
|
*
|
|
* @note Can also be used to be called *after* a custom operation.
|
|
*
|
|
* @param[in] netif The network interface.
|
|
* @param[in] opt The option parameters.
|
|
*
|
|
* @return Return value of netdev_driver_t::set() of gnrc_netif_t::dev of
|
|
* @p netif.
|
|
*/
|
|
int gnrc_netif_set_from_netdev(gnrc_netif_t *netif,
|
|
const gnrc_netapi_opt_t *opt);
|
|
|
|
/**
|
|
* @brief Gets an interface by the netdev type (and index)
|
|
*
|
|
* @pre The netdev has been registered with @ref netdev_register
|
|
*
|
|
* @param[in] type driver type of the netdev, can be @ref NETDEV_ANY
|
|
* @param[in] index index of the netdev, can be @ref NETDEV_INDEX_ANY
|
|
*
|
|
* @return The network interface that has a netdev of matching type and index
|
|
* NULL if no matching interface could be found
|
|
*/
|
|
gnrc_netif_t *gnrc_netif_get_by_type(netdev_type_t type, uint8_t index);
|
|
|
|
/**
|
|
* @brief Converts a hardware address to a human readable string.
|
|
*
|
|
* @note Compatibility wrapper for @see l2util_addr_to_str
|
|
*
|
|
* @details The format will be like `xx:xx:xx:xx` where `xx` are the bytes
|
|
* of @p addr in hexadecimal representation.
|
|
*
|
|
* @pre `(out != NULL) && ((addr != NULL) || (addr_len == 0))`
|
|
* @pre @p out **MUST** have allocated at least 3 * @p addr_len bytes.
|
|
*
|
|
* @param[in] addr A hardware address.
|
|
* @param[in] addr_len Length of @p addr.
|
|
* @param[out] out A string to store the output in. Must at least have
|
|
* 3 * @p addr_len bytes allocated.
|
|
*
|
|
* @return @p out.
|
|
*/
|
|
static inline char *gnrc_netif_addr_to_str(const uint8_t *addr, size_t addr_len, char *out)
|
|
{
|
|
return l2util_addr_to_str(addr, addr_len, out);
|
|
}
|
|
|
|
/**
|
|
* @brief Parses a string of colon-separated hexadecimals to a hardware
|
|
* address.
|
|
*
|
|
* @note Compatibility wrapper for @see l2util_addr_from_str
|
|
*
|
|
* @details The input format must be like `xx:xx:xx:xx` where `xx` will be the
|
|
* bytes of @p addr in hexadecimal representation.
|
|
*
|
|
* @pre `(out != NULL)`
|
|
* @pre @p out **MUST** have allocated at least
|
|
* @ref GNRC_NETIF_L2ADDR_MAXLEN bytes.
|
|
*
|
|
* @param[in] str A string of colon-separated hexadecimals.
|
|
* @param[out] out The resulting hardware address. Must at least have
|
|
* @ref GNRC_NETIF_L2ADDR_MAXLEN bytes allocated.
|
|
*
|
|
* @return Actual length of @p out on success.
|
|
* @return 0, on failure.
|
|
*/
|
|
static inline size_t gnrc_netif_addr_from_str(const char *str, uint8_t *out)
|
|
{
|
|
return l2util_addr_from_str(str, out);
|
|
}
|
|
|
|
/**
|
|
* @brief Send a GNRC packet via a given @ref gnrc_netif_t interface.
|
|
*
|
|
* @param netif pointer to the interface
|
|
* @param pkt packet to be sent.
|
|
*
|
|
* @return 1 if packet was successfully delivered
|
|
* @return -1 on error
|
|
*/
|
|
static inline int gnrc_netif_send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
|
|
{
|
|
return gnrc_netapi_send(netif->pid, pkt);
|
|
}
|
|
|
|
#if defined(MODULE_GNRC_NETIF_BUS) || DOXYGEN
|
|
/**
|
|
* @brief Get a message bus of a given @ref gnrc_netif_t interface.
|
|
*
|
|
* @param netif pointer to the interface
|
|
* @param type GNRC message bus [type](@ref gnrc_netif_bus_t)
|
|
*
|
|
* @return the message bus for the interface
|
|
*/
|
|
static inline msg_bus_t* gnrc_netif_get_bus(gnrc_netif_t *netif,
|
|
gnrc_netif_bus_t type)
|
|
{
|
|
assert(type < GNRC_NETIF_BUS_NUMOF);
|
|
return &netif->bus[type];
|
|
}
|
|
|
|
/**
|
|
* @brief Wait for a global address to become available.
|
|
* This function blocks until a valid global address has been
|
|
* configured, e.g. by receiving a router advertisement or via DHCPv6.
|
|
*
|
|
* Requires the `gnrc_netif_bus` module.
|
|
*
|
|
* @param netif pointer to the interface
|
|
* May be NULL, then this checks for a global address
|
|
* on *any* interface.
|
|
* @param timeout_ms Time to wait for an address to become available, in ms.
|
|
*
|
|
* @return true if a global address is configured
|
|
*/
|
|
bool gnrc_netif_ipv6_wait_for_global_address(gnrc_netif_t *netif,
|
|
uint32_t timeout_ms);
|
|
#endif /* MODULE_GNRC_NETIF_BUS */
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* NET_GNRC_NETIF_H */
|
|
/** @} */
|