1*4691Swnj /* tcp_usrreq.c 1.21 81/10/31 */ 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 184567Swnj tcp_timeo() 194497Swnj { 204567Swnj register struct tcb *tp; 214567Swnj int s = splnet(); 224567Swnj COUNT(TCP_TIMEO); 234497Swnj 244567Swnj /* 254567Swnj * Search through tcb's and update active timers. 264567Swnj */ 274682Swnj for (tp = tcb.tcb_next; tp != (struct tcb *)&tcb; tp = tp->tcb_next) { 284567Swnj if (tp->t_init != 0 && --tp->t_init == 0) 294567Swnj tcp_usrreq(ISTIMER, TINIT, tp, 0); 304567Swnj if (tp->t_rexmt != 0 && --tp->t_rexmt == 0) 314567Swnj tcp_usrreq(ISTIMER, TREXMT, tp, 0); 324567Swnj if (tp->t_rexmttl != 0 && --tp->t_rexmttl == 0) 334567Swnj tcp_usrreq(ISTIMER, TREXMTTL, tp, 0); 344567Swnj if (tp->t_persist != 0 && --tp->t_persist == 0) 354567Swnj tcp_usrreq(ISTIMER, TPERSIST, tp, 0); 364567Swnj if (tp->t_finack != 0 && --tp->t_finack == 0) 374567Swnj tcp_usrreq(ISTIMER, TFINACK, tp, 0); 384567Swnj tp->t_xmt++; 394567Swnj } 404664Swnj tcp_iss += ISSINCR; /* increment iss */ 414567Swnj timeout(tcp_timeo, 0, hz); /* reschedule every second */ 424567Swnj splx(s); 434497Swnj } 444497Swnj 454584Swnj tcp_usrreq(input, timertype, tp, mp) 464584Swnj int input, timertype; 474567Swnj register struct tcb *tp; 484584Swnj struct mbuf *mp; 494497Swnj { 504567Swnj int s = splnet(); 514567Swnj register int nstate; 524584Swnj #ifdef TCPDEBUG 534584Swnj struct tcp_debug tdb; 544584Swnj #endif 554567Swnj COUNT(TCP_USRREQ); 564497Swnj 574567Swnj nstate = tp->t_state; 584576Swnj tp->tc_flags &= ~TC_NET_KEEP; 594567Swnj acounts[nstate][input]++; 604584Swnj #ifdef TCPDEBUG 614584Swnj if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) { 624605Swnj tdb_setup(tp, (struct th *)0, input, &tdb); 634584Swnj tdb.td_tim = timertype; 644584Swnj } else 654584Swnj tdb.td_tod = 0; 664584Swnj #endif 674567Swnj switch (tcp_fstab[nstate][input]) { 684497Swnj 694567Swnj default: 704567Swnj printf("tcp: bad state: tcb=%x state=%d input=%d\n", 714567Swnj tp, tp->t_state, input); 724567Swnj nstate = EFAILEC; 734567Swnj break; 744497Swnj 754567Swnj case LIS_CLS: /* 1 */ 764676Swnj tcp_open(tp, PASSIVE); 774567Swnj nstate = LISTEN; 784567Swnj break; 794497Swnj 804567Swnj case SYS_CLS: /* 2 */ 814676Swnj tcp_open(tp, ACTIVE); 824676Swnj tcp_sndctl(tp); 834567Swnj nstate = SYN_SENT; 844567Swnj break; 854497Swnj 864567Swnj case CLS_OPN: /* 10 */ 874676Swnj tcp_close(tp, UCLOSED); 884567Swnj nstate = CLOSED; 894567Swnj break; 904497Swnj 914567Swnj case CL2_CLW: /* 10 */ 924576Swnj tp->tc_flags |= TC_SND_FIN; 934676Swnj tcp_sndctl(tp); 944576Swnj tp->tc_flags |= TC_USR_CLOSED; 954567Swnj nstate = CLOSING2; 964567Swnj break; 974497Swnj 984567Swnj case TIMERS: /* 14,17,34,35,36,37,38 */ 994584Swnj nstate = tcp_timers(tp, timertype); 1004567Swnj break; 1014497Swnj 1024567Swnj case CLS_RWT: /* 20 */ 103*4691Swnj if ((tp->tc_flags&TC_FIN_RCVD) && 104*4691Swnj (tp->tc_flags&TC_USR_CLOSED) == 0 && 105*4691Swnj rcv_empty(tp)) 106*4691Swnj to_user(tp, UCLOSED); 1074567Swnj if (rcv_empty(tp)) { 1084676Swnj tcp_close(tp, UCLOSED); 1094567Swnj nstate = CLOSED; 1104567Swnj } else 1114567Swnj nstate = RCV_WAIT; 1124567Swnj break; 1134497Swnj 1144567Swnj case FW1_SYR: /* 24,25 */ 1154576Swnj tp->tc_flags |= TC_SND_FIN; 1164676Swnj tcp_sndctl(tp); 1174576Swnj tp->tc_flags |= TC_USR_CLOSED; 1184567Swnj nstate = FIN_W1; 1194567Swnj break; 1204567Swnj 1214567Swnj case SSS_SND: /* 40,41 */ 1224678Swnj nstate = tcp_usrsend(tp, mp); 1234567Swnj break; 1244567Swnj 1254567Swnj case SSS_RCV: /* 42 */ 1264676Swnj tcp_sndwin(tp); /* send new window */ 127*4691Swnj if ((tp->tc_flags&TC_FIN_RCVD) && 128*4691Swnj (tp->tc_flags&TC_USR_CLOSED) == 0 && 129*4691Swnj rcv_empty(tp)) 130*4691Swnj to_user(tp, UCLOSED); 1314567Swnj break; 1324567Swnj 1334567Swnj case CLS_NSY: /* 44 */ 1344676Swnj tcp_close(tp, UABORT); 1354567Swnj nstate = CLOSED; 1364567Swnj break; 1374567Swnj 1384567Swnj case CLS_SYN: /* 45 */ 1394576Swnj tp->tc_flags |= TC_SND_RST; 1404676Swnj tcp_sndnull(tp); 1414676Swnj tcp_close(tp, UABORT); 1424567Swnj nstate = CLOSED; 1434567Swnj break; 1444567Swnj 1454567Swnj case CLS_ACT: /* 47 */ 1464676Swnj tcp_close(tp, UNETDWN); 1474567Swnj nstate = CLOSED; 1484567Swnj break; 1494567Swnj 1504567Swnj case NOP: 1514567Swnj break; 1524567Swnj 1534567Swnj case CLS_ERR: 1544567Swnj to_user(tp->t_ucb, UCLSERR); 1554567Swnj break; 1564567Swnj } 1574567Swnj #ifdef TCPDEBUG 1584605Swnj if (tdb.td_tod) 1594605Swnj tdb_stuff(&tdb, nstate); 1604567Swnj #endif 1614567Swnj /* YECH */ 1624567Swnj switch (nstate) { 1634567Swnj 1644584Swnj case CLOSED: 1654567Swnj case SAME: 1664567Swnj break; 1674567Swnj 1684567Swnj case EFAILEC: 1694584Swnj if (mp) 1704584Swnj m_freem(dtom(mp)); 1714567Swnj break; 1724567Swnj 1734567Swnj default: 1744567Swnj tp->t_state = nstate; 1754567Swnj break; 1764567Swnj } 1774567Swnj splx(s); 1784497Swnj } 1794497Swnj 1804682Swnj /* 1814682Swnj * Open routine, called to initialize newly created tcb fields. 1824682Swnj */ 1834682Swnj tcp_open(tp, mode) 1844567Swnj register struct tcb *tp; 1854567Swnj int mode; 1864497Swnj { 1874682Swnj register struct ucb *up = tp->t_ucb; 1884682Swnj COUNT(TCP_OPEN); 1894497Swnj 1904682Swnj /* 1914682Swnj * Link in tcb queue and make 1924682Swnj * initialize empty reassembly queue. 1934682Swnj */ 1944682Swnj tp->tcb_next = tcb.tcb_next; 1954682Swnj tcb.tcb_next->tcb_prev = tp; 1964682Swnj tp->tcb_prev = (struct tcb *)&tcb; 1974682Swnj tcb.tcb_next = tp; 1984682Swnj tp->t_rcv_next = tp->t_rcv_prev = (struct th *)tp; 1994497Swnj 2004682Swnj /* 2014682Swnj * Initialize sequence numbers and 2024682Swnj * round trip retransmit timer. 2034682Swnj * (Other fields were init'd to zero when tcb allocated.) 2044682Swnj */ 2054567Swnj tp->t_xmtime = T_REXMT; 2064682Swnj tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una = 2074682Swnj tp->iss = tcp_iss; 2084567Swnj tp->snd_off = tp->iss + 1; 2094664Swnj tcp_iss += (ISSINCR >> 1) + 1; 2104567Swnj 2114682Swnj /* 2124682Swnj * Set timeout for open. 2134682Swnj * SHOULD THIS BE A HIGHER LEVEL FUNCTION!?! THINK SO. 2144682Swnj */ 2154682Swnj if (up->uc_timeo) 2164682Swnj tp->t_init = up->uc_timeo; 2174682Swnj else if (mode == ACTIVE) 2184682Swnj tp->t_init = T_INIT; 2194682Swnj /* else 2204682Swnj tp->t_init = 0; */ 2214682Swnj up->uc_timeo = 0; /* ### */ 2224497Swnj } 2234497Swnj 2244682Swnj /* 2254682Swnj * Internal close of a connection, shutting down the tcb. 2264682Swnj */ 2274676Swnj tcp_close(tp, state) 2284567Swnj register struct tcb *tp; 2294567Swnj short state; 2304497Swnj { 2314682Swnj register struct ucb *up = tp->t_ucb; 2324567Swnj register struct th *t; 2334567Swnj register struct mbuf *m; 2344682Swnj COUNT(TCP_CLOSE); 2354497Swnj 2364682Swnj /* 2374682Swnj * Cancel all timers. 2384682Swnj * SHOULD LOOP HERE !?! 2394682Swnj */ 2404567Swnj tp->t_init = tp->t_rexmt = tp->t_rexmttl = tp->t_persist = 2414567Swnj tp->t_finack = 0; 2424497Swnj 2434682Swnj /* 2444682Swnj * Remque the tcb 2454682Swnj */ 2464682Swnj tp->tcb_prev->tcb_next = tp->tcb_next; 2474682Swnj tp->tcb_next->tcb_prev = tp->tcb_prev; 2484567Swnj 2494682Swnj /* 2504682Swnj * Discard all buffers... 2514682Swnj * 2524682Swnj * SHOULD COUNT EACH RESOURCE TO 0 AND PANIC IF CONFUSED 2534682Swnj */ 2544567Swnj for (t = tp->t_rcv_next; t != (struct th *)tp; t = t->t_next) 2554567Swnj m_freem(dtom(t)); 2564567Swnj if (up->uc_rbuf != NULL) { 2574567Swnj m_freem(up->uc_rbuf); 2584567Swnj up->uc_rbuf = NULL; 2594567Swnj } 2604657Swnj up->uc_rcc = 0; 2614567Swnj if (up->uc_sbuf != NULL) { 2624567Swnj m_freem(up->uc_sbuf); 2634567Swnj up->uc_sbuf = NULL; 2644567Swnj } 2654592Swnj up->uc_ssize = 0; 2664567Swnj for (m = tp->t_rcv_unack; m != NULL; m = m->m_act) { 2674567Swnj m_freem(m); 2684567Swnj tp->t_rcv_unack = NULL; 2694567Swnj } 2704682Swnj 2714682Swnj /* 2724682Swnj * Free tcp send template. 2734682Swnj */ 2744664Swnj if (up->uc_template) { 2754664Swnj m_free(dtom(up->uc_template)); 2764664Swnj up->uc_template = 0; 2774664Swnj } 2784682Swnj 2794682Swnj /* 2804682Swnj * Free the tcb 2814682Swnj * WOULD THIS BETTER BE DONE AT USER CLOSE? 2824682Swnj */ 2834670Swnj wmemfree((caddr_t)tp, 1024); 2844567Swnj up->uc_tcb = NULL; 2854567Swnj 2864682Swnj /* 2874682Swnj * Lower buffer allocation. 2884682Swnj * SHOULD BE A M_ROUTINE CALL. 2894682Swnj */ 2904664Swnj mbstat.m_lowat -= up->uc_snd + (up->uc_rhiwat/MSIZE) + 2; 2914664Swnj mbstat.m_hiwat = 2 * mbstat.m_lowat; 2924682Swnj 2934682Swnj /* 2944682Swnj * Free routing table entry. 2954682Swnj */ 2964567Swnj if (up->uc_host != NULL) { 2974567Swnj h_free(up->uc_host); 2984567Swnj up->uc_host = NULL; 2994567Swnj } 3004567Swnj 3014682Swnj /* 3024682Swnj * If user has initiated close (via close call), delete ucb 3034682Swnj * entry, otherwise just wakeup so user can issue close call 3044682Swnj */ 3054576Swnj if (tp->tc_flags&TC_USR_ABORT) 3064567Swnj up->uc_proc = NULL; 3074567Swnj else 3084682Swnj to_user(up, state); /* ### */ 3094497Swnj } 3104497Swnj 3114682Swnj /* 3124682Swnj * User routine to send data queue headed by m0 into the protocol. 3134682Swnj */ 3144678Swnj tcp_usrsend(tp, m0) 3154584Swnj register struct tcb *tp; 3164584Swnj struct mbuf *m0; 3174497Swnj { 3184497Swnj register struct mbuf *m, *n; 3194584Swnj register struct ucb *up = tp->t_ucb; 3204497Swnj register off; 3214574Swnj seq_t last; 3224682Swnj COUNT(TCP_USRSEND); 3234497Swnj 3244497Swnj last = tp->snd_off; 3254584Swnj for (m = n = m0; m != NULL; m = m->m_next) { 3264497Swnj up->uc_ssize++; 3274591Swnj if (m->m_off > MMAXOFF) 3284588Swnj up->uc_ssize += NMBPG; 3294497Swnj last += m->m_len; 3304497Swnj } 3314588Swnj if ((m = up->uc_sbuf) == NULL) 3324588Swnj up->uc_sbuf = n; 3334588Swnj else { 3344588Swnj while (m->m_next != NULL) { 3354497Swnj m = m->m_next; 3364497Swnj last += m->m_len; 3374497Swnj } 3384591Swnj if (m->m_off <= MMAXOFF) { 3394588Swnj last += m->m_len; 3404588Swnj off = m->m_off + m->m_len; 3414591Swnj while (n && n->m_off <= MMAXOFF && 3424591Swnj (MMAXOFF - off) >= n->m_len) { 3434588Swnj bcopy((caddr_t)((int)n + n->m_off), 3444588Swnj (caddr_t)((int)m + off), n->m_len); 3454588Swnj m->m_len += n->m_len; 3464588Swnj off += n->m_len; 3474588Swnj up->uc_ssize--; 3484588Swnj n = m_free(n); 3494588Swnj } 3504497Swnj } 3514497Swnj m->m_next = n; 3524588Swnj } 3534588Swnj if (up->uc_flags & UEOL) 3544497Swnj tp->snd_end = last; 3554588Swnj if (up->uc_flags & UURG) { 3564497Swnj tp->snd_urp = last+1; 3574576Swnj tp->tc_flags |= TC_SND_URG; 3584567Swnj } 3594678Swnj tcp_send(tp); 3604567Swnj return (SAME); 3614497Swnj } 3624497Swnj 3634682Swnj /* 3644682Swnj * TCP timer went off processing. 3654682Swnj */ 3664584Swnj tcp_timers(tp, timertype) 3674584Swnj register struct tcb *tp; 3684584Swnj int timertype; 3694497Swnj { 3704497Swnj 3714567Swnj COUNT(TCP_TIMERS); 3724584Swnj switch (timertype) { 3734497Swnj 3744567Swnj case TINIT: /* initialization timer */ 3754576Swnj if ((tp->tc_flags&TC_SYN_ACKED) == 0) { /* 35 */ 3764676Swnj tcp_close(tp, UINTIMO); 3774567Swnj return (CLOSED); 3784567Swnj } 3794567Swnj return (SAME); 3804497Swnj 3814567Swnj case TFINACK: /* fin-ack timer */ 3824567Swnj switch (tp->t_state) { 3834497Swnj 3844567Swnj case TIME_WAIT: 3854567Swnj /* 3864567Swnj * We can be sure our ACK of foreign FIN was rcvd, 3874567Swnj * and can close if no data left for user. 3884567Swnj */ 3894567Swnj if (rcv_empty(tp)) { 3904676Swnj tcp_close(tp, UCLOSED); /* 14 */ 3914567Swnj return (CLOSED); 3924567Swnj } 3934567Swnj return (RCV_WAIT); /* 17 */ 3944497Swnj 3954567Swnj case CLOSING1: 3964576Swnj tp->tc_flags |= TC_WAITED_2_ML; 3974567Swnj return (SAME); 3984497Swnj 3994567Swnj default: 4004567Swnj return (SAME); 4014567Swnj } 4024497Swnj 4034567Swnj case TREXMT: /* retransmission timer */ 4044567Swnj if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ 4054567Swnj /* 4064567Swnj * Set up for a retransmission, increase rexmt time 4074567Swnj * in case of multiple retransmissions. 4084567Swnj */ 4094567Swnj tp->snd_nxt = tp->snd_una; 4104576Swnj tp->tc_flags |= TC_REXMT; 4114567Swnj tp->t_xmtime = tp->t_xmtime << 1; 4124567Swnj if (tp->t_xmtime > T_REMAX) 4134567Swnj tp->t_xmtime = T_REMAX; 4144678Swnj tcp_send(tp); 4154567Swnj } 4164567Swnj return (SAME); 4174497Swnj 4184567Swnj case TREXMTTL: /* retransmit too long */ 4194567Swnj if (tp->t_rtl_val > tp->snd_una) /* 36 */ 4204567Swnj to_user(tp->t_ucb, URXTIMO); 4214567Swnj /* 4224567Swnj * If user has already closed, abort the connection. 4234567Swnj */ 4244576Swnj if (tp->tc_flags & TC_USR_CLOSED) { 4254676Swnj tcp_close(tp, URXTIMO); 4264567Swnj return (CLOSED); 4274567Swnj } 4284567Swnj return (SAME); 4294497Swnj 4304567Swnj case TPERSIST: /* persist timer */ 4314567Swnj /* 4324567Swnj * Force a byte send through closed window. 4334567Swnj */ 4344576Swnj tp->tc_flags |= TC_FORCE_ONE; 4354678Swnj tcp_send(tp); 4364567Swnj return (SAME); 4374567Swnj } 4384567Swnj panic("tcp_timers"); 4394497Swnj } 4404497Swnj 4414567Swnj /* THIS ROUTINE IS A CROCK */ 4424567Swnj to_user(up, state) 4434567Swnj register struct ucb *up; 4444567Swnj register short state; 4454497Swnj { 4464567Swnj COUNT(TO_USER); 4474497Swnj 4484567Swnj up->uc_state |= state; 4494567Swnj netwakeup(up); 4504567Swnj if (state == UURGENT) 4514567Swnj psignal(up->uc_proc, SIGURG); 4524497Swnj } 4534584Swnj 4544584Swnj #ifdef TCPDEBUG 4554682Swnj /* 4564682Swnj * TCP debugging utility subroutines. 4574682Swnj * THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID. 4584682Swnj */ 4594670Swnj tdb_setup(tp, n, input, tdp) 4604670Swnj struct tcb *tp; 4614670Swnj register struct th *n; 4624670Swnj int input; 4634670Swnj register struct tcp_debug *tdp; 4644670Swnj { 4654670Swnj 4664682Swnj COUNT(TDB_SETUP); 4674670Swnj tdp->td_tod = time; 4684670Swnj tdp->td_tcb = tp; 4694670Swnj tdp->td_old = tp->t_state; 4704670Swnj tdp->td_inp = input; 4714670Swnj tdp->td_tim = 0; 4724670Swnj tdp->td_new = -1; 4734670Swnj if (n) { 4744670Swnj tdp->td_sno = n->t_seq; 4754670Swnj tdp->td_ano = n->t_ackno; 4764670Swnj tdp->td_wno = n->t_win; 4774670Swnj tdp->td_lno = n->t_len; 4784670Swnj tdp->td_flg = n->th_flags; 4794670Swnj } else 4804670Swnj tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno = 4814670Swnj tdp->td_flg = 0; 4824670Swnj } 4834670Swnj 4844670Swnj tdb_stuff(tdp, nstate) 4854670Swnj struct tcp_debug *tdp; 4864670Swnj int nstate; 4874670Swnj { 4884682Swnj COUNT(TDB_STUFF); 4894670Swnj 4904670Swnj tdp->td_new = nstate; 4914670Swnj tcp_debug[tdbx++ % TDBSIZE] = *tdp; 4924670Swnj if (tcpconsdebug & 2) 4934670Swnj tcp_prt(tdp); 4944670Swnj } 4954682Swnj 4964682Swnj /* BETTER VERSION OF THIS ROUTINE? */ 4974682Swnj tcp_prt(tdp) 4984682Swnj register struct tcp_debug *tdp; 4994682Swnj { 5004682Swnj COUNT(TCP_PRT); 5014682Swnj 5024682Swnj printf("TCP(%x) %s x %s", 5034682Swnj tdp->td_tcb, tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]); 5044682Swnj if (tdp->td_inp == ISTIMER) 5054682Swnj printf("(%s)", tcptimers[tdp->td_tim]); 5064682Swnj printf(" --> %s", 5074682Swnj tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]); 5084682Swnj /* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */ 5094682Swnj if (tdp->td_new < 0) 5104682Swnj printf(" (FAILED)"); 5114682Swnj if (tdp->td_sno) { 5124682Swnj printf(" sno %x ano %x win %d len %d flags %x", 5134682Swnj tdp->td_sno, tdp->td_ano, tdp->td_wno, 5144682Swnj tdp->td_lno, tdp->td_flg); 5154682Swnj } 5164682Swnj printf("\n"); 5174682Swnj } 5184670Swnj #endif 519