xref: /csrg-svn/sys/netiso/if_cons.c (revision 40783)
1 /***********************************************************
2 		Copyright IBM Corporation 1987
3 
4                       All Rights Reserved
5 
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted,
8 provided that the above copyright notice appear in all copies and that
9 both that copyright notice and this permission notice appear in
10 supporting documentation, and that the name of IBM not be
11 used in advertising or publicity pertaining to distribution of the
12 software without specific, written prior permission.
13 
14 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 SOFTWARE.
21 
22 ******************************************************************/
23 
24 /*
25  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26  */
27 /*
28  * $Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $
29  * $Source: /usr/argo/sys/netiso/RCS/if_cons.c,v $
30  *
31  * cons.c - Connection Oriented Network Service:
32  * including support for a) user transport-level service,
33  *	b) COSNS below CLNP, and c) CONS below TP.
34  */
35 
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 #ifdef ARGO_DEBUG
41 #define Static
42 unsigned LAST_CALL_PCB;
43 #else ARGO_DEBUG
44 #define Static static
45 #endif ARGO_DEBUG
46 
47 #include "ecn.h"
48 #include "argoxtwentyfive.h"
49 
50 #if NARGOXTWENTYFIVE > 0
51 
52 #ifdef KERNEL
53 
54 #include "param.h"
55 #include "systm.h"
56 #include "mbuf.h"
57 #include "protosw.h"
58 #include "socket.h"
59 #include "socketvar.h"
60 #include "errno.h"
61 #include "ioctl.h"
62 #include "tsleep.h"
63 
64 #include "../net/if.h"
65 #include "../net/netisr.h"
66 #include "../net/route.h"
67 
68 #include "../netiso/iso_errno.h"
69 #include "../netiso/argo_debug.h"
70 #include "../netiso/tp_trace.h"
71 #include "../netiso/iso.h"
72 #include "../netiso/cons.h"
73 #include "../netiso/iso_pcb.h"
74 #include "../netiso/cons_pcb.h"
75 #include "../caif/eicon.h"
76 
77 #ifdef ARGO_DEBUG
78 #define MT_XCONN	0x50
79 #define MT_XCLOSE	0x51
80 #define MT_XCONFIRM	0x52
81 #define MT_XDATA	0x53
82 #define MT_XHEADER	0x54
83 #else
84 #define MT_XCONN	MT_DATA
85 #define MT_XCLOSE	MT_DATA
86 #define MT_XCONFIRM	MT_DATA
87 #define MT_XDATA	MT_DATA
88 #define MT_XHEADER	MT_HEADER
89 #endif ARGO_DEBUG
90 
91 #define DONTCLEAR	 -1
92 
93 /*********************************************************************
94  * cons.c - CONS interface to the eicon adapter
95  * Includes connection manager - for (TP, CLNP)/x.25
96  *
97  * TODO: figure out what resources we might run out of besides mbufs.
98  *  If we run out of any of them (including mbufs) close and recycle
99  *  lru x% of the connections, for some parameter x.
100  *
101  * There are 4 interfaces from above:
102  * 0) from CLNP:
103  *    cons is an interface driver - CLNP calls
104  *    cosns_output(ifp, m, dst), a device-type interface output routine
105  *    that does some connection management stuff and queues a
106  *    request on the eicon driver queue by calling ifp->if_output.
107  *    The eicon's ifp structure contains cosns_output as its output routine
108  *    rather than ifp_>if_output! Kludge, but we don't have much choice...
109  *    X25 connections created in this manner may always be multiplexed
110  *    but only with their own kind (not with connections servicing TP
111  *    directly.)
112  *	  	co_flags & CONSF_DGM
113  * 1) from TP0:
114  *    cons CO network service
115  *    TP associates a transport connection with a network connection.
116  * 	  cons_output( isop, m, len, isdgm==0 )
117  *        co_flags == 0
118  * 2) from TP 4:
119  *	  It's a datagram service, like clnp is. - even though it calls
120  *			cons_output( isop, m, len, isdgm==1 )
121  *	  it eventually goes through
122  *			cosns_output(ifp, m, dst).
123  *    TP4 permits multiplexing (reuse, possibly simultaneously) of the
124  *	  network connections.
125  *    This means that many sockets (many tpcbs) may be associated with
126  *    this cons_pcb, hence cannot have a back ptr from cons_pcb to a tpcb.
127  *        co_flags & CONSF_DGM
128  *    co_socket is null since there may be many sockets that use this copcb.
129  * 3) from user: cons_usrreq(), cons_ctloutput()
130  *    cons is a standard transport service interface.
131  *    There is a 1-1 correspondence between net connections and sockets.
132  *	  co_socket points to a socket.
133  *
134 NOTE:
135 	streams would really be nice. sigh.
136 NOTE:
137 	eicon <--> cons interface: the first mbuf (the ecn_request structure)
138 	had better NOT be a cluster.
139 NOTE:
140 	PVCs could be handled by config-ing a cons with an address and with the
141 	IFF_POINTTOPOINT flag on.  This code would then have to skip the
142 	connection setup stuff for pt-to-pt links.
143 NOTE:
144 	We keep track of the ifp for each connection.  Right now this is
145 	unnecessary, but just in case someone comes up with some kind
146 	of a kludge to allow > 1 eicon to be attached at a time,
147 	(i.e., some meaningful netof( a type 37 address ) ),
148 	we do keep track of this.
149 
150 
151  *********************************************************************/
152 
153 #define touch(copcb) copcb->co_ttl = copcb->co_init_ttl
154 
155 #define CONS_IFQMAXLEN 5
156 
157 #define SET_CHANMASK( isop, chan )\
158 	if( (u_int)(chan) < 32 ) \
159 		(isop)->isop_chanmask = (1<<((chan)-1));\
160 	else \
161 		(isop)->isop_negchanmask = (1<<((256-(chan))-1))
162 
163 #define ADD_CHANMASK( isop, chan )\
164 	if( (u_int)(chan) < 32 ) \
165 		(isop)->isop_chanmask |= (1<<((chan)-1));\
166 	else \
167 		(isop)->isop_negchanmask |= (1<<((256-(chan))-1))
168 
169 struct ifnet 			*consif; /* TO BE REMOVED */
170 Static int				consinit(), consioctl(), consattach();
171 
172 /* protosw pointers for getting to higher layer */
173 Static 	struct protosw	*CLNP_proto;
174 Static 	struct protosw	*TP_proto;
175 Static 	struct protosw	*X25_proto;
176 Static 	int				issue_clear_req();
177 
178 #ifndef	PHASEONE
179 extern	struct ifaddr	*ifa_ifwithnet();
180 #endif	PHASEONE
181 
182 extern	struct ifaddr	*ifa_ifwithaddr();
183 
184 Static  struct socket	dummysocket; /* for use by cosns */
185 
186 extern struct	isopcb	tp_isopcb; /* chain of all TP pcbs */
187 struct	isopcb			cons_isopcb; /* chain of all cons pcbs */
188 struct	isopcb			tp_incoming_pending;  /* incoming connections
189 										for TP, pending */
190 
191 struct isopcb 	*Xpcblist[] =  {
192 	&cons_isopcb,
193 	&tp_incoming_pending,
194 	&tp_isopcb,
195 	(struct isopcb *)0
196 };
197 
198 Static 	int parse_facil(), NSAPtoDTE(), make_partial_x25_packet();
199 Static	int FACILtoNSAP(), DTEtoNSAP();
200 Static	struct cons_pcb *cons_chan_to_pcb();
201 
202 #define HIGH_NIBBLE 1
203 #define LOW_NIBBLE 0
204 
205 /*
206  * NAME:	nibble_copy()
207  * FUNCTION and ARGUMENTS:
208  * 	copies (len) nibbles from (src_octet), high or low nibble
209  *  to (dst_octet), high or low nibble,
210  * src_nibble & dst_nibble should be:
211  * 	HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble
212  * 	LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble
213  * RETURNS: VOID
214  */
215 void
216 nibble_copy( src_octet, src_nibble, dst_octet, dst_nibble, len)
217 	register char  	*src_octet;
218 	register char  	*dst_octet;
219 	register unsigned		src_nibble;
220 	register unsigned 		dst_nibble;
221 	int		len;
222 {
223 
224 	register 	i;
225 	register 	unsigned dshift, sshift;
226 
227 	IFDEBUG(D_CADDR)
228 		printf("nibble_copy ( 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 		/* clear dst_nibble  */
238 		*dst_octet 	&= ~(0xf<< dshift);
239 
240 		/* set dst nibble */
241 		*dst_octet 	|= ( 0xf & (*src_octet >> sshift))<< dshift;
242 
243 		dshift		^= SHIFT;
244 		sshift		^= SHIFT;
245 		src_nibble 	= 1-src_nibble;
246 		dst_nibble 	= 1-dst_nibble;
247 		src_octet	+= src_nibble;
248 		dst_octet 	+= dst_nibble;
249 	}
250 	IFDEBUG(D_CADDR)
251 		printf("nibble_copy DONE\n");
252 	ENDDEBUG
253 }
254 
255 /*
256  * NAME:	nibble_match()
257  * FUNCTION and ARGUMENTS:
258  * 	compares src_octet/src_nibble and dst_octet/dst_nibble  for len nibbles.
259  * RETURNS: 0 if they differ, 1 if they are the same.
260  */
261 int
262 nibble_match( src_octet, src_nibble, dst_octet, dst_nibble, len)
263 	register char  	*src_octet;
264 	register char  	*dst_octet;
265 	register unsigned		src_nibble;
266 	register unsigned 		dst_nibble;
267 	int		len;
268 {
269 
270 	register 	i;
271 	register 	unsigned dshift, sshift;
272 	u_char		nibble_a, nibble_b;
273 
274 	IFDEBUG(D_CADDR)
275 		printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n",
276 		 src_octet, src_nibble, dst_octet, dst_nibble, len);
277 	ENDDEBUG
278 #define SHIFT 0x4
279 
280 	dshift = dst_nibble << 2;
281 	sshift = src_nibble << 2;
282 
283 	for (i=0; i<len; i++) {
284 		nibble_b = ((*dst_octet)>>dshift) & 0xf;
285 		nibble_a = ( 0xf & (*src_octet >> sshift));
286 		if( nibble_b != nibble_a )
287 			return 0;
288 
289 		dshift		^= SHIFT;
290 		sshift		^= SHIFT;
291 		src_nibble 	= 1-src_nibble;
292 		dst_nibble 	= 1-dst_nibble;
293 		src_octet	+= src_nibble;
294 		dst_octet 	+= dst_nibble;
295 	}
296 	IFDEBUG(D_CADDR)
297 		printf("nibble_match DONE\n");
298 	ENDDEBUG
299 	return 1;
300 }
301 
302 #ifdef ARGO_DEBUG
303 
304 Static
305 dump_copcb(copcb, str)
306 	char * str;
307 	register struct cons_pcb *copcb;
308 {
309 	printf("XPCB DUMP %s\n", str);
310 	if (copcb) {
311 		printf("\t copcb 0x%x next 0x%x head 0x%x socket 0x%x ifp 0x%x\n",
312 			copcb, copcb->co_next, copcb->co_head, copcb->co_socket, copcb->co_ifp);
313 		printf("\t channel 0x%x state 0x%x flags 0x%x proto 0x%x\n",
314 			copcb->co_channel, copcb->co_state, copcb->co_flags, copcb->co_proto);
315 		printf("\t laddr :\n");
316 		dump_isoaddr(&copcb->co_laddr);
317 		printf("\t faddr :\n");
318 		dump_isoaddr(&copcb->co_faddr);
319 		printf("\tttl 0x%x init_ttl 0x%x pending: %d\n",
320 			copcb->co_ttl, copcb->co_init_ttl, copcb->co_pending.ifq_len);
321 	}
322 	printf("END DUMP\n");
323 }
324 #endif ARGO_DEBUG
325 
326 /*
327  * FUNCTION : choose_output - chooses between the eicon and loopback.
328  * This MUST be here because the ifp->if_output routine is cosns_output
329  * -- due to our need to look like a device driver for CLNP. sigh.
330  * ARGUMENTS & PURPOSE:  (copcb) ptr to a protocol control block for
331  *			x.25, (m) is an mbuf ptr. *m is a request destined either
332  * 			for the eicon driver or for the loopback driver.
333  * RETURNS : whatever error value the 2I or loopback returns.
334  */
335 Static int
336 choose_output( ifp, m, loop)
337 	struct ifnet 	*ifp;
338 	struct mbuf 	*m;
339 	int				loop;
340 {
341 	int error;
342 
343 	if( !m )
344 		return 0;
345 	ASSERT(m->m_len != 0);
346 	if( loop != 0)
347 		error = lpboutput( ifp, m );
348 	else
349 		error = ecnoutput( ifp,  m );
350 
351 	if (error == 0)
352 		ifp->if_opackets ++;
353 	else {
354 		ifp->if_oerrors ++;
355 		IFTRACE(D_CDATA)
356 			tptrace( TPPTmisc,
357 			"choose_output: ifp  m error loop\n",
358 				ifp, m, error, loop);
359 		ENDTRACE
360 	}
361 	IFDEBUG(D_CCONS)
362 		printf("choose_output returns 0x%x\n", error );
363 	ENDDEBUG
364 	return error;
365 }
366 
367 /*
368  **************************** NET PROTOCOL cons ***************************
369  */
370 
371 /*
372  * NAME:	cons_init()
373  * CALLED FROM:
374  *	autoconf
375  * FUNCTION:
376  *	initialize the protocol
377  */
378 cons_init()
379 {
380 	init_lpb();
381 	consattach();
382 
383 	/* protocol init stuff */
384 
385 	consintrq.ifq_maxlen = IFQ_MAXLEN;
386 	consintrq.ifq_head = consintrq.ifq_tail =  (struct mbuf *)0;
387 
388 	CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM);
389 	X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM);
390 	TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET);
391 	IFDEBUG(D_CCONS)
392 		printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n",
393 			CLNP_proto, X25_proto, TP_proto);
394 	ENDDEBUG
395 
396 	cons_isopcb.isop_next = cons_isopcb.isop_prev = &cons_isopcb;
397 	tp_incoming_pending.isop_next = tp_incoming_pending.isop_prev =
398 			&tp_incoming_pending;
399 }
400 
401 #ifdef notdef
402 
403 /*
404  * NAME:	cons_free_lru()
405  * some day CALLED FROM:
406  * 	wherever we run out of mbufs (not used right yet)
407  * FUNCTION:
408  *	get rid of the num least recently used connections and
409  *  recycle their mbufs.
410  * NOTE: GROTESQUELY INEFFICIENT needs to be written nicely
411  */
412 
413 Static
414 cons_free_lru(qty)
415 	int qty;
416 {
417 	register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist;
418 	register struct cons_pcb *copcb;
419 	struct cons_pcb 			Lru;
420 	struct cons_pcb 			*lru;
421 
422 	IFDEBUG(D_CCONS)
423 		printf("cons_free_lru( 0x%x )\n", qty);
424 	ENDDEBUG
425 
426 	Lru.co_ttl = X25_TTL;
427 	lru = &Lru;
428 
429 	while (qty > 1) { /* GROT */
430 		cons_free_lru( 1 );
431 		qty -- ;
432 	}
433 
434 	for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) {
435 		copcb = (struct cons_pcb *)copcb->co_next;
436 		while (copcb !=  *copcblist) {
437 			if( copcb->co_ttl < lru->co_ttl )
438 				lru = copcb;
439 			copcb = (struct cons_pcb *)copcb->co_next;
440 		}
441 	}
442 
443 	if(lru->co_socket) {
444 		soisdisconnected(lru->co_socket);
445 		sohasoutofband(lru->co_socket); /* signal */
446 	}
447 
448 	cons_clear_and_detach( lru, E_CO_HLI_RESYNC, PRC_TIMXCEED_REASS);
449 }
450 #endif notdef
451 
452 /*
453  * NAME:	cons_slowtimo()
454  * CALLED FROM:
455  * 	the clock
456  * FUNCTION:
457  *	get rid of any timed-out cons connections
458  *  cons connections get "touched" with every use, meaning the
459  *  time-to-live gets reset to its max value w/ every use.
460  *  The slowtimo() rtn decrements the time-to-live for each
461  *  cons connection.  If one of them hits zero ---> zap the connection.
462  *  This really only applies to those used for CLNP and TP4.
463  *  TP4 keeps the connections open with keepalive.
464  * TODO:
465  *  Have this happen ONLY for international connections since
466  *  there's no connect time charge for domestic calls.
467  *  Make default 5 min; make a user option to change it.
468  * TODO:
469  *  Maybe if the ttl gets lower than a certain threshold, move this
470  *  copcb to the END of its queue so it doesn't slow down the others.
471  */
472 
473 cons_slowtimo()
474 {
475 	register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist;
476 	register struct cons_pcb *copcb;
477 	int s = splnet();
478 	int	qlen = 0;
479 	int qdrops = 0;
480 	int	nvisited = 0;
481 
482 #ifdef ARGO_DEBUG
483 	Static int count;
484 
485 	count = 0;
486 #endif ARGO_DEBUG
487 
488 	IncStat(co_slowtimo);
489 	for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) {
490 #ifdef ARGO_DEBUG
491 		if( copcb == (struct cons_pcb *)0 ) {
492 			ASSERT( 0 );
493 			panic("TURNING OFF cons_slowtimo()!!! \n");
494 		}
495 #endif ARGO_DEBUG
496 		copcb = (struct cons_pcb *)copcb->co_next;
497 		while (copcb !=  *copcblist) {
498 #ifdef ARGO_DEBUG
499 			if(++count >50 ) {
500 				printf("cons PANIC: slowtimo LOOP\n");
501 				splx(s);
502 				return;
503 			}
504 #endif ARGO_DEBUG
505 #ifdef notdef
506 			if( copcb->co_init_ttl == 0 ) {
507 	ASSERT( (struct isopcb *)(*copcblist)==(struct isopcb *)&tp_isopcb );
508 				copcb = (struct cons_pcb *)copcb->co_next;
509 				continue;
510 			}
511 #endif notdef
512 			nvisited ++;
513 			ASSERT( copcb != (struct cons_pcb *)0 );
514 			qlen += copcb->co_pending.ifq_len;
515 			qdrops += copcb->co_pending.ifq_drops;
516 
517 			if( copcb->co_socket) {
518 				/* don't want XTS, TP0 connections to be subject to time out */
519 				copcb = (struct cons_pcb *)copcb->co_next;
520 				continue;
521 			}
522 
523 			if( -- (copcb->co_ttl) > 0 )  {
524 				copcb = (struct cons_pcb *)copcb->co_next;
525 				continue;
526 			}
527 
528 			IncStat(co_timedout);
529 
530 			IFDEBUG(D_CCONN)
531 				printf("TIMING OUT chan 0x%x copcb 0x%x flags 0x%x\n",
532 					copcb->co_channel, copcb, copcb->co_flags );
533 			ENDDEBUG
534 
535 			{
536 				register struct cons_pcb * next =
537 					(struct cons_pcb *)copcb->co_next;
538 				cons_clear_and_detach(copcb,
539 						E_CO_HLI_RESYNC, PRC_TIMXCEED_REASS);
540 				copcb = next;
541 			}
542 		}
543 	}
544 	if(nvisited) {
545 		cons_stat.co_avg_qlen = qlen / nvisited;
546 		cons_stat.co_avg_qdrop = qdrops / nvisited;
547 		cons_stat.co_active = nvisited;
548 	}
549 done:
550 	splx(s);
551 }
552 
553 DUMP_PCBLIST()
554 {
555 	register int i=0;
556 	register struct cons_pcb *copcb;
557 	register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist;
558 
559 	for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) {
560 		printf("FOR %d: 0x%x ", ++i, copcb);
561 		copcb = (struct cons_pcb *)copcb->co_next;
562 		printf(" next 0x%x, *copcblist 0x%x\n",  copcb, *copcblist);
563 		while (copcb !=  *copcblist) {
564 			ASSERT( copcb != (struct cons_pcb *)0 );
565 			printf("\tCOPCB 0x%x\n", copcb);
566 			if( copcb )
567 				dump_buf(copcb, sizeof( *copcb));
568 			else
569 				break;
570 			copcb = (struct cons_pcb *)copcb->co_next;
571 		}
572 	}
573 }
574 
575 /*
576  * NAME:	cons_pcballoc()
577  * CALLED FROM:
578  *	cons_usrreq() when doing PRU_ATTACH,
579  *  cons_incoming() when opening a new connection.
580  * FUNCTION and ARGUMENTS:
581  *	Allocates a new pcb.
582  *  The flags and proto arguments are stashed into the new pcb.
583  * RETURN VALUE:
584  *  E* if error, 0 if ok
585  */
586 Static int
587 cons_pcballoc(so, head, flags, proto, dest)
588 	struct socket	*so;
589 	struct	isopcb	*head;
590 	u_short 		flags;
591 	struct protosw	*proto;
592 	struct	cons_pcb **dest;
593 {
594 	int 					error;
595 	register struct cons_pcb *copcb;
596 
597 	IFDEBUG(D_CCONN)
598 		printf("cons_pcballoc (0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
599 			so, head, flags, proto, dest);
600 	ENDDEBUG
601 	if(proto == (struct protosw *)0)
602 		return EPROTONOSUPPORT;
603 
604 	if( ( error = iso_pcballoc(so, head) ) == EOK )  {
605 		/* Have allocated a cleared mbuf */
606 
607 		copcb = (struct cons_pcb *)so->so_pcb;
608 		copcb->co_ttl = copcb->co_init_ttl = X25_TTL;
609 		copcb->co_flags = flags;
610 		copcb->co_proto = proto;
611 		copcb->co_pending.ifq_maxlen = CONS_IFQMAXLEN;
612 		copcb->co_myself = copcb;
613 
614 		if (so == &dummysocket)
615 			copcb->co_socket = (struct socket *)0;
616 
617 		*dest = copcb;
618 	}
619 done:
620 	IFDEBUG(D_CCONN)
621 		printf("cons_pcballoc returns 0x%x: DUMP\n", copcb);
622 		dump_buf( copcb, sizeof(*copcb));
623 	ENDDEBUG
624 	if( (flags & CONSF_ICRE) == 0) {
625 		struct dte_addr *dtea = &(*dest)->co_peer_dte;
626 		int len;
627 
628 		error = iso_8208snparesolve(&(*dest)->co_faddr, dtea, &len);
629 		ASSERT(error == 0);
630 		ASSERT(len == sizeof(struct dte_addr));
631 	}
632 
633 	return error;
634 }
635 
636 /*
637  * NAME:	cons_connect()
638  * CALLED FROM:
639  *	cons_usrreq() when opening a new connection.
640  * FUNCTION anD ARGUMENTS:
641  *  Figures out which device to use, finding a route if one doesn't
642  *  already exist.
643  * 	Builds an eicon connection request and gives it to the device.
644  * RETURN VALUE:
645  *  returns E*
646  */
647 Static int
648 cons_connect( copcb )
649 	register struct cons_pcb *copcb;
650 {
651 	register struct eicon_request *ecnrq;
652 	register struct mbuf 	*m;
653 	int 					error = 0;
654 	struct ifaddr 			*ifa;
655 
656 	IFDEBUG(D_CCONN)
657 		printf("cons_connect( 0x%x ) : ifp 0x%x\npeer: ", copcb, copcb->co_ifp);
658 		dump_isoaddr(&copcb->co_faddr);
659 		printf("\nmyaddr: ");
660 		dump_isoaddr(&copcb->co_laddr);
661 		printf("\n" );
662 	ENDDEBUG
663 
664 	/* PHASE 2: this call is OK */
665 	if( ifa = ifa_ifwithaddr(&copcb->co_faddr ) ) {
666 		/* foreign address is me */
667 		copcb->co_ifp = ifa->ifa_ifp;
668 		IFDEBUG(D_CCONN)
669 			printf("cons_connect: after if_withaddr copcb->co_ifp 0x%x\n",
670 				copcb->co_ifp);
671 		ENDDEBUG
672 
673 		if( (ifa->ifa_ifp->if_flags&(IFF_LOOPBACK|IFF_UP)) ==
674 												(IFF_LOOPBACK|IFF_UP)) {
675 			copcb->co_flags |= CONSF_LOOPBACK;
676 		}
677 		bcopy((caddr_t)&ifa->ifa_addr, (caddr_t)&copcb->co_laddr,
678 			sizeof(struct sockaddr));
679 	}
680 	IFDEBUG(D_CCONN)
681 		printf("cons_connect: co_flags 0x%x\n", copcb->co_flags);
682 		if( ifa ) {
683 			printf(" cons_connect withaddr returns %s\n",
684 				copcb->co_ifp->if_name);
685 		}
686 	ENDDEBUG
687 	else if ( copcb->co_ifp == (struct ifnet *)0 ) {
688 #ifdef	PHASEONE
689 		/*
690 		 *	We need to get the local nsap address.
691 		 *	First, route to the destination. This will provide us with
692 		 *	an ifp. Second, determine which local address linked on
693 		 *	that ifp is appropriate
694 		 */
695 		struct sockaddr_iso	*first_hop;		/* filled by clnp_route */
696 		struct iso_addr	*localaddr, *clnp_srcaddr();
697 
698 		if (error = clnp_route(&copcb->co_faddr,
699 			&((struct isopcb *)copcb)->isop_route, /* flags */0,
700 			&first_hop, &copcb->co_ifp))
701 			goto bad;
702 
703 		/* determine local address based upon ifp */
704 		if ((localaddr = clnp_srcaddr(copcb->co_ifp,
705 				&first_hop->siso_addr)) == NULL) {
706 			error = ENETUNREACH;
707 			goto bad;
708 		}
709 		copcb->co_laddr.siso_family = AF_ISO;
710 		copcb->co_laddr.siso_addr = *localaddr;
711 #else
712 		/* Foreign addr isn't me (lpb). If still don't have an ifp or have
713 		 * an ifp but don't know its address, look for a route
714 		 */
715 		if( ifa = ifa_ifwithnet(&copcb->co_faddr) ) {
716 			copcb->co_ifp =  ifa->ifa_ifp;
717 			IFDEBUG(D_CCONN)
718 				printf(" cons_connect withnet returns %s\n",
719 										copcb->co_ifp->if_name);
720 			ENDDEBUG
721 		} else {
722 			printf("cons PANIC: connect: can't find SNPA \n");
723 			error = ENETUNREACH;
724 			goto bad;
725 		}
726 #endif	PHASEONE
727 	}
728 #ifndef	PHASEONE
729 	if( ifa == (struct ifaddr *)0 ) {
730 		struct ifaddr * iso_ifwithidi();
731 
732 		if( ifa = iso_ifwithidi(&copcb->co_faddr) ) {
733 			copcb->co_ifp =  ifa->ifa_ifp;
734 			IFDEBUG(D_CCONN)
735 				printf(" cons_connect withnet returns %s\n",
736 										copcb->co_ifp->if_name);
737 			ENDDEBUG
738 		} else {
739 			printf("cons PANIC: connect: can't find SNPA \n");
740 			error = ENETUNREACH;
741 			goto bad;
742 		}
743 	}
744 	bcopy((caddr_t)&ifa->ifa_addr, (caddr_t)&copcb->co_laddr,
745 		sizeof(struct sockaddr));
746 #endif	PHASEONE
747 
748 	copcb->co_state = CONNECTING;
749 
750 	ASSERT( copcb->co_ifp != (struct ifnet *) 0);
751 	if ( copcb->co_ifp == (struct ifnet *)0 ) {
752 		error = ENETUNREACH;
753 		goto bad;
754 	}
755 
756 	m = m_getclr(M_DONTWAIT, MT_XCONN);
757 	if( !m ) {
758 		copcb->co_ifp->if_oerrors ++;
759 		error = ENOBUFS;
760 		goto bad;
761 	}
762 	m->m_len = sizeof(struct eicon_request);
763 
764 	ecnrq = mtod(m, struct eicon_request *);
765 
766 	copcb->co_myself = copcb;
767 	ecnrq->e_pcb = (caddr_t)copcb;
768 #ifdef ARGO_DEBUG
769 	LAST_CALL_PCB = (unsigned) ecnrq->e_pcb;
770 #endif ARGO_DEBUG
771 	ecnrq->e_cmd = ECN_CALL;
772 	ecnrq->e_vc = 0; /* mbz ? */
773 	ecnrq->e_info = 0; /* mbz */
774 
775 	/* get data buffer */
776 	{ 	struct mbuf *n;
777 
778 		MGET(n, M_DONTWAIT, MT_XCONN);
779 		if( n==MNULL ) {
780 			copcb->co_ifp->if_oerrors ++;
781 			error = ENOBUFS;
782 			goto bad;
783 		}
784 		e_data(ecnrq) = n; /* e_data is really dtom(ecnrq)->m_next */
785 	}
786 
787 	IFDEBUG(D_CCONN)
788 		printf(
789 		"calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
790 			&copcb->co_laddr, &copcb->co_faddr,
791 			copcb->co_proto->pr_protocol,
792 			e_data(ecnrq),
793 			copcb->co_flags & CONSF_XTS);
794 	ENDDEBUG
795 	if( error = make_partial_x25_packet( copcb, e_data(ecnrq)) ) {
796 		copcb->co_ifp->if_oerrors ++;
797 		m_freem(m);
798 		goto bad;
799 	}
800 
801 	IncStat(co_call);
802 
803 	IFDEBUG(D_CDUMP_REQ)
804 		printf("cons_connect ecnrq:\n");
805 		dump_buf(ecnrq, sizeof(*ecnrq));
806 	ENDDEBUG
807 
808 	ASSERT( copcb->co_channel == 0);
809 	if( copcb->co_channel != 0) {
810 		printf("cons_connect PANIC: channel is 0x%x\n", copcb->co_channel);
811 	}
812 
813 	error = choose_output(copcb->co_ifp, m, copcb->co_flags & CONSF_LOOPBACK);
814 
815 	switch( error ) {
816 		case 0: /* ok */
817 			break;
818 		default: /* problem */
819 			printf("cons: PANIC: if_output returns 0x%x\n", error);
820 			cons_clear_and_detach( copcb, DONTCLEAR, PRC_ROUTEDEAD);
821 	}
822 
823 bad:
824 	IFTRACE(D_CDATA)
825 		tptrace( TPPTmisc,
826 		"cons_connect: choose (copcb m) returned  error\n",
827 			copcb, m, error, 0);
828 	ENDTRACE
829 	return error;
830 }
831 
832 /*
833  * NAME:	cons_find()
834  * CALLED FROM:
835  *	cosns_output1() thus:
836  *		cons_find( CONSF_DGM, dst, proto, 0, 0) where
837  *		proto is one of { TP_proto, CLNP_proto }
838  * FUNCTION and ARGUMENTS:
839  *  Looks through list of connections for the destination,
840  *  for one marked for the use indicated by flags.
841  *  If none found, opens up a new connection.
842  *   These connections will be eliminated by :
843  *     a) slowtimo timer, or
844  *     b) the need for a new connection, when we've run out of resources.
845  *  The argument flags describes the type of pcb we want - may
846  *  specify multiplexing-ok, datagram use, etc.
847  *  The argument proto points the the higher layer protocol that
848  *  will be using this connection.
849  * RETURN VALUE:
850  *  returns a ptr to a pcb whose characteristics match those
851  *  described by (flags, proto)
852  */
853 
854 Static struct cons_pcb *
855 cons_find(flags, dst, proto, addl_criteria, mask)
856 	u_int flags, mask;
857 	struct sockaddr_iso *dst;
858 	struct protosw *proto;
859 	int	(*addl_criteria)();
860 {
861 	register struct cons_pcb *copcb;
862 	register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist;
863 	int s = splnet(); /* or whatever, for the device! */
864 	struct dte_addr dest_dte;
865 	int	 dummy;
866 
867 	struct	copcb_descriptor {
868 		int	xd_qlen;
869 		struct cons_pcb *xd_pcb;
870 	} next_best = {
871 		0, (struct cons_pcb *)0
872 	};
873 
874 	IFDEBUG(D_CFIND)
875 		printf("cons_find( flags 0x%x proto 0x%x) ", flags, proto);
876 	ENDDEBUG
877 
878 	if ( iso_8208snparesolve(dst, &dest_dte, &dummy)) {
879 		ASSERT(0);
880 		return (struct cons_pcb *)0; /* error */
881 	}
882 	ASSERT(dummy == sizeof(struct dte_addr));
883 
884 	for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) {
885 		copcb = (struct cons_pcb *)copcb->co_next;
886 		while (copcb !=  *copcblist) {
887 			IFDEBUG(D_CFIND)
888 				printf(
889 				"cons_find: chan 0x%x flags 0x%x proto 0x%x state 0x%x \n",
890 					copcb->co_channel, copcb->co_flags, copcb->co_proto,
891 					copcb->co_state);
892 			ENDDEBUG
893 			/*
894 			 * if flags is a subset of the bits in co_flags, it will suffice
895 			 */
896 			if( ((copcb->co_flags & flags) == flags ) &&
897 				/* PHASE2: where do we get the mask if we use nsaps ????
898 				 * If dte addresses are used, then use
899 				 * nibble compare otherwise...???
900 				 */
901 #ifdef notdef
902 				iso_addrmatch1(&(copcb->co_faddr.siso_addr), &(dst->siso_addr))
903 #else
904 				dest_dte.dtea_niblen == copcb->co_peer_dte.dtea_niblen &&
905 				nibble_match( (char *)&(copcb->co_peer_dte.dtea_addr),
906 					HIGH_NIBBLE, (char *)dest_dte.dtea_addr,
907 					HIGH_NIBBLE, dest_dte.dtea_niblen)
908 #endif notdef
909 				&&
910 				(copcb->co_proto == proto)  &&
911 				(copcb->co_state >= MIN_USABLE_STATE)) {
912 					IFDEBUG(D_CFIND)
913 						printf(
914 						"cons_find: add'l criteria...\n" );
915 					ENDDEBUG
916 					if((copcb->co_state != OPEN) &&
917 						(next_best.xd_qlen > copcb->co_pending.ifq_len)) {
918 						next_best.xd_pcb = copcb;
919 						next_best.xd_qlen = copcb->co_pending.ifq_len;
920 					}
921 					if( !addl_criteria || (*addl_criteria)(copcb, mask) ) {
922 						goto found; /* have to break out of 2 loops */
923 					}
924 				}
925 			copcb = (struct cons_pcb *)copcb->co_next ;
926 		}
927 	}
928 #ifdef notdef
929 	/* TODO:
930 	 * have a limit of the number of calls per desitination.
931 	 * If we didn't find one already open AND our limit for this
932 	 * destination hasn't been reached, return 0 'cause
933 	 * then the caller will open a new one.
934 	 * Otherwise return next_best.
935 	 * To do this we need some sort of per-destination info.
936 	 * Could go into the directory service. Oh, grotesque.
937 	 */
938 #endif notdef
939 	if( copcb == (struct cons_pcb *)0 ) {
940 		copcb = next_best.xd_pcb; /* may be zero too */
941 		IFDEBUG(D_CFIND)
942 			printf("NEXT_BEST! \n");
943 			dump_copcb(copcb, "find: next_best");
944 		ENDDEBUG
945 	}
946 found:
947 
948 	splx(s);
949 
950 	IFDEBUG(D_CFIND)
951 		printf("returns 0x%x \n", copcb);
952 	ENDDEBUG
953 	return copcb;
954 }
955 
956 
957 /*
958  * NAME:	issue_clear_req()
959  * CALLED FROM:
960  *	cons_clear() and wherever we get an error from x.25 that makes us
961  *  	want to close the vc on which it came, but don't have
962  *		a copcb assoc. with that vc.
963  * FUNCTION and ARGUMENTS:
964  *  Creates an eicon_request for a clear request, returns it in an mbuf.
965  *  (chan) is the channel on which to do the clear, (reason) is the
966  *  clear reason(diagnostic).
967  * RETURN VALUE:
968  *  returns E*
969  */
970 Static int
971 issue_clear_req(chan, reason, ifp, loop)
972 	u_char 			chan, reason;
973 	struct	ifnet 	*ifp;
974 	int				loop;
975 {
976 	register struct mbuf 			*m;
977 	register struct mbuf 			*cdm;
978 	register struct eicon_request 	*ecnrq;
979 	struct e_clear_data 			*ecd;
980 
981 	IFDEBUG(D_CCONN)
982 		printf("issue_clear_req(0x%x, 0x%x, 0x%x, 0x%x)\n",
983 			chan, reason, ifp, loop);
984 	ENDDEBUG
985 	m = m_getclr(M_DONTWAIT, MT_XCLOSE);
986 	if( !m ) {
987 		return ENOBUFS;
988 	}
989 	m->m_len = sizeof(struct eicon_request);
990 	ecnrq = mtod(m, struct eicon_request *);
991 	ecnrq->e_cmd = ECN_CLEAR;
992 	ecnrq->e_vc = chan & 0xff;
993 	/*
994 	 *  see p. 149 of 8208 for reasons (diagnostic codes)
995 	 */
996 	MGET(cdm, M_DONTWAIT, MT_XCLOSE);
997 	if( !cdm ) {
998 		m_freem(m);
999 		return ENOBUFS;
1000 	}
1001 	cdm->m_len = sizeof(struct e_clear_data); /* cause, diagnostic */
1002 	e_data(ecnrq) = cdm;
1003 
1004 	ecd = mtod(cdm, struct e_clear_data *);
1005 	ecd->ecd_cause = 0x0; /* DTE initiated, diagnostic tells more */
1006 	ecd->ecd_diagnostic = (u_char)reason;
1007 
1008 	IncStat(co_clear_out);
1009 	return choose_output(ifp, m, loop);
1010 }
1011 
1012 
1013 /*
1014  * NAME:	cons_clear()
1015  * CALLED FROM:
1016  *  cons_usrreq(), PRU_DISCONNECT,
1017  *  cons_slowtimo(), cons_free_lru()
1018  * FUNCTION and ARGUMENTS:
1019  *	Builds a clear request for the connection represented by copcb,
1020  *  gives it to the device.
1021  * ECN_CLEAR(request) takes e_vc only, returns adr_status.
1022  * RETURN VALUE:
1023  */
1024 
1025 Static int
1026 cons_clear( copcb, reason)
1027 	register struct cons_pcb *copcb;
1028 	u_char					reason;
1029 {
1030 	register struct mbuf			*m;
1031 	int								error;
1032 
1033 	IFDEBUG(D_CCONN)
1034 		printf("cons_clear(0x%x, 0x%x)\n", copcb, reason);
1035 	ENDDEBUG
1036 	if( !copcb) {
1037 		printf("cons PANIC: clear: No copcb\n");
1038 		return 0;
1039 	}
1040 	while( copcb->co_pending.ifq_len > 0 ) {
1041 		register int s = splimp();
1042 
1043 		IF_DEQUEUE( &copcb->co_pending, m );
1044 		splx(s);
1045 		m_freem(m);
1046 	}
1047 	if( (copcb->co_state == CLOSED) || (copcb->co_state == CLOSING) )
1048 		return 0;
1049 
1050 #ifdef ARGO_DEBUG
1051 	if( copcb->co_state == CONNECTING) {
1052 		IFDEBUG(D_CCONN)
1053 			dump_copcb(copcb, "clear");
1054 		ENDDEBUG
1055 	} else if( (copcb->co_channel == 0) || (copcb->co_channel == X_NOCHANNEL) ) {
1056 		IFDEBUG(D_CCONN)
1057 			dump_copcb(copcb, "clear");
1058 		ENDDEBUG
1059 	}
1060 #endif ARGO_DEBUG
1061 
1062 	copcb->co_state = CLOSING;
1063 
1064 	IFDEBUG(D_CCONN)
1065 		printf("cons_clear: channel 0x%x copcb 0x%x dst: ",
1066 			copcb->co_channel,  copcb);
1067 		dump_isoaddr(&copcb->co_faddr);
1068 		dump_copcb(copcb, "clear");
1069 	ENDDEBUG
1070 
1071 	error = issue_clear_req(copcb->co_channel, reason, copcb->co_ifp,
1072 		copcb->co_flags & CONSF_LOOPBACK);
1073 	copcb->co_channel = X_NOCHANNEL;
1074 	copcb->co_state = CLOSED;
1075 	return error;
1076 }
1077 
1078 
1079 /*
1080  * NAME:	cons_senddata()
1081  * CALLED FROM:
1082  *  cons_output(), consoutput(), consintr()
1083  * FUNCTION and ARGUMENTS:
1084  *	issued a data (write) command - if the device isn't ready,
1085  *  it enqueues the command on a per-connection queue.
1086  * RETURN VALUE:
1087  *	ENOBUFS
1088  *  Is responsible for freeing m0!
1089  *
1090  * ECN_SEND (write)
1091  */
1092 
1093 Static int
1094 cons_senddata(copcb, m0)
1095 	register struct cons_pcb *copcb;
1096 	struct mbuf *m0;
1097 {
1098 	register struct mbuf *m;
1099 	register struct eicon_request *ecnrq;
1100 	int s;
1101 
1102 	IFDEBUG(D_CDATA)
1103 		printf("cons_senddata( 0x%x, m 0x%x ) chan 0x%x",
1104 			copcb, m0, copcb->co_channel );
1105 		printf(" co_lport 0x%x\n", copcb->co_lport);
1106 	ENDDEBUG
1107 	if( m0 == MNULL )
1108 		return;
1109 	ASSERT( m0->m_len > 0);
1110 	if( m0->m_len <= 0) {
1111 		printf("cons_senddata : BAD MLEN? 0x%x", m0->m_len);
1112 	}
1113 
1114 	touch(copcb);
1115 
1116 	if( (copcb->co_state == CONNECTING) || (copcb->co_state == ACKWAIT) ) {
1117 		IFDEBUG(D_CDATA)
1118 			printf("senddata PUTTING ON PENDING Q copcb 0x%x state 0x%x\n",
1119 				copcb, copcb->co_state);
1120 		ENDDEBUG
1121 		s = splimp();
1122 		if (IF_QFULL(&copcb->co_pending)) {
1123 			IFDEBUG(D_CDATA)
1124 				printf("senddata DROPPING m0 0x%x\n",  m0);
1125 			ENDDEBUG
1126 			IF_DROP(&copcb->co_pending);
1127 			if(copcb->co_ifp) {
1128 				copcb->co_ifp->if_snd.ifq_drops ++;
1129 			}
1130 			IncStat(co_Xdrops);
1131 			copcb->co_ifp->if_oerrors ++;
1132 			splx(s);
1133 			m_freem (m0);
1134 
1135 			if( copcb->co_proto  && copcb->co_proto->pr_ctlinput ) {
1136 				(*copcb->co_proto->pr_ctlinput)(PRC_QUENCH,
1137 				(struct sockaddr_iso *)&copcb->co_faddr,
1138 				(caddr_t)copcb);
1139 
1140 				return 0;
1141 			} else
1142 				return E_CO_QFULL;
1143 		}
1144 		IFDEBUG(D_CDATA)
1145 			printf("Putting 0x%x on 0x%x->pending Q\n", m0, copcb);
1146 		ENDDEBUG
1147 		IF_ENQUEUE( &copcb->co_pending, m0 );
1148 		splx(s);
1149 		return 0;
1150 	}
1151 	if(copcb->co_channel == 0 ) {
1152 		return E_CO_CHAN;
1153 	}
1154 	ASSERT( copcb->co_state == OPEN);
1155 
1156 	m = m_getclr(M_DONTWAIT, MT_XDATA);
1157 	if( !m ) {
1158 		copcb->co_ifp->if_oerrors ++;
1159 		m_freem (m0);
1160 		return ENOBUFS;
1161 	}
1162 	m->m_len = sizeof(struct eicon_request);
1163 	ecnrq = mtod(m, struct eicon_request *);
1164 	ecnrq->e_pcb = (caddr_t)copcb;
1165 	if( copcb->co_myself != copcb ) {
1166 		struct mbuf *mm;
1167 		/* TODO: REMOVE THIS DEBUGGING HACK */
1168 		ASSERT(0);
1169 		printf("BAD e_pcb from HL (0x%x,0x%x)\n", copcb, copcb->co_myself);
1170 		mm = dtom( copcb );
1171 		if(mm->m_type == MT_FREE)
1172 			printf("FREED MBUF!\n");
1173 		return ENETDOWN;
1174 	}
1175 	ASSERT( copcb->co_channel != 0);
1176 	ASSERT( copcb->co_channel != X_NOCHANNEL);
1177 	ecnrq->e_vc = (copcb->co_channel & 0xff);
1178 	ecnrq->e_cmd = ECN_SEND;
1179 	e_data(ecnrq) = m0;
1180 	{
1181 		/* TODO: REMOVE THIS DEBUGGING HACK */
1182 		struct mbuf *thedata = e_data(ecnrq);
1183 		u_int *firstint = mtod( thedata, u_int *);
1184 
1185 		if( (*firstint & 0xff000000) != 0x81000000 ) {
1186 			/* not clnp */
1187 			switch( ((*firstint) & 0x00ff0000) >> 20 ) {
1188 			case 0x1:
1189 			case 0x2:
1190 			case 0x3:
1191 			case 0x6:
1192 			case 0x7:
1193 			case 0x8:
1194 			case 0xc:
1195 			case 0xd:
1196 			case 0xe:
1197 			case 0xf:
1198 				break;
1199 			default:
1200 				printf(" ECN_SEND! BAD DATA\n" );
1201 				dump_buf( thedata, 20 + 12 );
1202 				m_freem( m0 );
1203 				return ENETDOWN;
1204 			}
1205 		}
1206 	}
1207 
1208 	ecnrq->e_info = 0;
1209 
1210 	IFDEBUG(D_CDUMP_REQ)
1211 		printf("senddata ecnrq\n");
1212 	ENDDEBUG
1213 	IncStat(co_send);
1214 
1215 	ASSERT( copcb->co_state == OPEN );
1216 	copcb->co_state = ACKWAIT;
1217 
1218 	if( copcb->co_myself != copcb ) {
1219 		struct mbuf *mm;
1220 		/* TODO: REMOVE this and all mention of co_myself */
1221 		ASSERT(0);
1222 		printf("BAD e_pcb TO THE BOARD ecn (0x%x) cmd 0x%x\n",
1223 			ecnrq->e_pcb, ecnrq->e_cmd);
1224 		mm = dtom( copcb );
1225 		if(mm->m_type == MT_FREE)
1226 			printf("FREED MBUF!\n");
1227 		dump_buf (ecnrq, sizeof (*ecnrq));
1228 		return ENETDOWN;
1229 	}
1230 
1231 	return
1232 	  choose_output(copcb->co_ifp, dtom(ecnrq), copcb->co_flags&CONSF_LOOPBACK);
1233 }
1234 
1235 /*
1236  * NAME:	cons_send_on_vc()
1237  * CALLED FROM:
1238  *  tp_error_emit()
1239  * FUNCTION and ARGUMENTS:
1240  *  Take a packet(m0), of length (datalen) from tp and
1241  * send it on the channel (chan).
1242  *
1243  * RETURN VALUE:
1244  *  whatever (E*) is returned form the net layer output routine.
1245  */
1246 int
1247 cons_send_on_vc(chan, m, datalen)
1248 	int				chan;
1249 	struct mbuf 	*m;
1250 	int				datalen;
1251 {
1252 	struct cons_pcb	*copcb = (struct cons_pcb *)0;
1253 
1254 	if(m == MNULL)
1255 		return;
1256 
1257 	if((copcb =
1258 #ifdef ARGO_DEBUG
1259 		cons_chan_to_pcb( chan, __LINE__ )
1260 #else ARGO_DEBUG
1261 		cons_chan_to_pcb( chan )
1262 #endif ARGO_DEBUG
1263 			) == (struct cons_pcb *)0 )
1264 		return E_CO_CHAN;
1265 	IFDEBUG(D_CCONS)
1266 		printf("cons_send_on_vc m 0x%x m_len 0x%x\n", m, m->m_len);
1267 	ENDDEBUG
1268 	return cons_senddata( copcb, m);
1269 }
1270 
1271 /*
1272  * NAME:	cons_output()
1273  * CALLED FROM:
1274  *  tpiso_output(), can have whatever interface we want it to...
1275  *  tpiso_output() decides whether to give a packet to CLNP or to
1276  *  cons; if the latter, it calls this routine.
1277  * FUNCTION and ARGUMENTS:
1278  *  tp has alloc-ed a pcb - but it may not be open.
1279  *  some classes of tp may allow multiplexing, in which
1280  *  case, you may choose to send the data on ANOTHER cons connection.
1281  *  This decides which net connection to use, opens one if necessary.
1282  *  Then it sends the data.
1283  */
1284 
1285 cons_output(isop, m, len, isdgm)
1286 	struct isopcb 	*isop;
1287 	struct mbuf 	*m;
1288 	int 			len;
1289 	int				isdgm;
1290 {
1291 	struct cons_pcb	*copcb = (struct cons_pcb *)0;
1292 	int				error;
1293 	int 			s = splnet();
1294 
1295 	IFDEBUG(D_CCONS)
1296 		printf("cons_output( isop 0x%x, m 0x%x, len 0x%x, dgm 0x%x )\n",
1297 			isop,m,len, isdgm);
1298 	ENDDEBUG
1299 
1300 	if( m == MNULL )
1301 		return 0;
1302 	ASSERT(m->m_len > 0);
1303 	if( isdgm ) {
1304 		error = cosns_output1(0, m, &isop->isop_faddr, TP_proto, isop);
1305 		IFDEBUG(D_CDATA)
1306 			if(error)
1307 			printf("cosns_output1 RETURNS ERROR 0x%x\n", error);
1308 		ENDDEBUG
1309 		return error;
1310 	}
1311 
1312 	if( isop->isop_chanmask  || isop->isop_negchanmask) {
1313 		register int	mask = isop->isop_chanmask;
1314 		register int	chan = 1;
1315 
1316 		if( mask == 0)
1317 			mask = isop->isop_negchanmask;
1318 
1319 		for ( chan=1; (mask & 1)==0; chan++,mask>>=1 ) ;
1320 
1321 		if( isop->isop_chanmask == 0 )
1322 			chan = -chan;
1323 
1324 		IFDEBUG(D_CCONS)
1325 			printf(
1326 			"cons_output: isop 0x%x cmask 0x%x negmask 0x%x, chan 0x%x\n",
1327 			isop, isop->isop_chanmask, isop->isop_negchanmask, chan);
1328 		ENDDEBUG
1329 		ASSERT( chan != 0);
1330 #ifdef ARGO_DEBUG
1331 		copcb = cons_chan_to_pcb( chan, __LINE__ );
1332 #else ARGO_DEBUG
1333 		copcb = cons_chan_to_pcb( chan );
1334 #endif ARGO_DEBUG
1335 	}
1336 	if( copcb == (struct cons_pcb *)0 ) {
1337 		/* get a new one */
1338 
1339 		if(( error = cons_pcballoc(&dummysocket, &cons_isopcb, CONSF_OCRE,
1340 												TP_proto, &copcb)) != EOK ) {
1341 			IFDEBUG(D_CCONS)
1342 				printf("cosns_output: no copcb; returns 0x%x\n", error);
1343 			ENDDEBUG
1344 			(void) m_freem (m);
1345 			splx(s);
1346 			return error ;
1347 		}
1348 
1349 		/* abbreviated form of iso_pcbconnect(): */
1350 		bcopy((caddr_t)&isop->isop_faddr, (caddr_t)&copcb->co_faddr,
1351 									sizeof(struct sockaddr_iso));
1352 
1353 		if ( error = cons_connect( copcb ) ) { /* if it doesn't work */
1354 			/* oh, dear, throw packet away */
1355 			remque((struct isopcb *)copcb);
1356 			(void) m_free(dtom(copcb));
1357 			(void) m_freem( m );
1358 			splx(s);
1359 			return error;
1360 		}
1361 
1362 		if( copcb->co_socket ) {
1363 			while( (copcb->co_state != OPEN) &&
1364 				!(error = copcb->co_socket->so_error) ) {
1365 				IFDEBUG(D_CCONS)
1366 					printf(
1367 	"SLEEP1 copcb 0x%x isop 0x%x state 0x%x chan 0x%x mask 0x%x neg 0x%x\n",
1368 						copcb, isop, copcb->co_state, copcb->co_channel,
1369 						((struct isopcb *)isop)->isop_chanmask,
1370 						((struct isopcb *)isop)->isop_negchanmask
1371 					);
1372 				ENDDEBUG
1373 				tsleep( (caddr_t)&copcb->co_state, PZERO+1,
1374 					SLP_ISO_CONSOUT, 0);
1375 				IFDEBUG(D_CCONS)
1376 					printf("AFTER SLEEP 1 chan 0x%x chanmask 0x%x negchanmask 0x%x\n",
1377 						copcb->co_channel, isop->isop_chanmask,
1378 						isop->isop_negchanmask);
1379 				ENDDEBUG
1380 			}
1381 			if( !error )
1382 				SET_CHANMASK( isop, copcb->co_channel);
1383 		}
1384 
1385 	}
1386 
1387 	IFDEBUG(D_CDATA)
1388 		printf("cons_output calling senddata(0x%x 0x%x)\n", copcb, m);
1389 		ASSERT(m != MNULL);
1390 		ASSERT(m->m_len != 0);
1391 	ENDDEBUG
1392 
1393 	if( !error )
1394 		error =  cons_senddata( copcb, m);
1395 	splx(s);
1396 	return error;
1397 }
1398 
1399 /*
1400  * NAME:	cons_openvc()
1401  * CALLED FROM:
1402  *  TP when it decides to open a VC for TP 0
1403  * FUNCTION:
1404  *  opens a connection and stashes the pcb info in the socket
1405  *  substitute for iso_pcbconnect/ in_pcbconnect for the class 0 case
1406  *  only.
1407  */
1408 int
1409 cons_openvc(copcb, faddr, so)
1410 	struct cons_pcb 			*copcb;
1411 	struct	sockaddr_iso	*faddr;
1412 	struct	socket			*so;
1413 {
1414 	int 					error = 0;
1415 	int 					s = splnet();
1416 	struct cons_pcb 		*cons_chan_to_pcb();
1417 
1418 
1419 	ASSERT( copcb->co_socket == so );
1420 	IFTRACE(D_CCONN)
1421 		tptrace(TPPTmisc, "cons_openvc( copcb so )\n", copcb, so, 0, 0);
1422 	ENDTRACE
1423 	IFDEBUG(D_CCONN)
1424 		printf("cons_openvc( copcb 0x%x, so 0x%x )\n", copcb,so);
1425 	ENDDEBUG
1426 	/*
1427 	 * initialize the copcb part of the isopcb
1428 	 */
1429 	copcb->co_ttl = copcb->co_init_ttl = X25_TTL;
1430 	copcb->co_flags = CONSF_OCRE;
1431 	copcb->co_proto = TP_proto;
1432 	copcb->co_pending.ifq_maxlen = CONS_IFQMAXLEN;
1433 
1434 	/* abbreviated form of iso_pcbconnect(): */
1435 	bcopy((caddr_t)faddr, (caddr_t)&copcb->co_faddr,
1436 								sizeof(struct sockaddr_iso));
1437 
1438 	ASSERT( copcb->co_socket == so );
1439 	if( error = cons_connect( copcb ) )
1440 		goto done;
1441 	while( (copcb->co_state != OPEN) && !(error = so->so_error) ) {
1442 		IFDEBUG(D_CCONS)
1443 			printf(
1444 		"SLEEP2 copcb 0x%x state 0x%x chan 0x%x mask 0x%x neg 0x%x\n",
1445 				copcb, copcb->co_state, copcb->co_channel,
1446 				copcb->co_chanmask,
1447 				copcb->co_negchanmask
1448 			);
1449 		ENDDEBUG
1450 		tsleep((caddr_t)&copcb->co_state, PZERO+2, SLP_ISO_CONSCONN, 0);
1451 		IFDEBUG(D_CCONS)
1452 			printf("AFTER SLEEP2 chan 0x%x chanmask 0x%x negchanmask 0x%x\n",
1453 				copcb->co_channel, copcb->co_chanmask,
1454 				copcb->co_negchanmask);
1455 		ENDDEBUG
1456 	}
1457 	if( !error )
1458 		SET_CHANMASK( (struct isopcb *)copcb, copcb->co_channel);
1459 done:
1460 	ASSERT( copcb->co_socket == so );
1461 	splx(s);
1462 
1463 	IFDEBUG(D_CCONN)
1464 		printf("cons_openvc: copcb 0x%x error 0x%x\n", copcb, error );
1465 	ENDDEBUG
1466 	return error;
1467 }
1468 
1469 /*
1470  * NAME:	cons_netcmd()
1471  * CALLED FROM:
1472  *  tp_route_to() when it decides to accept or reject an incoming
1473  *  connection it calls this.
1474  * FUNCTION:
1475  *  either closes the cons connection named by (channel)
1476  *  or associates the copcb with the channel #.
1477  *	and removes the old copcb from the tp_incoming_pending list.
1478  */
1479 int
1480 cons_netcmd(cmd, isop, channel, isdgm)
1481 	int 					cmd;
1482 	struct isopcb 			*isop;
1483 	int						channel;
1484 {
1485 	int 					s = splnet();
1486 	int 					error = 0;
1487 	struct cons_pcb 		*copcb = (struct cons_pcb *)0;
1488 	struct cons_pcb 		*cons_chan_to_pcb();
1489 
1490 	IFTRACE(D_CCONN)
1491 		tptrace(TPPTmisc, "cons_netcmd( cmd isopcb channel isdgm)\n",
1492 			cmd,isop,channel, isdgm);
1493 	ENDTRACE
1494 	IFDEBUG(D_CCONN)
1495 		printf("cons_netcmd( cmd 0x%x, isop 0x%x, channel 0x%x, isdgm 0x%x)\n",
1496 			cmd,isop,channel, isdgm);
1497 		if( isop )
1498 			printf("cons_netcmd: isop->socket 0x%x\n",
1499 			isop->isop_socket);
1500 	ENDDEBUG
1501 	ASSERT(cmd != CONN_OPEN);
1502 
1503 	/* Can we find a cons-level pcb based on channel? */
1504 	if(channel) {
1505 		if((copcb =
1506 #ifdef ARGO_DEBUG
1507 			cons_chan_to_pcb( channel, __LINE__ )
1508 #else ARGO_DEBUG
1509 			cons_chan_to_pcb( channel)
1510 #endif ARGO_DEBUG
1511 				) == (struct cons_pcb *)0) {
1512 			error = ECONNABORTED;
1513 			splx(s);
1514 			return error;
1515 		}
1516 		if( copcb == (struct cons_pcb *) isop ) {
1517 			copcb = (struct cons_pcb *)0;
1518 			/* avoid operating on a pcb twice */
1519 		} else {
1520 			/* if isop is null (close/refuse):
1521 			 * this would remove from the TP list, which is NOT what we want
1522 			 * so only remove if there is an isop (gag)
1523 			 */
1524 			if( isop ) {
1525 				remque((struct cons_pcb *)copcb); /* take it off pending list */
1526 			} else {
1527 				ASSERT( (cmd == CONN_CLOSE) || (cmd == CONN_REFUSE) );
1528 			}
1529 		}
1530 	}
1531 	/* now we have one of these cases:
1532 	 * 1) isop is non-null and copcb is null
1533 	 * 2) isop is non-null and copcb is non-null and they are different
1534 	 * 3) isop is null and copcb is non-null
1535 	 */
1536 	ASSERT( (isop != (struct isopcb *)0) || (copcb != (struct cons_pcb *)0));
1537 
1538 	switch(cmd) {
1539 
1540 		case CONN_CONFIRM:
1541 			if( isdgm ) {
1542 				/* we want two separate pcbs */
1543 				/* if we don't have a copcb, get one */
1544 
1545 				if( copcb == (struct cons_pcb *)0 ) {
1546 					if(( error = cons_pcballoc(&dummysocket, &cons_isopcb,
1547 						((struct cons_pcb *)isop)->co_flags,
1548 						TP_proto, &copcb)) != EOK )
1549 							return error;
1550 					/* copy missing info from isop */
1551 					copcb->co_laddr = isop->isop_laddr;
1552 					copcb->co_faddr = isop->isop_faddr;
1553 					/* don't care about tsuffices */
1554 					((struct cons_pcb *)isop)->co_channel  = 0;
1555 												/* no longer used */
1556 
1557 					copcb->co_ifp = ((struct cons_pcb *)isop)->co_ifp ;
1558 					ASSERT( copcb->co_pending.ifq_len == 0 );
1559 
1560 				} else {
1561 					insque((struct isopcb *)copcb,
1562 						(struct isopcb *)&cons_isopcb);
1563 				}
1564 				copcb->co_state = OPEN;
1565 				copcb->co_flags |= CONSF_DGM;
1566 				copcb->co_channel = channel;
1567 				ASSERT(copcb->co_channel != 0);
1568 
1569 				IFDEBUG(D_CCONN)
1570 					printf("cons_netcmd: put 0x%x on regular list \n", copcb);
1571 				ENDDEBUG
1572 			} else {
1573 				/* must be TP 0, since this is never called from XTS code */
1574 				/* we want ONE pcb, namely isop.
1575 				 * If this TPE were the active side,
1576 				 * there ought not to be a copcb, since TP should
1577 				 * know that you can't send a CR with dgm and negot down
1578 				 * to non-dgm.
1579 				 * If this TPE were the passive side, we want to copy from
1580 				 * the copcb that was on the pending list, and delete the
1581 				 * pending copcb.
1582 				 */
1583 				if( copcb ) {
1584 					IFDEBUG(D_CCONN)
1585 						printf("cons_netcmd: copied info from 0x%x to 0x%x\n",
1586 							copcb, isop);
1587 					ENDDEBUG
1588 					isop->isop_laddr = copcb->co_laddr;
1589 					isop->isop_faddr = copcb->co_faddr;
1590 					/* tsuffices, socket should be there already */
1591 					((struct cons_pcb *)isop)->co_flags =
1592 									copcb->co_flags & ~CONSF_DGM;
1593 					((struct cons_pcb *)isop)->co_init_ttl = copcb->co_init_ttl;
1594 					touch(((struct cons_pcb *)isop));
1595 					((struct cons_pcb *)isop)->co_channel = channel;
1596 					((struct cons_pcb *)isop)->co_ifp = copcb->co_ifp;
1597 					((struct cons_pcb *)isop)->co_proto = copcb->co_proto;
1598 					((struct cons_pcb *)isop)->co_myself =
1599 						(struct cons_pcb *)isop;
1600 					SET_CHANMASK( isop, ((struct cons_pcb *)isop)->co_channel );
1601 					ASSERT( copcb->co_pending.ifq_len == 0 );
1602 
1603 					/* get rid of the copcb that was on the pending list */
1604 					(void) m_free(dtom(copcb));
1605 				}
1606 				((struct cons_pcb *)isop)->co_state = OPEN;
1607 			}
1608 			break;
1609 
1610 		case CONN_CLOSE:
1611 		case CONN_REFUSE:
1612 			/* if dgm then ignore; the connections will
1613 			 * be re-used or will time out
1614 			 */
1615 			if( isdgm )
1616 				break;
1617 
1618 			/* we should never come in here with both isop and copcb
1619 			 * unless is dgm, hence the following assertion:
1620 			 */
1621 			ASSERT( (copcb == (struct cons_pcb *)0) ||
1622 				(isop == (struct isopcb *)0) );
1623 
1624 			/* close whichever pcb we have */
1625 			if( copcb )
1626 				error = cons_clear(copcb, (cmd == CONN_CLOSE)?
1627 					E_CO_HLI_DISCN:E_CO_HLI_REJT);
1628 			if( isop )
1629 				error = cons_clear((struct cons_pcb *)isop, (cmd == CONN_CLOSE)?
1630 					E_CO_HLI_DISCN:E_CO_HLI_REJT);
1631 
1632 			if(copcb &&  (copcb->co_socket == (struct socket *)0) ) {
1633 				ASSERT( copcb->co_flags & (CONSF_DGM | CONSF_ICRE) );
1634 				(void) m_free(dtom(copcb)); /* detached */
1635 			}
1636 			/* isop will always be detached by the higher layer */
1637 			break;
1638 		default:
1639 			error = EOPNOTSUPP;
1640 			break;
1641 	}
1642 	splx(s);
1643 
1644 	IFDEBUG(D_CCONN)
1645 		printf("cons_netcmd returns 0x%x: isop 0x%x\n", isop, error );
1646 	ENDDEBUG
1647 	return error;
1648 }
1649 
1650 
1651 /*
1652  * NAME:	addr_proto_consistency_check()
1653  * CALLED FROM: cons_incoming()
1654  * FUNCTION and ARGUMENTS:
1655  *  Enforces a set of rules regarding what addresses will serve
1656  *  what protocol stack.  This is a kludge forced upon us by the
1657  *  fact that there's no way to tell which NET layer you want to
1658  *  run when opening a socket.  Besides, no doubt, OSI directory
1659  *  services won't advertise any kind of a protocol stack with the
1660  *  NSAPs.  sigh.
1661  * RETURNS
1662  * 	EAFNOSUPPORT or EOK.
1663  */
1664 Static int
1665 addr_proto_consistency_check(proto, addr)
1666 	int						proto;
1667 	struct 	sockaddr_iso	*addr;
1668 {
1669 	switch( proto ) {
1670 		case ISOPROTO_CLNP:
1671 			break;
1672 
1673 		case ISOPROTO_INACT_NL:
1674 		case ISOPROTO_CLTP:
1675 			return E_CO_HLI_PROTOID;
1676 
1677 		case ISOPROTO_TP:
1678 		case ISOPROTO_X25:
1679 			/* hl is TP or X.25 */
1680 			if (addr->siso_addr.isoa_afi != AFI_37)
1681 				return E_CO_AIWP;
1682 				/* kludge - necessary because this is the only type of
1683 				 * NSAP we build for an incoming NC
1684 				 */
1685 			break;
1686 		default: /* unsupported */
1687 			return E_CO_HLI_PROTOID;
1688 	}
1689 	return EOK;
1690 }
1691 /*
1692  * NAME:	cons_incoming()
1693  * CALLED FROM:
1694  *  consintr() for incoming OPEN
1695  * FUNCTION and ARGUMENTS:
1696  *  Determines which higher layer gets this call, and
1697  *  thus whether to immediately accept, reject, or to let the
1698  *	higher layer determine this question.
1699  */
1700 Static
1701 cons_incoming(ifp, ecnrq)
1702 	struct ifnet 					*ifp;
1703 	register struct eicon_request 	*ecnrq;
1704 {
1705 	struct sockaddr_iso 	me;
1706 	struct sockaddr_iso 	peer;
1707 	struct cons_pcb			*copcb;
1708 	int 					loop = 0;
1709 	int						proto =0;
1710 	int						error = 0;
1711 	struct	dte_addr		peer_dte;
1712 
1713 	IFDEBUG(D_INCOMING)
1714 		printf("consincoming enter: ifp 0x%x ecnrq 0x%x\n", ifp, ecnrq);
1715 	ENDDEBUG
1716 	bzero( &me, sizeof(me));
1717 	error = parse_facil( mtod(e_data(ecnrq), caddr_t),
1718 						(e_data(ecnrq))->m_len, &me, &peer, &proto,
1719 						&peer_dte);
1720 	loop = is_me( &peer ); /* <-- THIS may be a problem :
1721 							* peer may be nonsense.
1722 							* We can only expect that WE will do it right
1723 							* and never will we get an error return from
1724 							* parse_facil on a facil that WE generated,
1725 							* so if garbage comes in, peer will be garbage,
1726 							* and loop will be false.
1727 							*/
1728 	if( error != EOK ) {
1729 		(void) issue_clear_req(ecnrq->e_vc, error, ifp, loop);
1730 		IncStat(co_parse_facil_err);
1731 		IncStat(co_Rdrops);
1732 		return;
1733 	}
1734 
1735 	if( (error = addr_proto_consistency_check(proto, &me)) != EOK ) {
1736 		/* problem with consistency */
1737 		(void) issue_clear_req(ecnrq->e_vc, error, ifp, loop);
1738 		IncStat(co_addr_proto_consist_err);
1739 		IncStat(co_Rdrops);
1740 		return;
1741 	} else {
1742 		switch( proto ) {
1743 			case ISOPROTO_X25:
1744 				copcb = (struct cons_pcb *)
1745 						((struct cons_pcb *)(&cons_isopcb))->co_next;
1746 
1747 				while (copcb != (struct cons_pcb *)&cons_isopcb) {
1748 					if( copcb->co_lport == me.siso_tsuffix ) {
1749 						/* for cons "transport service",
1750 						 * multiplexing is not allowed
1751 						 */
1752 						if( !copcb->co_socket ) {
1753 							printf(
1754 							"PANIC cons_incoming NOT TP but no sock\n");
1755 							copcb = (struct cons_pcb *)0;
1756 							break;
1757 						}
1758 						if( copcb->co_socket->so_options & SO_ACCEPTCONN ) {
1759 							struct cons_pcb *newx;
1760 
1761 							newx = (struct cons_pcb *)
1762 									sonewconn(copcb->co_socket)->so_pcb;
1763 							newx->co_laddr = copcb->co_laddr;
1764 							newx->co_peer_dte = peer_dte;
1765 							newx->co_proto = copcb->co_proto;
1766 							newx->co_myself = newx;
1767 							touch(copcb);
1768 							copcb = newx;
1769 							soisconnected(copcb->co_socket);
1770 							break;
1771 						} /* else keep looking */
1772 					}
1773 					copcb = (struct cons_pcb *)copcb->co_next;
1774 				}
1775 				if (copcb == (struct cons_pcb *)&cons_isopcb)
1776 					copcb = (struct cons_pcb *) 0;
1777 				break;
1778 
1779 			case ISOPROTO_TP:
1780 				ASSERT( me.siso_tsuffix == 0 );
1781 				/*
1782 				 * We treat this rather like we do for CLNP.
1783 				 * TP can't tell which socket
1784 				 * wants this until the TP header comes in, so there's no way
1785 				 * to associate this channel with a tpcb/isopcb.
1786 				 * We assume data will arrive (a CR TPDU) and be given to TP along with
1787 				 * the channel number.  We can then expect TP to call us with
1788 				 * the channel number and pcb ptr, telling us to keep this connection
1789 				 * or clear it.
1790 				 * Now, tp will have created an isopcb in the tp_isopcb list.
1791 				 * We will have to keep another copcb though, because there is no
1792 				 * 1-1 correspondence between socket and copcb when multiplexing
1793 				 * is allowed.
1794 				 * But we want to save the peer address, ifp, and state, proto.
1795 				 * If the channel should clear before TP responds, we need
1796 				 * to know that also, so we create a tp-pending list...
1797 				 */
1798 				if( cons_pcballoc(&dummysocket, &tp_incoming_pending,
1799 								CONSF_ICRE, TP_proto, &copcb) != EOK )  {
1800 					copcb = (struct cons_pcb *)0;
1801 				} else {
1802 					copcb->co_peer_dte = peer_dte;
1803 				}
1804 				break;
1805 
1806 
1807 			case ISOPROTO_CLNP:
1808 				if( cons_pcballoc(&dummysocket, &cons_isopcb,
1809 						CONSF_ICRE | CONSF_DGM, CLNP_proto, &copcb ) != EOK ) {
1810 					/* choke */
1811 					copcb = (struct cons_pcb *)0;
1812 				} else {
1813 					copcb->co_peer_dte = peer_dte;
1814 				}
1815 				break;
1816 
1817 		default:
1818 			panic("cons_incoming");
1819 		} /* end switch */
1820 
1821 		if(copcb) {
1822 			touch(copcb);
1823 			copcb->co_channel = (int)ecnrq->e_vc;
1824 			ASSERT( copcb->co_channel != 0);
1825 			copcb->co_state = OPEN;
1826 			copcb->co_ifp = ifp;
1827 			copcb->co_laddr = me;
1828 			copcb->co_faddr = peer;
1829 			if(loop)
1830 				copcb->co_flags |= CONSF_LOOPBACK;
1831 			IFDEBUG(D_CADDR)
1832 				printf("cons_incoming found XPCB 0x%x, loop 0x%x\n",
1833 						copcb, loop);
1834 				printf("\nco_laddr: ");
1835 				dump_buf(&copcb->co_laddr, sizeof(copcb->co_laddr));
1836 				printf("\nco_faddr: ");
1837 				dump_buf(&copcb->co_faddr, sizeof(copcb->co_faddr));
1838 				printf("\n");
1839 			ENDDEBUG
1840 		} else {
1841 			ifp->if_ierrors ++;
1842 			(void) issue_clear_req(ecnrq->e_vc, E_CO_OSI_UNSAP, ifp, loop);
1843 			IncStat(co_no_copcb);
1844 			IncStat(co_Rdrops);
1845 		}
1846 	}
1847 	/* caller frees the mbuf so we don't have to do any such thing */
1848 }
1849 
1850 /*
1851  **************************** DEVICE cons ***************************
1852  */
1853 
1854 /*
1855  * NAME:	cosns_output()
1856  * CALLED FROM:
1857  *  clnp - this routine is given as the device-output routine
1858  *  for the adcom driver.
1859  * FUNCTION and ARGUMENTS:
1860  *  (ifp) is the cons/adcom, found by routing function.
1861  *  (m0) is the clnp datagram.
1862  *  (dst) is the destination address
1863  * This routine finds an x.25 connection for datagram use and
1864  * sends the packet.
1865  */
1866 int
1867 cosns_output(ifp, m0, dst)
1868 {
1869 	return cosns_output1(ifp, m0, dst, CLNP_proto, NULL);
1870 }
1871 
1872 /* DEBUGGING ONLY? */
1873 int	total_cosns_len = 0;
1874 int	total_cosns_cnt = 0;
1875 int	total_pkts_to_clnp = 0;
1876 
1877 /*
1878  *		The isop is passed here so that if we have set x25crud in the
1879  *		pcb, it can be passed down to cons_connect. It could be null
1880  *		however, in the case of tp4/x25/clnp
1881  */
1882 Static int
1883 cosns_output1(ifp, m0, dst, proto, isop)
1884 	struct ifnet *ifp;
1885 	register struct mbuf *m0;
1886 	struct sockaddr_iso *dst;
1887 	struct protosw *proto;
1888 	struct isopcb	*isop;		/* NULL if coming from clnp */
1889 {
1890 	register struct cons_pcb *copcb;
1891 	int 					s = splnet();
1892 	int						error = 0;
1893 
1894 	{ 	register struct mbuf *n=m0;
1895 		register int len = 0;
1896 
1897 		for(;;) {
1898 			len += n->m_len;
1899 			if (n->m_next == MNULL ) {
1900 				break;
1901 			}
1902 			n = n->m_next;
1903 		}
1904 		total_cosns_len += len;
1905 		total_cosns_cnt ++;
1906 
1907 	}
1908 
1909 	IFDEBUG(D_CCONS)
1910 		printf("cosns_output1( ifp 0x%x, m 0x%x, dst 0x%x )\n", ifp, m0, dst );
1911 	ENDDEBUG
1912 	if ( ! (copcb = cons_find( CONSF_DGM, dst, proto, 0, 0) )) {
1913 		struct cons_pcb *newcopcb; /* so we can pass addr of this to pcballoc */
1914 
1915 		if( (error = cons_pcballoc(&dummysocket, &cons_isopcb,
1916 				CONSF_DGM | CONSF_OCRE, proto, &newcopcb) )  != EOK ) {
1917 			IFDEBUG(D_CCONS)
1918 				printf("cosns_output: no copcb; returns \n");
1919 			ENDDEBUG
1920 			(void) m_freem(m0);
1921 			goto done;
1922 		}
1923 		copcb = newcopcb;
1924 
1925 		/* abbreviated form of iso_pcbconnect(): */
1926 		bcopy((caddr_t)dst, (caddr_t)&copcb->co_faddr,
1927 									sizeof(struct sockaddr_iso));
1928 
1929 		/* copy x25crud into copcb if necessary */
1930 		if ((isop != NULL) && (isop->isop_x25crud_len > 0)) {
1931 			bcopy(isop->isop_x25crud, copcb->co_x25crud,
1932 				isop->isop_x25crud_len);
1933 			copcb->co_x25crud_len = isop->isop_x25crud_len;
1934 		}
1935 
1936 		copcb->co_ifp = ifp; /* NULL IF COMING FROM TP4! */
1937 
1938 		if ( error = cons_connect( copcb ) ) { /* if it doesn't work */
1939 			/* oh, dear, throw packet away */
1940 			remque((struct isopcb *)copcb);
1941 			(void) m_free(dtom(copcb));
1942 			(void) m_freem(m0);
1943 			goto done;
1944 		}
1945 	}
1946 	IFDEBUG(D_CDATA)
1947 		printf("cosns_output1 @ senddata: state 0x%x flags 0x%x channel 0x%x\n",
1948 			copcb->co_state, copcb->co_flags, copcb->co_channel);
1949 	ENDDEBUG
1950 	ASSERT(copcb->co_channel != X_NOCHANNEL);
1951 	error = cons_senddata(copcb, m0);
1952 done:
1953 	splx(s);
1954 	return error;
1955 }
1956 
1957 
1958 /*
1959  **************************** TRANSPORT cons ***************************
1960  */
1961 
1962 
1963 /*
1964  * NAME:	cons_detach()
1965  * CALLED FROM:
1966  *  cons_usrreq() on PRU_DETACH
1967  *  cons_netcmd() when TP releases a net connection
1968  *	cons_slowtimo()  when timeout releases a net connection
1969  * FUNCTION and ARGUMENT:
1970  *  removes the copcb from the list of copcbs in use, and frees the mbufs.
1971  *  detaches the pcb from the socket, where a socket exists.
1972  * RETURN VALUE:
1973  *  ENOTCONN if it couldn't find the copcb in the list of connections.
1974  */
1975 
1976 Static int
1977 cons_detach( copcb )
1978 	register struct cons_pcb *copcb;
1979 {
1980 	struct socket *so = copcb->co_socket;
1981 
1982 	IFDEBUG(D_CCONN)
1983 		printf("cons_detach( copcb 0x%x )\n", copcb);
1984 	ENDDEBUG
1985 	if(so) {
1986 		if (so->so_head) {
1987 			if (!soqremque(so, 0) && !soqremque(so, 1))
1988 				panic("sofree dq");
1989 			so->so_head = 0;
1990 		}
1991 		((struct isopcb *)copcb)->isop_options = 0; /* kludge */
1992 		iso_pcbdetach(copcb); /* detaches from so */
1993 	} else {
1994 		remque((struct isopcb *)copcb);
1995 		(void) m_free(dtom(copcb));
1996 	}
1997 }
1998 
1999 Static int
2000 cons_clear_and_detach(copcb, clearreason, ctlcmd)
2001 	register struct cons_pcb *copcb;
2002 	int					clearreason;
2003 	int						ctlcmd;
2004 {
2005 	IFDEBUG(D_CCONN)
2006 		printf("Clear and Detach (0x%x, 0x%x, 0x%x)\n",
2007 						copcb, clearreason, ctlcmd);
2008 	ENDDEBUG
2009 	if( clearreason != DONTCLEAR ) {
2010 		(void) cons_clear( copcb ,  clearreason );
2011 	}
2012 	if( copcb->co_proto  && copcb->co_proto->pr_ctlinput )
2013 		(*copcb->co_proto->pr_ctlinput)(ctlcmd,
2014 			(struct sockaddr_iso *)&copcb->co_faddr, (caddr_t)copcb);
2015 
2016 	if( copcb->co_socket == (struct socket *)0 ) {
2017 		/* tp4, clnp users only */
2018 		(void) cons_detach( copcb );
2019 	} /* else detach will be called by the socket's closing */
2020 		else {
2021 			ASSERT( copcb->co_socket != &dummysocket );
2022 			ASSERT( (copcb->co_flags & CONSF_DGM) == 0 );
2023 	}
2024 	IFDEBUG(D_CCONN)
2025 		printf("END OF Clear and Detach (0x%x, 0x%x, 0x%x)\n",
2026 						copcb, clearreason, ctlcmd);
2027 	ENDDEBUG
2028 }
2029 
2030 Static int
2031 cons_pcbbind( copcb, nam )
2032 	register struct cons_pcb *copcb;
2033 	struct mbuf *nam;
2034 {
2035 	int error;
2036 
2037 	if( error = iso_pcbbind( copcb, nam) )
2038 		return error;
2039 
2040 	/* iso_pcbbind already ensured that if port < 1024 it's superuser */
2041 	/* Now we check: must be in range 0 .. 23 or in range 1024 .. 99 */
2042 
2043 	if( (copcb->co_lport < X25_PORT_RESERVED)  ||
2044 			 ((copcb->co_lport >= ISO_PORT_RESERVED) &&
2045 			  (copcb->co_lport <= X25_PORT_USERMAX))) {
2046 		munge( copcb->co_lport, (&copcb->co_laddr)->siso_addr.t37_idi +
2047 			ADDR37_IDI_LEN, 1 /* nibble */);
2048 		munge( copcb->co_fport, (&copcb->co_faddr)->siso_addr.t37_idi +
2049 			ADDR37_IDI_LEN, 1 /* nibble */);
2050 		 return 0;
2051 	} else
2052 		return EADDRNOTAVAIL;
2053 }
2054 /*
2055  * NAME:	cons_usrreq()
2056  * CALLED FROM:
2057  *  user level via proto switch
2058  * FUNCTION and ARGUMENTS:
2059  *  so : socket
2060  *  req: which PRU* request
2061  *  m : data or mbuf ptr into which to stash data
2062  *	nam: mbuf ptr which is really a sockaddr_iso
2063  *  ifq: in PRU_CONTROL case, an ifnet structure
2064  * RETURN VALUE:
2065  *  ENOTCONN if trying to do something which requires a connection
2066  * 	 and it's not yet connected
2067  *  EISCONN if trying to do something which cannot be done to a connection
2068  * 	 but it's connected
2069  * 	ENOBUFS if ran out of mbufs
2070  * 	EWOULDBLOCK if in nonblocking mode & can't send right away
2071  * 	EOPNOSUPP if req isn't supported
2072  * 	E* other passed up from lower layers or from other routines
2073  */
2074 
2075 cons_usrreq(so, req, m, nam, ifp)
2076 	struct socket *so;
2077 	u_int req;
2078 	struct mbuf *m, *nam;
2079 	int *ifp;
2080 {
2081 	struct cons_pcb *copcb =  (struct cons_pcb *)so->so_pcb;
2082 	int 					s = splnet();
2083 	int 					error = 0;
2084 
2085 	IFDEBUG(D_CCONS)
2086 		printf("cons_usrreq 0x%x so 0x%x copcb 0x%x\n", req, so, copcb);
2087 	ENDDEBUG
2088 	if (req == PRU_CONTROL) {
2089 		error =  iso_control(so, (int)m, (caddr_t)nam, (struct ifnet *)ifp);
2090 		splx(s);
2091 		return error;
2092 	}
2093 	if (copcb == (struct cons_pcb *)0  &&  req != PRU_ATTACH) {
2094 		splx(s);
2095 		return ENOTCONN;
2096 	}
2097 
2098 	switch (req) {
2099 
2100 	case PRU_ATTACH:
2101 		if (copcb) {
2102 			error = EISCONN;
2103 			break;
2104 		}
2105 		soreserve(so, X25_SBSIZE, X25_SBSIZE); /* CONS size */
2106 		error = cons_pcballoc(so, &cons_isopcb, CONSF_XTS, X25_proto, &copcb );
2107 		break;
2108 
2109 	case PRU_ABORT: 	/* called from close() */
2110 		/* called for each incoming connect queued on the parent (accepting)
2111 		 * socket (SO_ACCEPTCONN);
2112 		 */
2113 		 error = cons_detach ( copcb );
2114 		 break;
2115 
2116 	case PRU_DETACH: 	/* called from close() */
2117 		/* called after disconnect was called iff was connected at the time
2118 		 * of the close, or directly if socket never got connected */
2119 		error = cons_detach ( copcb );
2120 		break;
2121 
2122 	case PRU_SHUTDOWN:
2123 		/* recv end may have been released; local credit might be zero  */
2124 	case PRU_DISCONNECT:
2125 		soisdisconnected(so);
2126 			error = cons_clear(copcb, E_CO_HLI_DISCN);
2127 		break;
2128 
2129 	case PRU_BIND:
2130 		error = cons_pcbbind( copcb, nam);
2131 		break;
2132 
2133 	case PRU_LISTEN:
2134 		if (copcb->co_lport == 0)
2135 			error = cons_pcbbind( copcb, 0 );
2136 		break;
2137 
2138 
2139 	case PRU_SOCKADDR: {
2140 			struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *);
2141 
2142 			nam->m_len = sizeof (struct sockaddr_iso);
2143 			if(copcb->co_ifp)
2144 				bcopy( (caddr_t)&copcb->co_laddr,
2145 						(caddr_t)siso, sizeof(struct sockaddr_iso) );
2146 
2147 			((struct sockaddr_iso *)siso)->siso_tsuffix = copcb->co_lport;
2148 		}
2149 		break;
2150 
2151 	case PRU_PEERADDR:
2152 		if( (so->so_state & SS_ISCONNECTED) &&
2153 			(so->so_state & SS_ISDISCONNECTING) == 0) {
2154 				struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *);
2155 
2156 			nam->m_len = sizeof (struct sockaddr_iso);
2157 			bcopy( (caddr_t)&copcb->co_faddr, (caddr_t)siso,
2158 									sizeof(struct sockaddr_iso) );
2159 		} else
2160 			error = ENOTCONN;
2161 		break;
2162 
2163 	case PRU_CONNECT:
2164 		/* TODO: We need to bind to the RIGHT interface.
2165 		 * The only way to have the right interface is to have
2166 		 * the right route.
2167 		 */
2168 		IFDEBUG(D_CCONN)
2169 			printf("PRU_CONNECT 1: local tsuffix 0x%x so->so_head 0x%x nam:\n",
2170 				copcb->co_lport, so->so_head);
2171 			dump_isoaddr( mtod(nam, struct sockaddr_iso *) );
2172 		ENDDEBUG
2173 		if (copcb->co_lport == 0) {
2174 			if( error = cons_pcbbind( copcb, 0 ))
2175 				break;
2176 		}
2177 		IFDEBUG(D_CCONN)
2178 			printf("PRU_CONNECT 2: local tsuffix 0x%x so->so_head 0x%x nam:\n",
2179 				copcb->co_lport, so->so_head);
2180 			dump_isoaddr( mtod(nam, struct sockaddr_iso *) );
2181 		ENDDEBUG
2182 
2183 		{ 	/* change the destination address so the last 2 digits
2184 			 * are the port/suffix/selector (whatever you want to call it)
2185 			 */
2186 			register struct sockaddr_iso *siso =
2187 							mtod(nam, struct sockaddr_iso *);
2188 			if( (siso->siso_tsuffix < X25_PORT_RESERVED)  ||
2189 				 ((siso->siso_tsuffix >= ISO_PORT_RESERVED) &&
2190 				  (siso->siso_tsuffix <= X25_PORT_USERMAX)))
2191 			munge( siso->siso_tsuffix,
2192 					siso->siso_addr.t37_idi + ADDR37_IDI_LEN,
2193 					1 /* nibble */);
2194 		}
2195 
2196 		soisconnecting(so);
2197 		if (error = iso_pcbconnect(copcb, nam))
2198 			break;
2199 		error = cons_connect( copcb );
2200 		if ( error ) {
2201 			/*
2202 			remque((struct isopcb *)copcb);
2203 			(void) m_free(dtom(copcb));
2204 			*/
2205 			break;
2206 		}
2207 		while( (copcb->co_state != OPEN)&&(copcb->co_socket->so_error == 0) ) {
2208 			IFDEBUG(D_CCONN)
2209 				printf("PRU_CONNECT: error 0x%x sleeping on 0x%x\n",
2210 					copcb->co_socket->so_error,
2211 					(caddr_t)&copcb->co_state );
2212 			ENDDEBUG
2213 			sleep((caddr_t)&copcb->co_state, PZERO+3, SLP_ISO_CONS, 0 );
2214 		}
2215 
2216 		ASSERT( copcb->co_channel != 0);
2217 
2218 		SET_CHANMASK ( (struct isopcb *)copcb, copcb->co_channel);
2219 		break;
2220 
2221 	case PRU_ACCEPT:
2222 		/* so here is the NEW socket */
2223 		so->so_error = 0;
2224 		if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTED)== 0) {
2225 			error = EWOULDBLOCK;
2226 			break;
2227 		}
2228 		{
2229 			struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *);
2230 
2231 			/* copy the peer's address into the return argument */
2232 			nam->m_len = sizeof (struct sockaddr_iso);
2233 			bcopy( (caddr_t)&copcb->co_faddr, (caddr_t)siso,
2234 				sizeof(struct sockaddr_iso));
2235 		}
2236 		break;
2237 
2238 	case PRU_SEND:
2239 	case PRU_SENDEOT:
2240 		/*
2241 		 * sosend calls this until sbspace goes negative.
2242 		 * Sbspace may be made negative by appending this mbuf chain,
2243 		 * possibly by a whole cluster.
2244 		 */
2245 		{
2246 			/* no need to actually queue this stuff and dequeue it,
2247 			 * just bump the pointers in so_snd so that higher
2248 			 * layer of socket code will cause it to sleep when
2249 			 * we've run out of socket space
2250 			 * TODO:
2251 			 * Unfortunately that makes sbflush vomit so we have
2252 			 * to allocate a single real mbuf (say size 240)
2253 			 * and sballoc it and sbfree it upon CONS_SEND_DONE.
2254 			 * Oh, my, is this sickening or what?
2255 			 */
2256 			{
2257 				struct mbuf *mx;
2258 
2259 				MGET(mx, M_DONTWAIT, MT_DATA);
2260 				mx->m_len = MLEN;
2261 				sbappend((caddr_t)&copcb->co_socket->so_snd, mx);
2262 			}
2263 			if( m ) {
2264 				IFDEBUG(D_CDATA)
2265 					printf("X.25 Usrreq calling cons_senddata(0x%x, 0x%x)\n",
2266 						copcb, m);
2267 				ENDDEBUG
2268 				error = cons_senddata(copcb, m);
2269 			}
2270 			IFDEBUG(D_CCONS)
2271 				printf("PRU_SEND sent tsuffix 0x%x, m 0x%x error 0x%x\n",
2272 					copcb->co_lport, m, error);
2273 			ENDDEBUG
2274 
2275 			if( req == PRU_SENDEOT ) {
2276 				while(copcb->co_socket->so_snd.sb_cc > 0)
2277 					sbwait(&copcb->co_socket->so_snd);
2278 			}
2279 		}
2280 		break;
2281 
2282 	case PRU_CONTROL:
2283 		error = cons_ioctl(so, m, (caddr_t)nam);
2284 		break;
2285 
2286 
2287 	case PRU_RCVD:
2288 	case PRU_RCVOOB:
2289 	case PRU_SENDOOB:
2290 		/* COULD support INTERRUPT packets as oob */
2291 	case PRU_PROTOSEND:
2292 	case PRU_PROTORCV:
2293 	case PRU_SENSE:
2294 	case PRU_SLOWTIMO:
2295 	case PRU_CONNECT2:
2296 	case PRU_FASTTIMO:
2297 	default:
2298 		error = EOPNOTSUPP;
2299 	}
2300 
2301 	IFDEBUG(D_CCONS)
2302 		printf("cons_usrreq cmd 0x%x copcb 0x%x returned error 0x%x\n",
2303 			req, copcb, error);
2304 	ENDDEBUG
2305 	splx(s);
2306 	return error;
2307 }
2308 
2309 /*
2310  * NAME:	cons_input()
2311  * CALLED FROM:
2312  *  consintr() through the isosw protosw for "transport" version of X25
2313  * FUNCTION & ARGUMENTS:
2314  *  process incoming data
2315  */
2316 cons_input(m, faddr, laddr, so)
2317 	register struct mbuf *m;
2318 	struct sockaddr_iso *faddr, *laddr; /* not used */
2319 	register struct socket *so;
2320 {
2321 	IFDEBUG(D_CCONS)
2322 		printf("cons_input( m 0x%x, so 0x%x)\n", m,so);
2323 	ENDDEBUG
2324 	sbappend(&so->so_rcv, m);
2325 	sbwakeup(&so->so_rcv);
2326 }
2327 
2328 #ifdef notdef
2329 /*
2330  * NAME:	cons_ctloutput()
2331  * CALLED FROM:
2332  *  set/get sockopts()
2333  * 	Presently the protosw has 0 in the ctloutput spot
2334  *	 because we haven't inplemented anything yet.
2335  * 	If there's reason to put some options in here,
2336  * 	be sure to stick this routine name in the protosw in iso_proto.c
2337  */
2338 cons_ctloutput(cmd, so, level, optname, mp)
2339 	int 			cmd, level, optname;
2340 	struct socket	*so;
2341 	struct mbuf 	**mp;
2342 {
2343 	int 			s = splnet();
2344 
2345 	splx(s);
2346 	return EOPNOTSUPP;
2347 }
2348 #endif notdef
2349 
2350 
2351 /*
2352  * NAME:	cons_ctlinput()
2353  * CALLED FROM:
2354  *  lower layer when ECN_CLEAR occurs : this routine is here
2355  *  for consistency - cons subnet service calls its higher layer
2356  *  through the protosw entry.
2357  * FUNCTION & ARGUMENTS:
2358  *  cmd is a PRC_* command, list found in ../sys/protosw.h
2359  *  copcb is the obvious.
2360  *  This serves the higher-layer cons service.
2361  * NOTE: this takes 3rd arg. because cons uses it to inform itself
2362  *  of things (timeouts, etc) but has a pcb instead of an address.
2363  */
2364 cons_ctlinput(cmd, sa, copcb)
2365 	int cmd;
2366 	struct sockaddr *sa;
2367 	register struct cons_pcb *copcb;
2368 {
2369 	int 			error = 0;
2370 	int 			s = splnet();
2371 	extern u_char 	inetctlerrmap[];
2372 	extern int 		iso_rtchange();
2373 
2374 	IFDEBUG(D_CCONS)
2375 		printf("cons_ctlinput( cmd 0x%x, copcb 0x%x)\n", cmd, copcb);
2376 	ENDDEBUG
2377 	/* co_socket had better exist */
2378 	switch (cmd) {
2379 		case PRC_CONS_SEND_DONE:
2380 			ASSERT( copcb->co_socket );
2381 			ASSERT( copcb->co_flags & CONSF_XTS );
2382 			sbdrop((caddr_t)&copcb->co_socket->so_snd, MLEN);
2383 			sbwakeup((caddr_t)&copcb->co_socket->so_snd);
2384 			break;
2385 
2386 		case PRC_ROUTEDEAD:
2387 			error = ENETUNREACH;
2388 			break;
2389 
2390 		case PRC_TIMXCEED_REASS:
2391 			error = ETIMEDOUT;
2392 			break;
2393 
2394 	/*
2395 		case PRC_QUENCH:
2396 			iso_pcbnotify(&cons_pcb, sa,
2397 					(int)inetctlerrmap[cmd], iso_rtchange);
2398 			iso_pcbnotify(&tp_incoming_pending, sa,
2399 					(int)inetctlerrmap[cmd], tpiso_quench);
2400 			iso_pcbnotify(&tp_isopcb, sa,
2401 					(int)inetctlerrmap[cmd], tpiso_quench);
2402 	*/
2403 
2404 		case PRC_IFDOWN:
2405 			iso_pcbnotify(&cons_isopcb, sa,
2406 					(int)inetctlerrmap[cmd], iso_rtchange);
2407 			iso_pcbnotify(&tp_incoming_pending, sa,
2408 					(int)inetctlerrmap[cmd], iso_rtchange);
2409 			iso_pcbnotify(&tp_isopcb, sa,
2410 					(int)inetctlerrmap[cmd], iso_rtchange);
2411 			break;
2412 
2413 
2414 		default:
2415 			printf("cons_ctlinput: unknown cmd 0x%x\n", cmd);
2416 	}
2417 	if(error) {
2418 		soisdisconnected(copcb->co_socket);
2419 		sohasoutofband(copcb->co_socket);
2420 	}
2421 	splx(s);
2422 }
2423 
2424 /*
2425  *********************** SERVES ALL cons embodiments  *******************
2426  */
2427 
2428 /*
2429  * NAME:	cons_chan_to_pcb()
2430  * CALLED FROM:
2431  *  cons_chan_to_tpcb() in tp_cons.c
2432  * and in this file: incoming requests that give only a channel number, i.e.,
2433  *  ECN_ACCEPT, ECN_RECEIVE, ECN_CLEAR
2434  * FUNCTION:
2435  *  identify the pcb assoc with that channel
2436  * RETURN:
2437  *  ptr to the pcb
2438  */
2439 struct cons_pcb *
2440 #ifdef ARGO_DEBUG
2441 cons_chan_to_pcb( channel, linenumber )
2442 	int	linenumber;
2443 #else ARGO_DEBUG
2444 cons_chan_to_pcb( channel)
2445 #endif ARGO_DEBUG
2446 	register int channel;
2447 {
2448 	register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist;
2449 	register struct cons_pcb *copcb;
2450 
2451 	/* just to be sure */
2452 	channel = channel & 0xff;
2453 
2454 	for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) {
2455 		copcb = (struct cons_pcb *)copcb->co_next;
2456 		while (copcb !=  *copcblist) {
2457 			if ( copcb->co_channel == channel )
2458 				goto found; /* want to break out of both loops */
2459 
2460 			copcb = (struct cons_pcb *)copcb->co_next;
2461 		}
2462 	}
2463 found: /* or maybe not... */
2464 	IFDEBUG(D_CCONS)
2465 		printf("cons_chan_to_pcb( 0x%x, %d ) %s 0x%x\n", channel, linenumber,
2466 			copcb?"FOUND":"FAILED", copcb);
2467 	ENDDEBUG
2468 
2469 	return copcb;
2470 }
2471 
2472 
2473 /*
2474  * NAME:	is_me()
2475  * CALLED FROM:
2476  *  cons_incoming().  Perhaps could just expand in line.
2477  * FUNCTION and ARGUMENTS:
2478  * 	for the given remote address (remadr) if it exactly matches
2479  *  one of the addresses of ME, and I am up as loopback,
2480  *  return TRUE, else return FALSE.
2481  * RETURNS:
2482  *  Boolean
2483  */
2484 Static int
2485 is_me(remaddr)
2486 	struct	sockaddr_iso	*remaddr;
2487 {
2488 	struct	ifnet 			*ifp = consif;
2489 									/* PHASE2: this is ok */
2490 	struct ifaddr 			*ifa = ifa_ifwithaddr(remaddr);
2491 
2492 	IFDEBUG(D_CADDR)
2493 		printf("is_me: withaddr returns %s\n",
2494 			ifa?ifa->ifa_ifp->if_name:"NONE");
2495 	ENDDEBUG
2496 	if( ifa ) {
2497 		/* remaddr matches one of my interfaces exactly */
2498 		if( ifa->ifa_ifp->if_flags & IFF_LOOPBACK ) {
2499 			ASSERT( ifp == ifa->ifa_ifp );
2500 			return 1;
2501 		}
2502 	}
2503 	return 0;
2504 }
2505 
2506 find_error_reason( ecnrq )
2507 	register struct eicon_request 	*ecnrq;
2508 {
2509 	extern u_char x25_error_stats[];
2510 	int error;
2511 	struct mbuf *cdm;
2512 	struct e_clear_data *ecd;
2513 
2514 	cdm = e_data(ecnrq);
2515 	if( cdm && cdm->m_len > 0 ) {
2516 		ecd = mtod(cdm, struct e_clear_data *);
2517 		switch( ecd->ecd_cause ) {
2518 			case 0x00:
2519 			case 0x80:
2520 				/* DTE originated; look at the diagnostic */
2521 				error = (CONL_ERROR_MASK | ecd->ecd_diagnostic);
2522 				goto done;
2523 
2524 			case 0x01: /* number busy */
2525 			case 0x81:
2526 			case 0x09: /* Out of order */
2527 			case 0x89:
2528 			case 0x11: /* Remot Procedure Error */
2529 			case 0x91:
2530 			case 0x19: /* reverse charging accept not subscribed */
2531 			case 0x99:
2532 			case 0x21: /* Incampat destination */
2533 			case 0xa1:
2534 			case 0x29: /* fast select accept not subscribed */
2535 			case 0xa9:
2536 			case 0x39: /* ship absent */
2537 			case 0xb9:
2538 			case 0x03: /* invalid facil request */
2539 			case 0x83:
2540 			case 0x0b: /* access barred */
2541 			case 0x8b:
2542 			case 0x13: /* local procedure error */
2543 			case 0x93:
2544 			case 0x05: /* network congestion */
2545 			case 0x85:
2546 			case 0x8d: /* not obtainable */
2547 			case 0x0d:
2548 			case 0x95: /* RPOA out of order */
2549 			case 0x15:
2550 				/* take out bit 8
2551 				 * so we don't have to have so many perror entries
2552 				 */
2553 				error = (CONL_ERROR_MASK | 0x100 | (ecd->ecd_cause & ~0x80));
2554 				goto done;
2555 
2556 			case 0xc1: /* gateway-detected proc error */
2557 			case 0xc3: /* gateway congestion */
2558 
2559 				error = (CONL_ERROR_MASK | 0x100 | ecd->ecd_cause);
2560 				goto done;
2561 		}
2562 	}
2563 	/* otherwise, a *hopefully* valid perror exists in the e_reason field */
2564 	error = ecnrq->e_reason;
2565 	if (error = 0) {
2566 		printf("Incoming PKT TYPE 0x%x with reason 0x%x\n",
2567 			ecnrq->e_cmd,
2568 			ecnrq->e_reason);
2569 		error = E_CO_HLI_DISCA;
2570 	}
2571 
2572 done:
2573 	if(error & 0x1ff == 0) {
2574 		error = 0;
2575 	} else if( error & 0x1ff > sizeof(x25_error_stats)) {
2576 			ASSERT(0);
2577 	} else {
2578 			x25_error_stats[error& 0x1ff] ++;
2579 	}
2580 	return error;
2581 }
2582 
2583 /*
2584  * NAME:	consintr()
2585  * CALLED FROM:
2586  *  the eicon driver via software interrupt
2587  * FUNCTION and ARGUMENTS:
2588  *  processes incoming indications, passing them
2589  *  along to clnp, tp, or x.25-transport as appropriate.
2590  */
2591 consintr()
2592 {
2593 	struct	ifnet 					*ifp = consif;
2594 	register struct eicon_request 	*ecnrq;
2595 	register struct cons_pcb 		*copcb = (struct cons_pcb *)0;
2596 	register struct mbuf 			*m;
2597 	int 							s, s0 = splnet();
2598 
2599 	IncStat(co_intr);
2600 	ifp->if_ipackets ++;
2601 
2602 	for(;;) {
2603 		/*
2604 		 * Get next request off input queue
2605 		 */
2606 		s = splimp();
2607 		IF_DEQUEUE(&consintrq, m);
2608 		splx(s);
2609 		IFDEBUG(D_INCOMING)
2610 			printf("cons intr() 0x%x m_off 0x%x m_len 0x%x dequeued\n",
2611 				m, m?m->m_off:0, m?m->m_len:0);
2612 		ENDDEBUG
2613 
2614 		if (m == 0) {
2615 			splx(s0);
2616 			return;
2617 		}
2618 
2619 		if((m->m_off != MMINOFF)||(m->m_len != sizeof (struct eicon_request))){
2620 			ifp->if_ierrors ++;
2621 			IncStat(co_Rdrops);
2622 			printf("Cons R DROP! BAD MBUF FROM LL 0x%x sizeof(...) 0x%x\n",
2623 					m, sizeof(struct eicon_request));
2624 			continue;
2625 		}
2626 
2627 		ecnrq = mtod(m, struct eicon_request *);
2628 
2629 
2630 		IFDEBUG(D_INCOMING)
2631 			printf("INTR: e_cmd 0x%x, e_data 0x%x\n", ecnrq->e_cmd,
2632 				e_data(ecnrq));
2633 			if( e_data(ecnrq) != 0 ) {
2634 				/* let's just look at the first few bytes */
2635 				/*
2636 				dump_buf( e_data(ecnrq), (e_data(ecnrq))->m_len + 12);
2637 				*/
2638 				dump_buf( e_data(ecnrq), 20  + 12);
2639 			}
2640 		ENDDEBUG
2641 		IFTRACE(D_CDATA)
2642 			tptrace( TPPTmisc, "INTR: req_type m lun\n",
2643 				ecnrq->e_cmd, m, ecnrq->e_vc, 0);
2644 		ENDTRACE
2645 
2646 		switch( ecnrq->e_cmd ) {
2647 
2648 			case ECN_ACK:  /* data put on the board */
2649 				IncStat(co_ack);
2650 				ASSERT( ecnrq->e_vc != 0);
2651 				/* from ACKWAIT to OPEN */
2652 				if ( (copcb =
2653 #ifdef ARGO_DEBUG
2654 					cons_chan_to_pcb( (int)ecnrq->e_vc, __LINE__ )
2655 #else ARGO_DEBUG
2656 					cons_chan_to_pcb( (int)ecnrq->e_vc )
2657 #endif ARGO_DEBUG
2658 										) == (struct cons_pcb *)0 )
2659 					break;
2660 				copcb->co_state = OPEN;
2661 				/*
2662 				 * Anything on the pending queue for this connection?
2663 				 */
2664 				if( copcb->co_pending.ifq_len == 0 ) {
2665 					if( copcb->co_proto->pr_ctlinput )
2666 						/* for the sake of higher layer protocol (tp) */
2667 						(*copcb->co_proto->pr_ctlinput)
2668 							(PRC_CONS_SEND_DONE,
2669 							(struct sockaddr_iso *)&copcb->co_faddr,
2670 							(caddr_t)copcb);
2671 				} else {
2672 					register struct mbuf *m0;
2673 
2674 					s = splimp();
2675 					IF_DEQUEUE( &copcb->co_pending, m0 );
2676 					splx(s);
2677 					/* CAN ONLY DO 1 item here
2678 					 * if you change this if to while, HA HA
2679 					 * it'll go right back onto
2680 					 * the pending queue (which means things will
2681 					 * be reordered on the queue!)
2682 					 */
2683 					if( m0 ) {
2684 						IFDEBUG(D_CDATA)
2685 							printf("ACK sending pending queue 0x%x len 0x%x\n",
2686 								m0, m0->m_len);
2687 						ENDDEBUG
2688 						ASSERT( m0->m_len != 0);
2689 						(void) cons_senddata(copcb, m0);
2690 					}
2691 				}
2692 
2693 				/* send more? */
2694 				break;
2695 
2696 			case ECN_ACCEPT:  /* call accepted at other end */
2697 				/* adr_src, adr_dst are as given in the ECN_CALL
2698 				 * pcb field is copied from our ECN_CALL
2699 				 * request, confirm gives me a channel number
2700 				 */
2701 				ASSERT( ecnrq->e_vc != 0);
2702 
2703 				IncStat(co_accept);
2704 				if(copcb =
2705 #ifdef ARGO_DEBUG
2706 				cons_chan_to_pcb((int)ecnrq->e_vc, __LINE__ )
2707 #else ARGO_DEBUG
2708 				cons_chan_to_pcb((int)ecnrq->e_vc)
2709 #endif ARGO_DEBUG
2710 												) {
2711 					/* error: already exists */
2712 					printf("cons PANIC: dbl confirm for channel 0x%x\n",
2713 						ecnrq->e_vc);
2714 					break;
2715 				}
2716 				copcb = (struct cons_pcb *)ecnrq->e_pcb;
2717 				if( copcb->co_myself != copcb ) {
2718 					struct mbuf *mm;
2719 					/* TODO: REMOVE */
2720 					ASSERT(0);
2721 					printf("BAD e_pcb from ecn (0x%x) cmd 0x%x\n",
2722 						ecnrq->e_pcb, ecnrq->e_cmd);
2723 					mm = dtom( copcb );
2724 					if(mm->m_type == MT_FREE)
2725 						printf("FREED MBUF!\n");
2726 					dump_buf (ecnrq, sizeof (*ecnrq));
2727 					panic("BAD ecnrq");
2728 					break;
2729 				}
2730 				touch(copcb);
2731 				copcb->co_state = OPEN;
2732 				copcb->co_channel = (int)ecnrq->e_vc;
2733 				if(copcb->co_socket) {
2734 					/* tp0 will take care of itself */
2735 					if( copcb->co_flags & CONSF_XTS)
2736 						soisconnected(copcb->co_socket); /* wake 'em up */
2737 				}
2738 				wakeup( (caddr_t)&copcb->co_state );
2739 
2740 				/*
2741 				 * Anything on the pending queue for this connection?
2742 				 */
2743 				if( copcb->co_pending.ifq_len > 0 ) {
2744 					register struct mbuf *m0;
2745 
2746 					s = splimp();
2747 					IF_DEQUEUE( &copcb->co_pending, m0 );
2748 					splx(s);
2749 					/* CAN ONLY DO 1 item here
2750 					 * if you change this if to while, HA HA
2751 					 * it'll go right back onto
2752 					 * the pending queue (which means things will
2753 					 * be reordered on the queue!)
2754 					 */
2755 					if( m0 ) {
2756 						IFDEBUG(D_CDATA)
2757 							printf("ACPT sending pending queue 0x%x len 0x%x\n",
2758 								m0, m0->m_len);
2759 						ENDDEBUG
2760 						ASSERT( m0->m_len != 0);
2761 						(void) cons_senddata(copcb, m0);
2762 					}
2763 				}
2764 				break;
2765 
2766 			case ECN_REFUSE:
2767 				/* other end refused our connect request */
2768 				/* src, dst are as given in the ECN_CALL */
2769 
2770 				IncStat(co_refuse);
2771 				copcb = (struct cons_pcb *)ecnrq->e_pcb;
2772 				if( copcb->co_myself != copcb ) {
2773 					struct mbuf *mm;
2774 					/* TODO: REMOVE */
2775 					ASSERT(0);
2776 					printf("BAD e_pcb from ecn (0x%x) cmd 0x%x\n",
2777 						ecnrq->e_pcb, ecnrq->e_cmd);
2778 					mm = dtom( copcb );
2779 					if(mm->m_type == MT_FREE)
2780 						printf("FREED MBUF!\n");
2781 					dump_buf (ecnrq, sizeof (*ecnrq));
2782 					dump_buf (copcb, sizeof (*copcb));
2783 					panic("BAD ecnrq");
2784 					break;
2785 				}
2786 				touch(copcb);
2787 				copcb->co_state = CLOSED; /* do we have to do a clear?? */
2788 				copcb->co_channel = X_NOCHANNEL;
2789 				if(copcb->co_socket) {
2790 					copcb->co_socket->so_error = ECONNREFUSED;
2791 					/* TODO: if there's diagnostic info in the
2792 					 * packet, and it's more useful than this E*,
2793 					 * get it
2794 					 */
2795 					soisdisconnected(copcb->co_socket); /* wake 'em up */
2796 					IFDEBUG(D_INCOMING)
2797 						printf("ECN_REFUSE: waking up 0x%x\n",
2798 							(caddr_t)&copcb->co_state );
2799 					ENDDEBUG
2800 					wakeup( (caddr_t)&copcb->co_state );
2801 				}
2802 				/*
2803 				 * Anything on the pending queue for this connection?
2804 				 */
2805 				while( copcb->co_pending.ifq_len > 0 ) {
2806 					register struct mbuf *m0;
2807 
2808 					s = splimp();
2809 					IF_DEQUEUE( &copcb->co_pending, m0 );
2810 					splx(s);
2811 					m_freem(m0);
2812 				}
2813 				if ( ecnrq->e_reason  == E_CO_NORESOURCES ) {
2814 					IncStat(co_noresources);
2815 					cons_clear_and_detach( copcb, DONTCLEAR, PRC_QUENCH );
2816 				} else if(copcb->co_socket ) {
2817 					copcb->co_socket->so_error = find_error_reason( ecnrq );
2818 				}
2819 				break;
2820 
2821 			case ECN_CONNECT:  /* incoming call */
2822 				/*
2823 				 * ECN_CONNECT indication gives adc_src, adc_dst  and channel
2824 				 */
2825 				ASSERT( ecnrq->e_vc != 0);
2826 
2827 				IncStat(co_connect);
2828 				cons_incoming(ifp, ecnrq);
2829 				break;
2830 
2831 			case ECN_RESET:
2832 			case ECN_CLEAR:
2833 				/*
2834 				 * ECN_CLEAR(indication) (if we can construct such a beast)
2835 				 * gives e_vc,
2836 				 * Throw away anything queued pending on this connection
2837 				 * give a reset indication to the upper layer if TP
2838 				 * free the mbufs
2839 				 */
2840 				ASSERT( ecnrq->e_vc != 0);
2841 				if( ecnrq->e_cmd == ECN_CLEAR )
2842 					IncStat(co_clear_in);
2843 				else
2844 					IncStat(co_reset_in);
2845 #ifdef ARGO_DEBUG
2846 				if( ! (copcb=cons_chan_to_pcb((int)ecnrq->e_vc, __LINE__)) )
2847 #else ARGO_DEBUG
2848 				if( ! (copcb=cons_chan_to_pcb((int)ecnrq->e_vc)) )
2849 #endif ARGO_DEBUG
2850 
2851 					break;
2852 				while( copcb->co_pending.ifq_len ) {
2853 					register struct mbuf *m0;
2854 
2855 					s = splimp();
2856 					IF_DEQUEUE( &copcb->co_pending, m0 );
2857 					splx(s);
2858 					m_freem(m0);
2859 				}
2860 				copcb->co_state = CLOSED; /* do we have to do a clear? */
2861 				copcb->co_channel = X_NOCHANNEL;
2862 
2863 				cons_clear_and_detach( copcb, DONTCLEAR, PRC_ROUTEDEAD );
2864 				if (copcb->co_socket ) {
2865 					copcb->co_socket->so_error = find_error_reason( ecnrq );
2866 				}
2867 				break;
2868 
2869 			case ECN_RECEIVE:
2870 				 /*
2871 				  * ECN_RECEIVE (read)
2872 				  */
2873 				ASSERT( ecnrq->e_vc != 0);
2874 				IncStat(co_receive);
2875 				{
2876 					/* TODO: REMOVE */
2877 					struct mbuf *thedata = e_data(ecnrq);
2878 					u_int *firstint = mtod( thedata, u_int *);
2879 
2880 					if( (*firstint & 0xff000000) != 0x81000000 ) {
2881 						/* not clnp */
2882 						switch( ((*firstint) & 0x00ff0000) >> 20 ) {
2883 						case 0x1:
2884 						case 0x2:
2885 						case 0x3:
2886 						case 0x6:
2887 						case 0x7:
2888 						case 0x8:
2889 						case 0xc:
2890 						case 0xd:
2891 						case 0xe:
2892 						case 0xf:
2893 							break;
2894 						default:
2895 							printf(" ECN_RECEIVE! BAD DATA\n" );
2896 							dump_buf( thedata, 20 + 12 );
2897 							m_freem( m );
2898 							splx(s0);
2899 						}
2900 					}
2901 				}
2902 				if ( (copcb =
2903 #ifdef ARGO_DEBUG
2904 					cons_chan_to_pcb( (int)ecnrq->e_vc, __LINE__ )
2905 #else ARGO_DEBUG
2906 					cons_chan_to_pcb( (int)ecnrq->e_vc )
2907 #endif ARGO_DEBUG
2908 											) == (struct cons_pcb *)0 ) {
2909 					ifp->if_ierrors ++;
2910 					IFTRACE(D_CDATA)
2911 						tptrace(TPPTmisc, "ECN_RECEIVE DROPPED chan \n",
2912 							ecnrq->e_vc, 0, 0, 0);
2913 					ENDTRACE
2914 					break;
2915 				}
2916 
2917 				touch(copcb);
2918 				if( ecnrq->e_info & ECN_INFO_RCVD_INT )  {
2919 					/* interrupt packet */
2920 						printf("consintr: interrupt pkttype : DROPPED\n");
2921 					IncStat(co_intrpt_pkts_in);
2922 					IncStat(co_Rdrops);
2923 					break;
2924 				}
2925 				/* new way */
2926 				if( copcb->co_proto == CLNP_proto )
2927 				{
2928 					/* IP: put it on the queue and set soft interrupt */
2929 					struct ifqueue *ifq;
2930 					extern struct ifqueue clnlintrq;
2931 					register struct mbuf *ifpp; /* for ptr to ifp */
2932 					register struct mbuf *data = e_data(ecnrq);
2933 
2934 					total_pkts_to_clnp ++;
2935 
2936 					/* when acting as a subnet service, have to prepend a
2937 					 * pointer to the ifnet before handing this to clnp
2938 					 * GAG
2939 					 */
2940 					if( ( data->m_off > MMINOFF + sizeof(struct snpa_hdr)) &&
2941 						( data->m_off <= MMAXOFF )) {
2942 						data->m_off -= sizeof(struct snpa_hdr);
2943 						data->m_len += sizeof(struct snpa_hdr);
2944 					} else {
2945 						MGET(ifpp, M_DONTWAIT, MT_XHEADER);
2946 						if( !ifpp ) {
2947 							ifp->if_ierrors ++;
2948 							splx(s0);
2949 							m_freem(m); /* frees everything */
2950 							return;
2951 						}
2952 						ifpp->m_len = sizeof(struct snpa_hdr);
2953 						ifpp->m_act = 0;
2954 						ifpp->m_next = data;
2955 						data = ifpp;
2956 					}
2957 					IFTRACE(D_CDATA)
2958 						tptrace(TPPTmisc, "-->CLNP copcb\n", copcb, 0, 0, 0);
2959 					ENDTRACE
2960 					{
2961 						/*
2962 						 *	TODO: if we ever use esis/cons we have to
2963 						 *	think of something reasonable to stick in the
2964 						 *	snh_shost,snh_dhost fields. I guess
2965 						 *	the x.121 address is what we want.
2966 						 *
2967 						 *	That would also require length fields in the
2968 						 *	snpa_hdr structure.
2969 						 */
2970 						struct snpa_hdr 	*snh =
2971 							mtod(data, struct snpa_hdr *);
2972 						bzero((caddr_t)&snh, sizeof(struct snpa_hdr));
2973 						bcopy((caddr_t)&ifp, (caddr_t)&snh->snh_ifp,
2974 							sizeof(struct ifnet *));
2975 					}
2976 					*( mtod(data, struct ifnet **) ) = ifp; /* KLUDGE */
2977 
2978 					ifq = &clnlintrq;
2979 					splimp();
2980 					if (IF_QFULL(ifq)) {
2981 						IF_DROP(ifq);
2982 						m_freem(m);
2983 						IFDEBUG(D_INCOMING)
2984 							printf("DROPPED! ecnrq 0x%x, data 0x%x\n", m,data);
2985 						ENDDEBUG
2986 						splx(s0);
2987 						ifp->if_ierrors ++;
2988 						return;
2989 					}
2990 					IF_ENQUEUE(ifq, data);
2991 					IFDEBUG(D_INCOMING)
2992 						printf(
2993 				"0x%x enqueued on ip Q: m_len 0x%x m_type 0x%x m_off 0x%x\n",
2994 							data, data->m_len, data->m_type, data->m_off);
2995 						dump_buf(mtod(data, caddr_t), data->m_len);
2996 					ENDDEBUG
2997 					e_data(ecnrq) = (struct mbuf *)0;
2998 					schednetisr(NETISR_CLNP);
2999 				} else {
3000 					/* HL is NOT clnp */
3001 					IFTRACE(D_CDATA)
3002 						tptrace(TPPTmisc,
3003 							"-->HL pr_input so copcb channel\n",
3004 							copcb->co_proto->pr_input,
3005 							copcb->co_socket, copcb,
3006 							copcb->co_channel);
3007 					ENDTRACE
3008 					IFDEBUG(D_INCOMING)
3009 						printf( "0x%x --> HL proto 0x%x chan 0x%x\n",
3010 							e_data(ecnrq), copcb->co_proto, copcb->co_channel );
3011 					ENDDEBUG
3012 
3013 					(*copcb->co_proto->pr_input)(e_data(ecnrq),
3014 						&copcb->co_faddr,
3015 						&copcb->co_laddr,
3016 						copcb->co_socket, /* used by cons-transport interface */
3017 						(copcb->co_flags & CONSF_DGM)?0:
3018 							copcb->co_channel);/* used by tp-cons interface */
3019 
3020 					/*
3021 					 * the pr_input will free the data chain, so we must
3022 					 * zero the ptr to is so that m_free doesn't panic
3023 					 */
3024 					e_data(ecnrq) = (struct mbuf *)0;
3025 				}
3026 				break;
3027 
3028 			default:
3029 				/* error */
3030 				ifp->if_ierrors ++;
3031 				printf("consintr: unknown request\n");
3032 		}
3033 		IFDEBUG(D_INCOMING)
3034 			printf("consintr: m_freem( 0x%x )\n", m);
3035 		ENDDEBUG
3036 		m_freem( m );
3037 	}
3038 	splx(s0);
3039 }
3040 
3041 /*
3042  * Process an ioctl request.
3043  * also set-time-limit, extend-time-limit
3044  * for ALL channels, the time-limit ioctls will be done by open-a-dummy-socket,
3045  * do ioctl with the channel number, close the socket (dumb!).
3046  */
3047 /* ARGSUSED */
3048 cons_ioctl(so, cmd, data)
3049 	struct socket *so;
3050 	int cmd;
3051 	caddr_t data;
3052 {
3053 	int 	s = splnet();
3054 	int 	error = 0;
3055 
3056 	IFDEBUG(D_CCONS)
3057 		printf("cons_ioctl( cmd 0x%x )\n", cmd);
3058 	ENDDEBUG
3059 
3060 #ifdef notdef
3061 	switch (cmd) {
3062 
3063 	default:
3064 #endif notdef
3065 		error = EOPNOTSUPP;
3066 #ifdef notdef
3067 	}
3068 #endif notdef
3069 
3070 	splx(s);
3071 	return (error);
3072 }
3073 
3074 
3075 /*
3076  *************************************************************
3077  *                                                           *
3078  *                                                           *
3079  * Interface to CO Subnetwork service from CLNP              *
3080  * Must be a device interface.                             *****
3081  *                                                          ***
3082  *                                                           *
3083  *                                                          Poof!
3084  */
3085 
3086 /*
3087  * NAME:	consioctl()
3088  * CALLED FROM:
3089  * 	called through the ifnet structure.
3090  * FUNCTION and ARGUMENTS:
3091  *	the usual ioctl stuff
3092  * RETURNS:
3093  * 	E*
3094  * SIDE EFFECTS:
3095  * NOTES:
3096  */
3097 consioctl(ifp, cmd, data)
3098 	register struct ifnet *ifp;
3099 	register int cmd;
3100 	register caddr_t data;
3101 {
3102 	register struct ifaddr 		*ifa = (struct ifaddr *)data;
3103 	register int 				s = splimp();
3104 	register struct ifreq 		*ifr = (struct ifreq *)data;
3105 	register int 				error = 0;
3106 	void						consshutdown();
3107 
3108 	switch (cmd) {
3109 	case SIOCSIFADDR:
3110 		switch (ifa->ifa_addr.sa_family) {
3111 		case AF_ISO:
3112 			if( (ifp->if_flags & IFF_UP ) == 0)
3113 				consinit(ifp->if_unit);
3114 			break;
3115 		default:
3116 			printf("CANNOT config cons with address family %d\n",
3117 				ifa->ifa_addr.sa_family);
3118 			break;
3119 		}
3120 		break;
3121 	case SIOCSIFFLAGS:
3122 		IFDEBUG(D_CCONS)
3123 			printf("consioctl: set flags to x%x\n", ifr->ifr_flags);
3124 			printf("consioctl: ifp flags are x%x\n", ifp->if_flags);
3125 		ENDDEBUG
3126 		if( ifr->ifr_flags & IFF_LOOPBACK )
3127 			ifp->if_flags |= IFF_LOOPBACK;
3128 		else
3129 			ifp->if_flags &= ~IFF_LOOPBACK;
3130 
3131 		/* if board is down but request takes it up, init the board */
3132 		if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0)
3133 			consinit(ifp->if_unit);
3134 
3135 		/* if board is up but request takes it down, shut the board down */
3136 		if (((ifr->ifr_flags & IFF_UP) == 0) && (ifp->if_flags & IFF_UP)) {
3137 			consshutdown(ifp->if_unit);
3138 		}
3139 		IFDEBUG(D_CCONS)
3140 			printf("consioctl: flags are x%x\n", ifp->if_flags);
3141 		ENDDEBUG
3142 		break;
3143 	case SIOCGSTATUS:
3144 		/* warning: must coerse ifp to (struct ifstatus *) in order to use */
3145 		IFDEBUG(D_CCONS)
3146 			printf("consioctl: EICON status request\n");
3147 		ENDDEBUG
3148 #if NECN>0
3149 		ecnioctl(ifp, cmd, data);
3150 #else
3151 		error = ENODEV;
3152 #endif NECN>0
3153 		break;
3154 	default:
3155 		error = EINVAL;
3156 	}
3157 	splx(s);
3158 	return error;
3159 }
3160 
3161 /*
3162  * NAME:	consattach()
3163  * CALLED FROM:
3164  * 	cons_init() (which comes from autoconf)
3165  * FUNCTION and ARGUMENTS:
3166  *	creates an ifp and fills it in; calls ifattach() on it.
3167  * RETURNS:
3168  *  no return value
3169  * SIDE EFFECTS:
3170  * NOTES:
3171  */
3172 consattach()
3173 {
3174 	register struct ifnet		*ifp;
3175 	register struct mbuf 		*m;
3176 
3177 	if(sizeof(struct ifnet) > MLEN) {
3178 		printf("Can't attach cons!  sizeof(struct ifnet) > MLEN\n");
3179 		return;
3180 	}
3181 	MGET(m, M_DONTWAIT, MT_IFADDR);
3182 	if( !m ) {
3183 		printf("Can't attach cons!  NO MBUFS!\n");
3184 		return;
3185 	}
3186 	m->m_len = sizeof(struct ifnet);
3187 	ifp = consif = mtod(m, struct ifnet *);
3188 	ifp->if_unit = 0;
3189 	ifp->if_name = "cons";
3190 	ifp->if_mtu = ECN_MTU;
3191 	ifp->if_init = consinit;
3192 	ifp->if_ioctl = consioctl;
3193 	ifp->if_output = cosns_output; /* called by clnp */
3194 	ifp->if_flags = IFF_LOOPBACK;  /* default */
3195 	if_attach(ifp);
3196 	printf("cons%d: pseudo device attached \n", ifp->if_unit);
3197 }
3198 
3199 /*
3200  * NAME:	consinit()
3201  * CALLED FROM:
3202  * 	consioctl()
3203  * FUNCTION and ARGUMENTS:
3204  * 	Initializes apropos data structures, etc.
3205  *  Marks the device as up.
3206  *  Zaps the address list.
3207  *  Calls device layer restart on the device if necessary.
3208  */
3209 Static
3210 consinit(_unit)
3211 register int	_unit;	/* unit to initialize */
3212 {
3213 	struct ifnet			*ecnifp();
3214 	struct ifnet 			*ifp;
3215 	int		s;
3216 
3217 	if ((ifp = ecnifp(_unit)) != (struct ifnet *)0 ) {
3218 		ecnrestart(ifp);
3219 		IncStat(co_restart);
3220 	}
3221 	if (consif->if_addrlist == (struct ifaddr *)0)
3222 		return;
3223 	if ((consif->if_flags & IFF_UP) == 0) {
3224 		s = splimp();
3225 		consif->if_flags |= IFF_UP;
3226 		splx(s);
3227 	}
3228 
3229 }
3230 
3231 /*
3232  * NAME:	consshutdown()
3233  * CALLED FROM:
3234  *	cons_ioctl() when user takes down an interface w/ SIOCSIFFLAGS
3235  * FUNCTION and ARGUMENTS:
3236  *  calls lower layer shutdown routine on the device.
3237  *  and marks the if as down if the if is the sw loopback pseudodevice.
3238  * RETURNS:
3239  *	no return value
3240  */
3241 void
3242 consshutdown(_unit)
3243 register int	_unit;	/* unit to shutdown */
3244 {
3245 	extern	struct ifnet 	*ecnifp();
3246 	struct ifnet 			*ifp;
3247 	int 					s;
3248 
3249 	if ((ifp = ecnifp(_unit)) != (struct ifnet *)0 ) {
3250 		ecnshutdown(ifp);
3251 	}
3252 	if ((consif->if_flags & IFF_UP) ) {
3253 		s = splimp();
3254 		consif->if_flags &= ~IFF_UP;
3255 		splx(s);
3256 	}
3257 }
3258 #endif KERNEL
3259 
3260 /*
3261  * NAME:	munge()
3262  * CALLED FROM:
3263  * 	cons_pcbbind(), cons_usrreq()
3264  * FUNCTION and ARGUMENTS:
3265  *  Takes the argument (value) and stashes it into the last two
3266  *  nibbles of an X.121 address.  Does this in the two nibbles beginning
3267  *  at the location defined by the character pointer (dst_octet) and the
3268  *  integer (dst_nibble).  Nibble 0 is the lower nibble (high
3269  *  order 4 bits); nibble 1 is the low order 4 bits of *(dst_octet).
3270  *
3271  * RETURNS:
3272  * 	no return value
3273  */
3274 Static
3275 munge( value, dst_octet, dst_nibble)
3276 	int value;
3277 	caddr_t dst_octet;
3278 	int dst_nibble;
3279 {
3280 	IFDEBUG(D_CCONN)
3281 		printf("MUNGE: value 0x%x dst_octet 0x%x, nibble 0x%x)\n",
3282 			value, dst_octet, dst_nibble);
3283 	ENDDEBUG
3284 	if (value >= ISO_PORT_RESERVED)
3285 		value -= 1000;
3286 
3287 	{
3288 		/* convert so it  looks like a decimal number */
3289 		register int tens, ones;
3290 
3291 		tens = value/10;
3292 		ASSERT( tens <= 9 );
3293 		ones = value - (tens * 10);
3294 
3295 		value = tens * 16 + ones;
3296 	}
3297 
3298 	dst_octet --;
3299 	/* leave nibble same 'cause it's one after the last set nibble */
3300 
3301 	*dst_octet &= ~(0xff<<(dst_nibble << 2)); /* zero it */
3302 	*dst_octet |= ((value>>4) << (dst_nibble<<2));
3303 	dst_nibble = 1-dst_nibble;
3304 	dst_octet += dst_nibble;
3305 
3306 	*dst_octet &= ~(0xff<<(dst_nibble << 2)); /* zero it */
3307 	*dst_octet |= ((value&0xff) << (dst_nibble<<2));
3308 }
3309 
3310 /*
3311  * NAME:	unmunge()
3312  * CALLED FROM:
3313  *  DTEtoNSAP(), FACILtoNSAP()
3314  * FUNCTION and ARGUMENTS:
3315  *  return the port/tsuffix represented by the two digits found in a
3316  *  bcd string beginning at the (dst_nibble)th nibble of the
3317  *  octet BEFORE (dst_octet).
3318  *
3319  * dst_octet,dst_nibble  is the nibble after the one we'll look at
3320  * RETURNS:
3321  *  an integer, the port/tsuffix
3322  *  Note- converts to a port > 1000 if necessary.
3323  */
3324 Static int
3325 unmunge( dst_octet, dst_nibble )
3326 	caddr_t dst_octet;
3327 	int dst_nibble;
3328 {
3329 		register u_short last = 0;
3330 
3331 		dst_octet --;
3332 		/* leave nibble same 'cause it's one after the last set nibble */
3333 		IFDEBUG(D_CADDR)
3334 			printf("unmunge: *octet 0x%x, nibble 0x%x\n", *dst_octet,
3335 				dst_nibble);
3336 		ENDDEBUG
3337 
3338 		last = ((*dst_octet) & (0xff<<(dst_nibble<<2)));
3339 		dst_nibble = 1-dst_nibble;
3340 		dst_octet += dst_nibble;
3341 
3342 		last |= ((*dst_octet) & (0xff<<(dst_nibble << 2)));
3343 		{
3344 			/* convert to a decimal number */
3345 			register int tens, ones;
3346 
3347 			tens = (last&0xf0)>>4;
3348 			ones = last&0xf;
3349 
3350 			last = tens * 10 + ones;
3351 		}
3352 
3353 		IFDEBUG(D_CADDR)
3354 			printf("unmunge computes 0x%x\n", last);
3355 		ENDDEBUG
3356 		if((int)last+1000 >= ISO_PORT_RESERVED)
3357 			last += 1000;
3358 		IFDEBUG(D_CADDR)
3359 			printf("unmunge returns 0x%x\n", last);
3360 		ENDDEBUG
3361 		return last;
3362 }
3363 
3364 /*
3365  * NAME:	make_partial_x25_packet()
3366  *
3367  * FUNCTION and ARGUMENTS:
3368  *	Makes part of an X.25 call packet, for use by the eicon board.
3369  *  (src) and (dst) are the NSAP-addresses of source and destination.
3370  *	(proto) is the higher-layer protocol number (in iso.h)
3371  *	(buf) is a ptr to a buffer into which to write this partial header.
3372  *
3373  *  The partial header looks like (choke):
3374  *	octet		meaning
3375  *  1			calling DTE len  |  called DTE len (lengths in nibbles)
3376  *  2..n-1		called DTE addr  | (<-- boundary may be middle of an octet)
3377  *  			calling DTE addr  | zero nibble to round to octet boundary.
3378  *	n			Facility length (in octets)
3379  *	n+1			Facility field, which is a set of:
3380  *	  m			facil code
3381  *	  m+1		facil param len (for >2-byte facilities) in octets
3382  *	  m+2..p	facil param field
3383  *  q			user data (protocol identification octet)
3384  *
3385  *
3386  * RETURNS:
3387  *  0 if OK
3388  *  E* if failed.
3389  */
3390 
3391 #ifdef X25_1984
3392 int cons_use_facils = 1;
3393 #else X25_1984
3394 int cons_use_facils = 0;
3395 #endif X25_1984
3396 
3397 int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */
3398 
3399 Static int
3400 make_partial_x25_packet(copcb, m)
3401 	struct cons_pcb *copcb;
3402 	struct mbuf *m;
3403 {
3404 	struct sockaddr_iso	*src, *dst;
3405 	u_int				proto;
3406 	int					flag;
3407 	caddr_t 			buf = mtod(m, caddr_t);
3408 	register caddr_t	ptr	= buf + 1;  /* make room for 2 length nibbles */
3409 	register int		len	= 0;
3410 	int 				buflen	=0;
3411 	caddr_t				facil_len;
3412 	int 				oddness	= 0;
3413 
3414 	src = &copcb->co_laddr;
3415 	dst = &copcb->co_faddr;
3416 	proto = copcb->co_proto->pr_protocol,
3417 	flag = copcb->co_flags & CONSF_XTS;
3418 
3419 
3420 	IFDEBUG(D_CCONN)
3421 		printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
3422 			src, dst, proto, m, flag);
3423 	ENDDEBUG
3424 
3425 	/*
3426 	 * Note - order of addrs in x25 pkt hdr is wierd:
3427 	 * calling len/called len/called addr/calling addr (p.40 ISO 8202)
3428 	 */
3429 	if( (len = copcb->co_peer_dte.dtea_niblen) > 0 ) {
3430 		nibble_copy( (char *)(copcb->co_peer_dte.dtea_addr), HIGH_NIBBLE,
3431 			ptr, HIGH_NIBBLE, len);
3432 	} else {
3433 		if ((len =  NSAPtoDTE( ptr, HIGH_NIBBLE, dst)) <=0 ) {
3434 			return E_CO_OSI_UNSAP;
3435 		}
3436 	}
3437 	*buf = len; /* fill in called dte addr length */
3438 	ptr += len>>1; /* len is in nibbles */
3439 	oddness += len&0x1;
3440 
3441 	if ((len =  NSAPtoDTE( ptr, 1-(len&0x1), src)) <=0 ) {
3442 		return E_CO_OSI_UNSAP;
3443 	}
3444 	ptr += len>>1; /* len is in nibbles */
3445 	*buf |= len << 4; /* fill in calling dte addr length */
3446 	oddness += len&0x1;
3447 
3448 	IFDEBUG(D_CADDR)
3449 		printf("make_partial  2: ptr 0x%x, len 0x%x oddness 0x%x\n",
3450 			ptr, len, oddness );
3451 	ENDDEBUG
3452 	/* if either of the addresses were an odd length, the count is off by 1 */
3453 	if( oddness ) {
3454 		ptr ++;
3455 	}
3456 
3457 	/* ptr now points to facil length (len of whole facil field in OCTETS */
3458 	facil_len = ptr ++;
3459 
3460 	IFDEBUG(D_CADDR)
3461 		printf("make_partial  calling: ptr 0x%x, len 0x%x\n", ptr,
3462 				src->siso_addr.isoa_len);
3463 	ENDDEBUG
3464 	if( cons_use_facils ) {
3465 		*ptr = 0xcb; /* calling facility code */
3466 		ptr ++;
3467 		ptr ++; /* leave room for facil param len (in OCTETS + 1) */
3468 		ptr ++; /* leave room for the facil param len (in nibbles),
3469 				* high two bits of which indicate full/partial NSAP
3470 				*/
3471 		len = src->siso_addr.isoa_len;
3472 		bcopy( &src->siso_addr.isoa_afi, ptr, len);
3473 		*(ptr-2) = len+2; /* facil param len in octets */
3474 		*(ptr-1) = len<<1; /* facil param len in nibbles */
3475 		ptr += len;
3476 
3477 		IFDEBUG(D_CADDR)
3478 			printf("make_partial  called: ptr 0x%x, len 0x%x\n", ptr,
3479 					dst->siso_addr.isoa_len);
3480 		ENDDEBUG
3481 		*ptr = 0xc9; /* called facility code */
3482 		ptr ++;
3483 		ptr ++; /* leave room for facil param len (in OCTETS + 1) */
3484 		ptr ++; /* leave room for the facil param len (in nibbles),
3485 				* high two bits of which indicate full/partial NSAP
3486 				*/
3487 		len = dst->siso_addr.isoa_len;
3488 		bcopy( &dst->siso_addr.isoa_afi, ptr, len);
3489 		*(ptr-2) = len+2; /* facil param len = addr len + 1 for each of these
3490 						  * two length fields, in octets */
3491 		*(ptr-1) = len<<1; /* facil param len in nibbles */
3492 		ptr += len;
3493 
3494 	}
3495 	*facil_len = ptr - facil_len - 1;
3496 	if(*facil_len > X25_FACIL_LEN_MAX )
3497 		return E_CO_PNA_LONG;
3498 
3499 	if( cons_use_udata ) {
3500 		if (copcb->co_x25crud_len > 0) {
3501 			/*
3502 			 *	The user specified something. Stick it in
3503 			 */
3504 			bcopy(copcb->co_x25crud, ptr, copcb->co_x25crud_len);
3505 			ptr += copcb->co_x25crud_len;
3506 		} else {
3507 			/* protocol identifier */
3508 			switch (proto) {
3509 					/* unfortunately all are considered 1 protocol */
3510 				case ISOPROTO_TP0:
3511 				case ISOPROTO_TP1:
3512 				case ISOPROTO_TP2:
3513 				case ISOPROTO_TP3:
3514 				case ISOPROTO_TP4:
3515 				case ISOPROTO_CLTP:
3516 					/* no user data for TP */
3517 					break;
3518 
3519 				case ISOPROTO_CLNP:
3520 					*ptr = 0x81;
3521 					ptr++; /* count the proto id byte! */
3522 					break;
3523 				case ISOPROTO_INACT_NL:
3524 					*ptr = 0x0;
3525 					ptr++; /* count the proto id byte! */
3526 					break;
3527 				case ISOPROTO_X25:
3528 					*ptr = 0xff; /* reserved for future extensions */
3529 						  /* we're stealing this value for local use */
3530 					ptr++; /* count the proto id byte! */
3531 					break;
3532 				default:
3533 					return EPROTONOSUPPORT;
3534 			}
3535 		}
3536 	}
3537 
3538 	buflen = (int)(ptr - buf);
3539 
3540 	IFDEBUG(D_CDUMP_REQ)
3541 		register int i;
3542 
3543 		printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n",
3544 			buf, buflen, buflen);
3545 		for( i=0; i < buflen; ) {
3546 			printf("+%d: %x %x %x %x    %x %x %x %x\n",
3547 				i,
3548 				*(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3),
3549 				*(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7));
3550 			i+=8;
3551 		}
3552 	ENDDEBUG
3553 	IFDEBUG(D_CADDR)
3554 		printf("make_partial returns buf 0x%x size 0x%x bytes\n",
3555 			mtod(m, caddr_t), buflen);
3556 	ENDDEBUG
3557 
3558 	ASSERT( X25_PARTIAL_PKT_LEN_MAX < MLEN );
3559 
3560 	if(buflen > X25_PARTIAL_PKT_LEN_MAX)
3561 		return E_CO_PNA_LONG;
3562 
3563 	m->m_len = buflen;
3564 	return  0;
3565 }
3566 
3567 /*
3568  * NAME:	NSAPtoDTE()
3569  * CALLED FROM:
3570  *  make_partial_x25_packet()
3571  * FUNCTION and ARGUMENTS:
3572  *  get a DTE address from an NSAP-address (struct sockaddr_iso)
3573  *  (dst_octet) is the octet into which to begin stashing the DTE addr
3574  *  (dst_nibble) takes 0 or 1.  1 means begin filling in the DTE addr
3575  * 		in the high-order nibble of dst_octet.  0 means low-order nibble.
3576  *  (addr) is the NSAP-address
3577  *  (flag) is true if the transport suffix is to become the
3578  *		last two digits of the DTE address
3579  *  A DTE address is a series of BCD digits
3580  *
3581  *	A DTE address may have leading zeros. The are significant.
3582  *		1 digit per nibble, may be an odd number of nibbles.
3583  *
3584  *  An NSAP-address has the DTE address in the IDI. Leading zeros are
3585  *		significant. Trailing hex f indicates the end of the DTE address.
3586  *  	Also is a series of BCD digits, one per nibble.
3587  *
3588  * RETURNS
3589  *  # significant digits in the DTE address, -1 if error.
3590  */
3591 
3592 Static int
3593 NSAPtoDTE( dst_octet, dst_nibble, addr)
3594 	caddr_t 	dst_octet;
3595 	int			dst_nibble;
3596 	register struct sockaddr_iso *addr;
3597 {
3598 	int 	error;
3599 	u_char	x121string[7]; /* maximum is 14 digits */
3600 	int		x121strlen;
3601 	struct	dte_addr *dtea;
3602 
3603 	IFDEBUG(D_CADDR)
3604 		printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&addr->siso_addr));
3605 	ENDDEBUG
3606 
3607 	error = iso_8208snparesolve(addr, x121string, &x121strlen);
3608 	ASSERT(error == 0);
3609 	if(  error != 0 ) {
3610 		/* no snpa - cannot send */
3611 		IFDEBUG(D_CADDR)
3612 			printf("NSAPtoDTE: 8208resolve: %d\n", error );
3613 		ENDDEBUG
3614 		return 0;
3615 	}
3616 	ASSERT(x121strlen == sizeof(struct dte_addr));
3617 	dtea = (struct dte_addr *)x121string;
3618 	x121strlen = dtea->dtea_niblen;
3619 
3620 	nibble_copy((char *)x121string, HIGH_NIBBLE,
3621 		dst_octet, dst_nibble, x121strlen);
3622 	return x121strlen;
3623 }
3624 
3625 /*
3626  * NAME:	FACILtoNSAP()
3627  * CALLED FROM:
3628  *  parse_facil()
3629  * FUNCTION and ARGUMENTS:
3630  * 	Creates and NSAP in the sockaddr_iso (addr) from the
3631  *  x.25 facility found at (buf), of length (buf_len).
3632  * RETURNS:
3633  *  0 if ok, non-zero if error;
3634  */
3635 
3636 Static int
3637 FACILtoNSAP( buf, buf_len, addr)
3638 	caddr_t 		buf;
3639 	u_char			buf_len; /* in bytes */
3640 	register struct sockaddr_iso *addr;
3641 {
3642 	int len_in_nibbles;
3643 
3644 	IFDEBUG(D_CADDR)
3645 		printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n",
3646 			buf, buf_len, addr );
3647 	ENDDEBUG
3648 
3649 	len_in_nibbles = *buf;
3650 	/* despite the fact that X.25 makes us put a length in nibbles
3651 	 * here, the NSAP-addrs are always in full octets
3652 	 */
3653 	buf ++;
3654 
3655 	bzero( addr, sizeof (struct sockaddr_iso) );
3656 
3657 	ASSERT(buf_len <= 1+sizeof (struct iso_addr));
3658 	if(buf_len > 1+sizeof (struct iso_addr)) {
3659 		return -1; /* error */
3660 	}
3661 	ASSERT(len_in_nibbles == (buf_len - 1)<<1);
3662 	if(len_in_nibbles != (buf_len - 1)<<1) {
3663 		return -2; /* error */
3664 	}
3665 	bcopy(buf, &addr->siso_addr.isoa_afi, buf_len-1);
3666 	addr->siso_addr.isoa_len = buf_len-1;
3667 	IFDEBUG(D_CADDR)
3668 		printf("FACILtoNSAP: isoa_len 0x%x\n",
3669 			addr->siso_addr.isoa_len);
3670 	ENDDEBUG
3671 	addr->siso_family = AF_ISO;
3672 
3673 	addr->siso_tsuffix =
3674 		unmunge( ((caddr_t)&addr->siso_addr.t37_idi) + ADDR37_IDI_LEN , 1 );
3675 	return 0;
3676 }
3677 
3678 /*
3679  * NAME:	DTEtoNSAP()
3680  * CALLED FROM:
3681  *  parse_facil()
3682  * FUNCTION and ARGUMENTS:
3683  *  Creates a type 37 NSAP in the sockaddr_iso (addr)
3684  * 	from a DTE address found at the (src_nibble)th nibble of
3685  * 	the octet (src_octet), of length (src_nib_len).
3686  *
3687  * RETURNS:
3688  *  0 if ok; E* otherwise.
3689  */
3690 
3691 Static  int
3692 DTEtoNSAP(addr, src_octet, src_nibble, src_nib_len)
3693 	struct sockaddr_iso *addr;
3694 	caddr_t src_octet;
3695 	int src_nibble, src_nib_len;
3696 {
3697 	caddr_t				dst_octet;
3698 	int					pad_len;
3699 	int					dst_nibble;
3700 	char				first_nib;
3701 	static				char *z_pad = "\0\0\0\0\0\0\0";
3702 	static				char *f_pad = "\021\021\021\021\021\021\021";
3703 
3704 	IFDEBUG(D_CADDR)
3705 		printf("DTEtoNSAP( 0x%x, 0x%x, 0x%x, 0x%x )\n",
3706 			src_octet, src_nibble, src_nib_len, addr );
3707 	ENDDEBUG
3708 
3709 	bzero( addr, sizeof(*addr));
3710 	addr->siso_family = AF_ISO;
3711 	/*
3712 	 * Coming from a DTE addr it's always type 37.
3713 	 * src_octet <-- starting place in the NSAP-address of
3714 	 * the embedded SNPA-address (x.121 addr or DTE addr).
3715 	 */
3716 	addr->siso_addr.isoa_afi = 0x37;
3717 
3718 	/* first, figure out what pad to use and pad */
3719 
3720 	first_nib = (*src_octet) >> (SHIFT*(1-src_nibble));
3721 	pad_len = (ADDR37_IDI_LEN<<1 - src_nib_len);
3722 	nibble_copy(first_nib? z_pad : f_pad, HIGH_NIBBLE,
3723 		(caddr_t) addr->siso_addr.t37_idi, HIGH_NIBBLE, pad_len);
3724 
3725 	dst_octet += (pad_len>>1);
3726 	dst_nibble = 1-(pad_len & 0x1);
3727 	IFDEBUG(D_CADDR)
3728 		printf("DTEtoNSAP 2( 0x%x, 0x%x, 0x%x, 0x%x )\n",
3729 			dst_octet, dst_nibble, pad_len, src_nib_len );
3730 	ENDDEBUG
3731 
3732 	/* now copy the dte address */
3733 	nibble_copy( src_octet, src_nibble, dst_octet, dst_nibble, src_nib_len);
3734 
3735 	addr->siso_addr.isoa_len = ADDR37_IDI_LEN + ADDR37_DSP_LEN +1 /* for afi */;
3736 		/* kludge */
3737 
3738 	addr->siso_tsuffix = unmunge(
3739 		(caddr_t) &(addr->siso_addr.t37_idi[ADDR37_IDI_LEN]), HIGH_NIBBLE);
3740 
3741 	IFDEBUG(D_CADDR)
3742 		printf("DTEtoNSAP 3 returning 0 tsuffix 0x%x\n", addr->siso_tsuffix);
3743 	ENDDEBUG
3744 
3745 	return 0; /* ok */
3746 }
3747 
3748 /*
3749  * FUNCTION and ARGUMENTS:
3750  *	parses (buf_len) bytes beginning at (buf) and finds
3751  *  a called nsap, a calling nsap, and protocol identifier.
3752  * RETURNS:
3753  *  0 if ok, E* otherwise.
3754  */
3755 
3756 Static int
3757 parse_facil( buf, buf_len, called, calling, proto, peer_dte)
3758 	caddr_t 		buf;
3759 	u_char			buf_len; /* in bytes */
3760 	register struct sockaddr_iso *called, *calling;
3761 	int				*proto;
3762 	struct	dte_addr	*peer_dte;
3763 {
3764 	register int 	i;
3765 	caddr_t			ptr;
3766 	caddr_t 		facil_len;
3767 	int 			facil_param_len;
3768 	struct 	sockaddr_iso *addr;
3769 	int				addrs_not_parsed = (int)0xcb + (int)0xc9;
3770 
3771 	IFDEBUG(D_CADDR)
3772 		printf("parse_facil( 0x%x, 0x%x, 0x%x, 0x%x, 0x%x )\n",
3773 			buf, buf_len, called, calling, *proto);
3774 		dump_buf(buf, buf_len);
3775 	ENDDEBUG
3776 
3777 	/* find the beginnings of the facility fields in buf
3778 	 * by skipping over the called & calling DTE addresses
3779 	 * i <- # nibbles in called + # nibbles in calling
3780 	 * i += 1 so that an odd nibble gets rounded up to even
3781 	 * before dividing by 2, then divide by two to get # octets
3782 	 */
3783 	i = (int)(*buf >> 4) + (int)(*buf&0xf);
3784 	i++;
3785 	ptr = (caddr_t) (buf + (i>>1));
3786 	/* now i is number of octets */
3787 
3788 	ptr ++; /* plus one for the DTE lengths byte */
3789 
3790 	/* ptr now is at facil_length field */
3791 	facil_len = ptr++;
3792 	IFDEBUG(D_CADDR)
3793 		printf("parse_facils: facil length is  0x%x\n", (int) *facil_len);
3794 	ENDDEBUG
3795 
3796 	while( ptr <= (caddr_t)(facil_len + (int)*facil_len) ) {
3797 		/* get NSAP addresses from facilities */
3798 		switch (*ptr) {
3799 			case 0xcb:
3800 				facil_param_len = 0;
3801 				addr = calling;
3802 				addrs_not_parsed -= 0xcb;
3803 				break;
3804 			case 0xc9:
3805 				facil_param_len = 0;
3806 				addr = called;
3807 				addrs_not_parsed -= 0xc9;
3808 				break;
3809 
3810 				/* from here to default are legit cases that I ignore */
3811 
3812 				/* variable length */
3813 			case 0xca:  /* end-to-end transit delay negot */
3814 			case 0xc6:  /* network user id */
3815 			case 0xc5: 	/* charging info : indicating monetary unit */
3816 			case 0xc2: 	/* charging info : indicating segment count */
3817 			case 0xc1: 	/* charging info : indicating call duration */
3818 			case 0xc4: 	/* RPOA extended format */
3819 			case 0xc3: 	/* call redirection notification */
3820 				facil_param_len = 0;
3821 				addr = (struct sockaddr_iso *)0;
3822 				break;
3823 
3824 				/* 1 octet */
3825 			case 0x0a:  /* min. throughput class negot */
3826 			case 0x02:  /* throughput class */
3827 			case 0x03:  case 0x47:  /* CUG shit */
3828 			case 0x0b:  /* expedited data negot */
3829 			case 0x01:  /* Fast select or reverse charging
3830 						(example of intelligent protocol design) */
3831 			case 0x04: 	/* charging info : requesting service */
3832 			case 0x08: 	/* called line addr modified notification */
3833 				facil_param_len = 1;
3834 				addr = (struct sockaddr_iso *)0;
3835 				break;
3836 
3837 				/* any 2 octets */
3838 			case 0x42:  /* pkt size */
3839 			case 0x43:  /* win size */
3840 			case 0x44:  /* RPOA basic format */
3841 			case 0x41:  /* bilateral CUG shit */
3842 			case 0x49: 	/* transit delay selection and indication */
3843 				facil_param_len = 2;
3844 				addr = (struct sockaddr_iso *)0;
3845 				break;
3846 
3847 				/* don't have any 3 octets */
3848 				/*
3849 				facil_param_len = 3;
3850 				*/
3851 			default:
3852 				ASSERT(0);
3853 				printf(
3854 "BOGUS FACILITY CODE facil_len 0x%x *facil_len 0x%x, ptr 0x%x *ptr 0x%x\n",
3855 					facil_len, *facil_len,
3856 					ptr, *ptr);
3857 				addr = (struct sockaddr_iso *)0;
3858 				/* facil that we don't handle */
3859 				return E_CO_HLI_REJI;
3860 		}
3861 		ptr++; /* one for facil code */
3862 		if(facil_param_len == 0) /* variable length */
3863 			facil_param_len = (int)*ptr; /* 1 + the real facil param */
3864 		if( addr &&  FACILtoNSAP(ptr+1, facil_param_len-1, addr) ) {
3865 			return E_CO_OSI_UNSAP;
3866 		}
3867 		ptr += facil_param_len;
3868 	}
3869 	if( addrs_not_parsed ) {
3870 		/* no facilities, get NSAP addresses from DTE addresses */
3871 		register int ed, ing;
3872 
3873 		ed = (int)(*buf&0xf);
3874 		if( ed == 0 ) {
3875 			panic("Called DTE address absent");
3876 		}
3877 		DTEtoNSAP(called, (buf + 1)/*octet*/,
3878 			1/*nibble*/, ed);
3879 
3880 		ing = (int)(*buf >> 4);
3881 		if( ing == 0 ) {
3882 			printf("cons: panic: Calling DTE address absent");
3883 			return E_CO_HLI_REJI;
3884 		}
3885 		nibble_copy((buf + (ed>>1)+1)/*octet*/, 1-(ed&0x1)/*nibble*/,
3886 			peer_dte->dtea_addr, HIGH_NIBBLE, ing);
3887 		DTEtoNSAP(calling, (buf + (ed>>1)+1)/*octet*/,
3888 			1-(ed&0x1)/*nibble*/, ing);
3889 
3890 	}
3891 
3892 	ASSERT( ptr == (caddr_t)(facil_len + 1 + (int)*facil_len) );
3893 
3894 	/*
3895 	 * now look for user data to find protocol identifier
3896 	 */
3897 	if( ptr == buf + buf_len ) {
3898 		/* no user data */
3899 		*proto = ISOPROTO_TP; /* to proto id --> use TP */
3900 		IFDEBUG(D_CADDR)
3901 			printf("NO USER DATA: use TP\n");
3902 		ENDDEBUG
3903 	} else {
3904 		ASSERT ( ptr < buf + buf_len );
3905 		if ( ptr >= buf + buf_len ) {
3906 			printf("ptr 0x%x buf 0x%x buf_len 0x%x buf+buf_len 0x%x\n",
3907 				ptr, buf, buf_len, buf+buf_len);
3908 		}
3909 		IFDEBUG(D_CADDR)
3910 			printf("proto byte 0x%x, value 0x%x\n", ptr, *ptr);
3911 		ENDDEBUG
3912 		switch(*ptr) {
3913 		case 0x81:
3914 			*proto = ISOPROTO_CLNP;
3915 			break;
3916 		case 0x0:
3917 			*proto = ISOPROTO_INACT_NL;
3918 			break;
3919 		case  'e': /* for EAN */
3920 			*proto = ISOPROTO_TP;
3921 			/* can check for "an2" or can ignore the rest of the u data */
3922 			break;
3923 		case 0xff: /* reserved for future extensions */
3924 			*proto =  ISOPROTO_X25;
3925 			break;
3926 		case 0x82: /* 9542 not implemented */
3927 		case 0x84: /* 8878/A SNDCP not implemented */
3928 		default:
3929 			*proto =  -1;
3930 			return E_CO_HLI_PROTOID;
3931 		}
3932 	}
3933 	return 0;
3934 }
3935 
3936 #endif NARGOXTWENTYFIVE > 0
3937