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