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