Greg Steiert / pegasus_dev

Dependents:   blinky_max32630fthr

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 <stdio.h>
00020 #include <stdbool.h>
00021 #include <string.h>
00022 
00023 #include "eth_arch.h"
00024 #include "lwip/opt.h"
00025 #include "lwip/api.h"
00026 #include "lwip/inet.h"
00027 #include "lwip/netif.h"
00028 #include "lwip/dhcp.h"
00029 #include "lwip/tcpip.h"
00030 #include "lwip/tcp.h"
00031 #include "lwip/ip.h"
00032 #include "lwip/mld6.h"
00033 #include "lwip/dns.h"
00034 #include "lwip/udp.h"
00035 
00036 #include "emac_api.h"
00037 
00038 #if DEVICE_EMAC
00039     #define MBED_NETIF_INIT_FN emac_lwip_if_init
00040 #else
00041     #define MBED_NETIF_INIT_FN eth_arch_enetif_init
00042 #endif
00043 
00044 #define DHCP_TIMEOUT 15000
00045 
00046 /* Static arena of sockets */
00047 static struct lwip_socket {
00048     bool in_use;
00049 
00050     struct netconn *conn;
00051     struct netbuf *buf;
00052     u16_t offset;
00053 
00054     void (*cb)(void *);
00055     void *data;
00056 } lwip_arena[MEMP_NUM_NETCONN];
00057 
00058 static bool lwip_connected = false;
00059 
00060 static void mbed_lwip_arena_init(void)
00061 {
00062     memset(lwip_arena, 0, sizeof lwip_arena);
00063 }
00064 
00065 static struct lwip_socket *mbed_lwip_arena_alloc(void)
00066 {
00067     sys_prot_t prot = sys_arch_protect();
00068 
00069     for (int i = 0; i < MEMP_NUM_NETCONN; i++) {
00070         if (!lwip_arena[i].in_use) {
00071             struct lwip_socket *s = &lwip_arena[i];
00072             memset(s, 0, sizeof *s);
00073             s->in_use = true;
00074             sys_arch_unprotect(prot);
00075             return s;
00076         }
00077     }
00078 
00079     sys_arch_unprotect(prot);
00080     return 0;
00081 }
00082 
00083 static void mbed_lwip_arena_dealloc(struct lwip_socket *s)
00084 {
00085     s->in_use = false;
00086 }
00087 
00088 static void mbed_lwip_socket_callback(struct netconn *nc, enum netconn_evt eh, u16_t len)
00089 {
00090     sys_prot_t prot = sys_arch_protect();
00091 
00092     for (int i = 0; i < MEMP_NUM_NETCONN; i++) {
00093         if (lwip_arena[i].in_use
00094             && lwip_arena[i].conn == nc
00095             && lwip_arena[i].cb) {
00096             lwip_arena[i].cb(lwip_arena[i].data);
00097         }
00098     }
00099 
00100     sys_arch_unprotect(prot);
00101 }
00102 
00103 
00104 /* TCP/IP and Network Interface Initialisation */
00105 static struct netif lwip_netif;
00106 static bool lwip_dhcp = false;
00107 static char lwip_mac_address[NSAPI_MAC_SIZE] = "\0";
00108 
00109 #if !LWIP_IPV4 || !LWIP_IPV6
00110 static bool all_zeros(const uint8_t *p, int len)
00111 {
00112     for (int i = 0; i < len; i++) {
00113         if (p[i]) {
00114             return false;
00115         }
00116     }
00117 
00118     return true;
00119 }
00120 #endif
00121 
00122 static bool convert_mbed_addr_to_lwip(ip_addr_t *out, const nsapi_addr_t *in)
00123 {
00124 #if LWIP_IPV6
00125     if (in->version == NSAPI_IPv6 ) {
00126          IP_SET_TYPE(out, IPADDR_TYPE_V6);
00127          MEMCPY(ip_2_ip6(out), in->bytes, sizeof(ip6_addr_t));
00128          return true;
00129     }
00130 #if !LWIP_IPV4
00131     /* For bind() and other purposes, need to accept "null" of other type */
00132     /* (People use IPv4 0.0.0.0 as a general null) */
00133     if (in->version == NSAPI_UNSPEC  ||
00134         (in->version == NSAPI_IPv4  && all_zeros(in->bytes, 4))) {
00135         ip_addr_set_zero_ip6(out);
00136         return true;
00137     }
00138 #endif
00139 #endif
00140 
00141 #if LWIP_IPV4
00142     if (in->version == NSAPI_IPv4 ) {
00143          IP_SET_TYPE(out, IPADDR_TYPE_V4);
00144          MEMCPY(ip_2_ip4(out), in->bytes, sizeof(ip4_addr_t));
00145          return true;
00146     }
00147 #if !LWIP_IPV6
00148     /* For symmetry with above, accept IPv6 :: as a general null */
00149     if (in->version == NSAPI_UNSPEC  ||
00150         (in->version == NSAPI_IPv6  && all_zeros(in->bytes, 16))) {
00151         ip_addr_set_zero_ip4(out);
00152         return true;
00153     }
00154 #endif
00155 #endif
00156 
00157 #if LWIP_IPV4 && LWIP_IPV6
00158     if (in->version == NSAPI_UNSPEC ) {
00159 #if IP_VERSION_PREF == PREF_IPV4
00160         ip_addr_set_zero_ip4(out);
00161 #else
00162         ip_addr_set_zero_ip6(out);
00163 #endif
00164         return true;
00165     }
00166 #endif
00167 
00168     return false;
00169 }
00170 
00171 static bool convert_lwip_addr_to_mbed(nsapi_addr_t *out, const ip_addr_t *in)
00172 {
00173 #if LWIP_IPV6
00174     if (IP_IS_V6(in)) {
00175         out->version = NSAPI_IPv6 ;
00176         MEMCPY(out->bytes, ip_2_ip6(in), sizeof(ip6_addr_t));
00177         return true;
00178     }
00179 #endif
00180 #if LWIP_IPV4
00181     if (IP_IS_V4(in)) {
00182         out->version = NSAPI_IPv4 ;
00183         MEMCPY(out->bytes, ip_2_ip4(in), sizeof(ip4_addr_t));
00184         return true;
00185     }
00186 #endif
00187     return false;
00188 }
00189 
00190 static const ip_addr_t *mbed_lwip_get_ipv4_addr(const struct netif *netif)
00191 {
00192 #if LWIP_IPV4
00193     if (!netif_is_up(netif)) {
00194         return NULL;
00195     }
00196 
00197     if (!ip4_addr_isany(netif_ip4_addr(netif))) {
00198         return netif_ip_addr4(netif);
00199     }
00200 #endif
00201 
00202     return NULL;
00203 }
00204 
00205 static const ip_addr_t *mbed_lwip_get_ipv6_addr(const struct netif *netif)
00206 {
00207 #if LWIP_IPV6
00208     if (!netif_is_up(netif)) {
00209         return NULL;
00210     }
00211 
00212     for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
00213         if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
00214                 !ip6_addr_islinklocal(netif_ip6_addr(netif, i))) {
00215             return netif_ip_addr6(netif, i);
00216         }
00217     }
00218 #endif
00219 
00220     return NULL;
00221 
00222 }
00223 
00224 const ip_addr_t *mbed_lwip_get_ip_addr(bool any_addr, const struct netif *netif)
00225 {
00226     const ip_addr_t *pref_ip_addr = 0;
00227     const ip_addr_t *npref_ip_addr = 0;
00228 
00229 #if IP_VERSION_PREF == PREF_IPV4
00230     pref_ip_addr = mbed_lwip_get_ipv4_addr(netif);
00231     npref_ip_addr = mbed_lwip_get_ipv6_addr(netif);
00232 #else
00233     pref_ip_addr = mbed_lwip_get_ipv6_addr(netif);
00234     npref_ip_addr = mbed_lwip_get_ipv4_addr(netif);
00235 #endif
00236 
00237     if (pref_ip_addr) {
00238         return pref_ip_addr;
00239     } else if (npref_ip_addr && any_addr) {
00240         return npref_ip_addr;
00241     }
00242 
00243     return NULL;
00244 }
00245 
00246 #if LWIP_IPV6
00247 void add_dns_addr(struct netif *lwip_netif)
00248 {
00249     const ip_addr_t *ip_addr = mbed_lwip_get_ip_addr(true, lwip_netif);
00250     if (ip_addr) {
00251         if (IP_IS_V6(ip_addr)) {
00252             const ip_addr_t *dns_ip_addr;
00253             bool dns_addr_exists = false;
00254 
00255             for (char numdns = 0; numdns < DNS_MAX_SERVERS; numdns++) {
00256                 dns_ip_addr = dns_getserver(numdns);
00257                 if (!ip_addr_isany(dns_ip_addr)) {
00258                    dns_addr_exists = true;
00259                    break;
00260                 }
00261             }
00262 
00263             if (!dns_addr_exists) {
00264                 /* 2001:4860:4860::8888 google */
00265                 ip_addr_t ipv6_dns_addr = IPADDR6_INIT(
00266                         PP_HTONL(0x20014860UL),
00267                         PP_HTONL(0x48600000UL),
00268                         PP_HTONL(0x00000000UL),
00269                         PP_HTONL(0x00008888UL));
00270                 dns_setserver(0, &ipv6_dns_addr);
00271             }
00272         }
00273     }
00274 }
00275 #endif
00276 
00277 static sys_sem_t lwip_tcpip_inited;
00278 static void mbed_lwip_tcpip_init_irq(void *eh)
00279 {
00280     sys_sem_signal(&lwip_tcpip_inited);
00281 }
00282 
00283 static sys_sem_t lwip_netif_linked;
00284 static void mbed_lwip_netif_link_irq(struct netif *lwip_netif)
00285 {
00286     if (netif_is_link_up(lwip_netif)) {
00287         sys_sem_signal(&lwip_netif_linked);
00288     }
00289 }
00290 
00291 static sys_sem_t lwip_netif_has_addr;
00292 static void mbed_lwip_netif_status_irq(struct netif *lwip_netif)
00293 {
00294     static bool any_addr = true;
00295 
00296     // Indicates that has address
00297     if (any_addr == true && mbed_lwip_get_ip_addr(true, lwip_netif)) {
00298         sys_sem_signal(&lwip_netif_has_addr);
00299         any_addr = false;
00300         return;
00301     }
00302 
00303     // Indicates that has preferred address
00304     if (mbed_lwip_get_ip_addr(false, lwip_netif)) {
00305         sys_sem_signal(&lwip_netif_has_addr);
00306     }
00307 }
00308 
00309 static void mbed_lwip_set_mac_address(void)
00310 {
00311 #if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
00312     snprintf(lwip_mac_address, 19, "%02x:%02x:%02x:%02x:%02x:%02x",
00313             MBED_MAC_ADDR_0, MBED_MAC_ADDR_1, MBED_MAC_ADDR_2,
00314             MBED_MAC_ADDR_3, MBED_MAC_ADDR_4, MBED_MAC_ADDR_5);
00315 #else
00316     char mac[6];
00317     mbed_mac_address(mac);
00318     snprintf(lwip_mac_address, 19, "%02x:%02x:%02x:%02x:%02x:%02x",
00319             mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
00320 #endif
00321 }
00322 
00323 /* LWIP interface implementation */
00324 const char *mbed_lwip_get_mac_address(void)
00325 {
00326     return lwip_mac_address[0] ? lwip_mac_address : 0;
00327 }
00328 
00329 char *mbed_lwip_get_ip_address(char *buf, nsapi_size_t buflen)
00330 {
00331     const ip_addr_t *addr = mbed_lwip_get_ip_addr(true, &lwip_netif);
00332     if (!addr) {
00333         return NULL;
00334     }
00335 #if LWIP_IPV6
00336     if (IP_IS_V6(addr)) {
00337         return ip6addr_ntoa_r(ip_2_ip6(addr), buf, buflen);
00338     }
00339 #endif
00340 #if LWIP_IPV4
00341     if (IP_IS_V4(addr)) {
00342         return ip4addr_ntoa_r(ip_2_ip4(addr), buf, buflen);
00343     }
00344 #endif
00345     return NULL;
00346 }
00347 
00348 const char *mbed_lwip_get_netmask(char *buf, nsapi_size_t buflen)
00349 {
00350 #if LWIP_IPV4
00351     const ip4_addr_t *addr = netif_ip4_netmask(&lwip_netif);
00352     if (!ip4_addr_isany(addr)) {
00353         return ip4addr_ntoa_r(addr, buf, buflen);
00354     } else {
00355         return NULL;
00356     }
00357 #else
00358     return NULL;
00359 #endif
00360 }
00361 
00362 char *mbed_lwip_get_gateway(char *buf, nsapi_size_t buflen)
00363 {
00364 #if LWIP_IPV4
00365     const ip4_addr_t *addr = netif_ip4_gw(&lwip_netif);
00366     if (!ip4_addr_isany(addr)) {
00367         return ip4addr_ntoa_r(addr, buf, buflen);
00368     } else {
00369         return NULL;
00370     }
00371 #else
00372     return NULL;
00373 #endif
00374 }
00375 
00376 nsapi_error_t mbed_lwip_init(emac_interface_t *emac)
00377 {
00378     // Check if we've already brought up lwip
00379     if (!mbed_lwip_get_mac_address()) {
00380         // Set up network
00381         mbed_lwip_set_mac_address();
00382 
00383         sys_sem_new(&lwip_tcpip_inited, 0);
00384         sys_sem_new(&lwip_netif_linked, 0);
00385         sys_sem_new(&lwip_netif_has_addr, 0);
00386 
00387         tcpip_init(mbed_lwip_tcpip_init_irq, NULL);
00388         sys_arch_sem_wait(&lwip_tcpip_inited, 0);
00389 
00390         memset(&lwip_netif, 0, sizeof lwip_netif);
00391         if (!netif_add(&lwip_netif,
00392 #if LWIP_IPV4
00393                 0, 0, 0,
00394 #endif
00395                 emac, MBED_NETIF_INIT_FN, tcpip_input)) {
00396             return NSAPI_ERROR_DEVICE_ERROR ;
00397         }
00398 
00399         netif_set_default(&lwip_netif);
00400 
00401         netif_set_link_callback(&lwip_netif, mbed_lwip_netif_link_irq);
00402         netif_set_status_callback(&lwip_netif, mbed_lwip_netif_status_irq);
00403 
00404 #if !DEVICE_EMAC
00405         eth_arch_enable_interrupts();
00406 #endif
00407     }
00408 
00409     return NSAPI_ERROR_OK ;
00410 }
00411 
00412 nsapi_error_t mbed_lwip_bringup(bool dhcp, const char *ip, const char *netmask, const char *gw)
00413 {
00414     // Check if we've already connected
00415     if (lwip_connected) {
00416         return NSAPI_ERROR_PARAMETER ;
00417     }
00418 
00419     if(mbed_lwip_init(NULL) != NSAPI_ERROR_OK ) {
00420         return NSAPI_ERROR_DEVICE_ERROR ;
00421     }
00422 
00423     // Zero out socket set
00424     mbed_lwip_arena_init();
00425 
00426 #if LWIP_IPV6
00427     netif_create_ip6_linklocal_address(&lwip_netif, 1/*from MAC*/);
00428 #if LWIP_IPV6_MLD
00429   /*
00430    * For hardware/netifs that implement MAC filtering.
00431    * All-nodes link-local is handled by default, so we must let the hardware know
00432    * to allow multicast packets in.
00433    * Should set mld_mac_filter previously. */
00434   if (lwip_netif.mld_mac_filter != NULL) {
00435     ip6_addr_t ip6_allnodes_ll;
00436     ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll);
00437     lwip_netif.mld_mac_filter(&lwip_netif, &ip6_allnodes_ll, MLD6_ADD_MAC_FILTER);
00438   }
00439 #endif /* LWIP_IPV6_MLD */
00440 
00441 #if LWIP_IPV6_AUTOCONFIG
00442     /* IPv6 address autoconfiguration not enabled by default */
00443   lwip_netif.ip6_autoconfig_enabled = 1;
00444 #endif /* LWIP_IPV6_AUTOCONFIG */
00445 
00446 #endif
00447 
00448     u32_t ret;
00449 
00450     if (!netif_is_link_up(&lwip_netif)) {
00451         ret = sys_arch_sem_wait(&lwip_netif_linked, 15000);
00452 
00453         if (ret == SYS_ARCH_TIMEOUT) {
00454             return NSAPI_ERROR_NO_CONNECTION ;
00455         }
00456     }
00457 
00458 #if LWIP_IPV4
00459     if (!dhcp) {
00460         ip4_addr_t ip_addr;
00461         ip4_addr_t netmask_addr;
00462         ip4_addr_t gw_addr;
00463 
00464         if (!inet_aton(ip, &ip_addr) ||
00465             !inet_aton(netmask, &netmask_addr) ||
00466             !inet_aton(gw, &gw_addr)) {
00467             return NSAPI_ERROR_PARAMETER ;
00468         }
00469 
00470         netif_set_addr(&lwip_netif, &ip_addr, &netmask_addr, &gw_addr);
00471     }
00472 #endif
00473 
00474     netif_set_up(&lwip_netif);
00475 
00476 #if LWIP_IPV4
00477     // Connect to the network
00478     lwip_dhcp = dhcp;
00479 
00480     if (lwip_dhcp) {
00481         err_t err = dhcp_start(&lwip_netif);
00482         if (err) {
00483             return NSAPI_ERROR_DHCP_FAILURE ;
00484         }
00485     }
00486 #endif
00487 
00488     // If doesn't have address
00489     if (!mbed_lwip_get_ip_addr(true, &lwip_netif)) {
00490         ret = sys_arch_sem_wait(&lwip_netif_has_addr, 15000);
00491         if (ret == SYS_ARCH_TIMEOUT) {
00492             return NSAPI_ERROR_DHCP_FAILURE ;
00493         }
00494         lwip_connected = true;
00495     }
00496 
00497 #if ADDR_TIMEOUT
00498     // If address is not for preferred stack waits a while to see
00499     // if preferred stack address is acquired
00500     if (!mbed_lwip_get_ip_addr(false, &lwip_netif)) {
00501         ret = sys_arch_sem_wait(&lwip_netif_has_addr, ADDR_TIMEOUT * 1000);
00502     }
00503 #endif
00504 
00505 #if LWIP_IPV6
00506     add_dns_addr(&lwip_netif);
00507 #endif
00508 
00509     return 0;
00510 }
00511 
00512 nsapi_error_t mbed_lwip_bringdown(void)
00513 {
00514     // Check if we've connected
00515     if (!lwip_connected) {
00516         return NSAPI_ERROR_PARAMETER ;
00517     }
00518 
00519 #if LWIP_IPV4
00520     // Disconnect from the network
00521     if (lwip_dhcp) {
00522         dhcp_release(&lwip_netif);
00523         dhcp_stop(&lwip_netif);
00524         lwip_dhcp = false;
00525     } else {
00526         netif_set_down(&lwip_netif);
00527     }
00528 #endif
00529 
00530     lwip_connected = false;
00531     // TO DO - actually remove addresses from stack, and shut down properly
00532     return 0;
00533 }
00534 
00535 /* LWIP error remapping */
00536 static nsapi_error_t mbed_lwip_err_remap(err_t err) {
00537     switch (err) {
00538         case ERR_OK:
00539         case ERR_CLSD:
00540         case ERR_RST:
00541             return 0;
00542         case ERR_MEM:
00543             return NSAPI_ERROR_NO_MEMORY ;
00544         case ERR_CONN:
00545             return NSAPI_ERROR_NO_CONNECTION ;
00546         case ERR_TIMEOUT:
00547         case ERR_RTE:
00548         case ERR_INPROGRESS:
00549         case ERR_WOULDBLOCK:
00550             return NSAPI_ERROR_WOULD_BLOCK ;
00551         case ERR_VAL:
00552         case ERR_USE:
00553         case ERR_ISCONN:
00554         case ERR_ARG:
00555             return NSAPI_ERROR_PARAMETER ;
00556         default:
00557             return NSAPI_ERROR_DEVICE_ERROR ;
00558     }
00559 }
00560 
00561 /* LWIP network stack implementation */
00562 static nsapi_error_t mbed_lwip_gethostbyname(nsapi_stack_t *stack, const char *host, nsapi_addr_t *addr, nsapi_version_t version)
00563 {
00564     ip_addr_t lwip_addr;
00565 
00566 #if LWIP_IPV4 && LWIP_IPV6
00567     u8_t addr_type;
00568     if (version == NSAPI_UNSPEC ) {
00569         const ip_addr_t *ip_addr;
00570         ip_addr = mbed_lwip_get_ip_addr(true, &lwip_netif);
00571         if (IP_IS_V6(ip_addr)) {
00572             addr_type = NETCONN_DNS_IPV6;
00573         } else {
00574             addr_type = NETCONN_DNS_IPV4;
00575         }
00576     } else if (version == NSAPI_IPv4 ) {
00577         addr_type = NETCONN_DNS_IPV4;
00578     } else if (version == NSAPI_IPv6 ) {
00579         addr_type = NETCONN_DNS_IPV6;
00580     }
00581     err_t err = netconn_gethostbyname_addrtype(host, &lwip_addr, addr_type);
00582 #elif LWIP_IPV4
00583     if (version != NSAPI_IPv4  && version != NSAPI_UNSPEC ) {
00584         return NSAPI_ERROR_DNS_FAILURE ;
00585     }
00586     err_t err = netconn_gethostbyname(host, &lwip_addr);
00587 #elif LWIP_IPV6
00588     if (version != NSAPI_IPv6  && version != NSAPI_UNSPEC ) {
00589         return NSAPI_ERROR_DNS_FAILURE ;
00590     }
00591     err_t err = netconn_gethostbyname(host, &lwip_addr);
00592 #endif
00593 
00594     if (err != ERR_OK) {
00595         return NSAPI_ERROR_DNS_FAILURE ;
00596     }
00597 
00598     convert_lwip_addr_to_mbed(addr, &lwip_addr);
00599 
00600     return 0;
00601 }
00602 
00603 static nsapi_error_t mbed_lwip_socket_open(nsapi_stack_t *stack, nsapi_socket_t *handle, nsapi_protocol_t proto)
00604 {
00605     // check if network is connected
00606     if (!lwip_connected) {
00607         return NSAPI_ERROR_NO_CONNECTION ;
00608     }
00609 
00610     // allocate a socket
00611     struct lwip_socket *s = mbed_lwip_arena_alloc();
00612     if (!s) {
00613         return NSAPI_ERROR_NO_SOCKET ;
00614     }
00615 
00616     u8_t lwip_proto = proto == NSAPI_TCP  ? NETCONN_TCP : NETCONN_UDP;
00617 
00618 #if LWIP_IPV6 && LWIP_IPV4
00619     const ip_addr_t *ip_addr;
00620     ip_addr = mbed_lwip_get_ip_addr(true, &lwip_netif);
00621 
00622     if (IP_IS_V6(ip_addr)) {
00623         // Enable IPv6 (or dual-stack). LWIP dual-stack support is
00624         // currently incomplete as of 2.0.0rc2 - eg we will only be able
00625         // to do a UDP sendto to an address matching the type selected
00626         // here. Matching "get_ip_addr" and DNS logic, use v4 if
00627         // available.
00628         lwip_proto |= NETCONN_TYPE_IPV6;
00629     }
00630 #elif LWIP_IPV6
00631     lwip_proto |= NETCONN_TYPE_IPV6;
00632 #endif
00633 
00634     s->conn = netconn_new_with_callback(lwip_proto, mbed_lwip_socket_callback);
00635 
00636     if (!s->conn) {
00637         mbed_lwip_arena_dealloc(s);
00638         return NSAPI_ERROR_NO_SOCKET ;
00639     }
00640 
00641     netconn_set_recvtimeout(s->conn, 1);
00642     *(struct lwip_socket **)handle = s;
00643     return 0;
00644 }
00645 
00646 static nsapi_error_t mbed_lwip_socket_close(nsapi_stack_t *stack, nsapi_socket_t handle)
00647 {
00648     struct lwip_socket *s = (struct lwip_socket *)handle;
00649 
00650     err_t err = netconn_delete(s->conn);
00651     mbed_lwip_arena_dealloc(s);
00652     return mbed_lwip_err_remap(err);
00653 }
00654 
00655 static nsapi_error_t mbed_lwip_socket_bind(nsapi_stack_t *stack, nsapi_socket_t handle, nsapi_addr_t addr, uint16_t port)
00656 {
00657     struct lwip_socket *s = (struct lwip_socket *)handle;
00658     ip_addr_t ip_addr;
00659 
00660     if ((s->conn->type == NETCONN_TCP && s->conn->pcb.tcp->local_port != 0) ||
00661         (s->conn->type == NETCONN_UDP && s->conn->pcb.udp->local_port != 0)) {
00662         return NSAPI_ERROR_PARAMETER ;
00663     }
00664 
00665     if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
00666         return NSAPI_ERROR_PARAMETER ;
00667     }
00668 
00669     err_t err = netconn_bind(s->conn, &ip_addr, port);
00670     return mbed_lwip_err_remap(err);
00671 }
00672 
00673 static nsapi_error_t mbed_lwip_socket_listen(nsapi_stack_t *stack, nsapi_socket_t handle, int backlog)
00674 {
00675     struct lwip_socket *s = (struct lwip_socket *)handle;
00676 
00677     err_t err = netconn_listen_with_backlog(s->conn, backlog);
00678     return mbed_lwip_err_remap(err);
00679 }
00680 
00681 static nsapi_error_t mbed_lwip_socket_connect(nsapi_stack_t *stack, nsapi_socket_t handle, nsapi_addr_t addr, uint16_t port)
00682 {
00683     struct lwip_socket *s = (struct lwip_socket *)handle;
00684     ip_addr_t ip_addr;
00685 
00686     if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
00687         return NSAPI_ERROR_PARAMETER ;
00688     }
00689 
00690     netconn_set_nonblocking(s->conn, false);
00691     err_t err = netconn_connect(s->conn, &ip_addr, port);
00692     netconn_set_nonblocking(s->conn, true);
00693 
00694     return mbed_lwip_err_remap(err);
00695 }
00696 
00697 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)
00698 {
00699     struct lwip_socket *s = (struct lwip_socket *)server;
00700     struct lwip_socket *ns = mbed_lwip_arena_alloc();
00701     if (!ns) {
00702         return NSAPI_ERROR_NO_SOCKET ;
00703     }
00704 
00705     err_t err = netconn_accept(s->conn, &ns->conn);
00706     if (err != ERR_OK) {
00707         mbed_lwip_arena_dealloc(ns);
00708         return mbed_lwip_err_remap(err);
00709     }
00710 
00711     netconn_set_recvtimeout(ns->conn, 1);
00712     *(struct lwip_socket **)handle = ns;
00713 
00714     ip_addr_t peer_addr;
00715     (void) netconn_peer(ns->conn, &peer_addr, port);
00716     convert_lwip_addr_to_mbed(addr, &peer_addr);
00717 
00718     return 0;
00719 }
00720 
00721 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)
00722 {
00723     struct lwip_socket *s = (struct lwip_socket *)handle;
00724     size_t bytes_written = 0;
00725 
00726     err_t err = netconn_write_partly(s->conn, data, size, NETCONN_COPY, &bytes_written);
00727     if (err != ERR_OK) {
00728         return mbed_lwip_err_remap(err);
00729     }
00730 
00731     return (nsapi_size_or_error_t)bytes_written;
00732 }
00733 
00734 static nsapi_size_or_error_t mbed_lwip_socket_recv(nsapi_stack_t *stack, nsapi_socket_t handle, void *data, nsapi_size_t size)
00735 {
00736     struct lwip_socket *s = (struct lwip_socket *)handle;
00737 
00738     if (!s->buf) {
00739         err_t err = netconn_recv(s->conn, &s->buf);
00740         s->offset = 0;
00741 
00742         if (err != ERR_OK) {
00743             return mbed_lwip_err_remap(err);
00744         }
00745     }
00746 
00747     u16_t recv = netbuf_copy_partial(s->buf, data, (u16_t)size, s->offset);
00748     s->offset += recv;
00749 
00750     if (s->offset >= netbuf_len(s->buf)) {
00751         netbuf_delete(s->buf);
00752         s->buf = 0;
00753     }
00754 
00755     return recv;
00756 }
00757 
00758 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)
00759 {
00760     struct lwip_socket *s = (struct lwip_socket *)handle;
00761     ip_addr_t ip_addr;
00762 
00763     if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
00764         return NSAPI_ERROR_PARAMETER ;
00765     }
00766 
00767     struct netbuf *buf = netbuf_new();
00768     err_t err = netbuf_ref(buf, data, (u16_t)size);
00769     if (err != ERR_OK) {
00770         netbuf_free(buf);
00771         return mbed_lwip_err_remap(err);
00772     }
00773 
00774     err = netconn_sendto(s->conn, buf, &ip_addr, port);
00775     netbuf_delete(buf);
00776     if (err != ERR_OK) {
00777         return mbed_lwip_err_remap(err);
00778     }
00779 
00780     return size;
00781 }
00782 
00783 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)
00784 {
00785     struct lwip_socket *s = (struct lwip_socket *)handle;
00786     struct netbuf *buf;
00787 
00788     err_t err = netconn_recv(s->conn, &buf);
00789     if (err != ERR_OK) {
00790         return mbed_lwip_err_remap(err);
00791     }
00792 
00793     convert_lwip_addr_to_mbed(addr, netbuf_fromaddr(buf));
00794     *port = netbuf_fromport(buf);
00795 
00796     u16_t recv = netbuf_copy(buf, data, (u16_t)size);
00797     netbuf_delete(buf);
00798 
00799     return recv;
00800 }
00801 
00802 static nsapi_error_t mbed_lwip_setsockopt(nsapi_stack_t *stack, nsapi_socket_t handle, int level, int optname, const void *optval, unsigned optlen)
00803 {
00804     struct lwip_socket *s = (struct lwip_socket *)handle;
00805 
00806     switch (optname) {
00807         case NSAPI_KEEPALIVE :
00808             if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) {
00809                 return NSAPI_ERROR_UNSUPPORTED ;
00810             }
00811 
00812             s->conn->pcb.tcp->so_options |= SOF_KEEPALIVE;
00813             return 0;
00814 
00815         case NSAPI_KEEPIDLE :
00816             if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) {
00817                 return NSAPI_ERROR_UNSUPPORTED ;
00818             }
00819 
00820             s->conn->pcb.tcp->keep_idle = *(int*)optval;
00821             return 0;
00822 
00823         case NSAPI_KEEPINTVL :
00824             if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) {
00825                 return NSAPI_ERROR_UNSUPPORTED ;
00826             }
00827 
00828             s->conn->pcb.tcp->keep_intvl = *(int*)optval;
00829             return 0;
00830 
00831         case NSAPI_REUSEADDR :
00832             if (optlen != sizeof(int)) {
00833                 return NSAPI_ERROR_UNSUPPORTED ;
00834             }
00835 
00836             if (*(int *)optval) {
00837                 s->conn->pcb.tcp->so_options |= SOF_REUSEADDR;
00838             } else {
00839                 s->conn->pcb.tcp->so_options &= ~SOF_REUSEADDR;
00840             }
00841             return 0;
00842 
00843         default:
00844             return NSAPI_ERROR_UNSUPPORTED ;
00845     }
00846 }
00847 
00848 static void mbed_lwip_socket_attach(nsapi_stack_t *stack, nsapi_socket_t handle, void (*callback)(void *), void *data)
00849 {
00850     struct lwip_socket *s = (struct lwip_socket *)handle;
00851 
00852     s->cb = callback;
00853     s->data = data;
00854 }
00855 
00856 /* LWIP network stack */
00857 const nsapi_stack_api_t lwip_stack_api = {
00858     .gethostbyname      = mbed_lwip_gethostbyname,
00859     .socket_open        = mbed_lwip_socket_open,
00860     .socket_close       = mbed_lwip_socket_close,
00861     .socket_bind        = mbed_lwip_socket_bind,
00862     .socket_listen      = mbed_lwip_socket_listen,
00863     .socket_connect     = mbed_lwip_socket_connect,
00864     .socket_accept      = mbed_lwip_socket_accept,
00865     .socket_send        = mbed_lwip_socket_send,
00866     .socket_recv        = mbed_lwip_socket_recv,
00867     .socket_sendto      = mbed_lwip_socket_sendto,
00868     .socket_recvfrom    = mbed_lwip_socket_recvfrom,
00869     .setsockopt         = mbed_lwip_setsockopt,
00870     .socket_attach      = mbed_lwip_socket_attach,
00871 };
00872 
00873 nsapi_stack_t lwip_stack = {
00874     .stack_api = &lwip_stack_api,
00875 };