1*4734Swnj /* tcp_usrreq.c 1.24 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 18*4734Swnj /* 19*4734Swnj * Tcp finite state machine entries for timer and user generated 20*4734Swnj * requests. These routines raise the ipl to that of the network 21*4734Swnj * to prevent reentry. In particluar, this requires that the software 22*4734Swnj * clock interrupt have lower priority than the network so that 23*4734Swnj * we can enter the network from timeout routines without improperly 24*4734Swnj * nesting the interrupt stack. 25*4734Swnj */ 26*4734Swnj 27*4734Swnj /* 28*4734Swnj * Tcp protocol timeout routine called once per second. 29*4734Swnj * Updates the timers in all active tcb's and 30*4734Swnj * causes finite state machine actions if timers expire. 31*4734Swnj */ 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; 454731Swnj for (i = 0; i < TNTIMERS; i++) 464731Swnj if (*tmp && --*tmp == 0) 474731Swnj tcp_usrreq(ISTIMER, i, tp, 0); 484567Swnj tp->t_xmt++; 494567Swnj } 504664Swnj tcp_iss += ISSINCR; /* increment iss */ 514567Swnj timeout(tcp_timeo, 0, hz); /* reschedule every second */ 524567Swnj splx(s); 534497Swnj } 544497Swnj 554731Swnj /* 56*4734Swnj * Cancel all timers for tcp tp. 57*4734Swnj */ 58*4734Swnj tcp_tcancel(tp) 59*4734Swnj struct tcb *tp; 60*4734Swnj { 61*4734Swnj register u_char *tmp = &tp->t_init; 62*4734Swnj register int i; 63*4734Swnj 64*4734Swnj for (i = 0; i < TNTIMERS; i++) 65*4734Swnj *tmp++ = 0; 66*4734Swnj } 67*4734Swnj 68*4734Swnj /* 694731Swnj * Process a TCP user request for tcp tb. If this is a send request 704731Swnj * then m is the mbuf chain of send data. If this is a timer expiration 714731Swnj * (called from the software clock routine), then timertype tells which timer. 724731Swnj */ 734731Swnj tcp_usrreq(input, timertype, tp, m) 744584Swnj int input, timertype; 754567Swnj register struct tcb *tp; 764731Swnj struct mbuf *m; 774497Swnj { 784567Swnj int s = splnet(); 794567Swnj register int nstate; 804584Swnj #ifdef TCPDEBUG 814584Swnj struct tcp_debug tdb; 824584Swnj #endif 834567Swnj COUNT(TCP_USRREQ); 844497Swnj 854567Swnj nstate = tp->t_state; 864576Swnj tp->tc_flags &= ~TC_NET_KEEP; 874731Swnj #ifdef KPROF 884567Swnj acounts[nstate][input]++; 894731Swnj #endif 904584Swnj #ifdef TCPDEBUG 914584Swnj if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) { 924605Swnj tdb_setup(tp, (struct th *)0, input, &tdb); 934584Swnj tdb.td_tim = timertype; 944584Swnj } else 954584Swnj tdb.td_tod = 0; 964584Swnj #endif 974731Swnj switch (input) { 984497Swnj 994731Swnj /* 1004731Swnj * Passive open. Create a tcp control block 1014731Swnj * and enter listen state. 1024731Swnj */ 103*4734Swnj case IUOPENA: 1044731Swnj if (nstate != 0 && nstate != CLOSED) 1054731Swnj goto bad; 1064676Swnj tcp_open(tp, PASSIVE); 1074567Swnj nstate = LISTEN; 1084567Swnj break; 1094497Swnj 1104731Swnj /* 1114731Swnj * Active open. Create a tcp control block, 1124731Swnj * send a SYN and enter SYN_SENT state. 1134731Swnj */ 114*4734Swnj case IUOPENR: 1154731Swnj if (nstate != 0 && nstate != CLOSED) 1164731Swnj goto bad; 1174676Swnj tcp_open(tp, ACTIVE); 1184676Swnj tcp_sndctl(tp); 1194567Swnj nstate = SYN_SENT; 1204567Swnj break; 1214497Swnj 1224731Swnj /* 1234731Swnj * Tcp close call. Can be generated by a user ioctl (half-close), 1244731Swnj * or when higher level close occurs, if a close hasn't happened 1254731Swnj * already. 1264731Swnj */ 1274731Swnj case IUCLOSE: 1284731Swnj switch (nstate) { 1294497Swnj 1304731Swnj /* 1314731Swnj * If we are aborting out of a listener or a active 1324731Swnj * connection which has not yet completed we can just 1334731Swnj * delete the tcb. 1344731Swnj */ 1354731Swnj case LISTEN: 136*4734Swnj case SYN_SENT: 1374731Swnj tcp_close(tp, UCLOSED); 1384731Swnj nstate = CLOSED; 1394731Swnj break; 1404731Swnj 1414731Swnj /* 1424731Swnj * If we have gotten as far as receiving a syn from 1434731Swnj * our foreign peer, we must be sure to send a FIN. 1444731Swnj * If we have gotten a FIN from the foreign peer already 1454731Swnj * (CLOSE_WAIT state), then all that remains is to wait 1464731Swnj * for his ack of the FIN (LAST_ACK state). If we have 1474731Swnj * not gotten a FIN from the foreign peer then we need 1484731Swnj * to either: 1494731Swnj * 1. rcv ack of our FIN (to FIN_W2) and then 1504731Swnj * send an ACK (to TIME_WAIT) and timeout at 2*MSL. 1514731Swnj * or 2. receive hist FIN (to CLOSING), send an ACK 1524731Swnj * (to TIME_WAIT), and then timeout. 1534731Swnj * In any case this starts with a transition to FIN_W1 here. 1544731Swnj */ 155*4734Swnj case SYN_RCVD: 1564731Swnj case L_SYN_RCVD: 1574731Swnj case ESTAB: 158*4734Swnj case CLOSE_WAIT: 1594731Swnj tp->tc_flags |= TC_SND_FIN; 1604731Swnj tcp_sndctl(tp); 1614731Swnj tp->tc_flags |= TC_USR_CLOSED; 1624731Swnj nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK; 1634731Swnj break; 1644731Swnj 1654731Swnj /* 1664731Swnj * In these states the user has already closed; 1674731Swnj * trying to close again is an error. 1684731Swnj */ 1694731Swnj case FIN_W1: 1704731Swnj case FIN_W2: 1714731Swnj case TIME_WAIT: 1724731Swnj case CLOSING: 1734731Swnj case LAST_ACK: 1744731Swnj case RCV_WAIT: 1754731Swnj to_user(tp->t_ucb, UCLSERR); 1764731Swnj break; 1774731Swnj 1784731Swnj default: 1794731Swnj goto bad; 1804731Swnj } 1814567Swnj break; 1824497Swnj 1834731Swnj /* 1844731Swnj * TCP Timer processing. 1854731Swnj * Timers should expire only on open connections 1864731Swnj * not in LISTEN state. 1874731Swnj */ 188*4734Swnj case ISTIMER: 1894731Swnj switch (nstate) { 1904731Swnj 1914731Swnj case 0: 1924731Swnj case CLOSED: 1934731Swnj case LISTEN: 1944731Swnj goto bad; 1954731Swnj 1964731Swnj default: 1974731Swnj nstate = tcp_timers(tp, timertype); 1984731Swnj } 1994567Swnj break; 2004497Swnj 2014731Swnj /* 2024731Swnj * User notification of more window availability after 2034731Swnj * reading out data. This should not happen before a connection 2044731Swnj * is established or after it is closed. 2054731Swnj * If the foreign peer has closed and the local entity 2064731Swnj * has not, inform him of the FIN (give end of file). 2074731Swnj * If the local entity is in RCV_WAIT state (draining data 2084731Swnj * out of the TCP buffers after foreign close) and there 2094731Swnj * is no more data, institute a close. 2104731Swnj */ 211*4734Swnj case IURECV: 2124731Swnj if (nstate < ESTAB || nstate == CLOSED) 2134731Swnj goto bad; 214*4734Swnj tcp_sndwin(tp); 2154691Swnj if ((tp->tc_flags&TC_FIN_RCVD) && 2164691Swnj (tp->tc_flags&TC_USR_CLOSED) == 0 && 2174691Swnj rcv_empty(tp)) 2184691Swnj to_user(tp, UCLOSED); 2194731Swnj if (nstate == RCV_WAIT && rcv_empty(tp)) { 2204676Swnj tcp_close(tp, UCLOSED); 2214567Swnj nstate = CLOSED; 2224731Swnj } 2234567Swnj break; 2244497Swnj 2254731Swnj /* 2264731Swnj * Send request on open connection. 2274731Swnj * Should not happen if the connection is not yet established. 2284731Swnj * Allowed only on ESTAB connection and after FIN from 2294731Swnj * foreign peer. 2304731Swnj */ 231*4734Swnj case IUSEND: 2324731Swnj switch (nstate) { 2334567Swnj 2344731Swnj case ESTAB: 2354731Swnj case CLOSE_WAIT: 2364731Swnj nstate = tcp_usrsend(tp, m); 2374731Swnj break; 2384731Swnj 2394731Swnj default: 2404731Swnj if (nstate < ESTAB) 2414731Swnj goto bad; 2424731Swnj to_user(tp, UCLSERR); 2434731Swnj break; 2444731Swnj } 2454567Swnj break; 2464567Swnj 2474731Swnj /* 2484731Swnj * User abort of connection. 2494731Swnj * If a SYN has been received, but we have not exchanged FINs 2504731Swnj * then we need to send an RST. In any case we then 2514731Swnj * enter closed state. 2524731Swnj */ 253*4734Swnj case IUABORT: 2544731Swnj if (nstate == 0 || nstate == CLOSED) 2554731Swnj break; 2564731Swnj switch (nstate) { 2574567Swnj 2584731Swnj case 0: 2594731Swnj case CLOSED: 2604731Swnj break; 2614567Swnj 2624731Swnj case SYN_RCVD: 2634731Swnj case ESTAB: 2644731Swnj case FIN_W1: 2654731Swnj case FIN_W2: 2664731Swnj case CLOSE_WAIT: 2674731Swnj tp->tc_flags |= TC_SND_RST; 2684731Swnj tcp_sndnull(tp); 2694731Swnj /* fall into ... */ 2704731Swnj 2714731Swnj default: 2724731Swnj tcp_close(tp, UABORT); 2734731Swnj nstate = CLOSED; 2744731Swnj } 2754567Swnj break; 2764567Swnj 2774731Swnj /* 2784731Swnj * Network down entry. Discard the tcb and force 2794731Swnj * the state to be closed, ungracefully. 2804731Swnj */ 281*4734Swnj case INCLEAR: 2824731Swnj if (nstate == 0 || nstate == CLOSED) 2834731Swnj break; 2844676Swnj tcp_close(tp, UNETDWN); 2854567Swnj nstate = CLOSED; 2864567Swnj break; 2874567Swnj 2884731Swnj default: 2894731Swnj panic("tcp_usrreq"); 2904731Swnj bad: 2914731Swnj printf("tcp: bad state: tcb=%x state=%d input=%d\n", 2924731Swnj tp, tp->t_state, input); 2934731Swnj nstate = EFAILEC; 2944567Swnj break; 2954567Swnj } 2964567Swnj #ifdef TCPDEBUG 2974605Swnj if (tdb.td_tod) 2984605Swnj tdb_stuff(&tdb, nstate); 2994567Swnj #endif 3004567Swnj /* YECH */ 3014567Swnj switch (nstate) { 3024567Swnj 3034584Swnj case CLOSED: 3044567Swnj case SAME: 3054567Swnj break; 3064567Swnj 3074567Swnj case EFAILEC: 3084731Swnj if (m) 3094731Swnj m_freem(dtom(m)); 3104567Swnj break; 3114567Swnj 3124567Swnj default: 3134567Swnj tp->t_state = nstate; 3144567Swnj break; 3154567Swnj } 3164567Swnj splx(s); 3174497Swnj } 3184497Swnj 3194682Swnj /* 3204682Swnj * Open routine, called to initialize newly created tcb fields. 3214682Swnj */ 3224682Swnj tcp_open(tp, mode) 3234567Swnj register struct tcb *tp; 3244567Swnj int mode; 3254497Swnj { 3264682Swnj register struct ucb *up = tp->t_ucb; 3274682Swnj COUNT(TCP_OPEN); 3284497Swnj 3294682Swnj /* 3304682Swnj * Link in tcb queue and make 3314682Swnj * initialize empty reassembly queue. 3324682Swnj */ 3334682Swnj tp->tcb_next = tcb.tcb_next; 3344682Swnj tcb.tcb_next->tcb_prev = tp; 3354682Swnj tp->tcb_prev = (struct tcb *)&tcb; 3364682Swnj tcb.tcb_next = tp; 3374682Swnj tp->t_rcv_next = tp->t_rcv_prev = (struct th *)tp; 3384497Swnj 3394682Swnj /* 3404682Swnj * Initialize sequence numbers and 3414682Swnj * round trip retransmit timer. 3424682Swnj * (Other fields were init'd to zero when tcb allocated.) 3434682Swnj */ 3444567Swnj tp->t_xmtime = T_REXMT; 3454682Swnj tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una = 3464682Swnj tp->iss = tcp_iss; 3474567Swnj tp->snd_off = tp->iss + 1; 3484664Swnj tcp_iss += (ISSINCR >> 1) + 1; 3494567Swnj 3504682Swnj /* 3514682Swnj * Set timeout for open. 3524682Swnj * SHOULD THIS BE A HIGHER LEVEL FUNCTION!?! THINK SO. 3534682Swnj */ 3544682Swnj if (up->uc_timeo) 3554682Swnj tp->t_init = up->uc_timeo; 3564682Swnj else if (mode == ACTIVE) 3574682Swnj tp->t_init = T_INIT; 3584682Swnj /* else 3594682Swnj tp->t_init = 0; */ 3604682Swnj up->uc_timeo = 0; /* ### */ 3614497Swnj } 3624497Swnj 3634682Swnj /* 3644682Swnj * Internal close of a connection, shutting down the tcb. 3654682Swnj */ 3664676Swnj tcp_close(tp, state) 3674567Swnj register struct tcb *tp; 3684567Swnj short state; 3694497Swnj { 3704682Swnj register struct ucb *up = tp->t_ucb; 3714567Swnj register struct th *t; 3724567Swnj register struct mbuf *m; 3734682Swnj COUNT(TCP_CLOSE); 3744497Swnj 3754682Swnj /* 376*4734Swnj * Remove from tcb queue and cancel timers. 3774682Swnj */ 3784682Swnj tp->tcb_prev->tcb_next = tp->tcb_next; 3794682Swnj tp->tcb_next->tcb_prev = tp->tcb_prev; 380*4734Swnj tcp_tcancel(tp); 3814567Swnj 3824682Swnj /* 383*4734Swnj * Discard all buffers. 3844682Swnj */ 3854567Swnj for (t = tp->t_rcv_next; t != (struct th *)tp; t = t->t_next) 3864567Swnj m_freem(dtom(t)); 387*4734Swnj if (up->uc_rbuf) { 3884567Swnj m_freem(up->uc_rbuf); 3894567Swnj up->uc_rbuf = NULL; 3904567Swnj } 3914657Swnj up->uc_rcc = 0; 392*4734Swnj if (up->uc_sbuf) { 3934567Swnj m_freem(up->uc_sbuf); 3944567Swnj up->uc_sbuf = NULL; 3954567Swnj } 3964592Swnj up->uc_ssize = 0; 3974567Swnj for (m = tp->t_rcv_unack; m != NULL; m = m->m_act) { 3984567Swnj m_freem(m); 3994567Swnj tp->t_rcv_unack = NULL; 4004567Swnj } 4014682Swnj 4024682Swnj /* 403*4734Swnj * Free tcp send template, the tcb itself, 404*4734Swnj * the routing table entry, and the space we had reserved 405*4734Swnj * in the meory pool. 4064682Swnj */ 407*4734Swnj if (tp->t_template) { 408*4734Swnj m_free(dtom(tp->t_template)); 409*4734Swnj tp->t_template = 0; 4104664Swnj } 4114670Swnj wmemfree((caddr_t)tp, 1024); 412*4734Swnj up->uc_pcb = 0; 413*4734Swnj if (up->uc_host) { 4144567Swnj h_free(up->uc_host); 415*4734Swnj up->uc_host = 0; 4164567Swnj } 417*4734Swnj m_release(up->uc_snd + (up->uc_rhiwat/MSIZE) + 2); 4184567Swnj 4194682Swnj /* 4204682Swnj * If user has initiated close (via close call), delete ucb 4214682Swnj * entry, otherwise just wakeup so user can issue close call 4224682Swnj */ 423*4734Swnj if (tp->tc_flags&TC_USR_ABORT) /* ### */ 424*4734Swnj up->uc_proc = NULL; /* ### */ 425*4734Swnj else /* ### */ 4264682Swnj to_user(up, state); /* ### */ 4274497Swnj } 4284497Swnj 4294682Swnj /* 430*4734Swnj * Send data queue headed by m0 into the protocol. 4314682Swnj */ 4324678Swnj tcp_usrsend(tp, m0) 4334584Swnj register struct tcb *tp; 4344584Swnj struct mbuf *m0; 4354497Swnj { 4364497Swnj register struct mbuf *m, *n; 4374584Swnj register struct ucb *up = tp->t_ucb; 4384497Swnj register off; 4394574Swnj seq_t last; 4404682Swnj COUNT(TCP_USRSEND); 4414497Swnj 4424497Swnj last = tp->snd_off; 4434584Swnj for (m = n = m0; m != NULL; m = m->m_next) { 4444497Swnj up->uc_ssize++; 4454591Swnj if (m->m_off > MMAXOFF) 4464588Swnj up->uc_ssize += NMBPG; 4474497Swnj last += m->m_len; 4484497Swnj } 4494588Swnj if ((m = up->uc_sbuf) == NULL) 4504588Swnj up->uc_sbuf = n; 4514588Swnj else { 4524588Swnj while (m->m_next != NULL) { 4534497Swnj m = m->m_next; 4544497Swnj last += m->m_len; 4554497Swnj } 4564591Swnj if (m->m_off <= MMAXOFF) { 4574588Swnj last += m->m_len; 4584588Swnj off = m->m_off + m->m_len; 4594591Swnj while (n && n->m_off <= MMAXOFF && 4604591Swnj (MMAXOFF - off) >= n->m_len) { 4614588Swnj bcopy((caddr_t)((int)n + n->m_off), 4624588Swnj (caddr_t)((int)m + off), n->m_len); 4634588Swnj m->m_len += n->m_len; 4644588Swnj off += n->m_len; 4654588Swnj up->uc_ssize--; 4664588Swnj n = m_free(n); 4674588Swnj } 4684497Swnj } 4694497Swnj m->m_next = n; 4704588Swnj } 4714588Swnj if (up->uc_flags & UEOL) 4724497Swnj tp->snd_end = last; 4734588Swnj if (up->uc_flags & UURG) { 4744497Swnj tp->snd_urp = last+1; 4754576Swnj tp->tc_flags |= TC_SND_URG; 4764567Swnj } 4774678Swnj tcp_send(tp); 4784567Swnj return (SAME); 4794497Swnj } 4804497Swnj 4814682Swnj /* 4824682Swnj * TCP timer went off processing. 4834682Swnj */ 4844584Swnj tcp_timers(tp, timertype) 4854584Swnj register struct tcb *tp; 4864584Swnj int timertype; 4874497Swnj { 4884497Swnj 4894567Swnj COUNT(TCP_TIMERS); 4904584Swnj switch (timertype) { 4914497Swnj 4924567Swnj case TINIT: /* initialization timer */ 4934576Swnj if ((tp->tc_flags&TC_SYN_ACKED) == 0) { /* 35 */ 4944676Swnj tcp_close(tp, UINTIMO); 4954567Swnj return (CLOSED); 4964567Swnj } 4974567Swnj return (SAME); 4984497Swnj 4994567Swnj case TFINACK: /* fin-ack timer */ 5004567Swnj switch (tp->t_state) { 5014497Swnj 5024567Swnj case TIME_WAIT: 5034567Swnj /* 5044567Swnj * We can be sure our ACK of foreign FIN was rcvd, 5054567Swnj * and can close if no data left for user. 5064567Swnj */ 5074567Swnj if (rcv_empty(tp)) { 5084676Swnj tcp_close(tp, UCLOSED); /* 14 */ 5094567Swnj return (CLOSED); 5104567Swnj } 5114567Swnj return (RCV_WAIT); /* 17 */ 5124497Swnj 5134731Swnj case CLOSING: 5144576Swnj tp->tc_flags |= TC_WAITED_2_ML; 5154567Swnj return (SAME); 5164497Swnj 5174567Swnj default: 5184567Swnj return (SAME); 5194567Swnj } 5204497Swnj 5214567Swnj case TREXMT: /* retransmission timer */ 5224567Swnj if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ 5234567Swnj /* 5244567Swnj * Set up for a retransmission, increase rexmt time 5254567Swnj * in case of multiple retransmissions. 5264567Swnj */ 5274567Swnj tp->snd_nxt = tp->snd_una; 5284576Swnj tp->tc_flags |= TC_REXMT; 5294567Swnj tp->t_xmtime = tp->t_xmtime << 1; 5304567Swnj if (tp->t_xmtime > T_REMAX) 5314567Swnj tp->t_xmtime = T_REMAX; 5324678Swnj tcp_send(tp); 5334567Swnj } 5344567Swnj return (SAME); 5354497Swnj 5364567Swnj case TREXMTTL: /* retransmit too long */ 5374567Swnj if (tp->t_rtl_val > tp->snd_una) /* 36 */ 5384567Swnj to_user(tp->t_ucb, URXTIMO); 5394567Swnj /* 5404567Swnj * If user has already closed, abort the connection. 5414567Swnj */ 5424576Swnj if (tp->tc_flags & TC_USR_CLOSED) { 5434676Swnj tcp_close(tp, URXTIMO); 5444567Swnj return (CLOSED); 5454567Swnj } 5464567Swnj return (SAME); 5474497Swnj 5484567Swnj case TPERSIST: /* persist timer */ 5494567Swnj /* 5504567Swnj * Force a byte send through closed window. 5514567Swnj */ 5524576Swnj tp->tc_flags |= TC_FORCE_ONE; 5534678Swnj tcp_send(tp); 5544567Swnj return (SAME); 5554567Swnj } 5564567Swnj panic("tcp_timers"); 5574497Swnj } 5584497Swnj 5594567Swnj /* THIS ROUTINE IS A CROCK */ 5604567Swnj to_user(up, state) 5614567Swnj register struct ucb *up; 5624567Swnj register short state; 5634497Swnj { 5644567Swnj COUNT(TO_USER); 5654497Swnj 5664567Swnj up->uc_state |= state; 5674567Swnj netwakeup(up); 5684567Swnj if (state == UURGENT) 5694567Swnj psignal(up->uc_proc, SIGURG); 5704497Swnj } 5714584Swnj 5724584Swnj #ifdef TCPDEBUG 5734682Swnj /* 5744682Swnj * TCP debugging utility subroutines. 5754682Swnj * THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID. 5764682Swnj */ 5774670Swnj tdb_setup(tp, n, input, tdp) 5784670Swnj struct tcb *tp; 5794670Swnj register struct th *n; 5804670Swnj int input; 5814670Swnj register struct tcp_debug *tdp; 5824670Swnj { 5834670Swnj 5844682Swnj COUNT(TDB_SETUP); 5854670Swnj tdp->td_tod = time; 5864670Swnj tdp->td_tcb = tp; 5874670Swnj tdp->td_old = tp->t_state; 5884670Swnj tdp->td_inp = input; 5894670Swnj tdp->td_tim = 0; 5904670Swnj tdp->td_new = -1; 5914670Swnj if (n) { 5924670Swnj tdp->td_sno = n->t_seq; 5934670Swnj tdp->td_ano = n->t_ackno; 5944670Swnj tdp->td_wno = n->t_win; 5954670Swnj tdp->td_lno = n->t_len; 5964670Swnj tdp->td_flg = n->th_flags; 5974670Swnj } else 5984670Swnj tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno = 5994670Swnj tdp->td_flg = 0; 6004670Swnj } 6014670Swnj 6024670Swnj tdb_stuff(tdp, nstate) 6034670Swnj struct tcp_debug *tdp; 6044670Swnj int nstate; 6054670Swnj { 6064682Swnj COUNT(TDB_STUFF); 6074670Swnj 6084670Swnj tdp->td_new = nstate; 6094670Swnj tcp_debug[tdbx++ % TDBSIZE] = *tdp; 6104670Swnj if (tcpconsdebug & 2) 6114670Swnj tcp_prt(tdp); 6124670Swnj } 6134682Swnj 6144682Swnj tcp_prt(tdp) 6154682Swnj register struct tcp_debug *tdp; 6164682Swnj { 6174682Swnj COUNT(TCP_PRT); 6184682Swnj 6194698Swnj printf("%x ", ((int)tdp->td_tcb)&0xffffff); 6204698Swnj if (tdp->td_inp == INSEND) { 6214698Swnj printf("SEND #%x", tdp->td_sno); 6224698Swnj tdp->td_lno = ntohs(tdp->td_lno); 6234698Swnj tdp->td_wno = ntohs(tdp->td_wno); 6244698Swnj } else { 6254698Swnj if (tdp->td_inp == INRECV) 6264698Swnj printf("RCV #%x ", tdp->td_sno); 6274698Swnj printf("%s.%s", 6284698Swnj tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]); 6294698Swnj if (tdp->td_inp == ISTIMER) 6304698Swnj printf("(%s)", tcptimers[tdp->td_tim]); 6314698Swnj printf(" -> %s", 6324698Swnj tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]); 6334698Swnj if (tdp->td_new == -1) 6344698Swnj printf(" (FAILED)"); 6354698Swnj } 6364682Swnj /* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */ 6374698Swnj if (tdp->td_lno) 6384698Swnj printf(" len=%d", tdp->td_lno); 6394698Swnj if (tdp->td_wno) 6404698Swnj printf(" win=%d", tdp->td_wno); 6414698Swnj if (tdp->td_flg & TH_FIN) printf(" FIN"); 6424698Swnj if (tdp->td_flg & TH_SYN) printf(" SYN"); 6434698Swnj if (tdp->td_flg & TH_RST) printf(" RST"); 6444698Swnj if (tdp->td_flg & TH_EOL) printf(" EOL"); 6454698Swnj if (tdp->td_flg & TH_ACK) printf(" ACK %x", tdp->td_ano); 6464698Swnj if (tdp->td_flg & TH_URG) printf(" URG"); 6474682Swnj printf("\n"); 6484682Swnj } 6494670Swnj #endif 650