1*4664Swnj /* tcp_usrreq.c 1.14 81/10/29 */ 24567Swnj 34497Swnj #include "../h/param.h" 44567Swnj #include "../h/systm.h" 5*4664Swnj #include "../h/mbuf.h" 6*4664Swnj #include "../h/socket.h" 7*4664Swnj #include "../inet/inet.h" 8*4664Swnj #include "../inet/inet_systm.h" 9*4664Swnj #include "../inet/imp.h" 10*4664Swnj #include "../inet/ip.h" 11*4664Swnj #include "../inet/tcp.h" 124567Swnj #define TCPFSTAB 134584Swnj #ifdef TCPDEBUG 144584Swnj #define TCPSTATES 154584Swnj #endif 16*4664Swnj #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 */ 27*4664Swnj for (tp = tcb_head; tp != NULL; tp = tp->t_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 } 40*4664Swnj 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 */ 764567Swnj t_open(tp, PASSIVE); 774567Swnj nstate = LISTEN; 784567Swnj break; 794497Swnj 804567Swnj case SYS_CLS: /* 2 */ 814567Swnj t_open(tp, ACTIVE); 824567Swnj send_ctl(tp); 834567Swnj nstate = SYN_SENT; 844567Swnj break; 854497Swnj 864567Swnj case CLS_OPN: /* 10 */ 874567Swnj t_close(tp, UCLOSED); 884567Swnj nstate = CLOSED; 894567Swnj break; 904497Swnj 914567Swnj case CL2_CLW: /* 10 */ 924576Swnj tp->tc_flags |= TC_SND_FIN; 934567Swnj send_ctl(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 */ 1034567Swnj present_data(tp); 1044567Swnj if (rcv_empty(tp)) { 1054567Swnj t_close(tp, UCLOSED); 1064567Swnj nstate = CLOSED; 1074567Swnj } else 1084567Swnj nstate = RCV_WAIT; 1094567Swnj break; 1104497Swnj 1114567Swnj case FW1_SYR: /* 24,25 */ 1124576Swnj tp->tc_flags |= TC_SND_FIN; 1134567Swnj send_ctl(tp); 1144576Swnj tp->tc_flags |= TC_USR_CLOSED; 1154567Swnj nstate = FIN_W1; 1164567Swnj break; 1174567Swnj 1184567Swnj case SSS_SND: /* 40,41 */ 1194602Swnj nstate = sss_send(tp, mp); 1204567Swnj break; 1214567Swnj 1224567Swnj case SSS_RCV: /* 42 */ 1234567Swnj send_ctl(tp); /* send new window */ 1244567Swnj present_data(tp); 1254567Swnj break; 1264567Swnj 1274567Swnj case CLS_NSY: /* 44 */ 1284567Swnj t_close(tp, UABORT); 1294567Swnj nstate = CLOSED; 1304567Swnj break; 1314567Swnj 1324567Swnj case CLS_SYN: /* 45 */ 1334576Swnj tp->tc_flags |= TC_SND_RST; 1344567Swnj send_null(tp); 1354567Swnj t_close(tp, UABORT); 1364567Swnj nstate = CLOSED; 1374567Swnj break; 1384567Swnj 1394567Swnj case CLS_ACT: /* 47 */ 1404567Swnj t_close(tp, UNETDWN); 1414567Swnj nstate = CLOSED; 1424567Swnj break; 1434567Swnj 1444567Swnj case NOP: 1454567Swnj break; 1464567Swnj 1474567Swnj case CLS_ERR: 1484567Swnj to_user(tp->t_ucb, UCLSERR); 1494567Swnj break; 1504567Swnj } 1514567Swnj #ifdef TCPDEBUG 1524605Swnj if (tdb.td_tod) 1534605Swnj tdb_stuff(&tdb, nstate); 1544567Swnj #endif 1554567Swnj /* YECH */ 1564567Swnj switch (nstate) { 1574567Swnj 1584584Swnj case CLOSED: 1594567Swnj case SAME: 1604567Swnj break; 1614567Swnj 1624567Swnj case EFAILEC: 1634584Swnj if (mp) 1644584Swnj m_freem(dtom(mp)); 1654567Swnj break; 1664567Swnj 1674567Swnj default: 1684567Swnj tp->t_state = nstate; 1694567Swnj break; 1704567Swnj } 1714567Swnj splx(s); 1724497Swnj } 1734497Swnj 1744567Swnj t_open(tp, mode) /* set up a tcb for a connection */ 1754567Swnj register struct tcb *tp; 1764567Swnj int mode; 1774497Swnj { 1784567Swnj register struct ucb *up; 1794567Swnj COUNT(T_OPEN); 1804497Swnj 1814567Swnj /* enqueue the tcb */ 1824497Swnj 183*4664Swnj if (tcb_head == NULL) { 184*4664Swnj tcb_head = tp; 185*4664Swnj tcb_tail = tp; 1864567Swnj } else { 187*4664Swnj tp->t_tcb_next = tcb_head; 188*4664Swnj tcb_head->t_tcb_prev = tp; 189*4664Swnj tcb_head = tp; 1904567Swnj } 1914497Swnj 1924567Swnj /* initialize non-zero tcb fields */ 1934497Swnj 1944567Swnj tp->t_rcv_next = (struct th *)tp; 1954567Swnj tp->t_rcv_prev = (struct th *)tp; 1964567Swnj tp->t_xmtime = T_REXMT; 1974567Swnj tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = 198*4664Swnj tp->snd_una = tp->iss = tcp_iss; 1994567Swnj tp->snd_off = tp->iss + 1; 200*4664Swnj tcp_iss += (ISSINCR >> 1) + 1; 2014567Swnj 2024567Swnj /* set timeout for open */ 2034567Swnj 2044567Swnj up = tp->t_ucb; 2054567Swnj tp->t_init = (up->uc_timeo != 0 ? up->uc_timeo : 2064567Swnj (mode == ACTIVE ? T_INIT : 0)); 2074567Swnj up->uc_timeo = 0; /* overlays uc_ssize */ 2084497Swnj } 2094497Swnj 2104567Swnj t_close(tp, state) 2114567Swnj register struct tcb *tp; 2124567Swnj short state; 2134497Swnj { 2144567Swnj register struct ucb *up; 2154567Swnj register struct th *t; 2164567Swnj register struct mbuf *m; 2174567Swnj COUNT(T_CLOSE); 2184497Swnj 2194567Swnj up = tp->t_ucb; 2204497Swnj 2214567Swnj tp->t_init = tp->t_rexmt = tp->t_rexmttl = tp->t_persist = 2224567Swnj tp->t_finack = 0; 2234497Swnj 2244567Swnj /* delete tcb */ 2254567Swnj 2264567Swnj if (tp->t_tcb_prev == NULL) 227*4664Swnj tcb_head = tp->t_tcb_next; 2284567Swnj else 2294567Swnj tp->t_tcb_prev->t_tcb_next = tp->t_tcb_next; 2304567Swnj if (tp->t_tcb_next == NULL) 231*4664Swnj tcb_tail = tp->t_tcb_prev; 2324567Swnj else 2334567Swnj tp->t_tcb_next->t_tcb_prev = tp->t_tcb_prev; 2344567Swnj 2354567Swnj /* free all data on receive and send buffers */ 2364567Swnj 2374567Swnj for (t = tp->t_rcv_next; t != (struct th *)tp; t = t->t_next) 2384567Swnj m_freem(dtom(t)); 2394567Swnj 2404567Swnj if (up->uc_rbuf != NULL) { 2414567Swnj m_freem(up->uc_rbuf); 2424567Swnj up->uc_rbuf = NULL; 2434567Swnj } 2444657Swnj up->uc_rcc = 0; 2454567Swnj if (up->uc_sbuf != NULL) { 2464567Swnj m_freem(up->uc_sbuf); 2474567Swnj up->uc_sbuf = NULL; 2484567Swnj } 2494592Swnj up->uc_ssize = 0; 2504567Swnj for (m = tp->t_rcv_unack; m != NULL; m = m->m_act) { 2514567Swnj m_freem(m); 2524567Swnj tp->t_rcv_unack = NULL; 2534567Swnj } 254*4664Swnj if (up->uc_template) { 255*4664Swnj m_free(dtom(up->uc_template)); 256*4664Swnj up->uc_template = 0; 257*4664Swnj } 2584588Swnj m = dtom(tp); 2594588Swnj m->m_off = 0; 2604588Swnj m_free(m); 2614567Swnj up->uc_tcb = NULL; 2624567Swnj 2634567Swnj /* lower buffer allocation and decrement host entry */ 2644567Swnj 265*4664Swnj mbstat.m_lowat -= up->uc_snd + (up->uc_rhiwat/MSIZE) + 2; 266*4664Swnj mbstat.m_hiwat = 2 * mbstat.m_lowat; 2674567Swnj if (up->uc_host != NULL) { 2684567Swnj h_free(up->uc_host); 2694567Swnj up->uc_host = NULL; 2704567Swnj } 2714567Swnj 2724567Swnj /* if user has initiated close (via close call), delete ucb 2734567Swnj entry, otherwise just wakeup so user can issue close call */ 2744567Swnj 2754576Swnj if (tp->tc_flags&TC_USR_ABORT) 2764567Swnj up->uc_proc = NULL; 2774567Swnj else 2784567Swnj to_user(up, state); 2794497Swnj } 2804497Swnj 2814602Swnj sss_send(tp, m0) 2824584Swnj register struct tcb *tp; 2834584Swnj struct mbuf *m0; 2844497Swnj { 2854497Swnj register struct mbuf *m, *n; 2864584Swnj register struct ucb *up = tp->t_ucb; 2874497Swnj register off; 2884574Swnj seq_t last; 2894602Swnj COUNT(SSS_SEND); 2904497Swnj 2914497Swnj last = tp->snd_off; 2924584Swnj for (m = n = m0; m != NULL; m = m->m_next) { 2934497Swnj up->uc_ssize++; 2944591Swnj if (m->m_off > MMAXOFF) 2954588Swnj up->uc_ssize += NMBPG; 2964497Swnj last += m->m_len; 2974497Swnj } 2984588Swnj if ((m = up->uc_sbuf) == NULL) 2994588Swnj up->uc_sbuf = n; 3004588Swnj else { 3014588Swnj while (m->m_next != NULL) { 3024497Swnj m = m->m_next; 3034497Swnj last += m->m_len; 3044497Swnj } 3054591Swnj if (m->m_off <= MMAXOFF) { 3064588Swnj last += m->m_len; 3074588Swnj off = m->m_off + m->m_len; 3084591Swnj while (n && n->m_off <= MMAXOFF && 3094591Swnj (MMAXOFF - off) >= n->m_len) { 3104588Swnj bcopy((caddr_t)((int)n + n->m_off), 3114588Swnj (caddr_t)((int)m + off), n->m_len); 3124588Swnj m->m_len += n->m_len; 3134588Swnj off += n->m_len; 3144588Swnj up->uc_ssize--; 3154588Swnj n = m_free(n); 3164588Swnj } 3174497Swnj } 3184497Swnj m->m_next = n; 3194588Swnj } 3204588Swnj if (up->uc_flags & UEOL) 3214497Swnj tp->snd_end = last; 3224588Swnj if (up->uc_flags & UURG) { 3234497Swnj tp->snd_urp = last+1; 3244576Swnj tp->tc_flags |= TC_SND_URG; 3254567Swnj } 3264497Swnj send(tp); 3274567Swnj return (SAME); 3284497Swnj } 3294497Swnj 3304584Swnj tcp_timers(tp, timertype) 3314584Swnj register struct tcb *tp; 3324584Swnj int timertype; 3334497Swnj { 3344497Swnj 3354567Swnj COUNT(TCP_TIMERS); 3364584Swnj switch (timertype) { 3374497Swnj 3384567Swnj case TINIT: /* initialization timer */ 3394576Swnj if ((tp->tc_flags&TC_SYN_ACKED) == 0) { /* 35 */ 3404567Swnj t_close(tp, UINTIMO); 3414567Swnj return (CLOSED); 3424567Swnj } 3434567Swnj return (SAME); 3444497Swnj 3454567Swnj case TFINACK: /* fin-ack timer */ 3464567Swnj switch (tp->t_state) { 3474497Swnj 3484567Swnj case TIME_WAIT: 3494567Swnj /* 3504567Swnj * We can be sure our ACK of foreign FIN was rcvd, 3514567Swnj * and can close if no data left for user. 3524567Swnj */ 3534567Swnj if (rcv_empty(tp)) { 3544567Swnj t_close(tp, UCLOSED); /* 14 */ 3554567Swnj return (CLOSED); 3564567Swnj } 3574567Swnj return (RCV_WAIT); /* 17 */ 3584497Swnj 3594567Swnj case CLOSING1: 3604576Swnj tp->tc_flags |= TC_WAITED_2_ML; 3614567Swnj return (SAME); 3624497Swnj 3634567Swnj default: 3644567Swnj return (SAME); 3654567Swnj } 3664497Swnj 3674567Swnj case TREXMT: /* retransmission timer */ 3684567Swnj if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ 3694567Swnj /* 3704567Swnj * Set up for a retransmission, increase rexmt time 3714567Swnj * in case of multiple retransmissions. 3724567Swnj */ 3734567Swnj tp->snd_nxt = tp->snd_una; 3744576Swnj tp->tc_flags |= TC_REXMT; 3754567Swnj tp->t_xmtime = tp->t_xmtime << 1; 3764567Swnj if (tp->t_xmtime > T_REMAX) 3774567Swnj tp->t_xmtime = T_REMAX; 3784567Swnj send(tp); 3794567Swnj } 3804567Swnj return (SAME); 3814497Swnj 3824567Swnj case TREXMTTL: /* retransmit too long */ 3834567Swnj if (tp->t_rtl_val > tp->snd_una) /* 36 */ 3844567Swnj to_user(tp->t_ucb, URXTIMO); 3854567Swnj /* 3864567Swnj * If user has already closed, abort the connection. 3874567Swnj */ 3884576Swnj if (tp->tc_flags & TC_USR_CLOSED) { 3894567Swnj t_close(tp, URXTIMO); 3904567Swnj return (CLOSED); 3914567Swnj } 3924567Swnj return (SAME); 3934497Swnj 3944567Swnj case TPERSIST: /* persist timer */ 3954567Swnj /* 3964567Swnj * Force a byte send through closed window. 3974567Swnj */ 3984576Swnj tp->tc_flags |= TC_FORCE_ONE; 3994567Swnj send(tp); 4004567Swnj return (SAME); 4014567Swnj } 4024567Swnj panic("tcp_timers"); 4034497Swnj } 4044497Swnj 4054567Swnj /* THIS ROUTINE IS A CROCK */ 4064567Swnj to_user(up, state) 4074567Swnj register struct ucb *up; 4084567Swnj register short state; 4094497Swnj { 4104567Swnj COUNT(TO_USER); 4114497Swnj 4124567Swnj up->uc_state |= state; 4134567Swnj netwakeup(up); 4144567Swnj if (state == UURGENT) 4154567Swnj psignal(up->uc_proc, SIGURG); 4164497Swnj } 4174584Swnj 4184584Swnj #ifdef TCPDEBUG 4194584Swnj tcp_prt(tdp) 4204584Swnj register struct tcp_debug *tdp; 4214584Swnj { 4224584Swnj COUNT(TCP_PRT); 4234584Swnj 4244605Swnj printf("TCP(%x) %s x %s", 4254584Swnj tdp->td_tcb, tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]); 4264584Swnj if (tdp->td_inp == ISTIMER) 4274584Swnj printf("(%s)", tcptimers[tdp->td_tim]); 4284584Swnj printf(" --> %s", 4294584Swnj tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]); 4304584Swnj /* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */ 4314584Swnj if (tdp->td_new < 0) 4324584Swnj printf(" (FAILED)"); 4334605Swnj if (tdp->td_sno) { 4344605Swnj printf(" sno %x ano %x win %d len %d flags %x", 4354605Swnj tdp->td_sno, tdp->td_ano, tdp->td_wno, tdp->td_lno, tdp->td_flg); 4364605Swnj } 4374584Swnj printf("\n"); 4384584Swnj } 4394584Swnj #endif 440