1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)tuba_usrreq.c 8.1 (Berkeley) 06/10/93 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 tuba_inpcb; 47 extern 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 remque(inp); 112 insque(inp, &tuba_inpcb); 113 inp->inp_head = &tuba_inpcb; 114 tp = intotcpcb(inp); 115 if (tp == 0) 116 panic("tuba_usrreq 3"); 117 tp->t_tuba_pcb = (caddr_t) isop; 118 } 119 goto notrace; 120 121 /* 122 * PRU_DETACH detaches the TCP protocol from the socket. 123 * If the protocol state is non-embryonic, then can't 124 * do this directly: have to initiate a PRU_DISCONNECT, 125 * which may finish later; embryonic TCB's can just 126 * be discarded here. 127 */ 128 case PRU_DETACH: 129 if (tp->t_state > TCPS_LISTEN) 130 tp = tcp_disconnect(tp); 131 else 132 tp = tcp_close(tp); 133 if (tp == 0) 134 tuba_pcbdetach(isop); 135 break; 136 137 /* 138 * Give the socket an address. 139 */ 140 case PRU_BIND: 141 siso = mtod(nam, struct sockaddr_iso *); 142 if (siso->siso_tlen && siso->siso_tlen != 2) { 143 error = EINVAL; 144 break; 145 } 146 if ((error = iso_pcbbind(isop, nam)) || 147 (siso = isop->isop_laddr) == 0) 148 break; 149 bcopy(TSEL(siso), &inp->inp_lport, 2); 150 if (siso->siso_nlen && 151 !(inp->inp_laddr.s_addr = tuba_lookup(siso, M_WAITOK))) 152 error = ENOBUFS; 153 break; 154 155 /* 156 * Prepare to accept connections. 157 */ 158 case PRU_CONNECT: 159 case PRU_LISTEN: 160 if (inp->inp_lport == 0 && 161 (error = iso_pcbbind(isop, (struct mbuf *)0))) 162 break; 163 bcopy(TSEL(isop->isop_laddr), &inp->inp_lport, 2); 164 if (req == PRU_LISTEN) { 165 tp->t_state = TCPS_LISTEN; 166 break; 167 } 168 /*FALLTHROUGH*/ 169 /* 170 * Initiate connection to peer. 171 * Create a template for use in transmissions on this connection. 172 * Enter SYN_SENT state, and mark socket as connecting. 173 * Start keep-alive timer, and seed output sequence space. 174 * Send initial segment on connection. 175 */ 176 /* case PRU_CONNECT: */ 177 if (error = iso_pcbconnect(isop, nam)) 178 break; 179 if ((siso = isop->isop_laddr) && siso->siso_nlen > 1) 180 siso->siso_data[siso->siso_nlen - 1] = ISOPROTO_TCP; 181 else 182 panic("tuba_usrreq: connect"); 183 siso = mtod(nam, struct sockaddr_iso *); 184 if (!(inp->inp_faddr.s_addr = tuba_lookup(siso, M_WAITOK))) { 185 unconnect: 186 iso_pcbdisconnect(isop); 187 error = ENOBUFS; 188 break; 189 } 190 bcopy(TSEL(isop->isop_faddr), &inp->inp_fport, 2); 191 if (inp->inp_laddr.s_addr == 0 && 192 (inp->inp_laddr.s_addr = 193 tuba_lookup(isop->isop_laddr, M_WAITOK)) == 0) 194 goto unconnect; 195 if ((tp->t_template = tcp_template(tp)) == 0) 196 goto unconnect; 197 soisconnecting(so); 198 tcpstat.tcps_connattempt++; 199 tp->t_state = TCPS_SYN_SENT; 200 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; 201 tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; 202 tcp_sendseqinit(tp); 203 error = tcp_output(tp); 204 tuba_refcnt(isop, 1); 205 break; 206 207 /* 208 * Initiate disconnect from peer. 209 * If connection never passed embryonic stage, just drop; 210 * else if don't need to let data drain, then can just drop anyways, 211 * else have to begin TCP shutdown process: mark socket disconnecting, 212 * drain unread data, state switch to reflect user close, and 213 * send segment (e.g. FIN) to peer. Socket will be really disconnected 214 * when peer sends FIN and acks ours. 215 * 216 * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB. 217 */ 218 case PRU_DISCONNECT: 219 if ((tp = tcp_disconnect(tp)) == 0) 220 tuba_pcbdetach(isop); 221 break; 222 223 /* 224 * Accept a connection. Essentially all the work is 225 * done at higher levels; just return the address 226 * of the peer, storing through addr. 227 */ 228 case PRU_ACCEPT: 229 bcopy((caddr_t)isop->isop_faddr, mtod(nam, caddr_t), 230 nam->m_len = isop->isop_faddr->siso_len); 231 break; 232 233 /* 234 * Mark the connection as being incapable of further output. 235 */ 236 case PRU_SHUTDOWN: 237 socantsendmore(so); 238 tp = tcp_usrclosed(tp); 239 if (tp) 240 error = tcp_output(tp); 241 else 242 tuba_pcbdetach(isop); 243 break; 244 /* 245 * Abort the TCP. 246 */ 247 case PRU_ABORT: 248 if ((tp = tcp_drop(tp, ECONNABORTED)) == 0) 249 tuba_pcbdetach(isop); 250 break; 251 252 253 case PRU_SOCKADDR: 254 if (isop->isop_laddr) 255 bcopy((caddr_t)isop->isop_laddr, mtod(nam, caddr_t), 256 nam->m_len = isop->isop_laddr->siso_len); 257 break; 258 259 case PRU_PEERADDR: 260 if (isop->isop_faddr) 261 bcopy((caddr_t)isop->isop_faddr, mtod(nam, caddr_t), 262 nam->m_len = isop->isop_faddr->siso_len); 263 break; 264 265 default: 266 error = tcp_usrreq(so, req, m, nam, control); 267 goto notrace; 268 } 269 if (tp && (so->so_options & SO_DEBUG)) 270 tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req); 271 notrace: 272 splx(s); 273 return(error); 274 } 275 276 tuba_ctloutput(op, so, level, optname, mp) 277 int op; 278 struct socket *so; 279 int level, optname; 280 struct mbuf **mp; 281 { 282 int clnp_ctloutput(), tcp_ctloutput(); 283 284 return ((level != IPPROTO_TCP ? clnp_ctloutput : tcp_ctloutput) 285 (op, so, level, optname, mp)); 286 } 287