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 <jukka.rissanen@linux.intel.com>
This commit is contained in:
Jukka Rissanen 2016-05-16 09:43:22 +03:00
commit 61edc68c9e
8 changed files with 263 additions and 102 deletions

View file

@ -220,7 +220,7 @@ packet_input(struct net_buf *buf)
#if UIP_ACTIVE_OPEN #if UIP_ACTIVE_OPEN
struct uip_conn * struct uip_conn *
tcp_connect(const uip_ipaddr_t *ripaddr, uint16_t port, void *appstate, 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; 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.p = process;
c->appstate.state = appstate; c->appstate.state = appstate;
tcpip_poll_tcp(c); tcpip_poll_tcp(c, buf);
return c; return c;
} }
@ -837,12 +837,18 @@ tcpip_poll_udp(struct uip_udp_conn *conn)
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#if UIP_TCP #if UIP_TCP
void 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 */ /* We are sending here the initial SYN */
struct net_buf *buf = ip_buf_get_tx(conn->appstate.state); struct net_buf *buf = ip_buf_get_tx(conn->appstate.state);
uip_set_conn(buf) = conn; uip_set_conn(data_buf) = conn;
conn->buf = ip_buf_ref(buf);
/* 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); process_post_synch(&tcpip_process, TCP_POLL, conn, buf);
} }
@ -899,7 +905,6 @@ tcpip_uipcall(struct net_buf *buf)
} }
} }
#endif /* UIP_TCP */ #endif /* UIP_TCP */
if(ts->p != NULL) { if(ts->p != NULL) {
process_post_synch(ts->p, tcpip_event, ts->state, buf); process_post_synch(ts->p, tcpip_event, ts->state, buf);
} }

View file

@ -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, 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. * 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. * \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); void tcpip_resend_syn(struct uip_conn *conn, struct net_buf *buf);

View file

@ -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, memcpy(&uip_buf(buf)[UIP_LLH_LEN + UIP_IPUDPH_LEN], data,
len > UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPUDPH_LEN? len > UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPUDPH_LEN?
UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPUDPH_LEN: 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 */ /* The packet was dropped, we can return now */
return 0; return 0;
} }

View file

@ -284,8 +284,7 @@ void uip_setipid(uint16_t id);
* *
* \hideinitializer * \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. * Periodic processing for a connection identified by its number.
@ -331,7 +330,7 @@ void uip_setipid(uint16_t id);
*/ */
#if UIP_TCP #if UIP_TCP
#define uip_periodic(buf, conn) do { uip_set_conn(buf) = &uip_conns[conn]; \ #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 * Macro to determine whether a specific uIP connection is active
@ -355,7 +354,7 @@ void uip_setipid(uint16_t id);
* \hideinitializer * \hideinitializer
*/ */
#define uip_periodic_conn(buf, conn) do { uip_set_conn(buf) = conn; \ #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. * Request that a particular connection should be polled.
@ -369,7 +368,7 @@ void uip_setipid(uint16_t id);
* \hideinitializer * \hideinitializer
*/ */
#define uip_poll_conn(buf, conn) do { uip_set_conn(buf) = conn; \ #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 */ #endif /* UIP_TCP */
@ -423,7 +422,7 @@ void uip_setipid(uint16_t id);
* \hideinitializer * \hideinitializer
*/ */
#define uip_udp_periodic_conn(buf, conn) do { uip_set_udp_conn(buf) = conn; \ #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 */ #endif /* UIP_UDP */
/** \brief Abandon the reassembly of the current packet */ /** \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; extern uint16_t uip_urglen, uip_surglen;
#endif /* UIP_URGDATA > 0 */ #endif /* UIP_URGDATA > 0 */
/** /**
* Representation of a uIP TCP connection. * Representation of a uIP TCP connection.
* *
@ -1569,7 +1567,7 @@ uip_ext_hdr_options_process(); */
* *
* The actual uIP function which does all the work. * 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() /* The following flags are passed as an argument to the uip_process()
function. They are used to distinguish between the two cases where function. They are used to distinguish between the two cases where

View file

@ -678,8 +678,9 @@ uip_add_rcv_nxt(struct net_buf *buf, uint16_t n)
#endif /* UIP_TCP */ #endif /* UIP_TCP */
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
uint8_t 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 #if UIP_TCP
register struct uip_conn *uip_connr = uip_conn(buf); register struct uip_conn *uip_connr = uip_conn(buf);
#endif #endif

View file

