Implementation of the NetworkSocketAPI for LWIP

Dependencies:   lwip-eth lwip-sys lwip

Dependents:   HelloLWIPInterface HelloLWIPInterfaceNonBlocking LWIPInterfaceTests SimpleHTTPExample ... more

Committer:
Christopher Haster
Date:
Thu Apr 21 18:23:35 2016 -0500
Revision:
21:9600bd29a088
Parent:
20:8b55d035d127
Add rudimentary support for server side

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 21:9600bd29a088 142 struct tcp_pcb *npcb;
Christopher Haster 17:7db2f5d503d4 143 struct pbuf *rx_chain;
Christopher Haster 17:7db2f5d503d4 144 Semaphore *sem;
Christopher Haster 17:7db2f5d503d4 145
Christopher Haster 17:7db2f5d503d4 146 void (*callback)(void *);
Christopher Haster 17:7db2f5d503d4 147 void *data;
Christopher Haster 17:7db2f5d503d4 148 };
Christopher Haster 17:7db2f5d503d4 149
Christopher Haster 17:7db2f5d503d4 150 static void udp_recv_irq(
Christopher Haster 17:7db2f5d503d4 151 void *arg, struct udp_pcb *upcb, struct pbuf *p,
Christopher Haster 17:7db2f5d503d4 152 struct ip_addr *addr, uint16_t port);
Christopher Haster 17:7db2f5d503d4 153
Christopher Haster 17:7db2f5d503d4 154 int LWIPInterface::socket_open(void **handle, nsapi_protocol_t proto)
Christopher Haster 17:7db2f5d503d4 155 {
Christopher Haster 17:7db2f5d503d4 156 struct lwip_socket *s = new struct lwip_socket;
Christopher Haster 17:7db2f5d503d4 157 if (!s) {
Christopher Haster 17:7db2f5d503d4 158 return NSAPI_ERROR_NO_SOCKET;
Christopher Haster 17:7db2f5d503d4 159 }
Christopher Haster 17:7db2f5d503d4 160
Christopher Haster 17:7db2f5d503d4 161 memset(s, 0, sizeof *s);
Christopher Haster 17:7db2f5d503d4 162
Christopher Haster 17:7db2f5d503d4 163 switch (proto) {
Christopher Haster 17:7db2f5d503d4 164 case NSAPI_UDP:
Christopher Haster 17:7db2f5d503d4 165 s->proto = proto;
Christopher Haster 17:7db2f5d503d4 166 s->udp = udp_new();
Christopher Haster 17:7db2f5d503d4 167 if (!s->udp) {
Christopher Haster 17:7db2f5d503d4 168 return NSAPI_ERROR_NO_SOCKET;
Christopher Haster 17:7db2f5d503d4 169 }
Christopher Haster 17:7db2f5d503d4 170
Christopher Haster 17:7db2f5d503d4 171 udp_recv(s->udp, udp_recv_irq, s);
Christopher Haster 17:7db2f5d503d4 172 *handle = s;
geky 18:5890b186a607 173 return 0;
Christopher Haster 17:7db2f5d503d4 174
Christopher Haster 17:7db2f5d503d4 175 case NSAPI_TCP:
Christopher Haster 17:7db2f5d503d4 176 s->proto = proto;
Christopher Haster 17:7db2f5d503d4 177 s->tcp = tcp_new();
Christopher Haster 17:7db2f5d503d4 178 if (!s->tcp) {
Christopher Haster 17:7db2f5d503d4 179 return NSAPI_ERROR_NO_SOCKET;
Christopher Haster 17:7db2f5d503d4 180 }
Christopher Haster 17:7db2f5d503d4 181
Christopher Haster 17:7db2f5d503d4 182 tcp_arg(s->tcp, s);
Christopher Haster 17:7db2f5d503d4 183 //tcp_err(s->tcp, tcp_error_irq);
Christopher Haster 17:7db2f5d503d4 184 *handle = s;
geky 18:5890b186a607 185 return 0;
Christopher Haster 17:7db2f5d503d4 186 }
Christopher Haster 17:7db2f5d503d4 187
Christopher Haster 17:7db2f5d503d4 188 return NSAPI_ERROR_DEVICE_ERROR;
Christopher Haster 17:7db2f5d503d4 189 }
Christopher Haster 17:7db2f5d503d4 190
Christopher Haster 17:7db2f5d503d4 191 int LWIPInterface::socket_close(void *handle)
Christopher Haster 17:7db2f5d503d4 192 {
Christopher Haster 17:7db2f5d503d4 193 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 194 int err = 0;
Christopher Haster 17:7db2f5d503d4 195
Christopher Haster 17:7db2f5d503d4 196 switch (s->proto) {
Christopher Haster 17:7db2f5d503d4 197 case NSAPI_UDP:
Christopher Haster 17:7db2f5d503d4 198 udp_disconnect(s->udp);
Christopher Haster 20:8b55d035d127 199 udp_remove(s->udp);
Christopher Haster 17:7db2f5d503d4 200 break;
Christopher Haster 17:7db2f5d503d4 201
Christopher Haster 17:7db2f5d503d4 202 case NSAPI_TCP:
Christopher Haster 17:7db2f5d503d4 203 if (tcp_close(s->tcp)) {
Christopher Haster 17:7db2f5d503d4 204 err = NSAPI_ERROR_DEVICE_ERROR;
Christopher Haster 17:7db2f5d503d4 205 }
Christopher Haster 17:7db2f5d503d4 206 break;
Christopher Haster 17:7db2f5d503d4 207 }
Christopher Haster 17:7db2f5d503d4 208
Christopher Haster 17:7db2f5d503d4 209 if (s->rx_chain) {
Christopher Haster 17:7db2f5d503d4 210 pbuf_free(s->rx_chain);
Christopher Haster 17:7db2f5d503d4 211 s->rx_chain = 0;
Christopher Haster 17:7db2f5d503d4 212 }
Christopher Haster 17:7db2f5d503d4 213
Christopher Haster 17:7db2f5d503d4 214 delete s;
Christopher Haster 17:7db2f5d503d4 215
Christopher Haster 17:7db2f5d503d4 216 return err;
Christopher Haster 17:7db2f5d503d4 217 }
Christopher Haster 17:7db2f5d503d4 218
Christopher Haster 17:7db2f5d503d4 219
Christopher Haster 17:7db2f5d503d4 220 int LWIPInterface::socket_bind(void *handle, const SocketAddress &address)
Christopher Haster 17:7db2f5d503d4 221 {
Christopher Haster 17:7db2f5d503d4 222 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 223 ip_addr_t ip_addr = ip_addr_any; // TODO use address
Christopher Haster 17:7db2f5d503d4 224
Christopher Haster 17:7db2f5d503d4 225 switch (s->proto) {
Christopher Haster 17:7db2f5d503d4 226 case NSAPI_UDP:
Christopher Haster 17:7db2f5d503d4 227 if (udp_bind(s->udp, &ip_addr, address.get_port())) {
Christopher Haster 17:7db2f5d503d4 228 return NSAPI_ERROR_DEVICE_ERROR;
Christopher Haster 17:7db2f5d503d4 229 }
Christopher Haster 17:7db2f5d503d4 230 return 0;
Christopher Haster 17:7db2f5d503d4 231
Christopher Haster 17:7db2f5d503d4 232 case NSAPI_TCP:
Christopher Haster 17:7db2f5d503d4 233 if (tcp_bind(s->tcp, &ip_addr, address.get_port())) {
Christopher Haster 17:7db2f5d503d4 234 return NSAPI_ERROR_DEVICE_ERROR;
Christopher Haster 17:7db2f5d503d4 235 }
Christopher Haster 17:7db2f5d503d4 236 return 0;
Christopher Haster 17:7db2f5d503d4 237 }
Christopher Haster 17:7db2f5d503d4 238
Christopher Haster 17:7db2f5d503d4 239 return NSAPI_ERROR_DEVICE_ERROR;
Christopher Haster 17:7db2f5d503d4 240 }
Christopher Haster 17:7db2f5d503d4 241
Christopher Haster 21:9600bd29a088 242 static err_t tcp_accept_irq(void *arg, struct tcp_pcb *tpcb, err_t err);
Christopher Haster 21:9600bd29a088 243
Christopher Haster 17:7db2f5d503d4 244 int LWIPInterface::socket_listen(void *handle, int backlog)
Christopher Haster 17:7db2f5d503d4 245 {
Christopher Haster 21:9600bd29a088 246 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 21:9600bd29a088 247
Christopher Haster 21:9600bd29a088 248 if (s->tcp->state != LISTEN) {
Christopher Haster 21:9600bd29a088 249 struct tcp_pcb *server = tcp_listen(s->tcp);
Christopher Haster 21:9600bd29a088 250 if (!server) {
Christopher Haster 21:9600bd29a088 251 return NSAPI_ERROR_NO_SOCKET;
Christopher Haster 21:9600bd29a088 252 }
Christopher Haster 21:9600bd29a088 253
Christopher Haster 21:9600bd29a088 254 s->tcp = server;
Christopher Haster 21:9600bd29a088 255 s->npcb = 0;
Christopher Haster 21:9600bd29a088 256 }
Christopher Haster 21:9600bd29a088 257
Christopher Haster 21:9600bd29a088 258 tcp_arg(s->tcp, s);
Christopher Haster 21:9600bd29a088 259 tcp_accept(s->tcp, tcp_accept_irq);
Christopher Haster 21:9600bd29a088 260 return 0;
Christopher Haster 17:7db2f5d503d4 261 }
Christopher Haster 17:7db2f5d503d4 262
Christopher Haster 17:7db2f5d503d4 263 static err_t tcp_sent_irq(void *arg, struct tcp_pcb *tpcb, uint16_t len);
Christopher Haster 17:7db2f5d503d4 264 static err_t tcp_recv_irq(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
Christopher Haster 17:7db2f5d503d4 265
Christopher Haster 17:7db2f5d503d4 266 static err_t tcp_connect_irq(void *handle, struct tcp_pcb *tpcb, err_t err)
Christopher Haster 17:7db2f5d503d4 267 {
Christopher Haster 17:7db2f5d503d4 268 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 269 tcp_sent(tpcb, tcp_sent_irq);
Christopher Haster 17:7db2f5d503d4 270 tcp_recv(tpcb, tcp_recv_irq);
Christopher Haster 17:7db2f5d503d4 271
Christopher Haster 17:7db2f5d503d4 272 s->sem->release();
Christopher Haster 17:7db2f5d503d4 273
Christopher Haster 17:7db2f5d503d4 274 return ERR_OK;
Christopher Haster 17:7db2f5d503d4 275 }
Christopher Haster 17:7db2f5d503d4 276
Christopher Haster 17:7db2f5d503d4 277 int LWIPInterface::socket_connect(void *handle, const SocketAddress &addr)
Christopher Haster 17:7db2f5d503d4 278 {
Christopher Haster 17:7db2f5d503d4 279 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 280
Christopher Haster 17:7db2f5d503d4 281 ip_addr_t ip_addr;
Christopher Haster 17:7db2f5d503d4 282 inet_aton(addr.get_ip_address(), &ip_addr);
Christopher Haster 17:7db2f5d503d4 283
Christopher Haster 17:7db2f5d503d4 284 Semaphore connected(0);
Christopher Haster 17:7db2f5d503d4 285 s->sem = &connected;
Christopher Haster 17:7db2f5d503d4 286
Christopher Haster 17:7db2f5d503d4 287 tcp_connect(s->tcp, &ip_addr, addr.get_port(), tcp_connect_irq);
Christopher Haster 17:7db2f5d503d4 288
Christopher Haster 17:7db2f5d503d4 289 // Wait for connection
Christopher Haster 17:7db2f5d503d4 290 if (connected.wait(1500) < 0) {
Christopher Haster 17:7db2f5d503d4 291 return NSAPI_ERROR_NO_CONNECTION;
Christopher Haster 17:7db2f5d503d4 292 }
Christopher Haster 17:7db2f5d503d4 293
Christopher Haster 17:7db2f5d503d4 294 return 0;
Christopher Haster 17:7db2f5d503d4 295 }
Christopher Haster 17:7db2f5d503d4 296
Christopher Haster 21:9600bd29a088 297 static err_t tcp_refuse_irq(void *handle, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
Christopher Haster 21:9600bd29a088 298 {
Christopher Haster 21:9600bd29a088 299 return ERR_WOULDBLOCK;
Christopher Haster 21:9600bd29a088 300 }
Christopher Haster 21:9600bd29a088 301
Christopher Haster 21:9600bd29a088 302 static err_t tcp_accept_irq(void *handle, struct tcp_pcb *npcb, err_t err)
Christopher Haster 21:9600bd29a088 303 {
Christopher Haster 21:9600bd29a088 304 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 21:9600bd29a088 305 if (s->npcb) {
Christopher Haster 21:9600bd29a088 306 tcp_abort(npcb);
Christopher Haster 21:9600bd29a088 307 return ERR_ABRT;
Christopher Haster 21:9600bd29a088 308 }
Christopher Haster 21:9600bd29a088 309
Christopher Haster 21:9600bd29a088 310 tcp_recv(npcb, tcp_refuse_irq);
Christopher Haster 21:9600bd29a088 311 s->npcb = npcb;
Christopher Haster 21:9600bd29a088 312
Christopher Haster 21:9600bd29a088 313 if (s->callback) {
Christopher Haster 21:9600bd29a088 314 s->callback(s->data);
Christopher Haster 21:9600bd29a088 315 }
Christopher Haster 21:9600bd29a088 316
Christopher Haster 21:9600bd29a088 317 return ERR_OK;
Christopher Haster 21:9600bd29a088 318 }
Christopher Haster 21:9600bd29a088 319
Christopher Haster 17:7db2f5d503d4 320 int LWIPInterface::socket_accept(void **handle, void *server)
Christopher Haster 17:7db2f5d503d4 321 {
Christopher Haster 21:9600bd29a088 322 struct lwip_socket *s = (struct lwip_socket *)server;
Christopher Haster 21:9600bd29a088 323 if (!s->npcb) {
Christopher Haster 21:9600bd29a088 324 return NSAPI_ERROR_WOULD_BLOCK;
Christopher Haster 21:9600bd29a088 325 }
Christopher Haster 21:9600bd29a088 326
Christopher Haster 21:9600bd29a088 327 struct lwip_socket *ns = new struct lwip_socket;
Christopher Haster 21:9600bd29a088 328 if (!ns) {
Christopher Haster 21:9600bd29a088 329 return NSAPI_ERROR_NO_SOCKET;
Christopher Haster 21:9600bd29a088 330 }
Christopher Haster 21:9600bd29a088 331
Christopher Haster 21:9600bd29a088 332 memset(ns, 0, sizeof *ns);
Christopher Haster 21:9600bd29a088 333
Christopher Haster 21:9600bd29a088 334 ns->tcp = s->npcb;
Christopher Haster 21:9600bd29a088 335 s->npcb = 0;
Christopher Haster 21:9600bd29a088 336
Christopher Haster 21:9600bd29a088 337 tcp_accepted(ns->tcp);
Christopher Haster 21:9600bd29a088 338 tcp_arg(ns->tcp, ns);
Christopher Haster 21:9600bd29a088 339 //tcp_err(ns->tcp, tcp_error_irq);
Christopher Haster 21:9600bd29a088 340 tcp_sent(ns->tcp, tcp_sent_irq);
Christopher Haster 21:9600bd29a088 341 tcp_recv(ns->tcp, tcp_recv_irq);
Christopher Haster 21:9600bd29a088 342 *handle = ns;
Christopher Haster 21:9600bd29a088 343 return 0;
Christopher Haster 17:7db2f5d503d4 344 }
Christopher Haster 17:7db2f5d503d4 345
Christopher Haster 17:7db2f5d503d4 346 static struct pbuf *pbuf_consume(struct pbuf *p, size_t consume, bool free_partial)
Christopher Haster 17:7db2f5d503d4 347 {
Christopher Haster 17:7db2f5d503d4 348 do {
Christopher Haster 17:7db2f5d503d4 349 if (consume <= p->len) {
Christopher Haster 17:7db2f5d503d4 350 // advance the payload pointer by the number of bytes copied
Christopher Haster 17:7db2f5d503d4 351 p->payload = (char *)p->payload + consume;
Christopher Haster 17:7db2f5d503d4 352 // reduce the length by the number of bytes copied
Christopher Haster 17:7db2f5d503d4 353 p->len -= consume;
Christopher Haster 17:7db2f5d503d4 354 // break out of the loop
Christopher Haster 17:7db2f5d503d4 355 consume = 0;
Christopher Haster 17:7db2f5d503d4 356 }
Christopher Haster 17:7db2f5d503d4 357 if (p->len == 0 || consume > p->len || (consume == 0 && free_partial)) {
Christopher Haster 17:7db2f5d503d4 358 struct pbuf *q;
Christopher Haster 17:7db2f5d503d4 359 q = p->next;
Christopher Haster 17:7db2f5d503d4 360 // decrement the number of bytes copied by the length of the buffer
Christopher Haster 17:7db2f5d503d4 361 if(consume > p->len)
Christopher Haster 17:7db2f5d503d4 362 consume -= p->len;
Christopher Haster 17:7db2f5d503d4 363 // Free the current pbuf
Christopher Haster 17:7db2f5d503d4 364 // NOTE: This operation is interrupt safe, but not thread safe.
Christopher Haster 17:7db2f5d503d4 365 if (q != NULL) {
Christopher Haster 17:7db2f5d503d4 366 pbuf_ref(q);
Christopher Haster 17:7db2f5d503d4 367 }
Christopher Haster 17:7db2f5d503d4 368 pbuf_free(p);
Christopher Haster 17:7db2f5d503d4 369 p = q;
Christopher Haster 17:7db2f5d503d4 370 }
Christopher Haster 17:7db2f5d503d4 371 } while (consume);
Christopher Haster 17:7db2f5d503d4 372 return p;
Christopher Haster 17:7db2f5d503d4 373 }
Christopher Haster 17:7db2f5d503d4 374
Christopher Haster 17:7db2f5d503d4 375 static err_t tcp_sent_irq(void *handle, struct tcp_pcb *tpcb, uint16_t len)
Christopher Haster 17:7db2f5d503d4 376 {
Christopher Haster 17:7db2f5d503d4 377 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 378 if (s->callback) {
Christopher Haster 17:7db2f5d503d4 379 s->callback(s->data);
Christopher Haster 17:7db2f5d503d4 380 }
Christopher Haster 17:7db2f5d503d4 381
Christopher Haster 17:7db2f5d503d4 382 return ERR_OK;
Christopher Haster 17:7db2f5d503d4 383 }
Christopher Haster 17:7db2f5d503d4 384
Christopher Haster 17:7db2f5d503d4 385 int LWIPInterface::socket_send(void *handle, const void *buf, unsigned size)
Christopher Haster 17:7db2f5d503d4 386 {
Christopher Haster 17:7db2f5d503d4 387 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 388
Christopher Haster 17:7db2f5d503d4 389 if (tcp_write(s->tcp, buf, size, TCP_WRITE_FLAG_COPY)) {
Christopher Haster 17:7db2f5d503d4 390 return NSAPI_ERROR_DEVICE_ERROR;
Christopher Haster 17:7db2f5d503d4 391 }
Christopher Haster 17:7db2f5d503d4 392
Christopher Haster 17:7db2f5d503d4 393 tcp_output(s->tcp);
Christopher Haster 17:7db2f5d503d4 394
Christopher Haster 17:7db2f5d503d4 395 return size;
Christopher Haster 17:7db2f5d503d4 396 }
Christopher Haster 17:7db2f5d503d4 397
Christopher Haster 17:7db2f5d503d4 398 static err_t tcp_recv_irq(void *handle, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
Christopher Haster 17:7db2f5d503d4 399 {
Christopher Haster 17:7db2f5d503d4 400 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 401
Christopher Haster 17:7db2f5d503d4 402 // Check for disconnect
Christopher Haster 17:7db2f5d503d4 403 if (!p) {
Christopher Haster 17:7db2f5d503d4 404 // Zero pcb during disconnect, since disconnect will cause a free
Christopher Haster 17:7db2f5d503d4 405 switch (tpcb->state) {
Christopher Haster 17:7db2f5d503d4 406 case FIN_WAIT_1:
Christopher Haster 17:7db2f5d503d4 407 case FIN_WAIT_2:
Christopher Haster 17:7db2f5d503d4 408 case TIME_WAIT:
Christopher Haster 17:7db2f5d503d4 409 s->tcp = 0;
Christopher Haster 17:7db2f5d503d4 410 break;
Christopher Haster 17:7db2f5d503d4 411 default:
Christopher Haster 17:7db2f5d503d4 412 break;
Christopher Haster 17:7db2f5d503d4 413 }
Christopher Haster 17:7db2f5d503d4 414 return ERR_OK;
Christopher Haster 17:7db2f5d503d4 415 }
Christopher Haster 17:7db2f5d503d4 416
Christopher Haster 17:7db2f5d503d4 417 __disable_irq();
Christopher Haster 17:7db2f5d503d4 418 if (!s->rx_chain) {
Christopher Haster 17:7db2f5d503d4 419 s->rx_chain = p;
Christopher Haster 17:7db2f5d503d4 420 } else {
Christopher Haster 17:7db2f5d503d4 421 pbuf_cat(s->rx_chain, p);
Christopher Haster 17:7db2f5d503d4 422 }
Christopher Haster 17:7db2f5d503d4 423 __enable_irq();
Christopher Haster 17:7db2f5d503d4 424
Christopher Haster 17:7db2f5d503d4 425 if (s->callback) {
Christopher Haster 17:7db2f5d503d4 426 s->callback(s->data);
Christopher Haster 17:7db2f5d503d4 427 }
Christopher Haster 17:7db2f5d503d4 428
Christopher Haster 17:7db2f5d503d4 429 return ERR_OK;
Christopher Haster 17:7db2f5d503d4 430 }
Christopher Haster 17:7db2f5d503d4 431
Christopher Haster 17:7db2f5d503d4 432 int LWIPInterface::socket_recv(void *handle, void *buf, unsigned size)
Christopher Haster 17:7db2f5d503d4 433 {
Christopher Haster 17:7db2f5d503d4 434 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 435
Christopher Haster 17:7db2f5d503d4 436 // Disconnected
Christopher Haster 17:7db2f5d503d4 437 if (!s->tcp && !s->rx_chain) {
Christopher Haster 17:7db2f5d503d4 438 return NSAPI_ERROR_NO_CONNECTION;
Christopher Haster 17:7db2f5d503d4 439 }
Christopher Haster 17:7db2f5d503d4 440
Christopher Haster 17:7db2f5d503d4 441 // Nothing ready
Christopher Haster 17:7db2f5d503d4 442 if (!s->rx_chain) {
Christopher Haster 17:7db2f5d503d4 443 return NSAPI_ERROR_WOULD_BLOCK;
Christopher Haster 17:7db2f5d503d4 444 }
Christopher Haster 17:7db2f5d503d4 445
Christopher Haster 17:7db2f5d503d4 446 // Copy out pbuf
Christopher Haster 17:7db2f5d503d4 447 struct pbuf *p = s->rx_chain;
Christopher Haster 17:7db2f5d503d4 448 int copied = pbuf_copy_partial(p, buf, size, 0);
Christopher Haster 17:7db2f5d503d4 449 s->rx_chain = pbuf_consume(p, copied, false);
Christopher Haster 17:7db2f5d503d4 450
Christopher Haster 17:7db2f5d503d4 451 // Update TCP window
Christopher Haster 17:7db2f5d503d4 452 tcp_recved(s->tcp, copied);
Christopher Haster 17:7db2f5d503d4 453 return copied;
Christopher Haster 17:7db2f5d503d4 454 }
Christopher Haster 17:7db2f5d503d4 455
Christopher Haster 17:7db2f5d503d4 456 int LWIPInterface::socket_sendto(void *handle, const SocketAddress &addr, const void *buf, unsigned size)
Christopher Haster 17:7db2f5d503d4 457 {
Christopher Haster 17:7db2f5d503d4 458 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 459
Christopher Haster 17:7db2f5d503d4 460 struct pbuf *pb = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
Christopher Haster 17:7db2f5d503d4 461 if (pbuf_take(pb, buf, size)) {
Christopher Haster 17:7db2f5d503d4 462 return NSAPI_ERROR_DEVICE_ERROR;
Christopher Haster 17:7db2f5d503d4 463 }
Christopher Haster 17:7db2f5d503d4 464
Christopher Haster 17:7db2f5d503d4 465 ip_addr_t id_addr;
Christopher Haster 17:7db2f5d503d4 466 inet_aton(addr.get_ip_address(), &id_addr);
Christopher Haster 17:7db2f5d503d4 467
Christopher Haster 17:7db2f5d503d4 468 err_t err = udp_sendto(s->udp, pb, &id_addr, addr.get_port());
Christopher Haster 17:7db2f5d503d4 469 pbuf_free(pb);
Christopher Haster 17:7db2f5d503d4 470 if (err) {
Christopher Haster 17:7db2f5d503d4 471 return NSAPI_ERROR_DEVICE_ERROR;
Christopher Haster 17:7db2f5d503d4 472 }
Christopher Haster 17:7db2f5d503d4 473
Christopher Haster 17:7db2f5d503d4 474 if (s->callback) {
Christopher Haster 17:7db2f5d503d4 475 s->callback(s->data);
Christopher Haster 17:7db2f5d503d4 476 }
Christopher Haster 17:7db2f5d503d4 477
Christopher Haster 17:7db2f5d503d4 478 return size;
Christopher Haster 17:7db2f5d503d4 479 }
Christopher Haster 17:7db2f5d503d4 480
Christopher Haster 17:7db2f5d503d4 481 static void udp_recv_irq(
Christopher Haster 17:7db2f5d503d4 482 void *handle, struct udp_pcb *upcb, struct pbuf *p,
Christopher Haster 17:7db2f5d503d4 483 struct ip_addr *addr, uint16_t port)
Christopher Haster 17:7db2f5d503d4 484 {
Christopher Haster 17:7db2f5d503d4 485 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 486
Christopher Haster 17:7db2f5d503d4 487 __disable_irq();
Christopher Haster 17:7db2f5d503d4 488 if (!s->rx_chain) {
Christopher Haster 17:7db2f5d503d4 489 s->rx_chain = p;
Christopher Haster 17:7db2f5d503d4 490 } else {
Christopher Haster 17:7db2f5d503d4 491 // Attach p to buffer chain without changing the tot_len
Christopher Haster 17:7db2f5d503d4 492 // NOTE: This is not how pbufs are intended to work, but it is necessary to deal with
Christopher Haster 17:7db2f5d503d4 493 // a) fragmentation and b) packet queueing
Christopher Haster 17:7db2f5d503d4 494 struct pbuf *q = s->rx_chain;
Christopher Haster 17:7db2f5d503d4 495 while (q->next) { q = q->next; }
Christopher Haster 17:7db2f5d503d4 496 q->next = p;
Christopher Haster 17:7db2f5d503d4 497 }
Christopher Haster 17:7db2f5d503d4 498 __enable_irq();
Christopher Haster 17:7db2f5d503d4 499
Christopher Haster 17:7db2f5d503d4 500 if (s->callback) {
Christopher Haster 17:7db2f5d503d4 501 s->callback(s->data);
Christopher Haster 17:7db2f5d503d4 502 }
Christopher Haster 17:7db2f5d503d4 503 }
Christopher Haster 17:7db2f5d503d4 504
Christopher Haster 17:7db2f5d503d4 505 int LWIPInterface::socket_recvfrom(void *handle, SocketAddress *addr, void *buf, unsigned size)
Christopher Haster 17:7db2f5d503d4 506 {
Christopher Haster 17:7db2f5d503d4 507 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 508
Christopher Haster 17:7db2f5d503d4 509 // Disconnected
Christopher Haster 17:7db2f5d503d4 510 if (!s->udp && !s->rx_chain) {
Christopher Haster 17:7db2f5d503d4 511 return NSAPI_ERROR_NO_CONNECTION;
Christopher Haster 17:7db2f5d503d4 512 }
Christopher Haster 17:7db2f5d503d4 513
Christopher Haster 17:7db2f5d503d4 514 // Nothing ready
Christopher Haster 17:7db2f5d503d4 515 if (!s->rx_chain) {
Christopher Haster 17:7db2f5d503d4 516 return NSAPI_ERROR_WOULD_BLOCK;
Christopher Haster 17:7db2f5d503d4 517 }
Christopher Haster 17:7db2f5d503d4 518
Christopher Haster 17:7db2f5d503d4 519 struct pbuf *p = s->rx_chain;
Christopher Haster 17:7db2f5d503d4 520
Christopher Haster 17:7db2f5d503d4 521 if (addr) {
Christopher Haster 17:7db2f5d503d4 522 struct udp_hdr *udphdr;
Christopher Haster 17:7db2f5d503d4 523 struct ip_hdr *iphdr;
Christopher Haster 17:7db2f5d503d4 524
Christopher Haster 17:7db2f5d503d4 525 // roll back the pbuf by udp_hdr to find the source port
Christopher Haster 17:7db2f5d503d4 526 pbuf_header(p, UDP_HLEN);
Christopher Haster 17:7db2f5d503d4 527 udphdr = (struct udp_hdr *)p->payload;
Christopher Haster 17:7db2f5d503d4 528
Christopher Haster 17:7db2f5d503d4 529 // roll back the pbuf by ip_hdr to find the source IP
Christopher Haster 17:7db2f5d503d4 530 pbuf_header(p, IP_HLEN);
Christopher Haster 17:7db2f5d503d4 531 iphdr = (struct ip_hdr *)p->payload;
Christopher Haster 17:7db2f5d503d4 532
Christopher Haster 17:7db2f5d503d4 533 // put the pbuf back where it was
Christopher Haster 17:7db2f5d503d4 534 pbuf_header(p, -UDP_HLEN - IP_HLEN);
Christopher Haster 17:7db2f5d503d4 535
Christopher Haster 17:7db2f5d503d4 536 addr->set_ip_address(inet_ntoa(iphdr->src));
Christopher Haster 17:7db2f5d503d4 537 addr->set_port(ntohs(udphdr->src));
Christopher Haster 17:7db2f5d503d4 538 }
Christopher Haster 17:7db2f5d503d4 539
Christopher Haster 17:7db2f5d503d4 540 // Copy out pbuf
Christopher Haster 17:7db2f5d503d4 541 size = size < p->tot_len ? size : p->tot_len;
Christopher Haster 17:7db2f5d503d4 542 int copied = pbuf_copy_partial(p, buf, size, 0);
Christopher Haster 17:7db2f5d503d4 543 s->rx_chain = pbuf_consume(p, p->tot_len, true);
Christopher Haster 17:7db2f5d503d4 544
Christopher Haster 17:7db2f5d503d4 545 return copied;
Christopher Haster 17:7db2f5d503d4 546 }
Christopher Haster 17:7db2f5d503d4 547
Christopher Haster 17:7db2f5d503d4 548 void LWIPInterface::socket_attach(void *handle, void (*callback)(void *), void *data)
Christopher Haster 17:7db2f5d503d4 549 {
Christopher Haster 17:7db2f5d503d4 550 struct lwip_socket *s = (struct lwip_socket *)handle;
Christopher Haster 17:7db2f5d503d4 551 s->callback = callback;
Christopher Haster 17:7db2f5d503d4 552 s->data = data;
Christopher Haster 17:7db2f5d503d4 553 }