1*4576Swnj /* tcp_usrreq.c 1.6 81/10/21 */ 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 124497Swnj #include "../bbnnet/fsm.h" 134497Swnj 144567Swnj /* 154567Swnj * This file contains the top level routines for actions 164567Swnj * called by the user and by the clock routines, while input 174567Swnj * actions for network data are driven by tcp_input. The two 184567Swnj * main entry points here are tcp_timeo, which decrements tcp timers 194567Swnj * each second and runs timer action routines when the timers go off, 204567Swnj * and tcp_usrreq, which performs requests generated by or on behalf 214567Swnj * of user processes. Both routines raise the ipl to splnet to block 224567Swnj * off tcp_input processing (triggered by imp's) during the work 234567Swnj * here. 244567Swnj */ 254567Swnj 264567Swnj tcp_timeo() 274497Swnj { 284567Swnj register struct tcb *tp; 294567Swnj int s = splnet(); 304567Swnj COUNT(TCP_TIMEO); 314497Swnj 324567Swnj /* 334567Swnj * Search through tcb's and update active timers. 344567Swnj */ 354567Swnj for (tp = netcb.n_tcb_head; tp != NULL; tp = tp->t_tcb_next) { 364567Swnj if (tp->t_init != 0 && --tp->t_init == 0) 374567Swnj tcp_usrreq(ISTIMER, TINIT, tp, 0); 384567Swnj if (tp->t_rexmt != 0 && --tp->t_rexmt == 0) 394567Swnj tcp_usrreq(ISTIMER, TREXMT, tp, 0); 404567Swnj if (tp->t_rexmttl != 0 && --tp->t_rexmttl == 0) 414567Swnj tcp_usrreq(ISTIMER, TREXMTTL, tp, 0); 424567Swnj if (tp->t_persist != 0 && --tp->t_persist == 0) 434567Swnj tcp_usrreq(ISTIMER, TPERSIST, tp, 0); 444567Swnj if (tp->t_finack != 0 && --tp->t_finack == 0) 454567Swnj tcp_usrreq(ISTIMER, TFINACK, tp, 0); 464567Swnj tp->t_xmt++; 474567Swnj } 484567Swnj netcb.n_iss += ISSINCR; /* increment iss */ 494567Swnj timeout(tcp_timeo, 0, hz); /* reschedule every second */ 504567Swnj splx(s); 514497Swnj } 524497Swnj 534567Swnj tcp_usrreq(input, stype, tp, m) 544567Swnj int input, stype; 554567Swnj register struct tcb *tp; 564567Swnj char *m; 574497Swnj { 584567Swnj struct work w; 594567Swnj int s = splnet(); 604567Swnj register int nstate; 614567Swnj register struct work *wp = &w; 624567Swnj COUNT(TCP_USRREQ); 634497Swnj 644567Swnj wp->w_type = input; 654567Swnj wp->w_stype = stype; 664567Swnj wp->w_tcb = tp; 674567Swnj wp->w_dat = m; 684567Swnj nstate = tp->t_state; 69*4576Swnj tp->tc_flags &= ~TC_NET_KEEP; 704567Swnj acounts[nstate][input]++; 714567Swnj switch (tcp_fstab[nstate][input]) { 724497Swnj 734567Swnj default: 744567Swnj printf("tcp: bad state: tcb=%x state=%d input=%d\n", 754567Swnj tp, tp->t_state, input); 764567Swnj nstate = EFAILEC; 774567Swnj break; 784497Swnj 794567Swnj case LIS_CLS: /* 1 */ 804567Swnj t_open(tp, PASSIVE); 814567Swnj nstate = LISTEN; 824567Swnj break; 834497Swnj 844567Swnj case SYS_CLS: /* 2 */ 854567Swnj t_open(tp, ACTIVE); 864567Swnj send_ctl(tp); 874567Swnj nstate = SYN_SENT; 884567Swnj break; 894497Swnj 904567Swnj case CLS_OPN: /* 10 */ 914567Swnj t_close(tp, UCLOSED); 924567Swnj nstate = CLOSED; 934567Swnj break; 944497Swnj 954567Swnj case CL2_CLW: /* 10 */ 96*4576Swnj tp->tc_flags |= TC_SND_FIN; 974567Swnj send_ctl(tp); 98*4576Swnj tp->tc_flags |= TC_USR_CLOSED; 994567Swnj nstate = CLOSING2; 1004567Swnj break; 1014497Swnj 1024567Swnj case TIMERS: /* 14,17,34,35,36,37,38 */ 1034567Swnj nstate = tcp_timers(wp); 1044567Swnj break; 1054497Swnj 1064567Swnj case CLS_RWT: /* 20 */ 1074567Swnj present_data(tp); 1084567Swnj if (rcv_empty(tp)) { 1094567Swnj t_close(tp, UCLOSED); 1104567Swnj nstate = CLOSED; 1114567Swnj } else 1124567Swnj nstate = RCV_WAIT; 1134567Swnj break; 1144497Swnj 1154567Swnj case FW1_SYR: /* 24,25 */ 116*4576Swnj tp->tc_flags |= TC_SND_FIN; 1174567Swnj send_ctl(tp); 118*4576Swnj tp->tc_flags |= TC_USR_CLOSED; 1194567Swnj nstate = FIN_W1; 1204567Swnj break; 1214567Swnj 1224567Swnj case SSS_SND: /* 40,41 */ 1234567Swnj nstate = sss_snd(wp); 1244567Swnj break; 1254567Swnj 1264567Swnj case SSS_RCV: /* 42 */ 1274567Swnj send_ctl(tp); /* send new window */ 1284567Swnj present_data(tp); 1294567Swnj break; 1304567Swnj 1314567Swnj case CLS_NSY: /* 44 */ 1324567Swnj t_close(tp, UABORT); 1334567Swnj nstate = CLOSED; 1344567Swnj break; 1354567Swnj 1364567Swnj case CLS_SYN: /* 45 */ 137*4576Swnj tp->tc_flags |= TC_SND_RST; 1384567Swnj send_null(tp); 1394567Swnj t_close(tp, UABORT); 1404567Swnj nstate = CLOSED; 1414567Swnj break; 1424567Swnj 1434567Swnj case CLS_ACT: /* 47 */ 1444567Swnj t_close(tp, UNETDWN); 1454567Swnj nstate = CLOSED; 1464567Swnj break; 1474567Swnj 1484567Swnj case NOP: 1494567Swnj break; 1504567Swnj 1514567Swnj case CLS_ERR: 1524567Swnj to_user(tp->t_ucb, UCLSERR); 1534567Swnj break; 1544567Swnj } 1554567Swnj if (tp->t_ucb->uc_flags & UDEBUG) 1564567Swnj tcp_debug(tp, wp, input, nstate); 1574567Swnj #ifdef TCPDEBUG 1584567Swnj tcp_prt(tp, input, wp->w_stype, nstate); 1594567Swnj #endif 1604567Swnj /* YECH */ 1614567Swnj switch (nstate) { 1624567Swnj 1634567Swnj case SAME: 1644567Swnj break; 1654567Swnj 1664567Swnj case EFAILEC: 1674567Swnj if (m) 1684567Swnj m_freem(dtom(m)); 1694567Swnj break; 1704567Swnj 1714567Swnj default: 1724567Swnj tp->t_state = nstate; 1734567Swnj break; 1744567Swnj } 1754567Swnj splx(s); 1764497Swnj } 1774497Swnj 1784567Swnj t_open(tp, mode) /* set up a tcb for a connection */ 1794567Swnj register struct tcb *tp; 1804567Swnj int mode; 1814497Swnj { 1824567Swnj register struct ucb *up; 1834567Swnj COUNT(T_OPEN); 1844497Swnj 1854567Swnj /* enqueue the tcb */ 1864497Swnj 1874567Swnj if (netcb.n_tcb_head == NULL) { 1884567Swnj netcb.n_tcb_head = tp; 1894567Swnj netcb.n_tcb_tail = tp; 1904567Swnj } else { 1914567Swnj tp->t_tcb_next = netcb.n_tcb_head; 1924567Swnj netcb.n_tcb_head->t_tcb_prev = tp; 1934567Swnj netcb.n_tcb_head = tp; 1944567Swnj } 1954497Swnj 1964567Swnj /* initialize non-zero tcb fields */ 1974497Swnj 1984567Swnj tp->t_rcv_next = (struct th *)tp; 1994567Swnj tp->t_rcv_prev = (struct th *)tp; 2004567Swnj tp->t_xmtime = T_REXMT; 2014567Swnj tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = 2024567Swnj tp->snd_una = tp->iss = netcb.n_iss; 2034567Swnj tp->snd_off = tp->iss + 1; 2044567Swnj netcb.n_iss += (ISSINCR >> 1) + 1; 2054567Swnj 2064567Swnj /* set timeout for open */ 2074567Swnj 2084567Swnj up = tp->t_ucb; 2094567Swnj tp->t_init = (up->uc_timeo != 0 ? up->uc_timeo : 2104567Swnj (mode == ACTIVE ? T_INIT : 0)); 2114567Swnj up->uc_timeo = 0; /* overlays uc_ssize */ 2124497Swnj } 2134497Swnj 2144567Swnj t_close(tp, state) 2154567Swnj register struct tcb *tp; 2164567Swnj short state; 2174497Swnj { 2184567Swnj register struct ucb *up; 2194567Swnj register struct th *t; 2204567Swnj register struct mbuf *m; 2214567Swnj register struct work *w; 2224567Swnj COUNT(T_CLOSE); 2234497Swnj 2244567Swnj up = tp->t_ucb; 2254497Swnj 2264567Swnj tp->t_init = tp->t_rexmt = tp->t_rexmttl = tp->t_persist = 2274567Swnj tp->t_finack = 0; 2284497Swnj 2294567Swnj /* delete tcb */ 2304567Swnj 2314567Swnj if (tp->t_tcb_prev == NULL) 2324567Swnj netcb.n_tcb_head = tp->t_tcb_next; 2334567Swnj else 2344567Swnj tp->t_tcb_prev->t_tcb_next = tp->t_tcb_next; 2354567Swnj if (tp->t_tcb_next == NULL) 2364567Swnj netcb.n_tcb_tail = tp->t_tcb_prev; 2374567Swnj else 2384567Swnj tp->t_tcb_next->t_tcb_prev = tp->t_tcb_prev; 2394567Swnj 2404567Swnj /* free all data on receive and send buffers */ 2414567Swnj 2424567Swnj for (t = tp->t_rcv_next; t != (struct th *)tp; t = t->t_next) 2434567Swnj m_freem(dtom(t)); 2444567Swnj 2454567Swnj if (up->uc_rbuf != NULL) { 2464567Swnj m_freem(up->uc_rbuf); 2474567Swnj up->uc_rbuf = NULL; 2484567Swnj } 2494567Swnj if (up->uc_sbuf != NULL) { 2504567Swnj m_freem(up->uc_sbuf); 2514567Swnj up->uc_sbuf = NULL; 2524567Swnj } 2534567Swnj for (m = tp->t_rcv_unack; m != NULL; m = m->m_act) { 2544567Swnj m_freem(m); 2554567Swnj tp->t_rcv_unack = NULL; 2564567Swnj } 2574567Swnj m_free(dtom(tp)); 2584567Swnj up->uc_tcb = NULL; 2594567Swnj 2604567Swnj /* lower buffer allocation and decrement host entry */ 2614567Swnj 2624567Swnj netcb.n_lowat -= up->uc_snd + up->uc_rcv + 2; 2634567Swnj netcb.n_hiwat = 2 * netcb.n_lowat; 2644567Swnj if (up->uc_host != NULL) { 2654567Swnj h_free(up->uc_host); 2664567Swnj up->uc_host = NULL; 2674567Swnj } 2684567Swnj 2694567Swnj /* if user has initiated close (via close call), delete ucb 2704567Swnj entry, otherwise just wakeup so user can issue close call */ 2714567Swnj 272*4576Swnj if (tp->tc_flags&TC_USR_ABORT) 2734567Swnj up->uc_proc = NULL; 2744567Swnj else 2754567Swnj to_user(up, state); 2764567Swnj 2774497Swnj } 2784497Swnj 2794567Swnj sss_snd(wp) 2804567Swnj struct work *wp; 2814497Swnj { 2824497Swnj register struct tcb *tp; 2834497Swnj register struct mbuf *m, *n; 2844497Swnj register struct ucb *up; 2854497Swnj register off; 2864574Swnj seq_t last; 2874497Swnj 2884497Swnj tp = wp->w_tcb; 2894497Swnj up = tp->t_ucb; 2904497Swnj 2914497Swnj last = tp->snd_off; 2924497Swnj 2934497Swnj /* count number of mbufs in send data */ 2944497Swnj 2954497Swnj for (m = n = (struct mbuf *)wp->w_dat; m != NULL; m = m->m_next) { 2964497Swnj up->uc_ssize++; 2974497Swnj last += m->m_len; 2984497Swnj } 2994497Swnj 3004497Swnj /* find end of send buffer and append data */ 3014497Swnj 3024567Swnj if ((m = up->uc_sbuf) != NULL) { /* something in send buffer */ 3034567Swnj while (m->m_next != NULL) { /* find the end */ 3044497Swnj m = m->m_next; 3054497Swnj last += m->m_len; 3064497Swnj } 3074497Swnj last += m->m_len; 3084497Swnj 3094497Swnj /* if there's room in old buffer for new data, consolidate */ 3104497Swnj 3114497Swnj off = m->m_off + m->m_len; 3124497Swnj while (n != NULL && (MSIZE - off) >= n->m_len) { 3134567Swnj bcopy((caddr_t)((int)n + n->m_off), 3144497Swnj (caddr_t)((int)m + off), n->m_len); 3154497Swnj m->m_len += n->m_len; 3164497Swnj off += n->m_len; 3174497Swnj up->uc_ssize--; 3184497Swnj n = m_free(n); 3194497Swnj } 3204497Swnj m->m_next = n; 3214497Swnj 3224567Swnj } else /* nothing in send buffer */ 3234497Swnj up->uc_sbuf = n; 3244497Swnj 3254567Swnj if (up->uc_flags & UEOL) { /* set EOL */ 3264497Swnj tp->snd_end = last; 3274497Swnj } 3284497Swnj 3294567Swnj if (up->uc_flags & UURG) { /* urgent data */ 3304497Swnj tp->snd_urp = last+1; 331*4576Swnj tp->tc_flags |= TC_SND_URG; 3324567Swnj } 3334497Swnj 3344497Swnj send(tp); 3354497Swnj 3364567Swnj return (SAME); 3374497Swnj } 3384497Swnj 3394567Swnj tcp_timers(wp) 3404567Swnj struct work *wp; 3414497Swnj { 3424567Swnj register struct tcb *tp = wp->w_tcb; 3434567Swnj register type = wp->w_stype; 3444497Swnj 3454567Swnj COUNT(TCP_TIMERS); 3464567Swnj switch (type) { 3474497Swnj 3484567Swnj case TINIT: /* initialization timer */ 349*4576Swnj if ((tp->tc_flags&TC_SYN_ACKED) == 0) { /* 35 */ 3504567Swnj t_close(tp, UINTIMO); 3514567Swnj return (CLOSED); 3524567Swnj } 3534567Swnj return (SAME); 3544497Swnj 3554567Swnj case TFINACK: /* fin-ack timer */ 3564567Swnj switch (tp->t_state) { 3574497Swnj 3584567Swnj case TIME_WAIT: 3594567Swnj /* 3604567Swnj * We can be sure our ACK of foreign FIN was rcvd, 3614567Swnj * and can close if no data left for user. 3624567Swnj */ 3634567Swnj if (rcv_empty(tp)) { 3644567Swnj t_close(tp, UCLOSED); /* 14 */ 3654567Swnj return (CLOSED); 3664567Swnj } 3674567Swnj return (RCV_WAIT); /* 17 */ 3684497Swnj 3694567Swnj case CLOSING1: 370*4576Swnj tp->tc_flags |= TC_WAITED_2_ML; 3714567Swnj return (SAME); 3724497Swnj 3734567Swnj default: 3744567Swnj return (SAME); 3754567Swnj } 3764497Swnj 3774567Swnj case TREXMT: /* retransmission timer */ 3784567Swnj if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ 3794567Swnj /* 3804567Swnj * Set up for a retransmission, increase rexmt time 3814567Swnj * in case of multiple retransmissions. 3824567Swnj */ 3834567Swnj tp->snd_nxt = tp->snd_una; 384*4576Swnj tp->tc_flags |= TC_REXMT; 3854567Swnj tp->t_xmtime = tp->t_xmtime << 1; 3864567Swnj if (tp->t_xmtime > T_REMAX) 3874567Swnj tp->t_xmtime = T_REMAX; 3884567Swnj send(tp); 3894567Swnj } 3904567Swnj return (SAME); 3914497Swnj 3924567Swnj case TREXMTTL: /* retransmit too long */ 3934567Swnj if (tp->t_rtl_val > tp->snd_una) /* 36 */ 3944567Swnj to_user(tp->t_ucb, URXTIMO); 3954567Swnj /* 3964567Swnj * If user has already closed, abort the connection. 3974567Swnj */ 398*4576Swnj if (tp->tc_flags & TC_USR_CLOSED) { 3994567Swnj t_close(tp, URXTIMO); 4004567Swnj return (CLOSED); 4014567Swnj } 4024567Swnj return (SAME); 4034497Swnj 4044567Swnj case TPERSIST: /* persist timer */ 4054567Swnj /* 4064567Swnj * Force a byte send through closed window. 4074567Swnj */ 408*4576Swnj tp->tc_flags |= TC_FORCE_ONE; 4094567Swnj send(tp); 4104567Swnj return (SAME); 4114567Swnj } 4124567Swnj panic("tcp_timers"); 4134497Swnj } 4144497Swnj 4154567Swnj tcp_debug(tp, wp, input, newstate) /* write a debugging record */ 4164567Swnj register struct tcb *tp; 4174567Swnj register struct work *wp; 4184567Swnj int input, newstate; 4194497Swnj { 4204567Swnj struct t_debug debuf; 4214567Swnj register struct th *n; 4224567Swnj register off_t siz; 4234567Swnj COUNT(TCP_DEBUG); 4244497Swnj 4254567Swnj /* look for debugging file inode */ 4264497Swnj 4274567Swnj if (netcb.n_debug == 0) 4284567Swnj return; 4294567Swnj debuf.t_tod = time; 4304567Swnj if ((debuf.t_tcb = tp) != NULL) 4314567Swnj debuf.t_old = tp->t_state; 4324567Swnj else 4334567Swnj debuf.t_old = 0; 4344567Swnj debuf.t_inp = input; 4354567Swnj debuf.t_tim = wp->w_stype; 4364567Swnj debuf.t_new = newstate; 4374567Swnj if (input == INRECV) { 4384567Swnj n = (struct th *)wp->w_dat; 4394567Swnj debuf.t_sno = n->t_seq; 4404567Swnj debuf.t_ano = n->t_ackno; 4414567Swnj debuf.t_wno = n->t_win; 4424567Swnj if (debuf.t_new == -1) 4434567Swnj debuf.t_lno = ((struct ip *)n)->ip_len; 4444567Swnj else 4454567Swnj debuf.t_lno = n->t_len; 4464567Swnj debuf.t_flg = *(char *)((int)&n->t_win - 1); 4474567Swnj } 4484567Swnj /* STUFF INTO CIRC BUFFER */ 4494497Swnj } 4504497Swnj 4514567Swnj #ifdef TCPDEBUG 4524567Swnj 4534567Swnj tcp_prt(tp, input, timer, newstate) /* print debugging info on the console */ 4544567Swnj register struct tcb *tp; 4554567Swnj register input, timer, newstate; 4564497Swnj { 4574567Swnj register oldstate; 4584567Swnj COUNT(TCP_PRT); 4594497Swnj 4604567Swnj oldstate = tp->t_state; 4614567Swnj printf("TCP(%X) %s X %s", tp, tcpstates[oldstate], tcpinputs[input]); 4624567Swnj if (input == ISTIMER) 4634567Swnj printf("(%s)", tcptimers[timer]); 4644567Swnj printf(" --> %s", tcpstates[ (newstate > 0) ? newstate : oldstate ]); 4654567Swnj if (newstate < 0) 4664567Swnj printf(" (FAILED)\n"); 4674567Swnj else 4684567Swnj putchar('\n'); 4694497Swnj } 4704567Swnj #endif 4714497Swnj 4724567Swnj /* THIS ROUTINE IS A CROCK */ 4734567Swnj to_user(up, state) 4744567Swnj register struct ucb *up; 4754567Swnj register short state; 4764497Swnj { 4774567Swnj COUNT(TO_USER); 4784497Swnj 4794567Swnj up->uc_state |= state; 4804567Swnj netwakeup(up); 4814567Swnj if (state == UURGENT) 4824567Swnj psignal(up->uc_proc, SIGURG); 4834497Swnj } 484