Merge Transaction TCP, courtesy of Andras Olah <olah@cs.utwente.nl> and

Bob Braden <braden@isi.edu>.

NB: This has not had David's TCP ACK hack re-integrated.  It is not clear
what the correct solution to this problem is, if any.  If a better solution
doesn't pop up in response to this message, I'll put David's code back in
(or he's welcome to do so himself).
This commit is contained in:
Garrett Wollman 1995-02-09 23:13:27 +00:00
parent fd65acba73
commit a0292f2375
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=6283
10 changed files with 1898 additions and 244 deletions

View File

@ -97,15 +97,12 @@ struct protosw inetsw[] = {
#ifdef TTCP
{ SOCK_STREAM, &inetdomain, IPPROTO_TCP,
PR_CONNREQUIRED|PR_IMPLOPCL|PR_WANTRCVD,
#else
{ SOCK_STREAM, &inetdomain, IPPROTO_TCP, PR_CONNREQUIRED|PR_WANTRCVD,
#endif
tcp_input, 0, tcp_ctlinput, tcp_ctloutput,
tcp_usrreq,
tcp_init, tcp_fasttimo, tcp_slowtimo, tcp_drain, tcp_sysctl
#else
{ SOCK_STREAM, &inetdomain, IPPROTO_TCP, PR_CONNREQUIRED|PR_WANTRCVD,
tcp_input, 0, tcp_ctlinput, tcp_ctloutput,
tcp_usrreq,
tcp_init, tcp_fasttimo, tcp_slowtimo, tcp_drain,
#endif
},
{ SOCK_RAW, &inetdomain, IPPROTO_RAW, PR_ATOMIC|PR_ADDR,
rip_input, rip_output, 0, rip_ctloutput,

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)tcp_debug.c 8.1 (Berkeley) 6/10/93
* $Id$
* $Id: tcp_debug.c,v 1.2 1994/08/02 07:48:54 davidg Exp $
*/
#ifdef TCPDEBUG
@ -102,7 +102,7 @@ tcp_trace(act, ostate, tp, ti, req)
if (tcpconsdebug == 0)
return;
if (tp)
printf("%x %s:", tp, tcpstates[ostate]);
printf("%p %s:", tp, tcpstates[ostate]);
else
printf("???????? ");
printf("%s ", tanames[act]);
@ -130,11 +130,14 @@ tcp_trace(act, ostate, tp, ti, req)
printf("@%x, urp=%x", ack, ti->ti_urp);
flags = ti->ti_flags;
if (flags) {
#ifndef lint
char *cp = "<";
#define pf(f) { if (ti->ti_flags&TH_/**/f) { printf("%s%s", cp, "f"); cp = ","; } }
#define pf(f) { \
if (ti->ti_flags & TH_##f) { \
printf("%s%s", cp, #f); \
cp = ","; \
} \
}
pf(SYN); pf(ACK); pf(FIN); pf(RST); pf(PUSH); pf(URG);
#endif
printf(">");
}
break;

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)tcp_output.c 8.3 (Berkeley) 12/30/93
* $Id: tcp_output.c,v 1.5 1995/01/24 08:03:22 davidg Exp $
* $Id: tcp_output.c,v 1.6 1995/01/26 03:56:20 davidg Exp $
*/
#include <sys/param.h>
@ -66,8 +66,6 @@ extern struct mbuf *m_copypack();
#endif
#define MAX_TCPOPTLEN 32 /* max # bytes that go in options */
/*
* Tcp output routine: figure out what should be sent and send it.
*/
@ -80,9 +78,13 @@ tcp_output(tp)
int off, flags, error;
register struct mbuf *m;
register struct tcpiphdr *ti;
u_char opt[MAX_TCPOPTLEN];
u_char opt[TCP_MAXOLEN];
unsigned optlen, hdrlen;
int idle, sendalot;
#ifdef TTCP
struct rmxp_tao *taop;
struct rmxp_tao tao_noncached;
#endif
/*
* Determine length of data that should be transmitted,
@ -104,6 +106,17 @@ again:
win = min(tp->snd_wnd, tp->snd_cwnd);
flags = tcp_outflags[tp->t_state];
#ifdef TTCP
/*
* Get standard flags, and add SYN or FIN if requested by 'hidden'
* state flags.
*/
if (tp->t_flags & TF_NEEDFIN)
flags |= TH_FIN;
if (tp->t_flags & TF_NEEDSYN)
flags |= TH_SYN;
#endif /* TTCP */
/*
* If in persist timeout with window of 0, send 1 byte.
* Otherwise, if window is small but nonzero
@ -139,6 +152,26 @@ again:
len = min(so->so_snd.sb_cc, win) - off;
#ifdef TTCP
if ((taop = tcp_gettaocache(tp->t_inpcb)) == NULL) {
taop = &tao_noncached;
bzero(taop, sizeof(*taop));
}
/*
* Lop off SYN bit if it has already been sent. However, if this
* is SYN-SENT state and if segment contains data and if we don't
* know that foreign host supports TAO, suppress sending segment.
*/
if ((flags & TH_SYN) && SEQ_GT(tp->snd_nxt, tp->snd_una)) {
flags &= ~TH_SYN;
off--, len++;
if (len > 0 && tp->t_state == TCPS_SYN_SENT &&
taop->tao_ccsent == 0)
return 0;
}
#endif /* TTCP */
if (len < 0) {
/*
* If FIN has been sent but not acked,
@ -179,11 +212,18 @@ again:
if (len == tp->t_maxseg)
goto send;
if ((idle || tp->t_flags & TF_NODELAY) &&
#ifdef TTCP
(tp->t_flags & TF_NOPUSH) == 0 &&
#endif
len + off >= so->so_snd.sb_cc)
goto send;
if (tp->t_force)
goto send;
#ifdef TTCP
if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0)
#else
if (len >= tp->max_sndwnd / 2)
#endif
goto send;
if (SEQ_LT(tp->snd_nxt, tp->snd_max))
goto send;
@ -216,7 +256,12 @@ again:
*/
if (tp->t_flags & TF_ACKNOW)
goto send;
#ifdef TTCP
if ((flags & TH_RST) ||
((flags & TH_SYN) && (tp->t_flags & TF_NEEDSYN) == 0))
#else
if (flags & (TH_SYN|TH_RST))
#endif
goto send;
if (SEQ_GT(tp->snd_up, tp->snd_una))
goto send;
@ -279,10 +324,10 @@ send:
u_short mss;
opt[0] = TCPOPT_MAXSEG;
opt[1] = 4;
mss = htons((u_short) tcp_mss(tp, 0));
opt[1] = TCPOLEN_MAXSEG;
mss = htons((u_short) tcp_mssopt(tp));
bcopy((caddr_t)&mss, (caddr_t)(opt + 2), sizeof(mss));
optlen = 4;
optlen = TCPOLEN_MAXSEG;
if ((tp->t_flags & TF_REQ_SCALE) &&
((flags & TH_ACK) == 0 ||
@ -303,8 +348,12 @@ send:
* and our peer have sent timestamps in our SYN's.
*/
if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP &&
(flags & TH_RST) == 0 &&
(flags & TH_RST) == 0 &&
#ifdef TTCP
((flags & TH_ACK) == 0 ||
#else
((flags & (TH_SYN|TH_ACK)) == TH_SYN ||
#endif
(tp->t_flags & TF_RCVD_TSTMP))) {
u_long *lp = (u_long *)(opt + optlen);
@ -315,27 +364,108 @@ send:
optlen += TCPOLEN_TSTAMP_APPA;
}
#ifdef TTCP
/*
* Send `CC-family' options if our side wants to use them (TF_REQ_CC),
* options are allowed (!TF_NOOPT) and it's not a RST.
*/
if ((tp->t_flags & (TF_REQ_CC|TF_NOOPT)) == TF_REQ_CC &&
(flags & TH_RST) == 0) {
switch (flags & (TH_SYN|TH_ACK)) {
/*
* This is a normal ACK, send CC if we received CC before
* from our peer.
*/
case TH_ACK:
if (!(tp->t_flags & TF_RCVD_CC))
break;
/*FALLTHROUGH*/
/*
* We can only get here in T/TCP's SYN_SENT* state, when
* we're a sending a non-SYN segment without waiting for
* the ACK of our SYN. A check above assures that we only
* do this if our peer understands T/TCP.
*/
case 0:
opt[optlen++] = TCPOPT_NOP;
opt[optlen++] = TCPOPT_NOP;
opt[optlen++] = TCPOPT_CC;
opt[optlen++] = TCPOLEN_CC;
*(u_int32_t *)&opt[optlen] = htonl(tp->cc_send);
optlen += 4;
break;
/*
* This is our initial SYN, check whether we have to use
* CC or CC.new.
*/
case TH_SYN:
opt[optlen++] = TCPOPT_NOP;
opt[optlen++] = TCPOPT_NOP;
if (taop->tao_ccsent != 0 &&
CC_GEQ(tp->cc_send, taop->tao_ccsent)) {
opt[optlen++] = TCPOPT_CC;
taop->tao_ccsent = tp->cc_send;
} else {
opt[optlen++] = TCPOPT_CCNEW;
taop->tao_ccsent = 0;
}
opt[optlen++] = TCPOLEN_CC;
*(u_int32_t *)&opt[optlen] = htonl(tp->cc_send);
optlen += 4;
break;
/*
* This is a SYN,ACK; send CC and CC.echo if we received
* CC from our peer.
*/
case (TH_SYN|TH_ACK):
if (tp->t_flags & TF_RCVD_CC) {
opt[optlen++] = TCPOPT_NOP;
opt[optlen++] = TCPOPT_NOP;
opt[optlen++] = TCPOPT_CC;
opt[optlen++] = TCPOLEN_CC;
*(u_int32_t *)&opt[optlen] =
htonl(tp->cc_send);
optlen += 4;
opt[optlen++] = TCPOPT_NOP;
opt[optlen++] = TCPOPT_NOP;
opt[optlen++] = TCPOPT_CCECHO;
opt[optlen++] = TCPOLEN_CC;
*(u_int32_t *)&opt[optlen] =
htonl(tp->cc_recv);
optlen += 4;
}
break;
}
}
#endif /* TTCP */
hdrlen += optlen;
/*
* Adjust data length if insertion of options will
* bump the packet length beyond the t_maxseg length.
* bump the packet length beyond the t_maxopd length.
* Clear the FIN bit because we cut off the tail of
* the segment.
*/
if (len > tp->t_maxseg - optlen) {
if (len + optlen > tp->t_maxopd) {
/*
* If there is still more to send, don't close the connection.
*/
flags &= ~TH_FIN;
len = tp->t_maxseg - optlen;
len = tp->t_maxopd - optlen;
sendalot = 1;
}
}
#ifdef DIAGNOSTIC
/*#ifdef DIAGNOSTIC*/
if (max_linkhdr + hdrlen > MHLEN)
panic("tcphdr too big");
#endif
/*#endif*/
/*
* Grab a header mbuf, attaching a copy of data to

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93
* $Id: tcp_subr.c,v 1.4 1994/10/02 17:48:44 phk Exp $
* $Id: tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp $
*/
#include <sys/param.h>
@ -54,16 +54,24 @@
#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
#include <netinet/tcp.h>
#define TCPOUTFLAGS
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
#include <netinet/tcpip.h>
#ifdef TCPDEBUG
#include <netinet/tcp_debug.h>
#endif
/* patchable/settable parameters for tcp */
int tcp_mssdflt = TCP_MSS;
int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ;
int tcp_do_rfc1323 = 1;
#ifdef TTCP
int tcp_do_rfc1644 = 1;
static void tcp_cleartaocache(void);
#endif
extern struct inpcb *tcp_last_inpcb;
@ -75,6 +83,10 @@ tcp_init()
{
tcp_iss = 1; /* wrong */
#ifdef TTCP
tcp_ccgen = 1;
tcp_cleartaocache();
#endif
tcb.inp_next = tcb.inp_prev = &tcb;
if (max_protohdr < sizeof(struct tcpiphdr))
max_protohdr = sizeof(struct tcpiphdr);
@ -196,6 +208,10 @@ tcp_respond(tp, ti, m, ack, seq, flags)
ti->ti_sum = in_cksum(m, tlen);
((struct ip *)ti)->ip_len = tlen;
((struct ip *)ti)->ip_ttl = ip_defttl;
#ifdef TCPDEBUG
if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
tcp_trace(TA_OUTPUT, 0, tp, ti, 0);
#endif
(void) ip_output(m, NULL, ro, 0, NULL);
}
@ -215,9 +231,14 @@ tcp_newtcpcb(inp)
return ((struct tcpcb *)0);
bzero((char *) tp, sizeof(struct tcpcb));
tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
tp->t_maxseg = tcp_mssdflt;
tp->t_maxseg = tp->t_maxopd = tcp_mssdflt;
tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
if (tcp_do_rfc1323)
tp->t_flags = (TF_REQ_SCALE|TF_REQ_TSTMP);
#ifdef TTCP
if (tcp_do_rfc1644)
tp->t_flags |= TF_REQ_CC;
#endif
tp->t_inpcb = inp;
/*
* Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
@ -444,3 +465,65 @@ tcp_quench(inp, errno)
if (tp)
tp->snd_cwnd = tp->t_maxseg;
}
/*
* Look-up the routing entry to the peer of this inpcb. If no route
* is found and it cannot be allocated the return NULL. This routine
* is called by TCP routines that access the rmx structure and by tcp_mss
* to get the interface MTU.
*/
struct rtentry *
tcp_rtlookup(inp)
struct inpcb *inp;
{
struct route *ro;
struct rtentry *rt;
ro = &inp->inp_route;
rt = ro->ro_rt;
if (rt == NULL || !(rt->rt_flags & RTF_UP)) {
/* No route yet, so try to acquire one */
if (inp->inp_faddr.s_addr != INADDR_ANY) {
ro->ro_dst.sa_family = AF_INET;
ro->ro_dst.sa_len = sizeof(ro->ro_dst);
((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
inp->inp_faddr;
rtalloc(ro);
rt = ro->ro_rt;
}
}
return rt;
}
#ifdef TTCP
/*
* Return a pointer to the cached information about the remote host.
* The cached information is stored in the protocol specific part of
* the route metrics.
*/
struct rmxp_tao *
tcp_gettaocache(inp)
struct inpcb *inp;
{
struct rtentry *rt = tcp_rtlookup(inp);
/* Make sure this is a host route and is up. */
if (rt == NULL ||
(rt->rt_flags & (RTF_UP|RTF_HOST)) != (RTF_UP|RTF_HOST))
return NULL;
return rmx_taop(rt->rt_rmx);
}
/*
* Clear all the TAO cache entries, called from tcp_init.
*
* XXX
* This routine is just an empty one, because we assume that the routing
* routing tables are initialized at the same time when TCP, so there is
* nothing in the cache left over.
*/
static void
tcp_cleartaocache(void)
{ }
#endif /* TTCP */

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)tcp_timer.c 8.1 (Berkeley) 6/10/93
* $Id$
* $Id: tcp_timer.c,v 1.2 1994/08/02 07:49:10 davidg Exp $
*/
#ifndef TUBA_INCLUDE
@ -123,6 +123,9 @@ tcp_slowtimo()
}
}
tp->t_idle++;
#ifdef TTCP
tp->t_duration++;
#endif
if (tp->t_rtt)
tp->t_rtt++;
tpgone:
@ -212,6 +215,12 @@ tcp_timers(tp, timer)
tp->t_srtt = 0;
}
tp->snd_nxt = tp->snd_una;
#ifdef TTCP
/*
* Force a segment to be sent.
*/
tp->t_flags |= TF_ACKNOW;
#endif
/*
* If timing a segment in this window, stop the timer.
*/

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93
* $Id: tcp_subr.c,v 1.4 1994/10/02 17:48:44 phk Exp $
* $Id: tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp $
*/
#include <sys/param.h>
@ -54,16 +54,24 @@
#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
#include <netinet/tcp.h>
#define TCPOUTFLAGS
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
#include <netinet/tcpip.h>
#ifdef TCPDEBUG
#include <netinet/tcp_debug.h>
#endif
/* patchable/settable parameters for tcp */
int tcp_mssdflt = TCP_MSS;
int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ;
int tcp_do_rfc1323 = 1;
#ifdef TTCP
int tcp_do_rfc1644 = 1;
static void tcp_cleartaocache(void);
#endif
extern struct inpcb *tcp_last_inpcb;
@ -75,6 +83,10 @@ tcp_init()
{
tcp_iss = 1; /* wrong */
#ifdef TTCP
tcp_ccgen = 1;
tcp_cleartaocache();
#endif
tcb.inp_next = tcb.inp_prev = &tcb;
if (max_protohdr < sizeof(struct tcpiphdr))
max_protohdr = sizeof(struct tcpiphdr);
@ -196,6 +208,10 @@ tcp_respond(tp, ti, m, ack, seq, flags)
ti->ti_sum = in_cksum(m, tlen);
((struct ip *)ti)->ip_len = tlen;
((struct ip *)ti)->ip_ttl = ip_defttl;
#ifdef TCPDEBUG
if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
tcp_trace(TA_OUTPUT, 0, tp, ti, 0);
#endif
(void) ip_output(m, NULL, ro, 0, NULL);
}
@ -215,9 +231,14 @@ tcp_newtcpcb(inp)
return ((struct tcpcb *)0);
bzero((char *) tp, sizeof(struct tcpcb));
tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
tp->t_maxseg = tcp_mssdflt;
tp->t_maxseg = tp->t_maxopd = tcp_mssdflt;
tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
if (tcp_do_rfc1323)
tp->t_flags = (TF_REQ_SCALE|TF_REQ_TSTMP);
#ifdef TTCP
if (tcp_do_rfc1644)
tp->t_flags |= TF_REQ_CC;
#endif
tp->t_inpcb = inp;
/*
* Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
@ -444,3 +465,65 @@ tcp_quench(inp, errno)
if (tp)
tp->snd_cwnd = tp->t_maxseg;
}
/*
* Look-up the routing entry to the peer of this inpcb. If no route
* is found and it cannot be allocated the return NULL. This routine
* is called by TCP routines that access the rmx structure and by tcp_mss
* to get the interface MTU.
*/
struct rtentry *
tcp_rtlookup(inp)
struct inpcb *inp;
{
struct route *ro;
struct rtentry *rt;
ro = &inp->inp_route;
rt = ro->ro_rt;
if (rt == NULL || !(rt->rt_flags & RTF_UP)) {
/* No route yet, so try to acquire one */
if (inp->inp_faddr.s_addr != INADDR_ANY) {
ro->ro_dst.sa_family = AF_INET;
ro->ro_dst.sa_len = sizeof(ro->ro_dst);
((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
inp->inp_faddr;
rtalloc(ro);
rt = ro->ro_rt;
}
}
return rt;
}
#ifdef TTCP
/*
* Return a pointer to the cached information about the remote host.
* The cached information is stored in the protocol specific part of
* the route metrics.
*/
struct rmxp_tao *
tcp_gettaocache(inp)
struct inpcb *inp;
{
struct rtentry *rt = tcp_rtlookup(inp);
/* Make sure this is a host route and is up. */
if (rt == NULL ||
(rt->rt_flags & (RTF_UP|RTF_HOST)) != (RTF_UP|RTF_HOST))
return NULL;
return rmx_taop(rt->rt_rmx);
}
/*
* Clear all the TAO cache entries, called from tcp_init.
*
* XXX
* This routine is just an empty one, because we assume that the routing
* routing tables are initialized at the same time when TCP, so there is
* nothing in the cache left over.
*/
static void
tcp_cleartaocache(void)
{ }
#endif /* TTCP */

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)tcp_usrreq.c 8.2 (Berkeley) 1/3/94
* $Id: tcp_usrreq.c,v 1.5 1994/09/15 10:36:56 davidg Exp $
* $Id: tcp_usrreq.c,v 1.6 1994/12/15 20:39:34 wollman Exp $
*/
#include <sys/param.h>
@ -84,7 +84,9 @@ tcp_usrreq(so, req, m, nam, control)
struct sockaddr_in *sinp;
int s;
int error = 0;
#ifdef TCPDEBUG
int ostate;
#endif
if (req == PRU_CONTROL)
return (in_control(so, (int)m, (caddr_t)nam,
@ -113,9 +115,14 @@ tcp_usrreq(so, req, m, nam, control)
#ifdef KPROF
tcp_acounts[tp->t_state][req]++;
#endif
#ifdef TCPDEBUG
ostate = tp->t_state;
} else
ostate = 0;
#else /* TCPDEBUG */
}
#endif /* TCPDEBUG */
switch (req) {
/*
@ -196,6 +203,10 @@ tcp_usrreq(so, req, m, nam, control)
break;
}
#ifdef TTCP
if ((error = tcp_connect(tp, nam)) != 0)
break;
#else /* TTCP */
if (inp->inp_lport == 0) {
error = in_pcbbind(inp, (struct mbuf *)0);
if (error)
@ -220,6 +231,7 @@ tcp_usrreq(so, req, m, nam, control)
tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
tcp_sendseqinit(tp);
#endif /* TTCP */
error = tcp_output(tp);
break;
@ -275,9 +287,37 @@ tcp_usrreq(so, req, m, nam, control)
* Do a send by putting data in output queue and updating urgent
* marker if URG set. Possibly send more data.
*/
#ifdef TTCP
case PRU_SEND_EOF:
#endif
case PRU_SEND:
sbappend(&so->so_snd, m);
error = tcp_output(tp);
#ifdef TTCP
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.
*/
error = tcp_connect(tp, nam);
if (error)
break;
tp->snd_wnd = TTCP_CLIENT_SND_WND;
tcp_mss(tp, -1);
}
if (req == PRU_SEND_EOF) {
/*
* Close the send side of the connection after
* the data is sent.
*/
socantsendmore(so);
tp = tcp_usrclosed(tp);
}
if (tp != NULL)
#endif TTCP
error = tcp_output(tp);
break;
/*
@ -345,7 +385,9 @@ tcp_usrreq(so, req, m, nam, control)
*/
case PRU_SLOWTIMO:
tp = tcp_timers(tp, (int)nam);
#ifdef TCPDEBUG
req |= (int)nam << 8; /* for debug's sake */
#endif
break;
default:
@ -359,6 +401,83 @@ tcp_usrreq(so, req, m, nam, control)
return (error);
}
#ifdef TTCP
/*
* Common subroutine to open a TCP connection to remote host specified
* by struct sockaddr_in in mbuf *nam. Call in_pcbbind to assign a local
* port number if needed. Call in_pcbladdr to do the routing and to choose
* a local host address (interface). If there is an existing incarnation
* of the same connection in TIME-WAIT state and if the remote host was
* sending CC options and if the connection duration was < MSL, then
* truncate the previous TIME-WAIT state and proceed.
* Initialize connection parameters and enter SYN-SENT state.
*/
int
tcp_connect(tp, nam)
register struct tcpcb *tp;
struct mbuf *nam;
{
struct inpcb *inp = tp->t_inpcb, *oinp;
struct socket *so = inp->inp_socket;
struct tcpcb *otp;
struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
struct sockaddr_in *ifaddr;
int error;
if (inp->inp_lport == 0) {
error = in_pcbbind(inp, NULL);
if (error)
return error;
}
/*
* Cannot simply call in_pcbconnect, because there might be an
* earlier incarnation of this same connection still in
* TIME_WAIT state, creating an ADDRINUSE error.
*/
error = in_pcbladdr(inp, nam, &ifaddr);
oinp = in_pcblookup(inp->inp_head,
sin->sin_addr, sin->sin_port,
inp->inp_laddr.s_addr != INADDR_ANY ? inp->inp_laddr
: ifaddr->sin_addr,
inp->inp_lport, 0);
if (oinp) {
if (oinp != inp && (otp = intotcpcb(oinp)) != NULL &&
otp->t_state == TCPS_TIME_WAIT &&
otp->t_duration < TCPTV_MSL &&
(otp->t_flags & TF_RCVD_CC))
otp = tcp_close(otp);
else
return EADDRINUSE;
}
if (inp->inp_laddr.s_addr == INADDR_ANY)
inp->inp_laddr = ifaddr->sin_addr;
inp->inp_faddr = sin->sin_addr;
inp->inp_fport = sin->sin_port;
tp->t_template = tcp_template(tp);
if (tp->t_template == 0) {
in_pcbdisconnect(inp);
return ENOBUFS;
}
/* Compute window scaling to request. */
while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
(TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
tp->request_r_scale++;
soisconnecting(so);
tcpstat.tcps_connattempt++;
tp->t_state = TCPS_SYN_SENT;
tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
tcp_sendseqinit(tp);
tp->cc_send = CC_INC(tcp_ccgen);
return 0;
}
#endif /* TTCP */
int
tcp_ctloutput(op, so, level, optname, mp)
int op;
@ -409,6 +528,26 @@ tcp_ctloutput(op, so, level, optname, mp)
error = EINVAL;
break;
#ifdef TTCP
case TCP_NOOPT:
if (m == NULL || m->m_len < sizeof (int))
error = EINVAL;
else if (*mtod(m, int *))
tp->t_flags |= TF_NOOPT;
else
tp->t_flags &= ~TF_NOOPT;
break;
case TCP_NOPUSH:
if (m == NULL || m->m_len < sizeof (int))
error = EINVAL;
else if (*mtod(m, int *))
tp->t_flags |= TF_NOPUSH;
else
tp->t_flags &= ~TF_NOPUSH;
break;
#endif /* TTCP */
default:
error = ENOPROTOOPT;
break;
@ -428,6 +567,14 @@ tcp_ctloutput(op, so, level, optname, mp)
case TCP_MAXSEG:
*mtod(m, int *) = tp->t_maxseg;
break;
#ifdef TTCP
case TCP_NOOPT:
*mtod(m, int *) = tp->t_flags & TF_NOOPT;
break;
case TCP_NOPUSH:
*mtod(m, int *) = tp->t_flags & TF_NOPUSH;
break;
#endif /* TTCP */
default:
error = ENOPROTOOPT;
break;
@ -533,12 +680,22 @@ tcp_usrclosed(tp)
case TCPS_CLOSED:
case TCPS_LISTEN:
#ifndef TTCP
case TCPS_SYN_SENT:
#endif
tp->t_state = TCPS_CLOSED;
tp = tcp_close(tp);
break;
#ifdef TTCP
case TCPS_SYN_SENT:
case TCPS_SYN_RECEIVED:
tp->t_flags |= TF_NEEDFIN;
break;
#else
case TCPS_SYN_RECEIVED:
#endif
case TCPS_ESTABLISHED:
tp->t_state = TCPS_FIN_WAIT_1;
break;
@ -551,3 +708,43 @@ tcp_usrclosed(tp)
soisdisconnected(tp->t_inpcb->inp_socket);
return (tp);
}
/*
* Sysctl for tcp variables.
*/
int
tcp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
int *name;
u_int namelen;
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
{
extern int tcp_do_rfc1323;
#ifdef TTCP
extern int tcp_do_rfc1644;
#endif
extern int tcp_mssdflt;
/* All sysctl names at this level are terminal. */
if (namelen != 1)
return (ENOTDIR);
switch (name[0]) {
case TCPCTL_DO_RFC1323:
return (sysctl_int(oldp, oldlenp, newp, newlen,
&tcp_do_rfc1323));
#ifdef TTCP
case TCPCTL_DO_RFC1644:
return (sysctl_int(oldp, oldlenp, newp, newlen,
&tcp_do_rfc1644));
#endif
case TCPCTL_MSSDFLT:
return (sysctl_int(oldp, oldlenp, newp, newlen,
&tcp_mssdflt));
default:
return (ENOPROTOOPT);
}
/* NOTREACHED */
}

View File

@ -179,7 +179,7 @@ struct rmxp_tao {
#define TAOF_UNDEF 0 /* we don't know yet */
#endif /* notyet */
};
#define rmx_taop(r) ((struct rmxp_tao *)&(r).rmx_pspec)
#define rmx_taop(r) ((struct rmxp_tao *)(r).rmx_filler)
#endif /* TTCP */
#define intotcpcb(ip) ((struct tcpcb *)(ip)->inp_ppcb)
@ -333,11 +333,7 @@ struct rmxp_tao *
#endif
void tcp_init __P((void));
void tcp_input __P((struct mbuf *, int));
#ifdef TTCP
void tcp_mss __P((struct tcpcb *, int));
#else
int tcp_mss __P((struct tcpcb *, u_int));
#endif
int tcp_mssopt __P((struct tcpcb *));
struct tcpcb *
tcp_newtcpcb __P((struct inpcb *));