156483Ssklower /* 256484Ssklower * Copyright (c) 1992 Regents of the University of California. 356483Ssklower * All rights reserved. 456483Ssklower * 556483Ssklower * %sccs.include.redist.c% 656483Ssklower * 7*56565Ssklower * @(#)tuba_usrreq.c 7.3 (Berkeley) 10/15/92 856483Ssklower */ 956483Ssklower 10*56565Ssklower #include <sys/param.h> 11*56565Ssklower #include <sys/systm.h> 12*56565Ssklower #include <sys/malloc.h> 13*56565Ssklower #include <sys/mbuf.h> 14*56565Ssklower #include <sys/socket.h> 15*56565Ssklower #include <sys/socketvar.h> 16*56565Ssklower #include <sys/protosw.h> 17*56565Ssklower #include <sys/errno.h> 18*56565Ssklower #include <sys/stat.h> 1956483Ssklower 20*56565Ssklower #include <net/if.h> 21*56565Ssklower #include <net/route.h> 2256483Ssklower 23*56565Ssklower #include <netinet/in.h> 24*56565Ssklower #include <netinet/in_systm.h> 25*56565Ssklower #include <netinet/ip.h> 26*56565Ssklower #include <netinet/in_pcb.h> 27*56565Ssklower #include <netinet/ip_var.h> 28*56565Ssklower #include <netinet/tcp.h> 29*56565Ssklower #include <netinet/tcp_fsm.h> 30*56565Ssklower #include <netinet/tcp_seq.h> 31*56565Ssklower #include <netinet/tcp_timer.h> 32*56565Ssklower #include <netinet/tcp_var.h> 33*56565Ssklower #include <netinet/tcpip.h> 34*56565Ssklower #include <netinet/tcp_debug.h> 3556483Ssklower 36*56565Ssklower #include <netiso/argo_debug.h> 37*56565Ssklower #include <netiso/iso.h> 38*56565Ssklower #include <netiso/clnp.h> 39*56565Ssklower #include <netiso/iso_pcb.h> 40*56565Ssklower #include <netiso/iso_var.h> 41*56565Ssklower #include <netiso/tuba_addr.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; 66*56565Ssklower 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) { 84*56565Ssklower tp = intotcpcb(inp); 8556483Ssklower if (tp == 0) 8656483Ssklower panic("tuba_usrreq"); 8756483Ssklower ostate = tp->t_state; 88*56565Ssklower 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*56565Ssklower isop = (struct isopcb *) tp->t_tuba_pcb = so->so_pcb; 10556483Ssklower if (error = tcp_userreq(so, req, m, nam, control)) { 10656483Ssklower isop->isop_socket = 0; 10756483Ssklower isop_detach(isop); 10856483Ssklower } 10956483Ssklower goto notrace; 11056483Ssklower 11156483Ssklower /* 11256483Ssklower * PRU_DETACH detaches the TCP protocol from the socket. 11356483Ssklower * If the protocol state is non-embryonic, then can't 11456483Ssklower * do this directly: have to initiate a PRU_DISCONNECT, 11556483Ssklower * which may finish later; embryonic TCB's can just 11656483Ssklower * be discarded here. 11756483Ssklower */ 11856483Ssklower case PRU_DETACH: 11956483Ssklower if (tp->t_state > TCPS_LISTEN) 12056483Ssklower tp = tcp_disconnect(tp); 12156483Ssklower else 12256483Ssklower tp = tcp_close(tp); 12356483Ssklower if (tp == 0) 12456483Ssklower tuba_pcbdetach(isop); 12556483Ssklower break; 12656483Ssklower 12756483Ssklower /* 12856483Ssklower * Give the socket an address. 12956483Ssklower */ 13056483Ssklower case PRU_BIND: 13156483Ssklower siso = mtod(nam, struct sockaddr_iso *); 13256483Ssklower if (siso->siso_tlen && siso->siso_tlen != 2) { 13356483Ssklower error = EINVAL; 13456483Ssklower break; 13556483Ssklower } 13656483Ssklower if ((error = iso_pcbbind(isop, nam)) || 13756483Ssklower (siso = isop->isop_laddr) == 0) 13856483Ssklower break; 13956483Ssklower bcopy(TSEL(siso), &inp->inp_lport, 2); 14056483Ssklower if (siso->siso_nlen && 14156483Ssklower !(inp->inp_laddr.s_addr = tuba_lookup(&siso->siso_addr))) 14256483Ssklower error = ENOBUFS; 14356483Ssklower break; 14456483Ssklower 14556483Ssklower /* 14656483Ssklower * Prepare to accept connections. 14756483Ssklower */ 14856483Ssklower case PRU_CONNECT: 14956483Ssklower case PRU_LISTEN: 15056483Ssklower if (inp->inp_lport == 0 && 15156483Ssklower (error = iso_pcbbind(isop, (struct mbuf *)0))) 15256483Ssklower break; 15356483Ssklower bcopy(TSEL(isop->isop_laddr), &inp->inp_lport, 2); 154*56565Ssklower if (req == PRU_LISTEN) { 15556483Ssklower tp->t_state = TCPS_LISTEN; 15656483Ssklower break; 15756483Ssklower } 15856483Ssklower /*FALLTHROUGH*/ 15956483Ssklower /* 16056483Ssklower * Initiate connection to peer. 16156483Ssklower * Create a template for use in transmissions on this connection. 16256483Ssklower * Enter SYN_SENT state, and mark socket as connecting. 16356483Ssklower * Start keep-alive timer, and seed output sequence space. 16456483Ssklower * Send initial segment on connection. 16556483Ssklower */ 16656483Ssklower /* case PRU_CONNECT: */ 16756483Ssklower if (error = iso_pcbconnect(isop, nam)) 16856483Ssklower break; 16956483Ssklower siso = mtod(nam, struct sockaddr_iso *); 17056483Ssklower if (!(inp->inp_faddr.s_addr = tuba_lookup(&siso->siso_addr))) { 17156483Ssklower unconnect: 17256483Ssklower iso_pcbdisconnect(isop); 17356483Ssklower error = ENOBUFS; 17456483Ssklower break; 17556483Ssklower } 17656483Ssklower bcopy(TSEL(isop->isop_faddr), &inp->inp_fport, 2); 177*56565Ssklower if (inp->inp_laddr.s_addr == 0 && 17856483Ssklower (inp->inp_laddr.s_addr = 17956483Ssklower tuba_lookup(&isop->isop_laddr->siso_addr)) == 0) 18056483Ssklower goto unconnect; 18156483Ssklower if ((tp->t_template = tcp_template(tp)) == 0) 18256483Ssklower goto unconnect; 18356483Ssklower soisconnecting(so); 18456483Ssklower tcpstat.tcps_connattempt++; 18556483Ssklower tp->t_state = TCPS_SYN_SENT; 18656483Ssklower tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; 18756483Ssklower tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; 18856483Ssklower tcp_sendseqinit(tp); 18956483Ssklower error = tcp_output(tp); 19056483Ssklower tuba_refcnt(isop, 1); 19156483Ssklower break; 19256483Ssklower 19356483Ssklower /* 19456483Ssklower * Initiate disconnect from peer. 19556483Ssklower * If connection never passed embryonic stage, just drop; 19656483Ssklower * else if don't need to let data drain, then can just drop anyways, 19756483Ssklower * else have to begin TCP shutdown process: mark socket disconnecting, 19856483Ssklower * drain unread data, state switch to reflect user close, and 19956483Ssklower * send segment (e.g. FIN) to peer. Socket will be really disconnected 20056483Ssklower * when peer sends FIN and acks ours. 20156483Ssklower * 20256483Ssklower * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB. 20356483Ssklower */ 20456483Ssklower case PRU_DISCONNECT: 20556483Ssklower if ((tp = tcp_disconnect(tp)) == 0) 20656483Ssklower tuba_pcbdetach(isop); 20756483Ssklower break; 20856483Ssklower 20956483Ssklower /* 21056483Ssklower * Accept a connection. Essentially all the work is 21156483Ssklower * done at higher levels; just return the address 21256483Ssklower * of the peer, storing through addr. 21356483Ssklower */ 21456483Ssklower case PRU_ACCEPT: 21556483Ssklower bcopy((caddr_t)isop->isop_faddr, mtod(m, caddr_t), 21656483Ssklower nam->m_len = isop->isop_faddr->siso_len); 21756483Ssklower break; 21856483Ssklower 21956483Ssklower /* 22056483Ssklower * Mark the connection as being incapable of further output. 22156483Ssklower */ 22256483Ssklower case PRU_SHUTDOWN: 22356483Ssklower socantsendmore(so); 22456483Ssklower tp = tcp_usrclosed(tp); 22556483Ssklower if (tp) 22656483Ssklower error = tcp_output(tp); 22756483Ssklower else 22856483Ssklower tuba_pcbdetach(isop); 22956483Ssklower break; 23056483Ssklower /* 23156483Ssklower * Abort the TCP. 23256483Ssklower */ 23356483Ssklower case PRU_ABORT: 23456483Ssklower if ((tp = tcp_drop(tp, ECONNABORTED)) == 0) 23556483Ssklower tuba_pcbdetach(isop); 23656483Ssklower break; 23756483Ssklower 23856483Ssklower 23956483Ssklower case PRU_SOCKADDR: 24056483Ssklower if (isop->isop_laddr) 24156483Ssklower bcopy((caddr_t)isop->isop_laddr, mtod(m, caddr_t), 24256483Ssklower nam->m_len = isop->isop_laddr->siso_len); 24356483Ssklower break; 24456483Ssklower 24556483Ssklower case PRU_PEERADDR: 24656483Ssklower if (isop->isop_faddr) 24756483Ssklower bcopy((caddr_t)isop->isop_faddr, mtod(m, caddr_t), 24856483Ssklower nam->m_len = isop->isop_faddr->siso_len); 24956483Ssklower break; 25056483Ssklower 25156483Ssklower default: 25256483Ssklower error = tcp_usrreq(so, req, m, nam, control); 25356483Ssklower goto notrace; 25456483Ssklower } 25556483Ssklower if (tp && (so->so_options & SO_DEBUG)) 25656483Ssklower tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req); 25756483Ssklower notrace: 25856483Ssklower splx(s); 25956483Ssklower return(error); 26056483Ssklower } 26156483Ssklower 26256483Ssklower tuba_ctloutput(op, so, level, optname, mp) 26356483Ssklower int op; 26456483Ssklower struct socket *so; 26556483Ssklower int level, optname; 26656483Ssklower struct mbuf **mp; 26756483Ssklower { 26856483Ssklower int clnp_ctloutput(), tcp_ctloutput(); 26956483Ssklower 27056483Ssklower return ((level != IPPROTO_TCP ? clnp_ctloutput : tcp_ctloutput) 27156483Ssklower (clnp_ctloutput(op, so, level, optname, mp))); 27256483Ssklower } 273