1*4735Swnj /* tcp_usrreq.c 1.25 81/11/04 */ 24567Swnj 34497Swnj #include "../h/param.h" 44567Swnj #include "../h/systm.h" 54664Swnj #include "../h/mbuf.h" 64664Swnj #include "../h/socket.h" 74664Swnj #include "../inet/inet.h" 84664Swnj #include "../inet/inet_systm.h" 94664Swnj #include "../inet/imp.h" 104664Swnj #include "../inet/ip.h" 114664Swnj #include "../inet/tcp.h" 124567Swnj #define TCPFSTAB 134584Swnj #ifdef TCPDEBUG 144584Swnj #define TCPSTATES 154584Swnj #endif 164664Swnj #include "../inet/tcp_fsm.h" 174497Swnj 184734Swnj /* 194734Swnj * Tcp finite state machine entries for timer and user generated 204734Swnj * requests. These routines raise the ipl to that of the network 214734Swnj * to prevent reentry. In particluar, this requires that the software 224734Swnj * clock interrupt have lower priority than the network so that 234734Swnj * we can enter the network from timeout routines without improperly 244734Swnj * nesting the interrupt stack. 254734Swnj */ 264734Swnj 274734Swnj /* 284734Swnj * Tcp protocol timeout routine called once per second. 294734Swnj * Updates the timers in all active tcb's and 304734Swnj * causes finite state machine actions if timers expire. 314734Swnj */ 324567Swnj tcp_timeo() 334497Swnj { 344567Swnj register struct tcb *tp; 354567Swnj int s = splnet(); 364731Swnj register u_char *tmp; 374731Swnj register int i; 384567Swnj COUNT(TCP_TIMEO); 394497Swnj 404567Swnj /* 414567Swnj * Search through tcb's and update active timers. 424567Swnj */ 434682Swnj for (tp = tcb.tcb_next; tp != (struct tcb *)&tcb; tp = tp->tcb_next) { 444731Swnj tmp = &tp->t_init; 45*4735Swnj for (i = 0; i < TNTIMERS; i++) { 464731Swnj if (*tmp && --*tmp == 0) 474731Swnj tcp_usrreq(ISTIMER, i, tp, 0); 48*4735Swnj tmp++; 49*4735Swnj } 504567Swnj tp->t_xmt++; 514567Swnj } 524664Swnj tcp_iss += ISSINCR; /* increment iss */ 534567Swnj timeout(tcp_timeo, 0, hz); /* reschedule every second */ 544567Swnj splx(s); 554497Swnj } 564497Swnj 574731Swnj /* 584734Swnj * Cancel all timers for tcp tp. 594734Swnj */ 604734Swnj tcp_tcancel(tp) 614734Swnj struct tcb *tp; 624734Swnj { 634734Swnj register u_char *tmp = &tp->t_init; 644734Swnj register int i; 654734Swnj 664734Swnj for (i = 0; i < TNTIMERS; i++) 674734Swnj *tmp++ = 0; 684734Swnj } 694734Swnj 704734Swnj /* 714731Swnj * Process a TCP user request for tcp tb. If this is a send request 724731Swnj * then m is the mbuf chain of send data. If this is a timer expiration 734731Swnj * (called from the software clock routine), then timertype tells which timer. 744731Swnj */ 754731Swnj tcp_usrreq(input, timertype, tp, m) 764584Swnj int input, timertype; 774567Swnj register struct tcb *tp; 784731Swnj struct mbuf *m; 794497Swnj { 804567Swnj int s = splnet(); 814567Swnj register int nstate; 824584Swnj #ifdef TCPDEBUG 834584Swnj struct tcp_debug tdb; 844584Swnj #endif 854567Swnj COUNT(TCP_USRREQ); 864497Swnj 874567Swnj nstate = tp->t_state; 884576Swnj tp->tc_flags &= ~TC_NET_KEEP; 894731Swnj #ifdef KPROF 904567Swnj acounts[nstate][input]++; 914731Swnj #endif 924584Swnj #ifdef TCPDEBUG 934584Swnj if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) { 944605Swnj tdb_setup(tp, (struct th *)0, input, &tdb); 954584Swnj tdb.td_tim = timertype; 964584Swnj } else 974584Swnj tdb.td_tod = 0; 984584Swnj #endif 994731Swnj switch (input) { 1004497Swnj 1014731Swnj /* 1024731Swnj * Passive open. Create a tcp control block 1034731Swnj * and enter listen state. 1044731Swnj */ 1054734Swnj case IUOPENA: 1064731Swnj if (nstate != 0 && nstate != CLOSED) 1074731Swnj goto bad; 1084676Swnj tcp_open(tp, PASSIVE); 1094567Swnj nstate = LISTEN; 1104567Swnj break; 1114497Swnj 1124731Swnj /* 1134731Swnj * Active open. Create a tcp control block, 1144731Swnj * send a SYN and enter SYN_SENT state. 1154731Swnj */ 1164734Swnj case IUOPENR: 1174731Swnj if (nstate != 0 && nstate != CLOSED) 1184731Swnj goto bad; 1194676Swnj tcp_open(tp, ACTIVE); 1204676Swnj tcp_sndctl(tp); 1214567Swnj nstate = SYN_SENT; 1224567Swnj break; 1234497Swnj 1244731Swnj /* 1254731Swnj * Tcp close call. Can be generated by a user ioctl (half-close), 1264731Swnj * or when higher level close occurs, if a close hasn't happened 1274731Swnj * already. 1284731Swnj */ 1294731Swnj case IUCLOSE: 1304731Swnj switch (nstate) { 1314497Swnj 1324731Swnj /* 1334731Swnj * If we are aborting out of a listener or a active 1344731Swnj * connection which has not yet completed we can just 1354731Swnj * delete the tcb. 1364731Swnj */ 1374731Swnj case LISTEN: 1384734Swnj case SYN_SENT: 1394731Swnj tcp_close(tp, UCLOSED); 1404731Swnj nstate = CLOSED; 1414731Swnj break; 1424731Swnj 1434731Swnj /* 1444731Swnj * If we have gotten as far as receiving a syn from 1454731Swnj * our foreign peer, we must be sure to send a FIN. 1464731Swnj * If we have gotten a FIN from the foreign peer already 1474731Swnj * (CLOSE_WAIT state), then all that remains is to wait 1484731Swnj * for his ack of the FIN (LAST_ACK state). If we have 1494731Swnj * not gotten a FIN from the foreign peer then we need 1504731Swnj * to either: 1514731Swnj * 1. rcv ack of our FIN (to FIN_W2) and then 1524731Swnj * send an ACK (to TIME_WAIT) and timeout at 2*MSL. 1534731Swnj * or 2. receive hist FIN (to CLOSING), send an ACK 1544731Swnj * (to TIME_WAIT), and then timeout. 1554731Swnj * In any case this starts with a transition to FIN_W1 here. 1564731Swnj */ 1574734Swnj case SYN_RCVD: 1584731Swnj case L_SYN_RCVD: 1594731Swnj case ESTAB: 1604734Swnj case CLOSE_WAIT: 1614731Swnj tp->tc_flags |= TC_SND_FIN; 1624731Swnj tcp_sndctl(tp); 1634731Swnj tp->tc_flags |= TC_USR_CLOSED; 1644731Swnj nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK; 1654731Swnj break; 1664731Swnj 1674731Swnj /* 1684731Swnj * In these states the user has already closed; 1694731Swnj * trying to close again is an error. 1704731Swnj */ 1714731Swnj case FIN_W1: 1724731Swnj case FIN_W2: 1734731Swnj case TIME_WAIT: 1744731Swnj case CLOSING: 1754731Swnj case LAST_ACK: 1764731Swnj case RCV_WAIT: 1774731Swnj to_user(tp->t_ucb, UCLSERR); 1784731Swnj break; 1794731Swnj 1804731Swnj default: 1814731Swnj goto bad; 1824731Swnj } 1834567Swnj break; 1844497Swnj 1854731Swnj /* 1864731Swnj * TCP Timer processing. 1874731Swnj * Timers should expire only on open connections 1884731Swnj * not in LISTEN state. 1894731Swnj */ 1904734Swnj case ISTIMER: 1914731Swnj switch (nstate) { 1924731Swnj 1934731Swnj case 0: 1944731Swnj case CLOSED: 1954731Swnj case LISTEN: 1964731Swnj goto bad; 1974731Swnj 1984731Swnj default: 1994731Swnj nstate = tcp_timers(tp, timertype); 2004731Swnj } 2014567Swnj break; 2024497Swnj 2034731Swnj /* 2044731Swnj * User notification of more window availability after 2054731Swnj * reading out data. This should not happen before a connection 2064731Swnj * is established or after it is closed. 2074731Swnj * If the foreign peer has closed and the local entity 2084731Swnj * has not, inform him of the FIN (give end of file). 2094731Swnj * If the local entity is in RCV_WAIT state (draining data 2104731Swnj * out of the TCP buffers after foreign close) and there 2114731Swnj * is no more data, institute a close. 2124731Swnj */ 2134734Swnj case IURECV: 2144731Swnj if (nstate < ESTAB || nstate == CLOSED) 2154731Swnj goto bad; 2164734Swnj tcp_sndwin(tp); 2174691Swnj if ((tp->tc_flags&TC_FIN_RCVD) && 2184691Swnj (tp->tc_flags&TC_USR_CLOSED) == 0 && 2194691Swnj rcv_empty(tp)) 2204691Swnj to_user(tp, UCLOSED); 2214731Swnj if (nstate == RCV_WAIT && rcv_empty(tp)) { 2224676Swnj tcp_close(tp, UCLOSED); 2234567Swnj nstate = CLOSED; 2244731Swnj } 2254567Swnj break; 2264497Swnj 2274731Swnj /* 2284731Swnj * Send request on open connection. 2294731Swnj * Should not happen if the connection is not yet established. 2304731Swnj * Allowed only on ESTAB connection and after FIN from 2314731Swnj * foreign peer. 2324731Swnj */ 2334734Swnj case IUSEND: 2344731Swnj switch (nstate) { 2354567Swnj 2364731Swnj case ESTAB: 2374731Swnj case CLOSE_WAIT: 2384731Swnj nstate = tcp_usrsend(tp, m); 2394731Swnj break; 2404731Swnj 2414731Swnj default: 2424731Swnj if (nstate < ESTAB) 2434731Swnj goto bad; 2444731Swnj to_user(tp, UCLSERR); 2454731Swnj break; 2464731Swnj } 2474567Swnj break; 2484567Swnj 2494731Swnj /* 2504731Swnj * User abort of connection. 2514731Swnj * If a SYN has been received, but we have not exchanged FINs 2524731Swnj * then we need to send an RST. In any case we then 2534731Swnj * enter closed state. 2544731Swnj */ 2554734Swnj case IUABORT: 2564731Swnj if (nstate == 0 || nstate == CLOSED) 2574731Swnj break; 2584731Swnj switch (nstate) { 2594567Swnj 2604731Swnj case 0: 2614731Swnj case CLOSED: 2624731Swnj break; 2634567Swnj 2644731Swnj case SYN_RCVD: 2654731Swnj case ESTAB: 2664731Swnj case FIN_W1: 2674731Swnj case FIN_W2: 2684731Swnj case CLOSE_WAIT: 2694731Swnj tp->tc_flags |= TC_SND_RST; 2704731Swnj tcp_sndnull(tp); 2714731Swnj /* fall into ... */ 2724731Swnj 2734731Swnj default: 2744731Swnj tcp_close(tp, UABORT); 2754731Swnj nstate = CLOSED; 2764731Swnj } 2774567Swnj break; 2784567Swnj 2794731Swnj /* 2804731Swnj * Network down entry. Discard the tcb and force 2814731Swnj * the state to be closed, ungracefully. 2824731Swnj */ 2834734Swnj case INCLEAR: 2844731Swnj if (nstate == 0 || nstate == CLOSED) 2854731Swnj break; 2864676Swnj tcp_close(tp, UNETDWN); 2874567Swnj nstate = CLOSED; 2884567Swnj break; 2894567Swnj 2904731Swnj default: 2914731Swnj panic("tcp_usrreq"); 2924731Swnj bad: 2934731Swnj printf("tcp: bad state: tcb=%x state=%d input=%d\n", 2944731Swnj tp, tp->t_state, input); 2954731Swnj nstate = EFAILEC; 2964567Swnj break; 2974567Swnj } 2984567Swnj #ifdef TCPDEBUG 2994605Swnj if (tdb.td_tod) 3004605Swnj tdb_stuff(&tdb, nstate); 3014567Swnj #endif 3024567Swnj /* YECH */ 3034567Swnj switch (nstate) { 3044567Swnj 3054584Swnj case CLOSED: 3064567Swnj case SAME: 3074567Swnj break; 3084567Swnj 3094567Swnj case EFAILEC: 3104731Swnj if (m) 3114731Swnj m_freem(dtom(m)); 3124567Swnj break; 3134567Swnj 3144567Swnj default: 3154567Swnj tp->t_state = nstate; 3164567Swnj break; 3174567Swnj } 3184567Swnj splx(s); 3194497Swnj } 3204497Swnj 3214682Swnj /* 3224682Swnj * Open routine, called to initialize newly created tcb fields. 3234682Swnj */ 3244682Swnj tcp_open(tp, mode) 3254567Swnj register struct tcb *tp; 3264567Swnj int mode; 3274497Swnj { 3284682Swnj register struct ucb *up = tp->t_ucb; 3294682Swnj COUNT(TCP_OPEN); 3304497Swnj 3314682Swnj /* 3324682Swnj * Link in tcb queue and make 3334682Swnj * initialize empty reassembly queue. 3344682Swnj */ 3354682Swnj tp->tcb_next = tcb.tcb_next; 3364682Swnj tcb.tcb_next->tcb_prev = tp; 3374682Swnj tp->tcb_prev = (struct tcb *)&tcb; 3384682Swnj tcb.tcb_next = tp; 3394682Swnj tp->t_rcv_next = tp->t_rcv_prev = (struct th *)tp; 3404497Swnj 3414682Swnj /* 3424682Swnj * Initialize sequence numbers and 3434682Swnj * round trip retransmit timer. 3444682Swnj * (Other fields were init'd to zero when tcb allocated.) 3454682Swnj */ 3464567Swnj tp->t_xmtime = T_REXMT; 3474682Swnj tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una = 3484682Swnj tp->iss = tcp_iss; 3494567Swnj tp->snd_off = tp->iss + 1; 3504664Swnj tcp_iss += (ISSINCR >> 1) + 1; 3514567Swnj 3524682Swnj /* 3534682Swnj * Set timeout for open. 3544682Swnj * SHOULD THIS BE A HIGHER LEVEL FUNCTION!?! THINK SO. 3554682Swnj */ 3564682Swnj if (up->uc_timeo) 3574682Swnj tp->t_init = up->uc_timeo; 3584682Swnj else if (mode == ACTIVE) 3594682Swnj tp->t_init = T_INIT; 3604682Swnj /* else 3614682Swnj tp->t_init = 0; */ 3624682Swnj up->uc_timeo = 0; /* ### */ 3634497Swnj } 3644497Swnj 3654682Swnj /* 3664682Swnj * Internal close of a connection, shutting down the tcb. 3674682Swnj */ 3684676Swnj tcp_close(tp, state) 3694567Swnj register struct tcb *tp; 3704567Swnj short state; 3714497Swnj { 3724682Swnj register struct ucb *up = tp->t_ucb; 3734567Swnj register struct th *t; 3744567Swnj register struct mbuf *m; 3754682Swnj COUNT(TCP_CLOSE); 3764497Swnj 3774682Swnj /* 3784734Swnj * Remove from tcb queue and cancel timers. 3794682Swnj */ 3804682Swnj tp->tcb_prev->tcb_next = tp->tcb_next; 3814682Swnj tp->tcb_next->tcb_prev = tp->tcb_prev; 3824734Swnj tcp_tcancel(tp); 3834567Swnj 3844682Swnj /* 3854734Swnj * Discard all buffers. 3864682Swnj */ 3874567Swnj for (t = tp->t_rcv_next; t != (struct th *)tp; t = t->t_next) 3884567Swnj m_freem(dtom(t)); 3894734Swnj if (up->uc_rbuf) { 3904567Swnj m_freem(up->uc_rbuf); 3914567Swnj up->uc_rbuf = NULL; 3924567Swnj } 3934657Swnj up->uc_rcc = 0; 3944734Swnj if (up->uc_sbuf) { 3954567Swnj m_freem(up->uc_sbuf); 3964567Swnj up->uc_sbuf = NULL; 3974567Swnj } 3984592Swnj up->uc_ssize = 0; 3994567Swnj for (m = tp->t_rcv_unack; m != NULL; m = m->m_act) { 4004567Swnj m_freem(m); 4014567Swnj tp->t_rcv_unack = NULL; 4024567Swnj } 4034682Swnj 4044682Swnj /* 4054734Swnj * Free tcp send template, the tcb itself, 4064734Swnj * the routing table entry, and the space we had reserved 4074734Swnj * in the meory pool. 4084682Swnj */ 4094734Swnj if (tp->t_template) { 4104734Swnj m_free(dtom(tp->t_template)); 4114734Swnj tp->t_template = 0; 4124664Swnj } 4134670Swnj wmemfree((caddr_t)tp, 1024); 4144734Swnj up->uc_pcb = 0; 4154734Swnj if (up->uc_host) { 4164567Swnj h_free(up->uc_host); 4174734Swnj up->uc_host = 0; 4184567Swnj } 4194734Swnj m_release(up->uc_snd + (up->uc_rhiwat/MSIZE) + 2); 4204567Swnj 4214682Swnj /* 4224682Swnj * If user has initiated close (via close call), delete ucb 4234682Swnj * entry, otherwise just wakeup so user can issue close call 4244682Swnj */ 4254734Swnj if (tp->tc_flags&TC_USR_ABORT) /* ### */ 4264734Swnj up->uc_proc = NULL; /* ### */ 4274734Swnj else /* ### */ 4284682Swnj to_user(up, state); /* ### */ 4294497Swnj } 4304497Swnj 4314682Swnj /* 4324734Swnj * Send data queue headed by m0 into the protocol. 4334682Swnj */ 4344678Swnj tcp_usrsend(tp, m0) 4354584Swnj register struct tcb *tp; 4364584Swnj struct mbuf *m0; 4374497Swnj { 4384497Swnj register struct mbuf *m, *n; 4394584Swnj register struct ucb *up = tp->t_ucb; 4404497Swnj register off; 4414574Swnj seq_t last; 4424682Swnj COUNT(TCP_USRSEND); 4434497Swnj 4444497Swnj last = tp->snd_off; 4454584Swnj for (m = n = m0; m != NULL; m = m->m_next) { 4464497Swnj up->uc_ssize++; 4474591Swnj if (m->m_off > MMAXOFF) 4484588Swnj up->uc_ssize += NMBPG; 4494497Swnj last += m->m_len; 4504497Swnj } 4514588Swnj if ((m = up->uc_sbuf) == NULL) 4524588Swnj up->uc_sbuf = n; 4534588Swnj else { 4544588Swnj while (m->m_next != NULL) { 4554497Swnj m = m->m_next; 4564497Swnj last += m->m_len; 4574497Swnj } 4584591Swnj if (m->m_off <= MMAXOFF) { 4594588Swnj last += m->m_len; 4604588Swnj off = m->m_off + m->m_len; 4614591Swnj while (n && n->m_off <= MMAXOFF && 4624591Swnj (MMAXOFF - off) >= n->m_len) { 4634588Swnj bcopy((caddr_t)((int)n + n->m_off), 4644588Swnj (caddr_t)((int)m + off), n->m_len); 4654588Swnj m->m_len += n->m_len; 4664588Swnj off += n->m_len; 4674588Swnj up->uc_ssize--; 4684588Swnj n = m_free(n); 4694588Swnj } 4704497Swnj } 4714497Swnj m->m_next = n; 4724588Swnj } 4734588Swnj if (up->uc_flags & UEOL) 4744497Swnj tp->snd_end = last; 4754588Swnj if (up->uc_flags & UURG) { 4764497Swnj tp->snd_urp = last+1; 4774576Swnj tp->tc_flags |= TC_SND_URG; 4784567Swnj } 4794678Swnj tcp_send(tp); 4804567Swnj return (SAME); 4814497Swnj } 4824497Swnj 4834682Swnj /* 4844682Swnj * TCP timer went off processing. 4854682Swnj */ 4864584Swnj tcp_timers(tp, timertype) 4874584Swnj register struct tcb *tp; 4884584Swnj int timertype; 4894497Swnj { 4904497Swnj 4914567Swnj COUNT(TCP_TIMERS); 4924584Swnj switch (timertype) { 4934497Swnj 4944567Swnj case TINIT: /* initialization timer */ 4954576Swnj if ((tp->tc_flags&TC_SYN_ACKED) == 0) { /* 35 */ 4964676Swnj tcp_close(tp, UINTIMO); 4974567Swnj return (CLOSED); 4984567Swnj } 4994567Swnj return (SAME); 5004497Swnj 5014567Swnj case TFINACK: /* fin-ack timer */ 5024567Swnj switch (tp->t_state) { 5034497Swnj 5044567Swnj case TIME_WAIT: 5054567Swnj /* 5064567Swnj * We can be sure our ACK of foreign FIN was rcvd, 5074567Swnj * and can close if no data left for user. 5084567Swnj */ 5094567Swnj if (rcv_empty(tp)) { 5104676Swnj tcp_close(tp, UCLOSED); /* 14 */ 5114567Swnj return (CLOSED); 5124567Swnj } 5134567Swnj return (RCV_WAIT); /* 17 */ 5144497Swnj 5154731Swnj case CLOSING: 5164576Swnj tp->tc_flags |= TC_WAITED_2_ML; 5174567Swnj return (SAME); 5184497Swnj 5194567Swnj default: 5204567Swnj return (SAME); 5214567Swnj } 5224497Swnj 5234567Swnj case TREXMT: /* retransmission timer */ 5244567Swnj if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ 5254567Swnj /* 5264567Swnj * Set up for a retransmission, increase rexmt time 5274567Swnj * in case of multiple retransmissions. 5284567Swnj */ 5294567Swnj tp->snd_nxt = tp->snd_una; 5304576Swnj tp->tc_flags |= TC_REXMT; 5314567Swnj tp->t_xmtime = tp->t_xmtime << 1; 5324567Swnj if (tp->t_xmtime > T_REMAX) 5334567Swnj tp->t_xmtime = T_REMAX; 5344678Swnj tcp_send(tp); 5354567Swnj } 5364567Swnj return (SAME); 5374497Swnj 5384567Swnj case TREXMTTL: /* retransmit too long */ 5394567Swnj if (tp->t_rtl_val > tp->snd_una) /* 36 */ 5404567Swnj to_user(tp->t_ucb, URXTIMO); 5414567Swnj /* 5424567Swnj * If user has already closed, abort the connection. 5434567Swnj */ 5444576Swnj if (tp->tc_flags & TC_USR_CLOSED) { 5454676Swnj tcp_close(tp, URXTIMO); 5464567Swnj return (CLOSED); 5474567Swnj } 5484567Swnj return (SAME); 5494497Swnj 5504567Swnj case TPERSIST: /* persist timer */ 5514567Swnj /* 5524567Swnj * Force a byte send through closed window. 5534567Swnj */ 5544576Swnj tp->tc_flags |= TC_FORCE_ONE; 5554678Swnj tcp_send(tp); 5564567Swnj return (SAME); 5574567Swnj } 5584567Swnj panic("tcp_timers"); 5594497Swnj } 5604497Swnj 5614567Swnj /* THIS ROUTINE IS A CROCK */ 5624567Swnj to_user(up, state) 5634567Swnj register struct ucb *up; 5644567Swnj register short state; 5654497Swnj { 5664567Swnj COUNT(TO_USER); 5674497Swnj 5684567Swnj up->uc_state |= state; 5694567Swnj netwakeup(up); 5704567Swnj if (state == UURGENT) 5714567Swnj psignal(up->uc_proc, SIGURG); 5724497Swnj } 5734584Swnj 5744584Swnj #ifdef TCPDEBUG 5754682Swnj /* 5764682Swnj * TCP debugging utility subroutines. 5774682Swnj * THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID. 5784682Swnj */ 5794670Swnj tdb_setup(tp, n, input, tdp) 5804670Swnj struct tcb *tp; 5814670Swnj register struct th *n; 5824670Swnj int input; 5834670Swnj register struct tcp_debug *tdp; 5844670Swnj { 5854670Swnj 5864682Swnj COUNT(TDB_SETUP); 5874670Swnj tdp->td_tod = time; 5884670Swnj tdp->td_tcb = tp; 5894670Swnj tdp->td_old = tp->t_state; 5904670Swnj tdp->td_inp = input; 5914670Swnj tdp->td_tim = 0; 5924670Swnj tdp->td_new = -1; 5934670Swnj if (n) { 5944670Swnj tdp->td_sno = n->t_seq; 5954670Swnj tdp->td_ano = n->t_ackno; 5964670Swnj tdp->td_wno = n->t_win; 5974670Swnj tdp->td_lno = n->t_len; 5984670Swnj tdp->td_flg = n->th_flags; 5994670Swnj } else 6004670Swnj tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno = 6014670Swnj tdp->td_flg = 0; 6024670Swnj } 6034670Swnj 6044670Swnj tdb_stuff(tdp, nstate) 6054670Swnj struct tcp_debug *tdp; 6064670Swnj int nstate; 6074670Swnj { 6084682Swnj COUNT(TDB_STUFF); 6094670Swnj 6104670Swnj tdp->td_new = nstate; 6114670Swnj tcp_debug[tdbx++ % TDBSIZE] = *tdp; 6124670Swnj if (tcpconsdebug & 2) 6134670Swnj tcp_prt(tdp); 6144670Swnj } 6154682Swnj 6164682Swnj tcp_prt(tdp) 6174682Swnj register struct tcp_debug *tdp; 6184682Swnj { 6194682Swnj COUNT(TCP_PRT); 6204682Swnj 6214698Swnj printf("%x ", ((int)tdp->td_tcb)&0xffffff); 6224698Swnj if (tdp->td_inp == INSEND) { 6234698Swnj printf("SEND #%x", tdp->td_sno); 6244698Swnj tdp->td_lno = ntohs(tdp->td_lno); 6254698Swnj tdp->td_wno = ntohs(tdp->td_wno); 6264698Swnj } else { 6274698Swnj if (tdp->td_inp == INRECV) 6284698Swnj printf("RCV #%x ", tdp->td_sno); 6294698Swnj printf("%s.%s", 6304698Swnj tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]); 6314698Swnj if (tdp->td_inp == ISTIMER) 6324698Swnj printf("(%s)", tcptimers[tdp->td_tim]); 6334698Swnj printf(" -> %s", 6344698Swnj tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]); 6354698Swnj if (tdp->td_new == -1) 6364698Swnj printf(" (FAILED)"); 6374698Swnj } 6384682Swnj /* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */ 6394698Swnj if (tdp->td_lno) 6404698Swnj printf(" len=%d", tdp->td_lno); 6414698Swnj if (tdp->td_wno) 6424698Swnj printf(" win=%d", tdp->td_wno); 6434698Swnj if (tdp->td_flg & TH_FIN) printf(" FIN"); 6444698Swnj if (tdp->td_flg & TH_SYN) printf(" SYN"); 6454698Swnj if (tdp->td_flg & TH_RST) printf(" RST"); 6464698Swnj if (tdp->td_flg & TH_EOL) printf(" EOL"); 6474698Swnj if (tdp->td_flg & TH_ACK) printf(" ACK %x", tdp->td_ano); 6484698Swnj if (tdp->td_flg & TH_URG) printf(" URG"); 6494682Swnj printf("\n"); 6504682Swnj } 6514670Swnj #endif 652