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