1*17064Sbloom /* tcp_usrreq.c 6.4 84/08/29 */ 24567Swnj 3*17064Sbloom #include "param.h" 4*17064Sbloom #include "systm.h" 5*17064Sbloom #include "mbuf.h" 6*17064Sbloom #include "socket.h" 7*17064Sbloom #include "socketvar.h" 8*17064Sbloom #include "protosw.h" 9*17064Sbloom #include "errno.h" 10*17064Sbloom #include "stat.h" 118697Sroot 128697Sroot #include "../net/if.h" 138697Sroot #include "../net/route.h" 1410896Ssam 15*17064Sbloom #include "in.h" 16*17064Sbloom #include "in_pcb.h" 17*17064Sbloom #include "in_systm.h" 18*17064Sbloom #include "ip.h" 19*17064Sbloom #include "ip_var.h" 20*17064Sbloom #include "tcp.h" 21*17064Sbloom #include "tcp_fsm.h" 22*17064Sbloom #include "tcp_seq.h" 23*17064Sbloom #include "tcp_timer.h" 24*17064Sbloom #include "tcp_var.h" 25*17064Sbloom #include "tcpip.h" 26*17064Sbloom #include "tcp_debug.h" 274497Swnj 285280Sroot /* 295280Sroot * TCP protocol interface to socket abstraction. 305280Sroot */ 315280Sroot extern char *tcpstates[]; 324954Swnj struct tcpcb *tcp_newtcpcb(); 3312766Ssam int tcpsenderrors; 345280Sroot 354734Swnj /* 365280Sroot * Process a TCP user request for TCP tb. If this is a send request 374731Swnj * then m is the mbuf chain of send data. If this is a timer expiration 384731Swnj * (called from the software clock routine), then timertype tells which timer. 394731Swnj */ 408601Sroot /*ARGSUSED*/ 4112766Ssam tcp_usrreq(so, req, m, nam, rights) 424809Swnj struct socket *so; 434809Swnj int req; 4412766Ssam struct mbuf *m, *nam, *rights; 454497Swnj { 464886Swnj register struct inpcb *inp = sotoinpcb(so); 474911Swnj register struct tcpcb *tp; 484567Swnj int s = splnet(); 494809Swnj int error = 0; 505270Sroot int ostate; 514497Swnj 5212766Ssam if (rights && rights->m_len) { 5312766Ssam splx(s); 5412766Ssam return (EINVAL); 5512766Ssam } 564886Swnj /* 575280Sroot * When a TCP is attached to a socket, then there will be 585280Sroot * a (struct inpcb) pointed at by the socket, and this 595280Sroot * structure will point at a subsidary (struct tcpcb). 604886Swnj */ 615089Swnj if (inp == 0 && req != PRU_ATTACH) { 625075Swnj splx(s); 635280Sroot return (EINVAL); /* XXX */ 645075Swnj } 655075Swnj if (inp) { 664911Swnj tp = intotcpcb(inp); 678272Sroot /* WHAT IF TP IS 0? */ 684731Swnj #ifdef KPROF 695075Swnj tcp_acounts[tp->t_state][req]++; 704731Swnj #endif 715270Sroot ostate = tp->t_state; 727511Sroot } else 737511Sroot ostate = 0; 744809Swnj switch (req) { 754497Swnj 765280Sroot /* 775280Sroot * TCP attaches to socket via PRU_ATTACH, reserving space, 788272Sroot * and an internet control block. 795280Sroot */ 804809Swnj case PRU_ATTACH: 814954Swnj if (inp) { 824809Swnj error = EISCONN; 834911Swnj break; 844886Swnj } 858640Sroot error = tcp_attach(so); 865075Swnj if (error) 874954Swnj break; 8810397Ssam if ((so->so_options & SO_LINGER) && so->so_linger == 0) 895392Swnj so->so_linger = TCP_LINGERTIME; 905280Sroot tp = sototcpcb(so); 914567Swnj break; 924497Swnj 935280Sroot /* 945280Sroot * PRU_DETACH detaches the TCP protocol from the socket. 955280Sroot * If the protocol state is non-embryonic, then can't 965280Sroot * do this directly: have to initiate a PRU_DISCONNECT, 975280Sroot * which may finish later; embryonic TCB's can just 985280Sroot * be discarded here. 995280Sroot */ 1004809Swnj case PRU_DETACH: 1015280Sroot if (tp->t_state > TCPS_LISTEN) 10210397Ssam tp = tcp_disconnect(tp); 10310397Ssam else 10410397Ssam tp = tcp_close(tp); 1054809Swnj break; 1064809Swnj 1075280Sroot /* 1088272Sroot * Give the socket an address. 1098272Sroot */ 1108272Sroot case PRU_BIND: 1118272Sroot error = in_pcbbind(inp, nam); 1128272Sroot if (error) 1138272Sroot break; 1148272Sroot break; 1158272Sroot 1168272Sroot /* 1178272Sroot * Prepare to accept connections. 1188272Sroot */ 1198272Sroot case PRU_LISTEN: 1208272Sroot if (inp->inp_lport == 0) 1218272Sroot error = in_pcbbind(inp, (struct mbuf *)0); 1228272Sroot if (error == 0) 1238272Sroot tp->t_state = TCPS_LISTEN; 1248272Sroot break; 1258272Sroot 1268272Sroot /* 1275280Sroot * Initiate connection to peer. 1285280Sroot * Create a template for use in transmissions on this connection. 1295280Sroot * Enter SYN_SENT state, and mark socket as connecting. 1305280Sroot * Start keep-alive timer, and seed output sequence space. 1315280Sroot * Send initial segment on connection. 1325280Sroot */ 1334809Swnj case PRU_CONNECT: 1348272Sroot if (inp->inp_lport == 0) { 1358272Sroot error = in_pcbbind(inp, (struct mbuf *)0); 1368272Sroot if (error) 1378272Sroot break; 1388272Sroot } 1398272Sroot error = in_pcbconnect(inp, nam); 1404954Swnj if (error) 1414886Swnj break; 1425174Swnj tp->t_template = tcp_template(tp); 1435280Sroot if (tp->t_template == 0) { 1445280Sroot in_pcbdisconnect(inp); 1455280Sroot error = ENOBUFS; 1465280Sroot break; 1475280Sroot } 1484886Swnj soisconnecting(so); 1495075Swnj tp->t_state = TCPS_SYN_SENT; 1505245Sroot tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; 1515245Sroot tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; 1525245Sroot tcp_sendseqinit(tp); 1536506Ssam error = tcp_output(tp); 1544567Swnj break; 1554497Swnj 1565280Sroot /* 15713117Ssam * Create a TCP connection between two sockets. 15813117Ssam */ 15913117Ssam case PRU_CONNECT2: 16013117Ssam error = EOPNOTSUPP; 16113117Ssam break; 16213117Ssam 16313117Ssam /* 1645280Sroot * Initiate disconnect from peer. 1655280Sroot * If connection never passed embryonic stage, just drop; 1665280Sroot * else if don't need to let data drain, then can just drop anyways, 1675280Sroot * else have to begin TCP shutdown process: mark socket disconnecting, 1685280Sroot * drain unread data, state switch to reflect user close, and 1695280Sroot * send segment (e.g. FIN) to peer. Socket will be really disconnected 1705280Sroot * when peer sends FIN and acks ours. 1715280Sroot * 1725280Sroot * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB. 1735280Sroot */ 1745280Sroot case PRU_DISCONNECT: 17510397Ssam tp = tcp_disconnect(tp); 1765245Sroot break; 1775245Sroot 1785280Sroot /* 1795280Sroot * Accept a connection. Essentially all the work is 1805280Sroot * done at higher levels; just return the address 1815280Sroot * of the peer, storing through addr. 1825280Sroot */ 1836117Swnj case PRU_ACCEPT: { 1848272Sroot struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 1856117Swnj 1868272Sroot nam->m_len = sizeof (struct sockaddr_in); 1878272Sroot sin->sin_family = AF_INET; 1888272Sroot sin->sin_port = inp->inp_fport; 1898272Sroot sin->sin_addr = inp->inp_faddr; 1908272Sroot break; 1916117Swnj } 1924925Swnj 1935280Sroot /* 1945280Sroot * Mark the connection as being incapable of further output. 1955280Sroot */ 1964809Swnj case PRU_SHUTDOWN: 1975089Swnj socantsendmore(so); 19810397Ssam tp = tcp_usrclosed(tp); 19910397Ssam if (tp) 20010397Ssam error = tcp_output(tp); 2014567Swnj break; 2024497Swnj 2035280Sroot /* 2045280Sroot * After a receive, possibly send window update to peer. 2055280Sroot */ 2064809Swnj case PRU_RCVD: 2075113Swnj (void) tcp_output(tp); 2084567Swnj break; 2094497Swnj 2105280Sroot /* 2115280Sroot * Do a send by putting data in output queue and updating urgent 2125280Sroot * marker if URG set. Possibly send more data. 2135280Sroot */ 2144809Swnj case PRU_SEND: 2155075Swnj sbappend(&so->so_snd, m); 2166506Ssam #ifdef notdef 2175089Swnj if (tp->t_flags & TF_PUSH) 2185075Swnj tp->snd_end = tp->snd_una + so->so_snd.sb_cc; 2196506Ssam #endif 2206506Ssam error = tcp_output(tp); 22112766Ssam if (error) { /* XXX fix to use other path */ 22212766Ssam if (error == ENOBUFS) /* XXX */ 22312766Ssam error = 0; /* XXX */ 22412766Ssam tcpsenderrors++; 22512766Ssam } 2264567Swnj break; 2274567Swnj 2285280Sroot /* 2295280Sroot * Abort the TCP. 2305280Sroot */ 2314809Swnj case PRU_ABORT: 23210397Ssam tp = tcp_drop(tp, ECONNABORTED); 2334567Swnj break; 2344567Swnj 2355280Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */ 2364809Swnj case PRU_CONTROL: 2374886Swnj error = EOPNOTSUPP; 2384809Swnj break; 23916989Skarels /* END UNIMPLEMENTED HOOKS */ 2404809Swnj 2415113Swnj case PRU_SENSE: 24216989Skarels ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; 24316989Skarels return (0); 2445113Swnj 2455113Swnj case PRU_RCVOOB: 2465442Swnj if (so->so_oobmark == 0 && 2475442Swnj (so->so_state & SS_RCVATMARK) == 0) { 2485417Swnj error = EINVAL; 2495417Swnj break; 2505417Swnj } 2515549Swnj if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) { 2525442Swnj error = EWOULDBLOCK; 2535549Swnj break; 2545442Swnj } 2558310Sroot m->m_len = 1; 2565549Swnj *mtod(m, caddr_t) = tp->t_iobc; 2575113Swnj break; 2585113Swnj 2595113Swnj case PRU_SENDOOB: 2605442Swnj if (sbspace(&so->so_snd) < -512) { 26111229Ssam m_freem(m); 2625442Swnj error = ENOBUFS; 2635442Swnj break; 2645442Swnj } 2655417Swnj tp->snd_up = tp->snd_una + so->so_snd.sb_cc + 1; 2665417Swnj sbappend(&so->so_snd, m); 2675549Swnj tp->t_force = 1; 2686506Ssam error = tcp_output(tp); 2695549Swnj tp->t_force = 0; 2705113Swnj break; 2715113Swnj 2726510Ssam case PRU_SOCKADDR: 2738272Sroot in_setsockaddr(inp, nam); 2746510Ssam break; 2756510Ssam 27614123Ssam case PRU_PEERADDR: 27714123Ssam in_setpeeraddr(inp, nam); 27814123Ssam break; 27914123Ssam 2805280Sroot /* 2815280Sroot * TCP slow timer went off; going through this 2825280Sroot * routine for tracing's sake. 2835280Sroot */ 2844809Swnj case PRU_SLOWTIMO: 28510397Ssam tp = tcp_timers(tp, (int)nam); 2868272Sroot req |= (int)nam << 8; /* for debug's sake */ 2874809Swnj break; 2884809Swnj 2894731Swnj default: 2904731Swnj panic("tcp_usrreq"); 2914567Swnj } 2925270Sroot if (tp && (so->so_options & SO_DEBUG)) 2935270Sroot tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req); 2944567Swnj splx(s); 2954886Swnj return (error); 2964497Swnj } 2975245Sroot 2985953Swnj int tcp_sendspace = 1024*2; 2996601Ssam int tcp_recvspace = 1024*2; 3005280Sroot /* 3015280Sroot * Attach TCP protocol to socket, allocating 3025280Sroot * internet protocol control block, tcp control block, 3035280Sroot * bufer space, and entering LISTEN state if to accept connections. 3045280Sroot */ 3058272Sroot tcp_attach(so) 3065280Sroot struct socket *so; 3075280Sroot { 3085280Sroot register struct tcpcb *tp; 3095280Sroot struct inpcb *inp; 3105280Sroot int error; 3115280Sroot 3129031Sroot error = soreserve(so, tcp_sendspace, tcp_recvspace); 3135280Sroot if (error) 31417047Skarels return (error); 3157511Sroot error = in_pcballoc(so, &tcb); 3167511Sroot if (error) 31717047Skarels return (error); 3188272Sroot inp = sotoinpcb(so); 3195280Sroot tp = tcp_newtcpcb(inp); 3207511Sroot if (tp == 0) { 32117047Skarels int nofd = so->so_state & SS_NOFDREF; /* XXX */ 32217047Skarels 32317047Skarels so->so_state &= ~SS_NOFDREF; /* don't free the socket yet */ 32417047Skarels in_pcbdetach(inp); 32517047Skarels so->so_state |= nofd; 32617047Skarels return (ENOBUFS); 3277511Sroot } 3288272Sroot tp->t_state = TCPS_CLOSED; 3295280Sroot return (0); 3305280Sroot } 3315280Sroot 3325280Sroot /* 3335280Sroot * Initiate (or continue) disconnect. 3345280Sroot * If embryonic state, just send reset (once). 33513221Ssam * If in ``let data drain'' option and linger null, just drop. 3365280Sroot * Otherwise (hard), mark socket disconnecting and drop 3375280Sroot * current input data; switch states based on user close, and 3385280Sroot * send segment to peer (with FIN). 3395280Sroot */ 34010397Ssam struct tcpcb * 3415280Sroot tcp_disconnect(tp) 34210397Ssam register struct tcpcb *tp; 3435280Sroot { 3445280Sroot struct socket *so = tp->t_inpcb->inp_socket; 3455280Sroot 3465280Sroot if (tp->t_state < TCPS_ESTABLISHED) 34710397Ssam tp = tcp_close(tp); 34813221Ssam else if ((so->so_options & SO_LINGER) && so->so_linger == 0) 34910397Ssam tp = tcp_drop(tp, 0); 3505280Sroot else { 3515280Sroot soisdisconnecting(so); 3525280Sroot sbflush(&so->so_rcv); 35310397Ssam tp = tcp_usrclosed(tp); 35410397Ssam if (tp) 35510397Ssam (void) tcp_output(tp); 3565280Sroot } 35710397Ssam return (tp); 3585280Sroot } 3595280Sroot 3605280Sroot /* 3615280Sroot * User issued close, and wish to trail through shutdown states: 3625280Sroot * if never received SYN, just forget it. If got a SYN from peer, 3635280Sroot * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. 3645280Sroot * If already got a FIN from peer, then almost done; go to LAST_ACK 3655280Sroot * state. In all other cases, have already sent FIN to peer (e.g. 3665280Sroot * after PRU_SHUTDOWN), and just have to play tedious game waiting 3675280Sroot * for peer to send FIN or not respond to keep-alives, etc. 3685897Swnj * We can let the user exit from the close as soon as the FIN is acked. 3695280Sroot */ 37010397Ssam struct tcpcb * 3715245Sroot tcp_usrclosed(tp) 37210397Ssam register struct tcpcb *tp; 3735245Sroot { 3745245Sroot 3755245Sroot switch (tp->t_state) { 3765245Sroot 37712438Ssam case TCPS_CLOSED: 3785245Sroot case TCPS_LISTEN: 3795245Sroot case TCPS_SYN_SENT: 3805245Sroot tp->t_state = TCPS_CLOSED; 38110397Ssam tp = tcp_close(tp); 3825245Sroot break; 3835245Sroot 3845245Sroot case TCPS_SYN_RECEIVED: 3855245Sroot case TCPS_ESTABLISHED: 3865245Sroot tp->t_state = TCPS_FIN_WAIT_1; 3875245Sroot break; 3885245Sroot 3895245Sroot case TCPS_CLOSE_WAIT: 3905245Sroot tp->t_state = TCPS_LAST_ACK; 3915245Sroot break; 3925245Sroot } 39310397Ssam if (tp && tp->t_state >= TCPS_FIN_WAIT_2) 3945897Swnj soisdisconnected(tp->t_inpcb->inp_socket); 39510397Ssam return (tp); 3965245Sroot } 397