mbed os with nrf51 internal bandgap enabled to read battery level

Dependents:   BLE_file_test BLE_Blink ExternalEncoder

Committer:
elessair
Date:
Sun Oct 23 15:10:02 2016 +0000
Revision:
0:f269e3021894
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
elessair 0:f269e3021894 1 /* LWIP implementation of NetworkInterfaceAPI
elessair 0:f269e3021894 2 * Copyright (c) 2015 ARM Limited
elessair 0:f269e3021894 3 *
elessair 0:f269e3021894 4 * Licensed under the Apache License, Version 2.0 (the "License");
elessair 0:f269e3021894 5 * you may not use this file except in compliance with the License.
elessair 0:f269e3021894 6 * You may obtain a copy of the License at
elessair 0:f269e3021894 7 *
elessair 0:f269e3021894 8 * http://www.apache.org/licenses/LICENSE-2.0
elessair 0:f269e3021894 9 *
elessair 0:f269e3021894 10 * Unless required by applicable law or agreed to in writing, software
elessair 0:f269e3021894 11 * distributed under the License is distributed on an "AS IS" BASIS,
elessair 0:f269e3021894 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
elessair 0:f269e3021894 13 * See the License for the specific language governing permissions and
elessair 0:f269e3021894 14 * limitations under the License.
elessair 0:f269e3021894 15 */
elessair 0:f269e3021894 16
elessair 0:f269e3021894 17 #include "nsapi.h"
elessair 0:f269e3021894 18 #include "mbed_interface.h"
elessair 0:f269e3021894 19 #include <stdio.h>
elessair 0:f269e3021894 20 #include <stdbool.h>
elessair 0:f269e3021894 21 #include <string.h>
elessair 0:f269e3021894 22
elessair 0:f269e3021894 23 #include "eth_arch.h"
elessair 0:f269e3021894 24 #include "lwip/opt.h"
elessair 0:f269e3021894 25 #include "lwip/api.h"
elessair 0:f269e3021894 26 #include "lwip/inet.h"
elessair 0:f269e3021894 27 #include "lwip/netif.h"
elessair 0:f269e3021894 28 #include "lwip/dhcp.h"
elessair 0:f269e3021894 29 #include "lwip/tcpip.h"
elessair 0:f269e3021894 30 #include "lwip/tcp.h"
elessair 0:f269e3021894 31 #include "lwip/ip.h"
elessair 0:f269e3021894 32 #include "lwip/mld6.h"
elessair 0:f269e3021894 33 #include "lwip/dns.h"
elessair 0:f269e3021894 34 #include "lwip/udp.h"
elessair 0:f269e3021894 35
elessair 0:f269e3021894 36 #include "emac_api.h"
elessair 0:f269e3021894 37
elessair 0:f269e3021894 38 #if DEVICE_EMAC
elessair 0:f269e3021894 39 #define MBED_NETIF_INIT_FN emac_lwip_if_init
elessair 0:f269e3021894 40 #else
elessair 0:f269e3021894 41 #define MBED_NETIF_INIT_FN eth_arch_enetif_init
elessair 0:f269e3021894 42 #endif
elessair 0:f269e3021894 43
elessair 0:f269e3021894 44 #define DHCP_TIMEOUT 15000
elessair 0:f269e3021894 45
elessair 0:f269e3021894 46 /* Static arena of sockets */
elessair 0:f269e3021894 47 static struct lwip_socket {
elessair 0:f269e3021894 48 bool in_use;
elessair 0:f269e3021894 49
elessair 0:f269e3021894 50 struct netconn *conn;
elessair 0:f269e3021894 51 struct netbuf *buf;
elessair 0:f269e3021894 52 u16_t offset;
elessair 0:f269e3021894 53
elessair 0:f269e3021894 54 void (*cb)(void *);
elessair 0:f269e3021894 55 void *data;
elessair 0:f269e3021894 56 } lwip_arena[MEMP_NUM_NETCONN];
elessair 0:f269e3021894 57
elessair 0:f269e3021894 58 static bool lwip_connected = false;
elessair 0:f269e3021894 59
elessair 0:f269e3021894 60 static void mbed_lwip_arena_init(void)
elessair 0:f269e3021894 61 {
elessair 0:f269e3021894 62 memset(lwip_arena, 0, sizeof lwip_arena);
elessair 0:f269e3021894 63 }
elessair 0:f269e3021894 64
elessair 0:f269e3021894 65 static struct lwip_socket *mbed_lwip_arena_alloc(void)
elessair 0:f269e3021894 66 {
elessair 0:f269e3021894 67 sys_prot_t prot = sys_arch_protect();
elessair 0:f269e3021894 68
elessair 0:f269e3021894 69 for (int i = 0; i < MEMP_NUM_NETCONN; i++) {
elessair 0:f269e3021894 70 if (!lwip_arena[i].in_use) {
elessair 0:f269e3021894 71 struct lwip_socket *s = &lwip_arena[i];
elessair 0:f269e3021894 72 memset(s, 0, sizeof *s);
elessair 0:f269e3021894 73 s->in_use = true;
elessair 0:f269e3021894 74 sys_arch_unprotect(prot);
elessair 0:f269e3021894 75 return s;
elessair 0:f269e3021894 76 }
elessair 0:f269e3021894 77 }
elessair 0:f269e3021894 78
elessair 0:f269e3021894 79 sys_arch_unprotect(prot);
elessair 0:f269e3021894 80 return 0;
elessair 0:f269e3021894 81 }
elessair 0:f269e3021894 82
elessair 0:f269e3021894 83 static void mbed_lwip_arena_dealloc(struct lwip_socket *s)
elessair 0:f269e3021894 84 {
elessair 0:f269e3021894 85 s->in_use = false;
elessair 0:f269e3021894 86 }
elessair 0:f269e3021894 87
elessair 0:f269e3021894 88 static void mbed_lwip_socket_callback(struct netconn *nc, enum netconn_evt eh, u16_t len)
elessair 0:f269e3021894 89 {
elessair 0:f269e3021894 90 sys_prot_t prot = sys_arch_protect();
elessair 0:f269e3021894 91
elessair 0:f269e3021894 92 for (int i = 0; i < MEMP_NUM_NETCONN; i++) {
elessair 0:f269e3021894 93 if (lwip_arena[i].in_use
elessair 0:f269e3021894 94 && lwip_arena[i].conn == nc
elessair 0:f269e3021894 95 && lwip_arena[i].cb) {
elessair 0:f269e3021894 96 lwip_arena[i].cb(lwip_arena[i].data);
elessair 0:f269e3021894 97 }
elessair 0:f269e3021894 98 }
elessair 0:f269e3021894 99
elessair 0:f269e3021894 100 sys_arch_unprotect(prot);
elessair 0:f269e3021894 101 }
elessair 0:f269e3021894 102
elessair 0:f269e3021894 103
elessair 0:f269e3021894 104 /* TCP/IP and Network Interface Initialisation */
elessair 0:f269e3021894 105 static struct netif lwip_netif;
elessair 0:f269e3021894 106 static bool lwip_dhcp = false;
elessair 0:f269e3021894 107 static char lwip_mac_address[NSAPI_MAC_SIZE] = "\0";
elessair 0:f269e3021894 108
elessair 0:f269e3021894 109 #if !LWIP_IPV4 || !LWIP_IPV6
elessair 0:f269e3021894 110 static bool all_zeros(const uint8_t *p, int len)
elessair 0:f269e3021894 111 {
elessair 0:f269e3021894 112 for (int i = 0; i < len; i++) {
elessair 0:f269e3021894 113 if (p[i]) {
elessair 0:f269e3021894 114 return false;
elessair 0:f269e3021894 115 }
elessair 0:f269e3021894 116 }
elessair 0:f269e3021894 117
elessair 0:f269e3021894 118 return true;
elessair 0:f269e3021894 119 }
elessair 0:f269e3021894 120 #endif
elessair 0:f269e3021894 121
elessair 0:f269e3021894 122 static bool convert_mbed_addr_to_lwip(ip_addr_t *out, const nsapi_addr_t *in)
elessair 0:f269e3021894 123 {
elessair 0:f269e3021894 124 #if LWIP_IPV6
elessair 0:f269e3021894 125 if (in->version == NSAPI_IPv6) {
elessair 0:f269e3021894 126 IP_SET_TYPE(out, IPADDR_TYPE_V6);
elessair 0:f269e3021894 127 MEMCPY(ip_2_ip6(out), in->bytes, sizeof(ip6_addr_t));
elessair 0:f269e3021894 128 return true;
elessair 0:f269e3021894 129 }
elessair 0:f269e3021894 130 #if !LWIP_IPV4
elessair 0:f269e3021894 131 /* For bind() and other purposes, need to accept "null" of other type */
elessair 0:f269e3021894 132 /* (People use IPv4 0.0.0.0 as a general null) */
elessair 0:f269e3021894 133 if (in->version == NSAPI_IPv4 && all_zeros(in->bytes, 4)) {
elessair 0:f269e3021894 134 ip_addr_set_zero_ip6(out);
elessair 0:f269e3021894 135 return true;
elessair 0:f269e3021894 136 }
elessair 0:f269e3021894 137 #endif
elessair 0:f269e3021894 138 #endif
elessair 0:f269e3021894 139
elessair 0:f269e3021894 140 #if LWIP_IPV4
elessair 0:f269e3021894 141 if (in->version == NSAPI_IPv4) {
elessair 0:f269e3021894 142 IP_SET_TYPE(out, IPADDR_TYPE_V4);
elessair 0:f269e3021894 143 MEMCPY(ip_2_ip4(out), in->bytes, sizeof(ip4_addr_t));
elessair 0:f269e3021894 144 return true;
elessair 0:f269e3021894 145 }
elessair 0:f269e3021894 146 #if !LWIP_IPV6
elessair 0:f269e3021894 147 /* For symmetry with above, accept IPv6 :: as a general null */
elessair 0:f269e3021894 148 if (in->version == NSAPI_IPv6 && all_zeros(in->bytes, 16)) {
elessair 0:f269e3021894 149 ip_addr_set_zero_ip4(out);
elessair 0:f269e3021894 150 return true;
elessair 0:f269e3021894 151 }
elessair 0:f269e3021894 152 #endif
elessair 0:f269e3021894 153 #endif
elessair 0:f269e3021894 154
elessair 0:f269e3021894 155 return false;
elessair 0:f269e3021894 156 }
elessair 0:f269e3021894 157
elessair 0:f269e3021894 158 static bool convert_lwip_addr_to_mbed(nsapi_addr_t *out, const ip_addr_t *in)
elessair 0:f269e3021894 159 {
elessair 0:f269e3021894 160 #if LWIP_IPV6
elessair 0:f269e3021894 161 if (IP_IS_V6(in)) {
elessair 0:f269e3021894 162 out->version = NSAPI_IPv6;
elessair 0:f269e3021894 163 MEMCPY(out->bytes, ip_2_ip6(in), sizeof(ip6_addr_t));
elessair 0:f269e3021894 164 return true;
elessair 0:f269e3021894 165 }
elessair 0:f269e3021894 166 #endif
elessair 0:f269e3021894 167 #if LWIP_IPV4
elessair 0:f269e3021894 168 if (IP_IS_V4(in)) {
elessair 0:f269e3021894 169 out->version = NSAPI_IPv4;
elessair 0:f269e3021894 170 MEMCPY(out->bytes, ip_2_ip4(in), sizeof(ip4_addr_t));
elessair 0:f269e3021894 171 return true;
elessair 0:f269e3021894 172 }
elessair 0:f269e3021894 173 #endif
elessair 0:f269e3021894 174 return false;
elessair 0:f269e3021894 175 }
elessair 0:f269e3021894 176
elessair 0:f269e3021894 177 static const ip_addr_t *mbed_lwip_get_ipv4_addr(const struct netif *netif)
elessair 0:f269e3021894 178 {
elessair 0:f269e3021894 179 #if LWIP_IPV4
elessair 0:f269e3021894 180 if (!netif_is_up(netif)) {
elessair 0:f269e3021894 181 return NULL;
elessair 0:f269e3021894 182 }
elessair 0:f269e3021894 183
elessair 0:f269e3021894 184 if (!ip4_addr_isany(netif_ip4_addr(netif))) {
elessair 0:f269e3021894 185 return netif_ip_addr4(netif);
elessair 0:f269e3021894 186 }
elessair 0:f269e3021894 187 #endif
elessair 0:f269e3021894 188
elessair 0:f269e3021894 189 return NULL;
elessair 0:f269e3021894 190 }
elessair 0:f269e3021894 191
elessair 0:f269e3021894 192 static const ip_addr_t *mbed_lwip_get_ipv6_addr(const struct netif *netif)
elessair 0:f269e3021894 193 {
elessair 0:f269e3021894 194 #if LWIP_IPV6
elessair 0:f269e3021894 195 if (!netif_is_up(netif)) {
elessair 0:f269e3021894 196 return NULL;
elessair 0:f269e3021894 197 }
elessair 0:f269e3021894 198
elessair 0:f269e3021894 199 for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
elessair 0:f269e3021894 200 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
elessair 0:f269e3021894 201 !ip6_addr_islinklocal(netif_ip6_addr(netif, i))) {
elessair 0:f269e3021894 202 return netif_ip_addr6(netif, i);
elessair 0:f269e3021894 203 }
elessair 0:f269e3021894 204 }
elessair 0:f269e3021894 205 #endif
elessair 0:f269e3021894 206
elessair 0:f269e3021894 207 return NULL;
elessair 0:f269e3021894 208
elessair 0:f269e3021894 209 }
elessair 0:f269e3021894 210
elessair 0:f269e3021894 211 const ip_addr_t *mbed_lwip_get_ip_addr(bool any_addr, const struct netif *netif)
elessair 0:f269e3021894 212 {
elessair 0:f269e3021894 213 const ip_addr_t *pref_ip_addr = 0;
elessair 0:f269e3021894 214 const ip_addr_t *npref_ip_addr = 0;
elessair 0:f269e3021894 215
elessair 0:f269e3021894 216 #if IP_VERSION_PREF == PREF_IPV4
elessair 0:f269e3021894 217 pref_ip_addr = mbed_lwip_get_ipv4_addr(netif);
elessair 0:f269e3021894 218 npref_ip_addr = mbed_lwip_get_ipv6_addr(netif);
elessair 0:f269e3021894 219 #else
elessair 0:f269e3021894 220 pref_ip_addr = mbed_lwip_get_ipv6_addr(netif);
elessair 0:f269e3021894 221 npref_ip_addr = mbed_lwip_get_ipv4_addr(netif);
elessair 0:f269e3021894 222 #endif
elessair 0:f269e3021894 223
elessair 0:f269e3021894 224 if (pref_ip_addr) {
elessair 0:f269e3021894 225 return pref_ip_addr;
elessair 0:f269e3021894 226 } else if (npref_ip_addr && any_addr) {
elessair 0:f269e3021894 227 return npref_ip_addr;
elessair 0:f269e3021894 228 }
elessair 0:f269e3021894 229
elessair 0:f269e3021894 230 return NULL;
elessair 0:f269e3021894 231 }
elessair 0:f269e3021894 232
elessair 0:f269e3021894 233 #if LWIP_IPV6
elessair 0:f269e3021894 234 void add_dns_addr(struct netif *lwip_netif)
elessair 0:f269e3021894 235 {
elessair 0:f269e3021894 236 const ip_addr_t *ip_addr = mbed_lwip_get_ip_addr(true, lwip_netif);
elessair 0:f269e3021894 237 if (ip_addr) {
elessair 0:f269e3021894 238 if (IP_IS_V6(ip_addr)) {
elessair 0:f269e3021894 239 const ip_addr_t *dns_ip_addr;
elessair 0:f269e3021894 240 bool dns_addr_exists = false;
elessair 0:f269e3021894 241
elessair 0:f269e3021894 242 for (char numdns = 0; numdns < DNS_MAX_SERVERS; numdns++) {
elessair 0:f269e3021894 243 dns_ip_addr = dns_getserver(numdns);
elessair 0:f269e3021894 244 if (!ip_addr_isany(dns_ip_addr)) {
elessair 0:f269e3021894 245 dns_addr_exists = true;
elessair 0:f269e3021894 246 break;
elessair 0:f269e3021894 247 }
elessair 0:f269e3021894 248 }
elessair 0:f269e3021894 249
elessair 0:f269e3021894 250 if (!dns_addr_exists) {
elessair 0:f269e3021894 251 /* 2001:4860:4860::8888 google */
elessair 0:f269e3021894 252 ip_addr_t ipv6_dns_addr = IPADDR6_INIT(
elessair 0:f269e3021894 253 PP_HTONL(0x20014860UL),
elessair 0:f269e3021894 254 PP_HTONL(0x48600000UL),
elessair 0:f269e3021894 255 PP_HTONL(0x00000000UL),
elessair 0:f269e3021894 256 PP_HTONL(0x00008888UL));
elessair 0:f269e3021894 257 dns_setserver(0, &ipv6_dns_addr);
elessair 0:f269e3021894 258 }
elessair 0:f269e3021894 259 }
elessair 0:f269e3021894 260 }
elessair 0:f269e3021894 261 }
elessair 0:f269e3021894 262 #endif
elessair 0:f269e3021894 263
elessair 0:f269e3021894 264 static sys_sem_t lwip_tcpip_inited;
elessair 0:f269e3021894 265 static void mbed_lwip_tcpip_init_irq(void *eh)
elessair 0:f269e3021894 266 {
elessair 0:f269e3021894 267 sys_sem_signal(&lwip_tcpip_inited);
elessair 0:f269e3021894 268 }
elessair 0:f269e3021894 269
elessair 0:f269e3021894 270 static sys_sem_t lwip_netif_linked;
elessair 0:f269e3021894 271 static void mbed_lwip_netif_link_irq(struct netif *lwip_netif)
elessair 0:f269e3021894 272 {
elessair 0:f269e3021894 273 if (netif_is_link_up(lwip_netif)) {
elessair 0:f269e3021894 274 sys_sem_signal(&lwip_netif_linked);
elessair 0:f269e3021894 275 }
elessair 0:f269e3021894 276 }
elessair 0:f269e3021894 277
elessair 0:f269e3021894 278 static sys_sem_t lwip_netif_has_addr;
elessair 0:f269e3021894 279 static void mbed_lwip_netif_status_irq(struct netif *lwip_netif)
elessair 0:f269e3021894 280 {
elessair 0:f269e3021894 281 static bool any_addr = true;
elessair 0:f269e3021894 282
elessair 0:f269e3021894 283 // Indicates that has address
elessair 0:f269e3021894 284 if (any_addr == true && mbed_lwip_get_ip_addr(true, lwip_netif)) {
elessair 0:f269e3021894 285 sys_sem_signal(&lwip_netif_has_addr);
elessair 0:f269e3021894 286 any_addr = false;
elessair 0:f269e3021894 287 return;
elessair 0:f269e3021894 288 }
elessair 0:f269e3021894 289
elessair 0:f269e3021894 290 // Indicates that has preferred address
elessair 0:f269e3021894 291 if (mbed_lwip_get_ip_addr(false, lwip_netif)) {
elessair 0:f269e3021894 292 sys_sem_signal(&lwip_netif_has_addr);
elessair 0:f269e3021894 293 }
elessair 0:f269e3021894 294 }
elessair 0:f269e3021894 295
elessair 0:f269e3021894 296 static void mbed_lwip_set_mac_address(void)
elessair 0:f269e3021894 297 {
elessair 0:f269e3021894 298 #if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
elessair 0:f269e3021894 299 snprintf(lwip_mac_address, 19, "%02x:%02x:%02x:%02x:%02x:%02x",
elessair 0:f269e3021894 300 MBED_MAC_ADDR_0, MBED_MAC_ADDR_1, MBED_MAC_ADDR_2,
elessair 0:f269e3021894 301 MBED_MAC_ADDR_3, MBED_MAC_ADDR_4, MBED_MAC_ADDR_5);
elessair 0:f269e3021894 302 #else
elessair 0:f269e3021894 303 char mac[6];
elessair 0:f269e3021894 304 mbed_mac_address(mac);
elessair 0:f269e3021894 305 snprintf(lwip_mac_address, 19, "%02x:%02x:%02x:%02x:%02x:%02x",
elessair 0:f269e3021894 306 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
elessair 0:f269e3021894 307 #endif
elessair 0:f269e3021894 308 }
elessair 0:f269e3021894 309
elessair 0:f269e3021894 310 /* LWIP interface implementation */
elessair 0:f269e3021894 311 const char *mbed_lwip_get_mac_address(void)
elessair 0:f269e3021894 312 {
elessair 0:f269e3021894 313 return lwip_mac_address[0] ? lwip_mac_address : 0;
elessair 0:f269e3021894 314 }
elessair 0:f269e3021894 315
elessair 0:f269e3021894 316 char *mbed_lwip_get_ip_address(char *buf, int buflen)
elessair 0:f269e3021894 317 {
elessair 0:f269e3021894 318 const ip_addr_t *addr = mbed_lwip_get_ip_addr(true, &lwip_netif);
elessair 0:f269e3021894 319 if (!addr) {
elessair 0:f269e3021894 320 return NULL;
elessair 0:f269e3021894 321 }
elessair 0:f269e3021894 322 #if LWIP_IPV6
elessair 0:f269e3021894 323 if (IP_IS_V6(addr)) {
elessair 0:f269e3021894 324 return ip6addr_ntoa_r(ip_2_ip6(addr), buf, buflen);
elessair 0:f269e3021894 325 }
elessair 0:f269e3021894 326 #endif
elessair 0:f269e3021894 327 #if LWIP_IPV4
elessair 0:f269e3021894 328 if (IP_IS_V4(addr)) {
elessair 0:f269e3021894 329 return ip4addr_ntoa_r(ip_2_ip4(addr), buf, buflen);
elessair 0:f269e3021894 330 }
elessair 0:f269e3021894 331 #endif
elessair 0:f269e3021894 332 return NULL;
elessair 0:f269e3021894 333 }
elessair 0:f269e3021894 334
elessair 0:f269e3021894 335 const char *mbed_lwip_get_netmask(char *buf, int buflen)
elessair 0:f269e3021894 336 {
elessair 0:f269e3021894 337 #if LWIP_IPV4
elessair 0:f269e3021894 338 const ip4_addr_t *addr = netif_ip4_netmask(&lwip_netif);
elessair 0:f269e3021894 339 if (!ip4_addr_isany(addr)) {
elessair 0:f269e3021894 340 return ip4addr_ntoa_r(addr, buf, buflen);
elessair 0:f269e3021894 341 } else {
elessair 0:f269e3021894 342 return NULL;
elessair 0:f269e3021894 343 }
elessair 0:f269e3021894 344 #else
elessair 0:f269e3021894 345 return NULL;
elessair 0:f269e3021894 346 #endif
elessair 0:f269e3021894 347 }
elessair 0:f269e3021894 348
elessair 0:f269e3021894 349 char *mbed_lwip_get_gateway(char *buf, int buflen)
elessair 0:f269e3021894 350 {
elessair 0:f269e3021894 351 #if LWIP_IPV4
elessair 0:f269e3021894 352 const ip4_addr_t *addr = netif_ip4_gw(&lwip_netif);
elessair 0:f269e3021894 353 if (!ip4_addr_isany(addr)) {
elessair 0:f269e3021894 354 return ip4addr_ntoa_r(addr, buf, buflen);
elessair 0:f269e3021894 355 } else {
elessair 0:f269e3021894 356 return NULL;
elessair 0:f269e3021894 357 }
elessair 0:f269e3021894 358 #else
elessair 0:f269e3021894 359 return NULL;
elessair 0:f269e3021894 360 #endif
elessair 0:f269e3021894 361 }
elessair 0:f269e3021894 362
elessair 0:f269e3021894 363 int mbed_lwip_init(emac_interface_t *emac)
elessair 0:f269e3021894 364 {
elessair 0:f269e3021894 365 // Check if we've already brought up lwip
elessair 0:f269e3021894 366 if (!mbed_lwip_get_mac_address()) {
elessair 0:f269e3021894 367 // Set up network
elessair 0:f269e3021894 368 mbed_lwip_set_mac_address();
elessair 0:f269e3021894 369
elessair 0:f269e3021894 370 sys_sem_new(&lwip_tcpip_inited, 0);
elessair 0:f269e3021894 371 sys_sem_new(&lwip_netif_linked, 0);
elessair 0:f269e3021894 372 sys_sem_new(&lwip_netif_has_addr, 0);
elessair 0:f269e3021894 373
elessair 0:f269e3021894 374 tcpip_init(mbed_lwip_tcpip_init_irq, NULL);
elessair 0:f269e3021894 375 sys_arch_sem_wait(&lwip_tcpip_inited, 0);
elessair 0:f269e3021894 376
elessair 0:f269e3021894 377 memset(&lwip_netif, 0, sizeof lwip_netif);
elessair 0:f269e3021894 378 if (!netif_add(&lwip_netif,
elessair 0:f269e3021894 379 #if LWIP_IPV4
elessair 0:f269e3021894 380 0, 0, 0,
elessair 0:f269e3021894 381 #endif
elessair 0:f269e3021894 382 emac, MBED_NETIF_INIT_FN, tcpip_input)) {
elessair 0:f269e3021894 383 return NSAPI_ERROR_DEVICE_ERROR;
elessair 0:f269e3021894 384 }
elessair 0:f269e3021894 385
elessair 0:f269e3021894 386 netif_set_default(&lwip_netif);
elessair 0:f269e3021894 387
elessair 0:f269e3021894 388 netif_set_link_callback(&lwip_netif, mbed_lwip_netif_link_irq);
elessair 0:f269e3021894 389 netif_set_status_callback(&lwip_netif, mbed_lwip_netif_status_irq);
elessair 0:f269e3021894 390
elessair 0:f269e3021894 391 #if !DEVICE_EMAC
elessair 0:f269e3021894 392 eth_arch_enable_interrupts();
elessair 0:f269e3021894 393 #endif
elessair 0:f269e3021894 394 }
elessair 0:f269e3021894 395
elessair 0:f269e3021894 396 return NSAPI_ERROR_OK;
elessair 0:f269e3021894 397 }
elessair 0:f269e3021894 398
elessair 0:f269e3021894 399 int mbed_lwip_bringup(bool dhcp, const char *ip, const char *netmask, const char *gw)
elessair 0:f269e3021894 400 {
elessair 0:f269e3021894 401 // Check if we've already connected
elessair 0:f269e3021894 402 if (lwip_connected) {
elessair 0:f269e3021894 403 return NSAPI_ERROR_PARAMETER;
elessair 0:f269e3021894 404 }
elessair 0:f269e3021894 405
elessair 0:f269e3021894 406 if(mbed_lwip_init(NULL) != NSAPI_ERROR_OK) {
elessair 0:f269e3021894 407 return NSAPI_ERROR_DEVICE_ERROR;
elessair 0:f269e3021894 408 }
elessair 0:f269e3021894 409
elessair 0:f269e3021894 410 // Zero out socket set
elessair 0:f269e3021894 411 mbed_lwip_arena_init();
elessair 0:f269e3021894 412
elessair 0:f269e3021894 413 #if LWIP_IPV6
elessair 0:f269e3021894 414 netif_create_ip6_linklocal_address(&lwip_netif, 1/*from MAC*/);
elessair 0:f269e3021894 415 #if LWIP_IPV6_MLD
elessair 0:f269e3021894 416 /*
elessair 0:f269e3021894 417 * For hardware/netifs that implement MAC filtering.
elessair 0:f269e3021894 418 * All-nodes link-local is handled by default, so we must let the hardware know
elessair 0:f269e3021894 419 * to allow multicast packets in.
elessair 0:f269e3021894 420 * Should set mld_mac_filter previously. */
elessair 0:f269e3021894 421 if (lwip_netif.mld_mac_filter != NULL) {
elessair 0:f269e3021894 422 ip6_addr_t ip6_allnodes_ll;
elessair 0:f269e3021894 423 ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll);
elessair 0:f269e3021894 424 lwip_netif.mld_mac_filter(&lwip_netif, &ip6_allnodes_ll, MLD6_ADD_MAC_FILTER);
elessair 0:f269e3021894 425 }
elessair 0:f269e3021894 426 #endif /* LWIP_IPV6_MLD */
elessair 0:f269e3021894 427
elessair 0:f269e3021894 428 #if LWIP_IPV6_AUTOCONFIG
elessair 0:f269e3021894 429 /* IPv6 address autoconfiguration not enabled by default */
elessair 0:f269e3021894 430 lwip_netif.ip6_autoconfig_enabled = 1;
elessair 0:f269e3021894 431 #endif /* LWIP_IPV6_AUTOCONFIG */
elessair 0:f269e3021894 432
elessair 0:f269e3021894 433 #endif
elessair 0:f269e3021894 434
elessair 0:f269e3021894 435 u32_t ret;
elessair 0:f269e3021894 436
elessair 0:f269e3021894 437 if (!netif_is_link_up(&lwip_netif)) {
elessair 0:f269e3021894 438 ret = sys_arch_sem_wait(&lwip_netif_linked, 15000);
elessair 0:f269e3021894 439
elessair 0:f269e3021894 440 if (ret == SYS_ARCH_TIMEOUT) {
elessair 0:f269e3021894 441 return NSAPI_ERROR_NO_CONNECTION;
elessair 0:f269e3021894 442 }
elessair 0:f269e3021894 443 }
elessair 0:f269e3021894 444
elessair 0:f269e3021894 445 #if LWIP_IPV4
elessair 0:f269e3021894 446 if (!dhcp) {
elessair 0:f269e3021894 447 ip4_addr_t ip_addr;
elessair 0:f269e3021894 448 ip4_addr_t netmask_addr;
elessair 0:f269e3021894 449 ip4_addr_t gw_addr;
elessair 0:f269e3021894 450
elessair 0:f269e3021894 451 if (!inet_aton(ip, &ip_addr) ||
elessair 0:f269e3021894 452 !inet_aton(netmask, &netmask_addr) ||
elessair 0:f269e3021894 453 !inet_aton(gw, &gw_addr)) {
elessair 0:f269e3021894 454 return NSAPI_ERROR_PARAMETER;
elessair 0:f269e3021894 455 }
elessair 0:f269e3021894 456
elessair 0:f269e3021894 457 netif_set_addr(&lwip_netif, &ip_addr, &netmask_addr, &gw_addr);
elessair 0:f269e3021894 458 }
elessair 0:f269e3021894 459 #endif
elessair 0:f269e3021894 460
elessair 0:f269e3021894 461 netif_set_up(&lwip_netif);
elessair 0:f269e3021894 462
elessair 0:f269e3021894 463 #if LWIP_IPV4
elessair 0:f269e3021894 464 // Connect to the network
elessair 0:f269e3021894 465 lwip_dhcp = dhcp;
elessair 0:f269e3021894 466
elessair 0:f269e3021894 467 if (lwip_dhcp) {
elessair 0:f269e3021894 468 err_t err = dhcp_start(&lwip_netif);
elessair 0:f269e3021894 469 if (err) {
elessair 0:f269e3021894 470 return NSAPI_ERROR_DHCP_FAILURE;
elessair 0:f269e3021894 471 }
elessair 0:f269e3021894 472 }
elessair 0:f269e3021894 473 #endif
elessair 0:f269e3021894 474
elessair 0:f269e3021894 475 // If doesn't have address
elessair 0:f269e3021894 476 if (!mbed_lwip_get_ip_addr(true, &lwip_netif)) {
elessair 0:f269e3021894 477 ret = sys_arch_sem_wait(&lwip_netif_has_addr, 15000);
elessair 0:f269e3021894 478 if (ret == SYS_ARCH_TIMEOUT) {
elessair 0:f269e3021894 479 return NSAPI_ERROR_DHCP_FAILURE;
elessair 0:f269e3021894 480 }
elessair 0:f269e3021894 481 lwip_connected = true;
elessair 0:f269e3021894 482 }
elessair 0:f269e3021894 483
elessair 0:f269e3021894 484 #if ADDR_TIMEOUT
elessair 0:f269e3021894 485 // If address is not for preferred stack waits a while to see
elessair 0:f269e3021894 486 // if preferred stack address is acquired
elessair 0:f269e3021894 487 if (!mbed_lwip_get_ip_addr(false, &lwip_netif)) {
elessair 0:f269e3021894 488 ret = sys_arch_sem_wait(&lwip_netif_has_addr, ADDR_TIMEOUT * 1000);
elessair 0:f269e3021894 489 }
elessair 0:f269e3021894 490 #endif
elessair 0:f269e3021894 491
elessair 0:f269e3021894 492 #if LWIP_IPV6
elessair 0:f269e3021894 493 add_dns_addr(&lwip_netif);
elessair 0:f269e3021894 494 #endif
elessair 0:f269e3021894 495
elessair 0:f269e3021894 496 return 0;
elessair 0:f269e3021894 497 }
elessair 0:f269e3021894 498
elessair 0:f269e3021894 499 int mbed_lwip_bringdown(void)
elessair 0:f269e3021894 500 {
elessair 0:f269e3021894 501 // Check if we've connected
elessair 0:f269e3021894 502 if (!lwip_connected) {
elessair 0:f269e3021894 503 return NSAPI_ERROR_PARAMETER;
elessair 0:f269e3021894 504 }
elessair 0:f269e3021894 505
elessair 0:f269e3021894 506 #if LWIP_IPV4
elessair 0:f269e3021894 507 // Disconnect from the network
elessair 0:f269e3021894 508 if (lwip_dhcp) {
elessair 0:f269e3021894 509 dhcp_release(&lwip_netif);
elessair 0:f269e3021894 510 dhcp_stop(&lwip_netif);
elessair 0:f269e3021894 511 lwip_dhcp = false;
elessair 0:f269e3021894 512 } else {
elessair 0:f269e3021894 513 netif_set_down(&lwip_netif);
elessair 0:f269e3021894 514 }
elessair 0:f269e3021894 515 #endif
elessair 0:f269e3021894 516
elessair 0:f269e3021894 517 lwip_connected = false;
elessair 0:f269e3021894 518 // TO DO - actually remove addresses from stack, and shut down properly
elessair 0:f269e3021894 519 return 0;
elessair 0:f269e3021894 520 }
elessair 0:f269e3021894 521
elessair 0:f269e3021894 522 /* LWIP error remapping */
elessair 0:f269e3021894 523 static int mbed_lwip_err_remap(err_t err) {
elessair 0:f269e3021894 524 switch (err) {
elessair 0:f269e3021894 525 case ERR_OK:
elessair 0:f269e3021894 526 case ERR_CLSD:
elessair 0:f269e3021894 527 case ERR_RST:
elessair 0:f269e3021894 528 return 0;
elessair 0:f269e3021894 529 case ERR_MEM:
elessair 0:f269e3021894 530 return NSAPI_ERROR_NO_MEMORY;
elessair 0:f269e3021894 531 case ERR_CONN:
elessair 0:f269e3021894 532 return NSAPI_ERROR_NO_CONNECTION;
elessair 0:f269e3021894 533 case ERR_TIMEOUT:
elessair 0:f269e3021894 534 case ERR_RTE:
elessair 0:f269e3021894 535 case ERR_INPROGRESS:
elessair 0:f269e3021894 536 case ERR_WOULDBLOCK:
elessair 0:f269e3021894 537 return NSAPI_ERROR_WOULD_BLOCK;
elessair 0:f269e3021894 538 case ERR_VAL:
elessair 0:f269e3021894 539 case ERR_USE:
elessair 0:f269e3021894 540 case ERR_ISCONN:
elessair 0:f269e3021894 541 case ERR_ARG:
elessair 0:f269e3021894 542 return NSAPI_ERROR_PARAMETER;
elessair 0:f269e3021894 543 default:
elessair 0:f269e3021894 544 return NSAPI_ERROR_DEVICE_ERROR;
elessair 0:f269e3021894 545 }
elessair 0:f269e3021894 546 }
elessair 0:f269e3021894 547
elessair 0:f269e3021894 548 /* LWIP network stack implementation */
elessair 0:f269e3021894 549 static int mbed_lwip_gethostbyname(nsapi_stack_t *stack, const char *host, nsapi_addr_t *addr, nsapi_version_t version)
elessair 0:f269e3021894 550 {
elessair 0:f269e3021894 551 ip_addr_t lwip_addr;
elessair 0:f269e3021894 552
elessair 0:f269e3021894 553 #if LWIP_IPV4 && LWIP_IPV6
elessair 0:f269e3021894 554 u8_t addr_type;
elessair 0:f269e3021894 555 if (version == NSAPI_UNSPEC) {
elessair 0:f269e3021894 556 const ip_addr_t *ip_addr;
elessair 0:f269e3021894 557 ip_addr = mbed_lwip_get_ip_addr(true, &lwip_netif);
elessair 0:f269e3021894 558 if (IP_IS_V6(ip_addr)) {
elessair 0:f269e3021894 559 addr_type = NETCONN_DNS_IPV6;
elessair 0:f269e3021894 560 } else {
elessair 0:f269e3021894 561 addr_type = NETCONN_DNS_IPV4;
elessair 0:f269e3021894 562 }
elessair 0:f269e3021894 563 } else if (version == NSAPI_IPv4) {
elessair 0:f269e3021894 564 addr_type = NETCONN_DNS_IPV4;
elessair 0:f269e3021894 565 } else if (version == NSAPI_IPv6) {
elessair 0:f269e3021894 566 addr_type = NETCONN_DNS_IPV6;
elessair 0:f269e3021894 567 }
elessair 0:f269e3021894 568 err_t err = netconn_gethostbyname_addrtype(host, &lwip_addr, addr_type);
elessair 0:f269e3021894 569 #elif LWIP_IPV4
elessair 0:f269e3021894 570 if (version != NSAPI_IPv4 && version != NSAPI_UNSPEC) {
elessair 0:f269e3021894 571 return NSAPI_ERROR_DNS_FAILURE;
elessair 0:f269e3021894 572 }
elessair 0:f269e3021894 573 err_t err = netconn_gethostbyname(host, &lwip_addr);
elessair 0:f269e3021894 574 #elif LWIP_IPV6
elessair 0:f269e3021894 575 if (version != NSAPI_IPv6 && version != NSAPI_UNSPEC) {
elessair 0:f269e3021894 576 return NSAPI_ERROR_DNS_FAILURE;
elessair 0:f269e3021894 577 }
elessair 0:f269e3021894 578 err_t err = netconn_gethostbyname(host, &lwip_addr);
elessair 0:f269e3021894 579 #endif
elessair 0:f269e3021894 580
elessair 0:f269e3021894 581 if (err != ERR_OK) {
elessair 0:f269e3021894 582 return NSAPI_ERROR_DNS_FAILURE;
elessair 0:f269e3021894 583 }
elessair 0:f269e3021894 584
elessair 0:f269e3021894 585 convert_lwip_addr_to_mbed(addr, &lwip_addr);
elessair 0:f269e3021894 586
elessair 0:f269e3021894 587 return 0;
elessair 0:f269e3021894 588 }
elessair 0:f269e3021894 589
elessair 0:f269e3021894 590 static int mbed_lwip_socket_open(nsapi_stack_t *stack, nsapi_socket_t *handle, nsapi_protocol_t proto)
elessair 0:f269e3021894 591 {
elessair 0:f269e3021894 592 // check if network is connected
elessair 0:f269e3021894 593 if (!lwip_connected) {
elessair 0:f269e3021894 594 return NSAPI_ERROR_NO_CONNECTION;
elessair 0:f269e3021894 595 }
elessair 0:f269e3021894 596
elessair 0:f269e3021894 597 // allocate a socket
elessair 0:f269e3021894 598 struct lwip_socket *s = mbed_lwip_arena_alloc();
elessair 0:f269e3021894 599 if (!s) {
elessair 0:f269e3021894 600 return NSAPI_ERROR_NO_SOCKET;
elessair 0:f269e3021894 601 }
elessair 0:f269e3021894 602
elessair 0:f269e3021894 603 u8_t lwip_proto = proto == NSAPI_TCP ? NETCONN_TCP : NETCONN_UDP;
elessair 0:f269e3021894 604
elessair 0:f269e3021894 605 #if LWIP_IPV6 && LWIP_IPV4
elessair 0:f269e3021894 606 const ip_addr_t *ip_addr;
elessair 0:f269e3021894 607 ip_addr = mbed_lwip_get_ip_addr(true, &lwip_netif);
elessair 0:f269e3021894 608
elessair 0:f269e3021894 609 if (IP_IS_V6(ip_addr)) {
elessair 0:f269e3021894 610 // Enable IPv6 (or dual-stack). LWIP dual-stack support is
elessair 0:f269e3021894 611 // currently incomplete as of 2.0.0rc2 - eg we will only be able
elessair 0:f269e3021894 612 // to do a UDP sendto to an address matching the type selected
elessair 0:f269e3021894 613 // here. Matching "get_ip_addr" and DNS logic, use v4 if
elessair 0:f269e3021894 614 // available.
elessair 0:f269e3021894 615 lwip_proto |= NETCONN_TYPE_IPV6;
elessair 0:f269e3021894 616 }
elessair 0:f269e3021894 617 #elif LWIP_IPV6
elessair 0:f269e3021894 618 lwip_proto |= NETCONN_TYPE_IPV6;
elessair 0:f269e3021894 619 #endif
elessair 0:f269e3021894 620
elessair 0:f269e3021894 621 s->conn = netconn_new_with_callback(lwip_proto, mbed_lwip_socket_callback);
elessair 0:f269e3021894 622
elessair 0:f269e3021894 623 if (!s->conn) {
elessair 0:f269e3021894 624 mbed_lwip_arena_dealloc(s);
elessair 0:f269e3021894 625 return NSAPI_ERROR_NO_SOCKET;
elessair 0:f269e3021894 626 }
elessair 0:f269e3021894 627
elessair 0:f269e3021894 628 netconn_set_recvtimeout(s->conn, 1);
elessair 0:f269e3021894 629 *(struct lwip_socket **)handle = s;
elessair 0:f269e3021894 630 return 0;
elessair 0:f269e3021894 631 }
elessair 0:f269e3021894 632
elessair 0:f269e3021894 633 static int mbed_lwip_socket_close(nsapi_stack_t *stack, nsapi_socket_t handle)
elessair 0:f269e3021894 634 {
elessair 0:f269e3021894 635 struct lwip_socket *s = (struct lwip_socket *)handle;
elessair 0:f269e3021894 636
elessair 0:f269e3021894 637 err_t err = netconn_delete(s->conn);
elessair 0:f269e3021894 638 mbed_lwip_arena_dealloc(s);
elessair 0:f269e3021894 639 return mbed_lwip_err_remap(err);
elessair 0:f269e3021894 640 }
elessair 0:f269e3021894 641
elessair 0:f269e3021894 642 static int mbed_lwip_socket_bind(nsapi_stack_t *stack, nsapi_socket_t handle, nsapi_addr_t addr, uint16_t port)
elessair 0:f269e3021894 643 {
elessair 0:f269e3021894 644 struct lwip_socket *s = (struct lwip_socket *)handle;
elessair 0:f269e3021894 645 ip_addr_t ip_addr;
elessair 0:f269e3021894 646
elessair 0:f269e3021894 647 if ((s->conn->type == NETCONN_TCP && s->conn->pcb.tcp->local_port != 0) ||
elessair 0:f269e3021894 648 (s->conn->type == NETCONN_UDP && s->conn->pcb.udp->local_port != 0)) {
elessair 0:f269e3021894 649 return NSAPI_ERROR_PARAMETER;
elessair 0:f269e3021894 650 }
elessair 0:f269e3021894 651
elessair 0:f269e3021894 652 if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
elessair 0:f269e3021894 653 return NSAPI_ERROR_PARAMETER;
elessair 0:f269e3021894 654 }
elessair 0:f269e3021894 655
elessair 0:f269e3021894 656 err_t err = netconn_bind(s->conn, &ip_addr, port);
elessair 0:f269e3021894 657 return mbed_lwip_err_remap(err);
elessair 0:f269e3021894 658 }
elessair 0:f269e3021894 659
elessair 0:f269e3021894 660 static int mbed_lwip_socket_listen(nsapi_stack_t *stack, nsapi_socket_t handle, int backlog)
elessair 0:f269e3021894 661 {
elessair 0:f269e3021894 662 struct lwip_socket *s = (struct lwip_socket *)handle;
elessair 0:f269e3021894 663
elessair 0:f269e3021894 664 err_t err = netconn_listen_with_backlog(s->conn, backlog);
elessair 0:f269e3021894 665 return mbed_lwip_err_remap(err);
elessair 0:f269e3021894 666 }
elessair 0:f269e3021894 667
elessair 0:f269e3021894 668 static int mbed_lwip_socket_connect(nsapi_stack_t *stack, nsapi_socket_t handle, nsapi_addr_t addr, uint16_t port)
elessair 0:f269e3021894 669 {
elessair 0:f269e3021894 670 struct lwip_socket *s = (struct lwip_socket *)handle;
elessair 0:f269e3021894 671 ip_addr_t ip_addr;
elessair 0:f269e3021894 672
elessair 0:f269e3021894 673 if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
elessair 0:f269e3021894 674 return NSAPI_ERROR_PARAMETER;
elessair 0:f269e3021894 675 }
elessair 0:f269e3021894 676
elessair 0:f269e3021894 677 netconn_set_nonblocking(s->conn, false);
elessair 0:f269e3021894 678 err_t err = netconn_connect(s->conn, &ip_addr, port);
elessair 0:f269e3021894 679 netconn_set_nonblocking(s->conn, true);
elessair 0:f269e3021894 680
elessair 0:f269e3021894 681 return mbed_lwip_err_remap(err);
elessair 0:f269e3021894 682 }
elessair 0:f269e3021894 683
elessair 0:f269e3021894 684 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)
elessair 0:f269e3021894 685 {
elessair 0:f269e3021894 686 struct lwip_socket *s = (struct lwip_socket *)server;
elessair 0:f269e3021894 687 struct lwip_socket *ns = mbed_lwip_arena_alloc();
elessair 0:f269e3021894 688 if (!ns) {
elessair 0:f269e3021894 689 return NSAPI_ERROR_NO_SOCKET;
elessair 0:f269e3021894 690 }
elessair 0:f269e3021894 691
elessair 0:f269e3021894 692 err_t err = netconn_accept(s->conn, &ns->conn);
elessair 0:f269e3021894 693 if (err != ERR_OK) {
elessair 0:f269e3021894 694 mbed_lwip_arena_dealloc(ns);
elessair 0:f269e3021894 695 return mbed_lwip_err_remap(err);
elessair 0:f269e3021894 696 }
elessair 0:f269e3021894 697
elessair 0:f269e3021894 698 netconn_set_recvtimeout(ns->conn, 1);
elessair 0:f269e3021894 699 *(struct lwip_socket **)handle = ns;
elessair 0:f269e3021894 700
elessair 0:f269e3021894 701 ip_addr_t peer_addr;
elessair 0:f269e3021894 702 (void) netconn_peer(ns->conn, &peer_addr, port);
elessair 0:f269e3021894 703 convert_lwip_addr_to_mbed(addr, &peer_addr);
elessair 0:f269e3021894 704
elessair 0:f269e3021894 705 return 0;
elessair 0:f269e3021894 706 }
elessair 0:f269e3021894 707
elessair 0:f269e3021894 708 static int mbed_lwip_socket_send(nsapi_stack_t *stack, nsapi_socket_t handle, const void *data, unsigned size)
elessair 0:f269e3021894 709 {
elessair 0:f269e3021894 710 struct lwip_socket *s = (struct lwip_socket *)handle;
elessair 0:f269e3021894 711 size_t bytes_written = 0;
elessair 0:f269e3021894 712
elessair 0:f269e3021894 713 err_t err = netconn_write_partly(s->conn, data, size, NETCONN_COPY, &bytes_written);
elessair 0:f269e3021894 714 if (err != ERR_OK) {
elessair 0:f269e3021894 715 return mbed_lwip_err_remap(err);
elessair 0:f269e3021894 716 }
elessair 0:f269e3021894 717
elessair 0:f269e3021894 718 return (int)bytes_written;
elessair 0:f269e3021894 719 }
elessair 0:f269e3021894 720
elessair 0:f269e3021894 721 static int mbed_lwip_socket_recv(nsapi_stack_t *stack, nsapi_socket_t handle, void *data, unsigned size)
elessair 0:f269e3021894 722 {
elessair 0:f269e3021894 723 struct lwip_socket *s = (struct lwip_socket *)handle;
elessair 0:f269e3021894 724
elessair 0:f269e3021894 725 if (!s->buf) {
elessair 0:f269e3021894 726 err_t err = netconn_recv(s->conn, &s->buf);
elessair 0:f269e3021894 727 s->offset = 0;
elessair 0:f269e3021894 728
elessair 0:f269e3021894 729 if (err != ERR_OK) {
elessair 0:f269e3021894 730 return mbed_lwip_err_remap(err);
elessair 0:f269e3021894 731 }
elessair 0:f269e3021894 732 }
elessair 0:f269e3021894 733
elessair 0:f269e3021894 734 u16_t recv = netbuf_copy_partial(s->buf, data, (u16_t)size, s->offset);
elessair 0:f269e3021894 735 s->offset += recv;
elessair 0:f269e3021894 736
elessair 0:f269e3021894 737 if (s->offset >= netbuf_len(s->buf)) {
elessair 0:f269e3021894 738 netbuf_delete(s->buf);
elessair 0:f269e3021894 739 s->buf = 0;
elessair 0:f269e3021894 740 }
elessair 0:f269e3021894 741
elessair 0:f269e3021894 742 return recv;
elessair 0:f269e3021894 743 }
elessair 0:f269e3021894 744
elessair 0:f269e3021894 745 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)
elessair 0:f269e3021894 746 {
elessair 0:f269e3021894 747 struct lwip_socket *s = (struct lwip_socket *)handle;
elessair 0:f269e3021894 748 ip_addr_t ip_addr;
elessair 0:f269e3021894 749
elessair 0:f269e3021894 750 if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
elessair 0:f269e3021894 751 return NSAPI_ERROR_PARAMETER;
elessair 0:f269e3021894 752 }
elessair 0:f269e3021894 753
elessair 0:f269e3021894 754 struct netbuf *buf = netbuf_new();
elessair 0:f269e3021894 755 err_t err = netbuf_ref(buf, data, (u16_t)size);
elessair 0:f269e3021894 756 if (err != ERR_OK) {
elessair 0:f269e3021894 757 netbuf_free(buf);
elessair 0:f269e3021894 758 return mbed_lwip_err_remap(err);
elessair 0:f269e3021894 759 }
elessair 0:f269e3021894 760
elessair 0:f269e3021894 761 err = netconn_sendto(s->conn, buf, &ip_addr, port);
elessair 0:f269e3021894 762 netbuf_delete(buf);
elessair 0:f269e3021894 763 if (err != ERR_OK) {
elessair 0:f269e3021894 764 return mbed_lwip_err_remap(err);
elessair 0:f269e3021894 765 }
elessair 0:f269e3021894 766
elessair 0:f269e3021894 767 return size;
elessair 0:f269e3021894 768 }
elessair 0:f269e3021894 769
elessair 0:f269e3021894 770 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)
elessair 0:f269e3021894 771 {
elessair 0:f269e3021894 772 struct lwip_socket *s = (struct lwip_socket *)handle;
elessair 0:f269e3021894 773 struct netbuf *buf;
elessair 0:f269e3021894 774
elessair 0:f269e3021894 775 err_t err = netconn_recv(s->conn, &buf);
elessair 0:f269e3021894 776 if (err != ERR_OK) {
elessair 0:f269e3021894 777 return mbed_lwip_err_remap(err);
elessair 0:f269e3021894 778 }
elessair 0:f269e3021894 779
elessair 0:f269e3021894 780 convert_lwip_addr_to_mbed(addr, netbuf_fromaddr(buf));
elessair 0:f269e3021894 781 *port = netbuf_fromport(buf);
elessair 0:f269e3021894 782
elessair 0:f269e3021894 783 u16_t recv = netbuf_copy(buf, data, (u16_t)size);
elessair 0:f269e3021894 784 netbuf_delete(buf);
elessair 0:f269e3021894 785
elessair 0:f269e3021894 786 return recv;
elessair 0:f269e3021894 787 }
elessair 0:f269e3021894 788
elessair 0:f269e3021894 789 static int mbed_lwip_setsockopt(nsapi_stack_t *stack, nsapi_socket_t handle, int level, int optname, const void *optval, unsigned optlen)
elessair 0:f269e3021894 790 {
elessair 0:f269e3021894 791 struct lwip_socket *s = (struct lwip_socket *)handle;
elessair 0:f269e3021894 792
elessair 0:f269e3021894 793 switch (optname) {
elessair 0:f269e3021894 794 case NSAPI_KEEPALIVE:
elessair 0:f269e3021894 795 if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) {
elessair 0:f269e3021894 796 return NSAPI_ERROR_UNSUPPORTED;
elessair 0:f269e3021894 797 }
elessair 0:f269e3021894 798
elessair 0:f269e3021894 799 s->conn->pcb.tcp->so_options |= SOF_KEEPALIVE;
elessair 0:f269e3021894 800 return 0;
elessair 0:f269e3021894 801
elessair 0:f269e3021894 802 case NSAPI_KEEPIDLE:
elessair 0:f269e3021894 803 if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) {
elessair 0:f269e3021894 804 return NSAPI_ERROR_UNSUPPORTED;
elessair 0:f269e3021894 805 }
elessair 0:f269e3021894 806
elessair 0:f269e3021894 807 s->conn->pcb.tcp->keep_idle = *(int*)optval;
elessair 0:f269e3021894 808 return 0;
elessair 0:f269e3021894 809
elessair 0:f269e3021894 810 case NSAPI_KEEPINTVL:
elessair 0:f269e3021894 811 if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) {
elessair 0:f269e3021894 812 return NSAPI_ERROR_UNSUPPORTED;
elessair 0:f269e3021894 813 }
elessair 0:f269e3021894 814
elessair 0:f269e3021894 815 s->conn->pcb.tcp->keep_intvl = *(int*)optval;
elessair 0:f269e3021894 816 return 0;
elessair 0:f269e3021894 817
elessair 0:f269e3021894 818 case NSAPI_REUSEADDR:
elessair 0:f269e3021894 819 if (optlen != sizeof(int)) {
elessair 0:f269e3021894 820 return NSAPI_ERROR_UNSUPPORTED;
elessair 0:f269e3021894 821 }
elessair 0:f269e3021894 822
elessair 0:f269e3021894 823 if (*(int *)optval) {
elessair 0:f269e3021894 824 s->conn->pcb.tcp->so_options |= SOF_REUSEADDR;
elessair 0:f269e3021894 825 } else {
elessair 0:f269e3021894 826 s->conn->pcb.tcp->so_options &= ~SOF_REUSEADDR;
elessair 0:f269e3021894 827 }
elessair 0:f269e3021894 828 return 0;
elessair 0:f269e3021894 829
elessair 0:f269e3021894 830 default:
elessair 0:f269e3021894 831 return NSAPI_ERROR_UNSUPPORTED;
elessair 0:f269e3021894 832 }
elessair 0:f269e3021894 833 }
elessair 0:f269e3021894 834
elessair 0:f269e3021894 835 static void mbed_lwip_socket_attach(nsapi_stack_t *stack, nsapi_socket_t handle, void (*callback)(void *), void *data)
elessair 0:f269e3021894 836 {
elessair 0:f269e3021894 837 struct lwip_socket *s = (struct lwip_socket *)handle;
elessair 0:f269e3021894 838
elessair 0:f269e3021894 839 s->cb = callback;
elessair 0:f269e3021894 840 s->data = data;
elessair 0:f269e3021894 841 }
elessair 0:f269e3021894 842
elessair 0:f269e3021894 843 /* LWIP network stack */
elessair 0:f269e3021894 844 const nsapi_stack_api_t lwip_stack_api = {
elessair 0:f269e3021894 845 .gethostbyname = mbed_lwip_gethostbyname,
elessair 0:f269e3021894 846 .socket_open = mbed_lwip_socket_open,
elessair 0:f269e3021894 847 .socket_close = mbed_lwip_socket_close,
elessair 0:f269e3021894 848 .socket_bind = mbed_lwip_socket_bind,
elessair 0:f269e3021894 849 .socket_listen = mbed_lwip_socket_listen,
elessair 0:f269e3021894 850 .socket_connect = mbed_lwip_socket_connect,
elessair 0:f269e3021894 851 .socket_accept = mbed_lwip_socket_accept,
elessair 0:f269e3021894 852 .socket_send = mbed_lwip_socket_send,
elessair 0:f269e3021894 853 .socket_recv = mbed_lwip_socket_recv,
elessair 0:f269e3021894 854 .socket_sendto = mbed_lwip_socket_sendto,
elessair 0:f269e3021894 855 .socket_recvfrom = mbed_lwip_socket_recvfrom,
elessair 0:f269e3021894 856 .setsockopt = mbed_lwip_setsockopt,
elessair 0:f269e3021894 857 .socket_attach = mbed_lwip_socket_attach,
elessair 0:f269e3021894 858 };
elessair 0:f269e3021894 859
elessair 0:f269e3021894 860 nsapi_stack_t lwip_stack = {
elessair 0:f269e3021894 861 .stack_api = &lwip_stack_api,
elessair 0:f269e3021894 862 };