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