1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

sys/net/gnrc/sock: Add support for RX timestamp

This commit is contained in:
Marian Buschsieweke 2020-12-04 11:11:46 +01:00
parent 599c2a145e
commit d95192e97b
No known key found for this signature in database
GPG Key ID: 61F64C6599B1539F
7 changed files with 129 additions and 16 deletions

View File

@ -43,6 +43,7 @@ PSEUDOMODULES += gnrc_netapi_callbacks
PSEUDOMODULES += gnrc_netapi_mbox
PSEUDOMODULES += gnrc_netif_bus
PSEUDOMODULES += gnrc_netif_events
PSEUDOMODULES += gnrc_netif_timestamp
PSEUDOMODULES += gnrc_pktbuf_cmd
PSEUDOMODULES += gnrc_netif_6lo
PSEUDOMODULES += gnrc_netif_ipv6

View File

@ -179,6 +179,9 @@ endif
ifneq (,$(filter gnrc_sock_%,$(USEMODULE)))
USEMODULE += gnrc_sock
ifneq (,$(filter sock_aux_timestamp,$(USEMODULE)))
USEMODULE += gnrc_netif_timestamp
endif
endif
ifneq (,$(filter gnrc_sock_async,$(USEMODULE)))

View File

@ -88,6 +88,17 @@ extern "C" {
* @ref IEEE802154_FCF_FRAME_PEND
*/
#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 lqi; /**< lqi of received packet (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;
/**
@ -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);
}
/**
* @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)
/**
* @brief Converts the source address of a given @ref net_gnrc_netif_hdr to

View File

@ -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,
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 */
(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));
remote->family = AF_INET6;
#if IS_USED(MODULE_SOCK_AUX_LOCAL)
if (aux.local != NULL) {
memcpy(&aux.local->addr, &ipv6_hdr->dst, sizeof(ipv6_addr_t));
aux.local->family = AF_INET6;
if (aux->local != NULL) {
memcpy(&aux->local->addr, &ipv6_hdr->dst, sizeof(ipv6_addr_t));
aux->local->family = AF_INET6;
}
#endif /* MODULE_SOCK_AUX_LOCAL */
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;
/* TODO: use API in #5511 */
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 */

View File

@ -70,18 +70,17 @@ typedef struct {
*/
sock_ip_ep_t *local;
#endif
#if !IS_USED(MODULE_SOCK_AUX_LOCAL) || DOXYGEN
/**
* @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;
#if IS_USED(MODULE_SOCK_AUX_TIMESTAMP) || DOXYGEN
uint64_t *timestamp; /**< timestamp PDU was received at in nanoseconds */
#endif
/**
* @brief Flags
*/
uint8_t flags;
} gnrc_sock_recv_aux_t;
#define GNRC_SOCK_RECV_AUX_FLAG_TIMESTAMP 0x01 /**< Timestamp valid */
/**
* @brief Internal helper functions for GNRC
* @internal
@ -143,7 +142,7 @@ void gnrc_sock_create(gnrc_sock_reg_t *reg, gnrc_nettype_t type, uint32_t demux_
* @internal
*/
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

View File

@ -135,7 +135,12 @@ ssize_t sock_ip_recv_buf_aux(sock_ip_t *sock, void **data, void **buf_ctx,
_aux.local = &aux->local;
}
#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) {
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)) {
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
*data = pkt->data;
*buf_ctx = pkt;

View File

@ -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;
}
#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) {
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->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
*data = pkt->data;
*buf_ctx = pkt;