sandbox / LWIPInterface

Dependencies:   lwip-eth lwip-sys lwip

Fork of LWIPInterface by Christopher Haster

Committer:
Christopher Haster
Date:
Tue Apr 19 18:38:13 2016 -0500
Revision:
17:7db2f5d503d4
Parent:
16:1efb0d91c223
Child:
18:5890b186a607
Matched changes to the NSAPI

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