From 61edc68c9ecf221d18acc8037d541f5d79eee3c7 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 16 May 2016 09:43:22 +0300 Subject: [PATCH] net: tcp: Supporting TCP client functionality when using IPv6 The application can initiate TCP connection when using IPv6. Change-Id: I632fa2559d5deb40d71288762bd13fbc2aac9cc7 Signed-off-by: Jukka Rissanen --- net/ip/contiki/ip/tcpip.c | 17 ++-- net/ip/contiki/ip/tcpip.h | 5 +- net/ip/contiki/ip/uip-udp-packet.c | 2 +- net/ip/contiki/ip/uip.h | 14 ++- net/ip/contiki/ipv4/uip.c | 3 +- net/ip/contiki/ipv6/uip6.c | 93 +++++++++++++++++--- net/ip/net_context.c | 133 ++++++++++++++++++++--------- net/ip/net_core.c | 98 +++++++++++++-------- 8 files changed, 263 insertions(+), 102 deletions(-) diff --git a/net/ip/contiki/ip/tcpip.c b/net/ip/contiki/ip/tcpip.c index 646c3017b99..0a6dc4fed21 100644 --- a/net/ip/contiki/ip/tcpip.c +++ b/net/ip/contiki/ip/tcpip.c @@ -220,7 +220,7 @@ packet_input(struct net_buf *buf) #if UIP_ACTIVE_OPEN struct uip_conn * tcp_connect(const uip_ipaddr_t *ripaddr, uint16_t port, void *appstate, - struct process *process) + struct process *process, struct net_buf *buf) { struct uip_conn *c; @@ -232,7 +232,7 @@ tcp_connect(const uip_ipaddr_t *ripaddr, uint16_t port, void *appstate, c->appstate.p = process; c->appstate.state = appstate; - tcpip_poll_tcp(c); + tcpip_poll_tcp(c, buf); return c; } @@ -837,12 +837,18 @@ tcpip_poll_udp(struct uip_udp_conn *conn) /*---------------------------------------------------------------------------*/ #if UIP_TCP void -tcpip_poll_tcp(struct uip_conn *conn) +tcpip_poll_tcp(struct uip_conn *conn, struct net_buf *data_buf) { /* We are sending here the initial SYN */ struct net_buf *buf = ip_buf_get_tx(conn->appstate.state); - uip_set_conn(buf) = conn; - conn->buf = ip_buf_ref(buf); + uip_set_conn(data_buf) = conn; + + /* The conn->buf will be freed after we have established the connection, + * sent the message and received an ack to it. This will happen in + * net_core.c:net_send(). + */ + conn->buf = ip_buf_ref(data_buf); + process_post_synch(&tcpip_process, TCP_POLL, conn, buf); } @@ -899,7 +905,6 @@ tcpip_uipcall(struct net_buf *buf) } } #endif /* UIP_TCP */ - if(ts->p != NULL) { process_post_synch(ts->p, tcpip_event, ts->state, buf); } diff --git a/net/ip/contiki/ip/tcpip.h b/net/ip/contiki/ip/tcpip.h index 7967c1389b6..253a02da5cb 100644 --- a/net/ip/contiki/ip/tcpip.h +++ b/net/ip/contiki/ip/tcpip.h @@ -167,7 +167,8 @@ CCIF void tcp_unlisten(uint16_t port, struct process *handler); * */ CCIF struct uip_conn *tcp_connect(const uip_ipaddr_t *ripaddr, uint16_t port, - void *appstate, struct process *process); + void *appstate, struct process *process, + struct net_buf *buf); /** * Cause a specified TCP connection to be polled. @@ -180,7 +181,7 @@ CCIF struct uip_conn *tcp_connect(const uip_ipaddr_t *ripaddr, uint16_t port, * \param conn A pointer to the TCP connection that should be polled. * */ -void tcpip_poll_tcp(struct uip_conn *conn); +void tcpip_poll_tcp(struct uip_conn *conn, struct net_buf *data_buf); void tcpip_resend_syn(struct uip_conn *conn, struct net_buf *buf); diff --git a/net/ip/contiki/ip/uip-udp-packet.c b/net/ip/contiki/ip/uip-udp-packet.c index 72c9ad9c723..db7382ad020 100644 --- a/net/ip/contiki/ip/uip-udp-packet.c +++ b/net/ip/contiki/ip/uip-udp-packet.c @@ -62,7 +62,7 @@ uip_udp_packet_send(struct net_buf *buf, struct uip_udp_conn *c, const void *dat memcpy(&uip_buf(buf)[UIP_LLH_LEN + UIP_IPUDPH_LEN], data, len > UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPUDPH_LEN? UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPUDPH_LEN: len); - if (uip_process(buf, UIP_UDP_SEND_CONN) == 0) { + if (uip_process(&buf, UIP_UDP_SEND_CONN) == 0) { /* The packet was dropped, we can return now */ return 0; } diff --git a/net/ip/contiki/ip/uip.h b/net/ip/contiki/ip/uip.h index 70e26f78297..cae581bcf99 100644 --- a/net/ip/contiki/ip/uip.h +++ b/net/ip/contiki/ip/uip.h @@ -284,8 +284,7 @@ void uip_setipid(uint16_t id); * * \hideinitializer */ -#define uip_input(buf) uip_process(buf, UIP_DATA) - +#define uip_input(buf) uip_process(&buf, UIP_DATA) /** * Periodic processing for a connection identified by its number. @@ -331,7 +330,7 @@ void uip_setipid(uint16_t id); */ #if UIP_TCP #define uip_periodic(buf, conn) do { uip_set_conn(buf) = &uip_conns[conn]; \ - uip_process(buf, UIP_TIMER); } while (0) + uip_process(&buf, UIP_TIMER); } while (0) /** * Macro to determine whether a specific uIP connection is active @@ -355,7 +354,7 @@ void uip_setipid(uint16_t id); * \hideinitializer */ #define uip_periodic_conn(buf, conn) do { uip_set_conn(buf) = conn; \ - uip_process(buf, UIP_TIMER); } while (0) + uip_process(&buf, UIP_TIMER); } while (0) /** * Request that a particular connection should be polled. @@ -369,7 +368,7 @@ void uip_setipid(uint16_t id); * \hideinitializer */ #define uip_poll_conn(buf, conn) do { uip_set_conn(buf) = conn; \ - uip_process(buf, UIP_POLL_REQUEST); } while (0) + uip_process(&buf, UIP_POLL_REQUEST); } while (0) #endif /* UIP_TCP */ @@ -423,7 +422,7 @@ void uip_setipid(uint16_t id); * \hideinitializer */ #define uip_udp_periodic_conn(buf, conn) do { uip_set_udp_conn(buf) = conn; \ - uip_process(buf, UIP_UDP_TIMER); } while(0) + uip_process(&buf, UIP_UDP_TIMER); } while(0) #endif /* UIP_UDP */ /** \brief Abandon the reassembly of the current packet */ @@ -1299,7 +1298,6 @@ extern uint8_t uip_ext_len; extern uint16_t uip_urglen, uip_surglen; #endif /* UIP_URGDATA > 0 */ - /** * Representation of a uIP TCP connection. * @@ -1569,7 +1567,7 @@ uip_ext_hdr_options_process(); */ * * The actual uIP function which does all the work. */ -uint8_t uip_process(struct net_buf *buf, uint8_t flag); +uint8_t uip_process(struct net_buf **buf, uint8_t flag); /* The following flags are passed as an argument to the uip_process() function. They are used to distinguish between the two cases where diff --git a/net/ip/contiki/ipv4/uip.c b/net/ip/contiki/ipv4/uip.c index 5f53e61b29d..42631a778be 100644 --- a/net/ip/contiki/ipv4/uip.c +++ b/net/ip/contiki/ipv4/uip.c @@ -678,8 +678,9 @@ uip_add_rcv_nxt(struct net_buf *buf, uint16_t n) #endif /* UIP_TCP */ /*---------------------------------------------------------------------------*/ uint8_t -uip_process(struct net_buf *buf, uint8_t flag) +uip_process(struct net_buf **buf_out, uint8_t flag) { + struct net_buf *buf = &buf_out; #if UIP_TCP register struct uip_conn *uip_connr = uip_conn(buf); #endif diff --git a/net/ip/contiki/ipv6/uip6.c b/net/ip/contiki/ipv6/uip6.c index 55e6de6c8cf..5731bf37608 100644 --- a/net/ip/contiki/ipv6/uip6.c +++ b/net/ip/contiki/ipv6/uip6.c @@ -92,6 +92,9 @@ extern void net_context_set_connection_status(struct net_context *context, void *net_context_get_internal_connection(struct net_context *context); void net_context_set_internal_connection(struct net_context *context, void *conn); +struct net_context *net_context_find_internal_connection(void *conn); +void net_context_tcp_set_pending(struct net_context *context, + struct net_buf *buf); /*---------------------------------------------------------------------------*/ /* For Debug, logging, statistics */ @@ -988,7 +991,7 @@ static inline void handle_tcp_retransmit_timer(struct net_buf *not_used, PRINTF("%s: connection %p buf %p\n", __func__, conn, conn ? conn->buf : 0); if (conn && conn->buf) { conn->timer = 0; - if (uip_process(conn->buf, UIP_TIMER)) { + if (uip_process(&conn->buf, UIP_TIMER)) { tcpip_resend_syn(conn, conn->buf); } } @@ -1008,8 +1011,9 @@ static inline void tcp_cancel_retrans_timer(struct uip_conn *conn) /*---------------------------------------------------------------------------*/ uint8_t -uip_process(struct net_buf *buf, uint8_t flag) +uip_process(struct net_buf **buf_out, uint8_t flag) { + struct net_buf *buf = *buf_out; #if UIP_TCP register struct uip_conn *uip_connr = uip_conn(buf); uint8_t c; @@ -1020,6 +1024,7 @@ uip_process(struct net_buf *buf, uint8_t flag) goto udp_send; } #endif /* UIP_UDP */ + #if UIP_TCP if(flag != UIP_TCP_SEND_CONN) { #endif @@ -1102,7 +1107,7 @@ uip_process(struct net_buf *buf, uint8_t flag) #if UIP_TCP uip_len(buf) = 0; uip_slen(buf) = 0; - + /* Increase the initial sequence number. */ if(++iss[3] == 0) { if(++iss[2] == 0) { @@ -1125,6 +1130,11 @@ uip_process(struct net_buf *buf, uint8_t flag) uip_connr->tcpstateflags = UIP_CLOSED; } } else if(uip_connr->tcpstateflags != UIP_CLOSED) { + if (!uip_connr->buf) { + /* There cannot be any data pending if buf is NULL */ + uip_outstanding(uip_connr) = 0; + } + /* * If the connection has outstanding data, we increase the * connection's timer and see if it has reached the RTO value @@ -1137,7 +1147,6 @@ uip_process(struct net_buf *buf, uint8_t flag) uip_connr->tcpstateflags == UIP_SYN_RCVD) && uip_connr->nrtx == UIP_MAXSYNRTX)) { uip_connr->tcpstateflags = UIP_CLOSED; - /* * We call UIP_APPCALL() with uip_flags set to * UIP_TIMEDOUT to inform the application that the @@ -1901,7 +1910,13 @@ uip_process(struct net_buf *buf, uint8_t flag) uip_connr->snd_nxt[2] = iss[2]; uip_connr->snd_nxt[3] = iss[3]; uip_connr->len = 1; - uip_connr->buf = ip_buf_ref(buf); + + if (flag == UIP_TCP_SEND_CONN) { + /* So we are trying send some data to other host */ + if (uip_connr->buf && uip_connr->buf != buf) { + uip_connr->buf = ip_buf_ref(buf); + } + } /* rcv_nxt should be the seqno from the incoming packet + 1. */ uip_connr->rcv_nxt[3] = UIP_TCP_BUF(buf)->seqno[3]; @@ -2150,6 +2165,7 @@ tcp_send_syn: uip_slen(buf) = 0; ip_buf_sent_status(buf) = 0; uip_set_conn(buf) = uip_connr; + if (uip_connr->buf) { /* Now that we know the original connection request, clear * the buf in connr @@ -2158,11 +2174,26 @@ tcp_send_syn: net_context_set_internal_connection(ip_buf_context(uip_connr->buf), uip_connr); tcp_cancel_retrans_timer(uip_connr); - ip_buf_unref(uip_connr->buf); - uip_connr->buf = NULL; + + /* We received ACK for syn */ + if (uip_connr->buf) { + net_context_set_connection_status(ip_buf_context(uip_connr->buf), -EINPROGRESS); + } + + /* Now send the pending data */ + buf = uip_connr->buf; + *buf_out = buf; + + uip_flags(buf) = UIP_CONNECTED; } - UIP_APPCALL(buf); - goto appsend; + /* Right now we have received SYN-ACK so we can now start to send data. + * The UIP_APPCALL() will cause a call to this function by the + * net_context.c TCP process thread which will call + * handle_tcp_connection(). + */ + UIP_APPCALL(buf); + PRINTF("Returning now buf %p ref %p\n", buf, buf->ref); + return 0; } /* Inform the application that the connection failed */ uip_flags(buf) = UIP_ABORT; @@ -2275,6 +2306,33 @@ tcp_send_syn: */ uip_slen(buf) = 0; } + + if (uip_connr->buf) { + net_context_tcp_set_pending(ip_buf_context(uip_connr->buf), NULL); + net_context_set_internal_connection(ip_buf_context(uip_connr->buf), + uip_connr); + + /* At this point we have received ACK to data in uip_connr->buf */ + + /* This is not an error but tells net_core.c:net_send() that + * user should be able to send now more data. + */ + net_context_set_connection_status(ip_buf_context(uip_connr->buf), + EISCONN); + + /* Eventually the uip_connr->buf will be freed + * by net_core.c:net_send() + */ + + tcp_cancel_retrans_timer(uip_connr); + + } else { + /* We have no pending data so this will cause ACK to be sent to + * peer in few lines below. + */ + uip_flags(buf) |= UIP_NEWDATA; + } + UIP_APPCALL(buf); appsend: @@ -2323,6 +2381,15 @@ tcp_send_syn: PRINTF("Setting connection %p to pending length %d\n", uip_connr, uip_connr->len); + if (uip_connr->buf) { + if (uip_connr->buf != buf) { + PRINTF("Data packet %p already pending....\n", + uip_connr->buf); + } + } else { + uip_connr->buf = ip_buf_ref(buf); + } + } else { /* If the application already had unacknowledged data, we @@ -2567,11 +2634,13 @@ uip_send(struct net_buf *buf, const void *data, int len) memmove(uip_sappdata(buf), (data), uip_slen(buf)); } } - if (uip_process(buf, UIP_TCP_SEND_CONN)) { - int ret = tcpip_ipv6_output(buf); + if (uip_process(&buf, UIP_TCP_SEND_CONN)) { + int ret; + + ret = tcpip_ipv6_output(buf); if (!ret) { PRINTF("Packet %p sending failed.\n", buf); - ip_buf_unref(buf); + ip_buf_sent_status(buf) = -EAGAIN; } } } diff --git a/net/ip/net_context.c b/net/ip/net_context.c index 83dabcb06ce..b5a44967b9f 100644 --- a/net/ip/net_context.c +++ b/net/ip/net_context.c @@ -70,7 +70,7 @@ struct net_context { enum net_tcp_type tcp_type; int connection_status; void *conn; - struct net_buf *last_sent; + struct net_buf *pending; }; #endif }; @@ -272,53 +272,25 @@ static int handle_tcp_connection(struct psock *p, enum tcp_event_type type, int net_context_tcp_send(struct net_buf *buf) { + bool connected, reset; + /* Prepare data to be sent */ - /* If we have already tried to send this buf, then set the flag - * accordingly so that psock can actually try to send the data. - */ - if (ip_buf_context(buf)->last_sent == buf) { - uip_flags(buf) |= UIP_REXMIT; - } else { - ip_buf_context(buf)->last_sent = buf; - } - - ip_buf_ref(buf); - process_post_synch(&ip_buf_context(buf)->tcp, tcpip_event, INT_TO_POINTER(TCP_WRITE_EVENT), buf); + connected = uip_flags(buf) & UIP_CONNECTED; + reset = uip_flags(buf) & UIP_ABORT; + /* If the buffer ref is 1, then the buffer was sent and it * is cleared already. */ if (buf->ref == 1) { - ip_buf_unref(buf); return 0; } - ip_buf_unref(buf); - - /* If we get -EAGAIN, then we need to retry the packet sending - * after we have received ACK from peer. Store the packet to be - * sent out later. - */ - if (ip_buf_sent_status(buf) == -EAGAIN) { - if (!uip_conn(buf)) { - ; - } else if (!uip_conn(buf)->buf) { - uip_conn(buf)->buf = ip_buf_ref(buf); - } else { - /* We just could not send the packet and thus need to - * discard it. - */ - ip_buf_sent_status(buf) = -EBUSY; - } - } - - ip_buf_context(buf)->connection_status = ip_buf_sent_status(buf); - return ip_buf_sent_status(buf); } @@ -327,11 +299,16 @@ int net_context_tcp_send(struct net_buf *buf) */ PROCESS_THREAD(tcp, ev, data, buf, user_data) { + NET_DBG("tcp %p ev %p data %p buf %p user_data %p next line %d\n", + process_thread_tcp, ev, data, buf, user_data, + process_pt->lc); + PROCESS_BEGIN(); while(1) { PROCESS_YIELD_UNTIL(ev == tcpip_event); + try_send: if (POINTER_TO_INT(data) == TCP_WRITE_EVENT) { /* We want to send data to peer. */ struct net_context *context = user_data; @@ -389,6 +366,23 @@ PROCESS_THREAD(tcp, ev, data, buf, user_data) } continue; + } else { + if (buf && uip_aborted(buf)) { + struct net_context *context = user_data; + NET_DBG("Connection aborted context %p\n", + user_data); + context->connection_status = -ECONNRESET; + continue; + } + + if (buf && uip_connected(buf)) { + struct net_context *context = user_data; + NET_DBG("Connection established context %p\n", + user_data); + context->connection_status = -EALREADY; + data = INT_TO_POINTER(TCP_WRITE_EVENT); + goto try_send; + } } read_data: @@ -418,6 +412,9 @@ PROCESS_THREAD(tcp, ev, data, buf, user_data) ip_buf_appdatalen(clone) = uip_len(buf); ip_buf_len(clone) = ip_buf_len(buf); ip_buf_context(clone) = user_data; + if (!ip_buf_context(buf)) { + ip_buf_context(buf) = user_data; + } uip_set_conn(clone) = uip_conn(buf); uip_flags(clone) = uip_flags(buf); uip_flags(clone) |= UIP_CONNECTED; @@ -442,7 +439,7 @@ PROCESS_THREAD(tcp, ev, data, buf, user_data) PROCESS_END(); } -int net_context_tcp_init(struct net_context *context, +int net_context_tcp_init(struct net_context *context, struct net_buf *buf, enum net_tcp_type tcp_type) { if (!context || context->tuple.ip_proto != IPPROTO_TCP) { @@ -462,6 +459,12 @@ int net_context_tcp_init(struct net_context *context, * us first, then we are the client. */ context->tcp_type = tcp_type; + } else if (context->tcp_type != tcp_type) { + /* This means that we have already selected that we + * are either client or server. Use the context + * value. + */ + return 0; } context->tcp.thread = process_thread_tcp; @@ -475,7 +478,7 @@ int net_context_tcp_init(struct net_context *context, #if UIP_ACTIVE_OPEN } else { context->tcp.name = "TCP client"; - context->connection_status = -EAGAIN; + context->connection_status = -EINPROGRESS; #ifdef CONFIG_NETWORKING_WITH_IPV6 NET_DBG("Connecting to "); @@ -485,7 +488,7 @@ int net_context_tcp_init(struct net_context *context, tcp_connect((uip_ipaddr_t *) &context->tuple.remote_addr->in6_addr, UIP_HTONS(context->tuple.remote_port), - context, &context->tcp); + context, &context->tcp, buf); #else /* CONFIG_NETWORKING_WITH_IPV6 */ NET_DBG("Connecting to "); PRINT6ADDR((const uip_ipaddr_t *)&context->tuple.remote_addr->in_addr); @@ -494,7 +497,7 @@ int net_context_tcp_init(struct net_context *context, tcp_connect((uip_ipaddr_t *) &context->tuple.remote_addr->in_addr, UIP_HTONS(context->tuple.remote_port), - context, &context->tcp); + context, &context->tcp, buf); #endif /* CONFIG_NETWORKING_WITH_IPV6 */ #endif /* UIP_ACTIVE_OPEN */ } @@ -543,6 +546,15 @@ void net_context_set_receiver_registered(struct net_context *context) context->receiver_registered = true; } +void net_context_unset_receiver_registered(struct net_context *context) +{ + if (!context) { + return; + } + + context->receiver_registered = false; +} + int net_context_get_connection_status(struct net_context *context) { if (!context) { @@ -571,6 +583,7 @@ void net_context_set_connection_status(struct net_context *context, } if (context->tuple.ip_proto == IPPROTO_TCP) { + NET_DBG("context %p status %d\n", context, status); context->connection_status = status; } #endif @@ -608,3 +621,47 @@ void net_context_set_internal_connection(struct net_context *context, } #endif } + +struct net_context *net_context_find_internal_connection(void *conn) +{ +#if !defined(CONFIG_NETWORKING_WITH_TCP) + return NULL; +#else + int i; + + for (i = 0; i < NET_MAX_CONTEXT; i++) { + if (contexts[i].conn == conn) { + return &contexts[i]; + } + } + + return NULL; +#endif +} + +struct net_buf *net_context_tcp_get_pending(struct net_context *context) +{ +#if !defined(CONFIG_NETWORKING_WITH_TCP) + return NULL; +#else + if (!context) { + return NULL; + } + + return context->pending; +#endif +} + +void net_context_tcp_set_pending(struct net_context *context, + struct net_buf *buf) +{ +#if !defined(CONFIG_NETWORKING_WITH_TCP) + return; +#else + if (!context) { + return; + } + + context->pending = buf; +#endif +} diff --git a/net/ip/net_core.c b/net/ip/net_core.c index d4942cad11c..a44a3248682 100644 --- a/net/ip/net_core.c +++ b/net/ip/net_core.c @@ -65,9 +65,16 @@ struct simple_udp_connection * net_context_get_udp_connection(struct net_context *context); int net_context_get_receiver_registered(struct net_context *context); void net_context_set_receiver_registered(struct net_context *context); -int net_context_tcp_init(struct net_context *context, +int net_context_tcp_init(struct net_context *context, struct net_buf *buf, enum net_tcp_type); int net_context_tcp_send(struct net_buf *buf); +void *net_context_get_internal_connection(struct net_context *context); +struct net_buf *net_context_tcp_get_pending(struct net_context *context); +void net_context_tcp_set_pending(struct net_context *context, + struct net_buf *buf); +void net_context_set_connection_status(struct net_context *context, + int status); +void net_context_unset_receiver_registered(struct net_context *context); /* Stacks for the tx & rx fibers. * FIXME: stack size needs fine-tuning @@ -103,46 +110,65 @@ int net_send(struct net_buf *buf) { int ret = 0; - if (ip_buf_len(buf) == 0) { + if (!buf || ip_buf_len(buf) == 0) { return -ENODATA; } + if (buf->len && !uip_appdatalen(buf)) { + uip_appdatalen(buf) = buf->len; + } + #ifdef CONFIG_NETWORKING_WITH_TCP #define MAX_TCP_RETRY_COUNT 5 - net_context_tcp_init(ip_buf_context(buf), NET_TCP_TYPE_CLIENT); - if (ip_buf_context(buf)) { - if (net_context_get_connection_status( - ip_buf_context(buf)) == -ETIMEDOUT) { - return -ETIMEDOUT; - } - if (ip_buf_tcp_retry_count(buf) < MAX_TCP_RETRY_COUNT) { - int ret; - - if (net_context_get_tuple( - ip_buf_context(buf))->ip_proto == + if (ip_buf_context(buf) && + net_context_get_tuple(ip_buf_context(buf))->ip_proto == IPPROTO_TCP) { - if (uip_conn(buf) && uip_conn(buf)->len > 0) { - /* There is already pending packet to - * be sent. Application needs to try to - * send data a bit later. - * Do not wait forever thou so that - * the connection can proceed if - * needed. - */ - ip_buf_tcp_retry_count(buf)++; - return -EAGAIN; - } - ret = net_context_get_connection_status( - ip_buf_context(buf)); - if (ret < 0) { - ip_buf_tcp_retry_count(buf)++; - return ret; + struct uip_conn *conn; + int status; + + net_context_tcp_init(ip_buf_context(buf), buf, + NET_TCP_TYPE_CLIENT); + + status = net_context_get_connection_status( + ip_buf_context(buf)); + NET_DBG("context %p buf %p status %d\n", + ip_buf_context(buf), buf, status); + + switch (status) { + case EISCONN: + /* User should be able to send new data now. */ + NET_DBG("Send new data buf %p ref %d\n", buf, buf->ref); + net_context_set_connection_status(ip_buf_context(buf), + 0); + conn = (struct uip_conn *)net_context_get_internal_connection(ip_buf_context(buf)); + if (conn->buf) { + ip_buf_unref(conn->buf); + + if (conn->buf == buf) { + conn->buf = NULL; + return 0; } + + conn->buf = NULL; } - } else { - ip_buf_tcp_retry_count(buf) = 0; - ret = -EAGAIN; + break; + + case -EALREADY: + NET_DBG("Connection established\n"); + return 0; + + case -EINPROGRESS: + NET_DBG("Connection being established\n"); + return status; + + case -ECONNRESET: + NET_DBG("Connection reset\n"); + net_context_unset_receiver_registered( + ip_buf_context(buf)); + return status; } + + ret = status; } #endif @@ -596,7 +622,7 @@ struct net_buf *net_receive(struct net_context *context, int32_t timeout) break; case IPPROTO_TCP: #ifdef CONFIG_NETWORKING_WITH_TCP - ret = net_context_tcp_init(context, NET_TCP_TYPE_SERVER); + ret = net_context_tcp_init(context, NULL, NET_TCP_TYPE_SERVER); if (ret) { NET_DBG("TCP connection init failed\n"); ret = -ENOENT; @@ -763,7 +789,11 @@ static int check_and_send_packet(struct net_buf *buf) */ ret = 1; } else { - ip_buf_sent_status(buf) = 0; + ip_buf_sent_status(buf) = ret; + ret = true; /* This will prevent caller to discard + * the buffer that needs to be resent + * again. + */ } #else NET_DBG("TCP not supported\n");