1*56483Ssklower /* 2*56483Ssklower * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 3*56483Ssklower * All rights reserved. 4*56483Ssklower * 5*56483Ssklower * %sccs.include.redist.c% 6*56483Ssklower * 7*56483Ssklower * @(#)tuba_usrreq.c 7.1 (Berkeley) 10/09/92 8*56483Ssklower */ 9*56483Ssklower 10*56483Ssklower #include "param.h" 11*56483Ssklower #include "systm.h" 12*56483Ssklower #include "malloc.h" 13*56483Ssklower #include "mbuf.h" 14*56483Ssklower #include "socket.h" 15*56483Ssklower #include "socketvar.h" 16*56483Ssklower #include "protosw.h" 17*56483Ssklower #include "errno.h" 18*56483Ssklower #include "stat.h" 19*56483Ssklower 20*56483Ssklower #include "net/if.h" 21*56483Ssklower #include "net/route.h" 22*56483Ssklower 23*56483Ssklower #include "in.h" 24*56483Ssklower #include "in_systm.h" 25*56483Ssklower #include "ip.h" 26*56483Ssklower #include "in_pcb.h" 27*56483Ssklower #include "ip_var.h" 28*56483Ssklower #include "tcp.h" 29*56483Ssklower #include "tcp_fsm.h" 30*56483Ssklower #include "tcp_seq.h" 31*56483Ssklower #include "tcp_timer.h" 32*56483Ssklower #include "tcp_var.h" 33*56483Ssklower #include "tcpip.h" 34*56483Ssklower #include "tcp_debug.h" 35*56483Ssklower 36*56483Ssklower #include "netiso/argo_debug.h" 37*56483Ssklower #include "netiso/iso.h" 38*56483Ssklower #include "netiso/clnp.h" 39*56483Ssklower #include "netiso/iso_pcb.h" 40*56483Ssklower #include "netiso/iso_var.h" 41*56483Ssklower /* 42*56483Ssklower * TCP protocol interface to socket abstraction. 43*56483Ssklower */ 44*56483Ssklower extern char *tcpstates[]; 45*56483Ssklower extern struct inpcb tcb; 46*56483Ssklower struct isopcb tuba_isopcb; 47*56483Ssklower 48*56483Ssklower /* 49*56483Ssklower * Process a TCP user request for TCP tb. If this is a send request 50*56483Ssklower * then m is the mbuf chain of send data. If this is a timer expiration 51*56483Ssklower * (called from the software clock routine), then timertype tells which timer. 52*56483Ssklower */ 53*56483Ssklower /*ARGSUSED*/ 54*56483Ssklower tuba_usrreq(so, req, m, nam, control) 55*56483Ssklower struct socket *so; 56*56483Ssklower int req; 57*56483Ssklower struct mbuf *m, *nam, *control; 58*56483Ssklower { 59*56483Ssklower register struct inpcb *inp; 60*56483Ssklower register struct isopcb *isop; 61*56483Ssklower register struct tcpcb *tp; 62*56483Ssklower int s; 63*56483Ssklower int error = 0; 64*56483Ssklower int ostate; 65*56483Ssklower struct sockaddr_iso siso; 66*56483Ssklower 67*56483Ssklower if (req == PRU_CONTROL) 68*56483Ssklower return (iso_control(so, (int)m, (caddr_t)nam, 69*56483Ssklower (struct ifnet *)control)); 70*56483Ssklower 71*56483Ssklower s = splnet(); 72*56483Ssklower inp = sotoinpcb(so); 73*56483Ssklower /* 74*56483Ssklower * When a TCP is attached to a socket, then there will be 75*56483Ssklower * a (struct inpcb) pointed at by the socket, and this 76*56483Ssklower * structure will point at a subsidary (struct tcpcb). 77*56483Ssklower */ 78*56483Ssklower if (inp == 0 && req != PRU_ATTACH) { 79*56483Ssklower splx(s); 80*56483Ssklower return (EINVAL); /* XXX */ 81*56483Ssklower } 82*56483Ssklower if (inp) { 83*56483Ssklower tp = inpcbtotcpcb(inp); 84*56483Ssklower if (tp == 0) 85*56483Ssklower panic("tuba_usrreq"); 86*56483Ssklower ostate = tp->t_state; 87*56483Ssklower isop = tp->tp_tuba_pcb; 88*56483Ssklower if (isop == 0) 89*56483Ssklower panic("tuba_usrreq 2"); 90*56483Ssklower } else 91*56483Ssklower ostate = 0; 92*56483Ssklower switch (req) { 93*56483Ssklower 94*56483Ssklower /* 95*56483Ssklower * TCP attaches to socket via PRU_ATTACH, reserving space, 96*56483Ssklower * and an internet control block. We also need to 97*56483Ssklower * allocate an isopcb and separate the control block from 98*56483Ssklower * tcp/ip ones. 99*56483Ssklower */ 100*56483Ssklower case PRU_ATTACH: 101*56483Ssklower if (error = iso_pcballoc(so, &tuba_isopcb)) 102*56483Ssklower break; 103*56483Ssklower isop = (struct isopcb *) tp->tp_tuba_pcb = so->so_pcb; 104*56483Ssklower if (error = tcp_userreq(so, req, m, nam, control)) { 105*56483Ssklower isop->isop_socket = 0; 106*56483Ssklower isop_detach(isop); 107*56483Ssklower } 108*56483Ssklower goto notrace; 109*56483Ssklower 110*56483Ssklower /* 111*56483Ssklower * PRU_DETACH detaches the TCP protocol from the socket. 112*56483Ssklower * If the protocol state is non-embryonic, then can't 113*56483Ssklower * do this directly: have to initiate a PRU_DISCONNECT, 114*56483Ssklower * which may finish later; embryonic TCB's can just 115*56483Ssklower * be discarded here. 116*56483Ssklower */ 117*56483Ssklower case PRU_DETACH: 118*56483Ssklower if (tp->t_state > TCPS_LISTEN) 119*56483Ssklower tp = tcp_disconnect(tp); 120*56483Ssklower else 121*56483Ssklower tp = tcp_close(tp); 122*56483Ssklower if (tp == 0) 123*56483Ssklower tuba_pcbdetach(isop); 124*56483Ssklower break; 125*56483Ssklower 126*56483Ssklower /* 127*56483Ssklower * Give the socket an address. 128*56483Ssklower */ 129*56483Ssklower case PRU_BIND: 130*56483Ssklower siso = mtod(nam, struct sockaddr_iso *); 131*56483Ssklower if (siso->siso_tlen && siso->siso_tlen != 2) { 132*56483Ssklower error = EINVAL; 133*56483Ssklower break; 134*56483Ssklower } 135*56483Ssklower if ((error = iso_pcbbind(isop, nam)) || 136*56483Ssklower (siso = isop->isop_laddr) == 0) 137*56483Ssklower break; 138*56483Ssklower bcopy(TSEL(siso), &inp->inp_lport, 2); 139*56483Ssklower if (siso->siso_nlen && 140*56483Ssklower !(inp->inp_laddr.s_addr = tuba_lookup(&siso->siso_addr))) 141*56483Ssklower error = ENOBUFS; 142*56483Ssklower break; 143*56483Ssklower 144*56483Ssklower /* 145*56483Ssklower * Prepare to accept connections. 146*56483Ssklower */ 147*56483Ssklower case PRU_CONNECT: 148*56483Ssklower case PRU_LISTEN: 149*56483Ssklower if (inp->inp_lport == 0 && 150*56483Ssklower (error = iso_pcbbind(isop, (struct mbuf *)0))) 151*56483Ssklower break; 152*56483Ssklower bcopy(TSEL(isop->isop_laddr), &inp->inp_lport, 2); 153*56483Ssklower if (cmd == PRU_LISTEN) { 154*56483Ssklower tp->t_state = TCPS_LISTEN; 155*56483Ssklower break; 156*56483Ssklower } 157*56483Ssklower /*FALLTHROUGH*/ 158*56483Ssklower /* 159*56483Ssklower * Initiate connection to peer. 160*56483Ssklower * Create a template for use in transmissions on this connection. 161*56483Ssklower * Enter SYN_SENT state, and mark socket as connecting. 162*56483Ssklower * Start keep-alive timer, and seed output sequence space. 163*56483Ssklower * Send initial segment on connection. 164*56483Ssklower */ 165*56483Ssklower /* case PRU_CONNECT: */ 166*56483Ssklower if (error = iso_pcbconnect(isop, nam)) 167*56483Ssklower break; 168*56483Ssklower siso = mtod(nam, struct sockaddr_iso *); 169*56483Ssklower if (!(inp->inp_faddr.s_addr = tuba_lookup(&siso->siso_addr))) { 170*56483Ssklower unconnect: 171*56483Ssklower iso_pcbdisconnect(isop); 172*56483Ssklower error = ENOBUFS; 173*56483Ssklower break; 174*56483Ssklower } 175*56483Ssklower bcopy(TSEL(isop->isop_faddr), &inp->inp_fport, 2); 176*56483Ssklower if ((inp->inp_laddr.s_addr == 0 && 177*56483Ssklower (inp->inp_laddr.s_addr = 178*56483Ssklower tuba_lookup(&isop->isop_laddr->siso_addr)) == 0) 179*56483Ssklower goto unconnect; 180*56483Ssklower if ((tp->t_template = tcp_template(tp)) == 0) 181*56483Ssklower goto unconnect; 182*56483Ssklower soisconnecting(so); 183*56483Ssklower tcpstat.tcps_connattempt++; 184*56483Ssklower tp->t_state = TCPS_SYN_SENT; 185*56483Ssklower tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; 186*56483Ssklower tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; 187*56483Ssklower tcp_sendseqinit(tp); 188*56483Ssklower error = tcp_output(tp); 189*56483Ssklower tuba_refcnt(isop, 1); 190*56483Ssklower break; 191*56483Ssklower 192*56483Ssklower /* 193*56483Ssklower * Initiate disconnect from peer. 194*56483Ssklower * If connection never passed embryonic stage, just drop; 195*56483Ssklower * else if don't need to let data drain, then can just drop anyways, 196*56483Ssklower * else have to begin TCP shutdown process: mark socket disconnecting, 197*56483Ssklower * drain unread data, state switch to reflect user close, and 198*56483Ssklower * send segment (e.g. FIN) to peer. Socket will be really disconnected 199*56483Ssklower * when peer sends FIN and acks ours. 200*56483Ssklower * 201*56483Ssklower * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB. 202*56483Ssklower */ 203*56483Ssklower case PRU_DISCONNECT: 204*56483Ssklower if ((tp = tcp_disconnect(tp)) == 0) 205*56483Ssklower tuba_pcbdetach(isop); 206*56483Ssklower break; 207*56483Ssklower 208*56483Ssklower /* 209*56483Ssklower * Accept a connection. Essentially all the work is 210*56483Ssklower * done at higher levels; just return the address 211*56483Ssklower * of the peer, storing through addr. 212*56483Ssklower */ 213*56483Ssklower case PRU_ACCEPT: 214*56483Ssklower bcopy((caddr_t)isop->isop_faddr, mtod(m, caddr_t), 215*56483Ssklower nam->m_len = isop->isop_faddr->siso_len); 216*56483Ssklower break; 217*56483Ssklower 218*56483Ssklower /* 219*56483Ssklower * Mark the connection as being incapable of further output. 220*56483Ssklower */ 221*56483Ssklower case PRU_SHUTDOWN: 222*56483Ssklower socantsendmore(so); 223*56483Ssklower tp = tcp_usrclosed(tp); 224*56483Ssklower if (tp) 225*56483Ssklower error = tcp_output(tp); 226*56483Ssklower else 227*56483Ssklower tuba_pcbdetach(isop); 228*56483Ssklower break; 229*56483Ssklower /* 230*56483Ssklower * Abort the TCP. 231*56483Ssklower */ 232*56483Ssklower case PRU_ABORT: 233*56483Ssklower if ((tp = tcp_drop(tp, ECONNABORTED)) == 0) 234*56483Ssklower tuba_pcbdetach(isop); 235*56483Ssklower break; 236*56483Ssklower 237*56483Ssklower 238*56483Ssklower case PRU_SOCKADDR: 239*56483Ssklower if (isop->isop_laddr) 240*56483Ssklower bcopy((caddr_t)isop->isop_laddr, mtod(m, caddr_t), 241*56483Ssklower nam->m_len = isop->isop_laddr->siso_len); 242*56483Ssklower break; 243*56483Ssklower 244*56483Ssklower case PRU_PEERADDR: 245*56483Ssklower if (isop->isop_faddr) 246*56483Ssklower bcopy((caddr_t)isop->isop_faddr, mtod(m, caddr_t), 247*56483Ssklower nam->m_len = isop->isop_faddr->siso_len); 248*56483Ssklower break; 249*56483Ssklower 250*56483Ssklower default: 251*56483Ssklower error = tcp_usrreq(so, req, m, nam, control); 252*56483Ssklower goto notrace; 253*56483Ssklower } 254*56483Ssklower if (tp && (so->so_options & SO_DEBUG)) 255*56483Ssklower tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req); 256*56483Ssklower notrace: 257*56483Ssklower splx(s); 258*56483Ssklower return(error); 259*56483Ssklower } 260*56483Ssklower 261*56483Ssklower tuba_ctloutput(op, so, level, optname, mp) 262*56483Ssklower int op; 263*56483Ssklower struct socket *so; 264*56483Ssklower int level, optname; 265*56483Ssklower struct mbuf **mp; 266*56483Ssklower { 267*56483Ssklower int clnp_ctloutput(), tcp_ctloutput(); 268*56483Ssklower 269*56483Ssklower return ((level != IPPROTO_TCP ? clnp_ctloutput : tcp_ctloutput) 270*56483Ssklower (clnp_ctloutput(op, so, level, optname, mp))); 271*56483Ssklower } 272