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