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