STM32F7 Ethernet interface for nucleo STM32F767

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_stack.c Source File

lwip_stack.c

00001 /* LWIP implementation of NetworkInterfaceAPI
00002  * Copyright (c) 2015 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 
00017 #include "nsapi.h"
00018 #include "mbed_interface.h"
00019 #include "mbed_assert.h"
00020 #include <stdio.h>
00021 #include <stdbool.h>
00022 #include <string.h>
00023 #include "lwip_stack.h"
00024 
00025 #include "eth_arch.h"
00026 #include "lwip/opt.h"
00027 #include "lwip/api.h"
00028 #include "lwip/inet.h"
00029 #include "lwip/netif.h"
00030 #include "lwip/dhcp.h"
00031 #include "lwip/tcpip.h"
00032 #include "lwip/tcp.h"
00033 #include "lwip/ip.h"
00034 #include "lwip/mld6.h"
00035 #include "lwip/igmp.h"
00036 #include "lwip/dns.h"
00037 #include "lwip/udp.h"
00038 #include "lwip_errno.h"
00039 #include "netif/lwip_ethernet.h"
00040 #include "emac_api.h"
00041 #include "ppp_lwip.h"
00042 
00043 static nsapi_error_t mbed_lwip_err_remap(err_t err);
00044 
00045 #if DEVICE_EMAC
00046     #define MBED_NETIF_INIT_FN emac_lwip_if_init
00047 #else
00048     #define MBED_NETIF_INIT_FN eth_arch_enetif_init
00049 #endif
00050 
00051 #ifndef LWIP_SOCKET_MAX_MEMBERSHIPS
00052     #define LWIP_SOCKET_MAX_MEMBERSHIPS 4
00053 #endif
00054 
00055 /* Static arena of sockets */
00056 static struct lwip_socket {
00057     bool in_use;
00058 
00059     struct netconn *conn;
00060     struct netbuf *buf;
00061     u16_t offset;
00062 
00063     void (*cb)(void *);
00064     void *data;
00065 
00066     // Track multicast addresses subscribed to by this socket
00067     nsapi_ip_mreq_t *multicast_memberships;
00068     uint32_t         multicast_memberships_count;
00069     uint32_t         multicast_memberships_registry;
00070 
00071 } lwip_arena[MEMP_NUM_NETCONN];
00072 
00073 static bool lwip_inited = false;
00074 static bool lwip_connected = false;
00075 static bool netif_inited = false;
00076 static bool netif_is_ppp = false;
00077 
00078 static nsapi_error_t mbed_lwip_setsockopt(nsapi_stack_t *stack, nsapi_socket_t handle, int level, int optname, const void *optval, unsigned optlen);
00079 
00080 static inline uint32_t next_registered_multicast_member(const struct lwip_socket *s, uint32_t index) {
00081     while (!(s->multicast_memberships_registry & (0x0001 << index))) { index++; }
00082     return index;
00083 }
00084 
00085 static inline uint32_t next_free_multicast_member(const struct lwip_socket *s, uint32_t index) {
00086     while ((s->multicast_memberships_registry & (0x0001 << index))) { index++; }
00087     return index;
00088 }
00089 
00090 static inline void set_multicast_member_registry_bit(struct lwip_socket *s, uint32_t index) {
00091     s->multicast_memberships_registry |= (0x0001 << index);
00092 }
00093 
00094 static inline void clear_multicast_member_registry_bit(struct lwip_socket *s, uint32_t index) {
00095     s->multicast_memberships_registry &= ~(0x0001 << index);
00096 }
00097 
00098 static struct lwip_socket *mbed_lwip_arena_alloc(void)
00099 {
00100     sys_prot_t prot = sys_arch_protect();
00101 
00102     for (int i = 0; i < MEMP_NUM_NETCONN; i++) {
00103         if (!lwip_arena[i].in_use) {
00104             struct lwip_socket *s = &lwip_arena[i];
00105             memset(s, 0, sizeof *s);
00106             s->in_use = true;
00107             sys_arch_unprotect(prot);
00108             return s;
00109         }
00110     }
00111 
00112     sys_arch_unprotect(prot);
00113     return 0;
00114 }
00115 
00116 static void mbed_lwip_arena_dealloc(struct lwip_socket *s)
00117 {
00118     s->in_use = false;
00119 
00120     while (s->multicast_memberships_count > 0) {
00121         uint32_t index = 0;
00122         index = next_registered_multicast_member(s, index);
00123 
00124         mbed_lwip_setsockopt(NULL, s, NSAPI_SOCKET , NSAPI_DROP_MEMBERSHIP , &s->multicast_memberships[index],
00125             sizeof(s->multicast_memberships[index]));
00126         index++;
00127     }
00128 
00129     free(s->multicast_memberships);
00130     s->multicast_memberships = NULL;
00131 }
00132 
00133 static void mbed_lwip_socket_callback(struct netconn *nc, enum netconn_evt eh, u16_t len)
00134 {
00135     // Filter send minus events
00136     if (eh == NETCONN_EVT_SENDMINUS && nc->state == NETCONN_WRITE) {
00137         return;
00138     }
00139 
00140     sys_prot_t prot = sys_arch_protect();
00141 
00142     for (int i = 0; i < MEMP_NUM_NETCONN; i++) {
00143         if (lwip_arena[i].in_use
00144             && lwip_arena[i].conn == nc
00145             && lwip_arena[i].cb) {
00146             lwip_arena[i].cb(lwip_arena[i].data);
00147         }
00148     }
00149 
00150     sys_arch_unprotect(prot);
00151 }
00152 
00153 
00154 /* TCP/IP and Network Interface Initialisation */
00155 static struct netif lwip_netif;
00156 #if LWIP_DHCP
00157 static bool lwip_dhcp = false;
00158 #endif
00159 static char lwip_mac_address[NSAPI_MAC_SIZE];
00160 
00161 #if !LWIP_IPV4 || !LWIP_IPV6
00162 static bool all_zeros(const uint8_t *p, int len)
00163 {
00164     for (int i = 0; i < len; i++) {
00165         if (p[i]) {
00166             return false;
00167         }
00168     }
00169 
00170     return true;
00171 }
00172 #endif
00173 
00174 static bool convert_mbed_addr_to_lwip(ip_addr_t *out, const nsapi_addr_t *in)
00175 {
00176 #if LWIP_IPV6
00177     if (in->version == NSAPI_IPv6 ) {
00178          IP_SET_TYPE(out, IPADDR_TYPE_V6);
00179          MEMCPY(ip_2_ip6(out), in->bytes, sizeof(ip6_addr_t));
00180          return true;
00181     }
00182 #if !LWIP_IPV4
00183     /* For bind() and other purposes, need to accept "null" of other type */
00184     /* (People use IPv4 0.0.0.0 as a general null) */
00185     if (in->version == NSAPI_UNSPEC  ||
00186         (in->version == NSAPI_IPv4  && all_zeros(in->bytes, 4))) {
00187         ip_addr_set_zero_ip6(out);
00188         return true;
00189     }
00190 #endif
00191 #endif
00192 
00193 #if LWIP_IPV4
00194     if (in->version == NSAPI_IPv4 ) {
00195          IP_SET_TYPE(out, IPADDR_TYPE_V4);
00196          MEMCPY(ip_2_ip4(out), in->bytes, sizeof(ip4_addr_t));
00197          return true;
00198     }
00199 #if !LWIP_IPV6
00200     /* For symmetry with above, accept IPv6 :: as a general null */
00201     if (in->version == NSAPI_UNSPEC  ||
00202         (in->version == NSAPI_IPv6  && all_zeros(in->bytes, 16))) {
00203         ip_addr_set_zero_ip4(out);
00204         return true;
00205     }
00206 #endif
00207 #endif
00208 
00209 #if LWIP_IPV4 && LWIP_IPV6
00210     if (in->version == NSAPI_UNSPEC ) {
00211 #if IP_VERSION_PREF == PREF_IPV4
00212         ip_addr_set_zero_ip4(out);
00213 #else
00214         ip_addr_set_zero_ip6(out);
00215 #endif
00216         return true;
00217     }
00218 #endif
00219 
00220     return false;
00221 }
00222 
00223 static bool convert_lwip_addr_to_mbed(nsapi_addr_t *out, const ip_addr_t *in)
00224 {
00225 #if LWIP_IPV6
00226     if (IP_IS_V6(in)) {
00227         out->version = NSAPI_IPv6 ;
00228         MEMCPY(out->bytes, ip_2_ip6(in), sizeof(ip6_addr_t));
00229         return true;
00230     }
00231 #endif
00232 #if LWIP_IPV4
00233     if (IP_IS_V4(in)) {
00234         out->version = NSAPI_IPv4 ;
00235         MEMCPY(out->bytes, ip_2_ip4(in), sizeof(ip4_addr_t));
00236         return true;
00237     }
00238 #endif
00239 #if LWIP_IPV6 && LWIP_IPV4
00240     return false;
00241 #endif
00242 }
00243 
00244 #if LWIP_IPV4
00245 static const ip_addr_t *mbed_lwip_get_ipv4_addr(const struct netif *netif)
00246 {
00247     if (!netif_is_up(netif)) {
00248         return NULL;
00249     }
00250 
00251     if (!ip4_addr_isany(netif_ip4_addr(netif))) {
00252         return netif_ip_addr4(netif);
00253     }
00254 
00255     return NULL;
00256 }
00257 #endif
00258 
00259 #if LWIP_IPV6
00260 static const ip_addr_t *mbed_lwip_get_ipv6_addr(const struct netif *netif)
00261 {
00262 
00263     if (!netif_is_up(netif)) {
00264         return NULL;
00265     }
00266 
00267     for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
00268         if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
00269                 !ip6_addr_islinklocal(netif_ip6_addr(netif, i))) {
00270             return netif_ip_addr6(netif, i);
00271         }
00272     }
00273 
00274     return NULL;
00275 }
00276 #endif
00277 
00278 const ip_addr_t *mbed_lwip_get_ip_addr(bool any_addr, const struct netif *netif)
00279 {
00280     const ip_addr_t *pref_ip_addr = 0;
00281     const ip_addr_t *npref_ip_addr = 0;
00282 
00283 #if LWIP_IPV4 && LWIP_IPV6
00284 #if IP_VERSION_PREF == PREF_IPV4
00285     pref_ip_addr = mbed_lwip_get_ipv4_addr(netif);
00286     npref_ip_addr = mbed_lwip_get_ipv6_addr(netif);
00287 #else
00288     pref_ip_addr = mbed_lwip_get_ipv6_addr(netif);
00289     npref_ip_addr = mbed_lwip_get_ipv4_addr(netif);
00290 #endif
00291 #elif LWIP_IPV6
00292     pref_ip_addr = mbed_lwip_get_ipv6_addr(netif);
00293 #elif LWIP_IPV4
00294     pref_ip_addr = mbed_lwip_get_ipv4_addr(netif);
00295 #endif
00296 
00297     if (pref_ip_addr) {
00298         return pref_ip_addr;
00299     } else if (npref_ip_addr && any_addr) {
00300         return npref_ip_addr;
00301     }
00302 
00303     return NULL;
00304 }
00305 
00306 static void add_dns_addr_to_dns_list_index(const u8_t addr_type, const u8_t index)
00307 {
00308 #if LWIP_IPV6
00309     if (addr_type == IPADDR_TYPE_V6) {
00310         /* 2001:4860:4860::8888 google */
00311         ip_addr_t ipv6_dns_addr = IPADDR6_INIT(
00312                 PP_HTONL(0x20014860UL),
00313                 PP_HTONL(0x48600000UL),
00314                 PP_HTONL(0x00000000UL),
00315                 PP_HTONL(0x00008888UL));
00316         dns_setserver(index, &ipv6_dns_addr);
00317     }
00318 #endif
00319 #if LWIP_IPV4
00320     if (addr_type == IPADDR_TYPE_V4) {
00321         /* 8.8.8.8 google */
00322         ip_addr_t ipv4_dns_addr = IPADDR4_INIT(0x08080808);
00323         dns_setserver(index, &ipv4_dns_addr);
00324     }
00325 #endif
00326 }
00327 
00328 static int get_ip_addr_type(const ip_addr_t *ip_addr)
00329 {
00330 #if LWIP_IPV6
00331     if (IP_IS_V6(ip_addr)) {
00332         return IPADDR_TYPE_V6;
00333     }
00334 #endif
00335 #if LWIP_IPV4
00336     if (IP_IS_V4(ip_addr)) {
00337         return IPADDR_TYPE_V4;
00338     }
00339 #endif
00340 #if LWIP_IPV6 && LWIP_IPV4
00341     return IPADDR_TYPE_ANY;
00342 #endif
00343 }
00344 
00345 void add_dns_addr(struct netif *lwip_netif)
00346 {
00347     // Check for existing dns address
00348     for (char numdns = 0; numdns < DNS_MAX_SERVERS; numdns++) {
00349         const ip_addr_t *dns_ip_addr = dns_getserver(numdns);
00350         if (!ip_addr_isany(dns_ip_addr)) {
00351             return;
00352         }
00353     }
00354 
00355     // Get preferred ip version
00356     const ip_addr_t *ip_addr = mbed_lwip_get_ip_addr(false, lwip_netif);
00357     u8_t addr_type = IPADDR_TYPE_ANY;
00358 
00359     // Add preferred ip version dns address to index 0
00360     if (ip_addr) {
00361         addr_type = get_ip_addr_type(ip_addr);
00362         add_dns_addr_to_dns_list_index(addr_type, 0);
00363     }
00364 
00365 #if LWIP_IPV4 && LWIP_IPV6
00366     if (!ip_addr) {
00367         // Get address for any ip version
00368         ip_addr = mbed_lwip_get_ip_addr(true, lwip_netif);
00369         if (!ip_addr) {
00370             return;
00371         }
00372         addr_type = get_ip_addr_type(ip_addr);
00373         // Add the dns address to index 0
00374         add_dns_addr_to_dns_list_index(addr_type, 0);
00375     }
00376 
00377     if (addr_type == IPADDR_TYPE_V4) {
00378         // If ipv4 is preferred and ipv6 is available add ipv6 dns address to index 1
00379         ip_addr = mbed_lwip_get_ipv6_addr(lwip_netif);
00380     } else if (addr_type == IPADDR_TYPE_V6) {
00381         // If ipv6 is preferred and ipv4 is available add ipv4 dns address to index 1
00382         ip_addr = mbed_lwip_get_ipv4_addr(lwip_netif);
00383     } else {
00384         ip_addr = NULL;
00385     }
00386 
00387     if (ip_addr) {
00388         addr_type = get_ip_addr_type(ip_addr);
00389         add_dns_addr_to_dns_list_index(addr_type, 1);
00390     }
00391 #endif
00392 }
00393 
00394 static sys_sem_t lwip_tcpip_inited;
00395 static void mbed_lwip_tcpip_init_irq(void *eh)
00396 {
00397     sys_sem_signal(&lwip_tcpip_inited);
00398 }
00399 
00400 static sys_sem_t lwip_netif_linked;
00401 static sys_sem_t lwip_netif_unlinked;
00402 static void mbed_lwip_netif_link_irq(struct netif *lwip_netif)
00403 {
00404     if (netif_is_link_up(lwip_netif)) {
00405         sys_sem_signal(&lwip_netif_linked);
00406     } else {
00407         sys_sem_signal(&lwip_netif_unlinked);
00408     }
00409 }
00410 
00411 static char lwip_has_addr_state = 0;
00412 
00413 #define HAS_ANY_ADDR  1
00414 static sys_sem_t lwip_netif_has_any_addr;
00415 #if PREF_ADDR_TIMEOUT
00416 #define HAS_PREF_ADDR 2
00417 static sys_sem_t lwip_netif_has_pref_addr;
00418 #endif
00419 #if BOTH_ADDR_TIMEOUT
00420 #define HAS_BOTH_ADDR 4
00421 static sys_sem_t lwip_netif_has_both_addr;
00422 #endif
00423 
00424 static void mbed_lwip_netif_status_irq(struct netif *lwip_netif)
00425 {
00426     if (netif_is_up(lwip_netif)) {
00427         if (!(lwip_has_addr_state & HAS_ANY_ADDR) && mbed_lwip_get_ip_addr(true, lwip_netif)) {
00428             sys_sem_signal(&lwip_netif_has_any_addr);
00429             lwip_has_addr_state |= HAS_ANY_ADDR;
00430         }
00431 #if PREF_ADDR_TIMEOUT
00432         if (!(lwip_has_addr_state & HAS_PREF_ADDR) && mbed_lwip_get_ip_addr(false, lwip_netif)) {
00433             sys_sem_signal(&lwip_netif_has_pref_addr);
00434             lwip_has_addr_state |= HAS_PREF_ADDR;
00435         }
00436 #endif
00437 #if BOTH_ADDR_TIMEOUT
00438         if (!(lwip_has_addr_state & HAS_BOTH_ADDR) && mbed_lwip_get_ipv4_addr(lwip_netif) && mbed_lwip_get_ipv6_addr(lwip_netif)) {
00439             sys_sem_signal(&lwip_netif_has_both_addr);
00440             lwip_has_addr_state |= HAS_BOTH_ADDR;
00441         }
00442 #endif
00443     }
00444 }
00445 
00446 #if LWIP_ETHERNET
00447 static void mbed_lwip_set_mac_address(struct netif *netif)
00448 {
00449 #if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
00450     netif->hwaddr[0] = MBED_MAC_ADDR_0;
00451     netif->hwaddr[1] = MBED_MAC_ADDR_1;
00452     netif->hwaddr[2] = MBED_MAC_ADDR_2;
00453     netif->hwaddr[3] = MBED_MAC_ADDR_3;
00454     netif->hwaddr[4] = MBED_MAC_ADDR_4;
00455     netif->hwaddr[5] = MBED_MAC_ADDR_5;
00456 #else
00457     mbed_mac_address((char *)netif->hwaddr);
00458 #endif
00459 
00460     netif->hwaddr_len = ETH_HWADDR_LEN;
00461 
00462     /* Use mac address as additional seed to random number generator */
00463     uint64_t seed = netif->hwaddr[0];
00464     for (uint8_t i = 1; i < 8; i++) {
00465         seed <<= 8;
00466         seed |= netif->hwaddr[i % 6];
00467     }
00468     lwip_add_random_seed(seed);
00469 }
00470 
00471 static void mbed_lwip_record_mac_address(const struct netif *netif)
00472 {
00473     const u8_t *mac = netif->hwaddr;
00474     snprintf(lwip_mac_address, NSAPI_MAC_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
00475              mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
00476 }
00477 #endif // LWIP_ETHERNET
00478 
00479 /* LWIP interface implementation */
00480 const char *mbed_lwip_get_mac_address(void)
00481 {
00482     return lwip_mac_address[0] ? lwip_mac_address : NULL;
00483 }
00484 
00485 char *mbed_lwip_get_ip_address(char *buf, nsapi_size_t buflen)
00486 {
00487     const ip_addr_t *addr = mbed_lwip_get_ip_addr(true, &lwip_netif);
00488     if (!addr) {
00489         return NULL;
00490     }
00491 #if LWIP_IPV6
00492     if (IP_IS_V6(addr)) {
00493         return ip6addr_ntoa_r(ip_2_ip6(addr), buf, buflen);
00494     }
00495 #endif
00496 #if LWIP_IPV4
00497     if (IP_IS_V4(addr)) {
00498         return ip4addr_ntoa_r(ip_2_ip4(addr), buf, buflen);
00499     }
00500 #endif
00501 #if LWIP_IPV6 && LWIP_IPV4
00502     return NULL;
00503 #endif
00504 }
00505 
00506 char *mbed_lwip_get_netmask(char *buf, nsapi_size_t buflen)
00507 {
00508 #if LWIP_IPV4
00509     const ip4_addr_t *addr = netif_ip4_netmask(&lwip_netif);
00510     if (!ip4_addr_isany(addr)) {
00511         return ip4addr_ntoa_r(addr, buf, buflen);
00512     } else {
00513         return NULL;
00514     }
00515 #else
00516     return NULL;
00517 #endif
00518 }
00519 
00520 char *mbed_lwip_get_gateway(char *buf, nsapi_size_t buflen)
00521 {
00522 #if LWIP_IPV4
00523     const ip4_addr_t *addr = netif_ip4_gw(&lwip_netif);
00524     if (!ip4_addr_isany(addr)) {
00525         return ip4addr_ntoa_r(addr, buf, buflen);
00526     } else {
00527         return NULL;
00528     }
00529 #else
00530     return NULL;
00531 #endif
00532 }
00533 
00534 static void mbed_lwip_core_init(void)
00535 {
00536 
00537     // Check if we've already brought up lwip
00538     if (!lwip_inited) {
00539     // Seed lwip random
00540         lwip_seed_random();
00541 
00542         // Initialise TCP sequence number
00543         uint32_t tcp_isn_secret[4];
00544         for (int i = 0; i < 4; i++) {
00545             tcp_isn_secret[i] = LWIP_RAND();
00546         }
00547         lwip_init_tcp_isn(0, (u8_t *) &tcp_isn_secret);
00548 
00549         sys_sem_new(&lwip_tcpip_inited, 0);
00550         sys_sem_new(&lwip_netif_linked, 0);
00551         sys_sem_new(&lwip_netif_unlinked, 0);
00552         sys_sem_new(&lwip_netif_has_any_addr, 0);
00553 #if PREF_ADDR_TIMEOUT
00554         sys_sem_new(&lwip_netif_has_pref_addr, 0);
00555 #endif
00556 #if BOTH_ADDR_TIMEOUT
00557         sys_sem_new(&lwip_netif_has_both_addr, 0);
00558 #endif
00559         tcpip_init(mbed_lwip_tcpip_init_irq, NULL);
00560         sys_arch_sem_wait(&lwip_tcpip_inited, 0);
00561 
00562         lwip_inited = true;
00563     }
00564 }
00565 
00566 nsapi_error_t mbed_lwip_emac_init(emac_interface_t *emac)
00567 {
00568 #if LWIP_ETHERNET
00569     // Choose a MAC address - driver can override
00570     mbed_lwip_set_mac_address(&lwip_netif);
00571 
00572     // Set up network
00573     if (!netif_add(&lwip_netif,
00574 #if LWIP_IPV4
00575                    0, 0, 0,
00576 #endif
00577                    emac, MBED_NETIF_INIT_FN, tcpip_input)) {
00578         return NSAPI_ERROR_DEVICE_ERROR ;
00579     }
00580 
00581     // Note the MAC address actually in use
00582     mbed_lwip_record_mac_address(&lwip_netif);
00583 
00584 #if !DEVICE_EMAC
00585     eth_arch_enable_interrupts();
00586 #endif
00587 
00588     return NSAPI_ERROR_OK ;
00589 #else
00590     return NSAPI_ERROR_UNSUPPORTED ;
00591 #endif //LWIP_ETHERNET
00592 }
00593 
00594 // Backwards compatibility with people using DEVICE_EMAC
00595 nsapi_error_t mbed_lwip_init(emac_interface_t *emac)
00596 {
00597     nsapi_error_t ret;
00598     mbed_lwip_core_init();
00599     ret = mbed_lwip_emac_init(emac);
00600     if (ret == NSAPI_ERROR_OK ) {
00601         netif_inited = true;
00602     }
00603     return ret;
00604 }
00605 
00606 // Backwards compatibility with people using DEVICE_EMAC
00607 nsapi_error_t mbed_lwip_bringup(bool dhcp, const char *ip, const char *netmask, const char *gw)
00608 {
00609     return mbed_lwip_bringup_2(dhcp, false, ip, netmask, gw, DEFAULT_STACK);
00610 }
00611 
00612 nsapi_error_t mbed_lwip_bringup_2(bool dhcp, bool ppp, const char *ip, const char *netmask, const char *gw, const nsapi_ip_stack_t stack)
00613 {
00614     // Check if we've already connected
00615     if (lwip_connected) {
00616         return NSAPI_ERROR_PARAMETER ;
00617     }
00618 
00619     mbed_lwip_core_init();
00620 
00621     nsapi_error_t ret;
00622     if (netif_inited) {
00623         /* Can't cope with changing mode */
00624         if (netif_is_ppp == ppp) {
00625             ret = NSAPI_ERROR_OK ;
00626         } else {
00627             ret = NSAPI_ERROR_PARAMETER ;
00628         }
00629     } else {
00630         if (ppp) {
00631             ret = ppp_lwip_if_init(&lwip_netif, stack);
00632         } else {
00633             ret = mbed_lwip_emac_init(NULL);
00634         }
00635     }
00636 
00637     if (ret != NSAPI_ERROR_OK ) {
00638         return ret;
00639     }
00640 
00641     netif_inited = true;
00642     if (ppp) {
00643         netif_is_ppp = ppp;
00644     }
00645 
00646     netif_set_default(&lwip_netif);
00647     netif_set_link_callback(&lwip_netif, mbed_lwip_netif_link_irq);
00648     netif_set_status_callback(&lwip_netif, mbed_lwip_netif_status_irq);
00649 
00650 #if LWIP_IPV6
00651     if (stack != IPV4_STACK) {
00652         if (lwip_netif.hwaddr_len == ETH_HWADDR_LEN) {
00653             netif_create_ip6_linklocal_address(&lwip_netif, 1/*from MAC*/);
00654         }
00655 
00656 #if LWIP_IPV6_MLD
00657         /*
00658          * For hardware/netifs that implement MAC filtering.
00659          * All-nodes link-local is handled by default, so we must let the hardware know
00660          * to allow multicast packets in.
00661          * Should set mld_mac_filter previously. */
00662         if (lwip_netif.mld_mac_filter != NULL) {
00663             ip6_addr_t ip6_allnodes_ll;
00664             ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll);
00665             lwip_netif.mld_mac_filter(&lwip_netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER);
00666         }
00667 #endif /* LWIP_IPV6_MLD */
00668 
00669 #if LWIP_IPV6_AUTOCONFIG
00670         /* IPv6 address autoconfiguration not enabled by default */
00671         lwip_netif.ip6_autoconfig_enabled = 1;
00672     } else {
00673         // Disable router solidifications
00674         lwip_netif.rs_count = 0;
00675     }
00676 #endif /* LWIP_IPV6_AUTOCONFIG */
00677 #endif // LWIP_IPV6
00678 
00679 #if LWIP_IPV4
00680     if (stack != IPV6_STACK) {
00681         if (!dhcp && !ppp) {
00682             ip4_addr_t ip_addr;
00683             ip4_addr_t netmask_addr;
00684             ip4_addr_t gw_addr;
00685 
00686             if (!inet_aton(ip, &ip_addr) ||
00687                 !inet_aton(netmask, &netmask_addr) ||
00688                 !inet_aton(gw, &gw_addr)) {
00689                 return NSAPI_ERROR_PARAMETER ;
00690             }
00691 
00692             netif_set_addr(&lwip_netif, &ip_addr, &netmask_addr, &gw_addr);
00693         }
00694     }
00695 #endif
00696 
00697     if (ppp) {
00698        err_t err = ppp_lwip_connect();
00699        if (err) {
00700            return mbed_lwip_err_remap(err);
00701        }
00702     }
00703 
00704     if (!netif_is_link_up(&lwip_netif)) {
00705         if (sys_arch_sem_wait(&lwip_netif_linked, 15000) == SYS_ARCH_TIMEOUT) {
00706             if (ppp) {
00707                 (void) ppp_lwip_disconnect();
00708             }
00709             return NSAPI_ERROR_NO_CONNECTION ;
00710         }
00711     }
00712 
00713     if (!ppp) {
00714         netif_set_up(&lwip_netif);
00715     }
00716 
00717 #if LWIP_DHCP
00718     if (stack != IPV6_STACK) {
00719         // Connect to the network
00720         lwip_dhcp = dhcp;
00721 
00722         if (lwip_dhcp) {
00723             err_t err = dhcp_start(&lwip_netif);
00724             if (err) {
00725                 return NSAPI_ERROR_DHCP_FAILURE ;
00726             }
00727         }
00728     }
00729 #endif
00730 
00731     // If doesn't have address
00732     if (!mbed_lwip_get_ip_addr(true, &lwip_netif)) {
00733         if (sys_arch_sem_wait(&lwip_netif_has_any_addr, DHCP_TIMEOUT * 1000) == SYS_ARCH_TIMEOUT) {
00734             if (ppp) {
00735                 (void) ppp_lwip_disconnect();
00736             }
00737             return NSAPI_ERROR_DHCP_FAILURE ;
00738         }
00739     }
00740 
00741 #if PREF_ADDR_TIMEOUT
00742     if (stack != IPV4_STACK && stack != IPV6_STACK) {
00743         // If address is not for preferred stack waits a while to see
00744         // if preferred stack address is acquired
00745         if (!mbed_lwip_get_ip_addr(false, &lwip_netif)) {
00746             sys_arch_sem_wait(&lwip_netif_has_pref_addr, PREF_ADDR_TIMEOUT * 1000);
00747         }
00748     }
00749 #endif
00750 #if BOTH_ADDR_TIMEOUT
00751     if (stack != IPV4_STACK && stack != IPV6_STACK) {
00752         // If addresses for both stacks are not available waits a while to
00753         // see if address for both stacks are acquired
00754         if (!(mbed_lwip_get_ipv4_addr(&lwip_netif) && mbed_lwip_get_ipv6_addr(&lwip_netif))) {
00755             sys_arch_sem_wait(&lwip_netif_has_both_addr, BOTH_ADDR_TIMEOUT * 1000);
00756         }
00757     }
00758 #endif
00759 
00760     add_dns_addr(&lwip_netif);
00761 
00762     lwip_connected = true;
00763     return 0;
00764 }
00765 
00766 #if LWIP_IPV6
00767 void mbed_lwip_clear_ipv6_addresses(struct netif *lwip_netif)
00768 {
00769     for (u8_t i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
00770         netif_ip6_addr_set_state(lwip_netif, i, IP6_ADDR_INVALID);
00771     }
00772 }
00773 #endif
00774 
00775 // Backwards compatibility with people using DEVICE_EMAC
00776 nsapi_error_t mbed_lwip_bringdown(void)
00777 {
00778     return mbed_lwip_bringdown_2(false);
00779 }
00780 
00781 nsapi_error_t mbed_lwip_bringdown_2(bool ppp)
00782 {
00783     // Check if we've connected
00784     if (!lwip_connected) {
00785         return NSAPI_ERROR_PARAMETER ;
00786     }
00787 
00788 #if LWIP_DHCP
00789     // Disconnect from the network
00790     if (lwip_dhcp) {
00791         dhcp_release(&lwip_netif);
00792         dhcp_stop(&lwip_netif);
00793         lwip_dhcp = false;
00794     }
00795 #endif
00796 
00797     if (ppp) {
00798         /* this is a blocking call, returns when PPP is properly closed */
00799        err_t err = ppp_lwip_disconnect();
00800        if (err) {
00801            return mbed_lwip_err_remap(err);
00802        }
00803        MBED_ASSERT(!netif_is_link_up(&lwip_netif));
00804        /*if (netif_is_link_up(&lwip_netif)) {
00805            if (sys_arch_sem_wait(&lwip_netif_unlinked, 15000) == SYS_ARCH_TIMEOUT) {
00806                return NSAPI_ERROR_DEVICE_ERROR;
00807            }
00808        }*/
00809     } else {
00810         netif_set_down(&lwip_netif);
00811     }
00812 
00813 #if LWIP_IPV6
00814     mbed_lwip_clear_ipv6_addresses(&lwip_netif);
00815 #endif
00816 
00817     sys_sem_free(&lwip_netif_has_any_addr);
00818     sys_sem_new(&lwip_netif_has_any_addr, 0);
00819 #if PREF_ADDR_TIMEOUT
00820     sys_sem_free(&lwip_netif_has_pref_addr);
00821     sys_sem_new(&lwip_netif_has_pref_addr, 0);
00822 #endif
00823 #if BOTH_ADDR_TIMEOUT
00824     sys_sem_free(&lwip_netif_has_both_addr);
00825     sys_sem_new(&lwip_netif_has_both_addr, 0);
00826 #endif
00827     lwip_has_addr_state = 0;
00828     lwip_connected = false;
00829     return 0;
00830 }
00831 
00832 /* LWIP error remapping */
00833 static nsapi_error_t mbed_lwip_err_remap(err_t err) {
00834     switch (err) {
00835         case ERR_OK:
00836         case ERR_CLSD:
00837             return 0;
00838         case ERR_MEM:
00839         case ERR_BUF:
00840             return NSAPI_ERROR_NO_MEMORY ;
00841         case ERR_CONN:
00842         case ERR_RST:
00843         case ERR_ABRT:
00844             return NSAPI_ERROR_NO_CONNECTION ;
00845         case ERR_TIMEOUT:
00846         case ERR_RTE:
00847         case ERR_WOULDBLOCK:
00848             return NSAPI_ERROR_WOULD_BLOCK ;
00849         case ERR_VAL:
00850         case ERR_USE:
00851         case ERR_ARG:
00852             return NSAPI_ERROR_PARAMETER ;
00853         case ERR_INPROGRESS:
00854             return NSAPI_ERROR_IN_PROGRESS ;
00855         case ERR_ALREADY:
00856             return NSAPI_ERROR_ALREADY ;
00857         case ERR_ISCONN:
00858             return NSAPI_ERROR_IS_CONNECTED ;
00859         default:
00860             return NSAPI_ERROR_DEVICE_ERROR ;
00861     }
00862 }
00863 
00864 /* LWIP network stack implementation */
00865 static nsapi_error_t mbed_lwip_gethostbyname(nsapi_stack_t *stack, const char *host, nsapi_addr_t *addr, nsapi_version_t version)
00866 {
00867     ip_addr_t lwip_addr;
00868 
00869 #if LWIP_IPV4 && LWIP_IPV6
00870     u8_t addr_type;
00871     if (version == NSAPI_UNSPEC ) {
00872         const ip_addr_t *ip_addr;
00873         ip_addr = mbed_lwip_get_ip_addr(true, &lwip_netif);
00874         // Prefer IPv6
00875         if (IP_IS_V6(ip_addr)) {
00876             // If IPv4 is available use it as backup
00877             if (mbed_lwip_get_ipv4_addr(&lwip_netif)) {
00878                 addr_type = NETCONN_DNS_IPV6_IPV4;
00879             } else {
00880                 addr_type = NETCONN_DNS_IPV6;
00881             }
00882         // Prefer IPv4
00883         } else {
00884             // If IPv6 is available use it as backup
00885             if (mbed_lwip_get_ipv6_addr(&lwip_netif)) {
00886                 addr_type = NETCONN_DNS_IPV4_IPV6;
00887             } else {
00888                 addr_type = NETCONN_DNS_IPV4;
00889             }
00890         }
00891     } else if (version == NSAPI_IPv4 ) {
00892         addr_type = NETCONN_DNS_IPV4;
00893     } else if (version == NSAPI_IPv6 ) {
00894         addr_type = NETCONN_DNS_IPV6;
00895     } else {
00896         return NSAPI_ERROR_DNS_FAILURE ;
00897     }
00898     err_t err = netconn_gethostbyname_addrtype(host, &lwip_addr, addr_type);
00899 #elif LWIP_IPV4
00900     if (version != NSAPI_IPv4  && version != NSAPI_UNSPEC ) {
00901         return NSAPI_ERROR_DNS_FAILURE ;
00902     }
00903     err_t err = netconn_gethostbyname(host, &lwip_addr);
00904 #elif LWIP_IPV6
00905     if (version != NSAPI_IPv6  && version != NSAPI_UNSPEC ) {
00906         return NSAPI_ERROR_DNS_FAILURE ;
00907     }
00908     err_t err = netconn_gethostbyname(host, &lwip_addr);
00909 #endif
00910 
00911     if (err != ERR_OK) {
00912         return NSAPI_ERROR_DNS_FAILURE ;
00913     }
00914 
00915     convert_lwip_addr_to_mbed(addr, &lwip_addr);
00916 
00917     return 0;
00918 }
00919 
00920 static nsapi_error_t mbed_lwip_add_dns_server(nsapi_stack_t *stack, nsapi_addr_t addr)
00921 {
00922     // Shift all dns servers down to give precedence to new server
00923     for (int i = DNS_MAX_SERVERS-1; i > 0; i--) {
00924         dns_setserver(i, dns_getserver(i-1));
00925     }
00926 
00927     ip_addr_t ip_addr;
00928     if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
00929         return NSAPI_ERROR_PARAMETER ;
00930     }
00931 
00932     dns_setserver(0, &ip_addr);
00933     return 0;
00934 }
00935 
00936 static nsapi_error_t mbed_lwip_socket_open(nsapi_stack_t *stack, nsapi_socket_t *handle, nsapi_protocol_t proto)
00937 {
00938     // check if network is connected
00939     if (!lwip_connected) {
00940         return NSAPI_ERROR_NO_CONNECTION ;
00941     }
00942 
00943     // allocate a socket
00944     struct lwip_socket *s = mbed_lwip_arena_alloc();
00945     if (!s) {
00946         return NSAPI_ERROR_NO_SOCKET ;
00947     }
00948 
00949     enum netconn_type lwip_proto = proto == NSAPI_TCP  ? NETCONN_TCP : NETCONN_UDP;
00950 
00951 #if LWIP_IPV6
00952     // Enable IPv6 (or dual-stack)
00953     lwip_proto |= NETCONN_TYPE_IPV6;
00954 #endif
00955 
00956     s->conn = netconn_new_with_callback(lwip_proto, mbed_lwip_socket_callback);
00957 
00958     if (!s->conn) {
00959         mbed_lwip_arena_dealloc(s);
00960         return NSAPI_ERROR_NO_SOCKET ;
00961     }
00962 
00963     netconn_set_recvtimeout(s->conn, 1);
00964     *(struct lwip_socket **)handle = s;
00965     return 0;
00966 }
00967 
00968 static nsapi_error_t mbed_lwip_socket_close(nsapi_stack_t *stack, nsapi_socket_t handle)
00969 {
00970     struct lwip_socket *s = (struct lwip_socket *)handle;
00971 
00972     netbuf_delete(s->buf);
00973     err_t err = netconn_delete(s->conn);
00974     mbed_lwip_arena_dealloc(s);
00975     return mbed_lwip_err_remap(err);
00976 }
00977 
00978 static nsapi_error_t mbed_lwip_socket_bind(nsapi_stack_t *stack, nsapi_socket_t handle, nsapi_addr_t addr, uint16_t port)
00979 {
00980     struct lwip_socket *s = (struct lwip_socket *)handle;
00981     ip_addr_t ip_addr;
00982 
00983     if (
00984 #if LWIP_TCP
00985         (s->conn->type == NETCONN_TCP && s->conn->pcb.tcp->local_port != 0) ||
00986 #endif
00987         (s->conn->type == NETCONN_UDP && s->conn->pcb.udp->local_port != 0)) {
00988         return NSAPI_ERROR_PARAMETER ;
00989     }
00990 
00991     if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
00992         return NSAPI_ERROR_PARAMETER ;
00993     }
00994 
00995     err_t err = netconn_bind(s->conn, &ip_addr, port);
00996     return mbed_lwip_err_remap(err);
00997 }
00998 
00999 static nsapi_error_t mbed_lwip_socket_listen(nsapi_stack_t *stack, nsapi_socket_t handle, int backlog)
01000 {
01001     struct lwip_socket *s = (struct lwip_socket *)handle;
01002 
01003     err_t err = netconn_listen_with_backlog(s->conn, backlog);
01004     return mbed_lwip_err_remap(err);
01005 }
01006 
01007 static nsapi_error_t mbed_lwip_socket_connect(nsapi_stack_t *stack, nsapi_socket_t handle, nsapi_addr_t addr, uint16_t port)
01008 {
01009     struct lwip_socket *s = (struct lwip_socket *)handle;
01010     ip_addr_t ip_addr;
01011 
01012     if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
01013         return NSAPI_ERROR_PARAMETER ;
01014     }
01015 
01016     netconn_set_nonblocking(s->conn, false);
01017     err_t err = netconn_connect(s->conn, &ip_addr, port);
01018     netconn_set_nonblocking(s->conn, true);
01019 
01020     return mbed_lwip_err_remap(err);
01021 }
01022 
01023 static nsapi_error_t mbed_lwip_socket_accept(nsapi_stack_t *stack, nsapi_socket_t server, nsapi_socket_t *handle, nsapi_addr_t *addr, uint16_t *port)
01024 {
01025     struct lwip_socket *s = (struct lwip_socket *)server;
01026     struct lwip_socket *ns = mbed_lwip_arena_alloc();
01027     if (!ns) {
01028         return NSAPI_ERROR_NO_SOCKET ;
01029     }
01030 
01031     err_t err = netconn_accept(s->conn, &ns->conn);
01032     if (err != ERR_OK) {
01033         mbed_lwip_arena_dealloc(ns);
01034         return mbed_lwip_err_remap(err);
01035     }
01036 
01037     netconn_set_recvtimeout(ns->conn, 1);
01038     *(struct lwip_socket **)handle = ns;
01039 
01040     ip_addr_t peer_addr;
01041     (void) netconn_peer(ns->conn, &peer_addr, port);
01042     convert_lwip_addr_to_mbed(addr, &peer_addr);
01043 
01044     netconn_set_nonblocking(ns->conn, true);
01045 
01046     return 0;
01047 }
01048 
01049 static nsapi_size_or_error_t mbed_lwip_socket_send(nsapi_stack_t *stack, nsapi_socket_t handle, const void *data, nsapi_size_t size)
01050 {
01051     struct lwip_socket *s = (struct lwip_socket *)handle;
01052     size_t bytes_written = 0;
01053 
01054     err_t err = netconn_write_partly(s->conn, data, size, NETCONN_COPY, &bytes_written);
01055     if (err != ERR_OK) {
01056         return mbed_lwip_err_remap(err);
01057     }
01058 
01059     return (nsapi_size_or_error_t)bytes_written;
01060 }
01061 
01062 static nsapi_size_or_error_t mbed_lwip_socket_recv(nsapi_stack_t *stack, nsapi_socket_t handle, void *data, nsapi_size_t size)
01063 {
01064     struct lwip_socket *s = (struct lwip_socket *)handle;
01065 
01066     if (!s->buf) {
01067         err_t err = netconn_recv(s->conn, &s->buf);
01068         s->offset = 0;
01069 
01070         if (err != ERR_OK) {
01071             return mbed_lwip_err_remap(err);
01072         }
01073     }
01074 
01075     u16_t recv = netbuf_copy_partial(s->buf, data, (u16_t)size, s->offset);
01076     s->offset += recv;
01077 
01078     if (s->offset >= netbuf_len(s->buf)) {
01079         netbuf_delete(s->buf);
01080         s->buf = 0;
01081     }
01082 
01083     return recv;
01084 }
01085 
01086 static nsapi_size_or_error_t mbed_lwip_socket_sendto(nsapi_stack_t *stack, nsapi_socket_t handle, nsapi_addr_t addr, uint16_t port, const void *data, nsapi_size_t size)
01087 {
01088     struct lwip_socket *s = (struct lwip_socket *)handle;
01089     ip_addr_t ip_addr;
01090 
01091     if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
01092         return NSAPI_ERROR_PARAMETER ;
01093     }
01094 
01095     struct netbuf *buf = netbuf_new();
01096     err_t err = netbuf_ref(buf, data, (u16_t)size);
01097     if (err != ERR_OK) {
01098         netbuf_free(buf);
01099         return mbed_lwip_err_remap(err);
01100     }
01101 
01102     err = netconn_sendto(s->conn, buf, &ip_addr, port);
01103     netbuf_delete(buf);
01104     if (err != ERR_OK) {
01105         return mbed_lwip_err_remap(err);
01106     }
01107 
01108     return size;
01109 }
01110 
01111 static nsapi_size_or_error_t mbed_lwip_socket_recvfrom(nsapi_stack_t *stack, nsapi_socket_t handle, nsapi_addr_t *addr, uint16_t *port, void *data, nsapi_size_t size)
01112 {
01113     struct lwip_socket *s = (struct lwip_socket *)handle;
01114     struct netbuf *buf;
01115 
01116     err_t err = netconn_recv(s->conn, &buf);
01117     if (err != ERR_OK) {
01118         return mbed_lwip_err_remap(err);
01119     }
01120 
01121     convert_lwip_addr_to_mbed(addr, netbuf_fromaddr(buf));
01122     *port = netbuf_fromport(buf);
01123 
01124     u16_t recv = netbuf_copy(buf, data, (u16_t)size);
01125     netbuf_delete(buf);
01126 
01127     return recv;
01128 }
01129 
01130 static int32_t find_multicast_member(const struct lwip_socket *s, const nsapi_ip_mreq_t *imr) {
01131     uint32_t count = 0;
01132     uint32_t index = 0;
01133     // Set upper limit on while loop, should break out when the membership pair is found
01134     while (count < s->multicast_memberships_count) {
01135         index = next_registered_multicast_member(s, index);
01136 
01137         if (memcmp(&s->multicast_memberships[index].imr_multiaddr, &imr->imr_multiaddr, sizeof(nsapi_addr_t)) == 0 &&
01138            memcmp(&s->multicast_memberships[index].imr_interface, &imr->imr_interface, sizeof(nsapi_addr_t)) == 0) {
01139             return index;
01140         }
01141         count++;
01142         index++;
01143     }
01144 
01145     return -1;
01146 }
01147 
01148 static nsapi_error_t mbed_lwip_setsockopt(nsapi_stack_t *stack, nsapi_socket_t handle, int level, int optname, const void *optval, unsigned optlen)
01149 {
01150     struct lwip_socket *s = (struct lwip_socket *)handle;
01151 
01152     switch (optname) {
01153 #if LWIP_TCP
01154         case NSAPI_KEEPALIVE :
01155             if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) {
01156                 return NSAPI_ERROR_UNSUPPORTED ;
01157             }
01158 
01159             s->conn->pcb.tcp->so_options |= SOF_KEEPALIVE;
01160             return 0;
01161 
01162         case NSAPI_KEEPIDLE :
01163             if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) {
01164                 return NSAPI_ERROR_UNSUPPORTED ;
01165             }
01166 
01167             s->conn->pcb.tcp->keep_idle = *(int*)optval;
01168             return 0;
01169 
01170         case NSAPI_KEEPINTVL :
01171             if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) {
01172                 return NSAPI_ERROR_UNSUPPORTED ;
01173             }
01174 
01175             s->conn->pcb.tcp->keep_intvl = *(int*)optval;
01176             return 0;
01177 #endif
01178 
01179         case NSAPI_REUSEADDR :
01180             if (optlen != sizeof(int)) {
01181                 return NSAPI_ERROR_UNSUPPORTED ;
01182             }
01183 
01184             if (*(int *)optval) {
01185                 ip_set_option(s->conn->pcb.ip, SOF_REUSEADDR);
01186             } else {
01187                 ip_reset_option(s->conn->pcb.ip, SOF_REUSEADDR);
01188             }
01189             return 0;
01190 
01191         case NSAPI_ADD_MEMBERSHIP :
01192         case NSAPI_DROP_MEMBERSHIP : {
01193             if (optlen != sizeof(nsapi_ip_mreq_t)) {
01194                 return NSAPI_ERROR_PARAMETER ;
01195             }
01196             err_t igmp_err;
01197             const nsapi_ip_mreq_t *imr = optval;
01198 
01199             /* Check interface address type matches group, or is unspecified */
01200             if (imr->imr_interface.version != NSAPI_UNSPEC  && imr->imr_interface.version != imr->imr_multiaddr.version) {
01201                 return NSAPI_ERROR_PARAMETER ;
01202             }
01203 
01204             ip_addr_t if_addr;
01205             ip_addr_t multi_addr;
01206 
01207             /* Convert the group address */
01208             if (!convert_mbed_addr_to_lwip(&multi_addr, &imr->imr_multiaddr)) {
01209                 return NSAPI_ERROR_PARAMETER ;
01210             }
01211 
01212             /* Convert the interface address, or make sure it's the correct sort of "any" */
01213             if (imr->imr_interface.version != NSAPI_UNSPEC ) {
01214                 if (!convert_mbed_addr_to_lwip(&if_addr, &imr->imr_interface)) {
01215                     return NSAPI_ERROR_PARAMETER ;
01216                 }
01217             } else {
01218                 ip_addr_set_any(IP_IS_V6(&if_addr), &if_addr);
01219             }
01220 
01221             igmp_err = ERR_USE; // Maps to NSAPI_ERROR_UNSUPPORTED
01222             int32_t member_pair_index = find_multicast_member(s, imr);
01223 
01224             if (optname == NSAPI_ADD_MEMBERSHIP ) {
01225                 if (!s->multicast_memberships) {
01226                     // First multicast join on this socket, allocate space for membership tracking
01227                     s->multicast_memberships = malloc(sizeof(nsapi_ip_mreq_t) * LWIP_SOCKET_MAX_MEMBERSHIPS);
01228                     if (!s->multicast_memberships) {
01229                         return NSAPI_ERROR_NO_MEMORY ;
01230                     }
01231                 } else if(s->multicast_memberships_count == LWIP_SOCKET_MAX_MEMBERSHIPS) {
01232                     return NSAPI_ERROR_NO_MEMORY ;
01233                 }
01234 
01235                 if (member_pair_index != -1) {
01236                     return NSAPI_ERROR_ADDRESS_IN_USE ;
01237                 }
01238 
01239                 member_pair_index = next_free_multicast_member(s, 0);
01240 
01241                 sys_prot_t prot = sys_arch_protect();
01242 
01243                 #if LWIP_IPV4
01244                 if (IP_IS_V4(&if_addr)) {
01245                     igmp_err = igmp_joingroup(ip_2_ip4(&if_addr), ip_2_ip4(&multi_addr));
01246                 }
01247                 #endif
01248                 #if LWIP_IPV6
01249                 if (IP_IS_V6(&if_addr)) {
01250                     igmp_err = mld6_joingroup(ip_2_ip6(&if_addr), ip_2_ip6(&multi_addr));
01251                 }
01252                 #endif
01253 
01254                 sys_arch_unprotect(prot);
01255 
01256                 if (igmp_err == ERR_OK) {
01257                     set_multicast_member_registry_bit(s, member_pair_index);
01258                     s->multicast_memberships[member_pair_index] = *imr;
01259                     s->multicast_memberships_count++;
01260                 }
01261             } else {
01262                 if (member_pair_index == -1) {
01263                     return NSAPI_ERROR_NO_ADDRESS ;
01264                 }
01265 
01266                 clear_multicast_member_registry_bit(s, member_pair_index);
01267                 s->multicast_memberships_count--;
01268 
01269                 sys_prot_t prot = sys_arch_protect();
01270 
01271                 #if LWIP_IPV4
01272                 if (IP_IS_V4(&if_addr)) {
01273                     igmp_err = igmp_leavegroup(ip_2_ip4(&if_addr), ip_2_ip4(&multi_addr));
01274                 }
01275                 #endif
01276                 #if LWIP_IPV6
01277                 if (IP_IS_V6(&if_addr)) {
01278                     igmp_err = mld6_leavegroup(ip_2_ip6(&if_addr), ip_2_ip6(&multi_addr));
01279                 }
01280                 #endif
01281 
01282                 sys_arch_unprotect(prot);
01283             }
01284 
01285             return mbed_lwip_err_remap(igmp_err);
01286          }
01287 
01288         default:
01289             return NSAPI_ERROR_UNSUPPORTED ;
01290     }
01291 }
01292 
01293 static void mbed_lwip_socket_attach(nsapi_stack_t *stack, nsapi_socket_t handle, void (*callback)(void *), void *data)
01294 {
01295     struct lwip_socket *s = (struct lwip_socket *)handle;
01296 
01297     s->cb = callback;
01298     s->data = data;
01299 }
01300 
01301 /* LWIP network stack */
01302 const nsapi_stack_api_t lwip_stack_api = {
01303     .gethostbyname      = mbed_lwip_gethostbyname,
01304     .add_dns_server     = mbed_lwip_add_dns_server,
01305     .socket_open        = mbed_lwip_socket_open,
01306     .socket_close       = mbed_lwip_socket_close,
01307     .socket_bind        = mbed_lwip_socket_bind,
01308     .socket_listen      = mbed_lwip_socket_listen,
01309     .socket_connect     = mbed_lwip_socket_connect,
01310     .socket_accept      = mbed_lwip_socket_accept,
01311     .socket_send        = mbed_lwip_socket_send,
01312     .socket_recv        = mbed_lwip_socket_recv,
01313     .socket_sendto      = mbed_lwip_socket_sendto,
01314     .socket_recvfrom    = mbed_lwip_socket_recvfrom,
01315     .setsockopt         = mbed_lwip_setsockopt,
01316     .socket_attach      = mbed_lwip_socket_attach,
01317 };
01318 
01319 nsapi_stack_t lwip_stack = {
01320     .stack_api = &lwip_stack_api,
01321 };