aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/transport/lwip/transport_handler.c
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/transport/lwip/transport_handler.c')
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/transport/lwip/transport_handler.c630
1 files changed, 630 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/transport/lwip/transport_handler.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/transport/lwip/transport_handler.c
new file mode 100644
index 0000000..4537053
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/socket/transport/lwip/transport_handler.c
@@ -0,0 +1,630 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "iot_defines.h"
+#include "iot_errors.h"
+#include "sdk_config.h"
+#include "socket_common.h"
+#include "socket_trace.h"
+#include "transport_if.h"
+#include "portdb.h"
+#include "app_timer.h"
+#include "mem_manager.h"
+#include "nrf_fifo.h"
+#include "mbuf.h"
+#include "app_util.h"
+#include "nrf_platform_port.h"
+#include "app_util_platform.h"
+
+#include "lwip/opt.h"
+#include "lwip/init.h"
+#include "lwip/tcp.h"
+#include "lwip/timers.h"
+
+/**@brief Verify that IPv6 address length is correct. */
+#define VERIFY_ADDRESS_LEN(len) \
+ do { \
+ if ((len) != sizeof(sockaddr_in6_t)) { \
+ return NRF_ERROR_NULL | IOT_SOCKET_ERR_BASE; \
+ } \
+ } while (0)
+
+#define LWIP_SYS_TIMER_INTERVAL APP_TIMER_TICKS(100) /**< Interval for timer used as trigger to send. */
+
+#define SOCKET_MAX_PENDING_PACKETS 32 /**< Maximum number of pending received packets. */
+#define SOCKET_MAX_PENDING_CONNECTIONS 10 /**< Maximum number of simultaneous connections. */
+
+/**@brief TCP state */
+typedef enum
+{
+ TCP_STATE_IDLE,
+ TCP_STATE_REQUEST_CONNECTION,
+ TCP_STATE_CONNECTED,
+ TCP_STATE_DATA_TX_IN_PROGRESS,
+ TCP_STATE_TCP_SEND_PENDING,
+ TCP_STATE_DISCONNECTED
+} tcp_state_t;
+
+/**@brief LwIP handle structure. */
+typedef struct {
+ struct tcp_pcb * p_pcb; /**< A pointer to LwIP TCP protocol control block. */
+ socket_t * p_socket; /**< A pointer to corresponding socket. */
+ nrf_fifo_t conn_queue; /**< Connections queue. */
+ mbuf_t mbuf; /**< Memory management queue. */
+ volatile tcp_state_t tcp_state; /**< TCP state. */
+} lwip_handle_t;
+
+static lwip_handle_t lwip_handles[SOCKET_MAX_SOCKET_COUNT]; /**< LwIP handle array. */
+
+/**@brief Timer for LwIP. */
+APP_TIMER_DEF(m_lwip_timer_id);
+
+static err_t lwip_recv_callback(void * p_arg,
+ struct tcp_pcb * p_pcb,
+ struct pbuf * p_pbuf,
+ err_t err);
+
+static uint32_t lwip_buf_read(void * p_ctx,
+ uint32_t read_offset,
+ uint8_t * p_destbuf,
+ uint32_t destbuf_len)
+{
+ struct pbuf * p_pbuf = (struct pbuf *)p_ctx;
+ uint32_t copy_len = MIN(destbuf_len, (p_pbuf->len - read_offset));
+ memcpy(p_destbuf, (void *)(((uint8_t *)p_pbuf->payload) + read_offset), copy_len);
+ return copy_len;
+}
+
+static uint32_t lwip_buf_len(void * p_ctx)
+{
+ struct pbuf * p_pbuf = (struct pbuf *)p_ctx;
+ return p_pbuf->len;
+}
+
+static void lwip_buf_free(void * p_ctx)
+{
+ nrf_free(((struct pbuf *)p_ctx)->payload);
+ (void) pbuf_free((struct pbuf *)p_ctx);
+}
+
+static void lwip_timer_callback(void * p_ctx)
+{
+ (void) p_ctx;
+ sys_check_timeouts();
+}
+
+void nrf_driver_interface_up(iot_interface_t const * p_interface)
+{
+ UNUSED_PARAMETER(p_interface);
+ transport_interface_up();
+}
+
+void nrf_driver_interface_down(iot_interface_t const * p_interface)
+{
+ UNUSED_PARAMETER(p_interface);
+ transport_interface_down();
+}
+
+void transport_handler_init(void)
+{
+ lwip_init();
+ uint32_t err_code = nrf_driver_init();
+ APP_ERROR_CHECK(err_code);
+ for (uint32_t i = 0; i < SOCKET_MAX_SOCKET_COUNT; i++)
+ {
+ lwip_handles[i].p_pcb = NULL;
+ lwip_handles[i].p_socket = NULL;
+ lwip_handles[i].tcp_state = TCP_STATE_IDLE;
+ }
+ err_code = app_timer_create(&m_lwip_timer_id,
+ APP_TIMER_MODE_REPEATED,
+ lwip_timer_callback);
+ APP_ERROR_CHECK(err_code);
+ err_code = app_timer_start(m_lwip_timer_id, LWIP_SYS_TIMER_INTERVAL, NULL);
+ APP_ERROR_CHECK(err_code);
+ SOCKET_TRACE("Initialized LWIP transport handler\r\n");
+}
+
+static void lwip_error_handler(void * p_arg, err_t err)
+{
+ (void) p_arg;
+ SOCKET_TRACE("Error occured: %d\r\n", (int)err);
+ if(err == ERR_ABRT)
+ {
+ portdb_reset();
+ }
+}
+
+static err_t lwip_poll_handler(void * p_arg, struct tcp_pcb * p_pcb)
+{
+ (void) p_arg;
+ (void) p_pcb;
+
+ return ERR_OK;
+}
+
+static void lwip_drop_connection(void * p_ctx)
+{
+ struct tcp_pcb * p_pcb = (struct tcp_pcb *)p_ctx;
+ tcp_abort(p_pcb);
+}
+
+static lwip_handle_t * lwip_handle_allocate(socket_t * p_socket, struct tcp_pcb * p_pcb)
+{
+ lwip_handle_t * p_handle = NULL;
+ for (uint32_t i = 0; i < SOCKET_MAX_SOCKET_COUNT; i++)
+ {
+ if (lwip_handles[i].p_pcb == NULL)
+ {
+ p_handle = &lwip_handles[i];
+ (void)mbuf_init(&p_handle->mbuf,
+ lwip_buf_read,
+ lwip_buf_len,
+ lwip_buf_free,
+ SOCKET_MAX_PENDING_PACKETS);
+ (void) nrf_fifo_init(&p_handle->conn_queue,
+ SOCKET_MAX_PENDING_CONNECTIONS,
+ socket_wait,
+ lwip_drop_connection);
+ p_handle->p_socket = p_socket;
+ p_handle->tcp_state = TCP_STATE_IDLE;
+ if (p_pcb == NULL)
+ {
+ p_handle->p_pcb = tcp_new();
+ }
+ else
+ {
+ p_handle->p_pcb = p_pcb;
+ }
+ tcp_arg(p_handle->p_pcb, p_handle);
+ tcp_setprio(p_handle->p_pcb, TCP_PRIO_MIN);
+ tcp_recv(p_handle->p_pcb, lwip_recv_callback);
+ tcp_err(p_handle->p_pcb, lwip_error_handler);
+ tcp_poll(p_handle->p_pcb, lwip_poll_handler, 0);
+ break;
+ }
+ }
+ SOCKET_TRACE("Allocated LWIP socket handle\r\n");
+ return p_handle;
+}
+
+static void lwip_handle_free(lwip_handle_t * p_handle)
+{
+ nrf_fifo_deinit(&p_handle->conn_queue);
+ mbuf_deinit(&p_handle->mbuf);
+ p_handle->p_pcb = NULL;
+ p_handle->p_socket = NULL;
+ p_handle->tcp_state = TCP_STATE_IDLE;
+ SOCKET_TRACE("Released LWIP socket handle\r\n");
+}
+
+static uint32_t lwip_transport_open(socket_t * p_socket)
+{
+ lwip_handle_t * p_handle = NULL;
+ uint32_t err_code = NRF_SUCCESS;
+ switch (p_socket->so_params.so_type)
+ {
+ case SOCK_STREAM:
+ p_handle = lwip_handle_allocate(p_socket, NULL);
+ if (p_handle == NULL)
+ {
+ err_code = NRF_ERROR_NULL;
+ }
+ else
+ {
+ p_socket->so_ctx = p_handle;
+ }
+ break;
+ default:
+ err_code = NRF_ERROR_NULL;
+ break;
+ }
+ return err_code;
+}
+
+uint32_t lwip_error_convert(err_t lwip_err)
+{
+ uint32_t err_code = NRF_ERROR_NULL;
+ switch (lwip_err)
+ {
+ case ERR_OK:
+ err_code = NRF_SUCCESS;
+ break;
+ case ERR_MEM:
+ err_code = SOCKET_NO_MEM;
+ break;
+ case ERR_TIMEOUT:
+ err_code = SOCKET_TIMEOUT;
+ break;
+ case ERR_RTE:
+ err_code = SOCKET_NO_ROUTE;
+ break;
+ default:
+ err_code = NRF_ERROR_NULL;
+ break;
+ }
+ return err_code;
+}
+
+static uint32_t lwip_transport_close(socket_t * p_socket)
+{
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_socket->so_ctx;
+ portdb_free((uint16_t)p_handle->p_pcb->local_port);
+ err_t err_code = tcp_close(p_handle->p_pcb);
+ if (err_code == ERR_OK)
+ {
+ lwip_handle_free(p_handle);
+ }
+ return lwip_error_convert(err_code);
+}
+
+static err_t lwip_connect_callback(void * p_arg, struct tcp_pcb * p_pcb, err_t err)
+{
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_arg;
+ // TODO: Error check
+ SOCKET_TRACE("New connection\r\n");
+ p_handle->tcp_state = TCP_STATE_CONNECTED;
+ return ERR_OK;
+}
+
+static err_t lwip_recv_callback(void * p_arg,
+ struct tcp_pcb * p_pcb,
+ struct pbuf * p_pbuf,
+ err_t err)
+{
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_arg;
+ socket_t * p_socket = p_handle->p_socket;
+ if (err == ERR_OK)
+ {
+ uint8_t * p_payload_cp = nrf_malloc(p_pbuf->len);
+ struct pbuf * p_pbuf_cp = pbuf_alloc(PBUF_RAW, p_pbuf->len, PBUF_REF);
+
+ memcpy(p_payload_cp, p_pbuf->payload, p_pbuf->len);
+ p_pbuf_cp->payload = p_payload_cp;
+ p_pbuf_cp->len = p_pbuf->len;
+ p_pbuf_cp->tot_len = p_pbuf->tot_len;
+
+ uint32_t err_code = mbuf_write(&p_handle->mbuf, p_pbuf_cp);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_socket->so_read_evt++;
+ }
+ else
+ {
+ err = ERR_MEM;
+ }
+ }
+ return err;
+}
+
+static uint32_t lwip_wait_for_state(lwip_handle_t * p_handle, tcp_state_t state)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ while (err_code == NRF_SUCCESS &&
+ p_handle->tcp_state != state &&
+ p_handle->tcp_state != TCP_STATE_DISCONNECTED)
+ {
+ err_code = socket_wait();
+ }
+ if (err_code == NRF_SUCCESS && p_handle->tcp_state != state)
+ {
+ err_code = NRF_ERROR_NULL;
+ }
+ return err_code;
+}
+
+static void lwipaddr_to_sockaddr(const ip6_addr_t * p_lwip_addr, sockaddr_in6_t * p_addr_in6)
+{
+ struct in6_addr * addr = &p_addr_in6->sin6_addr;
+ addr->s6_addr[0] = p_lwip_addr->addr[0] & 0xFF;
+ addr->s6_addr[1] = (p_lwip_addr->addr[0] >> 8) & 0xFF;
+ addr->s6_addr[2] = (p_lwip_addr->addr[0] >> 16) & 0xFF;
+ addr->s6_addr[3] = (p_lwip_addr->addr[0] >> 24) & 0xFF;
+
+ addr->s6_addr[4] = p_lwip_addr->addr[1] & 0xFF;
+ addr->s6_addr[5] = (p_lwip_addr->addr[1] >> 8) & 0xFF;
+ addr->s6_addr[6] = (p_lwip_addr->addr[1] >> 16) & 0xFF;
+ addr->s6_addr[7] = (p_lwip_addr->addr[1] >> 24) & 0xFF;
+
+ addr->s6_addr[8] = p_lwip_addr->addr[2] & 0xFF;
+ addr->s6_addr[9] = (p_lwip_addr->addr[2] >> 8) & 0xFF;
+ addr->s6_addr[10] = (p_lwip_addr->addr[2] >> 16) & 0xFF;
+ addr->s6_addr[11] = (p_lwip_addr->addr[2] >> 24) & 0xFF;
+
+ addr->s6_addr[12] = p_lwip_addr->addr[3] & 0xFF;
+ addr->s6_addr[13] = (p_lwip_addr->addr[3] >> 8) & 0xFF;
+ addr->s6_addr[14] = (p_lwip_addr->addr[3] >> 16) & 0xFF;
+ addr->s6_addr[15] = (p_lwip_addr->addr[3] >> 24) & 0xFF;
+}
+
+static void sockaddr_to_lwipaddr(const sockaddr_in6_t * p_addr_in6, ip6_addr_t * p_lwip_addr)
+{
+ const struct in6_addr * addr = &p_addr_in6->sin6_addr;
+ IP6_ADDR_PART(p_lwip_addr, 0, addr->s6_addr[0], addr->s6_addr[1], addr->s6_addr[2], addr->s6_addr[3]);
+ IP6_ADDR_PART(p_lwip_addr, 1, addr->s6_addr[4], addr->s6_addr[5], addr->s6_addr[6], addr->s6_addr[7]);
+ IP6_ADDR_PART(p_lwip_addr, 2, addr->s6_addr[8], addr->s6_addr[9], addr->s6_addr[10], addr->s6_addr[11]);
+ IP6_ADDR_PART(p_lwip_addr, 3, addr->s6_addr[12], addr->s6_addr[13], addr->s6_addr[14], addr->s6_addr[15]);
+}
+
+static uint32_t lwip_transport_bind(socket_t * p_socket, const void * p_addr, socklen_t addr_len)
+{
+ VERIFY_ADDRESS_LEN(addr_len);
+ const sockaddr_in6_t * p_addr_in6 = (const sockaddr_in6_t *)p_addr;
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_socket->so_ctx;
+
+ uint16_t port = HTONS(p_addr_in6->sin6_port);
+ uint32_t err_code = portdb_register(port);
+ if (err_code == NRF_SUCCESS)
+ {
+ ip6_addr_t lwip_addr;
+ sockaddr_to_lwipaddr(p_addr_in6, &lwip_addr);
+ err_t err = tcp_bind(p_handle->p_pcb, &lwip_addr, port);
+ err_code = lwip_error_convert(err);
+ }
+ return err_code;
+}
+
+static uint32_t lwip_transport_connect(socket_t * p_socket,
+ const void * p_addr,
+ socklen_t addr_len)
+{
+ VERIFY_ADDRESS_LEN(addr_len);
+
+ bool is_blocking = ((p_socket->so_flags & O_NONBLOCK) == 0);
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_socket->so_ctx;
+ const sockaddr_in6_t * p_addr_in6 = (const sockaddr_in6_t *)p_addr;
+ uint16_t port = 0;
+ uint32_t err_code = portdb_alloc(&port);
+
+ SOCKET_TRACE("Binding to port %d\r\n", (int)port);
+ if (err_code == NRF_SUCCESS)
+ {
+ ip6_addr_t any_addr;
+ ip6_addr_set_any(&any_addr);
+ err_t err = tcp_bind (p_handle->p_pcb, &any_addr, port);
+ SOCKET_TRACE("Err %d from bind\r\n", (int)err);
+ err_code = lwip_error_convert(err);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ ip6_addr_t remote_addr;
+ sockaddr_to_lwipaddr(p_addr_in6, &remote_addr);
+
+ p_handle->tcp_state = TCP_STATE_REQUEST_CONNECTION;
+ err_t err = tcp_connect(p_handle->p_pcb, &remote_addr, HTONS(p_addr_in6->sin6_port), lwip_connect_callback);
+ SOCKET_TRACE("Err %d from connect\r\n", (int)err);
+ err_code = lwip_error_convert(err);
+
+ if (err_code == NRF_SUCCESS && is_blocking)
+ {
+ err_code = lwip_wait_for_state(p_handle, TCP_STATE_CONNECTED);
+ }
+ }
+ if (err_code != NRF_SUCCESS)
+ {
+ SOCKET_TRACE("Error %d when connecting to socket\r\n", (int)err_code);
+ portdb_free(port);
+ }
+ else
+ {
+ SOCKET_TRACE("Successfully connected to remote host!\r\n");
+ }
+
+ return err_code;
+}
+
+static err_t lwip_send_complete(void * p_arg, struct tcp_pcb * p_pcb, u16_t len)
+{
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_arg;
+ if (p_handle->tcp_state == TCP_STATE_TCP_SEND_PENDING)
+ {
+ p_handle->tcp_state = TCP_STATE_DATA_TX_IN_PROGRESS;
+ }
+ return ERR_OK;
+}
+
+static inline uint32_t lwip_check_connected(socket_t * p_socket)
+{
+ return (p_socket->so_state == STATE_CONNECTED || p_socket->so_params.so_type == SOCK_DGRAM) ?
+ NRF_SUCCESS : SOCKET_NOT_CONNECTED;
+}
+
+
+static uint32_t lwip_transport_send(socket_t * p_socket,
+ const void * p_buf,
+ uint32_t buf_len,
+ int flags,
+ const void * p_destaddr,
+ socklen_t destaddr_len)
+{
+ (void) p_destaddr;
+ (void) destaddr_len;
+
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_socket->so_ctx;
+ if ((p_socket->so_flags & O_NONBLOCK) != 0 &&
+ (flags & MSG_WAITALL) == 0)
+ {
+ flags |= MSG_DONTWAIT;
+ }
+
+ uint32_t err_code = lwip_check_connected(p_socket);
+ if (err_code == NRF_SUCCESS)
+ {
+ uint32_t len = tcp_sndbuf(p_handle->p_pcb);
+ if (len >= buf_len)
+ {
+ tcp_sent(p_handle->p_pcb, lwip_send_complete);
+ p_handle->tcp_state = TCP_STATE_TCP_SEND_PENDING;
+ err_t err = tcp_write(p_handle->p_pcb, p_buf, buf_len, 1);
+ err_code = lwip_error_convert(err);
+ if (err_code == NRF_SUCCESS &&
+ (flags & MSG_DONTWAIT) == 0)
+ {
+ err_code = lwip_wait_for_state(p_handle, TCP_STATE_DATA_TX_IN_PROGRESS);
+ }
+ }
+ else
+ {
+ err_code = SOCKET_NO_MEM;
+ }
+ }
+ return err_code;
+}
+
+
+static uint32_t lwip_transport_recv(socket_t * p_socket,
+ void * p_buf,
+ uint32_t * p_buf_size,
+ int flags,
+ void * p_srcaddr,
+ socklen_t * p_srcaddr_len)
+{
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_socket->so_ctx;
+ if ((p_socket->so_flags & O_NONBLOCK) != 0 &&
+ (flags & MSG_WAITALL) == 0)
+ {
+ flags |= MSG_DONTWAIT;
+ }
+ uint32_t err_code = lwip_check_connected(p_socket);
+ if (err_code == NRF_SUCCESS)
+ {
+ if (mbuf_empty(&p_handle->mbuf) == true)
+ {
+ if ((flags & MSG_DONTWAIT) != 0)
+ {
+ err_code = SOCKET_WOULD_BLOCK;
+ }
+ else
+ {
+ while ((mbuf_empty(&p_handle->mbuf) == true) && (err_code == NRF_SUCCESS))
+ {
+ err_code = socket_wait();
+ }
+ }
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ *p_buf_size = mbuf_read(&p_handle->mbuf, p_buf, *p_buf_size);
+ tcp_recved(p_handle->p_pcb, *p_buf_size);
+ p_socket->so_read_evt = 0;
+ }
+ return err_code;
+}
+
+static err_t lwip_accept_callback(void * p_arg, struct tcp_pcb * p_pcb, err_t err)
+{
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_arg;
+ socket_t * p_socket = p_handle->p_socket;
+ if (err == ERR_OK)
+ {
+ (void) nrf_fifo_enq(&p_handle->conn_queue, p_pcb, true);
+ // TODO: Error check
+ p_socket->so_read_evt++;
+ }
+ return err;
+}
+
+static uint32_t lwip_transport_listen(socket_t * p_socket, int backlog)
+{
+ lwip_handle_t * p_handle = (lwip_handle_t *)p_socket->so_ctx;
+ uint32_t err_code = NRF_SUCCESS;
+ struct tcp_pcb * p_pcb = tcp_listen_with_backlog(p_handle->p_pcb, backlog);
+ if (p_pcb == NULL)
+ {
+ err_code = SOCKET_ADDRESS_IN_USE;
+ }
+ else
+ {
+ p_handle->p_pcb = p_pcb;
+ tcp_accept(p_handle->p_pcb, lwip_accept_callback);
+ }
+ return err_code;
+}
+
+static uint32_t lwip_transport_accept(socket_t * p_socket,
+ socket_t * p_client,
+ void * p_cliaddr,
+ socklen_t * p_cliaddr_len)
+{
+ VERIFY_ADDRESS_LEN(*p_cliaddr_len);
+ struct tcp_pcb * p_client_pcb = NULL;
+ lwip_handle_t * p_lwip_handle = (lwip_handle_t *)p_socket->so_ctx;
+ uint32_t err_code = nrf_fifo_deq(&p_lwip_handle->conn_queue,
+ (void **)&p_client_pcb,
+ (p_socket->so_flags & O_NONBLOCK) == 0);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ lwip_handle_t * p_lwip_client = lwip_handle_allocate(p_client, p_client_pcb);
+ sockaddr_in6_t * p_sockaddr = (sockaddr_in6_t *)p_cliaddr;
+
+ p_client->so_ctx = p_lwip_client;
+
+ lwipaddr_to_sockaddr(&p_client_pcb->remote_ip, p_sockaddr);
+ p_sockaddr->sin6_port = p_client_pcb->remote_port;
+ p_sockaddr->sin6_len = *p_cliaddr_len;
+ p_sockaddr->sin6_family = AF_INET6;
+ p_sockaddr->sin6_flowinfo = 0;
+ p_sockaddr->sin6_scope_id = 0;
+
+ /*lint -save -e548 */
+ tcp_accepted(p_lwip_handle->p_pcb);
+ /*lint -restore */
+ }
+
+ return err_code;
+}
+
+/**
+ * @brief Transport for LwIP socket.
+ */
+socket_transport_t transport_impl =
+{
+ .open = lwip_transport_open,
+ .bind = lwip_transport_bind,
+ .connect = lwip_transport_connect,
+ .send = lwip_transport_send,
+ .recv = lwip_transport_recv,
+ .listen = lwip_transport_listen,
+ .accept = lwip_transport_accept,
+ .close = lwip_transport_close
+};