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