LwIP with PPP & Ethernet integration

Dependents:   NetworkingCoreLib

This is the mbed port of the LwIP stack: http://savannah.nongnu.org/projects/lwip/

It includes contributed content from NXP's port for LPCxxxx devices: http://www.lpcware.com/content/project/lightweight-ip-lwip-networking-stack

Licence

LwIP is licenced under the BSD licence:

Copyright (c) 2001-2004 Swedish Institute of Computer Science. 
All rights reserved. 
Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met: 
1. Redistributions of source code must retain the above copyright notice, 
this list of conditions and the following disclaimer. 
2. Redistributions in binary form must reproduce the above copyright notice, 
this list of conditions and the following disclaimer in the documentation 
and/or other materials provided with the distribution. 
3. The name of the author may not be used to endorse or promote products 
derived from this software without specific prior written permission. 
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.
Committer:
donatien
Date:
Fri May 25 08:56:35 2012 +0000
Revision:
2:1a87f74b8e3b
Parent:
0:8e01dca41002
Removed compilation of EMAC driver when using PPP

Who changed what in which revision?

UserRevisionLine numberNew contents of line
donatien 0:8e01dca41002 1 /**
donatien 0:8e01dca41002 2 * @file
donatien 0:8e01dca41002 3 * Sequential API Internal module
donatien 0:8e01dca41002 4 *
donatien 0:8e01dca41002 5 */
donatien 0:8e01dca41002 6
donatien 0:8e01dca41002 7 /*
donatien 0:8e01dca41002 8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
donatien 0:8e01dca41002 9 * All rights reserved.
donatien 0:8e01dca41002 10 *
donatien 0:8e01dca41002 11 * Redistribution and use in source and binary forms, with or without modification,
donatien 0:8e01dca41002 12 * are permitted provided that the following conditions are met:
donatien 0:8e01dca41002 13 *
donatien 0:8e01dca41002 14 * 1. Redistributions of source code must retain the above copyright notice,
donatien 0:8e01dca41002 15 * this list of conditions and the following disclaimer.
donatien 0:8e01dca41002 16 * 2. Redistributions in binary form must reproduce the above copyright notice,
donatien 0:8e01dca41002 17 * this list of conditions and the following disclaimer in the documentation
donatien 0:8e01dca41002 18 * and/or other materials provided with the distribution.
donatien 0:8e01dca41002 19 * 3. The name of the author may not be used to endorse or promote products
donatien 0:8e01dca41002 20 * derived from this software without specific prior written permission.
donatien 0:8e01dca41002 21 *
donatien 0:8e01dca41002 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
donatien 0:8e01dca41002 23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
donatien 0:8e01dca41002 24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
donatien 0:8e01dca41002 25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
donatien 0:8e01dca41002 26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
donatien 0:8e01dca41002 27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
donatien 0:8e01dca41002 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
donatien 0:8e01dca41002 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
donatien 0:8e01dca41002 30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
donatien 0:8e01dca41002 31 * OF SUCH DAMAGE.
donatien 0:8e01dca41002 32 *
donatien 0:8e01dca41002 33 * This file is part of the lwIP TCP/IP stack.
donatien 0:8e01dca41002 34 *
donatien 0:8e01dca41002 35 * Author: Adam Dunkels <adam@sics.se>
donatien 0:8e01dca41002 36 *
donatien 0:8e01dca41002 37 */
donatien 0:8e01dca41002 38
donatien 0:8e01dca41002 39 #include "lwip/opt.h"
donatien 0:8e01dca41002 40
donatien 0:8e01dca41002 41 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
donatien 0:8e01dca41002 42
donatien 0:8e01dca41002 43 #include "lwip/api_msg.h"
donatien 0:8e01dca41002 44
donatien 0:8e01dca41002 45 #include "lwip/ip.h"
donatien 0:8e01dca41002 46 #include "lwip/udp.h"
donatien 0:8e01dca41002 47 #include "lwip/tcp.h"
donatien 0:8e01dca41002 48 #include "lwip/raw.h"
donatien 0:8e01dca41002 49
donatien 0:8e01dca41002 50 #include "lwip/memp.h"
donatien 0:8e01dca41002 51 #include "lwip/tcpip.h"
donatien 0:8e01dca41002 52 #include "lwip/igmp.h"
donatien 0:8e01dca41002 53 #include "lwip/dns.h"
donatien 0:8e01dca41002 54
donatien 0:8e01dca41002 55 #include <string.h>
donatien 0:8e01dca41002 56
donatien 0:8e01dca41002 57 #define SET_NONBLOCKING_CONNECT(conn, val) do { if(val) { \
donatien 0:8e01dca41002 58 (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \
donatien 0:8e01dca41002 59 } else { \
donatien 0:8e01dca41002 60 (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0)
donatien 0:8e01dca41002 61 #define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0)
donatien 0:8e01dca41002 62
donatien 0:8e01dca41002 63 /* forward declarations */
donatien 0:8e01dca41002 64 #if LWIP_TCP
donatien 0:8e01dca41002 65 static err_t do_writemore(struct netconn *conn);
donatien 0:8e01dca41002 66 static void do_close_internal(struct netconn *conn);
donatien 0:8e01dca41002 67 #endif
donatien 0:8e01dca41002 68
donatien 0:8e01dca41002 69 #if LWIP_RAW
donatien 0:8e01dca41002 70 /**
donatien 0:8e01dca41002 71 * Receive callback function for RAW netconns.
donatien 0:8e01dca41002 72 * Doesn't 'eat' the packet, only references it and sends it to
donatien 0:8e01dca41002 73 * conn->recvmbox
donatien 0:8e01dca41002 74 *
donatien 0:8e01dca41002 75 * @see raw.h (struct raw_pcb.recv) for parameters and return value
donatien 0:8e01dca41002 76 */
donatien 0:8e01dca41002 77 static u8_t
donatien 0:8e01dca41002 78 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
donatien 0:8e01dca41002 79 ip_addr_t *addr)
donatien 0:8e01dca41002 80 {
donatien 0:8e01dca41002 81 struct pbuf *q;
donatien 0:8e01dca41002 82 struct netbuf *buf;
donatien 0:8e01dca41002 83 struct netconn *conn;
donatien 0:8e01dca41002 84
donatien 0:8e01dca41002 85 LWIP_UNUSED_ARG(addr);
donatien 0:8e01dca41002 86 conn = (struct netconn *)arg;
donatien 0:8e01dca41002 87
donatien 0:8e01dca41002 88 if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) {
donatien 0:8e01dca41002 89 #if LWIP_SO_RCVBUF
donatien 0:8e01dca41002 90 int recv_avail;
donatien 0:8e01dca41002 91 SYS_ARCH_GET(conn->recv_avail, recv_avail);
donatien 0:8e01dca41002 92 if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {
donatien 0:8e01dca41002 93 return 0;
donatien 0:8e01dca41002 94 }
donatien 0:8e01dca41002 95 #endif /* LWIP_SO_RCVBUF */
donatien 0:8e01dca41002 96 /* copy the whole packet into new pbufs */
donatien 0:8e01dca41002 97 q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
donatien 0:8e01dca41002 98 if(q != NULL) {
donatien 0:8e01dca41002 99 if (pbuf_copy(q, p) != ERR_OK) {
donatien 0:8e01dca41002 100 pbuf_free(q);
donatien 0:8e01dca41002 101 q = NULL;
donatien 0:8e01dca41002 102 }
donatien 0:8e01dca41002 103 }
donatien 0:8e01dca41002 104
donatien 0:8e01dca41002 105 if (q != NULL) {
donatien 0:8e01dca41002 106 u16_t len;
donatien 0:8e01dca41002 107 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
donatien 0:8e01dca41002 108 if (buf == NULL) {
donatien 0:8e01dca41002 109 pbuf_free(q);
donatien 0:8e01dca41002 110 return 0;
donatien 0:8e01dca41002 111 }
donatien 0:8e01dca41002 112
donatien 0:8e01dca41002 113 buf->p = q;
donatien 0:8e01dca41002 114 buf->ptr = q;
donatien 0:8e01dca41002 115 ip_addr_copy(buf->addr, *ip_current_src_addr());
donatien 0:8e01dca41002 116 buf->port = pcb->protocol;
donatien 0:8e01dca41002 117
donatien 0:8e01dca41002 118 len = q->tot_len;
donatien 0:8e01dca41002 119 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
donatien 0:8e01dca41002 120 netbuf_delete(buf);
donatien 0:8e01dca41002 121 return 0;
donatien 0:8e01dca41002 122 } else {
donatien 0:8e01dca41002 123 #if LWIP_SO_RCVBUF
donatien 0:8e01dca41002 124 SYS_ARCH_INC(conn->recv_avail, len);
donatien 0:8e01dca41002 125 #endif /* LWIP_SO_RCVBUF */
donatien 0:8e01dca41002 126 /* Register event with callback */
donatien 0:8e01dca41002 127 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
donatien 0:8e01dca41002 128 }
donatien 0:8e01dca41002 129 }
donatien 0:8e01dca41002 130 }
donatien 0:8e01dca41002 131
donatien 0:8e01dca41002 132 return 0; /* do not eat the packet */
donatien 0:8e01dca41002 133 }
donatien 0:8e01dca41002 134 #endif /* LWIP_RAW*/
donatien 0:8e01dca41002 135
donatien 0:8e01dca41002 136 #if LWIP_UDP
donatien 0:8e01dca41002 137 /**
donatien 0:8e01dca41002 138 * Receive callback function for UDP netconns.
donatien 0:8e01dca41002 139 * Posts the packet to conn->recvmbox or deletes it on memory error.
donatien 0:8e01dca41002 140 *
donatien 0:8e01dca41002 141 * @see udp.h (struct udp_pcb.recv) for parameters
donatien 0:8e01dca41002 142 */
donatien 0:8e01dca41002 143 static void
donatien 0:8e01dca41002 144 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
donatien 0:8e01dca41002 145 ip_addr_t *addr, u16_t port)
donatien 0:8e01dca41002 146 {
donatien 0:8e01dca41002 147 struct netbuf *buf;
donatien 0:8e01dca41002 148 struct netconn *conn;
donatien 0:8e01dca41002 149 u16_t len;
donatien 0:8e01dca41002 150 #if LWIP_SO_RCVBUF
donatien 0:8e01dca41002 151 int recv_avail;
donatien 0:8e01dca41002 152 #endif /* LWIP_SO_RCVBUF */
donatien 0:8e01dca41002 153
donatien 0:8e01dca41002 154 LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
donatien 0:8e01dca41002 155 LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
donatien 0:8e01dca41002 156 LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
donatien 0:8e01dca41002 157 conn = (struct netconn *)arg;
donatien 0:8e01dca41002 158 LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
donatien 0:8e01dca41002 159
donatien 0:8e01dca41002 160 #if LWIP_SO_RCVBUF
donatien 0:8e01dca41002 161 SYS_ARCH_GET(conn->recv_avail, recv_avail);
donatien 0:8e01dca41002 162 if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) ||
donatien 0:8e01dca41002 163 ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
donatien 0:8e01dca41002 164 #else /* LWIP_SO_RCVBUF */
donatien 0:8e01dca41002 165 if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) {
donatien 0:8e01dca41002 166 #endif /* LWIP_SO_RCVBUF */
donatien 0:8e01dca41002 167 pbuf_free(p);
donatien 0:8e01dca41002 168 return;
donatien 0:8e01dca41002 169 }
donatien 0:8e01dca41002 170
donatien 0:8e01dca41002 171 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
donatien 0:8e01dca41002 172 if (buf == NULL) {
donatien 0:8e01dca41002 173 pbuf_free(p);
donatien 0:8e01dca41002 174 return;
donatien 0:8e01dca41002 175 } else {
donatien 0:8e01dca41002 176 buf->p = p;
donatien 0:8e01dca41002 177 buf->ptr = p;
donatien 0:8e01dca41002 178 ip_addr_set(&buf->addr, addr);
donatien 0:8e01dca41002 179 buf->port = port;
donatien 0:8e01dca41002 180 #if LWIP_NETBUF_RECVINFO
donatien 0:8e01dca41002 181 {
donatien 0:8e01dca41002 182 const struct ip_hdr* iphdr = ip_current_header();
donatien 0:8e01dca41002 183 /* get the UDP header - always in the first pbuf, ensured by udp_input */
donatien 0:8e01dca41002 184 const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));
donatien 0:8e01dca41002 185 #if LWIP_CHECKSUM_ON_COPY
donatien 0:8e01dca41002 186 buf->flags = NETBUF_FLAG_DESTADDR;
donatien 0:8e01dca41002 187 #endif /* LWIP_CHECKSUM_ON_COPY */
donatien 0:8e01dca41002 188 ip_addr_set(&buf->toaddr, ip_current_dest_addr());
donatien 0:8e01dca41002 189 buf->toport_chksum = udphdr->dest;
donatien 0:8e01dca41002 190 }
donatien 0:8e01dca41002 191 #endif /* LWIP_NETBUF_RECVINFO */
donatien 0:8e01dca41002 192 }
donatien 0:8e01dca41002 193
donatien 0:8e01dca41002 194 len = p->tot_len;
donatien 0:8e01dca41002 195 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
donatien 0:8e01dca41002 196 netbuf_delete(buf);
donatien 0:8e01dca41002 197 return;
donatien 0:8e01dca41002 198 } else {
donatien 0:8e01dca41002 199 #if LWIP_SO_RCVBUF
donatien 0:8e01dca41002 200 SYS_ARCH_INC(conn->recv_avail, len);
donatien 0:8e01dca41002 201 #endif /* LWIP_SO_RCVBUF */
donatien 0:8e01dca41002 202 /* Register event with callback */
donatien 0:8e01dca41002 203 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
donatien 0:8e01dca41002 204 }
donatien 0:8e01dca41002 205 }
donatien 0:8e01dca41002 206 #endif /* LWIP_UDP */
donatien 0:8e01dca41002 207
donatien 0:8e01dca41002 208 #if LWIP_TCP
donatien 0:8e01dca41002 209 /**
donatien 0:8e01dca41002 210 * Receive callback function for TCP netconns.
donatien 0:8e01dca41002 211 * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
donatien 0:8e01dca41002 212 *
donatien 0:8e01dca41002 213 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
donatien 0:8e01dca41002 214 */
donatien 0:8e01dca41002 215 static err_t
donatien 0:8e01dca41002 216 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
donatien 0:8e01dca41002 217 {
donatien 0:8e01dca41002 218 struct netconn *conn;
donatien 0:8e01dca41002 219 u16_t len;
donatien 0:8e01dca41002 220
donatien 0:8e01dca41002 221 LWIP_UNUSED_ARG(pcb);
donatien 0:8e01dca41002 222 LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
donatien 0:8e01dca41002 223 LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
donatien 0:8e01dca41002 224 conn = (struct netconn *)arg;
donatien 0:8e01dca41002 225 LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
donatien 0:8e01dca41002 226
donatien 0:8e01dca41002 227 if (conn == NULL) {
donatien 0:8e01dca41002 228 return ERR_VAL;
donatien 0:8e01dca41002 229 }
donatien 0:8e01dca41002 230 if (!sys_mbox_valid(&conn->recvmbox)) {
donatien 0:8e01dca41002 231 /* recvmbox already deleted */
donatien 0:8e01dca41002 232 if (p != NULL) {
donatien 0:8e01dca41002 233 tcp_recved(pcb, p->tot_len);
donatien 0:8e01dca41002 234 pbuf_free(p);
donatien 0:8e01dca41002 235 }
donatien 0:8e01dca41002 236 return ERR_OK;
donatien 0:8e01dca41002 237 }
donatien 0:8e01dca41002 238 /* Unlike for UDP or RAW pcbs, don't check for available space
donatien 0:8e01dca41002 239 using recv_avail since that could break the connection
donatien 0:8e01dca41002 240 (data is already ACKed) */
donatien 0:8e01dca41002 241
donatien 0:8e01dca41002 242 /* don't overwrite fatal errors! */
donatien 0:8e01dca41002 243 NETCONN_SET_SAFE_ERR(conn, err);
donatien 0:8e01dca41002 244
donatien 0:8e01dca41002 245 if (p != NULL) {
donatien 0:8e01dca41002 246 len = p->tot_len;
donatien 0:8e01dca41002 247 } else {
donatien 0:8e01dca41002 248 len = 0;
donatien 0:8e01dca41002 249 }
donatien 0:8e01dca41002 250
donatien 0:8e01dca41002 251 if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) {
donatien 0:8e01dca41002 252 /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
donatien 0:8e01dca41002 253 return ERR_MEM;
donatien 0:8e01dca41002 254 } else {
donatien 0:8e01dca41002 255 #if LWIP_SO_RCVBUF
donatien 0:8e01dca41002 256 SYS_ARCH_INC(conn->recv_avail, len);
donatien 0:8e01dca41002 257 #endif /* LWIP_SO_RCVBUF */
donatien 0:8e01dca41002 258 /* Register event with callback */
donatien 0:8e01dca41002 259 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
donatien 0:8e01dca41002 260 }
donatien 0:8e01dca41002 261
donatien 0:8e01dca41002 262 return ERR_OK;
donatien 0:8e01dca41002 263 }
donatien 0:8e01dca41002 264
donatien 0:8e01dca41002 265 /**
donatien 0:8e01dca41002 266 * Poll callback function for TCP netconns.
donatien 0:8e01dca41002 267 * Wakes up an application thread that waits for a connection to close
donatien 0:8e01dca41002 268 * or data to be sent. The application thread then takes the
donatien 0:8e01dca41002 269 * appropriate action to go on.
donatien 0:8e01dca41002 270 *
donatien 0:8e01dca41002 271 * Signals the conn->sem.
donatien 0:8e01dca41002 272 * netconn_close waits for conn->sem if closing failed.
donatien 0:8e01dca41002 273 *
donatien 0:8e01dca41002 274 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
donatien 0:8e01dca41002 275 */
donatien 0:8e01dca41002 276 static err_t
donatien 0:8e01dca41002 277 poll_tcp(void *arg, struct tcp_pcb *pcb)
donatien 0:8e01dca41002 278 {
donatien 0:8e01dca41002 279 struct netconn *conn = (struct netconn *)arg;
donatien 0:8e01dca41002 280
donatien 0:8e01dca41002 281 LWIP_UNUSED_ARG(pcb);
donatien 0:8e01dca41002 282 LWIP_ASSERT("conn != NULL", (conn != NULL));
donatien 0:8e01dca41002 283
donatien 0:8e01dca41002 284 if (conn->state == NETCONN_WRITE) {
donatien 0:8e01dca41002 285 do_writemore(conn);
donatien 0:8e01dca41002 286 } else if (conn->state == NETCONN_CLOSE) {
donatien 0:8e01dca41002 287 do_close_internal(conn);
donatien 0:8e01dca41002 288 }
donatien 0:8e01dca41002 289 /* @todo: implement connect timeout here? */
donatien 0:8e01dca41002 290
donatien 0:8e01dca41002 291 /* Did a nonblocking write fail before? Then check available write-space. */
donatien 0:8e01dca41002 292 if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
donatien 0:8e01dca41002 293 /* If the queued byte- or pbuf-count drops below the configured low-water limit,
donatien 0:8e01dca41002 294 let select mark this pcb as writable again. */
donatien 0:8e01dca41002 295 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
donatien 0:8e01dca41002 296 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
donatien 0:8e01dca41002 297 conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
donatien 0:8e01dca41002 298 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
donatien 0:8e01dca41002 299 }
donatien 0:8e01dca41002 300 }
donatien 0:8e01dca41002 301
donatien 0:8e01dca41002 302 return ERR_OK;
donatien 0:8e01dca41002 303 }
donatien 0:8e01dca41002 304
donatien 0:8e01dca41002 305 /**
donatien 0:8e01dca41002 306 * Sent callback function for TCP netconns.
donatien 0:8e01dca41002 307 * Signals the conn->sem and calls API_EVENT.
donatien 0:8e01dca41002 308 * netconn_write waits for conn->sem if send buffer is low.
donatien 0:8e01dca41002 309 *
donatien 0:8e01dca41002 310 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
donatien 0:8e01dca41002 311 */
donatien 0:8e01dca41002 312 static err_t
donatien 0:8e01dca41002 313 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
donatien 0:8e01dca41002 314 {
donatien 0:8e01dca41002 315 struct netconn *conn = (struct netconn *)arg;
donatien 0:8e01dca41002 316
donatien 0:8e01dca41002 317 LWIP_UNUSED_ARG(pcb);
donatien 0:8e01dca41002 318 LWIP_ASSERT("conn != NULL", (conn != NULL));
donatien 0:8e01dca41002 319
donatien 0:8e01dca41002 320 if (conn->state == NETCONN_WRITE) {
donatien 0:8e01dca41002 321 do_writemore(conn);
donatien 0:8e01dca41002 322 } else if (conn->state == NETCONN_CLOSE) {
donatien 0:8e01dca41002 323 do_close_internal(conn);
donatien 0:8e01dca41002 324 }
donatien 0:8e01dca41002 325
donatien 0:8e01dca41002 326 if (conn) {
donatien 0:8e01dca41002 327 /* If the queued byte- or pbuf-count drops below the configured low-water limit,
donatien 0:8e01dca41002 328 let select mark this pcb as writable again. */
donatien 0:8e01dca41002 329 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
donatien 0:8e01dca41002 330 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
donatien 0:8e01dca41002 331 conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
donatien 0:8e01dca41002 332 API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
donatien 0:8e01dca41002 333 }
donatien 0:8e01dca41002 334 }
donatien 0:8e01dca41002 335
donatien 0:8e01dca41002 336 return ERR_OK;
donatien 0:8e01dca41002 337 }
donatien 0:8e01dca41002 338
donatien 0:8e01dca41002 339 /**
donatien 0:8e01dca41002 340 * Error callback function for TCP netconns.
donatien 0:8e01dca41002 341 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
donatien 0:8e01dca41002 342 * The application thread has then to decide what to do.
donatien 0:8e01dca41002 343 *
donatien 0:8e01dca41002 344 * @see tcp.h (struct tcp_pcb.err) for parameters
donatien 0:8e01dca41002 345 */
donatien 0:8e01dca41002 346 static void
donatien 0:8e01dca41002 347 err_tcp(void *arg, err_t err)
donatien 0:8e01dca41002 348 {
donatien 0:8e01dca41002 349 struct netconn *conn;
donatien 0:8e01dca41002 350 enum netconn_state old_state;
donatien 0:8e01dca41002 351 SYS_ARCH_DECL_PROTECT(lev);
donatien 0:8e01dca41002 352
donatien 0:8e01dca41002 353 conn = (struct netconn *)arg;
donatien 0:8e01dca41002 354 LWIP_ASSERT("conn != NULL", (conn != NULL));
donatien 0:8e01dca41002 355
donatien 0:8e01dca41002 356 conn->pcb.tcp = NULL;
donatien 0:8e01dca41002 357
donatien 0:8e01dca41002 358 /* no check since this is always fatal! */
donatien 0:8e01dca41002 359 SYS_ARCH_PROTECT(lev);
donatien 0:8e01dca41002 360 conn->last_err = err;
donatien 0:8e01dca41002 361 SYS_ARCH_UNPROTECT(lev);
donatien 0:8e01dca41002 362
donatien 0:8e01dca41002 363 /* reset conn->state now before waking up other threads */
donatien 0:8e01dca41002 364 old_state = conn->state;
donatien 0:8e01dca41002 365 conn->state = NETCONN_NONE;
donatien 0:8e01dca41002 366
donatien 0:8e01dca41002 367 /* Notify the user layer about a connection error. Used to signal
donatien 0:8e01dca41002 368 select. */
donatien 0:8e01dca41002 369 API_EVENT(conn, NETCONN_EVT_ERROR, 0);
donatien 0:8e01dca41002 370 /* Try to release selects pending on 'read' or 'write', too.
donatien 0:8e01dca41002 371 They will get an error if they actually try to read or write. */
donatien 0:8e01dca41002 372 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
donatien 0:8e01dca41002 373 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
donatien 0:8e01dca41002 374
donatien 0:8e01dca41002 375 /* pass NULL-message to recvmbox to wake up pending recv */
donatien 0:8e01dca41002 376 if (sys_mbox_valid(&conn->recvmbox)) {
donatien 0:8e01dca41002 377 /* use trypost to prevent deadlock */
donatien 0:8e01dca41002 378 sys_mbox_trypost(&conn->recvmbox, NULL);
donatien 0:8e01dca41002 379 }
donatien 0:8e01dca41002 380 /* pass NULL-message to acceptmbox to wake up pending accept */
donatien 0:8e01dca41002 381 if (sys_mbox_valid(&conn->acceptmbox)) {
donatien 0:8e01dca41002 382 /* use trypost to preven deadlock */
donatien 0:8e01dca41002 383 sys_mbox_trypost(&conn->acceptmbox, NULL);
donatien 0:8e01dca41002 384 }
donatien 0:8e01dca41002 385
donatien 0:8e01dca41002 386 if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
donatien 0:8e01dca41002 387 (old_state == NETCONN_CONNECT)) {
donatien 0:8e01dca41002 388 /* calling do_writemore/do_close_internal is not necessary
donatien 0:8e01dca41002 389 since the pcb has already been deleted! */
donatien 0:8e01dca41002 390 int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
donatien 0:8e01dca41002 391 SET_NONBLOCKING_CONNECT(conn, 0);
donatien 0:8e01dca41002 392
donatien 0:8e01dca41002 393 if (!was_nonblocking_connect) {
donatien 0:8e01dca41002 394 /* set error return code */
donatien 0:8e01dca41002 395 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
donatien 0:8e01dca41002 396 conn->current_msg->err = err;
donatien 0:8e01dca41002 397 conn->current_msg = NULL;
donatien 0:8e01dca41002 398 /* wake up the waiting task */
donatien 0:8e01dca41002 399 sys_sem_signal(&conn->op_completed);
donatien 0:8e01dca41002 400 }
donatien 0:8e01dca41002 401 } else {
donatien 0:8e01dca41002 402 LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
donatien 0:8e01dca41002 403 }
donatien 0:8e01dca41002 404 }
donatien 0:8e01dca41002 405
donatien 0:8e01dca41002 406 /**
donatien 0:8e01dca41002 407 * Setup a tcp_pcb with the correct callback function pointers
donatien 0:8e01dca41002 408 * and their arguments.
donatien 0:8e01dca41002 409 *
donatien 0:8e01dca41002 410 * @param conn the TCP netconn to setup
donatien 0:8e01dca41002 411 */
donatien 0:8e01dca41002 412 static void
donatien 0:8e01dca41002 413 setup_tcp(struct netconn *conn)
donatien 0:8e01dca41002 414 {
donatien 0:8e01dca41002 415 struct tcp_pcb *pcb;
donatien 0:8e01dca41002 416
donatien 0:8e01dca41002 417 pcb = conn->pcb.tcp;
donatien 0:8e01dca41002 418 tcp_arg(pcb, conn);
donatien 0:8e01dca41002 419 tcp_recv(pcb, recv_tcp);
donatien 0:8e01dca41002 420 tcp_sent(pcb, sent_tcp);
donatien 0:8e01dca41002 421 tcp_poll(pcb, poll_tcp, 4);
donatien 0:8e01dca41002 422 tcp_err(pcb, err_tcp);
donatien 0:8e01dca41002 423 }
donatien 0:8e01dca41002 424
donatien 0:8e01dca41002 425 /**
donatien 0:8e01dca41002 426 * Accept callback function for TCP netconns.
donatien 0:8e01dca41002 427 * Allocates a new netconn and posts that to conn->acceptmbox.
donatien 0:8e01dca41002 428 *
donatien 0:8e01dca41002 429 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
donatien 0:8e01dca41002 430 */
donatien 0:8e01dca41002 431 static err_t
donatien 0:8e01dca41002 432 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
donatien 0:8e01dca41002 433 {
donatien 0:8e01dca41002 434 struct netconn *newconn;
donatien 0:8e01dca41002 435 struct netconn *conn = (struct netconn *)arg;
donatien 0:8e01dca41002 436
donatien 0:8e01dca41002 437 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state)));
donatien 0:8e01dca41002 438
donatien 0:8e01dca41002 439 if (!sys_mbox_valid(&conn->acceptmbox)) {
donatien 0:8e01dca41002 440 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
donatien 0:8e01dca41002 441 return ERR_VAL;
donatien 0:8e01dca41002 442 }
donatien 0:8e01dca41002 443
donatien 0:8e01dca41002 444 /* We have to set the callback here even though
donatien 0:8e01dca41002 445 * the new socket is unknown. conn->socket is marked as -1. */
donatien 0:8e01dca41002 446 newconn = netconn_alloc(conn->type, conn->callback);
donatien 0:8e01dca41002 447 if (newconn == NULL) {
donatien 0:8e01dca41002 448 return ERR_MEM;
donatien 0:8e01dca41002 449 }
donatien 0:8e01dca41002 450 newconn->pcb.tcp = newpcb;
donatien 0:8e01dca41002 451 setup_tcp(newconn);
donatien 0:8e01dca41002 452 /* no protection: when creating the pcb, the netconn is not yet known
donatien 0:8e01dca41002 453 to the application thread */
donatien 0:8e01dca41002 454 newconn->last_err = err;
donatien 0:8e01dca41002 455
donatien 0:8e01dca41002 456 if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
donatien 0:8e01dca41002 457 /* When returning != ERR_OK, the pcb is aborted in tcp_process(),
donatien 0:8e01dca41002 458 so do nothing here! */
donatien 0:8e01dca41002 459 newconn->pcb.tcp = NULL;
donatien 0:8e01dca41002 460 /* no need to drain since we know the recvmbox is empty. */
donatien 0:8e01dca41002 461 sys_mbox_free(&newconn->recvmbox);
donatien 0:8e01dca41002 462 sys_mbox_set_invalid(&newconn->recvmbox);
donatien 0:8e01dca41002 463 netconn_free(newconn);
donatien 0:8e01dca41002 464 return ERR_MEM;
donatien 0:8e01dca41002 465 } else {
donatien 0:8e01dca41002 466 /* Register event with callback */
donatien 0:8e01dca41002 467 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
donatien 0:8e01dca41002 468 }
donatien 0:8e01dca41002 469
donatien 0:8e01dca41002 470 return ERR_OK;
donatien 0:8e01dca41002 471 }
donatien 0:8e01dca41002 472 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 473
donatien 0:8e01dca41002 474 /**
donatien 0:8e01dca41002 475 * Create a new pcb of a specific type.
donatien 0:8e01dca41002 476 * Called from do_newconn().
donatien 0:8e01dca41002 477 *
donatien 0:8e01dca41002 478 * @param msg the api_msg_msg describing the connection type
donatien 0:8e01dca41002 479 * @return msg->conn->err, but the return value is currently ignored
donatien 0:8e01dca41002 480 */
donatien 0:8e01dca41002 481 static void
donatien 0:8e01dca41002 482 pcb_new(struct api_msg_msg *msg)
donatien 0:8e01dca41002 483 {
donatien 0:8e01dca41002 484 LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
donatien 0:8e01dca41002 485
donatien 0:8e01dca41002 486 /* Allocate a PCB for this connection */
donatien 0:8e01dca41002 487 switch(NETCONNTYPE_GROUP(msg->conn->type)) {
donatien 0:8e01dca41002 488 #if LWIP_RAW
donatien 0:8e01dca41002 489 case NETCONN_RAW:
donatien 0:8e01dca41002 490 msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
donatien 0:8e01dca41002 491 if(msg->conn->pcb.raw == NULL) {
donatien 0:8e01dca41002 492 msg->err = ERR_MEM;
donatien 0:8e01dca41002 493 break;
donatien 0:8e01dca41002 494 }
donatien 0:8e01dca41002 495 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
donatien 0:8e01dca41002 496 break;
donatien 0:8e01dca41002 497 #endif /* LWIP_RAW */
donatien 0:8e01dca41002 498 #if LWIP_UDP
donatien 0:8e01dca41002 499 case NETCONN_UDP:
donatien 0:8e01dca41002 500 msg->conn->pcb.udp = udp_new();
donatien 0:8e01dca41002 501 if(msg->conn->pcb.udp == NULL) {
donatien 0:8e01dca41002 502 msg->err = ERR_MEM;
donatien 0:8e01dca41002 503 break;
donatien 0:8e01dca41002 504 }
donatien 0:8e01dca41002 505 #if LWIP_UDPLITE
donatien 0:8e01dca41002 506 if (msg->conn->type==NETCONN_UDPLITE) {
donatien 0:8e01dca41002 507 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
donatien 0:8e01dca41002 508 }
donatien 0:8e01dca41002 509 #endif /* LWIP_UDPLITE */
donatien 0:8e01dca41002 510 if (msg->conn->type==NETCONN_UDPNOCHKSUM) {
donatien 0:8e01dca41002 511 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
donatien 0:8e01dca41002 512 }
donatien 0:8e01dca41002 513 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
donatien 0:8e01dca41002 514 break;
donatien 0:8e01dca41002 515 #endif /* LWIP_UDP */
donatien 0:8e01dca41002 516 #if LWIP_TCP
donatien 0:8e01dca41002 517 case NETCONN_TCP:
donatien 0:8e01dca41002 518 msg->conn->pcb.tcp = tcp_new();
donatien 0:8e01dca41002 519 if(msg->conn->pcb.tcp == NULL) {
donatien 0:8e01dca41002 520 msg->err = ERR_MEM;
donatien 0:8e01dca41002 521 break;
donatien 0:8e01dca41002 522 }
donatien 0:8e01dca41002 523 setup_tcp(msg->conn);
donatien 0:8e01dca41002 524 break;
donatien 0:8e01dca41002 525 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 526 default:
donatien 0:8e01dca41002 527 /* Unsupported netconn type, e.g. protocol disabled */
donatien 0:8e01dca41002 528 msg->err = ERR_VAL;
donatien 0:8e01dca41002 529 break;
donatien 0:8e01dca41002 530 }
donatien 0:8e01dca41002 531 }
donatien 0:8e01dca41002 532
donatien 0:8e01dca41002 533 /**
donatien 0:8e01dca41002 534 * Create a new pcb of a specific type inside a netconn.
donatien 0:8e01dca41002 535 * Called from netconn_new_with_proto_and_callback.
donatien 0:8e01dca41002 536 *
donatien 0:8e01dca41002 537 * @param msg the api_msg_msg describing the connection type
donatien 0:8e01dca41002 538 */
donatien 0:8e01dca41002 539 void
donatien 0:8e01dca41002 540 do_newconn(struct api_msg_msg *msg)
donatien 0:8e01dca41002 541 {
donatien 0:8e01dca41002 542 msg->err = ERR_OK;
donatien 0:8e01dca41002 543 if(msg->conn->pcb.tcp == NULL) {
donatien 0:8e01dca41002 544 pcb_new(msg);
donatien 0:8e01dca41002 545 }
donatien 0:8e01dca41002 546 /* Else? This "new" connection already has a PCB allocated. */
donatien 0:8e01dca41002 547 /* Is this an error condition? Should it be deleted? */
donatien 0:8e01dca41002 548 /* We currently just are happy and return. */
donatien 0:8e01dca41002 549
donatien 0:8e01dca41002 550 TCPIP_APIMSG_ACK(msg);
donatien 0:8e01dca41002 551 }
donatien 0:8e01dca41002 552
donatien 0:8e01dca41002 553 /**
donatien 0:8e01dca41002 554 * Create a new netconn (of a specific type) that has a callback function.
donatien 0:8e01dca41002 555 * The corresponding pcb is NOT created!
donatien 0:8e01dca41002 556 *
donatien 0:8e01dca41002 557 * @param t the type of 'connection' to create (@see enum netconn_type)
donatien 0:8e01dca41002 558 * @param proto the IP protocol for RAW IP pcbs
donatien 0:8e01dca41002 559 * @param callback a function to call on status changes (RX available, TX'ed)
donatien 0:8e01dca41002 560 * @return a newly allocated struct netconn or
donatien 0:8e01dca41002 561 * NULL on memory error
donatien 0:8e01dca41002 562 */
donatien 0:8e01dca41002 563 struct netconn*
donatien 0:8e01dca41002 564 netconn_alloc(enum netconn_type t, netconn_callback callback)
donatien 0:8e01dca41002 565 {
donatien 0:8e01dca41002 566 struct netconn *conn;
donatien 0:8e01dca41002 567 int size = 0;
donatien 0:8e01dca41002 568
donatien 0:8e01dca41002 569 conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
donatien 0:8e01dca41002 570 if (conn == NULL) {
donatien 0:8e01dca41002 571 return NULL;
donatien 0:8e01dca41002 572 }
donatien 0:8e01dca41002 573
donatien 0:8e01dca41002 574 conn->last_err = ERR_OK;
donatien 0:8e01dca41002 575 conn->type = t;
donatien 0:8e01dca41002 576 conn->pcb.tcp = NULL;
donatien 0:8e01dca41002 577
donatien 0:8e01dca41002 578 #if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \
donatien 0:8e01dca41002 579 (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE)
donatien 0:8e01dca41002 580 size = DEFAULT_RAW_RECVMBOX_SIZE;
donatien 0:8e01dca41002 581 #else
donatien 0:8e01dca41002 582 switch(NETCONNTYPE_GROUP(t)) {
donatien 0:8e01dca41002 583 #if LWIP_RAW
donatien 0:8e01dca41002 584 case NETCONN_RAW:
donatien 0:8e01dca41002 585 size = DEFAULT_RAW_RECVMBOX_SIZE;
donatien 0:8e01dca41002 586 break;
donatien 0:8e01dca41002 587 #endif /* LWIP_RAW */
donatien 0:8e01dca41002 588 #if LWIP_UDP
donatien 0:8e01dca41002 589 case NETCONN_UDP:
donatien 0:8e01dca41002 590 size = DEFAULT_UDP_RECVMBOX_SIZE;
donatien 0:8e01dca41002 591 break;
donatien 0:8e01dca41002 592 #endif /* LWIP_UDP */
donatien 0:8e01dca41002 593 #if LWIP_TCP
donatien 0:8e01dca41002 594 case NETCONN_TCP:
donatien 0:8e01dca41002 595 size = DEFAULT_TCP_RECVMBOX_SIZE;
donatien 0:8e01dca41002 596 break;
donatien 0:8e01dca41002 597 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 598 default:
donatien 0:8e01dca41002 599 LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
donatien 0:8e01dca41002 600 break;
donatien 0:8e01dca41002 601 }
donatien 0:8e01dca41002 602 #endif
donatien 0:8e01dca41002 603
donatien 0:8e01dca41002 604 if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
donatien 0:8e01dca41002 605 memp_free(MEMP_NETCONN, conn);
donatien 0:8e01dca41002 606 return NULL;
donatien 0:8e01dca41002 607 }
donatien 0:8e01dca41002 608 if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
donatien 0:8e01dca41002 609 sys_sem_free(&conn->op_completed);
donatien 0:8e01dca41002 610 memp_free(MEMP_NETCONN, conn);
donatien 0:8e01dca41002 611 return NULL;
donatien 0:8e01dca41002 612 }
donatien 0:8e01dca41002 613
donatien 0:8e01dca41002 614 #if LWIP_TCP
donatien 0:8e01dca41002 615 sys_mbox_set_invalid(&conn->acceptmbox);
donatien 0:8e01dca41002 616 #endif
donatien 0:8e01dca41002 617 conn->state = NETCONN_NONE;
donatien 0:8e01dca41002 618 #if LWIP_SOCKET
donatien 0:8e01dca41002 619 /* initialize socket to -1 since 0 is a valid socket */
donatien 0:8e01dca41002 620 conn->socket = -1;
donatien 0:8e01dca41002 621 #endif /* LWIP_SOCKET */
donatien 0:8e01dca41002 622 conn->callback = callback;
donatien 0:8e01dca41002 623 #if LWIP_TCP
donatien 0:8e01dca41002 624 conn->current_msg = NULL;
donatien 0:8e01dca41002 625 conn->write_offset = 0;
donatien 0:8e01dca41002 626 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 627 #if LWIP_SO_RCVTIMEO
donatien 0:8e01dca41002 628 conn->recv_timeout = 0;
donatien 0:8e01dca41002 629 #endif /* LWIP_SO_RCVTIMEO */
donatien 0:8e01dca41002 630 #if LWIP_SO_RCVBUF
donatien 0:8e01dca41002 631 conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
donatien 0:8e01dca41002 632 conn->recv_avail = 0;
donatien 0:8e01dca41002 633 #endif /* LWIP_SO_RCVBUF */
donatien 0:8e01dca41002 634 conn->flags = 0;
donatien 0:8e01dca41002 635 return conn;
donatien 0:8e01dca41002 636 }
donatien 0:8e01dca41002 637
donatien 0:8e01dca41002 638 /**
donatien 0:8e01dca41002 639 * Delete a netconn and all its resources.
donatien 0:8e01dca41002 640 * The pcb is NOT freed (since we might not be in the right thread context do this).
donatien 0:8e01dca41002 641 *
donatien 0:8e01dca41002 642 * @param conn the netconn to free
donatien 0:8e01dca41002 643 */
donatien 0:8e01dca41002 644 void
donatien 0:8e01dca41002 645 netconn_free(struct netconn *conn)
donatien 0:8e01dca41002 646 {
donatien 0:8e01dca41002 647 LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
donatien 0:8e01dca41002 648 LWIP_ASSERT("recvmbox must be deallocated before calling this function",
donatien 0:8e01dca41002 649 !sys_mbox_valid(&conn->recvmbox));
donatien 0:8e01dca41002 650 #if LWIP_TCP
donatien 0:8e01dca41002 651 LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
donatien 0:8e01dca41002 652 !sys_mbox_valid(&conn->acceptmbox));
donatien 0:8e01dca41002 653 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 654
donatien 0:8e01dca41002 655 sys_sem_free(&conn->op_completed);
donatien 0:8e01dca41002 656 sys_sem_set_invalid(&conn->op_completed);
donatien 0:8e01dca41002 657
donatien 0:8e01dca41002 658 memp_free(MEMP_NETCONN, conn);
donatien 0:8e01dca41002 659 }
donatien 0:8e01dca41002 660
donatien 0:8e01dca41002 661 /**
donatien 0:8e01dca41002 662 * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in
donatien 0:8e01dca41002 663 * these mboxes
donatien 0:8e01dca41002 664 *
donatien 0:8e01dca41002 665 * @param conn the netconn to free
donatien 0:8e01dca41002 666 * @bytes_drained bytes drained from recvmbox
donatien 0:8e01dca41002 667 * @accepts_drained pending connections drained from acceptmbox
donatien 0:8e01dca41002 668 */
donatien 0:8e01dca41002 669 static void
donatien 0:8e01dca41002 670 netconn_drain(struct netconn *conn)
donatien 0:8e01dca41002 671 {
donatien 0:8e01dca41002 672 void *mem;
donatien 0:8e01dca41002 673 #if LWIP_TCP
donatien 0:8e01dca41002 674 struct pbuf *p;
donatien 0:8e01dca41002 675 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 676
donatien 0:8e01dca41002 677 /* This runs in tcpip_thread, so we don't need to lock against rx packets */
donatien 0:8e01dca41002 678
donatien 0:8e01dca41002 679 /* Delete and drain the recvmbox. */
donatien 0:8e01dca41002 680 if (sys_mbox_valid(&conn->recvmbox)) {
donatien 0:8e01dca41002 681 while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
donatien 0:8e01dca41002 682 #if LWIP_TCP
donatien 0:8e01dca41002 683 if (conn->type == NETCONN_TCP) {
donatien 0:8e01dca41002 684 if(mem != NULL) {
donatien 0:8e01dca41002 685 p = (struct pbuf*)mem;
donatien 0:8e01dca41002 686 /* pcb might be set to NULL already by err_tcp() */
donatien 0:8e01dca41002 687 if (conn->pcb.tcp != NULL) {
donatien 0:8e01dca41002 688 tcp_recved(conn->pcb.tcp, p->tot_len);
donatien 0:8e01dca41002 689 }
donatien 0:8e01dca41002 690 pbuf_free(p);
donatien 0:8e01dca41002 691 }
donatien 0:8e01dca41002 692 } else
donatien 0:8e01dca41002 693 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 694 {
donatien 0:8e01dca41002 695 netbuf_delete((struct netbuf *)mem);
donatien 0:8e01dca41002 696 }
donatien 0:8e01dca41002 697 }
donatien 0:8e01dca41002 698 sys_mbox_free(&conn->recvmbox);
donatien 0:8e01dca41002 699 sys_mbox_set_invalid(&conn->recvmbox);
donatien 0:8e01dca41002 700 }
donatien 0:8e01dca41002 701
donatien 0:8e01dca41002 702 /* Delete and drain the acceptmbox. */
donatien 0:8e01dca41002 703 #if LWIP_TCP
donatien 0:8e01dca41002 704 if (sys_mbox_valid(&conn->acceptmbox)) {
donatien 0:8e01dca41002 705 while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
donatien 0:8e01dca41002 706 struct netconn *newconn = (struct netconn *)mem;
donatien 0:8e01dca41002 707 /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
donatien 0:8e01dca41002 708 /* pcb might be set to NULL already by err_tcp() */
donatien 0:8e01dca41002 709 if (conn->pcb.tcp != NULL) {
donatien 0:8e01dca41002 710 tcp_accepted(conn->pcb.tcp);
donatien 0:8e01dca41002 711 }
donatien 0:8e01dca41002 712 /* drain recvmbox */
donatien 0:8e01dca41002 713 netconn_drain(newconn);
donatien 0:8e01dca41002 714 if (newconn->pcb.tcp != NULL) {
donatien 0:8e01dca41002 715 tcp_abort(newconn->pcb.tcp);
donatien 0:8e01dca41002 716 newconn->pcb.tcp = NULL;
donatien 0:8e01dca41002 717 }
donatien 0:8e01dca41002 718 netconn_free(newconn);
donatien 0:8e01dca41002 719 }
donatien 0:8e01dca41002 720 sys_mbox_free(&conn->acceptmbox);
donatien 0:8e01dca41002 721 sys_mbox_set_invalid(&conn->acceptmbox);
donatien 0:8e01dca41002 722 }
donatien 0:8e01dca41002 723 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 724 }
donatien 0:8e01dca41002 725
donatien 0:8e01dca41002 726 #if LWIP_TCP
donatien 0:8e01dca41002 727 /**
donatien 0:8e01dca41002 728 * Internal helper function to close a TCP netconn: since this sometimes
donatien 0:8e01dca41002 729 * doesn't work at the first attempt, this function is called from multiple
donatien 0:8e01dca41002 730 * places.
donatien 0:8e01dca41002 731 *
donatien 0:8e01dca41002 732 * @param conn the TCP netconn to close
donatien 0:8e01dca41002 733 */
donatien 0:8e01dca41002 734 static void
donatien 0:8e01dca41002 735 do_close_internal(struct netconn *conn)
donatien 0:8e01dca41002 736 {
donatien 0:8e01dca41002 737 err_t err;
donatien 0:8e01dca41002 738 u8_t shut, shut_rx, shut_tx, close;
donatien 0:8e01dca41002 739
donatien 0:8e01dca41002 740 LWIP_ASSERT("invalid conn", (conn != NULL));
donatien 0:8e01dca41002 741 LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));
donatien 0:8e01dca41002 742 LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
donatien 0:8e01dca41002 743 LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
donatien 0:8e01dca41002 744 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
donatien 0:8e01dca41002 745
donatien 0:8e01dca41002 746 shut = conn->current_msg->msg.sd.shut;
donatien 0:8e01dca41002 747 shut_rx = shut & NETCONN_SHUT_RD;
donatien 0:8e01dca41002 748 shut_tx = shut & NETCONN_SHUT_WR;
donatien 0:8e01dca41002 749 /* shutting down both ends is the same as closing */
donatien 0:8e01dca41002 750 close = shut == NETCONN_SHUT_RDWR;
donatien 0:8e01dca41002 751
donatien 0:8e01dca41002 752 /* Set back some callback pointers */
donatien 0:8e01dca41002 753 if (close) {
donatien 0:8e01dca41002 754 tcp_arg(conn->pcb.tcp, NULL);
donatien 0:8e01dca41002 755 }
donatien 0:8e01dca41002 756 if (conn->pcb.tcp->state == LISTEN) {
donatien 0:8e01dca41002 757 tcp_accept(conn->pcb.tcp, NULL);
donatien 0:8e01dca41002 758 } else {
donatien 0:8e01dca41002 759 /* some callbacks have to be reset if tcp_close is not successful */
donatien 0:8e01dca41002 760 if (shut_rx) {
donatien 0:8e01dca41002 761 tcp_recv(conn->pcb.tcp, NULL);
donatien 0:8e01dca41002 762 tcp_accept(conn->pcb.tcp, NULL);
donatien 0:8e01dca41002 763 }
donatien 0:8e01dca41002 764 if (shut_tx) {
donatien 0:8e01dca41002 765 tcp_sent(conn->pcb.tcp, NULL);
donatien 0:8e01dca41002 766 }
donatien 0:8e01dca41002 767 if (close) {
donatien 0:8e01dca41002 768 tcp_poll(conn->pcb.tcp, NULL, 4);
donatien 0:8e01dca41002 769 tcp_err(conn->pcb.tcp, NULL);
donatien 0:8e01dca41002 770 }
donatien 0:8e01dca41002 771 }
donatien 0:8e01dca41002 772 /* Try to close the connection */
donatien 0:8e01dca41002 773 if (shut == NETCONN_SHUT_RDWR) {
donatien 0:8e01dca41002 774 err = tcp_close(conn->pcb.tcp);
donatien 0:8e01dca41002 775 } else {
donatien 0:8e01dca41002 776 err = tcp_shutdown(conn->pcb.tcp, shut & NETCONN_SHUT_RD, shut & NETCONN_SHUT_WR);
donatien 0:8e01dca41002 777 }
donatien 0:8e01dca41002 778 if (err == ERR_OK) {
donatien 0:8e01dca41002 779 /* Closing succeeded */
donatien 0:8e01dca41002 780 conn->current_msg->err = ERR_OK;
donatien 0:8e01dca41002 781 conn->current_msg = NULL;
donatien 0:8e01dca41002 782 conn->state = NETCONN_NONE;
donatien 0:8e01dca41002 783 /* Set back some callback pointers as conn is going away */
donatien 0:8e01dca41002 784 conn->pcb.tcp = NULL;
donatien 0:8e01dca41002 785 /* Trigger select() in socket layer. Make sure everybody notices activity
donatien 0:8e01dca41002 786 on the connection, error first! */
donatien 0:8e01dca41002 787 if (close) {
donatien 0:8e01dca41002 788 API_EVENT(conn, NETCONN_EVT_ERROR, 0);
donatien 0:8e01dca41002 789 }
donatien 0:8e01dca41002 790 if (shut_rx) {
donatien 0:8e01dca41002 791 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
donatien 0:8e01dca41002 792 }
donatien 0:8e01dca41002 793 if (shut_tx) {
donatien 0:8e01dca41002 794 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
donatien 0:8e01dca41002 795 }
donatien 0:8e01dca41002 796 /* wake up the application task */
donatien 0:8e01dca41002 797 sys_sem_signal(&conn->op_completed);
donatien 0:8e01dca41002 798 } else {
donatien 0:8e01dca41002 799 /* Closing failed, restore some of the callbacks */
donatien 0:8e01dca41002 800 /* Closing of listen pcb will never fail! */
donatien 0:8e01dca41002 801 LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN));
donatien 0:8e01dca41002 802 tcp_sent(conn->pcb.tcp, sent_tcp);
donatien 0:8e01dca41002 803 tcp_poll(conn->pcb.tcp, poll_tcp, 4);
donatien 0:8e01dca41002 804 tcp_err(conn->pcb.tcp, err_tcp);
donatien 0:8e01dca41002 805 tcp_arg(conn->pcb.tcp, conn);
donatien 0:8e01dca41002 806 /* don't restore recv callback: we don't want to receive any more data */
donatien 0:8e01dca41002 807 }
donatien 0:8e01dca41002 808 /* If closing didn't succeed, we get called again either
donatien 0:8e01dca41002 809 from poll_tcp or from sent_tcp */
donatien 0:8e01dca41002 810 }
donatien 0:8e01dca41002 811 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 812
donatien 0:8e01dca41002 813 /**
donatien 0:8e01dca41002 814 * Delete the pcb inside a netconn.
donatien 0:8e01dca41002 815 * Called from netconn_delete.
donatien 0:8e01dca41002 816 *
donatien 0:8e01dca41002 817 * @param msg the api_msg_msg pointing to the connection
donatien 0:8e01dca41002 818 */
donatien 0:8e01dca41002 819 void
donatien 0:8e01dca41002 820 do_delconn(struct api_msg_msg *msg)
donatien 0:8e01dca41002 821 {
donatien 0:8e01dca41002 822 /* @todo TCP: abort running write/connect? */
donatien 0:8e01dca41002 823 if ((msg->conn->state != NETCONN_NONE) &&
donatien 0:8e01dca41002 824 (msg->conn->state != NETCONN_LISTEN) &&
donatien 0:8e01dca41002 825 (msg->conn->state != NETCONN_CONNECT)) {
donatien 0:8e01dca41002 826 /* this only happens for TCP netconns */
donatien 0:8e01dca41002 827 LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP);
donatien 0:8e01dca41002 828 msg->err = ERR_INPROGRESS;
donatien 0:8e01dca41002 829 } else {
donatien 0:8e01dca41002 830 LWIP_ASSERT("blocking connect in progress",
donatien 0:8e01dca41002 831 (msg->conn->state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));
donatien 0:8e01dca41002 832 /* Drain and delete mboxes */
donatien 0:8e01dca41002 833 netconn_drain(msg->conn);
donatien 0:8e01dca41002 834
donatien 0:8e01dca41002 835 if (msg->conn->pcb.tcp != NULL) {
donatien 0:8e01dca41002 836
donatien 0:8e01dca41002 837 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
donatien 0:8e01dca41002 838 #if LWIP_RAW
donatien 0:8e01dca41002 839 case NETCONN_RAW:
donatien 0:8e01dca41002 840 raw_remove(msg->conn->pcb.raw);
donatien 0:8e01dca41002 841 break;
donatien 0:8e01dca41002 842 #endif /* LWIP_RAW */
donatien 0:8e01dca41002 843 #if LWIP_UDP
donatien 0:8e01dca41002 844 case NETCONN_UDP:
donatien 0:8e01dca41002 845 msg->conn->pcb.udp->recv_arg = NULL;
donatien 0:8e01dca41002 846 udp_remove(msg->conn->pcb.udp);
donatien 0:8e01dca41002 847 break;
donatien 0:8e01dca41002 848 #endif /* LWIP_UDP */
donatien 0:8e01dca41002 849 #if LWIP_TCP
donatien 0:8e01dca41002 850 case NETCONN_TCP:
donatien 0:8e01dca41002 851 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
donatien 0:8e01dca41002 852 msg->conn->write_offset == 0);
donatien 0:8e01dca41002 853 msg->conn->state = NETCONN_CLOSE;
donatien 0:8e01dca41002 854 msg->msg.sd.shut = NETCONN_SHUT_RDWR;
donatien 0:8e01dca41002 855 msg->conn->current_msg = msg;
donatien 0:8e01dca41002 856 do_close_internal(msg->conn);
donatien 0:8e01dca41002 857 /* API_EVENT is called inside do_close_internal, before releasing
donatien 0:8e01dca41002 858 the application thread, so we can return at this point! */
donatien 0:8e01dca41002 859 return;
donatien 0:8e01dca41002 860 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 861 default:
donatien 0:8e01dca41002 862 break;
donatien 0:8e01dca41002 863 }
donatien 0:8e01dca41002 864 msg->conn->pcb.tcp = NULL;
donatien 0:8e01dca41002 865 }
donatien 0:8e01dca41002 866 /* tcp netconns don't come here! */
donatien 0:8e01dca41002 867
donatien 0:8e01dca41002 868 /* @todo: this lets select make the socket readable and writable,
donatien 0:8e01dca41002 869 which is wrong! errfd instead? */
donatien 0:8e01dca41002 870 API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
donatien 0:8e01dca41002 871 API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
donatien 0:8e01dca41002 872 }
donatien 0:8e01dca41002 873 if (sys_sem_valid(&msg->conn->op_completed)) {
donatien 0:8e01dca41002 874 sys_sem_signal(&msg->conn->op_completed);
donatien 0:8e01dca41002 875 }
donatien 0:8e01dca41002 876 }
donatien 0:8e01dca41002 877
donatien 0:8e01dca41002 878 /**
donatien 0:8e01dca41002 879 * Bind a pcb contained in a netconn
donatien 0:8e01dca41002 880 * Called from netconn_bind.
donatien 0:8e01dca41002 881 *
donatien 0:8e01dca41002 882 * @param msg the api_msg_msg pointing to the connection and containing
donatien 0:8e01dca41002 883 * the IP address and port to bind to
donatien 0:8e01dca41002 884 */
donatien 0:8e01dca41002 885 void
donatien 0:8e01dca41002 886 do_bind(struct api_msg_msg *msg)
donatien 0:8e01dca41002 887 {
donatien 0:8e01dca41002 888 if (ERR_IS_FATAL(msg->conn->last_err)) {
donatien 0:8e01dca41002 889 msg->err = msg->conn->last_err;
donatien 0:8e01dca41002 890 } else {
donatien 0:8e01dca41002 891 msg->err = ERR_VAL;
donatien 0:8e01dca41002 892 if (msg->conn->pcb.tcp != NULL) {
donatien 0:8e01dca41002 893 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
donatien 0:8e01dca41002 894 #if LWIP_RAW
donatien 0:8e01dca41002 895 case NETCONN_RAW:
donatien 0:8e01dca41002 896 msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
donatien 0:8e01dca41002 897 break;
donatien 0:8e01dca41002 898 #endif /* LWIP_RAW */
donatien 0:8e01dca41002 899 #if LWIP_UDP
donatien 0:8e01dca41002 900 case NETCONN_UDP:
donatien 0:8e01dca41002 901 msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
donatien 0:8e01dca41002 902 break;
donatien 0:8e01dca41002 903 #endif /* LWIP_UDP */
donatien 0:8e01dca41002 904 #if LWIP_TCP
donatien 0:8e01dca41002 905 case NETCONN_TCP:
donatien 0:8e01dca41002 906 msg->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port);
donatien 0:8e01dca41002 907 break;
donatien 0:8e01dca41002 908 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 909 default:
donatien 0:8e01dca41002 910 break;
donatien 0:8e01dca41002 911 }
donatien 0:8e01dca41002 912 }
donatien 0:8e01dca41002 913 }
donatien 0:8e01dca41002 914 TCPIP_APIMSG_ACK(msg);
donatien 0:8e01dca41002 915 }
donatien 0:8e01dca41002 916
donatien 0:8e01dca41002 917 #if LWIP_TCP
donatien 0:8e01dca41002 918 /**
donatien 0:8e01dca41002 919 * TCP callback function if a connection (opened by tcp_connect/do_connect) has
donatien 0:8e01dca41002 920 * been established (or reset by the remote host).
donatien 0:8e01dca41002 921 *
donatien 0:8e01dca41002 922 * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
donatien 0:8e01dca41002 923 */
donatien 0:8e01dca41002 924 static err_t
donatien 0:8e01dca41002 925 do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
donatien 0:8e01dca41002 926 {
donatien 0:8e01dca41002 927 struct netconn *conn;
donatien 0:8e01dca41002 928 int was_blocking;
donatien 0:8e01dca41002 929
donatien 0:8e01dca41002 930 LWIP_UNUSED_ARG(pcb);
donatien 0:8e01dca41002 931
donatien 0:8e01dca41002 932 conn = (struct netconn *)arg;
donatien 0:8e01dca41002 933
donatien 0:8e01dca41002 934 if (conn == NULL) {
donatien 0:8e01dca41002 935 return ERR_VAL;
donatien 0:8e01dca41002 936 }
donatien 0:8e01dca41002 937
donatien 0:8e01dca41002 938 LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
donatien 0:8e01dca41002 939 LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect",
donatien 0:8e01dca41002 940 (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn));
donatien 0:8e01dca41002 941
donatien 0:8e01dca41002 942 if (conn->current_msg != NULL) {
donatien 0:8e01dca41002 943 conn->current_msg->err = err;
donatien 0:8e01dca41002 944 }
donatien 0:8e01dca41002 945 if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) {
donatien 0:8e01dca41002 946 setup_tcp(conn);
donatien 0:8e01dca41002 947 }
donatien 0:8e01dca41002 948 was_blocking = !IN_NONBLOCKING_CONNECT(conn);
donatien 0:8e01dca41002 949 SET_NONBLOCKING_CONNECT(conn, 0);
donatien 0:8e01dca41002 950 conn->current_msg = NULL;
donatien 0:8e01dca41002 951 conn->state = NETCONN_NONE;
donatien 0:8e01dca41002 952 if (!was_blocking) {
donatien 0:8e01dca41002 953 NETCONN_SET_SAFE_ERR(conn, ERR_OK);
donatien 0:8e01dca41002 954 }
donatien 0:8e01dca41002 955 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
donatien 0:8e01dca41002 956
donatien 0:8e01dca41002 957 if (was_blocking) {
donatien 0:8e01dca41002 958 sys_sem_signal(&conn->op_completed);
donatien 0:8e01dca41002 959 }
donatien 0:8e01dca41002 960 return ERR_OK;
donatien 0:8e01dca41002 961 }
donatien 0:8e01dca41002 962 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 963
donatien 0:8e01dca41002 964 /**
donatien 0:8e01dca41002 965 * Connect a pcb contained inside a netconn
donatien 0:8e01dca41002 966 * Called from netconn_connect.
donatien 0:8e01dca41002 967 *
donatien 0:8e01dca41002 968 * @param msg the api_msg_msg pointing to the connection and containing
donatien 0:8e01dca41002 969 * the IP address and port to connect to
donatien 0:8e01dca41002 970 */
donatien 0:8e01dca41002 971 void
donatien 0:8e01dca41002 972 do_connect(struct api_msg_msg *msg)
donatien 0:8e01dca41002 973 {
donatien 0:8e01dca41002 974 if (msg->conn->pcb.tcp == NULL) {
donatien 0:8e01dca41002 975 /* This may happen when calling netconn_connect() a second time */
donatien 0:8e01dca41002 976 msg->err = ERR_CLSD;
donatien 0:8e01dca41002 977 } else {
donatien 0:8e01dca41002 978 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
donatien 0:8e01dca41002 979 #if LWIP_RAW
donatien 0:8e01dca41002 980 case NETCONN_RAW:
donatien 0:8e01dca41002 981 msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
donatien 0:8e01dca41002 982 break;
donatien 0:8e01dca41002 983 #endif /* LWIP_RAW */
donatien 0:8e01dca41002 984 #if LWIP_UDP
donatien 0:8e01dca41002 985 case NETCONN_UDP:
donatien 0:8e01dca41002 986 msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
donatien 0:8e01dca41002 987 break;
donatien 0:8e01dca41002 988 #endif /* LWIP_UDP */
donatien 0:8e01dca41002 989 #if LWIP_TCP
donatien 0:8e01dca41002 990 case NETCONN_TCP:
donatien 0:8e01dca41002 991 /* Prevent connect while doing any other action. */
donatien 0:8e01dca41002 992 if (msg->conn->state != NETCONN_NONE) {
donatien 0:8e01dca41002 993 msg->err = ERR_ISCONN;
donatien 0:8e01dca41002 994 } else {
donatien 0:8e01dca41002 995 setup_tcp(msg->conn);
donatien 0:8e01dca41002 996 msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr,
donatien 0:8e01dca41002 997 msg->msg.bc.port, do_connected);
donatien 0:8e01dca41002 998 if (msg->err == ERR_OK) {
donatien 0:8e01dca41002 999 u8_t non_blocking = netconn_is_nonblocking(msg->conn);
donatien 0:8e01dca41002 1000 msg->conn->state = NETCONN_CONNECT;
donatien 0:8e01dca41002 1001 SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
donatien 0:8e01dca41002 1002 if (non_blocking) {
donatien 0:8e01dca41002 1003 msg->err = ERR_INPROGRESS;
donatien 0:8e01dca41002 1004 } else {
donatien 0:8e01dca41002 1005 msg->conn->current_msg = msg;
donatien 0:8e01dca41002 1006 /* sys_sem_signal() is called from do_connected (or err_tcp()),
donatien 0:8e01dca41002 1007 * when the connection is established! */
donatien 0:8e01dca41002 1008 return;
donatien 0:8e01dca41002 1009 }
donatien 0:8e01dca41002 1010 }
donatien 0:8e01dca41002 1011 }
donatien 0:8e01dca41002 1012 break;
donatien 0:8e01dca41002 1013 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 1014 default:
donatien 0:8e01dca41002 1015 LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0));
donatien 0:8e01dca41002 1016 break;
donatien 0:8e01dca41002 1017 }
donatien 0:8e01dca41002 1018 }
donatien 0:8e01dca41002 1019 sys_sem_signal(&msg->conn->op_completed);
donatien 0:8e01dca41002 1020 }
donatien 0:8e01dca41002 1021
donatien 0:8e01dca41002 1022 /**
donatien 0:8e01dca41002 1023 * Connect a pcb contained inside a netconn
donatien 0:8e01dca41002 1024 * Only used for UDP netconns.
donatien 0:8e01dca41002 1025 * Called from netconn_disconnect.
donatien 0:8e01dca41002 1026 *
donatien 0:8e01dca41002 1027 * @param msg the api_msg_msg pointing to the connection to disconnect
donatien 0:8e01dca41002 1028 */
donatien 0:8e01dca41002 1029 void
donatien 0:8e01dca41002 1030 do_disconnect(struct api_msg_msg *msg)
donatien 0:8e01dca41002 1031 {
donatien 0:8e01dca41002 1032 #if LWIP_UDP
donatien 0:8e01dca41002 1033 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
donatien 0:8e01dca41002 1034 udp_disconnect(msg->conn->pcb.udp);
donatien 0:8e01dca41002 1035 msg->err = ERR_OK;
donatien 0:8e01dca41002 1036 } else
donatien 0:8e01dca41002 1037 #endif /* LWIP_UDP */
donatien 0:8e01dca41002 1038 {
donatien 0:8e01dca41002 1039 msg->err = ERR_VAL;
donatien 0:8e01dca41002 1040 }
donatien 0:8e01dca41002 1041 TCPIP_APIMSG_ACK(msg);
donatien 0:8e01dca41002 1042 }
donatien 0:8e01dca41002 1043
donatien 0:8e01dca41002 1044 #if LWIP_TCP
donatien 0:8e01dca41002 1045 /**
donatien 0:8e01dca41002 1046 * Set a TCP pcb contained in a netconn into listen mode
donatien 0:8e01dca41002 1047 * Called from netconn_listen.
donatien 0:8e01dca41002 1048 *
donatien 0:8e01dca41002 1049 * @param msg the api_msg_msg pointing to the connection
donatien 0:8e01dca41002 1050 */
donatien 0:8e01dca41002 1051 void
donatien 0:8e01dca41002 1052 do_listen(struct api_msg_msg *msg)
donatien 0:8e01dca41002 1053 {
donatien 0:8e01dca41002 1054 if (ERR_IS_FATAL(msg->conn->last_err)) {
donatien 0:8e01dca41002 1055 msg->err = msg->conn->last_err;
donatien 0:8e01dca41002 1056 } else {
donatien 0:8e01dca41002 1057 msg->err = ERR_CONN;
donatien 0:8e01dca41002 1058 if (msg->conn->pcb.tcp != NULL) {
donatien 0:8e01dca41002 1059 if (msg->conn->type == NETCONN_TCP) {
donatien 0:8e01dca41002 1060 if (msg->conn->state == NETCONN_NONE) {
donatien 0:8e01dca41002 1061 #if TCP_LISTEN_BACKLOG
donatien 0:8e01dca41002 1062 struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
donatien 0:8e01dca41002 1063 #else /* TCP_LISTEN_BACKLOG */
donatien 0:8e01dca41002 1064 struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp);
donatien 0:8e01dca41002 1065 #endif /* TCP_LISTEN_BACKLOG */
donatien 0:8e01dca41002 1066 if (lpcb == NULL) {
donatien 0:8e01dca41002 1067 /* in this case, the old pcb is still allocated */
donatien 0:8e01dca41002 1068 msg->err = ERR_MEM;
donatien 0:8e01dca41002 1069 } else {
donatien 0:8e01dca41002 1070 /* delete the recvmbox and allocate the acceptmbox */
donatien 0:8e01dca41002 1071 if (sys_mbox_valid(&msg->conn->recvmbox)) {
donatien 0:8e01dca41002 1072 /** @todo: should we drain the recvmbox here? */
donatien 0:8e01dca41002 1073 sys_mbox_free(&msg->conn->recvmbox);
donatien 0:8e01dca41002 1074 sys_mbox_set_invalid(&msg->conn->recvmbox);
donatien 0:8e01dca41002 1075 }
donatien 0:8e01dca41002 1076 msg->err = ERR_OK;
donatien 0:8e01dca41002 1077 if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
donatien 0:8e01dca41002 1078 msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
donatien 0:8e01dca41002 1079 }
donatien 0:8e01dca41002 1080 if (msg->err == ERR_OK) {
donatien 0:8e01dca41002 1081 msg->conn->state = NETCONN_LISTEN;
donatien 0:8e01dca41002 1082 msg->conn->pcb.tcp = lpcb;
donatien 0:8e01dca41002 1083 tcp_arg(msg->conn->pcb.tcp, msg->conn);
donatien 0:8e01dca41002 1084 tcp_accept(msg->conn->pcb.tcp, accept_function);
donatien 0:8e01dca41002 1085 } else {
donatien 0:8e01dca41002 1086 /* since the old pcb is already deallocated, free lpcb now */
donatien 0:8e01dca41002 1087 tcp_close(lpcb);
donatien 0:8e01dca41002 1088 msg->conn->pcb.tcp = NULL;
donatien 0:8e01dca41002 1089 }
donatien 0:8e01dca41002 1090 }
donatien 0:8e01dca41002 1091 }
donatien 0:8e01dca41002 1092 }
donatien 0:8e01dca41002 1093 }
donatien 0:8e01dca41002 1094 }
donatien 0:8e01dca41002 1095 TCPIP_APIMSG_ACK(msg);
donatien 0:8e01dca41002 1096 }
donatien 0:8e01dca41002 1097 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 1098
donatien 0:8e01dca41002 1099 /**
donatien 0:8e01dca41002 1100 * Send some data on a RAW or UDP pcb contained in a netconn
donatien 0:8e01dca41002 1101 * Called from netconn_send
donatien 0:8e01dca41002 1102 *
donatien 0:8e01dca41002 1103 * @param msg the api_msg_msg pointing to the connection
donatien 0:8e01dca41002 1104 */
donatien 0:8e01dca41002 1105 void
donatien 0:8e01dca41002 1106 do_send(struct api_msg_msg *msg)
donatien 0:8e01dca41002 1107 {
donatien 0:8e01dca41002 1108 if (ERR_IS_FATAL(msg->conn->last_err)) {
donatien 0:8e01dca41002 1109 msg->err = msg->conn->last_err;
donatien 0:8e01dca41002 1110 } else {
donatien 0:8e01dca41002 1111 msg->err = ERR_CONN;
donatien 0:8e01dca41002 1112 if (msg->conn->pcb.tcp != NULL) {
donatien 0:8e01dca41002 1113 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
donatien 0:8e01dca41002 1114 #if LWIP_RAW
donatien 0:8e01dca41002 1115 case NETCONN_RAW:
donatien 0:8e01dca41002 1116 if (ip_addr_isany(&msg->msg.b->addr)) {
donatien 0:8e01dca41002 1117 msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
donatien 0:8e01dca41002 1118 } else {
donatien 0:8e01dca41002 1119 msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
donatien 0:8e01dca41002 1120 }
donatien 0:8e01dca41002 1121 break;
donatien 0:8e01dca41002 1122 #endif
donatien 0:8e01dca41002 1123 #if LWIP_UDP
donatien 0:8e01dca41002 1124 case NETCONN_UDP:
donatien 0:8e01dca41002 1125 #if LWIP_CHECKSUM_ON_COPY
donatien 0:8e01dca41002 1126 if (ip_addr_isany(&msg->msg.b->addr)) {
donatien 0:8e01dca41002 1127 msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
donatien 0:8e01dca41002 1128 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
donatien 0:8e01dca41002 1129 } else {
donatien 0:8e01dca41002 1130 msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
donatien 0:8e01dca41002 1131 &msg->msg.b->addr, msg->msg.b->port,
donatien 0:8e01dca41002 1132 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
donatien 0:8e01dca41002 1133 }
donatien 0:8e01dca41002 1134 #else /* LWIP_CHECKSUM_ON_COPY */
donatien 0:8e01dca41002 1135 if (ip_addr_isany(&msg->msg.b->addr)) {
donatien 0:8e01dca41002 1136 msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
donatien 0:8e01dca41002 1137 } else {
donatien 0:8e01dca41002 1138 msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
donatien 0:8e01dca41002 1139 }
donatien 0:8e01dca41002 1140 #endif /* LWIP_CHECKSUM_ON_COPY */
donatien 0:8e01dca41002 1141 break;
donatien 0:8e01dca41002 1142 #endif /* LWIP_UDP */
donatien 0:8e01dca41002 1143 default:
donatien 0:8e01dca41002 1144 break;
donatien 0:8e01dca41002 1145 }
donatien 0:8e01dca41002 1146 }
donatien 0:8e01dca41002 1147 }
donatien 0:8e01dca41002 1148 TCPIP_APIMSG_ACK(msg);
donatien 0:8e01dca41002 1149 }
donatien 0:8e01dca41002 1150
donatien 0:8e01dca41002 1151 #if LWIP_TCP
donatien 0:8e01dca41002 1152 /**
donatien 0:8e01dca41002 1153 * Indicate data has been received from a TCP pcb contained in a netconn
donatien 0:8e01dca41002 1154 * Called from netconn_recv
donatien 0:8e01dca41002 1155 *
donatien 0:8e01dca41002 1156 * @param msg the api_msg_msg pointing to the connection
donatien 0:8e01dca41002 1157 */
donatien 0:8e01dca41002 1158 void
donatien 0:8e01dca41002 1159 do_recv(struct api_msg_msg *msg)
donatien 0:8e01dca41002 1160 {
donatien 0:8e01dca41002 1161 msg->err = ERR_OK;
donatien 0:8e01dca41002 1162 if (msg->conn->pcb.tcp != NULL) {
donatien 0:8e01dca41002 1163 if (msg->conn->type == NETCONN_TCP) {
donatien 0:8e01dca41002 1164 #if TCP_LISTEN_BACKLOG
donatien 0:8e01dca41002 1165 if (msg->conn->pcb.tcp->state == LISTEN) {
donatien 0:8e01dca41002 1166 tcp_accepted(msg->conn->pcb.tcp);
donatien 0:8e01dca41002 1167 } else
donatien 0:8e01dca41002 1168 #endif /* TCP_LISTEN_BACKLOG */
donatien 0:8e01dca41002 1169 {
donatien 0:8e01dca41002 1170 u32_t remaining = msg->msg.r.len;
donatien 0:8e01dca41002 1171 do {
donatien 0:8e01dca41002 1172 u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
donatien 0:8e01dca41002 1173 tcp_recved(msg->conn->pcb.tcp, recved);
donatien 0:8e01dca41002 1174 remaining -= recved;
donatien 0:8e01dca41002 1175 }while(remaining != 0);
donatien 0:8e01dca41002 1176 }
donatien 0:8e01dca41002 1177 }
donatien 0:8e01dca41002 1178 }
donatien 0:8e01dca41002 1179 TCPIP_APIMSG_ACK(msg);
donatien 0:8e01dca41002 1180 }
donatien 0:8e01dca41002 1181
donatien 0:8e01dca41002 1182 /**
donatien 0:8e01dca41002 1183 * See if more data needs to be written from a previous call to netconn_write.
donatien 0:8e01dca41002 1184 * Called initially from do_write. If the first call can't send all data
donatien 0:8e01dca41002 1185 * (because of low memory or empty send-buffer), this function is called again
donatien 0:8e01dca41002 1186 * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
donatien 0:8e01dca41002 1187 * blocking application thread (waiting in netconn_write) is released.
donatien 0:8e01dca41002 1188 *
donatien 0:8e01dca41002 1189 * @param conn netconn (that is currently in state NETCONN_WRITE) to process
donatien 0:8e01dca41002 1190 * @return ERR_OK
donatien 0:8e01dca41002 1191 * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
donatien 0:8e01dca41002 1192 */
donatien 0:8e01dca41002 1193 static err_t
donatien 0:8e01dca41002 1194 do_writemore(struct netconn *conn)
donatien 0:8e01dca41002 1195 {
donatien 0:8e01dca41002 1196 err_t err = ERR_OK;
donatien 0:8e01dca41002 1197 void *dataptr;
donatien 0:8e01dca41002 1198 u16_t len, available;
donatien 0:8e01dca41002 1199 u8_t write_finished = 0;
donatien 0:8e01dca41002 1200 size_t diff;
donatien 0:8e01dca41002 1201 u8_t dontblock = netconn_is_nonblocking(conn) ||
donatien 0:8e01dca41002 1202 (conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK);
donatien 0:8e01dca41002 1203 u8_t apiflags = conn->current_msg->msg.w.apiflags;
donatien 0:8e01dca41002 1204
donatien 0:8e01dca41002 1205 LWIP_ASSERT("conn != NULL", conn != NULL);
donatien 0:8e01dca41002 1206 LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
donatien 0:8e01dca41002 1207 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
donatien 0:8e01dca41002 1208 LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
donatien 0:8e01dca41002 1209 LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len",
donatien 0:8e01dca41002 1210 conn->write_offset < conn->current_msg->msg.w.len);
donatien 0:8e01dca41002 1211
donatien 0:8e01dca41002 1212 dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
donatien 0:8e01dca41002 1213 diff = conn->current_msg->msg.w.len - conn->write_offset;
donatien 0:8e01dca41002 1214 if (diff > 0xffffUL) { /* max_u16_t */
donatien 0:8e01dca41002 1215 len = 0xffff;
donatien 0:8e01dca41002 1216 #if LWIP_TCPIP_CORE_LOCKING
donatien 0:8e01dca41002 1217 conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
donatien 0:8e01dca41002 1218 #endif
donatien 0:8e01dca41002 1219 apiflags |= TCP_WRITE_FLAG_MORE;
donatien 0:8e01dca41002 1220 } else {
donatien 0:8e01dca41002 1221 len = (u16_t)diff;
donatien 0:8e01dca41002 1222 }
donatien 0:8e01dca41002 1223 available = tcp_sndbuf(conn->pcb.tcp);
donatien 0:8e01dca41002 1224 if (available < len) {
donatien 0:8e01dca41002 1225 /* don't try to write more than sendbuf */
donatien 0:8e01dca41002 1226 len = available;
donatien 0:8e01dca41002 1227 #if LWIP_TCPIP_CORE_LOCKING
donatien 0:8e01dca41002 1228 conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
donatien 0:8e01dca41002 1229 #endif
donatien 0:8e01dca41002 1230 apiflags |= TCP_WRITE_FLAG_MORE;
donatien 0:8e01dca41002 1231 }
donatien 0:8e01dca41002 1232 if (dontblock && (len < conn->current_msg->msg.w.len)) {
donatien 0:8e01dca41002 1233 /* failed to send all data at once -> nonblocking write not possible */
donatien 0:8e01dca41002 1234 err = ERR_MEM;
donatien 0:8e01dca41002 1235 }
donatien 0:8e01dca41002 1236 if (err == ERR_OK) {
donatien 0:8e01dca41002 1237 LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
donatien 0:8e01dca41002 1238 err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
donatien 0:8e01dca41002 1239 }
donatien 0:8e01dca41002 1240 if (dontblock && (err == ERR_MEM)) {
donatien 0:8e01dca41002 1241 /* nonblocking write failed */
donatien 0:8e01dca41002 1242 write_finished = 1;
donatien 0:8e01dca41002 1243 err = ERR_WOULDBLOCK;
donatien 0:8e01dca41002 1244 /* let poll_tcp check writable space to mark the pcb
donatien 0:8e01dca41002 1245 writable again */
donatien 0:8e01dca41002 1246 conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
donatien 0:8e01dca41002 1247 /* let select mark this pcb as non-writable. */
donatien 0:8e01dca41002 1248 API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
donatien 0:8e01dca41002 1249 } else {
donatien 0:8e01dca41002 1250 /* if OK or memory error, check available space */
donatien 0:8e01dca41002 1251 if (((err == ERR_OK) || (err == ERR_MEM)) &&
donatien 0:8e01dca41002 1252 ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
donatien 0:8e01dca41002 1253 (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT))) {
donatien 0:8e01dca41002 1254 /* The queued byte- or pbuf-count exceeds the configured low-water limit,
donatien 0:8e01dca41002 1255 let select mark this pcb as non-writable. */
donatien 0:8e01dca41002 1256 API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
donatien 0:8e01dca41002 1257 }
donatien 0:8e01dca41002 1258
donatien 0:8e01dca41002 1259 if (err == ERR_OK) {
donatien 0:8e01dca41002 1260 conn->write_offset += len;
donatien 0:8e01dca41002 1261 if (conn->write_offset == conn->current_msg->msg.w.len) {
donatien 0:8e01dca41002 1262 /* everything was written */
donatien 0:8e01dca41002 1263 write_finished = 1;
donatien 0:8e01dca41002 1264 conn->write_offset = 0;
donatien 0:8e01dca41002 1265 }
donatien 0:8e01dca41002 1266 tcp_output(conn->pcb.tcp);
donatien 0:8e01dca41002 1267 } else if (err == ERR_MEM) {
donatien 0:8e01dca41002 1268 /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
donatien 0:8e01dca41002 1269 we do NOT return to the application thread, since ERR_MEM is
donatien 0:8e01dca41002 1270 only a temporary error! */
donatien 0:8e01dca41002 1271
donatien 0:8e01dca41002 1272 /* tcp_write returned ERR_MEM, try tcp_output anyway */
donatien 0:8e01dca41002 1273 tcp_output(conn->pcb.tcp);
donatien 0:8e01dca41002 1274
donatien 0:8e01dca41002 1275 #if LWIP_TCPIP_CORE_LOCKING
donatien 0:8e01dca41002 1276 conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
donatien 0:8e01dca41002 1277 #endif
donatien 0:8e01dca41002 1278 } else {
donatien 0:8e01dca41002 1279 /* On errors != ERR_MEM, we don't try writing any more but return
donatien 0:8e01dca41002 1280 the error to the application thread. */
donatien 0:8e01dca41002 1281 write_finished = 1;
donatien 0:8e01dca41002 1282 }
donatien 0:8e01dca41002 1283 }
donatien 0:8e01dca41002 1284
donatien 0:8e01dca41002 1285 if (write_finished) {
donatien 0:8e01dca41002 1286 /* everything was written: set back connection state
donatien 0:8e01dca41002 1287 and back to application task */
donatien 0:8e01dca41002 1288 conn->current_msg->err = err;
donatien 0:8e01dca41002 1289 conn->current_msg = NULL;
donatien 0:8e01dca41002 1290 conn->state = NETCONN_NONE;
donatien 0:8e01dca41002 1291 #if LWIP_TCPIP_CORE_LOCKING
donatien 0:8e01dca41002 1292 if ((conn->flags & NETCONN_FLAG_WRITE_DELAYED) != 0)
donatien 0:8e01dca41002 1293 #endif
donatien 0:8e01dca41002 1294 {
donatien 0:8e01dca41002 1295 sys_sem_signal(&conn->op_completed);
donatien 0:8e01dca41002 1296 }
donatien 0:8e01dca41002 1297 }
donatien 0:8e01dca41002 1298 #if LWIP_TCPIP_CORE_LOCKING
donatien 0:8e01dca41002 1299 else
donatien 0:8e01dca41002 1300 return ERR_MEM;
donatien 0:8e01dca41002 1301 #endif
donatien 0:8e01dca41002 1302 return ERR_OK;
donatien 0:8e01dca41002 1303 }
donatien 0:8e01dca41002 1304 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 1305
donatien 0:8e01dca41002 1306 /**
donatien 0:8e01dca41002 1307 * Send some data on a TCP pcb contained in a netconn
donatien 0:8e01dca41002 1308 * Called from netconn_write
donatien 0:8e01dca41002 1309 *
donatien 0:8e01dca41002 1310 * @param msg the api_msg_msg pointing to the connection
donatien 0:8e01dca41002 1311 */
donatien 0:8e01dca41002 1312 void
donatien 0:8e01dca41002 1313 do_write(struct api_msg_msg *msg)
donatien 0:8e01dca41002 1314 {
donatien 0:8e01dca41002 1315 if (ERR_IS_FATAL(msg->conn->last_err)) {
donatien 0:8e01dca41002 1316 msg->err = msg->conn->last_err;
donatien 0:8e01dca41002 1317 } else {
donatien 0:8e01dca41002 1318 if (msg->conn->type == NETCONN_TCP) {
donatien 0:8e01dca41002 1319 #if LWIP_TCP
donatien 0:8e01dca41002 1320 if (msg->conn->state != NETCONN_NONE) {
donatien 0:8e01dca41002 1321 /* netconn is connecting, closing or in blocking write */
donatien 0:8e01dca41002 1322 msg->err = ERR_INPROGRESS;
donatien 0:8e01dca41002 1323 } else if (msg->conn->pcb.tcp != NULL) {
donatien 0:8e01dca41002 1324 msg->conn->state = NETCONN_WRITE;
donatien 0:8e01dca41002 1325 /* set all the variables used by do_writemore */
donatien 0:8e01dca41002 1326 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
donatien 0:8e01dca41002 1327 msg->conn->write_offset == 0);
donatien 0:8e01dca41002 1328 LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
donatien 0:8e01dca41002 1329 msg->conn->current_msg = msg;
donatien 0:8e01dca41002 1330 msg->conn->write_offset = 0;
donatien 0:8e01dca41002 1331 #if LWIP_TCPIP_CORE_LOCKING
donatien 0:8e01dca41002 1332 msg->conn->flags &= ~NETCONN_FLAG_WRITE_DELAYED;
donatien 0:8e01dca41002 1333 if (do_writemore(msg->conn) != ERR_OK) {
donatien 0:8e01dca41002 1334 LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
donatien 0:8e01dca41002 1335 UNLOCK_TCPIP_CORE();
donatien 0:8e01dca41002 1336 sys_arch_sem_wait(&msg->conn->op_completed, 0);
donatien 0:8e01dca41002 1337 LOCK_TCPIP_CORE();
donatien 0:8e01dca41002 1338 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
donatien 0:8e01dca41002 1339 }
donatien 0:8e01dca41002 1340 #else /* LWIP_TCPIP_CORE_LOCKING */
donatien 0:8e01dca41002 1341 do_writemore(msg->conn);
donatien 0:8e01dca41002 1342 #endif /* LWIP_TCPIP_CORE_LOCKING */
donatien 0:8e01dca41002 1343 /* for both cases: if do_writemore was called, don't ACK the APIMSG
donatien 0:8e01dca41002 1344 since do_writemore ACKs it! */
donatien 0:8e01dca41002 1345 return;
donatien 0:8e01dca41002 1346 } else {
donatien 0:8e01dca41002 1347 msg->err = ERR_CONN;
donatien 0:8e01dca41002 1348 }
donatien 0:8e01dca41002 1349 #else /* LWIP_TCP */
donatien 0:8e01dca41002 1350 msg->err = ERR_VAL;
donatien 0:8e01dca41002 1351 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 1352 #if (LWIP_UDP || LWIP_RAW)
donatien 0:8e01dca41002 1353 } else {
donatien 0:8e01dca41002 1354 msg->err = ERR_VAL;
donatien 0:8e01dca41002 1355 #endif /* (LWIP_UDP || LWIP_RAW) */
donatien 0:8e01dca41002 1356 }
donatien 0:8e01dca41002 1357 }
donatien 0:8e01dca41002 1358 TCPIP_APIMSG_ACK(msg);
donatien 0:8e01dca41002 1359 }
donatien 0:8e01dca41002 1360
donatien 0:8e01dca41002 1361 /**
donatien 0:8e01dca41002 1362 * Return a connection's local or remote address
donatien 0:8e01dca41002 1363 * Called from netconn_getaddr
donatien 0:8e01dca41002 1364 *
donatien 0:8e01dca41002 1365 * @param msg the api_msg_msg pointing to the connection
donatien 0:8e01dca41002 1366 */
donatien 0:8e01dca41002 1367 void
donatien 0:8e01dca41002 1368 do_getaddr(struct api_msg_msg *msg)
donatien 0:8e01dca41002 1369 {
donatien 0:8e01dca41002 1370 if (msg->conn->pcb.ip != NULL) {
donatien 0:8e01dca41002 1371 *(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip :
donatien 0:8e01dca41002 1372 msg->conn->pcb.ip->remote_ip);
donatien 0:8e01dca41002 1373
donatien 0:8e01dca41002 1374 msg->err = ERR_OK;
donatien 0:8e01dca41002 1375 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
donatien 0:8e01dca41002 1376 #if LWIP_RAW
donatien 0:8e01dca41002 1377 case NETCONN_RAW:
donatien 0:8e01dca41002 1378 if (msg->msg.ad.local) {
donatien 0:8e01dca41002 1379 *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
donatien 0:8e01dca41002 1380 } else {
donatien 0:8e01dca41002 1381 /* return an error as connecting is only a helper for upper layers */
donatien 0:8e01dca41002 1382 msg->err = ERR_CONN;
donatien 0:8e01dca41002 1383 }
donatien 0:8e01dca41002 1384 break;
donatien 0:8e01dca41002 1385 #endif /* LWIP_RAW */
donatien 0:8e01dca41002 1386 #if LWIP_UDP
donatien 0:8e01dca41002 1387 case NETCONN_UDP:
donatien 0:8e01dca41002 1388 if (msg->msg.ad.local) {
donatien 0:8e01dca41002 1389 *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
donatien 0:8e01dca41002 1390 } else {
donatien 0:8e01dca41002 1391 if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
donatien 0:8e01dca41002 1392 msg->err = ERR_CONN;
donatien 0:8e01dca41002 1393 } else {
donatien 0:8e01dca41002 1394 *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
donatien 0:8e01dca41002 1395 }
donatien 0:8e01dca41002 1396 }
donatien 0:8e01dca41002 1397 break;
donatien 0:8e01dca41002 1398 #endif /* LWIP_UDP */
donatien 0:8e01dca41002 1399 #if LWIP_TCP
donatien 0:8e01dca41002 1400 case NETCONN_TCP:
donatien 0:8e01dca41002 1401 *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port);
donatien 0:8e01dca41002 1402 break;
donatien 0:8e01dca41002 1403 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 1404 default:
donatien 0:8e01dca41002 1405 LWIP_ASSERT("invalid netconn_type", 0);
donatien 0:8e01dca41002 1406 break;
donatien 0:8e01dca41002 1407 }
donatien 0:8e01dca41002 1408 } else {
donatien 0:8e01dca41002 1409 msg->err = ERR_CONN;
donatien 0:8e01dca41002 1410 }
donatien 0:8e01dca41002 1411 TCPIP_APIMSG_ACK(msg);
donatien 0:8e01dca41002 1412 }
donatien 0:8e01dca41002 1413
donatien 0:8e01dca41002 1414 /**
donatien 0:8e01dca41002 1415 * Close a TCP pcb contained in a netconn
donatien 0:8e01dca41002 1416 * Called from netconn_close
donatien 0:8e01dca41002 1417 *
donatien 0:8e01dca41002 1418 * @param msg the api_msg_msg pointing to the connection
donatien 0:8e01dca41002 1419 */
donatien 0:8e01dca41002 1420 void
donatien 0:8e01dca41002 1421 do_close(struct api_msg_msg *msg)
donatien 0:8e01dca41002 1422 {
donatien 0:8e01dca41002 1423 #if LWIP_TCP
donatien 0:8e01dca41002 1424 /* @todo: abort running write/connect? */
donatien 0:8e01dca41002 1425 if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) {
donatien 0:8e01dca41002 1426 /* this only happens for TCP netconns */
donatien 0:8e01dca41002 1427 LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP);
donatien 0:8e01dca41002 1428 msg->err = ERR_INPROGRESS;
donatien 0:8e01dca41002 1429 } else if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {
donatien 0:8e01dca41002 1430 if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) {
donatien 0:8e01dca41002 1431 /* LISTEN doesn't support half shutdown */
donatien 0:8e01dca41002 1432 msg->err = ERR_CONN;
donatien 0:8e01dca41002 1433 } else {
donatien 0:8e01dca41002 1434 if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
donatien 0:8e01dca41002 1435 /* Drain and delete mboxes */
donatien 0:8e01dca41002 1436 netconn_drain(msg->conn);
donatien 0:8e01dca41002 1437 }
donatien 0:8e01dca41002 1438 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
donatien 0:8e01dca41002 1439 msg->conn->write_offset == 0);
donatien 0:8e01dca41002 1440 msg->conn->state = NETCONN_CLOSE;
donatien 0:8e01dca41002 1441 msg->conn->current_msg = msg;
donatien 0:8e01dca41002 1442 do_close_internal(msg->conn);
donatien 0:8e01dca41002 1443 /* for tcp netconns, do_close_internal ACKs the message */
donatien 0:8e01dca41002 1444 return;
donatien 0:8e01dca41002 1445 }
donatien 0:8e01dca41002 1446 } else
donatien 0:8e01dca41002 1447 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 1448 {
donatien 0:8e01dca41002 1449 msg->err = ERR_VAL;
donatien 0:8e01dca41002 1450 }
donatien 0:8e01dca41002 1451 sys_sem_signal(&msg->conn->op_completed);
donatien 0:8e01dca41002 1452 }
donatien 0:8e01dca41002 1453
donatien 0:8e01dca41002 1454 #if LWIP_IGMP
donatien 0:8e01dca41002 1455 /**
donatien 0:8e01dca41002 1456 * Join multicast groups for UDP netconns.
donatien 0:8e01dca41002 1457 * Called from netconn_join_leave_group
donatien 0:8e01dca41002 1458 *
donatien 0:8e01dca41002 1459 * @param msg the api_msg_msg pointing to the connection
donatien 0:8e01dca41002 1460 */
donatien 0:8e01dca41002 1461 void
donatien 0:8e01dca41002 1462 do_join_leave_group(struct api_msg_msg *msg)
donatien 0:8e01dca41002 1463 {
donatien 0:8e01dca41002 1464 if (ERR_IS_FATAL(msg->conn->last_err)) {
donatien 0:8e01dca41002 1465 msg->err = msg->conn->last_err;
donatien 0:8e01dca41002 1466 } else {
donatien 0:8e01dca41002 1467 if (msg->conn->pcb.tcp != NULL) {
donatien 0:8e01dca41002 1468 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
donatien 0:8e01dca41002 1469 #if LWIP_UDP
donatien 0:8e01dca41002 1470 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
donatien 0:8e01dca41002 1471 msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
donatien 0:8e01dca41002 1472 } else {
donatien 0:8e01dca41002 1473 msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
donatien 0:8e01dca41002 1474 }
donatien 0:8e01dca41002 1475 #endif /* LWIP_UDP */
donatien 0:8e01dca41002 1476 #if (LWIP_TCP || LWIP_RAW)
donatien 0:8e01dca41002 1477 } else {
donatien 0:8e01dca41002 1478 msg->err = ERR_VAL;
donatien 0:8e01dca41002 1479 #endif /* (LWIP_TCP || LWIP_RAW) */
donatien 0:8e01dca41002 1480 }
donatien 0:8e01dca41002 1481 } else {
donatien 0:8e01dca41002 1482 msg->err = ERR_CONN;
donatien 0:8e01dca41002 1483 }
donatien 0:8e01dca41002 1484 }
donatien 0:8e01dca41002 1485 TCPIP_APIMSG_ACK(msg);
donatien 0:8e01dca41002 1486 }
donatien 0:8e01dca41002 1487 #endif /* LWIP_IGMP */
donatien 0:8e01dca41002 1488
donatien 0:8e01dca41002 1489 #if LWIP_DNS
donatien 0:8e01dca41002 1490 /**
donatien 0:8e01dca41002 1491 * Callback function that is called when DNS name is resolved
donatien 0:8e01dca41002 1492 * (or on timeout). A waiting application thread is waked up by
donatien 0:8e01dca41002 1493 * signaling the semaphore.
donatien 0:8e01dca41002 1494 */
donatien 0:8e01dca41002 1495 static void
donatien 0:8e01dca41002 1496 do_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
donatien 0:8e01dca41002 1497 {
donatien 0:8e01dca41002 1498 struct dns_api_msg *msg = (struct dns_api_msg*)arg;
donatien 0:8e01dca41002 1499
donatien 0:8e01dca41002 1500 LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0);
donatien 0:8e01dca41002 1501 LWIP_UNUSED_ARG(name);
donatien 0:8e01dca41002 1502
donatien 0:8e01dca41002 1503 if (ipaddr == NULL) {
donatien 0:8e01dca41002 1504 /* timeout or memory error */
donatien 0:8e01dca41002 1505 *msg->err = ERR_VAL;
donatien 0:8e01dca41002 1506 } else {
donatien 0:8e01dca41002 1507 /* address was resolved */
donatien 0:8e01dca41002 1508 *msg->err = ERR_OK;
donatien 0:8e01dca41002 1509 *msg->addr = *ipaddr;
donatien 0:8e01dca41002 1510 }
donatien 0:8e01dca41002 1511 /* wake up the application task waiting in netconn_gethostbyname */
donatien 0:8e01dca41002 1512 sys_sem_signal(msg->sem);
donatien 0:8e01dca41002 1513 }
donatien 0:8e01dca41002 1514
donatien 0:8e01dca41002 1515 /**
donatien 0:8e01dca41002 1516 * Execute a DNS query
donatien 0:8e01dca41002 1517 * Called from netconn_gethostbyname
donatien 0:8e01dca41002 1518 *
donatien 0:8e01dca41002 1519 * @param arg the dns_api_msg pointing to the query
donatien 0:8e01dca41002 1520 */
donatien 0:8e01dca41002 1521 void
donatien 0:8e01dca41002 1522 do_gethostbyname(void *arg)
donatien 0:8e01dca41002 1523 {
donatien 0:8e01dca41002 1524 struct dns_api_msg *msg = (struct dns_api_msg*)arg;
donatien 0:8e01dca41002 1525
donatien 0:8e01dca41002 1526 *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg);
donatien 0:8e01dca41002 1527 if (*msg->err != ERR_INPROGRESS) {
donatien 0:8e01dca41002 1528 /* on error or immediate success, wake up the application
donatien 0:8e01dca41002 1529 * task waiting in netconn_gethostbyname */
donatien 0:8e01dca41002 1530 sys_sem_signal(msg->sem);
donatien 0:8e01dca41002 1531 }
donatien 0:8e01dca41002 1532 }
donatien 0:8e01dca41002 1533 #endif /* LWIP_DNS */
donatien 0:8e01dca41002 1534
donatien 0:8e01dca41002 1535 #endif /* LWIP_NETCONN */