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

Merge pull request #15773 from benpicco/tools/zep_dispatch-topology

tools/zep_dispatch: add support for advanced topologies
This commit is contained in:
benpicco 2021-07-07 12:14:43 +02:00 committed by GitHub
commit 1407559f33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 728 additions and 51 deletions

View File

@ -133,6 +133,7 @@ extern int (*real_fputc)(int c, FILE *stream);
extern int (*real_fgetc)(FILE *stream);
extern mode_t (*real_umask)(mode_t cmask);
extern ssize_t (*real_writev)(int fildes, const struct iovec *iov, int iovcnt);
extern ssize_t (*real_send)(int sockfd, const void *buf, size_t len, int flags);
#ifdef __MACH__
#else

View File

@ -402,9 +402,12 @@ static void _send_zep_hello(socket_zep_t *dev)
.hdr.version = 2,
.type = SOCKET_ZEP_V2_TYPE_HELLO,
.resv = "HELLO",
.length = sizeof(dev->netdev.long_addr),
};
real_write(dev->sock_fd, &hdr, sizeof(hdr));
/* append HW addr */
real_send(dev->sock_fd, &hdr, sizeof(hdr), MSG_MORE);
real_send(dev->sock_fd, dev->netdev.long_addr, sizeof(dev->netdev.long_addr), 0);
}
}
@ -428,14 +431,17 @@ void socket_zep_setup(socket_zep_t *dev, const socket_zep_params_t *params, uint
dev->sock_fd = res;
}
if (_connect_remote(dev, params) == 0) {
/* send dummy data to connect to dispatcher */
_send_zep_hello(dev);
}
/* only send hello if we are connected to a remote */
bool send_hello = !_connect_remote(dev, params);
/* setup hardware address */
netdev_ieee802154_setup(&dev->netdev);
/* send dummy data to connect to dispatcher */
if (send_hello) {
_send_zep_hello(dev);
}
native_async_read_setup();
native_async_read_add_handler(dev->sock_fd, dev, _socket_isr);
}

View File

@ -97,6 +97,7 @@ int (*real_fputc)(int c, FILE *stream);
int (*real_fgetc)(FILE *stream);
mode_t (*real_umask)(mode_t cmask);
ssize_t (*real_writev)(int fildes, const struct iovec *iov, int iovcnt);
ssize_t (*real_send)(int sockfd, const void *buf, size_t len, int flags);
#ifdef __MACH__
#else
@ -484,6 +485,7 @@ void _native_init_syscalls(void)
*(void **)(&real_clearerr) = dlsym(RTLD_NEXT, "clearerr");
*(void **)(&real_umask) = dlsym(RTLD_NEXT, "umask");
*(void **)(&real_writev) = dlsym(RTLD_NEXT, "writev");
*(void **)(&real_send) = dlsym(RTLD_NEXT, "send");
*(void **)(&real_fclose) = dlsym(RTLD_NEXT, "fclose");
*(void **)(&real_fseek) = dlsym(RTLD_NEXT, "fseek");
*(void **)(&real_fputc) = dlsym(RTLD_NEXT, "fputc");

2
dist/tools/zep_dispatch/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.gv
*.pdf

View File

@ -1,4 +1,6 @@
CFLAGS?=-g -O3 -Wall -Wextra
CFLAGS ?= -g -O3 -Wall -Wextra
CFLAGS += $(RIOT_INCLUDE)
CFLAGS += -DNDEBUG # avoid assert re-definition
BINARY := bin/zep_dispatch
all: bin $(BINARY)
@ -6,11 +8,35 @@ all: bin $(BINARY)
bin:
mkdir bin
RIOTBASE:=../../..
RIOT_INCLUDE=$(RIOTBASE)/core/include
SRCS:=$(wildcard *.c)
$(BINARY): $(SRCS)
$(CC) $(CFLAGS) $(CFLAGS_EXTRA) -I$(RIOT_INCLUDE) $(SRCS) -o $@
RIOTBASE := ../../..
ZEP_PORT_BASE ?= 17754
TOPOLOGY ?= example.topo
GV_OUT ?= example.gv
RIOT_INCLUDE += -I$(RIOTBASE)/core/include
RIOT_INCLUDE += -I$(RIOTBASE)/cpu/native/include
RIOT_INCLUDE += -I$(RIOTBASE)/drivers/include
RIOT_INCLUDE += -I$(RIOTBASE)/sys/include
SRCS := $(wildcard *.c)
SRCS += $(RIOTBASE)/sys/net/link_layer/ieee802154/ieee802154.c
$(BINARY): $(SRCS)
$(CC) $(CFLAGS) $(CFLAGS_EXTRA) $(SRCS) -o $@
.PHONY: clean run graph help
clean:
rm -f $(BINARY)
run: $(BINARY)
$(BINARY) -t $(TOPOLOGY) -g $(GV_OUT) ::1 $(ZEP_PORT_BASE)
graph:
killall -USR1 zep_dispatch
dot -Tpdf $(GV_OUT) > $(GV_OUT).pdf
help:
@echo "run start ZEP dispatcher with the given \$$TOPOLOGY file"
@echo "graph print topology to \$$GV_OUT.pdf"
@echo "clean remove ZEP dispatcher binary"

