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