BBR 1 Ebene

Revision:
0:fbdae7e6d805
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-os/features/nanostack/nanostack-interface/NanostackInterface.cpp	Mon May 14 11:29:06 2018 +0000
@@ -0,0 +1,928 @@
+/*
+ * Copyright (c) 2016-2017, Arm Limited and affiliates.
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed 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.
+ */
+
+/* Nanostack implementation of NetworkSocketAPI */
+
+#include "mbed.h"
+#include "rtos.h"
+#include "NanostackInterface.h"
+#include "NanostackLockGuard.h"
+
+#include "ns_address.h"
+#include "nsdynmemLIB.h"
+#include "eventOS_scheduler.h"
+#include "randLIB.h"
+#include "ip6string.h"
+
+#include "mesh_system.h" // from inside mbed-mesh-api
+#include "socket_api.h"
+#include "net_interface.h"
+
+// Uncomment to enable trace
+//#define HAVE_DEBUG
+#include "ns_trace.h"
+#define TRACE_GROUP "nsif"
+
+#define NS_INTERFACE_SOCKETS_MAX  16  //same as NanoStack SOCKET_MAX
+
+#define MALLOC  ns_dyn_mem_alloc
+#define FREE    ns_dyn_mem_free
+
+// Socket state progressions:
+// UDP: UNOPENED -> DATAGRAM
+// TCP client: UNOPENED -> OPENED -> CONNECTING -> STREAM -> CLOSED
+// TCP server: UNOPENED -> OPENED -> LISTENING
+// TCP accept: UNOPENED -> STREAM -> CLOSED
+enum socket_mode_t {
+    SOCKET_MODE_UNOPENED,   // No socket ID
+    SOCKET_MODE_DATAGRAM,   // Socket is datagram type
+    SOCKET_MODE_OPENED,     // Socket ID but no assigned use yet
+    SOCKET_MODE_CONNECTING, // Socket is connecting but not open yet
+    SOCKET_MODE_STREAM,     // Socket has an open stream
+    SOCKET_MODE_CLOSED,     // Socket is closed and resources are freed
+    SOCKET_MODE_LISTENING,  // Socket is listening for connections
+};
+
+
+class NanostackSocket {
+public:
+    static void socket_callback(void *cb);
+    static void* operator new(std::size_t sz);
+    static void operator delete(void* ptr);
+
+    NanostackSocket(int8_t protocol);
+    ~NanostackSocket(void);
+    bool open(void);
+    int accept(NanostackSocket *accepted_socket, ns_address_t *addr);
+    void close(void);
+    bool closed(void) {return SOCKET_MODE_CLOSED == mode;}
+    bool is_connecting(void);
+    void set_connecting(ns_address_t *addr);
+    bool is_connected(void);
+    void set_connected(void);
+    bool is_listening(void);
+    void set_listening(void);
+
+    // Socket events from nanostack
+    void event_data(socket_callback_t *sock_cb);
+    void event_connect_done(socket_callback_t *sock_cb);
+    void event_connect_fail(socket_callback_t *sock_cb);
+    void event_connect_closed(socket_callback_t *sock_cb);
+    void event_connection_reset(socket_callback_t *sock_cb);
+    void event_tx_done(socket_callback_t *sock_cb);
+    void event_tx_fail(socket_callback_t *sock_cb);
+    void event_incoming_connection(socket_callback_t *sock_cb);
+
+    // Run callback to signal the next layer of the NSAPI
+    void signal_event(void);
+
+    void (*callback)(void *);
+    void *callback_data;
+    int8_t socket_id;           /*!< allocated socket ID */
+    int8_t proto;               /*!< UDP or TCP */
+    bool addr_valid;
+    ns_address_t ns_address;
+private:
+    bool attach(int8_t socket_id);
+    socket_mode_t mode;
+};
+
+static NanostackSocket * socket_tbl[NS_INTERFACE_SOCKETS_MAX];
+
+nsapi_error_t map_mesh_error(mesh_error_t err)
+{
+    switch (err) {
+        case MESH_ERROR_NONE: return 0;
+        case MESH_ERROR_MEMORY: return NSAPI_ERROR_NO_MEMORY;
+        case MESH_ERROR_PARAM: return NSAPI_ERROR_UNSUPPORTED;
+        case MESH_ERROR_STATE: return NSAPI_ERROR_DEVICE_ERROR;
+        default: return NSAPI_ERROR_DEVICE_ERROR;
+    }
+}
+
+static void convert_mbed_addr_to_ns(ns_address_t *ns_addr,
+                             const SocketAddress *s_addr)
+{
+    ns_addr->type = ADDRESS_IPV6;
+    ns_addr->identifier = s_addr->get_port();
+    memcpy(ns_addr->address, s_addr->get_ip_bytes(), 16);
+}
+
+static void convert_ns_addr_to_mbed(SocketAddress *s_addr, const ns_address_t *ns_addr)
+{
+    s_addr->set_port(ns_addr->identifier);
+    s_addr->set_ip_bytes(ns_addr->address, NSAPI_IPv6);
+}
+
+static int8_t find_interface_by_address(const uint8_t target_addr[16])
+{
+    for (int if_id = 1; if_id <= 127; if_id++) {
+        int i = 0;
+        uint8_t if_addr[16];
+        while (arm_net_address_list_get_next(if_id, &i, if_addr) == 0) {
+            if (memcmp(target_addr, if_addr, 16) == 0) {
+                return if_id;
+            }
+        }
+    }
+    return -1;
+}
+
+void* NanostackSocket::operator new(std::size_t sz) {
+    return MALLOC(sz);
+}
+void NanostackSocket::operator delete(void* ptr) {
+    FREE(ptr);
+}
+
+NanostackSocket::NanostackSocket(int8_t protocol)
+{
+    nanostack_assert_locked();
+
+    callback = NULL;
+    callback_data = NULL;
+    socket_id = -1;
+    proto = protocol;
+    addr_valid = false;
+    memset(&ns_address, 0, sizeof(ns_address));
+    mode = SOCKET_MODE_UNOPENED;
+}
+
+NanostackSocket::~NanostackSocket()
+{
+    nanostack_assert_locked();
+
+    if (mode != SOCKET_MODE_CLOSED) {
+        close();
+    }
+}
+
+bool NanostackSocket::open(void)
+{
+    nanostack_assert_locked();
+    MBED_ASSERT(SOCKET_MODE_UNOPENED == mode);
+
+    int temp_socket = socket_open(proto, 0, socket_callback);
+
+    if (temp_socket < 0) {
+        tr_error("NanostackSocket::open() failed");
+        return false;
+    }
+
+    if (proto == SOCKET_TCP) {
+        /* Receive and send buffers enabled by default */
+        mode = SOCKET_MODE_OPENED;
+    } else {
+        static const int32_t rcvbuf_size = 2048;
+        socket_setsockopt(temp_socket, SOCKET_SOL_SOCKET, SOCKET_SO_RCVBUF, &rcvbuf_size, sizeof rcvbuf_size);
+        mode = SOCKET_MODE_DATAGRAM;
+    }
+
+    return attach(temp_socket);
+}
+
+int NanostackSocket::accept(NanostackSocket *accepted_socket, ns_address_t *addr)
+{
+    nanostack_assert_locked();
+    MBED_ASSERT(SOCKET_MODE_LISTENING == mode && SOCKET_MODE_UNOPENED == accepted_socket->mode);
+
+    int temp_socket = socket_accept(socket_id, addr, socket_callback);
+    if (temp_socket < 0) {
+        tr_error("NanostackSocket::accept() failed");
+        return temp_socket;
+    }
+    if (!accepted_socket->attach(temp_socket)) {
+        return -1;
+    }
+    accepted_socket->mode = SOCKET_MODE_STREAM;
+    return temp_socket;
+}
+
+bool NanostackSocket::attach(int8_t temp_socket)
+{
+    nanostack_assert_locked();
+    if (temp_socket >= NS_INTERFACE_SOCKETS_MAX) {
+        MBED_ASSERT(false);
+        return false;
+    }
+    if (socket_tbl[temp_socket] != NULL) {
+        MBED_ASSERT(false);
+        return false;
+    }
+    socket_id = temp_socket;
+    socket_tbl[socket_id] = this;
+    return true;
+}
+
+void NanostackSocket::close()
+{
+    nanostack_assert_locked();
+    MBED_ASSERT(mode != SOCKET_MODE_CLOSED);
+
+    if (socket_id >= 0) {
+        nsapi_error_t ret = socket_close(socket_id);
+        MBED_ASSERT(0 == ret);
+        MBED_ASSERT(socket_tbl[socket_id] == this);
+        socket_tbl[socket_id] = NULL;
+        socket_id = -1;
+    } else {
+        MBED_ASSERT(SOCKET_MODE_UNOPENED == mode);
+    }
+
+    mode = SOCKET_MODE_CLOSED;
+    signal_event();
+}
+
+bool NanostackSocket::is_connecting()
+{
+    return SOCKET_MODE_CONNECTING == mode;
+}
+
+void NanostackSocket::set_connecting(ns_address_t *addr)
+{
+    nanostack_assert_locked();
+    MBED_ASSERT(SOCKET_MODE_OPENED == mode);
+
+    memcpy(&ns_address, addr, sizeof(ns_address_t));
+    mode = SOCKET_MODE_CONNECTING;
+}
+
+bool NanostackSocket::is_connected()
+{
+    return SOCKET_MODE_STREAM == mode;
+}
+
+void NanostackSocket::set_connected()
+{
+    nanostack_assert_locked();
+    MBED_ASSERT(SOCKET_MODE_CONNECTING == mode);
+
+    mode = SOCKET_MODE_STREAM;
+}
+
+bool NanostackSocket::is_listening()
+{
+    return SOCKET_MODE_LISTENING == mode;
+}
+
+void NanostackSocket::set_listening()
+{
+    nanostack_assert_locked();
+    MBED_ASSERT(SOCKET_MODE_OPENED == mode);
+
+    mode = SOCKET_MODE_LISTENING;
+}
+
+void NanostackSocket::signal_event()
+{
+    nanostack_assert_locked();
+
+    if (callback != NULL) {
+        callback(callback_data);
+    }
+}
+
+void NanostackSocket::socket_callback(void *cb) {
+    nanostack_assert_locked();
+
+    socket_callback_t *sock_cb = (socket_callback_t *) cb;
+    NanostackSocket *socket = socket_tbl[sock_cb->socket_id];
+    MBED_ASSERT(socket != NULL);
+
+    tr_debug("socket_callback() sock=%d, event=%d, interface=%d, data len=%d",
+                     sock_cb->socket_id, sock_cb->event_type, sock_cb->interface_id, sock_cb->d_len);
+
+    switch (sock_cb->event_type) {
+        case SOCKET_DATA:
+            tr_debug("SOCKET_DATA, sock=%d, bytes=%d", sock_cb->socket_id, sock_cb->d_len);
+            socket->event_data(sock_cb);
+            break;
+        case SOCKET_CONNECT_DONE:
+            tr_debug("SOCKET_CONNECT_DONE");
+            socket->event_connect_done(sock_cb);
+            break;
+        case SOCKET_CONNECT_FAIL:
+            tr_debug("SOCKET_CONNECT_FAIL");
+            socket->event_connect_fail(sock_cb);
+            break;
+        case SOCKET_CONNECT_AUTH_FAIL:
+            tr_debug("SOCKET_CONNECT_AUTH_FAIL");
+            break;
+        case SOCKET_INCOMING_CONNECTION:
+            tr_debug("SOCKET_INCOMING_CONNECTION");
+            socket->event_incoming_connection(sock_cb);
+            break;
+        case SOCKET_TX_FAIL:
+            tr_debug("SOCKET_TX_FAIL");
+            socket->event_tx_fail(sock_cb);
+            break;
+        case SOCKET_CONNECT_CLOSED:
+            tr_debug("SOCKET_CONNECT_CLOSED");
+            socket->event_connect_closed(sock_cb);
+            break;
+        case SOCKET_CONNECTION_RESET:
+            tr_debug("SOCKET_CONNECTION_RESET");
+            socket->event_connection_reset(sock_cb);
+            break;
+        case SOCKET_NO_ROUTE:
+            tr_debug("SOCKET_NO_ROUTE");
+            socket->event_tx_fail(sock_cb);
+            break;
+        case SOCKET_TX_DONE:
+            socket->event_tx_done(sock_cb);
+            break;
+        case SOCKET_NO_RAM:
+            tr_debug("SOCKET_NO_RAM");
+            socket->event_tx_fail(sock_cb);
+            break;
+        case SOCKET_CONNECTION_PROBLEM:
+            tr_debug("SOCKET_CONNECTION_PROBLEM");
+            break;
+        default:
+            break;
+    }
+}
+
+
+void NanostackSocket::event_data(socket_callback_t *sock_cb)
+{
+    nanostack_assert_locked();
+    MBED_ASSERT((SOCKET_MODE_STREAM == mode) ||
+                (SOCKET_MODE_DATAGRAM == mode));
+
+    signal_event();
+}
+
+void NanostackSocket::event_tx_done(socket_callback_t *sock_cb)
+{
+    nanostack_assert_locked();
+    MBED_ASSERT((SOCKET_MODE_STREAM == mode) ||
+                (SOCKET_MODE_DATAGRAM == mode));
+
+    if (mode == SOCKET_MODE_DATAGRAM) {
+        tr_debug("SOCKET_TX_DONE, %d bytes sent", sock_cb->d_len);
+    } else if (mode == SOCKET_MODE_STREAM) {
+        tr_debug("SOCKET_TX_DONE, %d bytes remaining", sock_cb->d_len);
+    }
+
+    signal_event();
+}
+
+void NanostackSocket::event_connect_done(socket_callback_t *sock_cb)
+{
+    nanostack_assert_locked();
+    MBED_ASSERT(SOCKET_MODE_CONNECTING == mode);
+
+    set_connected();
+    signal_event();
+}
+
+void NanostackSocket::event_connect_fail(socket_callback_t *sock_cb)
+{
+    nanostack_assert_locked();
+    MBED_ASSERT(mode == SOCKET_MODE_CONNECTING);
+    close();
+}
+
+void NanostackSocket::event_incoming_connection(socket_callback_t *sock_cb)
+{
+    nanostack_assert_locked();
+    MBED_ASSERT(mode == SOCKET_MODE_LISTENING);
+    signal_event();
+}
+
+void NanostackSocket::event_connect_closed(socket_callback_t *sock_cb)
+{
+    nanostack_assert_locked();
+
+    // Can happen if we have an orderly close()
+    // Might never happen as we have not implemented shutdown() in abstraction layer.
+    MBED_ASSERT(mode == SOCKET_MODE_STREAM);
+    close();
+}
+
+void NanostackSocket::event_tx_fail(socket_callback_t *sock_cb)
+{
+    nanostack_assert_locked();
+
+    switch (mode) {
+        case SOCKET_MODE_CONNECTING:
+        case SOCKET_MODE_STREAM:
+            // TX_FAIL is fatal for stream sockets
+            close();
+            break;
+        case SOCKET_MODE_DATAGRAM:
+            // TX_FAIL is non-fatal for datagram sockets
+            break;
+        default:
+            MBED_ASSERT(false);
+            break;
+    }
+}
+
+void NanostackSocket::event_connection_reset(socket_callback_t *sock_cb)
+{
+    nanostack_assert_locked();
+
+    // Only TCP sockets can be closed by the remote end
+    MBED_ASSERT((SOCKET_MODE_STREAM == mode) ||
+                (SOCKET_MODE_CONNECTING == mode));
+    close();
+}
+
+NanostackInterface *NanostackInterface::_ns_interface;
+
+NanostackInterface *NanostackInterface::get_stack()
+{
+    NanostackLockGuard lock;
+
+    if (NULL == _ns_interface) {
+        _ns_interface = new NanostackInterface();
+    }
+
+    return _ns_interface;
+}
+
+const char * NanostackInterface::get_ip_address()
+{
+    NanostackLockGuard lock;
+
+    for (int if_id = 1; if_id <= 127; if_id++) {
+        uint8_t address[16];
+        int ret = arm_net_address_get(if_id, ADDR_IPV6_GP, address);
+        if (ret == 0) {
+            ip6tos(address, text_ip_address);
+            return text_ip_address;
+        }
+    }
+    // Must result a valid IPv6 address
+    // For gethostbyname() to detect IP version.
+    return "::";
+}
+
+nsapi_error_t NanostackInterface::socket_open(void **handle, nsapi_protocol_t protocol)
+{
+    // Validate parameters
+    if (NULL == handle) {
+        MBED_ASSERT(false);
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+    int8_t ns_proto;
+    if (NSAPI_UDP == protocol) {
+        ns_proto = SOCKET_UDP;
+    } else if (NSAPI_TCP == protocol) {
+        ns_proto = SOCKET_TCP;
+    } else {
+        MBED_ASSERT(false);
+        return NSAPI_ERROR_UNSUPPORTED;
+    }
+    *handle = (void*)NULL;
+
+    NanostackLockGuard lock;
+
+    NanostackSocket * socket = new NanostackSocket(ns_proto);
+    if (socket == NULL) {
+        tr_debug("socket_open() ret=%i", NSAPI_ERROR_NO_MEMORY);
+        return NSAPI_ERROR_NO_MEMORY;
+    }
+    if (!socket->open()) {
+        delete socket;
+        tr_debug("socket_open() ret=%i", NSAPI_ERROR_DEVICE_ERROR);
+        return NSAPI_ERROR_DEVICE_ERROR;
+    }
+    *handle = (void*)socket;
+
+    tr_debug("socket_open() socket=%p, sock_id=%d, ret=0", socket, socket->socket_id);
+
+    return NSAPI_ERROR_OK;
+}
+
+nsapi_error_t NanostackInterface::socket_close(void *handle)
+{
+    NanostackLockGuard lock;
+    // Validate parameters
+    NanostackSocket * socket = static_cast<NanostackSocket *>(handle);
+    if (NULL == handle) {
+        MBED_ASSERT(false);
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+    tr_debug("socket_close(socket=%p) sock_id=%d", socket, socket->socket_id);
+
+    delete socket;
+
+    return 0;
+
+}
+
+nsapi_size_or_error_t NanostackInterface::do_sendto(void *handle, const ns_address_t *address, const void *data, nsapi_size_t size)
+{
+    // Validate parameters
+    NanostackSocket * socket = static_cast<NanostackSocket *>(handle);
+    if (handle == NULL) {
+        MBED_ASSERT(false);
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    nsapi_size_or_error_t ret;
+
+    NanostackLockGuard lock;
+
+    if (socket->closed() || (!address && !socket->is_connected())) {
+        ret = NSAPI_ERROR_NO_CONNECTION;
+        goto out;
+    }
+
+    if (address && socket->proto == SOCKET_TCP) {
+        tr_error("socket_sendto() not supported with TCP!");
+        ret = NSAPI_ERROR_IS_CONNECTED;
+        goto out;
+    }
+
+    int retcode;
+#if 0
+    retcode = ::socket_sendto(socket->socket_id, address,
+                                            data, size);
+#else
+    // Use sendmsg purely to get the new return style
+    // of returning data written rather than 0 on success,
+    // which means TCP can do partial writes. (Sadly,
+    // it's the only call which takes flags so we can
+    // leave the NS_MSG_LEGACY0 flag clear).
+    ns_msghdr_t msg;
+    ns_iovec_t iov;
+    iov.iov_base = const_cast<void *>(data);
+    iov.iov_len = size;
+    msg.msg_name = const_cast<ns_address_t *>(address);
+    msg.msg_namelen = address ? sizeof *address : 0;
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    msg.msg_control = NULL;
+    msg.msg_controllen = 0;
+    retcode = ::socket_sendmsg(socket->socket_id, &msg, 0);
+#endif
+
+    /*
+     * \return length if entire amount written (which could be 0)
+     * \return value >0 and <length if partial amount written (stream only)
+     * \return NS_EWOULDBLOCK if nothing written due to lack of queue space.
+     * \return -1 Invalid socket ID or message structure.
+     * \return -2 Socket memory allocation fail.
+     * \return -3 TCP state not established or address scope not defined .
+     * \return -4 Socket TX process busy or unknown interface.
+     * \return -5 Socket not connected
+     * \return -6 Packet too short (ICMP raw socket error).
+     * */
+    if (retcode == NS_EWOULDBLOCK) {
+        ret = NSAPI_ERROR_WOULD_BLOCK;
+    } else if (retcode < 0) {
+        tr_error("socket_sendmsg: error=%d", retcode);
+        ret = NSAPI_ERROR_DEVICE_ERROR;
+    } else {
+        ret = retcode;
+    }
+
+out:
+    tr_debug("socket_sendto(socket=%p) sock_id=%d, ret=%i", socket, socket->socket_id, ret);
+
+    return ret;
+}
+
+nsapi_size_or_error_t NanostackInterface::socket_sendto(void *handle, const SocketAddress &address, const void *data, nsapi_size_t size)
+{
+    if (address.get_ip_version() != NSAPI_IPv6) {
+        return NSAPI_ERROR_UNSUPPORTED;
+    }
+
+    ns_address_t ns_address;
+    convert_mbed_addr_to_ns(&ns_address, &address);
+    /*No lock gaurd needed here as do_sendto() will handle locks.*/
+    return do_sendto(handle, &ns_address, data, size);
+}
+
+nsapi_size_or_error_t NanostackInterface::socket_recvfrom(void *handle, SocketAddress *address, void *buffer, nsapi_size_t size)
+{
+    // Validate parameters
+    NanostackSocket *socket = static_cast<NanostackSocket *>(handle);
+    if (handle == NULL) {
+        MBED_ASSERT(false);
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    nsapi_size_or_error_t ret;
+
+    NanostackLockGuard lock;
+
+    if (socket->closed()) {
+        ret = NSAPI_ERROR_NO_CONNECTION;
+        goto out;
+    }
+
+    ns_address_t ns_address;
+
+    int retcode;
+    retcode = ::socket_recvfrom(socket->socket_id, buffer, size, 0, &ns_address);
+
+    if (retcode == NS_EWOULDBLOCK) {
+        ret = NSAPI_ERROR_WOULD_BLOCK;
+    } else if (retcode < 0) {
+        ret = NSAPI_ERROR_PARAMETER;
+    } else {
+        ret = retcode;
+        if (address != NULL) {
+            convert_ns_addr_to_mbed(address, &ns_address);
+        }
+    }
+
+out:
+    if (address) {
+        tr_debug("socket_recvfrom(socket=%p) sock_id=%d, ret=%i, addr=[%s]:%i", socket, socket->socket_id, ret,
+                 trace_ipv6(address->get_ip_bytes()), address->get_port());
+    } else {
+        tr_debug("socket_recv(socket=%p) sock_id=%d, ret=%i", socket, socket->socket_id, ret);
+    }
+
+    return ret;
+}
+
+nsapi_error_t NanostackInterface::socket_bind(void *handle, const SocketAddress &address)
+{
+    // Validate parameters
+    NanostackSocket *socket = static_cast<NanostackSocket *>(handle);
+    if (handle == NULL) {
+        MBED_ASSERT(false);
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    const void *addr_field;
+    switch (address.get_ip_version()) {
+        case NSAPI_IPv6:
+            addr_field = address.get_ip_bytes();
+            break;
+        case NSAPI_UNSPEC:
+            addr_field = &ns_in6addr_any;
+            break;
+        default:
+            return NSAPI_ERROR_UNSUPPORTED;
+    }
+
+    NanostackLockGuard lock;
+
+    ns_address_t ns_address;
+    ns_address.type = ADDRESS_IPV6;
+    memcpy(ns_address.address, addr_field, sizeof ns_address.address);
+    ns_address.identifier = address.get_port();
+    nsapi_error_t ret;
+    int retcode = ::socket_bind(socket->socket_id, &ns_address);
+
+    if (retcode == 0) {
+        ret = NSAPI_ERROR_OK;
+    } else {
+        ret = NSAPI_ERROR_PARAMETER;
+    }
+
+    tr_debug("socket_bind(socket=%p) sock_id=%d, retcode=%i, ret=%i", socket, socket->socket_id, retcode, ret);
+
+    return ret;
+}
+
+nsapi_error_t NanostackInterface::setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen)
+{
+    NanostackSocket *socket = static_cast<NanostackSocket *>(handle);
+    if (handle == NULL) {
+        MBED_ASSERT(false);
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    NanostackLockGuard lock;
+
+    ns_ipv6_mreq_t ns_mreq;
+
+    if (level == NSAPI_SOCKET) {
+        switch (optname) {
+            case NSAPI_ADD_MEMBERSHIP:
+            case NSAPI_DROP_MEMBERSHIP: {
+                if (optlen != sizeof(nsapi_ip_mreq_t)) {
+                    return NSAPI_ERROR_PARAMETER;
+                }
+                const nsapi_ip_mreq_t *imr = static_cast<const nsapi_ip_mreq_t *>(optval);
+
+                /* Check address types are IPv6, or unspecified for interface */
+                if (imr->imr_multiaddr.version != NSAPI_IPv6 ||
+                    (imr->imr_interface.version != NSAPI_UNSPEC && imr->imr_interface.version != NSAPI_IPv6)) {
+                    return NSAPI_ERROR_PARAMETER;
+                }
+
+                /* Convert all parameters to Nanostack native, and proceed with setsockopt */
+                memcpy(ns_mreq.ipv6mr_multiaddr, imr->imr_multiaddr.bytes, 16);
+                if (imr->imr_interface.version == NSAPI_UNSPEC || memcmp(imr->imr_interface.bytes, ns_in6addr_any, 16) == 0) {
+                    ns_mreq.ipv6mr_interface = 0;
+                } else {
+                    // If this fails, Nanostack will itself fault the invalid -1 interface ID
+                    ns_mreq.ipv6mr_interface = find_interface_by_address(imr->imr_interface.bytes);
+                }
+
+                level = SOCKET_IPPROTO_IPV6;
+                optname = optname == NSAPI_ADD_MEMBERSHIP ? SOCKET_IPV6_JOIN_GROUP : SOCKET_IPV6_LEAVE_GROUP;
+                optval = &ns_mreq;
+                optlen = sizeof ns_mreq;
+                break;
+            }
+            default:
+                return NSAPI_ERROR_PARAMETER;
+        }
+    }
+
+    if (::socket_setsockopt(socket->socket_id, level, optname, optval, optlen) == 0) {
+        return NSAPI_ERROR_OK;
+    } else {
+        return NSAPI_ERROR_PARAMETER;
+    }
+}
+
+nsapi_error_t NanostackInterface::getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen)
+{
+    NanostackSocket *socket = static_cast<NanostackSocket *>(handle);
+    if (handle == NULL) {
+        MBED_ASSERT(false);
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    nsapi_error_t ret;
+
+    NanostackLockGuard lock;
+
+    uint16_t optlen16 = *optlen;
+    if (::socket_getsockopt(socket->socket_id, level, optname, optval, &optlen16) == 0) {
+        ret = NSAPI_ERROR_OK;
+        *optlen = optlen16;
+    } else {
+        ret = NSAPI_ERROR_PARAMETER;
+    }
+
+    return ret;
+}
+
+nsapi_error_t NanostackInterface::socket_listen(void *handle, int backlog)
+{
+    //Check if socket exists
+    NanostackSocket *socket = static_cast<NanostackSocket *>(handle);
+    if (handle == NULL) {
+        MBED_ASSERT(false);
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    nsapi_error_t ret = NSAPI_ERROR_OK;
+
+    NanostackLockGuard lock;
+
+    if(::socket_listen(socket->socket_id, backlog) < 0) {
+        ret = NSAPI_ERROR_PARAMETER;
+    } else {
+        socket->set_listening();
+    }
+
+    return ret;
+}
+
+nsapi_error_t NanostackInterface::socket_connect(void *handle, const SocketAddress &addr)
+{
+    // Validate parameters
+    NanostackSocket *socket = static_cast<NanostackSocket *>(handle);
+    nsapi_error_t ret;
+    if (handle == NULL) {
+        MBED_ASSERT(false);
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    NanostackLockGuard lock;
+
+    if (addr.get_ip_version() != NSAPI_IPv6) {
+        ret = NSAPI_ERROR_UNSUPPORTED;
+        goto out;
+    }
+
+    if (socket->closed()) {
+        ret = NSAPI_ERROR_NO_CONNECTION;
+        goto out;
+    }
+
+    if (socket->is_connecting()) {
+        ret = NSAPI_ERROR_ALREADY;
+        goto out;
+    }
+
+    if (socket->is_connected()) {
+        ret = NSAPI_ERROR_IS_CONNECTED;
+        goto out;
+    }
+
+    ns_address_t ns_addr;
+
+    convert_mbed_addr_to_ns(&ns_addr, &addr);
+    if (::socket_connect(socket->socket_id, &ns_addr, 0) == 0) {
+        if (socket->proto == SOCKET_TCP) {
+            socket->set_connecting(&ns_addr);
+            ret = NSAPI_ERROR_IN_PROGRESS;
+        } else {
+            ret = NSAPI_ERROR_OK;
+        }
+    } else {
+        ret = NSAPI_ERROR_DEVICE_ERROR;
+    }
+
+out:
+    tr_debug("socket_connect(socket=%p) sock_id=%d, ret=%i", socket, socket->socket_id, ret);
+
+    return ret;
+}
+
+nsapi_error_t NanostackInterface::socket_accept(void *server, void **handle, SocketAddress *address)
+{
+    NanostackSocket * socket = static_cast<NanostackSocket *>(server);
+    NanostackSocket *accepted_sock = NULL;
+    nsapi_error_t ret;
+
+    if (handle == NULL) {
+        MBED_ASSERT(false);
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    NanostackLockGuard lock;
+
+    if (!socket->is_listening()) {
+        ret = NSAPI_ERROR_PARAMETER;
+        goto out;
+    }
+
+    accepted_sock = new NanostackSocket(socket->proto);
+    if (accepted_sock == NULL) {
+        ret = NSAPI_ERROR_NO_MEMORY;
+        goto out;
+    }
+
+    ns_address_t ns_addr;
+    int retcode;
+    retcode = socket->accept(accepted_sock, &ns_addr);
+    if (retcode < 0) {
+        delete accepted_sock;
+        if (retcode == NS_EWOULDBLOCK) {
+            ret = NSAPI_ERROR_WOULD_BLOCK;
+        } else {
+            ret = NSAPI_ERROR_DEVICE_ERROR;
+        }
+        goto out;
+    }
+    ret = NSAPI_ERROR_OK;
+
+    if (address) {
+        convert_ns_addr_to_mbed(address, &ns_addr);
+    }
+
+    *handle = accepted_sock;
+
+out:
+    tr_debug("socket_accept() socket=%p, sock_id=%d, ret=%i", accepted_sock, accepted_sock ? accepted_sock->socket_id : -1, ret);
+
+    return ret;
+}
+
+nsapi_size_or_error_t NanostackInterface::socket_send(void *handle, const void *data, nsapi_size_t size)
+{
+    return do_sendto(handle, NULL, data, size);
+}
+
+nsapi_size_or_error_t NanostackInterface::socket_recv(void *handle, void *data, nsapi_size_t size)
+{
+    return socket_recvfrom(handle, NULL, data, size);
+}
+
+void NanostackInterface::socket_attach(void *handle, void (*callback)(void *), void *id)
+{
+    // Validate parameters
+    NanostackSocket * socket = static_cast<NanostackSocket *>(handle);
+    if (handle == NULL) {
+        MBED_ASSERT(false);
+        return;
+    }
+
+    NanostackLockGuard lock;
+
+    socket->callback = callback;
+    socket->callback_data = id;
+
+    tr_debug("socket_attach(socket=%p) sock_id=%d", socket, socket->socket_id);
+}