46
dist/tools/zep_dispatch/README.md vendored Normal file
View File

@ -0,0 +1,46 @@
ZEP packet dispatcher
=====================
The ZEP dispatcher is a simple daemon that forwards ZEP packets to all connected
nodes.
```
usage: zep_dispatch [-t topology] [-s seed] [-g graphviz_out] <address> <port>
```
By default the dispatcher will forward every packet it receives to every other
connected node (flat topology).
Advanced Topology Mode
----------------------
It is possible to simulate a more complex topology as well as packet loss by
specifying a topology file.
The file format is:
```
<node_a> <node_b> [weight_ab] [weight_ba]
```
This line defines a connection between <node_a> and <node_b>.
The weight of the edge <node_a> -> <node_b> is <weight_ab>.
An edge weight is a float value between 0 and 1 that represents the probability of
a successful packet transmission on that path.
A weight of `0` would mean no connection, whereas a weight of `1` would be a perfect
connection. Intermediate values are possible, e.g. `0.6` would result in a packet
loss probability of 40%.
The weights can be omitted.
If both weights are omitted, a perfect connection is assumed.
If <weight_ba> is omitted, a symmetric connection is assumed and <weight_ab> is used
for both directions.
refer to the file `example.topo` for an example.
There can only be as many nodes connected to the dispatcher as have been named in
the topology file.
Any additional nodes that try to connect will be ignored.

7
dist/tools/zep_dispatch/example.topo vendored Normal file
View File

@ -0,0 +1,7 @@
# A and B are connected with an ideal link
A B
# A and C are connected with a symmetric link with 10% packet loss
A C 0.9
# B and C are on an asymmetric connection
# The path B -> C has 60% packet loss while C -> B has 30% packet loss
B C 0.4 0.7

View File

