xref: /csrg-svn/sys/netiso/if_cons.c (revision 50648)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*50648Ssklower  *	@(#)if_cons.c	7.11 (Berkeley) 07/29/91
849268Sbostic  */
949268Sbostic 
1036381Ssklower /***********************************************************
1136381Ssklower 		Copyright IBM Corporation 1987
1236381Ssklower 
1336381Ssklower                       All Rights Reserved
1436381Ssklower 
1536381Ssklower Permission to use, copy, modify, and distribute this software and its
1636381Ssklower documentation for any purpose and without fee is hereby granted,
1736381Ssklower provided that the above copyright notice appear in all copies and that
1836381Ssklower both that copyright notice and this permission notice appear in
1936381Ssklower supporting documentation, and that the name of IBM not be
2036381Ssklower used in advertising or publicity pertaining to distribution of the
2136381Ssklower software without specific, written prior permission.
2236381Ssklower 
2336381Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436381Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536381Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636381Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736381Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836381Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936381Ssklower SOFTWARE.
3036381Ssklower 
3136381Ssklower ******************************************************************/
3236381Ssklower 
3336381Ssklower /*
3436381Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536381Ssklower  */
3636381Ssklower /*
3736381Ssklower  * $Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $
3836381Ssklower  * $Source: /usr/argo/sys/netiso/RCS/if_cons.c,v $
3936381Ssklower  *
4036381Ssklower  * cons.c - Connection Oriented Network Service:
4136381Ssklower  * including support for a) user transport-level service,
4236381Ssklower  *	b) COSNS below CLNP, and c) CONS below TP.
4345899Ssklower  */
4436381Ssklower 
4545899Ssklower #ifdef TPCONS
4645899Ssklower #ifdef KERNEL
4736381Ssklower #ifdef ARGO_DEBUG
4836381Ssklower #define Static
4936381Ssklower unsigned LAST_CALL_PCB;
5036381Ssklower #else ARGO_DEBUG
5136381Ssklower #define Static static
5236381Ssklower #endif ARGO_DEBUG
5336381Ssklower 
5436381Ssklower 
5536381Ssklower 
5645899Ssklower #ifndef SOCK_STREAM
5736381Ssklower #include "param.h"
5836381Ssklower #include "systm.h"
5936381Ssklower #include "mbuf.h"
6036381Ssklower #include "protosw.h"
6136381Ssklower #include "socket.h"
6236381Ssklower #include "socketvar.h"
6336381Ssklower #include "errno.h"
6436381Ssklower #include "ioctl.h"
6540783Smarc #include "tsleep.h"
6636381Ssklower 
6736381Ssklower #include "../net/if.h"
6836381Ssklower #include "../net/netisr.h"
6936381Ssklower #include "../net/route.h"
7036381Ssklower 
7145899Ssklower #include "iso_errno.h"
7245899Ssklower #include "argo_debug.h"
7345899Ssklower #include "tp_trace.h"
7445899Ssklower #include "iso.h"
7545899Ssklower #include "cons.h"
7645899Ssklower #include "iso_pcb.h"
7736381Ssklower 
7845899Ssklower #include "../netccitt/x25.h"
7945899Ssklower #include "../netccitt/pk.h"
8045899Ssklower #include "../netccitt/pk_var.h"
8145899Ssklower #endif
8245899Ssklower 
8336381Ssklower #ifdef ARGO_DEBUG
8436381Ssklower #define MT_XCONN	0x50
8536381Ssklower #define MT_XCLOSE	0x51
8636381Ssklower #define MT_XCONFIRM	0x52
8736381Ssklower #define MT_XDATA	0x53
8836381Ssklower #define MT_XHEADER	0x54
8936381Ssklower #else
9036381Ssklower #define MT_XCONN	MT_DATA
9136381Ssklower #define MT_XCLOSE	MT_DATA
9236381Ssklower #define MT_XCONFIRM	MT_DATA
9336381Ssklower #define MT_XDATA	MT_DATA
9436381Ssklower #define MT_XHEADER	MT_HEADER
9536381Ssklower #endif ARGO_DEBUG
9636381Ssklower 
9736381Ssklower #define DONTCLEAR	 -1
9836381Ssklower 
9936381Ssklower /*********************************************************************
10045899Ssklower  * cons.c - CONS interface to the x.25 layer
10136381Ssklower  *
10236381Ssklower  * TODO: figure out what resources we might run out of besides mbufs.
10336381Ssklower  *  If we run out of any of them (including mbufs) close and recycle
10436381Ssklower  *  lru x% of the connections, for some parameter x.
10536381Ssklower  *
10645899Ssklower  * There are 2 interfaces from above:
10736381Ssklower  * 1) from TP0:
10836381Ssklower  *    cons CO network service
10936381Ssklower  *    TP associates a transport connection with a network connection.
11036381Ssklower  * 	  cons_output( isop, m, len, isdgm==0 )
11136381Ssklower  *        co_flags == 0
11245899Ssklower  * 2) from TP4:
11336381Ssklower  *	  It's a datagram service, like clnp is. - even though it calls
11436381Ssklower  *			cons_output( isop, m, len, isdgm==1 )
11536381Ssklower  *	  it eventually goes through
11636381Ssklower  *			cosns_output(ifp, m, dst).
11736381Ssklower  *    TP4 permits multiplexing (reuse, possibly simultaneously) of the
11836381Ssklower  *	  network connections.
11936381Ssklower  *    This means that many sockets (many tpcbs) may be associated with
12045899Ssklower  *    this pklcd, hence cannot have a back ptr from pklcd to a tpcb.
12136381Ssklower  *        co_flags & CONSF_DGM
12245899Ssklower  *    co_socket is null since there may be many sockets that use this pklcd.
12336381Ssklower  *
12436381Ssklower NOTE:
12536381Ssklower 	streams would really be nice. sigh.
12636381Ssklower NOTE:
12736381Ssklower 	PVCs could be handled by config-ing a cons with an address and with the
12836381Ssklower 	IFF_POINTTOPOINT flag on.  This code would then have to skip the
12936381Ssklower 	connection setup stuff for pt-to-pt links.
13036381Ssklower 
13136381Ssklower 
13236381Ssklower  *********************************************************************/
13336381Ssklower 
13436381Ssklower 
13536381Ssklower #define CONS_IFQMAXLEN 5
13636381Ssklower 
13736381Ssklower 
13836381Ssklower /* protosw pointers for getting to higher layer */
13936381Ssklower Static 	struct protosw	*CLNP_proto;
14036381Ssklower Static 	struct protosw	*TP_proto;
14136381Ssklower Static 	struct protosw	*X25_proto;
14236381Ssklower Static 	int				issue_clear_req();
14336381Ssklower 
14436381Ssklower #ifndef	PHASEONE
14536381Ssklower extern	struct ifaddr	*ifa_ifwithnet();
14636381Ssklower #endif	PHASEONE
14736381Ssklower 
14836381Ssklower extern	struct ifaddr	*ifa_ifwithaddr();
14936381Ssklower 
15036381Ssklower extern struct	isopcb	tp_isopcb; /* chain of all TP pcbs */
15136381Ssklower 
15236381Ssklower 
15336381Ssklower Static 	int parse_facil(), NSAPtoDTE(), make_partial_x25_packet();
15436381Ssklower Static	int FACILtoNSAP(), DTEtoNSAP();
15545899Ssklower Static	struct pklcd *cons_chan_to_pcb();
15636381Ssklower 
15736381Ssklower #define HIGH_NIBBLE 1
15836381Ssklower #define LOW_NIBBLE 0
15936381Ssklower 
16036381Ssklower /*
16136381Ssklower  * NAME:	nibble_copy()
16236381Ssklower  * FUNCTION and ARGUMENTS:
16336381Ssklower  * 	copies (len) nibbles from (src_octet), high or low nibble
16436381Ssklower  *  to (dst_octet), high or low nibble,
16536381Ssklower  * src_nibble & dst_nibble should be:
16636381Ssklower  * 	HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble
16736381Ssklower  * 	LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble
16836381Ssklower  * RETURNS: VOID
16936381Ssklower  */
17036381Ssklower void
17145899Ssklower nibble_copy(src_octet, src_nibble, dst_octet, dst_nibble, len)
17236381Ssklower 	register char  	*src_octet;
17336381Ssklower 	register char  	*dst_octet;
17436381Ssklower 	register unsigned		src_nibble;
17536381Ssklower 	register unsigned 		dst_nibble;
17636381Ssklower 	int		len;
17736381Ssklower {
17836381Ssklower 
17936381Ssklower 	register 	i;
18036381Ssklower 	register 	unsigned dshift, sshift;
18136381Ssklower 
18236381Ssklower 	IFDEBUG(D_CADDR)
18336381Ssklower 		printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n",
18436381Ssklower 		 src_octet, src_nibble, dst_octet, dst_nibble, len);
18536381Ssklower 	ENDDEBUG
18636381Ssklower #define SHIFT 0x4
18736381Ssklower 
18836381Ssklower 	dshift = dst_nibble << 2;
18936381Ssklower 	sshift = src_nibble << 2;
19036381Ssklower 
19136381Ssklower 	for (i=0; i<len; i++) {
19236381Ssklower 		/* clear dst_nibble  */
19336381Ssklower 		*dst_octet 	&= ~(0xf<< dshift);
19436381Ssklower 
19536381Ssklower 		/* set dst nibble */
19636381Ssklower 		*dst_octet 	|= ( 0xf & (*src_octet >> sshift))<< dshift;
19736381Ssklower 
19836381Ssklower 		dshift		^= SHIFT;
19936381Ssklower 		sshift		^= SHIFT;
20036381Ssklower 		src_nibble 	= 1-src_nibble;
20136381Ssklower 		dst_nibble 	= 1-dst_nibble;
20236381Ssklower 		src_octet	+= src_nibble;
20336381Ssklower 		dst_octet 	+= dst_nibble;
20436381Ssklower 	}
20536381Ssklower 	IFDEBUG(D_CADDR)
20636381Ssklower 		printf("nibble_copy DONE\n");
20736381Ssklower 	ENDDEBUG
20836381Ssklower }
20936381Ssklower 
21036381Ssklower /*
21136381Ssklower  * NAME:	nibble_match()
21236381Ssklower  * FUNCTION and ARGUMENTS:
21336381Ssklower  * 	compares src_octet/src_nibble and dst_octet/dst_nibble  for len nibbles.
21436381Ssklower  * RETURNS: 0 if they differ, 1 if they are the same.
21536381Ssklower  */
21636381Ssklower int
21736381Ssklower nibble_match( src_octet, src_nibble, dst_octet, dst_nibble, len)
21836381Ssklower 	register char  	*src_octet;
21936381Ssklower 	register char  	*dst_octet;
22036381Ssklower 	register unsigned		src_nibble;
22136381Ssklower 	register unsigned 		dst_nibble;
22236381Ssklower 	int		len;
22336381Ssklower {
22436381Ssklower 
22536381Ssklower 	register 	i;
22636381Ssklower 	register 	unsigned dshift, sshift;
22736381Ssklower 	u_char		nibble_a, nibble_b;
22836381Ssklower 
22936381Ssklower 	IFDEBUG(D_CADDR)
23036381Ssklower 		printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n",
23136381Ssklower 		 src_octet, src_nibble, dst_octet, dst_nibble, len);
23236381Ssklower 	ENDDEBUG
23336381Ssklower #define SHIFT 0x4
23436381Ssklower 
23536381Ssklower 	dshift = dst_nibble << 2;
23636381Ssklower 	sshift = src_nibble << 2;
23736381Ssklower 
23836381Ssklower 	for (i=0; i<len; i++) {
23936381Ssklower 		nibble_b = ((*dst_octet)>>dshift) & 0xf;
24036381Ssklower 		nibble_a = ( 0xf & (*src_octet >> sshift));
24145899Ssklower 		if (nibble_b != nibble_a)
24236381Ssklower 			return 0;
24336381Ssklower 
24436381Ssklower 		dshift		^= SHIFT;
24536381Ssklower 		sshift		^= SHIFT;
24636381Ssklower 		src_nibble 	= 1-src_nibble;
24736381Ssklower 		dst_nibble 	= 1-dst_nibble;
24836381Ssklower 		src_octet	+= src_nibble;
24936381Ssklower 		dst_octet 	+= dst_nibble;
25036381Ssklower 	}
25136381Ssklower 	IFDEBUG(D_CADDR)
25236381Ssklower 		printf("nibble_match DONE\n");
25336381Ssklower 	ENDDEBUG
25436381Ssklower 	return 1;
25536381Ssklower }
25636381Ssklower 
25736381Ssklower /*
25836381Ssklower  **************************** NET PROTOCOL cons ***************************
25936381Ssklower  */
26036381Ssklower /*
26136381Ssklower  * NAME:	cons_init()
26236381Ssklower  * CALLED FROM:
26336381Ssklower  *	autoconf
26436381Ssklower  * FUNCTION:
26536381Ssklower  *	initialize the protocol
26636381Ssklower  */
26736381Ssklower cons_init()
26836381Ssklower {
26945899Ssklower 	int tp_incoming(), clnp_incoming();
27036381Ssklower 
27136381Ssklower 
27236381Ssklower 	CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM);
27336381Ssklower 	X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM);
27436381Ssklower 	TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET);
27536381Ssklower 	IFDEBUG(D_CCONS)
27636381Ssklower 		printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n",
27736381Ssklower 			CLNP_proto, X25_proto, TP_proto);
27836381Ssklower 	ENDDEBUG
27945899Ssklower #ifdef notdef
28045899Ssklower 	pk_protolisten(0x81, 0, clnp_incoming);
28145899Ssklower 	pk_protolisten(0x82, 0, esis_incoming);
28245899Ssklower 	pk_protolisten(0x84, 0, tp8878_A_incoming);
28349041Ssklower 	pk_protolisten(0, 0, tp_incoming);
28445899Ssklower #endif
28536381Ssklower }
28636381Ssklower 
28749937Ssklower tp_incoming(lcp, m)
28845899Ssklower struct pklcd *lcp;
28949937Ssklower register struct mbuf *m;
29036381Ssklower {
29145899Ssklower 	register struct isopcb *isop;
29245899Ssklower 	int cons_tpinput();
29336381Ssklower 
294*50648Ssklower 	if (iso_pcballoc((struct socket *)0, &tp_isopcb)) {
29549937Ssklower 		pk_close(lcp);
29645899Ssklower 		return;
29736381Ssklower 	}
298*50648Ssklower 	isop = tp_isopcb.isop_next;
29945899Ssklower 	lcp->lcd_upper = cons_tpinput;
30045899Ssklower 	lcp->lcd_upnext = (caddr_t)isop;
30149937Ssklower 	lcp->lcd_send(lcp); /* Confirms call */
30245899Ssklower 	isop->isop_chan = (caddr_t)lcp;
30345899Ssklower 	isop->isop_laddr = &isop->isop_sladdr;
30445899Ssklower 	isop->isop_faddr = &isop->isop_sfaddr;
30545899Ssklower 	DTEtoNSAP(isop->isop_laddr, &lcp->lcd_laddr);
30645899Ssklower 	DTEtoNSAP(isop->isop_faddr, &lcp->lcd_faddr);
307*50648Ssklower 	parse_facil(lcp, isop, &(mtod(m, struct x25_packet *)->packet_data),
30845899Ssklower 		m->m_pkthdr.len - PKHEADERLN);
30936381Ssklower }
31036381Ssklower 
31145899Ssklower cons_tpinput(lcp, m0)
31245899Ssklower struct mbuf *m0;
31345899Ssklower struct pklcd *lcp;
31436381Ssklower {
31545899Ssklower 	register struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext;
31645899Ssklower 	register struct x25_packet *xp;
317*50648Ssklower 	int cmd, ptype = CLEAR;
31836381Ssklower 
31949265Ssklower 	if (isop == 0)
32049265Ssklower 		return;
321*50648Ssklower 	if (m0 == 0)
32249041Ssklower 		goto dead;
32345899Ssklower 	switch(m0->m_type) {
32445899Ssklower 	case MT_DATA:
32545899Ssklower 	case MT_OOBDATA:
326*50648Ssklower 		tpcons_input(m0, isop->isop_faddr, isop->isop_laddr, (caddr_t)lcp);
32749584Ssklower 		return;
32836381Ssklower 
32945899Ssklower 	case MT_CONTROL:
330*50648Ssklower 		switch (ptype = pk_decode(mtod(m0, struct x25_packet *))) {
33136381Ssklower 
33245899Ssklower 		case RR:
33345899Ssklower 			cmd = PRC_CONS_SEND_DONE;
33445899Ssklower 			break;
33536381Ssklower 
33649265Ssklower 		case CALL_ACCEPTED:
33749265Ssklower 			if (lcp->lcd_sb.sb_mb)
33849265Ssklower 				lcp->lcd_send(lcp); /* XXX - fix this */
33949584Ssklower 			/*FALLTHROUGH*/
34049584Ssklower 		default:
34149584Ssklower 			return;
34249265Ssklower 
34349041Ssklower 		dead:
34449041Ssklower 		case CLEAR:
34549041Ssklower 		case CLEAR_CONF:
346*50648Ssklower 			lcp->lcd_upper = 0;
347*50648Ssklower 			lcp->lcd_upnext = 0;
348*50648Ssklower 			isop->isop_chan = 0;
349*50648Ssklower 		case RESET:
35045899Ssklower 			cmd = PRC_ROUTEDEAD;
35136381Ssklower 		}
35245899Ssklower 		tpcons_ctlinput(cmd, isop->isop_faddr, isop);
353*50648Ssklower 		if (cmd = PRC_ROUTEDEAD && isop->isop_refcnt == 0)
354*50648Ssklower 			iso_pcbdetach(isop);
35536381Ssklower 	}
35636381Ssklower }
35736381Ssklower 
35836381Ssklower /*
35936381Ssklower  * NAME:	cons_connect()
36036381Ssklower  * CALLED FROM:
36145899Ssklower  *	tpcons_pcbconnect() when opening a new connection.
36236381Ssklower  * FUNCTION anD ARGUMENTS:
36336381Ssklower  *  Figures out which device to use, finding a route if one doesn't
36436381Ssklower  *  already exist.
36536381Ssklower  * RETURN VALUE:
36636381Ssklower  *  returns E*
36736381Ssklower  */
36845899Ssklower cons_connect(isop)
36945899Ssklower 	register struct isopcb *isop;
37036381Ssklower {
37145899Ssklower 	register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
37236381Ssklower 	register struct mbuf 	*m;
37336381Ssklower 	struct ifaddr 			*ifa;
37449937Ssklower 	int error;
37536381Ssklower 
37636381Ssklower 	IFDEBUG(D_CCONN)
37745899Ssklower 		printf("cons_connect(0x%x): ", isop);
37845899Ssklower 		dump_isoaddr(isop->isop_faddr);
37945899Ssklower 		printf("myaddr: ");
38045899Ssklower 		dump_isoaddr(isop->isop_laddr);
38136381Ssklower 		printf("\n" );
38236381Ssklower 	ENDDEBUG
38345899Ssklower 	NSAPtoDTE(isop->isop_faddr, &lcp->lcd_faddr);
38449265Ssklower 	lcp->lcd_upper = cons_tpinput;
38549265Ssklower 	lcp->lcd_upnext = (caddr_t)isop;
38636381Ssklower 	IFDEBUG(D_CCONN)
38736381Ssklower 		printf(
38845899Ssklower 		"calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x)\n",
38945899Ssklower 			&lcp->lcd_faddr, &lcp->lcd_laddr,
39045899Ssklower 			isop->isop_socket->so_proto->pr_protocol);
39136381Ssklower 	ENDDEBUG
39249937Ssklower 	if ((error = make_partial_x25_packet(isop, lcp, m)) == 0)
39349937Ssklower 		error = pk_connect(lcp, &lcp->lcd_faddr);
39449937Ssklower 	return error;
39536381Ssklower }
39636381Ssklower 
39736381Ssklower /*
39836381Ssklower  **************************** DEVICE cons ***************************
39936381Ssklower  */
40036381Ssklower 
40136381Ssklower 
40236381Ssklower /*
40336381Ssklower  * NAME:	cons_ctlinput()
40436381Ssklower  * CALLED FROM:
40536381Ssklower  *  lower layer when ECN_CLEAR occurs : this routine is here
40636381Ssklower  *  for consistency - cons subnet service calls its higher layer
40736381Ssklower  *  through the protosw entry.
40836381Ssklower  * FUNCTION & ARGUMENTS:
40937536Smckusick  *  cmd is a PRC_* command, list found in ../sys/protosw.h
41036381Ssklower  *  copcb is the obvious.
41136381Ssklower  *  This serves the higher-layer cons service.
41236381Ssklower  * NOTE: this takes 3rd arg. because cons uses it to inform itself
41336381Ssklower  *  of things (timeouts, etc) but has a pcb instead of an address.
41436381Ssklower  */
41536381Ssklower cons_ctlinput(cmd, sa, copcb)
41636381Ssklower 	int cmd;
41736381Ssklower 	struct sockaddr *sa;
41845899Ssklower 	register struct pklcd *copcb;
41936381Ssklower {
42036381Ssklower }
42136381Ssklower 
42236381Ssklower 
42345899Ssklower find_error_reason( xp )
42445899Ssklower 	register struct x25_packet *xp;
42536381Ssklower {
42636381Ssklower 	extern u_char x25_error_stats[];
42745899Ssklower 	int error, cause;
42836381Ssklower 
42945899Ssklower 	if (xp) {
43045899Ssklower 		cause = 4[(char *)xp];
43145899Ssklower 		switch (cause) {
43236381Ssklower 			case 0x00:
43336381Ssklower 			case 0x80:
43436381Ssklower 				/* DTE originated; look at the diagnostic */
43545899Ssklower 				error = (CONL_ERROR_MASK | cause);
43636381Ssklower 				goto done;
43736381Ssklower 
43836381Ssklower 			case 0x01: /* number busy */
43936381Ssklower 			case 0x81:
44036381Ssklower 			case 0x09: /* Out of order */
44136381Ssklower 			case 0x89:
44236381Ssklower 			case 0x11: /* Remot Procedure Error */
44336381Ssklower 			case 0x91:
44436381Ssklower 			case 0x19: /* reverse charging accept not subscribed */
44536381Ssklower 			case 0x99:
44636381Ssklower 			case 0x21: /* Incampat destination */
44736381Ssklower 			case 0xa1:
44836381Ssklower 			case 0x29: /* fast select accept not subscribed */
44936381Ssklower 			case 0xa9:
45036381Ssklower 			case 0x39: /* ship absent */
45136381Ssklower 			case 0xb9:
45236381Ssklower 			case 0x03: /* invalid facil request */
45336381Ssklower 			case 0x83:
45436381Ssklower 			case 0x0b: /* access barred */
45536381Ssklower 			case 0x8b:
45636381Ssklower 			case 0x13: /* local procedure error */
45736381Ssklower 			case 0x93:
45836381Ssklower 			case 0x05: /* network congestion */
45936381Ssklower 			case 0x85:
46036381Ssklower 			case 0x8d: /* not obtainable */
46136381Ssklower 			case 0x0d:
46236381Ssklower 			case 0x95: /* RPOA out of order */
46336381Ssklower 			case 0x15:
46436381Ssklower 				/* take out bit 8
46536381Ssklower 				 * so we don't have to have so many perror entries
46636381Ssklower 				 */
46745899Ssklower 				error = (CONL_ERROR_MASK | 0x100 | (cause & ~0x80));
46836381Ssklower 				goto done;
46936381Ssklower 
47036381Ssklower 			case 0xc1: /* gateway-detected proc error */
47136381Ssklower 			case 0xc3: /* gateway congestion */
47236381Ssklower 
47345899Ssklower 				error = (CONL_ERROR_MASK | 0x100 | cause);
47436381Ssklower 				goto done;
47536381Ssklower 		}
47636381Ssklower 	}
47736381Ssklower 	/* otherwise, a *hopefully* valid perror exists in the e_reason field */
47845899Ssklower 	error = xp->packet_data;
47936381Ssklower 	if (error = 0) {
48036381Ssklower 		printf("Incoming PKT TYPE 0x%x with reason 0x%x\n",
48145899Ssklower 			pk_decode(xp),
48245899Ssklower 			cause);
48336381Ssklower 		error = E_CO_HLI_DISCA;
48436381Ssklower 	}
48536381Ssklower 
48636381Ssklower done:
48736381Ssklower 	return error;
48836381Ssklower }
48936381Ssklower 
49036381Ssklower 
49136381Ssklower 
49236381Ssklower #endif KERNEL
49336381Ssklower 
49436381Ssklower /*
49536381Ssklower  * NAME:	make_partial_x25_packet()
49636381Ssklower  *
49736381Ssklower  * FUNCTION and ARGUMENTS:
49845899Ssklower  *	Makes part of an X.25 call packet, for use by x25.
49936381Ssklower  *  (src) and (dst) are the NSAP-addresses of source and destination.
50036381Ssklower  *	(buf) is a ptr to a buffer into which to write this partial header.
50136381Ssklower  *
50245899Ssklower  *	 0			Facility length (in octets)
50345899Ssklower  *	 1			Facility field, which is a set of:
50436381Ssklower  *	  m			facil code
50536381Ssklower  *	  m+1		facil param len (for >2-byte facilities) in octets
50636381Ssklower  *	  m+2..p	facil param field
50736381Ssklower  *  q			user data (protocol identification octet)
50836381Ssklower  *
50936381Ssklower  *
51036381Ssklower  * RETURNS:
51136381Ssklower  *  0 if OK
51236381Ssklower  *  E* if failed.
51345899Ssklower  *
51445899Ssklower  * SIDE EFFECTS:
51545899Ssklower  * Stores facilites mbuf in X.25 control block, where the connect
51645899Ssklower  * routine knows where to look for it.
51736381Ssklower  */
51836381Ssklower 
51936381Ssklower #ifdef X25_1984
52036381Ssklower int cons_use_facils = 1;
52136381Ssklower #else X25_1984
52236381Ssklower int cons_use_facils = 0;
52336381Ssklower #endif X25_1984
52436381Ssklower 
52536381Ssklower int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */
52636381Ssklower 
52736381Ssklower Static int
52845899Ssklower make_partial_x25_packet(isop, lcp)
52945899Ssklower 	struct isopcb *isop;
53045899Ssklower 	struct pklcd *lcp;
53136381Ssklower {
53236381Ssklower 	u_int				proto;
53336381Ssklower 	int					flag;
53445899Ssklower 	caddr_t 			buf;
53549041Ssklower 	register caddr_t	ptr;
53636381Ssklower 	register int		len	= 0;
53736381Ssklower 	int 				buflen	=0;
53836381Ssklower 	caddr_t				facil_len;
53936381Ssklower 	int 				oddness	= 0;
54045899Ssklower 	struct mbuf *m;
54136381Ssklower 
54236381Ssklower 
54349584Ssklower 	IFDEBUG(D_CCONN)
54449584Ssklower 		printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
54549584Ssklower 			isop->isop_laddr, isop->isop_faddr, proto, m, flag);
54649584Ssklower 	ENDDEBUG
54749584Ssklower 	if (cons_use_udata) {
54849584Ssklower 		if (isop->isop_x25crud_len > 0) {
54949584Ssklower 			/*
55049584Ssklower 			 *	The user specified something. Stick it in
55149584Ssklower 			 */
55249584Ssklower 			bcopy(isop->isop_x25crud, lcp->lcd_faddr.x25_udata,
55349584Ssklower 					isop->isop_x25crud_len);
55449584Ssklower 			lcp->lcd_faddr.x25_udlen = isop->isop_x25crud_len;
55549584Ssklower 		}
55649584Ssklower 	}
55749584Ssklower 
55849584Ssklower 	if (cons_use_facils == 0) {
55949584Ssklower 		lcp->lcd_facilities = 0;
56049584Ssklower 		return 0;
56149584Ssklower 	}
56249937Ssklower 	MGETHDR(m, MT_DATA, M_WAITOK);
56345899Ssklower 	if (m == 0)
56445899Ssklower 		return ENOBUFS;
56545899Ssklower 	buf = mtod(m, caddr_t);
56649041Ssklower 	ptr = buf;
56736381Ssklower 
56836381Ssklower 	/* ptr now points to facil length (len of whole facil field in OCTETS */
56936381Ssklower 	facil_len = ptr ++;
57049937Ssklower 	m->m_len = 0;
57149937Ssklower 	pk_build_facilities(m, &lcp->lcd_faddr, 0);
57236381Ssklower 
57336381Ssklower 	IFDEBUG(D_CADDR)
57436381Ssklower 		printf("make_partial  calling: ptr 0x%x, len 0x%x\n", ptr,
57545899Ssklower 				isop->isop_laddr->siso_addr.isoa_len);
57636381Ssklower 	ENDDEBUG
57745899Ssklower 	if (cons_use_facils) {
57849937Ssklower 		*ptr++ = 0;	 /* Marker to separate X.25 facitilies from CCITT ones */
57949937Ssklower 		*ptr++ = 0x0f;
58036381Ssklower 		*ptr = 0xcb; /* calling facility code */
58136381Ssklower 		ptr ++;
58236381Ssklower 		ptr ++; /* leave room for facil param len (in OCTETS + 1) */
58336381Ssklower 		ptr ++; /* leave room for the facil param len (in nibbles),
58449937Ssklower 				 * high two bits of which indicate full/partial NSAP
58549937Ssklower 				 */
58645899Ssklower 		len = isop->isop_laddr->siso_addr.isoa_len;
58745899Ssklower 		bcopy( isop->isop_laddr->siso_data, ptr, len);
58849584Ssklower 		*(ptr-2) = len+1; /* facil param len in octets */
58936381Ssklower 		*(ptr-1) = len<<1; /* facil param len in nibbles */
59036381Ssklower 		ptr += len;
59136381Ssklower 
59236381Ssklower 		IFDEBUG(D_CADDR)
59336381Ssklower 			printf("make_partial  called: ptr 0x%x, len 0x%x\n", ptr,
59445899Ssklower 					isop->isop_faddr->siso_addr.isoa_len);
59536381Ssklower 		ENDDEBUG
59636381Ssklower 		*ptr = 0xc9; /* called facility code */
59736381Ssklower 		ptr ++;
59836381Ssklower 		ptr ++; /* leave room for facil param len (in OCTETS + 1) */
59936381Ssklower 		ptr ++; /* leave room for the facil param len (in nibbles),
60049937Ssklower 				 * high two bits of which indicate full/partial NSAP
60149937Ssklower 				 */
60245899Ssklower 		len = isop->isop_faddr->siso_nlen;
60345899Ssklower 		bcopy(isop->isop_faddr->siso_data, ptr, len);
60449584Ssklower 		*(ptr-2) = len+1; /* facil param len = addr len + 1 for each of these
60536381Ssklower 						  * two length fields, in octets */
60636381Ssklower 		*(ptr-1) = len<<1; /* facil param len in nibbles */
60736381Ssklower 		ptr += len;
60836381Ssklower 
60936381Ssklower 	}
61036381Ssklower 	*facil_len = ptr - facil_len - 1;
61145899Ssklower 	if (*facil_len > MAX_FACILITIES)
61236381Ssklower 		return E_CO_PNA_LONG;
61336381Ssklower 
61436381Ssklower 	buflen = (int)(ptr - buf);
61536381Ssklower 
61636381Ssklower 	IFDEBUG(D_CDUMP_REQ)
61736381Ssklower 		register int i;
61836381Ssklower 
61936381Ssklower 		printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n",
62036381Ssklower 			buf, buflen, buflen);
62136381Ssklower 		for( i=0; i < buflen; ) {
62236381Ssklower 			printf("+%d: %x %x %x %x    %x %x %x %x\n",
62336381Ssklower 				i,
62436381Ssklower 				*(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3),
62536381Ssklower 				*(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7));
62636381Ssklower 			i+=8;
62736381Ssklower 		}
62836381Ssklower 	ENDDEBUG
62936381Ssklower 	IFDEBUG(D_CADDR)
63036381Ssklower 		printf("make_partial returns buf 0x%x size 0x%x bytes\n",
63136381Ssklower 			mtod(m, caddr_t), buflen);
63236381Ssklower 	ENDDEBUG
63336381Ssklower 
63445899Ssklower 	if (buflen > MHLEN)
63536381Ssklower 		return E_CO_PNA_LONG;
63636381Ssklower 
63749937Ssklower 	m->m_pkthdr.len = m->m_len = buflen;
63845899Ssklower 	lcp->lcd_facilities = m;
63936381Ssklower 	return  0;
64036381Ssklower }
64136381Ssklower 
64236381Ssklower /*
64336381Ssklower  * NAME:	NSAPtoDTE()
64436381Ssklower  * CALLED FROM:
64536381Ssklower  *  make_partial_x25_packet()
64636381Ssklower  * FUNCTION and ARGUMENTS:
64736381Ssklower  *  get a DTE address from an NSAP-address (struct sockaddr_iso)
64836381Ssklower  *  (dst_octet) is the octet into which to begin stashing the DTE addr
64936381Ssklower  *  (dst_nibble) takes 0 or 1.  1 means begin filling in the DTE addr
65036381Ssklower  * 		in the high-order nibble of dst_octet.  0 means low-order nibble.
65136381Ssklower  *  (addr) is the NSAP-address
65236381Ssklower  *  (flag) is true if the transport suffix is to become the
65336381Ssklower  *		last two digits of the DTE address
65445899Ssklower  *  A DTE address is a series of ASCII digits
65536381Ssklower  *
65636381Ssklower  *	A DTE address may have leading zeros. The are significant.
65736381Ssklower  *		1 digit per nibble, may be an odd number of nibbles.
65836381Ssklower  *
65936381Ssklower  *  An NSAP-address has the DTE address in the IDI. Leading zeros are
66036381Ssklower  *		significant. Trailing hex f indicates the end of the DTE address.
66145899Ssklower  *  	The IDI is a series of BCD digits, one per nibble.
66236381Ssklower  *
66336381Ssklower  * RETURNS
66436381Ssklower  *  # significant digits in the DTE address, -1 if error.
66536381Ssklower  */
66636381Ssklower 
66736381Ssklower Static int
66845899Ssklower NSAPtoDTE(siso, sx25)
66945899Ssklower 	register struct sockaddr_iso *siso;
67045899Ssklower 	register struct sockaddr_x25 *sx25;
67136381Ssklower {
67245899Ssklower 	int		dtelen = -1;
67336381Ssklower 
67436381Ssklower 	IFDEBUG(D_CADDR)
67545899Ssklower 		printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&siso->siso_addr));
67636381Ssklower 	ENDDEBUG
67736381Ssklower 
67845899Ssklower 	if (siso->siso_data[0] == AFI_37) {
67945899Ssklower 		register char *out = sx25->x25_addr;
68045899Ssklower 		register char *in = siso->siso_data + 1;
68145899Ssklower 		register int nibble;
68249041Ssklower 		char *lim = siso->siso_data + siso->siso_nlen;
68349041Ssklower 		char *olim = out+15;
68445899Ssklower 		int lowNibble = 0;
68545899Ssklower 
68645899Ssklower 		while (in < lim) {
68745899Ssklower 			nibble = ((lowNibble ? *in++ : (*in >> 4)) & 0xf) | 0x30;
68845899Ssklower 			lowNibble ^= 1;
68949041Ssklower 			if (nibble != 0x3f && out < olim)
69045899Ssklower 				*out++ = nibble;
69145899Ssklower 		}
69245899Ssklower 		dtelen = out - sx25->x25_addr;
69345899Ssklower 		*out++ = 0;
69445899Ssklower 	} else {
69545899Ssklower 		/* error = iso_8208snparesolve(addr, x121string, &x121strlen);*/
696*50648Ssklower 		register struct rtentry *rt;
697*50648Ssklower 		extern struct sockaddr_iso blank_siso;
698*50648Ssklower 		struct sockaddr_iso nsiso;
69945899Ssklower 
700*50648Ssklower 		nsiso = blank_siso;
701*50648Ssklower 		bcopy(nsiso.siso_data, siso->siso_data,
702*50648Ssklower 				nsiso.siso_nlen = siso->siso_nlen);
703*50648Ssklower 		if (rt = rtalloc1(&nsiso, 1)) {
70445899Ssklower 			register struct sockaddr_x25 *sxx =
70545899Ssklower 							(struct sockaddr_x25 *)rt->rt_gateway;
70645899Ssklower 			register char *in = sxx->x25_addr;
70745899Ssklower 
70845899Ssklower 			rt->rt_use--;
70945899Ssklower 			if (sxx && sxx->x25_family == AF_CCITT) {
71045899Ssklower 				bcopy(sx25->x25_addr, sxx->x25_addr, sizeof(sx25->x25_addr));
71145899Ssklower 				while (*in++) {}
71245899Ssklower 				dtelen = in - sxx->x25_addr;
71345899Ssklower 			}
71445899Ssklower 		}
71536381Ssklower 	}
71645899Ssklower 	return dtelen;
71736381Ssklower }
71836381Ssklower 
71936381Ssklower /*
72036381Ssklower  * NAME:	FACILtoNSAP()
72136381Ssklower  * CALLED FROM:
72236381Ssklower  *  parse_facil()
72336381Ssklower  * FUNCTION and ARGUMENTS:
72436381Ssklower  * 	Creates and NSAP in the sockaddr_iso (addr) from the
72545899Ssklower  *  x.25 facility found at buf - 1.
72636381Ssklower  * RETURNS:
727*50648Ssklower  *  0 if ok, -1 if error.
72836381Ssklower  */
72936381Ssklower 
73036381Ssklower Static int
73145899Ssklower FACILtoNSAP(addr, buf)
732*50648Ssklower 	register u_char 		*buf;
73336381Ssklower 	register struct sockaddr_iso *addr;
73436381Ssklower {
735*50648Ssklower 	int			len_in_nibbles = *++buf & 0x3f;
736*50648Ssklower 	u_char		buf_len = (len_in_nibbles + 1) >> 1;; /* in bytes */
73736381Ssklower 
73836381Ssklower 	IFDEBUG(D_CADDR)
73936381Ssklower 		printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n",
74036381Ssklower 			buf, buf_len, addr );
74136381Ssklower 	ENDDEBUG
74236381Ssklower 
74345899Ssklower 	len_in_nibbles = *buf & 0x3f;
74436381Ssklower 	/* despite the fact that X.25 makes us put a length in nibbles
74536381Ssklower 	 * here, the NSAP-addrs are always in full octets
74636381Ssklower 	 */
74745899Ssklower 	switch (*buf++ & 0xc0) {
74845899Ssklower 	case 0:
74945899Ssklower 		/* Entire OSI NSAP address */
75045899Ssklower 		bcopy((caddr_t)buf, addr->siso_data, addr->siso_nlen = buf_len);
75145899Ssklower 		break;
75236381Ssklower 
75345899Ssklower 	case 40:
75445899Ssklower 		/* Partial OSI NSAP address, assume trailing */
75545899Ssklower 		if (buf_len + addr->siso_nlen > sizeof(addr->siso_addr))
75645899Ssklower 			return -1;
75745899Ssklower 		bcopy((caddr_t)buf, TSEL(addr), buf_len);
75845899Ssklower 		addr->siso_nlen += buf_len;
75945899Ssklower 		break;
76036381Ssklower 
76145899Ssklower 	default:
76245899Ssklower 		/* Rather than blow away the connection, just ignore and use
76345899Ssklower 		   NSAP from DTE */;
76436381Ssklower 	}
765*50648Ssklower 	return 0;
76645899Ssklower }
76736381Ssklower 
768*50648Ssklower Static
76945899Ssklower init_siso(siso)
77045899Ssklower register struct sockaddr_iso *siso;
77145899Ssklower {
77245899Ssklower 	siso->siso_len = sizeof (*siso);
77345899Ssklower 	siso->siso_family = AF_ISO;
77445899Ssklower 	siso->siso_data[0] = AFI_37;
77545899Ssklower 	siso->siso_nlen = 8;
77636381Ssklower }
77736381Ssklower 
77836381Ssklower /*
77936381Ssklower  * NAME:	DTEtoNSAP()
78036381Ssklower  * CALLED FROM:
78136381Ssklower  *  parse_facil()
78236381Ssklower  * FUNCTION and ARGUMENTS:
78336381Ssklower  *  Creates a type 37 NSAP in the sockaddr_iso (addr)
78445899Ssklower  * 	from a DTE address found in a sockaddr_x25.
78536381Ssklower  *
78636381Ssklower  * RETURNS:
78736381Ssklower  *  0 if ok; E* otherwise.
78836381Ssklower  */
78936381Ssklower 
79036381Ssklower Static  int
79145899Ssklower DTEtoNSAP(addr, sx)
79236381Ssklower 	struct sockaddr_iso *addr;
79345899Ssklower 	struct sockaddr_x25 *sx;
79436381Ssklower {
79545899Ssklower 	register char		*in, *out;
79645899Ssklower 	register int		first;
79745899Ssklower 	int					pad_tail = 0;
79845899Ssklower 	int 				src_len;
79936381Ssklower 
80036381Ssklower 
80145899Ssklower 	init_siso(addr);
80245899Ssklower 	in = sx->x25_addr;
803*50648Ssklower 	src_len = strlen(in);
804*50648Ssklower 	addr->siso_nlen = (src_len + 3) / 2;
805*50648Ssklower 	out = addr->siso_data;
806*50648Ssklower 	*out++ = 0x37;
807*50648Ssklower 	if (src_len & 1) {
80845899Ssklower 		pad_tail = 0xf;
80945899Ssklower 		src_len++;
81045899Ssklower 	}
811*50648Ssklower 	for (first = 0; src_len > 0; src_len--) {
812*50648Ssklower 		first |= 0xf & *in++;
81345899Ssklower 		if (src_len & 1) {
81445899Ssklower 			*out++ = first;
81545899Ssklower 			first = 0;
81645899Ssklower 		}
81745899Ssklower 		else first <<= 4;
81845899Ssklower 	}
81945899Ssklower 	if (pad_tail)
82045899Ssklower 		out[-1] |= 0xf;
82136381Ssklower 	return 0; /* ok */
82236381Ssklower }
82336381Ssklower 
82436381Ssklower /*
82536381Ssklower  * FUNCTION and ARGUMENTS:
82636381Ssklower  *	parses (buf_len) bytes beginning at (buf) and finds
82736381Ssklower  *  a called nsap, a calling nsap, and protocol identifier.
82836381Ssklower  * RETURNS:
82936381Ssklower  *  0 if ok, E* otherwise.
83036381Ssklower  */
83136381Ssklower 
832*50648Ssklower Static int
83345899Ssklower parse_facil(lcp, isop, buf, buf_len)
83436381Ssklower 	caddr_t 		buf;
83536381Ssklower 	u_char			buf_len; /* in bytes */
83645899Ssklower 	struct			isopcb *isop;
83745899Ssklower 	struct			pklcd *lcp;
83836381Ssklower {
83936381Ssklower 	register int 	i;
84045899Ssklower 	register u_char 	*ptr = (u_char *)buf;
84145899Ssklower 	u_char			*ptr_lim, *facil_lim;
84245899Ssklower 	int 			facil_param_len, facil_len;
84336381Ssklower 
84436381Ssklower 	IFDEBUG(D_CADDR)
84545899Ssklower 		printf("parse_facil(0x%x, 0x%x, 0x%x, 0x%x)\n",
846*50648Ssklower 			lcp, isop, buf, buf_len);
84736381Ssklower 		dump_buf(buf, buf_len);
84836381Ssklower 	ENDDEBUG
84936381Ssklower 
85036381Ssklower 	/* find the beginnings of the facility fields in buf
85136381Ssklower 	 * by skipping over the called & calling DTE addresses
85236381Ssklower 	 * i <- # nibbles in called + # nibbles in calling
85336381Ssklower 	 * i += 1 so that an odd nibble gets rounded up to even
85436381Ssklower 	 * before dividing by 2, then divide by two to get # octets
85536381Ssklower 	 */
85645899Ssklower 	i = (int)(*ptr >> 4) + (int)(*ptr&0xf);
85736381Ssklower 	i++;
85845899Ssklower 	ptr += i >> 1;
85936381Ssklower 	ptr ++; /* plus one for the DTE lengths byte */
86036381Ssklower 
86136381Ssklower 	/* ptr now is at facil_length field */
86245899Ssklower 	facil_len = *ptr++;
86345899Ssklower 	facil_lim = ptr + facil_len;
86436381Ssklower 	IFDEBUG(D_CADDR)
86545899Ssklower 		printf("parse_facils: facil length is  0x%x\n", (int) facil_len);
86636381Ssklower 	ENDDEBUG
86736381Ssklower 
868*50648Ssklower 	while (ptr < facil_lim) {
86936381Ssklower 		/* get NSAP addresses from facilities */
87045899Ssklower 		switch (*ptr++) {
87136381Ssklower 			case 0xcb:
87245899Ssklower 				/* calling NSAP */
87345899Ssklower 				facil_param_len = FACILtoNSAP(isop->isop_faddr, ptr);
87436381Ssklower 				break;
87536381Ssklower 			case 0xc9:
87645899Ssklower 				/* called NSAP */
87745899Ssklower 				facil_param_len = FACILtoNSAP(isop->isop_laddr, ptr);
87836381Ssklower 				break;
87936381Ssklower 
88036381Ssklower 				/* from here to default are legit cases that I ignore */
88136381Ssklower 				/* variable length */
88236381Ssklower 			case 0xca:  /* end-to-end transit delay negot */
88336381Ssklower 			case 0xc6:  /* network user id */
88436381Ssklower 			case 0xc5: 	/* charging info : indicating monetary unit */
88536381Ssklower 			case 0xc2: 	/* charging info : indicating segment count */
88636381Ssklower 			case 0xc1: 	/* charging info : indicating call duration */
88736381Ssklower 			case 0xc4: 	/* RPOA extended format */
88836381Ssklower 			case 0xc3: 	/* call redirection notification */
88936381Ssklower 				facil_param_len = 0;
89036381Ssklower 				break;
89136381Ssklower 
89236381Ssklower 				/* 1 octet */
89336381Ssklower 			case 0x0a:  /* min. throughput class negot */
89436381Ssklower 			case 0x02:  /* throughput class */
89536381Ssklower 			case 0x03:  case 0x47:  /* CUG shit */
89636381Ssklower 			case 0x0b:  /* expedited data negot */
89736381Ssklower 			case 0x01:  /* Fast select or reverse charging
89836381Ssklower 						(example of intelligent protocol design) */
89936381Ssklower 			case 0x04: 	/* charging info : requesting service */
90036381Ssklower 			case 0x08: 	/* called line addr modified notification */
901*50648Ssklower 			case 0x00:  /* marker to indicate beginning of CCITT facils */
90236381Ssklower 				facil_param_len = 1;
90336381Ssklower 				break;
90436381Ssklower 
90536381Ssklower 				/* any 2 octets */
90636381Ssklower 			case 0x42:  /* pkt size */
90736381Ssklower 			case 0x43:  /* win size */
90836381Ssklower 			case 0x44:  /* RPOA basic format */
90936381Ssklower 			case 0x41:  /* bilateral CUG shit */
91036381Ssklower 			case 0x49: 	/* transit delay selection and indication */
91136381Ssklower 				facil_param_len = 2;
91236381Ssklower 				break;
91336381Ssklower 
91436381Ssklower 			default:
91536381Ssklower 				printf(
916*50648Ssklower "BOGUS FACILITY CODE facil_lim 0x%x facil_len %d, ptr 0x%x *ptr 0x%x\n",
917*50648Ssklower 					facil_lim, facil_len, ptr - 1, ptr[-1]);
918*50648Ssklower 				/* facil that we don't handle
919*50648Ssklower 				return E_CO_HLI_REJI; */
920*50648Ssklower 				switch (ptr[-1] & 0xc0) {
921*50648Ssklower 				case 0x00:	facil_param_len = 1; break;
922*50648Ssklower 				case 0x40:	facil_param_len = 2; break;
923*50648Ssklower 				case 0x80:	facil_param_len = 3; break;
924*50648Ssklower 				case 0xc0:	facil_param_len = 0; break;
925*50648Ssklower 				}
92636381Ssklower 		}
92745899Ssklower 		if (facil_param_len == -1)
92845899Ssklower 			return E_CO_REG_ICDA;
92945899Ssklower 		if (facil_param_len == 0) /* variable length */
930*50648Ssklower 			facil_param_len = (int)*ptr++; /* 1 + the real facil param */
93136381Ssklower 		ptr += facil_param_len;
93236381Ssklower 	}
93336381Ssklower 	return 0;
93436381Ssklower }
93536381Ssklower 
93645899Ssklower #endif TPCONS
937