1*4584Swnj /* tcp_usrreq.c 1.7 81/10/22 */ 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 12*4584Swnj #ifdef TCPDEBUG 13*4584Swnj #define TCPSTATES 14*4584Swnj #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 44*4584Swnj tcp_usrreq(input, timertype, tp, mp) 45*4584Swnj int input, timertype; 464567Swnj register struct tcb *tp; 47*4584Swnj struct mbuf *mp; 484497Swnj { 494567Swnj int s = splnet(); 504567Swnj register int nstate; 51*4584Swnj #ifdef TCPDEBUG 52*4584Swnj struct tcp_debug tdb; 53*4584Swnj #endif 544567Swnj COUNT(TCP_USRREQ); 554497Swnj 564567Swnj nstate = tp->t_state; 574576Swnj tp->tc_flags &= ~TC_NET_KEEP; 584567Swnj acounts[nstate][input]++; 59*4584Swnj #ifdef TCPDEBUG 60*4584Swnj if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) { 61*4584Swnj tdb.td_tod = time; 62*4584Swnj tdb.td_tcb = tp; 63*4584Swnj tdb.td_old = nstate; 64*4584Swnj tdb.td_inp = input; 65*4584Swnj tdb.td_tim = timertype; 66*4584Swnj } else 67*4584Swnj tdb.td_tod = 0; 68*4584Swnj #endif 694567Swnj switch (tcp_fstab[nstate][input]) { 704497Swnj 714567Swnj default: 724567Swnj printf("tcp: bad state: tcb=%x state=%d input=%d\n", 734567Swnj tp, tp->t_state, input); 744567Swnj nstate = EFAILEC; 754567Swnj break; 764497Swnj 774567Swnj case LIS_CLS: /* 1 */ 784567Swnj t_open(tp, PASSIVE); 794567Swnj nstate = LISTEN; 804567Swnj break; 814497Swnj 824567Swnj case SYS_CLS: /* 2 */ 834567Swnj t_open(tp, ACTIVE); 844567Swnj send_ctl(tp); 854567Swnj nstate = SYN_SENT; 864567Swnj break; 874497Swnj 884567Swnj case CLS_OPN: /* 10 */ 894567Swnj t_close(tp, UCLOSED); 904567Swnj nstate = CLOSED; 914567Swnj break; 924497Swnj 934567Swnj case CL2_CLW: /* 10 */ 944576Swnj tp->tc_flags |= TC_SND_FIN; 954567Swnj send_ctl(tp); 964576Swnj tp->tc_flags |= TC_USR_CLOSED; 974567Swnj nstate = CLOSING2; 984567Swnj break; 994497Swnj 1004567Swnj case TIMERS: /* 14,17,34,35,36,37,38 */ 101*4584Swnj nstate = tcp_timers(tp, timertype); 1024567Swnj break; 1034497Swnj 1044567Swnj case CLS_RWT: /* 20 */ 1054567Swnj present_data(tp); 1064567Swnj if (rcv_empty(tp)) { 1074567Swnj t_close(tp, UCLOSED); 1084567Swnj nstate = CLOSED; 1094567Swnj } else 1104567Swnj nstate = RCV_WAIT; 1114567Swnj break; 1124497Swnj 1134567Swnj case FW1_SYR: /* 24,25 */ 1144576Swnj tp->tc_flags |= TC_SND_FIN; 1154567Swnj send_ctl(tp); 1164576Swnj tp->tc_flags |= TC_USR_CLOSED; 1174567Swnj nstate = FIN_W1; 1184567Swnj break; 1194567Swnj 1204567Swnj case SSS_SND: /* 40,41 */ 121*4584Swnj nstate = sss_snd(tp, mp); 1224567Swnj break; 1234567Swnj 1244567Swnj case SSS_RCV: /* 42 */ 1254567Swnj send_ctl(tp); /* send new window */ 1264567Swnj present_data(tp); 1274567Swnj break; 1284567Swnj 1294567Swnj case CLS_NSY: /* 44 */ 1304567Swnj t_close(tp, UABORT); 1314567Swnj nstate = CLOSED; 1324567Swnj break; 1334567Swnj 1344567Swnj case CLS_SYN: /* 45 */ 1354576Swnj tp->tc_flags |= TC_SND_RST; 1364567Swnj send_null(tp); 1374567Swnj t_close(tp, UABORT); 1384567Swnj nstate = CLOSED; 1394567Swnj break; 1404567Swnj 1414567Swnj case CLS_ACT: /* 47 */ 1424567Swnj t_close(tp, UNETDWN); 1434567Swnj nstate = CLOSED; 1444567Swnj break; 1454567Swnj 1464567Swnj case NOP: 1474567Swnj break; 1484567Swnj 1494567Swnj case CLS_ERR: 1504567Swnj to_user(tp->t_ucb, UCLSERR); 1514567Swnj break; 1524567Swnj } 1534567Swnj #ifdef TCPDEBUG 154*4584Swnj if (tdb.td_tod) { 155*4584Swnj tdb.td_new = nstate; 156*4584Swnj tcp_debug[tdbx++ % TDBSIZE] = tdb; 157*4584Swnj if (tcpconsdebug) 158*4584Swnj tcp_prt(&tdb); 159*4584Swnj } 1604567Swnj #endif 1614567Swnj /* YECH */ 1624567Swnj switch (nstate) { 1634567Swnj 164*4584Swnj case CLOSED: 1654567Swnj case SAME: 1664567Swnj break; 1674567Swnj 1684567Swnj case EFAILEC: 169*4584Swnj if (mp) 170*4584Swnj m_freem(dtom(mp)); 1714567Swnj break; 1724567Swnj 1734567Swnj default: 1744567Swnj tp->t_state = nstate; 1754567Swnj break; 1764567Swnj } 1774567Swnj splx(s); 1784497Swnj } 1794497Swnj 1804567Swnj t_open(tp, mode) /* set up a tcb for a connection */ 1814567Swnj register struct tcb *tp; 1824567Swnj int mode; 1834497Swnj { 1844567Swnj register struct ucb *up; 1854567Swnj COUNT(T_OPEN); 1864497Swnj 1874567Swnj /* enqueue the tcb */ 1884497Swnj 1894567Swnj if (netcb.n_tcb_head == NULL) { 1904567Swnj netcb.n_tcb_head = tp; 1914567Swnj netcb.n_tcb_tail = tp; 1924567Swnj } else { 1934567Swnj tp->t_tcb_next = netcb.n_tcb_head; 1944567Swnj netcb.n_tcb_head->t_tcb_prev = tp; 1954567Swnj netcb.n_tcb_head = tp; 1964567Swnj } 1974497Swnj 1984567Swnj /* initialize non-zero tcb fields */ 1994497Swnj 2004567Swnj tp->t_rcv_next = (struct th *)tp; 2014567Swnj tp->t_rcv_prev = (struct th *)tp; 2024567Swnj tp->t_xmtime = T_REXMT; 2034567Swnj tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = 2044567Swnj tp->snd_una = tp->iss = netcb.n_iss; 2054567Swnj tp->snd_off = tp->iss + 1; 2064567Swnj netcb.n_iss += (ISSINCR >> 1) + 1; 2074567Swnj 2084567Swnj /* set timeout for open */ 2094567Swnj 2104567Swnj up = tp->t_ucb; 2114567Swnj tp->t_init = (up->uc_timeo != 0 ? up->uc_timeo : 2124567Swnj (mode == ACTIVE ? T_INIT : 0)); 2134567Swnj up->uc_timeo = 0; /* overlays uc_ssize */ 2144497Swnj } 2154497Swnj 2164567Swnj t_close(tp, state) 2174567Swnj register struct tcb *tp; 2184567Swnj short state; 2194497Swnj { 2204567Swnj register struct ucb *up; 2214567Swnj register struct th *t; 2224567Swnj register struct mbuf *m; 2234567Swnj COUNT(T_CLOSE); 2244497Swnj 2254567Swnj up = tp->t_ucb; 2264497Swnj 2274567Swnj tp->t_init = tp->t_rexmt = tp->t_rexmttl = tp->t_persist = 2284567Swnj tp->t_finack = 0; 2294497Swnj 2304567Swnj /* delete tcb */ 2314567Swnj 2324567Swnj if (tp->t_tcb_prev == NULL) 2334567Swnj netcb.n_tcb_head = tp->t_tcb_next; 2344567Swnj else 2354567Swnj tp->t_tcb_prev->t_tcb_next = tp->t_tcb_next; 2364567Swnj if (tp->t_tcb_next == NULL) 2374567Swnj netcb.n_tcb_tail = tp->t_tcb_prev; 2384567Swnj else 2394567Swnj tp->t_tcb_next->t_tcb_prev = tp->t_tcb_prev; 2404567Swnj 2414567Swnj /* free all data on receive and send buffers */ 2424567Swnj 2434567Swnj for (t = tp->t_rcv_next; t != (struct th *)tp; t = t->t_next) 2444567Swnj m_freem(dtom(t)); 2454567Swnj 2464567Swnj if (up->uc_rbuf != NULL) { 2474567Swnj m_freem(up->uc_rbuf); 2484567Swnj up->uc_rbuf = NULL; 2494567Swnj } 2504567Swnj if (up->uc_sbuf != NULL) { 2514567Swnj m_freem(up->uc_sbuf); 2524567Swnj up->uc_sbuf = NULL; 2534567Swnj } 2544567Swnj for (m = tp->t_rcv_unack; m != NULL; m = m->m_act) { 2554567Swnj m_freem(m); 2564567Swnj tp->t_rcv_unack = NULL; 2574567Swnj } 2584567Swnj m_free(dtom(tp)); 2594567Swnj up->uc_tcb = NULL; 2604567Swnj 2614567Swnj /* lower buffer allocation and decrement host entry */ 2624567Swnj 2634567Swnj netcb.n_lowat -= up->uc_snd + up->uc_rcv + 2; 2644567Swnj netcb.n_hiwat = 2 * netcb.n_lowat; 2654567Swnj if (up->uc_host != NULL) { 2664567Swnj h_free(up->uc_host); 2674567Swnj up->uc_host = NULL; 2684567Swnj } 2694567Swnj 2704567Swnj /* if user has initiated close (via close call), delete ucb 2714567Swnj entry, otherwise just wakeup so user can issue close call */ 2724567Swnj 2734576Swnj if (tp->tc_flags&TC_USR_ABORT) 2744567Swnj up->uc_proc = NULL; 2754567Swnj else 2764567Swnj to_user(up, state); 2774497Swnj } 2784497Swnj 279*4584Swnj sss_snd(tp, m0) 280*4584Swnj register struct tcb *tp; 281*4584Swnj struct mbuf *m0; 2824497Swnj { 2834497Swnj register struct mbuf *m, *n; 284*4584Swnj register struct ucb *up = tp->t_ucb; 2854497Swnj register off; 2864574Swnj seq_t last; 2874497Swnj 2884497Swnj last = tp->snd_off; 2894497Swnj 2904497Swnj /* count number of mbufs in send data */ 2914497Swnj 292*4584Swnj for (m = n = m0; m != NULL; m = m->m_next) { 2934497Swnj up->uc_ssize++; 2944497Swnj last += m->m_len; 2954497Swnj } 2964497Swnj 2974497Swnj /* find end of send buffer and append data */ 2984497Swnj 2994567Swnj if ((m = up->uc_sbuf) != NULL) { /* something in send buffer */ 3004567Swnj while (m->m_next != NULL) { /* find the end */ 3014497Swnj m = m->m_next; 3024497Swnj last += m->m_len; 3034497Swnj } 3044497Swnj last += m->m_len; 3054497Swnj 3064497Swnj /* if there's room in old buffer for new data, consolidate */ 3074497Swnj 3084497Swnj off = m->m_off + m->m_len; 3094497Swnj while (n != NULL && (MSIZE - off) >= n->m_len) { 3104567Swnj bcopy((caddr_t)((int)n + n->m_off), 3114497Swnj (caddr_t)((int)m + off), n->m_len); 3124497Swnj m->m_len += n->m_len; 3134497Swnj off += n->m_len; 3144497Swnj up->uc_ssize--; 3154497Swnj n = m_free(n); 3164497Swnj } 3174497Swnj m->m_next = n; 3184497Swnj 3194567Swnj } else /* nothing in send buffer */ 3204497Swnj up->uc_sbuf = n; 3214497Swnj 3224567Swnj if (up->uc_flags & UEOL) { /* set EOL */ 3234497Swnj tp->snd_end = last; 3244497Swnj } 3254497Swnj 3264567Swnj if (up->uc_flags & UURG) { /* urgent data */ 3274497Swnj tp->snd_urp = last+1; 3284576Swnj tp->tc_flags |= TC_SND_URG; 3294567Swnj } 3304497Swnj 3314497Swnj send(tp); 3324497Swnj 3334567Swnj return (SAME); 3344497Swnj } 3354497Swnj 336*4584Swnj tcp_timers(tp, timertype) 337*4584Swnj register struct tcb *tp; 338*4584Swnj int timertype; 3394497Swnj { 3404497Swnj 3414567Swnj COUNT(TCP_TIMERS); 342*4584Swnj switch (timertype) { 3434497Swnj 3444567Swnj case TINIT: /* initialization timer */ 3454576Swnj if ((tp->tc_flags&TC_SYN_ACKED) == 0) { /* 35 */ 3464567Swnj t_close(tp, UINTIMO); 3474567Swnj return (CLOSED); 3484567Swnj } 3494567Swnj return (SAME); 3504497Swnj 3514567Swnj case TFINACK: /* fin-ack timer */ 3524567Swnj switch (tp->t_state) { 3534497Swnj 3544567Swnj case TIME_WAIT: 3554567Swnj /* 3564567Swnj * We can be sure our ACK of foreign FIN was rcvd, 3574567Swnj * and can close if no data left for user. 3584567Swnj */ 3594567Swnj if (rcv_empty(tp)) { 3604567Swnj t_close(tp, UCLOSED); /* 14 */ 3614567Swnj return (CLOSED); 3624567Swnj } 3634567Swnj return (RCV_WAIT); /* 17 */ 3644497Swnj 3654567Swnj case CLOSING1: 3664576Swnj tp->tc_flags |= TC_WAITED_2_ML; 3674567Swnj return (SAME); 3684497Swnj 3694567Swnj default: 3704567Swnj return (SAME); 3714567Swnj } 3724497Swnj 3734567Swnj case TREXMT: /* retransmission timer */ 3744567Swnj if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ 3754567Swnj /* 3764567Swnj * Set up for a retransmission, increase rexmt time 3774567Swnj * in case of multiple retransmissions. 3784567Swnj */ 3794567Swnj tp->snd_nxt = tp->snd_una; 3804576Swnj tp->tc_flags |= TC_REXMT; 3814567Swnj tp->t_xmtime = tp->t_xmtime << 1; 3824567Swnj if (tp->t_xmtime > T_REMAX) 3834567Swnj tp->t_xmtime = T_REMAX; 3844567Swnj send(tp); 3854567Swnj } 3864567Swnj return (SAME); 3874497Swnj 3884567Swnj case TREXMTTL: /* retransmit too long */ 3894567Swnj if (tp->t_rtl_val > tp->snd_una) /* 36 */ 3904567Swnj to_user(tp->t_ucb, URXTIMO); 3914567Swnj /* 3924567Swnj * If user has already closed, abort the connection. 3934567Swnj */ 3944576Swnj if (tp->tc_flags & TC_USR_CLOSED) { 3954567Swnj t_close(tp, URXTIMO); 3964567Swnj return (CLOSED); 3974567Swnj } 3984567Swnj return (SAME); 3994497Swnj 4004567Swnj case TPERSIST: /* persist timer */ 4014567Swnj /* 4024567Swnj * Force a byte send through closed window. 4034567Swnj */ 4044576Swnj tp->tc_flags |= TC_FORCE_ONE; 4054567Swnj send(tp); 4064567Swnj return (SAME); 4074567Swnj } 4084567Swnj panic("tcp_timers"); 4094497Swnj } 4104497Swnj 4114567Swnj /* THIS ROUTINE IS A CROCK */ 4124567Swnj to_user(up, state) 4134567Swnj register struct ucb *up; 4144567Swnj register short state; 4154497Swnj { 4164567Swnj COUNT(TO_USER); 4174497Swnj 4184567Swnj up->uc_state |= state; 4194567Swnj netwakeup(up); 4204567Swnj if (state == UURGENT) 4214567Swnj psignal(up->uc_proc, SIGURG); 4224497Swnj } 423*4584Swnj 424*4584Swnj #ifdef TCPDEBUG 425*4584Swnj tcp_prt(tdp) 426*4584Swnj register struct tcp_debug *tdp; 427*4584Swnj { 428*4584Swnj COUNT(TCP_PRT); 429*4584Swnj 430*4584Swnj printf("TCP(%X) %s X %s", 431*4584Swnj tdp->td_tcb, tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]); 432*4584Swnj if (tdp->td_inp == ISTIMER) 433*4584Swnj printf("(%s)", tcptimers[tdp->td_tim]); 434*4584Swnj printf(" --> %s", 435*4584Swnj tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]); 436*4584Swnj /* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */ 437*4584Swnj if (tdp->td_new < 0) 438*4584Swnj printf(" (FAILED)"); 439*4584Swnj printf("\n"); 440*4584Swnj } 441*4584Swnj #endif 442