diff --git a/boards/native/Makefile.dep b/boards/native/Makefile.dep index 8dc1684aab..911661afef 100644 --- a/boards/native/Makefile.dep +++ b/boards/native/Makefile.dep @@ -14,11 +14,4 @@ ifneq (,$(filter periph_can,$(FEATURES_USED))) endif endif -ifneq (,$(filter socket_zep,$(USEMODULE))) - USEMODULE += iolist - USEMODULE += netdev_ieee802154 - USEMODULE += checksum - USEMODULE += random -endif - USEMODULE += native_drivers diff --git a/cpu/native/Makefile.dep b/cpu/native/Makefile.dep index c90983f929..e75b24467b 100644 --- a/cpu/native/Makefile.dep +++ b/cpu/native/Makefile.dep @@ -30,6 +30,16 @@ ifneq (,$(filter native_cli_eui_provider,$(USEMODULE))) USEMODULE += l2util endif +ifneq (,$(filter socket_zep,$(USEMODULE))) + USEMODULE += iolist + USEMODULE += checksum + USEMODULE += random + USEMODULE += ieee802154 + ifneq (,$(filter netdev,$(USEMODULE))) + USEMODULE += netdev_ieee802154_submac + endif +endif + USEMODULE += periph # UART is needed by startup.c diff --git a/cpu/native/include/socket_zep.h b/cpu/native/include/socket_zep.h index 4731cb0a6a..034056d364 100644 --- a/cpu/native/include/socket_zep.h +++ b/cpu/native/include/socket_zep.h @@ -58,31 +58,13 @@ #include "net/netdev.h" #include "net/netdev/ieee802154.h" +#include "net/ieee802154/radio.h" #include "net/zep.h" #ifdef __cplusplus extern "C" { #endif -/** - * @brief ZEP device state - */ -typedef struct { - netdev_ieee802154_t netdev; /**< netdev internal member */ - int sock_fd; /**< socket fd */ - netdev_event_t last_event; /**< event triggered */ - uint32_t seq; /**< ZEP sequence number */ - /** - * @brief Receive buffer - */ - uint8_t rcv_buf[sizeof(zep_v2_data_hdr_t) + IEEE802154_FRAME_LEN_MAX]; - /** - * @brief Buffer for send header - */ - uint8_t snd_hdr_buf[sizeof(zep_v2_data_hdr_t)]; - uint16_t chksum_buf; /**< buffer for send checksum calculation */ -} socket_zep_t; - /** * @brief ZEP device initialization parameters */ @@ -93,15 +75,47 @@ typedef struct { char *remote_port; /**< local address string */ } socket_zep_params_t; +/** + * @brief ZEP device state + */ +typedef struct { + /** + * @brief command line parameters + */ + const socket_zep_params_t *params; + int sock_fd; /**< socket fd */ + uint32_t seq; /**< ZEP sequence number */ + /** + * @brief Receive buffer + */ + uint8_t rcv_buf[sizeof(zep_v2_data_hdr_t) + IEEE802154_FRAME_LEN_MAX]; + /** + * @brief Send buffer + */ + uint8_t snd_buf[sizeof(zep_v2_data_hdr_t) + IEEE802154_FRAME_LEN_MAX]; + uint8_t snd_len; /**< bytes to send */ + uint16_t pan_id; /**< PAN ID of the ZEP network */ + uint16_t chan; /**< virtual radio channel */ + /** + * @brief Short address of the virtual radio + */ + uint8_t addr_short[IEEE802154_SHORT_ADDRESS_LEN]; + /** + * @brief Long address of the virtual radio + */ + uint8_t addr_long[IEEE802154_LONG_ADDRESS_LEN]; + ieee802154_filter_mode_t filter_mode; /**< frame filter mode */ + ieee802154_trx_state_t state; /**< radio state */ + bool send_hello; /**< send HELLO packet on connect */ +} socket_zep_t; + /** * @brief Setup socket_zep_t structure * * @param[in] dev the preallocated socket_zep_t device handle to setup * @param[in] params initialization parameters - * @param[in] index index of @p params in a global parameter struct array. - * If initialized manually, pass a unique identifier instead. */ -void socket_zep_setup(socket_zep_t *dev, const socket_zep_params_t *params, uint8_t index); +void socket_zep_setup(socket_zep_t *dev, const socket_zep_params_t *params); /** * @brief Cleanup socket resources @@ -110,6 +124,14 @@ void socket_zep_setup(socket_zep_t *dev, const socket_zep_params_t *params, uint */ void socket_zep_cleanup(socket_zep_t *dev); +/** + * @brief Setup socket ZEP in order to be used with the IEEE 802.15.4 Radio HAL + * + * @param[in] dev pointer to the socket ZEP instance + * @param[in] hal pointer to the HAL descriptor associated to the device + */ +void socket_zep_hal_setup(socket_zep_t *dev, ieee802154_dev_t *hal); + #ifdef __cplusplus } #endif diff --git a/cpu/native/socket_zep/Kconfig b/cpu/native/socket_zep/Kconfig new file mode 100644 index 0000000000..4b3d70d305 --- /dev/null +++ b/cpu/native/socket_zep/Kconfig @@ -0,0 +1,17 @@ +menuconfig MODULE_SOCKET_ZEP + bool "Socket-based ZEP" + depends on CPU_MODEL_NATIVE + depends on TEST_KCONFIG + select MODULE_IOLIST + select MODULE_CHECKSUM + select MODULE_RANDOM + select MODULE_IEEE802154 + help + UDP socket-based IEEE 802.15.4 device over ZEP + +config MODULE_SOCKET_ZEP_HELLO + bool "Send a dummy HELLO packet on startup" + depends on MODULE_SOCKET_ZEP + help + Say y to send a dummy HELLO packet on startup. This is used to make + dispatchers aware of the node. diff --git a/cpu/native/socket_zep/socket_zep.c b/cpu/native/socket_zep/socket_zep.c index 4e9a95b174..47c458a298 100644 --- a/cpu/native/socket_zep/socket_zep.c +++ b/cpu/native/socket_zep/socket_zep.c @@ -11,6 +11,7 @@ * * @file * @author Martine Lenders + * @author Benjamin Valentin */ #include @@ -28,11 +29,11 @@ #include "byteorder.h" #include "checksum/ucrc16.h" #include "native_internal.h" -#include "random.h" +#include "net/ieee802154/radio.h" #include "socket_zep.h" -#define ENABLE_DEBUG 0 +#define ENABLE_DEBUG 0 #include "debug.h" #define _UNIX_NTP_ERA_OFFSET (2208988800U) @@ -51,10 +52,10 @@ static size_t _zep_hdr_fill_v2_data(socket_zep_t *dev, zep_v2_data_hdr_t *hdr, real_gettimeofday(&tv, NULL); hdr->hdr.version = 2; hdr->type = ZEP_V2_TYPE_DATA; - hdr->chan = dev->netdev.chan; + hdr->chan = dev->chan; hdr->dev = byteorder_htons((uint16_t)((((intptr_t)dev)) & 0xffff)); hdr->lqi_mode = 1; - hdr->lqi_val = 0xff; /* TODO: set */ + hdr->lqi_val = 0xff; /* set by ZEP dispatcher */ hdr->time.seconds = byteorder_htonl(tv.tv_sec + _UNIX_NTP_ERA_OFFSET); assert(tv.tv_usec < TV_USEC_PER_SEC); hdr->time.fraction = byteorder_htonl( @@ -78,62 +79,6 @@ static inline size_t _zep_hdr_fill(socket_zep_t *dev, zep_hdr_t *hdr, payload_len); } -static size_t _prep_vector(socket_zep_t *dev, const iolist_t *iolist, - unsigned n, struct iovec *out) -{ - size_t bytes; - dev->chksum_buf = 0; - - bytes = iolist_size(iolist); - bytes += sizeof(uint16_t); /* FCS field */ - out[0].iov_base = &dev->snd_hdr_buf; - out[0].iov_len = _zep_hdr_fill(dev, out[0].iov_base, bytes); - for (unsigned i = 0; i < n; i++) { - /* discard const qualifier, we won't change anything. Promise! */ - out[i + 1].iov_base = iolist->iol_base; - out[i + 1].iov_len = iolist->iol_len; - dev->chksum_buf = ucrc16_calc_le(out[i + 1].iov_base, out[i + 1].iov_len, - UCRC16_CCITT_POLY_LE, dev->chksum_buf); - iolist = iolist->iol_next; - } - dev->chksum_buf = byteorder_btols(byteorder_htons(dev->chksum_buf)).u16; - out[n + 1].iov_base = &dev->chksum_buf; - out[n + 1].iov_len = sizeof(uint16_t); - return bytes; -} - -static int _send(netdev_t *netdev, const iolist_t *iolist) -{ - netdev_ieee802154_t *netdev_ieee802154 = container_of(netdev, netdev_ieee802154_t, netdev); - socket_zep_t *dev = container_of(netdev_ieee802154, socket_zep_t, netdev); - unsigned n = iolist_count(iolist); - struct iovec v[n + 2]; - int res; - - assert((dev != NULL) && (dev->sock_fd != 0)); - _prep_vector(dev, iolist, n, v); - DEBUG("socket_zep::send(%p, %p, %u)\n", (void *)netdev, (void *)iolist, n); - /* simulate TX_STARTED interrupt */ - if (netdev->event_callback) { - dev->last_event = NETDEV_EVENT_TX_STARTED; - netdev_trigger_event_isr(netdev); - thread_yield(); - } - res = writev(dev->sock_fd, v, n + 2); - if (res < 0) { - DEBUG("socket_zep::send: error writing packet: %s\n", strerror(errno)); - return res; - } - /* simulate TX_COMPLETE interrupt */ - if (netdev->event_callback) { - dev->last_event = NETDEV_EVENT_TX_COMPLETE; - netdev_trigger_event_isr(netdev); - thread_yield(); - } - - return res - v[0].iov_len - v[n + 1].iov_len; -} - static void _continue_reading(socket_zep_t *dev) { /* work around lost signals */ @@ -148,8 +93,7 @@ static void _continue_reading(socket_zep_t *dev) if (real_select(dev->sock_fd + 1, &rfds, NULL, NULL, &t) == 1) { int sig = SIGIO; extern int _sig_pipefd[2]; - extern ssize_t (*real_write)(int fd, const void * buf, size_t count); - real_write(_sig_pipefd[1], &sig, sizeof(int)); + real_write(_sig_pipefd[1], &sig, sizeof(sig)); _native_sigpend++; } else { @@ -164,173 +108,44 @@ static inline bool _dst_not_me(socket_zep_t *dev, const void *buf) uint8_t dst_addr[IEEE802154_LONG_ADDRESS_LEN] = { 0 }; int dst_len; le_uint16_t dst_pan = { .u16 = 0 }; + bool is_ack = *(uint8_t *)buf & IEEE802154_FCF_TYPE_ACK; + + /* no need to check address if we are in promiscuous mode */ + if (dev->filter_mode == IEEE802154_FILTER_PROMISC || + dev->filter_mode == IEEE802154_FILTER_SNIFFER) { + return false; + } + + /* ignore everything but ACK frames */ + if ((dev->filter_mode == IEEE802154_FILTER_ACK_ONLY) && !is_ack) { + DEBUG("socket_zep::dst_not_me: ignoring non-ACK frame\n"); + return true; + } + + /* ACKs carry no address */ + if (is_ack) { + DEBUG("socket_zep::dst_not_me: got ACK\n"); + return false; + } + + dst_len = ieee802154_get_dst(buf, dst_addr, &dst_pan); + + if (dst_pan.u16 != dev->pan_id) { + DEBUG("socket_zep::dst_not_me: PAN ID %x != %x\n", dst_pan.u16, dev->pan_id); + return true; + } - dst_len = ieee802154_get_dst(buf, dst_addr, - &dst_pan); switch (dst_len) { - case IEEE802154_LONG_ADDRESS_LEN: - return memcmp(dst_addr, dev->netdev.long_addr, dst_len) != 0; - case IEEE802154_SHORT_ADDRESS_LEN: - return (memcmp(dst_addr, ieee802154_addr_bcast, dst_len) != 0) && - (memcmp(dst_addr, dev->netdev.short_addr, dst_len) != 0); - default: - return false; /* better safe than sorry ;-) */ + case IEEE802154_LONG_ADDRESS_LEN: + return memcmp(dst_addr, dev->addr_long, dst_len); + case IEEE802154_SHORT_ADDRESS_LEN: + return memcmp(dst_addr, ieee802154_addr_bcast, dst_len) && + memcmp(dst_addr, dev->addr_short, dst_len); + default: + return false; /* better safe than sorry ;-) */ } } -static int _recv(netdev_t *netdev, void *buf, size_t len, void *info) -{ - netdev_ieee802154_t *netdev_ieee802154 = container_of(netdev, netdev_ieee802154_t, netdev); - socket_zep_t *dev = container_of(netdev_ieee802154, socket_zep_t, netdev); - int size = 0; - - DEBUG("socket_zep::recv(%p, %p, %u, %p)\n", (void *)netdev, buf, - (unsigned)len, (void *)info); - if ((buf == NULL) || (len == 0)) { - int res = real_ioctl(dev->sock_fd, FIONREAD, &size); - - if (IS_ACTIVE(ENABLE_DEBUG)) { - if (res < 0) { - DEBUG("socket_zep::recv: error reading FIONREAD: %s", - strerror(errno)); - } - } - - return size; - } - else if (len > 0) { - size = real_read(dev->sock_fd, dev->rcv_buf, sizeof(dev->rcv_buf)); - - if (size > 0) { - zep_hdr_t *tmp = (zep_hdr_t *)&dev->rcv_buf; - - if ((tmp->preamble[0] != 'E') || (tmp->preamble[1] != 'X')) { - DEBUG("socket_zep::recv: invalid ZEP header"); - return -1; - } - switch (tmp->version) { - case 2: { - zep_v2_data_hdr_t *zep = (zep_v2_data_hdr_t *)tmp; - void *payload = &dev->rcv_buf[sizeof(zep_v2_data_hdr_t)]; - - if (zep->type != ZEP_V2_TYPE_DATA) { - DEBUG("socket_zep::recv: unexpected ZEP type\n"); - /* don't support ACK frames for now*/ - return -1; - } - if (((sizeof(zep_v2_data_hdr_t) + zep->length) != (unsigned)size) || - (zep->length > len) || (zep->chan != dev->netdev.chan) || - /* TODO promiscuous mode */ - _dst_not_me(dev, payload)) { - /* TODO: check checksum */ - return -1; - } - /* don't hand FCS to stack */ - size = zep->length - sizeof(uint16_t); - if (buf != NULL) { - memcpy(buf, payload, size); - if (info != NULL) { - struct netdev_radio_rx_info *rx_info = info; - rx_info->lqi = zep->lqi_val; - rx_info->rssi = UINT8_MAX; - } - } - break; - } - default: - DEBUG("socket_zep::recv: unexpected ZEP version\n"); - return -1; - } - } - else if (size == 0) { - DEBUG("socket_zep::recv: ignoring null-event\n"); - return -1; - } - else if (size == -1) { - if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { - } - else { - err(EXIT_FAILURE, "zep: read"); - } - } - else { - errx(EXIT_FAILURE, "internal error _rx_event"); - } - } - _continue_reading(dev); - - return size; -} - -static void _isr(netdev_t *netdev) -{ - if (netdev->event_callback) { - netdev_ieee802154_t *netdev_ieee802154 = container_of(netdev, netdev_ieee802154_t, netdev); - socket_zep_t *dev = container_of(netdev_ieee802154, socket_zep_t, netdev); - - DEBUG("socket_zep::isr: firing %u\n", (unsigned)dev->last_event); - netdev->event_callback(netdev, dev->last_event); - } - return; -} - -static void _socket_isr(int fd, void *arg) -{ - (void)fd; - (void)arg; - netdev_t *netdev = arg; - - DEBUG("socket_zep::_socket_isr: %d, %p (netdev == %p)\n", - fd, arg, (void *)netdev); - if (netdev == NULL) { - return; - } - if (netdev->event_callback) { - netdev_ieee802154_t *netdev_ieee802154 = container_of(netdev, netdev_ieee802154_t, netdev); - socket_zep_t *dev = container_of(netdev_ieee802154, socket_zep_t, netdev); - - dev->last_event = NETDEV_EVENT_RX_COMPLETE; - netdev_trigger_event_isr(netdev); - } -} - -static int _init(netdev_t *netdev) -{ - netdev_ieee802154_t *netdev_ieee802154 = container_of(netdev, netdev_ieee802154_t, netdev); - socket_zep_t *dev = container_of(netdev_ieee802154, socket_zep_t, netdev); - - netdev_ieee802154_reset(&dev->netdev); - - assert(dev != NULL); - dev->netdev.chan = CONFIG_IEEE802154_DEFAULT_CHANNEL; - - return 0; -} - -static int _get(netdev_t *netdev, netopt_t opt, void *value, size_t max_len) -{ - assert(netdev != NULL); - return netdev_ieee802154_get(container_of(netdev, netdev_ieee802154_t, netdev), - opt, value, max_len); -} - -static int _set(netdev_t *netdev, netopt_t opt, const void *value, - size_t value_len) -{ - assert(netdev != NULL); - return netdev_ieee802154_set(container_of(netdev, netdev_ieee802154_t, netdev), opt, - value, value_len); -} - -static const netdev_driver_t socket_zep_driver = { - .send = _send, - .recv = _recv, - .init = _init, - .isr = _isr, - .get = _get, - .set = _set, -}; - static int _bind_local(const socket_zep_params_t *params) { int res; @@ -401,55 +216,46 @@ static int _connect_remote(socket_zep_t *dev, const socket_zep_params_t *params) static void _send_zep_hello(socket_zep_t *dev) { - if (IS_USED(MODULE_SOCKET_ZEP_HELLO)) { + if (IS_USED(MODULE_SOCKET_ZEP_HELLO) && dev->send_hello) { /* dummy packet */ zep_v2_data_hdr_t hdr = { .hdr.preamble = "EX", .hdr.version = 2, .type = SOCKET_ZEP_V2_TYPE_HELLO, .resv = "HELLO", - .length = sizeof(dev->netdev.long_addr), + .length = sizeof(dev->addr_long), }; /* 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); + real_send(dev->sock_fd, dev->addr_long, sizeof(dev->addr_long), 0); } } -void socket_zep_setup(socket_zep_t *dev, const socket_zep_params_t *params, uint8_t index) +static void _socket_isr(int fd, void *arg) { - int res; + ieee802154_dev_t *dev = arg; + socket_zep_t *zepdev = dev->priv; + DEBUG("socket_zep::_socket_isr: bytes on %d\n", fd); + + if (zepdev->state == IEEE802154_TRX_STATE_RX_ON) { + dev->cb(dev, IEEE802154_RADIO_INDICATION_RX_DONE); + } else { + /* discard frame */ + uint8_t tmp; + real_read(fd, &tmp, sizeof(tmp)); + _continue_reading(zepdev); + } +} + +void socket_zep_setup(socket_zep_t *dev, const socket_zep_params_t *params) +{ DEBUG("socket_zep_setup(%p, %p)\n", (void *)dev, (void *)params); assert((params->remote_addr != NULL) && (params->remote_port != NULL)); - memset(dev, 0, sizeof(socket_zep_t)); - dev->netdev.netdev.driver = &socket_zep_driver; - - netdev_register(&dev->netdev.netdev, NETDEV_SOCKET_ZEP, index); - - res = _bind_local(params); - - if (res < 0) { - dev->sock_fd = socket(AF_INET6, SOCK_DGRAM, 0); - } else { - dev->sock_fd = res; - } - - /* 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); - } - + dev->params = params; native_async_read_setup(); - native_async_read_add_handler(dev->sock_fd, dev, _socket_isr); } void socket_zep_cleanup(socket_zep_t *dev) @@ -462,4 +268,355 @@ void socket_zep_cleanup(socket_zep_t *dev) dev->sock_fd = 0; } +static int _request_on(ieee802154_dev_t *dev) +{ + socket_zep_t *zepdev = dev->priv; + + DEBUG("socket_zep::request_on()\n"); + + int res = _bind_local(zepdev->params); + + if (res < 0) { + zepdev->sock_fd = socket(AF_INET6, SOCK_DGRAM, 0); + res = zepdev->sock_fd; + } else { + zepdev->sock_fd = res; + } + + if (res < 0) { + return res; + } + + native_async_read_add_handler(zepdev->sock_fd, dev, _socket_isr); + + /* only send hello if we are connected to a remote */ + zepdev->send_hello = !_connect_remote(zepdev, zepdev->params); + + return 0; +} + +static int _confirm_on(ieee802154_dev_t *dev) +{ + (void) dev; + return 0; +} + +static int _off(ieee802154_dev_t *dev) +{ + socket_zep_t *zepdev = dev->priv; + + DEBUG("socket_zep::off()\n"); + + close(zepdev->sock_fd); + zepdev->sock_fd = -1; + return 0; +} + +static int _set_cca_mode(ieee802154_dev_t *dev, ieee802154_cca_mode_t mode) +{ + (void) dev; + (void) mode; + return 0; +} + +static int _request_cca(ieee802154_dev_t *dev) +{ + (void) dev; + return 0; +} + +static int _confirm_cca(ieee802154_dev_t *dev) +{ + (void) dev; + assert(false); + return 0; +} + +static int _set_cca_threshold(ieee802154_dev_t *dev, int8_t threshold) +{ + (void) dev; + (void) threshold; + return 0; +} + +static int _set_csma_params(ieee802154_dev_t *dev, const ieee802154_csma_be_t *bd, + int8_t retries) +{ + (void) dev; + (void) bd; + (void) retries; + return 0; +} + +static int _config_phy(ieee802154_dev_t *dev, const ieee802154_phy_conf_t *conf) +{ + (void) dev; + (void) conf; + return 0; +} + +static int _config_addr_filter(ieee802154_dev_t *dev, ieee802154_af_cmd_t cmd, const void *value) +{ + socket_zep_t *zepdev = dev->priv; + + switch (cmd) { + case IEEE802154_AF_SHORT_ADDR: + memcpy(zepdev->addr_short, value, IEEE802154_SHORT_ADDRESS_LEN); + break; + case IEEE802154_AF_EXT_ADDR: + memcpy(zepdev->addr_long, value, IEEE802154_LONG_ADDRESS_LEN); + _send_zep_hello(zepdev); + break; + case IEEE802154_AF_PANID: + memcpy(&zepdev->pan_id, value, sizeof(zepdev->pan_id)); + break; + case IEEE802154_AF_PAN_COORD: + return -ENOTSUP; + } + + return 0; +} + +static int _config_src_addr_match(ieee802154_dev_t *dev, ieee802154_src_match_t cmd, + const void *value) +{ + (void) dev; + (void) cmd; + (void) value; + return -ENOTSUP; +} + +static int _set_frame_filter_mode(ieee802154_dev_t *dev, ieee802154_filter_mode_t mode) +{ + socket_zep_t *zepdev = dev->priv; + zepdev->filter_mode = mode; + return 0; +} + +static int _request_set_trx_state(ieee802154_dev_t *dev, ieee802154_trx_state_t state) +{ + socket_zep_t *zepdev = dev->priv; + zepdev->state = state; + return 0; +} + +static int _confirm_set_trx_state(ieee802154_dev_t *dev) +{ + (void) dev; + return 0; +} + +static int _write(ieee802154_dev_t *dev, const iolist_t *iolist) +{ + socket_zep_t *zepdev = dev->priv; + unsigned n = iolist_count(iolist); + size_t bytes = iolist_size(iolist) + sizeof(uint16_t); /* FCS field */ + uint8_t *out = zepdev->snd_buf; + uint16_t chksum = 0; + + DEBUG("socket_zep::write(%zu bytes)\n", bytes); + + out += _zep_hdr_fill(zepdev, (void *)out, bytes); + + /* make sure we are not overflowing the TX buffer */ + if (out + bytes > zepdev->snd_buf + sizeof(zepdev->snd_buf)) { + return -ENOBUFS; + } + + for (unsigned i = 0; i < n; i++) { + memcpy(out, iolist->iol_base, iolist->iol_len); + chksum = ucrc16_calc_le(iolist->iol_base, iolist->iol_len, + UCRC16_CCITT_POLY_LE, chksum); + out += iolist->iol_len; + iolist = iolist->iol_next; + } + chksum = byteorder_htols(chksum).u16; + memcpy(out, &chksum, sizeof(chksum)); + out += sizeof(chksum); + + zepdev->snd_len = out - zepdev->snd_buf; + + return 0; +} + +static int _request_transmit(ieee802154_dev_t *dev) +{ + socket_zep_t *zepdev = dev->priv; + + DEBUG("socket_zep::request_transmit(%zu bytes)\n", zepdev->snd_len); + + dev->cb(dev, IEEE802154_RADIO_INDICATION_TX_START); + + int res = real_write(zepdev->sock_fd, zepdev->snd_buf, zepdev->snd_len); + + dev->cb(dev, IEEE802154_RADIO_CONFIRM_TX_DONE); + + if (res < 0) { + return res; + } + + return 0; +} + +static int _confirm_transmit(ieee802154_dev_t *dev, ieee802154_tx_info_t *info) +{ + (void) dev; + + if (info) { + info->status = TX_STATUS_SUCCESS; + } + + return 0; +} + +int _len(ieee802154_dev_t *dev) +{ + size_t size; + socket_zep_t *zepdev = dev->priv; + + int res = real_ioctl(zepdev->sock_fd, FIONREAD, &size); + if (res < 0) { + DEBUG("socket_zep::len: error reading FIONREAD: %s", strerror(errno)); + return 0; + } + + DEBUG("socket_zep::len %zu bytes on %d\n", size, zepdev->sock_fd); + + if (size < sizeof(zep_v2_data_hdr_t)) { + return 0; + } + + /* report size without ZEP header and checksum */ + return size - (sizeof(zep_v2_data_hdr_t) + 2); +} + +static void _send_ack(socket_zep_t *zepdev, const void *frame) +{ + const uint8_t *rxbuf = frame; + uint8_t ack[3]; + zep_v2_data_hdr_t hdr; + + if ((rxbuf[0] & IEEE802154_FCF_ACK_REQ) == 0) { + return; + } + + DEBUG("socket_zep::send_ack: seq_no: %u\n", rxbuf[2]); + + _zep_hdr_fill(zepdev, &hdr.hdr, sizeof(ack) + 2); + + ack[0] = IEEE802154_FCF_TYPE_ACK; /* FCF */ + ack[1] = 0; /* FCF */ + ack[2] = rxbuf[2]; /* SeqNum */ + + /* calculate checksum */ + uint16_t chksum = ucrc16_calc_le(ack, 3, UCRC16_CCITT_POLY_LE, 0); + + real_send(zepdev->sock_fd, &hdr, sizeof(hdr), MSG_MORE); + real_send(zepdev->sock_fd, ack, sizeof(ack), MSG_MORE); + real_send(zepdev->sock_fd, &chksum, sizeof(chksum), 0); +} + +static int _read(ieee802154_dev_t *dev, void *buf, size_t max_size, + ieee802154_rx_info_t *info) +{ + int res; + socket_zep_t *zepdev = dev->priv; + + DEBUG("socket_zep::read: reading up to %u bytes into %p\n", max_size, buf); + + if (max_size + sizeof(zep_v2_data_hdr_t) > sizeof(zepdev->rcv_buf)) { + return 0; + } + + res = real_read(zepdev->sock_fd, zepdev->rcv_buf, max_size + sizeof(zep_v2_data_hdr_t)); + + DEBUG("socket_zep::read: got %d bytes\n", res); + + if (res <= (int)sizeof(zep_v2_data_hdr_t)) { + res = 0; + goto out; + } + + zep_hdr_t *tmp = (zep_hdr_t *)zepdev->rcv_buf; + + if ((tmp->preamble[0] != 'E') || (tmp->preamble[1] != 'X')) { + DEBUG("socket_zep::read: invalid ZEP header\n"); + res = -EINVAL; + goto out; + } + + if (tmp->version != 2) { + DEBUG("socket_zep::read: unsupported ZEP version %u\n", tmp->version); + res = -EINVAL; + goto out; + } + + switch (((zep_v2_ack_hdr_t *)tmp)->type) { + case ZEP_V2_TYPE_DATA: { + zep_v2_data_hdr_t *zep = (zep_v2_data_hdr_t *)tmp; + + if (info) { + info->lqi = zep->lqi_val; + info->rssi = -IEEE802154_RADIO_RSSI_OFFSET; + } + + if (_dst_not_me(zepdev, zep + 1)) { + DEBUG("socket_zep::read: dst not me\n"); + break; + } + + _send_ack(zepdev, zep + 1); + + memcpy(buf, zep + 1, max_size); + res = max_size; + + break; + } + default: + DEBUG("socket_zep::read: unknown type %u\n", ((zep_v2_ack_hdr_t *)tmp)->type); + res = -EINVAL; + break; + } + +out: + _continue_reading(zepdev); + + return res; +} + +static const ieee802154_radio_ops_t socket_zep_rf_ops = { + .caps = IEEE802154_CAP_24_GHZ + | IEEE802154_CAP_AUTO_CSMA + | IEEE802154_CAP_IRQ_TX_DONE + | IEEE802154_CAP_IRQ_TX_START + | IEEE802154_CAP_PHY_OQPSK + | IEEE802154_CAP_RX_CONTINUOUS, + + .write = _write, + .read = _read, + .request_transmit = _request_transmit, + .confirm_transmit = _confirm_transmit, + .len = _len, + .off = _off, + .request_on = _request_on, + .confirm_on = _confirm_on, + .request_set_trx_state = _request_set_trx_state, + .confirm_set_trx_state = _confirm_set_trx_state, + .request_cca = _request_cca, + .confirm_cca = _confirm_cca, + .set_cca_threshold = _set_cca_threshold, + .set_cca_mode = _set_cca_mode, + .config_phy = _config_phy, + .config_addr_filter = _config_addr_filter, + .config_src_addr_match = _config_src_addr_match, + .set_csma_params = _set_csma_params, + .set_frame_filter_mode = _set_frame_filter_mode, +}; + +void socket_zep_hal_setup(socket_zep_t *dev, ieee802154_dev_t *hal) +{ + hal->driver = &socket_zep_rf_ops; + hal->priv = dev; +} + /** @} */ diff --git a/drivers/Kconfig.net b/drivers/Kconfig.net index 37738a53c5..0634122267 100644 --- a/drivers/Kconfig.net +++ b/drivers/Kconfig.net @@ -18,6 +18,7 @@ rsource "ncv7356/Kconfig" rsource "pn532/Kconfig" rsource "rn2xx3/Kconfig" rsource "slipdev/Kconfig" +rsource "$(RIOTCPU)/native/socket_zep/Kconfig" rsource "sx126x/Kconfig" rsource "sx127x/Kconfig" rsource "tja1042/Kconfig" diff --git a/pkg/lwip/init_devs/auto_init_socket_zep.c b/pkg/lwip/init_devs/auto_init_socket_zep.c index 3dca78c9b3..ebd5b028c6 100644 --- a/pkg/lwip/init_devs/auto_init_socket_zep.c +++ b/pkg/lwip/init_devs/auto_init_socket_zep.c @@ -19,6 +19,7 @@ #include "socket_zep.h" #include "socket_zep_params.h" +#include "net/netdev/ieee802154_submac.h" #include "lwip_init_devs.h" @@ -29,12 +30,18 @@ static struct netif netif[NETIF_SOCKET_ZEP_NUMOF]; static socket_zep_t socket_zep_devs[NETIF_SOCKET_ZEP_NUMOF]; +static netdev_ieee802154_submac_t socket_zep_netdev[SOCKET_ZEP_MAX]; static void auto_init_socket_zep(void) { for (unsigned i = 0; i < NETIF_SOCKET_ZEP_NUMOF; i++) { - socket_zep_setup(&socket_zep_devs[i], &socket_zep_params[i], i); - if (lwip_add_6lowpan(&netif[i], &socket_zep_devs[i].netdev.netdev) == NULL) { + netdev_register(&socket_zep_netdev[i].dev.netdev, NETDEV_SOCKET_ZEP, i); + netdev_ieee802154_submac_init(&socket_zep_netdev[i]); + socket_zep_hal_setup(&socket_zep_devs[i], &socket_zep_netdev[i].submac.dev); + + socket_zep_setup(&socket_zep_devs[i], &socket_zep_params[i]); + + if (lwip_add_6lowpan(&netif[i], &socket_zep_netdev[i].dev.netdev) == NULL) { DEBUG("Could not add socket_zep device\n"); return; } diff --git a/sys/net/gnrc/netif/init_devs/auto_init_socket_zep.c b/sys/net/gnrc/netif/init_devs/auto_init_socket_zep.c index 8f8c8795f2..6f59ba6ffe 100644 --- a/sys/net/gnrc/netif/init_devs/auto_init_socket_zep.c +++ b/sys/net/gnrc/netif/init_devs/auto_init_socket_zep.c @@ -22,6 +22,7 @@ #include "socket_zep_params.h" #include "net/gnrc/netif/ieee802154.h" #include "include/init_devs.h" +#include "net/netdev/ieee802154_submac.h" #define ENABLE_DEBUG 0 #include "debug.h" @@ -40,17 +41,22 @@ static char _socket_zep_stacks[SOCKET_ZEP_MAX][SOCKET_ZEP_MAC_STACKSIZE]; static socket_zep_t _socket_zeps[SOCKET_ZEP_MAX]; static gnrc_netif_t _netif[SOCKET_ZEP_MAX]; +static netdev_ieee802154_submac_t _socket_zep_netdev[SOCKET_ZEP_MAX]; void auto_init_socket_zep(void) { for (int i = 0; i < SOCKET_ZEP_MAX; i++) { LOG_DEBUG("[auto_init_netif: initializing socket ZEP device #%u\n", i); /* setup netdev device */ - socket_zep_setup(&_socket_zeps[i], &socket_zep_params[i], i); + netdev_register(&_socket_zep_netdev[i].dev.netdev, NETDEV_SOCKET_ZEP, i); + netdev_ieee802154_submac_init(&_socket_zep_netdev[i]); + socket_zep_hal_setup(&_socket_zeps[i], &_socket_zep_netdev[i].submac.dev); + + socket_zep_setup(&_socket_zeps[i], &socket_zep_params[i]); gnrc_netif_ieee802154_create(&_netif[i], _socket_zep_stacks[i], SOCKET_ZEP_MAC_STACKSIZE, SOCKET_ZEP_MAC_PRIO, "socket_zep", - &_socket_zeps[i].netdev.netdev); + &_socket_zep_netdev[i].dev.netdev); } } /** @} */ diff --git a/sys/net/link_layer/ieee802154/submac.c b/sys/net/link_layer/ieee802154/submac.c index 3025ef103a..fc483c0064 100644 --- a/sys/net/link_layer/ieee802154/submac.c +++ b/sys/net/link_layer/ieee802154/submac.c @@ -406,6 +406,10 @@ int ieee802154_send(ieee802154_submac_t *submac, const iolist_t *iolist) return -EBUSY; } + if (iolist == NULL) { + return 0; + } + uint8_t *buf = iolist->iol_base; bool cnf = buf[0] & IEEE802154_FCF_ACK_REQ; diff --git a/tests/gnrc_netif_ieee802154/Makefile b/tests/gnrc_netif_ieee802154/Makefile index 874bf8c861..079b3c68c4 100644 --- a/tests/gnrc_netif_ieee802154/Makefile +++ b/tests/gnrc_netif_ieee802154/Makefile @@ -6,6 +6,7 @@ TERMFLAGS ?= -z "0.0.0.0:17755,localhost:17754" USEMODULE += socket_zep USEMODULE += auto_init_gnrc_netif +USEMODULE += netdev USEMODULE += gnrc USEMODULE += gnrc_netif_ieee802154 USEMODULE += gnrc_pktdump diff --git a/tests/ieee802154_hal/Makefile b/tests/ieee802154_hal/Makefile index 3f2ae06c03..73627c20dc 100644 --- a/tests/ieee802154_hal/Makefile +++ b/tests/ieee802154_hal/Makefile @@ -6,6 +6,7 @@ BOARD_WHITELIST := \ arduino-nano-33-ble \ cc2538dk \ feather-nrf52840 \ + native \ nrf52840dk \ nrf52840dongle \ nrf52840-mdk \ @@ -19,6 +20,16 @@ BOARD_WHITELIST := \ DISABLE_MODULE += auto_init_at86rf2xx auto_init_nrf802154 +ifeq ($(BOARD), native) + ZEP_PORT_BASE ?= 17754 + TERMFLAGS += -z [::1]:$(ZEP_PORT_BASE) + USEMODULE += socket_zep + # the same for Kconfig + ifeq (1,$(TEST_KCONFIG)) + KCONFIG_ADD_CONFIG += $(APPDIR)/app.config.test.native + endif +endif + USEMODULE += od USEMODULE += luid USEMODULE += l2util diff --git a/tests/ieee802154_hal/app.config.test.native b/tests/ieee802154_hal/app.config.test.native new file mode 100644 index 0000000000..3d0f40860f --- /dev/null +++ b/tests/ieee802154_hal/app.config.test.native @@ -0,0 +1,6 @@ +CONFIG_MODULE_SOCKET_ZEP=y + +# Should be autoselecting the MODULE_PRNG_HWRNG if possible +# Since the makefile cannot we have to override until end of migration +# Remove when TEST_KCONFIG is complete +CONFIG_MODULE_PRNG_TINYMT32=y diff --git a/tests/ieee802154_hal/common.h b/tests/ieee802154_hal/common.h index 62d2ad6908..ecd3e6a246 100644 --- a/tests/ieee802154_hal/common.h +++ b/tests/ieee802154_hal/common.h @@ -19,9 +19,15 @@ #define COMMON_H #include "net/ieee802154/radio.h" +#if IS_USED(MODULE_SOCKET_ZEP) +#include "socket_zep_params.h" +#else +#define SOCKET_ZEP_MAX 0 +#endif #define RADIOS_NUMOF IS_USED(MODULE_CC2538_RF) + \ - IS_USED(MODULE_NRF802154) + IS_USED(MODULE_NRF802154) + \ + SOCKET_ZEP_MAX #if RADIOS_NUMOF == 0 #error "Radio is not supported" @@ -39,6 +45,7 @@ extern "C" { typedef enum { IEEE802154_DEV_TYPE_CC2538_RF, IEEE802154_DEV_TYPE_NRF802154, + IEEE802154_DEV_TYPE_SOCKET_ZEP, } ieee802154_dev_type_t; typedef ieee802154_dev_t* (*ieee802154_dev_cb_t)(ieee802154_dev_type_t type, diff --git a/tests/ieee802154_hal/init_devs.c b/tests/ieee802154_hal/init_devs.c index 68368dc93e..2d60fe3850 100644 --- a/tests/ieee802154_hal/init_devs.c +++ b/tests/ieee802154_hal/init_devs.c @@ -31,6 +31,11 @@ #include "nrf802154.h" #endif +#ifdef MODULE_SOCKET_ZEP +#include "socket_zep.h" +#include "socket_zep_params.h" +#endif + void ieee802154_hal_test_init_devs(ieee802154_dev_cb_t cb, void *opaque) { /* Call the init function of the device (this should be handled by @@ -50,4 +55,12 @@ void ieee802154_hal_test_init_devs(ieee802154_dev_cb_t cb, void *opaque) nrf802154_init(); } #endif + +#ifdef MODULE_SOCKET_ZEP + static socket_zep_t _socket_zeps[SOCKET_ZEP_MAX]; + if ((radio = cb(IEEE802154_DEV_TYPE_SOCKET_ZEP, opaque)) ){ + socket_zep_hal_setup(&_socket_zeps[0], radio); + socket_zep_setup(&_socket_zeps[0], &socket_zep_params[0]); + } +#endif } diff --git a/tests/ieee802154_hal/main.c b/tests/ieee802154_hal/main.c index c1043fb7ba..d0219b04e1 100644 --- a/tests/ieee802154_hal/main.c +++ b/tests/ieee802154_hal/main.c @@ -248,6 +248,9 @@ static ieee802154_dev_t *_reg_callback(ieee802154_dev_type_t type, void *opaque) case IEEE802154_DEV_TYPE_NRF802154: printf("nrf52840"); break; + case IEEE802154_DEV_TYPE_SOCKET_ZEP: + printf("socket_zep"); + break; } puts("."); diff --git a/tests/ieee802154_submac/Makefile b/tests/ieee802154_submac/Makefile index 198d60d39e..1975e1bcc0 100644 --- a/tests/ieee802154_submac/Makefile +++ b/tests/ieee802154_submac/Makefile @@ -6,6 +6,7 @@ BOARD_WHITELIST := \ arduino-nano-33-ble \ cc2538dk \ feather-nrf52840 \ + native \ nrf52840dk \ nrf52840dongle \ nrf52840-mdk \ @@ -29,6 +30,12 @@ USEMODULE += ieee802154 USEMODULE += ieee802154_submac USEMODULE += ztimer_usec +ifeq ($(BOARD), native) + ZEP_PORT_BASE ?= 17754 + TERMFLAGS += -z [::1]:$(ZEP_PORT_BASE) + USEMODULE += socket_zep +endif + CFLAGS += -DEVENT_THREAD_MEDIUM_STACKSIZE=1024 include $(RIOTBASE)/Makefile.include diff --git a/tests/ieee802154_submac/main.c b/tests/ieee802154_submac/main.c index 0de03bd8dd..80982e3602 100644 --- a/tests/ieee802154_submac/main.c +++ b/tests/ieee802154_submac/main.c @@ -187,6 +187,9 @@ static ieee802154_dev_t *_reg_callback(ieee802154_dev_type_t type, void *opaque) case IEEE802154_DEV_TYPE_NRF802154: printf("nrf52840"); break; + case IEEE802154_DEV_TYPE_SOCKET_ZEP: + printf("socket_zep"); + break; } puts("."); diff --git a/tests/socket_zep/Makefile b/tests/socket_zep/Makefile index ce9afc7c5f..0073b01ed6 100644 --- a/tests/socket_zep/Makefile +++ b/tests/socket_zep/Makefile @@ -8,6 +8,7 @@ TEST_ON_CI_BLACKLIST += native USEMODULE += od USEMODULE += socket_zep +USEMODULE += netdev TERMFLAGS ?= -z [::1]:17754 diff --git a/tests/socket_zep/main.c b/tests/socket_zep/main.c index fab8d17ab9..499d20f571 100644 --- a/tests/socket_zep/main.c +++ b/tests/socket_zep/main.c @@ -24,6 +24,7 @@ #include "byteorder.h" #include "net/ieee802154.h" +#include "net/netdev/ieee802154_submac.h" #include "sched.h" #include "socket_zep.h" #include "socket_zep_params.h" @@ -40,6 +41,7 @@ static uint8_t _recvbuf[RECVBUF_SIZE]; static msg_t _msg_queue[MSG_QUEUE_SIZE]; static socket_zep_t _dev; +static netdev_ieee802154_submac_t _socket_zep_netdev; static kernel_pid_t _main_pid; static void _event_cb(netdev_t *dev, netdev_event_t event); @@ -48,11 +50,14 @@ static void _print_info(netdev_t *netdev); static void test_init(void) { const socket_zep_params_t *p = &socket_zep_params[0]; - netdev_t *netdev = &_dev.netdev.netdev; + netdev_t *netdev = &_socket_zep_netdev.dev.netdev; printf("Initializing socket ZEP with (local: [%s]:%s, remote: [%s]:%s)\n", p->local_addr, p->local_port, p->remote_addr, p->remote_port); - socket_zep_setup(&_dev, p, 0); + netdev_register(&_socket_zep_netdev.dev.netdev, NETDEV_SOCKET_ZEP, 0); + netdev_ieee802154_submac_init(&_socket_zep_netdev); + socket_zep_hal_setup(&_dev, &_socket_zep_netdev.submac.dev); + socket_zep_setup(&_dev, p); netdev->event_callback = _event_cb; expect(netdev->driver->init(netdev) >= 0); _print_info(netdev); @@ -60,7 +65,7 @@ static void test_init(void) static void test_send__iolist_NULL(void) { - netdev_t *netdev = &_dev.netdev.netdev; + netdev_t *netdev = &_socket_zep_netdev.dev.netdev; puts("Send zero-length packet"); int res = netdev->driver->send(netdev, NULL); @@ -77,11 +82,11 @@ static void test_send__iolist_not_NULL(void) iolist[0].iol_next = &iolist[1]; - netdev_t *netdev = &_dev.netdev.netdev; + netdev_t *netdev = &_socket_zep_netdev.dev.netdev; puts("Send 'Hello\\0World\\0'"); - int res = netdev->driver->send(netdev, iolist); - expect((res < 0) || (res == (sizeof("Hello")) + sizeof("World"))); + int res = netdev->driver->send(netdev, iolist); + expect((res < 0) || (res == 0)); if ((res < 0) && (errno == ECONNREFUSED)) { puts("No remote socket exists (use scripts in `tests/` to have proper tests)"); } @@ -91,7 +96,7 @@ static void test_recv(void) { puts("Waiting for an incoming message (use `make test`)"); while (1) { - netdev_t *netdev = &_dev.netdev.netdev; + netdev_t *netdev = &_socket_zep_netdev.dev.netdev; msg_t msg; msg_receive(&msg);