xref: /csrg-svn/sys/netiso/if_cons.c (revision 45899)
136381Ssklower /***********************************************************
236381Ssklower 		Copyright IBM Corporation 1987
336381Ssklower 
436381Ssklower                       All Rights Reserved
536381Ssklower 
636381Ssklower Permission to use, copy, modify, and distribute this software and its
736381Ssklower documentation for any purpose and without fee is hereby granted,
836381Ssklower provided that the above copyright notice appear in all copies and that
936381Ssklower both that copyright notice and this permission notice appear in
1036381Ssklower supporting documentation, and that the name of IBM not be
1136381Ssklower used in advertising or publicity pertaining to distribution of the
1236381Ssklower software without specific, written prior permission.
1336381Ssklower 
1436381Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536381Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636381Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736381Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836381Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936381Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036381Ssklower SOFTWARE.
2136381Ssklower 
2236381Ssklower ******************************************************************/
2336381Ssklower 
2436381Ssklower /*
2536381Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636381Ssklower  */
2736381Ssklower /*
2836381Ssklower  * $Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $
2936381Ssklower  * $Source: /usr/argo/sys/netiso/RCS/if_cons.c,v $
3036381Ssklower  *
3136381Ssklower  * cons.c - Connection Oriented Network Service:
3236381Ssklower  * including support for a) user transport-level service,
3336381Ssklower  *	b) COSNS below CLNP, and c) CONS below TP.
3436381Ssklower 
3536381Ssklower #ifndef lint
3636381Ssklower static char *rcsid = "$Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $";
3736381Ssklower #endif lint
38*45899Ssklower  */
3936381Ssklower 
40*45899Ssklower #ifdef TPCONS
41*45899Ssklower #ifdef KERNEL
4236381Ssklower #ifdef ARGO_DEBUG
4336381Ssklower #define Static
4436381Ssklower unsigned LAST_CALL_PCB;
4536381Ssklower #else ARGO_DEBUG
4636381Ssklower #define Static static
4736381Ssklower #endif ARGO_DEBUG
4836381Ssklower 
4936381Ssklower 
5036381Ssklower 
51*45899Ssklower #ifndef SOCK_STREAM
5236381Ssklower #include "param.h"
5336381Ssklower #include "systm.h"
5436381Ssklower #include "mbuf.h"
5536381Ssklower #include "protosw.h"
5636381Ssklower #include "socket.h"
5736381Ssklower #include "socketvar.h"
5836381Ssklower #include "errno.h"
5936381Ssklower #include "ioctl.h"
6040783Smarc #include "tsleep.h"
6136381Ssklower 
6236381Ssklower #include "../net/if.h"
6336381Ssklower #include "../net/netisr.h"
6436381Ssklower #include "../net/route.h"
6536381Ssklower 
66*45899Ssklower #include "iso_errno.h"
67*45899Ssklower #include "argo_debug.h"
68*45899Ssklower #include "tp_trace.h"
69*45899Ssklower #include "iso.h"
70*45899Ssklower #include "cons.h"
71*45899Ssklower #include "iso_pcb.h"
7236381Ssklower 
73*45899Ssklower #include "../netccitt/x25.h"
74*45899Ssklower #include "../netccitt/pk.h"
75*45899Ssklower #include "../netccitt/pk_var.h"
76*45899Ssklower #endif
77*45899Ssklower 
7836381Ssklower #ifdef ARGO_DEBUG
7936381Ssklower #define MT_XCONN	0x50
8036381Ssklower #define MT_XCLOSE	0x51
8136381Ssklower #define MT_XCONFIRM	0x52
8236381Ssklower #define MT_XDATA	0x53
8336381Ssklower #define MT_XHEADER	0x54
8436381Ssklower #else
8536381Ssklower #define MT_XCONN	MT_DATA
8636381Ssklower #define MT_XCLOSE	MT_DATA
8736381Ssklower #define MT_XCONFIRM	MT_DATA
8836381Ssklower #define MT_XDATA	MT_DATA
8936381Ssklower #define MT_XHEADER	MT_HEADER
9036381Ssklower #endif ARGO_DEBUG
9136381Ssklower 
9236381Ssklower #define DONTCLEAR	 -1
9336381Ssklower 
9436381Ssklower /*********************************************************************
95*45899Ssklower  * cons.c - CONS interface to the x.25 layer
9636381Ssklower  *
9736381Ssklower  * TODO: figure out what resources we might run out of besides mbufs.
9836381Ssklower  *  If we run out of any of them (including mbufs) close and recycle
9936381Ssklower  *  lru x% of the connections, for some parameter x.
10036381Ssklower  *
101*45899Ssklower  * There are 2 interfaces from above:
10236381Ssklower  * 1) from TP0:
10336381Ssklower  *    cons CO network service
10436381Ssklower  *    TP associates a transport connection with a network connection.
10536381Ssklower  * 	  cons_output( isop, m, len, isdgm==0 )
10636381Ssklower  *        co_flags == 0
107*45899Ssklower  * 2) from TP4:
10836381Ssklower  *	  It's a datagram service, like clnp is. - even though it calls
10936381Ssklower  *			cons_output( isop, m, len, isdgm==1 )
11036381Ssklower  *	  it eventually goes through
11136381Ssklower  *			cosns_output(ifp, m, dst).
11236381Ssklower  *    TP4 permits multiplexing (reuse, possibly simultaneously) of the
11336381Ssklower  *	  network connections.
11436381Ssklower  *    This means that many sockets (many tpcbs) may be associated with
115*45899Ssklower  *    this pklcd, hence cannot have a back ptr from pklcd to a tpcb.
11636381Ssklower  *        co_flags & CONSF_DGM
117*45899Ssklower  *    co_socket is null since there may be many sockets that use this pklcd.
11836381Ssklower  *
11936381Ssklower NOTE:
12036381Ssklower 	streams would really be nice. sigh.
12136381Ssklower NOTE:
12236381Ssklower 	PVCs could be handled by config-ing a cons with an address and with the
12336381Ssklower 	IFF_POINTTOPOINT flag on.  This code would then have to skip the
12436381Ssklower 	connection setup stuff for pt-to-pt links.
12536381Ssklower 
12636381Ssklower 
12736381Ssklower  *********************************************************************/
12836381Ssklower 
12936381Ssklower 
13036381Ssklower #define CONS_IFQMAXLEN 5
13136381Ssklower 
13236381Ssklower 
13336381Ssklower /* protosw pointers for getting to higher layer */
13436381Ssklower Static 	struct protosw	*CLNP_proto;
13536381Ssklower Static 	struct protosw	*TP_proto;
13636381Ssklower Static 	struct protosw	*X25_proto;
13736381Ssklower Static 	int				issue_clear_req();
13836381Ssklower 
13936381Ssklower #ifndef	PHASEONE
14036381Ssklower extern	struct ifaddr	*ifa_ifwithnet();
14136381Ssklower #endif	PHASEONE
14236381Ssklower 
14336381Ssklower extern	struct ifaddr	*ifa_ifwithaddr();
14436381Ssklower 
14536381Ssklower Static  struct socket	dummysocket; /* for use by cosns */
14636381Ssklower 
14736381Ssklower extern struct	isopcb	tp_isopcb; /* chain of all TP pcbs */
14836381Ssklower struct	isopcb			tp_incoming_pending;  /* incoming connections
14936381Ssklower 										for TP, pending */
15036381Ssklower 
15136381Ssklower struct isopcb 	*Xpcblist[] =  {
15236381Ssklower 	&tp_incoming_pending,
15336381Ssklower 	&tp_isopcb,
15436381Ssklower 	(struct isopcb *)0
15536381Ssklower };
15636381Ssklower 
15736381Ssklower Static 	int parse_facil(), NSAPtoDTE(), make_partial_x25_packet();
15836381Ssklower Static	int FACILtoNSAP(), DTEtoNSAP();
159*45899Ssklower Static	struct pklcd *cons_chan_to_pcb();
16036381Ssklower 
16136381Ssklower #define HIGH_NIBBLE 1
16236381Ssklower #define LOW_NIBBLE 0
16336381Ssklower 
16436381Ssklower /*
16536381Ssklower  * NAME:	nibble_copy()
16636381Ssklower  * FUNCTION and ARGUMENTS:
16736381Ssklower  * 	copies (len) nibbles from (src_octet), high or low nibble
16836381Ssklower  *  to (dst_octet), high or low nibble,
16936381Ssklower  * src_nibble & dst_nibble should be:
17036381Ssklower  * 	HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble
17136381Ssklower  * 	LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble
17236381Ssklower  * RETURNS: VOID
17336381Ssklower  */
17436381Ssklower void
175*45899Ssklower nibble_copy(src_octet, src_nibble, dst_octet, dst_nibble, len)
17636381Ssklower 	register char  	*src_octet;
17736381Ssklower 	register char  	*dst_octet;
17836381Ssklower 	register unsigned		src_nibble;
17936381Ssklower 	register unsigned 		dst_nibble;
18036381Ssklower 	int		len;
18136381Ssklower {
18236381Ssklower 
18336381Ssklower 	register 	i;
18436381Ssklower 	register 	unsigned dshift, sshift;
18536381Ssklower 
18636381Ssklower 	IFDEBUG(D_CADDR)
18736381Ssklower 		printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n",
18836381Ssklower 		 src_octet, src_nibble, dst_octet, dst_nibble, len);
18936381Ssklower 	ENDDEBUG
19036381Ssklower #define SHIFT 0x4
19136381Ssklower 
19236381Ssklower 	dshift = dst_nibble << 2;
19336381Ssklower 	sshift = src_nibble << 2;
19436381Ssklower 
19536381Ssklower 	for (i=0; i<len; i++) {
19636381Ssklower 		/* clear dst_nibble  */
19736381Ssklower 		*dst_octet 	&= ~(0xf<< dshift);
19836381Ssklower 
19936381Ssklower 		/* set dst nibble */
20036381Ssklower 		*dst_octet 	|= ( 0xf & (*src_octet >> sshift))<< dshift;
20136381Ssklower 
20236381Ssklower 		dshift		^= SHIFT;
20336381Ssklower 		sshift		^= SHIFT;
20436381Ssklower 		src_nibble 	= 1-src_nibble;
20536381Ssklower 		dst_nibble 	= 1-dst_nibble;
20636381Ssklower 		src_octet	+= src_nibble;
20736381Ssklower 		dst_octet 	+= dst_nibble;
20836381Ssklower 	}
20936381Ssklower 	IFDEBUG(D_CADDR)
21036381Ssklower 		printf("nibble_copy DONE\n");
21136381Ssklower 	ENDDEBUG
21236381Ssklower }
21336381Ssklower 
21436381Ssklower /*
21536381Ssklower  * NAME:	nibble_match()
21636381Ssklower  * FUNCTION and ARGUMENTS:
21736381Ssklower  * 	compares src_octet/src_nibble and dst_octet/dst_nibble  for len nibbles.
21836381Ssklower  * RETURNS: 0 if they differ, 1 if they are the same.
21936381Ssklower  */
22036381Ssklower int
22136381Ssklower nibble_match( src_octet, src_nibble, dst_octet, dst_nibble, len)
22236381Ssklower 	register char  	*src_octet;
22336381Ssklower 	register char  	*dst_octet;
22436381Ssklower 	register unsigned		src_nibble;
22536381Ssklower 	register unsigned 		dst_nibble;
22636381Ssklower 	int		len;
22736381Ssklower {
22836381Ssklower 
22936381Ssklower 	register 	i;
23036381Ssklower 	register 	unsigned dshift, sshift;
23136381Ssklower 	u_char		nibble_a, nibble_b;
23236381Ssklower 
23336381Ssklower 	IFDEBUG(D_CADDR)
23436381Ssklower 		printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n",
23536381Ssklower 		 src_octet, src_nibble, dst_octet, dst_nibble, len);
23636381Ssklower 	ENDDEBUG
23736381Ssklower #define SHIFT 0x4
23836381Ssklower 
23936381Ssklower 	dshift = dst_nibble << 2;
24036381Ssklower 	sshift = src_nibble << 2;
24136381Ssklower 
24236381Ssklower 	for (i=0; i<len; i++) {
24336381Ssklower 		nibble_b = ((*dst_octet)>>dshift) & 0xf;
24436381Ssklower 		nibble_a = ( 0xf & (*src_octet >> sshift));
245*45899Ssklower 		if (nibble_b != nibble_a)
24636381Ssklower 			return 0;
24736381Ssklower 
24836381Ssklower 		dshift		^= SHIFT;
24936381Ssklower 		sshift		^= SHIFT;
25036381Ssklower 		src_nibble 	= 1-src_nibble;
25136381Ssklower 		dst_nibble 	= 1-dst_nibble;
25236381Ssklower 		src_octet	+= src_nibble;
25336381Ssklower 		dst_octet 	+= dst_nibble;
25436381Ssklower 	}
25536381Ssklower 	IFDEBUG(D_CADDR)
25636381Ssklower 		printf("nibble_match DONE\n");
25736381Ssklower 	ENDDEBUG
25836381Ssklower 	return 1;
25936381Ssklower }
26036381Ssklower 
26136381Ssklower /*
26236381Ssklower  **************************** NET PROTOCOL cons ***************************
26336381Ssklower  */
26436381Ssklower /*
26536381Ssklower  * NAME:	cons_init()
26636381Ssklower  * CALLED FROM:
26736381Ssklower  *	autoconf
26836381Ssklower  * FUNCTION:
26936381Ssklower  *	initialize the protocol
27036381Ssklower  */
27136381Ssklower cons_init()
27236381Ssklower {
273*45899Ssklower 	int tp_incoming(), clnp_incoming();
27436381Ssklower 
27536381Ssklower 
27636381Ssklower 	CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM);
27736381Ssklower 	X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM);
27836381Ssklower 	TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET);
27936381Ssklower 	IFDEBUG(D_CCONS)
28036381Ssklower 		printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n",
28136381Ssklower 			CLNP_proto, X25_proto, TP_proto);
28236381Ssklower 	ENDDEBUG
283*45899Ssklower #ifdef notdef
284*45899Ssklower 	pk_protolisten(0x81, 0, clnp_incoming);
285*45899Ssklower 	pk_protolisten(0x82, 0, esis_incoming);
286*45899Ssklower 	pk_protolisten(0x84, 0, tp8878_A_incoming);
287*45899Ssklower #endif
288*45899Ssklower 	pk_protolisten(0, 0, tp_incoming);
28936381Ssklower }
29036381Ssklower 
291*45899Ssklower tp_incoming(lcp, m0)
292*45899Ssklower struct pklcd *lcp;
293*45899Ssklower struct mbuf *m0;
29436381Ssklower {
295*45899Ssklower 	register struct mbuf *m = m0->m_next; /* m0 has calling sockaddr_x25 */
296*45899Ssklower 	register struct isopcb *isop;
297*45899Ssklower 	extern struct isopcb tp_isopcb;
298*45899Ssklower 	int cons_tpinput();
29936381Ssklower 
300*45899Ssklower 	if (iso_pcballoc((struct socket *)0, &tp_incoming_pending)) {
301*45899Ssklower 		m_freem(m);
302*45899Ssklower 		pk_clear(lcp);
303*45899Ssklower 		return;
30436381Ssklower 	}
305*45899Ssklower 	isop = tp_incoming_pending.isop_next;
306*45899Ssklower 	pk_output(lcp); /* Confirms call */
307*45899Ssklower 	lcp->lcd_upper = cons_tpinput;
308*45899Ssklower 	lcp->lcd_upnext = (caddr_t)isop;
309*45899Ssklower 	isop->isop_chan = (caddr_t)lcp;
310*45899Ssklower 	isop->isop_laddr = &isop->isop_sladdr;
311*45899Ssklower 	isop->isop_faddr = &isop->isop_sfaddr;
312*45899Ssklower 	DTEtoNSAP(isop->isop_laddr, &lcp->lcd_laddr);
313*45899Ssklower 	DTEtoNSAP(isop->isop_faddr, &lcp->lcd_faddr);
314*45899Ssklower 	parse_facil(isop, lcp, &(mtod(m, struct x25_packet *)->packet_data),
315*45899Ssklower 		m->m_pkthdr.len - PKHEADERLN);
316*45899Ssklower 	m_freem(m);
31736381Ssklower }
31836381Ssklower 
319*45899Ssklower cons_tpinput(lcp, m0)
320*45899Ssklower struct mbuf *m0;
321*45899Ssklower struct pklcd *lcp;
32236381Ssklower {
323*45899Ssklower 	register struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext;
324*45899Ssklower 	register struct x25_packet *xp;
325*45899Ssklower 	int cmd;
32636381Ssklower 
327*45899Ssklower 	switch(m0->m_type) {
328*45899Ssklower 	case MT_DATA:
329*45899Ssklower 	case MT_OOBDATA:
330*45899Ssklower 		tpcons_input(m0, isop->isop_faddr, isop->isop_laddr,
331*45899Ssklower 			(struct socket *)0, (caddr_t)lcp);
33236381Ssklower 
333*45899Ssklower 	case MT_CONTROL:
334*45899Ssklower 		switch (pk_decode(mtod(m0, struct x25_packet *))) {
335*45899Ssklower 		default:
336*45899Ssklower 			return;
33736381Ssklower 
338*45899Ssklower 		case RR:
339*45899Ssklower 			cmd = PRC_CONS_SEND_DONE;
340*45899Ssklower 			break;
34136381Ssklower 
342*45899Ssklower 		case RESET:
343*45899Ssklower 			cmd = PRC_ROUTEDEAD;
34436381Ssklower 		}
345*45899Ssklower 		tpcons_ctlinput(cmd, isop->isop_faddr, isop);
34636381Ssklower 	}
34736381Ssklower }
34836381Ssklower 
34936381Ssklower /*
35036381Ssklower  * NAME:	cons_connect()
35136381Ssklower  * CALLED FROM:
352*45899Ssklower  *	tpcons_pcbconnect() when opening a new connection.
35336381Ssklower  * FUNCTION anD ARGUMENTS:
35436381Ssklower  *  Figures out which device to use, finding a route if one doesn't
35536381Ssklower  *  already exist.
35636381Ssklower  * RETURN VALUE:
35736381Ssklower  *  returns E*
35836381Ssklower  */
359*45899Ssklower cons_connect(isop)
360*45899Ssklower 	register struct isopcb *isop;
36136381Ssklower {
362*45899Ssklower 	register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
36336381Ssklower 	register struct mbuf 	*m;
36436381Ssklower 	struct ifaddr 			*ifa;
36536381Ssklower 
36636381Ssklower 	IFDEBUG(D_CCONN)
367*45899Ssklower 		printf("cons_connect(0x%x): ", isop);
368*45899Ssklower 		dump_isoaddr(isop->isop_faddr);
369*45899Ssklower 		printf("myaddr: ");
370*45899Ssklower 		dump_isoaddr(isop->isop_laddr);
37136381Ssklower 		printf("\n" );
37236381Ssklower 	ENDDEBUG
373*45899Ssklower 	NSAPtoDTE(isop->isop_faddr, &lcp->lcd_faddr);
37436381Ssklower 	IFDEBUG(D_CCONN)
37536381Ssklower 		printf(
376*45899Ssklower 		"calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x)\n",
377*45899Ssklower 			&lcp->lcd_faddr, &lcp->lcd_laddr,
378*45899Ssklower 			isop->isop_socket->so_proto->pr_protocol);
37936381Ssklower 	ENDDEBUG
380*45899Ssklower 	return (make_partial_x25_packet(isop, lcp, m) ||
381*45899Ssklower 		 pk_connect(lcp, &lcp->lcd_faddr));
38236381Ssklower }
38336381Ssklower 
38436381Ssklower /*
38536381Ssklower  **************************** DEVICE cons ***************************
38636381Ssklower  */
38736381Ssklower 
38836381Ssklower 
38936381Ssklower /*
39036381Ssklower  * NAME:	cons_ctlinput()
39136381Ssklower  * CALLED FROM:
39236381Ssklower  *  lower layer when ECN_CLEAR occurs : this routine is here
39336381Ssklower  *  for consistency - cons subnet service calls its higher layer
39436381Ssklower  *  through the protosw entry.
39536381Ssklower  * FUNCTION & ARGUMENTS:
39637536Smckusick  *  cmd is a PRC_* command, list found in ../sys/protosw.h
39736381Ssklower  *  copcb is the obvious.
39836381Ssklower  *  This serves the higher-layer cons service.
39936381Ssklower  * NOTE: this takes 3rd arg. because cons uses it to inform itself
40036381Ssklower  *  of things (timeouts, etc) but has a pcb instead of an address.
40136381Ssklower  */
40236381Ssklower cons_ctlinput(cmd, sa, copcb)
40336381Ssklower 	int cmd;
40436381Ssklower 	struct sockaddr *sa;
405*45899Ssklower 	register struct pklcd *copcb;
40636381Ssklower {
40736381Ssklower }
40836381Ssklower 
40936381Ssklower 
410*45899Ssklower find_error_reason( xp )
411*45899Ssklower 	register struct x25_packet *xp;
41236381Ssklower {
41336381Ssklower 	extern u_char x25_error_stats[];
414*45899Ssklower 	int error, cause;
41536381Ssklower 
416*45899Ssklower 	if (xp) {
417*45899Ssklower 		cause = 4[(char *)xp];
418*45899Ssklower 		switch (cause) {
41936381Ssklower 			case 0x00:
42036381Ssklower 			case 0x80:
42136381Ssklower 				/* DTE originated; look at the diagnostic */
422*45899Ssklower 				error = (CONL_ERROR_MASK | cause);
42336381Ssklower 				goto done;
42436381Ssklower 
42536381Ssklower 			case 0x01: /* number busy */
42636381Ssklower 			case 0x81:
42736381Ssklower 			case 0x09: /* Out of order */
42836381Ssklower 			case 0x89:
42936381Ssklower 			case 0x11: /* Remot Procedure Error */
43036381Ssklower 			case 0x91:
43136381Ssklower 			case 0x19: /* reverse charging accept not subscribed */
43236381Ssklower 			case 0x99:
43336381Ssklower 			case 0x21: /* Incampat destination */
43436381Ssklower 			case 0xa1:
43536381Ssklower 			case 0x29: /* fast select accept not subscribed */
43636381Ssklower 			case 0xa9:
43736381Ssklower 			case 0x39: /* ship absent */
43836381Ssklower 			case 0xb9:
43936381Ssklower 			case 0x03: /* invalid facil request */
44036381Ssklower 			case 0x83:
44136381Ssklower 			case 0x0b: /* access barred */
44236381Ssklower 			case 0x8b:
44336381Ssklower 			case 0x13: /* local procedure error */
44436381Ssklower 			case 0x93:
44536381Ssklower 			case 0x05: /* network congestion */
44636381Ssklower 			case 0x85:
44736381Ssklower 			case 0x8d: /* not obtainable */
44836381Ssklower 			case 0x0d:
44936381Ssklower 			case 0x95: /* RPOA out of order */
45036381Ssklower 			case 0x15:
45136381Ssklower 				/* take out bit 8
45236381Ssklower 				 * so we don't have to have so many perror entries
45336381Ssklower 				 */
454*45899Ssklower 				error = (CONL_ERROR_MASK | 0x100 | (cause & ~0x80));
45536381Ssklower 				goto done;
45636381Ssklower 
45736381Ssklower 			case 0xc1: /* gateway-detected proc error */
45836381Ssklower 			case 0xc3: /* gateway congestion */
45936381Ssklower 
460*45899Ssklower 				error = (CONL_ERROR_MASK | 0x100 | cause);
46136381Ssklower 				goto done;
46236381Ssklower 		}
46336381Ssklower 	}
46436381Ssklower 	/* otherwise, a *hopefully* valid perror exists in the e_reason field */
465*45899Ssklower 	error = xp->packet_data;
46636381Ssklower 	if (error = 0) {
46736381Ssklower 		printf("Incoming PKT TYPE 0x%x with reason 0x%x\n",
468*45899Ssklower 			pk_decode(xp),
469*45899Ssklower 			cause);
47036381Ssklower 		error = E_CO_HLI_DISCA;
47136381Ssklower 	}
47236381Ssklower 
47336381Ssklower done:
47436381Ssklower 	return error;
47536381Ssklower }
47636381Ssklower 
47736381Ssklower 
47836381Ssklower 
47936381Ssklower #endif KERNEL
48036381Ssklower 
48136381Ssklower /*
48236381Ssklower  * NAME:	make_partial_x25_packet()
48336381Ssklower  *
48436381Ssklower  * FUNCTION and ARGUMENTS:
485*45899Ssklower  *	Makes part of an X.25 call packet, for use by x25.
48636381Ssklower  *  (src) and (dst) are the NSAP-addresses of source and destination.
48736381Ssklower  *	(buf) is a ptr to a buffer into which to write this partial header.
48836381Ssklower  *
489*45899Ssklower  *	 0			Facility length (in octets)
490*45899Ssklower  *	 1			Facility field, which is a set of:
49136381Ssklower  *	  m			facil code
49236381Ssklower  *	  m+1		facil param len (for >2-byte facilities) in octets
49336381Ssklower  *	  m+2..p	facil param field
49436381Ssklower  *  q			user data (protocol identification octet)
49536381Ssklower  *
49636381Ssklower  *
49736381Ssklower  * RETURNS:
49836381Ssklower  *  0 if OK
49936381Ssklower  *  E* if failed.
500*45899Ssklower  *
501*45899Ssklower  * SIDE EFFECTS:
502*45899Ssklower  * Stores facilites mbuf in X.25 control block, where the connect
503*45899Ssklower  * routine knows where to look for it.
50436381Ssklower  */
50536381Ssklower 
50636381Ssklower #ifdef X25_1984
50736381Ssklower int cons_use_facils = 1;
50836381Ssklower #else X25_1984
50936381Ssklower int cons_use_facils = 0;
51036381Ssklower #endif X25_1984
51136381Ssklower 
51236381Ssklower int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */
51336381Ssklower 
51436381Ssklower Static int
515*45899Ssklower make_partial_x25_packet(isop, lcp)
516*45899Ssklower 	struct isopcb *isop;
517*45899Ssklower 	struct pklcd *lcp;
51836381Ssklower {
51936381Ssklower 	u_int				proto;
52036381Ssklower 	int					flag;
521*45899Ssklower 	caddr_t 			buf;
522*45899Ssklower 	register caddr_t	ptr	= buf;
52336381Ssklower 	register int		len	= 0;
52436381Ssklower 	int 				buflen	=0;
52536381Ssklower 	caddr_t				facil_len;
52636381Ssklower 	int 				oddness	= 0;
527*45899Ssklower 	struct mbuf *m;
52836381Ssklower 
52936381Ssklower 
530*45899Ssklower 	MGET(m, MT_DATA, M_WAITOK);
531*45899Ssklower 	if (m == 0)
532*45899Ssklower 		return ENOBUFS;
533*45899Ssklower 	buf = mtod(m, caddr_t);
53436381Ssklower 	IFDEBUG(D_CCONN)
53536381Ssklower 		printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
536*45899Ssklower 			isop->isop_laddr, isop->isop_faddr, proto, m, flag);
53736381Ssklower 	ENDDEBUG
53836381Ssklower 
53936381Ssklower 	/* ptr now points to facil length (len of whole facil field in OCTETS */
54036381Ssklower 	facil_len = ptr ++;
54136381Ssklower 
54236381Ssklower 	IFDEBUG(D_CADDR)
54336381Ssklower 		printf("make_partial  calling: ptr 0x%x, len 0x%x\n", ptr,
544*45899Ssklower 				isop->isop_laddr->siso_addr.isoa_len);
54536381Ssklower 	ENDDEBUG
546*45899Ssklower 	if (cons_use_facils) {
54736381Ssklower 		*ptr = 0xcb; /* calling facility code */
54836381Ssklower 		ptr ++;
54936381Ssklower 		ptr ++; /* leave room for facil param len (in OCTETS + 1) */
55036381Ssklower 		ptr ++; /* leave room for the facil param len (in nibbles),
55136381Ssklower 				* high two bits of which indicate full/partial NSAP
55236381Ssklower 				*/
553*45899Ssklower 		len = isop->isop_laddr->siso_addr.isoa_len;
554*45899Ssklower 		bcopy( isop->isop_laddr->siso_data, ptr, len);
55536381Ssklower 		*(ptr-2) = len+2; /* facil param len in octets */
55636381Ssklower 		*(ptr-1) = len<<1; /* facil param len in nibbles */
55736381Ssklower 		ptr += len;
55836381Ssklower 
55936381Ssklower 		IFDEBUG(D_CADDR)
56036381Ssklower 			printf("make_partial  called: ptr 0x%x, len 0x%x\n", ptr,
561*45899Ssklower 					isop->isop_faddr->siso_addr.isoa_len);
56236381Ssklower 		ENDDEBUG
56336381Ssklower 		*ptr = 0xc9; /* called facility code */
56436381Ssklower 		ptr ++;
56536381Ssklower 		ptr ++; /* leave room for facil param len (in OCTETS + 1) */
56636381Ssklower 		ptr ++; /* leave room for the facil param len (in nibbles),
56736381Ssklower 				* high two bits of which indicate full/partial NSAP
56836381Ssklower 				*/
569*45899Ssklower 		len = isop->isop_faddr->siso_nlen;
570*45899Ssklower 		bcopy(isop->isop_faddr->siso_data, ptr, len);
57136381Ssklower 		*(ptr-2) = len+2; /* facil param len = addr len + 1 for each of these
57236381Ssklower 						  * two length fields, in octets */
57336381Ssklower 		*(ptr-1) = len<<1; /* facil param len in nibbles */
57436381Ssklower 		ptr += len;
57536381Ssklower 
57636381Ssklower 	}
57736381Ssklower 	*facil_len = ptr - facil_len - 1;
578*45899Ssklower 	if (*facil_len > MAX_FACILITIES)
57936381Ssklower 		return E_CO_PNA_LONG;
58036381Ssklower 
581*45899Ssklower 	if (cons_use_udata) {
582*45899Ssklower 		if (isop->isop_x25crud_len > 0) {
58336381Ssklower 			/*
58436381Ssklower 			 *	The user specified something. Stick it in
58536381Ssklower 			 */
586*45899Ssklower 			bcopy(isop->isop_x25crud, lcp->lcd_faddr.x25_udata,
587*45899Ssklower 					isop->isop_x25crud_len);
588*45899Ssklower 			lcp->lcd_faddr.x25_udlen = isop->isop_x25crud_len;
58936381Ssklower 		}
59036381Ssklower 	}
59136381Ssklower 
59236381Ssklower 	buflen = (int)(ptr - buf);
59336381Ssklower 
59436381Ssklower 	IFDEBUG(D_CDUMP_REQ)
59536381Ssklower 		register int i;
59636381Ssklower 
59736381Ssklower 		printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n",
59836381Ssklower 			buf, buflen, buflen);
59936381Ssklower 		for( i=0; i < buflen; ) {
60036381Ssklower 			printf("+%d: %x %x %x %x    %x %x %x %x\n",
60136381Ssklower 				i,
60236381Ssklower 				*(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3),
60336381Ssklower 				*(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7));
60436381Ssklower 			i+=8;
60536381Ssklower 		}
60636381Ssklower 	ENDDEBUG
60736381Ssklower 	IFDEBUG(D_CADDR)
60836381Ssklower 		printf("make_partial returns buf 0x%x size 0x%x bytes\n",
60936381Ssklower 			mtod(m, caddr_t), buflen);
61036381Ssklower 	ENDDEBUG
61136381Ssklower 
612*45899Ssklower 	if (buflen > MHLEN)
61336381Ssklower 		return E_CO_PNA_LONG;
61436381Ssklower 
61536381Ssklower 	m->m_len = buflen;
616*45899Ssklower 	lcp->lcd_facilities = m;
61736381Ssklower 	return  0;
61836381Ssklower }
61936381Ssklower 
62036381Ssklower /*
62136381Ssklower  * NAME:	NSAPtoDTE()
62236381Ssklower  * CALLED FROM:
62336381Ssklower  *  make_partial_x25_packet()
62436381Ssklower  * FUNCTION and ARGUMENTS:
62536381Ssklower  *  get a DTE address from an NSAP-address (struct sockaddr_iso)
62636381Ssklower  *  (dst_octet) is the octet into which to begin stashing the DTE addr
62736381Ssklower  *  (dst_nibble) takes 0 or 1.  1 means begin filling in the DTE addr
62836381Ssklower  * 		in the high-order nibble of dst_octet.  0 means low-order nibble.
62936381Ssklower  *  (addr) is the NSAP-address
63036381Ssklower  *  (flag) is true if the transport suffix is to become the
63136381Ssklower  *		last two digits of the DTE address
632*45899Ssklower  *  A DTE address is a series of ASCII digits
63336381Ssklower  *
63436381Ssklower  *	A DTE address may have leading zeros. The are significant.
63536381Ssklower  *		1 digit per nibble, may be an odd number of nibbles.
63636381Ssklower  *
63736381Ssklower  *  An NSAP-address has the DTE address in the IDI. Leading zeros are
63836381Ssklower  *		significant. Trailing hex f indicates the end of the DTE address.
639*45899Ssklower  *  	The IDI is a series of BCD digits, one per nibble.
64036381Ssklower  *
64136381Ssklower  * RETURNS
64236381Ssklower  *  # significant digits in the DTE address, -1 if error.
64336381Ssklower  */
64436381Ssklower 
64536381Ssklower Static int
646*45899Ssklower NSAPtoDTE(siso, sx25)
647*45899Ssklower 	register struct sockaddr_iso *siso;
648*45899Ssklower 	register struct sockaddr_x25 *sx25;
64936381Ssklower {
650*45899Ssklower 	int		dtelen = -1;
65136381Ssklower 
65236381Ssklower 	IFDEBUG(D_CADDR)
653*45899Ssklower 		printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&siso->siso_addr));
65436381Ssklower 	ENDDEBUG
65536381Ssklower 
656*45899Ssklower 	if (siso->siso_data[0] == AFI_37) {
657*45899Ssklower 		register char *out = sx25->x25_addr;
658*45899Ssklower 		register char *in = siso->siso_data + 1;
659*45899Ssklower 		register int nibble;
660*45899Ssklower 		char *lim = in + 15;
661*45899Ssklower 		int lowNibble = 0;
662*45899Ssklower 
663*45899Ssklower 		while (in < lim) {
664*45899Ssklower 			nibble = ((lowNibble ? *in++ : (*in >> 4)) & 0xf) | 0x30;
665*45899Ssklower 			lowNibble ^= 1;
666*45899Ssklower 			if (nibble != 0x3f)
667*45899Ssklower 				*out++ = nibble;
668*45899Ssklower 		}
669*45899Ssklower 		dtelen = out - sx25->x25_addr;
670*45899Ssklower 		*out++ = 0;
671*45899Ssklower 	} else {
672*45899Ssklower 		register struct rtentry *rt = rtalloc1(siso, 1);
673*45899Ssklower 		/* error = iso_8208snparesolve(addr, x121string, &x121strlen);*/
674*45899Ssklower 
675*45899Ssklower 		if (rt) {
676*45899Ssklower 			register struct sockaddr_x25 *sxx =
677*45899Ssklower 							(struct sockaddr_x25 *)rt->rt_gateway;
678*45899Ssklower 			register char *in = sxx->x25_addr;
679*45899Ssklower 
680*45899Ssklower 			rt->rt_use--;
681*45899Ssklower 			if (sxx && sxx->x25_family == AF_CCITT) {
682*45899Ssklower 				bcopy(sx25->x25_addr, sxx->x25_addr, sizeof(sx25->x25_addr));
683*45899Ssklower 				while (*in++) {}
684*45899Ssklower 				dtelen = in - sxx->x25_addr;
685*45899Ssklower 			}
686*45899Ssklower 		}
68736381Ssklower 	}
688*45899Ssklower 	return dtelen;
68936381Ssklower }
69036381Ssklower 
69136381Ssklower /*
69236381Ssklower  * NAME:	FACILtoNSAP()
69336381Ssklower  * CALLED FROM:
69436381Ssklower  *  parse_facil()
69536381Ssklower  * FUNCTION and ARGUMENTS:
69636381Ssklower  * 	Creates and NSAP in the sockaddr_iso (addr) from the
697*45899Ssklower  *  x.25 facility found at buf - 1.
69836381Ssklower  * RETURNS:
699*45899Ssklower  *  length of parameter if ok, -1 if error.
70036381Ssklower  */
70136381Ssklower 
70236381Ssklower Static int
703*45899Ssklower FACILtoNSAP(addr, buf)
704*45899Ssklower 	u_char 		*buf;
70536381Ssklower 	register struct sockaddr_iso *addr;
70636381Ssklower {
707*45899Ssklower 	int len_in_nibbles, param_len = *buf++;
708*45899Ssklower 	u_char			buf_len; /* in bytes */
70936381Ssklower 
71036381Ssklower 	IFDEBUG(D_CADDR)
71136381Ssklower 		printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n",
71236381Ssklower 			buf, buf_len, addr );
71336381Ssklower 	ENDDEBUG
71436381Ssklower 
715*45899Ssklower 	len_in_nibbles = *buf & 0x3f;
716*45899Ssklower 	buf_len = (len_in_nibbles + 1) >> 1;
71736381Ssklower 	/* despite the fact that X.25 makes us put a length in nibbles
71836381Ssklower 	 * here, the NSAP-addrs are always in full octets
71936381Ssklower 	 */
720*45899Ssklower 	switch (*buf++ & 0xc0) {
721*45899Ssklower 	case 0:
722*45899Ssklower 		/* Entire OSI NSAP address */
723*45899Ssklower 		bcopy((caddr_t)buf, addr->siso_data, addr->siso_nlen = buf_len);
724*45899Ssklower 		break;
72536381Ssklower 
726*45899Ssklower 	case 40:
727*45899Ssklower 		/* Partial OSI NSAP address, assume trailing */
728*45899Ssklower 		if (buf_len + addr->siso_nlen > sizeof(addr->siso_addr))
729*45899Ssklower 			return -1;
730*45899Ssklower 		bcopy((caddr_t)buf, TSEL(addr), buf_len);
731*45899Ssklower 		addr->siso_nlen += buf_len;
732*45899Ssklower 		break;
73336381Ssklower 
734*45899Ssklower 	default:
735*45899Ssklower 		/* Rather than blow away the connection, just ignore and use
736*45899Ssklower 		   NSAP from DTE */;
73736381Ssklower 	}
738*45899Ssklower 	return param_len;
739*45899Ssklower }
74036381Ssklower 
741*45899Ssklower static
742*45899Ssklower init_siso(siso)
743*45899Ssklower register struct sockaddr_iso *siso;
744*45899Ssklower {
745*45899Ssklower 	siso->siso_len = sizeof (*siso);
746*45899Ssklower 	siso->siso_family = AF_ISO;
747*45899Ssklower 	siso->siso_data[0] = AFI_37;
748*45899Ssklower 	siso->siso_nlen = 8;
74936381Ssklower }
75036381Ssklower 
75136381Ssklower /*
75236381Ssklower  * NAME:	DTEtoNSAP()
75336381Ssklower  * CALLED FROM:
75436381Ssklower  *  parse_facil()
75536381Ssklower  * FUNCTION and ARGUMENTS:
75636381Ssklower  *  Creates a type 37 NSAP in the sockaddr_iso (addr)
757*45899Ssklower  * 	from a DTE address found in a sockaddr_x25.
75836381Ssklower  *
75936381Ssklower  * RETURNS:
76036381Ssklower  *  0 if ok; E* otherwise.
76136381Ssklower  */
76236381Ssklower 
76336381Ssklower Static  int
764*45899Ssklower DTEtoNSAP(addr, sx)
76536381Ssklower 	struct sockaddr_iso *addr;
766*45899Ssklower 	struct sockaddr_x25 *sx;
76736381Ssklower {
768*45899Ssklower 	register char		*in, *out;
769*45899Ssklower 	register int		first;
770*45899Ssklower 	int					pad_tail = 0;
771*45899Ssklower 	int 				src_len;
77236381Ssklower 
77336381Ssklower 
774*45899Ssklower 	init_siso(addr);
775*45899Ssklower 	src_len = strlen(sx->x25_addr);
776*45899Ssklower 	in = sx->x25_addr;
777*45899Ssklower 	out = addr->siso_data + 1;
778*45899Ssklower 	if (*in == '0' && (src_len & 1 == 0)) {
779*45899Ssklower 		pad_tail = 0xf;
780*45899Ssklower 		src_len++;
781*45899Ssklower 	}
782*45899Ssklower 	for (first = 0; src_len > 0; src_len --) {
783*45899Ssklower 		first |= *in++;
784*45899Ssklower 		if (src_len & 1) {
785*45899Ssklower 			*out++ = first;
786*45899Ssklower 			first = 0;
787*45899Ssklower 		}
788*45899Ssklower 		else first <<= 4;
789*45899Ssklower 	}
790*45899Ssklower 	if (pad_tail)
791*45899Ssklower 		out[-1] |= 0xf;
79236381Ssklower 	return 0; /* ok */
79336381Ssklower }
79436381Ssklower 
79536381Ssklower /*
79636381Ssklower  * FUNCTION and ARGUMENTS:
79736381Ssklower  *	parses (buf_len) bytes beginning at (buf) and finds
79836381Ssklower  *  a called nsap, a calling nsap, and protocol identifier.
79936381Ssklower  * RETURNS:
80036381Ssklower  *  0 if ok, E* otherwise.
80136381Ssklower  */
80236381Ssklower 
803*45899Ssklower static int
804*45899Ssklower parse_facil(lcp, isop, buf, buf_len)
80536381Ssklower 	caddr_t 		buf;
80636381Ssklower 	u_char			buf_len; /* in bytes */
807*45899Ssklower 	struct			isopcb *isop;
808*45899Ssklower 	struct			pklcd *lcp;
80936381Ssklower {
810*45899Ssklower 	register struct sockaddr_iso *called = isop->isop_laddr;
811*45899Ssklower 	register struct sockaddr_iso *calling = isop->isop_faddr;
81236381Ssklower 	register int 	i;
813*45899Ssklower 	register u_char 	*ptr = (u_char *)buf;
814*45899Ssklower 	u_char			*ptr_lim, *facil_lim;
815*45899Ssklower 	int 			facil_param_len, facil_len;
81636381Ssklower 
81736381Ssklower 	IFDEBUG(D_CADDR)
818*45899Ssklower 		printf("parse_facil(0x%x, 0x%x, 0x%x, 0x%x)\n",
819*45899Ssklower 			buf, buf_len, called, calling);
82036381Ssklower 		dump_buf(buf, buf_len);
82136381Ssklower 	ENDDEBUG
82236381Ssklower 
82336381Ssklower 	/* find the beginnings of the facility fields in buf
82436381Ssklower 	 * by skipping over the called & calling DTE addresses
82536381Ssklower 	 * i <- # nibbles in called + # nibbles in calling
82636381Ssklower 	 * i += 1 so that an odd nibble gets rounded up to even
82736381Ssklower 	 * before dividing by 2, then divide by two to get # octets
82836381Ssklower 	 */
829*45899Ssklower 	i = (int)(*ptr >> 4) + (int)(*ptr&0xf);
83036381Ssklower 	i++;
831*45899Ssklower 	ptr += i >> 1;
83236381Ssklower 	ptr ++; /* plus one for the DTE lengths byte */
83336381Ssklower 
83436381Ssklower 	/* ptr now is at facil_length field */
835*45899Ssklower 	facil_len = *ptr++;
836*45899Ssklower 	facil_lim = ptr + facil_len;
83736381Ssklower 	IFDEBUG(D_CADDR)
838*45899Ssklower 		printf("parse_facils: facil length is  0x%x\n", (int) facil_len);
83936381Ssklower 	ENDDEBUG
84036381Ssklower 
841*45899Ssklower 	while (ptr <= facil_lim) {
84236381Ssklower 		/* get NSAP addresses from facilities */
843*45899Ssklower 		switch (*ptr++) {
84436381Ssklower 			case 0xcb:
845*45899Ssklower 				/* calling NSAP */
846*45899Ssklower 				facil_param_len = FACILtoNSAP(isop->isop_faddr, ptr);
84736381Ssklower 				break;
84836381Ssklower 			case 0xc9:
849*45899Ssklower 				/* called NSAP */
850*45899Ssklower 				facil_param_len = FACILtoNSAP(isop->isop_laddr, ptr);
85136381Ssklower 				break;
85236381Ssklower 
85336381Ssklower 				/* from here to default are legit cases that I ignore */
85436381Ssklower 				/* variable length */
85536381Ssklower 			case 0xca:  /* end-to-end transit delay negot */
85636381Ssklower 			case 0xc6:  /* network user id */
85736381Ssklower 			case 0xc5: 	/* charging info : indicating monetary unit */
85836381Ssklower 			case 0xc2: 	/* charging info : indicating segment count */
85936381Ssklower 			case 0xc1: 	/* charging info : indicating call duration */
86036381Ssklower 			case 0xc4: 	/* RPOA extended format */
86136381Ssklower 			case 0xc3: 	/* call redirection notification */
86236381Ssklower 				facil_param_len = 0;
86336381Ssklower 				break;
86436381Ssklower 
86536381Ssklower 				/* 1 octet */
86636381Ssklower 			case 0x0a:  /* min. throughput class negot */
86736381Ssklower 			case 0x02:  /* throughput class */
86836381Ssklower 			case 0x03:  case 0x47:  /* CUG shit */
86936381Ssklower 			case 0x0b:  /* expedited data negot */
87036381Ssklower 			case 0x01:  /* Fast select or reverse charging
87136381Ssklower 						(example of intelligent protocol design) */
87236381Ssklower 			case 0x04: 	/* charging info : requesting service */
87336381Ssklower 			case 0x08: 	/* called line addr modified notification */
87436381Ssklower 				facil_param_len = 1;
87536381Ssklower 				break;
87636381Ssklower 
87736381Ssklower 				/* any 2 octets */
87836381Ssklower 			case 0x42:  /* pkt size */
87936381Ssklower 			case 0x43:  /* win size */
88036381Ssklower 			case 0x44:  /* RPOA basic format */
88136381Ssklower 			case 0x41:  /* bilateral CUG shit */
88236381Ssklower 			case 0x49: 	/* transit delay selection and indication */
88336381Ssklower 				facil_param_len = 2;
88436381Ssklower 				break;
88536381Ssklower 
88636381Ssklower 				/* don't have any 3 octets */
88736381Ssklower 				/*
88836381Ssklower 				facil_param_len = 3;
88936381Ssklower 				*/
89036381Ssklower 			default:
89136381Ssklower 				printf(
89236381Ssklower "BOGUS FACILITY CODE facil_len 0x%x *facil_len 0x%x, ptr 0x%x *ptr 0x%x\n",
893*45899Ssklower 					ptr, facil_len, ptr - 1, ptr[-1]);
89436381Ssklower 				/* facil that we don't handle */
89536381Ssklower 				return E_CO_HLI_REJI;
89636381Ssklower 		}
897*45899Ssklower 		if (facil_param_len == -1)
898*45899Ssklower 			return E_CO_REG_ICDA;
899*45899Ssklower 		if (facil_param_len == 0) /* variable length */
90036381Ssklower 			facil_param_len = (int)*ptr; /* 1 + the real facil param */
90136381Ssklower 		ptr += facil_param_len;
90236381Ssklower 	}
90336381Ssklower 	return 0;
90436381Ssklower }
90536381Ssklower 
906*45899Ssklower #endif TPCONS
907