1*9833Ssam /*	nsp_usrreq.c	1.5	82/12/18	*/
26830Ssam 
36830Ssam #include "../h/param.h"
46830Ssam #include "../h/systm.h"
56830Ssam #include "../h/mbuf.h"
66830Ssam #include "../h/socket.h"
76830Ssam #include "../h/socketvar.h"
86830Ssam #include "../h/protosw.h"
98409Swnj #include "../netdecnet/decnet.h"
108409Swnj #include "../netdecnet/dn_systm.h"
116830Ssam #include "../net/if.h"
128409Swnj #include "../netdecnet/nsp.h"
138409Swnj #include "../netdecnet/nsp_var.h"
148409Swnj #include <errno.h>
156830Ssam 
166830Ssam /*
176830Ssam  * NSP protocol interface to socket abstraction.
186830Ssam  */
196830Ssam struct	nspcb *nsp_newnspcb();
206830Ssam 
216830Ssam /*
226830Ssam  * Process an NSP user request for NSP np.  If this is a send request
236830Ssam  * then m is the mbuf chain of send data.  If this is a timer expiration
246830Ssam  * (called from the software clock routine), then timertype tells which timer.
256830Ssam  */
266830Ssam nsp_usrreq(so, req, m, addr)
276830Ssam 	struct socket *so;
286830Ssam 	int req;
296830Ssam 	struct mbuf *m;
306830Ssam 	caddr_t addr;
316830Ssam {
326830Ssam 	register struct nspcb *np = sotonspcb(so);
336830Ssam 	int s = splnet();
346830Ssam 	int error = 0;
356830Ssam 	int ostate;
366830Ssam COUNT(NSP_USRREQ);
376830Ssam 
386830Ssam 	/*
396830Ssam 	 * When an NSP is attached to a socket, then there will be
406830Ssam 	 * a (struct nspcb) pointed at by the socket.
416830Ssam 	 * The normal sequence of events is:
426830Ssam 	 *	PRU_ATTACH		creating these structures
436830Ssam 	 *	PRU_CONNECT		connecting to a remote peer
446830Ssam 	 *	(PRU_SEND|PRU_RCVD)*	exchanging data
456830Ssam 	 *	PRU_DISCONNECT		disconnecting from remote peer
466830Ssam 	 *	PRU_DETACH		deleting the structures
476830Ssam 	 * With the operations from PRU_CONNECT through PRU_DISCONNECT
486830Ssam 	 * possible repeated several times.
496830Ssam 	 *
506830Ssam 	 * MULTIPLE CONNECTS ARE NOT YET IMPLEMENTED.
516830Ssam 	 */
526830Ssam 	if (np == 0 && req != PRU_ATTACH) {
536830Ssam 		splx(s);
546830Ssam 		return (EINVAL);		/* XXX */
556830Ssam 	}
566830Ssam 	if (np) {
576830Ssam 		ostate = np->n_state;
586830Ssam 	}
596830Ssam 	switch (req) {
606830Ssam 
616830Ssam 	/*
626830Ssam 	 * NSP attaches to socket via PRU_ATTACH, reserving space
636830Ssam 	 * and NSP control block.
646830Ssam 	 **** If the socket is to receive connections,
656830Ssam 	 **** then the LISTEN state is entered.
666830Ssam 	 */
676830Ssam 	case PRU_ATTACH:
686830Ssam 		if (np) {
696830Ssam 			error = EISCONN;
706830Ssam 			break;
716830Ssam 		}
726830Ssam 		error = nsp_attach(so, (struct sockaddr *)addr);
736830Ssam 		if (error)
746830Ssam 			break;
756830Ssam 		np = sotonspcb(so);
766830Ssam 		break;
776830Ssam 
786830Ssam 	/*
796830Ssam 	 * PRU_DETACH detaches the NSP protocol from the socket.
806830Ssam 	 * If the protocol state is non-embryonic, then can't
816830Ssam 	 * do this directly: have to initiate a PRU_DISCONNECT,
826830Ssam 	 * which may finish later; embryonic nspcb's can just
836830Ssam 	 * be discarded here.
846830Ssam 	 */
856830Ssam 	case PRU_DETACH:
866830Ssam 		if (np->n_state != NS_O && np->n_state != NS_CL
876830Ssam 		    && np->n_state != NS_LI)
886830Ssam 			nsp_disconnect(np, <reason>);
896830Ssam 		else {
906830Ssam 			nsp_close(np);
916830Ssam 			np = 0;
926830Ssam 		}
936830Ssam 		break;
946830Ssam 
956830Ssam 	/*
966830Ssam 	 * Initiate connection to peer.
976830Ssam 	 * Enter CI state, and mark socket as connecting.
986830Ssam 	 **** Start keep-alive timer, and seed output sequence space.
996830Ssam 	 **** Send initial segment on connection.
1006830Ssam 	 */
1016830Ssam 	case PRU_CONNECT:
1026830Ssam 		error = dn_pcbconnect(np, (struct sockaddr_dn *)addr);
1036830Ssam 		if (error)
1046830Ssam 			break;
1056830Ssam 		soisconnecting(so);
1066830Ssam 		nsp_connect(np);
1076830Ssam 		break;
1086830Ssam 
1096830Ssam 	/*
1106830Ssam 	 * Initiate disconnect from peer.
1116830Ssam 	 * If connection never passed embryonic stage, just drop;
1126830Ssam 	 * else if don't need to let data drain, then can just drop anyways,
1136830Ssam 	 * else have to begin NSP shutdown process: mark socket disconnecting,
1146830Ssam 	 * drain unread data, state switch to reflect user close, and
1156830Ssam 	 * send segment (e.g. DI) to peer.  Socket will be really disconnected
1166830Ssam 	 * when peer sends DC to ack our DI.
1176830Ssam 	 *
1186830Ssam 	 * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC NSPCB.
1196830Ssam 	 */
1206830Ssam 	case PRU_DISCONNECT:
1216830Ssam 		nsp_disconnect(np);
1226830Ssam 		break;
1236830Ssam 
1246830Ssam 	/*
1256830Ssam 	 * Accept a connection.  Essentially all the work is
1266830Ssam 	 * done at higher levels; just return the address
1276830Ssam 	 * of the peer, storing through addr.
1286830Ssam 	 */
1296830Ssam 	case PRU_ACCEPT:
1306830Ssam 		dn_pcbconnaddr(np, (struct sockaddr *)addr);
1316830Ssam 		break;
1326830Ssam 
1336830Ssam /*** BEGIN NOT MODIFIED FOR NSP ***/
1346830Ssam 	/*
1356830Ssam 	 * Mark the connection as being incapable of further output.
1366830Ssam 	 */
1376830Ssam 	case PRU_SHUTDOWN:
1386830Ssam 		socantsendmore(so);
1396830Ssam 		nsp_usrclosed(np);
1406830Ssam 		(void) nsp_output(np);
1416830Ssam 		break;
1426830Ssam 
1436830Ssam 	/*
1446830Ssam 	 * After a receive, possibly send window update to peer.
1456830Ssam 	 */
1466830Ssam 	case PRU_RCVD:
1476830Ssam 		(void) nsp_output(np);
1486830Ssam 		break;
1496830Ssam /*** END NOT MODIFIED FOR NSP ***/
1506830Ssam 
1516830Ssam 	/*
1526830Ssam 	 * Do a send by putting data in output queue and
1536830Ssam 	 * calling output processor.
1546830Ssam 	 */
1556830Ssam 	case PRU_SEND:
1566830Ssam 		sbpappend(&so->so_snd, m);
1576830Ssam 		(void) nsp_output(np);
1586830Ssam 		break;
1596830Ssam 
1606830Ssam /*** BEGIN NOT MODIFIED FOR NSP ***/
1616830Ssam 	/*
1626830Ssam 	 * Abort the NSP.
1636830Ssam 	 */
1646830Ssam 	case PRU_ABORT:
1656830Ssam 		nsp_drop(np, ECONNABORTED);
1666830Ssam 		break;
1676830Ssam 
1686830Ssam /* SOME AS YET UNIMPLEMENTED HOOKS */
1696830Ssam 	case PRU_CONTROL:
1706830Ssam 		error = EOPNOTSUPP;
1716830Ssam 		break;
1726830Ssam 
1736830Ssam 	case PRU_SENSE:
1746830Ssam 		error = EOPNOTSUPP;
1756830Ssam 		break;
1766830Ssam /* END UNIMPLEMENTED HOOKS */
1776830Ssam 
1786830Ssam 	case PRU_RCVOOB:
1796830Ssam 		if (so->so_oobmark == 0 &&
1806830Ssam 		    (so->so_state & SS_RCVATMARK) == 0) {
1816830Ssam 			error = EINVAL;
1826830Ssam 			break;
1836830Ssam 		}
1846830Ssam 		if ((np->n_flags & NSP_RCVINTR) == 0) {
1856830Ssam 			error = EWOULDBLOCK;
1866830Ssam 			break;
1876830Ssam 		}
1886830Ssam 		/* RETURN THE DATA */
1896830Ssam 		break;
1906830Ssam 
1916830Ssam 	case PRU_SENDOOB:
1926830Ssam 		/*
1936830Ssam 		if interrupt data present return error (can't queue)
1946830Ssam 		if len > 16 return error
1956830Ssam 		put in xmt mbuf
1966830Ssam 		mark interrupt data available
1976830Ssam 		call nsp_output
1986830Ssam 		*/
1996830Ssam 		break;
2006830Ssam 
2016830Ssam 	/*
2026830Ssam 	 * NSP slow timer went off; going through this
2036830Ssam 	 * routine for tracing's sake.
2046830Ssam 	 */
2056830Ssam 	case PRU_SLOWTIMO:
2066830Ssam 		nsp_timers(np, (int)addr);
2076830Ssam 		req |= (int)addr << 8;		/* for debug's sake */
2086830Ssam 		break;
2096830Ssam /*** END NOT MODIFIED FOR NSP ***/
2106830Ssam 
2116830Ssam 	default:
2126830Ssam 		panic("nsp_usrreq");
2136830Ssam 	}
2146830Ssam 	if (np && (so->so_options & SO_DEBUG))
2156830Ssam 		nsp_trace(NA_USER, ostate, np, (struct XXXXXXXX *)0, req);
2166830Ssam 	splx(s);
2176830Ssam 	return (error);
2186830Ssam }
2196830Ssam 
2206830Ssam /*
2216830Ssam  * Attach NSP protocol to socket, allocating NSP control block,
2226830Ssam  * bufer space, and entering LISTEN state if to accept connections.
2236830Ssam  */
2246830Ssam nsp_attach(so, sa)
2256830Ssam 	struct socket *so;
2266830Ssam 	struct sockaddr *sa;
2276830Ssam {
2286830Ssam 	register struct nspcb *np;
2296830Ssam 	struct sockaddr_dn *sdn = (struct sockaddr_dn *)sa;
2306830Ssam 	struct mbuf *m;
2316830Ssam 	int error;
2326830Ssam 
2336830Ssam 	if (sdn) {
2346830Ssam 		if (sdn->sdn_family != AF_DECNET)
2356830Ssam 			return (EAFNOSUPPORT);
2366830Ssam 		/* the user has specified a sockaddr with a socreate.
2376830Ssam 		all this can do is allow the user to specify an object
2386830Ssam 		type or other info if he is going to wait for a connection.
2396830Ssam 		figure this out later. */
2406830Ssam 	} else {
2416830Ssam 		/* nothing specified, will expect a connect request soon */
2426830Ssam 	}
243*9833Ssam 	m = m_getclr(MT_CANTWAIT, MT_PCB);
2446830Ssam 	if (m == 0)
2456830Ssam 		return (ENOBUFS);
2466830Ssam 	if (sbreserve(&so->so_snd, 1024) == 0) {
2476830Ssam bad:
2488774Sroot 		(void) m_free(m);
2496830Ssam 		return (ENOBUFS);
2506830Ssam 	}
2516830Ssam 	if (sbreserve(&so->so_rcv, 1024) == 0) {
2526830Ssam 		sbrelease(&so->so_snd);
2536830Ssam 		goto bad;
2546830Ssam 	}
2556830Ssam 	np = mtod(m, struct nspcb *);
2566830Ssam 	np->n_head = &ncb;
2576830Ssam 	insque(np, &ncb);
2586830Ssam 	sp->so_pcb = (caddr_t)np;
2596830Ssam 	sdn = (struct sockaddr_dn *)&so->so_addr;
2606830Ssam 	sdn->sdn_family == AF_DECNET;
2616830Ssam 	sdn->sdn_addr = WHAT ELSE NEEDS TO BE FILLED IN HERE?
2626830Ssam 	if (so->so_options & SO_ACCEPTCONN) {
2636830Ssam 		np->n_state = NS_LI;
2646830Ssam 	} else
2656830Ssam 		np->n_state = NS_O;
2666830Ssam 	return (0);
2676830Ssam }
2686830Ssam 
2696830Ssam /*** BEGIN NOT MODIFIED FOR NSP ***/
2706830Ssam /*
2716830Ssam  * Initiate (or continue) disconnect.
2726830Ssam  * If embryonic state, just send reset (once).
2736830Ssam  * If not in ``let data drain'' option, just drop.
2746830Ssam  * Otherwise (hard), mark socket disconnecting and drop
2756830Ssam  * current input data; switch states based on user close, and
2766830Ssam  * send segment to peer (with FIN).
2776830Ssam  */
2786830Ssam nsp_disconnect(np)
2796830Ssam 	struct nspcb *np;
2806830Ssam {
2816830Ssam 	struct socket *so = np->n_socket;
2826830Ssam 
2836830Ssam 	if (np->n_state < NSPS_ESTABLISHED)
2846830Ssam 		nsp_close(np);
2856830Ssam 	else if (so->so_linger == 0)
2866830Ssam 		nsp_drop(np, 0);
2876830Ssam 	else {
2886830Ssam 		soisdisconnecting(so);
2896830Ssam 		sbflush(&so->so_rcv);
2906830Ssam 		nsp_usrclosed(np);
2916830Ssam 		(void) nsp_output(np);
2926830Ssam 	}
2936830Ssam }
2946830Ssam 
2956830Ssam /*
2966830Ssam  * User issued close, and wish to trail through shutdown states:
2976830Ssam  * if never received SYN, just forget it.  If got a SYN from peer,
2986830Ssam  * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
2996830Ssam  * If already got a FIN from peer, then almost done; go to LAST_ACK
3006830Ssam  * state.  In all other cases, have already sent FIN to peer (e.g.
3016830Ssam  * after PRU_SHUTDOWN), and just have to play tedious game waiting
3026830Ssam  * for peer to send FIN or not respond to keep-alives, etc.
3036830Ssam  */
3046830Ssam nsp_usrclosed(np)
3056830Ssam 	struct nspcb *np;
3066830Ssam {
3076830Ssam 
3086830Ssam 	switch (np->n_state) {
3096830Ssam 
3106830Ssam 	case NSPS_LISTEN:
3116830Ssam 	case NSPS_SYN_SENT:
3126830Ssam 		np->n_state = NSPS_CLOSED;
3136830Ssam 		nsp_close(np);
3146830Ssam 		break;
3156830Ssam 
3166830Ssam 	case NSPS_SYN_RECEIVED:
3176830Ssam 	case NSPS_ESTABLISHED:
3186830Ssam 		np->n_state = NSPS_FIN_WAIT_1;
3196830Ssam 		break;
3206830Ssam 
3216830Ssam 	case NSPS_CLOSE_WAIT:
3226830Ssam 		np->n_state = NSPS_LAST_ACK;
3236830Ssam 		break;
3246830Ssam 	}
3256830Ssam }
326