Implementation of the NetworkSocketAPI for LWIP

Dependencies:   lwip-eth lwip-sys lwip

Dependents:   HelloLWIPInterface HelloLWIPInterfaceNonBlocking LWIPInterfaceTests SimpleHTTPExample ... more

Committer:
Christopher Haster
Date:
Wed Apr 20 23:47:36 2016 -0500
Revision:
20:8b55d035d127
Parent:
18:5890b186a607
Child:
21:9600bd29a088
Fix memory leak of udp pcbs

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Christopher Haster 17:7db2f5d503d4 1 /* LWIP implementation of NetworkInterfaceAPI
Christopher Haster 17:7db2f5d503d4 2 * Copyright (c) 2015 ARM Limited
Christopher Haster 17:7db2f5d503d4 3 *
Christopher Haster 17:7db2f5d503d4 4 * Licensed under the Apache License, Version 2.0 (the "License");
Christopher Haster 17:7db2f5d503d4 5 * you may not use this file except in compliance with the License.
Christopher Haster 17:7db2f5d503d4 6 * You may obtain a copy of the License at
Christopher Haster 17:7db2f5d503d4 7 *
Christopher Haster 17:7db2f5d503d4 8 * http://www.apache.org/licenses/LICENSE-2.0
Christopher Haster 17:7db2f5d503d4 9 *
Christopher Haster 17:7db2f5d503d4 10 * Unless required by applicable law or agreed to in writing, software
Christopher Haster 17:7db2f5d503d4 11 * distributed under the License is distributed on an "AS IS" BASIS,
Christopher Haster 17:7db2f5d503d4 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Christopher Haster 17:7db2f5d503d4 13 * See the License for the specific language governing permissions and
Christopher Haster 17:7db2f5d503d4 14 * limitations under the License.
Christopher Haster 17:7db2f5d503d4 15 */
Christopher Haster 17:7db2f5d503d4 16
Christopher Haster 17:7db2f5d503d4 17 #include "mbed.h"
Christopher Haster 17:7db2f5d503d4 18 #include "LWIPInterface.h"
Christopher Haster 17:7db2f5d503d4 19
Christopher Haster 17:7db2f5d503d4 20 #include "lwip/inet.h"
Christopher Haster 17:7db2f5d503d4 21 #include "lwip/netif.h"
Christopher Haster 17:7db2f5d503d4 22 #include "lwip/dhcp.h"
Christopher Haster 17:7db2f5d503d4 23 #include "lwip/tcpip.h"
Christopher Haster 17:7db2f5d503d4 24 #include "lwip/sockets.h"
Christopher Haster 17:7db2f5d503d4 25 #include "lwip/netdb.h"
Christopher Haster 17:7db2f5d503d4 26 #include "netif/etharp.h"
Christopher Haster 17:7db2f5d503d4 27 #include "eth_arch.h"
Christopher Haster 17:7db2f5d503d4 28 #include "lwip/netif.h"
Christopher Haster 17:7db2f5d503d4 29 #include "lwip/udp.h"
Christopher Haster 17:7db2f5d503d4 30 #include "lwip/tcp.h"
Christopher Haster 17:7db2f5d503d4 31 #include "lwip/tcp_impl.h"
Christopher Haster 17:7db2f5d503d4 32 #include "lwip/timers.h"
Christopher Haster 17:7db2f5d503d4 33 #include "lwip/dns.h"
Christopher Haster 17:7db2f5d503d4 34 #include "lwip/def.h"
Christopher Haster 17:7db2f5d503d4 35 #include "lwip/ip_addr.h"
Christopher Haster 17:7db2f5d503d4 36
Christopher Haster 17:7db2f5d503d4 37
Christopher Haster 17:7db2f5d503d4 38 /* TCP/IP and Network Interface Initialisation */
Christopher Haster 17:7db2f5d503d4 39 static struct netif netif;
Christopher Haster 17:7db2f5d503d4 40
Christopher Haster 17:7db2f5d503d4 41 static char ip_addr[NSAPI_IP_SIZE] = "\0";
Christopher Haster 17:7db2f5d503d4 42 static char mac_addr[NSAPI_MAC_SIZE] = "\0";
Christopher Haster 17:7db2f5d503d4 43
Christopher Haster 17:7db2f5d503d4 44 static Semaphore tcpip_inited(0);
Christopher Haster 17:7db2f5d503d4 45 static Semaphore netif_linked(0);
Christopher Haster 17:7db2f5d503d4 46 static Semaphore netif_up(0);
Christopher Haster 17:7db2f5d503d4 47
Christopher Haster 17:7db2f5d503d4 48 static void tcpip_init_irq(void *)
Christopher Haster 17:7db2f5d503d4 49 {
Christopher Haster 17:7db2f5d503d4 50 tcpip_inited.release();
Christopher Haster 17:7db2f5d503d4 51 }
Christopher Haster 17:7db2f5d503d4 52
Christopher Haster 17:7db2f5d503d4 53 static void netif_link_irq(struct netif *netif)
Christopher Haster 17:7db2f5d503d4 54 {
Christopher Haster 17:7db2f5d503d4 55 if (netif_is_link_up(netif)) {
Christopher Haster 17:7db2f5d503d4 56 netif_linked.release();
Christopher Haster 17:7db2f5d503d4 57 }
Christopher Haster 17:7db2f5d503d4 58 }
Christopher Haster 17:7db2f5d503d4 59
Christopher Haster 17:7db2f5d503d4 60 static void netif_status_irq(struct netif *netif)
Christopher Haster 17:7db2f5d503d4 61 {
Christopher Haster 17:7db2f5d503d4 62 if (netif_is_up(netif)) {
Christopher Haster 17:7db2f5d503d4 63 strcpy(ip_addr, inet_ntoa(netif->ip_addr));
Christopher Haster 17:7db2f5d503d4 64 netif_up.release();
Christopher Haster 17:7db2f5d503d4 65 }
Christopher Haster 17:7db2f5d503d4 66 }
Christopher Haster 17:7db2f5d503d4 67
Christopher Haster 17:7db2f5d503d4 68 static void init_netif(ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw)
Christopher Haster 17:7db2f5d503d4 69 {
Christopher Haster 17:7db2f5d503d4 70 tcpip_init(tcpip_init_irq, NULL);
Christopher Haster 17:7db2f5d503d4 71 tcpip_inited.wait();
Christopher Haster 17:7db2f5d503d4 72
Christopher Haster 17:7db2f5d503d4 73 memset((void*) &netif, 0, sizeof(netif));
Christopher Haster 17:7db2f5d503d4 74 netif_add(&netif, ipaddr, netmask, gw, NULL, eth_arch_enetif_init, tcpip_input);
Christopher Haster 17:7db2f5d503d4 75 netif_set_default(&netif);
Christopher Haster 17:7db2f5d503d4 76
Christopher Haster 17:7db2f5d503d4 77 netif_set_link_callback (&netif, netif_link_irq);
Christopher Haster 17:7db2f5d503d4 78 netif_set_status_callback(&netif, netif_status_irq);
Christopher Haster 17:7db2f5d503d4 79 }
Christopher Haster 17:7db2f5d503d4 80
Christopher Haster 17:7db2f5d503d4 81 static void set_mac_address(void)
Christopher Haster 17:7db2f5d503d4 82 {
Christopher Haster 17:7db2f5d503d4 83 #if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
Christopher Haster 17:7db2f5d503d4 84 snprintf(mac_addr, 19, "%02x:%02x:%02x:%02x:%02x:%02x", MBED_MAC_ADDR_0, MBED_MAC_ADDR_1, MBED_MAC_ADDR_2,
Christopher Haster 17:7db2f5d503d4 85 MBED_MAC_ADDR_3, MBED_MAC_ADDR_4, MBED_MAC_ADDR_5);
Christopher Haster 17:7db2f5d503d4 86 #else
Christopher Haster 17:7db2f5d503d4 87 char mac[6];
Christopher Haster 17:7db2f5d503d4 88 mbed_mac_address(mac);
Christopher Haster 17:7db2f5d503d4 89 snprintf(mac_addr, 19, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
Christopher Haster 17:7db2f5d503d4 90 #endif
Christopher Haster 17:7db2f5d503d4 91 }
Christopher Haster 17:7db2f5d503d4 92
Christopher Haster 17:7db2f5d503d4 93
Christopher Haster 17:7db2f5d503d4 94 /* Interface implementation */
Christopher Haster 17:7db2f5d503d4 95 int LWIPInterface::connect()
Christopher Haster 17:7db2f5d503d4 96 {
Christopher Haster 17:7db2f5d503d4 97 // Set up network
Christopher Haster 17:7db2f5d503d4 98 set_mac_address();
Christopher Haster 17:7db2f5d503d4 99 init_netif(0, 0, 0);
Christopher Haster 17:7db2f5d503d4 100
Christopher Haster 17:7db2f5d503d4 101 // Connect to network
Christopher Haster 17:7db2f5d503d4 102 eth_arch_enable_interrupts();
Christopher Haster 17:7db2f5d503d4 103
Christopher Haster 17:7db2f5d503d4 104 dhcp_start(&netif);
Christopher Haster 17:7db2f5d503d4 105
Christopher Haster 17:7db2f5d503d4 106 // Wait for an IP Address
Christopher Haster 17:7db2f5d503d4 107 // -1: error, 0: timeout
Christopher Haster 17:7db2f5d503d4 108 if (netif_up.wait(1500) < 0) {
Christopher Haster 17:7db2f5d503d4 109 return NSAPI_ERROR_DHCP_FAILURE;
Christopher Haster 17:7db2f5d503d4 110 }
Christopher Haster 17:7db2f5d503d4 111
Christopher Haster 17:7db2f5d503d4 112 return 0;
Christopher Haster 17:7db2f5d503d4 113 }
Christopher Haster 17:7db2f5d503d4 114
Christopher Haster 17:7db2f5d503d4 115 int LWIPInterface::disconnect()
Christopher Haster 17:7db2f5d503d4 116 {
Christopher Haster 17:7db2f5d503d4 117 dhcp_release(&netif);
Christopher Haster 17:7db2f5d503d4 118 dhcp_stop(&netif);
Christopher Haster 17:7db2f5d503d4 119
Christopher Haster 17:7db2f5d503d4 120 eth_arch_disable_interrupts();
Christopher Haster 17:7db2f5d503d4 121
Christopher Haster 17:7db2f5d503d4 122 return 0;
Christopher Haster 17:7db2f5d503d4 123 }
Christopher Haster 17:7db2f5d503d4 124
Christopher Haster 17:7db2f5d503d4 125 const char *LWIPInterface::get_ip_address()
Christopher Haster 17:7db2f5d503d4 126 {
Christopher Haster 17:7db2f5d503d4 127 return ip_addr;
Christopher Haster 17:7db2f5d503d4 128 }
Christopher Haster 17:7db2f5d503d4 129
Christopher Haster 17:7db2f5d503d4 130 const char *LWIPInterface::get_mac_address()
Christopher Haster 17:7db2f5d503d4 131 {
Christopher Haster 17:7db2f5d503d4 132 return mac_addr;
Christopher Haster 17:7db2f5d503d4 133 }
Christopher Haster 17:7db2f5d503d4 134
Christopher Haster 17:7db2f5d503d4 135 struct lwip_socket {
Christopher Haster 17:7db2f5d503d4 136 nsapi_protocol_t proto;
Christopher Haster 17:7db2f5d503d4 137 union {
Christopher Haster 17:7db2f5d503d4 138 struct udp_pcb *udp;
Christopher Haster 17:7db2f5d503d4 139 struct tcp_pcb *tcp;
Christopher Haster 17:7db2f5d503d4 140 };
Christopher Haster 17:7db2f5d503d4 141
Christopher Haster 17:7db2f5d503d4 142 struct pbuf *rx_chain;
Christopher Haster 17:7db2f5d503d4 143 Semaphore *sem;
Christopher Haster 17:7db2f5d503d4 144
Christopher Haster 17:7db2f5d503d4 145 void (*callback)(void *);
Christopher Haster 17:7db2f5d503d4 146 void *data;
Christopher Haster 17:7db2f5d503d4 147 };
Christopher Haster 17:7db2f5d503d4 148
Christopher Haster 17:7db2f5d503d4 149 static void udp_recv_irq(
Christopher Haster 17:7db2f5d503d4 150 void *arg, struct udp_pcb *upcb, struct pbuf *p,
Christopher Haster 17:7db2f5d503d4 151 struct ip_addr *addr, uint16_t port);
Christopher Haster 17:7db2f5d503d4 152
Christopher Haster 17:7db2f5d503d4 153 int LWIPInterface::socket_open(void **handle, nsapi_protocol_t proto)
Christopher Haster 17:7db2f5d503d4 154 {
Christopher Haster 17:7db2f5d503d4 155 struct lwip_socket *s = new struct lwip_socket;
Christopher Haster 17:7db2f5d503d4 156 if (!s) {
Christopher Haster 17:7db2f5d503d4 157 return NSAPI_ERROR_NO_SOCKET;
Christopher Haster 17:7db2f5d503d4 158 }
Christopher Haster 17:7db2f5d503d4 159
Christopher Haster 17:7db2f5d503d4 160 memset(s, 0, sizeof *s);
Christopher Haster 17:7db2f5d503d4 161
Christopher Haster 17:7db2f5d503d4 162 switch (proto) {
Christopher Haster 17:7db2f5d503d4 163 case NSAPI_UDP:
Christopher Haster 17:7db2f5d503d4 164 s->proto = proto;
Christopher Haster 17:7db2f5d503d4 165 s->udp = udp_new();
Christopher Haster 17:7db2f5d503d4 166 if (!s->udp) {
Christopher Haster 17:7db2f5d503d4 167 return NSAPI_ERROR_NO_SOCKET;
Christopher Haster 17:7db2f5d503d4 168 }
Christopher Haster 17:7db2f5d503d4 169
Christopher Haster 17:7db2f5d503d4 170 udp_recv(s->udp, udp_recv_irq, s);
Christopher Haster 17:7db2f5d503d4 171 *handle = s;
geky 18:5890b186a607 172 return 0;
Christopher Haster 17:7db2f5d503d4 173
Christopher Haster 17:7db2f5d503d4 174 case NSAPI_TCP:
Christopher Haster 17:7db2f5d503d4 175 s->proto = proto;
Christopher Haster 17:7db2f5d503d4 176 s->tcp = tcp_new();
Christopher Haster 17:7db2f5d503d4 177 if (!s->tcp) {
Christopher Haster 17:7db2f5d503d4 178 return NSAPI_ERROR_NO_SOCKET;
Christopher Haster 17:7db2f5d503d4 179 }
Christopher Haster 17:7db2f5d503d4 180
Christopher Haster 17:7db2f5d503d4 181 tcp_arg(s->tcp, s);
Christopher Haster 17:7db2f5d503d4 182 //tcp_err(s->tcp, tcp_error_irq);
Christopher Haster 17:7db2f5d503d4 183 *handle = s;
geky 18:5890b186a607 184 return 0;
Christopher Haster 17:7db2f5d503d4 185 }
Christopher Haster 17:7db2f5d503d4 186
Christopher Haster 17:7db2f5d503d4 187 return NSAPI_ERROR_DEVICE_ERROR;
Christopher Haster 17:7db2f5d503d4 188 }
Christopher Haster 17:7db2f5d503d4 189
Christopher Haster 17:7db2f5d503d4 190 int LWIPInterface::socket_close(void *handle)
Christopher Haster 17:7db2f5d503d4 191 {
Christopher Haster 17:7db2f5d503d4 192 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 193 int err = 0;
Christopher Haster 17:7db2f5d503d4 194
Christopher Haster 17:7db2f5d503d4 195 switch (s->proto) {
Christopher Haster 17:7db2f5d503d4 196 case NSAPI_UDP:
Christopher Haster 17:7db2f5d503d4 197 udp_disconnect(s->udp);
Christopher Haster 20:8b55d035d127 198 udp_remove(s->udp);
Christopher Haster 17:7db2f5d503d4 199 break;
Christopher Haster 17:7db2f5d503d4 200
Christopher Haster 17:7db2f5d503d4 201 case NSAPI_TCP:
Christopher Haster 17:7db2f5d503d4 202 if (tcp_close(s->tcp)) {
Christopher Haster 17:7db2f5d503d4 203 err = NSAPI_ERROR_DEVICE_ERROR;
Christopher Haster 17:7db2f5d503d4 204 }
Christopher Haster 17:7db2f5d503d4 205 break;
Christopher Haster 17:7db2f5d503d4 206 }
Christopher Haster 17:7db2f5d503d4 207
Christopher Haster 17:7db2f5d503d4 208 if (s->rx_chain) {
Christopher Haster 17:7db2f5d503d4 209 pbuf_free(s->rx_chain);
Christopher Haster 17:7db2f5d503d4 210 s->rx_chain = 0;
Christopher Haster 17:7db2f5d503d4 211 }
Christopher Haster 17:7db2f5d503d4 212
Christopher Haster 17:7db2f5d503d4 213 delete s;
Christopher Haster 17:7db2f5d503d4 214
Christopher Haster 17:7db2f5d503d4 215 return err;
Christopher Haster 17:7db2f5d503d4 216 }
Christopher Haster 17:7db2f5d503d4 217
Christopher Haster 17:7db2f5d503d4 218
Christopher Haster 17:7db2f5d503d4 219 int LWIPInterface::socket_bind(void *handle, const SocketAddress &address)
Christopher Haster 17:7db2f5d503d4 220 {
Christopher Haster 17:7db2f5d503d4 221 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 222 ip_addr_t ip_addr = ip_addr_any; // TODO use address
Christopher Haster 17:7db2f5d503d4 223
Christopher Haster 17:7db2f5d503d4 224 switch (s->proto) {
Christopher Haster 17:7db2f5d503d4 225 case NSAPI_UDP:
Christopher Haster 17:7db2f5d503d4 226 if (udp_bind(s->udp, &ip_addr, address.get_port())) {
Christopher Haster 17:7db2f5d503d4 227 return NSAPI_ERROR_DEVICE_ERROR;
Christopher Haster 17:7db2f5d503d4 228 }
Christopher Haster 17:7db2f5d503d4 229 return 0;
Christopher Haster 17:7db2f5d503d4 230
Christopher Haster 17:7db2f5d503d4 231 case NSAPI_TCP:
Christopher Haster 17:7db2f5d503d4 232 if (tcp_bind(s->tcp, &ip_addr, address.get_port())) {
Christopher Haster 17:7db2f5d503d4 233 return NSAPI_ERROR_DEVICE_ERROR;
Christopher Haster 17:7db2f5d503d4 234 }
Christopher Haster 17:7db2f5d503d4 235 return 0;
Christopher Haster 17:7db2f5d503d4 236 }
Christopher Haster 17:7db2f5d503d4 237
Christopher Haster 17:7db2f5d503d4 238 return NSAPI_ERROR_DEVICE_ERROR;
Christopher Haster 17:7db2f5d503d4 239 }
Christopher Haster 17:7db2f5d503d4 240
Christopher Haster 17:7db2f5d503d4 241 int LWIPInterface::socket_listen(void *handle, int backlog)
Christopher Haster 17:7db2f5d503d4 242 {
Christopher Haster 17:7db2f5d503d4 243 return NSAPI_ERROR_UNSUPPORTED;
Christopher Haster 17:7db2f5d503d4 244 }
Christopher Haster 17:7db2f5d503d4 245
Christopher Haster 17:7db2f5d503d4 246 static err_t tcp_sent_irq(void *arg, struct tcp_pcb *tpcb, uint16_t len);
Christopher Haster 17:7db2f5d503d4 247 static err_t tcp_recv_irq(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
Christopher Haster 17:7db2f5d503d4 248
Christopher Haster 17:7db2f5d503d4 249 static err_t tcp_connect_irq(void *handle, struct tcp_pcb *tpcb, err_t err)
Christopher Haster 17:7db2f5d503d4 250 {
Christopher Haster 17:7db2f5d503d4 251 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 252 tcp_sent(tpcb, tcp_sent_irq);
Christopher Haster 17:7db2f5d503d4 253 tcp_recv(tpcb, tcp_recv_irq);
Christopher Haster 17:7db2f5d503d4 254
Christopher Haster 17:7db2f5d503d4 255 s->sem->release();
Christopher Haster 17:7db2f5d503d4 256
Christopher Haster 17:7db2f5d503d4 257 return ERR_OK;
Christopher Haster 17:7db2f5d503d4 258 }
Christopher Haster 17:7db2f5d503d4 259
Christopher Haster 17:7db2f5d503d4 260 int LWIPInterface::socket_connect(void *handle, const SocketAddress &addr)
Christopher Haster 17:7db2f5d503d4 261 {
Christopher Haster 17:7db2f5d503d4 262 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 263
Christopher Haster 17:7db2f5d503d4 264 ip_addr_t ip_addr;
Christopher Haster 17:7db2f5d503d4 265 inet_aton(addr.get_ip_address(), &ip_addr);
Christopher Haster 17:7db2f5d503d4 266
Christopher Haster 17:7db2f5d503d4 267 Semaphore connected(0);
Christopher Haster 17:7db2f5d503d4 268 s->sem = &connected;
Christopher Haster 17:7db2f5d503d4 269
Christopher Haster 17:7db2f5d503d4 270 tcp_connect(s->tcp, &ip_addr, addr.get_port(), tcp_connect_irq);
Christopher Haster 17:7db2f5d503d4 271
Christopher Haster 17:7db2f5d503d4 272 // Wait for connection
Christopher Haster 17:7db2f5d503d4 273 if (connected.wait(1500) < 0) {
Christopher Haster 17:7db2f5d503d4 274 return NSAPI_ERROR_NO_CONNECTION;
Christopher Haster 17:7db2f5d503d4 275 }
Christopher Haster 17:7db2f5d503d4 276
Christopher Haster 17:7db2f5d503d4 277 return 0;
Christopher Haster 17:7db2f5d503d4 278 }
Christopher Haster 17:7db2f5d503d4 279
Christopher Haster 17:7db2f5d503d4 280 int LWIPInterface::socket_accept(void **handle, void *server)
Christopher Haster 17:7db2f5d503d4 281 {
Christopher Haster 17:7db2f5d503d4 282 return NSAPI_ERROR_UNSUPPORTED;
Christopher Haster 17:7db2f5d503d4 283 }
Christopher Haster 17:7db2f5d503d4 284
Christopher Haster 17:7db2f5d503d4 285 static struct pbuf *pbuf_consume(struct pbuf *p, size_t consume, bool free_partial)
Christopher Haster 17:7db2f5d503d4 286 {
Christopher Haster 17:7db2f5d503d4 287 do {
Christopher Haster 17:7db2f5d503d4 288 if (consume <= p->len) {
Christopher Haster 17:7db2f5d503d4 289 // advance the payload pointer by the number of bytes copied
Christopher Haster 17:7db2f5d503d4 290 p->payload = (char *)p->payload + consume;
Christopher Haster 17:7db2f5d503d4 291 // reduce the length by the number of bytes copied
Christopher Haster 17:7db2f5d503d4 292 p->len -= consume;
Christopher Haster 17:7db2f5d503d4 293 // break out of the loop
Christopher Haster 17:7db2f5d503d4 294 consume = 0;
Christopher Haster 17:7db2f5d503d4 295 }
Christopher Haster 17:7db2f5d503d4 296 if (p->len == 0 || consume > p->len || (consume == 0 && free_partial)) {
Christopher Haster 17:7db2f5d503d4 297 struct pbuf *q;
Christopher Haster 17:7db2f5d503d4 298 q = p->next;
Christopher Haster 17:7db2f5d503d4 299 // decrement the number of bytes copied by the length of the buffer
Christopher Haster 17:7db2f5d503d4 300 if(consume > p->len)
Christopher Haster 17:7db2f5d503d4 301 consume -= p->len;
Christopher Haster 17:7db2f5d503d4 302 // Free the current pbuf
Christopher Haster 17:7db2f5d503d4 303 // NOTE: This operation is interrupt safe, but not thread safe.
Christopher Haster 17:7db2f5d503d4 304 if (q != NULL) {
Christopher Haster 17:7db2f5d503d4 305 pbuf_ref(q);
Christopher Haster 17:7db2f5d503d4 306 }
Christopher Haster 17:7db2f5d503d4 307 pbuf_free(p);
Christopher Haster 17:7db2f5d503d4 308 p = q;
Christopher Haster 17:7db2f5d503d4 309 }
Christopher Haster 17:7db2f5d503d4 310 } while (consume);
Christopher Haster 17:7db2f5d503d4 311 return p;
Christopher Haster 17:7db2f5d503d4 312 }
Christopher Haster 17:7db2f5d503d4 313
Christopher Haster 17:7db2f5d503d4 314 static err_t tcp_sent_irq(void *handle, struct tcp_pcb *tpcb, uint16_t len)
Christopher Haster 17:7db2f5d503d4 315 {
Christopher Haster 17:7db2f5d503d4 316 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 317 if (s->callback) {
Christopher Haster 17:7db2f5d503d4 318 s->callback(s->data);
Christopher Haster 17:7db2f5d503d4 319 }
Christopher Haster 17:7db2f5d503d4 320
Christopher Haster 17:7db2f5d503d4 321 return ERR_OK;
Christopher Haster 17:7db2f5d503d4 322 }
Christopher Haster 17:7db2f5d503d4 323
Christopher Haster 17:7db2f5d503d4 324 int LWIPInterface::socket_send(void *handle, const void *buf, unsigned size)
Christopher Haster 17:7db2f5d503d4 325 {
Christopher Haster 17:7db2f5d503d4 326 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 327
Christopher Haster 17:7db2f5d503d4 328 if (tcp_write(s->tcp, buf, size, TCP_WRITE_FLAG_COPY)) {
Christopher Haster 17:7db2f5d503d4 329 return NSAPI_ERROR_DEVICE_ERROR;
Christopher Haster 17:7db2f5d503d4 330 }
Christopher Haster 17:7db2f5d503d4 331
Christopher Haster 17:7db2f5d503d4 332 tcp_output(s->tcp);
Christopher Haster 17:7db2f5d503d4 333
Christopher Haster 17:7db2f5d503d4 334 return size;
Christopher Haster 17:7db2f5d503d4 335 }
Christopher Haster 17:7db2f5d503d4 336
Christopher Haster 17:7db2f5d503d4 337 static err_t tcp_recv_irq(void *handle, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
Christopher Haster 17:7db2f5d503d4 338 {
Christopher Haster 17:7db2f5d503d4 339 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 340
Christopher Haster 17:7db2f5d503d4 341 // Check for disconnect
Christopher Haster 17:7db2f5d503d4 342 if (!p) {
Christopher Haster 17:7db2f5d503d4 343 // Zero pcb during disconnect, since disconnect will cause a free
Christopher Haster 17:7db2f5d503d4 344 switch (tpcb->state) {
Christopher Haster 17:7db2f5d503d4 345 case FIN_WAIT_1:
Christopher Haster 17:7db2f5d503d4 346 case FIN_WAIT_2:
Christopher Haster 17:7db2f5d503d4 347 case TIME_WAIT:
Christopher Haster 17:7db2f5d503d4 348 s->tcp = 0;
Christopher Haster 17:7db2f5d503d4 349 break;
Christopher Haster 17:7db2f5d503d4 350 default:
Christopher Haster 17:7db2f5d503d4 351 break;
Christopher Haster 17:7db2f5d503d4 352 }
Christopher Haster 17:7db2f5d503d4 353 return ERR_OK;
Christopher Haster 17:7db2f5d503d4 354 }
Christopher Haster 17:7db2f5d503d4 355
Christopher Haster 17:7db2f5d503d4 356 __disable_irq();
Christopher Haster 17:7db2f5d503d4 357 if (!s->rx_chain) {
Christopher Haster 17:7db2f5d503d4 358 s->rx_chain = p;
Christopher Haster 17:7db2f5d503d4 359 } else {
Christopher Haster 17:7db2f5d503d4 360 pbuf_cat(s->rx_chain, p);
Christopher Haster 17:7db2f5d503d4 361 }
Christopher Haster 17:7db2f5d503d4 362 __enable_irq();
Christopher Haster 17:7db2f5d503d4 363
Christopher Haster 17:7db2f5d503d4 364 if (s->callback) {
Christopher Haster 17:7db2f5d503d4 365 s->callback(s->data);
Christopher Haster 17:7db2f5d503d4 366 }
Christopher Haster 17:7db2f5d503d4 367
Christopher Haster 17:7db2f5d503d4 368 return ERR_OK;
Christopher Haster 17:7db2f5d503d4 369 }
Christopher Haster 17:7db2f5d503d4 370
Christopher Haster 17:7db2f5d503d4 371 int LWIPInterface::socket_recv(void *handle, void *buf, unsigned size)
Christopher Haster 17:7db2f5d503d4 372 {
Christopher Haster 17:7db2f5d503d4 373 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 374
Christopher Haster 17:7db2f5d503d4 375 // Disconnected
Christopher Haster 17:7db2f5d503d4 376 if (!s->tcp && !s->rx_chain) {
Christopher Haster 17:7db2f5d503d4 377 return NSAPI_ERROR_NO_CONNECTION;
Christopher Haster 17:7db2f5d503d4 378 }
Christopher Haster 17:7db2f5d503d4 379
Christopher Haster 17:7db2f5d503d4 380 // Nothing ready
Christopher Haster 17:7db2f5d503d4 381 if (!s->rx_chain) {
Christopher Haster 17:7db2f5d503d4 382 return NSAPI_ERROR_WOULD_BLOCK;
Christopher Haster 17:7db2f5d503d4 383 }
Christopher Haster 17:7db2f5d503d4 384
Christopher Haster 17:7db2f5d503d4 385 // Copy out pbuf
Christopher Haster 17:7db2f5d503d4 386 struct pbuf *p = s->rx_chain;
Christopher Haster 17:7db2f5d503d4 387 int copied = pbuf_copy_partial(p, buf, size, 0);
Christopher Haster 17:7db2f5d503d4 388 s->rx_chain = pbuf_consume(p, copied, false);
Christopher Haster 17:7db2f5d503d4 389
Christopher Haster 17:7db2f5d503d4 390 // Update TCP window
Christopher Haster 17:7db2f5d503d4 391 tcp_recved(s->tcp, copied);
Christopher Haster 17:7db2f5d503d4 392 return copied;
Christopher Haster 17:7db2f5d503d4 393 }
Christopher Haster 17:7db2f5d503d4 394
Christopher Haster 17:7db2f5d503d4 395 int LWIPInterface::socket_sendto(void *handle, const SocketAddress &addr, const void *buf, unsigned size)
Christopher Haster 17:7db2f5d503d4 396 {
Christopher Haster 17:7db2f5d503d4 397 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 398
Christopher Haster 17:7db2f5d503d4 399 struct pbuf *pb = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
Christopher Haster 17:7db2f5d503d4 400 if (pbuf_take(pb, buf, size)) {
Christopher Haster 17:7db2f5d503d4 401 return NSAPI_ERROR_DEVICE_ERROR;
Christopher Haster 17:7db2f5d503d4 402 }
Christopher Haster 17:7db2f5d503d4 403
Christopher Haster 17:7db2f5d503d4 404 ip_addr_t id_addr;
Christopher Haster 17:7db2f5d503d4 405 inet_aton(addr.get_ip_address(), &id_addr);
Christopher Haster 17:7db2f5d503d4 406
Christopher Haster 17:7db2f5d503d4 407 err_t err = udp_sendto(s->udp, pb, &id_addr, addr.get_port());
Christopher Haster 17:7db2f5d503d4 408 pbuf_free(pb);
Christopher Haster 17:7db2f5d503d4 409 if (err) {
Christopher Haster 17:7db2f5d503d4 410 return NSAPI_ERROR_DEVICE_ERROR;
Christopher Haster 17:7db2f5d503d4 411 }
Christopher Haster 17:7db2f5d503d4 412
Christopher Haster 17:7db2f5d503d4 413 if (s->callback) {
Christopher Haster 17:7db2f5d503d4 414 s->callback(s->data);
Christopher Haster 17:7db2f5d503d4 415 }
Christopher Haster 17:7db2f5d503d4 416
Christopher Haster 17:7db2f5d503d4 417 return size;
Christopher Haster 17:7db2f5d503d4 418 }
Christopher Haster 17:7db2f5d503d4 419
Christopher Haster 17:7db2f5d503d4 420 static void udp_recv_irq(
Christopher Haster 17:7db2f5d503d4 421 void *handle, struct udp_pcb *upcb, struct pbuf *p,
Christopher Haster 17:7db2f5d503d4 422 struct ip_addr *addr, uint16_t port)
Christopher Haster 17:7db2f5d503d4 423 {
Christopher Haster 17:7db2f5d503d4 424 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 425
Christopher Haster 17:7db2f5d503d4 426 __disable_irq();
Christopher Haster 17:7db2f5d503d4 427 if (!s->rx_chain) {
Christopher Haster 17:7db2f5d503d4 428 s->rx_chain = p;
Christopher Haster 17:7db2f5d503d4 429 } else {
Christopher Haster 17:7db2f5d503d4 430 // Attach p to buffer chain without changing the tot_len
Christopher Haster 17:7db2f5d503d4 431 // NOTE: This is not how pbufs are intended to work, but it is necessary to deal with
Christopher Haster 17:7db2f5d503d4 432 // a) fragmentation and b) packet queueing
Christopher Haster 17:7db2f5d503d4 433 struct pbuf *q = s->rx_chain;
Christopher Haster 17:7db2f5d503d4 434 while (q->next) { q = q->next; }
Christopher Haster 17:7db2f5d503d4 435 q->next = p;
Christopher Haster 17:7db2f5d503d4 436 }
Christopher Haster 17:7db2f5d503d4 437 __enable_irq();
Christopher Haster 17:7db2f5d503d4 438
Christopher Haster 17:7db2f5d503d4 439 if (s->callback) {
Christopher Haster 17:7db2f5d503d4 440 s->callback(s->data);
Christopher Haster 17:7db2f5d503d4 441 }
Christopher Haster 17:7db2f5d503d4 442 }
Christopher Haster 17:7db2f5d503d4 443
Christopher Haster 17:7db2f5d503d4 444 int LWIPInterface::socket_recvfrom(void *handle, SocketAddress *addr, void *buf, unsigned size)
Christopher Haster 17:7db2f5d503d4 445 {
Christopher Haster 17:7db2f5d503d4 446 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 447
Christopher Haster 17:7db2f5d503d4 448 // Disconnected
Christopher Haster 17:7db2f5d503d4 449 if (!s->udp && !s->rx_chain) {
Christopher Haster 17:7db2f5d503d4 450 return NSAPI_ERROR_NO_CONNECTION;
Christopher Haster 17:7db2f5d503d4 451 }
Christopher Haster 17:7db2f5d503d4 452
Christopher Haster 17:7db2f5d503d4 453 // Nothing ready
Christopher Haster 17:7db2f5d503d4 454 if (!s->rx_chain) {
Christopher Haster 17:7db2f5d503d4 455 return NSAPI_ERROR_WOULD_BLOCK;
Christopher Haster 17:7db2f5d503d4 456 }
Christopher Haster 17:7db2f5d503d4 457
Christopher Haster 17:7db2f5d503d4 458 struct pbuf *p = s->rx_chain;
Christopher Haster 17:7db2f5d503d4 459
Christopher Haster 17:7db2f5d503d4 460 if (addr) {
Christopher Haster 17:7db2f5d503d4 461 struct udp_hdr *udphdr;
Christopher Haster 17:7db2f5d503d4 462 struct ip_hdr *iphdr;
Christopher Haster 17:7db2f5d503d4 463
Christopher Haster 17:7db2f5d503d4 464 // roll back the pbuf by udp_hdr to find the source port
Christopher Haster 17:7db2f5d503d4 465 pbuf_header(p, UDP_HLEN);
Christopher Haster 17:7db2f5d503d4 466 udphdr = (struct udp_hdr *)p->payload;
Christopher Haster 17:7db2f5d503d4 467
Christopher Haster 17:7db2f5d503d4 468 // roll back the pbuf by ip_hdr to find the source IP
Christopher Haster 17:7db2f5d503d4 469 pbuf_header(p, IP_HLEN);
Christopher Haster 17:7db2f5d503d4 470 iphdr = (struct ip_hdr *)p->payload;
Christopher Haster 17:7db2f5d503d4 471
Christopher Haster 17:7db2f5d503d4 472 // put the pbuf back where it was
Christopher Haster 17:7db2f5d503d4 473 pbuf_header(p, -UDP_HLEN - IP_HLEN);
Christopher Haster 17:7db2f5d503d4 474
Christopher Haster 17:7db2f5d503d4 475 addr->set_ip_address(inet_ntoa(iphdr->src));
Christopher Haster 17:7db2f5d503d4 476 addr->set_port(ntohs(udphdr->src));
Christopher Haster 17:7db2f5d503d4 477 }
Christopher Haster 17:7db2f5d503d4 478
Christopher Haster 17:7db2f5d503d4 479 // Copy out pbuf
Christopher Haster 17:7db2f5d503d4 480 size = size < p->tot_len ? size : p->tot_len;
Christopher Haster 17:7db2f5d503d4 481 int copied = pbuf_copy_partial(p, buf, size, 0);
Christopher Haster 17:7db2f5d503d4 482 s->rx_chain = pbuf_consume(p, p->tot_len, true);
Christopher Haster 17:7db2f5d503d4 483
Christopher Haster 17:7db2f5d503d4 484 return copied;
Christopher Haster 17:7db2f5d503d4 485 }
Christopher Haster 17:7db2f5d503d4 486
Christopher Haster 17:7db2f5d503d4 487 void LWIPInterface::socket_attach(void *handle, void (*callback)(void *), void *data)
Christopher Haster 17:7db2f5d503d4 488 {
Christopher Haster 17:7db2f5d503d4 489 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 490 s->callback = callback;
Christopher Haster 17:7db2f5d503d4 491 s->data = data;
Christopher Haster 17:7db2f5d503d4 492 }