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