1*4925Swnj /* tcp_usrreq.c 1.30 81/11/18 */ 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" 154900Swnj #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) 664911Swnj (void) tcp_usrreq(tp->t_inpcb->inp_socket, 674911Swnj PRU_SLOWTIMO, (struct mbuf *)0, 684911Swnj (caddr_t)i); 694735Swnj tmp++; 704735Swnj } 714567Swnj tp->t_xmt++; 724567Swnj } 734809Swnj tcp_iss += ISSINCR/2; /* increment iss */ 744567Swnj splx(s); 754497Swnj } 764497Swnj 774731Swnj /* 784734Swnj * Cancel all timers for tcp tp. 794734Swnj */ 804734Swnj tcp_tcancel(tp) 814886Swnj struct tcpcb *tp; 824734Swnj { 834809Swnj register short *tmp = &tp->t_init; 844734Swnj register int i; 854734Swnj 864734Swnj for (i = 0; i < TNTIMERS; i++) 874734Swnj *tmp++ = 0; 884734Swnj } 894734Swnj 904734Swnj /* 914731Swnj * Process a TCP user request for tcp tb. If this is a send request 924731Swnj * then m is the mbuf chain of send data. If this is a timer expiration 934731Swnj * (called from the software clock routine), then timertype tells which timer. 944731Swnj */ 954809Swnj tcp_usrreq(so, req, m, addr) 964809Swnj struct socket *so; 974809Swnj int req; 984731Swnj struct mbuf *m; 994809Swnj caddr_t addr; 1004497Swnj { 1014886Swnj register struct inpcb *inp = sotoinpcb(so); 1024911Swnj register struct tcpcb *tp; 1034567Swnj int s = splnet(); 1044567Swnj register int nstate; 1054584Swnj #ifdef TCPDEBUG 1064584Swnj struct tcp_debug tdb; 1074584Swnj #endif 1084809Swnj int error = 0; 1094567Swnj COUNT(TCP_USRREQ); 1104497Swnj 1114886Swnj /* 1124886Swnj * Make sure attached. If not, 1134886Swnj * only PRU_ATTACH is valid. 1144886Swnj */ 1154911Swnj #ifdef TCPDEBUG 1164911Swnj tdb.td_tod = 0; 1174911Swnj #endif 1184911Swnj if (inp == 0) { 1194886Swnj if (req != PRU_ATTACH) { 1204886Swnj splx(s); 1214886Swnj return (EINVAL); 1224886Swnj } 1234911Swnj } else { 1244911Swnj tp = intotcpcb(inp); 1254911Swnj nstate = tp->t_state; 1264731Swnj #ifdef KPROF 1274911Swnj tcp_acounts[nstate][req]++; 1284731Swnj #endif 1294584Swnj #ifdef TCPDEBUG 1304911Swnj if (((tp->t_socket->so_options & SO_DEBUG) || tcpconsdebug)) { 1314911Swnj tdb_setup(tp, (struct tcpiphdr *)0, req, &tdb); 1324911Swnj tdb.td_tim = timertype; 1334911Swnj } 1344584Swnj #endif 1354911Swnj tp->tc_flags &= ~TC_NET_KEEP; 1364911Swnj } 1374911Swnj 1384809Swnj switch (req) { 1394497Swnj 1404809Swnj case PRU_ATTACH: 1414911Swnj if (tp) { 1424809Swnj error = EISCONN; 1434911Swnj break; 1444886Swnj } 1454911Swnj tcp_attach(so); 1464911Swnj tp = sototcpcb(so); 1474886Swnj if (so->so_options & SO_ACCEPTCONN) { 1484911Swnj inp->inp_lhost = in_hostalloc(&n_lhost); /*XXX*/ 1494911Swnj inp->inp_lport = in_pcbgenport(&tcb); 1504886Swnj nstate = LISTEN; 1514886Swnj } else 1524886Swnj nstate = CLOSED; 1534567Swnj break; 1544497Swnj 1554809Swnj case PRU_DETACH: 1564911Swnj tcp_detach(tp); 1574809Swnj break; 1584809Swnj 1594809Swnj case PRU_CONNECT: 1604886Swnj if (tp->t_state != 0 && tp->t_state != CLOSED) 1614731Swnj goto bad; 162*4925Swnj inp->inp_fhost = in_hosteval((struct sockaddr *)addr, &error); 1634886Swnj if (inp->inp_fhost == 0) 1644886Swnj break; 1654911Swnj (void) tcp_sndctl(tp); 1664567Swnj nstate = SYN_SENT; 1674886Swnj soisconnecting(so); 1684567Swnj break; 1694497Swnj 170*4925Swnj case PRU_ACCEPT: 171*4925Swnj return (EOPNOTSUPP); /* XXX */ 172*4925Swnj 1734809Swnj case PRU_DISCONNECT: 1744886Swnj if ((tp->tc_flags & TC_FIN_RCVD) == 0) 1754886Swnj goto abort; 1764886Swnj if (nstate < ESTAB) 1774911Swnj tcp_disconnect(tp); 1784886Swnj else { 1794886Swnj tp->tc_flags |= TC_SND_FIN; 1804911Swnj (void) tcp_sndctl(tp); 1814886Swnj tp->tc_flags |= TC_USR_CLOSED; 1824886Swnj soisdisconnecting(so); 1834886Swnj } 1844809Swnj break; 1854809Swnj 1864809Swnj case PRU_SHUTDOWN: 1874731Swnj switch (nstate) { 1884497Swnj 1894731Swnj case LISTEN: 1904734Swnj case SYN_SENT: 1914731Swnj nstate = CLOSED; 1924731Swnj break; 1934731Swnj 1944734Swnj case SYN_RCVD: 1954731Swnj case L_SYN_RCVD: 1964731Swnj case ESTAB: 1974734Swnj case CLOSE_WAIT: 1984731Swnj tp->tc_flags |= TC_SND_FIN; 1994911Swnj (void) tcp_sndctl(tp); 2004731Swnj tp->tc_flags |= TC_USR_CLOSED; 2014731Swnj nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK; 2024731Swnj break; 2034731Swnj 2044731Swnj case FIN_W1: 2054731Swnj case FIN_W2: 2064731Swnj case TIME_WAIT: 2074731Swnj case CLOSING: 2084731Swnj case LAST_ACK: 2094731Swnj case RCV_WAIT: 2104731Swnj break; 2114731Swnj 2124731Swnj default: 2134731Swnj goto bad; 2144731Swnj } 2154567Swnj break; 2164497Swnj 2174809Swnj case PRU_RCVD: 2184731Swnj if (nstate < ESTAB || nstate == CLOSED) 2194731Swnj goto bad; 2204734Swnj tcp_sndwin(tp); 2214691Swnj if ((tp->tc_flags&TC_FIN_RCVD) && 2224691Swnj (tp->tc_flags&TC_USR_CLOSED) == 0 && 2234691Swnj rcv_empty(tp)) 2244886Swnj error = ESHUTDOWN; 2254809Swnj if (nstate == RCV_WAIT && rcv_empty(tp)) 2264567Swnj nstate = CLOSED; 2274567Swnj break; 2284497Swnj 2294809Swnj case PRU_SEND: 2304731Swnj switch (nstate) { 2314567Swnj 2324731Swnj case ESTAB: 2334731Swnj case CLOSE_WAIT: 2344886Swnj tcp_usrsend(tp, m); 2354731Swnj break; 2364731Swnj 2374731Swnj default: 2384731Swnj if (nstate < ESTAB) 2394731Swnj goto bad; 2404809Swnj m_freem(m); 2414886Swnj error = ENOTCONN; 2424731Swnj break; 2434731Swnj } 2444567Swnj break; 2454567Swnj 2464886Swnj abort: 2474809Swnj case PRU_ABORT: 2484886Swnj tcp_abort(tp); 2494567Swnj nstate = CLOSED; 2504567Swnj break; 2514567Swnj 2524809Swnj case PRU_CONTROL: 2534886Swnj error = EOPNOTSUPP; 2544809Swnj break; 2554809Swnj 2564809Swnj case PRU_SLOWTIMO: 2574809Swnj switch (nstate) { 2584809Swnj 2594809Swnj case 0: 2604809Swnj case CLOSED: 2614809Swnj case LISTEN: 2624809Swnj goto bad; 2634809Swnj 2644809Swnj default: 2654809Swnj nstate = tcp_timers(tp, (int)addr); 2664809Swnj } 2674809Swnj break; 2684809Swnj 2694731Swnj default: 2704731Swnj panic("tcp_usrreq"); 2714731Swnj bad: 2724731Swnj printf("tcp: bad state: tcb=%x state=%d input=%d\n", 2734809Swnj tp, tp->t_state, req); 2744731Swnj nstate = EFAILEC; 2754567Swnj break; 2764567Swnj } 2774567Swnj #ifdef TCPDEBUG 2784605Swnj if (tdb.td_tod) 2794605Swnj tdb_stuff(&tdb, nstate); 2804567Swnj #endif 2814567Swnj switch (nstate) { 2824567Swnj 2834584Swnj case CLOSED: 2844567Swnj case SAME: 2854567Swnj break; 2864567Swnj 2874567Swnj case EFAILEC: 2884731Swnj if (m) 2894731Swnj m_freem(dtom(m)); 2904567Swnj break; 2914567Swnj 2924567Swnj default: 2934567Swnj tp->t_state = nstate; 2944567Swnj break; 2954567Swnj } 2964567Swnj splx(s); 2974886Swnj return (error); 2984497Swnj } 2994497Swnj 3004809Swnj tcp_attach(so) 3014911Swnj struct socket *so; 3024809Swnj { 3034911Swnj register struct tcpcb *tp = sototcpcb(so); 3044809Swnj COUNT(TCP_ATTACH); 3054497Swnj 3064682Swnj /* 3074886Swnj * Make empty reassembly queue. 3084682Swnj */ 3094886Swnj tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; 3104497Swnj 3114682Swnj /* 3124886Swnj * Initialize sequence numbers and round trip retransmit timer. 3134682Swnj */ 3144567Swnj tp->t_xmtime = T_REXMT; 3154682Swnj tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una = 3164682Swnj tp->iss = tcp_iss; 3174567Swnj tp->snd_off = tp->iss + 1; 3184664Swnj tcp_iss += (ISSINCR >> 1) + 1; 3194497Swnj } 3204497Swnj 3214911Swnj tcp_detach(tp) 3224911Swnj struct tcpcb *tp; 3234497Swnj { 3244809Swnj COUNT(TCP_DETACH); 3254497Swnj 3264911Swnj in_pcbfree(tp->t_inpcb); 3274911Swnj (void) m_free(dtom(tp)); 3284886Swnj } 3294886Swnj 3304886Swnj tcp_disconnect(tp) 3314886Swnj register struct tcpcb *tp; 3324886Swnj { 3334886Swnj register struct tcpiphdr *t; 3344886Swnj 3354734Swnj tcp_tcancel(tp); 3364886Swnj t = tp->seg_next; 3374900Swnj 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) { 3414911Swnj (void) m_free(dtom(tp->t_template)); 3424734Swnj tp->t_template = 0; 3434664Swnj } 3444886Swnj in_pcbfree(tp->t_inpcb); 3454497Swnj } 3464497Swnj 3474911Swnj tcp_abort(tp) 3484911Swnj register struct tcpcb *tp; 3494886Swnj { 3504886Swnj 3514886Swnj switch (tp->t_state) { 3524886Swnj 3534886Swnj case SYN_RCVD: 3544886Swnj case ESTAB: 3554886Swnj case FIN_W1: 3564886Swnj case FIN_W2: 3574886Swnj case CLOSE_WAIT: 3584886Swnj tp->tc_flags |= TC_SND_RST; 3594886Swnj tcp_sndnull(tp); 3604886Swnj } 3614911Swnj soisdisconnected(tp->t_inpcb->inp_socket); 3624886Swnj } 3634886Swnj 3644682Swnj /* 3654734Swnj * Send data queue headed by m0 into the protocol. 3664682Swnj */ 3674678Swnj tcp_usrsend(tp, m0) 3684886Swnj register struct tcpcb *tp; 3694584Swnj struct mbuf *m0; 3704497Swnj { 3714886Swnj register struct socket *so = tp->t_inpcb->inp_socket; 3724682Swnj COUNT(TCP_USRSEND); 3734497Swnj 3744886Swnj sbappend(&so->so_snd, m0); 3754809Swnj if (tp->t_options & TO_EOL) 3764886Swnj tp->snd_end = tp->snd_off + so->so_snd.sb_cc; 3774809Swnj if (tp->t_options & TO_URG) { 3784886Swnj tp->snd_urp = tp->snd_off + so->so_snd.sb_cc + 1; 3794576Swnj tp->tc_flags |= TC_SND_URG; 3804567Swnj } 3814911Swnj (void) tcp_send(tp); 3824497Swnj } 3834497Swnj 3844682Swnj /* 3854682Swnj * TCP timer went off processing. 3864682Swnj */ 3874584Swnj tcp_timers(tp, timertype) 3884886Swnj register struct tcpcb *tp; 3894584Swnj int timertype; 3904497Swnj { 3914497Swnj 3924567Swnj COUNT(TCP_TIMERS); 3934584Swnj switch (timertype) { 3944497Swnj 3954567Swnj case TFINACK: /* fin-ack timer */ 3964567Swnj switch (tp->t_state) { 3974497Swnj 3984567Swnj case TIME_WAIT: 3994567Swnj /* 4004567Swnj * We can be sure our ACK of foreign FIN was rcvd, 4014567Swnj * and can close if no data left for user. 4024567Swnj */ 4034567Swnj if (rcv_empty(tp)) { 4044886Swnj tcp_disconnect(tp); 4054567Swnj return (CLOSED); 4064567Swnj } 4074567Swnj return (RCV_WAIT); /* 17 */ 4084497Swnj 4094731Swnj case CLOSING: 4104576Swnj tp->tc_flags |= TC_WAITED_2_ML; 4114567Swnj return (SAME); 4124497Swnj 4134567Swnj default: 4144567Swnj return (SAME); 4154567Swnj } 4164497Swnj 4174567Swnj case TREXMT: /* retransmission timer */ 4184567Swnj if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ 4194567Swnj /* 4204809Swnj * Set so for a retransmission, increase rexmt time 4214567Swnj * in case of multiple retransmissions. 4224567Swnj */ 4234567Swnj tp->snd_nxt = tp->snd_una; 4244576Swnj tp->tc_flags |= TC_REXMT; 4254567Swnj tp->t_xmtime = tp->t_xmtime << 1; 4264567Swnj if (tp->t_xmtime > T_REMAX) 4274567Swnj tp->t_xmtime = T_REMAX; 4284911Swnj (void) tcp_send(tp); 4294567Swnj } 4304567Swnj return (SAME); 4314497Swnj 4324567Swnj case TREXMTTL: /* retransmit too long */ 4334567Swnj if (tp->t_rtl_val > tp->snd_una) /* 36 */ 4344911Swnj tcp_error(tp, EIO); /* URXTIMO !?! */ 4354567Swnj /* 4364567Swnj * If user has already closed, abort the connection. 4374567Swnj */ 4384576Swnj if (tp->tc_flags & TC_USR_CLOSED) { 4394886Swnj tcp_abort(tp); 4404567Swnj return (CLOSED); 4414567Swnj } 4424567Swnj return (SAME); 4434497Swnj 4444567Swnj case TPERSIST: /* persist timer */ 4454567Swnj /* 4464567Swnj * Force a byte send through closed window. 4474567Swnj */ 4484576Swnj tp->tc_flags |= TC_FORCE_ONE; 4494911Swnj (void) tcp_send(tp); 4504567Swnj return (SAME); 4514567Swnj } 4524567Swnj panic("tcp_timers"); 4534911Swnj /*NOTREACHED*/ 4544497Swnj } 4554497Swnj 4564911Swnj /*ARGSUSED*/ 4574886Swnj tcp_sense(m) 4584886Swnj struct mbuf *m; 4594886Swnj { 4604886Swnj 4614886Swnj return (EOPNOTSUPP); 4624886Swnj } 4634886Swnj 4644911Swnj tcp_error(tp, errno) 4654911Swnj struct tcpcb *tp; 4664809Swnj int errno; 4674497Swnj { 4684911Swnj struct socket *so = tp->t_inpcb->inp_socket; 4694911Swnj COUNT(TCP_ERROR); 4704497Swnj 4714809Swnj so->so_error = errno; 4724886Swnj sorwakeup(so); 4734886Swnj sowwakeup(so); 4744497Swnj } 4754584Swnj 4764584Swnj #ifdef TCPDEBUG 4774682Swnj /* 4784682Swnj * TCP debugging utility subroutines. 4794682Swnj * THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID. 4804682Swnj */ 4814670Swnj tdb_setup(tp, n, input, tdp) 4824886Swnj struct tcpcb *tp; 4834886Swnj register struct tcpiphdr *n; 4844670Swnj int input; 4854670Swnj register struct tcp_debug *tdp; 4864670Swnj { 4874670Swnj 4884682Swnj COUNT(TDB_SETUP); 4894670Swnj tdp->td_tod = time; 4904670Swnj tdp->td_tcb = tp; 4914670Swnj tdp->td_old = tp->t_state; 4924670Swnj tdp->td_inp = input; 4934670Swnj tdp->td_tim = 0; 4944670Swnj tdp->td_new = -1; 4954670Swnj if (n) { 4964900Swnj tdp->td_sno = n->ti_seq; 4974900Swnj tdp->td_ano = n->ti_ackno; 4984670Swnj tdp->td_wno = n->t_win; 4994900Swnj tdp->td_lno = n->ti_len; 5004900Swnj tdp->td_flg = n->ti_flags; 5014670Swnj } else 5024670Swnj tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno = 5034670Swnj tdp->td_flg = 0; 5044670Swnj } 5054670Swnj 5064670Swnj tdb_stuff(tdp, nstate) 5074670Swnj struct tcp_debug *tdp; 5084670Swnj int nstate; 5094670Swnj { 5104682Swnj COUNT(TDB_STUFF); 5114670Swnj 5124670Swnj tdp->td_new = nstate; 5134670Swnj tcp_debug[tdbx++ % TDBSIZE] = *tdp; 5144670Swnj if (tcpconsdebug & 2) 5154670Swnj tcp_prt(tdp); 5164670Swnj } 5174682Swnj 5184682Swnj tcp_prt(tdp) 5194682Swnj register struct tcp_debug *tdp; 5204682Swnj { 5214682Swnj COUNT(TCP_PRT); 5224682Swnj 5234698Swnj printf("%x ", ((int)tdp->td_tcb)&0xffffff); 5244698Swnj if (tdp->td_inp == INSEND) { 5254698Swnj printf("SEND #%x", tdp->td_sno); 5264698Swnj tdp->td_lno = ntohs(tdp->td_lno); 5274698Swnj tdp->td_wno = ntohs(tdp->td_wno); 5284698Swnj } else { 5294698Swnj if (tdp->td_inp == INRECV) 5304698Swnj printf("RCV #%x ", tdp->td_sno); 5314698Swnj printf("%s.%s", 5324698Swnj tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]); 5334698Swnj if (tdp->td_inp == ISTIMER) 5344698Swnj printf("(%s)", tcptimers[tdp->td_tim]); 5354698Swnj printf(" -> %s", 5364698Swnj tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]); 5374698Swnj if (tdp->td_new == -1) 5384698Swnj printf(" (FAILED)"); 5394698Swnj } 5404682Swnj /* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */ 5414698Swnj if (tdp->td_lno) 5424698Swnj printf(" len=%d", tdp->td_lno); 5434698Swnj if (tdp->td_wno) 5444698Swnj printf(" win=%d", tdp->td_wno); 5454698Swnj if (tdp->td_flg & TH_FIN) printf(" FIN"); 5464698Swnj if (tdp->td_flg & TH_SYN) printf(" SYN"); 5474698Swnj if (tdp->td_flg & TH_RST) printf(" RST"); 5484698Swnj if (tdp->td_flg & TH_EOL) printf(" EOL"); 5494698Swnj if (tdp->td_flg & TH_ACK) printf(" ACK %x", tdp->td_ano); 5504698Swnj if (tdp->td_flg & TH_URG) printf(" URG"); 5514682Swnj printf("\n"); 5524682Swnj } 5534670Swnj #endif 554