xref: /csrg-svn/sys/netiso/if_cons.c (revision 49937)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*49937Ssklower  *	@(#)if_cons.c	7.10 (Berkeley) 05/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 Static  struct socket	dummysocket; /* for use by cosns */
15136381Ssklower 
15236381Ssklower extern struct	isopcb	tp_isopcb; /* chain of all TP pcbs */
15336381Ssklower struct	isopcb			tp_incoming_pending;  /* incoming connections
15436381Ssklower 										for TP, pending */
15536381Ssklower 
15636381Ssklower struct isopcb 	*Xpcblist[] =  {
15736381Ssklower 	&tp_incoming_pending,
15836381Ssklower 	&tp_isopcb,
15936381Ssklower 	(struct isopcb *)0
16036381Ssklower };
16136381Ssklower 
16236381Ssklower Static 	int parse_facil(), NSAPtoDTE(), make_partial_x25_packet();
16336381Ssklower Static	int FACILtoNSAP(), DTEtoNSAP();
16445899Ssklower Static	struct pklcd *cons_chan_to_pcb();
16536381Ssklower 
16636381Ssklower #define HIGH_NIBBLE 1
16736381Ssklower #define LOW_NIBBLE 0
16836381Ssklower 
16936381Ssklower /*
17036381Ssklower  * NAME:	nibble_copy()
17136381Ssklower  * FUNCTION and ARGUMENTS:
17236381Ssklower  * 	copies (len) nibbles from (src_octet), high or low nibble
17336381Ssklower  *  to (dst_octet), high or low nibble,
17436381Ssklower  * src_nibble & dst_nibble should be:
17536381Ssklower  * 	HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble
17636381Ssklower  * 	LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble
17736381Ssklower  * RETURNS: VOID
17836381Ssklower  */
17936381Ssklower void
18045899Ssklower nibble_copy(src_octet, src_nibble, dst_octet, dst_nibble, len)
18136381Ssklower 	register char  	*src_octet;
18236381Ssklower 	register char  	*dst_octet;
18336381Ssklower 	register unsigned		src_nibble;
18436381Ssklower 	register unsigned 		dst_nibble;
18536381Ssklower 	int		len;
18636381Ssklower {
18736381Ssklower 
18836381Ssklower 	register 	i;
18936381Ssklower 	register 	unsigned dshift, sshift;
19036381Ssklower 
19136381Ssklower 	IFDEBUG(D_CADDR)
19236381Ssklower 		printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n",
19336381Ssklower 		 src_octet, src_nibble, dst_octet, dst_nibble, len);
19436381Ssklower 	ENDDEBUG
19536381Ssklower #define SHIFT 0x4
19636381Ssklower 
19736381Ssklower 	dshift = dst_nibble << 2;
19836381Ssklower 	sshift = src_nibble << 2;
19936381Ssklower 
20036381Ssklower 	for (i=0; i<len; i++) {
20136381Ssklower 		/* clear dst_nibble  */
20236381Ssklower 		*dst_octet 	&= ~(0xf<< dshift);
20336381Ssklower 
20436381Ssklower 		/* set dst nibble */
20536381Ssklower 		*dst_octet 	|= ( 0xf & (*src_octet >> sshift))<< dshift;
20636381Ssklower 
20736381Ssklower 		dshift		^= SHIFT;
20836381Ssklower 		sshift		^= SHIFT;
20936381Ssklower 		src_nibble 	= 1-src_nibble;
21036381Ssklower 		dst_nibble 	= 1-dst_nibble;
21136381Ssklower 		src_octet	+= src_nibble;
21236381Ssklower 		dst_octet 	+= dst_nibble;
21336381Ssklower 	}
21436381Ssklower 	IFDEBUG(D_CADDR)
21536381Ssklower 		printf("nibble_copy DONE\n");
21636381Ssklower 	ENDDEBUG
21736381Ssklower }
21836381Ssklower 
21936381Ssklower /*
22036381Ssklower  * NAME:	nibble_match()
22136381Ssklower  * FUNCTION and ARGUMENTS:
22236381Ssklower  * 	compares src_octet/src_nibble and dst_octet/dst_nibble  for len nibbles.
22336381Ssklower  * RETURNS: 0 if they differ, 1 if they are the same.
22436381Ssklower  */
22536381Ssklower int
22636381Ssklower nibble_match( src_octet, src_nibble, dst_octet, dst_nibble, len)
22736381Ssklower 	register char  	*src_octet;
22836381Ssklower 	register char  	*dst_octet;
22936381Ssklower 	register unsigned		src_nibble;
23036381Ssklower 	register unsigned 		dst_nibble;
23136381Ssklower 	int		len;
23236381Ssklower {
23336381Ssklower 
23436381Ssklower 	register 	i;
23536381Ssklower 	register 	unsigned dshift, sshift;
23636381Ssklower 	u_char		nibble_a, nibble_b;
23736381Ssklower 
23836381Ssklower 	IFDEBUG(D_CADDR)
23936381Ssklower 		printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n",
24036381Ssklower 		 src_octet, src_nibble, dst_octet, dst_nibble, len);
24136381Ssklower 	ENDDEBUG
24236381Ssklower #define SHIFT 0x4
24336381Ssklower 
24436381Ssklower 	dshift = dst_nibble << 2;
24536381Ssklower 	sshift = src_nibble << 2;
24636381Ssklower 
24736381Ssklower 	for (i=0; i<len; i++) {
24836381Ssklower 		nibble_b = ((*dst_octet)>>dshift) & 0xf;
24936381Ssklower 		nibble_a = ( 0xf & (*src_octet >> sshift));
25045899Ssklower 		if (nibble_b != nibble_a)
25136381Ssklower 			return 0;
25236381Ssklower 
25336381Ssklower 		dshift		^= SHIFT;
25436381Ssklower 		sshift		^= SHIFT;
25536381Ssklower 		src_nibble 	= 1-src_nibble;
25636381Ssklower 		dst_nibble 	= 1-dst_nibble;
25736381Ssklower 		src_octet	+= src_nibble;
25836381Ssklower 		dst_octet 	+= dst_nibble;
25936381Ssklower 	}
26036381Ssklower 	IFDEBUG(D_CADDR)
26136381Ssklower 		printf("nibble_match DONE\n");
26236381Ssklower 	ENDDEBUG
26336381Ssklower 	return 1;
26436381Ssklower }
26536381Ssklower 
26636381Ssklower /*
26736381Ssklower  **************************** NET PROTOCOL cons ***************************
26836381Ssklower  */
26936381Ssklower /*
27036381Ssklower  * NAME:	cons_init()
27136381Ssklower  * CALLED FROM:
27236381Ssklower  *	autoconf
27336381Ssklower  * FUNCTION:
27436381Ssklower  *	initialize the protocol
27536381Ssklower  */
27636381Ssklower cons_init()
27736381Ssklower {
27845899Ssklower 	int tp_incoming(), clnp_incoming();
27936381Ssklower 
28036381Ssklower 
28136381Ssklower 	CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM);
28236381Ssklower 	X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM);
28336381Ssklower 	TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET);
28436381Ssklower 	IFDEBUG(D_CCONS)
28536381Ssklower 		printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n",
28636381Ssklower 			CLNP_proto, X25_proto, TP_proto);
28736381Ssklower 	ENDDEBUG
28845899Ssklower #ifdef notdef
28945899Ssklower 	pk_protolisten(0x81, 0, clnp_incoming);
29045899Ssklower 	pk_protolisten(0x82, 0, esis_incoming);
29145899Ssklower 	pk_protolisten(0x84, 0, tp8878_A_incoming);
29249041Ssklower 	pk_protolisten(0, 0, tp_incoming);
29345899Ssklower #endif
29436381Ssklower }
29536381Ssklower 
296*49937Ssklower tp_incoming(lcp, m)
29745899Ssklower struct pklcd *lcp;
298*49937Ssklower register struct mbuf *m;
29936381Ssklower {
30045899Ssklower 	register struct isopcb *isop;
30145899Ssklower 	extern struct isopcb tp_isopcb;
30245899Ssklower 	int cons_tpinput();
30336381Ssklower 
30445899Ssklower 	if (iso_pcballoc((struct socket *)0, &tp_incoming_pending)) {
305*49937Ssklower 		pk_close(lcp);
30645899Ssklower 		return;
30736381Ssklower 	}
30845899Ssklower 	isop = tp_incoming_pending.isop_next;
30945899Ssklower 	lcp->lcd_upper = cons_tpinput;
31045899Ssklower 	lcp->lcd_upnext = (caddr_t)isop;
311*49937Ssklower 	lcp->lcd_send(lcp); /* Confirms call */
31245899Ssklower 	isop->isop_chan = (caddr_t)lcp;
31345899Ssklower 	isop->isop_laddr = &isop->isop_sladdr;
31445899Ssklower 	isop->isop_faddr = &isop->isop_sfaddr;
31545899Ssklower 	DTEtoNSAP(isop->isop_laddr, &lcp->lcd_laddr);
31645899Ssklower 	DTEtoNSAP(isop->isop_faddr, &lcp->lcd_faddr);
31745899Ssklower 	parse_facil(isop, lcp, &(mtod(m, struct x25_packet *)->packet_data),
31845899Ssklower 		m->m_pkthdr.len - PKHEADERLN);
31936381Ssklower }
32036381Ssklower 
32145899Ssklower cons_tpinput(lcp, m0)
32245899Ssklower struct mbuf *m0;
32345899Ssklower struct pklcd *lcp;
32436381Ssklower {
32545899Ssklower 	register struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext;
32645899Ssklower 	register struct x25_packet *xp;
32745899Ssklower 	int cmd;
32836381Ssklower 
32949265Ssklower 	if (isop == 0)
33049265Ssklower 		return;
33149265Ssklower 	if (m0 == 0) {
33249265Ssklower 		isop->isop_chan = 0;
33349265Ssklower 		isop->isop_refcnt = 0;
33449265Ssklower 		lcp->lcd_upnext = 0;
33549265Ssklower 		lcp->lcd_upper = 0;
33649041Ssklower 		goto dead;
33749265Ssklower 	}
33845899Ssklower 	switch(m0->m_type) {
33945899Ssklower 	case MT_DATA:
34045899Ssklower 	case MT_OOBDATA:
34145899Ssklower 		tpcons_input(m0, isop->isop_faddr, isop->isop_laddr,
34245899Ssklower 			(struct socket *)0, (caddr_t)lcp);
34349584Ssklower 		return;
34436381Ssklower 
34545899Ssklower 	case MT_CONTROL:
34645899Ssklower 		switch (pk_decode(mtod(m0, struct x25_packet *))) {
34736381Ssklower 
34845899Ssklower 		case RR:
34945899Ssklower 			cmd = PRC_CONS_SEND_DONE;
35045899Ssklower 			break;
35136381Ssklower 
35249265Ssklower 		case CALL_ACCEPTED:
35349265Ssklower 			if (lcp->lcd_sb.sb_mb)
35449265Ssklower 				lcp->lcd_send(lcp); /* XXX - fix this */
35549584Ssklower 			/*FALLTHROUGH*/
35649584Ssklower 		default:
35749584Ssklower 			return;
35849265Ssklower 
35949041Ssklower 		dead:
36045899Ssklower 		case RESET:
36149041Ssklower 		case CLEAR:
36249041Ssklower 		case CLEAR_CONF:
36345899Ssklower 			cmd = PRC_ROUTEDEAD;
36436381Ssklower 		}
36545899Ssklower 		tpcons_ctlinput(cmd, isop->isop_faddr, isop);
36636381Ssklower 	}
36736381Ssklower }
36836381Ssklower 
36936381Ssklower /*
37036381Ssklower  * NAME:	cons_connect()
37136381Ssklower  * CALLED FROM:
37245899Ssklower  *	tpcons_pcbconnect() when opening a new connection.
37336381Ssklower  * FUNCTION anD ARGUMENTS:
37436381Ssklower  *  Figures out which device to use, finding a route if one doesn't
37536381Ssklower  *  already exist.
37636381Ssklower  * RETURN VALUE:
37736381Ssklower  *  returns E*
37836381Ssklower  */
37945899Ssklower cons_connect(isop)
38045899Ssklower 	register struct isopcb *isop;
38136381Ssklower {
38245899Ssklower 	register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
38336381Ssklower 	register struct mbuf 	*m;
38436381Ssklower 	struct ifaddr 			*ifa;
385*49937Ssklower 	int error;
38636381Ssklower 
38736381Ssklower 	IFDEBUG(D_CCONN)
38845899Ssklower 		printf("cons_connect(0x%x): ", isop);
38945899Ssklower 		dump_isoaddr(isop->isop_faddr);
39045899Ssklower 		printf("myaddr: ");
39145899Ssklower 		dump_isoaddr(isop->isop_laddr);
39236381Ssklower 		printf("\n" );
39336381Ssklower 	ENDDEBUG
39445899Ssklower 	NSAPtoDTE(isop->isop_faddr, &lcp->lcd_faddr);
39549265Ssklower 	lcp->lcd_upper = cons_tpinput;
39649265Ssklower 	lcp->lcd_upnext = (caddr_t)isop;
39736381Ssklower 	IFDEBUG(D_CCONN)
39836381Ssklower 		printf(
39945899Ssklower 		"calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x)\n",
40045899Ssklower 			&lcp->lcd_faddr, &lcp->lcd_laddr,
40145899Ssklower 			isop->isop_socket->so_proto->pr_protocol);
40236381Ssklower 	ENDDEBUG
403*49937Ssklower 	if ((error = make_partial_x25_packet(isop, lcp, m)) == 0)
404*49937Ssklower 		error = pk_connect(lcp, &lcp->lcd_faddr);
405*49937Ssklower 	return error;
40636381Ssklower }
40736381Ssklower 
40836381Ssklower /*
40936381Ssklower  **************************** DEVICE cons ***************************
41036381Ssklower  */
41136381Ssklower 
41236381Ssklower 
41336381Ssklower /*
41436381Ssklower  * NAME:	cons_ctlinput()
41536381Ssklower  * CALLED FROM:
41636381Ssklower  *  lower layer when ECN_CLEAR occurs : this routine is here
41736381Ssklower  *  for consistency - cons subnet service calls its higher layer
41836381Ssklower  *  through the protosw entry.
41936381Ssklower  * FUNCTION & ARGUMENTS:
42037536Smckusick  *  cmd is a PRC_* command, list found in ../sys/protosw.h
42136381Ssklower  *  copcb is the obvious.
42236381Ssklower  *  This serves the higher-layer cons service.
42336381Ssklower  * NOTE: this takes 3rd arg. because cons uses it to inform itself
42436381Ssklower  *  of things (timeouts, etc) but has a pcb instead of an address.
42536381Ssklower  */
42636381Ssklower cons_ctlinput(cmd, sa, copcb)
42736381Ssklower 	int cmd;
42836381Ssklower 	struct sockaddr *sa;
42945899Ssklower 	register struct pklcd *copcb;
43036381Ssklower {
43136381Ssklower }
43236381Ssklower 
43336381Ssklower 
43445899Ssklower find_error_reason( xp )
43545899Ssklower 	register struct x25_packet *xp;
43636381Ssklower {
43736381Ssklower 	extern u_char x25_error_stats[];
43845899Ssklower 	int error, cause;
43936381Ssklower 
44045899Ssklower 	if (xp) {
44145899Ssklower 		cause = 4[(char *)xp];
44245899Ssklower 		switch (cause) {
44336381Ssklower 			case 0x00:
44436381Ssklower 			case 0x80:
44536381Ssklower 				/* DTE originated; look at the diagnostic */
44645899Ssklower 				error = (CONL_ERROR_MASK | cause);
44736381Ssklower 				goto done;
44836381Ssklower 
44936381Ssklower 			case 0x01: /* number busy */
45036381Ssklower 			case 0x81:
45136381Ssklower 			case 0x09: /* Out of order */
45236381Ssklower 			case 0x89:
45336381Ssklower 			case 0x11: /* Remot Procedure Error */
45436381Ssklower 			case 0x91:
45536381Ssklower 			case 0x19: /* reverse charging accept not subscribed */
45636381Ssklower 			case 0x99:
45736381Ssklower 			case 0x21: /* Incampat destination */
45836381Ssklower 			case 0xa1:
45936381Ssklower 			case 0x29: /* fast select accept not subscribed */
46036381Ssklower 			case 0xa9:
46136381Ssklower 			case 0x39: /* ship absent */
46236381Ssklower 			case 0xb9:
46336381Ssklower 			case 0x03: /* invalid facil request */
46436381Ssklower 			case 0x83:
46536381Ssklower 			case 0x0b: /* access barred */
46636381Ssklower 			case 0x8b:
46736381Ssklower 			case 0x13: /* local procedure error */
46836381Ssklower 			case 0x93:
46936381Ssklower 			case 0x05: /* network congestion */
47036381Ssklower 			case 0x85:
47136381Ssklower 			case 0x8d: /* not obtainable */
47236381Ssklower 			case 0x0d:
47336381Ssklower 			case 0x95: /* RPOA out of order */
47436381Ssklower 			case 0x15:
47536381Ssklower 				/* take out bit 8
47636381Ssklower 				 * so we don't have to have so many perror entries
47736381Ssklower 				 */
47845899Ssklower 				error = (CONL_ERROR_MASK | 0x100 | (cause & ~0x80));
47936381Ssklower 				goto done;
48036381Ssklower 
48136381Ssklower 			case 0xc1: /* gateway-detected proc error */
48236381Ssklower 			case 0xc3: /* gateway congestion */
48336381Ssklower 
48445899Ssklower 				error = (CONL_ERROR_MASK | 0x100 | cause);
48536381Ssklower 				goto done;
48636381Ssklower 		}
48736381Ssklower 	}
48836381Ssklower 	/* otherwise, a *hopefully* valid perror exists in the e_reason field */
48945899Ssklower 	error = xp->packet_data;
49036381Ssklower 	if (error = 0) {
49136381Ssklower 		printf("Incoming PKT TYPE 0x%x with reason 0x%x\n",
49245899Ssklower 			pk_decode(xp),
49345899Ssklower 			cause);
49436381Ssklower 		error = E_CO_HLI_DISCA;
49536381Ssklower 	}
49636381Ssklower 
49736381Ssklower done:
49836381Ssklower 	return error;
49936381Ssklower }
50036381Ssklower 
50136381Ssklower 
50236381Ssklower 
50336381Ssklower #endif KERNEL
50436381Ssklower 
50536381Ssklower /*
50636381Ssklower  * NAME:	make_partial_x25_packet()
50736381Ssklower  *
50836381Ssklower  * FUNCTION and ARGUMENTS:
50945899Ssklower  *	Makes part of an X.25 call packet, for use by x25.
51036381Ssklower  *  (src) and (dst) are the NSAP-addresses of source and destination.
51136381Ssklower  *	(buf) is a ptr to a buffer into which to write this partial header.
51236381Ssklower  *
51345899Ssklower  *	 0			Facility length (in octets)
51445899Ssklower  *	 1			Facility field, which is a set of:
51536381Ssklower  *	  m			facil code
51636381Ssklower  *	  m+1		facil param len (for >2-byte facilities) in octets
51736381Ssklower  *	  m+2..p	facil param field
51836381Ssklower  *  q			user data (protocol identification octet)
51936381Ssklower  *
52036381Ssklower  *
52136381Ssklower  * RETURNS:
52236381Ssklower  *  0 if OK
52336381Ssklower  *  E* if failed.
52445899Ssklower  *
52545899Ssklower  * SIDE EFFECTS:
52645899Ssklower  * Stores facilites mbuf in X.25 control block, where the connect
52745899Ssklower  * routine knows where to look for it.
52836381Ssklower  */
52936381Ssklower 
53036381Ssklower #ifdef X25_1984
53136381Ssklower int cons_use_facils = 1;
53236381Ssklower #else X25_1984
53336381Ssklower int cons_use_facils = 0;
53436381Ssklower #endif X25_1984
53536381Ssklower 
53636381Ssklower int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */
53736381Ssklower 
53836381Ssklower Static int
53945899Ssklower make_partial_x25_packet(isop, lcp)
54045899Ssklower 	struct isopcb *isop;
54145899Ssklower 	struct pklcd *lcp;
54236381Ssklower {
54336381Ssklower 	u_int				proto;
54436381Ssklower 	int					flag;
54545899Ssklower 	caddr_t 			buf;
54649041Ssklower 	register caddr_t	ptr;
54736381Ssklower 	register int		len	= 0;
54836381Ssklower 	int 				buflen	=0;
54936381Ssklower 	caddr_t				facil_len;
55036381Ssklower 	int 				oddness	= 0;
55145899Ssklower 	struct mbuf *m;
55236381Ssklower 
55336381Ssklower 
55449584Ssklower 	IFDEBUG(D_CCONN)
55549584Ssklower 		printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
55649584Ssklower 			isop->isop_laddr, isop->isop_faddr, proto, m, flag);
55749584Ssklower 	ENDDEBUG
55849584Ssklower 	if (cons_use_udata) {
55949584Ssklower 		if (isop->isop_x25crud_len > 0) {
56049584Ssklower 			/*
56149584Ssklower 			 *	The user specified something. Stick it in
56249584Ssklower 			 */
56349584Ssklower 			bcopy(isop->isop_x25crud, lcp->lcd_faddr.x25_udata,
56449584Ssklower 					isop->isop_x25crud_len);
56549584Ssklower 			lcp->lcd_faddr.x25_udlen = isop->isop_x25crud_len;
56649584Ssklower 		}
56749584Ssklower 	}
56849584Ssklower 
56949584Ssklower 	if (cons_use_facils == 0) {
57049584Ssklower 		lcp->lcd_facilities = 0;
57149584Ssklower 		return 0;
57249584Ssklower 	}
573*49937Ssklower 	MGETHDR(m, MT_DATA, M_WAITOK);
57445899Ssklower 	if (m == 0)
57545899Ssklower 		return ENOBUFS;
57645899Ssklower 	buf = mtod(m, caddr_t);
57749041Ssklower 	ptr = buf;
57836381Ssklower 
57936381Ssklower 	/* ptr now points to facil length (len of whole facil field in OCTETS */
58036381Ssklower 	facil_len = ptr ++;
581*49937Ssklower 	m->m_len = 0;
582*49937Ssklower 	pk_build_facilities(m, &lcp->lcd_faddr, 0);
58336381Ssklower 
58436381Ssklower 	IFDEBUG(D_CADDR)
58536381Ssklower 		printf("make_partial  calling: ptr 0x%x, len 0x%x\n", ptr,
58645899Ssklower 				isop->isop_laddr->siso_addr.isoa_len);
58736381Ssklower 	ENDDEBUG
58845899Ssklower 	if (cons_use_facils) {
589*49937Ssklower 		*ptr++ = 0;	 /* Marker to separate X.25 facitilies from CCITT ones */
590*49937Ssklower 		*ptr++ = 0x0f;
59136381Ssklower 		*ptr = 0xcb; /* calling facility code */
59236381Ssklower 		ptr ++;
59336381Ssklower 		ptr ++; /* leave room for facil param len (in OCTETS + 1) */
59436381Ssklower 		ptr ++; /* leave room for the facil param len (in nibbles),
595*49937Ssklower 				 * high two bits of which indicate full/partial NSAP
596*49937Ssklower 				 */
59745899Ssklower 		len = isop->isop_laddr->siso_addr.isoa_len;
59845899Ssklower 		bcopy( isop->isop_laddr->siso_data, ptr, len);
59949584Ssklower 		*(ptr-2) = len+1; /* facil param len in octets */
60036381Ssklower 		*(ptr-1) = len<<1; /* facil param len in nibbles */
60136381Ssklower 		ptr += len;
60236381Ssklower 
60336381Ssklower 		IFDEBUG(D_CADDR)
60436381Ssklower 			printf("make_partial  called: ptr 0x%x, len 0x%x\n", ptr,
60545899Ssklower 					isop->isop_faddr->siso_addr.isoa_len);
60636381Ssklower 		ENDDEBUG
60736381Ssklower 		*ptr = 0xc9; /* called facility code */
60836381Ssklower 		ptr ++;
60936381Ssklower 		ptr ++; /* leave room for facil param len (in OCTETS + 1) */
61036381Ssklower 		ptr ++; /* leave room for the facil param len (in nibbles),
611*49937Ssklower 				 * high two bits of which indicate full/partial NSAP
612*49937Ssklower 				 */
61345899Ssklower 		len = isop->isop_faddr->siso_nlen;
61445899Ssklower 		bcopy(isop->isop_faddr->siso_data, ptr, len);
61549584Ssklower 		*(ptr-2) = len+1; /* facil param len = addr len + 1 for each of these
61636381Ssklower 						  * two length fields, in octets */
61736381Ssklower 		*(ptr-1) = len<<1; /* facil param len in nibbles */
61836381Ssklower 		ptr += len;
61936381Ssklower 
62036381Ssklower 	}
62136381Ssklower 	*facil_len = ptr - facil_len - 1;
62245899Ssklower 	if (*facil_len > MAX_FACILITIES)
62336381Ssklower 		return E_CO_PNA_LONG;
62436381Ssklower 
62536381Ssklower 	buflen = (int)(ptr - buf);
62636381Ssklower 
62736381Ssklower 	IFDEBUG(D_CDUMP_REQ)
62836381Ssklower 		register int i;
62936381Ssklower 
63036381Ssklower 		printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n",
63136381Ssklower 			buf, buflen, buflen);
63236381Ssklower 		for( i=0; i < buflen; ) {
63336381Ssklower 			printf("+%d: %x %x %x %x    %x %x %x %x\n",
63436381Ssklower 				i,
63536381Ssklower 				*(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3),
63636381Ssklower 				*(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7));
63736381Ssklower 			i+=8;
63836381Ssklower 		}
63936381Ssklower 	ENDDEBUG
64036381Ssklower 	IFDEBUG(D_CADDR)
64136381Ssklower 		printf("make_partial returns buf 0x%x size 0x%x bytes\n",
64236381Ssklower 			mtod(m, caddr_t), buflen);
64336381Ssklower 	ENDDEBUG
64436381Ssklower 
64545899Ssklower 	if (buflen > MHLEN)
64636381Ssklower 		return E_CO_PNA_LONG;
64736381Ssklower 
648*49937Ssklower 	m->m_pkthdr.len = m->m_len = buflen;
64945899Ssklower 	lcp->lcd_facilities = m;
65036381Ssklower 	return  0;
65136381Ssklower }
65236381Ssklower 
65336381Ssklower /*
65436381Ssklower  * NAME:	NSAPtoDTE()
65536381Ssklower  * CALLED FROM:
65636381Ssklower  *  make_partial_x25_packet()
65736381Ssklower  * FUNCTION and ARGUMENTS:
65836381Ssklower  *  get a DTE address from an NSAP-address (struct sockaddr_iso)
65936381Ssklower  *  (dst_octet) is the octet into which to begin stashing the DTE addr
66036381Ssklower  *  (dst_nibble) takes 0 or 1.  1 means begin filling in the DTE addr
66136381Ssklower  * 		in the high-order nibble of dst_octet.  0 means low-order nibble.
66236381Ssklower  *  (addr) is the NSAP-address
66336381Ssklower  *  (flag) is true if the transport suffix is to become the
66436381Ssklower  *		last two digits of the DTE address
66545899Ssklower  *  A DTE address is a series of ASCII digits
66636381Ssklower  *
66736381Ssklower  *	A DTE address may have leading zeros. The are significant.
66836381Ssklower  *		1 digit per nibble, may be an odd number of nibbles.
66936381Ssklower  *
67036381Ssklower  *  An NSAP-address has the DTE address in the IDI. Leading zeros are
67136381Ssklower  *		significant. Trailing hex f indicates the end of the DTE address.
67245899Ssklower  *  	The IDI is a series of BCD digits, one per nibble.
67336381Ssklower  *
67436381Ssklower  * RETURNS
67536381Ssklower  *  # significant digits in the DTE address, -1 if error.
67636381Ssklower  */
67736381Ssklower 
67836381Ssklower Static int
67945899Ssklower NSAPtoDTE(siso, sx25)
68045899Ssklower 	register struct sockaddr_iso *siso;
68145899Ssklower 	register struct sockaddr_x25 *sx25;
68236381Ssklower {
68345899Ssklower 	int		dtelen = -1;
68436381Ssklower 
68536381Ssklower 	IFDEBUG(D_CADDR)
68645899Ssklower 		printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&siso->siso_addr));
68736381Ssklower 	ENDDEBUG
68836381Ssklower 
68945899Ssklower 	if (siso->siso_data[0] == AFI_37) {
69045899Ssklower 		register char *out = sx25->x25_addr;
69145899Ssklower 		register char *in = siso->siso_data + 1;
69245899Ssklower 		register int nibble;
69349041Ssklower 		char *lim = siso->siso_data + siso->siso_nlen;
69449041Ssklower 		char *olim = out+15;
69545899Ssklower 		int lowNibble = 0;
69645899Ssklower 
69745899Ssklower 		while (in < lim) {
69845899Ssklower 			nibble = ((lowNibble ? *in++ : (*in >> 4)) & 0xf) | 0x30;
69945899Ssklower 			lowNibble ^= 1;
70049041Ssklower 			if (nibble != 0x3f && out < olim)
70145899Ssklower 				*out++ = nibble;
70245899Ssklower 		}
70345899Ssklower 		dtelen = out - sx25->x25_addr;
70445899Ssklower 		*out++ = 0;
70545899Ssklower 	} else {
70645899Ssklower 		register struct rtentry *rt = rtalloc1(siso, 1);
70745899Ssklower 		/* error = iso_8208snparesolve(addr, x121string, &x121strlen);*/
70845899Ssklower 
70945899Ssklower 		if (rt) {
71045899Ssklower 			register struct sockaddr_x25 *sxx =
71145899Ssklower 							(struct sockaddr_x25 *)rt->rt_gateway;
71245899Ssklower 			register char *in = sxx->x25_addr;
71345899Ssklower 
71445899Ssklower 			rt->rt_use--;
71545899Ssklower 			if (sxx && sxx->x25_family == AF_CCITT) {
71645899Ssklower 				bcopy(sx25->x25_addr, sxx->x25_addr, sizeof(sx25->x25_addr));
71745899Ssklower 				while (*in++) {}
71845899Ssklower 				dtelen = in - sxx->x25_addr;
71945899Ssklower 			}
72045899Ssklower 		}
72136381Ssklower 	}
72245899Ssklower 	return dtelen;
72336381Ssklower }
72436381Ssklower 
72536381Ssklower /*
72636381Ssklower  * NAME:	FACILtoNSAP()
72736381Ssklower  * CALLED FROM:
72836381Ssklower  *  parse_facil()
72936381Ssklower  * FUNCTION and ARGUMENTS:
73036381Ssklower  * 	Creates and NSAP in the sockaddr_iso (addr) from the
73145899Ssklower  *  x.25 facility found at buf - 1.
73236381Ssklower  * RETURNS:
73345899Ssklower  *  length of parameter if ok, -1 if error.
73436381Ssklower  */
73536381Ssklower 
73636381Ssklower Static int
73745899Ssklower FACILtoNSAP(addr, buf)
73845899Ssklower 	u_char 		*buf;
73936381Ssklower 	register struct sockaddr_iso *addr;
74036381Ssklower {
74145899Ssklower 	int len_in_nibbles, param_len = *buf++;
74245899Ssklower 	u_char			buf_len; /* in bytes */
74336381Ssklower 
74436381Ssklower 	IFDEBUG(D_CADDR)
74536381Ssklower 		printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n",
74636381Ssklower 			buf, buf_len, addr );
74736381Ssklower 	ENDDEBUG
74836381Ssklower 
74945899Ssklower 	len_in_nibbles = *buf & 0x3f;
75045899Ssklower 	buf_len = (len_in_nibbles + 1) >> 1;
75136381Ssklower 	/* despite the fact that X.25 makes us put a length in nibbles
75236381Ssklower 	 * here, the NSAP-addrs are always in full octets
75336381Ssklower 	 */
75445899Ssklower 	switch (*buf++ & 0xc0) {
75545899Ssklower 	case 0:
75645899Ssklower 		/* Entire OSI NSAP address */
75745899Ssklower 		bcopy((caddr_t)buf, addr->siso_data, addr->siso_nlen = buf_len);
75845899Ssklower 		break;
75936381Ssklower 
76045899Ssklower 	case 40:
76145899Ssklower 		/* Partial OSI NSAP address, assume trailing */
76245899Ssklower 		if (buf_len + addr->siso_nlen > sizeof(addr->siso_addr))
76345899Ssklower 			return -1;
76445899Ssklower 		bcopy((caddr_t)buf, TSEL(addr), buf_len);
76545899Ssklower 		addr->siso_nlen += buf_len;
76645899Ssklower 		break;
76736381Ssklower 
76845899Ssklower 	default:
76945899Ssklower 		/* Rather than blow away the connection, just ignore and use
77045899Ssklower 		   NSAP from DTE */;
77136381Ssklower 	}
77245899Ssklower 	return param_len;
77345899Ssklower }
77436381Ssklower 
77545899Ssklower static
77645899Ssklower init_siso(siso)
77745899Ssklower register struct sockaddr_iso *siso;
77845899Ssklower {
77945899Ssklower 	siso->siso_len = sizeof (*siso);
78045899Ssklower 	siso->siso_family = AF_ISO;
78145899Ssklower 	siso->siso_data[0] = AFI_37;
78245899Ssklower 	siso->siso_nlen = 8;
78336381Ssklower }
78436381Ssklower 
78536381Ssklower /*
78636381Ssklower  * NAME:	DTEtoNSAP()
78736381Ssklower  * CALLED FROM:
78836381Ssklower  *  parse_facil()
78936381Ssklower  * FUNCTION and ARGUMENTS:
79036381Ssklower  *  Creates a type 37 NSAP in the sockaddr_iso (addr)
79145899Ssklower  * 	from a DTE address found in a sockaddr_x25.
79236381Ssklower  *
79336381Ssklower  * RETURNS:
79436381Ssklower  *  0 if ok; E* otherwise.
79536381Ssklower  */
79636381Ssklower 
79736381Ssklower Static  int
79845899Ssklower DTEtoNSAP(addr, sx)
79936381Ssklower 	struct sockaddr_iso *addr;
80045899Ssklower 	struct sockaddr_x25 *sx;
80136381Ssklower {
80245899Ssklower 	register char		*in, *out;
80345899Ssklower 	register int		first;
80445899Ssklower 	int					pad_tail = 0;
80545899Ssklower 	int 				src_len;
80636381Ssklower 
80736381Ssklower 
80845899Ssklower 	init_siso(addr);
80945899Ssklower 	src_len = strlen(sx->x25_addr);
81045899Ssklower 	in = sx->x25_addr;
81145899Ssklower 	out = addr->siso_data + 1;
81245899Ssklower 	if (*in == '0' && (src_len & 1 == 0)) {
81345899Ssklower 		pad_tail = 0xf;
81445899Ssklower 		src_len++;
81545899Ssklower 	}
81645899Ssklower 	for (first = 0; src_len > 0; src_len --) {
81745899Ssklower 		first |= *in++;
81845899Ssklower 		if (src_len & 1) {
81945899Ssklower 			*out++ = first;
82045899Ssklower 			first = 0;
82145899Ssklower 		}
82245899Ssklower 		else first <<= 4;
82345899Ssklower 	}
82445899Ssklower 	if (pad_tail)
82545899Ssklower 		out[-1] |= 0xf;
82636381Ssklower 	return 0; /* ok */
82736381Ssklower }
82836381Ssklower 
82936381Ssklower /*
83036381Ssklower  * FUNCTION and ARGUMENTS:
83136381Ssklower  *	parses (buf_len) bytes beginning at (buf) and finds
83236381Ssklower  *  a called nsap, a calling nsap, and protocol identifier.
83336381Ssklower  * RETURNS:
83436381Ssklower  *  0 if ok, E* otherwise.
83536381Ssklower  */
83636381Ssklower 
83745899Ssklower static int
83845899Ssklower parse_facil(lcp, isop, buf, buf_len)
83936381Ssklower 	caddr_t 		buf;
84036381Ssklower 	u_char			buf_len; /* in bytes */
84145899Ssklower 	struct			isopcb *isop;
84245899Ssklower 	struct			pklcd *lcp;
84336381Ssklower {
84445899Ssklower 	register struct sockaddr_iso *called = isop->isop_laddr;
84545899Ssklower 	register struct sockaddr_iso *calling = isop->isop_faddr;
84636381Ssklower 	register int 	i;
84745899Ssklower 	register u_char 	*ptr = (u_char *)buf;
84845899Ssklower 	u_char			*ptr_lim, *facil_lim;
84945899Ssklower 	int 			facil_param_len, facil_len;
85036381Ssklower 
85136381Ssklower 	IFDEBUG(D_CADDR)
85245899Ssklower 		printf("parse_facil(0x%x, 0x%x, 0x%x, 0x%x)\n",
85345899Ssklower 			buf, buf_len, called, calling);
85436381Ssklower 		dump_buf(buf, buf_len);
85536381Ssklower 	ENDDEBUG
85636381Ssklower 
85736381Ssklower 	/* find the beginnings of the facility fields in buf
85836381Ssklower 	 * by skipping over the called & calling DTE addresses
85936381Ssklower 	 * i <- # nibbles in called + # nibbles in calling
86036381Ssklower 	 * i += 1 so that an odd nibble gets rounded up to even
86136381Ssklower 	 * before dividing by 2, then divide by two to get # octets
86236381Ssklower 	 */
86345899Ssklower 	i = (int)(*ptr >> 4) + (int)(*ptr&0xf);
86436381Ssklower 	i++;
86545899Ssklower 	ptr += i >> 1;
86636381Ssklower 	ptr ++; /* plus one for the DTE lengths byte */
86736381Ssklower 
86836381Ssklower 	/* ptr now is at facil_length field */
86945899Ssklower 	facil_len = *ptr++;
87045899Ssklower 	facil_lim = ptr + facil_len;
87136381Ssklower 	IFDEBUG(D_CADDR)
87245899Ssklower 		printf("parse_facils: facil length is  0x%x\n", (int) facil_len);
87336381Ssklower 	ENDDEBUG
87436381Ssklower 
87545899Ssklower 	while (ptr <= facil_lim) {
87636381Ssklower 		/* get NSAP addresses from facilities */
87745899Ssklower 		switch (*ptr++) {
87836381Ssklower 			case 0xcb:
87945899Ssklower 				/* calling NSAP */
88045899Ssklower 				facil_param_len = FACILtoNSAP(isop->isop_faddr, ptr);
88136381Ssklower 				break;
88236381Ssklower 			case 0xc9:
88345899Ssklower 				/* called NSAP */
88445899Ssklower 				facil_param_len = FACILtoNSAP(isop->isop_laddr, ptr);
88536381Ssklower 				break;
88636381Ssklower 
88736381Ssklower 				/* from here to default are legit cases that I ignore */
88836381Ssklower 				/* variable length */
88936381Ssklower 			case 0xca:  /* end-to-end transit delay negot */
89036381Ssklower 			case 0xc6:  /* network user id */
89136381Ssklower 			case 0xc5: 	/* charging info : indicating monetary unit */
89236381Ssklower 			case 0xc2: 	/* charging info : indicating segment count */
89336381Ssklower 			case 0xc1: 	/* charging info : indicating call duration */
89436381Ssklower 			case 0xc4: 	/* RPOA extended format */
89536381Ssklower 			case 0xc3: 	/* call redirection notification */
89636381Ssklower 				facil_param_len = 0;
89736381Ssklower 				break;
89836381Ssklower 
89936381Ssklower 				/* 1 octet */
90036381Ssklower 			case 0x0a:  /* min. throughput class negot */
90136381Ssklower 			case 0x02:  /* throughput class */
90236381Ssklower 			case 0x03:  case 0x47:  /* CUG shit */
90336381Ssklower 			case 0x0b:  /* expedited data negot */
90436381Ssklower 			case 0x01:  /* Fast select or reverse charging
90536381Ssklower 						(example of intelligent protocol design) */
90636381Ssklower 			case 0x04: 	/* charging info : requesting service */
90736381Ssklower 			case 0x08: 	/* called line addr modified notification */
90836381Ssklower 				facil_param_len = 1;
90936381Ssklower 				break;
91036381Ssklower 
91136381Ssklower 				/* any 2 octets */
91236381Ssklower 			case 0x42:  /* pkt size */
91336381Ssklower 			case 0x43:  /* win size */
91436381Ssklower 			case 0x44:  /* RPOA basic format */
91536381Ssklower 			case 0x41:  /* bilateral CUG shit */
91636381Ssklower 			case 0x49: 	/* transit delay selection and indication */
91736381Ssklower 				facil_param_len = 2;
91836381Ssklower 				break;
91936381Ssklower 
92036381Ssklower 				/* don't have any 3 octets */
92136381Ssklower 				/*
92236381Ssklower 				facil_param_len = 3;
92336381Ssklower 				*/
92436381Ssklower 			default:
92536381Ssklower 				printf(
92636381Ssklower "BOGUS FACILITY CODE facil_len 0x%x *facil_len 0x%x, ptr 0x%x *ptr 0x%x\n",
92745899Ssklower 					ptr, facil_len, ptr - 1, ptr[-1]);
92836381Ssklower 				/* facil that we don't handle */
92936381Ssklower 				return E_CO_HLI_REJI;
93036381Ssklower 		}
93145899Ssklower 		if (facil_param_len == -1)
93245899Ssklower 			return E_CO_REG_ICDA;
93345899Ssklower 		if (facil_param_len == 0) /* variable length */
93436381Ssklower 			facil_param_len = (int)*ptr; /* 1 + the real facil param */
93536381Ssklower 		ptr += facil_param_len;
93636381Ssklower 	}
93736381Ssklower 	return 0;
93836381Ssklower }
93936381Ssklower 
94045899Ssklower #endif TPCONS
941