Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers LWIPStack.cpp Source File

LWIPStack.cpp

00001 /* LWIP implementation of NSAPI NetworkStack
00002  * Copyright (c) 2017 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include "nsapi.h"
00017 #include "mbed_interface.h"
00018 #include "mbed_assert.h"
00019 #include "Semaphore.h"
00020 #include <stdio.h>
00021 #include <stdbool.h>
00022 #include <string.h>
00023 
00024 #include "lwip/opt.h"
00025 #include "lwip/api.h"
00026 #include "lwip/inet.h"
00027 #include "lwip/netif.h"
00028 #include "lwip/dhcp.h"
00029 #include "lwip/tcpip.h"
00030 #include "lwip/tcp.h"
00031 #include "lwip/ip.h"
00032 #include "lwip/mld6.h"
00033 #include "lwip/igmp.h"
00034 #include "lwip/dns.h"
00035 #include "lwip/udp.h"
00036 #include "lwip/raw.h"
00037 #include "lwip/netif.h"
00038 #include "lwip/lwip_errno.h"
00039 #include "lwip-sys/arch/sys_arch.h"
00040 
00041 #include "LWIPStack.h"
00042 #include "lwip_tools.h"
00043 
00044 #ifndef LWIP_SOCKET_MAX_MEMBERSHIPS
00045 #define LWIP_SOCKET_MAX_MEMBERSHIPS 4
00046 #endif
00047 
00048 void LWIP::socket_callback(struct netconn *nc, enum netconn_evt eh, u16_t len)
00049 {
00050     // Filter send minus events
00051     if (eh == NETCONN_EVT_SENDMINUS && nc->state == NETCONN_WRITE) {
00052         return;
00053     }
00054 
00055     LWIP &lwip = LWIP::get_instance();
00056     lwip.adaptation.lock();
00057 
00058     if (eh == NETCONN_EVT_RCVPLUS && nc->state == NETCONN_NONE) {
00059         lwip._event_flag.set(TCP_CLOSED_FLAG);
00060     }
00061 
00062     for (int i = 0; i < MEMP_NUM_NETCONN; i++) {
00063         if (lwip.arena[i].in_use
00064                 && lwip.arena[i].conn == nc
00065                 && lwip.arena[i].cb) {
00066             lwip.arena[i].cb(lwip.arena[i].data);
00067         }
00068     }
00069 
00070     lwip.adaptation.unlock();
00071 }
00072 
00073 void LWIP::tcpip_init_irq(void *eh)
00074 {
00075     static_cast<rtos::Semaphore *>(eh)->release();
00076     sys_tcpip_thread_set();
00077 }
00078 
00079 /* LWIP network stack implementation */
00080 LWIP::LWIP()
00081 {
00082     default_interface = NULL;
00083     tcpip_thread_id = NULL;
00084 
00085     // Seed lwip random
00086     lwip_seed_random();
00087 
00088     // Initialise TCP sequence number
00089     uint32_t tcp_isn_secret[4];
00090     for (int i = 0; i < 4; i++) {
00091         tcp_isn_secret[i] = LWIP_RAND();
00092     }
00093     lwip_init_tcp_isn(0, (u8_t *) &tcp_isn_secret);
00094 
00095     rtos::Semaphore tcpip_inited;
00096 
00097     tcpip_init(&LWIP::tcpip_init_irq, &tcpip_inited);
00098     tcpip_inited.acquire();
00099 
00100     // Zero out socket set
00101     arena_init();
00102 }
00103 
00104 nsapi_error_t LWIP::get_dns_server(int index, SocketAddress *address, const char *interface_name)
00105 {
00106     int dns_entries = 0;
00107 
00108     for (int i = 0; i < DNS_MAX_SERVERS; i++) {
00109         const ip_addr_t *ip_addr = dns_getserver(i, interface_name);
00110         if (!ip_addr_isany(ip_addr)) {
00111             if (index == dns_entries) {
00112                 nsapi_addr_t addr;
00113                 convert_lwip_addr_to_mbed(&addr, ip_addr);
00114                 address->set_addr(addr);
00115                 return NSAPI_ERROR_OK ;
00116             }
00117             dns_entries++;
00118         }
00119     }
00120     return NSAPI_ERROR_NO_ADDRESS ;
00121 }
00122 
00123 nsapi_error_t LWIP::add_dns_server(const SocketAddress &address, const char *interface_name)
00124 {
00125     int index;
00126     nsapi_addr_t addr = address.get_addr();
00127     const ip_addr_t *ip_addr_move;
00128     ip_addr_t ip_addr;
00129 
00130     if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
00131         return NSAPI_ERROR_PARAMETER ;
00132     }
00133 
00134     if (ip_addr_isany(&ip_addr)) {
00135         return NSAPI_ERROR_NO_ADDRESS ;
00136     }
00137 
00138     if (interface_name == NULL) {
00139         for (index = DNS_MAX_SERVERS - 1; index > 0; index--) {
00140             ip_addr_move = dns_getserver(index - 1, NULL);
00141             if (!ip_addr_isany(ip_addr_move)) {
00142                 dns_setserver(index, ip_addr_move, NULL);
00143             }
00144         }
00145         dns_setserver(0, &ip_addr, NULL);
00146     } else {
00147         for (index = DNS_MAX_SERVERS - 1; index > 0; index--) {
00148             ip_addr_move = dns_get_interface_server(index - 1, interface_name);
00149             if (!ip_addr_isany(ip_addr_move)) {
00150                 dns_add_interface_server(index, interface_name, ip_addr_move);
00151             }
00152         }
00153         dns_add_interface_server(0, interface_name, &ip_addr);
00154     }
00155     return NSAPI_ERROR_OK ;
00156 }
00157 
00158 void LWIP::tcpip_thread_callback(void *ptr)
00159 {
00160     lwip_callback *cb = static_cast<lwip_callback *>(ptr);
00161 
00162     if (cb->delay) {
00163         sys_timeout(cb->delay, LWIP::tcpip_thread_callback, ptr);
00164         cb->delay = 0;
00165     } else {
00166         cb->callback();
00167         delete cb;
00168     }
00169 }
00170 
00171 nsapi_error_t LWIP::call_in(int delay, mbed::Callback<void()> func)
00172 {
00173     lwip_callback *cb = new (std::nothrow) lwip_callback;
00174     if (!cb) {
00175         return NSAPI_ERROR_NO_MEMORY ;
00176     }
00177 
00178     cb->delay = delay;
00179     cb->callback = func;
00180 
00181     if (tcpip_callback_with_block(LWIP::tcpip_thread_callback, cb, 1) != ERR_OK) {
00182         return NSAPI_ERROR_NO_MEMORY ;
00183     }
00184 
00185     return NSAPI_ERROR_OK ;
00186 }
00187 
00188 LWIP::call_in_callback_cb_t LWIP::get_call_in_callback()
00189 {
00190     call_in_callback_cb_t cb(this, &LWIP::call_in);
00191     return cb;
00192 }
00193 
00194 const char *LWIP::get_ip_address()
00195 {
00196     if (!default_interface) {
00197         return NULL;
00198     }
00199 
00200     const ip_addr_t *addr = get_ip_addr(true, &default_interface->netif);
00201 
00202     if (!addr) {
00203         return NULL;
00204     }
00205 #if LWIP_IPV6
00206     if (IP_IS_V6(addr)) {
00207         return ip6addr_ntoa_r(ip_2_ip6(addr), ip_address, sizeof(ip_address));
00208     }
00209 #endif
00210 #if LWIP_IPV4
00211     if (IP_IS_V4(addr)) {
00212         return ip4addr_ntoa_r(ip_2_ip4(addr), ip_address, sizeof(ip_address));
00213     }
00214 #endif
00215 #if LWIP_IPV6 && LWIP_IPV4
00216     return NULL;
00217 #endif
00218 }
00219 
00220 nsapi_error_t LWIP::get_ip_address_if(SocketAddress *address, const char *interface_name)
00221 {
00222     if (!address) {
00223         return NSAPI_ERROR_PARAMETER ;
00224     }
00225 
00226     const ip_addr_t *addr;
00227 
00228     if (interface_name == NULL) {
00229         addr = get_ip_addr(true, &default_interface->netif);
00230     } else {
00231         addr = get_ip_addr(true, netif_find(interface_name));
00232     }
00233 #if LWIP_IPV6
00234     if (IP_IS_V6(addr)) {
00235         char buf[NSAPI_IPv6_SIZE];
00236         address->set_ip_address(ip6addr_ntoa_r(ip_2_ip6(addr), buf, NSAPI_IPv6_SIZE));
00237         return NSAPI_ERROR_OK ;
00238     }
00239 #endif
00240 #if LWIP_IPV4
00241     if (IP_IS_V4(addr)) {
00242         char buf[NSAPI_IPv4_SIZE];
00243         address->set_ip_address(ip4addr_ntoa_r(ip_2_ip4(addr), buf, NSAPI_IPv4_SIZE));
00244         return NSAPI_ERROR_OK ;
00245     }
00246 #endif
00247     return NSAPI_ERROR_UNSUPPORTED ;
00248 }
00249 
00250 nsapi_error_t LWIP::socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto)
00251 {
00252     // check if network is connected
00253 //    if (lwip_connected == NSAPI_STATUS_DISCONNECTED) {
00254 //        return NSAPI_ERROR_NO_CONNECTION;
00255 //    }
00256 
00257     // allocate a socket
00258     struct mbed_lwip_socket *s = arena_alloc();
00259     if (!s) {
00260         return NSAPI_ERROR_NO_SOCKET ;
00261     }
00262 
00263     enum netconn_type netconntype;
00264     if (proto == NSAPI_TCP ) {
00265         netconntype = NETCONN_TCP;
00266     } else if (proto == NSAPI_UDP ) {
00267         netconntype = NETCONN_UDP;
00268     } else if (proto == NSAPI_ICMP ) {
00269         netconntype = NETCONN_RAW;
00270     } else {
00271         return NSAPI_ERROR_UNSUPPORTED ;
00272     }
00273 
00274 #if LWIP_IPV6
00275     // Enable IPv6 (or dual-stack)
00276     netconntype = (enum netconn_type)(netconntype | NETCONN_TYPE_IPV6);
00277 #endif
00278 
00279     if (proto == NSAPI_ICMP ) {
00280         s->conn = netconn_new_with_proto_and_callback(NETCONN_RAW,
00281                                                       (u8_t)IP_PROTO_ICMP, &LWIP::socket_callback);
00282     } else {
00283         s->conn = netconn_new_with_callback(netconntype, &LWIP::socket_callback);
00284     }
00285 
00286     if (!s->conn) {
00287         arena_dealloc(s);
00288         return NSAPI_ERROR_NO_SOCKET ;
00289     }
00290 
00291     netconn_set_recvtimeout(s->conn, 1);
00292     *(struct mbed_lwip_socket **)handle = s;
00293     return 0;
00294 }
00295 
00296 nsapi_error_t LWIP::socket_close(nsapi_socket_t handle)
00297 {
00298     struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
00299 #if LWIP_TCP
00300     /* Check if TCP FSM is in ESTABLISHED state.
00301      * Then give extra time for connection close handshaking  until TIME_WAIT state.
00302      * The purpose is to prevent eth/wifi driver stop and  FIN ACK corrupt.
00303      * This may happend if network interface disconnect follows immediately after socket_close.*/
00304     if (NETCONNTYPE_GROUP(s->conn->type) == NETCONN_TCP && s->conn->pcb.tcp->state == ESTABLISHED) {
00305         _event_flag.clear(TCP_CLOSED_FLAG);
00306         netconn_shutdown(s->conn, false, true);
00307         _event_flag.wait_any(TCP_CLOSED_FLAG, TCP_CLOSE_TIMEOUT);
00308     }
00309 #endif
00310     pbuf_free(s->buf);
00311     err_t err = netconn_delete(s->conn);
00312     arena_dealloc(s);
00313     return err_remap(err);
00314 }
00315 
00316 nsapi_error_t LWIP::socket_bind(nsapi_socket_t handle, const SocketAddress &address)
00317 {
00318     struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
00319     ip_addr_t ip_addr;
00320 
00321     if (
00322 #if LWIP_TCP
00323         (NETCONNTYPE_GROUP(s->conn->type) == NETCONN_TCP && s->conn->pcb.tcp->local_port != 0) ||
00324 #endif
00325         (NETCONNTYPE_GROUP(s->conn->type) == NETCONN_UDP && s->conn->pcb.udp->local_port != 0)) {
00326         return NSAPI_ERROR_PARAMETER ;
00327     }
00328 
00329     nsapi_addr_t addr = address.get_addr();
00330     if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
00331         return NSAPI_ERROR_PARAMETER ;
00332     }
00333 
00334     if (!ip_addr_isany_val(ip_addr) && !is_local_addr(&ip_addr)) {
00335         return NSAPI_ERROR_PARAMETER ;
00336     }
00337 
00338     err_t err = netconn_bind(s->conn, &ip_addr, address.get_port());
00339     return err_remap(err);
00340 }
00341 
00342 nsapi_error_t LWIP::socket_listen(nsapi_socket_t handle, int backlog)
00343 {
00344 #if LWIP_TCP
00345     struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
00346 
00347     if (s->conn->pcb.tcp->local_port == 0) {
00348         return NSAPI_ERROR_PARAMETER ;
00349     }
00350 
00351     err_t err = netconn_listen_with_backlog(s->conn, backlog);
00352     return err_remap(err);
00353 #else
00354     return NSAPI_ERROR_UNSUPPORTED ;
00355 #endif
00356 }
00357 
00358 nsapi_error_t LWIP::socket_connect(nsapi_socket_t handle, const SocketAddress &address)
00359 {
00360     struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
00361     ip_addr_t ip_addr;
00362 
00363     nsapi_addr_t addr = address.get_addr();
00364     if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
00365         return NSAPI_ERROR_PARAMETER ;
00366     }
00367 
00368     netconn_set_nonblocking(s->conn, false);
00369     err_t err = netconn_connect(s->conn, &ip_addr, address.get_port());
00370     netconn_set_nonblocking(s->conn, true);
00371 
00372     return err_remap(err);
00373 }
00374 
00375 nsapi_error_t LWIP::socket_accept(nsapi_socket_t server, nsapi_socket_t *handle, SocketAddress *address)
00376 {
00377 #if LWIP_TCP
00378     struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)server;
00379     struct mbed_lwip_socket *ns = arena_alloc();
00380     if (!ns) {
00381         return NSAPI_ERROR_NO_SOCKET ;
00382     }
00383 
00384     if (s->conn->pcb.tcp->state != LISTEN) {
00385         return NSAPI_ERROR_PARAMETER ;
00386     }
00387 
00388     err_t err = netconn_accept(s->conn, &ns->conn);
00389     if (err != ERR_OK) {
00390         arena_dealloc(ns);
00391         return err_remap(err);
00392     }
00393 
00394     netconn_set_recvtimeout(ns->conn, 1);
00395     *(struct mbed_lwip_socket **)handle = ns;
00396 
00397     ip_addr_t peer_addr;
00398     nsapi_addr_t addr;
00399     u16_t port;
00400     (void) netconn_peer(ns->conn, &peer_addr, &port);
00401     convert_lwip_addr_to_mbed(&addr, &peer_addr);
00402 
00403     if (address) {
00404         address->set_addr(addr);
00405         address->set_port(port);
00406     }
00407 
00408     netconn_set_nonblocking(ns->conn, true);
00409 
00410     return 0;
00411 #else
00412     return NSAPI_ERROR_UNSUPPORTED ;
00413 #endif
00414 }
00415 
00416 nsapi_size_or_error_t LWIP::socket_send(nsapi_socket_t handle, const void *data, nsapi_size_t size)
00417 {
00418     struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
00419     size_t bytes_written = 0;
00420 
00421     err_t err = netconn_write_partly(s->conn, data, size, NETCONN_COPY, &bytes_written);
00422     if (err != ERR_OK) {
00423         return err_remap(err);
00424     }
00425 
00426     return (nsapi_size_or_error_t)bytes_written;
00427 }
00428 
00429 nsapi_size_or_error_t LWIP::socket_recv(nsapi_socket_t handle, void *data, nsapi_size_t size)
00430 {
00431 #if LWIP_TCP
00432     struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
00433 
00434     if (!s->buf) {
00435         err_t err = netconn_recv_tcp_pbuf(s->conn, &s->buf);
00436         s->offset = 0;
00437 
00438         if (err != ERR_OK) {
00439             return err_remap(err);
00440         }
00441     }
00442 
00443     u16_t recv = pbuf_copy_partial(s->buf, data, (u16_t)size, s->offset);
00444     s->offset += recv;
00445 
00446     if (s->offset >= s->buf->tot_len) {
00447         pbuf_free(s->buf);
00448         s->buf = 0;
00449     }
00450 
00451     return recv;
00452 #else
00453     return NSAPI_ERROR_UNSUPPORTED ;
00454 #endif
00455 }
00456 
00457 nsapi_size_or_error_t LWIP::socket_sendto(nsapi_socket_t handle, const SocketAddress &address, const void *data, nsapi_size_t size)
00458 {
00459     struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
00460     ip_addr_t ip_addr;
00461 
00462     nsapi_addr_t addr = address.get_addr();
00463     if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
00464         return NSAPI_ERROR_PARAMETER ;
00465     }
00466     struct netif *netif_ = netif_get_by_index(s->conn->pcb.ip->netif_idx);
00467     if (!netif_) {
00468         netif_ = &default_interface->netif;
00469     }
00470     if (netif_) {
00471         if ((addr.version == NSAPI_IPv4  && !get_ipv4_addr(netif_)) ||
00472                 (addr.version == NSAPI_IPv6  && !get_ipv6_addr(netif_) && !get_ipv6_link_local_addr(netif_))) {
00473             return NSAPI_ERROR_PARAMETER ;
00474         }
00475     }
00476     struct netbuf *buf = netbuf_new();
00477 
00478     err_t err = netbuf_ref(buf, data, (u16_t)size);
00479     if (err != ERR_OK) {
00480         netbuf_free(buf);
00481         return err_remap(err);
00482     }
00483 
00484     err = netconn_sendto(s->conn, buf, &ip_addr, address.get_port());
00485     netbuf_delete(buf);
00486     if (err != ERR_OK) {
00487         return err_remap(err);
00488     }
00489 
00490     return size;
00491 }
00492 
00493 nsapi_size_or_error_t LWIP::socket_recvfrom(nsapi_socket_t handle, SocketAddress *address, void *data, nsapi_size_t size)
00494 {
00495     struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
00496     struct netbuf *buf;
00497 
00498     err_t err = netconn_recv(s->conn, &buf);
00499     if (err != ERR_OK) {
00500         return err_remap(err);
00501     }
00502 
00503     if (address) {
00504         nsapi_addr_t addr;
00505         convert_lwip_addr_to_mbed(&addr, netbuf_fromaddr(buf));
00506         address->set_addr(addr);
00507         address->set_port(netbuf_fromport(buf));
00508     }
00509 
00510     u16_t recv = netbuf_copy(buf, data, (u16_t)size);
00511     netbuf_delete(buf);
00512 
00513     return recv;
00514 }
00515 
00516 int32_t LWIP::find_multicast_member(const struct mbed_lwip_socket *s, const nsapi_ip_mreq_t *imr)
00517 {
00518     uint32_t count = 0;
00519     uint32_t index = 0;
00520     // Set upper limit on while loop, should break out when the membership pair is found
00521     while (count < s->multicast_memberships_count) {
00522         index = next_registered_multicast_member(s, index);
00523 
00524         if (memcmp(&s->multicast_memberships[index].imr_multiaddr, &imr->imr_multiaddr, sizeof(nsapi_addr_t)) == 0 &&
00525                 memcmp(&s->multicast_memberships[index].imr_interface, &imr->imr_interface, sizeof(nsapi_addr_t)) == 0) {
00526             return index;
00527         }
00528         count++;
00529         index++;
00530     }
00531 
00532     return -1;
00533 }
00534 
00535 nsapi_error_t LWIP::setsockopt(nsapi_socket_t handle, int level, int optname, const void *optval, unsigned optlen)
00536 {
00537     struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
00538 
00539     switch (optname) {
00540         case NSAPI_BIND_TO_DEVICE :
00541             if (optlen > NSAPI_INTERFACE_NAME_MAX_SIZE) {
00542                 return NSAPI_ERROR_UNSUPPORTED ;
00543             }
00544 
00545             netconn_bind_if(s->conn,  netif_name_to_index((const char *)optval));
00546 
00547             return 0;
00548 #if LWIP_TCP
00549         case NSAPI_KEEPALIVE :
00550             if (optlen != sizeof(int) || NETCONNTYPE_GROUP(s->conn->type) != NETCONN_TCP) {
00551                 return NSAPI_ERROR_UNSUPPORTED ;
00552             }
00553 
00554             s->conn->pcb.tcp->so_options |= SOF_KEEPALIVE;
00555             return 0;
00556 
00557         case NSAPI_KEEPIDLE :
00558             if (optlen != sizeof(int) || NETCONNTYPE_GROUP(s->conn->type) != NETCONN_TCP) {
00559                 return NSAPI_ERROR_UNSUPPORTED ;
00560             }
00561 
00562             s->conn->pcb.tcp->keep_idle = *(int *)optval;
00563             return 0;
00564 
00565         case NSAPI_KEEPINTVL :
00566             if (optlen != sizeof(int) || NETCONNTYPE_GROUP(s->conn->type) != NETCONN_TCP) {
00567                 return NSAPI_ERROR_UNSUPPORTED ;
00568             }
00569 
00570             s->conn->pcb.tcp->keep_intvl = *(int *)optval;
00571             return 0;
00572 #endif
00573 
00574         case NSAPI_REUSEADDR :
00575             if (optlen != sizeof(int)) {
00576                 return NSAPI_ERROR_UNSUPPORTED ;
00577             }
00578 
00579             if (*(int *)optval) {
00580                 ip_set_option(s->conn->pcb.ip, SOF_REUSEADDR);
00581             } else {
00582                 ip_reset_option(s->conn->pcb.ip, SOF_REUSEADDR);
00583             }
00584             return 0;
00585 
00586         case NSAPI_ADD_MEMBERSHIP :
00587         case NSAPI_DROP_MEMBERSHIP : {
00588             if (optlen != sizeof(nsapi_ip_mreq_t)) {
00589                 return NSAPI_ERROR_PARAMETER ;
00590             }
00591             err_t igmp_err;
00592             const nsapi_ip_mreq_t *imr = static_cast<const nsapi_ip_mreq_t *>(optval);
00593 
00594             /* Check interface address type matches group, or is unspecified */
00595             if (imr->imr_interface.version != NSAPI_UNSPEC  && imr->imr_interface.version != imr->imr_multiaddr.version) {
00596                 return NSAPI_ERROR_PARAMETER ;
00597             }
00598 
00599             ip_addr_t if_addr;
00600             ip_addr_t multi_addr;
00601 
00602             /* Convert the group address */
00603             if (!convert_mbed_addr_to_lwip(&multi_addr, &imr->imr_multiaddr)) {
00604                 return NSAPI_ERROR_PARAMETER ;
00605             }
00606 
00607             if (imr->imr_interface.version != NSAPI_UNSPEC ) {
00608                 /* Convert the interface address */
00609                 if (!convert_mbed_addr_to_lwip(&if_addr, &imr->imr_interface)) {
00610                     return NSAPI_ERROR_PARAMETER ;
00611                 }
00612             } else {
00613                 /* Set interface address to "any", matching the group address type */
00614                 ip_addr_set_any(IP_IS_V6(&multi_addr), &if_addr);
00615             }
00616 
00617             igmp_err = ERR_USE; // Maps to NSAPI_ERROR_UNSUPPORTED
00618             int32_t member_pair_index = find_multicast_member(s, imr);
00619 
00620             if (optname == NSAPI_ADD_MEMBERSHIP ) {
00621                 if (!s->multicast_memberships) {
00622                     // First multicast join on this socket, allocate space for membership tracking
00623                     s->multicast_memberships = (nsapi_ip_mreq_t *)malloc(sizeof(nsapi_ip_mreq_t) * LWIP_SOCKET_MAX_MEMBERSHIPS);
00624                     if (!s->multicast_memberships) {
00625                         return NSAPI_ERROR_NO_MEMORY ;
00626                     }
00627                 } else if (s->multicast_memberships_count == LWIP_SOCKET_MAX_MEMBERSHIPS) {
00628                     return NSAPI_ERROR_NO_MEMORY ;
00629                 }
00630 
00631                 if (member_pair_index != -1) {
00632                     return NSAPI_ERROR_ADDRESS_IN_USE ;
00633                 }
00634 
00635                 member_pair_index = next_free_multicast_member(s, 0);
00636 
00637                 adaptation.lock();
00638 
00639 #if LWIP_IPV4
00640                 if (IP_IS_V4(&if_addr)) {
00641                     igmp_err = igmp_joingroup(ip_2_ip4(&if_addr), ip_2_ip4(&multi_addr));
00642                 }
00643 #endif
00644 #if LWIP_IPV6
00645                 if (IP_IS_V6(&if_addr)) {
00646                     igmp_err = mld6_joingroup(ip_2_ip6(&if_addr), ip_2_ip6(&multi_addr));
00647                 }
00648 #endif
00649 
00650                 adaptation.unlock();
00651 
00652                 if (igmp_err == ERR_OK) {
00653                     set_multicast_member_registry_bit(s, member_pair_index);
00654                     s->multicast_memberships[member_pair_index] = *imr;
00655                     s->multicast_memberships_count++;
00656                 }
00657             } else {
00658                 if (member_pair_index == -1) {
00659                     return NSAPI_ERROR_NO_ADDRESS ;
00660                 }
00661 
00662                 clear_multicast_member_registry_bit(s, member_pair_index);
00663                 s->multicast_memberships_count--;
00664 
00665                 adaptation.lock();
00666 
00667 #if LWIP_IPV4
00668                 if (IP_IS_V4(&if_addr)) {
00669                     igmp_err = igmp_leavegroup(ip_2_ip4(&if_addr), ip_2_ip4(&multi_addr));
00670                 }
00671 #endif
00672 #if LWIP_IPV6
00673                 if (IP_IS_V6(&if_addr)) {
00674                     igmp_err = mld6_leavegroup(ip_2_ip6(&if_addr), ip_2_ip6(&multi_addr));
00675                 }
00676 #endif
00677 
00678                 adaptation.unlock();
00679             }
00680 
00681             return err_remap(igmp_err);
00682         }
00683 
00684         default:
00685             return NSAPI_ERROR_UNSUPPORTED ;
00686     }
00687 }
00688 
00689 nsapi_error_t LWIP::getsockopt(nsapi_socket_t handle, int level, int optname, void *optval, unsigned *optlen)
00690 {
00691     return NSAPI_ERROR_UNSUPPORTED ;
00692 }
00693 
00694 
00695 void LWIP::socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data)
00696 {
00697     struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
00698 
00699     s->cb = callback;
00700     s->data = data;
00701 }
00702 
00703 LWIP &LWIP::get_instance()
00704 {
00705     static LWIP lwip;
00706     return lwip;
00707 }
00708 
00709 // This works as long as it's not ever set to something which corresponds to
00710 // a macro defined as a non-integer. Eg `#define Nanostack "Foo"`
00711 #define LWIP 0x11991199
00712 #if MBED_CONF_NSAPI_DEFAULT_STACK == LWIP
00713 #undef LWIP
00714 OnboardNetworkStack &OnboardNetworkStack::get_default_instance()
00715 {
00716     return LWIP::get_instance();
00717 }
00718 #endif