From 04a661a97c9db63a524f29f05c78e5cb0d5b5d3f Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 30 May 2015 09:12:27 -0600 Subject: [PATCH] TCP networking: Add support for network driver events --- net/devif/devif.h | 7 +- net/netdev/netdev.h | 6 +- net/socket/connect.c | 13 +- net/socket/net_close.c | 13 +- net/socket/net_monitor.c | 9 +- net/socket/net_sendfile.c | 7 +- net/socket/recvfrom.c | 13 +- net/tcp/Make.defs | 6 +- net/tcp/tcp.h | 76 ++++++++++- net/tcp/tcp_appsend.c | 15 ++- net/tcp/tcp_conn.c | 233 ++++++++++++++++++++++++---------- net/tcp/tcp_devpoll.c | 2 +- net/tcp/tcp_netpoll.c | 9 +- net/tcp/tcp_send_buffered.c | 4 +- net/tcp/tcp_send_unbuffered.c | 4 +- net/udp/udp.h | 2 + net/udp/udp_finddev.c | 36 +++--- 17 files changed, 324 insertions(+), 131 deletions(-) diff --git a/net/devif/devif.h b/net/devif/devif.h index 46fce99607..5b0f1626bd 100644 --- a/net/devif/devif.h +++ b/net/devif/devif.h @@ -193,8 +193,11 @@ /* The set of events that and implications to the TCP connection state */ -#define TCP_CONN_EVENTS (TCP_CLOSE | TCP_ABORT | TCP_CONNECTED | \ - TCP_TIMEDOUT | NETDEV_DOWN) +#define TCP_CONN_EVENTS \ + (TCP_CLOSE | TCP_ABORT | TCP_CONNECTED | TCP_TIMEDOUT | NETDEV_DOWN) + +#define TCP_DISCONN_EVENTS \ + (TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT | NETDEV_DOWN) /* IPv4/IPv6 Helpers */ diff --git a/net/netdev/netdev.h b/net/netdev/netdev.h index 8c9bd1077d..9b5ca75e6f 100644 --- a/net/netdev/netdev.h +++ b/net/netdev/netdev.h @@ -68,9 +68,11 @@ extern "C" #define EXTERN extern #endif -/* List of registered Ethernet device drivers */ - #if CONFIG_NSOCKET_DESCRIPTORS > 0 +/* List of registered Ethernet device drivers. This duplicates a declaration + * in net/netdev/netdev.h + */ + EXTERN struct net_driver_s *g_netdevices; #endif diff --git a/net/socket/connect.c b/net/socket/connect.c index 5775213f10..9d5d9699ef 100644 --- a/net/socket/connect.c +++ b/net/socket/connect.c @@ -118,7 +118,7 @@ static inline int psock_setup_callbacks(FAR struct socket *psock, /* Set up the connection "interrupt" handler */ pstate->tc_cb->flags = (TCP_NEWDATA | TCP_CLOSE | TCP_ABORT | - TCP_TIMEDOUT | TCP_CONNECTED); + TCP_TIMEDOUT | TCP_CONNECTED | NETDEV_DOWN); pstate->tc_cb->priv = (void*)pstate; pstate->tc_cb->event = psock_connect_interrupt; @@ -227,11 +227,20 @@ static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev, else if ((flags & TCP_TIMEDOUT) != 0) { - /* Indicate that the remote host is unreachable (or should this be timedout?) */ + /* Indicate that the connection timedout?)*/ pstate->tc_result = -ETIMEDOUT; } + else if ((flags & NETDEV_DOWN) != 0) + { + /* The network device went down. Indicate that the remote host + * is unreachable. + */ + + pstate->tc_result = -ENETUNREACH; + } + /* TCP_CONNECTED: The socket is successfully connected */ else if ((flags & TCP_CONNECTED) != 0) diff --git a/net/socket/net_close.c b/net/socket/net_close.c index c81a9b4bb6..ab71b80b1b 100644 --- a/net/socket/net_close.c +++ b/net/socket/net_close.c @@ -167,12 +167,14 @@ static uint16_t netclose_interrupt(FAR struct net_driver_s *dev, nllvdbg("conn: %p flags: %04x\n", conn, flags); - /* TCP_CLOSE: The remote host has closed the connection - * TCP_ABORT: The remote host has aborted the connection - * TCP_TIMEDOUT: The remote did not respond, the connection timed out + /* TCP_DISCONN_EVENTS: + * TCP_CLOSE: The remote host has closed the connection + * TCP_ABORT: The remote host has aborted the connection + * TCP_TIMEDOUT: The remote did not respond, the connection timed out + * NETDEV_DOWN: The network device went down */ - if ((flags & (TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT)) != 0) + if ((flags & TCP_DISCONN_EVENTS) != 0) { /* The disconnection is complete */ @@ -371,8 +373,7 @@ static inline int netclose_disconnect(FAR struct socket *psock) { /* Set up to receive TCP data event callbacks */ - state.cl_cb->flags = (TCP_NEWDATA | TCP_POLL | TCP_CLOSE | TCP_ABORT | - TCP_TIMEDOUT); + state.cl_cb->flags = (TCP_NEWDATA | TCP_POLL | TCP_DISCONN_EVENTS); state.cl_cb->event = netclose_interrupt; #ifdef CONFIG_NET_SOLINGER diff --git a/net/socket/net_monitor.c b/net/socket/net_monitor.c index 99049737ed..34a675eb36 100644 --- a/net/socket/net_monitor.c +++ b/net/socket/net_monitor.c @@ -89,9 +89,11 @@ static void connection_event(FAR struct tcp_conn_s *conn, uint16_t flags) { nllvdbg("flags: %04x s_flags: %02x\n", flags, psock->s_flags); - /* TCP_CLOSE, TCP_ABORT, or TCP_TIMEDOUT: Loss-of-connection events */ + /* TCP_DISCONN_EVENTS: TCP_CLOSE, TCP_ABORT, TCP_TIMEDOUT, or + * NETDEV_DOWN. All loss-of-connection events. + */ - if ((flags & (TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT)) != 0) + if ((flags & TCP_DISCONN_EVENTS) != 0) { net_lostconnection(psock, flags); } @@ -218,6 +220,7 @@ void net_lostconnection(FAR struct socket *psock, uint16_t flags) * TCP_CLOSE: The remote host has closed the connection * TCP_ABORT: The remote host has aborted the connection * TCP_TIMEDOUT: Connection aborted due to too many retransmissions. + * NETDEV_DOWN: The network device went down * * And we need to set these two socket status bits appropriately: * @@ -237,7 +240,7 @@ void net_lostconnection(FAR struct socket *psock, uint16_t flags) psock->s_flags &= ~_SF_CONNECTED; psock->s_flags |= _SF_CLOSED; } - else if ((flags & (TCP_ABORT | TCP_TIMEDOUT)) != 0) + else if ((flags & (TCP_ABORT | TCP_TIMEDOUT | NETDEV_DOWN)) != 0) { /* The loss of connection was less than graceful. This will (eventually) * be reported as an ENOTCONN error. diff --git a/net/socket/net_sendfile.c b/net/socket/net_sendfile.c index 52daf62036..749ee71e99 100644 --- a/net/socket/net_sendfile.c +++ b/net/socket/net_sendfile.c @@ -217,7 +217,7 @@ static uint16_t ack_interrupt(FAR struct net_driver_s *dev, FAR void *pvconn, /* Check for a loss of connection */ - else if ((flags & (TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT)) != 0) + else if ((flags & TCP_DISCONN_EVENTS) != 0) { /* Report not connected */ @@ -329,7 +329,7 @@ static uint16_t sendfile_interrupt(FAR struct net_driver_s *dev, FAR void *pvcon /* Check for a loss of connection */ - if ((flags & (TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT)) != 0) + if ((flags & TCP_DISCONN_EVENTS) != 0) { /* Report not connected */ @@ -707,8 +707,7 @@ ssize_t net_sendfile(int outfd, struct file *infile, off_t *offset, /* Set up the ACK callback in the connection */ - state.snd_ackcb->flags = (TCP_ACKDATA | TCP_REXMIT | TCP_CLOSE | - TCP_ABORT | TCP_TIMEDOUT); + state.snd_ackcb->flags = (TCP_ACKDATA | TCP_REXMIT | TCP_DISCONN_EVENTS); state.snd_ackcb->priv = (void*)&state; state.snd_ackcb->event = ack_interrupt; diff --git a/net/socket/recvfrom.c b/net/socket/recvfrom.c index 6b36dc7aa7..fa08778fe1 100644 --- a/net/socket/recvfrom.c +++ b/net/socket/recvfrom.c @@ -804,12 +804,14 @@ static uint16_t recvfrom_tcpinterrupt(FAR struct net_driver_s *dev, /* Check for a loss of connection. * - * TCP_CLOSE: The remote host has closed the connection - * TCP_ABORT: The remote host has aborted the connection - * TCP_TIMEDOUT: Connection aborted due to too many retransmissions. + * TCP_DISCONN_EVENTS: + * TCP_CLOSE: The remote host has closed the connection + * TCP_ABORT: The remote host has aborted the connection + * TCP_TIMEDOUT: Connection aborted due to too many retransmissions. + * NETDEV_DOWN: The network device went down */ - else if ((flags & (TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT)) != 0) + else if ((flags & TCP_DISCONN_EVENTS) != 0) { nllvdbg("Lost connection\n"); @@ -1692,8 +1694,7 @@ static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, state.rf_cb = tcp_callback_alloc(conn); if (state.rf_cb) { - state.rf_cb->flags = (TCP_NEWDATA | TCP_POLL | TCP_CLOSE | - TCP_ABORT | TCP_TIMEDOUT); + state.rf_cb->flags = (TCP_NEWDATA | TCP_POLL | TCP_DISCONN_EVENTS); state.rf_cb->priv = (void*)&state; state.rf_cb->event = recvfrom_tcpinterrupt; diff --git a/net/tcp/Make.defs b/net/tcp/Make.defs index 6daf335320..9581c626ab 100644 --- a/net/tcp/Make.defs +++ b/net/tcp/Make.defs @@ -55,9 +55,9 @@ endif # Transport layer -NET_CSRCS += tcp_conn.c tcp_seqno.c tcp_devpoll.c tcp_timer.c tcp_send.c -NET_CSRCS += tcp_input.c tcp_appsend.c tcp_listen.c tcp_callback.c -NET_CSRCS += tcp_backlog.c tcp_ipselect.c +NET_CSRCS += tcp_conn.c tcp_seqno.c tcp_devpoll.c tcp_finddev.c tcp_timer.c +NET_CSRCS += tcp_send.c tcp_input.c tcp_appsend.c tcp_listen.c +NET_CSRCS += tcp_callback.c tcp_backlog.c tcp_ipselect.c # TCP write buffering diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index 3ef75ac82f..f48499e7f4 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -62,8 +62,17 @@ /* Allocate a new TCP data callback */ -#define tcp_callback_alloc(conn) devif_callback_alloc(NULL, &conn->list) -#define tcp_callback_free(conn,cb) devif_callback_free(NULL, cb, &conn->list) +#ifdef CONFIG_NETDEV_MULTINIC +# define tcp_callback_alloc(conn) \ + devif_callback_alloc(conn->dev, &conn->list) +# define tcp_callback_free(conn,cb) \ + devif_callback_free(conn->dev, cb, &conn->list) +#else +# define tcp_callback_alloc(conn) \ + devif_callback_alloc(g_netdevices, &conn->list) +# define tcp_callback_free(conn,cb) \ + devif_callback_free(g_netdevices, cb, &conn->list) +#endif /* Get the current maximum segment size that can be sent on the current * TCP connection. @@ -141,16 +150,26 @@ struct tcp_conn_s uint16_t unacked; /* Number bytes sent but not yet ACKed */ #endif +#ifdef CONFIG_NETDEV_MULTINIC + /* If the TCP socket is bound to a local address, then this is + * a reference to the device that routes traffic on the corresponding + * network. + */ + + FAR struct net_driver_s *dev; +#endif + +#ifdef CONFIG_NET_TCP_READAHEAD /* Read-ahead buffering. * * readahead - A singly linked list of type struct iob_qentry_s * where the TCP/IP read-ahead data is retained. */ -#ifdef CONFIG_NET_TCP_READAHEAD struct iob_queue_s readahead; /* Read-ahead buffering */ #endif +#ifdef CONFIG_NET_TCP_WRITE_BUFFERS /* Write buffering * * write_q - The queue of unsent I/O buffers. The head of this @@ -159,7 +178,6 @@ struct tcp_conn_s * chains. Sequence number ordering. */ -#ifdef CONFIG_NET_TCP_WRITE_BUFFERS sq_queue_t write_q; /* Write buffering for segments */ sq_queue_t unacked_q; /* Write buffering for un-ACKed segments */ uint16_t expired; /* Number segments retransmitted but not yet ACKed, @@ -168,6 +186,7 @@ struct tcp_conn_s uint32_t isn; /* Initial sequence number */ #endif +#ifdef CONFIG_NET_TCPBACKLOG /* Listen backlog support * * blparent - The backlog parent. If this connection is backlogged, @@ -178,7 +197,6 @@ struct tcp_conn_s * struct tcp_backlog_s tear-off structure that manages that backlog. */ -#ifdef CONFIG_NET_TCPBACKLOG FAR struct tcp_conn_s *blparent; FAR struct tcp_backlog_s *backlog; #endif @@ -269,6 +287,14 @@ extern "C" # define EXTERN extern #endif +#if CONFIG_NSOCKET_DESCRIPTORS > 0 +/* List of registered Ethernet device drivers. This duplicates a declaration + * in net/tcp/tcp.h + */ + +EXTERN struct net_driver_s *g_netdevices; +#endif + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ @@ -340,6 +366,46 @@ FAR struct tcp_conn_s *tcp_active(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *tcp_nextconn(FAR struct tcp_conn_s *conn); +/**************************************************************************** + * Function: tcp_find_ipv4_device + * + * Description: + * Select the network driver to use with the IPv4 TCP transaction. + * + * Input Parameters: + * conn - TCP connection structure. The locally bound address, laddr, + * should be set to a non-zero value in this structure. + * + * Returned Value: + * Zero (OK) is returned on success. A negated errno value is returned + * on failure. -ENODEV is the only expected error value. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv4 +int tcp_find_ipv4_device(FAR struct tcp_conn_s *conn); +#endif + +/**************************************************************************** + * Function: tcp_find_ipv6_device + * + * Description: + * Select the network driver to use with the IPv6 TCP transaction. + * + * Input Parameters: + * conn - TCP connection structure. The locally bound address, laddr, + * should be set to a non-zero value in this structure. + * + * Returned Value: + * Zero (OK) is returned on success. A negated errno value is returned + * on failure. -EHOSTUNREACH is the only expected error value. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +int tcp_find_ipv6_device(FAR struct tcp_conn_s *conn); +#endif + /**************************************************************************** * Name: tcp_alloc_accept * diff --git a/net/tcp/tcp_appsend.c b/net/tcp/tcp_appsend.c index a8f93fdd61..4f110f848a 100644 --- a/net/tcp/tcp_appsend.c +++ b/net/tcp/tcp_appsend.c @@ -130,9 +130,22 @@ void tcp_appsend(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, } #endif /* CONFIG_NET_IPv6 */ + /* Check If the device went down */ + + if ((result & NETDEV_DOWN) != 0) + { + /* If so, make sure that the connection is marked closed + * and do not try to send anything. + */ + + dev->d_sndlen = 0; + conn->tcpstateflags = TCP_CLOSED; + nllvdbg("TCP state: NETDEV_DOWN\n"); + } + /* Check for connection aborted */ - if ((result & TCP_ABORT) != 0) + else if ((result & TCP_ABORT) != 0) { dev->d_sndlen = 0; conn->tcpstateflags = TCP_CLOSED; diff --git a/net/tcp/tcp_conn.c b/net/tcp/tcp_conn.c index 9997e9a987..fd411cf8dc 100644 --- a/net/tcp/tcp_conn.c +++ b/net/tcp/tcp_conn.c @@ -514,6 +514,7 @@ static inline int tcp_ipv4_bind(FAR struct tcp_conn_s *conn, { net_lock_t flags; int port; + int ret; /* Verify or select a local port and address */ @@ -529,21 +530,40 @@ static inline int tcp_ipv4_bind(FAR struct tcp_conn_s *conn, port = tcp_selectport(ntohs(addr->sin_port)); #endif - net_unlock(flags); - if (port < 0) { + ndbg("tcp_selectport failed: %d\n", port); return port; } /* Save the local address in the connection structure. */ conn->lport = addr->sin_port; - #ifdef CONFIG_NETDEV_MULTINIC net_ipv4addr_copy(conn->u.ipv4.laddr, addr->sin_addr.s_addr); #endif + /* Find the device that can receive packets on the network + * associated with this local address. + */ + + ret = tcp_find_ipv4_device(conn); + if (ret < 0) + { + /* If no device is found, then the address is not reachable */ + + ndbg("tcp_find_ipv4_device failed: %d\n", ret); + + /* Back out the local address setting */ + + conn->lport = 0; +#ifdef CONFIG_NETDEV_MULTINIC + net_ipv4addr_copy(conn->u.ipv4.laddr, INADDR_ANY); +#endif + return ret; + } + + net_unlock(flags); return OK; } #endif /* CONFIG_NET_IPv4 */ @@ -569,6 +589,7 @@ static inline int tcp_ipv6_bind(FAR struct tcp_conn_s *conn, { net_lock_t flags; int port; + int ret; /* Verify or select a local port and address */ @@ -590,21 +611,40 @@ static inline int tcp_ipv6_bind(FAR struct tcp_conn_s *conn, port = tcp_selectport(ntohs(addr->sin6_port)); #endif - net_unlock(flags); - if (port < 0) { + ndbg("tcp_selectport failed: %d\n", port); return port; } /* Save the local address in the connection structure. */ conn->lport = addr->sin6_port; - #ifdef CONFIG_NETDEV_MULTINIC net_ipv6addr_copy(conn->u.ipv6.laddr, addr->sin6_addr.in6_u.u6_addr16); #endif + /* Find the device that can receive packets on the network + * associated with this local address. + */ + + ret = tcp_find_ipv6_device(conn); + if (ret < 0) + { + /* If no device is found, then the address is not reachable */ + + ndbg("tcp_find_ipv6_device failed: %d\n", ret); + + /* Back out the local address setting */ + + conn->lport = 0; +#ifdef CONFIG_NETDEV_MULTINIC + net_ipv6addr_copy(conn->u.ipv6.laddr, g_ipv6_allzeroaddr); +#endif + return ret; + } + + net_unlock(flags); return OK; } #endif /* CONFIG_NET_IPv6 */ @@ -928,6 +968,7 @@ FAR struct tcp_conn_s *tcp_alloc_accept(FAR struct net_driver_s *dev, { FAR struct tcp_conn_s *conn; uint8_t domain; + int ret; /* Get the appropriate IP domain */ @@ -945,15 +986,9 @@ FAR struct tcp_conn_s *tcp_alloc_accept(FAR struct net_driver_s *dev, conn = tcp_alloc(domain); if (conn) { - /* Fill in the necessary fields for the new connection. */ - - conn->rto = TCP_RTO; - conn->timer = TCP_RTO; - conn->sa = 0; - conn->sv = 4; - conn->nrtx = 0; - conn->lport = tcp->destport; - conn->rport = tcp->srcport; + /* Set up the local address (laddr) and the remote address (raddr) + * that describes the TCP connection. + */ #ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv4 @@ -962,11 +997,19 @@ FAR struct tcp_conn_s *tcp_alloc_accept(FAR struct net_driver_s *dev, { FAR struct ipv6_hdr_s *ip = IPv6BUF; + /* Set the IPv6 specific MSS and the IPv6 locally bound address */ + conn->mss = TCP_IPv6_INITIAL_MSS(dev); net_ipv6addr_copy(conn->u.ipv6.raddr, ip->srcipaddr); #ifdef CONFIG_NETDEV_MULTINIC net_ipv6addr_copy(conn->u.ipv6.laddr, ip->destipaddr); #endif + + /* Find the device that can receive packets on the network + * associated with this local address. + */ + + ret = tcp_find_ipv6_device(conn); } #endif /* CONFIG_NET_IPv6 */ @@ -977,6 +1020,8 @@ FAR struct tcp_conn_s *tcp_alloc_accept(FAR struct net_driver_s *dev, { FAR struct ipv4_hdr_s *ip = IPv4BUF; + /* Set the IPv6 specific MSS and the IPv4 locally bound address. */ + conn->mss = TCP_IPv4_INITIAL_MSS(dev); net_ipv4addr_copy(conn->u.ipv4.raddr, net_ip4addr_conv32(ip->srcipaddr)); @@ -984,9 +1029,40 @@ FAR struct tcp_conn_s *tcp_alloc_accept(FAR struct net_driver_s *dev, net_ipv4addr_copy(conn->u.ipv4.laddr, net_ip4addr_conv32(ip->destipaddr)); #endif + + /* Find the device that can receive packets on the network + * associated with this local address. + */ + + ret = tcp_find_ipv4_device(conn); } #endif /* CONFIG_NET_IPv4 */ + /* Verify that a network device that can provide packets to this + * local address was found. + */ + + if (ret < 0) + { + /* If no device is found, then the address is not reachable. + * That should be impossible in this context and we should + * probably really just assert here. + */ + + ndbg("Failed to find network device: %d\n", ret); + tcp_free(conn); + return NULL; + } + + /* Fill in the necessary fields for the new connection. */ + + conn->rto = TCP_RTO; + conn->timer = TCP_RTO; + conn->sa = 0; + conn->sv = 4; + conn->nrtx = 0; + conn->lport = tcp->destport; + conn->rport = tcp->srcport; conn->tcpstateflags = TCP_SYN_RCVD; tcp_initsequence(conn->sndseq); @@ -1090,6 +1166,7 @@ int tcp_connect(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr) { net_lock_t flags; int port; + int ret; /* The connection is expected to be in the TCP_ALLOCATED state.. i.e., * allocated via up_tcpalloc(), but not yet put into the active connections @@ -1153,13 +1230,80 @@ int tcp_connect(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr) #endif /* CONFIG_NETDEV_MULTINIC */ - net_unlock(flags); - /* Did we have a port assignment? */ if (port < 0) { - return port; + ret = port; + goto errout_with_lock; + } + + /* Set up the local address (laddr) and the remote address (raddr) that describes the TCP connection. + */ + +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + if (conn->domain == PF_INET) +#endif + { + FAR const struct sockaddr_in *inaddr = + (FAR const struct sockaddr_in *)addr; + + /* Save MSS and the port from the sockaddr (already in network order) */ + + conn->mss = MIN_IPv4_TCP_INITIAL_MSS; + conn->rport = inaddr->sin_port; + + /* The sockaddr address is 32-bits in network order. */ + + net_ipv4addr_copy(conn->u.ipv4.raddr, inaddr->sin_addr.s_addr); + + /* Find the device that can receive packets on the network associated + * with this local address. + */ + + ret = tcp_find_ipv4_device(conn); + } +#endif /* CONFIG_NET_IPv4 */ + +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + else +#endif + { + FAR const struct sockaddr_in6 *inaddr = + (FAR const struct sockaddr_in6 *)addr; + + /* Save MSS and the port from the sockaddr (already in network order) */ + + conn->mss = MIN_IPv6_TCP_INITIAL_MSS; + conn->rport = inaddr->sin6_port; + + /* The sockaddr address is 128-bits in network order. */ + + net_ipv6addr_copy(conn->u.ipv6.raddr, inaddr->sin6_addr.s6_addr16); + + /* Find the device that can receive packets on the network associated + * with this local address. + */ + + ret = tcp_find_ipv6_device(conn); + } +#endif /* CONFIG_NET_IPv6 */ + + /* Verify that a network device that can provide packets to this local + * address was found. + */ + + if (ret < 0) + { + /* If no device is found, then the address is not reachable. That + * should be impossible in this context and we should probably really + * just assert here. + */ + + ndbg("Failed to find network device: %d\n", ret); + goto errout_with_lock; } /* Initialize and return the connection structure, bind it to the port @@ -1184,46 +1328,6 @@ int tcp_connect(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr) conn->sent = 0; #endif - /* Save values that are specific to the IP address domain */ - -#ifdef CONFIG_NET_IPv4 -#ifdef CONFIG_NET_IPv6 - if (conn->domain == PF_INET) -#endif - { - FAR const struct sockaddr_in *inaddr = - (FAR const struct sockaddr_in *)addr; - - /* Save MSS and the port from the sockaddr (already in network order) */ - - conn->mss = MIN_IPv4_TCP_INITIAL_MSS; - conn->rport = inaddr->sin_port; - - /* The sockaddr address is 32-bits in network order. */ - - net_ipv4addr_copy(conn->u.ipv4.raddr, inaddr->sin_addr.s_addr); - } -#endif /* CONFIG_NET_IPv4 */ - -#ifdef CONFIG_NET_IPv6 -#ifdef CONFIG_NET_IPv4 - else -#endif - { - FAR const struct sockaddr_in6 *inaddr = - (FAR const struct sockaddr_in6 *)addr; - - /* Save MSS and the port from the sockaddr (already in network order) */ - - conn->mss = MIN_IPv6_TCP_INITIAL_MSS; - conn->rport = inaddr->sin6_port; - - /* The sockaddr address is 32-bits in network order. */ - - net_ipv6addr_copy(conn->u.ipv6.raddr, inaddr->sin6_addr.s6_addr16); - } -#endif /* CONFIG_NET_IPv6 */ - #ifdef CONFIG_NET_TCP_READAHEAD /* Initialize the list of TCP read-ahead buffers */ @@ -1237,17 +1341,14 @@ int tcp_connect(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr) sq_init(&conn->unacked_q); #endif - /* And, finally, put the connection structure into the active - * list. Because g_active_tcp_connections is accessed from user level and - * interrupt level, code, it is necessary to keep interrupts disabled during - * this operation. - */ + /* And, finally, put the connection structure into the active list. */ - flags = net_lock(); dq_addlast(&conn->node, &g_active_tcp_connections); - net_unlock(flags); + ret = OK; - return OK; +errout_with_lock: + net_unlock(flags); + return ret; } #endif /* CONFIG_NET && CONFIG_NET_TCP */ diff --git a/net/tcp/tcp_devpoll.c b/net/tcp/tcp_devpoll.c index ae10c8b65e..9f971db286 100644 --- a/net/tcp/tcp_devpoll.c +++ b/net/tcp/tcp_devpoll.c @@ -89,7 +89,7 @@ * None * * Assumptions: - * Called from the interrupt level or with interrupts disabled. + * Called with the network locked. * ****************************************************************************/ diff --git a/net/tcp/tcp_netpoll.c b/net/tcp/tcp_netpoll.c index cfa9a2b257..41793f3641 100644 --- a/net/tcp/tcp_netpoll.c +++ b/net/tcp/tcp_netpoll.c @@ -119,9 +119,9 @@ static uint16_t tcp_poll_interrupt(FAR struct net_driver_s *dev, FAR void *conn, /* Check for a loss of connection events. */ - if ((flags & (TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT | NETDEV_DOWN)) != 0) + if ((flags & TCP_DISCONN_EVENTS) != 0) { - /* Marki that the connection has been lost */ + /* Mark that the connection has been lost */ net_lostconnection(info->psock, flags); eventset |= (POLLERR | POLLHUP); @@ -208,13 +208,12 @@ int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds) * callback processing. */ - cb->flags = (TCP_NEWDATA | TCP_BACKLOG | TCP_POLL | TCP_CLOSE | - TCP_ABORT | TCP_TIMEDOUT | NETDEV_DOWN); + cb->flags = (TCP_NEWDATA | TCP_BACKLOG | TCP_POLL | TCP_DISCONN_EVENTS); cb->priv = (FAR void *)info; cb->event = tcp_poll_interrupt; /* Save the reference in the poll info structure as fds private as well - * for use durring poll teardown as well. + * for use during poll teardown as well. */ fds->priv = (FAR void *)info; diff --git a/net/tcp/tcp_send_buffered.c b/net/tcp/tcp_send_buffered.c index db814cfb64..5b87052cac 100644 --- a/net/tcp/tcp_send_buffered.c +++ b/net/tcp/tcp_send_buffered.c @@ -488,7 +488,7 @@ static uint16_t psock_send_interrupt(FAR struct net_driver_s *dev, /* Check for a loss of connection */ - else if ((flags & (TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT)) != 0) + else if ((flags & TCP_DISCONN_EVENTS) != 0) { nllvdbg("Lost connection: %04x\n", flags); @@ -1024,7 +1024,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, /* Set up the callback in the connection */ psock->s_sndcb->flags = (TCP_ACKDATA | TCP_REXMIT | TCP_POLL | - TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT); + TCP_DISCONN_EVENTS); psock->s_sndcb->priv = (void*)psock; psock->s_sndcb->event = psock_send_interrupt; diff --git a/net/tcp/tcp_send_unbuffered.c b/net/tcp/tcp_send_unbuffered.c index 9d7de805b2..9526332424 100644 --- a/net/tcp/tcp_send_unbuffered.c +++ b/net/tcp/tcp_send_unbuffered.c @@ -376,7 +376,7 @@ static uint16_t tcpsend_interrupt(FAR struct net_driver_s *dev, /* Check for a loss of connection */ - else if ((flags & (TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT)) != 0) + else if ((flags & TCP_DISCONN_EVENTS) != 0) { /* Report not connected */ @@ -810,7 +810,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock, /* Set up the callback in the connection */ state.snd_cb->flags = (TCP_ACKDATA | TCP_REXMIT | TCP_POLL | - TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT); + TCP_DISCONN_EVENTS); state.snd_cb->priv = (FAR void *)&state; state.snd_cb->event = tcpsend_interrupt; diff --git a/net/udp/udp.h b/net/udp/udp.h index fdc46a1709..8ecd0e8569 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -342,6 +342,7 @@ int udp_ipv6_input(FAR struct net_driver_s *dev); * * Input Parameters: * conn - UDP connection structure (not currently used). + * ipv4addr - The IPv4 address to use in the device selection. * * Returned Value: * A pointer to the network driver to use. @@ -361,6 +362,7 @@ FAR struct net_driver_s *udp_find_ipv4_device(FAR struct udp_conn_s *conn, * * Input Parameters: * conn - UDP connection structure (not currently used). + * ipv6addr - The IPv6 address to use in the device selection. * * Returned Value: * A pointer to the network driver to use. diff --git a/net/udp/udp_finddev.c b/net/udp/udp_finddev.c index 73f5e8cc18..38287d887d 100644 --- a/net/udp/udp_finddev.c +++ b/net/udp/udp_finddev.c @@ -40,6 +40,8 @@ #include #if defined(CONFIG_NET) && defined(CONFIG_NET_UDP) +#include + #include #include @@ -66,6 +68,7 @@ * * Input Parameters: * conn - UDP connection structure (not currently used). + * ipv4addr - The IPv4 address to use in the device selection. * * Returned Value: * A pointer to the network driver to use. @@ -77,17 +80,15 @@ FAR struct net_driver_s *udp_find_ipv4_device(FAR struct udp_conn_s *conn, in_addr_t ipv4addr) { #ifdef CONFIG_NETDEV_MULTINIC - FAR struct net_driver_s *dev; - - /* Return NULL if the address is INADDR_ANY. In this case, there is - * there may be multiple devices that can provide data so the exceptional - * events from any particular device are not important. + /* Return NULL if the address is INADDR_ANY. In this case, there may + * be multiple devices that can provide data so the exceptional events + * from any particular device are not important. * * Of course, it would be a problem if this is the remote address of * sendto(). */ - if ((net_ipv4addr_cmp(ipv4addr, INADDR_ANY)) + if (net_ipv4addr_cmp(ipv4addr, INADDR_ANY)) { return NULL; } @@ -99,8 +100,6 @@ FAR struct net_driver_s *udp_find_ipv4_device(FAR struct udp_conn_s *conn, return netdev_findby_ipv4addr(conn->u.ipv4.laddr, ipv4addr); #else - /* Return NULL if the address is IN6ADDR_ANY */ - /* There is only a single network device... the one at the head of the * g_netdevices list. */ @@ -118,6 +117,7 @@ FAR struct net_driver_s *udp_find_ipv4_device(FAR struct udp_conn_s *conn, * * Input Parameters: * conn - UDP connection structure (not currently used). + * ipv6addr - The IPv6 address to use in the device selection. * * Returned Value: * A pointer to the network driver to use. @@ -129,11 +129,9 @@ FAR struct net_driver_s *udp_find_ipv6_device(FAR struct udp_conn_s *conn, net_ipv6addr_t ipv6addr) { #ifdef CONFIG_NETDEV_MULTINIC - FAR struct net_driver_s *dev; - - /* Return NULL if the address is IN6ADDR_ANY. In this case, there is - * there may be multiple devices that can provide data so the exceptional - * events from any particular device are not important. + /* Return NULL if the address is IN6ADDR_ANY. In this case, there may + * be multiple devices that can provide data so the exceptional events + * from any particular device are not important. * * Of course, it would be a problem if this is the remote address of * sendto(). @@ -178,8 +176,6 @@ FAR struct net_driver_s *udp_find_ipv6_device(FAR struct udp_conn_s *conn, FAR struct net_driver_s *udp_find_laddr_device(FAR struct udp_conn_s *conn) { #ifdef CONFIG_NETDEV_MULTINIC - FAR struct net_driver_s *dev; - /* There are multiple network devices. We need to select the device that * is going to route the UDP packet based on the provided IP address. */ @@ -189,7 +185,7 @@ FAR struct net_driver_s *udp_find_laddr_device(FAR struct udp_conn_s *conn) if (conn->domain == PF_INET) #endif { - return upd_find_ipv4_device(conn, conn->u.ipv4.laddr); + return udp_find_ipv4_device(conn, conn->u.ipv4.laddr); } #endif @@ -198,7 +194,7 @@ FAR struct net_driver_s *udp_find_laddr_device(FAR struct udp_conn_s *conn) else #endif { - return upd_find_ipv6_device(conn, conn->u.ipv6.laddr); + return udp_find_ipv6_device(conn, conn->u.ipv6.laddr); } #endif @@ -229,8 +225,6 @@ FAR struct net_driver_s *udp_find_laddr_device(FAR struct udp_conn_s *conn) FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn) { #ifdef CONFIG_NETDEV_MULTINIC - FAR struct net_driver_s *dev; - /* There are multiple network devices. We need to select the device that * is going to route the UDP packet based on the provided IP address. */ @@ -240,7 +234,7 @@ FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn) if (conn->domain == PF_INET) #endif { - return upd_find_ipv4_device(conn, conn->u.ipv4.raddr); + return udp_find_ipv4_device(conn, conn->u.ipv4.raddr); } #endif @@ -249,7 +243,7 @@ FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn) else #endif { - return upd_find_ipv6_device(conn, conn->u.ipv6.raddr); + return udp_find_ipv6_device(conn, conn->u.ipv6.raddr); } #endif