1*4567Swnj /* tcp_usrreq.c 1.4 81/10/21 */ 2*4567Swnj 34497Swnj #include "../h/param.h" 4*4567Swnj #include "../h/systm.h" 54497Swnj #include "../bbnnet/net.h" 64497Swnj #include "../bbnnet/tcp.h" 74497Swnj #include "../bbnnet/ip.h" 84497Swnj #include "../bbnnet/imp.h" 94497Swnj #include "../bbnnet/ucb.h" 10*4567Swnj #define TCPFSTAB 114497Swnj #include "../bbnnet/fsm.h" 124497Swnj #include "../bbnnet/tcp_pred.h" 134497Swnj 14*4567Swnj /* 15*4567Swnj * This file contains the top level routines for actions 16*4567Swnj * called by the user and by the clock routines, while input 17*4567Swnj * actions for network data are driven by tcp_input. The two 18*4567Swnj * main entry points here are tcp_timeo, which decrements tcp timers 19*4567Swnj * each second and runs timer action routines when the timers go off, 20*4567Swnj * and tcp_usrreq, which performs requests generated by or on behalf 21*4567Swnj * of user processes. Both routines raise the ipl to splnet to block 22*4567Swnj * off tcp_input processing (triggered by imp's) during the work 23*4567Swnj * here. 24*4567Swnj */ 25*4567Swnj 26*4567Swnj tcp_timeo() 274497Swnj { 28*4567Swnj register struct tcb *tp; 29*4567Swnj int s = splnet(); 30*4567Swnj COUNT(TCP_TIMEO); 314497Swnj 32*4567Swnj /* 33*4567Swnj * Search through tcb's and update active timers. 34*4567Swnj */ 35*4567Swnj for (tp = netcb.n_tcb_head; tp != NULL; tp = tp->t_tcb_next) { 36*4567Swnj if (tp->t_init != 0 && --tp->t_init == 0) 37*4567Swnj tcp_usrreq(ISTIMER, TINIT, tp, 0); 38*4567Swnj if (tp->t_rexmt != 0 && --tp->t_rexmt == 0) 39*4567Swnj tcp_usrreq(ISTIMER, TREXMT, tp, 0); 40*4567Swnj if (tp->t_rexmttl != 0 && --tp->t_rexmttl == 0) 41*4567Swnj tcp_usrreq(ISTIMER, TREXMTTL, tp, 0); 42*4567Swnj if (tp->t_persist != 0 && --tp->t_persist == 0) 43*4567Swnj tcp_usrreq(ISTIMER, TPERSIST, tp, 0); 44*4567Swnj if (tp->t_finack != 0 && --tp->t_finack == 0) 45*4567Swnj tcp_usrreq(ISTIMER, TFINACK, tp, 0); 46*4567Swnj tp->t_xmt++; 47*4567Swnj } 48*4567Swnj netcb.n_iss += ISSINCR; /* increment iss */ 49*4567Swnj timeout(tcp_timeo, 0, hz); /* reschedule every second */ 50*4567Swnj splx(s); 514497Swnj } 524497Swnj 53*4567Swnj tcp_usrreq(input, stype, tp, m) 54*4567Swnj int input, stype; 55*4567Swnj register struct tcb *tp; 56*4567Swnj char *m; 574497Swnj { 58*4567Swnj struct work w; 59*4567Swnj int s = splnet(); 60*4567Swnj register int nstate; 61*4567Swnj register struct work *wp = &w; 62*4567Swnj COUNT(TCP_USRREQ); 634497Swnj 64*4567Swnj wp->w_type = input; 65*4567Swnj wp->w_stype = stype; 66*4567Swnj wp->w_tcb = tp; 67*4567Swnj wp->w_dat = m; 68*4567Swnj nstate = tp->t_state; 69*4567Swnj tp->net_keep = 0; 70*4567Swnj acounts[nstate][input]++; 71*4567Swnj switch (tcp_fstab[nstate][input]) { 724497Swnj 73*4567Swnj default: 74*4567Swnj printf("tcp: bad state: tcb=%x state=%d input=%d\n", 75*4567Swnj tp, tp->t_state, input); 76*4567Swnj nstate = EFAILEC; 77*4567Swnj break; 784497Swnj 79*4567Swnj case LIS_CLS: /* 1 */ 80*4567Swnj t_open(tp, PASSIVE); 81*4567Swnj nstate = LISTEN; 82*4567Swnj break; 834497Swnj 84*4567Swnj case SYS_CLS: /* 2 */ 85*4567Swnj t_open(tp, ACTIVE); 86*4567Swnj send_ctl(tp); 87*4567Swnj nstate = SYN_SENT; 88*4567Swnj break; 894497Swnj 90*4567Swnj case CLS_OPN: /* 10 */ 91*4567Swnj t_close(tp, UCLOSED); 92*4567Swnj nstate = CLOSED; 93*4567Swnj break; 944497Swnj 95*4567Swnj case CL2_CLW: /* 10 */ 96*4567Swnj tp->snd_fin = 1; 97*4567Swnj send_ctl(tp); 98*4567Swnj tp->usr_closed = 1; 99*4567Swnj nstate = CLOSING2; 100*4567Swnj break; 1014497Swnj 102*4567Swnj case TIMERS: /* 14,17,34,35,36,37,38 */ 103*4567Swnj nstate = tcp_timers(wp); 104*4567Swnj break; 1054497Swnj 106*4567Swnj case CLS_RWT: /* 20 */ 107*4567Swnj present_data(tp); 108*4567Swnj if (rcv_empty(tp)) { 109*4567Swnj t_close(tp, UCLOSED); 110*4567Swnj nstate = CLOSED; 111*4567Swnj } else 112*4567Swnj nstate = RCV_WAIT; 113*4567Swnj break; 1144497Swnj 115*4567Swnj case FW1_SYR: /* 24,25 */ 116*4567Swnj tp->snd_fin = 1; 117*4567Swnj send_ctl(tp); 118*4567Swnj tp->usr_closed = 1; 119*4567Swnj nstate = FIN_W1; 120*4567Swnj break; 121*4567Swnj 122*4567Swnj case SSS_SND: /* 40,41 */ 123*4567Swnj nstate = sss_snd(wp); 124*4567Swnj break; 125*4567Swnj 126*4567Swnj case SSS_RCV: /* 42 */ 127*4567Swnj send_ctl(tp); /* send new window */ 128*4567Swnj present_data(tp); 129*4567Swnj break; 130*4567Swnj 131*4567Swnj case CLS_NSY: /* 44 */ 132*4567Swnj t_close(tp, UABORT); 133*4567Swnj nstate = CLOSED; 134*4567Swnj break; 135*4567Swnj 136*4567Swnj case CLS_SYN: /* 45 */ 137*4567Swnj tp->snd_rst = 1; 138*4567Swnj send_null(tp); 139*4567Swnj t_close(tp, UABORT); 140*4567Swnj nstate = CLOSED; 141*4567Swnj break; 142*4567Swnj 143*4567Swnj case CLS_ACT: /* 47 */ 144*4567Swnj t_close(tp, UNETDWN); 145*4567Swnj nstate = CLOSED; 146*4567Swnj break; 147*4567Swnj 148*4567Swnj case NOP: 149*4567Swnj break; 150*4567Swnj 151*4567Swnj case CLS_ERR: 152*4567Swnj to_user(tp->t_ucb, UCLSERR); 153*4567Swnj break; 154*4567Swnj } 155*4567Swnj if (tp->t_ucb->uc_flags & UDEBUG) 156*4567Swnj tcp_debug(tp, wp, input, nstate); 157*4567Swnj #ifdef TCPDEBUG 158*4567Swnj tcp_prt(tp, input, wp->w_stype, nstate); 159*4567Swnj #endif 160*4567Swnj /* YECH */ 161*4567Swnj switch (nstate) { 162*4567Swnj 163*4567Swnj case SAME: 164*4567Swnj break; 165*4567Swnj 166*4567Swnj case EFAILEC: 167*4567Swnj if (m) 168*4567Swnj m_freem(dtom(m)); 169*4567Swnj break; 170*4567Swnj 171*4567Swnj default: 172*4567Swnj tp->t_state = nstate; 173*4567Swnj break; 174*4567Swnj } 175*4567Swnj splx(s); 1764497Swnj } 1774497Swnj 178*4567Swnj t_open(tp, mode) /* set up a tcb for a connection */ 179*4567Swnj register struct tcb *tp; 180*4567Swnj int mode; 1814497Swnj { 182*4567Swnj register struct ucb *up; 183*4567Swnj COUNT(T_OPEN); 1844497Swnj 185*4567Swnj /* enqueue the tcb */ 1864497Swnj 187*4567Swnj if (netcb.n_tcb_head == NULL) { 188*4567Swnj netcb.n_tcb_head = tp; 189*4567Swnj netcb.n_tcb_tail = tp; 190*4567Swnj } else { 191*4567Swnj tp->t_tcb_next = netcb.n_tcb_head; 192*4567Swnj netcb.n_tcb_head->t_tcb_prev = tp; 193*4567Swnj netcb.n_tcb_head = tp; 194*4567Swnj } 1954497Swnj 196*4567Swnj /* initialize non-zero tcb fields */ 1974497Swnj 198*4567Swnj tp->t_rcv_next = (struct th *)tp; 199*4567Swnj tp->t_rcv_prev = (struct th *)tp; 200*4567Swnj tp->t_xmtime = T_REXMT; 201*4567Swnj tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = 202*4567Swnj tp->snd_una = tp->iss = netcb.n_iss; 203*4567Swnj tp->snd_off = tp->iss + 1; 204*4567Swnj netcb.n_iss += (ISSINCR >> 1) + 1; 205*4567Swnj 206*4567Swnj /* set timeout for open */ 207*4567Swnj 208*4567Swnj up = tp->t_ucb; 209*4567Swnj tp->t_init = (up->uc_timeo != 0 ? up->uc_timeo : 210*4567Swnj (mode == ACTIVE ? T_INIT : 0)); 211*4567Swnj up->uc_timeo = 0; /* overlays uc_ssize */ 2124497Swnj } 2134497Swnj 214*4567Swnj t_close(tp, state) 215*4567Swnj register struct tcb *tp; 216*4567Swnj short state; 2174497Swnj { 218*4567Swnj register struct ucb *up; 219*4567Swnj register struct th *t; 220*4567Swnj register struct mbuf *m; 221*4567Swnj register struct work *w; 222*4567Swnj COUNT(T_CLOSE); 2234497Swnj 224*4567Swnj up = tp->t_ucb; 2254497Swnj 226*4567Swnj tp->t_init = tp->t_rexmt = tp->t_rexmttl = tp->t_persist = 227*4567Swnj tp->t_finack = 0; 2284497Swnj 229*4567Swnj /* delete tcb */ 230*4567Swnj 231*4567Swnj if (tp->t_tcb_prev == NULL) 232*4567Swnj netcb.n_tcb_head = tp->t_tcb_next; 233*4567Swnj else 234*4567Swnj tp->t_tcb_prev->t_tcb_next = tp->t_tcb_next; 235*4567Swnj if (tp->t_tcb_next == NULL) 236*4567Swnj netcb.n_tcb_tail = tp->t_tcb_prev; 237*4567Swnj else 238*4567Swnj tp->t_tcb_next->t_tcb_prev = tp->t_tcb_prev; 239*4567Swnj 240*4567Swnj /* free all data on receive and send buffers */ 241*4567Swnj 242*4567Swnj for (t = tp->t_rcv_next; t != (struct th *)tp; t = t->t_next) 243*4567Swnj m_freem(dtom(t)); 244*4567Swnj 245*4567Swnj if (up->uc_rbuf != NULL) { 246*4567Swnj m_freem(up->uc_rbuf); 247*4567Swnj up->uc_rbuf = NULL; 248*4567Swnj } 249*4567Swnj if (up->uc_sbuf != NULL) { 250*4567Swnj m_freem(up->uc_sbuf); 251*4567Swnj up->uc_sbuf = NULL; 252*4567Swnj } 253*4567Swnj for (m = tp->t_rcv_unack; m != NULL; m = m->m_act) { 254*4567Swnj m_freem(m); 255*4567Swnj tp->t_rcv_unack = NULL; 256*4567Swnj } 257*4567Swnj m_free(dtom(tp)); 258*4567Swnj up->uc_tcb = NULL; 259*4567Swnj 260*4567Swnj /* lower buffer allocation and decrement host entry */ 261*4567Swnj 262*4567Swnj netcb.n_lowat -= up->uc_snd + up->uc_rcv + 2; 263*4567Swnj netcb.n_hiwat = 2 * netcb.n_lowat; 264*4567Swnj if (up->uc_host != NULL) { 265*4567Swnj h_free(up->uc_host); 266*4567Swnj up->uc_host = NULL; 267*4567Swnj } 268*4567Swnj 269*4567Swnj /* if user has initiated close (via close call), delete ucb 270*4567Swnj entry, otherwise just wakeup so user can issue close call */ 271*4567Swnj 272*4567Swnj if (tp->usr_abort) 273*4567Swnj up->uc_proc = NULL; 274*4567Swnj else 275*4567Swnj to_user(up, state); 276*4567Swnj 2774497Swnj } 2784497Swnj 279*4567Swnj sss_snd(wp) 280*4567Swnj struct work *wp; 2814497Swnj { 2824497Swnj register struct tcb *tp; 2834497Swnj register struct mbuf *m, *n; 2844497Swnj register struct ucb *up; 2854497Swnj register off; 2864497Swnj sequence 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 302*4567Swnj if ((m = up->uc_sbuf) != NULL) { /* something in send buffer */ 303*4567Swnj 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) { 313*4567Swnj 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 322*4567Swnj } else /* nothing in send buffer */ 3234497Swnj up->uc_sbuf = n; 3244497Swnj 325*4567Swnj if (up->uc_flags & UEOL) { /* set EOL */ 3264497Swnj tp->snd_end = last; 3274497Swnj } 3284497Swnj 329*4567Swnj if (up->uc_flags & UURG) { /* urgent data */ 3304497Swnj tp->snd_urp = last+1; 331*4567Swnj tp->snd_urg = 1; 332*4567Swnj } 3334497Swnj 3344497Swnj send(tp); 3354497Swnj 336*4567Swnj return (SAME); 3374497Swnj } 3384497Swnj 339*4567Swnj tcp_timers(wp) 340*4567Swnj struct work *wp; 3414497Swnj { 342*4567Swnj register struct tcb *tp = wp->w_tcb; 343*4567Swnj register type = wp->w_stype; 3444497Swnj 345*4567Swnj COUNT(TCP_TIMERS); 346*4567Swnj switch (type) { 3474497Swnj 348*4567Swnj case TINIT: /* initialization timer */ 349*4567Swnj if (!tp->syn_acked) { /* 35 */ 350*4567Swnj t_close(tp, UINTIMO); 351*4567Swnj return (CLOSED); 352*4567Swnj } 353*4567Swnj return (SAME); 3544497Swnj 355*4567Swnj case TFINACK: /* fin-ack timer */ 356*4567Swnj switch (tp->t_state) { 3574497Swnj 358*4567Swnj case TIME_WAIT: 359*4567Swnj /* 360*4567Swnj * We can be sure our ACK of foreign FIN was rcvd, 361*4567Swnj * and can close if no data left for user. 362*4567Swnj */ 363*4567Swnj if (rcv_empty(tp)) { 364*4567Swnj t_close(tp, UCLOSED); /* 14 */ 365*4567Swnj return (CLOSED); 366*4567Swnj } 367*4567Swnj return (RCV_WAIT); /* 17 */ 3684497Swnj 369*4567Swnj case CLOSING1: 370*4567Swnj tp->waited_2_ml = 1; 371*4567Swnj return (SAME); 3724497Swnj 373*4567Swnj default: 374*4567Swnj return (SAME); 375*4567Swnj } 3764497Swnj 377*4567Swnj case TREXMT: /* retransmission timer */ 378*4567Swnj if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ 379*4567Swnj /* 380*4567Swnj * Set up for a retransmission, increase rexmt time 381*4567Swnj * in case of multiple retransmissions. 382*4567Swnj */ 383*4567Swnj tp->snd_nxt = tp->snd_una; 384*4567Swnj tp->rexmt = 1; 385*4567Swnj tp->t_xmtime = tp->t_xmtime << 1; 386*4567Swnj if (tp->t_xmtime > T_REMAX) 387*4567Swnj tp->t_xmtime = T_REMAX; 388*4567Swnj send(tp); 389*4567Swnj } 390*4567Swnj return (SAME); 3914497Swnj 392*4567Swnj case TREXMTTL: /* retransmit too long */ 393*4567Swnj if (tp->t_rtl_val > tp->snd_una) /* 36 */ 394*4567Swnj to_user(tp->t_ucb, URXTIMO); 395*4567Swnj /* 396*4567Swnj * If user has already closed, abort the connection. 397*4567Swnj */ 398*4567Swnj if (tp->usr_closed) { 399*4567Swnj t_close(tp, URXTIMO); 400*4567Swnj return (CLOSED); 401*4567Swnj } 402*4567Swnj return (SAME); 4034497Swnj 404*4567Swnj case TPERSIST: /* persist timer */ 405*4567Swnj /* 406*4567Swnj * Force a byte send through closed window. 407*4567Swnj */ 408*4567Swnj tp->force_one = 1; /* 38 */ 409*4567Swnj send(tp); 410*4567Swnj return (SAME); 411*4567Swnj } 412*4567Swnj panic("tcp_timers"); 4134497Swnj } 4144497Swnj 415*4567Swnj tcp_debug(tp, wp, input, newstate) /* write a debugging record */ 416*4567Swnj register struct tcb *tp; 417*4567Swnj register struct work *wp; 418*4567Swnj int input, newstate; 4194497Swnj { 420*4567Swnj struct t_debug debuf; 421*4567Swnj register struct th *n; 422*4567Swnj register off_t siz; 423*4567Swnj COUNT(TCP_DEBUG); 4244497Swnj 425*4567Swnj /* look for debugging file inode */ 4264497Swnj 427*4567Swnj if (netcb.n_debug == 0) 428*4567Swnj return; 429*4567Swnj debuf.t_tod = time; 430*4567Swnj if ((debuf.t_tcb = tp) != NULL) 431*4567Swnj debuf.t_old = tp->t_state; 432*4567Swnj else 433*4567Swnj debuf.t_old = 0; 434*4567Swnj debuf.t_inp = input; 435*4567Swnj debuf.t_tim = wp->w_stype; 436*4567Swnj debuf.t_new = newstate; 437*4567Swnj if (input == INRECV) { 438*4567Swnj n = (struct th *)wp->w_dat; 439*4567Swnj debuf.t_sno = n->t_seq; 440*4567Swnj debuf.t_ano = n->t_ackno; 441*4567Swnj debuf.t_wno = n->t_win; 442*4567Swnj if (debuf.t_new == -1) 443*4567Swnj debuf.t_lno = ((struct ip *)n)->ip_len; 444*4567Swnj else 445*4567Swnj debuf.t_lno = n->t_len; 446*4567Swnj debuf.t_flg = *(char *)((int)&n->t_win - 1); 447*4567Swnj } 448*4567Swnj /* STUFF INTO CIRC BUFFER */ 4494497Swnj } 4504497Swnj 451*4567Swnj #ifdef TCPDEBUG 452*4567Swnj 453*4567Swnj tcp_prt(tp, input, timer, newstate) /* print debugging info on the console */ 454*4567Swnj register struct tcb *tp; 455*4567Swnj register input, timer, newstate; 4564497Swnj { 457*4567Swnj register oldstate; 458*4567Swnj COUNT(TCP_PRT); 4594497Swnj 460*4567Swnj oldstate = tp->t_state; 461*4567Swnj printf("TCP(%X) %s X %s", tp, tcpstates[oldstate], tcpinputs[input]); 462*4567Swnj if (input == ISTIMER) 463*4567Swnj printf("(%s)", tcptimers[timer]); 464*4567Swnj printf(" --> %s", tcpstates[ (newstate > 0) ? newstate : oldstate ]); 465*4567Swnj if (newstate < 0) 466*4567Swnj printf(" (FAILED)\n"); 467*4567Swnj else 468*4567Swnj putchar('\n'); 4694497Swnj } 470*4567Swnj #endif 4714497Swnj 472*4567Swnj /* THIS ROUTINE IS A CROCK */ 473*4567Swnj to_user(up, state) 474*4567Swnj register struct ucb *up; 475*4567Swnj register short state; 4764497Swnj { 477*4567Swnj COUNT(TO_USER); 4784497Swnj 479*4567Swnj up->uc_state |= state; 480*4567Swnj netwakeup(up); 481*4567Swnj if (state == UURGENT) 482*4567Swnj psignal(up->uc_proc, SIGURG); 4834497Swnj } 484