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