@ -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_get_internal_connection(struct net_context *context);
void net_context_set_internal_connection(struct net_context *context, void net_context_set_internal_connection(struct net_context *context,
void *conn); 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 */ /* 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); PRINTF("%s: connection %p buf %p\n", __func__, conn, conn ? conn->buf : 0);
if (conn && conn->buf) { if (conn && conn->buf) {
conn->timer = 0; conn->timer = 0;
if (uip_process(conn->buf, UIP_TIMER)) { if (uip_process(&conn->buf, UIP_TIMER)) {
tcpip_resend_syn(conn, conn->buf); tcpip_resend_syn(conn, conn->buf);
} }
} }
@ -1008,8 +1011,9 @@ static inline void tcp_cancel_retrans_timer(struct uip_conn *conn)
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
uint8_t 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 #if UIP_TCP
register struct uip_conn *uip_connr = uip_conn(buf); register struct uip_conn *uip_connr = uip_conn(buf);
uint8_t c; uint8_t c;
@ -1020,6 +1024,7 @@ uip_process(struct net_buf *buf, uint8_t flag)
goto udp_send; goto udp_send;
} }
#endif /* UIP_UDP */ #endif /* UIP_UDP */
#if UIP_TCP #if UIP_TCP
if(flag != UIP_TCP_SEND_CONN) { if(flag != UIP_TCP_SEND_CONN) {
#endif #endif
@ -1102,7 +1107,7 @@ uip_process(struct net_buf *buf, uint8_t flag)
#if UIP_TCP #if UIP_TCP
uip_len(buf) = 0; uip_len(buf) = 0;
uip_slen(buf) = 0; uip_slen(buf) = 0;
/* Increase the initial sequence number. */ /* Increase the initial sequence number. */
if(++iss[3] == 0) { if(++iss[3] == 0) {
if(++iss[2] == 0) { if(++iss[2] == 0) {
@ -1125,6 +1130,11 @@ uip_process(struct net_buf *buf, uint8_t flag)
uip_connr->tcpstateflags = UIP_CLOSED; uip_connr->tcpstateflags = UIP_CLOSED;
} }
} else if(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 * If the connection has outstanding data, we increase the
* connection's timer and see if it has reached the RTO value * 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->tcpstateflags == UIP_SYN_RCVD) &&
uip_connr->nrtx == UIP_MAXSYNRTX)) { uip_connr->nrtx == UIP_MAXSYNRTX)) {
uip_connr->tcpstateflags = UIP_CLOSED; uip_connr->tcpstateflags = UIP_CLOSED;
/* /*
* We call UIP_APPCALL() with uip_flags set to * We call UIP_APPCALL() with uip_flags set to
* UIP_TIMEDOUT to inform the application that the * 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[2] = iss[2];
uip_connr->snd_nxt[3] = iss[3]; uip_connr->snd_nxt[3] = iss[3];
uip_connr->len = 1; 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. */ /* rcv_nxt should be the seqno from the incoming packet + 1. */
uip_connr->rcv_nxt[3] = UIP_TCP_BUF(buf)->seqno[3]; uip_connr->rcv_nxt[3] = UIP_TCP_BUF(buf)->seqno[3];
@ -2150,6 +2165,7 @@ tcp_send_syn:
uip_slen(buf) = 0; uip_slen(buf) = 0;
ip_buf_sent_status(buf) = 0; ip_buf_sent_status(buf) = 0;
uip_set_conn(buf) = uip_connr; uip_set_conn(buf) = uip_connr;
if (uip_connr->buf) { if (uip_connr->buf) {
/* Now that we know the original connection request, clear /* Now that we know the original connection request, clear
* the buf in connr * the buf in connr
@ -2158,11 +2174,26 @@ tcp_send_syn:
net_context_set_internal_connection(ip_buf_context(uip_connr->buf), net_context_set_internal_connection(ip_buf_context(uip_connr->buf),
uip_connr); uip_connr);
tcp_cancel_retrans_timer(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); /* Right now we have received SYN-ACK so we can now start to send data.
goto appsend; * 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 */ /* Inform the application that the connection failed */
uip_flags(buf) = UIP_ABORT; uip_flags(buf) = UIP_ABORT;
@ -2275,6 +2306,33 @@ tcp_send_syn:
*/ */
uip_slen(buf) = 0; 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); UIP_APPCALL(buf);
appsend: appsend:
@ -2323,6 +2381,15 @@ tcp_send_syn:
PRINTF("Setting connection %p to pending length %d\n", PRINTF("Setting connection %p to pending length %d\n",
uip_connr, uip_connr->len); 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 { } else {
/* If the application already had unacknowledged data, we /* 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)); memmove(uip_sappdata(buf), (data), uip_slen(buf));
} }
} }
if (uip_process(buf, UIP_TCP_SEND_CONN)) { if (uip_process(&buf, UIP_TCP_SEND_CONN)) {
int ret = tcpip_ipv6_output(buf); int ret;
ret = tcpip_ipv6_output(buf);
if (!ret) { if (!ret) {
PRINTF("Packet %p sending failed.\n", buf); PRINTF("Packet %p sending failed.\n", buf);
ip_buf_unref(buf); ip_buf_sent_status(buf) = -EAGAIN;
} }
} }
} }

View file

@ -70,7 +70,7 @@ struct net_context {
enum net_tcp_type tcp_type; enum net_tcp_type tcp_type;
int connection_status; int connection_status;
void *conn; void *conn;
struct net_buf *last_sent; struct net_buf *pending;
}; };
#endif #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) int net_context_tcp_send(struct net_buf *buf)
{ {
bool connected, reset;
/* Prepare data to be sent */ /* 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, process_post_synch(&ip_buf_context(buf)->tcp,
tcpip_event, tcpip_event,
INT_TO_POINTER(TCP_WRITE_EVENT), INT_TO_POINTER(TCP_WRITE_EVENT),
buf); 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 /* If the buffer ref is 1, then the buffer was sent and it
* is cleared already. * is cleared already.
*/ */
if (buf->ref == 1) { if (buf->ref == 1) {
ip_buf_unref(buf);
return 0; 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); 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) 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(); PROCESS_BEGIN();
while(1) { while(1) {
PROCESS_YIELD_UNTIL(ev == tcpip_event); PROCESS_YIELD_UNTIL(ev == tcpip_event);
try_send:
if (POINTER_TO_INT(data) == TCP_WRITE_EVENT) { if (POINTER_TO_INT(data) == TCP_WRITE_EVENT) {
/* We want to send data to peer. */ /* We want to send data to peer. */
struct net_context *context = user_data; struct net_context *context = user_data;
@ -389,6 +366,23 @@ PROCESS_THREAD(tcp, ev, data, buf, user_data)
} }
continue; 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: read_data:
@ -418,6 +412,9 @@ PROCESS_THREAD(tcp, ev, data, buf, user_data)
ip_buf_appdatalen(clone) = uip_len(buf); ip_buf_appdatalen(clone) = uip_len(buf);
ip_buf_len(clone) = ip_buf_len(buf); ip_buf_len(clone) = ip_buf_len(buf);
ip_buf_context(clone) = user_data; 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_set_conn(clone) = uip_conn(buf);
uip_flags(clone) = uip_flags(buf); uip_flags(clone) = uip_flags(buf);
uip_flags(clone) |= UIP_CONNECTED; uip_flags(clone) |= UIP_CONNECTED;
@ -442,7 +439,7 @@ PROCESS_THREAD(tcp, ev, data, buf, user_data)
PROCESS_END(); 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) enum net_tcp_type tcp_type)
{ {
if (!context || context->tuple.ip_proto != IPPROTO_TCP) { 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. * us first, then we are the client.
*/ */
context->tcp_type = tcp_type; 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; context->tcp.thread = process_thread_tcp;
@ -475,7 +478,7 @@ int net_context_tcp_init(struct net_context *context,
#if UIP_ACTIVE_OPEN #if UIP_ACTIVE_OPEN
} else { } else {
context->tcp.name = "TCP client"; context->tcp.name = "TCP client";
context->connection_status = -EAGAIN; context->connection_status = -EINPROGRESS;
#ifdef CONFIG_NETWORKING_WITH_IPV6 #ifdef CONFIG_NETWORKING_WITH_IPV6
NET_DBG("Connecting to "); NET_DBG("Connecting to ");
@ -485,7 +488,7 @@ int net_context_tcp_init(struct net_context *context,
tcp_connect((uip_ipaddr_t *) tcp_connect((uip_ipaddr_t *)
&context->tuple.remote_addr->in6_addr, &context->tuple.remote_addr->in6_addr,
UIP_HTONS(context->tuple.remote_port), UIP_HTONS(context->tuple.remote_port),
context, &context->tcp); context, &context->tcp, buf);
#else /* CONFIG_NETWORKING_WITH_IPV6 */ #else /* CONFIG_NETWORKING_WITH_IPV6 */
NET_DBG("Connecting to "); NET_DBG("Connecting to ");
PRINT6ADDR((const uip_ipaddr_t *)&context->tuple.remote_addr->in_addr); 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 *) tcp_connect((uip_ipaddr_t *)
&context->tuple.remote_addr->in_addr, &context->tuple.remote_addr->in_addr,
UIP_HTONS(context->tuple.remote_port), UIP_HTONS(context->tuple.remote_port),
context, &context->tcp); context, &context->tcp, buf);
#endif /* CONFIG_NETWORKING_WITH_IPV6 */ #endif /* CONFIG_NETWORKING_WITH_IPV6 */
#endif /* UIP_ACTIVE_OPEN */ #endif /* UIP_ACTIVE_OPEN */
} }
@ -543,6 +546,15 @@ void net_context_set_receiver_registered(struct net_context *context)
context->receiver_registered = true; 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) int net_context_get_connection_status(struct net_context *context)
{ {
if (!context) { if (!context) {
@ -571,6 +583,7 @@ void net_context_set_connection_status(struct net_context *context,
} }
if (context->tuple.ip_proto == IPPROTO_TCP) { if (context->tuple.ip_proto == IPPROTO_TCP) {
NET_DBG("context %p status %d\n", context, status);
context->connection_status = status; context->connection_status = status;
} }
#endif #endif
@ -608,3 +621,47 @@ void net_context_set_internal_connection(struct net_context *context,
} }
#endif #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
}

View file

@ -65,9 +65,16 @@ struct simple_udp_connection *
net_context_get_udp_connection(struct net_context *context); net_context_get_udp_connection(struct net_context *context);
int net_context_get_receiver_registered(struct net_context *context); int net_context_get_receiver_registered(struct net_context *context);
void net_context_set_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); enum net_tcp_type);
int net_context_tcp_send(struct net_buf *buf); 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. /* Stacks for the tx & rx fibers.
* FIXME: stack size needs fine-tuning * FIXME: stack size needs fine-tuning
@ -103,46 +110,65 @@ int net_send(struct net_buf *buf)
{ {
int ret = 0; int ret = 0;
if (ip_buf_len(buf) == 0) { if (!buf || ip_buf_len(buf) == 0) {
return -ENODATA; return -ENODATA;
} }
if (buf->len && !uip_appdatalen(buf)) {
uip_appdatalen(buf) = buf->len;
}
#ifdef CONFIG_NETWORKING_WITH_TCP #ifdef CONFIG_NETWORKING_WITH_TCP
#define MAX_TCP_RETRY_COUNT 5 #define MAX_TCP_RETRY_COUNT 5
net_context_tcp_init(ip_buf_context(buf), NET_TCP_TYPE_CLIENT); if (ip_buf_context(buf) &&
if (ip_buf_context(buf)) { net_context_get_tuple(ip_buf_context(buf))->ip_proto ==
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 ==
IPPROTO_TCP) { IPPROTO_TCP) {
if (uip_conn(buf) && uip_conn(buf)->len > 0) { struct uip_conn *conn;
/* There is already pending packet to int status;
* be sent. Application needs to try to
* send data a bit later. net_context_tcp_init(ip_buf_context(buf), buf,
* Do not wait forever thou so that NET_TCP_TYPE_CLIENT);
* the connection can proceed if
* needed. status = net_context_get_connection_status(
*/ ip_buf_context(buf));
ip_buf_tcp_retry_count(buf)++; NET_DBG("context %p buf %p status %d\n",
return -EAGAIN; ip_buf_context(buf), buf, status);
}
ret = net_context_get_connection_status( switch (status) {
ip_buf_context(buf)); case EISCONN:
if (ret < 0) { /* User should be able to send new data now. */
ip_buf_tcp_retry_count(buf)++; NET_DBG("Send new data buf %p ref %d\n", buf, buf->ref);
return ret; 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 { break;
ip_buf_tcp_retry_count(buf) = 0;
ret = -EAGAIN; 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 #endif
@ -596,7 +622,7 @@ struct net_buf *net_receive(struct net_context *context, int32_t timeout)
break; break;
case IPPROTO_TCP: case IPPROTO_TCP:
#ifdef CONFIG_NETWORKING_WITH_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) { if (ret) {
NET_DBG("TCP connection init failed\n"); NET_DBG("TCP connection init failed\n");
ret = -ENOENT; ret = -ENOENT;
@ -763,7 +789,11 @@ static int check_and_send_packet(struct net_buf *buf)
*/ */
ret = 1; ret = 1;
} else { } 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 #else
NET_DBG("TCP not supported\n"); NET_DBG("TCP not supported\n");