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