1*4900Swnj /* tcp_usrreq.c 1.28 81/11/15 */ 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" 104886Swnj #include "../net/inet_host.h" 114886Swnj #include "../net/inet_pcb.h" 124809Swnj #include "../net/inet_systm.h" 134809Swnj #include "../net/imp.h" 144809Swnj #include "../net/ip.h" 15*4900Swnj #include "../net/ip_var.h" 164809Swnj #include "../net/tcp.h" 174567Swnj #define TCPFSTAB 184584Swnj #ifdef TCPDEBUG 194584Swnj #define TCPSTATES 204584Swnj #endif 214809Swnj #include "../net/tcp_fsm.h" 224809Swnj #include "../net/tcp_var.h" 234809Swnj #include "/usr/include/errno.h" 244497Swnj 254734Swnj /* 264809Swnj * Tcp initialization 274809Swnj */ 284809Swnj tcp_init() 294809Swnj { 304809Swnj 314809Swnj tcp_iss = 1; /* wrong */ 324886Swnj tcb.inp_next = tcb.inp_prev = &tcb; 334809Swnj } 344809Swnj 354809Swnj /* 364734Swnj * Tcp finite state machine entries for timer and user generated 374734Swnj * requests. These routines raise the ipl to that of the network 384734Swnj * to prevent reentry. In particluar, this requires that the software 394734Swnj * clock interrupt have lower priority than the network so that 404734Swnj * we can enter the network from timeout routines without improperly 414734Swnj * nesting the interrupt stack. 424734Swnj */ 434734Swnj 444734Swnj /* 454809Swnj * Tcp protocol timeout routine called every 500 ms. 464734Swnj * Updates the timers in all active tcb's and 474734Swnj * causes finite state machine actions if timers expire. 484734Swnj */ 494809Swnj tcp_slowtimo() 504497Swnj { 514886Swnj register struct inpcb *ip; 524886Swnj register struct tcpcb *tp; 534567Swnj int s = splnet(); 544809Swnj register short *tmp; 554731Swnj register int i; 564567Swnj COUNT(TCP_TIMEO); 574497Swnj 584567Swnj /* 594567Swnj * Search through tcb's and update active timers. 604567Swnj */ 614886Swnj for (ip = tcb.inp_next; ip != &tcb; ip = ip->inp_next) { 624886Swnj tp = intotcpcb(ip); 634731Swnj tmp = &tp->t_init; 644735Swnj for (i = 0; i < TNTIMERS; i++) { 654731Swnj if (*tmp && --*tmp == 0) 664886Swnj tcp_usrreq(tp->t_inpcb->inp_socket, 674886Swnj PRU_SLOWTIMO, 0, i); 684735Swnj tmp++; 694735Swnj } 704567Swnj tp->t_xmt++; 714567Swnj } 724809Swnj tcp_iss += ISSINCR/2; /* increment iss */ 734567Swnj splx(s); 744497Swnj } 754497Swnj 764731Swnj /* 774734Swnj * Cancel all timers for tcp tp. 784734Swnj */ 794734Swnj tcp_tcancel(tp) 804886Swnj struct tcpcb *tp; 814734Swnj { 824809Swnj register short *tmp = &tp->t_init; 834734Swnj register int i; 844734Swnj 854734Swnj for (i = 0; i < TNTIMERS; i++) 864734Swnj *tmp++ = 0; 874734Swnj } 884734Swnj 894734Swnj /* 904731Swnj * Process a TCP user request for tcp tb. If this is a send request 914731Swnj * then m is the mbuf chain of send data. If this is a timer expiration 924731Swnj * (called from the software clock routine), then timertype tells which timer. 934731Swnj */ 944809Swnj tcp_usrreq(so, req, m, addr) 954809Swnj struct socket *so; 964809Swnj int req; 974731Swnj struct mbuf *m; 984809Swnj caddr_t addr; 994497Swnj { 1004886Swnj register struct inpcb *inp = sotoinpcb(so); 1014886Swnj register struct tcpcb *tp = intotcpcb(inp); 1024567Swnj int s = splnet(); 1034567Swnj register int nstate; 1044584Swnj #ifdef TCPDEBUG 1054584Swnj struct tcp_debug tdb; 1064584Swnj #endif 1074809Swnj int error = 0; 1084567Swnj COUNT(TCP_USRREQ); 1094497Swnj 1104886Swnj /* 1114886Swnj * Make sure attached. If not, 1124886Swnj * only PRU_ATTACH is valid. 1134886Swnj */ 1144809Swnj if (tp) { 1154809Swnj nstate = tp->t_state; 1164809Swnj tp->tc_flags &= ~TC_NET_KEEP; 1174886Swnj } else 1184886Swnj if (req != PRU_ATTACH) { 1194886Swnj splx(s); 1204886Swnj return (EINVAL); 1214886Swnj } 1224886Swnj 1234886Swnj /* 1244886Swnj * Do tracing and accounting. 1254886Swnj */ 1264731Swnj #ifdef KPROF 1274809Swnj acounts[nstate][req]++; 1284731Swnj #endif 1294584Swnj #ifdef TCPDEBUG 1304809Swnj if (tp && ((tp->t_socket->so_options & SO_DEBUG) || tcpconsdebug)) { 1314886Swnj tdb_setup(tp, (struct tcpiphdr *)0, req, &tdb); 1324584Swnj tdb.td_tim = timertype; 1334584Swnj } else 1344584Swnj tdb.td_tod = 0; 1354584Swnj #endif 1364809Swnj switch (req) { 1374497Swnj 1384809Swnj case PRU_ATTACH: 1394809Swnj if (tp) 1404809Swnj error = EISCONN; 1414886Swnj else { 1424886Swnj tcp_attach(so); 1434886Swnj tp = sototcpcb(so); 1444886Swnj } 1454886Swnj if (so->so_options & SO_ACCEPTCONN) { 146*4900Swnj inp->inp_lhost = in_hmake(&n_lhost); 1474886Swnj in_pcbgenport(&tcb, inp); 1484886Swnj nstate = LISTEN; 1494886Swnj } else 1504886Swnj nstate = CLOSED; 1514567Swnj break; 1524497Swnj 1534809Swnj case PRU_DETACH: 1544886Swnj tcp_detach(so); 1554809Swnj break; 1564809Swnj 1574809Swnj case PRU_CONNECT: 1584886Swnj if (tp->t_state != 0 && tp->t_state != CLOSED) 1594731Swnj goto bad; 1604886Swnj inp->inp_fhost = in_hmake((struct in_addr *)addr, &error); 1614886Swnj if (inp->inp_fhost == 0) 1624886Swnj break; 1634676Swnj tcp_sndctl(tp); 1644567Swnj nstate = SYN_SENT; 1654886Swnj soisconnecting(so); 1664567Swnj break; 1674497Swnj 1684809Swnj case PRU_DISCONNECT: 1694886Swnj if ((tp->tc_flags & TC_FIN_RCVD) == 0) 1704886Swnj goto abort; 1714886Swnj if (nstate < ESTAB) 1724886Swnj tcp_disconnect(so); 1734886Swnj else { 1744886Swnj tp->tc_flags |= TC_SND_FIN; 1754886Swnj tcp_sendctl(tp); 1764886Swnj tp->tc_flags |= TC_USR_CLOSED; 1774886Swnj soisdisconnecting(so); 1784886Swnj } 1794809Swnj break; 1804809Swnj 1814809Swnj case PRU_SHUTDOWN: 1824731Swnj switch (nstate) { 1834497Swnj 1844731Swnj case LISTEN: 1854734Swnj case SYN_SENT: 1864731Swnj nstate = CLOSED; 1874731Swnj break; 1884731Swnj 1894734Swnj case SYN_RCVD: 1904731Swnj case L_SYN_RCVD: 1914731Swnj case ESTAB: 1924734Swnj case CLOSE_WAIT: 1934731Swnj tp->tc_flags |= TC_SND_FIN; 1944731Swnj tcp_sndctl(tp); 1954731Swnj tp->tc_flags |= TC_USR_CLOSED; 1964731Swnj nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK; 1974731Swnj break; 1984731Swnj 1994731Swnj case FIN_W1: 2004731Swnj case FIN_W2: 2014731Swnj case TIME_WAIT: 2024731Swnj case CLOSING: 2034731Swnj case LAST_ACK: 2044731Swnj case RCV_WAIT: 2054731Swnj break; 2064731Swnj 2074731Swnj default: 2084731Swnj goto bad; 2094731Swnj } 2104567Swnj break; 2114497Swnj 2124809Swnj case PRU_RCVD: 2134731Swnj if (nstate < ESTAB || nstate == CLOSED) 2144731Swnj goto bad; 2154734Swnj tcp_sndwin(tp); 2164691Swnj if ((tp->tc_flags&TC_FIN_RCVD) && 2174691Swnj (tp->tc_flags&TC_USR_CLOSED) == 0 && 2184691Swnj rcv_empty(tp)) 2194886Swnj error = ESHUTDOWN; 2204809Swnj if (nstate == RCV_WAIT && rcv_empty(tp)) 2214567Swnj nstate = CLOSED; 2224567Swnj break; 2234497Swnj 2244809Swnj case PRU_SEND: 2254731Swnj switch (nstate) { 2264567Swnj 2274731Swnj case ESTAB: 2284731Swnj case CLOSE_WAIT: 2294886Swnj tcp_usrsend(tp, m); 2304731Swnj break; 2314731Swnj 2324731Swnj default: 2334731Swnj if (nstate < ESTAB) 2344731Swnj goto bad; 2354809Swnj m_freem(m); 2364886Swnj error = ENOTCONN; 2374731Swnj break; 2384731Swnj } 2394567Swnj break; 2404567Swnj 2414886Swnj abort: 2424809Swnj case PRU_ABORT: 2434886Swnj tcp_abort(tp); 2444567Swnj nstate = CLOSED; 2454567Swnj break; 2464567Swnj 2474809Swnj case PRU_CONTROL: 2484886Swnj error = EOPNOTSUPP; 2494809Swnj break; 2504809Swnj 2514809Swnj case PRU_SLOWTIMO: 2524809Swnj switch (nstate) { 2534809Swnj 2544809Swnj case 0: 2554809Swnj case CLOSED: 2564809Swnj case LISTEN: 2574809Swnj goto bad; 2584809Swnj 2594809Swnj default: 2604809Swnj nstate = tcp_timers(tp, (int)addr); 2614809Swnj } 2624809Swnj break; 2634809Swnj 2644731Swnj default: 2654731Swnj panic("tcp_usrreq"); 2664731Swnj bad: 2674731Swnj printf("tcp: bad state: tcb=%x state=%d input=%d\n", 2684809Swnj tp, tp->t_state, req); 2694731Swnj nstate = EFAILEC; 2704567Swnj break; 2714567Swnj } 2724567Swnj #ifdef TCPDEBUG 2734605Swnj if (tdb.td_tod) 2744605Swnj tdb_stuff(&tdb, nstate); 2754567Swnj #endif 2764567Swnj switch (nstate) { 2774567Swnj 2784584Swnj case CLOSED: 2794567Swnj case SAME: 2804567Swnj break; 2814567Swnj 2824567Swnj case EFAILEC: 2834731Swnj if (m) 2844731Swnj m_freem(dtom(m)); 2854567Swnj break; 2864567Swnj 2874567Swnj default: 2884567Swnj tp->t_state = nstate; 2894567Swnj break; 2904567Swnj } 2914567Swnj splx(s); 2924886Swnj return (error); 2934497Swnj } 2944497Swnj 2954809Swnj tcp_attach(so) 2964809Swnj register struct socket *so; 2974809Swnj { 2984886Swnj register struct tcpcb *tp; 2994809Swnj COUNT(TCP_ATTACH); 3004497Swnj 3014682Swnj /* 3024886Swnj * Make empty reassembly queue. 3034682Swnj */ 3044886Swnj tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; 3054497Swnj 3064682Swnj /* 3074886Swnj * Initialize sequence numbers and round trip retransmit timer. 3084682Swnj */ 3094567Swnj tp->t_xmtime = T_REXMT; 3104682Swnj tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una = 3114682Swnj tp->iss = tcp_iss; 3124567Swnj tp->snd_off = tp->iss + 1; 3134664Swnj tcp_iss += (ISSINCR >> 1) + 1; 3144497Swnj } 3154497Swnj 3164886Swnj tcp_detach(so) 3174886Swnj register struct socket *so; 3184497Swnj { 3194886Swnj register struct tcpcb *tp = (struct tcpcb *)so->so_pcb; 3204886Swnj register struct tcpiphdr *t; 3214567Swnj register struct mbuf *m; 3224809Swnj COUNT(TCP_DETACH); 3234497Swnj 3244886Swnj wmemfree((caddr_t)tp, 1024); 3254886Swnj m_release(so->so_rcv.sb_hiwat + so->so_snd.sb_hiwat + 2 * MSIZE); 3264886Swnj } 3274886Swnj 3284886Swnj tcp_disconnect(tp) 3294886Swnj register struct tcpcb *tp; 3304886Swnj { 3314886Swnj register struct tcpiphdr *t; 3324886Swnj register struct mbuf *m; 3334886Swnj register struct socket *so; 3344886Swnj 3354734Swnj tcp_tcancel(tp); 3364886Swnj t = tp->seg_next; 337*4900Swnj for (; t != (struct tcpiphdr *)tp; t = (struct tcpiphdr *)t->ti_next) 3384567Swnj m_freem(dtom(t)); 3394886Swnj tcp_drainunack(tp); 3404734Swnj if (tp->t_template) { 3414734Swnj m_free(dtom(tp->t_template)); 3424734Swnj tp->t_template = 0; 3434664Swnj } 3444886Swnj in_pcbfree(tp->t_inpcb); 3454497Swnj } 3464497Swnj 3474886Swnj tcp_abort(so) 3484886Swnj register struct socket *so; 3494886Swnj { 3504886Swnj register struct tcpcb *tp = sototcpcb(so); 3514886Swnj 3524886Swnj switch (tp->t_state) { 3534886Swnj 3544886Swnj case SYN_RCVD: 3554886Swnj case ESTAB: 3564886Swnj case FIN_W1: 3574886Swnj case FIN_W2: 3584886Swnj case CLOSE_WAIT: 3594886Swnj tp->tc_flags |= TC_SND_RST; 3604886Swnj tcp_sndnull(tp); 3614886Swnj } 3624886Swnj if (so) 3634886Swnj soisdisconnected(so); 3644886Swnj } 3654886Swnj 3664682Swnj /* 3674734Swnj * Send data queue headed by m0 into the protocol. 3684682Swnj */ 3694678Swnj tcp_usrsend(tp, m0) 3704886Swnj register struct tcpcb *tp; 3714584Swnj struct mbuf *m0; 3724497Swnj { 3734497Swnj register struct mbuf *m, *n; 3744886Swnj register struct socket *so = tp->t_inpcb->inp_socket; 3754497Swnj register off; 3764574Swnj seq_t last; 3774682Swnj COUNT(TCP_USRSEND); 3784497Swnj 3794886Swnj sbappend(&so->so_snd, m0); 3804809Swnj if (tp->t_options & TO_EOL) 3814886Swnj tp->snd_end = tp->snd_off + so->so_snd.sb_cc; 3824809Swnj if (tp->t_options & TO_URG) { 3834886Swnj tp->snd_urp = tp->snd_off + so->so_snd.sb_cc + 1; 3844576Swnj tp->tc_flags |= TC_SND_URG; 3854567Swnj } 3864678Swnj tcp_send(tp); 3874497Swnj } 3884497Swnj 3894682Swnj /* 3904682Swnj * TCP timer went off processing. 3914682Swnj */ 3924584Swnj tcp_timers(tp, timertype) 3934886Swnj register struct tcpcb *tp; 3944584Swnj int timertype; 3954497Swnj { 3964497Swnj 3974567Swnj COUNT(TCP_TIMERS); 3984584Swnj switch (timertype) { 3994497Swnj 4004567Swnj case TFINACK: /* fin-ack timer */ 4014567Swnj switch (tp->t_state) { 4024497Swnj 4034567Swnj case TIME_WAIT: 4044567Swnj /* 4054567Swnj * We can be sure our ACK of foreign FIN was rcvd, 4064567Swnj * and can close if no data left for user. 4074567Swnj */ 4084567Swnj if (rcv_empty(tp)) { 4094886Swnj tcp_disconnect(tp); 4104567Swnj return (CLOSED); 4114567Swnj } 4124567Swnj return (RCV_WAIT); /* 17 */ 4134497Swnj 4144731Swnj case CLOSING: 4154576Swnj tp->tc_flags |= TC_WAITED_2_ML; 4164567Swnj return (SAME); 4174497Swnj 4184567Swnj default: 4194567Swnj return (SAME); 4204567Swnj } 4214497Swnj 4224567Swnj case TREXMT: /* retransmission timer */ 4234567Swnj if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ 4244567Swnj /* 4254809Swnj * Set so for a retransmission, increase rexmt time 4264567Swnj * in case of multiple retransmissions. 4274567Swnj */ 4284567Swnj tp->snd_nxt = tp->snd_una; 4294576Swnj tp->tc_flags |= TC_REXMT; 4304567Swnj tp->t_xmtime = tp->t_xmtime << 1; 4314567Swnj if (tp->t_xmtime > T_REMAX) 4324567Swnj tp->t_xmtime = T_REMAX; 4334678Swnj tcp_send(tp); 4344567Swnj } 4354567Swnj return (SAME); 4364497Swnj 4374567Swnj case TREXMTTL: /* retransmit too long */ 4384567Swnj if (tp->t_rtl_val > tp->snd_una) /* 36 */ 4394886Swnj tcp_error(EIO); /* URXTIMO !?! */ 4404567Swnj /* 4414567Swnj * If user has already closed, abort the connection. 4424567Swnj */ 4434576Swnj if (tp->tc_flags & TC_USR_CLOSED) { 4444886Swnj tcp_abort(tp); 4454567Swnj return (CLOSED); 4464567Swnj } 4474567Swnj return (SAME); 4484497Swnj 4494567Swnj case TPERSIST: /* persist timer */ 4504567Swnj /* 4514567Swnj * Force a byte send through closed window. 4524567Swnj */ 4534576Swnj tp->tc_flags |= TC_FORCE_ONE; 4544678Swnj tcp_send(tp); 4554567Swnj return (SAME); 4564567Swnj } 4574567Swnj panic("tcp_timers"); 4584497Swnj } 4594497Swnj 4604886Swnj tcp_sense(m) 4614886Swnj struct mbuf *m; 4624886Swnj { 4634886Swnj 4644886Swnj return (EOPNOTSUPP); 4654886Swnj } 4664886Swnj 4674809Swnj tcp_error(so, errno) 4684809Swnj struct socket *so; 4694809Swnj int errno; 4704497Swnj { 4714567Swnj COUNT(TO_USER); 4724497Swnj 4734809Swnj so->so_error = errno; 4744886Swnj sorwakeup(so); 4754886Swnj sowwakeup(so); 4764497Swnj } 4774584Swnj 4784584Swnj #ifdef TCPDEBUG 4794682Swnj /* 4804682Swnj * TCP debugging utility subroutines. 4814682Swnj * THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID. 4824682Swnj */ 4834670Swnj tdb_setup(tp, n, input, tdp) 4844886Swnj struct tcpcb *tp; 4854886Swnj register struct tcpiphdr *n; 4864670Swnj int input; 4874670Swnj register struct tcp_debug *tdp; 4884670Swnj { 4894670Swnj 4904682Swnj COUNT(TDB_SETUP); 4914670Swnj tdp->td_tod = time; 4924670Swnj tdp->td_tcb = tp; 4934670Swnj tdp->td_old = tp->t_state; 4944670Swnj tdp->td_inp = input; 4954670Swnj tdp->td_tim = 0; 4964670Swnj tdp->td_new = -1; 4974670Swnj if (n) { 498*4900Swnj tdp->td_sno = n->ti_seq; 499*4900Swnj tdp->td_ano = n->ti_ackno; 5004670Swnj tdp->td_wno = n->t_win; 501*4900Swnj tdp->td_lno = n->ti_len; 502*4900Swnj tdp->td_flg = n->ti_flags; 5034670Swnj } else 5044670Swnj tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno = 5054670Swnj tdp->td_flg = 0; 5064670Swnj } 5074670Swnj 5084670Swnj tdb_stuff(tdp, nstate) 5094670Swnj struct tcp_debug *tdp; 5104670Swnj int nstate; 5114670Swnj { 5124682Swnj COUNT(TDB_STUFF); 5134670Swnj 5144670Swnj tdp->td_new = nstate; 5154670Swnj tcp_debug[tdbx++ % TDBSIZE] = *tdp; 5164670Swnj if (tcpconsdebug & 2) 5174670Swnj tcp_prt(tdp); 5184670Swnj } 5194682Swnj 5204682Swnj tcp_prt(tdp) 5214682Swnj register struct tcp_debug *tdp; 5224682Swnj { 5234682Swnj COUNT(TCP_PRT); 5244682Swnj 5254698Swnj printf("%x ", ((int)tdp->td_tcb)&0xffffff); 5264698Swnj if (tdp->td_inp == INSEND) { 5274698Swnj printf("SEND #%x", tdp->td_sno); 5284698Swnj tdp->td_lno = ntohs(tdp->td_lno); 5294698Swnj tdp->td_wno = ntohs(tdp->td_wno); 5304698Swnj } else { 5314698Swnj if (tdp->td_inp == INRECV) 5324698Swnj printf("RCV #%x ", tdp->td_sno); 5334698Swnj printf("%s.%s", 5344698Swnj tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]); 5354698Swnj if (tdp->td_inp == ISTIMER) 5364698Swnj printf("(%s)", tcptimers[tdp->td_tim]); 5374698Swnj printf(" -> %s", 5384698Swnj tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]); 5394698Swnj if (tdp->td_new == -1) 5404698Swnj printf(" (FAILED)"); 5414698Swnj } 5424682Swnj /* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */ 5434698Swnj if (tdp->td_lno) 5444698Swnj printf(" len=%d", tdp->td_lno); 5454698Swnj if (tdp->td_wno) 5464698Swnj printf(" win=%d", tdp->td_wno); 5474698Swnj if (tdp->td_flg & TH_FIN) printf(" FIN"); 5484698Swnj if (tdp->td_flg & TH_SYN) printf(" SYN"); 5494698Swnj if (tdp->td_flg & TH_RST) printf(" RST"); 5504698Swnj if (tdp->td_flg & TH_EOL) printf(" EOL"); 5514698Swnj if (tdp->td_flg & TH_ACK) printf(" ACK %x", tdp->td_ano); 5524698Swnj if (tdp->td_flg & TH_URG) printf(" URG"); 5534682Swnj printf("\n"); 5544682Swnj } 5554670Swnj #endif 556