Lee Kai Xuan / mbed-os

Fork of mbed-os by erkin yucel

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