1*13221Ssam /* tcp_usrreq.c 1.80 83/06/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" 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(); 3212766Ssam 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*/ 4012766Ssam tcp_usrreq(so, req, m, nam, rights) 414809Swnj struct socket *so; 424809Swnj int req; 4312766Ssam 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 5112766Ssam if (rights && rights->m_len) { 5212766Ssam splx(s); 5312766Ssam return (EINVAL); 5412766Ssam } 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 /* 15613117Ssam * Create a TCP connection between two sockets. 15713117Ssam */ 15813117Ssam case PRU_CONNECT2: 15913117Ssam error = EOPNOTSUPP; 16013117Ssam break; 16113117Ssam 16213117Ssam /* 1635280Sroot * Initiate disconnect from peer. 1645280Sroot * If connection never passed embryonic stage, just drop; 1655280Sroot * else if don't need to let data drain, then can just drop anyways, 1665280Sroot * else have to begin TCP shutdown process: mark socket disconnecting, 1675280Sroot * drain unread data, state switch to reflect user close, and 1685280Sroot * send segment (e.g. FIN) to peer. Socket will be really disconnected 1695280Sroot * when peer sends FIN and acks ours. 1705280Sroot * 1715280Sroot * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB. 1725280Sroot */ 1735280Sroot case PRU_DISCONNECT: 17410397Ssam tp = tcp_disconnect(tp); 1755245Sroot break; 1765245Sroot 1775280Sroot /* 1785280Sroot * Accept a connection. Essentially all the work is 1795280Sroot * done at higher levels; just return the address 1805280Sroot * of the peer, storing through addr. 1815280Sroot */ 1826117Swnj case PRU_ACCEPT: { 1838272Sroot struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 1846117Swnj 1858272Sroot nam->m_len = sizeof (struct sockaddr_in); 1868272Sroot sin->sin_family = AF_INET; 1878272Sroot sin->sin_port = inp->inp_fport; 1888272Sroot sin->sin_addr = inp->inp_faddr; 1898272Sroot break; 1906117Swnj } 1914925Swnj 1925280Sroot /* 1935280Sroot * Mark the connection as being incapable of further output. 1945280Sroot */ 1954809Swnj case PRU_SHUTDOWN: 1965089Swnj socantsendmore(so); 19710397Ssam tp = tcp_usrclosed(tp); 19810397Ssam if (tp) 19910397Ssam error = tcp_output(tp); 2004567Swnj break; 2014497Swnj 2025280Sroot /* 2035280Sroot * After a receive, possibly send window update to peer. 2045280Sroot */ 2054809Swnj case PRU_RCVD: 2065113Swnj (void) tcp_output(tp); 2074567Swnj break; 2084497Swnj 2095280Sroot /* 2105280Sroot * Do a send by putting data in output queue and updating urgent 2115280Sroot * marker if URG set. Possibly send more data. 2125280Sroot */ 2134809Swnj case PRU_SEND: 2145075Swnj sbappend(&so->so_snd, m); 2156506Ssam #ifdef notdef 2165089Swnj if (tp->t_flags & TF_PUSH) 2175075Swnj tp->snd_end = tp->snd_una + so->so_snd.sb_cc; 2186506Ssam #endif 2196506Ssam error = tcp_output(tp); 22012766Ssam if (error) { /* XXX fix to use other path */ 22112766Ssam if (error == ENOBUFS) /* XXX */ 22212766Ssam error = 0; /* XXX */ 22312766Ssam tcpsenderrors++; 22412766Ssam } 2254567Swnj break; 2264567Swnj 2275280Sroot /* 2285280Sroot * Abort the TCP. 2295280Sroot */ 2304809Swnj case PRU_ABORT: 23110397Ssam tp = tcp_drop(tp, ECONNABORTED); 2324567Swnj break; 2334567Swnj 2345280Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */ 2354809Swnj case PRU_CONTROL: 2364886Swnj error = EOPNOTSUPP; 2374809Swnj break; 2384809Swnj 2395113Swnj case PRU_SENSE: 2405113Swnj error = EOPNOTSUPP; 2415113Swnj break; 2425417Swnj /* END UNIMPLEMENTED HOOKS */ 2435113Swnj 2445113Swnj case PRU_RCVOOB: 2455442Swnj if (so->so_oobmark == 0 && 2465442Swnj (so->so_state & SS_RCVATMARK) == 0) { 2475417Swnj error = EINVAL; 2485417Swnj break; 2495417Swnj } 2505549Swnj if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) { 2515442Swnj error = EWOULDBLOCK; 2525549Swnj break; 2535442Swnj } 2548310Sroot m->m_len = 1; 2555549Swnj *mtod(m, caddr_t) = tp->t_iobc; 2565113Swnj break; 2575113Swnj 2585113Swnj case PRU_SENDOOB: 2595442Swnj if (sbspace(&so->so_snd) < -512) { 26011229Ssam m_freem(m); 2615442Swnj error = ENOBUFS; 2625442Swnj break; 2635442Swnj } 2645417Swnj tp->snd_up = tp->snd_una + so->so_snd.sb_cc + 1; 2655417Swnj sbappend(&so->so_snd, m); 2665549Swnj tp->t_force = 1; 2676506Ssam error = tcp_output(tp); 2685549Swnj tp->t_force = 0; 2695113Swnj break; 2705113Swnj 2716510Ssam case PRU_SOCKADDR: 2728272Sroot in_setsockaddr(inp, nam); 2736510Ssam break; 2746510Ssam 2755280Sroot /* 2765280Sroot * TCP slow timer went off; going through this 2775280Sroot * routine for tracing's sake. 2785280Sroot */ 2794809Swnj case PRU_SLOWTIMO: 28010397Ssam tp = tcp_timers(tp, (int)nam); 2818272Sroot req |= (int)nam << 8; /* for debug's sake */ 2824809Swnj break; 2834809Swnj 2844731Swnj default: 2854731Swnj panic("tcp_usrreq"); 2864567Swnj } 2875270Sroot if (tp && (so->so_options & SO_DEBUG)) 2885270Sroot tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req); 2894567Swnj splx(s); 2904886Swnj return (error); 2914497Swnj } 2925245Sroot 2935953Swnj int tcp_sendspace = 1024*2; 2946601Ssam int tcp_recvspace = 1024*2; 2955280Sroot /* 2965280Sroot * Attach TCP protocol to socket, allocating 2975280Sroot * internet protocol control block, tcp control block, 2985280Sroot * bufer space, and entering LISTEN state if to accept connections. 2995280Sroot */ 3008272Sroot tcp_attach(so) 3015280Sroot struct socket *so; 3025280Sroot { 3035280Sroot register struct tcpcb *tp; 3045280Sroot struct inpcb *inp; 3055280Sroot int error; 3065280Sroot 3079031Sroot error = soreserve(so, tcp_sendspace, tcp_recvspace); 3085280Sroot if (error) 3097511Sroot goto bad; 3107511Sroot error = in_pcballoc(so, &tcb); 3117511Sroot if (error) 3128272Sroot goto bad; 3138272Sroot inp = sotoinpcb(so); 3145280Sroot tp = tcp_newtcpcb(inp); 3157511Sroot if (tp == 0) { 3167511Sroot error = ENOBUFS; 3177511Sroot goto bad2; 3187511Sroot } 3198272Sroot tp->t_state = TCPS_CLOSED; 3205280Sroot return (0); 3217511Sroot bad2: 3227511Sroot in_pcbdetach(inp); 3237511Sroot bad: 3247511Sroot return (error); 3255280Sroot } 3265280Sroot 3275280Sroot /* 3285280Sroot * Initiate (or continue) disconnect. 3295280Sroot * If embryonic state, just send reset (once). 330*13221Ssam * If in ``let data drain'' option and linger null, just drop. 3315280Sroot * Otherwise (hard), mark socket disconnecting and drop 3325280Sroot * current input data; switch states based on user close, and 3335280Sroot * send segment to peer (with FIN). 3345280Sroot */ 33510397Ssam struct tcpcb * 3365280Sroot tcp_disconnect(tp) 33710397Ssam register struct tcpcb *tp; 3385280Sroot { 3395280Sroot struct socket *so = tp->t_inpcb->inp_socket; 3405280Sroot 3415280Sroot if (tp->t_state < TCPS_ESTABLISHED) 34210397Ssam tp = tcp_close(tp); 343*13221Ssam else if ((so->so_options & SO_LINGER) && so->so_linger == 0) 34410397Ssam tp = tcp_drop(tp, 0); 3455280Sroot else { 3465280Sroot soisdisconnecting(so); 3475280Sroot sbflush(&so->so_rcv); 34810397Ssam tp = tcp_usrclosed(tp); 34910397Ssam if (tp) 35010397Ssam (void) tcp_output(tp); 3515280Sroot } 35210397Ssam return (tp); 3535280Sroot } 3545280Sroot 3555280Sroot /* 3565280Sroot * User issued close, and wish to trail through shutdown states: 3575280Sroot * if never received SYN, just forget it. If got a SYN from peer, 3585280Sroot * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. 3595280Sroot * If already got a FIN from peer, then almost done; go to LAST_ACK 3605280Sroot * state. In all other cases, have already sent FIN to peer (e.g. 3615280Sroot * after PRU_SHUTDOWN), and just have to play tedious game waiting 3625280Sroot * for peer to send FIN or not respond to keep-alives, etc. 3635897Swnj * We can let the user exit from the close as soon as the FIN is acked. 3645280Sroot */ 36510397Ssam struct tcpcb * 3665245Sroot tcp_usrclosed(tp) 36710397Ssam register struct tcpcb *tp; 3685245Sroot { 3695245Sroot 3705245Sroot switch (tp->t_state) { 3715245Sroot 37212438Ssam case TCPS_CLOSED: 3735245Sroot case TCPS_LISTEN: 3745245Sroot case TCPS_SYN_SENT: 3755245Sroot tp->t_state = TCPS_CLOSED; 37610397Ssam tp = tcp_close(tp); 3775245Sroot break; 3785245Sroot 3795245Sroot case TCPS_SYN_RECEIVED: 3805245Sroot case TCPS_ESTABLISHED: 3815245Sroot tp->t_state = TCPS_FIN_WAIT_1; 3825245Sroot break; 3835245Sroot 3845245Sroot case TCPS_CLOSE_WAIT: 3855245Sroot tp->t_state = TCPS_LAST_ACK; 3865245Sroot break; 3875245Sroot } 38810397Ssam if (tp && tp->t_state >= TCPS_FIN_WAIT_2) 3895897Swnj soisdisconnected(tp->t_inpcb->inp_socket); 39010397Ssam return (tp); 3915245Sroot } 392