Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 29 Aug 2010 17:22:13 +0200
From:      Andre Oppermann <andre@freebsd.org>
To:        freebsd-net@freebsd.org
Subject:   Removal of deprecated implied connect for TCP
Message-ID:  <4C7A7B25.9040300@freebsd.org>

next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------030501000301080006010502
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

When T/TCP RFC1644 support was introduced in r6283 by wollman 15 years
ago the semantics of sendto(2) with regard to TCP sockets were changed.

It became possible directly do a sendto(2) call with the target address in
the *to argument instead of doing a connect(2) first and subsequent write(2)
or send(2) calls as the standard TCP API specifies.  Optionally MSG_EOR
could be specified to close the connection again right again after the
data has been sent out.

This is totally non-portable and no other OS (Linux, NetBSD, OpenBSD,
Solaris, HP-UX) ever supported this functionality for TCP sockets.
FreeBSD was the only OS to ever ship this.

T/TCP was ill-defined and had major security issues and never gained
any support. It has been defunct in FreeBSD and most code has been
removed about 6 years ago.  The sendto(2) extended functionality is one
of the last parts that persisted and remained around living a zombie life.

I want to remove it now because it is totally non-portable, has no
known users and complicates the TCP send path.  The patch is attached.

If you have any objections speak up now.

-- 
Andre

--------------030501000301080006010502
Content-Type: text/plain;
 name="tcp_usrreq-implied-connect.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="tcp_usrreq-implied-connect.diff"

Index: netinet/tcp_usrreq.c
===================================================================
--- netinet/tcp_usrreq.c	(revision 211874)
+++ netinet/tcp_usrreq.c	(working copy)
@@ -740,86 +740,34 @@
 	int error = 0;
 	struct inpcb *inp;
 	struct tcpcb *tp = NULL;
-	int headlocked = 0;
-#ifdef INET6
-	int isipv6;
-#endif
+
 	TCPDEBUG0;
 
