1*6830Ssam 
2*6830Ssam #include "../h/param.h"
3*6830Ssam #include "../h/systm.h"
4*6830Ssam #include "../h/mbuf.h"
5*6830Ssam #include "../h/socket.h"
6*6830Ssam #include "../h/socketvar.h"
7*6830Ssam #include "../h/protosw.h"
8*6830Ssam #include "../net/decnet.h"
9*6830Ssam #include "../net/dn_systm.h"
10*6830Ssam #include "../net/if.h"
11*6830Ssam #include "../net/nsp.h"
12*6830Ssam #include "../net/nsp_var.h"
13*6830Ssam #include "../errno.h"
14*6830Ssam 
15*6830Ssam /*
16*6830Ssam  * NSP protocol interface to socket abstraction.
17*6830Ssam  */
18*6830Ssam struct	nspcb *nsp_newnspcb();
19*6830Ssam 
20*6830Ssam /*
21*6830Ssam  * Process an NSP user request for NSP np.  If this is a send request
22*6830Ssam  * then m is the mbuf chain of send data.  If this is a timer expiration
23*6830Ssam  * (called from the software clock routine), then timertype tells which timer.
24*6830Ssam  */
25*6830Ssam nsp_usrreq(so, req, m, addr)
26*6830Ssam 	struct socket *so;
27*6830Ssam 	int req;
28*6830Ssam 	struct mbuf *m;
29*6830Ssam 	caddr_t addr;
30*6830Ssam {
31*6830Ssam 	register struct nspcb *np = sotonspcb(so);
32*6830Ssam 	int s = splnet();
33*6830Ssam 	int error = 0;
34*6830Ssam 	int ostate;
35*6830Ssam COUNT(NSP_USRREQ);
36*6830Ssam 
37*6830Ssam 	/*
38*6830Ssam 	 * When an NSP is attached to a socket, then there will be
39*6830Ssam 	 * a (struct nspcb) pointed at by the socket.
40*6830Ssam 	 * The normal sequence of events is:
41*6830Ssam 	 *	PRU_ATTACH		creating these structures
42*6830Ssam 	 *	PRU_CONNECT		connecting to a remote peer
43*6830Ssam 	 *	(PRU_SEND|PRU_RCVD)*	exchanging data
44*6830Ssam 	 *	PRU_DISCONNECT		disconnecting from remote peer
45*6830Ssam 	 *	PRU_DETACH		deleting the structures
46*6830Ssam 	 * With the operations from PRU_CONNECT through PRU_DISCONNECT
47*6830Ssam 	 * possible repeated several times.
48*6830Ssam 	 *
49*6830Ssam 	 * MULTIPLE CONNECTS ARE NOT YET IMPLEMENTED.
50*6830Ssam 	 */
51*6830Ssam 	if (np == 0 && req != PRU_ATTACH) {
52*6830Ssam 		splx(s);
53*6830Ssam 		return (EINVAL);		/* XXX */
54*6830Ssam 	}
55*6830Ssam 	if (np) {
56*6830Ssam 		ostate = np->n_state;
57*6830Ssam 	}
58*6830Ssam 	switch (req) {
59*6830Ssam 
60*6830Ssam 	/*
61*6830Ssam 	 * NSP attaches to socket via PRU_ATTACH, reserving space
62*6830Ssam 	 * and NSP control block.
63*6830Ssam 	 **** If the socket is to receive connections,
64*6830Ssam 	 **** then the LISTEN state is entered.
65*6830Ssam 	 */
66*6830Ssam 	case PRU_ATTACH:
67*6830Ssam 		if (np) {
68*6830Ssam 			error = EISCONN;
69*6830Ssam 			break;
70*6830Ssam 		}
71*6830Ssam 		error = nsp_attach(so, (struct sockaddr *)addr);
72*6830Ssam 		if (error)
73*6830Ssam 			break;
74*6830Ssam 		np = sotonspcb(so);
75*6830Ssam 		break;
76*6830Ssam 
77*6830Ssam 	/*
78*6830Ssam 	 * PRU_DETACH detaches the NSP protocol from the socket.
79*6830Ssam 	 * If the protocol state is non-embryonic, then can't
80*6830Ssam 	 * do this directly: have to initiate a PRU_DISCONNECT,
81*6830Ssam 	 * which may finish later; embryonic nspcb's can just
82*6830Ssam 	 * be discarded here.
83*6830Ssam 	 */
84*6830Ssam 	case PRU_DETACH:
85*6830Ssam 		if (np->n_state != NS_O && np->n_state != NS_CL
86*6830Ssam 		    && np->n_state != NS_LI)
87*6830Ssam 			nsp_disconnect(np, <reason>);
88*6830Ssam 		else {
89*6830Ssam 			nsp_close(np);
90*6830Ssam 			np = 0;
91*6830Ssam 		}
92*6830Ssam 		break;
93*6830Ssam 
94*6830Ssam 	/*
95*6830Ssam 	 * Initiate connection to peer.
96*6830Ssam 	 * Enter CI state, and mark socket as connecting.
97*6830Ssam 	 **** Start keep-alive timer, and seed output sequence space.
98*6830Ssam 	 **** Send initial segment on connection.
99*6830Ssam 	 */
100*6830Ssam 	case PRU_CONNECT:
101*6830Ssam 		error = dn_pcbconnect(np, (struct sockaddr_dn *)addr);
102*6830Ssam 		if (error)
103*6830Ssam 			break;
104*6830Ssam 		soisconnecting(so);
105*6830Ssam 		nsp_connect(np);
106*6830Ssam 		break;
107*6830Ssam 
108*6830Ssam 	/*
109*6830Ssam 	 * Initiate disconnect from peer.
110*6830Ssam 	 * If connection never passed embryonic stage, just drop;
111*6830Ssam 	 * else if don't need to let data drain, then can just drop anyways,
112*6830Ssam 	 * else have to begin NSP shutdown process: mark socket disconnecting,
113*6830Ssam 	 * drain unread data, state switch to reflect user close, and
114*6830Ssam 	 * send segment (e.g. DI) to peer.  Socket will be really disconnected
115*6830Ssam 	 * when peer sends DC to ack our DI.
116*6830Ssam 	 *
117*6830Ssam 	 * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC NSPCB.
118*6830Ssam 	 */
119*6830Ssam 	case PRU_DISCONNECT:
120*6830Ssam 		nsp_disconnect(np);
121*6830Ssam 		break;
122*6830Ssam 
123*6830Ssam 	/*
124*6830Ssam 	 * Accept a connection.  Essentially all the work is
125*6830Ssam 	 * done at higher levels; just return the address
126*6830Ssam 	 * of the peer, storing through addr.
127*6830Ssam 	 */
128*6830Ssam 	case PRU_ACCEPT:
129*6830Ssam 		dn_pcbconnaddr(np, (struct sockaddr *)addr);
130*6830Ssam 		break;
131*6830Ssam 
132*6830Ssam /*** BEGIN NOT MODIFIED FOR NSP ***/
133*6830Ssam 	/*
134*6830Ssam 	 * Mark the connection as being incapable of further output.
135*6830Ssam 	 */
136*6830Ssam 	case PRU_SHUTDOWN:
137*6830Ssam 		socantsendmore(so);
138*6830Ssam 		nsp_usrclosed(np);
139*6830Ssam 		(void) nsp_output(np);
140*6830Ssam 		break;
141*6830Ssam 
142*6830Ssam 	/*
143*6830Ssam 	 * After a receive, possibly send window update to peer.
144*6830Ssam 	 */
145*6830Ssam 	case PRU_RCVD:
146*6830Ssam 		(void) nsp_output(np);
147*6830Ssam 		break;
148*6830Ssam /*** END NOT MODIFIED FOR NSP ***/
149*6830Ssam 
150*6830Ssam 	/*
151*6830Ssam 	 * Do a send by putting data in output queue and
152*6830Ssam 	 * calling output processor.
153*6830Ssam 	 */
154*6830Ssam 	case PRU_SEND:
155*6830Ssam 		sbpappend(&so->so_snd, m);
156*6830Ssam 		(void) nsp_output(np);
157*6830Ssam 		break;
158*6830Ssam 
159*6830Ssam /*** BEGIN NOT MODIFIED FOR NSP ***/
160*6830Ssam 	/*
161*6830Ssam 	 * Abort the NSP.
162*6830Ssam 	 */
163*6830Ssam 	case PRU_ABORT:
164*6830Ssam 		nsp_drop(np, ECONNABORTED);
165*6830Ssam 		break;
166*6830Ssam 
167*6830Ssam /* SOME AS YET UNIMPLEMENTED HOOKS */
168*6830Ssam 	case PRU_CONTROL:
169*6830Ssam 		error = EOPNOTSUPP;
170*6830Ssam 		break;
171*6830Ssam 
172*6830Ssam 	case PRU_SENSE:
173*6830Ssam 		error = EOPNOTSUPP;
174*6830Ssam 		break;
175*6830Ssam /* END UNIMPLEMENTED HOOKS */
176*6830Ssam 
177*6830Ssam 	case PRU_RCVOOB:
178*6830Ssam 		if (so->so_oobmark == 0 &&
179*6830Ssam 		    (so->so_state & SS_RCVATMARK) == 0) {
180*6830Ssam 			error = EINVAL;
181*6830Ssam 			break;
182*6830Ssam 		}
183*6830Ssam 		if ((np->n_flags & NSP_RCVINTR) == 0) {
184*6830Ssam 			error = EWOULDBLOCK;
185*6830Ssam 			break;
186*6830Ssam 		}
187*6830Ssam 		/* RETURN THE DATA */
188*6830Ssam 		break;
189*6830Ssam 
190*6830Ssam 	case PRU_SENDOOB:
191*6830Ssam 		/*
192*6830Ssam 		if interrupt data present return error (can't queue)
193*6830Ssam 		if len > 16 return error
194*6830Ssam 		put in xmt mbuf
195*6830Ssam 		mark interrupt data available
196*6830Ssam 		call nsp_output
197*6830Ssam 		*/
198*6830Ssam 		break;
199*6830Ssam 
200*6830Ssam 	/*
201*6830Ssam 	 * NSP slow timer went off; going through this
202*6830Ssam 	 * routine for tracing's sake.
203*6830Ssam 	 */
204*6830Ssam 	case PRU_SLOWTIMO:
205*6830Ssam 		nsp_timers(np, (int)addr);
206*6830Ssam 		req |= (int)addr << 8;		/* for debug's sake */
207*6830Ssam 		break;
208*6830Ssam /*** END NOT MODIFIED FOR NSP ***/
209*6830Ssam 
210*6830Ssam 	default:
211*6830Ssam 		panic("nsp_usrreq");
212*6830Ssam 	}
213*6830Ssam 	if (np && (so->so_options & SO_DEBUG))
214*6830Ssam 		nsp_trace(NA_USER, ostate, np, (struct XXXXXXXX *)0, req);
215*6830Ssam 	splx(s);
216*6830Ssam 	return (error);
217*6830Ssam }
218*6830Ssam 
219*6830Ssam /*
220*6830Ssam  * Attach NSP protocol to socket, allocating NSP control block,
221*6830Ssam  * bufer space, and entering LISTEN state if to accept connections.
222*6830Ssam  */
223*6830Ssam nsp_attach(so, sa)
224*6830Ssam 	struct socket *so;
225*6830Ssam 	struct sockaddr *sa;
226*6830Ssam {
227*6830Ssam 	register struct nspcb *np;
228*6830Ssam 	struct sockaddr_dn *sdn = (struct sockaddr_dn *)sa;
229*6830Ssam 	struct mbuf *m;
230*6830Ssam 	int error;
231*6830Ssam 
232*6830Ssam 	if (sdn) {
233*6830Ssam 		if (sdn->sdn_family != AF_DECNET)
234*6830Ssam 			return (EAFNOSUPPORT);
235*6830Ssam 		/* the user has specified a sockaddr with a socreate.
236*6830Ssam 		all this can do is allow the user to specify an object
237*6830Ssam 		type or other info if he is going to wait for a connection.
238*6830Ssam 		figure this out later. */
239*6830Ssam 	} else {
240*6830Ssam 		/* nothing specified, will expect a connect request soon */
241*6830Ssam 	}
242*6830Ssam 	m = m_getclr(0);
243*6830Ssam 	if (m == 0)
244*6830Ssam 		return (ENOBUFS);
245*6830Ssam 	if (sbreserve(&so->so_snd, 1024) == 0) {
246*6830Ssam bad:
247*6830Ssam 		m_free(m);
248*6830Ssam 		return (ENOBUFS);
249*6830Ssam 	}
250*6830Ssam 	if (sbreserve(&so->so_rcv, 1024) == 0) {
251*6830Ssam 		sbrelease(&so->so_snd);
252*6830Ssam 		goto bad;
253*6830Ssam 	}
254*6830Ssam 	np = mtod(m, struct nspcb *);
255*6830Ssam 	np->n_head = &ncb;
256*6830Ssam 	insque(np, &ncb);
257*6830Ssam 	sp->so_pcb = (caddr_t)np;
258*6830Ssam 	sdn = (struct sockaddr_dn *)&so->so_addr;
259*6830Ssam 	sdn->sdn_family == AF_DECNET;
260*6830Ssam 	sdn->sdn_addr = WHAT ELSE NEEDS TO BE FILLED IN HERE?
261*6830Ssam 	if (so->so_options & SO_ACCEPTCONN) {
262*6830Ssam 		np->n_state = NS_LI;
263*6830Ssam 	} else
264*6830Ssam 		np->n_state = NS_O;
265*6830Ssam 	return (0);
266*6830Ssam }
267*6830Ssam 
268*6830Ssam /*** BEGIN NOT MODIFIED FOR NSP ***/
269*6830Ssam /*
270*6830Ssam  * Initiate (or continue) disconnect.
271*6830Ssam  * If embryonic state, just send reset (once).
272*6830Ssam  * If not in ``let data drain'' option, just drop.
273*6830Ssam  * Otherwise (hard), mark socket disconnecting and drop
274*6830Ssam  * current input data; switch states based on user close, and
275*6830Ssam  * send segment to peer (with FIN).
276*6830Ssam  */
277*6830Ssam nsp_disconnect(np)
278*6830Ssam 	struct nspcb *np;
279*6830Ssam {
280*6830Ssam 	struct socket *so = np->n_socket;
281*6830Ssam 
282*6830Ssam 	if (np->n_state < NSPS_ESTABLISHED)
283*6830Ssam 		nsp_close(np);
284*6830Ssam 	else if (so->so_linger == 0)
285*6830Ssam 		nsp_drop(np, 0);
286*6830Ssam 	else {
287*6830Ssam 		soisdisconnecting(so);
288*6830Ssam 		sbflush(&so->so_rcv);
289*6830Ssam 		nsp_usrclosed(np);
290*6830Ssam 		(void) nsp_output(np);
291*6830Ssam 	}
292*6830Ssam }
293*6830Ssam 
294*6830Ssam /*
295*6830Ssam  * User issued close, and wish to trail through shutdown states:
296*6830Ssam  * if never received SYN, just forget it.  If got a SYN from peer,
297*6830Ssam  * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
298*6830Ssam  * If already got a FIN from peer, then almost done; go to LAST_ACK
299*6830Ssam  * state.  In all other cases, have already sent FIN to peer (e.g.
300*6830Ssam  * after PRU_SHUTDOWN), and just have to play tedious game waiting
301*6830Ssam  * for peer to send FIN or not respond to keep-alives, etc.
302*6830Ssam  */
303*6830Ssam nsp_usrclosed(np)
304*6830Ssam 	struct nspcb *np;
305*6830Ssam {
306*6830Ssam 
307*6830Ssam 	switch (np->n_state) {
308*6830Ssam 
309*6830Ssam 	case NSPS_LISTEN:
310*6830Ssam 	case NSPS_SYN_SENT:
311*6830Ssam 		np->n_state = NSPS_CLOSED;
312*6830Ssam 		nsp_close(np);
313*6830Ssam 		break;
314*6830Ssam 
315*6830Ssam 	case NSPS_SYN_RECEIVED:
316*6830Ssam 	case NSPS_ESTABLISHED:
317*6830Ssam 		np->n_state = NSPS_FIN_WAIT_1;
318*6830Ssam 		break;
319*6830Ssam 
320*6830Ssam 	case NSPS_CLOSE_WAIT:
321*6830Ssam 		np->n_state = NSPS_LAST_ACK;
322*6830Ssam 		break;
323*6830Ssam 	}
324*6830Ssam }
325