xref: /csrg-svn/sys/netiso/if_cons.c (revision 37536)
136381Ssklower /***********************************************************
236381Ssklower 		Copyright IBM Corporation 1987
336381Ssklower 
436381Ssklower                       All Rights Reserved
536381Ssklower 
636381Ssklower Permission to use, copy, modify, and distribute this software and its
736381Ssklower documentation for any purpose and without fee is hereby granted,
836381Ssklower provided that the above copyright notice appear in all copies and that
936381Ssklower both that copyright notice and this permission notice appear in
1036381Ssklower supporting documentation, and that the name of IBM not be
1136381Ssklower used in advertising or publicity pertaining to distribution of the
1236381Ssklower software without specific, written prior permission.
1336381Ssklower 
1436381Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536381Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636381Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736381Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836381Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936381Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036381Ssklower SOFTWARE.
2136381Ssklower 
2236381Ssklower ******************************************************************/
2336381Ssklower 
2436381Ssklower /*
2536381Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636381Ssklower  */
2736381Ssklower /*
2836381Ssklower  * $Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $
2936381Ssklower  * $Source: /usr/argo/sys/netiso/RCS/if_cons.c,v $
3036381Ssklower  *
3136381Ssklower  * cons.c - Connection Oriented Network Service:
3236381Ssklower  * including support for a) user transport-level service,
3336381Ssklower  *	b) COSNS below CLNP, and c) CONS below TP.
3436381Ssklower  */
3536381Ssklower 
3636381Ssklower #ifndef lint
3736381Ssklower static char *rcsid = "$Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $";
3836381Ssklower #endif lint
3936381Ssklower 
4036381Ssklower #ifdef ARGO_DEBUG
4136381Ssklower #define Static
4236381Ssklower unsigned LAST_CALL_PCB;
4336381Ssklower #else ARGO_DEBUG
4436381Ssklower #define Static static
4536381Ssklower #endif ARGO_DEBUG
4636381Ssklower 
4736381Ssklower #include "ecn.h"
4836381Ssklower #include "argoxtwentyfive.h"
4936381Ssklower 
5036381Ssklower #if NARGOXTWENTYFIVE > 0
5136381Ssklower 
5236381Ssklower #ifdef KERNEL
5336381Ssklower 
5436381Ssklower #include "param.h"
5536381Ssklower #include "systm.h"
5636381Ssklower #include "mbuf.h"
5736381Ssklower #include "protosw.h"
5836381Ssklower #include "socket.h"
5936381Ssklower #include "socketvar.h"
6036381Ssklower #include "errno.h"
6136381Ssklower #include "ioctl.h"
6236381Ssklower 
6336381Ssklower #include "../net/if.h"
6436381Ssklower #include "../net/netisr.h"
6536381Ssklower #include "../net/route.h"
6636381Ssklower 
6736381Ssklower #include "../netiso/iso_errno.h"
6836381Ssklower #include "../netiso/argo_debug.h"
6936381Ssklower #include "../netiso/tp_trace.h"
7036381Ssklower #include "../netiso/iso.h"
7136381Ssklower #include "../netiso/cons.h"
7236381Ssklower #include "../netiso/iso_pcb.h"
7336381Ssklower #include "../netiso/cons_pcb.h"
7436381Ssklower #include "../caif/eicon.h"
7536381Ssklower 
7636381Ssklower #ifdef ARGO_DEBUG
7736381Ssklower #define MT_XCONN	0x50
7836381Ssklower #define MT_XCLOSE	0x51
7936381Ssklower #define MT_XCONFIRM	0x52
8036381Ssklower #define MT_XDATA	0x53
8136381Ssklower #define MT_XHEADER	0x54
8236381Ssklower #else
8336381Ssklower #define MT_XCONN	MT_DATA
8436381Ssklower #define MT_XCLOSE	MT_DATA
8536381Ssklower #define MT_XCONFIRM	MT_DATA
8636381Ssklower #define MT_XDATA	MT_DATA
8736381Ssklower #define MT_XHEADER	MT_HEADER
8836381Ssklower #endif ARGO_DEBUG
8936381Ssklower 
9036381Ssklower #define DONTCLEAR	 -1
9136381Ssklower 
9236381Ssklower /*********************************************************************
9336381Ssklower  * cons.c - CONS interface to the eicon adapter
9436381Ssklower  * Includes connection manager - for (TP, CLNP)/x.25
9536381Ssklower  *
9636381Ssklower  * TODO: figure out what resources we might run out of besides mbufs.
9736381Ssklower  *  If we run out of any of them (including mbufs) close and recycle
9836381Ssklower  *  lru x% of the connections, for some parameter x.
9936381Ssklower  *
10036381Ssklower  * There are 4 interfaces from above:
10136381Ssklower  * 0) from CLNP:
10236381Ssklower  *    cons is an interface driver - CLNP calls
10336381Ssklower  *    cosns_output(ifp, m, dst), a device-type interface output routine
10436381Ssklower  *    that does some connection management stuff and queues a
10536381Ssklower  *    request on the eicon driver queue by calling ifp->if_output.
10636381Ssklower  *    The eicon's ifp structure contains cosns_output as its output routine
10736381Ssklower  *    rather than ifp_>if_output! Kludge, but we don't have much choice...
10836381Ssklower  *    X25 connections created in this manner may always be multiplexed
10936381Ssklower  *    but only with their own kind (not with connections servicing TP
11036381Ssklower  *    directly.)
11136381Ssklower  *	  	co_flags & CONSF_DGM
11236381Ssklower  * 1) from TP0:
11336381Ssklower  *    cons CO network service
11436381Ssklower  *    TP associates a transport connection with a network connection.
11536381Ssklower  * 	  cons_output( isop, m, len, isdgm==0 )
11636381Ssklower  *        co_flags == 0
11736381Ssklower  * 2) from TP 4:
11836381Ssklower  *	  It's a datagram service, like clnp is. - even though it calls
11936381Ssklower  *			cons_output( isop, m, len, isdgm==1 )
12036381Ssklower  *	  it eventually goes through
12136381Ssklower  *			cosns_output(ifp, m, dst).
12236381Ssklower  *    TP4 permits multiplexing (reuse, possibly simultaneously) of the
12336381Ssklower  *	  network connections.
12436381Ssklower  *    This means that many sockets (many tpcbs) may be associated with
12536381Ssklower  *    this cons_pcb, hence cannot have a back ptr from cons_pcb to a tpcb.
12636381Ssklower  *        co_flags & CONSF_DGM
12736381Ssklower  *    co_socket is null since there may be many sockets that use this copcb.
12836381Ssklower  * 3) from user: cons_usrreq(), cons_ctloutput()
12936381Ssklower  *    cons is a standard transport service interface.
13036381Ssklower  *    There is a 1-1 correspondence between net connections and sockets.
13136381Ssklower  *	  co_socket points to a socket.
13236381Ssklower  *
13336381Ssklower NOTE:
13436381Ssklower 	streams would really be nice. sigh.
13536381Ssklower NOTE:
13636381Ssklower 	eicon <--> cons interface: the first mbuf (the ecn_request structure)
13736381Ssklower 	had better NOT be a cluster.
13836381Ssklower NOTE:
13936381Ssklower 	PVCs could be handled by config-ing a cons with an address and with the
14036381Ssklower 	IFF_POINTTOPOINT flag on.  This code would then have to skip the
14136381Ssklower 	connection setup stuff for pt-to-pt links.
14236381Ssklower NOTE:
14336381Ssklower 	We keep track of the ifp for each connection.  Right now this is
14436381Ssklower 	unnecessary, but just in case someone comes up with some kind
14536381Ssklower 	of a kludge to allow > 1 eicon to be attached at a time,
14636381Ssklower 	(i.e., some meaningful netof( a type 37 address ) ),
14736381Ssklower 	we do keep track of this.
14836381Ssklower 
14936381Ssklower 
15036381Ssklower  *********************************************************************/
15136381Ssklower 
15236381Ssklower #define touch(copcb) copcb->co_ttl = copcb->co_init_ttl
15336381Ssklower 
15436381Ssklower #define CONS_IFQMAXLEN 5
15536381Ssklower 
15636381Ssklower #define SET_CHANMASK( isop, chan )\
15736381Ssklower 	if( (u_int)(chan) < 32 ) \
15836381Ssklower 		(isop)->isop_chanmask = (1<<((chan)-1));\
15936381Ssklower 	else \
16036381Ssklower 		(isop)->isop_negchanmask = (1<<((256-(chan))-1))
16136381Ssklower 
16236381Ssklower #define ADD_CHANMASK( isop, chan )\
16336381Ssklower 	if( (u_int)(chan) < 32 ) \
16436381Ssklower 		(isop)->isop_chanmask |= (1<<((chan)-1));\
16536381Ssklower 	else \
16636381Ssklower 		(isop)->isop_negchanmask |= (1<<((256-(chan))-1))
16736381Ssklower 
16836381Ssklower struct ifnet 			*consif; /* TO BE REMOVED */
16936381Ssklower Static int				consinit(), consioctl(), consattach();
17036381Ssklower 
17136381Ssklower /* protosw pointers for getting to higher layer */
17236381Ssklower Static 	struct protosw	*CLNP_proto;
17336381Ssklower Static 	struct protosw	*TP_proto;
17436381Ssklower Static 	struct protosw	*X25_proto;
17536381Ssklower Static 	int				issue_clear_req();
17636381Ssklower 
17736381Ssklower #ifndef	PHASEONE
17836381Ssklower extern	struct ifaddr	*ifa_ifwithnet();
17936381Ssklower #endif	PHASEONE
18036381Ssklower 
18136381Ssklower extern	struct ifaddr	*ifa_ifwithaddr();
18236381Ssklower 
18336381Ssklower Static  struct socket	dummysocket; /* for use by cosns */
18436381Ssklower 
18536381Ssklower extern struct	isopcb	tp_isopcb; /* chain of all TP pcbs */
18636381Ssklower struct	isopcb			cons_isopcb; /* chain of all cons pcbs */
18736381Ssklower struct	isopcb			tp_incoming_pending;  /* incoming connections
18836381Ssklower 										for TP, pending */
18936381Ssklower 
19036381Ssklower struct isopcb 	*Xpcblist[] =  {
19136381Ssklower 	&cons_isopcb,
19236381Ssklower 	&tp_incoming_pending,
19336381Ssklower 	&tp_isopcb,
19436381Ssklower 	(struct isopcb *)0
19536381Ssklower };
19636381Ssklower 
19736381Ssklower Static 	int parse_facil(), NSAPtoDTE(), make_partial_x25_packet();
19836381Ssklower Static	int FACILtoNSAP(), DTEtoNSAP();
19936381Ssklower Static	struct cons_pcb *cons_chan_to_pcb();
20036381Ssklower 
20136381Ssklower #define HIGH_NIBBLE 1
20236381Ssklower #define LOW_NIBBLE 0
20336381Ssklower 
20436381Ssklower /*
20536381Ssklower  * NAME:	nibble_copy()
20636381Ssklower  * FUNCTION and ARGUMENTS:
20736381Ssklower  * 	copies (len) nibbles from (src_octet), high or low nibble
20836381Ssklower  *  to (dst_octet), high or low nibble,
20936381Ssklower  * src_nibble & dst_nibble should be:
21036381Ssklower  * 	HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble
21136381Ssklower  * 	LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble
21236381Ssklower  * RETURNS: VOID
21336381Ssklower  */
21436381Ssklower void
21536381Ssklower nibble_copy( src_octet, src_nibble, dst_octet, dst_nibble, len)
21636381Ssklower 	register char  	*src_octet;
21736381Ssklower 	register char  	*dst_octet;
21836381Ssklower 	register unsigned		src_nibble;
21936381Ssklower 	register unsigned 		dst_nibble;
22036381Ssklower 	int		len;
22136381Ssklower {
22236381Ssklower 
22336381Ssklower 	register 	i;
22436381Ssklower 	register 	unsigned dshift, sshift;
22536381Ssklower 
22636381Ssklower 	IFDEBUG(D_CADDR)
22736381Ssklower 		printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n",
22836381Ssklower 		 src_octet, src_nibble, dst_octet, dst_nibble, len);
22936381Ssklower 	ENDDEBUG
23036381Ssklower #define SHIFT 0x4
23136381Ssklower 
23236381Ssklower 	dshift = dst_nibble << 2;
23336381Ssklower 	sshift = src_nibble << 2;
23436381Ssklower 
23536381Ssklower 	for (i=0; i<len; i++) {
23636381Ssklower 		/* clear dst_nibble  */
23736381Ssklower 		*dst_octet 	&= ~(0xf<< dshift);
23836381Ssklower 
23936381Ssklower 		/* set dst nibble */
24036381Ssklower 		*dst_octet 	|= ( 0xf & (*src_octet >> sshift))<< dshift;
24136381Ssklower 
24236381Ssklower 		dshift		^= SHIFT;
24336381Ssklower 		sshift		^= SHIFT;
24436381Ssklower 		src_nibble 	= 1-src_nibble;
24536381Ssklower 		dst_nibble 	= 1-dst_nibble;
24636381Ssklower 		src_octet	+= src_nibble;
24736381Ssklower 		dst_octet 	+= dst_nibble;
24836381Ssklower 	}
24936381Ssklower 	IFDEBUG(D_CADDR)
25036381Ssklower 		printf("nibble_copy DONE\n");
25136381Ssklower 	ENDDEBUG
25236381Ssklower }
25336381Ssklower 
25436381Ssklower /*
25536381Ssklower  * NAME:	nibble_match()
25636381Ssklower  * FUNCTION and ARGUMENTS:
25736381Ssklower  * 	compares src_octet/src_nibble and dst_octet/dst_nibble  for len nibbles.
25836381Ssklower  * RETURNS: 0 if they differ, 1 if they are the same.
25936381Ssklower  */
26036381Ssklower int
26136381Ssklower nibble_match( src_octet, src_nibble, dst_octet, dst_nibble, len)
26236381Ssklower 	register char  	*src_octet;
26336381Ssklower 	register char  	*dst_octet;
26436381Ssklower 	register unsigned		src_nibble;
26536381Ssklower 	register unsigned 		dst_nibble;
26636381Ssklower 	int		len;
26736381Ssklower {
26836381Ssklower 
26936381Ssklower 	register 	i;
27036381Ssklower 	register 	unsigned dshift, sshift;
27136381Ssklower 	u_char		nibble_a, nibble_b;
27236381Ssklower 
27336381Ssklower 	IFDEBUG(D_CADDR)
27436381Ssklower 		printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n",
27536381Ssklower 		 src_octet, src_nibble, dst_octet, dst_nibble, len);
27636381Ssklower 	ENDDEBUG
27736381Ssklower #define SHIFT 0x4
27836381Ssklower 
27936381Ssklower 	dshift = dst_nibble << 2;
28036381Ssklower 	sshift = src_nibble << 2;
28136381Ssklower 
28236381Ssklower 	for (i=0; i<len; i++) {
28336381Ssklower 		nibble_b = ((*dst_octet)>>dshift) & 0xf;
28436381Ssklower 		nibble_a = ( 0xf & (*src_octet >> sshift));
28536381Ssklower 		if( nibble_b != nibble_a )
28636381Ssklower 			return 0;
28736381Ssklower 
28836381Ssklower 		dshift		^= SHIFT;
28936381Ssklower 		sshift		^= SHIFT;
29036381Ssklower 		src_nibble 	= 1-src_nibble;
29136381Ssklower 		dst_nibble 	= 1-dst_nibble;
29236381Ssklower 		src_octet	+= src_nibble;
29336381Ssklower 		dst_octet 	+= dst_nibble;
29436381Ssklower 	}
29536381Ssklower 	IFDEBUG(D_CADDR)
29636381Ssklower 		printf("nibble_match DONE\n");
29736381Ssklower 	ENDDEBUG
29836381Ssklower 	return 1;
29936381Ssklower }
30036381Ssklower 
30136381Ssklower #ifdef ARGO_DEBUG
30236381Ssklower 
30336381Ssklower Static
30436381Ssklower dump_copcb(copcb, str)
30536381Ssklower 	char * str;
30636381Ssklower 	register struct cons_pcb *copcb;
30736381Ssklower {
30836381Ssklower 	printf("XPCB DUMP %s\n", str);
30936381Ssklower 	if (copcb) {
31036381Ssklower 		printf("\t copcb 0x%x next 0x%x head 0x%x socket 0x%x ifp 0x%x\n",
31136381Ssklower 			copcb, copcb->co_next, copcb->co_head, copcb->co_socket, copcb->co_ifp);
31236381Ssklower 		printf("\t channel 0x%x state 0x%x flags 0x%x proto 0x%x\n",
31336381Ssklower 			copcb->co_channel, copcb->co_state, copcb->co_flags, copcb->co_proto);
31436381Ssklower 		printf("\t laddr :\n");
31536381Ssklower 		dump_isoaddr(&copcb->co_laddr);
31636381Ssklower 		printf("\t faddr :\n");
31736381Ssklower 		dump_isoaddr(&copcb->co_faddr);
31836381Ssklower 		printf("\tttl 0x%x init_ttl 0x%x pending: %d\n",
31936381Ssklower 			copcb->co_ttl, copcb->co_init_ttl, copcb->co_pending.ifq_len);
32036381Ssklower 	}
32136381Ssklower 	printf("END DUMP\n");
32236381Ssklower }
32336381Ssklower #endif ARGO_DEBUG
32436381Ssklower 
32536381Ssklower /*
32636381Ssklower  * FUNCTION : choose_output - chooses between the eicon and loopback.
32736381Ssklower  * This MUST be here because the ifp->if_output routine is cosns_output
32836381Ssklower  * -- due to our need to look like a device driver for CLNP. sigh.
32936381Ssklower  * ARGUMENTS & PURPOSE:  (copcb) ptr to a protocol control block for
33036381Ssklower  *			x.25, (m) is an mbuf ptr. *m is a request destined either
33136381Ssklower  * 			for the eicon driver or for the loopback driver.
33236381Ssklower  * RETURNS : whatever error value the 2I or loopback returns.
33336381Ssklower  */
33436381Ssklower Static int
33536381Ssklower choose_output( ifp, m, loop)
33636381Ssklower 	struct ifnet 	*ifp;
33736381Ssklower 	struct mbuf 	*m;
33836381Ssklower 	int				loop;
33936381Ssklower {
34036381Ssklower 	int error;
34136381Ssklower 
34236381Ssklower 	if( !m )
34336381Ssklower 		return 0;
34436381Ssklower 	ASSERT(m->m_len != 0);
34536381Ssklower 	if( loop != 0)
34636381Ssklower 		error = lpboutput( ifp, m );
34736381Ssklower 	else
34836381Ssklower 		error = ecnoutput( ifp,  m );
34936381Ssklower 
35036381Ssklower 	if (error == 0)
35136381Ssklower 		ifp->if_opackets ++;
35236381Ssklower 	else {
35336381Ssklower 		ifp->if_oerrors ++;
35436381Ssklower 		IFTRACE(D_CDATA)
35536381Ssklower 			tptrace( TPPTmisc,
35636381Ssklower 			"choose_output: ifp  m error loop\n",
35736381Ssklower 				ifp, m, error, loop);
35836381Ssklower 		ENDTRACE
35936381Ssklower 	}
36036381Ssklower 	IFDEBUG(D_CCONS)
36136381Ssklower 		printf("choose_output returns 0x%x\n", error );
36236381Ssklower 	ENDDEBUG
36336381Ssklower 	return error;
36436381Ssklower }
36536381Ssklower 
36636381Ssklower /*
36736381Ssklower  **************************** NET PROTOCOL cons ***************************
36836381Ssklower  */
36936381Ssklower 
37036381Ssklower /*
37136381Ssklower  * NAME:	cons_init()
37236381Ssklower  * CALLED FROM:
37336381Ssklower  *	autoconf
37436381Ssklower  * FUNCTION:
37536381Ssklower  *	initialize the protocol
37636381Ssklower  */
37736381Ssklower cons_init()
37836381Ssklower {
37936381Ssklower 	init_lpb();
38036381Ssklower 	consattach();
38136381Ssklower 
38236381Ssklower 	/* protocol init stuff */
38336381Ssklower 
38436381Ssklower 	consintrq.ifq_maxlen = IFQ_MAXLEN;
38536381Ssklower 	consintrq.ifq_head = consintrq.ifq_tail =  (struct mbuf *)0;
38636381Ssklower 
38736381Ssklower 	CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM);
38836381Ssklower 	X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM);
38936381Ssklower 	TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET);
39036381Ssklower 	IFDEBUG(D_CCONS)
39136381Ssklower 		printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n",
39236381Ssklower 			CLNP_proto, X25_proto, TP_proto);
39336381Ssklower 	ENDDEBUG
39436381Ssklower 
39536381Ssklower 	cons_isopcb.isop_next = cons_isopcb.isop_prev = &cons_isopcb;
39636381Ssklower 	tp_incoming_pending.isop_next = tp_incoming_pending.isop_prev =
39736381Ssklower 			&tp_incoming_pending;
39836381Ssklower }
39936381Ssklower 
40036381Ssklower #ifdef notdef
40136381Ssklower 
40236381Ssklower /*
40336381Ssklower  * NAME:	cons_free_lru()
40436381Ssklower  * some day CALLED FROM:
40536381Ssklower  * 	wherever we run out of mbufs (not used right yet)
40636381Ssklower  * FUNCTION:
40736381Ssklower  *	get rid of the num least recently used connections and
40836381Ssklower  *  recycle their mbufs.
40936381Ssklower  * NOTE: GROTESQUELY INEFFICIENT needs to be written nicely
41036381Ssklower  */
41136381Ssklower 
41236381Ssklower Static
41336381Ssklower cons_free_lru(qty)
41436381Ssklower 	int qty;
41536381Ssklower {
41636381Ssklower 	register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist;
41736381Ssklower 	register struct cons_pcb *copcb;
41836381Ssklower 	struct cons_pcb 			Lru;
41936381Ssklower 	struct cons_pcb 			*lru;
42036381Ssklower 
42136381Ssklower 	IFDEBUG(D_CCONS)
42236381Ssklower 		printf("cons_free_lru( 0x%x )\n", qty);
42336381Ssklower 	ENDDEBUG
42436381Ssklower 
42536381Ssklower 	Lru.co_ttl = X25_TTL;
42636381Ssklower 	lru = &Lru;
42736381Ssklower 
42836381Ssklower 	while (qty > 1) { /* GROT */
42936381Ssklower 		cons_free_lru( 1 );
43036381Ssklower 		qty -- ;
43136381Ssklower 	}
43236381Ssklower 
43336381Ssklower 	for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) {
43436381Ssklower 		copcb = (struct cons_pcb *)copcb->co_next;
43536381Ssklower 		while (copcb !=  *copcblist) {
43636381Ssklower 			if( copcb->co_ttl < lru->co_ttl )
43736381Ssklower 				lru = copcb;
43836381Ssklower 			copcb = (struct cons_pcb *)copcb->co_next;
43936381Ssklower 		}
44036381Ssklower 	}
44136381Ssklower 
44236381Ssklower 	if(lru->co_socket) {
44336381Ssklower 		soisdisconnected(lru->co_socket);
44436381Ssklower 		sohasoutofband(lru->co_socket); /* signal */
44536381Ssklower 	}
44636381Ssklower 
44736381Ssklower 	cons_clear_and_detach( lru, E_CO_HLI_RESYNC, PRC_TIMXCEED_REASS);
44836381Ssklower }
44936381Ssklower #endif notdef
45036381Ssklower 
45136381Ssklower /*
45236381Ssklower  * NAME:	cons_slowtimo()
45336381Ssklower  * CALLED FROM:
45436381Ssklower  * 	the clock
45536381Ssklower  * FUNCTION:
45636381Ssklower  *	get rid of any timed-out cons connections
45736381Ssklower  *  cons connections get "touched" with every use, meaning the
45836381Ssklower  *  time-to-live gets reset to its max value w/ every use.
45936381Ssklower  *  The slowtimo() rtn decrements the time-to-live for each
46036381Ssklower  *  cons connection.  If one of them hits zero ---> zap the connection.
46136381Ssklower  *  This really only applies to those used for CLNP and TP4.
46236381Ssklower  *  TP4 keeps the connections open with keepalive.
46336381Ssklower  * TODO:
46436381Ssklower  *  Have this happen ONLY for international connections since
46536381Ssklower  *  there's no connect time charge for domestic calls.
46636381Ssklower  *  Make default 5 min; make a user option to change it.
46736381Ssklower  * TODO:
46836381Ssklower  *  Maybe if the ttl gets lower than a certain threshold, move this
46936381Ssklower  *  copcb to the END of its queue so it doesn't slow down the others.
47036381Ssklower  */
47136381Ssklower 
47236381Ssklower cons_slowtimo()
47336381Ssklower {
47436381Ssklower 	register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist;
47536381Ssklower 	register struct cons_pcb *copcb;
47636381Ssklower 	int s = splnet();
47736381Ssklower 	int	qlen = 0;
47836381Ssklower 	int qdrops = 0;
47936381Ssklower 	int	nvisited = 0;
48036381Ssklower 
48136381Ssklower #ifdef ARGO_DEBUG
48236381Ssklower 	Static int count;
48336381Ssklower 
48436381Ssklower 	count = 0;
48536381Ssklower #endif ARGO_DEBUG
48636381Ssklower 
48736381Ssklower 	IncStat(co_slowtimo);
48836381Ssklower 	for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) {
48936381Ssklower #ifdef ARGO_DEBUG
49036381Ssklower 		if( copcb == (struct cons_pcb *)0 ) {
49136381Ssklower 			ASSERT( 0 );
49236381Ssklower 			panic("TURNING OFF cons_slowtimo()!!! \n");
49336381Ssklower 		}
49436381Ssklower #endif ARGO_DEBUG
49536381Ssklower 		copcb = (struct cons_pcb *)copcb->co_next;
49636381Ssklower 		while (copcb !=  *copcblist) {
49736381Ssklower #ifdef ARGO_DEBUG
49836381Ssklower 			if(++count >50 ) {
49936381Ssklower 				printf("cons PANIC: slowtimo LOOP\n");
50036381Ssklower 				splx(s);
50136381Ssklower 				return;
50236381Ssklower 			}
50336381Ssklower #endif ARGO_DEBUG
50436381Ssklower #ifdef notdef
50536381Ssklower 			if( copcb->co_init_ttl == 0 ) {
50636381Ssklower 	ASSERT( (struct isopcb *)(*copcblist)==(struct isopcb *)&tp_isopcb );
50736381Ssklower 				copcb = (struct cons_pcb *)copcb->co_next;
50836381Ssklower 				continue;
50936381Ssklower 			}
51036381Ssklower #endif notdef
51136381Ssklower 			nvisited ++;
51236381Ssklower 			ASSERT( copcb != (struct cons_pcb *)0 );
51336381Ssklower 			qlen += copcb->co_pending.ifq_len;
51436381Ssklower 			qdrops += copcb->co_pending.ifq_drops;
51536381Ssklower 
51636381Ssklower 			if( copcb->co_socket) {
51736381Ssklower 				/* don't want XTS, TP0 connections to be subject to time out */
51836381Ssklower 				copcb = (struct cons_pcb *)copcb->co_next;
51936381Ssklower 				continue;
52036381Ssklower 			}
52136381Ssklower 
52236381Ssklower 			if( -- (copcb->co_ttl) > 0 )  {
52336381Ssklower 				copcb = (struct cons_pcb *)copcb->co_next;
52436381Ssklower 				continue;
52536381Ssklower 			}
52636381Ssklower 
52736381Ssklower 			IncStat(co_timedout);
52836381Ssklower 
52936381Ssklower 			IFDEBUG(D_CCONN)
53036381Ssklower 				printf("TIMING OUT chan 0x%x copcb 0x%x flags 0x%x\n",
53136381Ssklower 					copcb->co_channel, copcb, copcb->co_flags );
53236381Ssklower 			ENDDEBUG
53336381Ssklower 
53436381Ssklower 			{
53536381Ssklower 				register struct cons_pcb * next =
53636381Ssklower 					(struct cons_pcb *)copcb->co_next;
53736381Ssklower 				cons_clear_and_detach(copcb,
53836381Ssklower 						E_CO_HLI_RESYNC, PRC_TIMXCEED_REASS);
53936381Ssklower 				copcb = next;
54036381Ssklower 			}
54136381Ssklower 		}
54236381Ssklower 	}
54336381Ssklower 	if(nvisited) {
54436381Ssklower 		cons_stat.co_avg_qlen = qlen / nvisited;
54536381Ssklower 		cons_stat.co_avg_qdrop = qdrops / nvisited;
54636381Ssklower 		cons_stat.co_active = nvisited;
54736381Ssklower 	}
54836381Ssklower done:
54936381Ssklower 	splx(s);
55036381Ssklower }
55136381Ssklower 
55236381Ssklower DUMP_PCBLIST()
55336381Ssklower {
55436381Ssklower 	register int i=0;
55536381Ssklower 	register struct cons_pcb *copcb;
55636381Ssklower 	register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist;
55736381Ssklower 
55836381Ssklower 	for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) {
55936381Ssklower 		printf("FOR %d: 0x%x ", ++i, copcb);
56036381Ssklower 		copcb = (struct cons_pcb *)copcb->co_next;
56136381Ssklower 		printf(" next 0x%x, *copcblist 0x%x\n",  copcb, *copcblist);
56236381Ssklower 		while (copcb !=  *copcblist) {
56336381Ssklower 			ASSERT( copcb != (struct cons_pcb *)0 );
56436381Ssklower 			printf("\tCOPCB 0x%x\n", copcb);
56536381Ssklower 			if( copcb )
56636381Ssklower 				dump_buf(copcb, sizeof( *copcb));
56736381Ssklower 			else
56836381Ssklower 				break;
56936381Ssklower 			copcb = (struct cons_pcb *)copcb->co_next;
57036381Ssklower 		}
57136381Ssklower 	}
57236381Ssklower }
57336381Ssklower 
57436381Ssklower /*
57536381Ssklower  * NAME:	cons_pcballoc()
57636381Ssklower  * CALLED FROM:
57736381Ssklower  *	cons_usrreq() when doing PRU_ATTACH,
57836381Ssklower  *  cons_incoming() when opening a new connection.
57936381Ssklower  * FUNCTION and ARGUMENTS:
58036381Ssklower  *	Allocates a new pcb.
58136381Ssklower  *  The flags and proto arguments are stashed into the new pcb.
58236381Ssklower  * RETURN VALUE:
58336381Ssklower  *  E* if error, 0 if ok
58436381Ssklower  */
58536381Ssklower Static int
58636381Ssklower cons_pcballoc(so, head, flags, proto, dest)
58736381Ssklower 	struct socket	*so;
58836381Ssklower 	struct	isopcb	*head;
58936381Ssklower 	u_short 		flags;
59036381Ssklower 	struct protosw	*proto;
59136381Ssklower 	struct	cons_pcb **dest;
59236381Ssklower {
59336381Ssklower 	int 					error;
59436381Ssklower 	register struct cons_pcb *copcb;
59536381Ssklower 
59636381Ssklower 	IFDEBUG(D_CCONN)
59736381Ssklower 		printf("cons_pcballoc (0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
59836381Ssklower 			so, head, flags, proto, dest);
59936381Ssklower 	ENDDEBUG
60036381Ssklower 	if(proto == (struct protosw *)0)
60136381Ssklower 		return EPROTONOSUPPORT;
60236381Ssklower 
60336381Ssklower 	if( ( error = iso_pcballoc(so, head) ) == EOK )  {
60436381Ssklower 		/* Have allocated a cleared mbuf */
60536381Ssklower 
60636381Ssklower 		copcb = (struct cons_pcb *)so->so_pcb;
60736381Ssklower 		copcb->co_ttl = copcb->co_init_ttl = X25_TTL;
60836381Ssklower 		copcb->co_flags = flags;
60936381Ssklower 		copcb->co_proto = proto;
61036381Ssklower 		copcb->co_pending.ifq_maxlen = CONS_IFQMAXLEN;
61136381Ssklower 		copcb->co_myself = copcb;
61236381Ssklower 
61336381Ssklower 		if (so == &dummysocket)
61436381Ssklower 			copcb->co_socket = (struct socket *)0;
61536381Ssklower 
61636381Ssklower 		*dest = copcb;
61736381Ssklower 	}
61836381Ssklower done:
61936381Ssklower 	IFDEBUG(D_CCONN)
62036381Ssklower 		printf("cons_pcballoc returns 0x%x: DUMP\n", copcb);
62136381Ssklower 		dump_buf( copcb, sizeof(*copcb));
62236381Ssklower 	ENDDEBUG
62336381Ssklower 	if( (flags & CONSF_ICRE) == 0) {
62436381Ssklower 		struct dte_addr *dtea = &(*dest)->co_peer_dte;
62536381Ssklower 		int len;
62636381Ssklower 
62736381Ssklower 		error = iso_8208snparesolve(&(*dest)->co_faddr, dtea, &len);
62836381Ssklower 		ASSERT(error == 0);
62936381Ssklower 		ASSERT(len == sizeof(struct dte_addr));
63036381Ssklower 	}
63136381Ssklower 
63236381Ssklower 	return error;
63336381Ssklower }
63436381Ssklower 
63536381Ssklower /*
63636381Ssklower  * NAME:	cons_connect()
63736381Ssklower  * CALLED FROM:
63836381Ssklower  *	cons_usrreq() when opening a new connection.
63936381Ssklower  * FUNCTION anD ARGUMENTS:
64036381Ssklower  *  Figures out which device to use, finding a route if one doesn't
64136381Ssklower  *  already exist.
64236381Ssklower  * 	Builds an eicon connection request and gives it to the device.
64336381Ssklower  * RETURN VALUE:
64436381Ssklower  *  returns E*
64536381Ssklower  */
64636381Ssklower Static int
64736381Ssklower cons_connect( copcb )
64836381Ssklower 	register struct cons_pcb *copcb;
64936381Ssklower {
65036381Ssklower 	register struct eicon_request *ecnrq;
65136381Ssklower 	register struct mbuf 	*m;
65236381Ssklower 	int 					error = 0;
65336381Ssklower 	struct ifaddr 			*ifa;
65436381Ssklower 
65536381Ssklower 	IFDEBUG(D_CCONN)
65636381Ssklower 		printf("cons_connect( 0x%x ) : ifp 0x%x\npeer: ", copcb, copcb->co_ifp);
65736381Ssklower 		dump_isoaddr(&copcb->co_faddr);
65836381Ssklower 		printf("\nmyaddr: ");
65936381Ssklower 		dump_isoaddr(&copcb->co_laddr);
66036381Ssklower 		printf("\n" );
66136381Ssklower 	ENDDEBUG
66236381Ssklower 
66336381Ssklower 	/* PHASE 2: this call is OK */
66436381Ssklower 	if( ifa = ifa_ifwithaddr(&copcb->co_faddr ) ) {
66536381Ssklower 		/* foreign address is me */
66636381Ssklower 		copcb->co_ifp = ifa->ifa_ifp;
66736381Ssklower 		IFDEBUG(D_CCONN)
66836381Ssklower 			printf("cons_connect: after if_withaddr copcb->co_ifp 0x%x\n",
66936381Ssklower 				copcb->co_ifp);
67036381Ssklower 		ENDDEBUG
67136381Ssklower 
67236381Ssklower 		if( (ifa->ifa_ifp->if_flags&(IFF_LOOPBACK|IFF_UP)) ==
67336381Ssklower 												(IFF_LOOPBACK|IFF_UP)) {
67436381Ssklower 			copcb->co_flags |= CONSF_LOOPBACK;
67536381Ssklower 		}
67636381Ssklower 		bcopy((caddr_t)&ifa->ifa_addr, (caddr_t)&copcb->co_laddr,
67736381Ssklower 			sizeof(struct sockaddr));
67836381Ssklower 	}
67936381Ssklower 	IFDEBUG(D_CCONN)
68036381Ssklower 		printf("cons_connect: co_flags 0x%x\n", copcb->co_flags);
68136381Ssklower 		if( ifa ) {
68236381Ssklower 			printf(" cons_connect withaddr returns %s\n",
68336381Ssklower 				copcb->co_ifp->if_name);
68436381Ssklower 		}
68536381Ssklower 	ENDDEBUG
68636381Ssklower 	else if ( copcb->co_ifp == (struct ifnet *)0 ) {
68736381Ssklower #ifdef	PHASEONE
68836381Ssklower 		/*
68936381Ssklower 		 *	We need to get the local nsap address.
69036381Ssklower 		 *	First, route to the destination. This will provide us with
69136381Ssklower 		 *	an ifp. Second, determine which local address linked on
69236381Ssklower 		 *	that ifp is appropriate
69336381Ssklower 		 */
69436381Ssklower 		struct sockaddr_iso	*first_hop;		/* filled by clnp_route */
69536381Ssklower 		struct iso_addr	*localaddr, *clnp_srcaddr();
69636381Ssklower 
69736381Ssklower 		if (error = clnp_route(&copcb->co_faddr,
69836381Ssklower 			&((struct isopcb *)copcb)->isop_route, /* flags */0,
69936381Ssklower 			&first_hop, &copcb->co_ifp))
70036381Ssklower 			goto bad;
70136381Ssklower 
70236381Ssklower 		/* determine local address based upon ifp */
70336381Ssklower 		if ((localaddr = clnp_srcaddr(copcb->co_ifp,
70436381Ssklower 				&first_hop->siso_addr)) == NULL) {
70536381Ssklower 			error = ENETUNREACH;
70636381Ssklower 			goto bad;
70736381Ssklower 		}
70836381Ssklower 		copcb->co_laddr.siso_family = AF_ISO;
70936381Ssklower 		copcb->co_laddr.siso_addr = *localaddr;
71036381Ssklower #else
71136381Ssklower 		/* Foreign addr isn't me (lpb). If still don't have an ifp or have
71236381Ssklower 		 * an ifp but don't know its address, look for a route
71336381Ssklower 		 */
71436381Ssklower 		if( ifa = ifa_ifwithnet(&copcb->co_faddr) ) {
71536381Ssklower 			copcb->co_ifp =  ifa->ifa_ifp;
71636381Ssklower 			IFDEBUG(D_CCONN)
71736381Ssklower 				printf(" cons_connect withnet returns %s\n",
71836381Ssklower 										copcb->co_ifp->if_name);
71936381Ssklower 			ENDDEBUG
72036381Ssklower 		} else {
72136381Ssklower 			printf("cons PANIC: connect: can't find SNPA \n");
72236381Ssklower 			error = ENETUNREACH;
72336381Ssklower 			goto bad;
72436381Ssklower 		}
72536381Ssklower #endif	PHASEONE
72636381Ssklower 	}
72736381Ssklower #ifndef	PHASEONE
72836381Ssklower 	if( ifa == (struct ifaddr *)0 ) {
72936381Ssklower 		struct ifaddr * iso_ifwithidi();
73036381Ssklower 
73136381Ssklower 		if( ifa = iso_ifwithidi(&copcb->co_faddr) ) {
73236381Ssklower 			copcb->co_ifp =  ifa->ifa_ifp;
73336381Ssklower 			IFDEBUG(D_CCONN)
73436381Ssklower 				printf(" cons_connect withnet returns %s\n",
73536381Ssklower 										copcb->co_ifp->if_name);
73636381Ssklower 			ENDDEBUG
73736381Ssklower 		} else {
73836381Ssklower 			printf("cons PANIC: connect: can't find SNPA \n");
73936381Ssklower 			error = ENETUNREACH;
74036381Ssklower 			goto bad;
74136381Ssklower 		}
74236381Ssklower 	}
74336381Ssklower 	bcopy((caddr_t)&ifa->ifa_addr, (caddr_t)&copcb->co_laddr,
74436381Ssklower 		sizeof(struct sockaddr));
74536381Ssklower #endif	PHASEONE
74636381Ssklower 
74736381Ssklower 	copcb->co_state = CONNECTING;
74836381Ssklower 
74936381Ssklower 	ASSERT( copcb->co_ifp != (struct ifnet *) 0);
75036381Ssklower 	if ( copcb->co_ifp == (struct ifnet *)0 ) {
75136381Ssklower 		error = ENETUNREACH;
75236381Ssklower 		goto bad;
75336381Ssklower 	}
75436381Ssklower 
75536381Ssklower 	m = m_getclr(M_DONTWAIT, MT_XCONN);
75636381Ssklower 	if( !m ) {
75736381Ssklower 		copcb->co_ifp->if_oerrors ++;
75836381Ssklower 		error = ENOBUFS;
75936381Ssklower 		goto bad;
76036381Ssklower 	}
76136381Ssklower 	m->m_len = sizeof(struct eicon_request);
76236381Ssklower 
76336381Ssklower 	ecnrq = mtod(m, struct eicon_request *);
76436381Ssklower 
76536381Ssklower 	copcb->co_myself = copcb;
76636381Ssklower 	ecnrq->e_pcb = (caddr_t)copcb;
76736381Ssklower #ifdef ARGO_DEBUG
76836381Ssklower 	LAST_CALL_PCB = (unsigned) ecnrq->e_pcb;
76936381Ssklower #endif ARGO_DEBUG
77036381Ssklower 	ecnrq->e_cmd = ECN_CALL;
77136381Ssklower 	ecnrq->e_vc = 0; /* mbz ? */
77236381Ssklower 	ecnrq->e_info = 0; /* mbz */
77336381Ssklower 
77436381Ssklower 	/* get data buffer */
77536381Ssklower 	{ 	struct mbuf *n;
77636381Ssklower 
77736381Ssklower 		MGET(n, M_DONTWAIT, MT_XCONN);
77836381Ssklower 		if( n==MNULL ) {
77936381Ssklower 			copcb->co_ifp->if_oerrors ++;
78036381Ssklower 			error = ENOBUFS;
78136381Ssklower 			goto bad;
78236381Ssklower 		}
78336381Ssklower 		e_data(ecnrq) = n; /* e_data is really dtom(ecnrq)->m_next */
78436381Ssklower 	}
78536381Ssklower 
78636381Ssklower 	IFDEBUG(D_CCONN)
78736381Ssklower 		printf(
78836381Ssklower 		"calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
78936381Ssklower 			&copcb->co_laddr, &copcb->co_faddr,
79036381Ssklower 			copcb->co_proto->pr_protocol,
79136381Ssklower 			e_data(ecnrq),
79236381Ssklower 			copcb->co_flags & CONSF_XTS);
79336381Ssklower 	ENDDEBUG
79436381Ssklower 	if( error = make_partial_x25_packet( copcb, e_data(ecnrq)) ) {
79536381Ssklower 		copcb->co_ifp->if_oerrors ++;
79636381Ssklower 		m_freem(m);
79736381Ssklower 		goto bad;
79836381Ssklower 	}
79936381Ssklower 
80036381Ssklower 	IncStat(co_call);
80136381Ssklower 
80236381Ssklower 	IFDEBUG(D_CDUMP_REQ)
80336381Ssklower 		printf("cons_connect ecnrq:\n");
80436381Ssklower 		dump_buf(ecnrq, sizeof(*ecnrq));
80536381Ssklower 	ENDDEBUG
80636381Ssklower 
80736381Ssklower 	ASSERT( copcb->co_channel == 0);
80836381Ssklower 	if( copcb->co_channel != 0) {
80936381Ssklower 		printf("cons_connect PANIC: channel is 0x%x\n", copcb->co_channel);
81036381Ssklower 	}
81136381Ssklower 
81236381Ssklower 	error = choose_output(copcb->co_ifp, m, copcb->co_flags & CONSF_LOOPBACK);
81336381Ssklower 
81436381Ssklower 	switch( error ) {
81536381Ssklower 		case 0: /* ok */
81636381Ssklower 			break;
81736381Ssklower 		default: /* problem */
81836381Ssklower 			printf("cons: PANIC: if_output returns 0x%x\n", error);
81936381Ssklower 			cons_clear_and_detach( copcb, DONTCLEAR, PRC_ROUTEDEAD);
82036381Ssklower 	}
82136381Ssklower 
82236381Ssklower bad:
82336381Ssklower 	IFTRACE(D_CDATA)
82436381Ssklower 		tptrace( TPPTmisc,
82536381Ssklower 		"cons_connect: choose (copcb m) returned  error\n",
82636381Ssklower 			copcb, m, error, 0);
82736381Ssklower 	ENDTRACE
82836381Ssklower 	return error;
82936381Ssklower }
83036381Ssklower 
83136381Ssklower /*
83236381Ssklower  * NAME:	cons_find()
83336381Ssklower  * CALLED FROM:
83436381Ssklower  *	cosns_output1() thus:
83536381Ssklower  *		cons_find( CONSF_DGM, dst, proto, 0, 0) where
83636381Ssklower  *		proto is one of { TP_proto, CLNP_proto }
83736381Ssklower  * FUNCTION and ARGUMENTS:
83836381Ssklower  *  Looks through list of connections for the destination,
83936381Ssklower  *  for one marked for the use indicated by flags.
84036381Ssklower  *  If none found, opens up a new connection.
84136381Ssklower  *   These connections will be eliminated by :
84236381Ssklower  *     a) slowtimo timer, or
84336381Ssklower  *     b) the need for a new connection, when we've run out of resources.
84436381Ssklower  *  The argument flags describes the type of pcb we want - may
84536381Ssklower  *  specify multiplexing-ok, datagram use, etc.
84636381Ssklower  *  The argument proto points the the higher layer protocol that
84736381Ssklower  *  will be using this connection.
84836381Ssklower  * RETURN VALUE:
84936381Ssklower  *  returns a ptr to a pcb whose characteristics match those
85036381Ssklower  *  described by (flags, proto)
85136381Ssklower  */
85236381Ssklower 
85336381Ssklower Static struct cons_pcb *
85436381Ssklower cons_find(flags, dst, proto, addl_criteria, mask)
85536381Ssklower 	u_int flags, mask;
85636381Ssklower 	struct sockaddr_iso *dst;
85736381Ssklower 	struct protosw *proto;
85836381Ssklower 	int	(*addl_criteria)();
85936381Ssklower {
86036381Ssklower 	register struct cons_pcb *copcb;
86136381Ssklower 	register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist;
86236381Ssklower 	int s = splnet(); /* or whatever, for the device! */
86336381Ssklower 	struct dte_addr dest_dte;
86436381Ssklower 	int	 dummy;
86536381Ssklower 
86636381Ssklower 	struct	copcb_descriptor {
86736381Ssklower 		int	xd_qlen;
86836381Ssklower 		struct cons_pcb *xd_pcb;
86936381Ssklower 	} next_best = {
87036381Ssklower 		0, (struct cons_pcb *)0
87136381Ssklower 	};
87236381Ssklower 
87336381Ssklower 	IFDEBUG(D_CFIND)
87436381Ssklower 		printf("cons_find( flags 0x%x proto 0x%x) ", flags, proto);
87536381Ssklower 	ENDDEBUG
87636381Ssklower 
87736381Ssklower 	if ( iso_8208snparesolve(dst, &dest_dte, &dummy)) {
87836381Ssklower 		ASSERT(0);
87936381Ssklower 		return (struct cons_pcb *)0; /* error */
88036381Ssklower 	}
88136381Ssklower 	ASSERT(dummy == sizeof(struct dte_addr));
88236381Ssklower 
88336381Ssklower 	for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) {
88436381Ssklower 		copcb = (struct cons_pcb *)copcb->co_next;
88536381Ssklower 		while (copcb !=  *copcblist) {
88636381Ssklower 			IFDEBUG(D_CFIND)
88736381Ssklower 				printf(
88836381Ssklower 				"cons_find: chan 0x%x flags 0x%x proto 0x%x state 0x%x \n",
88936381Ssklower 					copcb->co_channel, copcb->co_flags, copcb->co_proto,
89036381Ssklower 					copcb->co_state);
89136381Ssklower 			ENDDEBUG
89236381Ssklower 			/*
89336381Ssklower 			 * if flags is a subset of the bits in co_flags, it will suffice
89436381Ssklower 			 */
89536381Ssklower 			if( ((copcb->co_flags & flags) == flags ) &&
89636381Ssklower 				/* PHASE2: where do we get the mask if we use nsaps ????
89736381Ssklower 				 * If dte addresses are used, then use
89836381Ssklower 				 * nibble compare otherwise...???
89936381Ssklower 				 */
90036381Ssklower #ifdef notdef
90136381Ssklower 				iso_addrmatch1(&(copcb->co_faddr.siso_addr), &(dst->siso_addr))
90236381Ssklower #else
90336381Ssklower 				dest_dte.dtea_niblen == copcb->co_peer_dte.dtea_niblen &&
90436381Ssklower 				nibble_match( (char *)&(copcb->co_peer_dte.dtea_addr),
90536381Ssklower 					HIGH_NIBBLE, (char *)dest_dte.dtea_addr,
90636381Ssklower 					HIGH_NIBBLE, dest_dte.dtea_niblen)
90736381Ssklower #endif notdef
90836381Ssklower 				&&
90936381Ssklower 				(copcb->co_proto == proto)  &&
91036381Ssklower 				(copcb->co_state >= MIN_USABLE_STATE)) {
91136381Ssklower 					IFDEBUG(D_CFIND)
91236381Ssklower 						printf(
91336381Ssklower 						"cons_find: add'l criteria...\n" );
91436381Ssklower 					ENDDEBUG
91536381Ssklower 					if((copcb->co_state != OPEN) &&
91636381Ssklower 						(next_best.xd_qlen > copcb->co_pending.ifq_len)) {
91736381Ssklower 						next_best.xd_pcb = copcb;
91836381Ssklower 						next_best.xd_qlen = copcb->co_pending.ifq_len;
91936381Ssklower 					}
92036381Ssklower 					if( !addl_criteria || (*addl_criteria)(copcb, mask) ) {
92136381Ssklower 						goto found; /* have to break out of 2 loops */
92236381Ssklower 					}
92336381Ssklower 				}
92436381Ssklower 			copcb = (struct cons_pcb *)copcb->co_next ;
92536381Ssklower 		}
92636381Ssklower 	}
92736381Ssklower #ifdef notdef
92836381Ssklower 	/* TODO:
92936381Ssklower 	 * have a limit of the number of calls per desitination.
93036381Ssklower 	 * If we didn't find one already open AND our limit for this
93136381Ssklower 	 * destination hasn't been reached, return 0 'cause
93236381Ssklower 	 * then the caller will open a new one.
93336381Ssklower 	 * Otherwise return next_best.
93436381Ssklower 	 * To do this we need some sort of per-destination info.
93536381Ssklower 	 * Could go into the directory service. Oh, grotesque.
93636381Ssklower 	 */
93736381Ssklower #endif notdef
93836381Ssklower 	if( copcb == (struct cons_pcb *)0 ) {
93936381Ssklower 		copcb = next_best.xd_pcb; /* may be zero too */
94036381Ssklower 		IFDEBUG(D_CFIND)
94136381Ssklower 			printf("NEXT_BEST! \n");
94236381Ssklower 			dump_copcb(copcb, "find: next_best");
94336381Ssklower 		ENDDEBUG
94436381Ssklower 	}
94536381Ssklower found:
94636381Ssklower 
94736381Ssklower 	splx(s);
94836381Ssklower 
94936381Ssklower 	IFDEBUG(D_CFIND)
95036381Ssklower 		printf("returns 0x%x \n", copcb);
95136381Ssklower 	ENDDEBUG
95236381Ssklower 	return copcb;
95336381Ssklower }
95436381Ssklower 
95536381Ssklower 
95636381Ssklower /*
95736381Ssklower  * NAME:	issue_clear_req()
95836381Ssklower  * CALLED FROM:
95936381Ssklower  *	cons_clear() and wherever we get an error from x.25 that makes us
96036381Ssklower  *  	want to close the vc on which it came, but don't have
96136381Ssklower  *		a copcb assoc. with that vc.
96236381Ssklower  * FUNCTION and ARGUMENTS:
96336381Ssklower  *  Creates an eicon_request for a clear request, returns it in an mbuf.
96436381Ssklower  *  (chan) is the channel on which to do the clear, (reason) is the
96536381Ssklower  *  clear reason(diagnostic).
96636381Ssklower  * RETURN VALUE:
96736381Ssklower  *  returns E*
96836381Ssklower  */
96936381Ssklower Static int
97036381Ssklower issue_clear_req(chan, reason, ifp, loop)
97136381Ssklower 	u_char 			chan, reason;
97236381Ssklower 	struct	ifnet 	*ifp;
97336381Ssklower 	int				loop;
97436381Ssklower {
97536381Ssklower 	register struct mbuf 			*m;
97636381Ssklower 	register struct mbuf 			*cdm;
97736381Ssklower 	register struct eicon_request 	*ecnrq;
97836381Ssklower 	struct e_clear_data 			*ecd;
97936381Ssklower 
98036381Ssklower 	IFDEBUG(D_CCONN)
98136381Ssklower 		printf("issue_clear_req(0x%x, 0x%x, 0x%x, 0x%x)\n",
98236381Ssklower 			chan, reason, ifp, loop);
98336381Ssklower 	ENDDEBUG
98436381Ssklower 	m = m_getclr(M_DONTWAIT, MT_XCLOSE);
98536381Ssklower 	if( !m ) {
98636381Ssklower 		return ENOBUFS;
98736381Ssklower 	}
98836381Ssklower 	m->m_len = sizeof(struct eicon_request);
98936381Ssklower 	ecnrq = mtod(m, struct eicon_request *);
99036381Ssklower 	ecnrq->e_cmd = ECN_CLEAR;
99136381Ssklower 	ecnrq->e_vc = chan & 0xff;
99236381Ssklower 	/*
99336381Ssklower 	 *  see p. 149 of 8208 for reasons (diagnostic codes)
99436381Ssklower 	 */
99536381Ssklower 	MGET(cdm, M_DONTWAIT, MT_XCLOSE);
99636381Ssklower 	if( !cdm ) {
99736381Ssklower 		m_freem(m);
99836381Ssklower 		return ENOBUFS;
99936381Ssklower 	}
100036381Ssklower 	cdm->m_len = sizeof(struct e_clear_data); /* cause, diagnostic */
100136381Ssklower 	e_data(ecnrq) = cdm;
100236381Ssklower 
100336381Ssklower 	ecd = mtod(cdm, struct e_clear_data *);
100436381Ssklower 	ecd->ecd_cause = 0x0; /* DTE initiated, diagnostic tells more */
100536381Ssklower 	ecd->ecd_diagnostic = (u_char)reason;
100636381Ssklower 
100736381Ssklower 	IncStat(co_clear_out);
100836381Ssklower 	return choose_output(ifp, m, loop);
100936381Ssklower }
101036381Ssklower 
101136381Ssklower 
101236381Ssklower /*
101336381Ssklower  * NAME:	cons_clear()
101436381Ssklower  * CALLED FROM:
101536381Ssklower  *  cons_usrreq(), PRU_DISCONNECT,
101636381Ssklower  *  cons_slowtimo(), cons_free_lru()
101736381Ssklower  * FUNCTION and ARGUMENTS:
101836381Ssklower  *	Builds a clear request for the connection represented by copcb,
101936381Ssklower  *  gives it to the device.
102036381Ssklower  * ECN_CLEAR(request) takes e_vc only, returns adr_status.
102136381Ssklower  * RETURN VALUE:
102236381Ssklower  */
102336381Ssklower 
102436381Ssklower Static int
102536381Ssklower cons_clear( copcb, reason)
102636381Ssklower 	register struct cons_pcb *copcb;
102736381Ssklower 	u_char					reason;
102836381Ssklower {
102936381Ssklower 	register struct mbuf			*m;
103036381Ssklower 	int								error;
103136381Ssklower 
103236381Ssklower 	IFDEBUG(D_CCONN)
103336381Ssklower 		printf("cons_clear(0x%x, 0x%x)\n", copcb, reason);
103436381Ssklower 	ENDDEBUG
103536381Ssklower 	if( !copcb) {
103636381Ssklower 		printf("cons PANIC: clear: No copcb\n");
103736381Ssklower 		return 0;
103836381Ssklower 	}
103936381Ssklower 	while( copcb->co_pending.ifq_len > 0 ) {
104036381Ssklower 		register int s = splimp();
104136381Ssklower 
104236381Ssklower 		IF_DEQUEUE( &copcb->co_pending, m );
104336381Ssklower 		splx(s);
104436381Ssklower 		m_freem(m);
104536381Ssklower 	}
104636381Ssklower 	if( (copcb->co_state == CLOSED) || (copcb->co_state == CLOSING) )
104736381Ssklower 		return 0;
104836381Ssklower 
104936381Ssklower #ifdef ARGO_DEBUG
105036381Ssklower 	if( copcb->co_state == CONNECTING) {
105136381Ssklower 		IFDEBUG(D_CCONN)
105236381Ssklower 			dump_copcb(copcb, "clear");
105336381Ssklower 		ENDDEBUG
105436381Ssklower 	} else if( (copcb->co_channel == 0) || (copcb->co_channel == X_NOCHANNEL) ) {
105536381Ssklower 		IFDEBUG(D_CCONN)
105636381Ssklower 			dump_copcb(copcb, "clear");
105736381Ssklower 		ENDDEBUG
105836381Ssklower 	}
105936381Ssklower #endif ARGO_DEBUG
106036381Ssklower 
106136381Ssklower 	copcb->co_state = CLOSING;
106236381Ssklower 
106336381Ssklower 	IFDEBUG(D_CCONN)
106436381Ssklower 		printf("cons_clear: channel 0x%x copcb 0x%x dst: ",
106536381Ssklower 			copcb->co_channel,  copcb);
106636381Ssklower 		dump_isoaddr(&copcb->co_faddr);
106736381Ssklower 		dump_copcb(copcb, "clear");
106836381Ssklower 	ENDDEBUG
106936381Ssklower 
107036381Ssklower 	error = issue_clear_req(copcb->co_channel, reason, copcb->co_ifp,
107136381Ssklower 		copcb->co_flags & CONSF_LOOPBACK);
107236381Ssklower 	copcb->co_channel = X_NOCHANNEL;
107336381Ssklower 	copcb->co_state = CLOSED;
107436381Ssklower 	return error;
107536381Ssklower }
107636381Ssklower 
107736381Ssklower 
107836381Ssklower /*
107936381Ssklower  * NAME:	cons_senddata()
108036381Ssklower  * CALLED FROM:
108136381Ssklower  *  cons_output(), consoutput(), consintr()
108236381Ssklower  * FUNCTION and ARGUMENTS:
108336381Ssklower  *	issued a data (write) command - if the device isn't ready,
108436381Ssklower  *  it enqueues the command on a per-connection queue.
108536381Ssklower  * RETURN VALUE:
108636381Ssklower  *	ENOBUFS
108736381Ssklower  *  Is responsible for freeing m0!
108836381Ssklower  *
108936381Ssklower  * ECN_SEND (write)
109036381Ssklower  */
109136381Ssklower 
109236381Ssklower Static int
109336381Ssklower cons_senddata(copcb, m0)
109436381Ssklower 	register struct cons_pcb *copcb;
109536381Ssklower 	struct mbuf *m0;
109636381Ssklower {
109736381Ssklower 	register struct mbuf *m;
109836381Ssklower 	register struct eicon_request *ecnrq;
109936381Ssklower 	int s;
110036381Ssklower 
110136381Ssklower 	IFDEBUG(D_CDATA)
110236381Ssklower 		printf("cons_senddata( 0x%x, m 0x%x ) chan 0x%x",
110336381Ssklower 			copcb, m0, copcb->co_channel );
110436381Ssklower 		printf(" co_lport 0x%x\n", copcb->co_lport);
110536381Ssklower 	ENDDEBUG
110636381Ssklower 	if( m0 == MNULL )
110736381Ssklower 		return;
110836381Ssklower 	ASSERT( m0->m_len > 0);
110936381Ssklower 	if( m0->m_len <= 0) {
111036381Ssklower 		printf("cons_senddata : BAD MLEN? 0x%x", m0->m_len);
111136381Ssklower 	}
111236381Ssklower 
111336381Ssklower 	touch(copcb);
111436381Ssklower 
111536381Ssklower 	if( (copcb->co_state == CONNECTING) || (copcb->co_state == ACKWAIT) ) {
111636381Ssklower 		IFDEBUG(D_CDATA)
111736381Ssklower 			printf("senddata PUTTING ON PENDING Q copcb 0x%x state 0x%x\n",
111836381Ssklower 				copcb, copcb->co_state);
111936381Ssklower 		ENDDEBUG
112036381Ssklower 		s = splimp();
112136381Ssklower 		if (IF_QFULL(&copcb->co_pending)) {
112236381Ssklower 			IFDEBUG(D_CDATA)
112336381Ssklower 				printf("senddata DROPPING m0 0x%x\n",  m0);
112436381Ssklower 			ENDDEBUG
112536381Ssklower 			IF_DROP(&copcb->co_pending);
112636381Ssklower 			if(copcb->co_ifp) {
112736381Ssklower 				copcb->co_ifp->if_snd.ifq_drops ++;
112836381Ssklower 			}
112936381Ssklower 			IncStat(co_Xdrops);
113036381Ssklower 			copcb->co_ifp->if_oerrors ++;
113136381Ssklower 			splx(s);
113236381Ssklower 			m_freem (m0);
113336381Ssklower 
113436381Ssklower 			if( copcb->co_proto  && copcb->co_proto->pr_ctlinput ) {
113536381Ssklower 				(*copcb->co_proto->pr_ctlinput)(PRC_QUENCH,
113636381Ssklower 				(struct sockaddr_iso *)&copcb->co_faddr,
113736381Ssklower 				(caddr_t)copcb);
113836381Ssklower 
113936381Ssklower 				return 0;
114036381Ssklower 			} else
114136381Ssklower 				return E_CO_QFULL;
114236381Ssklower 		}
114336381Ssklower 		IFDEBUG(D_CDATA)
114436381Ssklower 			printf("Putting 0x%x on 0x%x->pending Q\n", m0, copcb);
114536381Ssklower 		ENDDEBUG
114636381Ssklower 		IF_ENQUEUE( &copcb->co_pending, m0 );
114736381Ssklower 		splx(s);
114836381Ssklower 		return 0;
114936381Ssklower 	}
115036381Ssklower 	if(copcb->co_channel == 0 ) {
115136381Ssklower 		return E_CO_CHAN;
115236381Ssklower 	}
115336381Ssklower 	ASSERT( copcb->co_state == OPEN);
115436381Ssklower 
115536381Ssklower 	m = m_getclr(M_DONTWAIT, MT_XDATA);
115636381Ssklower 	if( !m ) {
115736381Ssklower 		copcb->co_ifp->if_oerrors ++;
115836381Ssklower 		m_freem (m0);
115936381Ssklower 		return ENOBUFS;
116036381Ssklower 	}
116136381Ssklower 	m->m_len = sizeof(struct eicon_request);
116236381Ssklower 	ecnrq = mtod(m, struct eicon_request *);
116336381Ssklower 	ecnrq->e_pcb = (caddr_t)copcb;
116436381Ssklower 	if( copcb->co_myself != copcb ) {
116536381Ssklower 		struct mbuf *mm;
116636381Ssklower 		/* TODO: REMOVE THIS DEBUGGING HACK */
116736381Ssklower 		ASSERT(0);
116836381Ssklower 		printf("BAD e_pcb from HL (0x%x,0x%x)\n", copcb, copcb->co_myself);
116936381Ssklower 		mm = dtom( copcb );
117036381Ssklower 		if(mm->m_type == MT_FREE)
117136381Ssklower 			printf("FREED MBUF!\n");
117236381Ssklower 		return ENETDOWN;
117336381Ssklower 	}
117436381Ssklower 	ASSERT( copcb->co_channel != 0);
117536381Ssklower 	ASSERT( copcb->co_channel != X_NOCHANNEL);
117636381Ssklower 	ecnrq->e_vc = (copcb->co_channel & 0xff);
117736381Ssklower 	ecnrq->e_cmd = ECN_SEND;
117836381Ssklower 	e_data(ecnrq) = m0;
117936381Ssklower 	{
118036381Ssklower 		/* TODO: REMOVE THIS DEBUGGING HACK */
118136381Ssklower 		struct mbuf *thedata = e_data(ecnrq);
118236381Ssklower 		u_int *firstint = mtod( thedata, u_int *);
118336381Ssklower 
118436381Ssklower 		if( (*firstint & 0xff000000) != 0x81000000 ) {
118536381Ssklower 			/* not clnp */
118636381Ssklower 			switch( ((*firstint) & 0x00ff0000) >> 20 ) {
118736381Ssklower 			case 0x1:
118836381Ssklower 			case 0x2:
118936381Ssklower 			case 0x3:
119036381Ssklower 			case 0x6:
119136381Ssklower 			case 0x7:
119236381Ssklower 			case 0x8:
119336381Ssklower 			case 0xc:
119436381Ssklower 			case 0xd:
119536381Ssklower 			case 0xe:
119636381Ssklower 			case 0xf:
119736381Ssklower 				break;
119836381Ssklower 			default:
119936381Ssklower 				printf(" ECN_SEND! BAD DATA\n" );
120036381Ssklower 				dump_buf( thedata, 20 + 12 );
120136381Ssklower 				m_freem( m0 );
120236381Ssklower 				return ENETDOWN;
120336381Ssklower 			}
120436381Ssklower 		}
120536381Ssklower 	}
120636381Ssklower 
120736381Ssklower 	ecnrq->e_info = 0;
120836381Ssklower 
120936381Ssklower 	IFDEBUG(D_CDUMP_REQ)
121036381Ssklower 		printf("senddata ecnrq\n");
121136381Ssklower 	ENDDEBUG
121236381Ssklower 	IncStat(co_send);
121336381Ssklower 
121436381Ssklower 	ASSERT( copcb->co_state == OPEN );
121536381Ssklower 	copcb->co_state = ACKWAIT;
121636381Ssklower 
121736381Ssklower 	if( copcb->co_myself != copcb ) {
121836381Ssklower 		struct mbuf *mm;
121936381Ssklower 		/* TODO: REMOVE this and all mention of co_myself */
122036381Ssklower 		ASSERT(0);
122136381Ssklower 		printf("BAD e_pcb TO THE BOARD ecn (0x%x) cmd 0x%x\n",
122236381Ssklower 			ecnrq->e_pcb, ecnrq->e_cmd);
122336381Ssklower 		mm = dtom( copcb );
122436381Ssklower 		if(mm->m_type == MT_FREE)
122536381Ssklower 			printf("FREED MBUF!\n");
122636381Ssklower 		dump_buf (ecnrq, sizeof (*ecnrq));
122736381Ssklower 		return ENETDOWN;
122836381Ssklower 	}
122936381Ssklower 
123036381Ssklower 	return
123136381Ssklower 	  choose_output(copcb->co_ifp, dtom(ecnrq), copcb->co_flags&CONSF_LOOPBACK);
123236381Ssklower }
123336381Ssklower 
123436381Ssklower /*
123536381Ssklower  * NAME:	cons_send_on_vc()
123636381Ssklower  * CALLED FROM:
123736381Ssklower  *  tp_error_emit()
123836381Ssklower  * FUNCTION and ARGUMENTS:
123936381Ssklower  *  Take a packet(m0), of length (datalen) from tp and
124036381Ssklower  * send it on the channel (chan).
124136381Ssklower  *
124236381Ssklower  * RETURN VALUE:
124336381Ssklower  *  whatever (E*) is returned form the net layer output routine.
124436381Ssklower  */
124536381Ssklower int
124636381Ssklower cons_send_on_vc(chan, m, datalen)
124736381Ssklower 	int				chan;
124836381Ssklower 	struct mbuf 	*m;
124936381Ssklower 	int				datalen;
125036381Ssklower {
125136381Ssklower 	struct cons_pcb	*copcb = (struct cons_pcb *)0;
125236381Ssklower 
125336381Ssklower 	if(m == MNULL)
125436381Ssklower 		return;
125536381Ssklower 
125636381Ssklower 	if((copcb =
125736381Ssklower #ifdef ARGO_DEBUG
125836381Ssklower 		cons_chan_to_pcb( chan, __LINE__ )
125936381Ssklower #else ARGO_DEBUG
126036381Ssklower 		cons_chan_to_pcb( chan )
126136381Ssklower #endif ARGO_DEBUG
126236381Ssklower 			) == (struct cons_pcb *)0 )
126336381Ssklower 		return E_CO_CHAN;
126436381Ssklower 	IFDEBUG(D_CCONS)
126536381Ssklower 		printf("cons_send_on_vc m 0x%x m_len 0x%x\n", m, m->m_len);
126636381Ssklower 	ENDDEBUG
126736381Ssklower 	return cons_senddata( copcb, m);
126836381Ssklower }
126936381Ssklower 
127036381Ssklower /*
127136381Ssklower  * NAME:	cons_output()
127236381Ssklower  * CALLED FROM:
127336381Ssklower  *  tpiso_output(), can have whatever interface we want it to...
127436381Ssklower  *  tpiso_output() decides whether to give a packet to CLNP or to
127536381Ssklower  *  cons; if the latter, it calls this routine.
127636381Ssklower  * FUNCTION and ARGUMENTS:
127736381Ssklower  *  tp has alloc-ed a pcb - but it may not be open.
127836381Ssklower  *  some classes of tp may allow multiplexing, in which
127936381Ssklower  *  case, you may choose to send the data on ANOTHER cons connection.
128036381Ssklower  *  This decides which net connection to use, opens one if necessary.
128136381Ssklower  *  Then it sends the data.
128236381Ssklower  */
128336381Ssklower 
128436381Ssklower cons_output(isop, m, len, isdgm)
128536381Ssklower 	struct isopcb 	*isop;
128636381Ssklower 	struct mbuf 	*m;
128736381Ssklower 	int 			len;
128836381Ssklower 	int				isdgm;
128936381Ssklower {
129036381Ssklower 	struct cons_pcb	*copcb = (struct cons_pcb *)0;
129136381Ssklower 	int				error;
129236381Ssklower 	int 			s = splnet();
129336381Ssklower 
129436381Ssklower 	IFDEBUG(D_CCONS)
129536381Ssklower 		printf("cons_output( isop 0x%x, m 0x%x, len 0x%x, dgm 0x%x )\n",
129636381Ssklower 			isop,m,len, isdgm);
129736381Ssklower 	ENDDEBUG
129836381Ssklower 
129936381Ssklower 	if( m == MNULL )
130036381Ssklower 		return 0;
130136381Ssklower 	ASSERT(m->m_len > 0);
130236381Ssklower 	if( isdgm ) {
130336381Ssklower 		error = cosns_output1(0, m, &isop->isop_faddr, TP_proto, isop);
130436381Ssklower 		IFDEBUG(D_CDATA)
130536381Ssklower 			if(error)
130636381Ssklower 			printf("cosns_output1 RETURNS ERROR 0x%x\n", error);
130736381Ssklower 		ENDDEBUG
130836381Ssklower 		return error;
130936381Ssklower 	}
131036381Ssklower 
131136381Ssklower 	if( isop->isop_chanmask  || isop->isop_negchanmask) {
131236381Ssklower 		register int	mask = isop->isop_chanmask;
131336381Ssklower 		register int	chan = 1;
131436381Ssklower 
131536381Ssklower 		if( mask == 0)
131636381Ssklower 			mask = isop->isop_negchanmask;
131736381Ssklower 
131836381Ssklower 		for ( chan=1; (mask & 1)==0; chan++,mask>>=1 ) ;
131936381Ssklower 
132036381Ssklower 		if( isop->isop_chanmask == 0 )
132136381Ssklower 			chan = -chan;
132236381Ssklower 
132336381Ssklower 		IFDEBUG(D_CCONS)
132436381Ssklower 			printf(
132536381Ssklower 			"cons_output: isop 0x%x cmask 0x%x negmask 0x%x, chan 0x%x\n",
132636381Ssklower 			isop, isop->isop_chanmask, isop->isop_negchanmask, chan);
132736381Ssklower 		ENDDEBUG
132836381Ssklower 		ASSERT( chan != 0);
132936381Ssklower #ifdef ARGO_DEBUG
133036381Ssklower 		copcb = cons_chan_to_pcb( chan, __LINE__ );
133136381Ssklower #else ARGO_DEBUG
133236381Ssklower 		copcb = cons_chan_to_pcb( chan );
133336381Ssklower #endif ARGO_DEBUG
133436381Ssklower 	}
133536381Ssklower 	if( copcb == (struct cons_pcb *)0 ) {
133636381Ssklower 		/* get a new one */
133736381Ssklower 
133836381Ssklower 		if(( error = cons_pcballoc(&dummysocket, &cons_isopcb, CONSF_OCRE,
133936381Ssklower 												TP_proto, &copcb)) != EOK ) {
134036381Ssklower 			IFDEBUG(D_CCONS)
134136381Ssklower 				printf("cosns_output: no copcb; returns 0x%x\n", error);
134236381Ssklower 			ENDDEBUG
134336381Ssklower 			(void) m_freem (m);
134436381Ssklower 			splx(s);
134536381Ssklower 			return error ;
134636381Ssklower 		}
134736381Ssklower 
134836381Ssklower 		/* abbreviated form of iso_pcbconnect(): */
134936381Ssklower 		bcopy((caddr_t)&isop->isop_faddr, (caddr_t)&copcb->co_faddr,
135036381Ssklower 									sizeof(struct sockaddr_iso));
135136381Ssklower 
135236381Ssklower 		if ( error = cons_connect( copcb ) ) { /* if it doesn't work */
135336381Ssklower 			/* oh, dear, throw packet away */
135436381Ssklower 			remque((struct isopcb *)copcb);
135536381Ssklower 			(void) m_free(dtom(copcb));
135636381Ssklower 			(void) m_freem( m );
135736381Ssklower 			splx(s);
135836381Ssklower 			return error;
135936381Ssklower 		}
136036381Ssklower 
136136381Ssklower 		if( copcb->co_socket ) {
136236381Ssklower 			while( (copcb->co_state != OPEN) &&
136336381Ssklower 				!(error = copcb->co_socket->so_error) ) {
136436381Ssklower 				IFDEBUG(D_CCONS)
136536381Ssklower 					printf(
136636381Ssklower 	"SLEEP1 copcb 0x%x isop 0x%x state 0x%x chan 0x%x mask 0x%x neg 0x%x\n",
136736381Ssklower 						copcb, isop, copcb->co_state, copcb->co_channel,
136836381Ssklower 						((struct isopcb *)isop)->isop_chanmask,
136936381Ssklower 						((struct isopcb *)isop)->isop_negchanmask
137036381Ssklower 					);
137136381Ssklower 				ENDDEBUG
137236381Ssklower 				sleep( (caddr_t)&copcb->co_state, PZERO+1 );
137336381Ssklower 				IFDEBUG(D_CCONS)
137436381Ssklower 					printf("AFTER SLEEP 1 chan 0x%x chanmask 0x%x negchanmask 0x%x\n",
137536381Ssklower 						copcb->co_channel, isop->isop_chanmask,
137636381Ssklower 						isop->isop_negchanmask);
137736381Ssklower 				ENDDEBUG
137836381Ssklower 			}
137936381Ssklower 			if( !error )
138036381Ssklower 				SET_CHANMASK( isop, copcb->co_channel);
138136381Ssklower 		}
138236381Ssklower 
138336381Ssklower 	}
138436381Ssklower 
138536381Ssklower 	IFDEBUG(D_CDATA)
138636381Ssklower 		printf("cons_output calling senddata(0x%x 0x%x)\n", copcb, m);
138736381Ssklower 		ASSERT(m != MNULL);
138836381Ssklower 		ASSERT(m->m_len != 0);
138936381Ssklower 	ENDDEBUG
139036381Ssklower 
139136381Ssklower 	if( !error )
139236381Ssklower 		error =  cons_senddata( copcb, m);
139336381Ssklower 	splx(s);
139436381Ssklower 	return error;
139536381Ssklower }
139636381Ssklower 
139736381Ssklower /*
139836381Ssklower  * NAME:	cons_openvc()
139936381Ssklower  * CALLED FROM:
140036381Ssklower  *  TP when it decides to open a VC for TP 0
140136381Ssklower  * FUNCTION:
140236381Ssklower  *  opens a connection and stashes the pcb info in the socket
140336381Ssklower  *  substitute for iso_pcbconnect/ in_pcbconnect for the class 0 case
140436381Ssklower  *  only.
140536381Ssklower  */
140636381Ssklower int
140736381Ssklower cons_openvc(copcb, faddr, so)
140836381Ssklower 	struct cons_pcb 			*copcb;
140936381Ssklower 	struct	sockaddr_iso	*faddr;
141036381Ssklower 	struct	socket			*so;
141136381Ssklower {
141236381Ssklower 	int 					error = 0;
141336381Ssklower 	int 					s = splnet();
141436381Ssklower 	struct cons_pcb 		*cons_chan_to_pcb();
141536381Ssklower 
141636381Ssklower 
141736381Ssklower 	ASSERT( copcb->co_socket == so );
141836381Ssklower 	IFTRACE(D_CCONN)
141936381Ssklower 		tptrace(TPPTmisc, "cons_openvc( copcb so )\n", copcb, so, 0, 0);
142036381Ssklower 	ENDTRACE
142136381Ssklower 	IFDEBUG(D_CCONN)
142236381Ssklower 		printf("cons_openvc( copcb 0x%x, so 0x%x )\n", copcb,so);
142336381Ssklower 	ENDDEBUG
142436381Ssklower 	/*
142536381Ssklower 	 * initialize the copcb part of the isopcb
142636381Ssklower 	 */
142736381Ssklower 	copcb->co_ttl = copcb->co_init_ttl = X25_TTL;
142836381Ssklower 	copcb->co_flags = CONSF_OCRE;
142936381Ssklower 	copcb->co_proto = TP_proto;
143036381Ssklower 	copcb->co_pending.ifq_maxlen = CONS_IFQMAXLEN;
143136381Ssklower 
143236381Ssklower 	/* abbreviated form of iso_pcbconnect(): */
143336381Ssklower 	bcopy((caddr_t)faddr, (caddr_t)&copcb->co_faddr,
143436381Ssklower 								sizeof(struct sockaddr_iso));
143536381Ssklower 
143636381Ssklower 	ASSERT( copcb->co_socket == so );
143736381Ssklower 	if( error = cons_connect( copcb ) )
143836381Ssklower 		goto done;
143936381Ssklower 	while( (copcb->co_state != OPEN) && !(error = so->so_error) ) {
144036381Ssklower 		IFDEBUG(D_CCONS)
144136381Ssklower 			printf(
144236381Ssklower 		"SLEEP2 copcb 0x%x state 0x%x chan 0x%x mask 0x%x neg 0x%x\n",
144336381Ssklower 				copcb, copcb->co_state, copcb->co_channel,
144436381Ssklower 				copcb->co_chanmask,
144536381Ssklower 				copcb->co_negchanmask
144636381Ssklower 			);
144736381Ssklower 		ENDDEBUG
144836381Ssklower 		sleep( (caddr_t)&copcb->co_state, PZERO+2 );
144936381Ssklower 		IFDEBUG(D_CCONS)
145036381Ssklower 			printf("AFTER SLEEP2 chan 0x%x chanmask 0x%x negchanmask 0x%x\n",
145136381Ssklower 				copcb->co_channel, copcb->co_chanmask,
145236381Ssklower 				copcb->co_negchanmask);
145336381Ssklower 		ENDDEBUG
145436381Ssklower 	}
145536381Ssklower 	if( !error )
145636381Ssklower 		SET_CHANMASK( (struct isopcb *)copcb, copcb->co_channel);
145736381Ssklower done:
145836381Ssklower 	ASSERT( copcb->co_socket == so );
145936381Ssklower 	splx(s);
146036381Ssklower 
146136381Ssklower 	IFDEBUG(D_CCONN)
146236381Ssklower 		printf("cons_openvc: copcb 0x%x error 0x%x\n", copcb, error );
146336381Ssklower 	ENDDEBUG
146436381Ssklower 	return error;
146536381Ssklower }
146636381Ssklower 
146736381Ssklower /*
146836381Ssklower  * NAME:	cons_netcmd()
146936381Ssklower  * CALLED FROM:
147036381Ssklower  *  tp_route_to() when it decides to accept or reject an incoming
147136381Ssklower  *  connection it calls this.
147236381Ssklower  * FUNCTION:
147336381Ssklower  *  either closes the cons connection named by (channel)
147436381Ssklower  *  or associates the copcb with the channel #.
147536381Ssklower  *	and removes the old copcb from the tp_incoming_pending list.
147636381Ssklower  */
147736381Ssklower int
147836381Ssklower cons_netcmd(cmd, isop, channel, isdgm)
147936381Ssklower 	int 					cmd;
148036381Ssklower 	struct isopcb 			*isop;
148136381Ssklower 	int						channel;
148236381Ssklower {
148336381Ssklower 	int 					s = splnet();
148436381Ssklower 	int 					error = 0;
148536381Ssklower 	struct cons_pcb 		*copcb = (struct cons_pcb *)0;
148636381Ssklower 	struct cons_pcb 		*cons_chan_to_pcb();
148736381Ssklower 
148836381Ssklower 	IFTRACE(D_CCONN)
148936381Ssklower 		tptrace(TPPTmisc, "cons_netcmd( cmd isopcb channel isdgm)\n",
149036381Ssklower 			cmd,isop,channel, isdgm);
149136381Ssklower 	ENDTRACE
149236381Ssklower 	IFDEBUG(D_CCONN)
149336381Ssklower 		printf("cons_netcmd( cmd 0x%x, isop 0x%x, channel 0x%x, isdgm 0x%x)\n",
149436381Ssklower 			cmd,isop,channel, isdgm);
149536381Ssklower 		if( isop )
149636381Ssklower 			printf("cons_netcmd: isop->socket 0x%x\n",
149736381Ssklower 			isop->isop_socket);
149836381Ssklower 	ENDDEBUG
149936381Ssklower 	ASSERT(cmd != CONN_OPEN);
150036381Ssklower 
150136381Ssklower 	/* Can we find a cons-level pcb based on channel? */
150236381Ssklower 	if(channel) {
150336381Ssklower 		if((copcb =
150436381Ssklower #ifdef ARGO_DEBUG
150536381Ssklower 			cons_chan_to_pcb( channel, __LINE__ )
150636381Ssklower #else ARGO_DEBUG
150736381Ssklower 			cons_chan_to_pcb( channel)
150836381Ssklower #endif ARGO_DEBUG
150936381Ssklower 				) == (struct cons_pcb *)0) {
151036381Ssklower 			error = ECONNABORTED;
151136381Ssklower 			splx(s);
151236381Ssklower 			return error;
151336381Ssklower 		}
151436381Ssklower 		if( copcb == (struct cons_pcb *) isop ) {
151536381Ssklower 			copcb = (struct cons_pcb *)0;
151636381Ssklower 			/* avoid operating on a pcb twice */
151736381Ssklower 		} else {
151836381Ssklower 			/* if isop is null (close/refuse):
151936381Ssklower 			 * this would remove from the TP list, which is NOT what we want
152036381Ssklower 			 * so only remove if there is an isop (gag)
152136381Ssklower 			 */
152236381Ssklower 			if( isop ) {
152336381Ssklower 				remque((struct cons_pcb *)copcb); /* take it off pending list */
152436381Ssklower 			} else {
152536381Ssklower 				ASSERT( (cmd == CONN_CLOSE) || (cmd == CONN_REFUSE) );
152636381Ssklower 			}
152736381Ssklower 		}
152836381Ssklower 	}
152936381Ssklower 	/* now we have one of these cases:
153036381Ssklower 	 * 1) isop is non-null and copcb is null
153136381Ssklower 	 * 2) isop is non-null and copcb is non-null and they are different
153236381Ssklower 	 * 3) isop is null and copcb is non-null
153336381Ssklower 	 */
153436381Ssklower 	ASSERT( (isop != (struct isopcb *)0) || (copcb != (struct cons_pcb *)0));
153536381Ssklower 
153636381Ssklower 	switch(cmd) {
153736381Ssklower 
153836381Ssklower 		case CONN_CONFIRM:
153936381Ssklower 			if( isdgm ) {
154036381Ssklower 				/* we want two separate pcbs */
154136381Ssklower 				/* if we don't have a copcb, get one */
154236381Ssklower 
154336381Ssklower 				if( copcb == (struct cons_pcb *)0 ) {
154436381Ssklower 					if(( error = cons_pcballoc(&dummysocket, &cons_isopcb,
154536381Ssklower 						((struct cons_pcb *)isop)->co_flags,
154636381Ssklower 						TP_proto, &copcb)) != EOK )
154736381Ssklower 							return error;
154836381Ssklower 					/* copy missing info from isop */
154936381Ssklower 					copcb->co_laddr = isop->isop_laddr;
155036381Ssklower 					copcb->co_faddr = isop->isop_faddr;
155136381Ssklower 					/* don't care about tsuffices */
155236381Ssklower 					((struct cons_pcb *)isop)->co_channel  = 0;
155336381Ssklower 												/* no longer used */
155436381Ssklower 
155536381Ssklower 					copcb->co_ifp = ((struct cons_pcb *)isop)->co_ifp ;
155636381Ssklower 					ASSERT( copcb->co_pending.ifq_len == 0 );
155736381Ssklower 
155836381Ssklower 				} else {
155936381Ssklower 					insque((struct isopcb *)copcb,
156036381Ssklower 						(struct isopcb *)&cons_isopcb);
156136381Ssklower 				}
156236381Ssklower 				copcb->co_state = OPEN;
156336381Ssklower 				copcb->co_flags |= CONSF_DGM;
156436381Ssklower 				copcb->co_channel = channel;
156536381Ssklower 				ASSERT(copcb->co_channel != 0);
156636381Ssklower 
156736381Ssklower 				IFDEBUG(D_CCONN)
156836381Ssklower 					printf("cons_netcmd: put 0x%x on regular list \n", copcb);
156936381Ssklower 				ENDDEBUG
157036381Ssklower 			} else {
157136381Ssklower 				/* must be TP 0, since this is never called from XTS code */
157236381Ssklower 				/* we want ONE pcb, namely isop.
157336381Ssklower 				 * If this TPE were the active side,
157436381Ssklower 				 * there ought not to be a copcb, since TP should
157536381Ssklower 				 * know that you can't send a CR with dgm and negot down
157636381Ssklower 				 * to non-dgm.
157736381Ssklower 				 * If this TPE were the passive side, we want to copy from
157836381Ssklower 				 * the copcb that was on the pending list, and delete the
157936381Ssklower 				 * pending copcb.
158036381Ssklower 				 */
158136381Ssklower 				if( copcb ) {
158236381Ssklower 					IFDEBUG(D_CCONN)
158336381Ssklower 						printf("cons_netcmd: copied info from 0x%x to 0x%x\n",
158436381Ssklower 							copcb, isop);
158536381Ssklower 					ENDDEBUG
158636381Ssklower 					isop->isop_laddr = copcb->co_laddr;
158736381Ssklower 					isop->isop_faddr = copcb->co_faddr;
158836381Ssklower 					/* tsuffices, socket should be there already */
158936381Ssklower 					((struct cons_pcb *)isop)->co_flags =
159036381Ssklower 									copcb->co_flags & ~CONSF_DGM;
159136381Ssklower 					((struct cons_pcb *)isop)->co_init_ttl = copcb->co_init_ttl;
159236381Ssklower 					touch(((struct cons_pcb *)isop));
159336381Ssklower 					((struct cons_pcb *)isop)->co_channel = channel;
159436381Ssklower 					((struct cons_pcb *)isop)->co_ifp = copcb->co_ifp;
159536381Ssklower 					((struct cons_pcb *)isop)->co_proto = copcb->co_proto;
159636381Ssklower 					((struct cons_pcb *)isop)->co_myself =
159736381Ssklower 						(struct cons_pcb *)isop;
159836381Ssklower 					SET_CHANMASK( isop, ((struct cons_pcb *)isop)->co_channel );
159936381Ssklower 					ASSERT( copcb->co_pending.ifq_len == 0 );
160036381Ssklower 
160136381Ssklower 					/* get rid of the copcb that was on the pending list */
160236381Ssklower 					(void) m_free(dtom(copcb));
160336381Ssklower 				}
160436381Ssklower 				((struct cons_pcb *)isop)->co_state = OPEN;
160536381Ssklower 			}
160636381Ssklower 			break;
160736381Ssklower 
160836381Ssklower 		case CONN_CLOSE:
160936381Ssklower 		case CONN_REFUSE:
161036381Ssklower 			/* if dgm then ignore; the connections will
161136381Ssklower 			 * be re-used or will time out
161236381Ssklower 			 */
161336381Ssklower 			if( isdgm )
161436381Ssklower 				break;
161536381Ssklower 
161636381Ssklower 			/* we should never come in here with both isop and copcb
161736381Ssklower 			 * unless is dgm, hence the following assertion:
161836381Ssklower 			 */
161936381Ssklower 			ASSERT( (copcb == (struct cons_pcb *)0) ||
162036381Ssklower 				(isop == (struct isopcb *)0) );
162136381Ssklower 
162236381Ssklower 			/* close whichever pcb we have */
162336381Ssklower 			if( copcb )
162436381Ssklower 				error = cons_clear(copcb, (cmd == CONN_CLOSE)?
162536381Ssklower 					E_CO_HLI_DISCN:E_CO_HLI_REJT);
162636381Ssklower 			if( isop )
162736381Ssklower 				error = cons_clear((struct cons_pcb *)isop, (cmd == CONN_CLOSE)?
162836381Ssklower 					E_CO_HLI_DISCN:E_CO_HLI_REJT);
162936381Ssklower 
163036381Ssklower 			if(copcb &&  (copcb->co_socket == (struct socket *)0) ) {
163136381Ssklower 				ASSERT( copcb->co_flags & (CONSF_DGM | CONSF_ICRE) );
163236381Ssklower 				(void) m_free(dtom(copcb)); /* detached */
163336381Ssklower 			}
163436381Ssklower 			/* isop will always be detached by the higher layer */
163536381Ssklower 			break;
163636381Ssklower 		default:
163736381Ssklower 			error = EOPNOTSUPP;
163836381Ssklower 			break;
163936381Ssklower 	}
164036381Ssklower 	splx(s);
164136381Ssklower 
164236381Ssklower 	IFDEBUG(D_CCONN)
164336381Ssklower 		printf("cons_netcmd returns 0x%x: isop 0x%x\n", isop, error );
164436381Ssklower 	ENDDEBUG
164536381Ssklower 	return error;
164636381Ssklower }
164736381Ssklower 
164836381Ssklower 
164936381Ssklower /*
165036381Ssklower  * NAME:	addr_proto_consistency_check()
165136381Ssklower  * CALLED FROM: cons_incoming()
165236381Ssklower  * FUNCTION and ARGUMENTS:
165336381Ssklower  *  Enforces a set of rules regarding what addresses will serve
165436381Ssklower  *  what protocol stack.  This is a kludge forced upon us by the
165536381Ssklower  *  fact that there's no way to tell which NET layer you want to
165636381Ssklower  *  run when opening a socket.  Besides, no doubt, OSI directory
165736381Ssklower  *  services won't advertise any kind of a protocol stack with the
165836381Ssklower  *  NSAPs.  sigh.
165936381Ssklower  * RETURNS
166036381Ssklower  * 	EAFNOSUPPORT or EOK.
166136381Ssklower  */
166236381Ssklower Static int
166336381Ssklower addr_proto_consistency_check(proto, addr)
166436381Ssklower 	int						proto;
166536381Ssklower 	struct 	sockaddr_iso	*addr;
166636381Ssklower {
166736381Ssklower 	switch( proto ) {
166836381Ssklower 		case ISOPROTO_CLNP:
166936381Ssklower 			break;
167036381Ssklower 
167136381Ssklower 		case ISOPROTO_INACT_NL:
167236381Ssklower 		case ISOPROTO_CLTP:
167336381Ssklower 			return E_CO_HLI_PROTOID;
167436381Ssklower 
167536381Ssklower 		case ISOPROTO_TP:
167636381Ssklower 		case ISOPROTO_X25:
167736381Ssklower 			/* hl is TP or X.25 */
167836381Ssklower 			if (addr->siso_addr.isoa_afi != AFI_37)
167936381Ssklower 				return E_CO_AIWP;
168036381Ssklower 				/* kludge - necessary because this is the only type of
168136381Ssklower 				 * NSAP we build for an incoming NC
168236381Ssklower 				 */
168336381Ssklower 			break;
168436381Ssklower 		default: /* unsupported */
168536381Ssklower 			return E_CO_HLI_PROTOID;
168636381Ssklower 	}
168736381Ssklower 	return EOK;
168836381Ssklower }
168936381Ssklower /*
169036381Ssklower  * NAME:	cons_incoming()
169136381Ssklower  * CALLED FROM:
169236381Ssklower  *  consintr() for incoming OPEN
169336381Ssklower  * FUNCTION and ARGUMENTS:
169436381Ssklower  *  Determines which higher layer gets this call, and
169536381Ssklower  *  thus whether to immediately accept, reject, or to let the
169636381Ssklower  *	higher layer determine this question.
169736381Ssklower  */
169836381Ssklower Static
169936381Ssklower cons_incoming(ifp, ecnrq)
170036381Ssklower 	struct ifnet 					*ifp;
170136381Ssklower 	register struct eicon_request 	*ecnrq;
170236381Ssklower {
170336381Ssklower 	struct sockaddr_iso 	me;
170436381Ssklower 	struct sockaddr_iso 	peer;
170536381Ssklower 	struct cons_pcb			*copcb;
170636381Ssklower 	int 					loop = 0;
170736381Ssklower 	int						proto =0;
170836381Ssklower 	int						error = 0;
170936381Ssklower 	struct	dte_addr		peer_dte;
171036381Ssklower 
171136381Ssklower 	IFDEBUG(D_INCOMING)
171236381Ssklower 		printf("consincoming enter: ifp 0x%x ecnrq 0x%x\n", ifp, ecnrq);
171336381Ssklower 	ENDDEBUG
171436381Ssklower 	bzero( &me, sizeof(me));
171536381Ssklower 	error = parse_facil( mtod(e_data(ecnrq), caddr_t),
171636381Ssklower 						(e_data(ecnrq))->m_len, &me, &peer, &proto,
171736381Ssklower 						&peer_dte);
171836381Ssklower 	loop = is_me( &peer ); /* <-- THIS may be a problem :
171936381Ssklower 							* peer may be nonsense.
172036381Ssklower 							* We can only expect that WE will do it right
172136381Ssklower 							* and never will we get an error return from
172236381Ssklower 							* parse_facil on a facil that WE generated,
172336381Ssklower 							* so if garbage comes in, peer will be garbage,
172436381Ssklower 							* and loop will be false.
172536381Ssklower 							*/
172636381Ssklower 	if( error != EOK ) {
172736381Ssklower 		(void) issue_clear_req(ecnrq->e_vc, error, ifp, loop);
172836381Ssklower 		IncStat(co_parse_facil_err);
172936381Ssklower 		IncStat(co_Rdrops);
173036381Ssklower 		return;
173136381Ssklower 	}
173236381Ssklower 
173336381Ssklower 	if( (error = addr_proto_consistency_check(proto, &me)) != EOK ) {
173436381Ssklower 		/* problem with consistency */
173536381Ssklower 		(void) issue_clear_req(ecnrq->e_vc, error, ifp, loop);
173636381Ssklower 		IncStat(co_addr_proto_consist_err);
173736381Ssklower 		IncStat(co_Rdrops);
173836381Ssklower 		return;
173936381Ssklower 	} else {
174036381Ssklower 		switch( proto ) {
174136381Ssklower 			case ISOPROTO_X25:
174236381Ssklower 				copcb = (struct cons_pcb *)
174336381Ssklower 						((struct cons_pcb *)(&cons_isopcb))->co_next;
174436381Ssklower 
174536381Ssklower 				while (copcb != (struct cons_pcb *)&cons_isopcb) {
174636381Ssklower 					if( copcb->co_lport == me.siso_tsuffix ) {
174736381Ssklower 						/* for cons "transport service",
174836381Ssklower 						 * multiplexing is not allowed
174936381Ssklower 						 */
175036381Ssklower 						if( !copcb->co_socket ) {
175136381Ssklower 							printf(
175236381Ssklower 							"PANIC cons_incoming NOT TP but no sock\n");
175336381Ssklower 							copcb = (struct cons_pcb *)0;
175436381Ssklower 							break;
175536381Ssklower 						}
175636381Ssklower 						if( copcb->co_socket->so_options & SO_ACCEPTCONN ) {
175736381Ssklower 							struct cons_pcb *newx;
175836381Ssklower 
175936381Ssklower 							newx = (struct cons_pcb *)
176036381Ssklower 									sonewconn(copcb->co_socket)->so_pcb;
176136381Ssklower 							newx->co_laddr = copcb->co_laddr;
176236381Ssklower 							newx->co_peer_dte = peer_dte;
176336381Ssklower 							newx->co_proto = copcb->co_proto;
176436381Ssklower 							newx->co_myself = newx;
176536381Ssklower 							touch(copcb);
176636381Ssklower 							copcb = newx;
176736381Ssklower 							soisconnected(copcb->co_socket);
176836381Ssklower 							break;
176936381Ssklower 						} /* else keep looking */
177036381Ssklower 					}
177136381Ssklower 					copcb = (struct cons_pcb *)copcb->co_next;
177236381Ssklower 				}
177336381Ssklower 				if (copcb == (struct cons_pcb *)&cons_isopcb)
177436381Ssklower 					copcb = (struct cons_pcb *) 0;
177536381Ssklower 				break;
177636381Ssklower 
177736381Ssklower 			case ISOPROTO_TP:
177836381Ssklower 				ASSERT( me.siso_tsuffix == 0 );
177936381Ssklower 				/*
178036381Ssklower 				 * We treat this rather like we do for CLNP.
178136381Ssklower 				 * TP can't tell which socket
178236381Ssklower 				 * wants this until the TP header comes in, so there's no way
178336381Ssklower 				 * to associate this channel with a tpcb/isopcb.
178436381Ssklower 				 * We assume data will arrive (a CR TPDU) and be given to TP along with
178536381Ssklower 				 * the channel number.  We can then expect TP to call us with
178636381Ssklower 				 * the channel number and pcb ptr, telling us to keep this connection
178736381Ssklower 				 * or clear it.
178836381Ssklower 				 * Now, tp will have created an isopcb in the tp_isopcb list.
178936381Ssklower 				 * We will have to keep another copcb though, because there is no
179036381Ssklower 				 * 1-1 correspondence between socket and copcb when multiplexing
179136381Ssklower 				 * is allowed.
179236381Ssklower 				 * But we want to save the peer address, ifp, and state, proto.
179336381Ssklower 				 * If the channel should clear before TP responds, we need
179436381Ssklower 				 * to know that also, so we create a tp-pending list...
179536381Ssklower 				 */
179636381Ssklower 				if( cons_pcballoc(&dummysocket, &tp_incoming_pending,
179736381Ssklower 								CONSF_ICRE, TP_proto, &copcb) != EOK )  {
179836381Ssklower 					copcb = (struct cons_pcb *)0;
179936381Ssklower 				} else {
180036381Ssklower 					copcb->co_peer_dte = peer_dte;
180136381Ssklower 				}
180236381Ssklower 				break;
180336381Ssklower 
180436381Ssklower 
180536381Ssklower 			case ISOPROTO_CLNP:
180636381Ssklower 				if( cons_pcballoc(&dummysocket, &cons_isopcb,
180736381Ssklower 						CONSF_ICRE | CONSF_DGM, CLNP_proto, &copcb ) != EOK ) {
180836381Ssklower 					/* choke */
180936381Ssklower 					copcb = (struct cons_pcb *)0;
181036381Ssklower 				} else {
181136381Ssklower 					copcb->co_peer_dte = peer_dte;
181236381Ssklower 				}
181336381Ssklower 				break;
181436381Ssklower 
181536381Ssklower 		default:
181636381Ssklower 			panic("cons_incoming");
181736381Ssklower 		} /* end switch */
181836381Ssklower 
181936381Ssklower 		if(copcb) {
182036381Ssklower 			touch(copcb);
182136381Ssklower 			copcb->co_channel = (int)ecnrq->e_vc;
182236381Ssklower 			ASSERT( copcb->co_channel != 0);
182336381Ssklower 			copcb->co_state = OPEN;
182436381Ssklower 			copcb->co_ifp = ifp;
182536381Ssklower 			copcb->co_laddr = me;
182636381Ssklower 			copcb->co_faddr = peer;
182736381Ssklower 			if(loop)
182836381Ssklower 				copcb->co_flags |= CONSF_LOOPBACK;
182936381Ssklower 			IFDEBUG(D_CADDR)
183036381Ssklower 				printf("cons_incoming found XPCB 0x%x, loop 0x%x\n",
183136381Ssklower 						copcb, loop);
183236381Ssklower 				printf("\nco_laddr: ");
183336381Ssklower 				dump_buf(&copcb->co_laddr, sizeof(copcb->co_laddr));
183436381Ssklower 				printf("\nco_faddr: ");
183536381Ssklower 				dump_buf(&copcb->co_faddr, sizeof(copcb->co_faddr));
183636381Ssklower 				printf("\n");
183736381Ssklower 			ENDDEBUG
183836381Ssklower 		} else {
183936381Ssklower 			ifp->if_ierrors ++;
184036381Ssklower 			(void) issue_clear_req(ecnrq->e_vc, E_CO_OSI_UNSAP, ifp, loop);
184136381Ssklower 			IncStat(co_no_copcb);
184236381Ssklower 			IncStat(co_Rdrops);
184336381Ssklower 		}
184436381Ssklower 	}
184536381Ssklower 	/* caller frees the mbuf so we don't have to do any such thing */
184636381Ssklower }
184736381Ssklower 
184836381Ssklower /*
184936381Ssklower  **************************** DEVICE cons ***************************
185036381Ssklower  */
185136381Ssklower 
185236381Ssklower /*
185336381Ssklower  * NAME:	cosns_output()
185436381Ssklower  * CALLED FROM:
185536381Ssklower  *  clnp - this routine is given as the device-output routine
185636381Ssklower  *  for the adcom driver.
185736381Ssklower  * FUNCTION and ARGUMENTS:
185836381Ssklower  *  (ifp) is the cons/adcom, found by routing function.
185936381Ssklower  *  (m0) is the clnp datagram.
186036381Ssklower  *  (dst) is the destination address
186136381Ssklower  * This routine finds an x.25 connection for datagram use and
186236381Ssklower  * sends the packet.
186336381Ssklower  */
186436381Ssklower int
186536381Ssklower cosns_output(ifp, m0, dst)
186636381Ssklower {
186736381Ssklower 	return cosns_output1(ifp, m0, dst, CLNP_proto, NULL);
186836381Ssklower }
186936381Ssklower 
187036381Ssklower /* DEBUGGING ONLY? */
187136381Ssklower int	total_cosns_len = 0;
187236381Ssklower int	total_cosns_cnt = 0;
187336381Ssklower int	total_pkts_to_clnp = 0;
187436381Ssklower 
187536381Ssklower /*
187636381Ssklower  *		The isop is passed here so that if we have set x25crud in the
187736381Ssklower  *		pcb, it can be passed down to cons_connect. It could be null
187836381Ssklower  *		however, in the case of tp4/x25/clnp
187936381Ssklower  */
188036381Ssklower Static int
188136381Ssklower cosns_output1(ifp, m0, dst, proto, isop)
188236381Ssklower 	struct ifnet *ifp;
188336381Ssklower 	register struct mbuf *m0;
188436381Ssklower 	struct sockaddr_iso *dst;
188536381Ssklower 	struct protosw *proto;
188636381Ssklower 	struct isopcb	*isop;		/* NULL if coming from clnp */
188736381Ssklower {
188836381Ssklower 	register struct cons_pcb *copcb;
188936381Ssklower 	int 					s = splnet();
189036381Ssklower 	int						error = 0;
189136381Ssklower 
189236381Ssklower 	{ 	register struct mbuf *n=m0;
189336381Ssklower 		register int len = 0;
189436381Ssklower 
189536381Ssklower 		for(;;) {
189636381Ssklower 			len += n->m_len;
189736381Ssklower 			if (n->m_next == MNULL ) {
189836381Ssklower 				break;
189936381Ssklower 			}
190036381Ssklower 			n = n->m_next;
190136381Ssklower 		}
190236381Ssklower 		total_cosns_len += len;
190336381Ssklower 		total_cosns_cnt ++;
190436381Ssklower 
190536381Ssklower 	}
190636381Ssklower 
190736381Ssklower 	IFDEBUG(D_CCONS)
190836381Ssklower 		printf("cosns_output1( ifp 0x%x, m 0x%x, dst 0x%x )\n", ifp, m0, dst );
190936381Ssklower 	ENDDEBUG
191036381Ssklower 	if ( ! (copcb = cons_find( CONSF_DGM, dst, proto, 0, 0) )) {
191136381Ssklower 		struct cons_pcb *newcopcb; /* so we can pass addr of this to pcballoc */
191236381Ssklower 
191336381Ssklower 		if( (error = cons_pcballoc(&dummysocket, &cons_isopcb,
191436381Ssklower 				CONSF_DGM | CONSF_OCRE, proto, &newcopcb) )  != EOK ) {
191536381Ssklower 			IFDEBUG(D_CCONS)
191636381Ssklower 				printf("cosns_output: no copcb; returns \n");
191736381Ssklower 			ENDDEBUG
191836381Ssklower 			(void) m_freem(m0);
191936381Ssklower 			goto done;
192036381Ssklower 		}
192136381Ssklower 		copcb = newcopcb;
192236381Ssklower 
192336381Ssklower 		/* abbreviated form of iso_pcbconnect(): */
192436381Ssklower 		bcopy((caddr_t)dst, (caddr_t)&copcb->co_faddr,
192536381Ssklower 									sizeof(struct sockaddr_iso));
192636381Ssklower 
192736381Ssklower 		/* copy x25crud into copcb if necessary */
192836381Ssklower 		if ((isop != NULL) && (isop->isop_x25crud_len > 0)) {
192936381Ssklower 			bcopy(isop->isop_x25crud, copcb->co_x25crud,
193036381Ssklower 				isop->isop_x25crud_len);
193136381Ssklower 			copcb->co_x25crud_len = isop->isop_x25crud_len;
193236381Ssklower 		}
193336381Ssklower 
193436381Ssklower 		copcb->co_ifp = ifp; /* NULL IF COMING FROM TP4! */
193536381Ssklower 
193636381Ssklower 		if ( error = cons_connect( copcb ) ) { /* if it doesn't work */
193736381Ssklower 			/* oh, dear, throw packet away */
193836381Ssklower 			remque((struct isopcb *)copcb);
193936381Ssklower 			(void) m_free(dtom(copcb));
194036381Ssklower 			(void) m_freem(m0);
194136381Ssklower 			goto done;
194236381Ssklower 		}
194336381Ssklower 	}
194436381Ssklower 	IFDEBUG(D_CDATA)
194536381Ssklower 		printf("cosns_output1 @ senddata: state 0x%x flags 0x%x channel 0x%x\n",
194636381Ssklower 			copcb->co_state, copcb->co_flags, copcb->co_channel);
194736381Ssklower 	ENDDEBUG
194836381Ssklower 	ASSERT(copcb->co_channel != X_NOCHANNEL);
194936381Ssklower 	error = cons_senddata(copcb, m0);
195036381Ssklower done:
195136381Ssklower 	splx(s);
195236381Ssklower 	return error;
195336381Ssklower }
195436381Ssklower 
195536381Ssklower 
195636381Ssklower /*
195736381Ssklower  **************************** TRANSPORT cons ***************************
195836381Ssklower  */
195936381Ssklower 
196036381Ssklower 
196136381Ssklower /*
196236381Ssklower  * NAME:	cons_detach()
196336381Ssklower  * CALLED FROM:
196436381Ssklower  *  cons_usrreq() on PRU_DETACH
196536381Ssklower  *  cons_netcmd() when TP releases a net connection
196636381Ssklower  *	cons_slowtimo()  when timeout releases a net connection
196736381Ssklower  * FUNCTION and ARGUMENT:
196836381Ssklower  *  removes the copcb from the list of copcbs in use, and frees the mbufs.
196936381Ssklower  *  detaches the pcb from the socket, where a socket exists.
197036381Ssklower  * RETURN VALUE:
197136381Ssklower  *  ENOTCONN if it couldn't find the copcb in the list of connections.
197236381Ssklower  */
197336381Ssklower 
197436381Ssklower Static int
197536381Ssklower cons_detach( copcb )
197636381Ssklower 	register struct cons_pcb *copcb;
197736381Ssklower {
197836381Ssklower 	struct socket *so = copcb->co_socket;
197936381Ssklower 
198036381Ssklower 	IFDEBUG(D_CCONN)
198136381Ssklower 		printf("cons_detach( copcb 0x%x )\n", copcb);
198236381Ssklower 	ENDDEBUG
198336381Ssklower 	if(so) {
198436381Ssklower 		if (so->so_head) {
198536381Ssklower 			if (!soqremque(so, 0) && !soqremque(so, 1))
198636381Ssklower 				panic("sofree dq");
198736381Ssklower 			so->so_head = 0;
198836381Ssklower 		}
198936381Ssklower 		((struct isopcb *)copcb)->isop_options = 0; /* kludge */
199036381Ssklower 		iso_pcbdetach(copcb); /* detaches from so */
199136381Ssklower 	} else {
199236381Ssklower 		remque((struct isopcb *)copcb);
199336381Ssklower 		(void) m_free(dtom(copcb));
199436381Ssklower 	}
199536381Ssklower }
199636381Ssklower 
199736381Ssklower Static int
199836381Ssklower cons_clear_and_detach(copcb, clearreason, ctlcmd)
199936381Ssklower 	register struct cons_pcb *copcb;
200036381Ssklower 	int					clearreason;
200136381Ssklower 	int						ctlcmd;
200236381Ssklower {
200336381Ssklower 	IFDEBUG(D_CCONN)
200436381Ssklower 		printf("Clear and Detach (0x%x, 0x%x, 0x%x)\n",
200536381Ssklower 						copcb, clearreason, ctlcmd);
200636381Ssklower 	ENDDEBUG
200736381Ssklower 	if( clearreason != DONTCLEAR ) {
200836381Ssklower 		(void) cons_clear( copcb ,  clearreason );
200936381Ssklower 	}
201036381Ssklower 	if( copcb->co_proto  && copcb->co_proto->pr_ctlinput )
201136381Ssklower 		(*copcb->co_proto->pr_ctlinput)(ctlcmd,
201236381Ssklower 			(struct sockaddr_iso *)&copcb->co_faddr, (caddr_t)copcb);
201336381Ssklower 
201436381Ssklower 	if( copcb->co_socket == (struct socket *)0 ) {
201536381Ssklower 		/* tp4, clnp users only */
201636381Ssklower 		(void) cons_detach( copcb );
201736381Ssklower 	} /* else detach will be called by the socket's closing */
201836381Ssklower 		else {
201936381Ssklower 			ASSERT( copcb->co_socket != &dummysocket );
202036381Ssklower 			ASSERT( (copcb->co_flags & CONSF_DGM) == 0 );
202136381Ssklower 	}
202236381Ssklower 	IFDEBUG(D_CCONN)
202336381Ssklower 		printf("END OF Clear and Detach (0x%x, 0x%x, 0x%x)\n",
202436381Ssklower 						copcb, clearreason, ctlcmd);
202536381Ssklower 	ENDDEBUG
202636381Ssklower }
202736381Ssklower 
202836381Ssklower Static int
202936381Ssklower cons_pcbbind( copcb, nam )
203036381Ssklower 	register struct cons_pcb *copcb;
203136381Ssklower 	struct mbuf *nam;
203236381Ssklower {
203336381Ssklower 	int error;
203436381Ssklower 
203536381Ssklower 	if( error = iso_pcbbind( copcb, nam) )
203636381Ssklower 		return error;
203736381Ssklower 
203836381Ssklower 	/* iso_pcbbind already ensured that if port < 1024 it's superuser */
203936381Ssklower 	/* Now we check: must be in range 0 .. 23 or in range 1024 .. 99 */
204036381Ssklower 
204136381Ssklower 	if( (copcb->co_lport < X25_PORT_RESERVED)  ||
204236381Ssklower 			 ((copcb->co_lport >= ISO_PORT_RESERVED) &&
204336381Ssklower 			  (copcb->co_lport <= X25_PORT_USERMAX))) {
204436381Ssklower 		munge( copcb->co_lport, (&copcb->co_laddr)->siso_addr.t37_idi +
204536381Ssklower 			ADDR37_IDI_LEN, 1 /* nibble */);
204636381Ssklower 		munge( copcb->co_fport, (&copcb->co_faddr)->siso_addr.t37_idi +
204736381Ssklower 			ADDR37_IDI_LEN, 1 /* nibble */);
204836381Ssklower 		 return 0;
204936381Ssklower 	} else
205036381Ssklower 		return EADDRNOTAVAIL;
205136381Ssklower }
205236381Ssklower /*
205336381Ssklower  * NAME:	cons_usrreq()
205436381Ssklower  * CALLED FROM:
205536381Ssklower  *  user level via proto switch
205636381Ssklower  * FUNCTION and ARGUMENTS:
205736381Ssklower  *  so : socket
205836381Ssklower  *  req: which PRU* request
205936381Ssklower  *  m : data or mbuf ptr into which to stash data
206036381Ssklower  *	nam: mbuf ptr which is really a sockaddr_iso
206136381Ssklower  *  ifq: in PRU_CONTROL case, an ifnet structure
206236381Ssklower  * RETURN VALUE:
206336381Ssklower  *  ENOTCONN if trying to do something which requires a connection
206436381Ssklower  * 	 and it's not yet connected
206536381Ssklower  *  EISCONN if trying to do something which cannot be done to a connection
206636381Ssklower  * 	 but it's connected
206736381Ssklower  * 	ENOBUFS if ran out of mbufs
206836381Ssklower  * 	EWOULDBLOCK if in nonblocking mode & can't send right away
206936381Ssklower  * 	EOPNOSUPP if req isn't supported
207036381Ssklower  * 	E* other passed up from lower layers or from other routines
207136381Ssklower  */
207236381Ssklower 
207336381Ssklower cons_usrreq(so, req, m, nam, ifp)
207436381Ssklower 	struct socket *so;
207536381Ssklower 	u_int req;
207636381Ssklower 	struct mbuf *m, *nam;
207736381Ssklower 	int *ifp;
207836381Ssklower {
207936381Ssklower 	struct cons_pcb *copcb =  (struct cons_pcb *)so->so_pcb;
208036381Ssklower 	int 					s = splnet();
208136381Ssklower 	int 					error = 0;
208236381Ssklower 
208336381Ssklower 	IFDEBUG(D_CCONS)
208436381Ssklower 		printf("cons_usrreq 0x%x so 0x%x copcb 0x%x\n", req, so, copcb);
208536381Ssklower 	ENDDEBUG
208636381Ssklower 	if (req == PRU_CONTROL) {
208736381Ssklower 		error =  iso_control(so, (int)m, (caddr_t)nam, (struct ifnet *)ifp);
208836381Ssklower 		splx(s);
208936381Ssklower 		return error;
209036381Ssklower 	}
209136381Ssklower 	if (copcb == (struct cons_pcb *)0  &&  req != PRU_ATTACH) {
209236381Ssklower 		splx(s);
209336381Ssklower 		return ENOTCONN;
209436381Ssklower 	}
209536381Ssklower 
209636381Ssklower 	switch (req) {
209736381Ssklower 
209836381Ssklower 	case PRU_ATTACH:
209936381Ssklower 		if (copcb) {
210036381Ssklower 			error = EISCONN;
210136381Ssklower 			break;
210236381Ssklower 		}
210336381Ssklower 		soreserve(so, X25_SBSIZE, X25_SBSIZE); /* CONS size */
210436381Ssklower 		error = cons_pcballoc(so, &cons_isopcb, CONSF_XTS, X25_proto, &copcb );
210536381Ssklower 		break;
210636381Ssklower 
210736381Ssklower 	case PRU_ABORT: 	/* called from close() */
210836381Ssklower 		/* called for each incoming connect queued on the parent (accepting)
210936381Ssklower 		 * socket (SO_ACCEPTCONN);
211036381Ssklower 		 */
211136381Ssklower 		 error = cons_detach ( copcb );
211236381Ssklower 		 break;
211336381Ssklower 
211436381Ssklower 	case PRU_DETACH: 	/* called from close() */
211536381Ssklower 		/* called after disconnect was called iff was connected at the time
211636381Ssklower 		 * of the close, or directly if socket never got connected */
211736381Ssklower 		error = cons_detach ( copcb );
211836381Ssklower 		break;
211936381Ssklower 
212036381Ssklower 	case PRU_SHUTDOWN:
212136381Ssklower 		/* recv end may have been released; local credit might be zero  */
212236381Ssklower 	case PRU_DISCONNECT:
212336381Ssklower 		soisdisconnected(so);
212436381Ssklower 			error = cons_clear(copcb, E_CO_HLI_DISCN);
212536381Ssklower 		break;
212636381Ssklower 
212736381Ssklower 	case PRU_BIND:
212836381Ssklower 		error = cons_pcbbind( copcb, nam);
212936381Ssklower 		break;
213036381Ssklower 
213136381Ssklower 	case PRU_LISTEN:
213236381Ssklower 		if (copcb->co_lport == 0)
213336381Ssklower 			error = cons_pcbbind( copcb, 0 );
213436381Ssklower 		break;
213536381Ssklower 
213636381Ssklower 
213736381Ssklower 	case PRU_SOCKADDR: {
213836381Ssklower 			struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *);
213936381Ssklower 
214036381Ssklower 			nam->m_len = sizeof (struct sockaddr_iso);
214136381Ssklower 			if(copcb->co_ifp)
214236381Ssklower 				bcopy( (caddr_t)&copcb->co_laddr,
214336381Ssklower 						(caddr_t)siso, sizeof(struct sockaddr_iso) );
214436381Ssklower 
214536381Ssklower 			((struct sockaddr_iso *)siso)->siso_tsuffix = copcb->co_lport;
214636381Ssklower 		}
214736381Ssklower 		break;
214836381Ssklower 
214936381Ssklower 	case PRU_PEERADDR:
215036381Ssklower 		if( (so->so_state & SS_ISCONNECTED) &&
215136381Ssklower 			(so->so_state & SS_ISDISCONNECTING) == 0) {
215236381Ssklower 				struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *);
215336381Ssklower 
215436381Ssklower 			nam->m_len = sizeof (struct sockaddr_iso);
215536381Ssklower 			bcopy( (caddr_t)&copcb->co_faddr, (caddr_t)siso,
215636381Ssklower 									sizeof(struct sockaddr_iso) );
215736381Ssklower 		} else
215836381Ssklower 			error = ENOTCONN;
215936381Ssklower 		break;
216036381Ssklower 
216136381Ssklower 	case PRU_CONNECT:
216236381Ssklower 		/* TODO: We need to bind to the RIGHT interface.
216336381Ssklower 		 * The only way to have the right interface is to have
216436381Ssklower 		 * the right route.
216536381Ssklower 		 */
216636381Ssklower 		IFDEBUG(D_CCONN)
216736381Ssklower 			printf("PRU_CONNECT 1: local tsuffix 0x%x so->so_head 0x%x nam:\n",
216836381Ssklower 				copcb->co_lport, so->so_head);
216936381Ssklower 			dump_isoaddr( mtod(nam, struct sockaddr_iso *) );
217036381Ssklower 		ENDDEBUG
217136381Ssklower 		if (copcb->co_lport == 0) {
217236381Ssklower 			if( error = cons_pcbbind( copcb, 0 ))
217336381Ssklower 				break;
217436381Ssklower 		}
217536381Ssklower 		IFDEBUG(D_CCONN)
217636381Ssklower 			printf("PRU_CONNECT 2: local tsuffix 0x%x so->so_head 0x%x nam:\n",
217736381Ssklower 				copcb->co_lport, so->so_head);
217836381Ssklower 			dump_isoaddr( mtod(nam, struct sockaddr_iso *) );
217936381Ssklower 		ENDDEBUG
218036381Ssklower 
218136381Ssklower 		{ 	/* change the destination address so the last 2 digits
218236381Ssklower 			 * are the port/suffix/selector (whatever you want to call it)
218336381Ssklower 			 */
218436381Ssklower 			register struct sockaddr_iso *siso =
218536381Ssklower 							mtod(nam, struct sockaddr_iso *);
218636381Ssklower 			if( (siso->siso_tsuffix < X25_PORT_RESERVED)  ||
218736381Ssklower 				 ((siso->siso_tsuffix >= ISO_PORT_RESERVED) &&
218836381Ssklower 				  (siso->siso_tsuffix <= X25_PORT_USERMAX)))
218936381Ssklower 			munge( siso->siso_tsuffix,
219036381Ssklower 					siso->siso_addr.t37_idi + ADDR37_IDI_LEN,
219136381Ssklower 					1 /* nibble */);
219236381Ssklower 		}
219336381Ssklower 
219436381Ssklower 		soisconnecting(so);
219536381Ssklower 		if (error = iso_pcbconnect(copcb, nam))
219636381Ssklower 			break;
219736381Ssklower 		error = cons_connect( copcb );
219836381Ssklower 		if ( error ) {
219936381Ssklower 			/*
220036381Ssklower 			remque((struct isopcb *)copcb);
220136381Ssklower 			(void) m_free(dtom(copcb));
220236381Ssklower 			*/
220336381Ssklower 			break;
220436381Ssklower 		}
220536381Ssklower 		while( (copcb->co_state != OPEN)&&(copcb->co_socket->so_error == 0) ) {
220636381Ssklower 			IFDEBUG(D_CCONN)
220736381Ssklower 				printf("PRU_CONNECT: error 0x%x sleeping on 0x%x\n",
220836381Ssklower 					copcb->co_socket->so_error,
220936381Ssklower 					(caddr_t)&copcb->co_state );
221036381Ssklower 			ENDDEBUG
221136381Ssklower 			sleep( (caddr_t)&copcb->co_state, PZERO+3 );
221236381Ssklower 		}
221336381Ssklower 
221436381Ssklower 		ASSERT( copcb->co_channel != 0);
221536381Ssklower 
221636381Ssklower 		SET_CHANMASK ( (struct isopcb *)copcb, copcb->co_channel);
221736381Ssklower 		break;
221836381Ssklower 
221936381Ssklower 	case PRU_ACCEPT:
222036381Ssklower 		/* so here is the NEW socket */
222136381Ssklower 		so->so_error = 0;
222236381Ssklower 		if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTED)== 0) {
222336381Ssklower 			error = EWOULDBLOCK;
222436381Ssklower 			break;
222536381Ssklower 		}
222636381Ssklower 		{
222736381Ssklower 			struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *);
222836381Ssklower 
222936381Ssklower 			/* copy the peer's address into the return argument */
223036381Ssklower 			nam->m_len = sizeof (struct sockaddr_iso);
223136381Ssklower 			bcopy( (caddr_t)&copcb->co_faddr, (caddr_t)siso,
223236381Ssklower 				sizeof(struct sockaddr_iso));
223336381Ssklower 		}
223436381Ssklower 		break;
223536381Ssklower 
223636381Ssklower 	case PRU_SEND:
223736381Ssklower 	case PRU_SENDEOT:
223836381Ssklower 		/*
223936381Ssklower 		 * sosend calls this until sbspace goes negative.
224036381Ssklower 		 * Sbspace may be made negative by appending this mbuf chain,
224136381Ssklower 		 * possibly by a whole cluster.
224236381Ssklower 		 */
224336381Ssklower 		{
224436381Ssklower 			/* no need to actually queue this stuff and dequeue it,
224536381Ssklower 			 * just bump the pointers in so_snd so that higher
224636381Ssklower 			 * layer of socket code will cause it to sleep when
224736381Ssklower 			 * we've run out of socket space
224836381Ssklower 			 * TODO:
224936381Ssklower 			 * Unfortunately that makes sbflush vomit so we have
225036381Ssklower 			 * to allocate a single real mbuf (say size 240)
225136381Ssklower 			 * and sballoc it and sbfree it upon CONS_SEND_DONE.
225236381Ssklower 			 * Oh, my, is this sickening or what?
225336381Ssklower 			 */
225436381Ssklower 			{
225536381Ssklower 				struct mbuf *mx;
225636381Ssklower 
225736381Ssklower 				MGET(mx, M_DONTWAIT, MT_DATA);
225836381Ssklower 				mx->m_len = MLEN;
225936381Ssklower 				sbappend((caddr_t)&copcb->co_socket->so_snd, mx);
226036381Ssklower 			}
226136381Ssklower 			if( m ) {
226236381Ssklower 				IFDEBUG(D_CDATA)
226336381Ssklower 					printf("X.25 Usrreq calling cons_senddata(0x%x, 0x%x)\n",
226436381Ssklower 						copcb, m);
226536381Ssklower 				ENDDEBUG
226636381Ssklower 				error = cons_senddata(copcb, m);
226736381Ssklower 			}
226836381Ssklower 			IFDEBUG(D_CCONS)
226936381Ssklower 				printf("PRU_SEND sent tsuffix 0x%x, m 0x%x error 0x%x\n",
227036381Ssklower 					copcb->co_lport, m, error);
227136381Ssklower 			ENDDEBUG
227236381Ssklower 
227336381Ssklower 			if( req == PRU_SENDEOT ) {
227436381Ssklower 				while(copcb->co_socket->so_snd.sb_cc > 0)
227536381Ssklower 					sbwait(&copcb->co_socket->so_snd);
227636381Ssklower 			}
227736381Ssklower 		}
227836381Ssklower 		break;
227936381Ssklower 
228036381Ssklower 	case PRU_CONTROL:
228136381Ssklower 		error = cons_ioctl(so, m, (caddr_t)nam);
228236381Ssklower 		break;
228336381Ssklower 
228436381Ssklower 
228536381Ssklower 	case PRU_RCVD:
228636381Ssklower 	case PRU_RCVOOB:
228736381Ssklower 	case PRU_SENDOOB:
228836381Ssklower 		/* COULD support INTERRUPT packets as oob */
228936381Ssklower 	case PRU_PROTOSEND:
229036381Ssklower 	case PRU_PROTORCV:
229136381Ssklower 	case PRU_SENSE:
229236381Ssklower 	case PRU_SLOWTIMO:
229336381Ssklower 	case PRU_CONNECT2:
229436381Ssklower 	case PRU_FASTTIMO:
229536381Ssklower 	default:
229636381Ssklower 		error = EOPNOTSUPP;
229736381Ssklower 	}
229836381Ssklower 
229936381Ssklower 	IFDEBUG(D_CCONS)
230036381Ssklower 		printf("cons_usrreq cmd 0x%x copcb 0x%x returned error 0x%x\n",
230136381Ssklower 			req, copcb, error);
230236381Ssklower 	ENDDEBUG
230336381Ssklower 	splx(s);
230436381Ssklower 	return error;
230536381Ssklower }
230636381Ssklower 
230736381Ssklower /*
230836381Ssklower  * NAME:	cons_input()
230936381Ssklower  * CALLED FROM:
231036381Ssklower  *  consintr() through the isosw protosw for "transport" version of X25
231136381Ssklower  * FUNCTION & ARGUMENTS:
231236381Ssklower  *  process incoming data
231336381Ssklower  */
231436381Ssklower cons_input(m, faddr, laddr, so)
231536381Ssklower 	register struct mbuf *m;
231636381Ssklower 	struct sockaddr_iso *faddr, *laddr; /* not used */
231736381Ssklower 	register struct socket *so;
231836381Ssklower {
231936381Ssklower 	IFDEBUG(D_CCONS)
232036381Ssklower 		printf("cons_input( m 0x%x, so 0x%x)\n", m,so);
232136381Ssklower 	ENDDEBUG
232236381Ssklower 	sbappend(&so->so_rcv, m);
232336381Ssklower 	sbwakeup(&so->so_rcv);
232436381Ssklower }
232536381Ssklower 
232636381Ssklower #ifdef notdef
232736381Ssklower /*
232836381Ssklower  * NAME:	cons_ctloutput()
232936381Ssklower  * CALLED FROM:
233036381Ssklower  *  set/get sockopts()
233136381Ssklower  * 	Presently the protosw has 0 in the ctloutput spot
233236381Ssklower  *	 because we haven't inplemented anything yet.
233336381Ssklower  * 	If there's reason to put some options in here,
233436381Ssklower  * 	be sure to stick this routine name in the protosw in iso_proto.c
233536381Ssklower  */
233636381Ssklower cons_ctloutput(cmd, so, level, optname, mp)
233736381Ssklower 	int 			cmd, level, optname;
233836381Ssklower 	struct socket	*so;
233936381Ssklower 	struct mbuf 	**mp;
234036381Ssklower {
234136381Ssklower 	int 			s = splnet();
234236381Ssklower 
234336381Ssklower 	splx(s);
234436381Ssklower 	return EOPNOTSUPP;
234536381Ssklower }
234636381Ssklower #endif notdef
234736381Ssklower 
234836381Ssklower 
234936381Ssklower /*
235036381Ssklower  * NAME:	cons_ctlinput()
235136381Ssklower  * CALLED FROM:
235236381Ssklower  *  lower layer when ECN_CLEAR occurs : this routine is here
235336381Ssklower  *  for consistency - cons subnet service calls its higher layer
235436381Ssklower  *  through the protosw entry.
235536381Ssklower  * FUNCTION & ARGUMENTS:
2356*37536Smckusick  *  cmd is a PRC_* command, list found in ../sys/protosw.h
235736381Ssklower  *  copcb is the obvious.
235836381Ssklower  *  This serves the higher-layer cons service.
235936381Ssklower  * NOTE: this takes 3rd arg. because cons uses it to inform itself
236036381Ssklower  *  of things (timeouts, etc) but has a pcb instead of an address.
236136381Ssklower  */
236236381Ssklower cons_ctlinput(cmd, sa, copcb)
236336381Ssklower 	int cmd;
236436381Ssklower 	struct sockaddr *sa;
236536381Ssklower 	register struct cons_pcb *copcb;
236636381Ssklower {
236736381Ssklower 	int 			error = 0;
236836381Ssklower 	int 			s = splnet();
236936381Ssklower 	extern u_char 	inetctlerrmap[];
237036381Ssklower 	extern int 		iso_rtchange();
237136381Ssklower 
237236381Ssklower 	IFDEBUG(D_CCONS)
237336381Ssklower 		printf("cons_ctlinput( cmd 0x%x, copcb 0x%x)\n", cmd, copcb);
237436381Ssklower 	ENDDEBUG
237536381Ssklower 	/* co_socket had better exist */
237636381Ssklower 	switch (cmd) {
237736381Ssklower 		case PRC_CONS_SEND_DONE:
237836381Ssklower 			ASSERT( copcb->co_socket );
237936381Ssklower 			ASSERT( copcb->co_flags & CONSF_XTS );
238036381Ssklower 			sbdrop((caddr_t)&copcb->co_socket->so_snd, MLEN);
238136381Ssklower 			sbwakeup((caddr_t)&copcb->co_socket->so_snd);
238236381Ssklower 			break;
238336381Ssklower 
238436381Ssklower 		case PRC_ROUTEDEAD:
238536381Ssklower 			error = ENETUNREACH;
238636381Ssklower 			break;
238736381Ssklower 
238836381Ssklower 		case PRC_TIMXCEED_REASS:
238936381Ssklower 			error = ETIMEDOUT;
239036381Ssklower 			break;
239136381Ssklower 
239236381Ssklower 	/*
239336381Ssklower 		case PRC_QUENCH:
239436381Ssklower 			iso_pcbnotify(&cons_pcb, sa,
239536381Ssklower 					(int)inetctlerrmap[cmd], iso_rtchange);
239636381Ssklower 			iso_pcbnotify(&tp_incoming_pending, sa,
239736381Ssklower 					(int)inetctlerrmap[cmd], tpiso_quench);
239836381Ssklower 			iso_pcbnotify(&tp_isopcb, sa,
239936381Ssklower 					(int)inetctlerrmap[cmd], tpiso_quench);
240036381Ssklower 	*/
240136381Ssklower 
240236381Ssklower 		case PRC_IFDOWN:
240336381Ssklower 			iso_pcbnotify(&cons_isopcb, sa,
240436381Ssklower 					(int)inetctlerrmap[cmd], iso_rtchange);
240536381Ssklower 			iso_pcbnotify(&tp_incoming_pending, sa,
240636381Ssklower 					(int)inetctlerrmap[cmd], iso_rtchange);
240736381Ssklower 			iso_pcbnotify(&tp_isopcb, sa,
240836381Ssklower 					(int)inetctlerrmap[cmd], iso_rtchange);
240936381Ssklower 			break;
241036381Ssklower 
241136381Ssklower 
241236381Ssklower 		default:
241336381Ssklower 			printf("cons_ctlinput: unknown cmd 0x%x\n", cmd);
241436381Ssklower 	}
241536381Ssklower 	if(error) {
241636381Ssklower 		soisdisconnected(copcb->co_socket);
241736381Ssklower 		sohasoutofband(copcb->co_socket);
241836381Ssklower 	}
241936381Ssklower 	splx(s);
242036381Ssklower }
242136381Ssklower 
242236381Ssklower /*
242336381Ssklower  *********************** SERVES ALL cons embodiments  *******************
242436381Ssklower  */
242536381Ssklower 
242636381Ssklower /*
242736381Ssklower  * NAME:	cons_chan_to_pcb()
242836381Ssklower  * CALLED FROM:
242936381Ssklower  *  cons_chan_to_tpcb() in tp_cons.c
243036381Ssklower  * and in this file: incoming requests that give only a channel number, i.e.,
243136381Ssklower  *  ECN_ACCEPT, ECN_RECEIVE, ECN_CLEAR
243236381Ssklower  * FUNCTION:
243336381Ssklower  *  identify the pcb assoc with that channel
243436381Ssklower  * RETURN:
243536381Ssklower  *  ptr to the pcb
243636381Ssklower  */
243736381Ssklower struct cons_pcb *
243836381Ssklower #ifdef ARGO_DEBUG
243936381Ssklower cons_chan_to_pcb( channel, linenumber )
244036381Ssklower 	int	linenumber;
244136381Ssklower #else ARGO_DEBUG
244236381Ssklower cons_chan_to_pcb( channel)
244336381Ssklower #endif ARGO_DEBUG
244436381Ssklower 	register int channel;
244536381Ssklower {
244636381Ssklower 	register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist;
244736381Ssklower 	register struct cons_pcb *copcb;
244836381Ssklower 
244936381Ssklower 	/* just to be sure */
245036381Ssklower 	channel = channel & 0xff;
245136381Ssklower 
245236381Ssklower 	for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) {
245336381Ssklower 		copcb = (struct cons_pcb *)copcb->co_next;
245436381Ssklower 		while (copcb !=  *copcblist) {
245536381Ssklower 			if ( copcb->co_channel == channel )
245636381Ssklower 				goto found; /* want to break out of both loops */
245736381Ssklower 
245836381Ssklower 			copcb = (struct cons_pcb *)copcb->co_next;
245936381Ssklower 		}
246036381Ssklower 	}
246136381Ssklower found: /* or maybe not... */
246236381Ssklower 	IFDEBUG(D_CCONS)
246336381Ssklower 		printf("cons_chan_to_pcb( 0x%x, %d ) %s 0x%x\n", channel, linenumber,
246436381Ssklower 			copcb?"FOUND":"FAILED", copcb);
246536381Ssklower 	ENDDEBUG
246636381Ssklower 
246736381Ssklower 	return copcb;
246836381Ssklower }
246936381Ssklower 
247036381Ssklower 
247136381Ssklower /*
247236381Ssklower  * NAME:	is_me()
247336381Ssklower  * CALLED FROM:
247436381Ssklower  *  cons_incoming().  Perhaps could just expand in line.
247536381Ssklower  * FUNCTION and ARGUMENTS:
247636381Ssklower  * 	for the given remote address (remadr) if it exactly matches
247736381Ssklower  *  one of the addresses of ME, and I am up as loopback,
247836381Ssklower  *  return TRUE, else return FALSE.
247936381Ssklower  * RETURNS:
248036381Ssklower  *  Boolean
248136381Ssklower  */
248236381Ssklower Static int
248336381Ssklower is_me(remaddr)
248436381Ssklower 	struct	sockaddr_iso	*remaddr;
248536381Ssklower {
248636381Ssklower 	struct	ifnet 			*ifp = consif;
248736381Ssklower 									/* PHASE2: this is ok */
248836381Ssklower 	struct ifaddr 			*ifa = ifa_ifwithaddr(remaddr);
248936381Ssklower 
249036381Ssklower 	IFDEBUG(D_CADDR)
249136381Ssklower 		printf("is_me: withaddr returns %s\n",
249236381Ssklower 			ifa?ifa->ifa_ifp->if_name:"NONE");
249336381Ssklower 	ENDDEBUG
249436381Ssklower 	if( ifa ) {
249536381Ssklower 		/* remaddr matches one of my interfaces exactly */
249636381Ssklower 		if( ifa->ifa_ifp->if_flags & IFF_LOOPBACK ) {
249736381Ssklower 			ASSERT( ifp == ifa->ifa_ifp );
249836381Ssklower 			return 1;
249936381Ssklower 		}
250036381Ssklower 	}
250136381Ssklower 	return 0;
250236381Ssklower }
250336381Ssklower 
250436381Ssklower find_error_reason( ecnrq )
250536381Ssklower 	register struct eicon_request 	*ecnrq;
250636381Ssklower {
250736381Ssklower 	extern u_char x25_error_stats[];
250836381Ssklower 	int error;
250936381Ssklower 	struct mbuf *cdm;
251036381Ssklower 	struct e_clear_data *ecd;
251136381Ssklower 
251236381Ssklower 	cdm = e_data(ecnrq);
251336381Ssklower 	if( cdm && cdm->m_len > 0 ) {
251436381Ssklower 		ecd = mtod(cdm, struct e_clear_data *);
251536381Ssklower 		switch( ecd->ecd_cause ) {
251636381Ssklower 			case 0x00:
251736381Ssklower 			case 0x80:
251836381Ssklower 				/* DTE originated; look at the diagnostic */
251936381Ssklower 				error = (CONL_ERROR_MASK | ecd->ecd_diagnostic);
252036381Ssklower 				goto done;
252136381Ssklower 
252236381Ssklower 			case 0x01: /* number busy */
252336381Ssklower 			case 0x81:
252436381Ssklower 			case 0x09: /* Out of order */
252536381Ssklower 			case 0x89:
252636381Ssklower 			case 0x11: /* Remot Procedure Error */
252736381Ssklower 			case 0x91:
252836381Ssklower 			case 0x19: /* reverse charging accept not subscribed */
252936381Ssklower 			case 0x99:
253036381Ssklower 			case 0x21: /* Incampat destination */
253136381Ssklower 			case 0xa1:
253236381Ssklower 			case 0x29: /* fast select accept not subscribed */
253336381Ssklower 			case 0xa9:
253436381Ssklower 			case 0x39: /* ship absent */
253536381Ssklower 			case 0xb9:
253636381Ssklower 			case 0x03: /* invalid facil request */
253736381Ssklower 			case 0x83:
253836381Ssklower 			case 0x0b: /* access barred */
253936381Ssklower 			case 0x8b:
254036381Ssklower 			case 0x13: /* local procedure error */
254136381Ssklower 			case 0x93:
254236381Ssklower 			case 0x05: /* network congestion */
254336381Ssklower 			case 0x85:
254436381Ssklower 			case 0x8d: /* not obtainable */
254536381Ssklower 			case 0x0d:
254636381Ssklower 			case 0x95: /* RPOA out of order */
254736381Ssklower 			case 0x15:
254836381Ssklower 				/* take out bit 8
254936381Ssklower 				 * so we don't have to have so many perror entries
255036381Ssklower 				 */
255136381Ssklower 				error = (CONL_ERROR_MASK | 0x100 | (ecd->ecd_cause & ~0x80));
255236381Ssklower 				goto done;
255336381Ssklower 
255436381Ssklower 			case 0xc1: /* gateway-detected proc error */
255536381Ssklower 			case 0xc3: /* gateway congestion */
255636381Ssklower 
255736381Ssklower 				error = (CONL_ERROR_MASK | 0x100 | ecd->ecd_cause);
255836381Ssklower 				goto done;
255936381Ssklower 		}
256036381Ssklower 	}
256136381Ssklower 	/* otherwise, a *hopefully* valid perror exists in the e_reason field */
256236381Ssklower 	error = ecnrq->e_reason;
256336381Ssklower 	if (error = 0) {
256436381Ssklower 		printf("Incoming PKT TYPE 0x%x with reason 0x%x\n",
256536381Ssklower 			ecnrq->e_cmd,
256636381Ssklower 			ecnrq->e_reason);
256736381Ssklower 		error = E_CO_HLI_DISCA;
256836381Ssklower 	}
256936381Ssklower 
257036381Ssklower done:
257136381Ssklower 	if(error & 0x1ff == 0) {
257236381Ssklower 		error = 0;
257336381Ssklower 	} else if( error & 0x1ff > sizeof(x25_error_stats)) {
257436381Ssklower 			ASSERT(0);
257536381Ssklower 	} else {
257636381Ssklower 			x25_error_stats[error& 0x1ff] ++;
257736381Ssklower 	}
257836381Ssklower 	return error;
257936381Ssklower }
258036381Ssklower 
258136381Ssklower /*
258236381Ssklower  * NAME:	consintr()
258336381Ssklower  * CALLED FROM:
258436381Ssklower  *  the eicon driver via software interrupt
258536381Ssklower  * FUNCTION and ARGUMENTS:
258636381Ssklower  *  processes incoming indications, passing them
258736381Ssklower  *  along to clnp, tp, or x.25-transport as appropriate.
258836381Ssklower  */
258936381Ssklower consintr()
259036381Ssklower {
259136381Ssklower 	struct	ifnet 					*ifp = consif;
259236381Ssklower 	register struct eicon_request 	*ecnrq;
259336381Ssklower 	register struct cons_pcb 		*copcb = (struct cons_pcb *)0;
259436381Ssklower 	register struct mbuf 			*m;
259536381Ssklower 	int 							s, s0 = splnet();
259636381Ssklower 
259736381Ssklower 	IncStat(co_intr);
259836381Ssklower 	ifp->if_ipackets ++;
259936381Ssklower 
260036381Ssklower 	for(;;) {
260136381Ssklower 		/*
260236381Ssklower 		 * Get next request off input queue
260336381Ssklower 		 */
260436381Ssklower 		s = splimp();
260536381Ssklower 		IF_DEQUEUE(&consintrq, m);
260636381Ssklower 		splx(s);
260736381Ssklower 		IFDEBUG(D_INCOMING)
260836381Ssklower 			printf("cons intr() 0x%x m_off 0x%x m_len 0x%x dequeued\n",
260936381Ssklower 				m, m?m->m_off:0, m?m->m_len:0);
261036381Ssklower 		ENDDEBUG
261136381Ssklower 
261236381Ssklower 		if (m == 0) {
261336381Ssklower 			splx(s0);
261436381Ssklower 			return;
261536381Ssklower 		}
261636381Ssklower 
261736381Ssklower 		if((m->m_off != MMINOFF)||(m->m_len != sizeof (struct eicon_request))){
261836381Ssklower 			ifp->if_ierrors ++;
261936381Ssklower 			IncStat(co_Rdrops);
262036381Ssklower 			printf("Cons R DROP! BAD MBUF FROM LL 0x%x sizeof(...) 0x%x\n",
262136381Ssklower 					m, sizeof(struct eicon_request));
262236381Ssklower 			continue;
262336381Ssklower 		}
262436381Ssklower 
262536381Ssklower 		ecnrq = mtod(m, struct eicon_request *);
262636381Ssklower 
262736381Ssklower 
262836381Ssklower 		IFDEBUG(D_INCOMING)
262936381Ssklower 			printf("INTR: e_cmd 0x%x, e_data 0x%x\n", ecnrq->e_cmd,
263036381Ssklower 				e_data(ecnrq));
263136381Ssklower 			if( e_data(ecnrq) != 0 ) {
263236381Ssklower 				/* let's just look at the first few bytes */
263336381Ssklower 				/*
263436381Ssklower 				dump_buf( e_data(ecnrq), (e_data(ecnrq))->m_len + 12);
263536381Ssklower 				*/
263636381Ssklower 				dump_buf( e_data(ecnrq), 20  + 12);
263736381Ssklower 			}
263836381Ssklower 		ENDDEBUG
263936381Ssklower 		IFTRACE(D_CDATA)
264036381Ssklower 			tptrace( TPPTmisc, "INTR: req_type m lun\n",
264136381Ssklower 				ecnrq->e_cmd, m, ecnrq->e_vc, 0);
264236381Ssklower 		ENDTRACE
264336381Ssklower 
264436381Ssklower 		switch( ecnrq->e_cmd ) {
264536381Ssklower 
264636381Ssklower 			case ECN_ACK:  /* data put on the board */
264736381Ssklower 				IncStat(co_ack);
264836381Ssklower 				ASSERT( ecnrq->e_vc != 0);
264936381Ssklower 				/* from ACKWAIT to OPEN */
265036381Ssklower 				if ( (copcb =
265136381Ssklower #ifdef ARGO_DEBUG
265236381Ssklower 					cons_chan_to_pcb( (int)ecnrq->e_vc, __LINE__ )
265336381Ssklower #else ARGO_DEBUG
265436381Ssklower 					cons_chan_to_pcb( (int)ecnrq->e_vc )
265536381Ssklower #endif ARGO_DEBUG
265636381Ssklower 										) == (struct cons_pcb *)0 )
265736381Ssklower 					break;
265836381Ssklower 				copcb->co_state = OPEN;
265936381Ssklower 				/*
266036381Ssklower 				 * Anything on the pending queue for this connection?
266136381Ssklower 				 */
266236381Ssklower 				if( copcb->co_pending.ifq_len == 0 ) {
266336381Ssklower 					if( copcb->co_proto->pr_ctlinput )
266436381Ssklower 						/* for the sake of higher layer protocol (tp) */
266536381Ssklower 						(*copcb->co_proto->pr_ctlinput)
266636381Ssklower 							(PRC_CONS_SEND_DONE,
266736381Ssklower 							(struct sockaddr_iso *)&copcb->co_faddr,
266836381Ssklower 							(caddr_t)copcb);
266936381Ssklower 				} else {
267036381Ssklower 					register struct mbuf *m0;
267136381Ssklower 
267236381Ssklower 					s = splimp();
267336381Ssklower 					IF_DEQUEUE( &copcb->co_pending, m0 );
267436381Ssklower 					splx(s);
267536381Ssklower 					/* CAN ONLY DO 1 item here
267636381Ssklower 					 * if you change this if to while, HA HA
267736381Ssklower 					 * it'll go right back onto
267836381Ssklower 					 * the pending queue (which means things will
267936381Ssklower 					 * be reordered on the queue!)
268036381Ssklower 					 */
268136381Ssklower 					if( m0 ) {
268236381Ssklower 						IFDEBUG(D_CDATA)
268336381Ssklower 							printf("ACK sending pending queue 0x%x len 0x%x\n",
268436381Ssklower 								m0, m0->m_len);
268536381Ssklower 						ENDDEBUG
268636381Ssklower 						ASSERT( m0->m_len != 0);
268736381Ssklower 						(void) cons_senddata(copcb, m0);
268836381Ssklower 					}
268936381Ssklower 				}
269036381Ssklower 
269136381Ssklower 				/* send more? */
269236381Ssklower 				break;
269336381Ssklower 
269436381Ssklower 			case ECN_ACCEPT:  /* call accepted at other end */
269536381Ssklower 				/* adr_src, adr_dst are as given in the ECN_CALL
269636381Ssklower 				 * pcb field is copied from our ECN_CALL
269736381Ssklower 				 * request, confirm gives me a channel number
269836381Ssklower 				 */
269936381Ssklower 				ASSERT( ecnrq->e_vc != 0);
270036381Ssklower 
270136381Ssklower 				IncStat(co_accept);
270236381Ssklower 				if(copcb =
270336381Ssklower #ifdef ARGO_DEBUG
270436381Ssklower 				cons_chan_to_pcb((int)ecnrq->e_vc, __LINE__ )
270536381Ssklower #else ARGO_DEBUG
270636381Ssklower 				cons_chan_to_pcb((int)ecnrq->e_vc)
270736381Ssklower #endif ARGO_DEBUG
270836381Ssklower 												) {
270936381Ssklower 					/* error: already exists */
271036381Ssklower 					printf("cons PANIC: dbl confirm for channel 0x%x\n",
271136381Ssklower 						ecnrq->e_vc);
271236381Ssklower 					break;
271336381Ssklower 				}
271436381Ssklower 				copcb = (struct cons_pcb *)ecnrq->e_pcb;
271536381Ssklower 				if( copcb->co_myself != copcb ) {
271636381Ssklower 					struct mbuf *mm;
271736381Ssklower 					/* TODO: REMOVE */
271836381Ssklower 					ASSERT(0);
271936381Ssklower 					printf("BAD e_pcb from ecn (0x%x) cmd 0x%x\n",
272036381Ssklower 						ecnrq->e_pcb, ecnrq->e_cmd);
272136381Ssklower 					mm = dtom( copcb );
272236381Ssklower 					if(mm->m_type == MT_FREE)
272336381Ssklower 						printf("FREED MBUF!\n");
272436381Ssklower 					dump_buf (ecnrq, sizeof (*ecnrq));
272536381Ssklower 					panic("BAD ecnrq");
272636381Ssklower 					break;
272736381Ssklower 				}
272836381Ssklower 				touch(copcb);
272936381Ssklower 				copcb->co_state = OPEN;
273036381Ssklower 				copcb->co_channel = (int)ecnrq->e_vc;
273136381Ssklower 				if(copcb->co_socket) {
273236381Ssklower 					/* tp0 will take care of itself */
273336381Ssklower 					if( copcb->co_flags & CONSF_XTS)
273436381Ssklower 						soisconnected(copcb->co_socket); /* wake 'em up */
273536381Ssklower 				}
273636381Ssklower 				wakeup( (caddr_t)&copcb->co_state );
273736381Ssklower 
273836381Ssklower 				/*
273936381Ssklower 				 * Anything on the pending queue for this connection?
274036381Ssklower 				 */
274136381Ssklower 				if( copcb->co_pending.ifq_len > 0 ) {
274236381Ssklower 					register struct mbuf *m0;
274336381Ssklower 
274436381Ssklower 					s = splimp();
274536381Ssklower 					IF_DEQUEUE( &copcb->co_pending, m0 );
274636381Ssklower 					splx(s);
274736381Ssklower 					/* CAN ONLY DO 1 item here
274836381Ssklower 					 * if you change this if to while, HA HA
274936381Ssklower 					 * it'll go right back onto
275036381Ssklower 					 * the pending queue (which means things will
275136381Ssklower 					 * be reordered on the queue!)
275236381Ssklower 					 */
275336381Ssklower 					if( m0 ) {
275436381Ssklower 						IFDEBUG(D_CDATA)
275536381Ssklower 							printf("ACPT sending pending queue 0x%x len 0x%x\n",
275636381Ssklower 								m0, m0->m_len);
275736381Ssklower 						ENDDEBUG
275836381Ssklower 						ASSERT( m0->m_len != 0);
275936381Ssklower 						(void) cons_senddata(copcb, m0);
276036381Ssklower 					}
276136381Ssklower 				}
276236381Ssklower 				break;
276336381Ssklower 
276436381Ssklower 			case ECN_REFUSE:
276536381Ssklower 				/* other end refused our connect request */
276636381Ssklower 				/* src, dst are as given in the ECN_CALL */
276736381Ssklower 
276836381Ssklower 				IncStat(co_refuse);
276936381Ssklower 				copcb = (struct cons_pcb *)ecnrq->e_pcb;
277036381Ssklower 				if( copcb->co_myself != copcb ) {
277136381Ssklower 					struct mbuf *mm;
277236381Ssklower 					/* TODO: REMOVE */
277336381Ssklower 					ASSERT(0);
277436381Ssklower 					printf("BAD e_pcb from ecn (0x%x) cmd 0x%x\n",
277536381Ssklower 						ecnrq->e_pcb, ecnrq->e_cmd);
277636381Ssklower 					mm = dtom( copcb );
277736381Ssklower 					if(mm->m_type == MT_FREE)
277836381Ssklower 						printf("FREED MBUF!\n");
277936381Ssklower 					dump_buf (ecnrq, sizeof (*ecnrq));
278036381Ssklower 					dump_buf (copcb, sizeof (*copcb));
278136381Ssklower 					panic("BAD ecnrq");
278236381Ssklower 					break;
278336381Ssklower 				}
278436381Ssklower 				touch(copcb);
278536381Ssklower 				copcb->co_state = CLOSED; /* do we have to do a clear?? */
278636381Ssklower 				copcb->co_channel = X_NOCHANNEL;
278736381Ssklower 				if(copcb->co_socket) {
278836381Ssklower 					copcb->co_socket->so_error = ECONNREFUSED;
278936381Ssklower 					/* TODO: if there's diagnostic info in the
279036381Ssklower 					 * packet, and it's more useful than this E*,
279136381Ssklower 					 * get it
279236381Ssklower 					 */
279336381Ssklower 					soisdisconnected(copcb->co_socket); /* wake 'em up */
279436381Ssklower 					IFDEBUG(D_INCOMING)
279536381Ssklower 						printf("ECN_REFUSE: waking up 0x%x\n",
279636381Ssklower 							(caddr_t)&copcb->co_state );
279736381Ssklower 					ENDDEBUG
279836381Ssklower 					wakeup( (caddr_t)&copcb->co_state );
279936381Ssklower 				}
280036381Ssklower 				/*
280136381Ssklower 				 * Anything on the pending queue for this connection?
280236381Ssklower 				 */
280336381Ssklower 				while( copcb->co_pending.ifq_len > 0 ) {
280436381Ssklower 					register struct mbuf *m0;
280536381Ssklower 
280636381Ssklower 					s = splimp();
280736381Ssklower 					IF_DEQUEUE( &copcb->co_pending, m0 );
280836381Ssklower 					splx(s);
280936381Ssklower 					m_freem(m0);
281036381Ssklower 				}
281136381Ssklower 				if ( ecnrq->e_reason  == E_CO_NORESOURCES ) {
281236381Ssklower 					IncStat(co_noresources);
281336381Ssklower 					cons_clear_and_detach( copcb, DONTCLEAR, PRC_QUENCH );
281436381Ssklower 				} else if(copcb->co_socket ) {
281536381Ssklower 					copcb->co_socket->so_error = find_error_reason( ecnrq );
281636381Ssklower 				}
281736381Ssklower 				break;
281836381Ssklower 
281936381Ssklower 			case ECN_CONNECT:  /* incoming call */
282036381Ssklower 				/*
282136381Ssklower 				 * ECN_CONNECT indication gives adc_src, adc_dst  and channel
282236381Ssklower 				 */
282336381Ssklower 				ASSERT( ecnrq->e_vc != 0);
282436381Ssklower 
282536381Ssklower 				IncStat(co_connect);
282636381Ssklower 				cons_incoming(ifp, ecnrq);
282736381Ssklower 				break;
282836381Ssklower 
282936381Ssklower 			case ECN_RESET:
283036381Ssklower 			case ECN_CLEAR:
283136381Ssklower 				/*
283236381Ssklower 				 * ECN_CLEAR(indication) (if we can construct such a beast)
283336381Ssklower 				 * gives e_vc,
283436381Ssklower 				 * Throw away anything queued pending on this connection
283536381Ssklower 				 * give a reset indication to the upper layer if TP
283636381Ssklower 				 * free the mbufs
283736381Ssklower 				 */
283836381Ssklower 				ASSERT( ecnrq->e_vc != 0);
283936381Ssklower 				if( ecnrq->e_cmd == ECN_CLEAR )
284036381Ssklower 					IncStat(co_clear_in);
284136381Ssklower 				else
284236381Ssklower 					IncStat(co_reset_in);
284336381Ssklower #ifdef ARGO_DEBUG
284436381Ssklower 				if( ! (copcb=cons_chan_to_pcb((int)ecnrq->e_vc, __LINE__)) )
284536381Ssklower #else ARGO_DEBUG
284636381Ssklower 				if( ! (copcb=cons_chan_to_pcb((int)ecnrq->e_vc)) )
284736381Ssklower #endif ARGO_DEBUG
284836381Ssklower 
284936381Ssklower 					break;
285036381Ssklower 				while( copcb->co_pending.ifq_len ) {
285136381Ssklower 					register struct mbuf *m0;
285236381Ssklower 
285336381Ssklower 					s = splimp();
285436381Ssklower 					IF_DEQUEUE( &copcb->co_pending, m0 );
285536381Ssklower 					splx(s);
285636381Ssklower 					m_freem(m0);
285736381Ssklower 				}
285836381Ssklower 				copcb->co_state = CLOSED; /* do we have to do a clear? */
285936381Ssklower 				copcb->co_channel = X_NOCHANNEL;
286036381Ssklower 
286136381Ssklower 				cons_clear_and_detach( copcb, DONTCLEAR, PRC_ROUTEDEAD );
286236381Ssklower 				if (copcb->co_socket ) {
286336381Ssklower 					copcb->co_socket->so_error = find_error_reason( ecnrq );
286436381Ssklower 				}
286536381Ssklower 				break;
286636381Ssklower 
286736381Ssklower 			case ECN_RECEIVE:
286836381Ssklower 				 /*
286936381Ssklower 				  * ECN_RECEIVE (read)
287036381Ssklower 				  */
287136381Ssklower 				ASSERT( ecnrq->e_vc != 0);
287236381Ssklower 				IncStat(co_receive);
287336381Ssklower 				{
287436381Ssklower 					/* TODO: REMOVE */
287536381Ssklower 					struct mbuf *thedata = e_data(ecnrq);
287636381Ssklower 					u_int *firstint = mtod( thedata, u_int *);
287736381Ssklower 
287836381Ssklower 					if( (*firstint & 0xff000000) != 0x81000000 ) {
287936381Ssklower 						/* not clnp */
288036381Ssklower 						switch( ((*firstint) & 0x00ff0000) >> 20 ) {
288136381Ssklower 						case 0x1:
288236381Ssklower 						case 0x2:
288336381Ssklower 						case 0x3:
288436381Ssklower 						case 0x6:
288536381Ssklower 						case 0x7:
288636381Ssklower 						case 0x8:
288736381Ssklower 						case 0xc:
288836381Ssklower 						case 0xd:
288936381Ssklower 						case 0xe:
289036381Ssklower 						case 0xf:
289136381Ssklower 							break;
289236381Ssklower 						default:
289336381Ssklower 							printf(" ECN_RECEIVE! BAD DATA\n" );
289436381Ssklower 							dump_buf( thedata, 20 + 12 );
289536381Ssklower 							m_freem( m );
289636381Ssklower 							splx(s0);
289736381Ssklower 						}
289836381Ssklower 					}
289936381Ssklower 				}
290036381Ssklower 				if ( (copcb =
290136381Ssklower #ifdef ARGO_DEBUG
290236381Ssklower 					cons_chan_to_pcb( (int)ecnrq->e_vc, __LINE__ )
290336381Ssklower #else ARGO_DEBUG
290436381Ssklower 					cons_chan_to_pcb( (int)ecnrq->e_vc )
290536381Ssklower #endif ARGO_DEBUG
290636381Ssklower 											) == (struct cons_pcb *)0 ) {
290736381Ssklower 					ifp->if_ierrors ++;
290836381Ssklower 					IFTRACE(D_CDATA)
290936381Ssklower 						tptrace(TPPTmisc, "ECN_RECEIVE DROPPED chan \n",
291036381Ssklower 							ecnrq->e_vc, 0, 0, 0);
291136381Ssklower 					ENDTRACE
291236381Ssklower 					break;
291336381Ssklower 				}
291436381Ssklower 
291536381Ssklower 				touch(copcb);
291636381Ssklower 				if( ecnrq->e_info & ECN_INFO_RCVD_INT )  {
291736381Ssklower 					/* interrupt packet */
291836381Ssklower 						printf("consintr: interrupt pkttype : DROPPED\n");
291936381Ssklower 					IncStat(co_intrpt_pkts_in);
292036381Ssklower 					IncStat(co_Rdrops);
292136381Ssklower 					break;
292236381Ssklower 				}
292336381Ssklower 				/* new way */
292436381Ssklower 				if( copcb->co_proto == CLNP_proto )
292536381Ssklower 				{
292636381Ssklower 					/* IP: put it on the queue and set soft interrupt */
292736381Ssklower 					struct ifqueue *ifq;
292836381Ssklower 					extern struct ifqueue clnlintrq;
292936381Ssklower 					register struct mbuf *ifpp; /* for ptr to ifp */
293036381Ssklower 					register struct mbuf *data = e_data(ecnrq);
293136381Ssklower 
293236381Ssklower 					total_pkts_to_clnp ++;
293336381Ssklower 
293436381Ssklower 					/* when acting as a subnet service, have to prepend a
293536381Ssklower 					 * pointer to the ifnet before handing this to clnp
293636381Ssklower 					 * GAG
293736381Ssklower 					 */
293836381Ssklower 					if( ( data->m_off > MMINOFF + sizeof(struct snpa_hdr)) &&
293936381Ssklower 						( data->m_off <= MMAXOFF )) {
294036381Ssklower 						data->m_off -= sizeof(struct snpa_hdr);
294136381Ssklower 						data->m_len += sizeof(struct snpa_hdr);
294236381Ssklower 					} else {
294336381Ssklower 						MGET(ifpp, M_DONTWAIT, MT_XHEADER);
294436381Ssklower 						if( !ifpp ) {
294536381Ssklower 							ifp->if_ierrors ++;
294636381Ssklower 							splx(s0);
294736381Ssklower 							m_freem(m); /* frees everything */
294836381Ssklower 							return;
294936381Ssklower 						}
295036381Ssklower 						ifpp->m_len = sizeof(struct snpa_hdr);
295136381Ssklower 						ifpp->m_act = 0;
295236381Ssklower 						ifpp->m_next = data;
295336381Ssklower 						data = ifpp;
295436381Ssklower 					}
295536381Ssklower 					IFTRACE(D_CDATA)
295636381Ssklower 						tptrace(TPPTmisc, "-->CLNP copcb\n", copcb, 0, 0, 0);
295736381Ssklower 					ENDTRACE
295836381Ssklower 					{
295936381Ssklower 						/*
296036381Ssklower 						 *	TODO: if we ever use esis/cons we have to
296136381Ssklower 						 *	think of something reasonable to stick in the
296236381Ssklower 						 *	snh_shost,snh_dhost fields. I guess
296336381Ssklower 						 *	the x.121 address is what we want.
296436381Ssklower 						 *
296536381Ssklower 						 *	That would also require length fields in the
296636381Ssklower 						 *	snpa_hdr structure.
296736381Ssklower 						 */
296836381Ssklower 						struct snpa_hdr 	*snh =
296936381Ssklower 							mtod(data, struct snpa_hdr *);
297036381Ssklower 						bzero((caddr_t)&snh, sizeof(struct snpa_hdr));
297136381Ssklower 						bcopy((caddr_t)&ifp, (caddr_t)&snh->snh_ifp,
297236381Ssklower 							sizeof(struct ifnet *));
297336381Ssklower 					}
297436381Ssklower 					*( mtod(data, struct ifnet **) ) = ifp; /* KLUDGE */
297536381Ssklower 
297636381Ssklower 					ifq = &clnlintrq;
297736381Ssklower 					splimp();
297836381Ssklower 					if (IF_QFULL(ifq)) {
297936381Ssklower 						IF_DROP(ifq);
298036381Ssklower 						m_freem(m);
298136381Ssklower 						IFDEBUG(D_INCOMING)
298236381Ssklower 							printf("DROPPED! ecnrq 0x%x, data 0x%x\n", m,data);
298336381Ssklower 						ENDDEBUG
298436381Ssklower 						splx(s0);
298536381Ssklower 						ifp->if_ierrors ++;
298636381Ssklower 						return;
298736381Ssklower 					}
298836381Ssklower 					IF_ENQUEUE(ifq, data);
298936381Ssklower 					IFDEBUG(D_INCOMING)
299036381Ssklower 						printf(
299136381Ssklower 				"0x%x enqueued on ip Q: m_len 0x%x m_type 0x%x m_off 0x%x\n",
299236381Ssklower 							data, data->m_len, data->m_type, data->m_off);
299336381Ssklower 						dump_buf(mtod(data, caddr_t), data->m_len);
299436381Ssklower 					ENDDEBUG
299536381Ssklower 					e_data(ecnrq) = (struct mbuf *)0;
299636381Ssklower 					schednetisr(NETISR_CLNP);
299736381Ssklower 				} else {
299836381Ssklower 					/* HL is NOT clnp */
299936381Ssklower 					IFTRACE(D_CDATA)
300036381Ssklower 						tptrace(TPPTmisc,
300136381Ssklower 							"-->HL pr_input so copcb channel\n",
300236381Ssklower 							copcb->co_proto->pr_input,
300336381Ssklower 							copcb->co_socket, copcb,
300436381Ssklower 							copcb->co_channel);
300536381Ssklower 					ENDTRACE
300636381Ssklower 					IFDEBUG(D_INCOMING)
300736381Ssklower 						printf( "0x%x --> HL proto 0x%x chan 0x%x\n",
300836381Ssklower 							e_data(ecnrq), copcb->co_proto, copcb->co_channel );
300936381Ssklower 					ENDDEBUG
301036381Ssklower 
301136381Ssklower 					(*copcb->co_proto->pr_input)(e_data(ecnrq),
301236381Ssklower 						&copcb->co_faddr,
301336381Ssklower 						&copcb->co_laddr,
301436381Ssklower 						copcb->co_socket, /* used by cons-transport interface */
301536381Ssklower 						(copcb->co_flags & CONSF_DGM)?0:
301636381Ssklower 							copcb->co_channel);/* used by tp-cons interface */
301736381Ssklower 
301836381Ssklower 					/*
301936381Ssklower 					 * the pr_input will free the data chain, so we must
302036381Ssklower 					 * zero the ptr to is so that m_free doesn't panic
302136381Ssklower 					 */
302236381Ssklower 					e_data(ecnrq) = (struct mbuf *)0;
302336381Ssklower 				}
302436381Ssklower 				break;
302536381Ssklower 
302636381Ssklower 			default:
302736381Ssklower 				/* error */
302836381Ssklower 				ifp->if_ierrors ++;
302936381Ssklower 				printf("consintr: unknown request\n");
303036381Ssklower 		}
303136381Ssklower 		IFDEBUG(D_INCOMING)
303236381Ssklower 			printf("consintr: m_freem( 0x%x )\n", m);
303336381Ssklower 		ENDDEBUG
303436381Ssklower 		m_freem( m );
303536381Ssklower 	}
303636381Ssklower 	splx(s0);
303736381Ssklower }
303836381Ssklower 
303936381Ssklower /*
304036381Ssklower  * Process an ioctl request.
304136381Ssklower  * also set-time-limit, extend-time-limit
304236381Ssklower  * for ALL channels, the time-limit ioctls will be done by open-a-dummy-socket,
304336381Ssklower  * do ioctl with the channel number, close the socket (dumb!).
304436381Ssklower  */
304536381Ssklower /* ARGSUSED */
304636381Ssklower cons_ioctl(so, cmd, data)
304736381Ssklower 	struct socket *so;
304836381Ssklower 	int cmd;
304936381Ssklower 	caddr_t data;
305036381Ssklower {
305136381Ssklower 	int 	s = splnet();
305236381Ssklower 	int 	error = 0;
305336381Ssklower 
305436381Ssklower 	IFDEBUG(D_CCONS)
305536381Ssklower 		printf("cons_ioctl( cmd 0x%x )\n", cmd);
305636381Ssklower 	ENDDEBUG
305736381Ssklower 
305836381Ssklower #ifdef notdef
305936381Ssklower 	switch (cmd) {
306036381Ssklower 
306136381Ssklower 	default:
306236381Ssklower #endif notdef
306336381Ssklower 		error = EOPNOTSUPP;
306436381Ssklower #ifdef notdef
306536381Ssklower 	}
306636381Ssklower #endif notdef
306736381Ssklower 
306836381Ssklower 	splx(s);
306936381Ssklower 	return (error);
307036381Ssklower }
307136381Ssklower 
307236381Ssklower 
307336381Ssklower /*
307436381Ssklower  *************************************************************
307536381Ssklower  *                                                           *
307636381Ssklower  *                                                           *
307736381Ssklower  * Interface to CO Subnetwork service from CLNP              *
307836381Ssklower  * Must be a device interface.                             *****
307936381Ssklower  *                                                          ***
308036381Ssklower  *                                                           *
308136381Ssklower  *                                                          Poof!
308236381Ssklower  */
308336381Ssklower 
308436381Ssklower /*
308536381Ssklower  * NAME:	consioctl()
308636381Ssklower  * CALLED FROM:
308736381Ssklower  * 	called through the ifnet structure.
308836381Ssklower  * FUNCTION and ARGUMENTS:
308936381Ssklower  *	the usual ioctl stuff
309036381Ssklower  * RETURNS:
309136381Ssklower  * 	E*
309236381Ssklower  * SIDE EFFECTS:
309336381Ssklower  * NOTES:
309436381Ssklower  */
309536381Ssklower consioctl(ifp, cmd, data)
309636381Ssklower 	register struct ifnet *ifp;
309736381Ssklower 	register int cmd;
309836381Ssklower 	register caddr_t data;
309936381Ssklower {
310036381Ssklower 	register struct ifaddr 		*ifa = (struct ifaddr *)data;
310136381Ssklower 	register int 				s = splimp();
310236381Ssklower 	register struct ifreq 		*ifr = (struct ifreq *)data;
310336381Ssklower 	register int 				error = 0;
310436381Ssklower 	void						consshutdown();
310536381Ssklower 
310636381Ssklower 	switch (cmd) {
310736381Ssklower 	case SIOCSIFADDR:
310836381Ssklower 		switch (ifa->ifa_addr.sa_family) {
310936381Ssklower 		case AF_ISO:
311036381Ssklower 			if( (ifp->if_flags & IFF_UP ) == 0)
311136381Ssklower 				consinit(ifp->if_unit);
311236381Ssklower 			break;
311336381Ssklower 		default:
311436381Ssklower 			printf("CANNOT config cons with address family %d\n",
311536381Ssklower 				ifa->ifa_addr.sa_family);
311636381Ssklower 			break;
311736381Ssklower 		}
311836381Ssklower 		break;
311936381Ssklower 	case SIOCSIFFLAGS:
312036381Ssklower 		IFDEBUG(D_CCONS)
312136381Ssklower 			printf("consioctl: set flags to x%x\n", ifr->ifr_flags);
312236381Ssklower 			printf("consioctl: ifp flags are x%x\n", ifp->if_flags);
312336381Ssklower 		ENDDEBUG
312436381Ssklower 		if( ifr->ifr_flags & IFF_LOOPBACK )
312536381Ssklower 			ifp->if_flags |= IFF_LOOPBACK;
312636381Ssklower 		else
312736381Ssklower 			ifp->if_flags &= ~IFF_LOOPBACK;
312836381Ssklower 
312936381Ssklower 		/* if board is down but request takes it up, init the board */
313036381Ssklower 		if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0)
313136381Ssklower 			consinit(ifp->if_unit);
313236381Ssklower 
313336381Ssklower 		/* if board is up but request takes it down, shut the board down */
313436381Ssklower 		if (((ifr->ifr_flags & IFF_UP) == 0) && (ifp->if_flags & IFF_UP)) {
313536381Ssklower 			consshutdown(ifp->if_unit);
313636381Ssklower 		}
313736381Ssklower 		IFDEBUG(D_CCONS)
313836381Ssklower 			printf("consioctl: flags are x%x\n", ifp->if_flags);
313936381Ssklower 		ENDDEBUG
314036381Ssklower 		break;
314136381Ssklower 	case SIOCGSTATUS:
314236381Ssklower 		/* warning: must coerse ifp to (struct ifstatus *) in order to use */
314336381Ssklower 		IFDEBUG(D_CCONS)
314436381Ssklower 			printf("consioctl: EICON status request\n");
314536381Ssklower 		ENDDEBUG
314636381Ssklower #if NECN>0
314736381Ssklower 		ecnioctl(ifp, cmd, data);
314836381Ssklower #else
314936381Ssklower 		error = ENODEV;
315036381Ssklower #endif NECN>0
315136381Ssklower 		break;
315236381Ssklower 	default:
315336381Ssklower 		error = EINVAL;
315436381Ssklower 	}
315536381Ssklower 	splx(s);
315636381Ssklower 	return error;
315736381Ssklower }
315836381Ssklower 
315936381Ssklower /*
316036381Ssklower  * NAME:	consattach()
316136381Ssklower  * CALLED FROM:
316236381Ssklower  * 	cons_init() (which comes from autoconf)
316336381Ssklower  * FUNCTION and ARGUMENTS:
316436381Ssklower  *	creates an ifp and fills it in; calls ifattach() on it.
316536381Ssklower  * RETURNS:
316636381Ssklower  *  no return value
316736381Ssklower  * SIDE EFFECTS:
316836381Ssklower  * NOTES:
316936381Ssklower  */
317036381Ssklower consattach()
317136381Ssklower {
317236381Ssklower 	register struct ifnet		*ifp;
317336381Ssklower 	register struct mbuf 		*m;
317436381Ssklower 
317536381Ssklower 	if(sizeof(struct ifnet) > MLEN) {
317636381Ssklower 		printf("Can't attach cons!  sizeof(struct ifnet) > MLEN\n");
317736381Ssklower 		return;
317836381Ssklower 	}
317936381Ssklower 	MGET(m, M_DONTWAIT, MT_IFADDR);
318036381Ssklower 	if( !m ) {
318136381Ssklower 		printf("Can't attach cons!  NO MBUFS!\n");
318236381Ssklower 		return;
318336381Ssklower 	}
318436381Ssklower 	m->m_len = sizeof(struct ifnet);
318536381Ssklower 	ifp = consif = mtod(m, struct ifnet *);
318636381Ssklower 	ifp->if_unit = 0;
318736381Ssklower 	ifp->if_name = "cons";
318836381Ssklower 	ifp->if_mtu = ECN_MTU;
318936381Ssklower 	ifp->if_init = consinit;
319036381Ssklower 	ifp->if_ioctl = consioctl;
319136381Ssklower 	ifp->if_output = cosns_output; /* called by clnp */
319236381Ssklower 	ifp->if_flags = IFF_LOOPBACK;  /* default */
319336381Ssklower 	if_attach(ifp);
319436381Ssklower 	printf("cons%d: pseudo device attached \n", ifp->if_unit);
319536381Ssklower }
319636381Ssklower 
319736381Ssklower /*
319836381Ssklower  * NAME:	consinit()
319936381Ssklower  * CALLED FROM:
320036381Ssklower  * 	consioctl()
320136381Ssklower  * FUNCTION and ARGUMENTS:
320236381Ssklower  * 	Initializes apropos data structures, etc.
320336381Ssklower  *  Marks the device as up.
320436381Ssklower  *  Zaps the address list.
320536381Ssklower  *  Calls device layer restart on the device if necessary.
320636381Ssklower  */
320736381Ssklower Static
320836381Ssklower consinit(_unit)
320936381Ssklower register int	_unit;	/* unit to initialize */
321036381Ssklower {
321136381Ssklower 	struct ifnet			*ecnifp();
321236381Ssklower 	struct ifnet 			*ifp;
321336381Ssklower 	int		s;
321436381Ssklower 
321536381Ssklower 	if ((ifp = ecnifp(_unit)) != (struct ifnet *)0 ) {
321636381Ssklower 		ecnrestart(ifp);
321736381Ssklower 		IncStat(co_restart);
321836381Ssklower 	}
321936381Ssklower 	if (consif->if_addrlist == (struct ifaddr *)0)
322036381Ssklower 		return;
322136381Ssklower 	if ((consif->if_flags & IFF_UP) == 0) {
322236381Ssklower 		s = splimp();
322336381Ssklower 		consif->if_flags |= IFF_UP;
322436381Ssklower 		splx(s);
322536381Ssklower 	}
322636381Ssklower 
322736381Ssklower }
322836381Ssklower 
322936381Ssklower /*
323036381Ssklower  * NAME:	consshutdown()
323136381Ssklower  * CALLED FROM:
323236381Ssklower  *	cons_ioctl() when user takes down an interface w/ SIOCSIFFLAGS
323336381Ssklower  * FUNCTION and ARGUMENTS:
323436381Ssklower  *  calls lower layer shutdown routine on the device.
323536381Ssklower  *  and marks the if as down if the if is the sw loopback pseudodevice.
323636381Ssklower  * RETURNS:
323736381Ssklower  *	no return value
323836381Ssklower  */
323936381Ssklower void
324036381Ssklower consshutdown(_unit)
324136381Ssklower register int	_unit;	/* unit to shutdown */
324236381Ssklower {
324336381Ssklower 	extern	struct ifnet 	*ecnifp();
324436381Ssklower 	struct ifnet 			*ifp;
324536381Ssklower 	int 					s;
324636381Ssklower 
324736381Ssklower 	if ((ifp = ecnifp(_unit)) != (struct ifnet *)0 ) {
324836381Ssklower 		ecnshutdown(ifp);
324936381Ssklower 	}
325036381Ssklower 	if ((consif->if_flags & IFF_UP) ) {
325136381Ssklower 		s = splimp();
325236381Ssklower 		consif->if_flags &= ~IFF_UP;
325336381Ssklower 		splx(s);
325436381Ssklower 	}
325536381Ssklower }
325636381Ssklower #endif KERNEL
325736381Ssklower 
325836381Ssklower /*
325936381Ssklower  * NAME:	munge()
326036381Ssklower  * CALLED FROM:
326136381Ssklower  * 	cons_pcbbind(), cons_usrreq()
326236381Ssklower  * FUNCTION and ARGUMENTS:
326336381Ssklower  *  Takes the argument (value) and stashes it into the last two
326436381Ssklower  *  nibbles of an X.121 address.  Does this in the two nibbles beginning
326536381Ssklower  *  at the location defined by the character pointer (dst_octet) and the
326636381Ssklower  *  integer (dst_nibble).  Nibble 0 is the lower nibble (high
326736381Ssklower  *  order 4 bits); nibble 1 is the low order 4 bits of *(dst_octet).
326836381Ssklower  *
326936381Ssklower  * RETURNS:
327036381Ssklower  * 	no return value
327136381Ssklower  */
327236381Ssklower Static
327336381Ssklower munge( value, dst_octet, dst_nibble)
327436381Ssklower 	int value;
327536381Ssklower 	caddr_t dst_octet;
327636381Ssklower 	int dst_nibble;
327736381Ssklower {
327836381Ssklower 	IFDEBUG(D_CCONN)
327936381Ssklower 		printf("MUNGE: value 0x%x dst_octet 0x%x, nibble 0x%x)\n",
328036381Ssklower 			value, dst_octet, dst_nibble);
328136381Ssklower 	ENDDEBUG
328236381Ssklower 	if (value >= ISO_PORT_RESERVED)
328336381Ssklower 		value -= 1000;
328436381Ssklower 
328536381Ssklower 	{
328636381Ssklower 		/* convert so it  looks like a decimal number */
328736381Ssklower 		register int tens, ones;
328836381Ssklower 
328936381Ssklower 		tens = value/10;
329036381Ssklower 		ASSERT( tens <= 9 );
329136381Ssklower 		ones = value - (tens * 10);
329236381Ssklower 
329336381Ssklower 		value = tens * 16 + ones;
329436381Ssklower 	}
329536381Ssklower 
329636381Ssklower 	dst_octet --;
329736381Ssklower 	/* leave nibble same 'cause it's one after the last set nibble */
329836381Ssklower 
329936381Ssklower 	*dst_octet &= ~(0xff<<(dst_nibble << 2)); /* zero it */
330036381Ssklower 	*dst_octet |= ((value>>4) << (dst_nibble<<2));
330136381Ssklower 	dst_nibble = 1-dst_nibble;
330236381Ssklower 	dst_octet += dst_nibble;
330336381Ssklower 
330436381Ssklower 	*dst_octet &= ~(0xff<<(dst_nibble << 2)); /* zero it */
330536381Ssklower 	*dst_octet |= ((value&0xff) << (dst_nibble<<2));
330636381Ssklower }
330736381Ssklower 
330836381Ssklower /*
330936381Ssklower  * NAME:	unmunge()
331036381Ssklower  * CALLED FROM:
331136381Ssklower  *  DTEtoNSAP(), FACILtoNSAP()
331236381Ssklower  * FUNCTION and ARGUMENTS:
331336381Ssklower  *  return the port/tsuffix represented by the two digits found in a
331436381Ssklower  *  bcd string beginning at the (dst_nibble)th nibble of the
331536381Ssklower  *  octet BEFORE (dst_octet).
331636381Ssklower  *
331736381Ssklower  * dst_octet,dst_nibble  is the nibble after the one we'll look at
331836381Ssklower  * RETURNS:
331936381Ssklower  *  an integer, the port/tsuffix
332036381Ssklower  *  Note- converts to a port > 1000 if necessary.
332136381Ssklower  */
332236381Ssklower Static int
332336381Ssklower unmunge( dst_octet, dst_nibble )
332436381Ssklower 	caddr_t dst_octet;
332536381Ssklower 	int dst_nibble;
332636381Ssklower {
332736381Ssklower 		register u_short last = 0;
332836381Ssklower 
332936381Ssklower 		dst_octet --;
333036381Ssklower 		/* leave nibble same 'cause it's one after the last set nibble */
333136381Ssklower 		IFDEBUG(D_CADDR)
333236381Ssklower 			printf("unmunge: *octet 0x%x, nibble 0x%x\n", *dst_octet,
333336381Ssklower 				dst_nibble);
333436381Ssklower 		ENDDEBUG
333536381Ssklower 
333636381Ssklower 		last = ((*dst_octet) & (0xff<<(dst_nibble<<2)));
333736381Ssklower 		dst_nibble = 1-dst_nibble;
333836381Ssklower 		dst_octet += dst_nibble;
333936381Ssklower 
334036381Ssklower 		last |= ((*dst_octet) & (0xff<<(dst_nibble << 2)));
334136381Ssklower 		{
334236381Ssklower 			/* convert to a decimal number */
334336381Ssklower 			register int tens, ones;
334436381Ssklower 
334536381Ssklower 			tens = (last&0xf0)>>4;
334636381Ssklower 			ones = last&0xf;
334736381Ssklower 
334836381Ssklower 			last = tens * 10 + ones;
334936381Ssklower 		}
335036381Ssklower 
335136381Ssklower 		IFDEBUG(D_CADDR)
335236381Ssklower 			printf("unmunge computes 0x%x\n", last);
335336381Ssklower 		ENDDEBUG
335436381Ssklower 		if((int)last+1000 >= ISO_PORT_RESERVED)
335536381Ssklower 			last += 1000;
335636381Ssklower 		IFDEBUG(D_CADDR)
335736381Ssklower 			printf("unmunge returns 0x%x\n", last);
335836381Ssklower 		ENDDEBUG
335936381Ssklower 		return last;
336036381Ssklower }
336136381Ssklower 
336236381Ssklower /*
336336381Ssklower  * NAME:	make_partial_x25_packet()
336436381Ssklower  *
336536381Ssklower  * FUNCTION and ARGUMENTS:
336636381Ssklower  *	Makes part of an X.25 call packet, for use by the eicon board.
336736381Ssklower  *  (src) and (dst) are the NSAP-addresses of source and destination.
336836381Ssklower  *	(proto) is the higher-layer protocol number (in iso.h)
336936381Ssklower  *	(buf) is a ptr to a buffer into which to write this partial header.
337036381Ssklower  *
337136381Ssklower  *  The partial header looks like (choke):
337236381Ssklower  *	octet		meaning
337336381Ssklower  *  1			calling DTE len  |  called DTE len (lengths in nibbles)
337436381Ssklower  *  2..n-1		called DTE addr  | (<-- boundary may be middle of an octet)
337536381Ssklower  *  			calling DTE addr  | zero nibble to round to octet boundary.
337636381Ssklower  *	n			Facility length (in octets)
337736381Ssklower  *	n+1			Facility field, which is a set of:
337836381Ssklower  *	  m			facil code
337936381Ssklower  *	  m+1		facil param len (for >2-byte facilities) in octets
338036381Ssklower  *	  m+2..p	facil param field
338136381Ssklower  *  q			user data (protocol identification octet)
338236381Ssklower  *
338336381Ssklower  *
338436381Ssklower  * RETURNS:
338536381Ssklower  *  0 if OK
338636381Ssklower  *  E* if failed.
338736381Ssklower  */
338836381Ssklower 
338936381Ssklower #ifdef X25_1984
339036381Ssklower int cons_use_facils = 1;
339136381Ssklower #else X25_1984
339236381Ssklower int cons_use_facils = 0;
339336381Ssklower #endif X25_1984
339436381Ssklower 
339536381Ssklower int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */
339636381Ssklower 
339736381Ssklower Static int
339836381Ssklower make_partial_x25_packet(copcb, m)
339936381Ssklower 	struct cons_pcb *copcb;
340036381Ssklower 	struct mbuf *m;
340136381Ssklower {
340236381Ssklower 	struct sockaddr_iso	*src, *dst;
340336381Ssklower 	u_int				proto;
340436381Ssklower 	int					flag;
340536381Ssklower 	caddr_t 			buf = mtod(m, caddr_t);
340636381Ssklower 	register caddr_t	ptr	= buf + 1;  /* make room for 2 length nibbles */
340736381Ssklower 	register int		len	= 0;
340836381Ssklower 	int 				buflen	=0;
340936381Ssklower 	caddr_t				facil_len;
341036381Ssklower 	int 				oddness	= 0;
341136381Ssklower 
341236381Ssklower 	src = &copcb->co_laddr;
341336381Ssklower 	dst = &copcb->co_faddr;
341436381Ssklower 	proto = copcb->co_proto->pr_protocol,
341536381Ssklower 	flag = copcb->co_flags & CONSF_XTS;
341636381Ssklower 
341736381Ssklower 
341836381Ssklower 	IFDEBUG(D_CCONN)
341936381Ssklower 		printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
342036381Ssklower 			src, dst, proto, m, flag);
342136381Ssklower 	ENDDEBUG
342236381Ssklower 
342336381Ssklower 	/*
342436381Ssklower 	 * Note - order of addrs in x25 pkt hdr is wierd:
342536381Ssklower 	 * calling len/called len/called addr/calling addr (p.40 ISO 8202)
342636381Ssklower 	 */
342736381Ssklower 	if( (len = copcb->co_peer_dte.dtea_niblen) > 0 ) {
342836381Ssklower 		nibble_copy( (char *)(copcb->co_peer_dte.dtea_addr), HIGH_NIBBLE,
342936381Ssklower 			ptr, HIGH_NIBBLE, len);
343036381Ssklower 	} else {
343136381Ssklower 		if ((len =  NSAPtoDTE( ptr, HIGH_NIBBLE, dst)) <=0 ) {
343236381Ssklower 			return E_CO_OSI_UNSAP;
343336381Ssklower 		}
343436381Ssklower 	}
343536381Ssklower 	*buf = len; /* fill in called dte addr length */
343636381Ssklower 	ptr += len>>1; /* len is in nibbles */
343736381Ssklower 	oddness += len&0x1;
343836381Ssklower 
343936381Ssklower 	if ((len =  NSAPtoDTE( ptr, 1-(len&0x1), src)) <=0 ) {
344036381Ssklower 		return E_CO_OSI_UNSAP;
344136381Ssklower 	}
344236381Ssklower 	ptr += len>>1; /* len is in nibbles */
344336381Ssklower 	*buf |= len << 4; /* fill in calling dte addr length */
344436381Ssklower 	oddness += len&0x1;
344536381Ssklower 
344636381Ssklower 	IFDEBUG(D_CADDR)
344736381Ssklower 		printf("make_partial  2: ptr 0x%x, len 0x%x oddness 0x%x\n",
344836381Ssklower 			ptr, len, oddness );
344936381Ssklower 	ENDDEBUG
345036381Ssklower 	/* if either of the addresses were an odd length, the count is off by 1 */
345136381Ssklower 	if( oddness ) {
345236381Ssklower 		ptr ++;
345336381Ssklower 	}
345436381Ssklower 
345536381Ssklower 	/* ptr now points to facil length (len of whole facil field in OCTETS */
345636381Ssklower 	facil_len = ptr ++;
345736381Ssklower 
345836381Ssklower 	IFDEBUG(D_CADDR)
345936381Ssklower 		printf("make_partial  calling: ptr 0x%x, len 0x%x\n", ptr,
346036381Ssklower 				src->siso_addr.isoa_len);
346136381Ssklower 	ENDDEBUG
346236381Ssklower 	if( cons_use_facils ) {
346336381Ssklower 		*ptr = 0xcb; /* calling facility code */
346436381Ssklower 		ptr ++;
346536381Ssklower 		ptr ++; /* leave room for facil param len (in OCTETS + 1) */
346636381Ssklower 		ptr ++; /* leave room for the facil param len (in nibbles),
346736381Ssklower 				* high two bits of which indicate full/partial NSAP
346836381Ssklower 				*/
346936381Ssklower 		len = src->siso_addr.isoa_len;
347036381Ssklower 		bcopy( &src->siso_addr.isoa_afi, ptr, len);
347136381Ssklower 		*(ptr-2) = len+2; /* facil param len in octets */
347236381Ssklower 		*(ptr-1) = len<<1; /* facil param len in nibbles */
347336381Ssklower 		ptr += len;
347436381Ssklower 
347536381Ssklower 		IFDEBUG(D_CADDR)
347636381Ssklower 			printf("make_partial  called: ptr 0x%x, len 0x%x\n", ptr,
347736381Ssklower 					dst->siso_addr.isoa_len);
347836381Ssklower 		ENDDEBUG
347936381Ssklower 		*ptr = 0xc9; /* called facility code */
348036381Ssklower 		ptr ++;
348136381Ssklower 		ptr ++; /* leave room for facil param len (in OCTETS + 1) */
348236381Ssklower 		ptr ++; /* leave room for the facil param len (in nibbles),
348336381Ssklower 				* high two bits of which indicate full/partial NSAP
348436381Ssklower 				*/
348536381Ssklower 		len = dst->siso_addr.isoa_len;
348636381Ssklower 		bcopy( &dst->siso_addr.isoa_afi, ptr, len);
348736381Ssklower 		*(ptr-2) = len+2; /* facil param len = addr len + 1 for each of these
348836381Ssklower 						  * two length fields, in octets */
348936381Ssklower 		*(ptr-1) = len<<1; /* facil param len in nibbles */
349036381Ssklower 		ptr += len;
349136381Ssklower 
349236381Ssklower 	}
349336381Ssklower 	*facil_len = ptr - facil_len - 1;
349436381Ssklower 	if(*facil_len > X25_FACIL_LEN_MAX )
349536381Ssklower 		return E_CO_PNA_LONG;
349636381Ssklower 
349736381Ssklower 	if( cons_use_udata ) {
349836381Ssklower 		if (copcb->co_x25crud_len > 0) {
349936381Ssklower 			/*
350036381Ssklower 			 *	The user specified something. Stick it in
350136381Ssklower 			 */
350236381Ssklower 			bcopy(copcb->co_x25crud, ptr, copcb->co_x25crud_len);
350336381Ssklower 			ptr += copcb->co_x25crud_len;
350436381Ssklower 		} else {
350536381Ssklower 			/* protocol identifier */
350636381Ssklower 			switch (proto) {
350736381Ssklower 					/* unfortunately all are considered 1 protocol */
350836381Ssklower 				case ISOPROTO_TP0:
350936381Ssklower 				case ISOPROTO_TP1:
351036381Ssklower 				case ISOPROTO_TP2:
351136381Ssklower 				case ISOPROTO_TP3:
351236381Ssklower 				case ISOPROTO_TP4:
351336381Ssklower 				case ISOPROTO_CLTP:
351436381Ssklower 					/* no user data for TP */
351536381Ssklower 					break;
351636381Ssklower 
351736381Ssklower 				case ISOPROTO_CLNP:
351836381Ssklower 					*ptr = 0x81;
351936381Ssklower 					ptr++; /* count the proto id byte! */
352036381Ssklower 					break;
352136381Ssklower 				case ISOPROTO_INACT_NL:
352236381Ssklower 					*ptr = 0x0;
352336381Ssklower 					ptr++; /* count the proto id byte! */
352436381Ssklower 					break;
352536381Ssklower 				case ISOPROTO_X25:
352636381Ssklower 					*ptr = 0xff; /* reserved for future extensions */
352736381Ssklower 						  /* we're stealing this value for local use */
352836381Ssklower 					ptr++; /* count the proto id byte! */
352936381Ssklower 					break;
353036381Ssklower 				default:
353136381Ssklower 					return EPROTONOSUPPORT;
353236381Ssklower 			}
353336381Ssklower 		}
353436381Ssklower 	}
353536381Ssklower 
353636381Ssklower 	buflen = (int)(ptr - buf);
353736381Ssklower 
353836381Ssklower 	IFDEBUG(D_CDUMP_REQ)
353936381Ssklower 		register int i;
354036381Ssklower 
354136381Ssklower 		printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n",
354236381Ssklower 			buf, buflen, buflen);
354336381Ssklower 		for( i=0; i < buflen; ) {
354436381Ssklower 			printf("+%d: %x %x %x %x    %x %x %x %x\n",
354536381Ssklower 				i,
354636381Ssklower 				*(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3),
354736381Ssklower 				*(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7));
354836381Ssklower 			i+=8;
354936381Ssklower 		}
355036381Ssklower 	ENDDEBUG
355136381Ssklower 	IFDEBUG(D_CADDR)
355236381Ssklower 		printf("make_partial returns buf 0x%x size 0x%x bytes\n",
355336381Ssklower 			mtod(m, caddr_t), buflen);
355436381Ssklower 	ENDDEBUG
355536381Ssklower 
355636381Ssklower 	ASSERT( X25_PARTIAL_PKT_LEN_MAX < MLEN );
355736381Ssklower 
355836381Ssklower 	if(buflen > X25_PARTIAL_PKT_LEN_MAX)
355936381Ssklower 		return E_CO_PNA_LONG;
356036381Ssklower 
356136381Ssklower 	m->m_len = buflen;
356236381Ssklower 	return  0;
356336381Ssklower }
356436381Ssklower 
356536381Ssklower /*
356636381Ssklower  * NAME:	NSAPtoDTE()
356736381Ssklower  * CALLED FROM:
356836381Ssklower  *  make_partial_x25_packet()
356936381Ssklower  * FUNCTION and ARGUMENTS:
357036381Ssklower  *  get a DTE address from an NSAP-address (struct sockaddr_iso)
357136381Ssklower  *  (dst_octet) is the octet into which to begin stashing the DTE addr
357236381Ssklower  *  (dst_nibble) takes 0 or 1.  1 means begin filling in the DTE addr
357336381Ssklower  * 		in the high-order nibble of dst_octet.  0 means low-order nibble.
357436381Ssklower  *  (addr) is the NSAP-address
357536381Ssklower  *  (flag) is true if the transport suffix is to become the
357636381Ssklower  *		last two digits of the DTE address
357736381Ssklower  *  A DTE address is a series of BCD digits
357836381Ssklower  *
357936381Ssklower  *	A DTE address may have leading zeros. The are significant.
358036381Ssklower  *		1 digit per nibble, may be an odd number of nibbles.
358136381Ssklower  *
358236381Ssklower  *  An NSAP-address has the DTE address in the IDI. Leading zeros are
358336381Ssklower  *		significant. Trailing hex f indicates the end of the DTE address.
358436381Ssklower  *  	Also is a series of BCD digits, one per nibble.
358536381Ssklower  *
358636381Ssklower  * RETURNS
358736381Ssklower  *  # significant digits in the DTE address, -1 if error.
358836381Ssklower  */
358936381Ssklower 
359036381Ssklower Static int
359136381Ssklower NSAPtoDTE( dst_octet, dst_nibble, addr)
359236381Ssklower 	caddr_t 	dst_octet;
359336381Ssklower 	int			dst_nibble;
359436381Ssklower 	register struct sockaddr_iso *addr;
359536381Ssklower {
359636381Ssklower 	int 	error;
359736381Ssklower 	u_char	x121string[7]; /* maximum is 14 digits */
359836381Ssklower 	int		x121strlen;
359936381Ssklower 	struct	dte_addr *dtea;
360036381Ssklower 
360136381Ssklower 	IFDEBUG(D_CADDR)
360236381Ssklower 		printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&addr->siso_addr));
360336381Ssklower 	ENDDEBUG
360436381Ssklower 
360536381Ssklower 	error = iso_8208snparesolve(addr, x121string, &x121strlen);
360636381Ssklower 	ASSERT(error == 0);
360736381Ssklower 	if(  error != 0 ) {
360836381Ssklower 		/* no snpa - cannot send */
360936381Ssklower 		IFDEBUG(D_CADDR)
361036381Ssklower 			printf("NSAPtoDTE: 8208resolve: %d\n", error );
361136381Ssklower 		ENDDEBUG
361236381Ssklower 		return 0;
361336381Ssklower 	}
361436381Ssklower 	ASSERT(x121strlen == sizeof(struct dte_addr));
361536381Ssklower 	dtea = (struct dte_addr *)x121string;
361636381Ssklower 	x121strlen = dtea->dtea_niblen;
361736381Ssklower 
361836381Ssklower 	nibble_copy((char *)x121string, HIGH_NIBBLE,
361936381Ssklower 		dst_octet, dst_nibble, x121strlen);
362036381Ssklower 	return x121strlen;
362136381Ssklower }
362236381Ssklower 
362336381Ssklower /*
362436381Ssklower  * NAME:	FACILtoNSAP()
362536381Ssklower  * CALLED FROM:
362636381Ssklower  *  parse_facil()
362736381Ssklower  * FUNCTION and ARGUMENTS:
362836381Ssklower  * 	Creates and NSAP in the sockaddr_iso (addr) from the
362936381Ssklower  *  x.25 facility found at (buf), of length (buf_len).
363036381Ssklower  * RETURNS:
363136381Ssklower  *  0 if ok, non-zero if error;
363236381Ssklower  */
363336381Ssklower 
363436381Ssklower Static int
363536381Ssklower FACILtoNSAP( buf, buf_len, addr)
363636381Ssklower 	caddr_t 		buf;
363736381Ssklower 	u_char			buf_len; /* in bytes */
363836381Ssklower 	register struct sockaddr_iso *addr;
363936381Ssklower {
364036381Ssklower 	int len_in_nibbles;
364136381Ssklower 
364236381Ssklower 	IFDEBUG(D_CADDR)
364336381Ssklower 		printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n",
364436381Ssklower 			buf, buf_len, addr );
364536381Ssklower 	ENDDEBUG
364636381Ssklower 
364736381Ssklower 	len_in_nibbles = *buf;
364836381Ssklower 	/* despite the fact that X.25 makes us put a length in nibbles
364936381Ssklower 	 * here, the NSAP-addrs are always in full octets
365036381Ssklower 	 */
365136381Ssklower 	buf ++;
365236381Ssklower 
365336381Ssklower 	bzero( addr, sizeof (struct sockaddr_iso) );
365436381Ssklower 
365536381Ssklower 	ASSERT(buf_len <= 1+sizeof (struct iso_addr));
365636381Ssklower 	if(buf_len > 1+sizeof (struct iso_addr)) {
365736381Ssklower 		return -1; /* error */
365836381Ssklower 	}
365936381Ssklower 	ASSERT(len_in_nibbles == (buf_len - 1)<<1);
366036381Ssklower 	if(len_in_nibbles != (buf_len - 1)<<1) {
366136381Ssklower 		return -2; /* error */
366236381Ssklower 	}
366336381Ssklower 	bcopy(buf, &addr->siso_addr.isoa_afi, buf_len-1);
366436381Ssklower 	addr->siso_addr.isoa_len = buf_len-1;
366536381Ssklower 	IFDEBUG(D_CADDR)
366636381Ssklower 		printf("FACILtoNSAP: isoa_len 0x%x\n",
366736381Ssklower 			addr->siso_addr.isoa_len);
366836381Ssklower 	ENDDEBUG
366936381Ssklower 	addr->siso_family = AF_ISO;
367036381Ssklower 
367136381Ssklower 	addr->siso_tsuffix =
367236381Ssklower 		unmunge( ((caddr_t)&addr->siso_addr.t37_idi) + ADDR37_IDI_LEN , 1 );
367336381Ssklower 	return 0;
367436381Ssklower }
367536381Ssklower 
367636381Ssklower /*
367736381Ssklower  * NAME:	DTEtoNSAP()
367836381Ssklower  * CALLED FROM:
367936381Ssklower  *  parse_facil()
368036381Ssklower  * FUNCTION and ARGUMENTS:
368136381Ssklower  *  Creates a type 37 NSAP in the sockaddr_iso (addr)
368236381Ssklower  * 	from a DTE address found at the (src_nibble)th nibble of
368336381Ssklower  * 	the octet (src_octet), of length (src_nib_len).
368436381Ssklower  *
368536381Ssklower  * RETURNS:
368636381Ssklower  *  0 if ok; E* otherwise.
368736381Ssklower  */
368836381Ssklower 
368936381Ssklower Static  int
369036381Ssklower DTEtoNSAP(addr, src_octet, src_nibble, src_nib_len)
369136381Ssklower 	struct sockaddr_iso *addr;
369236381Ssklower 	caddr_t src_octet;
369336381Ssklower 	int src_nibble, src_nib_len;
369436381Ssklower {
369536381Ssklower 	caddr_t				dst_octet;
369636381Ssklower 	int					pad_len;
369736381Ssklower 	int					dst_nibble;
369836381Ssklower 	char				first_nib;
369936381Ssklower 	static				char *z_pad = "\0\0\0\0\0\0\0";
370036381Ssklower 	static				char *f_pad = "\021\021\021\021\021\021\021";
370136381Ssklower 
370236381Ssklower 	IFDEBUG(D_CADDR)
370336381Ssklower 		printf("DTEtoNSAP( 0x%x, 0x%x, 0x%x, 0x%x )\n",
370436381Ssklower 			src_octet, src_nibble, src_nib_len, addr );
370536381Ssklower 	ENDDEBUG
370636381Ssklower 
370736381Ssklower 	bzero( addr, sizeof(*addr));
370836381Ssklower 	addr->siso_family = AF_ISO;
370936381Ssklower 	/*
371036381Ssklower 	 * Coming from a DTE addr it's always type 37.
371136381Ssklower 	 * src_octet <-- starting place in the NSAP-address of
371236381Ssklower 	 * the embedded SNPA-address (x.121 addr or DTE addr).
371336381Ssklower 	 */
371436381Ssklower 	addr->siso_addr.isoa_afi = 0x37;
371536381Ssklower 
371636381Ssklower 	/* first, figure out what pad to use and pad */
371736381Ssklower 
371836381Ssklower 	first_nib = (*src_octet) >> (SHIFT*(1-src_nibble));
371936381Ssklower 	pad_len = (ADDR37_IDI_LEN<<1 - src_nib_len);
372036381Ssklower 	nibble_copy(first_nib? z_pad : f_pad, HIGH_NIBBLE,
372136381Ssklower 		(caddr_t) addr->siso_addr.t37_idi, HIGH_NIBBLE, pad_len);
372236381Ssklower 
372336381Ssklower 	dst_octet += (pad_len>>1);
372436381Ssklower 	dst_nibble = 1-(pad_len & 0x1);
372536381Ssklower 	IFDEBUG(D_CADDR)
372636381Ssklower 		printf("DTEtoNSAP 2( 0x%x, 0x%x, 0x%x, 0x%x )\n",
372736381Ssklower 			dst_octet, dst_nibble, pad_len, src_nib_len );
372836381Ssklower 	ENDDEBUG
372936381Ssklower 
373036381Ssklower 	/* now copy the dte address */
373136381Ssklower 	nibble_copy( src_octet, src_nibble, dst_octet, dst_nibble, src_nib_len);
373236381Ssklower 
373336381Ssklower 	addr->siso_addr.isoa_len = ADDR37_IDI_LEN + ADDR37_DSP_LEN +1 /* for afi */;
373436381Ssklower 		/* kludge */
373536381Ssklower 
373636381Ssklower 	addr->siso_tsuffix = unmunge(
373736381Ssklower 		(caddr_t) &(addr->siso_addr.t37_idi[ADDR37_IDI_LEN]), HIGH_NIBBLE);
373836381Ssklower 
373936381Ssklower 	IFDEBUG(D_CADDR)
374036381Ssklower 		printf("DTEtoNSAP 3 returning 0 tsuffix 0x%x\n", addr->siso_tsuffix);
374136381Ssklower 	ENDDEBUG
374236381Ssklower 
374336381Ssklower 	return 0; /* ok */
374436381Ssklower }
374536381Ssklower 
374636381Ssklower /*
374736381Ssklower  * FUNCTION and ARGUMENTS:
374836381Ssklower  *	parses (buf_len) bytes beginning at (buf) and finds
374936381Ssklower  *  a called nsap, a calling nsap, and protocol identifier.
375036381Ssklower  * RETURNS:
375136381Ssklower  *  0 if ok, E* otherwise.
375236381Ssklower  */
375336381Ssklower 
375436381Ssklower Static int
375536381Ssklower parse_facil( buf, buf_len, called, calling, proto, peer_dte)
375636381Ssklower 	caddr_t 		buf;
375736381Ssklower 	u_char			buf_len; /* in bytes */
375836381Ssklower 	register struct sockaddr_iso *called, *calling;
375936381Ssklower 	int				*proto;
376036381Ssklower 	struct	dte_addr	*peer_dte;
376136381Ssklower {
376236381Ssklower 	register int 	i;
376336381Ssklower 	caddr_t			ptr;
376436381Ssklower 	caddr_t 		facil_len;
376536381Ssklower 	int 			facil_param_len;
376636381Ssklower 	struct 	sockaddr_iso *addr;
376736381Ssklower 	int				addrs_not_parsed = (int)0xcb + (int)0xc9;
376836381Ssklower 
376936381Ssklower 	IFDEBUG(D_CADDR)
377036381Ssklower 		printf("parse_facil( 0x%x, 0x%x, 0x%x, 0x%x, 0x%x )\n",
377136381Ssklower 			buf, buf_len, called, calling, *proto);
377236381Ssklower 		dump_buf(buf, buf_len);
377336381Ssklower 	ENDDEBUG
377436381Ssklower 
377536381Ssklower 	/* find the beginnings of the facility fields in buf
377636381Ssklower 	 * by skipping over the called & calling DTE addresses
377736381Ssklower 	 * i <- # nibbles in called + # nibbles in calling
377836381Ssklower 	 * i += 1 so that an odd nibble gets rounded up to even
377936381Ssklower 	 * before dividing by 2, then divide by two to get # octets
378036381Ssklower 	 */
378136381Ssklower 	i = (int)(*buf >> 4) + (int)(*buf&0xf);
378236381Ssklower 	i++;
378336381Ssklower 	ptr = (caddr_t) (buf + (i>>1));
378436381Ssklower 	/* now i is number of octets */
378536381Ssklower 
378636381Ssklower 	ptr ++; /* plus one for the DTE lengths byte */
378736381Ssklower 
378836381Ssklower 	/* ptr now is at facil_length field */
378936381Ssklower 	facil_len = ptr++;
379036381Ssklower 	IFDEBUG(D_CADDR)
379136381Ssklower 		printf("parse_facils: facil length is  0x%x\n", (int) *facil_len);
379236381Ssklower 	ENDDEBUG
379336381Ssklower 
379436381Ssklower 	while( ptr <= (caddr_t)(facil_len + (int)*facil_len) ) {
379536381Ssklower 		/* get NSAP addresses from facilities */
379636381Ssklower 		switch (*ptr) {
379736381Ssklower 			case 0xcb:
379836381Ssklower 				facil_param_len = 0;
379936381Ssklower 				addr = calling;
380036381Ssklower 				addrs_not_parsed -= 0xcb;
380136381Ssklower 				break;
380236381Ssklower 			case 0xc9:
380336381Ssklower 				facil_param_len = 0;
380436381Ssklower 				addr = called;
380536381Ssklower 				addrs_not_parsed -= 0xc9;
380636381Ssklower 				break;
380736381Ssklower 
380836381Ssklower 				/* from here to default are legit cases that I ignore */
380936381Ssklower 
381036381Ssklower 				/* variable length */
381136381Ssklower 			case 0xca:  /* end-to-end transit delay negot */
381236381Ssklower 			case 0xc6:  /* network user id */
381336381Ssklower 			case 0xc5: 	/* charging info : indicating monetary unit */
381436381Ssklower 			case 0xc2: 	/* charging info : indicating segment count */
381536381Ssklower 			case 0xc1: 	/* charging info : indicating call duration */
381636381Ssklower 			case 0xc4: 	/* RPOA extended format */
381736381Ssklower 			case 0xc3: 	/* call redirection notification */
381836381Ssklower 				facil_param_len = 0;
381936381Ssklower 				addr = (struct sockaddr_iso *)0;
382036381Ssklower 				break;
382136381Ssklower 
382236381Ssklower 				/* 1 octet */
382336381Ssklower 			case 0x0a:  /* min. throughput class negot */
382436381Ssklower 			case 0x02:  /* throughput class */
382536381Ssklower 			case 0x03:  case 0x47:  /* CUG shit */
382636381Ssklower 			case 0x0b:  /* expedited data negot */
382736381Ssklower 			case 0x01:  /* Fast select or reverse charging
382836381Ssklower 						(example of intelligent protocol design) */
382936381Ssklower 			case 0x04: 	/* charging info : requesting service */
383036381Ssklower 			case 0x08: 	/* called line addr modified notification */
383136381Ssklower 				facil_param_len = 1;
383236381Ssklower 				addr = (struct sockaddr_iso *)0;
383336381Ssklower 				break;
383436381Ssklower 
383536381Ssklower 				/* any 2 octets */
383636381Ssklower 			case 0x42:  /* pkt size */
383736381Ssklower 			case 0x43:  /* win size */
383836381Ssklower 			case 0x44:  /* RPOA basic format */
383936381Ssklower 			case 0x41:  /* bilateral CUG shit */
384036381Ssklower 			case 0x49: 	/* transit delay selection and indication */
384136381Ssklower 				facil_param_len = 2;
384236381Ssklower 				addr = (struct sockaddr_iso *)0;
384336381Ssklower 				break;
384436381Ssklower 
384536381Ssklower 				/* don't have any 3 octets */
384636381Ssklower 				/*
384736381Ssklower 				facil_param_len = 3;
384836381Ssklower 				*/
384936381Ssklower 			default:
385036381Ssklower 				ASSERT(0);
385136381Ssklower 				printf(
385236381Ssklower "BOGUS FACILITY CODE facil_len 0x%x *facil_len 0x%x, ptr 0x%x *ptr 0x%x\n",
385336381Ssklower 					facil_len, *facil_len,
385436381Ssklower 					ptr, *ptr);
385536381Ssklower 				addr = (struct sockaddr_iso *)0;
385636381Ssklower 				/* facil that we don't handle */
385736381Ssklower 				return E_CO_HLI_REJI;
385836381Ssklower 		}
385936381Ssklower 		ptr++; /* one for facil code */
386036381Ssklower 		if(facil_param_len == 0) /* variable length */
386136381Ssklower 			facil_param_len = (int)*ptr; /* 1 + the real facil param */
386236381Ssklower 		if( addr &&  FACILtoNSAP(ptr+1, facil_param_len-1, addr) ) {
386336381Ssklower 			return E_CO_OSI_UNSAP;
386436381Ssklower 		}
386536381Ssklower 		ptr += facil_param_len;
386636381Ssklower 	}
386736381Ssklower 	if( addrs_not_parsed ) {
386836381Ssklower 		/* no facilities, get NSAP addresses from DTE addresses */
386936381Ssklower 		register int ed, ing;
387036381Ssklower 
387136381Ssklower 		ed = (int)(*buf&0xf);
387236381Ssklower 		if( ed == 0 ) {
387336381Ssklower 			panic("Called DTE address absent");
387436381Ssklower 		}
387536381Ssklower 		DTEtoNSAP(called, (buf + 1)/*octet*/,
387636381Ssklower 			1/*nibble*/, ed);
387736381Ssklower 
387836381Ssklower 		ing = (int)(*buf >> 4);
387936381Ssklower 		if( ing == 0 ) {
388036381Ssklower 			printf("cons: panic: Calling DTE address absent");
388136381Ssklower 			return E_CO_HLI_REJI;
388236381Ssklower 		}
388336381Ssklower 		nibble_copy((buf + (ed>>1)+1)/*octet*/, 1-(ed&0x1)/*nibble*/,
388436381Ssklower 			peer_dte->dtea_addr, HIGH_NIBBLE, ing);
388536381Ssklower 		DTEtoNSAP(calling, (buf + (ed>>1)+1)/*octet*/,
388636381Ssklower 			1-(ed&0x1)/*nibble*/, ing);
388736381Ssklower 
388836381Ssklower 	}
388936381Ssklower 
389036381Ssklower 	ASSERT( ptr == (caddr_t)(facil_len + 1 + (int)*facil_len) );
389136381Ssklower 
389236381Ssklower 	/*
389336381Ssklower 	 * now look for user data to find protocol identifier
389436381Ssklower 	 */
389536381Ssklower 	if( ptr == buf + buf_len ) {
389636381Ssklower 		/* no user data */
389736381Ssklower 		*proto = ISOPROTO_TP; /* to proto id --> use TP */
389836381Ssklower 		IFDEBUG(D_CADDR)
389936381Ssklower 			printf("NO USER DATA: use TP\n");
390036381Ssklower 		ENDDEBUG
390136381Ssklower 	} else {
390236381Ssklower 		ASSERT ( ptr < buf + buf_len );
390336381Ssklower 		if ( ptr >= buf + buf_len ) {
390436381Ssklower 			printf("ptr 0x%x buf 0x%x buf_len 0x%x buf+buf_len 0x%x\n",
390536381Ssklower 				ptr, buf, buf_len, buf+buf_len);
390636381Ssklower 		}
390736381Ssklower 		IFDEBUG(D_CADDR)
390836381Ssklower 			printf("proto byte 0x%x, value 0x%x\n", ptr, *ptr);
390936381Ssklower 		ENDDEBUG
391036381Ssklower 		switch(*ptr) {
391136381Ssklower 		case 0x81:
391236381Ssklower 			*proto = ISOPROTO_CLNP;
391336381Ssklower 			break;
391436381Ssklower 		case 0x0:
391536381Ssklower 			*proto = ISOPROTO_INACT_NL;
391636381Ssklower 			break;
391736381Ssklower 		case  'e': /* for EAN */
391836381Ssklower 			*proto = ISOPROTO_TP;
391936381Ssklower 			/* can check for "an2" or can ignore the rest of the u data */
392036381Ssklower 			break;
392136381Ssklower 		case 0xff: /* reserved for future extensions */
392236381Ssklower 			*proto =  ISOPROTO_X25;
392336381Ssklower 			break;
392436381Ssklower 		case 0x82: /* 9542 not implemented */
392536381Ssklower 		case 0x84: /* 8878/A SNDCP not implemented */
392636381Ssklower 		default:
392736381Ssklower 			*proto =  -1;
392836381Ssklower 			return E_CO_HLI_PROTOID;
392936381Ssklower 		}
393036381Ssklower 	}
393136381Ssklower 	return 0;
393236381Ssklower }
393336381Ssklower 
393436381Ssklower #endif NARGOXTWENTYFIVE > 0
3935