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