1*4911Swnj /* tcp_usrreq.c 1.29 81/11/16 */ 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) 66*4911Swnj (void) tcp_usrreq(tp->t_inpcb->inp_socket, 67*4911Swnj PRU_SLOWTIMO, (struct mbuf *)0, 68*4911Swnj (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); 102*4911Swnj 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 */ 115*4911Swnj #ifdef TCPDEBUG 116*4911Swnj tdb.td_tod = 0; 117*4911Swnj #endif 118*4911Swnj if (inp == 0) { 1194886Swnj if (req != PRU_ATTACH) { 1204886Swnj splx(s); 1214886Swnj return (EINVAL); 1224886Swnj } 123*4911Swnj } else { 124*4911Swnj tp = intotcpcb(inp); 125*4911Swnj nstate = tp->t_state; 1264731Swnj #ifdef KPROF 127*4911Swnj tcp_acounts[nstate][req]++; 1284731Swnj #endif 1294584Swnj #ifdef TCPDEBUG 130*4911Swnj if (((tp->t_socket->so_options & SO_DEBUG) || tcpconsdebug)) { 131*4911Swnj tdb_setup(tp, (struct tcpiphdr *)0, req, &tdb); 132*4911Swnj tdb.td_tim = timertype; 133*4911Swnj } 1344584Swnj #endif 135*4911Swnj tp->tc_flags &= ~TC_NET_KEEP; 136*4911Swnj } 137*4911Swnj 1384809Swnj switch (req) { 1394497Swnj 1404809Swnj case PRU_ATTACH: 141*4911Swnj if (tp) { 1424809Swnj error = EISCONN; 143*4911Swnj break; 1444886Swnj } 145*4911Swnj tcp_attach(so); 146*4911Swnj tp = sototcpcb(so); 1474886Swnj if (so->so_options & SO_ACCEPTCONN) { 148*4911Swnj inp->inp_lhost = in_hostalloc(&n_lhost); /*XXX*/ 149*4911Swnj inp->inp_lport = in_pcbgenport(&tcb); 1504886Swnj nstate = LISTEN; 1514886Swnj } else 1524886Swnj nstate = CLOSED; 1534567Swnj break; 1544497Swnj 1554809Swnj case PRU_DETACH: 156*4911Swnj tcp_detach(tp); 1574809Swnj break; 1584809Swnj 1594809Swnj case PRU_CONNECT: 1604886Swnj if (tp->t_state != 0 && tp->t_state != CLOSED) 1614731Swnj goto bad; 162*4911Swnj inp->inp_fhost = in_hosteval((struct inaddr *)addr, &error); 1634886Swnj if (inp->inp_fhost == 0) 1644886Swnj break; 165*4911Swnj (void) tcp_sndctl(tp); 1664567Swnj nstate = SYN_SENT; 1674886Swnj soisconnecting(so); 1684567Swnj break; 1694497Swnj 1704809Swnj case PRU_DISCONNECT: 1714886Swnj if ((tp->tc_flags & TC_FIN_RCVD) == 0) 1724886Swnj goto abort; 1734886Swnj if (nstate < ESTAB) 174*4911Swnj tcp_disconnect(tp); 1754886Swnj else { 1764886Swnj tp->tc_flags |= TC_SND_FIN; 177*4911Swnj (void) tcp_sndctl(tp); 1784886Swnj tp->tc_flags |= TC_USR_CLOSED; 1794886Swnj soisdisconnecting(so); 1804886Swnj } 1814809Swnj break; 1824809Swnj 183*4911Swnj case PRU_FLUSH: 184*4911Swnj error = EOPNOTSUPP; 185*4911Swnj break; 186*4911Swnj 1874809Swnj case PRU_SHUTDOWN: 1884731Swnj switch (nstate) { 1894497Swnj 1904731Swnj case LISTEN: 1914734Swnj case SYN_SENT: 1924731Swnj nstate = CLOSED; 1934731Swnj break; 1944731Swnj 1954734Swnj case SYN_RCVD: 1964731Swnj case L_SYN_RCVD: 1974731Swnj case ESTAB: 1984734Swnj case CLOSE_WAIT: 1994731Swnj tp->tc_flags |= TC_SND_FIN; 200*4911Swnj (void) tcp_sndctl(tp); 2014731Swnj tp->tc_flags |= TC_USR_CLOSED; 2024731Swnj nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK; 2034731Swnj break; 2044731Swnj 2054731Swnj case FIN_W1: 2064731Swnj case FIN_W2: 2074731Swnj case TIME_WAIT: 2084731Swnj case CLOSING: 2094731Swnj case LAST_ACK: 2104731Swnj case RCV_WAIT: 2114731Swnj break; 2124731Swnj 2134731Swnj default: 2144731Swnj goto bad; 2154731Swnj } 2164567Swnj break; 2174497Swnj 2184809Swnj case PRU_RCVD: 2194731Swnj if (nstate < ESTAB || nstate == CLOSED) 2204731Swnj goto bad; 2214734Swnj tcp_sndwin(tp); 2224691Swnj if ((tp->tc_flags&TC_FIN_RCVD) && 2234691Swnj (tp->tc_flags&TC_USR_CLOSED) == 0 && 2244691Swnj rcv_empty(tp)) 2254886Swnj error = ESHUTDOWN; 2264809Swnj if (nstate == RCV_WAIT && rcv_empty(tp)) 2274567Swnj nstate = CLOSED; 2284567Swnj break; 2294497Swnj 2304809Swnj case PRU_SEND: 2314731Swnj switch (nstate) { 2324567Swnj 2334731Swnj case ESTAB: 2344731Swnj case CLOSE_WAIT: 2354886Swnj tcp_usrsend(tp, m); 2364731Swnj break; 2374731Swnj 2384731Swnj default: 2394731Swnj if (nstate < ESTAB) 2404731Swnj goto bad; 2414809Swnj m_freem(m); 2424886Swnj error = ENOTCONN; 2434731Swnj break; 2444731Swnj } 2454567Swnj break; 2464567Swnj 2474886Swnj abort: 2484809Swnj case PRU_ABORT: 2494886Swnj tcp_abort(tp); 2504567Swnj nstate = CLOSED; 2514567Swnj break; 2524567Swnj 2534809Swnj case PRU_CONTROL: 2544886Swnj error = EOPNOTSUPP; 2554809Swnj break; 2564809Swnj 2574809Swnj case PRU_SLOWTIMO: 2584809Swnj switch (nstate) { 2594809Swnj 2604809Swnj case 0: 2614809Swnj case CLOSED: 2624809Swnj case LISTEN: 2634809Swnj goto bad; 2644809Swnj 2654809Swnj default: 2664809Swnj nstate = tcp_timers(tp, (int)addr); 2674809Swnj } 2684809Swnj break; 2694809Swnj 2704731Swnj default: 2714731Swnj panic("tcp_usrreq"); 2724731Swnj bad: 2734731Swnj printf("tcp: bad state: tcb=%x state=%d input=%d\n", 2744809Swnj tp, tp->t_state, req); 2754731Swnj nstate = EFAILEC; 2764567Swnj break; 2774567Swnj } 2784567Swnj #ifdef TCPDEBUG 2794605Swnj if (tdb.td_tod) 2804605Swnj tdb_stuff(&tdb, nstate); 2814567Swnj #endif 2824567Swnj switch (nstate) { 2834567Swnj 2844584Swnj case CLOSED: 2854567Swnj case SAME: 2864567Swnj break; 2874567Swnj 2884567Swnj case EFAILEC: 2894731Swnj if (m) 2904731Swnj m_freem(dtom(m)); 2914567Swnj break; 2924567Swnj 2934567Swnj default: 2944567Swnj tp->t_state = nstate; 2954567Swnj break; 2964567Swnj } 2974567Swnj splx(s); 2984886Swnj return (error); 2994497Swnj } 3004497Swnj 3014809Swnj tcp_attach(so) 302*4911Swnj struct socket *so; 3034809Swnj { 304*4911Swnj register struct tcpcb *tp = sototcpcb(so); 3054809Swnj COUNT(TCP_ATTACH); 3064497Swnj 3074682Swnj /* 3084886Swnj * Make empty reassembly queue. 3094682Swnj */ 3104886Swnj tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; 3114497Swnj 3124682Swnj /* 3134886Swnj * Initialize sequence numbers and round trip retransmit timer. 3144682Swnj */ 3154567Swnj tp->t_xmtime = T_REXMT; 3164682Swnj tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una = 3174682Swnj tp->iss = tcp_iss; 3184567Swnj tp->snd_off = tp->iss + 1; 3194664Swnj tcp_iss += (ISSINCR >> 1) + 1; 3204497Swnj } 3214497Swnj 322*4911Swnj tcp_detach(tp) 323*4911Swnj struct tcpcb *tp; 3244497Swnj { 3254809Swnj COUNT(TCP_DETACH); 3264497Swnj 327*4911Swnj in_pcbfree(tp->t_inpcb); 328*4911Swnj (void) m_free(dtom(tp)); 3294886Swnj } 3304886Swnj 3314886Swnj tcp_disconnect(tp) 3324886Swnj register struct tcpcb *tp; 3334886Swnj { 3344886Swnj register struct tcpiphdr *t; 3354886Swnj 3364734Swnj tcp_tcancel(tp); 3374886Swnj t = tp->seg_next; 3384900Swnj for (; t != (struct tcpiphdr *)tp; t = (struct tcpiphdr *)t->ti_next) 3394567Swnj m_freem(dtom(t)); 3404886Swnj tcp_drainunack(tp); 3414734Swnj if (tp->t_template) { 342*4911Swnj (void) m_free(dtom(tp->t_template)); 3434734Swnj tp->t_template = 0; 3444664Swnj } 3454886Swnj in_pcbfree(tp->t_inpcb); 3464497Swnj } 3474497Swnj 348*4911Swnj tcp_abort(tp) 349*4911Swnj register struct tcpcb *tp; 3504886Swnj { 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 } 362*4911Swnj soisdisconnected(tp->t_inpcb->inp_socket); 3634886Swnj } 3644886Swnj 3654682Swnj /* 366*4911Swnj /*###366 [cc] warning: struct/union or struct/union pointer required %%%*/ 367*4911Swnj /*###366 [cc] member of structure or union required %%%*/ 368*4911Swnj /*###366 [cc] tp_inpcb undefined %%%*/ 3694734Swnj * Send data queue headed by m0 into the protocol. 3704682Swnj */ 3714678Swnj tcp_usrsend(tp, m0) 3724886Swnj register struct tcpcb *tp; 3734584Swnj struct mbuf *m0; 3744497Swnj { 3754886Swnj register struct socket *so = tp->t_inpcb->inp_socket; 3764682Swnj COUNT(TCP_USRSEND); 3774497Swnj 3784886Swnj sbappend(&so->so_snd, m0); 3794809Swnj if (tp->t_options & TO_EOL) 3804886Swnj tp->snd_end = tp->snd_off + so->so_snd.sb_cc; 3814809Swnj if (tp->t_options & TO_URG) { 3824886Swnj tp->snd_urp = tp->snd_off + so->so_snd.sb_cc + 1; 3834576Swnj tp->tc_flags |= TC_SND_URG; 3844567Swnj } 385*4911Swnj (void) tcp_send(tp); 3864497Swnj } 3874497Swnj 3884682Swnj /* 3894682Swnj * TCP timer went off processing. 3904682Swnj */ 3914584Swnj tcp_timers(tp, timertype) 3924886Swnj 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)) { 4084886Swnj 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; 432*4911Swnj (void) 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*4911Swnj tcp_error(tp, EIO); /* URXTIMO !?! */ 4394567Swnj /* 4404567Swnj * If user has already closed, abort the connection. 4414567Swnj */ 4424576Swnj if (tp->tc_flags & TC_USR_CLOSED) { 4434886Swnj 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; 453*4911Swnj (void) tcp_send(tp); 4544567Swnj return (SAME); 4554567Swnj } 4564567Swnj panic("tcp_timers"); 457*4911Swnj /*NOTREACHED*/ 4584497Swnj } 4594497Swnj 460*4911Swnj /*ARGSUSED*/ 4614886Swnj tcp_sense(m) 4624886Swnj struct mbuf *m; 4634886Swnj { 4644886Swnj 4654886Swnj return (EOPNOTSUPP); 4664886Swnj } 4674886Swnj 468*4911Swnj tcp_error(tp, errno) 469*4911Swnj struct tcpcb *tp; 4704809Swnj int errno; 4714497Swnj { 472*4911Swnj struct socket *so = tp->t_inpcb->inp_socket; 473*4911Swnj COUNT(TCP_ERROR); 4744497Swnj 4754809Swnj so->so_error = errno; 4764886Swnj sorwakeup(so); 4774886Swnj sowwakeup(so); 4784497Swnj } 4794584Swnj 4804584Swnj #ifdef TCPDEBUG 4814682Swnj /* 4824682Swnj * TCP debugging utility subroutines. 4834682Swnj * THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID. 4844682Swnj */ 4854670Swnj tdb_setup(tp, n, input, tdp) 4864886Swnj struct tcpcb *tp; 4874886Swnj register struct tcpiphdr *n; 4884670Swnj int input; 4894670Swnj register struct tcp_debug *tdp; 4904670Swnj { 4914670Swnj 4924682Swnj COUNT(TDB_SETUP); 4934670Swnj tdp->td_tod = time; 4944670Swnj tdp->td_tcb = tp; 4954670Swnj tdp->td_old = tp->t_state; 4964670Swnj tdp->td_inp = input; 4974670Swnj tdp->td_tim = 0; 4984670Swnj tdp->td_new = -1; 4994670Swnj if (n) { 5004900Swnj tdp->td_sno = n->ti_seq; 5014900Swnj tdp->td_ano = n->ti_ackno; 5024670Swnj tdp->td_wno = n->t_win; 5034900Swnj tdp->td_lno = n->ti_len; 5044900Swnj tdp->td_flg = n->ti_flags; 5054670Swnj } else 5064670Swnj tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno = 5074670Swnj tdp->td_flg = 0; 5084670Swnj } 5094670Swnj 5104670Swnj tdb_stuff(tdp, nstate) 5114670Swnj struct tcp_debug *tdp; 5124670Swnj int nstate; 5134670Swnj { 5144682Swnj COUNT(TDB_STUFF); 5154670Swnj 5164670Swnj tdp->td_new = nstate; 5174670Swnj tcp_debug[tdbx++ % TDBSIZE] = *tdp; 5184670Swnj if (tcpconsdebug & 2) 5194670Swnj tcp_prt(tdp); 5204670Swnj } 5214682Swnj 5224682Swnj tcp_prt(tdp) 5234682Swnj register struct tcp_debug *tdp; 5244682Swnj { 5254682Swnj COUNT(TCP_PRT); 5264682Swnj 5274698Swnj printf("%x ", ((int)tdp->td_tcb)&0xffffff); 5284698Swnj if (tdp->td_inp == INSEND) { 5294698Swnj printf("SEND #%x", tdp->td_sno); 5304698Swnj tdp->td_lno = ntohs(tdp->td_lno); 5314698Swnj tdp->td_wno = ntohs(tdp->td_wno); 5324698Swnj } else { 5334698Swnj if (tdp->td_inp == INRECV) 5344698Swnj printf("RCV #%x ", tdp->td_sno); 5354698Swnj printf("%s.%s", 5364698Swnj tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]); 5374698Swnj if (tdp->td_inp == ISTIMER) 5384698Swnj printf("(%s)", tcptimers[tdp->td_tim]); 5394698Swnj printf(" -> %s", 5404698Swnj tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]); 5414698Swnj if (tdp->td_new == -1) 5424698Swnj printf(" (FAILED)"); 5434698Swnj } 5444682Swnj /* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */ 5454698Swnj if (tdp->td_lno) 5464698Swnj printf(" len=%d", tdp->td_lno); 5474698Swnj if (tdp->td_wno) 5484698Swnj printf(" win=%d", tdp->td_wno); 5494698Swnj if (tdp->td_flg & TH_FIN) printf(" FIN"); 5504698Swnj if (tdp->td_flg & TH_SYN) printf(" SYN"); 5514698Swnj if (tdp->td_flg & TH_RST) printf(" RST"); 5524698Swnj if (tdp->td_flg & TH_EOL) printf(" EOL"); 5534698Swnj if (tdp->td_flg & TH_ACK) printf(" ACK %x", tdp->td_ano); 5544698Swnj if (tdp->td_flg & TH_URG) printf(" URG"); 5554682Swnj printf("\n"); 5564682Swnj } 5574670Swnj #endif 558