@ -15,75 +15,175 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include "list.h"
#include "kernel_defines.h"
#include "topology.h"
#include "zep_parser.h"
typedef struct {
list_node_t node;
struct sockaddr_in6 addr;
} zep_client_t;
static void dispatch_loop(int sock)
{
list_node_t head = { .next = NULL };
typedef void (*dispatch_cb_t)(void *ctx, void *buffer, size_t len,
int sock, struct sockaddr_in6 *src_addr);
/* all nodes are directly connected */
static void _send_flat(void *ctx, void *buffer, size_t len,
int sock, struct sockaddr_in6 *src_addr)
{
list_node_t *head = ctx;
char addr_str[INET6_ADDRSTRLEN];
/* send packet to all other clients */
bool known_node = false;
list_node_t *prev = head;
for (list_node_t *n = head->next; n; n = n->next) {
struct sockaddr_in6 *addr = &container_of(n, zep_client_t, node)->addr;
/* don't echo packet back to sender */
if (memcmp(src_addr, addr, sizeof(*addr)) == 0) {
known_node = true;
/* remove client if sending fails */
}
else if (sendto(sock, buffer, len, 0, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN);
printf("removing [%s]:%d\n", addr_str, ntohs(addr->sin6_port));
prev->next = n->next;
free(n);
continue;
}
prev = n;
}
/* if the client new, add it to the broadcast list */
if (!known_node) {
inet_ntop(AF_INET6, &src_addr->sin6_addr, addr_str, INET6_ADDRSTRLEN);
printf("adding [%s]:%d\n", addr_str, ntohs(src_addr->sin6_port));
zep_client_t *client = malloc(sizeof(zep_client_t));
memcpy(&client->addr, src_addr, sizeof(*src_addr));
list_add(head, &client->node);
}
}
/* nodes are connected as described by topology */
static void _send_topology(void *ctx, void *buffer, size_t len,
int sock, struct sockaddr_in6 *src_addr)
{
uint8_t mac_src[8];
uint8_t mac_src_len;
if (zep_parse_mac(buffer, len, mac_src, &mac_src_len) &&
topology_add(ctx, mac_src, mac_src_len, src_addr)) {
topology_send(ctx, sock, mac_src, mac_src_len, buffer, len);
}
}
static void dispatch_loop(int sock, dispatch_cb_t dispatch, void *ctx)
{
puts("entering loop…");
while (1) {
char addr_str[INET6_ADDRSTRLEN];
uint8_t buffer[ZEP_DISPATCH_PDU];
struct sockaddr_in6 src_addr;
socklen_t addr_len = sizeof(src_addr);
/* receive incoming packet */
ssize_t bytes_in = recvfrom(sock, buffer, sizeof(buffer), 0,
(struct sockaddr*)&src_addr, &addr_len);
(struct sockaddr *)&src_addr, &addr_len);
if (bytes_in <= 0 || addr_len != sizeof(src_addr)) {
continue;
}
/* send packet to all other clients */
bool known_node = false;
list_node_t *prev = &head;
for (list_node_t* n = head.next; n; n = n->next) {
struct sockaddr_in6 *addr = &container_of(n, zep_client_t, node)->addr;
/* don't echo packet back to sender */
if (memcmp(&src_addr, addr, addr_len) == 0) {
known_node = true;
/* remove client if sending fails */
} else if (sendto(sock, buffer, bytes_in, 0, (struct sockaddr*)addr, addr_len) < 0) {
inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN);
printf("removing [%s]:%d\n", addr_str, ntohs(addr->sin6_port));
prev->next = n->next;
free(n);
continue;
}
prev = n;
}
/* if the client new, add it to the broadcast list */
if (!known_node) {
inet_ntop(AF_INET6, &src_addr.sin6_addr, addr_str, INET6_ADDRSTRLEN);
printf("adding [%s]:%d\n", addr_str, ntohs(src_addr.sin6_port));
zep_client_t *client = malloc(sizeof(zep_client_t));
memcpy(&client->addr, &src_addr, addr_len);
list_add(&head, &client->node);
}
dispatch(ctx, buffer, bytes_in, sock, &src_addr);
}
}
static topology_t topology;
static const char *graphviz_file;
static void _info_handler(int signal)
{
if (signal != SIGUSR1) {
return;
}
if (topology_print(graphviz_file, &topology)) {
fprintf(stderr, "can't open %s\n", graphviz_file);
}
else {
printf("graph written to %s\n", graphviz_file);
}
}
static void _print_help(const char *progname)
{
fprintf(stderr, "usage: %s [-t topology] [-s seed] [-g graphviz_out] <address> <port>\n",
progname);
fprintf(stderr, "\npositional arguments:\n");
fprintf(stderr, "\taddress\t\tlocal address to bind to\n");
fprintf(stderr, "\tport\t\tlocal port to bind to\n");
fprintf(stderr, "\noptional arguments:\n");
fprintf(stderr, "\t-t <file>\tLoad toplogy from file\n");
fprintf(stderr, "\t-s <seed>\tRandom seed used to simulate packet loss\n");
fprintf(stderr, "\t-g <file>\tFile to dump topology as Graphviz visualisation on SIGUSR1\n");
}
int main(int argc, char **argv)
{
if (argc < 3) {
fprintf(stderr, "usage: %s <address> <port>\n",
argv[0]);
int c;
unsigned int seed = time(NULL);
const char *topo_file = NULL;
const char *progname = argv[0];
while ((c = getopt(argc, argv, "t:s:g:")) != -1) {
switch (c) {
case 't':
topo_file = optarg;
break;
case 's':
seed = atoi(optarg);
break;
case 'g':
graphviz_file = optarg;
break;
default:
_print_help(progname);
exit(1);
}
}
argc -= optind;
argv += optind;
if (argc != 2) {
_print_help(progname);
exit(1);
}
srand(seed);
if (topo_file) {
if (topology_parse(topo_file, &topology)) {
fprintf(stderr, "can't open '%s'\n", topo_file);
return -1;
}
topology.flat = false;
}
else {
topology.flat = true;
}
if (graphviz_file) {
signal(SIGUSR1, _info_handler);
}
struct addrinfo hint = {
.ai_family = AF_INET6,
.ai_socktype = SOCK_DGRAM,
@ -92,8 +192,9 @@ int main(int argc, char **argv)
};
struct addrinfo *server_addr;
int res = getaddrinfo(argv[1], argv[2],
int res = getaddrinfo(argv[0], argv[1],
&hint, &server_addr);
if (res != 0) {
perror("getaddrinfo()");
exit(1);
@ -101,6 +202,7 @@ int main(int argc, char **argv)
int sock = socket(server_addr->ai_family, server_addr->ai_socktype,
server_addr->ai_protocol);
if (sock < 0) {
perror("socket() failed");
exit(1);
@ -113,7 +215,12 @@ int main(int argc, char **argv)
freeaddrinfo(server_addr);
dispatch_loop(sock);
if (topology.flat) {
dispatch_loop(sock, _send_flat, &topology.nodes);
}
else {
dispatch_loop(sock, _send_topology, &topology);
}
close(sock);

281
dist/tools/zep_dispatch/topology.c vendored Normal file
View File

@ -0,0 +1,281 @@
/*
* Copyright (C) 2021 Benjamin Valentin
*
* This file is subject to the terms and conditions of the GNU General Public
* License v2. See the file LICENSE for more details.
*/
#include <arpa/inet.h>
#include <netdb.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "kernel_defines.h"
#include "topology.h"
#include "zep_parser.h"
#define NODE_NAME_MAX_LEN 32
#define HW_ADDR_MAX_LEN 8
struct node {
list_node_t next;
char name[NODE_NAME_MAX_LEN];
uint8_t mac[HW_ADDR_MAX_LEN];
struct sockaddr_in6 addr;
uint8_t mac_len;
};
struct edge {
list_node_t next;
struct node *a;
struct node *b;
float weight_a_b;
float weight_b_a;
};
static char *_fmt_addr(char *out, size_t out_len, const uint8_t *addr, uint8_t addr_len)
{
char *start = out;
if (out_len < 3 * addr_len) {
return NULL;
}
while (addr_len--) {
out += sprintf(out, "%02X", *addr++);
*(out++) = addr_len ? ':' : '\0';
}
return start;
}
static struct node *_find_node_by_name(const list_node_t *nodes, const char *name)
{
for (list_node_t *node = nodes->next; node; node = node->next) {
struct node *super = container_of(node, struct node, next);
if (strncmp(super->name, name, sizeof(super->name)) == 0) {
return super;
}
}
return NULL;
}
static struct node *_find_or_create_node(list_node_t *nodes, const char *name)
{
struct node *node = _find_node_by_name(nodes, name);
if (node == NULL) {
node = malloc(sizeof(*node));
strncpy(node->name, name, sizeof(node->name) - 1);
node->mac_len = 0;
list_add(nodes, &node->next);
}
return node;
}
static bool _parse_line(char *line, list_node_t *nodes, list_node_t *edges)
{
struct edge *e;
if (*line == '#') {
return true;
}
char *a = strtok(line, "\t ");
char *b = strtok(NULL, "\n\t ");
char *e_ab = strtok(NULL, "\n\t ");
char *e_ba = strtok(NULL, "\n\t ");
if (a == NULL || b == NULL) {
return false;
}
if (e_ab == NULL) {
e_ab = "1";
}
if (e_ba == NULL) {
e_ba = e_ab;
}
e = malloc(sizeof(*e));
e->a = _find_or_create_node(nodes, a);
e->b = _find_or_create_node(nodes, b);
e->weight_a_b = atof(e_ab);
e->weight_b_a = atof(e_ba);
list_add(edges, &e->next);
return true;
}
int topology_print(const char *file, const topology_t *t)
{
FILE *out;
char addr_str[3 * HW_ADDR_MAX_LEN];
if (t->flat) {
// TODO
return 0;
}
if (strcmp(file, "-") == 0) {
out = stdout;
}
else {
out = fopen(file, "w");
}
if (out == NULL) {
return -1;
}
fprintf(out, "digraph G {\n");
for (list_node_t *node = t->nodes.next; node; node = node->next) {
struct node *super = container_of(node, struct node, next);
fprintf(out, "\t%s [ label = \"%s\\n[%s]\" ]\n",
super->name, super->name,
super->mac_len ? _fmt_addr(addr_str, sizeof(addr_str), super->mac, super->mac_len)
: "disconnected");
}
fprintf(out, "\n");
for (list_node_t *edge = t->edges.next; edge; edge = edge->next) {
struct edge *super = container_of(edge, struct edge, next);
fprintf(out, "\t%s -> %s [ label = \"%.2f\" ]\n",
super->a->name, super->b->name, super->weight_a_b);
fprintf(out, "\t%s -> %s [ label = \"%.2f\" ]\n",
super->b->name, super->a->name, super->weight_b_a);
}
fprintf(out, "}\n");
if (out != stdout) {
fclose(out);
}
return 0;
}
int topology_parse(const char *file, topology_t *out)
{
FILE *in;
memset(out, 0, sizeof(*out));
if (strcmp(file, "-") == 0) {
in = stdin;
}
else {
in = fopen(file, "r");
}
if (in == NULL) {
return -1;
}
char *line = NULL;
size_t line_len = 0;
while (getline(&line, &line_len, in) > 0) {
_parse_line(line, &out->nodes, &out->edges);
}
if (line) {
free(line);
}
return 0;
}
void topology_send(const topology_t *t, int sock,
const uint8_t *mac_src, size_t mac_src_len,
void *buffer, size_t len)
{
for (list_node_t *edge = t->edges.next; edge; edge = edge->next) {
struct edge *super = container_of(edge, struct edge, next);
if (!super->a->mac_len || !super->b->mac_len) {
continue;
}
if ((mac_src_len == super->a->mac_len) &&
(memcmp(super->a->mac, mac_src, mac_src_len) == 0)) {
/* packet loss */
if (random() > super->weight_a_b * RAND_MAX) {
return;
}
zep_set_lqi(buffer, super->weight_a_b * 0xFF);
sendto(sock, buffer, len, 0,
(struct sockaddr *)&super->b->addr,
sizeof(super->b->addr));
}
else if ((mac_src_len == super->a->mac_len) &&
(memcmp(super->b->mac, mac_src, mac_src_len) == 0)) {
/* packet loss */
if (random() > super->weight_b_a * RAND_MAX) {
return;
}
zep_set_lqi(buffer, super->weight_b_a * 0xFF);
sendto(sock, buffer, len, 0,
(struct sockaddr *)&super->a->addr,
sizeof(super->a->addr));
}
}
}
bool topology_add(topology_t *t, const uint8_t *mac, uint8_t mac_len,
struct sockaddr_in6 *addr)
{
struct node *empty = NULL;
char addr_str[3 * HW_ADDR_MAX_LEN];
if (mac_len > HW_ADDR_MAX_LEN) {
fprintf(stderr, "discarding frame with %u byte address\n", mac_len);
return false;
}
for (list_node_t *node = t->nodes.next; node; node = node->next) {
struct node *super = container_of(node, struct node, next);
/* store free node */
if (!super->mac_len) {
empty = super;
continue;
}
if (mac_len != super->mac_len) {
continue;
}
/* abort if node is already in list */
if (memcmp(super->mac, mac, mac_len) == 0) {
return true;
}
}
/* topology full - can't add node */
if (empty == NULL) {
fprintf(stderr, "can't add %s - topology full\n",
_fmt_addr(addr_str, sizeof(addr_str), mac, mac_len));
return false;
}
printf("adding node %s\n", _fmt_addr(addr_str, sizeof(addr_str), mac, mac_len));
/* add new node to empty spot */
memcpy(empty->mac, mac, sizeof(empty->mac));
memcpy(&empty->addr, addr, sizeof(empty->addr));
empty->mac_len = mac_len;
return true;
}

79
dist/tools/zep_dispatch/topology.h vendored Normal file
View File

@ -0,0 +1,79 @@
/*
* Copyright (C) 2021 Benjamin Valentin
*
* This file is subject to the terms and conditions of the GNU General Public
* License v2. See the file LICENSE for more details.
*/
#ifndef TOPOLOGY_H
#define TOPOLOGY_H
#include "list.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Struct describing a graph of nodes and their connections
*/
typedef struct {
bool flat; /**< flat topology, all nodes are connected to each other */
list_node_t nodes; /**< list of nodes */
list_node_t edges; /**< list of connections between nodes. Unused if topology is flat */
} topology_t;
/**
* @brief Parse a file with topology information
*
* @param[in] file Filename to open & parse
* May be "-" to use stdin
* @param[out] out Topology from file
*
* @return 0 on success, error otherwise
*/
int topology_parse(const char *file, topology_t *out);
/**
* @brief Print topology as Graphviz diagram
*
* @param[in] file_out Filename to write to
* May be "-" to use stdout
* @param[in] t The topology to render
*
* @return 0 on success, error otherwise
*/
int topology_print(const char *file_out, const topology_t *t);
/**
* @brief Populate a spot in the topology with a connected node
*
* @param[in, out] t topology to use
* @param[in] mac ZEP l2 address of the new node
* @param[in] mac_len ZEP l2 address length
* @param[in] addr real address of the virtual node
*
* @return true if the node could be added to the topology
*/
bool topology_add(topology_t *t, const uint8_t *mac, uint8_t mac_len,
struct sockaddr_in6 *addr);
/**
* @brief Send a buffer to all nodes connected to a source node
*
* @param[in] t topology to use
* @param[in] sock socket to use for sending
* @param[in] mac_src ZEP source l2 address
* @param[in] mac_src_len ZEP source l2 address length
* @param[in] buffer ZEP frame to send
* @param[in] len ZEP frame length
*/
void topology_send(const topology_t *t, int sock,
const uint8_t *mac_src, size_t mac_src_len,
void *buffer, size_t len);
#ifdef __cplusplus
}
#endif
#endif /* TOPOLOGY_H */

78
dist/tools/zep_dispatch/zep_parser.c vendored Normal file
View File

@ -0,0 +1,78 @@
/*
* Copyright (C) 2021 Benjamin Valentin
*
* This file is subject to the terms and conditions of the GNU General Public
* License v2. See the file LICENSE for more details.
*/
#include <string.h>
#include "net/ieee802154.h"
#include "net/zep.h"
#include "zep_parser.h"
#define SOCKET_ZEP_V2_TYPE_HELLO (255)
bool zep_parse_mac(const void *buffer, size_t len, void *out, uint8_t *out_len)
{
const void *payload;
const zep_v2_data_hdr_t *zep = buffer;
if (len == 0) {
return false;
}
if ((zep->hdr.preamble[0] != 'E') || (zep->hdr.preamble[1] != 'X')) {
return false;
}
if (zep->hdr.version != 2) {
return false;
}
switch (zep->type) {
case ZEP_V2_TYPE_DATA:
payload = (zep_v2_data_hdr_t *)zep + 1;
break;
case ZEP_V2_TYPE_ACK:
payload = (zep_v2_ack_hdr_t *)zep + 1;
break;
case SOCKET_ZEP_V2_TYPE_HELLO:
/* HELLO packet only contains HW addr as payload */
payload = (zep_v2_data_hdr_t *)zep + 1;
*out_len = zep->length;
if (*out_len < zep->length) {
return false;
}
memcpy(out, payload, zep->length);
*out_len = zep->length;
return true;
default:
return false;
}
le_uint16_t dst_pan;
int res = ieee802154_get_src(payload, out, &dst_pan);
if (res <= 0) {
return false;
}
*out_len = res;
/* check that we are not out of bounds */
return (uintptr_t)payload + *out_len < (uintptr_t)buffer + len;
}
void zep_set_lqi(void *buffer, uint8_t lqi)
{
zep_v2_data_hdr_t *zep = buffer;
if (zep->type != ZEP_V2_TYPE_DATA) {
return;
}
zep->lqi_val = lqi;
}

42
dist/tools/zep_dispatch/zep_parser.h vendored Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2021 Benjamin Valentin
*
* This file is subject to the terms and conditions of the GNU General Public
* License v2. See the file LICENSE for more details.
*/
#ifndef ZEP_PARSER_H
#define ZEP_PARSER_H
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Parse l2 source address of a ZEP frame
*
* @param[in] buffer ZEP frame
* @param[in] len size of buffer
* @param[out] out destination for l2 address
* @param[out] out_len l2 address length
*
* @return true if l2 address was found
*/
bool zep_parse_mac(const void *buffer, size_t len, void *out, uint8_t *out_len);
/**
* @brief Set link quality information in ZEP frame
*
* @param[out] buffer ZEP frame to modify
* @param[in] lqi link quality to write to ZEP header
*/
void zep_set_lqi(void *buffer, uint8_t lqi);
#ifdef __cplusplus
}
#endif
#endif /* ZEP_PARSER_H */