1*4657Swnj /* tcp_usrreq.c 1.13 81/10/29 */ 24567Swnj 34497Swnj #include "../h/param.h" 44567Swnj #include "../h/systm.h" 54497Swnj #include "../bbnnet/net.h" 64574Swnj #include "../bbnnet/mbuf.h" 74497Swnj #include "../bbnnet/tcp.h" 84497Swnj #include "../bbnnet/ip.h" 94497Swnj #include "../bbnnet/imp.h" 104497Swnj #include "../bbnnet/ucb.h" 114567Swnj #define TCPFSTAB 124584Swnj #ifdef TCPDEBUG 134584Swnj #define TCPSTATES 144584Swnj #endif 154497Swnj #include "../bbnnet/fsm.h" 164497Swnj 174567Swnj tcp_timeo() 184497Swnj { 194567Swnj register struct tcb *tp; 204567Swnj int s = splnet(); 214567Swnj COUNT(TCP_TIMEO); 224497Swnj 234567Swnj /* 244567Swnj * Search through tcb's and update active timers. 254567Swnj */ 264567Swnj for (tp = netcb.n_tcb_head; tp != NULL; tp = tp->t_tcb_next) { 274567Swnj if (tp->t_init != 0 && --tp->t_init == 0) 284567Swnj tcp_usrreq(ISTIMER, TINIT, tp, 0); 294567Swnj if (tp->t_rexmt != 0 && --tp->t_rexmt == 0) 304567Swnj tcp_usrreq(ISTIMER, TREXMT, tp, 0); 314567Swnj if (tp->t_rexmttl != 0 && --tp->t_rexmttl == 0) 324567Swnj tcp_usrreq(ISTIMER, TREXMTTL, tp, 0); 334567Swnj if (tp->t_persist != 0 && --tp->t_persist == 0) 344567Swnj tcp_usrreq(ISTIMER, TPERSIST, tp, 0); 354567Swnj if (tp->t_finack != 0 && --tp->t_finack == 0) 364567Swnj tcp_usrreq(ISTIMER, TFINACK, tp, 0); 374567Swnj tp->t_xmt++; 384567Swnj } 394567Swnj netcb.n_iss += ISSINCR; /* increment iss */ 404567Swnj timeout(tcp_timeo, 0, hz); /* reschedule every second */ 414567Swnj splx(s); 424497Swnj } 434497Swnj 444584Swnj tcp_usrreq(input, timertype, tp, mp) 454584Swnj int input, timertype; 464567Swnj register struct tcb *tp; 474584Swnj struct mbuf *mp; 484497Swnj { 494567Swnj int s = splnet(); 504567Swnj register int nstate; 514584Swnj #ifdef TCPDEBUG 524584Swnj struct tcp_debug tdb; 534584Swnj #endif 544567Swnj COUNT(TCP_USRREQ); 554497Swnj 564567Swnj nstate = tp->t_state; 574576Swnj tp->tc_flags &= ~TC_NET_KEEP; 584567Swnj acounts[nstate][input]++; 594584Swnj #ifdef TCPDEBUG 604584Swnj if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) { 614605Swnj tdb_setup(tp, (struct th *)0, input, &tdb); 624584Swnj tdb.td_tim = timertype; 634584Swnj } else 644584Swnj tdb.td_tod = 0; 654584Swnj #endif 664567Swnj switch (tcp_fstab[nstate][input]) { 674497Swnj 684567Swnj default: 694567Swnj printf("tcp: bad state: tcb=%x state=%d input=%d\n", 704567Swnj tp, tp->t_state, input); 714567Swnj nstate = EFAILEC; 724567Swnj break; 734497Swnj 744567Swnj case LIS_CLS: /* 1 */ 754567Swnj t_open(tp, PASSIVE); 764567Swnj nstate = LISTEN; 774567Swnj break; 784497Swnj 794567Swnj case SYS_CLS: /* 2 */ 804567Swnj t_open(tp, ACTIVE); 814567Swnj send_ctl(tp); 824567Swnj nstate = SYN_SENT; 834567Swnj break; 844497Swnj 854567Swnj case CLS_OPN: /* 10 */ 864567Swnj t_close(tp, UCLOSED); 874567Swnj nstate = CLOSED; 884567Swnj break; 894497Swnj 904567Swnj case CL2_CLW: /* 10 */ 914576Swnj tp->tc_flags |= TC_SND_FIN; 924567Swnj send_ctl(tp); 934576Swnj tp->tc_flags |= TC_USR_CLOSED; 944567Swnj nstate = CLOSING2; 954567Swnj break; 964497Swnj 974567Swnj case TIMERS: /* 14,17,34,35,36,37,38 */ 984584Swnj nstate = tcp_timers(tp, timertype); 994567Swnj break; 1004497Swnj 1014567Swnj case CLS_RWT: /* 20 */ 1024567Swnj present_data(tp); 1034567Swnj if (rcv_empty(tp)) { 1044567Swnj t_close(tp, UCLOSED); 1054567Swnj nstate = CLOSED; 1064567Swnj } else 1074567Swnj nstate = RCV_WAIT; 1084567Swnj break; 1094497Swnj 1104567Swnj case FW1_SYR: /* 24,25 */ 1114576Swnj tp->tc_flags |= TC_SND_FIN; 1124567Swnj send_ctl(tp); 1134576Swnj tp->tc_flags |= TC_USR_CLOSED; 1144567Swnj nstate = FIN_W1; 1154567Swnj break; 1164567Swnj 1174567Swnj case SSS_SND: /* 40,41 */ 1184602Swnj nstate = sss_send(tp, mp); 1194567Swnj break; 1204567Swnj 1214567Swnj case SSS_RCV: /* 42 */ 1224567Swnj send_ctl(tp); /* send new window */ 1234567Swnj present_data(tp); 1244567Swnj break; 1254567Swnj 1264567Swnj case CLS_NSY: /* 44 */ 1274567Swnj t_close(tp, UABORT); 1284567Swnj nstate = CLOSED; 1294567Swnj break; 1304567Swnj 1314567Swnj case CLS_SYN: /* 45 */ 1324576Swnj tp->tc_flags |= TC_SND_RST; 1334567Swnj send_null(tp); 1344567Swnj t_close(tp, UABORT); 1354567Swnj nstate = CLOSED; 1364567Swnj break; 1374567Swnj 1384567Swnj case CLS_ACT: /* 47 */ 1394567Swnj t_close(tp, UNETDWN); 1404567Swnj nstate = CLOSED; 1414567Swnj break; 1424567Swnj 1434567Swnj case NOP: 1444567Swnj break; 1454567Swnj 1464567Swnj case CLS_ERR: 1474567Swnj to_user(tp->t_ucb, UCLSERR); 1484567Swnj break; 1494567Swnj } 1504567Swnj #ifdef TCPDEBUG 1514605Swnj if (tdb.td_tod) 1524605Swnj tdb_stuff(&tdb, nstate); 1534567Swnj #endif 1544567Swnj /* YECH */ 1554567Swnj switch (nstate) { 1564567Swnj 1574584Swnj case CLOSED: 1584567Swnj case SAME: 1594567Swnj break; 1604567Swnj 1614567Swnj case EFAILEC: 1624584Swnj if (mp) 1634584Swnj m_freem(dtom(mp)); 1644567Swnj break; 1654567Swnj 1664567Swnj default: 1674567Swnj tp->t_state = nstate; 1684567Swnj break; 1694567Swnj } 1704567Swnj splx(s); 1714497Swnj } 1724497Swnj 1734567Swnj t_open(tp, mode) /* set up a tcb for a connection */ 1744567Swnj register struct tcb *tp; 1754567Swnj int mode; 1764497Swnj { 1774567Swnj register struct ucb *up; 1784567Swnj COUNT(T_OPEN); 1794497Swnj 1804567Swnj /* enqueue the tcb */ 1814497Swnj 1824567Swnj if (netcb.n_tcb_head == NULL) { 1834567Swnj netcb.n_tcb_head = tp; 1844567Swnj netcb.n_tcb_tail = tp; 1854567Swnj } else { 1864567Swnj tp->t_tcb_next = netcb.n_tcb_head; 1874567Swnj netcb.n_tcb_head->t_tcb_prev = tp; 1884567Swnj netcb.n_tcb_head = tp; 1894567Swnj } 1904497Swnj 1914567Swnj /* initialize non-zero tcb fields */ 1924497Swnj 1934567Swnj tp->t_rcv_next = (struct th *)tp; 1944567Swnj tp->t_rcv_prev = (struct th *)tp; 1954567Swnj tp->t_xmtime = T_REXMT; 1964567Swnj tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = 1974567Swnj tp->snd_una = tp->iss = netcb.n_iss; 1984567Swnj tp->snd_off = tp->iss + 1; 1994567Swnj netcb.n_iss += (ISSINCR >> 1) + 1; 2004567Swnj 2014567Swnj /* set timeout for open */ 2024567Swnj 2034567Swnj up = tp->t_ucb; 2044567Swnj tp->t_init = (up->uc_timeo != 0 ? up->uc_timeo : 2054567Swnj (mode == ACTIVE ? T_INIT : 0)); 2064567Swnj up->uc_timeo = 0; /* overlays uc_ssize */ 2074497Swnj } 2084497Swnj 2094567Swnj t_close(tp, state) 2104567Swnj register struct tcb *tp; 2114567Swnj short state; 2124497Swnj { 2134567Swnj register struct ucb *up; 2144567Swnj register struct th *t; 2154567Swnj register struct mbuf *m; 2164567Swnj COUNT(T_CLOSE); 2174497Swnj 2184567Swnj up = tp->t_ucb; 2194497Swnj 2204567Swnj tp->t_init = tp->t_rexmt = tp->t_rexmttl = tp->t_persist = 2214567Swnj tp->t_finack = 0; 2224497Swnj 2234567Swnj /* delete tcb */ 2244567Swnj 2254567Swnj if (tp->t_tcb_prev == NULL) 2264567Swnj netcb.n_tcb_head = tp->t_tcb_next; 2274567Swnj else 2284567Swnj tp->t_tcb_prev->t_tcb_next = tp->t_tcb_next; 2294567Swnj if (tp->t_tcb_next == NULL) 2304567Swnj netcb.n_tcb_tail = tp->t_tcb_prev; 2314567Swnj else 2324567Swnj tp->t_tcb_next->t_tcb_prev = tp->t_tcb_prev; 2334567Swnj 2344567Swnj /* free all data on receive and send buffers */ 2354567Swnj 2364567Swnj for (t = tp->t_rcv_next; t != (struct th *)tp; t = t->t_next) 2374567Swnj m_freem(dtom(t)); 2384567Swnj 2394567Swnj if (up->uc_rbuf != NULL) { 2404567Swnj m_freem(up->uc_rbuf); 2414567Swnj up->uc_rbuf = NULL; 2424567Swnj } 243*4657Swnj up->uc_rcc = 0; 2444567Swnj if (up->uc_sbuf != NULL) { 2454567Swnj m_freem(up->uc_sbuf); 2464567Swnj up->uc_sbuf = NULL; 2474567Swnj } 2484592Swnj up->uc_ssize = 0; 2494567Swnj for (m = tp->t_rcv_unack; m != NULL; m = m->m_act) { 2504567Swnj m_freem(m); 2514567Swnj tp->t_rcv_unack = NULL; 2524567Swnj } 2534588Swnj m = dtom(tp); 2544588Swnj m->m_off = 0; 2554588Swnj m_free(m); 2564567Swnj up->uc_tcb = NULL; 2574567Swnj 2584567Swnj /* lower buffer allocation and decrement host entry */ 2594567Swnj 260*4657Swnj netcb.n_lowat -= up->uc_snd + (up->uc_rhiwat/MSIZE) + 2; 2614567Swnj netcb.n_hiwat = 2 * netcb.n_lowat; 2624567Swnj if (up->uc_host != NULL) { 2634567Swnj h_free(up->uc_host); 2644567Swnj up->uc_host = NULL; 2654567Swnj } 2664567Swnj 2674567Swnj /* if user has initiated close (via close call), delete ucb 2684567Swnj entry, otherwise just wakeup so user can issue close call */ 2694567Swnj 2704576Swnj if (tp->tc_flags&TC_USR_ABORT) 2714567Swnj up->uc_proc = NULL; 2724567Swnj else 2734567Swnj to_user(up, state); 2744497Swnj } 2754497Swnj 2764602Swnj sss_send(tp, m0) 2774584Swnj register struct tcb *tp; 2784584Swnj struct mbuf *m0; 2794497Swnj { 2804497Swnj register struct mbuf *m, *n; 2814584Swnj register struct ucb *up = tp->t_ucb; 2824497Swnj register off; 2834574Swnj seq_t last; 2844602Swnj COUNT(SSS_SEND); 2854497Swnj 2864497Swnj last = tp->snd_off; 2874584Swnj for (m = n = m0; m != NULL; m = m->m_next) { 2884497Swnj up->uc_ssize++; 2894591Swnj if (m->m_off > MMAXOFF) 2904588Swnj up->uc_ssize += NMBPG; 2914497Swnj last += m->m_len; 2924497Swnj } 2934588Swnj if ((m = up->uc_sbuf) == NULL) 2944588Swnj up->uc_sbuf = n; 2954588Swnj else { 2964588Swnj while (m->m_next != NULL) { 2974497Swnj m = m->m_next; 2984497Swnj last += m->m_len; 2994497Swnj } 3004591Swnj if (m->m_off <= MMAXOFF) { 3014588Swnj last += m->m_len; 3024588Swnj off = m->m_off + m->m_len; 3034591Swnj while (n && n->m_off <= MMAXOFF && 3044591Swnj (MMAXOFF - off) >= n->m_len) { 3054588Swnj bcopy((caddr_t)((int)n + n->m_off), 3064588Swnj (caddr_t)((int)m + off), n->m_len); 3074588Swnj m->m_len += n->m_len; 3084588Swnj off += n->m_len; 3094588Swnj up->uc_ssize--; 3104588Swnj n = m_free(n); 3114588Swnj } 3124497Swnj } 3134497Swnj m->m_next = n; 3144588Swnj } 3154588Swnj if (up->uc_flags & UEOL) 3164497Swnj tp->snd_end = last; 3174588Swnj if (up->uc_flags & UURG) { 3184497Swnj tp->snd_urp = last+1; 3194576Swnj tp->tc_flags |= TC_SND_URG; 3204567Swnj } 3214497Swnj send(tp); 3224567Swnj return (SAME); 3234497Swnj } 3244497Swnj 3254584Swnj tcp_timers(tp, timertype) 3264584Swnj register struct tcb *tp; 3274584Swnj int timertype; 3284497Swnj { 3294497Swnj 3304567Swnj COUNT(TCP_TIMERS); 3314584Swnj switch (timertype) { 3324497Swnj 3334567Swnj case TINIT: /* initialization timer */ 3344576Swnj if ((tp->tc_flags&TC_SYN_ACKED) == 0) { /* 35 */ 3354567Swnj t_close(tp, UINTIMO); 3364567Swnj return (CLOSED); 3374567Swnj } 3384567Swnj return (SAME); 3394497Swnj 3404567Swnj case TFINACK: /* fin-ack timer */ 3414567Swnj switch (tp->t_state) { 3424497Swnj 3434567Swnj case TIME_WAIT: 3444567Swnj /* 3454567Swnj * We can be sure our ACK of foreign FIN was rcvd, 3464567Swnj * and can close if no data left for user. 3474567Swnj */ 3484567Swnj if (rcv_empty(tp)) { 3494567Swnj t_close(tp, UCLOSED); /* 14 */ 3504567Swnj return (CLOSED); 3514567Swnj } 3524567Swnj return (RCV_WAIT); /* 17 */ 3534497Swnj 3544567Swnj case CLOSING1: 3554576Swnj tp->tc_flags |= TC_WAITED_2_ML; 3564567Swnj return (SAME); 3574497Swnj 3584567Swnj default: 3594567Swnj return (SAME); 3604567Swnj } 3614497Swnj 3624567Swnj case TREXMT: /* retransmission timer */ 3634567Swnj if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ 3644567Swnj /* 3654567Swnj * Set up for a retransmission, increase rexmt time 3664567Swnj * in case of multiple retransmissions. 3674567Swnj */ 3684567Swnj tp->snd_nxt = tp->snd_una; 3694576Swnj tp->tc_flags |= TC_REXMT; 3704567Swnj tp->t_xmtime = tp->t_xmtime << 1; 3714567Swnj if (tp->t_xmtime > T_REMAX) 3724567Swnj tp->t_xmtime = T_REMAX; 3734567Swnj send(tp); 3744567Swnj } 3754567Swnj return (SAME); 3764497Swnj 3774567Swnj case TREXMTTL: /* retransmit too long */ 3784567Swnj if (tp->t_rtl_val > tp->snd_una) /* 36 */ 3794567Swnj to_user(tp->t_ucb, URXTIMO); 3804567Swnj /* 3814567Swnj * If user has already closed, abort the connection. 3824567Swnj */ 3834576Swnj if (tp->tc_flags & TC_USR_CLOSED) { 3844567Swnj t_close(tp, URXTIMO); 3854567Swnj return (CLOSED); 3864567Swnj } 3874567Swnj return (SAME); 3884497Swnj 3894567Swnj case TPERSIST: /* persist timer */ 3904567Swnj /* 3914567Swnj * Force a byte send through closed window. 3924567Swnj */ 3934576Swnj tp->tc_flags |= TC_FORCE_ONE; 3944567Swnj send(tp); 3954567Swnj return (SAME); 3964567Swnj } 3974567Swnj panic("tcp_timers"); 3984497Swnj } 3994497Swnj 4004567Swnj /* THIS ROUTINE IS A CROCK */ 4014567Swnj to_user(up, state) 4024567Swnj register struct ucb *up; 4034567Swnj register short state; 4044497Swnj { 4054567Swnj COUNT(TO_USER); 4064497Swnj 4074567Swnj up->uc_state |= state; 4084567Swnj netwakeup(up); 4094567Swnj if (state == UURGENT) 4104567Swnj psignal(up->uc_proc, SIGURG); 4114497Swnj } 4124584Swnj 4134584Swnj #ifdef TCPDEBUG 4144584Swnj tcp_prt(tdp) 4154584Swnj register struct tcp_debug *tdp; 4164584Swnj { 4174584Swnj COUNT(TCP_PRT); 4184584Swnj 4194605Swnj printf("TCP(%x) %s x %s", 4204584Swnj tdp->td_tcb, tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]); 4214584Swnj if (tdp->td_inp == ISTIMER) 4224584Swnj printf("(%s)", tcptimers[tdp->td_tim]); 4234584Swnj printf(" --> %s", 4244584Swnj tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]); 4254584Swnj /* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */ 4264584Swnj if (tdp->td_new < 0) 4274584Swnj printf(" (FAILED)"); 4284605Swnj if (tdp->td_sno) { 4294605Swnj printf(" sno %x ano %x win %d len %d flags %x", 4304605Swnj tdp->td_sno, tdp->td_ano, tdp->td_wno, tdp->td_lno, tdp->td_flg); 4314605Swnj } 4324584Swnj printf("\n"); 4334584Swnj } 4344584Swnj #endif 435