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