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