xref: /csrg-svn/sys/netiso/if_cons.c (revision 49265)
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 $
30*49265Ssklower  *	@(#)if_cons.c	7.7 (Berkeley) 05/06/91
3136381Ssklower  *
3236381Ssklower  * cons.c - Connection Oriented Network Service:
3336381Ssklower  * including support for a) user transport-level service,
3436381Ssklower  *	b) COSNS below CLNP, and c) CONS below TP.
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
3945899Ssklower  */
4036381Ssklower 
4145899Ssklower #ifdef TPCONS
4245899Ssklower #ifdef KERNEL
4336381Ssklower #ifdef ARGO_DEBUG
4436381Ssklower #define Static
4536381Ssklower unsigned LAST_CALL_PCB;
4636381Ssklower #else ARGO_DEBUG
4736381Ssklower #define Static static
4836381Ssklower #endif ARGO_DEBUG
4936381Ssklower 
5036381Ssklower 
5136381Ssklower 
5245899Ssklower #ifndef SOCK_STREAM
5336381Ssklower #include "param.h"
5436381Ssklower #include "systm.h"
5536381Ssklower #include "mbuf.h"
5636381Ssklower #include "protosw.h"
5736381Ssklower #include "socket.h"
5836381Ssklower #include "socketvar.h"
5936381Ssklower #include "errno.h"
6036381Ssklower #include "ioctl.h"
6140783Smarc #include "tsleep.h"
6236381Ssklower 
6336381Ssklower #include "../net/if.h"
6436381Ssklower #include "../net/netisr.h"
6536381Ssklower #include "../net/route.h"
6636381Ssklower 
6745899Ssklower #include "iso_errno.h"
6845899Ssklower #include "argo_debug.h"
6945899Ssklower #include "tp_trace.h"
7045899Ssklower #include "iso.h"
7145899Ssklower #include "cons.h"
7245899Ssklower #include "iso_pcb.h"
7336381Ssklower 
7445899Ssklower #include "../netccitt/x25.h"
7545899Ssklower #include "../netccitt/pk.h"
7645899Ssklower #include "../netccitt/pk_var.h"
7745899Ssklower #endif
7845899Ssklower 
7936381Ssklower #ifdef ARGO_DEBUG
8036381Ssklower #define MT_XCONN	0x50
8136381Ssklower #define MT_XCLOSE	0x51
8236381Ssklower #define MT_XCONFIRM	0x52
8336381Ssklower #define MT_XDATA	0x53
8436381Ssklower #define MT_XHEADER	0x54
8536381Ssklower #else
8636381Ssklower #define MT_XCONN	MT_DATA
8736381Ssklower #define MT_XCLOSE	MT_DATA
8836381Ssklower #define MT_XCONFIRM	MT_DATA
8936381Ssklower #define MT_XDATA	MT_DATA
9036381Ssklower #define MT_XHEADER	MT_HEADER
9136381Ssklower #endif ARGO_DEBUG
9236381Ssklower 
9336381Ssklower #define DONTCLEAR	 -1
9436381Ssklower 
9536381Ssklower /*********************************************************************
9645899Ssklower  * cons.c - CONS interface to the x.25 layer
9736381Ssklower  *
9836381Ssklower  * TODO: figure out what resources we might run out of besides mbufs.
9936381Ssklower  *  If we run out of any of them (including mbufs) close and recycle
10036381Ssklower  *  lru x% of the connections, for some parameter x.
10136381Ssklower  *
10245899Ssklower  * There are 2 interfaces from above:
10336381Ssklower  * 1) from TP0:
10436381Ssklower  *    cons CO network service
10536381Ssklower  *    TP associates a transport connection with a network connection.
10636381Ssklower  * 	  cons_output( isop, m, len, isdgm==0 )
10736381Ssklower  *        co_flags == 0
10845899Ssklower  * 2) from TP4:
10936381Ssklower  *	  It's a datagram service, like clnp is. - even though it calls
11036381Ssklower  *			cons_output( isop, m, len, isdgm==1 )
11136381Ssklower  *	  it eventually goes through
11236381Ssklower  *			cosns_output(ifp, m, dst).
11336381Ssklower  *    TP4 permits multiplexing (reuse, possibly simultaneously) of the
11436381Ssklower  *	  network connections.
11536381Ssklower  *    This means that many sockets (many tpcbs) may be associated with
11645899Ssklower  *    this pklcd, hence cannot have a back ptr from pklcd to a tpcb.
11736381Ssklower  *        co_flags & CONSF_DGM
11845899Ssklower  *    co_socket is null since there may be many sockets that use this pklcd.
11936381Ssklower  *
12036381Ssklower NOTE:
12136381Ssklower 	streams would really be nice. sigh.
12236381Ssklower NOTE:
12336381Ssklower 	PVCs could be handled by config-ing a cons with an address and with the
12436381Ssklower 	IFF_POINTTOPOINT flag on.  This code would then have to skip the
12536381Ssklower 	connection setup stuff for pt-to-pt links.
12636381Ssklower 
12736381Ssklower 
12836381Ssklower  *********************************************************************/
12936381Ssklower 
13036381Ssklower 
13136381Ssklower #define CONS_IFQMAXLEN 5
13236381Ssklower 
13336381Ssklower 
13436381Ssklower /* protosw pointers for getting to higher layer */
13536381Ssklower Static 	struct protosw	*CLNP_proto;
13636381Ssklower Static 	struct protosw	*TP_proto;
13736381Ssklower Static 	struct protosw	*X25_proto;
13836381Ssklower Static 	int				issue_clear_req();
13936381Ssklower 
14036381Ssklower #ifndef	PHASEONE
14136381Ssklower extern	struct ifaddr	*ifa_ifwithnet();
14236381Ssklower #endif	PHASEONE
14336381Ssklower 
14436381Ssklower extern	struct ifaddr	*ifa_ifwithaddr();
14536381Ssklower 
14636381Ssklower Static  struct socket	dummysocket; /* for use by cosns */
14736381Ssklower 
14836381Ssklower extern struct	isopcb	tp_isopcb; /* chain of all TP pcbs */
14936381Ssklower struct	isopcb			tp_incoming_pending;  /* incoming connections
15036381Ssklower 										for TP, pending */
15136381Ssklower 
15236381Ssklower struct isopcb 	*Xpcblist[] =  {
15336381Ssklower 	&tp_incoming_pending,
15436381Ssklower 	&tp_isopcb,
15536381Ssklower 	(struct isopcb *)0
15636381Ssklower };
15736381Ssklower 
15836381Ssklower Static 	int parse_facil(), NSAPtoDTE(), make_partial_x25_packet();
15936381Ssklower Static	int FACILtoNSAP(), DTEtoNSAP();
16045899Ssklower Static	struct pklcd *cons_chan_to_pcb();
16136381Ssklower 
16236381Ssklower #define HIGH_NIBBLE 1
16336381Ssklower #define LOW_NIBBLE 0
16436381Ssklower 
16536381Ssklower /*
16636381Ssklower  * NAME:	nibble_copy()
16736381Ssklower  * FUNCTION and ARGUMENTS:
16836381Ssklower  * 	copies (len) nibbles from (src_octet), high or low nibble
16936381Ssklower  *  to (dst_octet), high or low nibble,
17036381Ssklower  * src_nibble & dst_nibble should be:
17136381Ssklower  * 	HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble
17236381Ssklower  * 	LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble
17336381Ssklower  * RETURNS: VOID
17436381Ssklower  */
17536381Ssklower void
17645899Ssklower nibble_copy(src_octet, src_nibble, dst_octet, dst_nibble, len)
17736381Ssklower 	register char  	*src_octet;
17836381Ssklower 	register char  	*dst_octet;
17936381Ssklower 	register unsigned		src_nibble;
18036381Ssklower 	register unsigned 		dst_nibble;
18136381Ssklower 	int		len;
18236381Ssklower {
18336381Ssklower 
18436381Ssklower 	register 	i;
18536381Ssklower 	register 	unsigned dshift, sshift;
18636381Ssklower 
18736381Ssklower 	IFDEBUG(D_CADDR)
18836381Ssklower 		printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n",
18936381Ssklower 		 src_octet, src_nibble, dst_octet, dst_nibble, len);
19036381Ssklower 	ENDDEBUG
19136381Ssklower #define SHIFT 0x4
19236381Ssklower 
19336381Ssklower 	dshift = dst_nibble << 2;
19436381Ssklower 	sshift = src_nibble << 2;
19536381Ssklower 
19636381Ssklower 	for (i=0; i<len; i++) {
19736381Ssklower 		/* clear dst_nibble  */
19836381Ssklower 		*dst_octet 	&= ~(0xf<< dshift);
19936381Ssklower 
20036381Ssklower 		/* set dst nibble */
20136381Ssklower 		*dst_octet 	|= ( 0xf & (*src_octet >> sshift))<< dshift;
20236381Ssklower 
20336381Ssklower 		dshift		^= SHIFT;
20436381Ssklower 		sshift		^= SHIFT;
20536381Ssklower 		src_nibble 	= 1-src_nibble;
20636381Ssklower 		dst_nibble 	= 1-dst_nibble;
20736381Ssklower 		src_octet	+= src_nibble;
20836381Ssklower 		dst_octet 	+= dst_nibble;
20936381Ssklower 	}
21036381Ssklower 	IFDEBUG(D_CADDR)
21136381Ssklower 		printf("nibble_copy DONE\n");
21236381Ssklower 	ENDDEBUG
21336381Ssklower }
21436381Ssklower 
21536381Ssklower /*
21636381Ssklower  * NAME:	nibble_match()
21736381Ssklower  * FUNCTION and ARGUMENTS:
21836381Ssklower  * 	compares src_octet/src_nibble and dst_octet/dst_nibble  for len nibbles.
21936381Ssklower  * RETURNS: 0 if they differ, 1 if they are the same.
22036381Ssklower  */
22136381Ssklower int
22236381Ssklower nibble_match( src_octet, src_nibble, dst_octet, dst_nibble, len)
22336381Ssklower 	register char  	*src_octet;
22436381Ssklower 	register char  	*dst_octet;
22536381Ssklower 	register unsigned		src_nibble;
22636381Ssklower 	register unsigned 		dst_nibble;
22736381Ssklower 	int		len;
22836381Ssklower {
22936381Ssklower 
23036381Ssklower 	register 	i;
23136381Ssklower 	register 	unsigned dshift, sshift;
23236381Ssklower 	u_char		nibble_a, nibble_b;
23336381Ssklower 
23436381Ssklower 	IFDEBUG(D_CADDR)
23536381Ssklower 		printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n",
23636381Ssklower 		 src_octet, src_nibble, dst_octet, dst_nibble, len);
23736381Ssklower 	ENDDEBUG
23836381Ssklower #define SHIFT 0x4
23936381Ssklower 
24036381Ssklower 	dshift = dst_nibble << 2;
24136381Ssklower 	sshift = src_nibble << 2;
24236381Ssklower 
24336381Ssklower 	for (i=0; i<len; i++) {
24436381Ssklower 		nibble_b = ((*dst_octet)>>dshift) & 0xf;
24536381Ssklower 		nibble_a = ( 0xf & (*src_octet >> sshift));
24645899Ssklower 		if (nibble_b != nibble_a)
24736381Ssklower 			return 0;
24836381Ssklower 
24936381Ssklower 		dshift		^= SHIFT;
25036381Ssklower 		sshift		^= SHIFT;
25136381Ssklower 		src_nibble 	= 1-src_nibble;
25236381Ssklower 		dst_nibble 	= 1-dst_nibble;
25336381Ssklower 		src_octet	+= src_nibble;
25436381Ssklower 		dst_octet 	+= dst_nibble;
25536381Ssklower 	}
25636381Ssklower 	IFDEBUG(D_CADDR)
25736381Ssklower 		printf("nibble_match DONE\n");
25836381Ssklower 	ENDDEBUG
25936381Ssklower 	return 1;
26036381Ssklower }
26136381Ssklower 
26236381Ssklower /*
26336381Ssklower  **************************** NET PROTOCOL cons ***************************
26436381Ssklower  */
26536381Ssklower /*
26636381Ssklower  * NAME:	cons_init()
26736381Ssklower  * CALLED FROM:
26836381Ssklower  *	autoconf
26936381Ssklower  * FUNCTION:
27036381Ssklower  *	initialize the protocol
27136381Ssklower  */
27236381Ssklower cons_init()
27336381Ssklower {
27445899Ssklower 	int tp_incoming(), clnp_incoming();
27536381Ssklower 
27636381Ssklower 
27736381Ssklower 	CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM);
27836381Ssklower 	X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM);
27936381Ssklower 	TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET);
28036381Ssklower 	IFDEBUG(D_CCONS)
28136381Ssklower 		printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n",
28236381Ssklower 			CLNP_proto, X25_proto, TP_proto);
28336381Ssklower 	ENDDEBUG
28445899Ssklower #ifdef notdef
28545899Ssklower 	pk_protolisten(0x81, 0, clnp_incoming);
28645899Ssklower 	pk_protolisten(0x82, 0, esis_incoming);
28745899Ssklower 	pk_protolisten(0x84, 0, tp8878_A_incoming);
28849041Ssklower 	pk_protolisten(0, 0, tp_incoming);
28945899Ssklower #endif
29036381Ssklower }
29136381Ssklower 
29245899Ssklower tp_incoming(lcp, m0)
29345899Ssklower struct pklcd *lcp;
29445899Ssklower struct mbuf *m0;
29536381Ssklower {
29645899Ssklower 	register struct mbuf *m = m0->m_next; /* m0 has calling sockaddr_x25 */
29745899Ssklower 	register struct isopcb *isop;
29845899Ssklower 	extern struct isopcb tp_isopcb;
29945899Ssklower 	int cons_tpinput();
30036381Ssklower 
30145899Ssklower 	if (iso_pcballoc((struct socket *)0, &tp_incoming_pending)) {
30245899Ssklower 		m_freem(m);
30345899Ssklower 		pk_clear(lcp);
30445899Ssklower 		return;
30536381Ssklower 	}
30645899Ssklower 	isop = tp_incoming_pending.isop_next;
30745899Ssklower 	pk_output(lcp); /* Confirms call */
30845899Ssklower 	lcp->lcd_upper = cons_tpinput;
30945899Ssklower 	lcp->lcd_upnext = (caddr_t)isop;
31045899Ssklower 	isop->isop_chan = (caddr_t)lcp;
31145899Ssklower 	isop->isop_laddr = &isop->isop_sladdr;
31245899Ssklower 	isop->isop_faddr = &isop->isop_sfaddr;
31345899Ssklower 	DTEtoNSAP(isop->isop_laddr, &lcp->lcd_laddr);
31445899Ssklower 	DTEtoNSAP(isop->isop_faddr, &lcp->lcd_faddr);
31545899Ssklower 	parse_facil(isop, lcp, &(mtod(m, struct x25_packet *)->packet_data),
31645899Ssklower 		m->m_pkthdr.len - PKHEADERLN);
31745899Ssklower 	m_freem(m);
31836381Ssklower }
31936381Ssklower 
32045899Ssklower cons_tpinput(lcp, m0)
32145899Ssklower struct mbuf *m0;
32245899Ssklower struct pklcd *lcp;
32336381Ssklower {
32445899Ssklower 	register struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext;
32545899Ssklower 	register struct x25_packet *xp;
32645899Ssklower 	int cmd;
32736381Ssklower 
328*49265Ssklower 	if (isop == 0)
329*49265Ssklower 		return;
330*49265Ssklower 	if (m0 == 0) {
331*49265Ssklower 		isop->isop_chan = 0;
332*49265Ssklower 		isop->isop_refcnt = 0;
333*49265Ssklower 		lcp->lcd_upnext = 0;
334*49265Ssklower 		lcp->lcd_upper = 0;
33549041Ssklower 		goto dead;
336*49265Ssklower 	}
33745899Ssklower 	switch(m0->m_type) {
33845899Ssklower 	case MT_DATA:
33945899Ssklower 	case MT_OOBDATA:
34045899Ssklower 		tpcons_input(m0, isop->isop_faddr, isop->isop_laddr,
34145899Ssklower 			(struct socket *)0, (caddr_t)lcp);
34236381Ssklower 
34345899Ssklower 	case MT_CONTROL:
34445899Ssklower 		switch (pk_decode(mtod(m0, struct x25_packet *))) {
34545899Ssklower 		default:
34645899Ssklower 			return;
34736381Ssklower 
34845899Ssklower 		case RR:
34945899Ssklower 			cmd = PRC_CONS_SEND_DONE;
35045899Ssklower 			break;
35136381Ssklower 
352*49265Ssklower 		case CALL_ACCEPTED:
353*49265Ssklower 			if (lcp->lcd_sb.sb_mb)
354*49265Ssklower 				lcp->lcd_send(lcp); /* XXX - fix this */
355*49265Ssklower 			break;
356*49265Ssklower 
35749041Ssklower 		dead:
35845899Ssklower 		case RESET:
35949041Ssklower 		case CLEAR:
36049041Ssklower 		case CLEAR_CONF:
36145899Ssklower 			cmd = PRC_ROUTEDEAD;
36236381Ssklower 		}
36345899Ssklower 		tpcons_ctlinput(cmd, isop->isop_faddr, isop);
36436381Ssklower 	}
36536381Ssklower }
36636381Ssklower 
36736381Ssklower /*
36836381Ssklower  * NAME:	cons_connect()
36936381Ssklower  * CALLED FROM:
37045899Ssklower  *	tpcons_pcbconnect() when opening a new connection.
37136381Ssklower  * FUNCTION anD ARGUMENTS:
37236381Ssklower  *  Figures out which device to use, finding a route if one doesn't
37336381Ssklower  *  already exist.
37436381Ssklower  * RETURN VALUE:
37536381Ssklower  *  returns E*
37636381Ssklower  */
37745899Ssklower cons_connect(isop)
37845899Ssklower 	register struct isopcb *isop;
37936381Ssklower {
38045899Ssklower 	register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
38136381Ssklower 	register struct mbuf 	*m;
38236381Ssklower 	struct ifaddr 			*ifa;
38336381Ssklower 
38436381Ssklower 	IFDEBUG(D_CCONN)
38545899Ssklower 		printf("cons_connect(0x%x): ", isop);
38645899Ssklower 		dump_isoaddr(isop->isop_faddr);
38745899Ssklower 		printf("myaddr: ");
38845899Ssklower 		dump_isoaddr(isop->isop_laddr);
38936381Ssklower 		printf("\n" );
39036381Ssklower 	ENDDEBUG
39145899Ssklower 	NSAPtoDTE(isop->isop_faddr, &lcp->lcd_faddr);
392*49265Ssklower 	lcp->lcd_upper = cons_tpinput;
393*49265Ssklower 	lcp->lcd_upnext = (caddr_t)isop;
39436381Ssklower 	IFDEBUG(D_CCONN)
39536381Ssklower 		printf(
39645899Ssklower 		"calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x)\n",
39745899Ssklower 			&lcp->lcd_faddr, &lcp->lcd_laddr,
39845899Ssklower 			isop->isop_socket->so_proto->pr_protocol);
39936381Ssklower 	ENDDEBUG
40045899Ssklower 	return (make_partial_x25_packet(isop, lcp, m) ||
40145899Ssklower 		 pk_connect(lcp, &lcp->lcd_faddr));
40236381Ssklower }
40336381Ssklower 
40436381Ssklower /*
40536381Ssklower  **************************** DEVICE cons ***************************
40636381Ssklower  */
40736381Ssklower 
40836381Ssklower 
40936381Ssklower /*
41036381Ssklower  * NAME:	cons_ctlinput()
41136381Ssklower  * CALLED FROM:
41236381Ssklower  *  lower layer when ECN_CLEAR occurs : this routine is here
41336381Ssklower  *  for consistency - cons subnet service calls its higher layer
41436381Ssklower  *  through the protosw entry.
41536381Ssklower  * FUNCTION & ARGUMENTS:
41637536Smckusick  *  cmd is a PRC_* command, list found in ../sys/protosw.h
41736381Ssklower  *  copcb is the obvious.
41836381Ssklower  *  This serves the higher-layer cons service.
41936381Ssklower  * NOTE: this takes 3rd arg. because cons uses it to inform itself
42036381Ssklower  *  of things (timeouts, etc) but has a pcb instead of an address.
42136381Ssklower  */
42236381Ssklower cons_ctlinput(cmd, sa, copcb)
42336381Ssklower 	int cmd;
42436381Ssklower 	struct sockaddr *sa;
42545899Ssklower 	register struct pklcd *copcb;
42636381Ssklower {
42736381Ssklower }
42836381Ssklower 
42936381Ssklower 
43045899Ssklower find_error_reason( xp )
43145899Ssklower 	register struct x25_packet *xp;
43236381Ssklower {
43336381Ssklower 	extern u_char x25_error_stats[];
43445899Ssklower 	int error, cause;
43536381Ssklower 
43645899Ssklower 	if (xp) {
43745899Ssklower 		cause = 4[(char *)xp];
43845899Ssklower 		switch (cause) {
43936381Ssklower 			case 0x00:
44036381Ssklower 			case 0x80:
44136381Ssklower 				/* DTE originated; look at the diagnostic */
44245899Ssklower 				error = (CONL_ERROR_MASK | cause);
44336381Ssklower 				goto done;
44436381Ssklower 
44536381Ssklower 			case 0x01: /* number busy */
44636381Ssklower 			case 0x81:
44736381Ssklower 			case 0x09: /* Out of order */
44836381Ssklower 			case 0x89:
44936381Ssklower 			case 0x11: /* Remot Procedure Error */
45036381Ssklower 			case 0x91:
45136381Ssklower 			case 0x19: /* reverse charging accept not subscribed */
45236381Ssklower 			case 0x99:
45336381Ssklower 			case 0x21: /* Incampat destination */
45436381Ssklower 			case 0xa1:
45536381Ssklower 			case 0x29: /* fast select accept not subscribed */
45636381Ssklower 			case 0xa9:
45736381Ssklower 			case 0x39: /* ship absent */
45836381Ssklower 			case 0xb9:
45936381Ssklower 			case 0x03: /* invalid facil request */
46036381Ssklower 			case 0x83:
46136381Ssklower 			case 0x0b: /* access barred */
46236381Ssklower 			case 0x8b:
46336381Ssklower 			case 0x13: /* local procedure error */
46436381Ssklower 			case 0x93:
46536381Ssklower 			case 0x05: /* network congestion */
46636381Ssklower 			case 0x85:
46736381Ssklower 			case 0x8d: /* not obtainable */
46836381Ssklower 			case 0x0d:
46936381Ssklower 			case 0x95: /* RPOA out of order */
47036381Ssklower 			case 0x15:
47136381Ssklower 				/* take out bit 8
47236381Ssklower 				 * so we don't have to have so many perror entries
47336381Ssklower 				 */
47445899Ssklower 				error = (CONL_ERROR_MASK | 0x100 | (cause & ~0x80));
47536381Ssklower 				goto done;
47636381Ssklower 
47736381Ssklower 			case 0xc1: /* gateway-detected proc error */
47836381Ssklower 			case 0xc3: /* gateway congestion */
47936381Ssklower 
48045899Ssklower 				error = (CONL_ERROR_MASK | 0x100 | cause);
48136381Ssklower 				goto done;
48236381Ssklower 		}
48336381Ssklower 	}
48436381Ssklower 	/* otherwise, a *hopefully* valid perror exists in the e_reason field */
48545899Ssklower 	error = xp->packet_data;
48636381Ssklower 	if (error = 0) {
48736381Ssklower 		printf("Incoming PKT TYPE 0x%x with reason 0x%x\n",
48845899Ssklower 			pk_decode(xp),
48945899Ssklower 			cause);
49036381Ssklower 		error = E_CO_HLI_DISCA;
49136381Ssklower 	}
49236381Ssklower 
49336381Ssklower done:
49436381Ssklower 	return error;
49536381Ssklower }
49636381Ssklower 
49736381Ssklower 
49836381Ssklower 
49936381Ssklower #endif KERNEL
50036381Ssklower 
50136381Ssklower /*
50236381Ssklower  * NAME:	make_partial_x25_packet()
50336381Ssklower  *
50436381Ssklower  * FUNCTION and ARGUMENTS:
50545899Ssklower  *	Makes part of an X.25 call packet, for use by x25.
50636381Ssklower  *  (src) and (dst) are the NSAP-addresses of source and destination.
50736381Ssklower  *	(buf) is a ptr to a buffer into which to write this partial header.
50836381Ssklower  *
50945899Ssklower  *	 0			Facility length (in octets)
51045899Ssklower  *	 1			Facility field, which is a set of:
51136381Ssklower  *	  m			facil code
51236381Ssklower  *	  m+1		facil param len (for >2-byte facilities) in octets
51336381Ssklower  *	  m+2..p	facil param field
51436381Ssklower  *  q			user data (protocol identification octet)
51536381Ssklower  *
51636381Ssklower  *
51736381Ssklower  * RETURNS:
51836381Ssklower  *  0 if OK
51936381Ssklower  *  E* if failed.
52045899Ssklower  *
52145899Ssklower  * SIDE EFFECTS:
52245899Ssklower  * Stores facilites mbuf in X.25 control block, where the connect
52345899Ssklower  * routine knows where to look for it.
52436381Ssklower  */
52536381Ssklower 
52636381Ssklower #ifdef X25_1984
52736381Ssklower int cons_use_facils = 1;
52836381Ssklower #else X25_1984
52936381Ssklower int cons_use_facils = 0;
53036381Ssklower #endif X25_1984
53136381Ssklower 
53236381Ssklower int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */
53336381Ssklower 
53436381Ssklower Static int
53545899Ssklower make_partial_x25_packet(isop, lcp)
53645899Ssklower 	struct isopcb *isop;
53745899Ssklower 	struct pklcd *lcp;
53836381Ssklower {
53936381Ssklower 	u_int				proto;
54036381Ssklower 	int					flag;
54145899Ssklower 	caddr_t 			buf;
54249041Ssklower 	register caddr_t	ptr;
54336381Ssklower 	register int		len	= 0;
54436381Ssklower 	int 				buflen	=0;
54536381Ssklower 	caddr_t				facil_len;
54636381Ssklower 	int 				oddness	= 0;
54745899Ssklower 	struct mbuf *m;
54836381Ssklower 
54936381Ssklower 
55045899Ssklower 	MGET(m, MT_DATA, M_WAITOK);
55145899Ssklower 	if (m == 0)
55245899Ssklower 		return ENOBUFS;
55345899Ssklower 	buf = mtod(m, caddr_t);
55449041Ssklower 	ptr = buf;
55536381Ssklower 	IFDEBUG(D_CCONN)
55636381Ssklower 		printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
55745899Ssklower 			isop->isop_laddr, isop->isop_faddr, proto, m, flag);
55836381Ssklower 	ENDDEBUG
55936381Ssklower 
56036381Ssklower 	/* ptr now points to facil length (len of whole facil field in OCTETS */
56136381Ssklower 	facil_len = ptr ++;
56236381Ssklower 
56336381Ssklower 	IFDEBUG(D_CADDR)
56436381Ssklower 		printf("make_partial  calling: ptr 0x%x, len 0x%x\n", ptr,
56545899Ssklower 				isop->isop_laddr->siso_addr.isoa_len);
56636381Ssklower 	ENDDEBUG
56745899Ssklower 	if (cons_use_facils) {
56836381Ssklower 		*ptr = 0xcb; /* calling facility code */
56936381Ssklower 		ptr ++;
57036381Ssklower 		ptr ++; /* leave room for facil param len (in OCTETS + 1) */
57136381Ssklower 		ptr ++; /* leave room for the facil param len (in nibbles),
57236381Ssklower 				* high two bits of which indicate full/partial NSAP
57336381Ssklower 				*/
57445899Ssklower 		len = isop->isop_laddr->siso_addr.isoa_len;
57545899Ssklower 		bcopy( isop->isop_laddr->siso_data, ptr, len);
57636381Ssklower 		*(ptr-2) = len+2; /* facil param len in octets */
57736381Ssklower 		*(ptr-1) = len<<1; /* facil param len in nibbles */
57836381Ssklower 		ptr += len;
57936381Ssklower 
58036381Ssklower 		IFDEBUG(D_CADDR)
58136381Ssklower 			printf("make_partial  called: ptr 0x%x, len 0x%x\n", ptr,
58245899Ssklower 					isop->isop_faddr->siso_addr.isoa_len);
58336381Ssklower 		ENDDEBUG
58436381Ssklower 		*ptr = 0xc9; /* called facility code */
58536381Ssklower 		ptr ++;
58636381Ssklower 		ptr ++; /* leave room for facil param len (in OCTETS + 1) */
58736381Ssklower 		ptr ++; /* leave room for the facil param len (in nibbles),
58836381Ssklower 				* high two bits of which indicate full/partial NSAP
58936381Ssklower 				*/
59045899Ssklower 		len = isop->isop_faddr->siso_nlen;
59145899Ssklower 		bcopy(isop->isop_faddr->siso_data, ptr, len);
59236381Ssklower 		*(ptr-2) = len+2; /* facil param len = addr len + 1 for each of these
59336381Ssklower 						  * two length fields, in octets */
59436381Ssklower 		*(ptr-1) = len<<1; /* facil param len in nibbles */
59536381Ssklower 		ptr += len;
59636381Ssklower 
59736381Ssklower 	}
59836381Ssklower 	*facil_len = ptr - facil_len - 1;
59945899Ssklower 	if (*facil_len > MAX_FACILITIES)
60036381Ssklower 		return E_CO_PNA_LONG;
60136381Ssklower 
60245899Ssklower 	if (cons_use_udata) {
60345899Ssklower 		if (isop->isop_x25crud_len > 0) {
60436381Ssklower 			/*
60536381Ssklower 			 *	The user specified something. Stick it in
60636381Ssklower 			 */
60745899Ssklower 			bcopy(isop->isop_x25crud, lcp->lcd_faddr.x25_udata,
60845899Ssklower 					isop->isop_x25crud_len);
60945899Ssklower 			lcp->lcd_faddr.x25_udlen = isop->isop_x25crud_len;
61036381Ssklower 		}
61136381Ssklower 	}
61236381Ssklower 
61336381Ssklower 	buflen = (int)(ptr - buf);
61436381Ssklower 
61536381Ssklower 	IFDEBUG(D_CDUMP_REQ)
61636381Ssklower 		register int i;
61736381Ssklower 
61836381Ssklower 		printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n",
61936381Ssklower 			buf, buflen, buflen);
62036381Ssklower 		for( i=0; i < buflen; ) {
62136381Ssklower 			printf("+%d: %x %x %x %x    %x %x %x %x\n",
62236381Ssklower 				i,
62336381Ssklower 				*(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3),
62436381Ssklower 				*(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7));
62536381Ssklower 			i+=8;
62636381Ssklower 		}
62736381Ssklower 	ENDDEBUG
62836381Ssklower 	IFDEBUG(D_CADDR)
62936381Ssklower 		printf("make_partial returns buf 0x%x size 0x%x bytes\n",
63036381Ssklower 			mtod(m, caddr_t), buflen);
63136381Ssklower 	ENDDEBUG
63236381Ssklower 
63345899Ssklower 	if (buflen > MHLEN)
63436381Ssklower 		return E_CO_PNA_LONG;
63536381Ssklower 
63636381Ssklower 	m->m_len = buflen;
63745899Ssklower 	lcp->lcd_facilities = m;
63836381Ssklower 	return  0;
63936381Ssklower }
64036381Ssklower 
64136381Ssklower /*
64236381Ssklower  * NAME:	NSAPtoDTE()
64336381Ssklower  * CALLED FROM:
64436381Ssklower  *  make_partial_x25_packet()
64536381Ssklower  * FUNCTION and ARGUMENTS:
64636381Ssklower  *  get a DTE address from an NSAP-address (struct sockaddr_iso)
64736381Ssklower  *  (dst_octet) is the octet into which to begin stashing the DTE addr
64836381Ssklower  *  (dst_nibble) takes 0 or 1.  1 means begin filling in the DTE addr
64936381Ssklower  * 		in the high-order nibble of dst_octet.  0 means low-order nibble.
65036381Ssklower  *  (addr) is the NSAP-address
65136381Ssklower  *  (flag) is true if the transport suffix is to become the
65236381Ssklower  *		last two digits of the DTE address
65345899Ssklower  *  A DTE address is a series of ASCII digits
65436381Ssklower  *
65536381Ssklower  *	A DTE address may have leading zeros. The are significant.
65636381Ssklower  *		1 digit per nibble, may be an odd number of nibbles.
65736381Ssklower  *
65836381Ssklower  *  An NSAP-address has the DTE address in the IDI. Leading zeros are
65936381Ssklower  *		significant. Trailing hex f indicates the end of the DTE address.
66045899Ssklower  *  	The IDI is a series of BCD digits, one per nibble.
66136381Ssklower  *
66236381Ssklower  * RETURNS
66336381Ssklower  *  # significant digits in the DTE address, -1 if error.
66436381Ssklower  */
66536381Ssklower 
66636381Ssklower Static int
66745899Ssklower NSAPtoDTE(siso, sx25)
66845899Ssklower 	register struct sockaddr_iso *siso;
66945899Ssklower 	register struct sockaddr_x25 *sx25;
67036381Ssklower {
67145899Ssklower 	int		dtelen = -1;
67236381Ssklower 
67336381Ssklower 	IFDEBUG(D_CADDR)
67445899Ssklower 		printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&siso->siso_addr));
67536381Ssklower 	ENDDEBUG
67636381Ssklower 
67745899Ssklower 	if (siso->siso_data[0] == AFI_37) {
67845899Ssklower 		register char *out = sx25->x25_addr;
67945899Ssklower 		register char *in = siso->siso_data + 1;
68045899Ssklower 		register int nibble;
68149041Ssklower 		char *lim = siso->siso_data + siso->siso_nlen;
68249041Ssklower 		char *olim = out+15;
68345899Ssklower 		int lowNibble = 0;
68445899Ssklower 
68545899Ssklower 		while (in < lim) {
68645899Ssklower 			nibble = ((lowNibble ? *in++ : (*in >> 4)) & 0xf) | 0x30;
68745899Ssklower 			lowNibble ^= 1;
68849041Ssklower 			if (nibble != 0x3f && out < olim)
68945899Ssklower 				*out++ = nibble;
69045899Ssklower 		}
69145899Ssklower 		dtelen = out - sx25->x25_addr;
69245899Ssklower 		*out++ = 0;
69345899Ssklower 	} else {
69445899Ssklower 		register struct rtentry *rt = rtalloc1(siso, 1);
69545899Ssklower 		/* error = iso_8208snparesolve(addr, x121string, &x121strlen);*/
69645899Ssklower 
69745899Ssklower 		if (rt) {
69845899Ssklower 			register struct sockaddr_x25 *sxx =
69945899Ssklower 							(struct sockaddr_x25 *)rt->rt_gateway;
70045899Ssklower 			register char *in = sxx->x25_addr;
70145899Ssklower 
70245899Ssklower 			rt->rt_use--;
70345899Ssklower 			if (sxx && sxx->x25_family == AF_CCITT) {
70445899Ssklower 				bcopy(sx25->x25_addr, sxx->x25_addr, sizeof(sx25->x25_addr));
70545899Ssklower 				while (*in++) {}
70645899Ssklower 				dtelen = in - sxx->x25_addr;
70745899Ssklower 			}
70845899Ssklower 		}
70936381Ssklower 	}
71045899Ssklower 	return dtelen;
71136381Ssklower }
71236381Ssklower 
71336381Ssklower /*
71436381Ssklower  * NAME:	FACILtoNSAP()
71536381Ssklower  * CALLED FROM:
71636381Ssklower  *  parse_facil()
71736381Ssklower  * FUNCTION and ARGUMENTS:
71836381Ssklower  * 	Creates and NSAP in the sockaddr_iso (addr) from the
71945899Ssklower  *  x.25 facility found at buf - 1.
72036381Ssklower  * RETURNS:
72145899Ssklower  *  length of parameter if ok, -1 if error.
72236381Ssklower  */
72336381Ssklower 
72436381Ssklower Static int
72545899Ssklower FACILtoNSAP(addr, buf)
72645899Ssklower 	u_char 		*buf;
72736381Ssklower 	register struct sockaddr_iso *addr;
72836381Ssklower {
72945899Ssklower 	int len_in_nibbles, param_len = *buf++;
73045899Ssklower 	u_char			buf_len; /* in bytes */
73136381Ssklower 
73236381Ssklower 	IFDEBUG(D_CADDR)
73336381Ssklower 		printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n",
73436381Ssklower 			buf, buf_len, addr );
73536381Ssklower 	ENDDEBUG
73636381Ssklower 
73745899Ssklower 	len_in_nibbles = *buf & 0x3f;
73845899Ssklower 	buf_len = (len_in_nibbles + 1) >> 1;
73936381Ssklower 	/* despite the fact that X.25 makes us put a length in nibbles
74036381Ssklower 	 * here, the NSAP-addrs are always in full octets
74136381Ssklower 	 */
74245899Ssklower 	switch (*buf++ & 0xc0) {
74345899Ssklower 	case 0:
74445899Ssklower 		/* Entire OSI NSAP address */
74545899Ssklower 		bcopy((caddr_t)buf, addr->siso_data, addr->siso_nlen = buf_len);
74645899Ssklower 		break;
74736381Ssklower 
74845899Ssklower 	case 40:
74945899Ssklower 		/* Partial OSI NSAP address, assume trailing */
75045899Ssklower 		if (buf_len + addr->siso_nlen > sizeof(addr->siso_addr))
75145899Ssklower 			return -1;
75245899Ssklower 		bcopy((caddr_t)buf, TSEL(addr), buf_len);
75345899Ssklower 		addr->siso_nlen += buf_len;
75445899Ssklower 		break;
75536381Ssklower 
75645899Ssklower 	default:
75745899Ssklower 		/* Rather than blow away the connection, just ignore and use
75845899Ssklower 		   NSAP from DTE */;
75936381Ssklower 	}
76045899Ssklower 	return param_len;
76145899Ssklower }
76236381Ssklower 
76345899Ssklower static
76445899Ssklower init_siso(siso)
76545899Ssklower register struct sockaddr_iso *siso;
76645899Ssklower {
76745899Ssklower 	siso->siso_len = sizeof (*siso);
76845899Ssklower 	siso->siso_family = AF_ISO;
76945899Ssklower 	siso->siso_data[0] = AFI_37;
77045899Ssklower 	siso->siso_nlen = 8;
77136381Ssklower }
77236381Ssklower 
77336381Ssklower /*
77436381Ssklower  * NAME:	DTEtoNSAP()
77536381Ssklower  * CALLED FROM:
77636381Ssklower  *  parse_facil()
77736381Ssklower  * FUNCTION and ARGUMENTS:
77836381Ssklower  *  Creates a type 37 NSAP in the sockaddr_iso (addr)
77945899Ssklower  * 	from a DTE address found in a sockaddr_x25.
78036381Ssklower  *
78136381Ssklower  * RETURNS:
78236381Ssklower  *  0 if ok; E* otherwise.
78336381Ssklower  */
78436381Ssklower 
78536381Ssklower Static  int
78645899Ssklower DTEtoNSAP(addr, sx)
78736381Ssklower 	struct sockaddr_iso *addr;
78845899Ssklower 	struct sockaddr_x25 *sx;
78936381Ssklower {
79045899Ssklower 	register char		*in, *out;
79145899Ssklower 	register int		first;
79245899Ssklower 	int					pad_tail = 0;
79345899Ssklower 	int 				src_len;
79436381Ssklower 
79536381Ssklower 
79645899Ssklower 	init_siso(addr);
79745899Ssklower 	src_len = strlen(sx->x25_addr);
79845899Ssklower 	in = sx->x25_addr;
79945899Ssklower 	out = addr->siso_data + 1;
80045899Ssklower 	if (*in == '0' && (src_len & 1 == 0)) {
80145899Ssklower 		pad_tail = 0xf;
80245899Ssklower 		src_len++;
80345899Ssklower 	}
80445899Ssklower 	for (first = 0; src_len > 0; src_len --) {
80545899Ssklower 		first |= *in++;
80645899Ssklower 		if (src_len & 1) {
80745899Ssklower 			*out++ = first;
80845899Ssklower 			first = 0;
80945899Ssklower 		}
81045899Ssklower 		else first <<= 4;
81145899Ssklower 	}
81245899Ssklower 	if (pad_tail)
81345899Ssklower 		out[-1] |= 0xf;
81436381Ssklower 	return 0; /* ok */
81536381Ssklower }
81636381Ssklower 
81736381Ssklower /*
81836381Ssklower  * FUNCTION and ARGUMENTS:
81936381Ssklower  *	parses (buf_len) bytes beginning at (buf) and finds
82036381Ssklower  *  a called nsap, a calling nsap, and protocol identifier.
82136381Ssklower  * RETURNS:
82236381Ssklower  *  0 if ok, E* otherwise.
82336381Ssklower  */
82436381Ssklower 
82545899Ssklower static int
82645899Ssklower parse_facil(lcp, isop, buf, buf_len)
82736381Ssklower 	caddr_t 		buf;
82836381Ssklower 	u_char			buf_len; /* in bytes */
82945899Ssklower 	struct			isopcb *isop;
83045899Ssklower 	struct			pklcd *lcp;
83136381Ssklower {
83245899Ssklower 	register struct sockaddr_iso *called = isop->isop_laddr;
83345899Ssklower 	register struct sockaddr_iso *calling = isop->isop_faddr;
83436381Ssklower 	register int 	i;
83545899Ssklower 	register u_char 	*ptr = (u_char *)buf;
83645899Ssklower 	u_char			*ptr_lim, *facil_lim;
83745899Ssklower 	int 			facil_param_len, facil_len;
83836381Ssklower 
83936381Ssklower 	IFDEBUG(D_CADDR)
84045899Ssklower 		printf("parse_facil(0x%x, 0x%x, 0x%x, 0x%x)\n",
84145899Ssklower 			buf, buf_len, called, calling);
84236381Ssklower 		dump_buf(buf, buf_len);
84336381Ssklower 	ENDDEBUG
84436381Ssklower 
84536381Ssklower 	/* find the beginnings of the facility fields in buf
84636381Ssklower 	 * by skipping over the called & calling DTE addresses
84736381Ssklower 	 * i <- # nibbles in called + # nibbles in calling
84836381Ssklower 	 * i += 1 so that an odd nibble gets rounded up to even
84936381Ssklower 	 * before dividing by 2, then divide by two to get # octets
85036381Ssklower 	 */
85145899Ssklower 	i = (int)(*ptr >> 4) + (int)(*ptr&0xf);
85236381Ssklower 	i++;
85345899Ssklower 	ptr += i >> 1;
85436381Ssklower 	ptr ++; /* plus one for the DTE lengths byte */
85536381Ssklower 
85636381Ssklower 	/* ptr now is at facil_length field */
85745899Ssklower 	facil_len = *ptr++;
85845899Ssklower 	facil_lim = ptr + facil_len;
85936381Ssklower 	IFDEBUG(D_CADDR)
86045899Ssklower 		printf("parse_facils: facil length is  0x%x\n", (int) facil_len);
86136381Ssklower 	ENDDEBUG
86236381Ssklower 
86345899Ssklower 	while (ptr <= facil_lim) {
86436381Ssklower 		/* get NSAP addresses from facilities */
86545899Ssklower 		switch (*ptr++) {
86636381Ssklower 			case 0xcb:
86745899Ssklower 				/* calling NSAP */
86845899Ssklower 				facil_param_len = FACILtoNSAP(isop->isop_faddr, ptr);
86936381Ssklower 				break;
87036381Ssklower 			case 0xc9:
87145899Ssklower 				/* called NSAP */
87245899Ssklower 				facil_param_len = FACILtoNSAP(isop->isop_laddr, ptr);
87336381Ssklower 				break;
87436381Ssklower 
87536381Ssklower 				/* from here to default are legit cases that I ignore */
87636381Ssklower 				/* variable length */
87736381Ssklower 			case 0xca:  /* end-to-end transit delay negot */
87836381Ssklower 			case 0xc6:  /* network user id */
87936381Ssklower 			case 0xc5: 	/* charging info : indicating monetary unit */
88036381Ssklower 			case 0xc2: 	/* charging info : indicating segment count */
88136381Ssklower 			case 0xc1: 	/* charging info : indicating call duration */
88236381Ssklower 			case 0xc4: 	/* RPOA extended format */
88336381Ssklower 			case 0xc3: 	/* call redirection notification */
88436381Ssklower 				facil_param_len = 0;
88536381Ssklower 				break;
88636381Ssklower 
88736381Ssklower 				/* 1 octet */
88836381Ssklower 			case 0x0a:  /* min. throughput class negot */
88936381Ssklower 			case 0x02:  /* throughput class */
89036381Ssklower 			case 0x03:  case 0x47:  /* CUG shit */
89136381Ssklower 			case 0x0b:  /* expedited data negot */
89236381Ssklower 			case 0x01:  /* Fast select or reverse charging
89336381Ssklower 						(example of intelligent protocol design) */
89436381Ssklower 			case 0x04: 	/* charging info : requesting service */
89536381Ssklower 			case 0x08: 	/* called line addr modified notification */
89636381Ssklower 				facil_param_len = 1;
89736381Ssklower 				break;
89836381Ssklower 
89936381Ssklower 				/* any 2 octets */
90036381Ssklower 			case 0x42:  /* pkt size */
90136381Ssklower 			case 0x43:  /* win size */
90236381Ssklower 			case 0x44:  /* RPOA basic format */
90336381Ssklower 			case 0x41:  /* bilateral CUG shit */
90436381Ssklower 			case 0x49: 	/* transit delay selection and indication */
90536381Ssklower 				facil_param_len = 2;
90636381Ssklower 				break;
90736381Ssklower 
90836381Ssklower 				/* don't have any 3 octets */
90936381Ssklower 				/*
91036381Ssklower 				facil_param_len = 3;
91136381Ssklower 				*/
91236381Ssklower 			default:
91336381Ssklower 				printf(
91436381Ssklower "BOGUS FACILITY CODE facil_len 0x%x *facil_len 0x%x, ptr 0x%x *ptr 0x%x\n",
91545899Ssklower 					ptr, facil_len, ptr - 1, ptr[-1]);
91636381Ssklower 				/* facil that we don't handle */
91736381Ssklower 				return E_CO_HLI_REJI;
91836381Ssklower 		}
91945899Ssklower 		if (facil_param_len == -1)
92045899Ssklower 			return E_CO_REG_ICDA;
92145899Ssklower 		if (facil_param_len == 0) /* variable length */
92236381Ssklower 			facil_param_len = (int)*ptr; /* 1 + the real facil param */
92336381Ssklower 		ptr += facil_param_len;
92436381Ssklower 	}
92536381Ssklower 	return 0;
92636381Ssklower }
92736381Ssklower 
92845899Ssklower #endif TPCONS
929