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