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