Merge pull request #15560 from maribu/gnrc-aux-rx-timestamps
net/gnrc/sock: Implement sock_aux_timestamp for RX
This commit is contained in:
commit
08d86295d2
@ -43,6 +43,7 @@ PSEUDOMODULES += gnrc_netapi_callbacks
|
|||||||
PSEUDOMODULES += gnrc_netapi_mbox
|
PSEUDOMODULES += gnrc_netapi_mbox
|
||||||
PSEUDOMODULES += gnrc_netif_bus
|
PSEUDOMODULES += gnrc_netif_bus
|
||||||
PSEUDOMODULES += gnrc_netif_events
|
PSEUDOMODULES += gnrc_netif_events
|
||||||
|
PSEUDOMODULES += gnrc_netif_timestamp
|
||||||
PSEUDOMODULES += gnrc_pktbuf_cmd
|
PSEUDOMODULES += gnrc_pktbuf_cmd
|
||||||
PSEUDOMODULES += gnrc_netif_6lo
|
PSEUDOMODULES += gnrc_netif_6lo
|
||||||
PSEUDOMODULES += gnrc_netif_ipv6
|
PSEUDOMODULES += gnrc_netif_ipv6
|
||||||
|
|||||||
@ -185,6 +185,9 @@ endif
|
|||||||
|
|
||||||
ifneq (,$(filter gnrc_sock_%,$(USEMODULE)))
|
ifneq (,$(filter gnrc_sock_%,$(USEMODULE)))
|
||||||
USEMODULE += gnrc_sock
|
USEMODULE += gnrc_sock
|
||||||
|
ifneq (,$(filter sock_aux_timestamp,$(USEMODULE)))
|
||||||
|
USEMODULE += gnrc_netif_timestamp
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq (,$(filter gnrc_sock_async,$(USEMODULE)))
|
ifneq (,$(filter gnrc_sock_async,$(USEMODULE)))
|
||||||
|
|||||||
@ -88,6 +88,17 @@ extern "C" {
|
|||||||
* @ref IEEE802154_FCF_FRAME_PEND
|
* @ref IEEE802154_FCF_FRAME_PEND
|
||||||
*/
|
*/
|
||||||
#define GNRC_NETIF_HDR_FLAGS_MORE_DATA (0x10)
|
#define GNRC_NETIF_HDR_FLAGS_MORE_DATA (0x10)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Indicate presence of a valid timestamp
|
||||||
|
*
|
||||||
|
* @details If (and only if) module `gnrc_netif_timestamp` is used and the
|
||||||
|
* network device supplied the timestamp of reception of a frame, this
|
||||||
|
* timestamp is passed up the network stack through
|
||||||
|
* @ref gnrc_netif_hdr_t::timestamp and this flag is set. This flag
|
||||||
|
* can be used to check for presence of a valid timestamp.
|
||||||
|
*/
|
||||||
|
#define GNRC_NETIF_HDR_FLAGS_TIMESTAMP (0x08)
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
@ -105,6 +116,24 @@ typedef struct {
|
|||||||
uint8_t flags; /**< flags as defined above */
|
uint8_t flags; /**< flags as defined above */
|
||||||
uint8_t lqi; /**< lqi of received packet (optional) */
|
uint8_t lqi; /**< lqi of received packet (optional) */
|
||||||
int16_t rssi; /**< rssi of received packet in dBm (optional) */
|
int16_t rssi; /**< rssi of received packet in dBm (optional) */
|
||||||
|
#if IS_USED(MODULE_GNRC_NETIF_TIMESTAMP) || defined(DOXYGEN)
|
||||||
|
/**
|
||||||
|
* @brief Timestamp of reception in nanoseconds since epoch
|
||||||
|
*
|
||||||
|
* @note Only when @ref GNRC_NETIF_HDR_FLAGS_TIMESTAMP is set, this
|
||||||
|
* field contains valid info.
|
||||||
|
*
|
||||||
|
* This field is only provided if module `gnrc_netif_timestamp` is used.
|
||||||
|
* Keep in mind that when the hardware does not provide timestamping, the
|
||||||
|
* network device driver could choose to provide this in software, which
|
||||||
|
* adds the delay and jitter of the ISR handling to the timestamp. Please
|
||||||
|
* keep also in mind that a hardware implementation might not be able to
|
||||||
|
* reliable timestamp every frame - e.g. a full-duplex wired interface might
|
||||||
|
* be unable to timestamp a received frame while timestamping an outgoing
|
||||||
|
* frame.
|
||||||
|
*/
|
||||||
|
uint64_t timestamp;
|
||||||
|
#endif /* MODULE_GNRC_NETIF_TIMESTAMP */
|
||||||
} gnrc_netif_hdr_t;
|
} gnrc_netif_hdr_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -201,6 +230,50 @@ static inline void gnrc_netif_hdr_set_dst_addr(gnrc_netif_hdr_t *hdr,
|
|||||||
memcpy(((uint8_t *)(hdr + 1)) + hdr->src_l2addr_len, addr, addr_len);
|
memcpy(((uint8_t *)(hdr + 1)) + hdr->src_l2addr_len, addr, addr_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the timestamp in the netif header
|
||||||
|
* @param[out] hdr Header to set the timestamp in
|
||||||
|
* @param[in] timestamp Timestamp to set (nanoseconds since epoch)
|
||||||
|
*
|
||||||
|
* @details If the module gnrc_netif_timestamp is not used, a call to this
|
||||||
|
* function become a non-op (and will be fully optimized out by the
|
||||||
|
* compiler)
|
||||||
|
*/
|
||||||
|
static inline void gnrc_netif_hdr_set_timestamp(gnrc_netif_hdr_t *hdr,
|
||||||
|
uint64_t timestamp)
|
||||||
|
{
|
||||||
|
(void)hdr;
|
||||||
|
(void)timestamp;
|
||||||
|
#if IS_USED(MODULE_GNRC_NETIF_TIMESTAMP)
|
||||||
|
hdr->timestamp = timestamp;
|
||||||
|
hdr->flags |= GNRC_NETIF_HDR_FLAGS_TIMESTAMP;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the timestamp of the frame in nanoseconds since epoch
|
||||||
|
* @param[in] hdr Header to read the timestamp from
|
||||||
|
* @param[out] dest The timestamp will be stored here
|
||||||
|
* @retval 0 The timestamp was stored in @p dest
|
||||||
|
* @retval -1 No timestamp available, @p dest is unchanged
|
||||||
|
*
|
||||||
|
* @details If the module gnrc_netif_timestamp is not used, this will always
|
||||||
|
* return 0
|
||||||
|
*/
|
||||||
|
static inline int gnrc_netif_hdr_get_timestamp(const gnrc_netif_hdr_t *hdr,
|
||||||
|
uint64_t *dest)
|
||||||
|
{
|
||||||
|
(void)hdr;
|
||||||
|
(void)dest;
|
||||||
|
#if IS_USED(MODULE_GNRC_NETIF_TIMESTAMP)
|
||||||
|
if (hdr->flags & GNRC_NETIF_HDR_FLAGS_TIMESTAMP) {
|
||||||
|
*dest = hdr->timestamp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(MODULE_GNRC_IPV6) || defined(DOXYGEN)
|
#if defined(MODULE_GNRC_IPV6) || defined(DOXYGEN)
|
||||||
/**
|
/**
|
||||||
* @brief Converts the source address of a given @ref net_gnrc_netif_hdr to
|
* @brief Converts the source address of a given @ref net_gnrc_netif_hdr to
|
||||||
|
|||||||
@ -90,7 +90,7 @@ void gnrc_sock_create(gnrc_sock_reg_t *reg, gnrc_nettype_t type, uint32_t demux_
|
|||||||
|
|
||||||
ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt_out,
|
ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt_out,
|
||||||
uint32_t timeout, sock_ip_ep_t *remote,
|
uint32_t timeout, sock_ip_ep_t *remote,
|
||||||
gnrc_sock_recv_aux_t aux)
|
gnrc_sock_recv_aux_t *aux)
|
||||||
{
|
{
|
||||||
/* only used when some sock_aux_% module is used */
|
/* only used when some sock_aux_% module is used */
|
||||||
(void)aux;
|
(void)aux;
|
||||||
@ -154,9 +154,9 @@ ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt_out,
|
|||||||
memcpy(&remote->addr, &ipv6_hdr->src, sizeof(ipv6_addr_t));
|
memcpy(&remote->addr, &ipv6_hdr->src, sizeof(ipv6_addr_t));
|
||||||
remote->family = AF_INET6;
|
remote->family = AF_INET6;
|
||||||
#if IS_USED(MODULE_SOCK_AUX_LOCAL)
|
#if IS_USED(MODULE_SOCK_AUX_LOCAL)
|
||||||
if (aux.local != NULL) {
|
if (aux->local != NULL) {
|
||||||
memcpy(&aux.local->addr, &ipv6_hdr->dst, sizeof(ipv6_addr_t));
|
memcpy(&aux->local->addr, &ipv6_hdr->dst, sizeof(ipv6_addr_t));
|
||||||
aux.local->family = AF_INET6;
|
aux->local->family = AF_INET6;
|
||||||
}
|
}
|
||||||
#endif /* MODULE_SOCK_AUX_LOCAL */
|
#endif /* MODULE_SOCK_AUX_LOCAL */
|
||||||
netif = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF);
|
netif = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF);
|
||||||
@ -167,6 +167,13 @@ ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt_out,
|
|||||||
gnrc_netif_hdr_t *netif_hdr = netif->data;
|
gnrc_netif_hdr_t *netif_hdr = netif->data;
|
||||||
/* TODO: use API in #5511 */
|
/* TODO: use API in #5511 */
|
||||||
remote->netif = (uint16_t)netif_hdr->if_pid;
|
remote->netif = (uint16_t)netif_hdr->if_pid;
|
||||||
|
#if IS_USED(MODULE_SOCK_AUX_TIMESTAMP)
|
||||||
|
if (aux->timestamp != NULL) {
|
||||||
|
if (gnrc_netif_hdr_get_timestamp(netif_hdr, aux->timestamp) == 0) {
|
||||||
|
aux->flags |= GNRC_SOCK_RECV_AUX_FLAG_TIMESTAMP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* MODULE_SOCK_AUX_TIMESTAMP */
|
||||||
}
|
}
|
||||||
*pkt_out = pkt; /* set out parameter */
|
*pkt_out = pkt; /* set out parameter */
|
||||||
|
|
||||||
|
|||||||
@ -70,18 +70,17 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
sock_ip_ep_t *local;
|
sock_ip_ep_t *local;
|
||||||
#endif
|
#endif
|
||||||
#if !IS_USED(MODULE_SOCK_AUX_LOCAL) || DOXYGEN
|
#if IS_USED(MODULE_SOCK_AUX_TIMESTAMP) || DOXYGEN
|
||||||
/**
|
uint64_t *timestamp; /**< timestamp PDU was received at in nanoseconds */
|
||||||
* @brief Workaround in case no `sock_aux_%` module is used
|
|
||||||
*
|
|
||||||
* Empty structures are only allowed with a GNU extension. For portability,
|
|
||||||
* this member is present if and only if this structure would be otherwise
|
|
||||||
* empty.
|
|
||||||
*/
|
|
||||||
uint8_t this_struct_is_not_empty;
|
|
||||||
#endif
|
#endif
|
||||||
|
/**
|
||||||
|
* @brief Flags
|
||||||
|
*/
|
||||||
|
uint8_t flags;
|
||||||
} gnrc_sock_recv_aux_t;
|
} gnrc_sock_recv_aux_t;
|
||||||
|
|
||||||
|
#define GNRC_SOCK_RECV_AUX_FLAG_TIMESTAMP 0x01 /**< Timestamp valid */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Internal helper functions for GNRC
|
* @brief Internal helper functions for GNRC
|
||||||
* @internal
|
* @internal
|
||||||
@ -143,7 +142,7 @@ void gnrc_sock_create(gnrc_sock_reg_t *reg, gnrc_nettype_t type, uint32_t demux_
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt, uint32_t timeout,
|
ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt, uint32_t timeout,
|
||||||
sock_ip_ep_t *remote, gnrc_sock_recv_aux_t aux);
|
sock_ip_ep_t *remote, gnrc_sock_recv_aux_t *aux);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send a packet internally
|
* @brief Send a packet internally
|
||||||
|
|||||||
@ -135,7 +135,12 @@ ssize_t sock_ip_recv_buf_aux(sock_ip_t *sock, void **data, void **buf_ctx,
|
|||||||
_aux.local = &aux->local;
|
_aux.local = &aux->local;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
res = gnrc_sock_recv((gnrc_sock_reg_t *)sock, &pkt, timeout, &tmp, _aux);
|
#if IS_USED(MODULE_SOCK_AUX_TIMESTAMP)
|
||||||
|
if ((aux != NULL) && (aux->flags & SOCK_AUX_GET_TIMESTAMP)) {
|
||||||
|
_aux.timestamp = &aux->timestamp;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
res = gnrc_sock_recv((gnrc_sock_reg_t *)sock, &pkt, timeout, &tmp, &_aux);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -156,6 +161,16 @@ ssize_t sock_ip_recv_buf_aux(sock_ip_t *sock, void **data, void **buf_ctx,
|
|||||||
if ((aux != NULL) && (aux->flags & SOCK_AUX_GET_LOCAL)) {
|
if ((aux != NULL) && (aux->flags & SOCK_AUX_GET_LOCAL)) {
|
||||||
aux->flags &= ~(SOCK_AUX_GET_LOCAL);
|
aux->flags &= ~(SOCK_AUX_GET_LOCAL);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#if IS_USED(MODULE_SOCK_AUX_TIMESTAMP)
|
||||||
|
if ((aux != NULL) && (aux->flags & SOCK_AUX_GET_TIMESTAMP)) {
|
||||||
|
/* check if network interface did provide a timestamp; this depends on
|
||||||
|
* hardware support. A timestamp of zero is used to indicate a missing
|
||||||
|
* timestamp */
|
||||||
|
if (aux->timestamp > 0) {
|
||||||
|
aux->flags &= ~SOCK_AUX_GET_TIMESTAMP;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
*data = pkt->data;
|
*data = pkt->data;
|
||||||
*buf_ctx = pkt;
|
*buf_ctx = pkt;
|
||||||
|
|||||||
@ -224,7 +224,12 @@ ssize_t sock_udp_recv_buf_aux(sock_udp_t *sock, void **data, void **buf_ctx,
|
|||||||
_aux.local = (sock_ip_ep_t *)&aux->local;
|
_aux.local = (sock_ip_ep_t *)&aux->local;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
res = gnrc_sock_recv((gnrc_sock_reg_t *)sock, &pkt, timeout, &tmp, _aux);
|
#if IS_USED(MODULE_SOCK_AUX_TIMESTAMP)
|
||||||
|
if ((aux != NULL) && (aux->flags & SOCK_AUX_GET_TIMESTAMP)) {
|
||||||
|
_aux.timestamp = &aux->timestamp;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
res = gnrc_sock_recv((gnrc_sock_reg_t *)sock, &pkt, timeout, &tmp, &_aux);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -251,6 +256,16 @@ ssize_t sock_udp_recv_buf_aux(sock_udp_t *sock, void **data, void **buf_ctx,
|
|||||||
aux->flags &= ~SOCK_AUX_GET_LOCAL;
|
aux->flags &= ~SOCK_AUX_GET_LOCAL;
|
||||||
aux->local.port = sock->local.port;
|
aux->local.port = sock->local.port;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#if IS_USED(MODULE_SOCK_AUX_TIMESTAMP)
|
||||||
|
if ((aux != NULL) && (aux->flags & SOCK_AUX_GET_TIMESTAMP)) {
|
||||||
|
/* check if network interface did provide a timestamp; this depends on
|
||||||
|
* hardware support. A timestamp of zero is used to indicate a missing
|
||||||
|
* timestamp */
|
||||||
|
if (_aux.flags & GNRC_SOCK_RECV_AUX_FLAG_TIMESTAMP) {
|
||||||
|
aux->flags &= ~SOCK_AUX_GET_TIMESTAMP;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
*data = pkt->data;
|
*data = pkt->data;
|
||||||
*buf_ctx = pkt;
|
*buf_ctx = pkt;
|
||||||
|
|||||||
@ -1,11 +1,16 @@
|
|||||||
include ../Makefile.tests_common
|
include ../Makefile.tests_common
|
||||||
|
|
||||||
AUX_LOCAL ?= 1
|
AUX_LOCAL ?= 1
|
||||||
|
AUX_TIMESTAMP ?= 1
|
||||||
|
|
||||||
ifeq (1, $(AUX_LOCAL))
|
ifeq (1, $(AUX_LOCAL))
|
||||||
USEMODULE += sock_aux_local
|
USEMODULE += sock_aux_local
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq (1, $(AUX_LOCAL))
|
||||||
|
USEMODULE += sock_aux_timestamp
|
||||||
|
endif
|
||||||
|
|
||||||
USEMODULE += sock_ip
|
USEMODULE += sock_ip
|
||||||
USEMODULE += gnrc_ipv6
|
USEMODULE += gnrc_ipv6
|
||||||
USEMODULE += ps
|
USEMODULE += ps
|
||||||
|
|||||||
@ -349,13 +349,16 @@ static void test_sock_ip_recv__aux(void)
|
|||||||
static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_REMOTE };
|
static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_REMOTE };
|
||||||
static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
|
static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
|
||||||
static const sock_ip_ep_t local = { .family = AF_INET6 };
|
static const sock_ip_ep_t local = { .family = AF_INET6 };
|
||||||
|
static const inject_aux_t inject_aux = { .timestamp = 42 };
|
||||||
sock_ip_ep_t result;
|
sock_ip_ep_t result;
|
||||||
sock_ip_aux_rx_t aux = { .flags = SOCK_AUX_GET_LOCAL };
|
sock_ip_aux_rx_t aux = {
|
||||||
|
.flags = SOCK_AUX_GET_LOCAL | SOCK_AUX_GET_TIMESTAMP
|
||||||
|
};
|
||||||
|
|
||||||
expect(0 == sock_ip_create(&_sock, &local, NULL, _TEST_PROTO,
|
expect(0 == sock_ip_create(&_sock, &local, NULL, _TEST_PROTO,
|
||||||
SOCK_FLAGS_REUSE_EP));
|
SOCK_FLAGS_REUSE_EP));
|
||||||
expect(_inject_packet(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
|
expect(_inject_packet_aux(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
|
||||||
sizeof("ABCD"), _TEST_NETIF));
|
sizeof("ABCD"), _TEST_NETIF, &inject_aux));
|
||||||
expect(sizeof("ABCD") == sock_ip_recv_aux(&_sock, _test_buffer,
|
expect(sizeof("ABCD") == sock_ip_recv_aux(&_sock, _test_buffer,
|
||||||
sizeof(_test_buffer), 0, &result,
|
sizeof(_test_buffer), 0, &result,
|
||||||
&aux));
|
&aux));
|
||||||
@ -367,6 +370,12 @@ static void test_sock_ip_recv__aux(void)
|
|||||||
expect(memcmp(&aux.local.addr, &dst_addr, sizeof(dst_addr)) == 0);
|
expect(memcmp(&aux.local.addr, &dst_addr, sizeof(dst_addr)) == 0);
|
||||||
#else
|
#else
|
||||||
expect(aux.flags & SOCK_AUX_GET_LOCAL);
|
expect(aux.flags & SOCK_AUX_GET_LOCAL);
|
||||||
|
#endif
|
||||||
|
#if IS_USED(MODULE_SOCK_AUX_TIMESTAMP)
|
||||||
|
expect(!(aux.flags & SOCK_AUX_GET_TIMESTAMP));
|
||||||
|
expect(aux.timestamp == inject_aux.timestamp);
|
||||||
|
#else
|
||||||
|
expect(aux.flags & SOCK_AUX_GET_TIMESTAMP);
|
||||||
#endif
|
#endif
|
||||||
expect(_check_net());
|
expect(_check_net());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,9 +41,10 @@ void _prepare_send_checks(void)
|
|||||||
static gnrc_pktsnip_t *_build_ipv6_packet(const ipv6_addr_t *src,
|
static gnrc_pktsnip_t *_build_ipv6_packet(const ipv6_addr_t *src,
|
||||||
const ipv6_addr_t *dst, uint8_t nh,
|
const ipv6_addr_t *dst, uint8_t nh,
|
||||||
void *data, size_t data_len,
|
void *data, size_t data_len,
|
||||||
uint16_t netif)
|
uint16_t netif,
|
||||||
|
const inject_aux_t *aux)
|
||||||
{
|
{
|
||||||
gnrc_pktsnip_t *netif_hdr, *ipv6, *payload;
|
gnrc_pktsnip_t *netif_hdr_snip, *ipv6, *payload;
|
||||||
ipv6_hdr_t *ipv6_hdr;
|
ipv6_hdr_t *ipv6_hdr;
|
||||||
|
|
||||||
if ((netif > INT16_MAX) || (data_len > UINT16_MAX)) {
|
if ((netif > INT16_MAX) || (data_len > UINT16_MAX)) {
|
||||||
@ -63,21 +64,25 @@ static gnrc_pktsnip_t *_build_ipv6_packet(const ipv6_addr_t *src,
|
|||||||
ipv6_hdr->nh = nh;
|
ipv6_hdr->nh = nh;
|
||||||
ipv6_hdr->hl = 64;
|
ipv6_hdr->hl = 64;
|
||||||
payload = gnrc_pkt_append(payload, ipv6);
|
payload = gnrc_pkt_append(payload, ipv6);
|
||||||
netif_hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
|
netif_hdr_snip = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
|
||||||
if (netif_hdr == NULL) {
|
if (netif_hdr_snip == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
((gnrc_netif_hdr_t *)netif_hdr->data)->if_pid = (kernel_pid_t)netif;
|
gnrc_netif_hdr_t *netif_hdr = netif_hdr_snip->data;
|
||||||
return gnrc_pkt_append(payload, netif_hdr);
|
netif_hdr->if_pid = (kernel_pid_t)netif;
|
||||||
|
if (aux) {
|
||||||
|
gnrc_netif_hdr_set_timestamp(netif_hdr, aux->timestamp);
|
||||||
|
}
|
||||||
|
return gnrc_pkt_append(payload, netif_hdr_snip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool _inject_packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
|
bool _inject_packet_aux(const ipv6_addr_t *src, const ipv6_addr_t *dst,
|
||||||
uint8_t proto, void *data, size_t data_len,
|
uint8_t proto, void *data, size_t data_len,
|
||||||
uint16_t netif)
|
uint16_t netif, const inject_aux_t *aux)
|
||||||
{
|
{
|
||||||
gnrc_pktsnip_t *pkt = _build_ipv6_packet(src, dst, proto, data, data_len,
|
gnrc_pktsnip_t *pkt = _build_ipv6_packet(src, dst, proto, data, data_len,
|
||||||
netif);
|
netif, aux);
|
||||||
|
|
||||||
if (pkt == NULL) {
|
if (pkt == NULL) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -39,6 +39,31 @@ void _net_init(void);
|
|||||||
*/
|
*/
|
||||||
void _prepare_send_checks(void);
|
void _prepare_send_checks(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Structure containing auxiliary data to inject
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint64_t timestamp; /**< Timestamp of reception */
|
||||||
|
} inject_aux_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Injects a received IPv6 packet into the stack
|
||||||
|
*
|
||||||
|
* @param[in] src The source address of the IPv6 packet
|
||||||
|
* @param[in] dst The destination address of the IPv6 packet
|
||||||
|
* @param[in] proto The next header field of the IPv6 packet
|
||||||
|
* @param[in] data The payload of the IPv6 packet
|
||||||
|
* @param[in] data_len The payload length of the IPv6 packet
|
||||||
|
* @param[in] netif The interface the packet came over
|
||||||
|
* @param[in] aux Auxiliary data to inject
|
||||||
|
*
|
||||||
|
* @return true, if packet was successfully injected
|
||||||
|
* @return false, if an error occurred during injection
|
||||||
|
*/
|
||||||
|
bool _inject_packet_aux(const ipv6_addr_t *src, const ipv6_addr_t *dst,
|
||||||
|
uint8_t proto, void *data, size_t data_len,
|
||||||
|
uint16_t netif, const inject_aux_t *aux);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Injects a received IPv6 packet into the stack
|
* @brief Injects a received IPv6 packet into the stack
|
||||||
*
|
*
|
||||||
@ -52,9 +77,13 @@ void _prepare_send_checks(void);
|
|||||||
* @return true, if packet was successfully injected
|
* @return true, if packet was successfully injected
|
||||||
* @return false, if an error occurred during injection
|
* @return false, if an error occurred during injection
|
||||||
*/
|
*/
|
||||||
bool _inject_packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
|
static inline bool _inject_packet(const ipv6_addr_t *src,
|
||||||
uint8_t proto, void *data, size_t data_len,
|
const ipv6_addr_t *dst,
|
||||||
uint16_t netif);
|
uint8_t proto, void *data, size_t data_len,
|
||||||
|
uint16_t netif)
|
||||||
|
{
|
||||||
|
return _inject_packet_aux(src, dst, proto, data, data_len, netif, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Checks networking state (e.g. packet buffer state)
|
* @brief Checks networking state (e.g. packet buffer state)
|
||||||
|
|||||||
@ -1,11 +1,16 @@
|
|||||||
include ../Makefile.tests_common
|
include ../Makefile.tests_common
|
||||||
|
|
||||||
AUX_LOCAL ?= 1
|
AUX_LOCAL ?= 1
|
||||||
|
AUX_TIMESTAMP ?= 1
|
||||||
|
|
||||||
ifeq (1, $(AUX_LOCAL))
|
ifeq (1, $(AUX_LOCAL))
|
||||||
USEMODULE += sock_aux_local
|
USEMODULE += sock_aux_local
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq (1, $(AUX_LOCAL))
|
||||||
|
USEMODULE += sock_aux_timestamp
|
||||||
|
endif
|
||||||
|
|
||||||
USEMODULE += gnrc_sock_check_reuse
|
USEMODULE += gnrc_sock_check_reuse
|
||||||
USEMODULE += sock_udp
|
USEMODULE += sock_udp
|
||||||
USEMODULE += gnrc_ipv6
|
USEMODULE += gnrc_ipv6
|
||||||
|
|||||||
@ -429,13 +429,16 @@ static void test_sock_udp_recv__aux(void)
|
|||||||
static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
|
static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
|
||||||
static const sock_udp_ep_t local = { .family = AF_INET6,
|
static const sock_udp_ep_t local = { .family = AF_INET6,
|
||||||
.port = _TEST_PORT_LOCAL };
|
.port = _TEST_PORT_LOCAL };
|
||||||
|
static const inject_aux_t inject_aux = { .timestamp = 1337 };
|
||||||
sock_udp_ep_t result;
|
sock_udp_ep_t result;
|
||||||
sock_udp_aux_rx_t aux = { .flags = SOCK_AUX_GET_LOCAL };
|
sock_udp_aux_rx_t aux = {
|
||||||
|
.flags = SOCK_AUX_GET_LOCAL | SOCK_AUX_GET_TIMESTAMP
|
||||||
|
};
|
||||||
|
|
||||||
expect(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP));
|
expect(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP));
|
||||||
expect(_inject_packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE,
|
expect(_inject_packet_aux(&src_addr, &dst_addr, _TEST_PORT_REMOTE,
|
||||||
_TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"),
|
_TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"),
|
||||||
_TEST_NETIF));
|
_TEST_NETIF, &inject_aux));
|
||||||
expect(sizeof("ABCD") == sock_udp_recv_aux(&_sock, _test_buffer,
|
expect(sizeof("ABCD") == sock_udp_recv_aux(&_sock, _test_buffer,
|
||||||
sizeof(_test_buffer), 0,
|
sizeof(_test_buffer), 0,
|
||||||
&result, &aux));
|
&result, &aux));
|
||||||
@ -449,6 +452,12 @@ static void test_sock_udp_recv__aux(void)
|
|||||||
expect(_TEST_PORT_LOCAL == aux.local.port);
|
expect(_TEST_PORT_LOCAL == aux.local.port);
|
||||||
#else
|
#else
|
||||||
expect(aux.flags & SOCK_AUX_GET_LOCAL);
|
expect(aux.flags & SOCK_AUX_GET_LOCAL);
|
||||||
|
#endif
|
||||||
|
#if IS_USED(MODULE_SOCK_AUX_TIMESTAMP)
|
||||||
|
expect(!(aux.flags & SOCK_AUX_GET_TIMESTAMP));
|
||||||
|
expect(inject_aux.timestamp == aux.timestamp);
|
||||||
|
#else
|
||||||
|
expect(aux.flags & SOCK_AUX_GET_TIMESTAMP);
|
||||||
#endif
|
#endif
|
||||||
expect(_check_net());
|
expect(_check_net());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,9 +47,10 @@ static gnrc_pktsnip_t *_build_udp_packet(const ipv6_addr_t *src,
|
|||||||
const ipv6_addr_t *dst,
|
const ipv6_addr_t *dst,
|
||||||
uint16_t src_port, uint16_t dst_port,
|
uint16_t src_port, uint16_t dst_port,
|
||||||
void *data, size_t data_len,
|
void *data, size_t data_len,
|
||||||
uint16_t netif)
|
uint16_t netif,
|
||||||
|
const inject_aux_t *aux)
|
||||||
{
|
{
|
||||||
gnrc_pktsnip_t *netif_hdr, *ipv6, *udp;
|
gnrc_pktsnip_t *netif_hdr_snip, *ipv6, *udp;
|
||||||
udp_hdr_t *udp_hdr;
|
udp_hdr_t *udp_hdr;
|
||||||
ipv6_hdr_t *ipv6_hdr;
|
ipv6_hdr_t *ipv6_hdr;
|
||||||
uint16_t csum = 0;
|
uint16_t csum = 0;
|
||||||
@ -86,21 +87,25 @@ static gnrc_pktsnip_t *_build_udp_packet(const ipv6_addr_t *src,
|
|||||||
udp_hdr->checksum = byteorder_htons(~csum);
|
udp_hdr->checksum = byteorder_htons(~csum);
|
||||||
}
|
}
|
||||||
udp = gnrc_pkt_append(udp, ipv6);
|
udp = gnrc_pkt_append(udp, ipv6);
|
||||||
netif_hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
|
netif_hdr_snip = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
|
||||||
if (netif_hdr == NULL) {
|
if (netif_hdr_snip == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
((gnrc_netif_hdr_t *)netif_hdr->data)->if_pid = (kernel_pid_t)netif;
|
gnrc_netif_hdr_t *netif_hdr = netif_hdr_snip->data;
|
||||||
return gnrc_pkt_append(udp, netif_hdr);
|
netif_hdr->if_pid = (kernel_pid_t)netif;
|
||||||
|
if (aux) {
|
||||||
|
gnrc_netif_hdr_set_timestamp(netif_hdr, aux->timestamp);
|
||||||
|
}
|
||||||
|
return gnrc_pkt_append(udp, netif_hdr_snip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _inject_packet_aux(const ipv6_addr_t *src, const ipv6_addr_t *dst,
|
||||||
bool _inject_packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
|
uint16_t src_port, uint16_t dst_port,
|
||||||
uint16_t src_port, uint16_t dst_port,
|
void *data, size_t data_len, uint16_t netif,
|
||||||
void *data, size_t data_len, uint16_t netif)
|
const inject_aux_t *aux)
|
||||||
{
|
{
|
||||||
gnrc_pktsnip_t *pkt = _build_udp_packet(src, dst, src_port, dst_port,
|
gnrc_pktsnip_t *pkt = _build_udp_packet(src, dst, src_port, dst_port,
|
||||||
data, data_len, netif);
|
data, data_len, netif, aux);
|
||||||
|
|
||||||
if (pkt == NULL) {
|
if (pkt == NULL) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -39,6 +39,13 @@ void _net_init(void);
|
|||||||
*/
|
*/
|
||||||
void _prepare_send_checks(void);
|
void _prepare_send_checks(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Auxiliary data to inject
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint64_t timestamp; /**< Timestamp of reception */
|
||||||
|
} inject_aux_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Injects a received UDP packet into the stack
|
* @brief Injects a received UDP packet into the stack
|
||||||
*
|
*
|
||||||
@ -53,9 +60,33 @@ void _prepare_send_checks(void);
|
|||||||
* @return true, if packet was successfully injected
|
* @return true, if packet was successfully injected
|
||||||
* @return false, if an error occurred during injection
|
* @return false, if an error occurred during injection
|
||||||
*/
|
*/
|
||||||
bool _inject_packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
|
bool _inject_packet_aux(const ipv6_addr_t *src, const ipv6_addr_t *dst,
|
||||||
uint16_t src_port, uint16_t dst_port,
|
uint16_t src_port, uint16_t dst_port,
|
||||||
void *data, size_t data_len, uint16_t netif);
|
void *data, size_t data_len, uint16_t netif,
|
||||||
|
const inject_aux_t *aux);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Injects a received UDP packet into the stack
|
||||||
|
*
|
||||||
|
* @param[in] src The source address of the UDP packet
|
||||||
|
* @param[in] dst The destination address of the UDP packet
|
||||||
|
* @param[in] src_port The source port of the UDP packet
|
||||||
|
* @param[in] dst_port The destination port of the UDP packet
|
||||||
|
* @param[in] data The payload of the UDP packet
|
||||||
|
* @param[in] data_len The payload length of the UDP packet
|
||||||
|
* @param[in] netif The interface the packet came over
|
||||||
|
*
|
||||||
|
* @return true, if packet was successfully injected
|
||||||
|
* @return false, if an error occurred during injection
|
||||||
|
*/
|
||||||
|
static inline bool _inject_packet(const ipv6_addr_t *src,
|
||||||
|
const ipv6_addr_t *dst,
|
||||||
|
uint16_t src_port, uint16_t dst_port,
|
||||||
|
void *data, size_t data_len, uint16_t netif)
|
||||||
|
{
|
||||||
|
return _inject_packet_aux(src, dst, src_port, dst_port, data, data_len,
|
||||||
|
netif, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Checks networking state (e.g. packet buffer state)
|
* @brief Checks networking state (e.g. packet buffer state)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user