1*4954Swnj /* tcp_usrreq.c 1.31 81/11/20 */ 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_pcb.h" 114809Swnj #include "../net/inet_systm.h" 12*4954Swnj #include "../net/if.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 90*4954Swnj struct tcpcb *tcp_newtcpcb(); 914734Swnj /* 924731Swnj * Process a TCP user request for tcp tb. If this is a send request 934731Swnj * then m is the mbuf chain of send data. If this is a timer expiration 944731Swnj * (called from the software clock routine), then timertype tells which timer. 954731Swnj */ 964809Swnj tcp_usrreq(so, req, m, addr) 974809Swnj struct socket *so; 984809Swnj int req; 994731Swnj struct mbuf *m; 1004809Swnj caddr_t addr; 1014497Swnj { 1024886Swnj register struct inpcb *inp = sotoinpcb(so); 1034911Swnj register struct tcpcb *tp; 1044567Swnj int s = splnet(); 1054567Swnj register int nstate; 1064584Swnj #ifdef TCPDEBUG 1074584Swnj struct tcp_debug tdb; 1084584Swnj #endif 1094809Swnj int error = 0; 1104567Swnj COUNT(TCP_USRREQ); 1114497Swnj 1124886Swnj /* 1134886Swnj * Make sure attached. If not, 1144886Swnj * only PRU_ATTACH is valid. 1154886Swnj */ 1164911Swnj #ifdef TCPDEBUG 1174911Swnj tdb.td_tod = 0; 1184911Swnj #endif 1194911Swnj if (inp == 0) { 1204886Swnj if (req != PRU_ATTACH) { 1214886Swnj splx(s); 1224886Swnj return (EINVAL); 1234886Swnj } 1244911Swnj } else { 1254911Swnj tp = intotcpcb(inp); 1264911Swnj nstate = tp->t_state; 1274731Swnj #ifdef KPROF 1284911Swnj tcp_acounts[nstate][req]++; 1294731Swnj #endif 1304584Swnj #ifdef TCPDEBUG 1314911Swnj if (((tp->t_socket->so_options & SO_DEBUG) || tcpconsdebug)) { 1324911Swnj tdb_setup(tp, (struct tcpiphdr *)0, req, &tdb); 1334911Swnj tdb.td_tim = timertype; 1344911Swnj } 1354584Swnj #endif 1364911Swnj tp->tc_flags &= ~TC_NET_KEEP; 1374911Swnj } 1384911Swnj 1394809Swnj switch (req) { 1404497Swnj 1414809Swnj case PRU_ATTACH: 142*4954Swnj if (inp) { 1434809Swnj error = EISCONN; 1444911Swnj break; 1454886Swnj } 146*4954Swnj tp = tcp_newtcpcb(); 147*4954Swnj if (tp == 0) { 148*4954Swnj error = ENOBUFS; 149*4954Swnj break; 150*4954Swnj } 151*4954Swnj error = in_pcballoc(so, &tcb, 2048, 2048, (struct sockaddr_in *)addr); 152*4954Swnj if (error) { 153*4954Swnj m_free(dtom(tp)); 154*4954Swnj break; 155*4954Swnj } 156*4954Swnj inp = (struct inpcb *)so->so_pcb; 157*4954Swnj tp->t_inpcb = inp; 158*4954Swnj inp->inp_ppcb = (caddr_t)tp; 159*4954Swnj if (so->so_options & SO_ACCEPTCONN) 1604886Swnj nstate = LISTEN; 161*4954Swnj else 1624886Swnj nstate = CLOSED; 1634567Swnj break; 1644497Swnj 1654809Swnj case PRU_DETACH: 1664911Swnj tcp_detach(tp); 1674809Swnj break; 1684809Swnj 1694809Swnj case PRU_CONNECT: 1704886Swnj if (tp->t_state != 0 && tp->t_state != CLOSED) 1714731Swnj goto bad; 172*4954Swnj error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr); 173*4954Swnj if (error) 1744886Swnj break; 1754911Swnj (void) tcp_sndctl(tp); 1764567Swnj nstate = SYN_SENT; 1774886Swnj soisconnecting(so); 1784567Swnj break; 1794497Swnj 1804925Swnj case PRU_ACCEPT: 181*4954Swnj soisconnected(so); 182*4954Swnj break; 1834925Swnj 1844809Swnj case PRU_DISCONNECT: 1854886Swnj if ((tp->tc_flags & TC_FIN_RCVD) == 0) 1864886Swnj goto abort; 1874886Swnj if (nstate < ESTAB) 1884911Swnj tcp_disconnect(tp); 1894886Swnj else { 1904886Swnj tp->tc_flags |= TC_SND_FIN; 1914911Swnj (void) tcp_sndctl(tp); 1924886Swnj tp->tc_flags |= TC_USR_CLOSED; 1934886Swnj soisdisconnecting(so); 1944886Swnj } 1954809Swnj break; 1964809Swnj 1974809Swnj case PRU_SHUTDOWN: 1984731Swnj switch (nstate) { 1994497Swnj 2004731Swnj case LISTEN: 2014734Swnj case SYN_SENT: 2024731Swnj nstate = CLOSED; 2034731Swnj break; 2044731Swnj 2054734Swnj case SYN_RCVD: 2064731Swnj case L_SYN_RCVD: 2074731Swnj case ESTAB: 2084734Swnj case CLOSE_WAIT: 2094731Swnj tp->tc_flags |= TC_SND_FIN; 2104911Swnj (void) tcp_sndctl(tp); 2114731Swnj tp->tc_flags |= TC_USR_CLOSED; 2124731Swnj nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK; 2134731Swnj break; 2144731Swnj 2154731Swnj case FIN_W1: 2164731Swnj case FIN_W2: 2174731Swnj case TIME_WAIT: 2184731Swnj case CLOSING: 2194731Swnj case LAST_ACK: 2204731Swnj case RCV_WAIT: 2214731Swnj break; 2224731Swnj 2234731Swnj default: 2244731Swnj goto bad; 2254731Swnj } 2264567Swnj break; 2274497Swnj 2284809Swnj case PRU_RCVD: 2294731Swnj if (nstate < ESTAB || nstate == CLOSED) 2304731Swnj goto bad; 2314734Swnj tcp_sndwin(tp); 2324691Swnj if ((tp->tc_flags&TC_FIN_RCVD) && 2334691Swnj (tp->tc_flags&TC_USR_CLOSED) == 0 && 2344691Swnj rcv_empty(tp)) 2354886Swnj error = ESHUTDOWN; 2364809Swnj if (nstate == RCV_WAIT && rcv_empty(tp)) 2374567Swnj nstate = CLOSED; 2384567Swnj break; 2394497Swnj 2404809Swnj case PRU_SEND: 2414731Swnj switch (nstate) { 2424567Swnj 2434731Swnj case ESTAB: 2444731Swnj case CLOSE_WAIT: 2454886Swnj tcp_usrsend(tp, m); 2464731Swnj break; 2474731Swnj 2484731Swnj default: 2494731Swnj if (nstate < ESTAB) 2504731Swnj goto bad; 2514809Swnj m_freem(m); 2524886Swnj error = ENOTCONN; 2534731Swnj break; 2544731Swnj } 2554567Swnj break; 2564567Swnj 2574886Swnj abort: 2584809Swnj case PRU_ABORT: 2594886Swnj tcp_abort(tp); 2604567Swnj nstate = CLOSED; 2614567Swnj break; 2624567Swnj 2634809Swnj case PRU_CONTROL: 2644886Swnj error = EOPNOTSUPP; 2654809Swnj break; 2664809Swnj 2674809Swnj case PRU_SLOWTIMO: 2684809Swnj switch (nstate) { 2694809Swnj 2704809Swnj case 0: 2714809Swnj case CLOSED: 2724809Swnj case LISTEN: 2734809Swnj goto bad; 2744809Swnj 2754809Swnj default: 2764809Swnj nstate = tcp_timers(tp, (int)addr); 2774809Swnj } 2784809Swnj break; 2794809Swnj 2804731Swnj default: 2814731Swnj panic("tcp_usrreq"); 2824731Swnj bad: 2834731Swnj printf("tcp: bad state: tcb=%x state=%d input=%d\n", 2844809Swnj tp, tp->t_state, req); 2854731Swnj nstate = EFAILEC; 2864567Swnj break; 2874567Swnj } 2884567Swnj #ifdef TCPDEBUG 2894605Swnj if (tdb.td_tod) 2904605Swnj tdb_stuff(&tdb, nstate); 2914567Swnj #endif 2924567Swnj switch (nstate) { 2934567Swnj 2944584Swnj case CLOSED: 2954567Swnj case SAME: 2964567Swnj break; 2974567Swnj 2984567Swnj case EFAILEC: 2994731Swnj if (m) 3004731Swnj m_freem(dtom(m)); 3014567Swnj break; 3024567Swnj 3034567Swnj default: 3044567Swnj tp->t_state = nstate; 3054567Swnj break; 3064567Swnj } 3074567Swnj splx(s); 3084886Swnj return (error); 3094497Swnj } 3104497Swnj 311*4954Swnj struct tcpcb * 312*4954Swnj tcp_newtcpcb() 3134809Swnj { 314*4954Swnj struct mbuf *m = m_getclr(0); 315*4954Swnj register struct tcpcb *tp; 316*4954Swnj COUNT(TCP_NEWTCPCB); 3174497Swnj 318*4954Swnj if (m == 0) 319*4954Swnj return (0); 320*4954Swnj tp = mtod(m, struct tcpcb *); 321*4954Swnj 3224682Swnj /* 3234886Swnj * Make empty reassembly queue. 3244682Swnj */ 3254886Swnj tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; 3264497Swnj 3274682Swnj /* 3284886Swnj * Initialize sequence numbers and round trip retransmit timer. 3294682Swnj */ 3304567Swnj tp->t_xmtime = T_REXMT; 3314682Swnj tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una = 3324682Swnj tp->iss = tcp_iss; 3334567Swnj tp->snd_off = tp->iss + 1; 3344664Swnj tcp_iss += (ISSINCR >> 1) + 1; 335*4954Swnj return (tp); 3364497Swnj } 3374497Swnj 3384911Swnj tcp_detach(tp) 3394911Swnj struct tcpcb *tp; 3404497Swnj { 3414809Swnj COUNT(TCP_DETACH); 3424497Swnj 3434911Swnj in_pcbfree(tp->t_inpcb); 3444911Swnj (void) m_free(dtom(tp)); 3454886Swnj } 3464886Swnj 3474886Swnj tcp_disconnect(tp) 3484886Swnj register struct tcpcb *tp; 3494886Swnj { 3504886Swnj register struct tcpiphdr *t; 3514886Swnj 352*4954Swnj COUNT(TCP_DISCONNECT); 3534734Swnj tcp_tcancel(tp); 3544886Swnj t = tp->seg_next; 3554900Swnj for (; t != (struct tcpiphdr *)tp; t = (struct tcpiphdr *)t->ti_next) 3564567Swnj m_freem(dtom(t)); 3574886Swnj tcp_drainunack(tp); 3584734Swnj if (tp->t_template) { 3594911Swnj (void) m_free(dtom(tp->t_template)); 3604734Swnj tp->t_template = 0; 3614664Swnj } 3624886Swnj in_pcbfree(tp->t_inpcb); 3634497Swnj } 3644497Swnj 3654911Swnj tcp_abort(tp) 3664911Swnj register struct tcpcb *tp; 3674886Swnj { 3684886Swnj 369*4954Swnj COUNT(TCP_ABORT); 3704886Swnj switch (tp->t_state) { 3714886Swnj 3724886Swnj case SYN_RCVD: 3734886Swnj case ESTAB: 3744886Swnj case FIN_W1: 3754886Swnj case FIN_W2: 3764886Swnj case CLOSE_WAIT: 3774886Swnj tp->tc_flags |= TC_SND_RST; 3784886Swnj tcp_sndnull(tp); 3794886Swnj } 3804911Swnj soisdisconnected(tp->t_inpcb->inp_socket); 3814886Swnj } 3824886Swnj 3834682Swnj /* 3844734Swnj * Send data queue headed by m0 into the protocol. 3854682Swnj */ 3864678Swnj tcp_usrsend(tp, m0) 3874886Swnj register struct tcpcb *tp; 3884584Swnj struct mbuf *m0; 3894497Swnj { 3904886Swnj register struct socket *so = tp->t_inpcb->inp_socket; 3914682Swnj COUNT(TCP_USRSEND); 3924497Swnj 3934886Swnj sbappend(&so->so_snd, m0); 3944809Swnj if (tp->t_options & TO_EOL) 3954886Swnj tp->snd_end = tp->snd_off + so->so_snd.sb_cc; 3964809Swnj if (tp->t_options & TO_URG) { 3974886Swnj tp->snd_urp = tp->snd_off + so->so_snd.sb_cc + 1; 3984576Swnj tp->tc_flags |= TC_SND_URG; 3994567Swnj } 4004911Swnj (void) tcp_send(tp); 4014497Swnj } 4024497Swnj 4034682Swnj /* 4044682Swnj * TCP timer went off processing. 4054682Swnj */ 4064584Swnj tcp_timers(tp, timertype) 4074886Swnj register struct tcpcb *tp; 4084584Swnj int timertype; 4094497Swnj { 4104497Swnj 4114567Swnj COUNT(TCP_TIMERS); 4124584Swnj switch (timertype) { 4134497Swnj 4144567Swnj case TFINACK: /* fin-ack timer */ 4154567Swnj switch (tp->t_state) { 4164497Swnj 4174567Swnj case TIME_WAIT: 4184567Swnj /* 4194567Swnj * We can be sure our ACK of foreign FIN was rcvd, 4204567Swnj * and can close if no data left for user. 4214567Swnj */ 4224567Swnj if (rcv_empty(tp)) { 4234886Swnj tcp_disconnect(tp); 4244567Swnj return (CLOSED); 4254567Swnj } 4264567Swnj return (RCV_WAIT); /* 17 */ 4274497Swnj 4284731Swnj case CLOSING: 4294576Swnj tp->tc_flags |= TC_WAITED_2_ML; 4304567Swnj return (SAME); 4314497Swnj 4324567Swnj default: 4334567Swnj return (SAME); 4344567Swnj } 4354497Swnj 4364567Swnj case TREXMT: /* retransmission timer */ 4374567Swnj if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ 4384567Swnj /* 4394809Swnj * Set so for a retransmission, increase rexmt time 4404567Swnj * in case of multiple retransmissions. 4414567Swnj */ 4424567Swnj tp->snd_nxt = tp->snd_una; 4434576Swnj tp->tc_flags |= TC_REXMT; 4444567Swnj tp->t_xmtime = tp->t_xmtime << 1; 4454567Swnj if (tp->t_xmtime > T_REMAX) 4464567Swnj tp->t_xmtime = T_REMAX; 4474911Swnj (void) tcp_send(tp); 4484567Swnj } 4494567Swnj return (SAME); 4504497Swnj 4514567Swnj case TREXMTTL: /* retransmit too long */ 4524567Swnj if (tp->t_rtl_val > tp->snd_una) /* 36 */ 4534911Swnj tcp_error(tp, EIO); /* URXTIMO !?! */ 4544567Swnj /* 4554567Swnj * If user has already closed, abort the connection. 4564567Swnj */ 4574576Swnj if (tp->tc_flags & TC_USR_CLOSED) { 4584886Swnj tcp_abort(tp); 4594567Swnj return (CLOSED); 4604567Swnj } 4614567Swnj return (SAME); 4624497Swnj 4634567Swnj case TPERSIST: /* persist timer */ 4644567Swnj /* 4654567Swnj * Force a byte send through closed window. 4664567Swnj */ 4674576Swnj tp->tc_flags |= TC_FORCE_ONE; 4684911Swnj (void) tcp_send(tp); 4694567Swnj return (SAME); 4704567Swnj } 4714567Swnj panic("tcp_timers"); 4724911Swnj /*NOTREACHED*/ 4734497Swnj } 4744497Swnj 4754911Swnj /*ARGSUSED*/ 4764886Swnj tcp_sense(m) 4774886Swnj struct mbuf *m; 4784886Swnj { 4794886Swnj 480*4954Swnj COUNT(TCP_SENSE); 4814886Swnj return (EOPNOTSUPP); 4824886Swnj } 4834886Swnj 4844911Swnj tcp_error(tp, errno) 4854911Swnj struct tcpcb *tp; 4864809Swnj int errno; 4874497Swnj { 4884911Swnj struct socket *so = tp->t_inpcb->inp_socket; 489*4954Swnj 4904911Swnj COUNT(TCP_ERROR); 4914809Swnj so->so_error = errno; 4924886Swnj sorwakeup(so); 4934886Swnj sowwakeup(so); 4944497Swnj } 4954584Swnj 4964584Swnj #ifdef TCPDEBUG 4974682Swnj /* 4984682Swnj * TCP debugging utility subroutines. 4994682Swnj * THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID. 5004682Swnj */ 5014670Swnj tdb_setup(tp, n, input, tdp) 5024886Swnj struct tcpcb *tp; 5034886Swnj register struct tcpiphdr *n; 5044670Swnj int input; 5054670Swnj register struct tcp_debug *tdp; 5064670Swnj { 5074670Swnj 5084682Swnj COUNT(TDB_SETUP); 5094670Swnj tdp->td_tod = time; 5104670Swnj tdp->td_tcb = tp; 5114670Swnj tdp->td_old = tp->t_state; 5124670Swnj tdp->td_inp = input; 5134670Swnj tdp->td_tim = 0; 5144670Swnj tdp->td_new = -1; 5154670Swnj if (n) { 5164900Swnj tdp->td_sno = n->ti_seq; 5174900Swnj tdp->td_ano = n->ti_ackno; 5184670Swnj tdp->td_wno = n->t_win; 5194900Swnj tdp->td_lno = n->ti_len; 5204900Swnj tdp->td_flg = n->ti_flags; 5214670Swnj } else 5224670Swnj tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno = 5234670Swnj tdp->td_flg = 0; 5244670Swnj } 5254670Swnj 5264670Swnj tdb_stuff(tdp, nstate) 5274670Swnj struct tcp_debug *tdp; 5284670Swnj int nstate; 5294670Swnj { 5304682Swnj COUNT(TDB_STUFF); 5314670Swnj 5324670Swnj tdp->td_new = nstate; 5334670Swnj tcp_debug[tdbx++ % TDBSIZE] = *tdp; 5344670Swnj if (tcpconsdebug & 2) 5354670Swnj tcp_prt(tdp); 5364670Swnj } 5374682Swnj 5384682Swnj tcp_prt(tdp) 5394682Swnj register struct tcp_debug *tdp; 5404682Swnj { 5414682Swnj COUNT(TCP_PRT); 5424682Swnj 5434698Swnj printf("%x ", ((int)tdp->td_tcb)&0xffffff); 5444698Swnj if (tdp->td_inp == INSEND) { 5454698Swnj printf("SEND #%x", tdp->td_sno); 5464698Swnj tdp->td_lno = ntohs(tdp->td_lno); 5474698Swnj tdp->td_wno = ntohs(tdp->td_wno); 5484698Swnj } else { 5494698Swnj if (tdp->td_inp == INRECV) 5504698Swnj printf("RCV #%x ", tdp->td_sno); 5514698Swnj printf("%s.%s", 5524698Swnj tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]); 5534698Swnj if (tdp->td_inp == ISTIMER) 5544698Swnj printf("(%s)", tcptimers[tdp->td_tim]); 5554698Swnj printf(" -> %s", 5564698Swnj tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]); 5574698Swnj if (tdp->td_new == -1) 5584698Swnj printf(" (FAILED)"); 5594698Swnj } 5604682Swnj /* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */ 5614698Swnj if (tdp->td_lno) 5624698Swnj printf(" len=%d", tdp->td_lno); 5634698Swnj if (tdp->td_wno) 5644698Swnj printf(" win=%d", tdp->td_wno); 5654698Swnj if (tdp->td_flg & TH_FIN) printf(" FIN"); 5664698Swnj if (tdp->td_flg & TH_SYN) printf(" SYN"); 5674698Swnj if (tdp->td_flg & TH_RST) printf(" RST"); 5684698Swnj if (tdp->td_flg & TH_EOL) printf(" EOL"); 5694698Swnj if (tdp->td_flg & TH_ACK) printf(" ACK %x", tdp->td_ano); 5704698Swnj if (tdp->td_flg & TH_URG) printf(" URG"); 5714682Swnj printf("\n"); 5724682Swnj } 5734670Swnj #endif 574