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