156483Ssklower /* 256484Ssklower * Copyright (c) 1992 Regents of the University of California. 356483Ssklower * All rights reserved. 456483Ssklower * 556483Ssklower * %sccs.include.redist.c% 656483Ssklower * 7*56681Ssklower * @(#)tuba_usrreq.c 7.4 (Berkeley) 11/05/92 856483Ssklower */ 956483Ssklower 1056565Ssklower #include <sys/param.h> 1156565Ssklower #include <sys/systm.h> 1256565Ssklower #include <sys/malloc.h> 1356565Ssklower #include <sys/mbuf.h> 1456565Ssklower #include <sys/socket.h> 1556565Ssklower #include <sys/socketvar.h> 1656565Ssklower #include <sys/protosw.h> 1756565Ssklower #include <sys/errno.h> 1856565Ssklower #include <sys/stat.h> 1956483Ssklower 2056565Ssklower #include <net/if.h> 2156565Ssklower #include <net/route.h> 2256483Ssklower 2356565Ssklower #include <netinet/in.h> 2456565Ssklower #include <netinet/in_systm.h> 2556565Ssklower #include <netinet/ip.h> 2656565Ssklower #include <netinet/in_pcb.h> 2756565Ssklower #include <netinet/ip_var.h> 2856565Ssklower #include <netinet/tcp.h> 2956565Ssklower #include <netinet/tcp_fsm.h> 3056565Ssklower #include <netinet/tcp_seq.h> 3156565Ssklower #include <netinet/tcp_timer.h> 3256565Ssklower #include <netinet/tcp_var.h> 3356565Ssklower #include <netinet/tcpip.h> 3456565Ssklower #include <netinet/tcp_debug.h> 3556483Ssklower 3656565Ssklower #include <netiso/argo_debug.h> 3756565Ssklower #include <netiso/iso.h> 3856565Ssklower #include <netiso/clnp.h> 3956565Ssklower #include <netiso/iso_pcb.h> 4056565Ssklower #include <netiso/iso_var.h> 41*56681Ssklower #include <netiso/tuba_table.h> 4256483Ssklower /* 4356483Ssklower * TCP protocol interface to socket abstraction. 4456483Ssklower */ 4556483Ssklower extern char *tcpstates[]; 4656483Ssklower extern struct inpcb tcb; 4756483Ssklower struct isopcb tuba_isopcb; 4856483Ssklower 4956483Ssklower /* 5056483Ssklower * Process a TCP user request for TCP tb. If this is a send request 5156483Ssklower * then m is the mbuf chain of send data. If this is a timer expiration 5256483Ssklower * (called from the software clock routine), then timertype tells which timer. 5356483Ssklower */ 5456483Ssklower /*ARGSUSED*/ 5556483Ssklower tuba_usrreq(so, req, m, nam, control) 5656483Ssklower struct socket *so; 5756483Ssklower int req; 5856483Ssklower struct mbuf *m, *nam, *control; 5956483Ssklower { 6056483Ssklower register struct inpcb *inp; 6156483Ssklower register struct isopcb *isop; 6256483Ssklower register struct tcpcb *tp; 6356483Ssklower int s; 6456483Ssklower int error = 0; 6556483Ssklower int ostate; 6656565Ssklower struct sockaddr_iso *siso; 6756483Ssklower 6856483Ssklower if (req == PRU_CONTROL) 6956483Ssklower return (iso_control(so, (int)m, (caddr_t)nam, 7056483Ssklower (struct ifnet *)control)); 7156483Ssklower 7256483Ssklower s = splnet(); 7356483Ssklower inp = sotoinpcb(so); 7456483Ssklower /* 7556483Ssklower * When a TCP is attached to a socket, then there will be 7656483Ssklower * a (struct inpcb) pointed at by the socket, and this 7756483Ssklower * structure will point at a subsidary (struct tcpcb). 7856483Ssklower */ 7956483Ssklower if (inp == 0 && req != PRU_ATTACH) { 8056483Ssklower splx(s); 8156483Ssklower return (EINVAL); /* XXX */ 8256483Ssklower } 8356483Ssklower if (inp) { 8456565Ssklower tp = intotcpcb(inp); 8556483Ssklower if (tp == 0) 8656483Ssklower panic("tuba_usrreq"); 8756483Ssklower ostate = tp->t_state; 8856565Ssklower isop = (struct isopcb *)tp->t_tuba_pcb; 8956483Ssklower if (isop == 0) 9056483Ssklower panic("tuba_usrreq 2"); 9156483Ssklower } else 9256483Ssklower ostate = 0; 9356483Ssklower switch (req) { 9456483Ssklower 9556483Ssklower /* 9656483Ssklower * TCP attaches to socket via PRU_ATTACH, reserving space, 9756483Ssklower * and an internet control block. We also need to 9856483Ssklower * allocate an isopcb and separate the control block from 9956483Ssklower * tcp/ip ones. 10056483Ssklower */ 10156483Ssklower case PRU_ATTACH: 10256483Ssklower if (error = iso_pcballoc(so, &tuba_isopcb)) 10356483Ssklower break; 104*56681Ssklower isop = (struct isopcb *)so->so_pcb; 105*56681Ssklower so->so_pcb = 0; 106*56681Ssklower if (error = tcp_usrreq(so, req, m, nam, control)) { 10756483Ssklower isop->isop_socket = 0; 108*56681Ssklower iso_pcbdetach(isop); 109*56681Ssklower } else { 110*56681Ssklower inp = sotoinpcb(so); 111*56681Ssklower tp = intotcpcb(inp); 112*56681Ssklower if (tp == 0) 113*56681Ssklower panic("tuba_usrreq 3"); 114*56681Ssklower tp->t_tuba_pcb = (caddr_t) isop; 11556483Ssklower } 11656483Ssklower goto notrace; 11756483Ssklower 11856483Ssklower /* 11956483Ssklower * PRU_DETACH detaches the TCP protocol from the socket. 12056483Ssklower * If the protocol state is non-embryonic, then can't 12156483Ssklower * do this directly: have to initiate a PRU_DISCONNECT, 12256483Ssklower * which may finish later; embryonic TCB's can just 12356483Ssklower * be discarded here. 12456483Ssklower */ 12556483Ssklower case PRU_DETACH: 12656483Ssklower if (tp->t_state > TCPS_LISTEN) 12756483Ssklower tp = tcp_disconnect(tp); 12856483Ssklower else 12956483Ssklower tp = tcp_close(tp); 13056483Ssklower if (tp == 0) 13156483Ssklower tuba_pcbdetach(isop); 13256483Ssklower break; 13356483Ssklower 13456483Ssklower /* 13556483Ssklower * Give the socket an address. 13656483Ssklower */ 13756483Ssklower case PRU_BIND: 13856483Ssklower siso = mtod(nam, struct sockaddr_iso *); 13956483Ssklower if (siso->siso_tlen && siso->siso_tlen != 2) { 14056483Ssklower error = EINVAL; 14156483Ssklower break; 14256483Ssklower } 14356483Ssklower if ((error = iso_pcbbind(isop, nam)) || 14456483Ssklower (siso = isop->isop_laddr) == 0) 14556483Ssklower break; 14656483Ssklower bcopy(TSEL(siso), &inp->inp_lport, 2); 14756483Ssklower if (siso->siso_nlen && 148*56681Ssklower !(inp->inp_laddr.s_addr = tuba_lookup(&siso->siso_addr, M_WAITOK))) 14956483Ssklower error = ENOBUFS; 15056483Ssklower break; 15156483Ssklower 15256483Ssklower /* 15356483Ssklower * Prepare to accept connections. 15456483Ssklower */ 15556483Ssklower case PRU_CONNECT: 15656483Ssklower case PRU_LISTEN: 15756483Ssklower if (inp->inp_lport == 0 && 15856483Ssklower (error = iso_pcbbind(isop, (struct mbuf *)0))) 15956483Ssklower break; 16056483Ssklower bcopy(TSEL(isop->isop_laddr), &inp->inp_lport, 2); 16156565Ssklower if (req == PRU_LISTEN) { 16256483Ssklower tp->t_state = TCPS_LISTEN; 16356483Ssklower break; 16456483Ssklower } 16556483Ssklower /*FALLTHROUGH*/ 16656483Ssklower /* 16756483Ssklower * Initiate connection to peer. 16856483Ssklower * Create a template for use in transmissions on this connection. 16956483Ssklower * Enter SYN_SENT state, and mark socket as connecting. 17056483Ssklower * Start keep-alive timer, and seed output sequence space. 17156483Ssklower * Send initial segment on connection. 17256483Ssklower */ 17356483Ssklower /* case PRU_CONNECT: */ 17456483Ssklower if (error = iso_pcbconnect(isop, nam)) 17556483Ssklower break; 17656483Ssklower siso = mtod(nam, struct sockaddr_iso *); 177*56681Ssklower if (!(inp->inp_faddr.s_addr = tuba_lookup(&siso->siso_addr, M_WAITOK))) { 17856483Ssklower unconnect: 17956483Ssklower iso_pcbdisconnect(isop); 18056483Ssklower error = ENOBUFS; 18156483Ssklower break; 18256483Ssklower } 18356483Ssklower bcopy(TSEL(isop->isop_faddr), &inp->inp_fport, 2); 18456565Ssklower if (inp->inp_laddr.s_addr == 0 && 18556483Ssklower (inp->inp_laddr.s_addr = 186*56681Ssklower tuba_lookup(&isop->isop_laddr->siso_addr, M_WAITOK)) == 0) 18756483Ssklower goto unconnect; 18856483Ssklower if ((tp->t_template = tcp_template(tp)) == 0) 18956483Ssklower goto unconnect; 19056483Ssklower soisconnecting(so); 19156483Ssklower tcpstat.tcps_connattempt++; 19256483Ssklower tp->t_state = TCPS_SYN_SENT; 19356483Ssklower tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; 19456483Ssklower tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; 19556483Ssklower tcp_sendseqinit(tp); 19656483Ssklower error = tcp_output(tp); 19756483Ssklower tuba_refcnt(isop, 1); 19856483Ssklower break; 19956483Ssklower 20056483Ssklower /* 20156483Ssklower * Initiate disconnect from peer. 20256483Ssklower * If connection never passed embryonic stage, just drop; 20356483Ssklower * else if don't need to let data drain, then can just drop anyways, 20456483Ssklower * else have to begin TCP shutdown process: mark socket disconnecting, 20556483Ssklower * drain unread data, state switch to reflect user close, and 20656483Ssklower * send segment (e.g. FIN) to peer. Socket will be really disconnected 20756483Ssklower * when peer sends FIN and acks ours. 20856483Ssklower * 20956483Ssklower * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB. 21056483Ssklower */ 21156483Ssklower case PRU_DISCONNECT: 21256483Ssklower if ((tp = tcp_disconnect(tp)) == 0) 21356483Ssklower tuba_pcbdetach(isop); 21456483Ssklower break; 21556483Ssklower 21656483Ssklower /* 21756483Ssklower * Accept a connection. Essentially all the work is 21856483Ssklower * done at higher levels; just return the address 21956483Ssklower * of the peer, storing through addr. 22056483Ssklower */ 22156483Ssklower case PRU_ACCEPT: 22256483Ssklower bcopy((caddr_t)isop->isop_faddr, mtod(m, caddr_t), 22356483Ssklower nam->m_len = isop->isop_faddr->siso_len); 22456483Ssklower break; 22556483Ssklower 22656483Ssklower /* 22756483Ssklower * Mark the connection as being incapable of further output. 22856483Ssklower */ 22956483Ssklower case PRU_SHUTDOWN: 23056483Ssklower socantsendmore(so); 23156483Ssklower tp = tcp_usrclosed(tp); 23256483Ssklower if (tp) 23356483Ssklower error = tcp_output(tp); 23456483Ssklower else 23556483Ssklower tuba_pcbdetach(isop); 23656483Ssklower break; 23756483Ssklower /* 23856483Ssklower * Abort the TCP. 23956483Ssklower */ 24056483Ssklower case PRU_ABORT: 24156483Ssklower if ((tp = tcp_drop(tp, ECONNABORTED)) == 0) 24256483Ssklower tuba_pcbdetach(isop); 24356483Ssklower break; 24456483Ssklower 24556483Ssklower 24656483Ssklower case PRU_SOCKADDR: 24756483Ssklower if (isop->isop_laddr) 24856483Ssklower bcopy((caddr_t)isop->isop_laddr, mtod(m, caddr_t), 24956483Ssklower nam->m_len = isop->isop_laddr->siso_len); 25056483Ssklower break; 25156483Ssklower 25256483Ssklower case PRU_PEERADDR: 25356483Ssklower if (isop->isop_faddr) 25456483Ssklower bcopy((caddr_t)isop->isop_faddr, mtod(m, caddr_t), 25556483Ssklower nam->m_len = isop->isop_faddr->siso_len); 25656483Ssklower break; 25756483Ssklower 25856483Ssklower default: 25956483Ssklower error = tcp_usrreq(so, req, m, nam, control); 26056483Ssklower goto notrace; 26156483Ssklower } 26256483Ssklower if (tp && (so->so_options & SO_DEBUG)) 26356483Ssklower tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req); 26456483Ssklower notrace: 26556483Ssklower splx(s); 26656483Ssklower return(error); 26756483Ssklower } 26856483Ssklower 26956483Ssklower tuba_ctloutput(op, so, level, optname, mp) 27056483Ssklower int op; 27156483Ssklower struct socket *so; 27256483Ssklower int level, optname; 27356483Ssklower struct mbuf **mp; 27456483Ssklower { 27556483Ssklower int clnp_ctloutput(), tcp_ctloutput(); 27656483Ssklower 27756483Ssklower return ((level != IPPROTO_TCP ? clnp_ctloutput : tcp_ctloutput) 27856483Ssklower (clnp_ctloutput(op, so, level, optname, mp))); 27956483Ssklower } 280