1*12766Ssam /* tcp_usrreq.c 1.78 83/05/27 */ 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" 910896Ssam #include "../h/errno.h" 108697Sroot 118697Sroot #include "../net/if.h" 128697Sroot #include "../net/route.h" 1310896Ssam 148406Swnj #include "../netinet/in.h" 158406Swnj #include "../netinet/in_pcb.h" 168406Swnj #include "../netinet/in_systm.h" 178406Swnj #include "../netinet/ip.h" 188406Swnj #include "../netinet/ip_var.h" 198406Swnj #include "../netinet/tcp.h" 208406Swnj #include "../netinet/tcp_fsm.h" 218406Swnj #include "../netinet/tcp_seq.h" 228406Swnj #include "../netinet/tcp_timer.h" 238406Swnj #include "../netinet/tcp_var.h" 248406Swnj #include "../netinet/tcpip.h" 258406Swnj #include "../netinet/tcp_debug.h" 264497Swnj 275280Sroot /* 285280Sroot * TCP protocol interface to socket abstraction. 295280Sroot */ 305280Sroot extern char *tcpstates[]; 314954Swnj struct tcpcb *tcp_newtcpcb(); 32*12766Ssam int tcpsenderrors; 335280Sroot 344734Swnj /* 355280Sroot * Process a TCP user request for TCP tb. If this is a send request 364731Swnj * then m is the mbuf chain of send data. If this is a timer expiration 374731Swnj * (called from the software clock routine), then timertype tells which timer. 384731Swnj */ 398601Sroot /*ARGSUSED*/ 40*12766Ssam tcp_usrreq(so, req, m, nam, rights) 414809Swnj struct socket *so; 424809Swnj int req; 43*12766Ssam struct mbuf *m, *nam, *rights; 444497Swnj { 454886Swnj register struct inpcb *inp = sotoinpcb(so); 464911Swnj register struct tcpcb *tp; 474567Swnj int s = splnet(); 484809Swnj int error = 0; 495270Sroot int ostate; 504497Swnj 51*12766Ssam if (rights && rights->m_len) { 52*12766Ssam splx(s); 53*12766Ssam return (EINVAL); 54*12766Ssam } 554886Swnj /* 565280Sroot * When a TCP is attached to a socket, then there will be 575280Sroot * a (struct inpcb) pointed at by the socket, and this 585280Sroot * structure will point at a subsidary (struct tcpcb). 594886Swnj */ 605089Swnj if (inp == 0 && req != PRU_ATTACH) { 615075Swnj splx(s); 625280Sroot return (EINVAL); /* XXX */ 635075Swnj } 645075Swnj if (inp) { 654911Swnj tp = intotcpcb(inp); 668272Sroot /* WHAT IF TP IS 0? */ 674731Swnj #ifdef KPROF 685075Swnj tcp_acounts[tp->t_state][req]++; 694731Swnj #endif 705270Sroot ostate = tp->t_state; 717511Sroot } else 727511Sroot ostate = 0; 734809Swnj switch (req) { 744497Swnj 755280Sroot /* 765280Sroot * TCP attaches to socket via PRU_ATTACH, reserving space, 778272Sroot * and an internet control block. 785280Sroot */ 794809Swnj case PRU_ATTACH: 804954Swnj if (inp) { 814809Swnj error = EISCONN; 824911Swnj break; 834886Swnj } 848640Sroot error = tcp_attach(so); 855075Swnj if (error) 864954Swnj break; 8710397Ssam if ((so->so_options & SO_LINGER) && so->so_linger == 0) 885392Swnj so->so_linger = TCP_LINGERTIME; 895280Sroot tp = sototcpcb(so); 904567Swnj break; 914497Swnj 925280Sroot /* 935280Sroot * PRU_DETACH detaches the TCP protocol from the socket. 945280Sroot * If the protocol state is non-embryonic, then can't 955280Sroot * do this directly: have to initiate a PRU_DISCONNECT, 965280Sroot * which may finish later; embryonic TCB's can just 975280Sroot * be discarded here. 985280Sroot */ 994809Swnj case PRU_DETACH: 1005280Sroot if (tp->t_state > TCPS_LISTEN) 10110397Ssam tp = tcp_disconnect(tp); 10210397Ssam else 10310397Ssam tp = tcp_close(tp); 1044809Swnj break; 1054809Swnj 1065280Sroot /* 1078272Sroot * Give the socket an address. 1088272Sroot */ 1098272Sroot case PRU_BIND: 1108272Sroot error = in_pcbbind(inp, nam); 1118272Sroot if (error) 1128272Sroot break; 1138272Sroot break; 1148272Sroot 1158272Sroot /* 1168272Sroot * Prepare to accept connections. 1178272Sroot */ 1188272Sroot case PRU_LISTEN: 1198272Sroot if (inp->inp_lport == 0) 1208272Sroot error = in_pcbbind(inp, (struct mbuf *)0); 1218272Sroot if (error == 0) 1228272Sroot tp->t_state = TCPS_LISTEN; 1238272Sroot break; 1248272Sroot 1258272Sroot /* 1265280Sroot * Initiate connection to peer. 1275280Sroot * Create a template for use in transmissions on this connection. 1285280Sroot * Enter SYN_SENT state, and mark socket as connecting. 1295280Sroot * Start keep-alive timer, and seed output sequence space. 1305280Sroot * Send initial segment on connection. 1315280Sroot */ 1324809Swnj case PRU_CONNECT: 1338272Sroot if (inp->inp_lport == 0) { 1348272Sroot error = in_pcbbind(inp, (struct mbuf *)0); 1358272Sroot if (error) 1368272Sroot break; 1378272Sroot } 1388272Sroot error = in_pcbconnect(inp, nam); 1394954Swnj if (error) 1404886Swnj break; 1415174Swnj tp->t_template = tcp_template(tp); 1425280Sroot if (tp->t_template == 0) { 1435280Sroot in_pcbdisconnect(inp); 1445280Sroot error = ENOBUFS; 1455280Sroot break; 1465280Sroot } 1474886Swnj soisconnecting(so); 1485075Swnj tp->t_state = TCPS_SYN_SENT; 1495245Sroot tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; 1505245Sroot tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; 1515245Sroot tcp_sendseqinit(tp); 1526506Ssam error = tcp_output(tp); 1534567Swnj break; 1544497Swnj 1555280Sroot /* 1565280Sroot * Initiate disconnect from peer. 1575280Sroot * If connection never passed embryonic stage, just drop; 1585280Sroot * else if don't need to let data drain, then can just drop anyways, 1595280Sroot * else have to begin TCP shutdown process: mark socket disconnecting, 1605280Sroot * drain unread data, state switch to reflect user close, and 1615280Sroot * send segment (e.g. FIN) to peer. Socket will be really disconnected 1625280Sroot * when peer sends FIN and acks ours. 1635280Sroot * 1645280Sroot * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB. 1655280Sroot */ 1665280Sroot case PRU_DISCONNECT: 16710397Ssam tp = tcp_disconnect(tp); 1685245Sroot break; 1695245Sroot 1705280Sroot /* 1715280Sroot * Accept a connection. Essentially all the work is 1725280Sroot * done at higher levels; just return the address 1735280Sroot * of the peer, storing through addr. 1745280Sroot */ 1756117Swnj case PRU_ACCEPT: { 1768272Sroot struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 1776117Swnj 1788272Sroot nam->m_len = sizeof (struct sockaddr_in); 1798272Sroot sin->sin_family = AF_INET; 1808272Sroot sin->sin_port = inp->inp_fport; 1818272Sroot sin->sin_addr = inp->inp_faddr; 1828272Sroot break; 1836117Swnj } 1844925Swnj 1855280Sroot /* 1865280Sroot * Mark the connection as being incapable of further output. 1875280Sroot */ 1884809Swnj case PRU_SHUTDOWN: 1895089Swnj socantsendmore(so); 19010397Ssam tp = tcp_usrclosed(tp); 19110397Ssam if (tp) 19210397Ssam error = tcp_output(tp); 1934567Swnj break; 1944497Swnj 1955280Sroot /* 1965280Sroot * After a receive, possibly send window update to peer. 1975280Sroot */ 1984809Swnj case PRU_RCVD: 1995113Swnj (void) tcp_output(tp); 2004567Swnj break; 2014497Swnj 2025280Sroot /* 2035280Sroot * Do a send by putting data in output queue and updating urgent 2045280Sroot * marker if URG set. Possibly send more data. 2055280Sroot */ 2064809Swnj case PRU_SEND: 2075075Swnj sbappend(&so->so_snd, m); 2086506Ssam #ifdef notdef 2095089Swnj if (tp->t_flags & TF_PUSH) 2105075Swnj tp->snd_end = tp->snd_una + so->so_snd.sb_cc; 2116506Ssam #endif 2126506Ssam error = tcp_output(tp); 213*12766Ssam if (error) { /* XXX fix to use other path */ 214*12766Ssam if (error == ENOBUFS) /* XXX */ 215*12766Ssam error = 0; /* XXX */ 216*12766Ssam tcpsenderrors++; 217*12766Ssam } 2184567Swnj break; 2194567Swnj 2205280Sroot /* 2215280Sroot * Abort the TCP. 2225280Sroot */ 2234809Swnj case PRU_ABORT: 22410397Ssam tp = tcp_drop(tp, ECONNABORTED); 2254567Swnj break; 2264567Swnj 2275280Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */ 2284809Swnj case PRU_CONTROL: 2294886Swnj error = EOPNOTSUPP; 2304809Swnj break; 2314809Swnj 2325113Swnj case PRU_SENSE: 2335113Swnj error = EOPNOTSUPP; 2345113Swnj break; 2355417Swnj /* END UNIMPLEMENTED HOOKS */ 2365113Swnj 2375113Swnj case PRU_RCVOOB: 2385442Swnj if (so->so_oobmark == 0 && 2395442Swnj (so->so_state & SS_RCVATMARK) == 0) { 2405417Swnj error = EINVAL; 2415417Swnj break; 2425417Swnj } 2435549Swnj if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) { 2445442Swnj error = EWOULDBLOCK; 2455549Swnj break; 2465442Swnj } 2478310Sroot m->m_len = 1; 2485549Swnj *mtod(m, caddr_t) = tp->t_iobc; 2495113Swnj break; 2505113Swnj 2515113Swnj case PRU_SENDOOB: 2525442Swnj if (sbspace(&so->so_snd) < -512) { 25311229Ssam m_freem(m); 2545442Swnj error = ENOBUFS; 2555442Swnj break; 2565442Swnj } 2575417Swnj tp->snd_up = tp->snd_una + so->so_snd.sb_cc + 1; 2585417Swnj sbappend(&so->so_snd, m); 2595549Swnj tp->t_force = 1; 2606506Ssam error = tcp_output(tp); 2615549Swnj tp->t_force = 0; 2625113Swnj break; 2635113Swnj 2646510Ssam case PRU_SOCKADDR: 2658272Sroot in_setsockaddr(inp, nam); 2666510Ssam break; 2676510Ssam 2685280Sroot /* 2695280Sroot * TCP slow timer went off; going through this 2705280Sroot * routine for tracing's sake. 2715280Sroot */ 2724809Swnj case PRU_SLOWTIMO: 27310397Ssam tp = tcp_timers(tp, (int)nam); 2748272Sroot req |= (int)nam << 8; /* for debug's sake */ 2754809Swnj break; 2764809Swnj 2774731Swnj default: 2784731Swnj panic("tcp_usrreq"); 2794567Swnj } 2805270Sroot if (tp && (so->so_options & SO_DEBUG)) 2815270Sroot tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req); 2824567Swnj splx(s); 2834886Swnj return (error); 2844497Swnj } 2855245Sroot 2865953Swnj int tcp_sendspace = 1024*2; 2876601Ssam int tcp_recvspace = 1024*2; 2885280Sroot /* 2895280Sroot * Attach TCP protocol to socket, allocating 2905280Sroot * internet protocol control block, tcp control block, 2915280Sroot * bufer space, and entering LISTEN state if to accept connections. 2925280Sroot */ 2938272Sroot tcp_attach(so) 2945280Sroot struct socket *so; 2955280Sroot { 2965280Sroot register struct tcpcb *tp; 2975280Sroot struct inpcb *inp; 2985280Sroot int error; 2995280Sroot 3009031Sroot error = soreserve(so, tcp_sendspace, tcp_recvspace); 3015280Sroot if (error) 3027511Sroot goto bad; 3037511Sroot error = in_pcballoc(so, &tcb); 3047511Sroot if (error) 3058272Sroot goto bad; 3068272Sroot inp = sotoinpcb(so); 3075280Sroot tp = tcp_newtcpcb(inp); 3087511Sroot if (tp == 0) { 3097511Sroot error = ENOBUFS; 3107511Sroot goto bad2; 3117511Sroot } 3128272Sroot tp->t_state = TCPS_CLOSED; 3135280Sroot return (0); 3147511Sroot bad2: 3157511Sroot in_pcbdetach(inp); 3167511Sroot bad: 3177511Sroot return (error); 3185280Sroot } 3195280Sroot 3205280Sroot /* 3215280Sroot * Initiate (or continue) disconnect. 3225280Sroot * If embryonic state, just send reset (once). 3235280Sroot * If not in ``let data drain'' option, just drop. 3245280Sroot * Otherwise (hard), mark socket disconnecting and drop 3255280Sroot * current input data; switch states based on user close, and 3265280Sroot * send segment to peer (with FIN). 3275280Sroot */ 32810397Ssam struct tcpcb * 3295280Sroot tcp_disconnect(tp) 33010397Ssam register struct tcpcb *tp; 3315280Sroot { 3325280Sroot struct socket *so = tp->t_inpcb->inp_socket; 3335280Sroot 3345280Sroot if (tp->t_state < TCPS_ESTABLISHED) 33510397Ssam tp = tcp_close(tp); 3365392Swnj else if (so->so_linger == 0) 33710397Ssam tp = tcp_drop(tp, 0); 3385280Sroot else { 3395280Sroot soisdisconnecting(so); 3405280Sroot sbflush(&so->so_rcv); 34110397Ssam tp = tcp_usrclosed(tp); 34210397Ssam if (tp) 34310397Ssam (void) tcp_output(tp); 3445280Sroot } 34510397Ssam return (tp); 3465280Sroot } 3475280Sroot 3485280Sroot /* 3495280Sroot * User issued close, and wish to trail through shutdown states: 3505280Sroot * if never received SYN, just forget it. If got a SYN from peer, 3515280Sroot * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. 3525280Sroot * If already got a FIN from peer, then almost done; go to LAST_ACK 3535280Sroot * state. In all other cases, have already sent FIN to peer (e.g. 3545280Sroot * after PRU_SHUTDOWN), and just have to play tedious game waiting 3555280Sroot * for peer to send FIN or not respond to keep-alives, etc. 3565897Swnj * We can let the user exit from the close as soon as the FIN is acked. 3575280Sroot */ 35810397Ssam struct tcpcb * 3595245Sroot tcp_usrclosed(tp) 36010397Ssam register struct tcpcb *tp; 3615245Sroot { 3625245Sroot 3635245Sroot switch (tp->t_state) { 3645245Sroot 36512438Ssam case TCPS_CLOSED: 3665245Sroot case TCPS_LISTEN: 3675245Sroot case TCPS_SYN_SENT: 3685245Sroot tp->t_state = TCPS_CLOSED; 36910397Ssam tp = tcp_close(tp); 3705245Sroot break; 3715245Sroot 3725245Sroot case TCPS_SYN_RECEIVED: 3735245Sroot case TCPS_ESTABLISHED: 3745245Sroot tp->t_state = TCPS_FIN_WAIT_1; 3755245Sroot break; 3765245Sroot 3775245Sroot case TCPS_CLOSE_WAIT: 3785245Sroot tp->t_state = TCPS_LAST_ACK; 3795245Sroot break; 3805245Sroot } 38110397Ssam if (tp && tp->t_state >= TCPS_FIN_WAIT_2) 3825897Swnj soisdisconnected(tp->t_inpcb->inp_socket); 38310397Ssam return (tp); 3845245Sroot } 385