xref: /original-bsd/sys/netiso/tuba_usrreq.c (revision be1f24e8)
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