1*4886Swnj /* tcp_usrreq.c 1.27 81/11/14 */ 24567Swnj 34497Swnj #include "../h/param.h" 44567Swnj #include "../h/systm.h" 54664Swnj #include "../h/mbuf.h" 64664Swnj #include "../h/socket.h" 74809Swnj #include "../h/socketvar.h" 84809Swnj #include "../h/protosw.h" 94809Swnj #include "../net/inet.h" 10*4886Swnj #include "../net/inet_host.h" 11*4886Swnj #include "../net/inet_pcb.h" 124809Swnj #include "../net/inet_systm.h" 134809Swnj #include "../net/imp.h" 144809Swnj #include "../net/ip.h" 154809Swnj #include "../net/tcp.h" 164567Swnj #define TCPFSTAB 174584Swnj #ifdef TCPDEBUG 184584Swnj #define TCPSTATES 194584Swnj #endif 204809Swnj #include "../net/tcp_fsm.h" 214809Swnj #include "../net/tcp_var.h" 224809Swnj #include "/usr/include/errno.h" 234497Swnj 244734Swnj /* 254809Swnj * Tcp initialization 264809Swnj */ 274809Swnj tcp_init() 284809Swnj { 294809Swnj 304809Swnj tcp_iss = 1; /* wrong */ 31*4886Swnj tcb.inp_next = tcb.inp_prev = &tcb; 324809Swnj } 334809Swnj 344809Swnj /* 354734Swnj * Tcp finite state machine entries for timer and user generated 364734Swnj * requests. These routines raise the ipl to that of the network 374734Swnj * to prevent reentry. In particluar, this requires that the software 384734Swnj * clock interrupt have lower priority than the network so that 394734Swnj * we can enter the network from timeout routines without improperly 404734Swnj * nesting the interrupt stack. 414734Swnj */ 424734Swnj 434734Swnj /* 444809Swnj * Tcp protocol timeout routine called every 500 ms. 454734Swnj * Updates the timers in all active tcb's and 464734Swnj * causes finite state machine actions if timers expire. 474734Swnj */ 484809Swnj tcp_slowtimo() 494497Swnj { 50*4886Swnj register struct inpcb *ip; 51*4886Swnj register struct tcpcb *tp; 524567Swnj int s = splnet(); 534809Swnj register short *tmp; 544731Swnj register int i; 554567Swnj COUNT(TCP_TIMEO); 564497Swnj 574567Swnj /* 584567Swnj * Search through tcb's and update active timers. 594567Swnj */ 60*4886Swnj for (ip = tcb.inp_next; ip != &tcb; ip = ip->inp_next) { 61*4886Swnj tp = intotcpcb(ip); 624731Swnj tmp = &tp->t_init; 634735Swnj for (i = 0; i < TNTIMERS; i++) { 644731Swnj if (*tmp && --*tmp == 0) 65*4886Swnj tcp_usrreq(tp->t_inpcb->inp_socket, 66*4886Swnj PRU_SLOWTIMO, 0, i); 674735Swnj tmp++; 684735Swnj } 694567Swnj tp->t_xmt++; 704567Swnj } 714809Swnj tcp_iss += ISSINCR/2; /* increment iss */ 724567Swnj splx(s); 734497Swnj } 744497Swnj 754731Swnj /* 764734Swnj * Cancel all timers for tcp tp. 774734Swnj */ 784734Swnj tcp_tcancel(tp) 79*4886Swnj struct tcpcb *tp; 804734Swnj { 814809Swnj register short *tmp = &tp->t_init; 824734Swnj register int i; 834734Swnj 844734Swnj for (i = 0; i < TNTIMERS; i++) 854734Swnj *tmp++ = 0; 864734Swnj } 874734Swnj 884734Swnj /* 894731Swnj * Process a TCP user request for tcp tb. If this is a send request 904731Swnj * then m is the mbuf chain of send data. If this is a timer expiration 914731Swnj * (called from the software clock routine), then timertype tells which timer. 924731Swnj */ 934809Swnj tcp_usrreq(so, req, m, addr) 944809Swnj struct socket *so; 954809Swnj int req; 964731Swnj struct mbuf *m; 974809Swnj caddr_t addr; 984497Swnj { 99*4886Swnj register struct inpcb *inp = sotoinpcb(so); 100*4886Swnj register struct tcpcb *tp = intotcpcb(inp); 1014567Swnj int s = splnet(); 1024567Swnj register int nstate; 1034584Swnj #ifdef TCPDEBUG 1044584Swnj struct tcp_debug tdb; 1054584Swnj #endif 1064809Swnj int error = 0; 1074567Swnj COUNT(TCP_USRREQ); 1084497Swnj 109*4886Swnj /* 110*4886Swnj * Make sure attached. If not, 111*4886Swnj * only PRU_ATTACH is valid. 112*4886Swnj */ 1134809Swnj if (tp) { 1144809Swnj nstate = tp->t_state; 1154809Swnj tp->tc_flags &= ~TC_NET_KEEP; 116*4886Swnj } else 117*4886Swnj if (req != PRU_ATTACH) { 118*4886Swnj splx(s); 119*4886Swnj return (EINVAL); 120*4886Swnj } 121*4886Swnj 122*4886Swnj /* 123*4886Swnj * Do tracing and accounting. 124*4886Swnj */ 1254731Swnj #ifdef KPROF 1264809Swnj acounts[nstate][req]++; 1274731Swnj #endif 1284584Swnj #ifdef TCPDEBUG 1294809Swnj if (tp && ((tp->t_socket->so_options & SO_DEBUG) || tcpconsdebug)) { 130*4886Swnj tdb_setup(tp, (struct tcpiphdr *)0, req, &tdb); 1314584Swnj tdb.td_tim = timertype; 1324584Swnj } else 1334584Swnj tdb.td_tod = 0; 1344584Swnj #endif 1354809Swnj switch (req) { 1364497Swnj 1374809Swnj case PRU_ATTACH: 1384809Swnj if (tp) 1394809Swnj error = EISCONN; 140*4886Swnj else { 141*4886Swnj tcp_attach(so); 142*4886Swnj tp = sototcpcb(so); 143*4886Swnj } 144*4886Swnj if (so->so_options & SO_ACCEPTCONN) { 145*4886Swnj inp->inp_lhost = h_make(&n_lhost); 146*4886Swnj in_pcbgenport(&tcb, inp); 147*4886Swnj nstate = LISTEN; 148*4886Swnj } else 149*4886Swnj nstate = CLOSED; 1504567Swnj break; 1514497Swnj 1524809Swnj case PRU_DETACH: 153*4886Swnj tcp_detach(so); 1544809Swnj break; 1554809Swnj 1564809Swnj case PRU_CONNECT: 157*4886Swnj if (tp->t_state != 0 && tp->t_state != CLOSED) 1584731Swnj goto bad; 159*4886Swnj inp->inp_fhost = in_hmake((struct in_addr *)addr, &error); 160*4886Swnj if (inp->inp_fhost == 0) 161*4886Swnj break; 1624676Swnj tcp_sndctl(tp); 1634567Swnj nstate = SYN_SENT; 164*4886Swnj soisconnecting(so); 1654567Swnj break; 1664497Swnj 1674809Swnj case PRU_DISCONNECT: 168*4886Swnj if ((tp->tc_flags & TC_FIN_RCVD) == 0) 169*4886Swnj goto abort; 170*4886Swnj if (nstate < ESTAB) 171*4886Swnj tcp_disconnect(so); 172*4886Swnj else { 173*4886Swnj tp->tc_flags |= TC_SND_FIN; 174*4886Swnj tcp_sendctl(tp); 175*4886Swnj tp->tc_flags |= TC_USR_CLOSED; 176*4886Swnj soisdisconnecting(so); 177*4886Swnj } 1784809Swnj break; 1794809Swnj 1804809Swnj case PRU_SHUTDOWN: 1814731Swnj switch (nstate) { 1824497Swnj 1834731Swnj case LISTEN: 1844734Swnj case SYN_SENT: 1854731Swnj nstate = CLOSED; 1864731Swnj break; 1874731Swnj 1884734Swnj case SYN_RCVD: 1894731Swnj case L_SYN_RCVD: 1904731Swnj case ESTAB: 1914734Swnj case CLOSE_WAIT: 1924731Swnj tp->tc_flags |= TC_SND_FIN; 1934731Swnj tcp_sndctl(tp); 1944731Swnj tp->tc_flags |= TC_USR_CLOSED; 1954731Swnj nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK; 1964731Swnj break; 1974731Swnj 1984731Swnj case FIN_W1: 1994731Swnj case FIN_W2: 2004731Swnj case TIME_WAIT: 2014731Swnj case CLOSING: 2024731Swnj case LAST_ACK: 2034731Swnj case RCV_WAIT: 2044731Swnj break; 2054731Swnj 2064731Swnj default: 2074731Swnj goto bad; 2084731Swnj } 2094567Swnj break; 2104497Swnj 2114809Swnj case PRU_RCVD: 2124731Swnj if (nstate < ESTAB || nstate == CLOSED) 2134731Swnj goto bad; 2144734Swnj tcp_sndwin(tp); 2154691Swnj if ((tp->tc_flags&TC_FIN_RCVD) && 2164691Swnj (tp->tc_flags&TC_USR_CLOSED) == 0 && 2174691Swnj rcv_empty(tp)) 218*4886Swnj error = ESHUTDOWN; 2194809Swnj if (nstate == RCV_WAIT && rcv_empty(tp)) 2204567Swnj nstate = CLOSED; 2214567Swnj break; 2224497Swnj 2234809Swnj case PRU_SEND: 2244731Swnj switch (nstate) { 2254567Swnj 2264731Swnj case ESTAB: 2274731Swnj case CLOSE_WAIT: 228*4886Swnj tcp_usrsend(tp, m); 2294731Swnj break; 2304731Swnj 2314731Swnj default: 2324731Swnj if (nstate < ESTAB) 2334731Swnj goto bad; 2344809Swnj m_freem(m); 235*4886Swnj error = ENOTCONN; 2364731Swnj break; 2374731Swnj } 2384567Swnj break; 2394567Swnj 240*4886Swnj abort: 2414809Swnj case PRU_ABORT: 242*4886Swnj tcp_abort(tp); 2434567Swnj nstate = CLOSED; 2444567Swnj break; 2454567Swnj 2464809Swnj case PRU_CONTROL: 247*4886Swnj error = EOPNOTSUPP; 2484809Swnj break; 2494809Swnj 2504809Swnj case PRU_SLOWTIMO: 2514809Swnj switch (nstate) { 2524809Swnj 2534809Swnj case 0: 2544809Swnj case CLOSED: 2554809Swnj case LISTEN: 2564809Swnj goto bad; 2574809Swnj 2584809Swnj default: 2594809Swnj nstate = tcp_timers(tp, (int)addr); 2604809Swnj } 2614809Swnj break; 2624809Swnj 2634731Swnj default: 2644731Swnj panic("tcp_usrreq"); 2654731Swnj bad: 2664731Swnj printf("tcp: bad state: tcb=%x state=%d input=%d\n", 2674809Swnj tp, tp->t_state, req); 2684731Swnj nstate = EFAILEC; 2694567Swnj break; 2704567Swnj } 2714567Swnj #ifdef TCPDEBUG 2724605Swnj if (tdb.td_tod) 2734605Swnj tdb_stuff(&tdb, nstate); 2744567Swnj #endif 2754567Swnj switch (nstate) { 2764567Swnj 2774584Swnj case CLOSED: 2784567Swnj case SAME: 2794567Swnj break; 2804567Swnj 2814567Swnj case EFAILEC: 2824731Swnj if (m) 2834731Swnj m_freem(dtom(m)); 2844567Swnj break; 2854567Swnj 2864567Swnj default: 2874567Swnj tp->t_state = nstate; 2884567Swnj break; 2894567Swnj } 2904567Swnj splx(s); 291*4886Swnj return (error); 2924497Swnj } 2934497Swnj 2944809Swnj tcp_attach(so) 2954809Swnj register struct socket *so; 2964809Swnj { 297*4886Swnj register struct tcpcb *tp; 2984809Swnj COUNT(TCP_ATTACH); 2994497Swnj 3004682Swnj /* 301*4886Swnj * Make empty reassembly queue. 3024682Swnj */ 303*4886Swnj tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; 3044497Swnj 3054682Swnj /* 306*4886Swnj * Initialize sequence numbers and round trip retransmit timer. 3074682Swnj */ 3084567Swnj tp->t_xmtime = T_REXMT; 3094682Swnj tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una = 3104682Swnj tp->iss = tcp_iss; 3114567Swnj tp->snd_off = tp->iss + 1; 3124664Swnj tcp_iss += (ISSINCR >> 1) + 1; 3134497Swnj } 3144497Swnj 315*4886Swnj tcp_detach(so) 316*4886Swnj register struct socket *so; 3174497Swnj { 318*4886Swnj register struct tcpcb *tp = (struct tcpcb *)so->so_pcb; 319*4886Swnj register struct tcpiphdr *t; 3204567Swnj register struct mbuf *m; 3214809Swnj COUNT(TCP_DETACH); 3224497Swnj 323*4886Swnj wmemfree((caddr_t)tp, 1024); 324*4886Swnj m_release(so->so_rcv.sb_hiwat + so->so_snd.sb_hiwat + 2 * MSIZE); 325*4886Swnj } 326*4886Swnj 327*4886Swnj tcp_disconnect(tp) 328*4886Swnj register struct tcpcb *tp; 329*4886Swnj { 330*4886Swnj register struct tcpiphdr *t; 331*4886Swnj register struct mbuf *m; 332*4886Swnj register struct socket *so; 333*4886Swnj 3344734Swnj tcp_tcancel(tp); 335*4886Swnj t = tp->seg_next; 336*4886Swnj for (; t != (struct tcpiphdr *)tp; t = t->t_next) 3374567Swnj m_freem(dtom(t)); 338*4886Swnj tcp_drainunack(tp); 3394734Swnj if (tp->t_template) { 3404734Swnj m_free(dtom(tp->t_template)); 3414734Swnj tp->t_template = 0; 3424664Swnj } 343*4886Swnj in_pcbfree(tp->t_inpcb); 3444497Swnj } 3454497Swnj 346*4886Swnj tcp_abort(so) 347*4886Swnj register struct socket *so; 348*4886Swnj { 349*4886Swnj register struct tcpcb *tp = sototcpcb(so); 350*4886Swnj 351*4886Swnj switch (tp->t_state) { 352*4886Swnj 353*4886Swnj case SYN_RCVD: 354*4886Swnj case ESTAB: 355*4886Swnj case FIN_W1: 356*4886Swnj case FIN_W2: 357*4886Swnj case CLOSE_WAIT: 358*4886Swnj tp->tc_flags |= TC_SND_RST; 359*4886Swnj tcp_sndnull(tp); 360*4886Swnj } 361*4886Swnj if (so) 362*4886Swnj soisdisconnected(so); 363*4886Swnj } 364*4886Swnj 3654682Swnj /* 3664734Swnj * Send data queue headed by m0 into the protocol. 3674682Swnj */ 3684678Swnj tcp_usrsend(tp, m0) 369*4886Swnj register struct tcpcb *tp; 3704584Swnj struct mbuf *m0; 3714497Swnj { 3724497Swnj register struct mbuf *m, *n; 373*4886Swnj register struct socket *so = tp->t_inpcb->inp_socket; 3744497Swnj register off; 3754574Swnj seq_t last; 3764682Swnj COUNT(TCP_USRSEND); 3774497Swnj 378*4886Swnj sbappend(&so->so_snd, m0); 3794809Swnj if (tp->t_options & TO_EOL) 380*4886Swnj tp->snd_end = tp->snd_off + so->so_snd.sb_cc; 3814809Swnj if (tp->t_options & TO_URG) { 382*4886Swnj tp->snd_urp = tp->snd_off + so->so_snd.sb_cc + 1; 3834576Swnj tp->tc_flags |= TC_SND_URG; 3844567Swnj } 3854678Swnj tcp_send(tp); 3864497Swnj } 3874497Swnj 3884682Swnj /* 3894682Swnj * TCP timer went off processing. 3904682Swnj */ 3914584Swnj tcp_timers(tp, timertype) 392*4886Swnj register struct tcpcb *tp; 3934584Swnj int timertype; 3944497Swnj { 3954497Swnj 3964567Swnj COUNT(TCP_TIMERS); 3974584Swnj switch (timertype) { 3984497Swnj 3994567Swnj case TFINACK: /* fin-ack timer */ 4004567Swnj switch (tp->t_state) { 4014497Swnj 4024567Swnj case TIME_WAIT: 4034567Swnj /* 4044567Swnj * We can be sure our ACK of foreign FIN was rcvd, 4054567Swnj * and can close if no data left for user. 4064567Swnj */ 4074567Swnj if (rcv_empty(tp)) { 408*4886Swnj tcp_disconnect(tp); 4094567Swnj return (CLOSED); 4104567Swnj } 4114567Swnj return (RCV_WAIT); /* 17 */ 4124497Swnj 4134731Swnj case CLOSING: 4144576Swnj tp->tc_flags |= TC_WAITED_2_ML; 4154567Swnj return (SAME); 4164497Swnj 4174567Swnj default: 4184567Swnj return (SAME); 4194567Swnj } 4204497Swnj 4214567Swnj case TREXMT: /* retransmission timer */ 4224567Swnj if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ 4234567Swnj /* 4244809Swnj * Set so for a retransmission, increase rexmt time 4254567Swnj * in case of multiple retransmissions. 4264567Swnj */ 4274567Swnj tp->snd_nxt = tp->snd_una; 4284576Swnj tp->tc_flags |= TC_REXMT; 4294567Swnj tp->t_xmtime = tp->t_xmtime << 1; 4304567Swnj if (tp->t_xmtime > T_REMAX) 4314567Swnj tp->t_xmtime = T_REMAX; 4324678Swnj tcp_send(tp); 4334567Swnj } 4344567Swnj return (SAME); 4354497Swnj 4364567Swnj case TREXMTTL: /* retransmit too long */ 4374567Swnj if (tp->t_rtl_val > tp->snd_una) /* 36 */ 438*4886Swnj tcp_error(EIO); /* URXTIMO !?! */ 4394567Swnj /* 4404567Swnj * If user has already closed, abort the connection. 4414567Swnj */ 4424576Swnj if (tp->tc_flags & TC_USR_CLOSED) { 443*4886Swnj tcp_abort(tp); 4444567Swnj return (CLOSED); 4454567Swnj } 4464567Swnj return (SAME); 4474497Swnj 4484567Swnj case TPERSIST: /* persist timer */ 4494567Swnj /* 4504567Swnj * Force a byte send through closed window. 4514567Swnj */ 4524576Swnj tp->tc_flags |= TC_FORCE_ONE; 4534678Swnj tcp_send(tp); 4544567Swnj return (SAME); 4554567Swnj } 4564567Swnj panic("tcp_timers"); 4574497Swnj } 4584497Swnj 459*4886Swnj tcp_sense(m) 460*4886Swnj struct mbuf *m; 461*4886Swnj { 462*4886Swnj 463*4886Swnj return (EOPNOTSUPP); 464*4886Swnj } 465*4886Swnj 4664809Swnj tcp_error(so, errno) 4674809Swnj struct socket *so; 4684809Swnj int errno; 4694497Swnj { 4704567Swnj COUNT(TO_USER); 4714497Swnj 4724809Swnj so->so_error = errno; 473*4886Swnj sorwakeup(so); 474*4886Swnj sowwakeup(so); 4754497Swnj } 4764584Swnj 4774584Swnj #ifdef TCPDEBUG 4784682Swnj /* 4794682Swnj * TCP debugging utility subroutines. 4804682Swnj * THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID. 4814682Swnj */ 4824670Swnj tdb_setup(tp, n, input, tdp) 483*4886Swnj struct tcpcb *tp; 484*4886Swnj register struct tcpiphdr *n; 4854670Swnj int input; 4864670Swnj register struct tcp_debug *tdp; 4874670Swnj { 4884670Swnj 4894682Swnj COUNT(TDB_SETUP); 4904670Swnj tdp->td_tod = time; 4914670Swnj tdp->td_tcb = tp; 4924670Swnj tdp->td_old = tp->t_state; 4934670Swnj tdp->td_inp = input; 4944670Swnj tdp->td_tim = 0; 4954670Swnj tdp->td_new = -1; 4964670Swnj if (n) { 4974670Swnj tdp->td_sno = n->t_seq; 4984670Swnj tdp->td_ano = n->t_ackno; 4994670Swnj tdp->td_wno = n->t_win; 5004670Swnj tdp->td_lno = n->t_len; 5014670Swnj tdp->td_flg = n->th_flags; 5024670Swnj } else 5034670Swnj tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno = 5044670Swnj tdp->td_flg = 0; 5054670Swnj } 5064670Swnj 5074670Swnj tdb_stuff(tdp, nstate) 5084670Swnj struct tcp_debug *tdp; 5094670Swnj int nstate; 5104670Swnj { 5114682Swnj COUNT(TDB_STUFF); 5124670Swnj 5134670Swnj tdp->td_new = nstate; 5144670Swnj tcp_debug[tdbx++ % TDBSIZE] = *tdp; 5154670Swnj if (tcpconsdebug & 2) 5164670Swnj tcp_prt(tdp); 5174670Swnj } 5184682Swnj 5194682Swnj tcp_prt(tdp) 5204682Swnj register struct tcp_debug *tdp; 5214682Swnj { 5224682Swnj COUNT(TCP_PRT); 5234682Swnj 5244698Swnj printf("%x ", ((int)tdp->td_tcb)&0xffffff); 5254698Swnj if (tdp->td_inp == INSEND) { 5264698Swnj printf("SEND #%x", tdp->td_sno); 5274698Swnj tdp->td_lno = ntohs(tdp->td_lno); 5284698Swnj tdp->td_wno = ntohs(tdp->td_wno); 5294698Swnj } else { 5304698Swnj if (tdp->td_inp == INRECV) 5314698Swnj printf("RCV #%x ", tdp->td_sno); 5324698Swnj printf("%s.%s", 5334698Swnj tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]); 5344698Swnj if (tdp->td_inp == ISTIMER) 5354698Swnj printf("(%s)", tcptimers[tdp->td_tim]); 5364698Swnj printf(" -> %s", 5374698Swnj tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]); 5384698Swnj if (tdp->td_new == -1) 5394698Swnj printf(" (FAILED)"); 5404698Swnj } 5414682Swnj /* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */ 5424698Swnj if (tdp->td_lno) 5434698Swnj printf(" len=%d", tdp->td_lno); 5444698Swnj if (tdp->td_wno) 5454698Swnj printf(" win=%d", tdp->td_wno); 5464698Swnj if (tdp->td_flg & TH_FIN) printf(" FIN"); 5474698Swnj if (tdp->td_flg & TH_SYN) printf(" SYN"); 5484698Swnj if (tdp->td_flg & TH_RST) printf(" RST"); 5494698Swnj if (tdp->td_flg & TH_EOL) printf(" EOL"); 5504698Swnj if (tdp->td_flg & TH_ACK) printf(" ACK %x", tdp->td_ano); 5514698Swnj if (tdp->td_flg & TH_URG) printf(" URG"); 5524682Swnj printf("\n"); 5534682Swnj } 5544670Swnj #endif 555