156483Ssklower /* 256484Ssklower * Copyright (c) 1992 Regents of the University of California. 356483Ssklower * All rights reserved. 456483Ssklower * 556483Ssklower * %sccs.include.redist.c% 656483Ssklower * 7*58813Ssklower * @(#)tuba_usrreq.c 7.9 (Berkeley) 03/25/93 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> 4156681Ssklower #include <netiso/tuba_table.h> 4256483Ssklower /* 4356483Ssklower * TCP protocol interface to socket abstraction. 4456483Ssklower */ 4556483Ssklower extern char *tcpstates[]; 4656690Ssklower extern struct inpcb tuba_inpcb; 4756690Ssklower extern 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; 10456681Ssklower isop = (struct isopcb *)so->so_pcb; 10556681Ssklower so->so_pcb = 0; 10656681Ssklower if (error = tcp_usrreq(so, req, m, nam, control)) { 10756483Ssklower isop->isop_socket = 0; 10856681Ssklower iso_pcbdetach(isop); 10956681Ssklower } else { 11056681Ssklower inp = sotoinpcb(so); 11156690Ssklower remque(inp); 11256690Ssklower insque(inp, &tuba_inpcb); 11356690Ssklower inp->inp_head = &tuba_inpcb; 11456681Ssklower tp = intotcpcb(inp); 11556681Ssklower if (tp == 0) 11656681Ssklower panic("tuba_usrreq 3"); 11756681Ssklower tp->t_tuba_pcb = (caddr_t) isop; 11856483Ssklower } 11956483Ssklower goto notrace; 12056483Ssklower 12156483Ssklower /* 12256483Ssklower * PRU_DETACH detaches the TCP protocol from the socket. 12356483Ssklower * If the protocol state is non-embryonic, then can't 12456483Ssklower * do this directly: have to initiate a PRU_DISCONNECT, 12556483Ssklower * which may finish later; embryonic TCB's can just 12656483Ssklower * be discarded here. 12756483Ssklower */ 12856483Ssklower case PRU_DETACH: 12956483Ssklower if (tp->t_state > TCPS_LISTEN) 13056483Ssklower tp = tcp_disconnect(tp); 13156483Ssklower else 13256483Ssklower tp = tcp_close(tp); 13356483Ssklower if (tp == 0) 13456483Ssklower tuba_pcbdetach(isop); 13556483Ssklower break; 13656483Ssklower 13756483Ssklower /* 13856483Ssklower * Give the socket an address. 13956483Ssklower */ 14056483Ssklower case PRU_BIND: 14156483Ssklower siso = mtod(nam, struct sockaddr_iso *); 14256483Ssklower if (siso->siso_tlen && siso->siso_tlen != 2) { 14356483Ssklower error = EINVAL; 14456483Ssklower break; 14556483Ssklower } 14656483Ssklower if ((error = iso_pcbbind(isop, nam)) || 14756483Ssklower (siso = isop->isop_laddr) == 0) 14856483Ssklower break; 14956483Ssklower bcopy(TSEL(siso), &inp->inp_lport, 2); 15056483Ssklower if (siso->siso_nlen && 15156912Ssklower !(inp->inp_laddr.s_addr = tuba_lookup(siso, M_WAITOK))) 15256483Ssklower error = ENOBUFS; 15356483Ssklower break; 15456483Ssklower 15556483Ssklower /* 15656483Ssklower * Prepare to accept connections. 15756483Ssklower */ 15856483Ssklower case PRU_CONNECT: 15956483Ssklower case PRU_LISTEN: 16056483Ssklower if (inp->inp_lport == 0 && 16156483Ssklower (error = iso_pcbbind(isop, (struct mbuf *)0))) 16256483Ssklower break; 16356483Ssklower bcopy(TSEL(isop->isop_laddr), &inp->inp_lport, 2); 16456565Ssklower if (req == PRU_LISTEN) { 16556483Ssklower tp->t_state = TCPS_LISTEN; 16656483Ssklower break; 16756483Ssklower } 16856483Ssklower /*FALLTHROUGH*/ 16956483Ssklower /* 17056483Ssklower * Initiate connection to peer. 17156483Ssklower * Create a template for use in transmissions on this connection. 17256483Ssklower * Enter SYN_SENT state, and mark socket as connecting. 17356483Ssklower * Start keep-alive timer, and seed output sequence space. 17456483Ssklower * Send initial segment on connection. 17556483Ssklower */ 17656483Ssklower /* case PRU_CONNECT: */ 17756483Ssklower if (error = iso_pcbconnect(isop, nam)) 17856483Ssklower break; 17956903Ssklower if ((siso = isop->isop_laddr) && siso->siso_nlen > 1) 18056903Ssklower siso->siso_data[siso->siso_nlen - 1] = ISOPROTO_TCP; 18156903Ssklower else 18256903Ssklower panic("tuba_usrreq: connect"); 18356483Ssklower siso = mtod(nam, struct sockaddr_iso *); 18456912Ssklower if (!(inp->inp_faddr.s_addr = tuba_lookup(siso, M_WAITOK))) { 18556483Ssklower unconnect: 18656483Ssklower iso_pcbdisconnect(isop); 18756483Ssklower error = ENOBUFS; 18856483Ssklower break; 18956483Ssklower } 19056483Ssklower bcopy(TSEL(isop->isop_faddr), &inp->inp_fport, 2); 19156565Ssklower if (inp->inp_laddr.s_addr == 0 && 19256483Ssklower (inp->inp_laddr.s_addr = 19356912Ssklower tuba_lookup(isop->isop_laddr, M_WAITOK)) == 0) 19456483Ssklower goto unconnect; 19556483Ssklower if ((tp->t_template = tcp_template(tp)) == 0) 19656483Ssklower goto unconnect; 19756483Ssklower soisconnecting(so); 19856483Ssklower tcpstat.tcps_connattempt++; 19956483Ssklower tp->t_state = TCPS_SYN_SENT; 20056483Ssklower tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; 20156483Ssklower tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; 20256483Ssklower tcp_sendseqinit(tp); 20356483Ssklower error = tcp_output(tp); 20456483Ssklower tuba_refcnt(isop, 1); 20556483Ssklower break; 20656483Ssklower 20756483Ssklower /* 20856483Ssklower * Initiate disconnect from peer. 20956483Ssklower * If connection never passed embryonic stage, just drop; 21056483Ssklower * else if don't need to let data drain, then can just drop anyways, 21156483Ssklower * else have to begin TCP shutdown process: mark socket disconnecting, 21256483Ssklower * drain unread data, state switch to reflect user close, and 21356483Ssklower * send segment (e.g. FIN) to peer. Socket will be really disconnected 21456483Ssklower * when peer sends FIN and acks ours. 21556483Ssklower * 21656483Ssklower * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB. 21756483Ssklower */ 21856483Ssklower case PRU_DISCONNECT: 21956483Ssklower if ((tp = tcp_disconnect(tp)) == 0) 22056483Ssklower tuba_pcbdetach(isop); 22156483Ssklower break; 22256483Ssklower 22356483Ssklower /* 22456483Ssklower * Accept a connection. Essentially all the work is 22556483Ssklower * done at higher levels; just return the address 22656483Ssklower * of the peer, storing through addr. 22756483Ssklower */ 22856483Ssklower case PRU_ACCEPT: 22956704Ssklower bcopy((caddr_t)isop->isop_faddr, mtod(nam, caddr_t), 23056483Ssklower nam->m_len = isop->isop_faddr->siso_len); 23156483Ssklower break; 23256483Ssklower 23356483Ssklower /* 23456483Ssklower * Mark the connection as being incapable of further output. 23556483Ssklower */ 23656483Ssklower case PRU_SHUTDOWN: 23756483Ssklower socantsendmore(so); 23856483Ssklower tp = tcp_usrclosed(tp); 23956483Ssklower if (tp) 24056483Ssklower error = tcp_output(tp); 24156483Ssklower else 24256483Ssklower tuba_pcbdetach(isop); 24356483Ssklower break; 24456483Ssklower /* 24556483Ssklower * Abort the TCP. 24656483Ssklower */ 24756483Ssklower case PRU_ABORT: 24856483Ssklower if ((tp = tcp_drop(tp, ECONNABORTED)) == 0) 24956483Ssklower tuba_pcbdetach(isop); 25056483Ssklower break; 25156483Ssklower 25256483Ssklower 25356483Ssklower case PRU_SOCKADDR: 25456483Ssklower if (isop->isop_laddr) 255*58813Ssklower bcopy((caddr_t)isop->isop_laddr, mtod(nam, caddr_t), 25656483Ssklower nam->m_len = isop->isop_laddr->siso_len); 25756483Ssklower break; 25856483Ssklower 25956483Ssklower case PRU_PEERADDR: 26056483Ssklower if (isop->isop_faddr) 261*58813Ssklower bcopy((caddr_t)isop->isop_faddr, mtod(nam, caddr_t), 26256483Ssklower nam->m_len = isop->isop_faddr->siso_len); 26356483Ssklower break; 26456483Ssklower 26556483Ssklower default: 26656483Ssklower error = tcp_usrreq(so, req, m, nam, control); 26756483Ssklower goto notrace; 26856483Ssklower } 26956483Ssklower if (tp && (so->so_options & SO_DEBUG)) 27056483Ssklower tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req); 27156483Ssklower notrace: 27256483Ssklower splx(s); 27356483Ssklower return(error); 27456483Ssklower } 27556483Ssklower 27656483Ssklower tuba_ctloutput(op, so, level, optname, mp) 27756483Ssklower int op; 27856483Ssklower struct socket *so; 27956483Ssklower int level, optname; 28056483Ssklower struct mbuf **mp; 28156483Ssklower { 28256483Ssklower int clnp_ctloutput(), tcp_ctloutput(); 28356483Ssklower 28456483Ssklower return ((level != IPPROTO_TCP ? clnp_ctloutput : tcp_ctloutput) 28556912Ssklower (op, so, level, optname, mp)); 28656483Ssklower } 287