xref: /original-bsd/sys/netiso/if_cons.c (revision de3f5c4e)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)if_cons.c	7.9 (Berkeley) 05/09/91
8  */
9 
10 /***********************************************************
11 		Copyright IBM Corporation 1987
12 
13                       All Rights Reserved
14 
15 Permission to use, copy, modify, and distribute this software and its
16 documentation for any purpose and without fee is hereby granted,
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in
19 supporting documentation, and that the name of IBM not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.
22 
23 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 SOFTWARE.
30 
31 ******************************************************************/
32 
33 /*
34  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
35  */
36 /*
37  * $Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $
38  * $Source: /usr/argo/sys/netiso/RCS/if_cons.c,v $
39  *
40  * cons.c - Connection Oriented Network Service:
41  * including support for a) user transport-level service,
42  *	b) COSNS below CLNP, and c) CONS below TP.
43  */
44 
45 #ifdef TPCONS
46 #ifdef KERNEL
47 #ifdef ARGO_DEBUG
48 #define Static
49 unsigned LAST_CALL_PCB;
50 #else ARGO_DEBUG
51 #define Static static
52 #endif ARGO_DEBUG
53 
54 
55 
56 #ifndef SOCK_STREAM
57 #include "param.h"
58 #include "systm.h"
59 #include "mbuf.h"
60 #include "protosw.h"
61 #include "socket.h"
62 #include "socketvar.h"
63 #include "errno.h"
64 #include "ioctl.h"
65 #include "tsleep.h"
66 
67 #include "../net/if.h"
68 #include "../net/netisr.h"
69 #include "../net/route.h"
70 
71 #include "iso_errno.h"
72 #include "argo_debug.h"
73 #include "tp_trace.h"
74 #include "iso.h"
75 #include "cons.h"
76 #include "iso_pcb.h"
77 
78 #include "../netccitt/x25.h"
79 #include "../netccitt/pk.h"
80 #include "../netccitt/pk_var.h"
81 #endif
82 
83 #ifdef ARGO_DEBUG
84 #define MT_XCONN	0x50
85 #define MT_XCLOSE	0x51
86 #define MT_XCONFIRM	0x52
87 #define MT_XDATA	0x53
88 #define MT_XHEADER	0x54
89 #else
90 #define MT_XCONN	MT_DATA
91 #define MT_XCLOSE	MT_DATA
92 #define MT_XCONFIRM	MT_DATA
93 #define MT_XDATA	MT_DATA
94 #define MT_XHEADER	MT_HEADER
95 #endif ARGO_DEBUG
96 
97 #define DONTCLEAR	 -1
98 
99 /*********************************************************************
100  * cons.c - CONS interface to the x.25 layer
101  *
102  * TODO: figure out what resources we might run out of besides mbufs.
103  *  If we run out of any of them (including mbufs) close and recycle
104  *  lru x% of the connections, for some parameter x.
105  *
106  * There are 2 interfaces from above:
107  * 1) from TP0:
108  *    cons CO network service
109  *    TP associates a transport connection with a network connection.
110  * 	  cons_output( isop, m, len, isdgm==0 )
111  *        co_flags == 0
112  * 2) from TP4:
113  *	  It's a datagram service, like clnp is. - even though it calls
114  *			cons_output( isop, m, len, isdgm==1 )
115  *	  it eventually goes through
116  *			cosns_output(ifp, m, dst).
117  *    TP4 permits multiplexing (reuse, possibly simultaneously) of the
118  *	  network connections.
119  *    This means that many sockets (many tpcbs) may be associated with
120  *    this pklcd, hence cannot have a back ptr from pklcd to a tpcb.
121  *        co_flags & CONSF_DGM
122  *    co_socket is null since there may be many sockets that use this pklcd.
123  *
124 NOTE:
125 	streams would really be nice. sigh.
126 NOTE:
127 	PVCs could be handled by config-ing a cons with an address and with the
128 	IFF_POINTTOPOINT flag on.  This code would then have to skip the
129 	connection setup stuff for pt-to-pt links.
130 
131 
132  *********************************************************************/
133 
134 
135 #define CONS_IFQMAXLEN 5
136 
137 
138 /* protosw pointers for getting to higher layer */
139 Static 	struct protosw	*CLNP_proto;
140 Static 	struct protosw	*TP_proto;
141 Static 	struct protosw	*X25_proto;
142 Static 	int				issue_clear_req();
143 
144 #ifndef	PHASEONE
145 extern	struct ifaddr	*ifa_ifwithnet();
146 #endif	PHASEONE
147 
148 extern	struct ifaddr	*ifa_ifwithaddr();
149 
150 Static  struct socket	dummysocket; /* for use by cosns */
151 
152 extern struct	isopcb	tp_isopcb; /* chain of all TP pcbs */
153 struct	isopcb			tp_incoming_pending;  /* incoming connections
154 										for TP, pending */
155 
156 struct isopcb 	*Xpcblist[] =  {
157 	&tp_incoming_pending,
158 	&tp_isopcb,
159 	(struct isopcb *)0
160 };
161 
162 Static 	int parse_facil(), NSAPtoDTE(), make_partial_x25_packet();
163 Static	int FACILtoNSAP(), DTEtoNSAP();
164 Static	struct pklcd *cons_chan_to_pcb();
165 
166 #define HIGH_NIBBLE 1
167 #define LOW_NIBBLE 0
168 
169 /*
170  * NAME:	nibble_copy()
171  * FUNCTION and ARGUMENTS:
172  * 	copies (len) nibbles from (src_octet), high or low nibble
173  *  to (dst_octet), high or low nibble,
174  * src_nibble & dst_nibble should be:
175  * 	HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble
176  * 	LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble
177  * RETURNS: VOID
178  */
179 void
180 nibble_copy(src_octet, src_nibble, dst_octet, dst_nibble, len)
181 	register char  	*src_octet;
182 	register char  	*dst_octet;
183 	register unsigned		src_nibble;
184 	register unsigned 		dst_nibble;
185 	int		len;
186 {
187 
188 	register 	i;
189 	register 	unsigned dshift, sshift;
190 
191 	IFDEBUG(D_CADDR)
192 		printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n",
193 		 src_octet, src_nibble, dst_octet, dst_nibble, len);
194 	ENDDEBUG
195 #define SHIFT 0x4
196 
197 	dshift = dst_nibble << 2;
198 	sshift = src_nibble << 2;
199 
200 	for (i=0; i<len; i++) {
201 		/* clear dst_nibble  */
202 		*dst_octet 	&= ~(0xf<< dshift);
203 
204 		/* set dst nibble */
205 		*dst_octet 	|= ( 0xf & (*src_octet >> sshift))<< dshift;
206 
207 		dshift		^= SHIFT;
208 		sshift		^= SHIFT;
209 		src_nibble 	= 1-src_nibble;
210 		dst_nibble 	= 1-dst_nibble;
211 		src_octet	+= src_nibble;
212 		dst_octet 	+= dst_nibble;
213 	}
214 	IFDEBUG(D_CADDR)
215 		printf("nibble_copy DONE\n");
216 	ENDDEBUG
217 }
218 
219 /*
220  * NAME:	nibble_match()
221  * FUNCTION and ARGUMENTS:
222  * 	compares src_octet/src_nibble and dst_octet/dst_nibble  for len nibbles.
223  * RETURNS: 0 if they differ, 1 if they are the same.
224  */
225 int
226 nibble_match( src_octet, src_nibble, dst_octet, dst_nibble, len)
227 	register char  	*src_octet;
228 	register char  	*dst_octet;
229 	register unsigned		src_nibble;
230 	register unsigned 		dst_nibble;
231 	int		len;
232 {
233 
234 	register 	i;
235 	register 	unsigned dshift, sshift;
236 	u_char		nibble_a, nibble_b;
237 
238 	IFDEBUG(D_CADDR)
239 		printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n",
240 		 src_octet, src_nibble, dst_octet, dst_nibble, len);
241 	ENDDEBUG
242 #define SHIFT 0x4
243 
244 	dshift = dst_nibble << 2;
245 	sshift = src_nibble << 2;
246 
247 	for (i=0; i<len; i++) {
248 		nibble_b = ((*dst_octet)>>dshift) & 0xf;
249 		nibble_a = ( 0xf & (*src_octet >> sshift));
250 		if (nibble_b != nibble_a)
251 			return 0;
252 
253 		dshift		^= SHIFT;
254 		sshift		^= SHIFT;
255 		src_nibble 	= 1-src_nibble;
256 		dst_nibble 	= 1-dst_nibble;
257 		src_octet	+= src_nibble;
258 		dst_octet 	+= dst_nibble;
259 	}
260 	IFDEBUG(D_CADDR)
261 		printf("nibble_match DONE\n");
262 	ENDDEBUG
263 	return 1;
264 }
265 
266 /*
267  **************************** NET PROTOCOL cons ***************************
268  */
269 /*
270  * NAME:	cons_init()
271  * CALLED FROM:
272  *	autoconf
273  * FUNCTION:
274  *	initialize the protocol
275  */
276 cons_init()
277 {
278 	int tp_incoming(), clnp_incoming();
279 
280 
281 	CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM);
282 	X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM);
283 	TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET);
284 	IFDEBUG(D_CCONS)
285 		printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n",
286 			CLNP_proto, X25_proto, TP_proto);
287 	ENDDEBUG
288 #ifdef notdef
289 	pk_protolisten(0x81, 0, clnp_incoming);
290 	pk_protolisten(0x82, 0, esis_incoming);
291 	pk_protolisten(0x84, 0, tp8878_A_incoming);
292 	pk_protolisten(0, 0, tp_incoming);
293 #endif
294 }
295 
296 tp_incoming(lcp, m0)
297 struct pklcd *lcp;
298 struct mbuf *m0;
299 {
300 	register struct mbuf *m = m0->m_next; /* m0 has calling sockaddr_x25 */
301 	register struct isopcb *isop;
302 	extern struct isopcb tp_isopcb;
303 	int cons_tpinput();
304 
305 	if (iso_pcballoc((struct socket *)0, &tp_incoming_pending)) {
306 		m_freem(m);
307 		pk_clear(lcp);
308 		return;
309 	}
310 	isop = tp_incoming_pending.isop_next;
311 	pk_output(lcp); /* Confirms call */
312 	lcp->lcd_upper = cons_tpinput;
313 	lcp->lcd_upnext = (caddr_t)isop;
314 	isop->isop_chan = (caddr_t)lcp;
315 	isop->isop_laddr = &isop->isop_sladdr;
316 	isop->isop_faddr = &isop->isop_sfaddr;
317 	DTEtoNSAP(isop->isop_laddr, &lcp->lcd_laddr);
318 	DTEtoNSAP(isop->isop_faddr, &lcp->lcd_faddr);
319 	parse_facil(isop, lcp, &(mtod(m, struct x25_packet *)->packet_data),
320 		m->m_pkthdr.len - PKHEADERLN);
321 	m_freem(m);
322 }
323 
324 cons_tpinput(lcp, m0)
325 struct mbuf *m0;
326 struct pklcd *lcp;
327 {
328 	register struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext;
329 	register struct x25_packet *xp;
330 	int cmd;
331 
332 	if (isop == 0)
333 		return;
334 	if (m0 == 0) {
335 		isop->isop_chan = 0;
336 		isop->isop_refcnt = 0;
337 		lcp->lcd_upnext = 0;
338 		lcp->lcd_upper = 0;
339 		goto dead;
340 	}
341 	switch(m0->m_type) {
342 	case MT_DATA:
343 	case MT_OOBDATA:
344 		tpcons_input(m0, isop->isop_faddr, isop->isop_laddr,
345 			(struct socket *)0, (caddr_t)lcp);
346 		return;
347 
348 	case MT_CONTROL:
349 		switch (pk_decode(mtod(m0, struct x25_packet *))) {
350 
351 		case RR:
352 			cmd = PRC_CONS_SEND_DONE;
353 			break;
354 
355 		case CALL_ACCEPTED:
356 			if (lcp->lcd_sb.sb_mb)
357 				lcp->lcd_send(lcp); /* XXX - fix this */
358 			/*FALLTHROUGH*/
359 		default:
360 			return;
361 
362 		dead:
363 		case RESET:
364 		case CLEAR:
365 		case CLEAR_CONF:
366 			cmd = PRC_ROUTEDEAD;
367 		}
368 		tpcons_ctlinput(cmd, isop->isop_faddr, isop);
369 	}
370 }
371 
372 /*
373  * NAME:	cons_connect()
374  * CALLED FROM:
375  *	tpcons_pcbconnect() when opening a new connection.
376  * FUNCTION anD ARGUMENTS:
377  *  Figures out which device to use, finding a route if one doesn't
378  *  already exist.
379  * RETURN VALUE:
380  *  returns E*
381  */
382 cons_connect(isop)
383 	register struct isopcb *isop;
384 {
385 	register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
386 	register struct mbuf 	*m;
387 	struct ifaddr 			*ifa;
388 
389 	IFDEBUG(D_CCONN)
390 		printf("cons_connect(0x%x): ", isop);
391 		dump_isoaddr(isop->isop_faddr);
392 		printf("myaddr: ");
393 		dump_isoaddr(isop->isop_laddr);
394 		printf("\n" );
395 	ENDDEBUG
396 	NSAPtoDTE(isop->isop_faddr, &lcp->lcd_faddr);
397 	lcp->lcd_upper = cons_tpinput;
398 	lcp->lcd_upnext = (caddr_t)isop;
399 	IFDEBUG(D_CCONN)
400 		printf(
401 		"calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x)\n",
402 			&lcp->lcd_faddr, &lcp->lcd_laddr,
403 			isop->isop_socket->so_proto->pr_protocol);
404 	ENDDEBUG
405 	return (make_partial_x25_packet(isop, lcp, m) ||
406 		 pk_connect(lcp, &lcp->lcd_faddr));
407 }
408 
409 /*
410  **************************** DEVICE cons ***************************
411  */
412 
413 
414 /*
415  * NAME:	cons_ctlinput()
416  * CALLED FROM:
417  *  lower layer when ECN_CLEAR occurs : this routine is here
418  *  for consistency - cons subnet service calls its higher layer
419  *  through the protosw entry.
420  * FUNCTION & ARGUMENTS:
421  *  cmd is a PRC_* command, list found in ../sys/protosw.h
422  *  copcb is the obvious.
423  *  This serves the higher-layer cons service.
424  * NOTE: this takes 3rd arg. because cons uses it to inform itself
425  *  of things (timeouts, etc) but has a pcb instead of an address.
426  */
427 cons_ctlinput(cmd, sa, copcb)
428 	int cmd;
429 	struct sockaddr *sa;
430 	register struct pklcd *copcb;
431 {
432 }
433 
434 
435 find_error_reason( xp )
436 	register struct x25_packet *xp;
437 {
438 	extern u_char x25_error_stats[];
439 	int error, cause;
440 
441 	if (xp) {
442 		cause = 4[(char *)xp];
443 		switch (cause) {
444 			case 0x00:
445 			case 0x80:
446 				/* DTE originated; look at the diagnostic */
447 				error = (CONL_ERROR_MASK | cause);
448 				goto done;
449 
450 			case 0x01: /* number busy */
451 			case 0x81:
452 			case 0x09: /* Out of order */
453 			case 0x89:
454 			case 0x11: /* Remot Procedure Error */
455 			case 0x91:
456 			case 0x19: /* reverse charging accept not subscribed */
457 			case 0x99:
458 			case 0x21: /* Incampat destination */
459 			case 0xa1:
460 			case 0x29: /* fast select accept not subscribed */
461 			case 0xa9:
462 			case 0x39: /* ship absent */
463 			case 0xb9:
464 			case 0x03: /* invalid facil request */
465 			case 0x83:
466 			case 0x0b: /* access barred */
467 			case 0x8b:
468 			case 0x13: /* local procedure error */
469 			case 0x93:
470 			case 0x05: /* network congestion */
471 			case 0x85:
472 			case 0x8d: /* not obtainable */
473 			case 0x0d:
474 			case 0x95: /* RPOA out of order */
475 			case 0x15:
476 				/* take out bit 8
477 				 * so we don't have to have so many perror entries
478 				 */
479 				error = (CONL_ERROR_MASK | 0x100 | (cause & ~0x80));
480 				goto done;
481 
482 			case 0xc1: /* gateway-detected proc error */
483 			case 0xc3: /* gateway congestion */
484 
485 				error = (CONL_ERROR_MASK | 0x100 | cause);
486 				goto done;
487 		}
488 	}
489 	/* otherwise, a *hopefully* valid perror exists in the e_reason field */
490 	error = xp->packet_data;
491 	if (error = 0) {
492 		printf("Incoming PKT TYPE 0x%x with reason 0x%x\n",
493 			pk_decode(xp),
494 			cause);
495 		error = E_CO_HLI_DISCA;
496 	}
497 
498 done:
499 	return error;
500 }
501 
502 
503 
504 #endif KERNEL
505 
506 /*
507  * NAME:	make_partial_x25_packet()
508  *
509  * FUNCTION and ARGUMENTS:
510  *	Makes part of an X.25 call packet, for use by x25.
511  *  (src) and (dst) are the NSAP-addresses of source and destination.
512  *	(buf) is a ptr to a buffer into which to write this partial header.
513  *
514  *	 0			Facility length (in octets)
515  *	 1			Facility field, which is a set of:
516  *	  m			facil code
517  *	  m+1		facil param len (for >2-byte facilities) in octets
518  *	  m+2..p	facil param field
519  *  q			user data (protocol identification octet)
520  *
521  *
522  * RETURNS:
523  *  0 if OK
524  *  E* if failed.
525  *
526  * SIDE EFFECTS:
527  * Stores facilites mbuf in X.25 control block, where the connect
528  * routine knows where to look for it.
529  */
530 
531 #ifdef X25_1984
532 int cons_use_facils = 1;
533 #else X25_1984
534 int cons_use_facils = 0;
535 #endif X25_1984
536 
537 int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */
538 
539 Static int
540 make_partial_x25_packet(isop, lcp)
541 	struct isopcb *isop;
542 	struct pklcd *lcp;
543 {
544 	u_int				proto;
545 	int					flag;
546 	caddr_t 			buf;
547 	register caddr_t	ptr;
548 	register int		len	= 0;
549 	int 				buflen	=0;
550 	caddr_t				facil_len;
551 	int 				oddness	= 0;
552 	struct mbuf *m;
553 
554 
555 	IFDEBUG(D_CCONN)
556 		printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
557 			isop->isop_laddr, isop->isop_faddr, proto, m, flag);
558 	ENDDEBUG
559 	if (cons_use_udata) {
560 		if (isop->isop_x25crud_len > 0) {
561 			/*
562 			 *	The user specified something. Stick it in
563 			 */
564 			bcopy(isop->isop_x25crud, lcp->lcd_faddr.x25_udata,
565 					isop->isop_x25crud_len);
566 			lcp->lcd_faddr.x25_udlen = isop->isop_x25crud_len;
567 		}
568 	}
569 
570 	if (cons_use_facils == 0) {
571 		lcp->lcd_facilities = 0;
572 		return 0;
573 	}
574 	MGET(m, MT_DATA, M_WAITOK);
575 	if (m == 0)
576 		return ENOBUFS;
577 	buf = mtod(m, caddr_t);
578 	ptr = buf;
579 
580 	/* ptr now points to facil length (len of whole facil field in OCTETS */
581 	facil_len = ptr ++;
582 
583 	IFDEBUG(D_CADDR)
584 		printf("make_partial  calling: ptr 0x%x, len 0x%x\n", ptr,
585 				isop->isop_laddr->siso_addr.isoa_len);
586 	ENDDEBUG
587 	if (cons_use_facils) {
588 		*ptr = 0xcb; /* calling facility code */
589 		ptr ++;
590 		ptr ++; /* leave room for facil param len (in OCTETS + 1) */
591 		ptr ++; /* leave room for the facil param len (in nibbles),
592 				* high two bits of which indicate full/partial NSAP
593 				*/
594 		len = isop->isop_laddr->siso_addr.isoa_len;
595 		bcopy( isop->isop_laddr->siso_data, ptr, len);
596 		*(ptr-2) = len+1; /* facil param len in octets */
597 		*(ptr-1) = len<<1; /* facil param len in nibbles */
598 		ptr += len;
599 
600 		IFDEBUG(D_CADDR)
601 			printf("make_partial  called: ptr 0x%x, len 0x%x\n", ptr,
602 					isop->isop_faddr->siso_addr.isoa_len);
603 		ENDDEBUG
604 		*ptr = 0xc9; /* called facility code */
605 		ptr ++;
606 		ptr ++; /* leave room for facil param len (in OCTETS + 1) */
607 		ptr ++; /* leave room for the facil param len (in nibbles),
608 				* high two bits of which indicate full/partial NSAP
609 				*/
610 		len = isop->isop_faddr->siso_nlen;
611 		bcopy(isop->isop_faddr->siso_data, ptr, len);
612 		*(ptr-2) = len+1; /* facil param len = addr len + 1 for each of these
613 						  * two length fields, in octets */
614 		*(ptr-1) = len<<1; /* facil param len in nibbles */
615 		ptr += len;
616 
617 	}
618 	*facil_len = ptr - facil_len - 1;
619 	if (*facil_len > MAX_FACILITIES)
620 		return E_CO_PNA_LONG;
621 
622 	buflen = (int)(ptr - buf);
623 
624 	IFDEBUG(D_CDUMP_REQ)
625 		register int i;
626 
627 		printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n",
628 			buf, buflen, buflen);
629 		for( i=0; i < buflen; ) {
630 			printf("+%d: %x %x %x %x    %x %x %x %x\n",
631 				i,
632 				*(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3),
633 				*(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7));
634 			i+=8;
635 		}
636 	ENDDEBUG
637 	IFDEBUG(D_CADDR)
638 		printf("make_partial returns buf 0x%x size 0x%x bytes\n",
639 			mtod(m, caddr_t), buflen);
640 	ENDDEBUG
641 
642 	if (buflen > MHLEN)
643 		return E_CO_PNA_LONG;
644 
645 	m->m_len = buflen;
646 	lcp->lcd_facilities = m;
647 	return  0;
648 }
649 
650 /*
651  * NAME:	NSAPtoDTE()
652  * CALLED FROM:
653  *  make_partial_x25_packet()
654  * FUNCTION and ARGUMENTS:
655  *  get a DTE address from an NSAP-address (struct sockaddr_iso)
656  *  (dst_octet) is the octet into which to begin stashing the DTE addr
657  *  (dst_nibble) takes 0 or 1.  1 means begin filling in the DTE addr
658  * 		in the high-order nibble of dst_octet.  0 means low-order nibble.
659  *  (addr) is the NSAP-address
660  *  (flag) is true if the transport suffix is to become the
661  *		last two digits of the DTE address
662  *  A DTE address is a series of ASCII digits
663  *
664  *	A DTE address may have leading zeros. The are significant.
665  *		1 digit per nibble, may be an odd number of nibbles.
666  *
667  *  An NSAP-address has the DTE address in the IDI. Leading zeros are
668  *		significant. Trailing hex f indicates the end of the DTE address.
669  *  	The IDI is a series of BCD digits, one per nibble.
670  *
671  * RETURNS
672  *  # significant digits in the DTE address, -1 if error.
673  */
674 
675 Static int
676 NSAPtoDTE(siso, sx25)
677 	register struct sockaddr_iso *siso;
678 	register struct sockaddr_x25 *sx25;
679 {
680 	int		dtelen = -1;
681 
682 	IFDEBUG(D_CADDR)
683 		printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&siso->siso_addr));
684 	ENDDEBUG
685 
686 	if (siso->siso_data[0] == AFI_37) {
687 		register char *out = sx25->x25_addr;
688 		register char *in = siso->siso_data + 1;
689 		register int nibble;
690 		char *lim = siso->siso_data + siso->siso_nlen;
691 		char *olim = out+15;
692 		int lowNibble = 0;
693 
694 		while (in < lim) {
695 			nibble = ((lowNibble ? *in++ : (*in >> 4)) & 0xf) | 0x30;
696 			lowNibble ^= 1;
697 			if (nibble != 0x3f && out < olim)
698 				*out++ = nibble;
699 		}
700 		dtelen = out - sx25->x25_addr;
701 		*out++ = 0;
702 	} else {
703 		register struct rtentry *rt = rtalloc1(siso, 1);
704 		/* error = iso_8208snparesolve(addr, x121string, &x121strlen);*/
705 
706 		if (rt) {
707 			register struct sockaddr_x25 *sxx =
708 							(struct sockaddr_x25 *)rt->rt_gateway;
709 			register char *in = sxx->x25_addr;
710 
711 			rt->rt_use--;
712 			if (sxx && sxx->x25_family == AF_CCITT) {
713 				bcopy(sx25->x25_addr, sxx->x25_addr, sizeof(sx25->x25_addr));
714 				while (*in++) {}
715 				dtelen = in - sxx->x25_addr;
716 			}
717 		}
718 	}
719 	return dtelen;
720 }
721 
722 /*
723  * NAME:	FACILtoNSAP()
724  * CALLED FROM:
725  *  parse_facil()
726  * FUNCTION and ARGUMENTS:
727  * 	Creates and NSAP in the sockaddr_iso (addr) from the
728  *  x.25 facility found at buf - 1.
729  * RETURNS:
730  *  length of parameter if ok, -1 if error.
731  */
732 
733 Static int
734 FACILtoNSAP(addr, buf)
735 	u_char 		*buf;
736 	register struct sockaddr_iso *addr;
737 {
738 	int len_in_nibbles, param_len = *buf++;
739 	u_char			buf_len; /* in bytes */
740 
741 	IFDEBUG(D_CADDR)
742 		printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n",
743 			buf, buf_len, addr );
744 	ENDDEBUG
745 
746 	len_in_nibbles = *buf & 0x3f;
747 	buf_len = (len_in_nibbles + 1) >> 1;
748 	/* despite the fact that X.25 makes us put a length in nibbles
749 	 * here, the NSAP-addrs are always in full octets
750 	 */
751 	switch (*buf++ & 0xc0) {
752 	case 0:
753 		/* Entire OSI NSAP address */
754 		bcopy((caddr_t)buf, addr->siso_data, addr->siso_nlen = buf_len);
755 		break;
756 
757 	case 40:
758 		/* Partial OSI NSAP address, assume trailing */
759 		if (buf_len + addr->siso_nlen > sizeof(addr->siso_addr))
760 			return -1;
761 		bcopy((caddr_t)buf, TSEL(addr), buf_len);
762 		addr->siso_nlen += buf_len;
763 		break;
764 
765 	default:
766 		/* Rather than blow away the connection, just ignore and use
767 		   NSAP from DTE */;
768 	}
769 	return param_len;
770 }
771 
772 static
773 init_siso(siso)
774 register struct sockaddr_iso *siso;
775 {
776 	siso->siso_len = sizeof (*siso);
777 	siso->siso_family = AF_ISO;
778 	siso->siso_data[0] = AFI_37;
779 	siso->siso_nlen = 8;
780 }
781 
782 /*
783  * NAME:	DTEtoNSAP()
784  * CALLED FROM:
785  *  parse_facil()
786  * FUNCTION and ARGUMENTS:
787  *  Creates a type 37 NSAP in the sockaddr_iso (addr)
788  * 	from a DTE address found in a sockaddr_x25.
789  *
790  * RETURNS:
791  *  0 if ok; E* otherwise.
792  */
793 
794 Static  int
795 DTEtoNSAP(addr, sx)
796 	struct sockaddr_iso *addr;
797 	struct sockaddr_x25 *sx;
798 {
799 	register char		*in, *out;
800 	register int		first;
801 	int					pad_tail = 0;
802 	int 				src_len;
803 
804 
805 	init_siso(addr);
806 	src_len = strlen(sx->x25_addr);
807 	in = sx->x25_addr;
808 	out = addr->siso_data + 1;
809 	if (*in == '0' && (src_len & 1 == 0)) {
810 		pad_tail = 0xf;
811 		src_len++;
812 	}
813 	for (first = 0; src_len > 0; src_len --) {
814 		first |= *in++;
815 		if (src_len & 1) {
816 			*out++ = first;
817 			first = 0;
818 		}
819 		else first <<= 4;
820 	}
821 	if (pad_tail)
822 		out[-1] |= 0xf;
823 	return 0; /* ok */
824 }
825 
826 /*
827  * FUNCTION and ARGUMENTS:
828  *	parses (buf_len) bytes beginning at (buf) and finds
829  *  a called nsap, a calling nsap, and protocol identifier.
830  * RETURNS:
831  *  0 if ok, E* otherwise.
832  */
833 
834 static int
835 parse_facil(lcp, isop, buf, buf_len)
836 	caddr_t 		buf;
837 	u_char			buf_len; /* in bytes */
838 	struct			isopcb *isop;
839 	struct			pklcd *lcp;
840 {
841 	register struct sockaddr_iso *called = isop->isop_laddr;
842 	register struct sockaddr_iso *calling = isop->isop_faddr;
843 	register int 	i;
844 	register u_char 	*ptr = (u_char *)buf;
845 	u_char			*ptr_lim, *facil_lim;
846 	int 			facil_param_len, facil_len;
847 
848 	IFDEBUG(D_CADDR)
849 		printf("parse_facil(0x%x, 0x%x, 0x%x, 0x%x)\n",
850 			buf, buf_len, called, calling);
851 		dump_buf(buf, buf_len);
852 	ENDDEBUG
853 
854 	/* find the beginnings of the facility fields in buf
855 	 * by skipping over the called & calling DTE addresses
856 	 * i <- # nibbles in called + # nibbles in calling
857 	 * i += 1 so that an odd nibble gets rounded up to even
858 	 * before dividing by 2, then divide by two to get # octets
859 	 */
860 	i = (int)(*ptr >> 4) + (int)(*ptr&0xf);
861 	i++;
862 	ptr += i >> 1;
863 	ptr ++; /* plus one for the DTE lengths byte */
864 
865 	/* ptr now is at facil_length field */
866 	facil_len = *ptr++;
867 	facil_lim = ptr + facil_len;
868 	IFDEBUG(D_CADDR)
869 		printf("parse_facils: facil length is  0x%x\n", (int) facil_len);
870 	ENDDEBUG
871 
872 	while (ptr <= facil_lim) {
873 		/* get NSAP addresses from facilities */
874 		switch (*ptr++) {
875 			case 0xcb:
876 				/* calling NSAP */
877 				facil_param_len = FACILtoNSAP(isop->isop_faddr, ptr);
878 				break;
879 			case 0xc9:
880 				/* called NSAP */
881 				facil_param_len = FACILtoNSAP(isop->isop_laddr, ptr);
882 				break;
883 
884 				/* from here to default are legit cases that I ignore */
885 				/* variable length */
886 			case 0xca:  /* end-to-end transit delay negot */
887 			case 0xc6:  /* network user id */
888 			case 0xc5: 	/* charging info : indicating monetary unit */
889 			case 0xc2: 	/* charging info : indicating segment count */
890 			case 0xc1: 	/* charging info : indicating call duration */
891 			case 0xc4: 	/* RPOA extended format */
892 			case 0xc3: 	/* call redirection notification */
893 				facil_param_len = 0;
894 				break;
895 
896 				/* 1 octet */
897 			case 0x0a:  /* min. throughput class negot */
898 			case 0x02:  /* throughput class */
899 			case 0x03:  case 0x47:  /* CUG shit */
900 			case 0x0b:  /* expedited data negot */
901 			case 0x01:  /* Fast select or reverse charging
902 						(example of intelligent protocol design) */
903 			case 0x04: 	/* charging info : requesting service */
904 			case 0x08: 	/* called line addr modified notification */
905 				facil_param_len = 1;
906 				break;
907 
908 				/* any 2 octets */
909 			case 0x42:  /* pkt size */
910 			case 0x43:  /* win size */
911 			case 0x44:  /* RPOA basic format */
912 			case 0x41:  /* bilateral CUG shit */
913 			case 0x49: 	/* transit delay selection and indication */
914 				facil_param_len = 2;
915 				break;
916 
917 				/* don't have any 3 octets */
918 				/*
919 				facil_param_len = 3;
920 				*/
921 			default:
922 				printf(
923 "BOGUS FACILITY CODE facil_len 0x%x *facil_len 0x%x, ptr 0x%x *ptr 0x%x\n",
924 					ptr, facil_len, ptr - 1, ptr[-1]);
925 				/* facil that we don't handle */
926 				return E_CO_HLI_REJI;
927 		}
928 		if (facil_param_len == -1)
929 			return E_CO_REG_ICDA;
930 		if (facil_param_len == 0) /* variable length */
931 			facil_param_len = (int)*ptr; /* 1 + the real facil param */
932 		ptr += facil_param_len;
933 	}
934 	return 0;
935 }
936 
937 #endif TPCONS
938