-	/*
-	 * We require the pcbinfo lock in two cases:
-	 *
-	 * (1) An implied connect is taking place, which can result in
-	 *     binding IPs and ports and hence modification of the pcb hash
-	 *     chains.
-	 *
-	 * (2) PRUS_EOF is set, resulting in explicit close on the send.
-	 */
-	if ((nam != NULL) || (flags & PRUS_EOF)) {
-		INP_INFO_WLOCK(&V_tcbinfo);
-		headlocked = 1;
+	/* TCP doesn't do control messages (rights, creds, etc.) */
+	if (control != NULL && control->m_len) {
+		error = EINVAL;
+		goto out;
 	}
+
 	inp = sotoinpcb(so);
-	KASSERT(inp != NULL, ("tcp_usr_send: inp == NULL"));
+	KASSERT(inp != NULL, ("%s: inp == NULL", __func__));
 	INP_WLOCK(inp);
-	if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
-		if (control)
-			m_freem(control);
-		if (m)
-			m_freem(m);
+	if (inp->inp_flags & (INP_DROPPED | INP_TIMEWAIT)) {
 		error = ECONNRESET;
-		goto out;
+		goto done;
 	}
-#ifdef INET6
-	isipv6 = nam && nam->sa_family == AF_INET6;
-#endif /* INET6 */
 	tp = intotcpcb(inp);
+
 	TCPDEBUG1();
-	if (control) {
-		/* TCP doesn't do control messages (rights, creds, etc) */
-		if (control->m_len) {
-			m_freem(control);
-			if (m)
-				m_freem(m);
-			error = EINVAL;
-			goto out;
-		}
-		m_freem(control);	/* empty control, just free it */
-	}
+
+	/*
+	 * Append the new data to the send socket buffer and
+	 * try to send it (may be limited by CWND).
+	 */
 	if (!(flags & PRUS_OOB)) {
 		sbappendstream(&so->so_snd, m);
-		if (nam && tp->t_state < TCPS_SYN_SENT) {
-			/*
-			 * Do implied connect if not yet connected,
-			 * initialize window to default value, and
-			 * initialize maxseg/maxopd using peer's cached
-			 * MSS.
-			 */
-			INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
-#ifdef INET6
-			if (isipv6)
-				error = tcp6_connect(tp, nam, td);
-			else
-#endif /* INET6 */
-			error = tcp_connect(tp, nam, td);
-			if (error)
-				goto out;
-			tp->snd_wnd = TTCP_CLIENT_SND_WND;
-			tcp_mss(tp, -1);
-		}
-		if (flags & PRUS_EOF) {
-			/*
-			 * Close the send side of the connection after
-			 * the data is sent.
-			 */
-			INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
-			socantsendmore(so);
-			tcp_usrclosed(tp);
-		}
-		if (headlocked) {
-			INP_INFO_WUNLOCK(&V_tcbinfo);
-			headlocked = 0;
-		}
+		m = NULL;
+
 		if (!(inp->inp_flags & INP_DROPPED)) {
 			if (flags & PRUS_MORETOCOME)
 				tp->t_flags |= TF_MORETOCOME;
@@ -828,15 +776,11 @@
 				tp->t_flags &= ~TF_MORETOCOME;
 		}
 	} else {
-		/*
-		 * XXXRW: PRUS_EOF not implemented with PRUS_OOB?
-		 */
 		SOCKBUF_LOCK(&so->so_snd);
 		if (sbspace(&so->so_snd) < -512) {
 			SOCKBUF_UNLOCK(&so->so_snd);
-			m_freem(m);
 			error = ENOBUFS;
-			goto out;
+			goto done;
 		}
 		/*
 		 * According to RFC961 (Assigned Protocols),
@@ -847,42 +791,24 @@
 		 * Otherwise, snd_up should be one lower.
 		 */
 		sbappendstream_locked(&so->so_snd, m);
+		m = NULL;
 		SOCKBUF_UNLOCK(&so->so_snd);
-		if (nam && tp->t_state < TCPS_SYN_SENT) {
-			/*
-			 * Do implied connect if not yet connected,
-			 * initialize window to default value, and
-			 * initialize maxseg/maxopd using peer's cached
-			 * MSS.
-			 */
-			INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
-#ifdef INET6
-			if (isipv6)
-				error = tcp6_connect(tp, nam, td);
-			else
-#endif /* INET6 */
-			error = tcp_connect(tp, nam, td);
-			if (error)
-				goto out;
-			tp->snd_wnd = TTCP_CLIENT_SND_WND;
-			tcp_mss(tp, -1);
-			INP_INFO_WUNLOCK(&V_tcbinfo);
-			headlocked = 0;
-		} else if (nam) {
-			INP_INFO_WUNLOCK(&V_tcbinfo);
-			headlocked = 0;
-		}
+
 		tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
 		tp->t_flags |= TF_FORCEDATA;
 		error = tcp_output_send(tp);
 		tp->t_flags &= ~TF_FORCEDATA;
 	}
-out:
-	TCPDEBUG2((flags & PRUS_OOB) ? PRU_SENDOOB :
-		  ((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND));
+	TCPDEBUG2((flags & PRUS_OOB) ? PRU_SENDOOB : PRU_SEND);
+done:
 	INP_WUNLOCK(inp);
-	if (headlocked)
-		INP_INFO_WUNLOCK(&V_tcbinfo);
+out:
+	/* Free mbufs in error cases. */
+	if (m != NULL)
+		m_freem(m);
+	if (control != NULL)
+		m_freem(control);
+
 	return (error);
 }
 
Index: netinet/in_proto.c
===================================================================
--- netinet/in_proto.c	(revision 211874)
+++ netinet/in_proto.c	(working copy)
@@ -134,7 +134,7 @@
 	.pr_type =		SOCK_STREAM,
 	.pr_domain =		&inetdomain,
 	.pr_protocol =		IPPROTO_TCP,
-	.pr_flags =		PR_CONNREQUIRED|PR_IMPLOPCL|PR_WANTRCVD,
+	.pr_flags =		PR_CONNREQUIRED|PR_WANTRCVD,
 	.pr_input =		tcp_input,
 	.pr_ctlinput =		tcp_ctlinput,
 	.pr_ctloutput =		tcp_ctloutput,

--------------030501000301080006010502--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4C7A7B25.9040300>