From eb965d5fec1c7d4585d24d94248edad376cafe66 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 22 Jul 2023 14:19:37 +0200 Subject: [PATCH] arch/nrf91: add support for modem sockets --- arch/arm/src/nrf91/CMakeLists.txt | 62 +- arch/arm/src/nrf91/Kconfig | 2 + arch/arm/src/nrf91/Make.defs | 2 +- arch/arm/src/nrf91/nrf91_modem_sock.c | 1204 +++++++++++++++++++++++++ arch/arm/src/nrf91/nrf91_modem_sock.h | 29 + 5 files changed, 1268 insertions(+), 31 deletions(-) create mode 100644 arch/arm/src/nrf91/nrf91_modem_sock.c create mode 100644 arch/arm/src/nrf91/nrf91_modem_sock.h diff --git a/arch/arm/src/nrf91/CMakeLists.txt b/arch/arm/src/nrf91/CMakeLists.txt index 8ec367033e..a908b5f1ae 100644 --- a/arch/arm/src/nrf91/CMakeLists.txt +++ b/arch/arm/src/nrf91/CMakeLists.txt @@ -1,23 +1,22 @@ -############################################################################ +# ############################################################################## # arch/arm/src/nrf91/CMakeLists.txt # -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. The -# ASF licenses this file to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance with the -# License. You may obtain a copy of the License at +# Licensed to the Apache Software Foundation (ASF) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. The ASF licenses this +# file to you under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. +# License for the specific language governing permissions and limitations under +# the License. # -############################################################################ - +# ############################################################################## set(SRCS nrf91_start.c @@ -98,18 +97,18 @@ if(CONFIG_NRF91_MODEM) DOWNLOAD_NAME "sdk-nrfxlib-v${NRFXLIB_VER}.tar.gz" DOWNLOAD_DIR ${CMAKE_CURRENT_LIST_DIR} URL "${NRFXLIB_URL}/v${NRFXLIB_VER}.tar.gz" - SOURCE_DIR - ${CMAKE_CURRENT_LIST_DIR}/sdk-nrfxlib - BINARY_DIR - ${CMAKE_BINARY_DIR}/arch/sdk-nrfxlib - CONFIGURE_COMMAND - "" - BUILD_COMMAND - "" - INSTALL_COMMAND - "" - TEST_COMMAND - "" + SOURCE_DIR + ${CMAKE_CURRENT_LIST_DIR}/sdk-nrfxlib + BINARY_DIR + ${CMAKE_BINARY_DIR}/arch/sdk-nrfxlib + CONFIGURE_COMMAND + "" + BUILD_COMMAND + "" + INSTALL_COMMAND + "" + TEST_COMMAND + "" DOWNLOAD_NO_PROGRESS true TIMEOUT 30) @@ -120,7 +119,8 @@ if(CONFIG_NRF91_MODEM) endif() endif() - list(APPEND SRCS nrf91_modem.c nrf91_modem_os.c nrf91_nrfx_ipc.c) + list(APPEND SRCS nrf91_modem.c nrf91_modem_os.c nrf91_nrfx_ipc.c + nrf91_modem_sock.c) if(CONFIG_NRF91_MODEM_AT) list(APPEND SRCS nrf91_modem_at.c) @@ -130,22 +130,24 @@ if(CONFIG_NRF91_MODEM) if(CONFIG_ARCH_FPU) set(NRFXLIB_LIB_VARIANT hard-float) - else () + else() set(NRFXLIB_LIB_VARIANT soft-float) endif() if(CONFIG_NRF91_MODEM_LOG) set(MODEM_LIB_VARIANT libmodem_log.a) else() - set(MODEM_LIB_VARIANT libmodem_log.a) + set(MODEM_LIB_VARIANT libmodem.a) endif() - nuttx_library_import(modem - ${NRFXLIB_DIR}/nrf_modem/lib/cortex-m33/${NRFXLIB_LIB_VARIANT}/${MODEM_LIB_VARIANT}) + nuttx_library_import( + modem + ${NRFXLIB_DIR}/nrf_modem/lib/cortex-m33/${NRFXLIB_LIB_VARIANT}/${MODEM_LIB_VARIANT} + ) target_include_directories(arch PRIVATE ${NRFXLIB_DIR}/nrf_modem/include) target_link_libraries(arch PRIVATE modem) - target_link_libraries(modem INTERFACE arch c) + target_link_libraries(modem INTERFACE arch c net) endif() target_sources(arch PRIVATE ${SRCS}) diff --git a/arch/arm/src/nrf91/Kconfig b/arch/arm/src/nrf91/Kconfig index d9415a9905..34a5a48618 100644 --- a/arch/arm/src/nrf91/Kconfig +++ b/arch/arm/src/nrf91/Kconfig @@ -703,6 +703,8 @@ config NRF91_MODEM select ARCH_IRQPRIO select NRF91_IPC select NRF91_USE_LFCLK + select MODEM + select NETDEV_MODEM_LTE_IOCTL default n if NRF91_MODEM diff --git a/arch/arm/src/nrf91/Make.defs b/arch/arm/src/nrf91/Make.defs index d1d7078941..e1938205d3 100644 --- a/arch/arm/src/nrf91/Make.defs +++ b/arch/arm/src/nrf91/Make.defs @@ -104,7 +104,7 @@ distclean:: $(call DELDIR, chip/$(NRFXLIB_UNPACK)) endif -CHIP_CSRCS += nrf91_modem.c nrf91_modem_os.c nrf91_nrfx_ipc.c +CHIP_CSRCS += nrf91_modem.c nrf91_modem_os.c nrf91_nrfx_ipc.c nrf91_modem_sock.c ifeq ($(CONFIG_NRF91_MODEM_AT),y) CHIP_CSRCS += nrf91_modem_at.c diff --git a/arch/arm/src/nrf91/nrf91_modem_sock.c b/arch/arm/src/nrf91/nrf91_modem_sock.c new file mode 100644 index 0000000000..0416d21683 --- /dev/null +++ b/arch/arm/src/nrf91/nrf91_modem_sock.c @@ -0,0 +1,1204 @@ +/**************************************************************************** + * arch/arm/src/nrf91/nrf91_modem_sock.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#undef s6_addr +#include "nrf_socket.h" +#include "nrf_modem_at.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_NET_USRSOCK_CUSTOM +# error CONFIG_NET_USRSOCK_CUSTOM must be set +#endif + +#ifndef CONFIG_SCHED_LPWORK +# error CONFIG_SCHED_LPWORK must be set +#endif + +#define NRF91_USRSOCK_BUFSIZE (4096) + +#define MAX_CTRL_SOCKET_COUNT (1) +#define MAX_SOCKET_COUNT (NRF_MODEM_MAX_SOCKET_COUNT + \ + MAX_CTRL_SOCKET_COUNT) +#define CTRL_SOCKET_FIRST (NRF_MODEM_MAX_SOCKET_COUNT) + +/**************************************************************************** + * Private Data Types + ****************************************************************************/ + +struct nrf91_sock_s +{ + bool in_use; + bool recvpending; +}; + +struct nrf91_usrsock_s +{ + uint8_t in[NRF91_USRSOCK_BUFSIZE]; + uint8_t out[NRF91_USRSOCK_BUFSIZE]; + struct work_s pollwork; + struct nrf_pollfd pollfd; + struct nrf91_sock_s sock[MAX_SOCKET_COUNT]; +}; + +typedef int (*usrsock_handler_t)(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len); + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int nrf91_usrsock_socket_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len); +static int nrf91_usrsock_close_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len); +static int nrf91_usrsock_connect_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len); +static int nrf91_usrsock_sendto_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len); +static int nrf91_usrsock_recvfrom_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len); +static int nrf91_usrsock_setsockopt_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len); +static int nrf91_usrsock_getsockopt_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len); +static int nrf91_usrsock_getsockname_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len); +static int nrf91_usrsock_getpeername_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len); +static int nrf91_usrsock_bind_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len); +static int nrf91_usrsock_listen_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len); +static int nrf91_usrsock_accept_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len); +static int nrf91_usrsock_ioctl_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len); +static int nrf91_usrsock_shutdown_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct nrf91_usrsock_s g_usrsock; + +static const usrsock_handler_t g_usrsock_handler[] = +{ + [USRSOCK_REQUEST_SOCKET] = nrf91_usrsock_socket_handler, + [USRSOCK_REQUEST_CLOSE] = nrf91_usrsock_close_handler, + [USRSOCK_REQUEST_CONNECT] = nrf91_usrsock_connect_handler, + [USRSOCK_REQUEST_SENDTO] = nrf91_usrsock_sendto_handler, + [USRSOCK_REQUEST_RECVFROM] = nrf91_usrsock_recvfrom_handler, + [USRSOCK_REQUEST_SETSOCKOPT] = nrf91_usrsock_setsockopt_handler, + [USRSOCK_REQUEST_GETSOCKOPT] = nrf91_usrsock_getsockopt_handler, + [USRSOCK_REQUEST_GETSOCKNAME] = nrf91_usrsock_getsockname_handler, + [USRSOCK_REQUEST_GETPEERNAME] = nrf91_usrsock_getpeername_handler, + [USRSOCK_REQUEST_BIND] = nrf91_usrsock_bind_handler, + [USRSOCK_REQUEST_LISTEN] = nrf91_usrsock_listen_handler, + [USRSOCK_REQUEST_ACCEPT] = nrf91_usrsock_accept_handler, + [USRSOCK_REQUEST_IOCTL] = nrf91_usrsock_ioctl_handler, + [USRSOCK_REQUEST_SHUTDOWN] = nrf91_usrsock_shutdown_handler, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf2nx_family + ****************************************************************************/ + +static int nrf2nx_family(int nrf_family) +{ + int nx_family = 0; + + if (nrf_family == NRF_AF_UNSPEC) + { + nx_family = AF_UNSPEC; + } + else if (nrf_family == NRF_AF_INET) + { + nx_family = AF_INET; + } + else if (nrf_family == NRF_AF_INET6) + { + nx_family = AF_INET6; + } + else if (nrf_family == NRF_AF_PACKET) + { + nx_family = AF_PACKET; + } + + return nx_family; +} + +/**************************************************************************** + * Name: nx2nrf_family + ****************************************************************************/ + +static int nx2nrf_family(int nx_family) +{ + int nrf_family = 0; + + if (nx_family == AF_UNSPEC) + { + nrf_family = NRF_AF_UNSPEC; + } + else if (nx_family == AF_INET) + { + nrf_family = NRF_AF_INET; + } + else if (nx_family == AF_INET6) + { + nrf_family = NRF_AF_INET6; + } + else if (nx_family == AF_PACKET) + { + nrf_family = NRF_AF_PACKET; + } + else + { + nerr("unsupported nrf family %d\n", nx_family); + } + + return nrf_family; +} + +/**************************************************************************** + * Name: nx2nrf_type + ****************************************************************************/ + +static int nx2nrf_type(int nx_type) +{ + int nrf_type = 0; + + if (nx_type == SOCK_STREAM) + { + nrf_type = NRF_SOCK_STREAM; + } + else if (nx_type == SOCK_DGRAM) + { + nrf_type = NRF_SOCK_DGRAM; + } + else if (nx_type == SOCK_RAW) + { + nrf_type = NRF_SOCK_RAW; + } + else + { + nerr("unsupported nrf type %d\n", nx_type); + } + + return nrf_type; +} + +/**************************************************************************** + * Name: nx2nrf_protocol + ****************************************************************************/ + +static int nx2nrf_protocol(int nx_protocol) +{ + int nrf_protocol = 0; + + if (nx_protocol == IPPROTO_IP) + { + nrf_protocol = NRF_IPPROTO_IP; + } + else if (nx_protocol == IPPROTO_TCP) + { + nrf_protocol = NRF_IPPROTO_TCP; + } + else if (nx_protocol == IPPROTO_UDP) + { + nrf_protocol = NRF_IPPROTO_UDP; + } + else if (nx_protocol == IPPROTO_IPV6) + { + nrf_protocol = NRF_IPPROTO_IPV6; + } + else if (nx_protocol == IPPROTO_RAW) + { + nrf_protocol = NRF_IPPROTO_RAW; + } + else + { + nerr("unsupported nrf protocol %d\n", nx_protocol); + } + + return nrf_protocol; +} + +/**************************************************************************** + * Name: nx2nrf_sockaddr + ****************************************************************************/ + +static void nx2nrf_sockaddr(struct sockaddr *nxaddress, + struct nrf_sockaddr *address) +{ + address->sa_family = nx2nrf_family(nxaddress->sa_family); + + if (address->sa_family == NRF_AF_INET) + { + struct sockaddr_in *tmp1 = (struct sockaddr_in *)nxaddress; + struct nrf_sockaddr_in *tmp2 = (struct nrf_sockaddr_in *)address; + + tmp2->sin_port = tmp1->sin_port; + tmp2->sin_addr.s_addr = tmp1->sin_addr.s_addr; + tmp2->sin_len = sizeof(struct nrf_sockaddr_in); + } + else if (address->sa_family == NRF_AF_INET6) + { + struct sockaddr_in6 *tmp1 = (struct sockaddr_in6 *)nxaddress; + struct nrf_sockaddr_in6 *tmp2 = (struct nrf_sockaddr_in6 *)address; + + tmp2->sin6_port = tmp1->sin6_port; + memcpy(&tmp2->sin6_addr, &tmp1->sin6_addr, sizeof(struct in6_addr)); + tmp2->sin6_scope_id = tmp1->sin6_scope_id; + tmp2->sin6_len = sizeof(struct nrf_sockaddr_in6); + } + else + { + nerr("unsupported nrf sa_family %d\n", address->sa_family); + address->sa_family = 0; + } +} + +/**************************************************************************** + * Name: nrf2nx_sockaddr + ****************************************************************************/ + +static void nrf2nx_sockaddr(struct nrf_sockaddr *address, + struct sockaddr *nxaddress) +{ + nxaddress->sa_family = nrf2nx_family(address->sa_family); + + if (nxaddress->sa_family == AF_INET) + { + struct nrf_sockaddr_in *tmp1 = (struct nrf_sockaddr_in *)address; + struct sockaddr_in *tmp2 = (struct sockaddr_in *)nxaddress; + + tmp2->sin_port = tmp1->sin_port; + tmp2->sin_addr.s_addr = tmp1->sin_addr.s_addr; + } + else if (nxaddress->sa_family == AF_INET6) + { + struct nrf_sockaddr_in6 *tmp1 = (struct nrf_sockaddr_in6 *)address; + struct sockaddr_in6 *tmp2 = (struct sockaddr_in6 *)nxaddress; + + tmp2->sin6_port = tmp1->sin6_port; + tmp2->sin6_flowinfo = 0; + memcpy(&tmp2->sin6_addr, &tmp1->sin6_addr, sizeof(struct in6_addr)); + tmp2->sin6_scope_id = tmp1->sin6_scope_id; + } + else + { + nerr("unsupported nx sa_family %d\n", nxaddress->sa_family); + nxaddress->sa_family = 0; + } +} + +/**************************************************************************** + * Name: nrf_usrsock_shutdown + ****************************************************************************/ + +static int nrf_usrsock_shutdown(int sockfd, int how) +{ + /* TODO */ + + return 0; +} + +/**************************************************************************** + * Name: nrf91_usrsock_send + ****************************************************************************/ + +static int nrf91_usrsock_send(struct nrf91_usrsock_s *usrsock, + const void *buf, size_t len) +{ + return usrsock_response(buf, len, NULL); +} + +/**************************************************************************** + * Name: nrf91_usrsock_send_ack + ****************************************************************************/ + +static int nrf91_usrsock_send_ack(struct nrf91_usrsock_s *usrsock, + uint32_t xid, int32_t result) +{ + struct usrsock_message_req_ack_s ack; + + ack.head.msgid = USRSOCK_MESSAGE_RESPONSE_ACK; + ack.head.flags = (result == -EINPROGRESS); + ack.head.events = 0; + + ack.xid = xid; + ack.result = result; + + return nrf91_usrsock_send(usrsock, &ack, sizeof(ack)); +} + +/**************************************************************************** + * Name: nrf91_usrsock_send_dack + ****************************************************************************/ + +static int nrf91_usrsock_send_dack(struct nrf91_usrsock_s *usrsock, + struct usrsock_message_datareq_ack_s *ack, + uint32_t xid, int32_t result, + uint16_t valuelen, + uint16_t valuelen_nontrunc) +{ + ack->reqack.head.msgid = USRSOCK_MESSAGE_RESPONSE_DATA_ACK; + ack->reqack.head.flags = 0; + ack->reqack.head.events = 0; + + ack->reqack.xid = xid; + ack->reqack.result = result; + + if (result < 0) + { + result = 0; + valuelen = 0; + valuelen_nontrunc = 0; + } + else if (valuelen > valuelen_nontrunc) + { + valuelen = valuelen_nontrunc; + } + + ack->valuelen = valuelen; + ack->valuelen_nontrunc = valuelen_nontrunc; + + return nrf91_usrsock_send(usrsock, ack, sizeof(*ack) + valuelen + result); +} + +/**************************************************************************** + * Name: nrf91_usrsock_send_event + ****************************************************************************/ + +static int nrf91_usrsock_send_event(struct nrf91_usrsock_s *usrsock, + int16_t usockid, uint16_t events) +{ + struct usrsock_message_socket_event_s event; + + event.head.msgid = USRSOCK_MESSAGE_SOCKET_EVENT; + event.head.flags = USRSOCK_MESSAGE_FLAG_EVENT; + event.head.events = events; + + event.usockid = usockid; + + return nrf91_usrsock_send(usrsock, &event, sizeof(event)); +} + +/**************************************************************************** + * Name: nrf91_usrsock_event_callback + ****************************************************************************/ + +static int nrf91_usrsock_event_callback(int16_t usockid, uint16_t events) +{ + return nrf91_usrsock_send_event(&g_usrsock, usockid, events); +} + +/**************************************************************************** + * Name: nrf91_modem_getver + ****************************************************************************/ + +static int nrf91_modem_getver(lte_version_t *version) +{ + char buffer1[16]; + char buffer2[16]; + int ret = OK; + + memset(version, 0, sizeof(*version)); + ret = nrf_modem_at_scanf("AT%HWVERSION", "%%HWVERSION: %s %s", + buffer1, buffer2); + if (ret > 0) + { + strncpy(version->bb_product, buffer1, LTE_VER_BB_PRODUCT_LEN); + strncpy(version->np_package, buffer2, LTE_VER_NP_PACKAGE_LEN); + } + + ret = nrf_modem_at_scanf("AT+CGMR", "%s", buffer1); + if (ret > 0) + { + strncpy(version->fw_version, buffer1, LTE_VER_FIRMWARE_LEN); + ret = 0; + } + + return ret; +} + +/**************************************************************************** + * Name: nrf91_ioctl_ltecmd + ****************************************************************************/ + +static int nrf91_ioctl_ltecmd(int fd, int cmd, unsigned long arg) +{ + struct lte_ioctl_data_s *ltecmd = (struct lte_ioctl_data_s *)(arg); + int **result = (int **)ltecmd->outparam; + int ret = OK; + + switch (ltecmd->cmdid) + { + /* TODO: support for Nordic-specific functional modes 20-44 */ + + case LTE_CMDID_POWERON: + { + ret = nrf_modem_at_printf("AT+CFUN=1"); + break; + } + + case LTE_CMDID_POWEROFF: + { + ret = nrf_modem_at_printf("AT+CFUN=0"); + break; + } + + case LTE_CMDID_GETVER: + { + lte_version_t **version = + (lte_version_t **)(ltecmd->outparam + 1); + ret = nrf91_modem_getver(*version); + break; + } + + case LTE_CMDID_GETIMEI: + { + char **imei = (char **)(ltecmd->outparam + 1); + size_t **len = (size_t **)(ltecmd->outparam + 2); + char buffer[32]; + char *ptr; + ret = nrf_modem_at_cmd(buffer, 32, "AT+CGSN=1"); + ptr = strchr(buffer, '"') + 1; + ptr[LTE_IMEI_LEN - 1] = 0; + strncpy(*imei, ptr, **len); + break; + } + + case LTE_CMDID_GETQUAL: + { + lte_quality_t **quality = + (lte_quality_t **)(ltecmd->outparam + 1); + int tmp; + int rsrp; + int rsrq; + int rssi; + + ret = nrf_modem_at_scanf("AT+CESQ", + "+CESQ: %d,%d,%d,%d,%d,%d", + &tmp, &tmp, &tmp, &tmp, + &rsrq, &rsrp); + if (ret > 0) + { + (*quality)->rsrq = (rsrq / 2) - 19; + (*quality)->rsrp = rsrp - 140; + } + else + { + nerr("AT+CESQ failed %d\n", ret); + } + + ret = nrf_modem_at_scanf("AT+CSQ", + "+CSQ: %d,%d", + &rssi, &tmp); + if (ret > 0) + { + (*quality)->rssi = rssi; + (*quality)->sinr = 0; + } + else + { + nerr("AT+CSQ failed %d\n", ret); + } + + (*quality)->valid = true; + } + + /* TODO: commands from include/nuttx/wireless/lte/lte.h */ + + default: + { + nerr("unsupported cmd = %" PRId32, ltecmd->cmdid); + break; + } + } + + if (result) + { + **result = ret; + } + + return ret; +} + +/**************************************************************************** + * Name: nrf91_usrsock_ioctl + ****************************************************************************/ + +static int nrf91_usrsock_ioctl(int fd, int cmd, unsigned long arg) +{ + int ret = OK; + + if (fd < NRF_MODEM_MAX_SOCKET_COUNT) + { + nerr("ioctl not supported for socket %d", fd); + ret = -EACCES; + goto errout; + } + + switch (cmd) + { + case SIOCLTECMD: + { + ret = nrf91_ioctl_ltecmd(fd, cmd, arg); + break; + } + + default: + { + ret = -ENOTTY; + nerr("ioctl unsupported cmd %d", cmd); + break; + } + } + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf91_usrsock_getsockopt_handler + ****************************************************************************/ + +int nrf91_usrsock_setsockopt(int sockfd, int level, int optname, + const void *optval, unsigned int optlen) +{ + int ret = OK; + + ret = nrf_setsockopt(sockfd, level, optname, optval, + (nrf_socklen_t)optlen); + if (ret < 0) + { + nerr("nrf_setsockopt failed %d", errno); + ret = -errno; + } + + return ret; +} + +/**************************************************************************** + * Name: nrf91_usrsock_getsockopt_handler + ****************************************************************************/ + +int nrf91_usrsock_getsockopt(int sockfd, int level, int optname, + void *optval, unsigned int *optlen) +{ + int ret = OK; + + ret = nrf_getsockopt(sockfd, level, optname, optval, + (nrf_socklen_t *)optlen); + if (ret < 0) + { + nerr("nrf_getsockopt failed %d", errno); + ret = -errno; + } + + return ret; +} + +/**************************************************************************** + * Name: nrf91_usrsock_poll_work + ****************************************************************************/ + +static void nrf91_usrsock_poll_work(void *arg) +{ + struct nrf_pollfd *pollfd = arg; + uint16_t events = 0; + int ret = OK; + + if (pollfd->revents & NRF_POLLIN) + { + events |= USRSOCK_EVENT_RECVFROM_AVAIL; + } + + if (pollfd->revents & NRF_POLLERR) + { + events |= USRSOCK_EVENT_REMOTE_CLOSED; + } + + if (pollfd->revents & NRF_POLLHUP) + { + events |= USRSOCK_EVENT_REMOTE_CLOSED; + } + + if (events) + { + /* REVISIT: postpone REMOTE_CLOSED event if there are data to read */ + + if (events & USRSOCK_EVENT_REMOTE_CLOSED) + { + while (g_usrsock.sock[pollfd->fd].recvpending == true) + { + usleep(100); + } + } + + ret = nrf91_usrsock_event_callback(pollfd->fd, events); + if (ret < 0) + { + nerr("usrsock_event_callback failed %d", ret); + } + } +} + +/**************************************************************************** + * Name: nrf91_usrsock_poll_cb + * + * The callback is invoked in an interrupt service routine. + * + ****************************************************************************/ + +static void nrf91_usrsock_poll_cb(struct nrf_pollfd *pollfd) +{ + memcpy(&g_usrsock.pollfd, pollfd, sizeof(struct nrf_pollfd)); + + if (work_available(&g_usrsock.pollwork)) + { + work_queue(LPWORK, &g_usrsock.pollwork, nrf91_usrsock_poll_work, + &g_usrsock.pollfd, 0); + } +} + +/**************************************************************************** + * Name: nrf91_usrsock_socket_handler + ****************************************************************************/ + +static int nrf91_usrsock_socket_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len) +{ + const struct usrsock_request_socket_s *req = data; + struct nrf_modem_pollcb cb; + int fd = 0; + int ret = 0; + + if (req->type == SOCK_CTRL) + { + /* Only one CTRL socket supported for now */ + + fd = CTRL_SOCKET_FIRST; + } + else + { + fd = nrf_socket(nx2nrf_family(req->domain), + nx2nrf_type(req->type), + nx2nrf_protocol(req->protocol)); + if (ret < 0) + { + nerr("nrf_socket failed %d", errno); + ret = -errno; + } + else + { + cb.callback = nrf91_usrsock_poll_cb; + cb.events = NRF_POLLIN | NRF_POLLHUP; + cb.oneshot = false; + + ret = nrf_setsockopt(fd, NRF_SOL_SOCKET, NRF_SO_POLLCB, &cb, + sizeof(struct nrf_modem_pollcb)); + if (ret < 0) + { + nerr("failed to connect poll cb %d", errno); + ret = -errno; + } + } + } + + /* Mark socket as used */ + + if (fd >= 0) + { + usrsock->sock[fd].in_use = true; + usrsock->sock[fd].recvpending = false; + } + + ret = nrf91_usrsock_send_ack(usrsock, req->head.xid, fd); + + if (ret >= 0 && fd >= 0) + { + ret = nrf91_usrsock_send_event(usrsock, fd, + USRSOCK_EVENT_SENDTO_READY); + } + + return ret; +} + +/**************************************************************************** + * Name: nrf91_usrsock_close_handler + ****************************************************************************/ + +static int nrf91_usrsock_close_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len) +{ + const struct usrsock_request_close_s *req = data; + int ret = OK; + + if (req->usockid < NRF_MODEM_MAX_SOCKET_COUNT) + { + ret = nrf_close(req->usockid); + if (ret < 0) + { + nerr("nrf_close failed %d", errno); + ret = -errno; + } + + usrsock->sock[req->usockid].in_use = false; + } + + return nrf91_usrsock_send_ack(usrsock, req->head.xid, ret); +} + +/**************************************************************************** + * Name: nrf91_usrsock_connect_handler + ****************************************************************************/ + +static int nrf91_usrsock_connect_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len) +{ + const struct usrsock_request_connect_s *req = data; + struct nrf_sockaddr_in6 address; + int ret = 0; + + nx2nrf_sockaddr((struct sockaddr *)(req + 1), + (struct nrf_sockaddr *)&address); + + ret = nrf_connect(req->usockid, + (const struct nrf_sockaddr *)&address, + (nrf_socklen_t)req->addrlen); + if (ret < 0) + { + nerr("nrf_connect failed %d", errno); + ret = -errno; + } + + return nrf91_usrsock_send_ack(usrsock, req->head.xid, ret); +} + +/**************************************************************************** + * Name: nrf91_usrsock_sendto_handler + ****************************************************************************/ + +static int nrf91_usrsock_sendto_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len) +{ + const struct usrsock_request_sendto_s *req = data; + struct nrf_sockaddr_in6 address; + struct sockaddr *tmp = NULL; + int ret = 0; + bool sent = 0; + + if (req->addrlen != 0) + { + tmp = (struct sockaddr *)(req + 1); + nx2nrf_sockaddr(tmp, (struct nrf_sockaddr *)&address); + } + + ret = nrf_sendto(req->usockid, + (const void *)(req + 1) + req->addrlen, + req->buflen, + req->flags, + req->addrlen ? (struct nrf_sockaddr *)&address : NULL, + (nrf_socklen_t)req->addrlen); + if (ret < 0) + { + nerr("nrf_sendto failed %d", errno); + ret = -errno; + } + + sent = (ret > 0); + ret = nrf91_usrsock_send_ack(usrsock, req->head.xid, ret); + if (ret >= 0 && sent) + { + ret = nrf91_usrsock_send_event(usrsock, req->usockid, + USRSOCK_EVENT_SENDTO_READY); + } + + return ret; +} + +/**************************************************************************** + * Name: nrf91_usrsock_recvfrom_handler + ****************************************************************************/ + +static int nrf91_usrsock_recvfrom_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len) +{ + const struct usrsock_request_recvfrom_s *req = data; + struct usrsock_message_datareq_ack_s *ack = NULL; + struct sockaddr *tmp = NULL; + nrf_socklen_t outaddrlen = req->max_addrlen; + socklen_t inaddrlen = req->max_addrlen; + size_t buflen = req->max_buflen; + struct nrf_sockaddr_in6 address; + int ret; + int recvlen; + + ack = (struct usrsock_message_datareq_ack_s *)usrsock->out; + if (sizeof(*ack) + inaddrlen + buflen > sizeof(usrsock->out)) + { + buflen = sizeof(usrsock->out) - sizeof(*ack) - inaddrlen; + } + + if (outaddrlen != 0) + { + tmp = (struct sockaddr *)(ack + 1); + nx2nrf_sockaddr(tmp, (struct nrf_sockaddr *)&address); + } + + ret = nrf_recvfrom(req->usockid, + (void *)(ack + 1) + inaddrlen, + buflen, + req->flags, + outaddrlen ? (struct nrf_sockaddr *)&address: NULL, + (nrf_socklen_t)outaddrlen ? &outaddrlen : NULL); + if (ret < 0) + { + nerr("nrf_recvfrom failed %d", errno); + ret = -errno; + } + + recvlen = ret; + + if (ret > 0 && outaddrlen < inaddrlen) + { + memcpy((void *)(ack + 1) + outaddrlen, + (void *)(ack + 1) + inaddrlen, ret); + } + + /* Send data */ + + ret = nrf91_usrsock_send_dack(usrsock, ack, req->head.xid, + ret, inaddrlen, outaddrlen); + + /* REVISIT: signal that more data can be available */ + + if (ret >= 0 && buflen == recvlen) + { + usrsock->sock[req->usockid].recvpending = true; + ret = nrf91_usrsock_send_event(usrsock, req->usockid, + USRSOCK_EVENT_RECVFROM_AVAIL); + } + else + { + usrsock->sock[req->usockid].recvpending = false; + } + + return ret; +} + +/**************************************************************************** + * Name: nrf91_usrsock_setsockopt_handler + ****************************************************************************/ + +static int nrf91_usrsock_setsockopt_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len) +{ + const struct usrsock_request_setsockopt_s *req = data; + int ret = 0; + + ret = nrf91_usrsock_setsockopt(req->usockid, req->level, req->option, + req + 1, req->valuelen); + return nrf91_usrsock_send_ack(usrsock, req->head.xid, ret); +} + +/**************************************************************************** + * Name: nrf91_usrsock_getsockopt_handler + ****************************************************************************/ + +static int nrf91_usrsock_getsockopt_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len) +{ + const struct usrsock_request_getsockopt_s *req = data; + struct usrsock_message_datareq_ack_s *ack; + socklen_t optlen = req->max_valuelen; + int ret; + + ack = (struct usrsock_message_datareq_ack_s *)usrsock->out; + ret = nrf91_usrsock_getsockopt(req->usockid, req->level, req->option, + ack + 1, &optlen); + + return nrf91_usrsock_send_dack(usrsock, ack, req->head.xid, + ret, optlen, optlen); +} + +/**************************************************************************** + * Name: nrf91_usrsock_getsockname_handler + ****************************************************************************/ + +static int nrf91_usrsock_getsockname_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len) +{ + return -1; +} + +/**************************************************************************** + * Name: nrf91_usrsock_getpeername_handler + ****************************************************************************/ + +static int nrf91_usrsock_getpeername_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len) +{ + return -1; +} + +/**************************************************************************** + * Name: nrf91_usrsock_bind_handler + ****************************************************************************/ + +static int nrf91_usrsock_bind_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len) +{ + const struct usrsock_request_bind_s *req = data; + struct nrf_sockaddr_in6 address; + int ret = 0; + + nx2nrf_sockaddr((struct sockaddr *)(req + 1), + (struct nrf_sockaddr *)&address); + ret = nrf_bind(req->usockid, (const struct nrf_sockaddr *)&address, + req->addrlen); + + return nrf91_usrsock_send_ack(usrsock, req->head.xid, ret); +} + +/**************************************************************************** + * Name: nrf91_usrsock_listen_handler + ****************************************************************************/ + +static int nrf91_usrsock_listen_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len) +{ + const struct usrsock_request_listen_s *req = data; + int ret = 0; + + ret = nrf_listen(req->usockid, req->backlog); + if (ret < 0) + { + ret = -errno; + } + + return nrf91_usrsock_send_ack(usrsock, req->head.xid, ret); +} + +/**************************************************************************** + * Name: nrf91_usrsock_accept_handler + ****************************************************************************/ + +static int nrf91_usrsock_accept_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len) +{ + const struct usrsock_request_accept_s *req = data; + struct usrsock_message_datareq_ack_s *ack; + struct nrf_sockaddr_in6 address; + nrf_socklen_t outaddrlen; + socklen_t inaddrlen = req->max_addrlen; + int sockfd = 0; + int ret = 0; + + if (inaddrlen == sizeof(struct sockaddr_in)) + { + outaddrlen = sizeof(struct nrf_sockaddr_in); + } + else + { + outaddrlen = sizeof(struct nrf_sockaddr_in6); + } + + ack = (struct usrsock_message_datareq_ack_s *)usrsock->out; + sockfd = nrf_accept(req->usockid, + outaddrlen ? (struct nrf_sockaddr *)&address : NULL, + (nrf_socklen_t)outaddrlen ? &outaddrlen : NULL); + if (ret < 0) + { + nerr("nrf_accpet failed %d", errno); + ret = -errno; + } + + nrf2nx_sockaddr((struct nrf_sockaddr *)&address, + (struct sockaddr *)(ack + 1)); + + if (sockfd >= 0) + { + /* Append index as usockid to the payload */ + + if (outaddrlen <= inaddrlen) + { + *(int16_t *)((void *)(ack + 1) + outaddrlen) = sockfd; + } + else + { + *(int16_t *)((void *)(ack + 1) + inaddrlen) = sockfd; + } + + ret = sizeof(int16_t); /* Return usockid size */ + } + else + { + ret = sockfd; + } + + ret = nrf91_usrsock_send_dack(usrsock, ack, req->head.xid, ret, + inaddrlen, outaddrlen); + if (ret >= 0 && sockfd >= 0) + { + ret = nrf91_usrsock_send_event(usrsock, sockfd, + USRSOCK_EVENT_SENDTO_READY); + } + + return ret; +} + +/**************************************************************************** + * Name: nrf91_usrsock_ioctl_handler + ****************************************************************************/ + +static int nrf91_usrsock_ioctl_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len) +{ + const struct usrsock_request_ioctl_s *req = data; + struct usrsock_message_datareq_ack_s *ack = NULL; + int ret = 0; + + ack = (struct usrsock_message_datareq_ack_s *)usrsock->out; + memcpy(ack + 1, req + 1, req->arglen); + ret = nrf91_usrsock_ioctl(req->usockid, + req->cmd, + (unsigned long)(ack + 1)); + + return nrf91_usrsock_send_dack(usrsock, ack, req->head.xid, ret, + req->arglen, req->arglen); +} + +/**************************************************************************** + * Name: nrf91_usrsock_shutdown_handler + ****************************************************************************/ + +static int nrf91_usrsock_shutdown_handler(struct nrf91_usrsock_s *usrsock, + const void *data, size_t len) +{ + const struct usrsock_request_shutdown_s *req = data; + int ret = 0; + + ret = nrf_usrsock_shutdown(req->usockid, req->how); + return nrf91_usrsock_send_ack(usrsock, req->head.xid, ret); +} + +#ifndef CONFIG_NRF91_MODEM_AT +/**************************************************************************** + * Name: nrf91_modem_at_notify_handler + ****************************************************************************/ + +static void nrf91_modem_at_notify_handler(const char *notif) +{ + /* TODO */ + + printf("%s\n", notif); +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: usrsock_register + ****************************************************************************/ + +void usrsock_register(void) +{ +#ifndef CONFIG_NRF91_MODEM_AT + /* Initialize AT modem */ + + nrf_modem_at_notif_handler_set(nrf91_modem_at_notify_handler); + nrf_modem_at_cmd_custom_set(NULL, 0); +#endif +} + +/**************************************************************************** + * Name: usrsock_request + ****************************************************************************/ + +int usrsock_request(struct iovec *iov, unsigned int iovcnt) +{ + struct usrsock_request_common_s *common = NULL; + int ret = 0; + + /* Copy request to buffer */ + + ret = usrsock_iovec_get(g_usrsock.in, sizeof(g_usrsock.in), + iov, iovcnt, 0, NULL); + if (ret <= 0) + { + return ret; + } + + common = (struct usrsock_request_common_s *)g_usrsock.in; + + if (common->reqid >= 0 && + common->reqid < USRSOCK_REQUEST__MAX) + { + ret = g_usrsock_handler[common->reqid](&g_usrsock, + g_usrsock.in, ret); + if (ret < 0) + { + nerr("Usrsock request %d failed: %d\n", common->reqid, ret); + } + } + else + { + nerr("Invalid request id: %d\n", common->reqid); + } + + return ret; +} diff --git a/arch/arm/src/nrf91/nrf91_modem_sock.h b/arch/arm/src/nrf91/nrf91_modem_sock.h new file mode 100644 index 0000000000..8365541dfb --- /dev/null +++ b/arch/arm/src/nrf91/nrf91_modem_sock.h @@ -0,0 +1,29 @@ +/**************************************************************************** + * arch/arm/src/nrf91/nrf91_modem_sock.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/