From 8b5a83bba17ae375ad7bdc9685e4a19fe7519fff Mon Sep 17 00:00:00 2001 From: Bill Joy Date: Mon, 18 Jan 1982 05:20:52 -0800 Subject: [PATCH] more work on out-of-band SCCS-vsn: sys/netinet/tcp.h 1.20 SCCS-vsn: sys/netinet/tcp_input.c 1.49 SCCS-vsn: sys/netinet/tcp_output.c 4.29 SCCS-vsn: sys/netinet/tcp_subr.c 4.13 SCCS-vsn: sys/netinet/tcp_timer.c 4.12 SCCS-vsn: sys/netinet/tcp_timer.h 4.6 SCCS-vsn: sys/netinet/tcp_usrreq.c 1.48 SCCS-vsn: sys/netinet/tcp_var.h 4.15 --- usr/src/sys/netinet/tcp.h | 19 +++- usr/src/sys/netinet/tcp_input.c | 160 +++++++++++++++++++++++-------- usr/src/sys/netinet/tcp_output.c | 106 +++++++++++++++++--- usr/src/sys/netinet/tcp_subr.c | 3 +- usr/src/sys/netinet/tcp_timer.c | 17 +++- usr/src/sys/netinet/tcp_timer.h | 13 ++- usr/src/sys/netinet/tcp_usrreq.c | 45 ++++++++- usr/src/sys/netinet/tcp_var.h | 25 +++-- 8 files changed, 313 insertions(+), 75 deletions(-) diff --git a/usr/src/sys/netinet/tcp.h b/usr/src/sys/netinet/tcp.h index 25d2f96987..f885d73df7 100644 --- a/usr/src/sys/netinet/tcp.h +++ b/usr/src/sys/netinet/tcp.h @@ -1,4 +1,4 @@ -/* tcp.h 1.19 81/11/26 */ +/* tcp.h 1.20 82/01/17 */ typedef u_long tcp_seq; /* @@ -24,3 +24,20 @@ struct tcphdr { u_short th_sum; /* checksum */ u_short th_urp; /* urgent pointer */ }; + +#define TCPOPT_EOL 0 +#define TCPOPT_NOP 1 +#define TCPOPT_MAXSEG 2 + +#ifdef TCPTRUEOOB +/* + * True out-of-band as value added option. + * Advertise willingness with TCPOPT_WILOOB in + * initial segment. If peer is willing, will receive + * such also. Then can send TCPOPT_OOBDATA whenever oob data + * exists; peer should ack with TCPOPT_OOBACK in segment. + */ +#define TCPOPT_WILLOOB 64 /* bytes: 64, 2 */ +#define TCPOPT_OOBDATA 65 /* bytes: 65, 4, seq#, data */ +#define TCPOPT_OOBACK 66 /* bytes: 66, 3, ack# */ +#endif diff --git a/usr/src/sys/netinet/tcp_input.c b/usr/src/sys/netinet/tcp_input.c index 06632fbf90..f209e180f8 100644 --- a/usr/src/sys/netinet/tcp_input.c +++ b/usr/src/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* tcp_input.c 1.48 82/01/17 */ +/* tcp_input.c 1.49 82/01/17 */ #include "../h/param.h" #include "../h/systm.h" @@ -25,6 +25,7 @@ int tcpprintfs = 0; int tcpcksum = 1; struct sockaddr_in tcp_in = { AF_INET }; struct tcpiphdr tcp_saveti; +extern tcpnodelack; struct tcpcb *tcp_newtcpcb(); /* @@ -37,6 +38,7 @@ tcp_input(m0) register struct tcpiphdr *ti; struct inpcb *inp; register struct mbuf *m; + struct mbuf *om = 0; int len, tlen, off; register struct tcpcb *tp = 0; register int tiflags; @@ -82,7 +84,7 @@ COUNT(TCP_INPUT); /* * Check that TCP offset makes sense, - * process TCP options and adjust length. + * pull out TCP options and adjust length. */ off = ti->ti_off << 2; if (off < sizeof (struct tcphdr) || off > tlen) { @@ -90,10 +92,23 @@ COUNT(TCP_INPUT); goto drop; } ti->ti_len = tlen - off; -#if 0 - if (off > sizeof (struct tcphdr)) - tcp_options(ti); -#endif + if (off > sizeof (struct tcphdr)) { + if ((m = m_pullup(m, sizeof (struct ip) + off)) == 0) { + tcpstat.tcps_hdrops++; + goto drop; + } + ti = mtod(m, struct tcpiphdr *); + om = m_get(M_DONTWAIT); + if (om == 0) + goto drop; + om->m_off = MMINOFF; + om->m_len = off - sizeof (struct tcphdr); + { caddr_t op = mtod(m, caddr_t) + sizeof (struct tcpiphdr); + bcopy(op, mtod(om, caddr_t), om->m_len); + m->m_len -= om->m_len; + bcopy(op+om->m_len, op, m->m_len-sizeof (struct tcpiphdr)); + } + } tiflags = ti->ti_flags; #if vax @@ -134,6 +149,14 @@ COUNT(TCP_INPUT); tp->t_idle = 0; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; + /* + * Process options. + */ + if (om) { + tcp_dooptions(tp, om); + om = 0; + } + /* * Calculate amount of space in receive window, * and then do TCP input processing. @@ -509,22 +532,28 @@ printf("wl1 %x seq %x wl2 %x ack %x win %x wnd %x\n", tp->snd_wl1, ti->ti_seq, t /* * If an URG bit is set and in the segment and is greater than the - * current known urgent pointer, then signal the user that the - * remote side has out of band data. This should not happen + * current known urgent pointer, then mark the data stream. + * If the TCP is not doing out-of-band data, then indicate + * urgent to the user. This should not happen * in CLOSE_WAIT, CLOSING, LAST-ACK or TIME_WAIT STATES since * a FIN has been received from the remote side. In these states * we ignore the URG. */ if ((tiflags & TH_URG) && TCPS_HAVERCVDFIN(tp->t_state) == 0 && - ti->ti_urp <= ti->ti_len && SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { tp->rcv_up = ti->ti_seq + ti->ti_urp; so->so_oobmark = so->so_rcv.sb_cc + (tp->rcv_up - tp->rcv_nxt) - 1; if (so->so_oobmark == 0) so->so_state |= SS_RCVATMARK; - tcp_pulloutofband(so, ti); - sohasoutofband(so); +#ifdef TCPTRUEOOB + if ((tp->t_flags & TF_DOOOB) == 0) +#endif + { + sohasoutofband(so); + tp->t_oobflags |= TCPOOB_HAVEDATA; + } + } /* @@ -541,10 +570,10 @@ printf("wl1 %x seq %x wl2 %x ack %x win %x wnd %x\n", tp->snd_wl1, ti->ti_seq, t m->m_off += off; m->m_len -= off; tiflags = tcp_reass(tp, ti); -{ extern tcpdelack; -if (tcpdelack) tp->t_flags |= TF_DELACK; else - tp->t_flags |= TF_ACKNOW; /* XXX TF_DELACK */ -} + if (tcpnodelack == 0) + tp->t_flags |= TF_DELACK; + else + tp->t_flags |= TF_ACKNOW; } else { m_freem(m); tiflags &= ~TH_FIN; @@ -619,6 +648,8 @@ dropafterack: return; dropwithreset: + if (om) + m_free(om); /* * Generate a RST, dropping incoming segment. * Make ACK acceptable to originator of segment. @@ -642,37 +673,82 @@ drop: return; } -/* - * Pull the character before the urgent pointer into - * the TCP control block for presentation as out-of-band data. - * We leave ti->ti_len reflecting the out-of-band data, - * so that sequencing will continue to work. - */ -tcp_pulloutofband(so, ti) - struct socket *so; - struct tcpiphdr *ti; +tcp_dooptions(tp, om) + struct tcpcb *tp; + struct mbuf *om; { - register struct mbuf *m; - int cnt = sizeof (struct tcpiphdr) + ti->ti_urp - 1; - - m = dtom(ti); - while (cnt >= 0) { - if (m->m_len > cnt) { - char *cp = mtod(m, caddr_t) + cnt; - struct tcpcb *tp = sototcpcb(so); - - tp->t_oobc = *cp; - tp->t_haveoob = 1; - bcopy(cp+1, cp, m->m_len - cnt - 1); - m->m_len--; - return; + register u_char *cp; + int opt, optlen, cnt; + + cp = mtod(om, u_char *); + cnt = om->m_len; + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[0]; + if (opt == TCPOPT_EOL) + break; + if (opt == TCPOPT_NOP) + optlen = 1; + else + optlen = cp[1]; + switch (opt) { + + default: + break; + + case TCPOPT_MAXSEG: + if (optlen != 4) + continue; + tp->t_maxseg = *(u_short *)(cp + 2); +#if vax + tp->t_maxseg = ntohs(tp->t_maxseg); +#endif + break; + +#ifdef TCPTRUEOOB + case TCPOPT_WILLOOB: + tp->t_flags |= TF_DOOOB; +printf("tp %x dooob\n", tp); + break; + + case TCPOPT_OOBDATA: { + int seq; + + if (optlen != 4) + continue; + seq = cp[2]; + if (seq < tp->t_iobseq) + seq += 256; +printf("oobdata cp[2] %d iobseq %d seq %d\n", cp[2], tp->t_iobseq, seq); + if (seq - tp->t_iobseq > 128) { +printf("bad seq\n"); + tp->t_oobflags |= TCPOOB_OWEACK; + break; + } + tp->t_iobseq = cp[2]; + tp->t_iobc = cp[3]; +printf("take oob data %x input iobseq now %x\n", tp->t_iobc, tp->t_iobseq); + sohasoutofband(tp->t_inpcb->inp_socket); + break; } - cnt -= m->m_len; - m = m->m_next; - if (m == 0) + + case TCPOPT_OOBACK: { + int seq; + + if (optlen != 4) + continue; + if (tp->t_oobseq != cp[2]) { +printf("wrong ack\n"); + break; + } +printf("take oob ack %x and cancel rexmt\n", cp[2]); + tp->t_oobflags &= ~TCPOOB_NEEDACK; + tp->t_timer[TCPT_OOBREXMT] = 0; break; + } +#endif TCPTRUEOOB + } } - panic("tcp_pulloutofband"); + m_free(om); } /* diff --git a/usr/src/sys/netinet/tcp_output.c b/usr/src/sys/netinet/tcp_output.c index 812a86ec27..30041f6be1 100644 --- a/usr/src/sys/netinet/tcp_output.c +++ b/usr/src/sys/netinet/tcp_output.c @@ -1,4 +1,4 @@ -/* tcp_output.c 4.28 82/01/17 */ +/* tcp_output.c 4.29 82/01/17 */ #include "../h/param.h" #include "../h/systm.h" @@ -22,6 +22,18 @@ #include "../errno.h" char *tcpstates[]; /* XXX */ + +/* + * Initial options: indicate max segment length 1/2 of space + * allocated for receive; if TCPTRUEOOB is defined, indicate + * willingness to do true out-of-band. + */ +#ifndef TCPTRUEOOB +u_char tcp_initopt[4] = { TCPOPT_MAXSEG, 4, 0x0, 0x0, }; +#else +u_char tcp_initopt[6] = { TCPOPT_MAXSEG, 4, 0x0, 0x0, TCPOPT_WILLOOB, 2 }; +#endif + /* * Tcp output routine: figure out what should be sent and send it. */ @@ -34,7 +46,9 @@ tcp_output(tp) int off, flags; register struct mbuf *m; register struct tcpiphdr *ti; - int win; + int win, force; + u_char *opt; + unsigned optlen = 0; COUNT(TCP_OUTPUT); @@ -59,8 +73,16 @@ COUNT(TCP_OUTPUT); /* * Send if we owe peer an ACK. */ - if (tp->t_flags & TF_ACKNOW) + if (tp->t_flags&TF_ACKNOW) + goto send; + +#ifdef TCPTRUEOOB + /* + * Send if an out of band data or ack should be transmitted. + */ + if (tp->t_oobflags&(TCPOOB_OWEACK|TCPOOB_NEEDACK))) goto send; +#endif /* * Calculate available window in i, and also amount @@ -109,21 +131,73 @@ send: ti->ti_seq = htonl(ti->ti_seq); ti->ti_ack = htonl(ti->ti_ack); #endif - if (tp->t_tcpopt) { + /* + * Before ESTABLISHED, force sending of initial options + * unless TCP set to not do any options. + */ + if (tp->t_state < TCPS_ESTABLISHED) { + if (tp->t_flags&TF_NOOPT) + goto noopt; + opt = tcp_initopt; + optlen = sizeof (tcp_initopt); + *(u_short *)(opt + 2) = so->so_rcv.sb_hiwat / 2; +#if vax + *(u_short *)(opt + 2) = htons(*(u_short *)(opt + 2)); +#endif + } else { + if (tp->t_tcpopt == 0) + goto noopt; + opt = mtod(tp->t_tcpopt, u_char *); + optlen = tp->t_tcpopt->m_len; + } +#ifndef TCPTRUEOOB + if (opt) +#else + if (opt || (tp->t_oobflags&(TCPOOB_OWEACK|TCPOOB_NEEDACK))) +#endif + { m0 = m->m_next; m->m_next = m_get(0); if (m->m_next == 0) { (void) m_free(m); - m_freem(m); + m_freem(m0); return (0); } m->m_next->m_next = m0; - m->m_off = MMINOFF; - m->m_len = tp->t_tcpopt->m_len; - bcopy(mtod(tp->t_tcpopt, caddr_t), mtod(m, caddr_t), - (unsigned)tp->t_tcpopt->m_len); - ti->ti_off = (sizeof (struct tcphdr)+tp->t_tcpopt->m_len) >> 2; + m0 = m->m_next; + m0->m_off = MMINOFF; + m0->m_len = optlen; + bcopy(opt, mtod(m0, caddr_t), optlen); + opt = (u_char *)(mtod(m0, caddr_t) + optlen); +#ifdef TCPTRUEOOB + if (tp->t_oobflags&TCPOOB_OWEACK) { +printf("tp %x send OOBACK for %x\n", tp->t_iobseq); + *opt++ = TCPOPT_OOBACK; + *opt++ = 3; + *opt++ = tp->t_iobseq; + m0->m_len += 3; + tp->t_oobflags &= ~TCPOOB_OWEACK; + /* sender should rexmt oob to force ack repeat */ + } + if (tp->t_oobflags&TCPOOB_NEEDACK) { +printf("tp %x send OOBDATA seq %x data %x\n", tp->t_oobseq, tp->t_oobc); + *opt++ = TCPOPT_OOBDATA; + *opt++ = 4; + *opt++ = tp->t_oobseq; + *opt++ = tp->t_oobc; + m0->m_len += 4; + TCPT_RANGESET(tp->t_timer[TCPT_OOBREXMT], + tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX); + } +#endif + while (m0->m_len & 0x3) { + *opt++ = TCPOPT_EOL; + m0->m_len++; + } + optlen = m0->m_len; + ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2; } +noopt: ti->ti_flags = flags; win = sbspace(&so->so_rcv); if (win > 0) @@ -148,9 +222,13 @@ send: * Put TCP length in extended header, and then * checksum extended header and data. */ - if (len) - ti->ti_len = htons((u_short)(len + sizeof (struct tcphdr))); - ti->ti_sum = in_cksum(m, sizeof (struct tcpiphdr) + len); + if (len + optlen) { + ti->ti_len = sizeof (struct tcphdr) + optlen + len; +#if vax + ti->ti_len = htons((u_short)ti->ti_len); +#endif + } + ti->ti_sum = in_cksum(m, sizeof (struct tcpiphdr) + optlen + len); /* * Advance snd_nxt over sequence space of this segment @@ -202,7 +280,7 @@ send: * Fill in IP length and desired time to live and * send to IP level. */ - ((struct ip *)ti)->ip_len = len + sizeof (struct tcpiphdr); + ((struct ip *)ti)->ip_len = sizeof (struct tcpiphdr) + optlen + len; ((struct ip *)ti)->ip_ttl = TCP_TTL; if (ip_output(m, tp->t_ipopt) == 0) return (0); diff --git a/usr/src/sys/netinet/tcp_subr.c b/usr/src/sys/netinet/tcp_subr.c index 9f65033990..d9bc7b43c4 100644 --- a/usr/src/sys/netinet/tcp_subr.c +++ b/usr/src/sys/netinet/tcp_subr.c @@ -1,4 +1,4 @@ -/* tcp_subr.c 4.12 82/01/13 */ +/* tcp_subr.c 4.13 82/01/17 */ #include "../h/param.h" #include "../h/systm.h" @@ -159,6 +159,7 @@ COUNT(TCP_NEWTCPCB); tp = mtod(m, struct tcpcb *); tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; tp->t_maxseg = 1024; + tp->t_flags = TF_NOOPT; /* until all TCP's take options */ tp->t_inpcb = inp; inp->inp_ppcb = (caddr_t)tp; return (tp); diff --git a/usr/src/sys/netinet/tcp_timer.c b/usr/src/sys/netinet/tcp_timer.c index dc40da36b4..94fdc9ff54 100644 --- a/usr/src/sys/netinet/tcp_timer.c +++ b/usr/src/sys/netinet/tcp_timer.c @@ -1,4 +1,4 @@ -/* tcp_timer.c 4.11 82/01/13 */ +/* tcp_timer.c 4.12 82/01/17 */ #include "../h/param.h" #include "../h/systm.h" @@ -20,7 +20,7 @@ #include "../net/tcpip.h" #include "../errno.h" -int tcpdelack = 0; +int tcpnodelack = 0; /* * Fast timeout routine for processing delayed acks */ @@ -165,5 +165,18 @@ printf("rexmt set to %d\n", tp->t_timer[TCPT_REXMT]); tp->t_template, tp->rcv_nxt, tp->snd_una-1, 0); tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; return; + +#ifdef TCPTRUEOOB + /* + * Out-of-band data retransmit timer. + */ + case TCPT_OOBREXMT: + if (tp->t_flags & TF_NOOPT) + return; + (void) tcp_output(tp); + TCPT_RANGESET(tp->t_timer[TCPT_OOBREXMT], + 2 * tp->t_srtt, TCPTV_MIN, TCPTV_MAX); + return; +#endif } } diff --git a/usr/src/sys/netinet/tcp_timer.h b/usr/src/sys/netinet/tcp_timer.h index 4fa3912363..b29e04076e 100644 --- a/usr/src/sys/netinet/tcp_timer.h +++ b/usr/src/sys/netinet/tcp_timer.h @@ -1,15 +1,18 @@ -/* tcp_timer.h 4.5 82/01/13 */ +/* tcp_timer.h 4.6 82/01/17 */ /* * Definitions of the TCP timers. These timers are counted * down PR_SLOWHZ times a second. */ -#define TCPT_NTIMERS 4 +#define TCPT_NTIMERS 5 #define TCPT_REXMT 0 /* retransmit */ #define TCPT_PERSIST 1 /* retransmit persistance */ #define TCPT_KEEP 2 /* keep alive */ #define TCPT_2MSL 3 /* 2*msl quiet time timer */ +#ifdef TCPTRUEOOB +#define TCPT_OOBREXMT 4 /* out-of-band rexmt */ +#endif /* * The TCPT_REXMT timer is used to force retransmissions. @@ -41,6 +44,10 @@ * an ack segment in response from the peer. If, despite the TCPT_KEEP * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE * amount of time, then we drop the connection. + * + * The OOBREXMT timer is to force retransmissions of out-of-band indications. + * Because out-of-band data is considered critical, it does not exponential + * backoff, but runs at a multiple of smoothed round trip time until acked. */ #define TCP_TTL 15 /* time to live for TCP segs */ @@ -62,7 +69,7 @@ #ifdef TCPTIMERS char *tcptimers[] = - { "REXMT", "PERSIST", "KEEP", "2MSL" }; + { "REXMT", "PERSIST", "KEEP", "2MSL", "OOBREXMT" }; #endif /* diff --git a/usr/src/sys/netinet/tcp_usrreq.c b/usr/src/sys/netinet/tcp_usrreq.c index 6c4b5114b8..05c5a5836b 100644 --- a/usr/src/sys/netinet/tcp_usrreq.c +++ b/usr/src/sys/netinet/tcp_usrreq.c @@ -1,4 +1,4 @@ -/* tcp_usrreq.c 1.47 82/01/17 */ +/* tcp_usrreq.c 1.48 82/01/17 */ #include "../h/param.h" #include "../h/systm.h" @@ -204,22 +204,57 @@ COUNT(TCP_USRREQ); /* END UNIMPLEMENTED HOOKS */ case PRU_RCVOOB: - if (tp->t_haveoob == 0) { +#if TCPTRUEOOB + if (tp->t_flags & TF_DOOOB) { + if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) { + error = EWOULDBLOCK; + break; + } + *mtod(m, caddr_t) = tp->t_iobc; + tp->t_oobflags &= ~TCPOOB_HAVEDATA; + break; + } +#endif + if (so->so_oobmark == 0 && + (so->so_state & SS_RCVATMARK) == 0) { error = EINVAL; break; } - *mtod(m, caddr_t) = tp->t_oobc; - tp->t_haveoob = 0; + if (so->so_rcv.sb_cc < so->so_oobmark) { + error = EWOULDBLOCK; + return; + } + { struct mbuf *n = so->so_rcv.sb_mb; + int cnt = so->so_oobmark; + while (cnt > n->m_len) { + cnt -= n->m_len; + n = n->m_next; + } + *mtod(m, caddr_t) = *(mtod(n, caddr_t) + cnt); + } + tp->t_oobflags &= ~TCPOOB_HAVEDATA; break; case PRU_SENDOOB: + if (sbspace(&so->so_snd) < -512) { + error = ENOBUFS; + break; + } tp->snd_up = tp->snd_una + so->so_snd.sb_cc + 1; sbappend(&so->so_snd, m); /* if (tp->t_flags & TF_PUSH) tp->snd_end = tp->snd_una + so->so_snd.sb_cc; */ - (void) tcp_output(tp); +#ifdef TCPTRUEOOB + if (tp->t_flags & TF_DOOOB) { + tp->t_oobseq++; + tp->t_oobc = *mtod(m, caddr_t); +printf("sendoob seq now %x oobc %x\n", tp->t_oobseq, tp->t_oobc); + tp->t_oobflags |= TCPOOB_NEEDACK; + } +#endif + tp->t_force = 1; (void) tcp_output(tp); tp->t_force = 0; break; /* diff --git a/usr/src/sys/netinet/tcp_var.h b/usr/src/sys/netinet/tcp_var.h index dc3cc10218..ba523c361e 100644 --- a/usr/src/sys/netinet/tcp_var.h +++ b/usr/src/sys/netinet/tcp_var.h @@ -1,4 +1,4 @@ -/* tcp_var.h 4.14 82/01/17 */ +/* tcp_var.h 4.15 82/01/17 */ /* * Kernel variables for tcp. @@ -20,9 +20,11 @@ struct tcpcb { u_char t_flags; #define TF_ACKNOW 0x01 /* ack peer immediately */ #define TF_DELACK 0x02 /* ack, but try to delay it */ -#define TF_PUSH 0x04 /* push mode */ -#define TF_URG 0x08 /* urgent mode */ -#define TF_DONTKEEP 0x10 /* don't use keep-alives */ +#define TF_DONTKEEP 0x04 /* don't use keep-alives */ +#define TF_NOOPT 0x08 /* don't use tcp options */ +#ifdef TCPTRUEOOB +#define TF_DOOOB 0x10 /* do use out of band data */ +#endif struct tcpiphdr *t_template; /* skeletal packet for transmit */ struct inpcb *t_inpcb; /* back pointer to internet pcb */ /* @@ -55,9 +57,18 @@ struct tcpcb { short t_rtt; /* round trip time */ tcp_seq t_rtseq; /* sequence number being timed */ float t_srtt; /* smoothed round-trip time */ -/* out-of-band data; treat char before urgent pointer as out-of-band */ - char t_haveoob; /* have some */ - char t_oobc; /* the character */ +/* out-of-band data */ + char t_oobflags; /* have some */ +#define TCPOOB_HAVEDATA 0x01 + +#ifdef TCPTRUEOOB +#define TCPOOB_OWEACK 0x02 +#define TCPOOB_NEEDACK 0x04 + char t_iobc; /* input character */ + u_char t_iobseq; /* input receive sequence number */ + char t_oobc; /* output character */ + u_char t_oobseq; /* output transmit sequence number */ +#endif }; #define intotcpcb(ip) ((struct tcpcb *)(ip)->inp_ppcb) -- 2.20.1