136381Ssklower /*********************************************************** 236381Ssklower Copyright IBM Corporation 1987 336381Ssklower 436381Ssklower All Rights Reserved 536381Ssklower 636381Ssklower Permission to use, copy, modify, and distribute this software and its 736381Ssklower documentation for any purpose and without fee is hereby granted, 836381Ssklower provided that the above copyright notice appear in all copies and that 936381Ssklower both that copyright notice and this permission notice appear in 1036381Ssklower supporting documentation, and that the name of IBM not be 1136381Ssklower used in advertising or publicity pertaining to distribution of the 1236381Ssklower software without specific, written prior permission. 1336381Ssklower 1436381Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 1536381Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 1636381Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 1736381Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 1836381Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 1936381Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2036381Ssklower SOFTWARE. 2136381Ssklower 2236381Ssklower ******************************************************************/ 2336381Ssklower 2436381Ssklower /* 2536381Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 2636381Ssklower */ 2736381Ssklower /* 2836381Ssklower * $Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $ 2936381Ssklower * $Source: /usr/argo/sys/netiso/RCS/if_cons.c,v $ 3036381Ssklower * 3136381Ssklower * cons.c - Connection Oriented Network Service: 3236381Ssklower * including support for a) user transport-level service, 3336381Ssklower * b) COSNS below CLNP, and c) CONS below TP. 3436381Ssklower */ 3536381Ssklower 3636381Ssklower #ifndef lint 3736381Ssklower static char *rcsid = "$Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $"; 3836381Ssklower #endif lint 3936381Ssklower 4036381Ssklower #ifdef ARGO_DEBUG 4136381Ssklower #define Static 4236381Ssklower unsigned LAST_CALL_PCB; 4336381Ssklower #else ARGO_DEBUG 4436381Ssklower #define Static static 4536381Ssklower #endif ARGO_DEBUG 4636381Ssklower 4736381Ssklower #include "ecn.h" 4836381Ssklower #include "argoxtwentyfive.h" 4936381Ssklower 5036381Ssklower #if NARGOXTWENTYFIVE > 0 5136381Ssklower 5236381Ssklower #ifdef KERNEL 5336381Ssklower 5436381Ssklower #include "param.h" 5536381Ssklower #include "systm.h" 5636381Ssklower #include "mbuf.h" 5736381Ssklower #include "protosw.h" 5836381Ssklower #include "socket.h" 5936381Ssklower #include "socketvar.h" 6036381Ssklower #include "errno.h" 6136381Ssklower #include "ioctl.h" 62*40783Smarc #include "tsleep.h" 6336381Ssklower 6436381Ssklower #include "../net/if.h" 6536381Ssklower #include "../net/netisr.h" 6636381Ssklower #include "../net/route.h" 6736381Ssklower 6836381Ssklower #include "../netiso/iso_errno.h" 6936381Ssklower #include "../netiso/argo_debug.h" 7036381Ssklower #include "../netiso/tp_trace.h" 7136381Ssklower #include "../netiso/iso.h" 7236381Ssklower #include "../netiso/cons.h" 7336381Ssklower #include "../netiso/iso_pcb.h" 7436381Ssklower #include "../netiso/cons_pcb.h" 7536381Ssklower #include "../caif/eicon.h" 7636381Ssklower 7736381Ssklower #ifdef ARGO_DEBUG 7836381Ssklower #define MT_XCONN 0x50 7936381Ssklower #define MT_XCLOSE 0x51 8036381Ssklower #define MT_XCONFIRM 0x52 8136381Ssklower #define MT_XDATA 0x53 8236381Ssklower #define MT_XHEADER 0x54 8336381Ssklower #else 8436381Ssklower #define MT_XCONN MT_DATA 8536381Ssklower #define MT_XCLOSE MT_DATA 8636381Ssklower #define MT_XCONFIRM MT_DATA 8736381Ssklower #define MT_XDATA MT_DATA 8836381Ssklower #define MT_XHEADER MT_HEADER 8936381Ssklower #endif ARGO_DEBUG 9036381Ssklower 9136381Ssklower #define DONTCLEAR -1 9236381Ssklower 9336381Ssklower /********************************************************************* 9436381Ssklower * cons.c - CONS interface to the eicon adapter 9536381Ssklower * Includes connection manager - for (TP, CLNP)/x.25 9636381Ssklower * 9736381Ssklower * TODO: figure out what resources we might run out of besides mbufs. 9836381Ssklower * If we run out of any of them (including mbufs) close and recycle 9936381Ssklower * lru x% of the connections, for some parameter x. 10036381Ssklower * 10136381Ssklower * There are 4 interfaces from above: 10236381Ssklower * 0) from CLNP: 10336381Ssklower * cons is an interface driver - CLNP calls 10436381Ssklower * cosns_output(ifp, m, dst), a device-type interface output routine 10536381Ssklower * that does some connection management stuff and queues a 10636381Ssklower * request on the eicon driver queue by calling ifp->if_output. 10736381Ssklower * The eicon's ifp structure contains cosns_output as its output routine 10836381Ssklower * rather than ifp_>if_output! Kludge, but we don't have much choice... 10936381Ssklower * X25 connections created in this manner may always be multiplexed 11036381Ssklower * but only with their own kind (not with connections servicing TP 11136381Ssklower * directly.) 11236381Ssklower * co_flags & CONSF_DGM 11336381Ssklower * 1) from TP0: 11436381Ssklower * cons CO network service 11536381Ssklower * TP associates a transport connection with a network connection. 11636381Ssklower * cons_output( isop, m, len, isdgm==0 ) 11736381Ssklower * co_flags == 0 11836381Ssklower * 2) from TP 4: 11936381Ssklower * It's a datagram service, like clnp is. - even though it calls 12036381Ssklower * cons_output( isop, m, len, isdgm==1 ) 12136381Ssklower * it eventually goes through 12236381Ssklower * cosns_output(ifp, m, dst). 12336381Ssklower * TP4 permits multiplexing (reuse, possibly simultaneously) of the 12436381Ssklower * network connections. 12536381Ssklower * This means that many sockets (many tpcbs) may be associated with 12636381Ssklower * this cons_pcb, hence cannot have a back ptr from cons_pcb to a tpcb. 12736381Ssklower * co_flags & CONSF_DGM 12836381Ssklower * co_socket is null since there may be many sockets that use this copcb. 12936381Ssklower * 3) from user: cons_usrreq(), cons_ctloutput() 13036381Ssklower * cons is a standard transport service interface. 13136381Ssklower * There is a 1-1 correspondence between net connections and sockets. 13236381Ssklower * co_socket points to a socket. 13336381Ssklower * 13436381Ssklower NOTE: 13536381Ssklower streams would really be nice. sigh. 13636381Ssklower NOTE: 13736381Ssklower eicon <--> cons interface: the first mbuf (the ecn_request structure) 13836381Ssklower had better NOT be a cluster. 13936381Ssklower NOTE: 14036381Ssklower PVCs could be handled by config-ing a cons with an address and with the 14136381Ssklower IFF_POINTTOPOINT flag on. This code would then have to skip the 14236381Ssklower connection setup stuff for pt-to-pt links. 14336381Ssklower NOTE: 14436381Ssklower We keep track of the ifp for each connection. Right now this is 14536381Ssklower unnecessary, but just in case someone comes up with some kind 14636381Ssklower of a kludge to allow > 1 eicon to be attached at a time, 14736381Ssklower (i.e., some meaningful netof( a type 37 address ) ), 14836381Ssklower we do keep track of this. 14936381Ssklower 15036381Ssklower 15136381Ssklower *********************************************************************/ 15236381Ssklower 15336381Ssklower #define touch(copcb) copcb->co_ttl = copcb->co_init_ttl 15436381Ssklower 15536381Ssklower #define CONS_IFQMAXLEN 5 15636381Ssklower 15736381Ssklower #define SET_CHANMASK( isop, chan )\ 15836381Ssklower if( (u_int)(chan) < 32 ) \ 15936381Ssklower (isop)->isop_chanmask = (1<<((chan)-1));\ 16036381Ssklower else \ 16136381Ssklower (isop)->isop_negchanmask = (1<<((256-(chan))-1)) 16236381Ssklower 16336381Ssklower #define ADD_CHANMASK( isop, chan )\ 16436381Ssklower if( (u_int)(chan) < 32 ) \ 16536381Ssklower (isop)->isop_chanmask |= (1<<((chan)-1));\ 16636381Ssklower else \ 16736381Ssklower (isop)->isop_negchanmask |= (1<<((256-(chan))-1)) 16836381Ssklower 16936381Ssklower struct ifnet *consif; /* TO BE REMOVED */ 17036381Ssklower Static int consinit(), consioctl(), consattach(); 17136381Ssklower 17236381Ssklower /* protosw pointers for getting to higher layer */ 17336381Ssklower Static struct protosw *CLNP_proto; 17436381Ssklower Static struct protosw *TP_proto; 17536381Ssklower Static struct protosw *X25_proto; 17636381Ssklower Static int issue_clear_req(); 17736381Ssklower 17836381Ssklower #ifndef PHASEONE 17936381Ssklower extern struct ifaddr *ifa_ifwithnet(); 18036381Ssklower #endif PHASEONE 18136381Ssklower 18236381Ssklower extern struct ifaddr *ifa_ifwithaddr(); 18336381Ssklower 18436381Ssklower Static struct socket dummysocket; /* for use by cosns */ 18536381Ssklower 18636381Ssklower extern struct isopcb tp_isopcb; /* chain of all TP pcbs */ 18736381Ssklower struct isopcb cons_isopcb; /* chain of all cons pcbs */ 18836381Ssklower struct isopcb tp_incoming_pending; /* incoming connections 18936381Ssklower for TP, pending */ 19036381Ssklower 19136381Ssklower struct isopcb *Xpcblist[] = { 19236381Ssklower &cons_isopcb, 19336381Ssklower &tp_incoming_pending, 19436381Ssklower &tp_isopcb, 19536381Ssklower (struct isopcb *)0 19636381Ssklower }; 19736381Ssklower 19836381Ssklower Static int parse_facil(), NSAPtoDTE(), make_partial_x25_packet(); 19936381Ssklower Static int FACILtoNSAP(), DTEtoNSAP(); 20036381Ssklower Static struct cons_pcb *cons_chan_to_pcb(); 20136381Ssklower 20236381Ssklower #define HIGH_NIBBLE 1 20336381Ssklower #define LOW_NIBBLE 0 20436381Ssklower 20536381Ssklower /* 20636381Ssklower * NAME: nibble_copy() 20736381Ssklower * FUNCTION and ARGUMENTS: 20836381Ssklower * copies (len) nibbles from (src_octet), high or low nibble 20936381Ssklower * to (dst_octet), high or low nibble, 21036381Ssklower * src_nibble & dst_nibble should be: 21136381Ssklower * HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble 21236381Ssklower * LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble 21336381Ssklower * RETURNS: VOID 21436381Ssklower */ 21536381Ssklower void 21636381Ssklower nibble_copy( src_octet, src_nibble, dst_octet, dst_nibble, len) 21736381Ssklower register char *src_octet; 21836381Ssklower register char *dst_octet; 21936381Ssklower register unsigned src_nibble; 22036381Ssklower register unsigned dst_nibble; 22136381Ssklower int len; 22236381Ssklower { 22336381Ssklower 22436381Ssklower register i; 22536381Ssklower register unsigned dshift, sshift; 22636381Ssklower 22736381Ssklower IFDEBUG(D_CADDR) 22836381Ssklower printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", 22936381Ssklower src_octet, src_nibble, dst_octet, dst_nibble, len); 23036381Ssklower ENDDEBUG 23136381Ssklower #define SHIFT 0x4 23236381Ssklower 23336381Ssklower dshift = dst_nibble << 2; 23436381Ssklower sshift = src_nibble << 2; 23536381Ssklower 23636381Ssklower for (i=0; i<len; i++) { 23736381Ssklower /* clear dst_nibble */ 23836381Ssklower *dst_octet &= ~(0xf<< dshift); 23936381Ssklower 24036381Ssklower /* set dst nibble */ 24136381Ssklower *dst_octet |= ( 0xf & (*src_octet >> sshift))<< dshift; 24236381Ssklower 24336381Ssklower dshift ^= SHIFT; 24436381Ssklower sshift ^= SHIFT; 24536381Ssklower src_nibble = 1-src_nibble; 24636381Ssklower dst_nibble = 1-dst_nibble; 24736381Ssklower src_octet += src_nibble; 24836381Ssklower dst_octet += dst_nibble; 24936381Ssklower } 25036381Ssklower IFDEBUG(D_CADDR) 25136381Ssklower printf("nibble_copy DONE\n"); 25236381Ssklower ENDDEBUG 25336381Ssklower } 25436381Ssklower 25536381Ssklower /* 25636381Ssklower * NAME: nibble_match() 25736381Ssklower * FUNCTION and ARGUMENTS: 25836381Ssklower * compares src_octet/src_nibble and dst_octet/dst_nibble for len nibbles. 25936381Ssklower * RETURNS: 0 if they differ, 1 if they are the same. 26036381Ssklower */ 26136381Ssklower int 26236381Ssklower nibble_match( src_octet, src_nibble, dst_octet, dst_nibble, len) 26336381Ssklower register char *src_octet; 26436381Ssklower register char *dst_octet; 26536381Ssklower register unsigned src_nibble; 26636381Ssklower register unsigned dst_nibble; 26736381Ssklower int len; 26836381Ssklower { 26936381Ssklower 27036381Ssklower register i; 27136381Ssklower register unsigned dshift, sshift; 27236381Ssklower u_char nibble_a, nibble_b; 27336381Ssklower 27436381Ssklower IFDEBUG(D_CADDR) 27536381Ssklower printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", 27636381Ssklower src_octet, src_nibble, dst_octet, dst_nibble, len); 27736381Ssklower ENDDEBUG 27836381Ssklower #define SHIFT 0x4 27936381Ssklower 28036381Ssklower dshift = dst_nibble << 2; 28136381Ssklower sshift = src_nibble << 2; 28236381Ssklower 28336381Ssklower for (i=0; i<len; i++) { 28436381Ssklower nibble_b = ((*dst_octet)>>dshift) & 0xf; 28536381Ssklower nibble_a = ( 0xf & (*src_octet >> sshift)); 28636381Ssklower if( nibble_b != nibble_a ) 28736381Ssklower return 0; 28836381Ssklower 28936381Ssklower dshift ^= SHIFT; 29036381Ssklower sshift ^= SHIFT; 29136381Ssklower src_nibble = 1-src_nibble; 29236381Ssklower dst_nibble = 1-dst_nibble; 29336381Ssklower src_octet += src_nibble; 29436381Ssklower dst_octet += dst_nibble; 29536381Ssklower } 29636381Ssklower IFDEBUG(D_CADDR) 29736381Ssklower printf("nibble_match DONE\n"); 29836381Ssklower ENDDEBUG 29936381Ssklower return 1; 30036381Ssklower } 30136381Ssklower 30236381Ssklower #ifdef ARGO_DEBUG 30336381Ssklower 30436381Ssklower Static 30536381Ssklower dump_copcb(copcb, str) 30636381Ssklower char * str; 30736381Ssklower register struct cons_pcb *copcb; 30836381Ssklower { 30936381Ssklower printf("XPCB DUMP %s\n", str); 31036381Ssklower if (copcb) { 31136381Ssklower printf("\t copcb 0x%x next 0x%x head 0x%x socket 0x%x ifp 0x%x\n", 31236381Ssklower copcb, copcb->co_next, copcb->co_head, copcb->co_socket, copcb->co_ifp); 31336381Ssklower printf("\t channel 0x%x state 0x%x flags 0x%x proto 0x%x\n", 31436381Ssklower copcb->co_channel, copcb->co_state, copcb->co_flags, copcb->co_proto); 31536381Ssklower printf("\t laddr :\n"); 31636381Ssklower dump_isoaddr(&copcb->co_laddr); 31736381Ssklower printf("\t faddr :\n"); 31836381Ssklower dump_isoaddr(&copcb->co_faddr); 31936381Ssklower printf("\tttl 0x%x init_ttl 0x%x pending: %d\n", 32036381Ssklower copcb->co_ttl, copcb->co_init_ttl, copcb->co_pending.ifq_len); 32136381Ssklower } 32236381Ssklower printf("END DUMP\n"); 32336381Ssklower } 32436381Ssklower #endif ARGO_DEBUG 32536381Ssklower 32636381Ssklower /* 32736381Ssklower * FUNCTION : choose_output - chooses between the eicon and loopback. 32836381Ssklower * This MUST be here because the ifp->if_output routine is cosns_output 32936381Ssklower * -- due to our need to look like a device driver for CLNP. sigh. 33036381Ssklower * ARGUMENTS & PURPOSE: (copcb) ptr to a protocol control block for 33136381Ssklower * x.25, (m) is an mbuf ptr. *m is a request destined either 33236381Ssklower * for the eicon driver or for the loopback driver. 33336381Ssklower * RETURNS : whatever error value the 2I or loopback returns. 33436381Ssklower */ 33536381Ssklower Static int 33636381Ssklower choose_output( ifp, m, loop) 33736381Ssklower struct ifnet *ifp; 33836381Ssklower struct mbuf *m; 33936381Ssklower int loop; 34036381Ssklower { 34136381Ssklower int error; 34236381Ssklower 34336381Ssklower if( !m ) 34436381Ssklower return 0; 34536381Ssklower ASSERT(m->m_len != 0); 34636381Ssklower if( loop != 0) 34736381Ssklower error = lpboutput( ifp, m ); 34836381Ssklower else 34936381Ssklower error = ecnoutput( ifp, m ); 35036381Ssklower 35136381Ssklower if (error == 0) 35236381Ssklower ifp->if_opackets ++; 35336381Ssklower else { 35436381Ssklower ifp->if_oerrors ++; 35536381Ssklower IFTRACE(D_CDATA) 35636381Ssklower tptrace( TPPTmisc, 35736381Ssklower "choose_output: ifp m error loop\n", 35836381Ssklower ifp, m, error, loop); 35936381Ssklower ENDTRACE 36036381Ssklower } 36136381Ssklower IFDEBUG(D_CCONS) 36236381Ssklower printf("choose_output returns 0x%x\n", error ); 36336381Ssklower ENDDEBUG 36436381Ssklower return error; 36536381Ssklower } 36636381Ssklower 36736381Ssklower /* 36836381Ssklower **************************** NET PROTOCOL cons *************************** 36936381Ssklower */ 37036381Ssklower 37136381Ssklower /* 37236381Ssklower * NAME: cons_init() 37336381Ssklower * CALLED FROM: 37436381Ssklower * autoconf 37536381Ssklower * FUNCTION: 37636381Ssklower * initialize the protocol 37736381Ssklower */ 37836381Ssklower cons_init() 37936381Ssklower { 38036381Ssklower init_lpb(); 38136381Ssklower consattach(); 38236381Ssklower 38336381Ssklower /* protocol init stuff */ 38436381Ssklower 38536381Ssklower consintrq.ifq_maxlen = IFQ_MAXLEN; 38636381Ssklower consintrq.ifq_head = consintrq.ifq_tail = (struct mbuf *)0; 38736381Ssklower 38836381Ssklower CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM); 38936381Ssklower X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM); 39036381Ssklower TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET); 39136381Ssklower IFDEBUG(D_CCONS) 39236381Ssklower printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n", 39336381Ssklower CLNP_proto, X25_proto, TP_proto); 39436381Ssklower ENDDEBUG 39536381Ssklower 39636381Ssklower cons_isopcb.isop_next = cons_isopcb.isop_prev = &cons_isopcb; 39736381Ssklower tp_incoming_pending.isop_next = tp_incoming_pending.isop_prev = 39836381Ssklower &tp_incoming_pending; 39936381Ssklower } 40036381Ssklower 40136381Ssklower #ifdef notdef 40236381Ssklower 40336381Ssklower /* 40436381Ssklower * NAME: cons_free_lru() 40536381Ssklower * some day CALLED FROM: 40636381Ssklower * wherever we run out of mbufs (not used right yet) 40736381Ssklower * FUNCTION: 40836381Ssklower * get rid of the num least recently used connections and 40936381Ssklower * recycle their mbufs. 41036381Ssklower * NOTE: GROTESQUELY INEFFICIENT needs to be written nicely 41136381Ssklower */ 41236381Ssklower 41336381Ssklower Static 41436381Ssklower cons_free_lru(qty) 41536381Ssklower int qty; 41636381Ssklower { 41736381Ssklower register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist; 41836381Ssklower register struct cons_pcb *copcb; 41936381Ssklower struct cons_pcb Lru; 42036381Ssklower struct cons_pcb *lru; 42136381Ssklower 42236381Ssklower IFDEBUG(D_CCONS) 42336381Ssklower printf("cons_free_lru( 0x%x )\n", qty); 42436381Ssklower ENDDEBUG 42536381Ssklower 42636381Ssklower Lru.co_ttl = X25_TTL; 42736381Ssklower lru = &Lru; 42836381Ssklower 42936381Ssklower while (qty > 1) { /* GROT */ 43036381Ssklower cons_free_lru( 1 ); 43136381Ssklower qty -- ; 43236381Ssklower } 43336381Ssklower 43436381Ssklower for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) { 43536381Ssklower copcb = (struct cons_pcb *)copcb->co_next; 43636381Ssklower while (copcb != *copcblist) { 43736381Ssklower if( copcb->co_ttl < lru->co_ttl ) 43836381Ssklower lru = copcb; 43936381Ssklower copcb = (struct cons_pcb *)copcb->co_next; 44036381Ssklower } 44136381Ssklower } 44236381Ssklower 44336381Ssklower if(lru->co_socket) { 44436381Ssklower soisdisconnected(lru->co_socket); 44536381Ssklower sohasoutofband(lru->co_socket); /* signal */ 44636381Ssklower } 44736381Ssklower 44836381Ssklower cons_clear_and_detach( lru, E_CO_HLI_RESYNC, PRC_TIMXCEED_REASS); 44936381Ssklower } 45036381Ssklower #endif notdef 45136381Ssklower 45236381Ssklower /* 45336381Ssklower * NAME: cons_slowtimo() 45436381Ssklower * CALLED FROM: 45536381Ssklower * the clock 45636381Ssklower * FUNCTION: 45736381Ssklower * get rid of any timed-out cons connections 45836381Ssklower * cons connections get "touched" with every use, meaning the 45936381Ssklower * time-to-live gets reset to its max value w/ every use. 46036381Ssklower * The slowtimo() rtn decrements the time-to-live for each 46136381Ssklower * cons connection. If one of them hits zero ---> zap the connection. 46236381Ssklower * This really only applies to those used for CLNP and TP4. 46336381Ssklower * TP4 keeps the connections open with keepalive. 46436381Ssklower * TODO: 46536381Ssklower * Have this happen ONLY for international connections since 46636381Ssklower * there's no connect time charge for domestic calls. 46736381Ssklower * Make default 5 min; make a user option to change it. 46836381Ssklower * TODO: 46936381Ssklower * Maybe if the ttl gets lower than a certain threshold, move this 47036381Ssklower * copcb to the END of its queue so it doesn't slow down the others. 47136381Ssklower */ 47236381Ssklower 47336381Ssklower cons_slowtimo() 47436381Ssklower { 47536381Ssklower register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist; 47636381Ssklower register struct cons_pcb *copcb; 47736381Ssklower int s = splnet(); 47836381Ssklower int qlen = 0; 47936381Ssklower int qdrops = 0; 48036381Ssklower int nvisited = 0; 48136381Ssklower 48236381Ssklower #ifdef ARGO_DEBUG 48336381Ssklower Static int count; 48436381Ssklower 48536381Ssklower count = 0; 48636381Ssklower #endif ARGO_DEBUG 48736381Ssklower 48836381Ssklower IncStat(co_slowtimo); 48936381Ssklower for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) { 49036381Ssklower #ifdef ARGO_DEBUG 49136381Ssklower if( copcb == (struct cons_pcb *)0 ) { 49236381Ssklower ASSERT( 0 ); 49336381Ssklower panic("TURNING OFF cons_slowtimo()!!! \n"); 49436381Ssklower } 49536381Ssklower #endif ARGO_DEBUG 49636381Ssklower copcb = (struct cons_pcb *)copcb->co_next; 49736381Ssklower while (copcb != *copcblist) { 49836381Ssklower #ifdef ARGO_DEBUG 49936381Ssklower if(++count >50 ) { 50036381Ssklower printf("cons PANIC: slowtimo LOOP\n"); 50136381Ssklower splx(s); 50236381Ssklower return; 50336381Ssklower } 50436381Ssklower #endif ARGO_DEBUG 50536381Ssklower #ifdef notdef 50636381Ssklower if( copcb->co_init_ttl == 0 ) { 50736381Ssklower ASSERT( (struct isopcb *)(*copcblist)==(struct isopcb *)&tp_isopcb ); 50836381Ssklower copcb = (struct cons_pcb *)copcb->co_next; 50936381Ssklower continue; 51036381Ssklower } 51136381Ssklower #endif notdef 51236381Ssklower nvisited ++; 51336381Ssklower ASSERT( copcb != (struct cons_pcb *)0 ); 51436381Ssklower qlen += copcb->co_pending.ifq_len; 51536381Ssklower qdrops += copcb->co_pending.ifq_drops; 51636381Ssklower 51736381Ssklower if( copcb->co_socket) { 51836381Ssklower /* don't want XTS, TP0 connections to be subject to time out */ 51936381Ssklower copcb = (struct cons_pcb *)copcb->co_next; 52036381Ssklower continue; 52136381Ssklower } 52236381Ssklower 52336381Ssklower if( -- (copcb->co_ttl) > 0 ) { 52436381Ssklower copcb = (struct cons_pcb *)copcb->co_next; 52536381Ssklower continue; 52636381Ssklower } 52736381Ssklower 52836381Ssklower IncStat(co_timedout); 52936381Ssklower 53036381Ssklower IFDEBUG(D_CCONN) 53136381Ssklower printf("TIMING OUT chan 0x%x copcb 0x%x flags 0x%x\n", 53236381Ssklower copcb->co_channel, copcb, copcb->co_flags ); 53336381Ssklower ENDDEBUG 53436381Ssklower 53536381Ssklower { 53636381Ssklower register struct cons_pcb * next = 53736381Ssklower (struct cons_pcb *)copcb->co_next; 53836381Ssklower cons_clear_and_detach(copcb, 53936381Ssklower E_CO_HLI_RESYNC, PRC_TIMXCEED_REASS); 54036381Ssklower copcb = next; 54136381Ssklower } 54236381Ssklower } 54336381Ssklower } 54436381Ssklower if(nvisited) { 54536381Ssklower cons_stat.co_avg_qlen = qlen / nvisited; 54636381Ssklower cons_stat.co_avg_qdrop = qdrops / nvisited; 54736381Ssklower cons_stat.co_active = nvisited; 54836381Ssklower } 54936381Ssklower done: 55036381Ssklower splx(s); 55136381Ssklower } 55236381Ssklower 55336381Ssklower DUMP_PCBLIST() 55436381Ssklower { 55536381Ssklower register int i=0; 55636381Ssklower register struct cons_pcb *copcb; 55736381Ssklower register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist; 55836381Ssklower 55936381Ssklower for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) { 56036381Ssklower printf("FOR %d: 0x%x ", ++i, copcb); 56136381Ssklower copcb = (struct cons_pcb *)copcb->co_next; 56236381Ssklower printf(" next 0x%x, *copcblist 0x%x\n", copcb, *copcblist); 56336381Ssklower while (copcb != *copcblist) { 56436381Ssklower ASSERT( copcb != (struct cons_pcb *)0 ); 56536381Ssklower printf("\tCOPCB 0x%x\n", copcb); 56636381Ssklower if( copcb ) 56736381Ssklower dump_buf(copcb, sizeof( *copcb)); 56836381Ssklower else 56936381Ssklower break; 57036381Ssklower copcb = (struct cons_pcb *)copcb->co_next; 57136381Ssklower } 57236381Ssklower } 57336381Ssklower } 57436381Ssklower 57536381Ssklower /* 57636381Ssklower * NAME: cons_pcballoc() 57736381Ssklower * CALLED FROM: 57836381Ssklower * cons_usrreq() when doing PRU_ATTACH, 57936381Ssklower * cons_incoming() when opening a new connection. 58036381Ssklower * FUNCTION and ARGUMENTS: 58136381Ssklower * Allocates a new pcb. 58236381Ssklower * The flags and proto arguments are stashed into the new pcb. 58336381Ssklower * RETURN VALUE: 58436381Ssklower * E* if error, 0 if ok 58536381Ssklower */ 58636381Ssklower Static int 58736381Ssklower cons_pcballoc(so, head, flags, proto, dest) 58836381Ssklower struct socket *so; 58936381Ssklower struct isopcb *head; 59036381Ssklower u_short flags; 59136381Ssklower struct protosw *proto; 59236381Ssklower struct cons_pcb **dest; 59336381Ssklower { 59436381Ssklower int error; 59536381Ssklower register struct cons_pcb *copcb; 59636381Ssklower 59736381Ssklower IFDEBUG(D_CCONN) 59836381Ssklower printf("cons_pcballoc (0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", 59936381Ssklower so, head, flags, proto, dest); 60036381Ssklower ENDDEBUG 60136381Ssklower if(proto == (struct protosw *)0) 60236381Ssklower return EPROTONOSUPPORT; 60336381Ssklower 60436381Ssklower if( ( error = iso_pcballoc(so, head) ) == EOK ) { 60536381Ssklower /* Have allocated a cleared mbuf */ 60636381Ssklower 60736381Ssklower copcb = (struct cons_pcb *)so->so_pcb; 60836381Ssklower copcb->co_ttl = copcb->co_init_ttl = X25_TTL; 60936381Ssklower copcb->co_flags = flags; 61036381Ssklower copcb->co_proto = proto; 61136381Ssklower copcb->co_pending.ifq_maxlen = CONS_IFQMAXLEN; 61236381Ssklower copcb->co_myself = copcb; 61336381Ssklower 61436381Ssklower if (so == &dummysocket) 61536381Ssklower copcb->co_socket = (struct socket *)0; 61636381Ssklower 61736381Ssklower *dest = copcb; 61836381Ssklower } 61936381Ssklower done: 62036381Ssklower IFDEBUG(D_CCONN) 62136381Ssklower printf("cons_pcballoc returns 0x%x: DUMP\n", copcb); 62236381Ssklower dump_buf( copcb, sizeof(*copcb)); 62336381Ssklower ENDDEBUG 62436381Ssklower if( (flags & CONSF_ICRE) == 0) { 62536381Ssklower struct dte_addr *dtea = &(*dest)->co_peer_dte; 62636381Ssklower int len; 62736381Ssklower 62836381Ssklower error = iso_8208snparesolve(&(*dest)->co_faddr, dtea, &len); 62936381Ssklower ASSERT(error == 0); 63036381Ssklower ASSERT(len == sizeof(struct dte_addr)); 63136381Ssklower } 63236381Ssklower 63336381Ssklower return error; 63436381Ssklower } 63536381Ssklower 63636381Ssklower /* 63736381Ssklower * NAME: cons_connect() 63836381Ssklower * CALLED FROM: 63936381Ssklower * cons_usrreq() when opening a new connection. 64036381Ssklower * FUNCTION anD ARGUMENTS: 64136381Ssklower * Figures out which device to use, finding a route if one doesn't 64236381Ssklower * already exist. 64336381Ssklower * Builds an eicon connection request and gives it to the device. 64436381Ssklower * RETURN VALUE: 64536381Ssklower * returns E* 64636381Ssklower */ 64736381Ssklower Static int 64836381Ssklower cons_connect( copcb ) 64936381Ssklower register struct cons_pcb *copcb; 65036381Ssklower { 65136381Ssklower register struct eicon_request *ecnrq; 65236381Ssklower register struct mbuf *m; 65336381Ssklower int error = 0; 65436381Ssklower struct ifaddr *ifa; 65536381Ssklower 65636381Ssklower IFDEBUG(D_CCONN) 65736381Ssklower printf("cons_connect( 0x%x ) : ifp 0x%x\npeer: ", copcb, copcb->co_ifp); 65836381Ssklower dump_isoaddr(&copcb->co_faddr); 65936381Ssklower printf("\nmyaddr: "); 66036381Ssklower dump_isoaddr(&copcb->co_laddr); 66136381Ssklower printf("\n" ); 66236381Ssklower ENDDEBUG 66336381Ssklower 66436381Ssklower /* PHASE 2: this call is OK */ 66536381Ssklower if( ifa = ifa_ifwithaddr(&copcb->co_faddr ) ) { 66636381Ssklower /* foreign address is me */ 66736381Ssklower copcb->co_ifp = ifa->ifa_ifp; 66836381Ssklower IFDEBUG(D_CCONN) 66936381Ssklower printf("cons_connect: after if_withaddr copcb->co_ifp 0x%x\n", 67036381Ssklower copcb->co_ifp); 67136381Ssklower ENDDEBUG 67236381Ssklower 67336381Ssklower if( (ifa->ifa_ifp->if_flags&(IFF_LOOPBACK|IFF_UP)) == 67436381Ssklower (IFF_LOOPBACK|IFF_UP)) { 67536381Ssklower copcb->co_flags |= CONSF_LOOPBACK; 67636381Ssklower } 67736381Ssklower bcopy((caddr_t)&ifa->ifa_addr, (caddr_t)&copcb->co_laddr, 67836381Ssklower sizeof(struct sockaddr)); 67936381Ssklower } 68036381Ssklower IFDEBUG(D_CCONN) 68136381Ssklower printf("cons_connect: co_flags 0x%x\n", copcb->co_flags); 68236381Ssklower if( ifa ) { 68336381Ssklower printf(" cons_connect withaddr returns %s\n", 68436381Ssklower copcb->co_ifp->if_name); 68536381Ssklower } 68636381Ssklower ENDDEBUG 68736381Ssklower else if ( copcb->co_ifp == (struct ifnet *)0 ) { 68836381Ssklower #ifdef PHASEONE 68936381Ssklower /* 69036381Ssklower * We need to get the local nsap address. 69136381Ssklower * First, route to the destination. This will provide us with 69236381Ssklower * an ifp. Second, determine which local address linked on 69336381Ssklower * that ifp is appropriate 69436381Ssklower */ 69536381Ssklower struct sockaddr_iso *first_hop; /* filled by clnp_route */ 69636381Ssklower struct iso_addr *localaddr, *clnp_srcaddr(); 69736381Ssklower 69836381Ssklower if (error = clnp_route(&copcb->co_faddr, 69936381Ssklower &((struct isopcb *)copcb)->isop_route, /* flags */0, 70036381Ssklower &first_hop, &copcb->co_ifp)) 70136381Ssklower goto bad; 70236381Ssklower 70336381Ssklower /* determine local address based upon ifp */ 70436381Ssklower if ((localaddr = clnp_srcaddr(copcb->co_ifp, 70536381Ssklower &first_hop->siso_addr)) == NULL) { 70636381Ssklower error = ENETUNREACH; 70736381Ssklower goto bad; 70836381Ssklower } 70936381Ssklower copcb->co_laddr.siso_family = AF_ISO; 71036381Ssklower copcb->co_laddr.siso_addr = *localaddr; 71136381Ssklower #else 71236381Ssklower /* Foreign addr isn't me (lpb). If still don't have an ifp or have 71336381Ssklower * an ifp but don't know its address, look for a route 71436381Ssklower */ 71536381Ssklower if( ifa = ifa_ifwithnet(&copcb->co_faddr) ) { 71636381Ssklower copcb->co_ifp = ifa->ifa_ifp; 71736381Ssklower IFDEBUG(D_CCONN) 71836381Ssklower printf(" cons_connect withnet returns %s\n", 71936381Ssklower copcb->co_ifp->if_name); 72036381Ssklower ENDDEBUG 72136381Ssklower } else { 72236381Ssklower printf("cons PANIC: connect: can't find SNPA \n"); 72336381Ssklower error = ENETUNREACH; 72436381Ssklower goto bad; 72536381Ssklower } 72636381Ssklower #endif PHASEONE 72736381Ssklower } 72836381Ssklower #ifndef PHASEONE 72936381Ssklower if( ifa == (struct ifaddr *)0 ) { 73036381Ssklower struct ifaddr * iso_ifwithidi(); 73136381Ssklower 73236381Ssklower if( ifa = iso_ifwithidi(&copcb->co_faddr) ) { 73336381Ssklower copcb->co_ifp = ifa->ifa_ifp; 73436381Ssklower IFDEBUG(D_CCONN) 73536381Ssklower printf(" cons_connect withnet returns %s\n", 73636381Ssklower copcb->co_ifp->if_name); 73736381Ssklower ENDDEBUG 73836381Ssklower } else { 73936381Ssklower printf("cons PANIC: connect: can't find SNPA \n"); 74036381Ssklower error = ENETUNREACH; 74136381Ssklower goto bad; 74236381Ssklower } 74336381Ssklower } 74436381Ssklower bcopy((caddr_t)&ifa->ifa_addr, (caddr_t)&copcb->co_laddr, 74536381Ssklower sizeof(struct sockaddr)); 74636381Ssklower #endif PHASEONE 74736381Ssklower 74836381Ssklower copcb->co_state = CONNECTING; 74936381Ssklower 75036381Ssklower ASSERT( copcb->co_ifp != (struct ifnet *) 0); 75136381Ssklower if ( copcb->co_ifp == (struct ifnet *)0 ) { 75236381Ssklower error = ENETUNREACH; 75336381Ssklower goto bad; 75436381Ssklower } 75536381Ssklower 75636381Ssklower m = m_getclr(M_DONTWAIT, MT_XCONN); 75736381Ssklower if( !m ) { 75836381Ssklower copcb->co_ifp->if_oerrors ++; 75936381Ssklower error = ENOBUFS; 76036381Ssklower goto bad; 76136381Ssklower } 76236381Ssklower m->m_len = sizeof(struct eicon_request); 76336381Ssklower 76436381Ssklower ecnrq = mtod(m, struct eicon_request *); 76536381Ssklower 76636381Ssklower copcb->co_myself = copcb; 76736381Ssklower ecnrq->e_pcb = (caddr_t)copcb; 76836381Ssklower #ifdef ARGO_DEBUG 76936381Ssklower LAST_CALL_PCB = (unsigned) ecnrq->e_pcb; 77036381Ssklower #endif ARGO_DEBUG 77136381Ssklower ecnrq->e_cmd = ECN_CALL; 77236381Ssklower ecnrq->e_vc = 0; /* mbz ? */ 77336381Ssklower ecnrq->e_info = 0; /* mbz */ 77436381Ssklower 77536381Ssklower /* get data buffer */ 77636381Ssklower { struct mbuf *n; 77736381Ssklower 77836381Ssklower MGET(n, M_DONTWAIT, MT_XCONN); 77936381Ssklower if( n==MNULL ) { 78036381Ssklower copcb->co_ifp->if_oerrors ++; 78136381Ssklower error = ENOBUFS; 78236381Ssklower goto bad; 78336381Ssklower } 78436381Ssklower e_data(ecnrq) = n; /* e_data is really dtom(ecnrq)->m_next */ 78536381Ssklower } 78636381Ssklower 78736381Ssklower IFDEBUG(D_CCONN) 78836381Ssklower printf( 78936381Ssklower "calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", 79036381Ssklower &copcb->co_laddr, &copcb->co_faddr, 79136381Ssklower copcb->co_proto->pr_protocol, 79236381Ssklower e_data(ecnrq), 79336381Ssklower copcb->co_flags & CONSF_XTS); 79436381Ssklower ENDDEBUG 79536381Ssklower if( error = make_partial_x25_packet( copcb, e_data(ecnrq)) ) { 79636381Ssklower copcb->co_ifp->if_oerrors ++; 79736381Ssklower m_freem(m); 79836381Ssklower goto bad; 79936381Ssklower } 80036381Ssklower 80136381Ssklower IncStat(co_call); 80236381Ssklower 80336381Ssklower IFDEBUG(D_CDUMP_REQ) 80436381Ssklower printf("cons_connect ecnrq:\n"); 80536381Ssklower dump_buf(ecnrq, sizeof(*ecnrq)); 80636381Ssklower ENDDEBUG 80736381Ssklower 80836381Ssklower ASSERT( copcb->co_channel == 0); 80936381Ssklower if( copcb->co_channel != 0) { 81036381Ssklower printf("cons_connect PANIC: channel is 0x%x\n", copcb->co_channel); 81136381Ssklower } 81236381Ssklower 81336381Ssklower error = choose_output(copcb->co_ifp, m, copcb->co_flags & CONSF_LOOPBACK); 81436381Ssklower 81536381Ssklower switch( error ) { 81636381Ssklower case 0: /* ok */ 81736381Ssklower break; 81836381Ssklower default: /* problem */ 81936381Ssklower printf("cons: PANIC: if_output returns 0x%x\n", error); 82036381Ssklower cons_clear_and_detach( copcb, DONTCLEAR, PRC_ROUTEDEAD); 82136381Ssklower } 82236381Ssklower 82336381Ssklower bad: 82436381Ssklower IFTRACE(D_CDATA) 82536381Ssklower tptrace( TPPTmisc, 82636381Ssklower "cons_connect: choose (copcb m) returned error\n", 82736381Ssklower copcb, m, error, 0); 82836381Ssklower ENDTRACE 82936381Ssklower return error; 83036381Ssklower } 83136381Ssklower 83236381Ssklower /* 83336381Ssklower * NAME: cons_find() 83436381Ssklower * CALLED FROM: 83536381Ssklower * cosns_output1() thus: 83636381Ssklower * cons_find( CONSF_DGM, dst, proto, 0, 0) where 83736381Ssklower * proto is one of { TP_proto, CLNP_proto } 83836381Ssklower * FUNCTION and ARGUMENTS: 83936381Ssklower * Looks through list of connections for the destination, 84036381Ssklower * for one marked for the use indicated by flags. 84136381Ssklower * If none found, opens up a new connection. 84236381Ssklower * These connections will be eliminated by : 84336381Ssklower * a) slowtimo timer, or 84436381Ssklower * b) the need for a new connection, when we've run out of resources. 84536381Ssklower * The argument flags describes the type of pcb we want - may 84636381Ssklower * specify multiplexing-ok, datagram use, etc. 84736381Ssklower * The argument proto points the the higher layer protocol that 84836381Ssklower * will be using this connection. 84936381Ssklower * RETURN VALUE: 85036381Ssklower * returns a ptr to a pcb whose characteristics match those 85136381Ssklower * described by (flags, proto) 85236381Ssklower */ 85336381Ssklower 85436381Ssklower Static struct cons_pcb * 85536381Ssklower cons_find(flags, dst, proto, addl_criteria, mask) 85636381Ssklower u_int flags, mask; 85736381Ssklower struct sockaddr_iso *dst; 85836381Ssklower struct protosw *proto; 85936381Ssklower int (*addl_criteria)(); 86036381Ssklower { 86136381Ssklower register struct cons_pcb *copcb; 86236381Ssklower register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist; 86336381Ssklower int s = splnet(); /* or whatever, for the device! */ 86436381Ssklower struct dte_addr dest_dte; 86536381Ssklower int dummy; 86636381Ssklower 86736381Ssklower struct copcb_descriptor { 86836381Ssklower int xd_qlen; 86936381Ssklower struct cons_pcb *xd_pcb; 87036381Ssklower } next_best = { 87136381Ssklower 0, (struct cons_pcb *)0 87236381Ssklower }; 87336381Ssklower 87436381Ssklower IFDEBUG(D_CFIND) 87536381Ssklower printf("cons_find( flags 0x%x proto 0x%x) ", flags, proto); 87636381Ssklower ENDDEBUG 87736381Ssklower 87836381Ssklower if ( iso_8208snparesolve(dst, &dest_dte, &dummy)) { 87936381Ssklower ASSERT(0); 88036381Ssklower return (struct cons_pcb *)0; /* error */ 88136381Ssklower } 88236381Ssklower ASSERT(dummy == sizeof(struct dte_addr)); 88336381Ssklower 88436381Ssklower for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) { 88536381Ssklower copcb = (struct cons_pcb *)copcb->co_next; 88636381Ssklower while (copcb != *copcblist) { 88736381Ssklower IFDEBUG(D_CFIND) 88836381Ssklower printf( 88936381Ssklower "cons_find: chan 0x%x flags 0x%x proto 0x%x state 0x%x \n", 89036381Ssklower copcb->co_channel, copcb->co_flags, copcb->co_proto, 89136381Ssklower copcb->co_state); 89236381Ssklower ENDDEBUG 89336381Ssklower /* 89436381Ssklower * if flags is a subset of the bits in co_flags, it will suffice 89536381Ssklower */ 89636381Ssklower if( ((copcb->co_flags & flags) == flags ) && 89736381Ssklower /* PHASE2: where do we get the mask if we use nsaps ???? 89836381Ssklower * If dte addresses are used, then use 89936381Ssklower * nibble compare otherwise...??? 90036381Ssklower */ 90136381Ssklower #ifdef notdef 90236381Ssklower iso_addrmatch1(&(copcb->co_faddr.siso_addr), &(dst->siso_addr)) 90336381Ssklower #else 90436381Ssklower dest_dte.dtea_niblen == copcb->co_peer_dte.dtea_niblen && 90536381Ssklower nibble_match( (char *)&(copcb->co_peer_dte.dtea_addr), 90636381Ssklower HIGH_NIBBLE, (char *)dest_dte.dtea_addr, 90736381Ssklower HIGH_NIBBLE, dest_dte.dtea_niblen) 90836381Ssklower #endif notdef 90936381Ssklower && 91036381Ssklower (copcb->co_proto == proto) && 91136381Ssklower (copcb->co_state >= MIN_USABLE_STATE)) { 91236381Ssklower IFDEBUG(D_CFIND) 91336381Ssklower printf( 91436381Ssklower "cons_find: add'l criteria...\n" ); 91536381Ssklower ENDDEBUG 91636381Ssklower if((copcb->co_state != OPEN) && 91736381Ssklower (next_best.xd_qlen > copcb->co_pending.ifq_len)) { 91836381Ssklower next_best.xd_pcb = copcb; 91936381Ssklower next_best.xd_qlen = copcb->co_pending.ifq_len; 92036381Ssklower } 92136381Ssklower if( !addl_criteria || (*addl_criteria)(copcb, mask) ) { 92236381Ssklower goto found; /* have to break out of 2 loops */ 92336381Ssklower } 92436381Ssklower } 92536381Ssklower copcb = (struct cons_pcb *)copcb->co_next ; 92636381Ssklower } 92736381Ssklower } 92836381Ssklower #ifdef notdef 92936381Ssklower /* TODO: 93036381Ssklower * have a limit of the number of calls per desitination. 93136381Ssklower * If we didn't find one already open AND our limit for this 93236381Ssklower * destination hasn't been reached, return 0 'cause 93336381Ssklower * then the caller will open a new one. 93436381Ssklower * Otherwise return next_best. 93536381Ssklower * To do this we need some sort of per-destination info. 93636381Ssklower * Could go into the directory service. Oh, grotesque. 93736381Ssklower */ 93836381Ssklower #endif notdef 93936381Ssklower if( copcb == (struct cons_pcb *)0 ) { 94036381Ssklower copcb = next_best.xd_pcb; /* may be zero too */ 94136381Ssklower IFDEBUG(D_CFIND) 94236381Ssklower printf("NEXT_BEST! \n"); 94336381Ssklower dump_copcb(copcb, "find: next_best"); 94436381Ssklower ENDDEBUG 94536381Ssklower } 94636381Ssklower found: 94736381Ssklower 94836381Ssklower splx(s); 94936381Ssklower 95036381Ssklower IFDEBUG(D_CFIND) 95136381Ssklower printf("returns 0x%x \n", copcb); 95236381Ssklower ENDDEBUG 95336381Ssklower return copcb; 95436381Ssklower } 95536381Ssklower 95636381Ssklower 95736381Ssklower /* 95836381Ssklower * NAME: issue_clear_req() 95936381Ssklower * CALLED FROM: 96036381Ssklower * cons_clear() and wherever we get an error from x.25 that makes us 96136381Ssklower * want to close the vc on which it came, but don't have 96236381Ssklower * a copcb assoc. with that vc. 96336381Ssklower * FUNCTION and ARGUMENTS: 96436381Ssklower * Creates an eicon_request for a clear request, returns it in an mbuf. 96536381Ssklower * (chan) is the channel on which to do the clear, (reason) is the 96636381Ssklower * clear reason(diagnostic). 96736381Ssklower * RETURN VALUE: 96836381Ssklower * returns E* 96936381Ssklower */ 97036381Ssklower Static int 97136381Ssklower issue_clear_req(chan, reason, ifp, loop) 97236381Ssklower u_char chan, reason; 97336381Ssklower struct ifnet *ifp; 97436381Ssklower int loop; 97536381Ssklower { 97636381Ssklower register struct mbuf *m; 97736381Ssklower register struct mbuf *cdm; 97836381Ssklower register struct eicon_request *ecnrq; 97936381Ssklower struct e_clear_data *ecd; 98036381Ssklower 98136381Ssklower IFDEBUG(D_CCONN) 98236381Ssklower printf("issue_clear_req(0x%x, 0x%x, 0x%x, 0x%x)\n", 98336381Ssklower chan, reason, ifp, loop); 98436381Ssklower ENDDEBUG 98536381Ssklower m = m_getclr(M_DONTWAIT, MT_XCLOSE); 98636381Ssklower if( !m ) { 98736381Ssklower return ENOBUFS; 98836381Ssklower } 98936381Ssklower m->m_len = sizeof(struct eicon_request); 99036381Ssklower ecnrq = mtod(m, struct eicon_request *); 99136381Ssklower ecnrq->e_cmd = ECN_CLEAR; 99236381Ssklower ecnrq->e_vc = chan & 0xff; 99336381Ssklower /* 99436381Ssklower * see p. 149 of 8208 for reasons (diagnostic codes) 99536381Ssklower */ 99636381Ssklower MGET(cdm, M_DONTWAIT, MT_XCLOSE); 99736381Ssklower if( !cdm ) { 99836381Ssklower m_freem(m); 99936381Ssklower return ENOBUFS; 100036381Ssklower } 100136381Ssklower cdm->m_len = sizeof(struct e_clear_data); /* cause, diagnostic */ 100236381Ssklower e_data(ecnrq) = cdm; 100336381Ssklower 100436381Ssklower ecd = mtod(cdm, struct e_clear_data *); 100536381Ssklower ecd->ecd_cause = 0x0; /* DTE initiated, diagnostic tells more */ 100636381Ssklower ecd->ecd_diagnostic = (u_char)reason; 100736381Ssklower 100836381Ssklower IncStat(co_clear_out); 100936381Ssklower return choose_output(ifp, m, loop); 101036381Ssklower } 101136381Ssklower 101236381Ssklower 101336381Ssklower /* 101436381Ssklower * NAME: cons_clear() 101536381Ssklower * CALLED FROM: 101636381Ssklower * cons_usrreq(), PRU_DISCONNECT, 101736381Ssklower * cons_slowtimo(), cons_free_lru() 101836381Ssklower * FUNCTION and ARGUMENTS: 101936381Ssklower * Builds a clear request for the connection represented by copcb, 102036381Ssklower * gives it to the device. 102136381Ssklower * ECN_CLEAR(request) takes e_vc only, returns adr_status. 102236381Ssklower * RETURN VALUE: 102336381Ssklower */ 102436381Ssklower 102536381Ssklower Static int 102636381Ssklower cons_clear( copcb, reason) 102736381Ssklower register struct cons_pcb *copcb; 102836381Ssklower u_char reason; 102936381Ssklower { 103036381Ssklower register struct mbuf *m; 103136381Ssklower int error; 103236381Ssklower 103336381Ssklower IFDEBUG(D_CCONN) 103436381Ssklower printf("cons_clear(0x%x, 0x%x)\n", copcb, reason); 103536381Ssklower ENDDEBUG 103636381Ssklower if( !copcb) { 103736381Ssklower printf("cons PANIC: clear: No copcb\n"); 103836381Ssklower return 0; 103936381Ssklower } 104036381Ssklower while( copcb->co_pending.ifq_len > 0 ) { 104136381Ssklower register int s = splimp(); 104236381Ssklower 104336381Ssklower IF_DEQUEUE( &copcb->co_pending, m ); 104436381Ssklower splx(s); 104536381Ssklower m_freem(m); 104636381Ssklower } 104736381Ssklower if( (copcb->co_state == CLOSED) || (copcb->co_state == CLOSING) ) 104836381Ssklower return 0; 104936381Ssklower 105036381Ssklower #ifdef ARGO_DEBUG 105136381Ssklower if( copcb->co_state == CONNECTING) { 105236381Ssklower IFDEBUG(D_CCONN) 105336381Ssklower dump_copcb(copcb, "clear"); 105436381Ssklower ENDDEBUG 105536381Ssklower } else if( (copcb->co_channel == 0) || (copcb->co_channel == X_NOCHANNEL) ) { 105636381Ssklower IFDEBUG(D_CCONN) 105736381Ssklower dump_copcb(copcb, "clear"); 105836381Ssklower ENDDEBUG 105936381Ssklower } 106036381Ssklower #endif ARGO_DEBUG 106136381Ssklower 106236381Ssklower copcb->co_state = CLOSING; 106336381Ssklower 106436381Ssklower IFDEBUG(D_CCONN) 106536381Ssklower printf("cons_clear: channel 0x%x copcb 0x%x dst: ", 106636381Ssklower copcb->co_channel, copcb); 106736381Ssklower dump_isoaddr(&copcb->co_faddr); 106836381Ssklower dump_copcb(copcb, "clear"); 106936381Ssklower ENDDEBUG 107036381Ssklower 107136381Ssklower error = issue_clear_req(copcb->co_channel, reason, copcb->co_ifp, 107236381Ssklower copcb->co_flags & CONSF_LOOPBACK); 107336381Ssklower copcb->co_channel = X_NOCHANNEL; 107436381Ssklower copcb->co_state = CLOSED; 107536381Ssklower return error; 107636381Ssklower } 107736381Ssklower 107836381Ssklower 107936381Ssklower /* 108036381Ssklower * NAME: cons_senddata() 108136381Ssklower * CALLED FROM: 108236381Ssklower * cons_output(), consoutput(), consintr() 108336381Ssklower * FUNCTION and ARGUMENTS: 108436381Ssklower * issued a data (write) command - if the device isn't ready, 108536381Ssklower * it enqueues the command on a per-connection queue. 108636381Ssklower * RETURN VALUE: 108736381Ssklower * ENOBUFS 108836381Ssklower * Is responsible for freeing m0! 108936381Ssklower * 109036381Ssklower * ECN_SEND (write) 109136381Ssklower */ 109236381Ssklower 109336381Ssklower Static int 109436381Ssklower cons_senddata(copcb, m0) 109536381Ssklower register struct cons_pcb *copcb; 109636381Ssklower struct mbuf *m0; 109736381Ssklower { 109836381Ssklower register struct mbuf *m; 109936381Ssklower register struct eicon_request *ecnrq; 110036381Ssklower int s; 110136381Ssklower 110236381Ssklower IFDEBUG(D_CDATA) 110336381Ssklower printf("cons_senddata( 0x%x, m 0x%x ) chan 0x%x", 110436381Ssklower copcb, m0, copcb->co_channel ); 110536381Ssklower printf(" co_lport 0x%x\n", copcb->co_lport); 110636381Ssklower ENDDEBUG 110736381Ssklower if( m0 == MNULL ) 110836381Ssklower return; 110936381Ssklower ASSERT( m0->m_len > 0); 111036381Ssklower if( m0->m_len <= 0) { 111136381Ssklower printf("cons_senddata : BAD MLEN? 0x%x", m0->m_len); 111236381Ssklower } 111336381Ssklower 111436381Ssklower touch(copcb); 111536381Ssklower 111636381Ssklower if( (copcb->co_state == CONNECTING) || (copcb->co_state == ACKWAIT) ) { 111736381Ssklower IFDEBUG(D_CDATA) 111836381Ssklower printf("senddata PUTTING ON PENDING Q copcb 0x%x state 0x%x\n", 111936381Ssklower copcb, copcb->co_state); 112036381Ssklower ENDDEBUG 112136381Ssklower s = splimp(); 112236381Ssklower if (IF_QFULL(&copcb->co_pending)) { 112336381Ssklower IFDEBUG(D_CDATA) 112436381Ssklower printf("senddata DROPPING m0 0x%x\n", m0); 112536381Ssklower ENDDEBUG 112636381Ssklower IF_DROP(&copcb->co_pending); 112736381Ssklower if(copcb->co_ifp) { 112836381Ssklower copcb->co_ifp->if_snd.ifq_drops ++; 112936381Ssklower } 113036381Ssklower IncStat(co_Xdrops); 113136381Ssklower copcb->co_ifp->if_oerrors ++; 113236381Ssklower splx(s); 113336381Ssklower m_freem (m0); 113436381Ssklower 113536381Ssklower if( copcb->co_proto && copcb->co_proto->pr_ctlinput ) { 113636381Ssklower (*copcb->co_proto->pr_ctlinput)(PRC_QUENCH, 113736381Ssklower (struct sockaddr_iso *)&copcb->co_faddr, 113836381Ssklower (caddr_t)copcb); 113936381Ssklower 114036381Ssklower return 0; 114136381Ssklower } else 114236381Ssklower return E_CO_QFULL; 114336381Ssklower } 114436381Ssklower IFDEBUG(D_CDATA) 114536381Ssklower printf("Putting 0x%x on 0x%x->pending Q\n", m0, copcb); 114636381Ssklower ENDDEBUG 114736381Ssklower IF_ENQUEUE( &copcb->co_pending, m0 ); 114836381Ssklower splx(s); 114936381Ssklower return 0; 115036381Ssklower } 115136381Ssklower if(copcb->co_channel == 0 ) { 115236381Ssklower return E_CO_CHAN; 115336381Ssklower } 115436381Ssklower ASSERT( copcb->co_state == OPEN); 115536381Ssklower 115636381Ssklower m = m_getclr(M_DONTWAIT, MT_XDATA); 115736381Ssklower if( !m ) { 115836381Ssklower copcb->co_ifp->if_oerrors ++; 115936381Ssklower m_freem (m0); 116036381Ssklower return ENOBUFS; 116136381Ssklower } 116236381Ssklower m->m_len = sizeof(struct eicon_request); 116336381Ssklower ecnrq = mtod(m, struct eicon_request *); 116436381Ssklower ecnrq->e_pcb = (caddr_t)copcb; 116536381Ssklower if( copcb->co_myself != copcb ) { 116636381Ssklower struct mbuf *mm; 116736381Ssklower /* TODO: REMOVE THIS DEBUGGING HACK */ 116836381Ssklower ASSERT(0); 116936381Ssklower printf("BAD e_pcb from HL (0x%x,0x%x)\n", copcb, copcb->co_myself); 117036381Ssklower mm = dtom( copcb ); 117136381Ssklower if(mm->m_type == MT_FREE) 117236381Ssklower printf("FREED MBUF!\n"); 117336381Ssklower return ENETDOWN; 117436381Ssklower } 117536381Ssklower ASSERT( copcb->co_channel != 0); 117636381Ssklower ASSERT( copcb->co_channel != X_NOCHANNEL); 117736381Ssklower ecnrq->e_vc = (copcb->co_channel & 0xff); 117836381Ssklower ecnrq->e_cmd = ECN_SEND; 117936381Ssklower e_data(ecnrq) = m0; 118036381Ssklower { 118136381Ssklower /* TODO: REMOVE THIS DEBUGGING HACK */ 118236381Ssklower struct mbuf *thedata = e_data(ecnrq); 118336381Ssklower u_int *firstint = mtod( thedata, u_int *); 118436381Ssklower 118536381Ssklower if( (*firstint & 0xff000000) != 0x81000000 ) { 118636381Ssklower /* not clnp */ 118736381Ssklower switch( ((*firstint) & 0x00ff0000) >> 20 ) { 118836381Ssklower case 0x1: 118936381Ssklower case 0x2: 119036381Ssklower case 0x3: 119136381Ssklower case 0x6: 119236381Ssklower case 0x7: 119336381Ssklower case 0x8: 119436381Ssklower case 0xc: 119536381Ssklower case 0xd: 119636381Ssklower case 0xe: 119736381Ssklower case 0xf: 119836381Ssklower break; 119936381Ssklower default: 120036381Ssklower printf(" ECN_SEND! BAD DATA\n" ); 120136381Ssklower dump_buf( thedata, 20 + 12 ); 120236381Ssklower m_freem( m0 ); 120336381Ssklower return ENETDOWN; 120436381Ssklower } 120536381Ssklower } 120636381Ssklower } 120736381Ssklower 120836381Ssklower ecnrq->e_info = 0; 120936381Ssklower 121036381Ssklower IFDEBUG(D_CDUMP_REQ) 121136381Ssklower printf("senddata ecnrq\n"); 121236381Ssklower ENDDEBUG 121336381Ssklower IncStat(co_send); 121436381Ssklower 121536381Ssklower ASSERT( copcb->co_state == OPEN ); 121636381Ssklower copcb->co_state = ACKWAIT; 121736381Ssklower 121836381Ssklower if( copcb->co_myself != copcb ) { 121936381Ssklower struct mbuf *mm; 122036381Ssklower /* TODO: REMOVE this and all mention of co_myself */ 122136381Ssklower ASSERT(0); 122236381Ssklower printf("BAD e_pcb TO THE BOARD ecn (0x%x) cmd 0x%x\n", 122336381Ssklower ecnrq->e_pcb, ecnrq->e_cmd); 122436381Ssklower mm = dtom( copcb ); 122536381Ssklower if(mm->m_type == MT_FREE) 122636381Ssklower printf("FREED MBUF!\n"); 122736381Ssklower dump_buf (ecnrq, sizeof (*ecnrq)); 122836381Ssklower return ENETDOWN; 122936381Ssklower } 123036381Ssklower 123136381Ssklower return 123236381Ssklower choose_output(copcb->co_ifp, dtom(ecnrq), copcb->co_flags&CONSF_LOOPBACK); 123336381Ssklower } 123436381Ssklower 123536381Ssklower /* 123636381Ssklower * NAME: cons_send_on_vc() 123736381Ssklower * CALLED FROM: 123836381Ssklower * tp_error_emit() 123936381Ssklower * FUNCTION and ARGUMENTS: 124036381Ssklower * Take a packet(m0), of length (datalen) from tp and 124136381Ssklower * send it on the channel (chan). 124236381Ssklower * 124336381Ssklower * RETURN VALUE: 124436381Ssklower * whatever (E*) is returned form the net layer output routine. 124536381Ssklower */ 124636381Ssklower int 124736381Ssklower cons_send_on_vc(chan, m, datalen) 124836381Ssklower int chan; 124936381Ssklower struct mbuf *m; 125036381Ssklower int datalen; 125136381Ssklower { 125236381Ssklower struct cons_pcb *copcb = (struct cons_pcb *)0; 125336381Ssklower 125436381Ssklower if(m == MNULL) 125536381Ssklower return; 125636381Ssklower 125736381Ssklower if((copcb = 125836381Ssklower #ifdef ARGO_DEBUG 125936381Ssklower cons_chan_to_pcb( chan, __LINE__ ) 126036381Ssklower #else ARGO_DEBUG 126136381Ssklower cons_chan_to_pcb( chan ) 126236381Ssklower #endif ARGO_DEBUG 126336381Ssklower ) == (struct cons_pcb *)0 ) 126436381Ssklower return E_CO_CHAN; 126536381Ssklower IFDEBUG(D_CCONS) 126636381Ssklower printf("cons_send_on_vc m 0x%x m_len 0x%x\n", m, m->m_len); 126736381Ssklower ENDDEBUG 126836381Ssklower return cons_senddata( copcb, m); 126936381Ssklower } 127036381Ssklower 127136381Ssklower /* 127236381Ssklower * NAME: cons_output() 127336381Ssklower * CALLED FROM: 127436381Ssklower * tpiso_output(), can have whatever interface we want it to... 127536381Ssklower * tpiso_output() decides whether to give a packet to CLNP or to 127636381Ssklower * cons; if the latter, it calls this routine. 127736381Ssklower * FUNCTION and ARGUMENTS: 127836381Ssklower * tp has alloc-ed a pcb - but it may not be open. 127936381Ssklower * some classes of tp may allow multiplexing, in which 128036381Ssklower * case, you may choose to send the data on ANOTHER cons connection. 128136381Ssklower * This decides which net connection to use, opens one if necessary. 128236381Ssklower * Then it sends the data. 128336381Ssklower */ 128436381Ssklower 128536381Ssklower cons_output(isop, m, len, isdgm) 128636381Ssklower struct isopcb *isop; 128736381Ssklower struct mbuf *m; 128836381Ssklower int len; 128936381Ssklower int isdgm; 129036381Ssklower { 129136381Ssklower struct cons_pcb *copcb = (struct cons_pcb *)0; 129236381Ssklower int error; 129336381Ssklower int s = splnet(); 129436381Ssklower 129536381Ssklower IFDEBUG(D_CCONS) 129636381Ssklower printf("cons_output( isop 0x%x, m 0x%x, len 0x%x, dgm 0x%x )\n", 129736381Ssklower isop,m,len, isdgm); 129836381Ssklower ENDDEBUG 129936381Ssklower 130036381Ssklower if( m == MNULL ) 130136381Ssklower return 0; 130236381Ssklower ASSERT(m->m_len > 0); 130336381Ssklower if( isdgm ) { 130436381Ssklower error = cosns_output1(0, m, &isop->isop_faddr, TP_proto, isop); 130536381Ssklower IFDEBUG(D_CDATA) 130636381Ssklower if(error) 130736381Ssklower printf("cosns_output1 RETURNS ERROR 0x%x\n", error); 130836381Ssklower ENDDEBUG 130936381Ssklower return error; 131036381Ssklower } 131136381Ssklower 131236381Ssklower if( isop->isop_chanmask || isop->isop_negchanmask) { 131336381Ssklower register int mask = isop->isop_chanmask; 131436381Ssklower register int chan = 1; 131536381Ssklower 131636381Ssklower if( mask == 0) 131736381Ssklower mask = isop->isop_negchanmask; 131836381Ssklower 131936381Ssklower for ( chan=1; (mask & 1)==0; chan++,mask>>=1 ) ; 132036381Ssklower 132136381Ssklower if( isop->isop_chanmask == 0 ) 132236381Ssklower chan = -chan; 132336381Ssklower 132436381Ssklower IFDEBUG(D_CCONS) 132536381Ssklower printf( 132636381Ssklower "cons_output: isop 0x%x cmask 0x%x negmask 0x%x, chan 0x%x\n", 132736381Ssklower isop, isop->isop_chanmask, isop->isop_negchanmask, chan); 132836381Ssklower ENDDEBUG 132936381Ssklower ASSERT( chan != 0); 133036381Ssklower #ifdef ARGO_DEBUG 133136381Ssklower copcb = cons_chan_to_pcb( chan, __LINE__ ); 133236381Ssklower #else ARGO_DEBUG 133336381Ssklower copcb = cons_chan_to_pcb( chan ); 133436381Ssklower #endif ARGO_DEBUG 133536381Ssklower } 133636381Ssklower if( copcb == (struct cons_pcb *)0 ) { 133736381Ssklower /* get a new one */ 133836381Ssklower 133936381Ssklower if(( error = cons_pcballoc(&dummysocket, &cons_isopcb, CONSF_OCRE, 134036381Ssklower TP_proto, &copcb)) != EOK ) { 134136381Ssklower IFDEBUG(D_CCONS) 134236381Ssklower printf("cosns_output: no copcb; returns 0x%x\n", error); 134336381Ssklower ENDDEBUG 134436381Ssklower (void) m_freem (m); 134536381Ssklower splx(s); 134636381Ssklower return error ; 134736381Ssklower } 134836381Ssklower 134936381Ssklower /* abbreviated form of iso_pcbconnect(): */ 135036381Ssklower bcopy((caddr_t)&isop->isop_faddr, (caddr_t)&copcb->co_faddr, 135136381Ssklower sizeof(struct sockaddr_iso)); 135236381Ssklower 135336381Ssklower if ( error = cons_connect( copcb ) ) { /* if it doesn't work */ 135436381Ssklower /* oh, dear, throw packet away */ 135536381Ssklower remque((struct isopcb *)copcb); 135636381Ssklower (void) m_free(dtom(copcb)); 135736381Ssklower (void) m_freem( m ); 135836381Ssklower splx(s); 135936381Ssklower return error; 136036381Ssklower } 136136381Ssklower 136236381Ssklower if( copcb->co_socket ) { 136336381Ssklower while( (copcb->co_state != OPEN) && 136436381Ssklower !(error = copcb->co_socket->so_error) ) { 136536381Ssklower IFDEBUG(D_CCONS) 136636381Ssklower printf( 136736381Ssklower "SLEEP1 copcb 0x%x isop 0x%x state 0x%x chan 0x%x mask 0x%x neg 0x%x\n", 136836381Ssklower copcb, isop, copcb->co_state, copcb->co_channel, 136936381Ssklower ((struct isopcb *)isop)->isop_chanmask, 137036381Ssklower ((struct isopcb *)isop)->isop_negchanmask 137136381Ssklower ); 137236381Ssklower ENDDEBUG 1373*40783Smarc tsleep( (caddr_t)&copcb->co_state, PZERO+1, 1374*40783Smarc SLP_ISO_CONSOUT, 0); 137536381Ssklower IFDEBUG(D_CCONS) 137636381Ssklower printf("AFTER SLEEP 1 chan 0x%x chanmask 0x%x negchanmask 0x%x\n", 137736381Ssklower copcb->co_channel, isop->isop_chanmask, 137836381Ssklower isop->isop_negchanmask); 137936381Ssklower ENDDEBUG 138036381Ssklower } 138136381Ssklower if( !error ) 138236381Ssklower SET_CHANMASK( isop, copcb->co_channel); 138336381Ssklower } 138436381Ssklower 138536381Ssklower } 138636381Ssklower 138736381Ssklower IFDEBUG(D_CDATA) 138836381Ssklower printf("cons_output calling senddata(0x%x 0x%x)\n", copcb, m); 138936381Ssklower ASSERT(m != MNULL); 139036381Ssklower ASSERT(m->m_len != 0); 139136381Ssklower ENDDEBUG 139236381Ssklower 139336381Ssklower if( !error ) 139436381Ssklower error = cons_senddata( copcb, m); 139536381Ssklower splx(s); 139636381Ssklower return error; 139736381Ssklower } 139836381Ssklower 139936381Ssklower /* 140036381Ssklower * NAME: cons_openvc() 140136381Ssklower * CALLED FROM: 140236381Ssklower * TP when it decides to open a VC for TP 0 140336381Ssklower * FUNCTION: 140436381Ssklower * opens a connection and stashes the pcb info in the socket 140536381Ssklower * substitute for iso_pcbconnect/ in_pcbconnect for the class 0 case 140636381Ssklower * only. 140736381Ssklower */ 140836381Ssklower int 140936381Ssklower cons_openvc(copcb, faddr, so) 141036381Ssklower struct cons_pcb *copcb; 141136381Ssklower struct sockaddr_iso *faddr; 141236381Ssklower struct socket *so; 141336381Ssklower { 141436381Ssklower int error = 0; 141536381Ssklower int s = splnet(); 141636381Ssklower struct cons_pcb *cons_chan_to_pcb(); 141736381Ssklower 141836381Ssklower 141936381Ssklower ASSERT( copcb->co_socket == so ); 142036381Ssklower IFTRACE(D_CCONN) 142136381Ssklower tptrace(TPPTmisc, "cons_openvc( copcb so )\n", copcb, so, 0, 0); 142236381Ssklower ENDTRACE 142336381Ssklower IFDEBUG(D_CCONN) 142436381Ssklower printf("cons_openvc( copcb 0x%x, so 0x%x )\n", copcb,so); 142536381Ssklower ENDDEBUG 142636381Ssklower /* 142736381Ssklower * initialize the copcb part of the isopcb 142836381Ssklower */ 142936381Ssklower copcb->co_ttl = copcb->co_init_ttl = X25_TTL; 143036381Ssklower copcb->co_flags = CONSF_OCRE; 143136381Ssklower copcb->co_proto = TP_proto; 143236381Ssklower copcb->co_pending.ifq_maxlen = CONS_IFQMAXLEN; 143336381Ssklower 143436381Ssklower /* abbreviated form of iso_pcbconnect(): */ 143536381Ssklower bcopy((caddr_t)faddr, (caddr_t)&copcb->co_faddr, 143636381Ssklower sizeof(struct sockaddr_iso)); 143736381Ssklower 143836381Ssklower ASSERT( copcb->co_socket == so ); 143936381Ssklower if( error = cons_connect( copcb ) ) 144036381Ssklower goto done; 144136381Ssklower while( (copcb->co_state != OPEN) && !(error = so->so_error) ) { 144236381Ssklower IFDEBUG(D_CCONS) 144336381Ssklower printf( 144436381Ssklower "SLEEP2 copcb 0x%x state 0x%x chan 0x%x mask 0x%x neg 0x%x\n", 144536381Ssklower copcb, copcb->co_state, copcb->co_channel, 144636381Ssklower copcb->co_chanmask, 144736381Ssklower copcb->co_negchanmask 144836381Ssklower ); 144936381Ssklower ENDDEBUG 1450*40783Smarc tsleep((caddr_t)&copcb->co_state, PZERO+2, SLP_ISO_CONSCONN, 0); 145136381Ssklower IFDEBUG(D_CCONS) 145236381Ssklower printf("AFTER SLEEP2 chan 0x%x chanmask 0x%x negchanmask 0x%x\n", 145336381Ssklower copcb->co_channel, copcb->co_chanmask, 145436381Ssklower copcb->co_negchanmask); 145536381Ssklower ENDDEBUG 145636381Ssklower } 145736381Ssklower if( !error ) 145836381Ssklower SET_CHANMASK( (struct isopcb *)copcb, copcb->co_channel); 145936381Ssklower done: 146036381Ssklower ASSERT( copcb->co_socket == so ); 146136381Ssklower splx(s); 146236381Ssklower 146336381Ssklower IFDEBUG(D_CCONN) 146436381Ssklower printf("cons_openvc: copcb 0x%x error 0x%x\n", copcb, error ); 146536381Ssklower ENDDEBUG 146636381Ssklower return error; 146736381Ssklower } 146836381Ssklower 146936381Ssklower /* 147036381Ssklower * NAME: cons_netcmd() 147136381Ssklower * CALLED FROM: 147236381Ssklower * tp_route_to() when it decides to accept or reject an incoming 147336381Ssklower * connection it calls this. 147436381Ssklower * FUNCTION: 147536381Ssklower * either closes the cons connection named by (channel) 147636381Ssklower * or associates the copcb with the channel #. 147736381Ssklower * and removes the old copcb from the tp_incoming_pending list. 147836381Ssklower */ 147936381Ssklower int 148036381Ssklower cons_netcmd(cmd, isop, channel, isdgm) 148136381Ssklower int cmd; 148236381Ssklower struct isopcb *isop; 148336381Ssklower int channel; 148436381Ssklower { 148536381Ssklower int s = splnet(); 148636381Ssklower int error = 0; 148736381Ssklower struct cons_pcb *copcb = (struct cons_pcb *)0; 148836381Ssklower struct cons_pcb *cons_chan_to_pcb(); 148936381Ssklower 149036381Ssklower IFTRACE(D_CCONN) 149136381Ssklower tptrace(TPPTmisc, "cons_netcmd( cmd isopcb channel isdgm)\n", 149236381Ssklower cmd,isop,channel, isdgm); 149336381Ssklower ENDTRACE 149436381Ssklower IFDEBUG(D_CCONN) 149536381Ssklower printf("cons_netcmd( cmd 0x%x, isop 0x%x, channel 0x%x, isdgm 0x%x)\n", 149636381Ssklower cmd,isop,channel, isdgm); 149736381Ssklower if( isop ) 149836381Ssklower printf("cons_netcmd: isop->socket 0x%x\n", 149936381Ssklower isop->isop_socket); 150036381Ssklower ENDDEBUG 150136381Ssklower ASSERT(cmd != CONN_OPEN); 150236381Ssklower 150336381Ssklower /* Can we find a cons-level pcb based on channel? */ 150436381Ssklower if(channel) { 150536381Ssklower if((copcb = 150636381Ssklower #ifdef ARGO_DEBUG 150736381Ssklower cons_chan_to_pcb( channel, __LINE__ ) 150836381Ssklower #else ARGO_DEBUG 150936381Ssklower cons_chan_to_pcb( channel) 151036381Ssklower #endif ARGO_DEBUG 151136381Ssklower ) == (struct cons_pcb *)0) { 151236381Ssklower error = ECONNABORTED; 151336381Ssklower splx(s); 151436381Ssklower return error; 151536381Ssklower } 151636381Ssklower if( copcb == (struct cons_pcb *) isop ) { 151736381Ssklower copcb = (struct cons_pcb *)0; 151836381Ssklower /* avoid operating on a pcb twice */ 151936381Ssklower } else { 152036381Ssklower /* if isop is null (close/refuse): 152136381Ssklower * this would remove from the TP list, which is NOT what we want 152236381Ssklower * so only remove if there is an isop (gag) 152336381Ssklower */ 152436381Ssklower if( isop ) { 152536381Ssklower remque((struct cons_pcb *)copcb); /* take it off pending list */ 152636381Ssklower } else { 152736381Ssklower ASSERT( (cmd == CONN_CLOSE) || (cmd == CONN_REFUSE) ); 152836381Ssklower } 152936381Ssklower } 153036381Ssklower } 153136381Ssklower /* now we have one of these cases: 153236381Ssklower * 1) isop is non-null and copcb is null 153336381Ssklower * 2) isop is non-null and copcb is non-null and they are different 153436381Ssklower * 3) isop is null and copcb is non-null 153536381Ssklower */ 153636381Ssklower ASSERT( (isop != (struct isopcb *)0) || (copcb != (struct cons_pcb *)0)); 153736381Ssklower 153836381Ssklower switch(cmd) { 153936381Ssklower 154036381Ssklower case CONN_CONFIRM: 154136381Ssklower if( isdgm ) { 154236381Ssklower /* we want two separate pcbs */ 154336381Ssklower /* if we don't have a copcb, get one */ 154436381Ssklower 154536381Ssklower if( copcb == (struct cons_pcb *)0 ) { 154636381Ssklower if(( error = cons_pcballoc(&dummysocket, &cons_isopcb, 154736381Ssklower ((struct cons_pcb *)isop)->co_flags, 154836381Ssklower TP_proto, &copcb)) != EOK ) 154936381Ssklower return error; 155036381Ssklower /* copy missing info from isop */ 155136381Ssklower copcb->co_laddr = isop->isop_laddr; 155236381Ssklower copcb->co_faddr = isop->isop_faddr; 155336381Ssklower /* don't care about tsuffices */ 155436381Ssklower ((struct cons_pcb *)isop)->co_channel = 0; 155536381Ssklower /* no longer used */ 155636381Ssklower 155736381Ssklower copcb->co_ifp = ((struct cons_pcb *)isop)->co_ifp ; 155836381Ssklower ASSERT( copcb->co_pending.ifq_len == 0 ); 155936381Ssklower 156036381Ssklower } else { 156136381Ssklower insque((struct isopcb *)copcb, 156236381Ssklower (struct isopcb *)&cons_isopcb); 156336381Ssklower } 156436381Ssklower copcb->co_state = OPEN; 156536381Ssklower copcb->co_flags |= CONSF_DGM; 156636381Ssklower copcb->co_channel = channel; 156736381Ssklower ASSERT(copcb->co_channel != 0); 156836381Ssklower 156936381Ssklower IFDEBUG(D_CCONN) 157036381Ssklower printf("cons_netcmd: put 0x%x on regular list \n", copcb); 157136381Ssklower ENDDEBUG 157236381Ssklower } else { 157336381Ssklower /* must be TP 0, since this is never called from XTS code */ 157436381Ssklower /* we want ONE pcb, namely isop. 157536381Ssklower * If this TPE were the active side, 157636381Ssklower * there ought not to be a copcb, since TP should 157736381Ssklower * know that you can't send a CR with dgm and negot down 157836381Ssklower * to non-dgm. 157936381Ssklower * If this TPE were the passive side, we want to copy from 158036381Ssklower * the copcb that was on the pending list, and delete the 158136381Ssklower * pending copcb. 158236381Ssklower */ 158336381Ssklower if( copcb ) { 158436381Ssklower IFDEBUG(D_CCONN) 158536381Ssklower printf("cons_netcmd: copied info from 0x%x to 0x%x\n", 158636381Ssklower copcb, isop); 158736381Ssklower ENDDEBUG 158836381Ssklower isop->isop_laddr = copcb->co_laddr; 158936381Ssklower isop->isop_faddr = copcb->co_faddr; 159036381Ssklower /* tsuffices, socket should be there already */ 159136381Ssklower ((struct cons_pcb *)isop)->co_flags = 159236381Ssklower copcb->co_flags & ~CONSF_DGM; 159336381Ssklower ((struct cons_pcb *)isop)->co_init_ttl = copcb->co_init_ttl; 159436381Ssklower touch(((struct cons_pcb *)isop)); 159536381Ssklower ((struct cons_pcb *)isop)->co_channel = channel; 159636381Ssklower ((struct cons_pcb *)isop)->co_ifp = copcb->co_ifp; 159736381Ssklower ((struct cons_pcb *)isop)->co_proto = copcb->co_proto; 159836381Ssklower ((struct cons_pcb *)isop)->co_myself = 159936381Ssklower (struct cons_pcb *)isop; 160036381Ssklower SET_CHANMASK( isop, ((struct cons_pcb *)isop)->co_channel ); 160136381Ssklower ASSERT( copcb->co_pending.ifq_len == 0 ); 160236381Ssklower 160336381Ssklower /* get rid of the copcb that was on the pending list */ 160436381Ssklower (void) m_free(dtom(copcb)); 160536381Ssklower } 160636381Ssklower ((struct cons_pcb *)isop)->co_state = OPEN; 160736381Ssklower } 160836381Ssklower break; 160936381Ssklower 161036381Ssklower case CONN_CLOSE: 161136381Ssklower case CONN_REFUSE: 161236381Ssklower /* if dgm then ignore; the connections will 161336381Ssklower * be re-used or will time out 161436381Ssklower */ 161536381Ssklower if( isdgm ) 161636381Ssklower break; 161736381Ssklower 161836381Ssklower /* we should never come in here with both isop and copcb 161936381Ssklower * unless is dgm, hence the following assertion: 162036381Ssklower */ 162136381Ssklower ASSERT( (copcb == (struct cons_pcb *)0) || 162236381Ssklower (isop == (struct isopcb *)0) ); 162336381Ssklower 162436381Ssklower /* close whichever pcb we have */ 162536381Ssklower if( copcb ) 162636381Ssklower error = cons_clear(copcb, (cmd == CONN_CLOSE)? 162736381Ssklower E_CO_HLI_DISCN:E_CO_HLI_REJT); 162836381Ssklower if( isop ) 162936381Ssklower error = cons_clear((struct cons_pcb *)isop, (cmd == CONN_CLOSE)? 163036381Ssklower E_CO_HLI_DISCN:E_CO_HLI_REJT); 163136381Ssklower 163236381Ssklower if(copcb && (copcb->co_socket == (struct socket *)0) ) { 163336381Ssklower ASSERT( copcb->co_flags & (CONSF_DGM | CONSF_ICRE) ); 163436381Ssklower (void) m_free(dtom(copcb)); /* detached */ 163536381Ssklower } 163636381Ssklower /* isop will always be detached by the higher layer */ 163736381Ssklower break; 163836381Ssklower default: 163936381Ssklower error = EOPNOTSUPP; 164036381Ssklower break; 164136381Ssklower } 164236381Ssklower splx(s); 164336381Ssklower 164436381Ssklower IFDEBUG(D_CCONN) 164536381Ssklower printf("cons_netcmd returns 0x%x: isop 0x%x\n", isop, error ); 164636381Ssklower ENDDEBUG 164736381Ssklower return error; 164836381Ssklower } 164936381Ssklower 165036381Ssklower 165136381Ssklower /* 165236381Ssklower * NAME: addr_proto_consistency_check() 165336381Ssklower * CALLED FROM: cons_incoming() 165436381Ssklower * FUNCTION and ARGUMENTS: 165536381Ssklower * Enforces a set of rules regarding what addresses will serve 165636381Ssklower * what protocol stack. This is a kludge forced upon us by the 165736381Ssklower * fact that there's no way to tell which NET layer you want to 165836381Ssklower * run when opening a socket. Besides, no doubt, OSI directory 165936381Ssklower * services won't advertise any kind of a protocol stack with the 166036381Ssklower * NSAPs. sigh. 166136381Ssklower * RETURNS 166236381Ssklower * EAFNOSUPPORT or EOK. 166336381Ssklower */ 166436381Ssklower Static int 166536381Ssklower addr_proto_consistency_check(proto, addr) 166636381Ssklower int proto; 166736381Ssklower struct sockaddr_iso *addr; 166836381Ssklower { 166936381Ssklower switch( proto ) { 167036381Ssklower case ISOPROTO_CLNP: 167136381Ssklower break; 167236381Ssklower 167336381Ssklower case ISOPROTO_INACT_NL: 167436381Ssklower case ISOPROTO_CLTP: 167536381Ssklower return E_CO_HLI_PROTOID; 167636381Ssklower 167736381Ssklower case ISOPROTO_TP: 167836381Ssklower case ISOPROTO_X25: 167936381Ssklower /* hl is TP or X.25 */ 168036381Ssklower if (addr->siso_addr.isoa_afi != AFI_37) 168136381Ssklower return E_CO_AIWP; 168236381Ssklower /* kludge - necessary because this is the only type of 168336381Ssklower * NSAP we build for an incoming NC 168436381Ssklower */ 168536381Ssklower break; 168636381Ssklower default: /* unsupported */ 168736381Ssklower return E_CO_HLI_PROTOID; 168836381Ssklower } 168936381Ssklower return EOK; 169036381Ssklower } 169136381Ssklower /* 169236381Ssklower * NAME: cons_incoming() 169336381Ssklower * CALLED FROM: 169436381Ssklower * consintr() for incoming OPEN 169536381Ssklower * FUNCTION and ARGUMENTS: 169636381Ssklower * Determines which higher layer gets this call, and 169736381Ssklower * thus whether to immediately accept, reject, or to let the 169836381Ssklower * higher layer determine this question. 169936381Ssklower */ 170036381Ssklower Static 170136381Ssklower cons_incoming(ifp, ecnrq) 170236381Ssklower struct ifnet *ifp; 170336381Ssklower register struct eicon_request *ecnrq; 170436381Ssklower { 170536381Ssklower struct sockaddr_iso me; 170636381Ssklower struct sockaddr_iso peer; 170736381Ssklower struct cons_pcb *copcb; 170836381Ssklower int loop = 0; 170936381Ssklower int proto =0; 171036381Ssklower int error = 0; 171136381Ssklower struct dte_addr peer_dte; 171236381Ssklower 171336381Ssklower IFDEBUG(D_INCOMING) 171436381Ssklower printf("consincoming enter: ifp 0x%x ecnrq 0x%x\n", ifp, ecnrq); 171536381Ssklower ENDDEBUG 171636381Ssklower bzero( &me, sizeof(me)); 171736381Ssklower error = parse_facil( mtod(e_data(ecnrq), caddr_t), 171836381Ssklower (e_data(ecnrq))->m_len, &me, &peer, &proto, 171936381Ssklower &peer_dte); 172036381Ssklower loop = is_me( &peer ); /* <-- THIS may be a problem : 172136381Ssklower * peer may be nonsense. 172236381Ssklower * We can only expect that WE will do it right 172336381Ssklower * and never will we get an error return from 172436381Ssklower * parse_facil on a facil that WE generated, 172536381Ssklower * so if garbage comes in, peer will be garbage, 172636381Ssklower * and loop will be false. 172736381Ssklower */ 172836381Ssklower if( error != EOK ) { 172936381Ssklower (void) issue_clear_req(ecnrq->e_vc, error, ifp, loop); 173036381Ssklower IncStat(co_parse_facil_err); 173136381Ssklower IncStat(co_Rdrops); 173236381Ssklower return; 173336381Ssklower } 173436381Ssklower 173536381Ssklower if( (error = addr_proto_consistency_check(proto, &me)) != EOK ) { 173636381Ssklower /* problem with consistency */ 173736381Ssklower (void) issue_clear_req(ecnrq->e_vc, error, ifp, loop); 173836381Ssklower IncStat(co_addr_proto_consist_err); 173936381Ssklower IncStat(co_Rdrops); 174036381Ssklower return; 174136381Ssklower } else { 174236381Ssklower switch( proto ) { 174336381Ssklower case ISOPROTO_X25: 174436381Ssklower copcb = (struct cons_pcb *) 174536381Ssklower ((struct cons_pcb *)(&cons_isopcb))->co_next; 174636381Ssklower 174736381Ssklower while (copcb != (struct cons_pcb *)&cons_isopcb) { 174836381Ssklower if( copcb->co_lport == me.siso_tsuffix ) { 174936381Ssklower /* for cons "transport service", 175036381Ssklower * multiplexing is not allowed 175136381Ssklower */ 175236381Ssklower if( !copcb->co_socket ) { 175336381Ssklower printf( 175436381Ssklower "PANIC cons_incoming NOT TP but no sock\n"); 175536381Ssklower copcb = (struct cons_pcb *)0; 175636381Ssklower break; 175736381Ssklower } 175836381Ssklower if( copcb->co_socket->so_options & SO_ACCEPTCONN ) { 175936381Ssklower struct cons_pcb *newx; 176036381Ssklower 176136381Ssklower newx = (struct cons_pcb *) 176236381Ssklower sonewconn(copcb->co_socket)->so_pcb; 176336381Ssklower newx->co_laddr = copcb->co_laddr; 176436381Ssklower newx->co_peer_dte = peer_dte; 176536381Ssklower newx->co_proto = copcb->co_proto; 176636381Ssklower newx->co_myself = newx; 176736381Ssklower touch(copcb); 176836381Ssklower copcb = newx; 176936381Ssklower soisconnected(copcb->co_socket); 177036381Ssklower break; 177136381Ssklower } /* else keep looking */ 177236381Ssklower } 177336381Ssklower copcb = (struct cons_pcb *)copcb->co_next; 177436381Ssklower } 177536381Ssklower if (copcb == (struct cons_pcb *)&cons_isopcb) 177636381Ssklower copcb = (struct cons_pcb *) 0; 177736381Ssklower break; 177836381Ssklower 177936381Ssklower case ISOPROTO_TP: 178036381Ssklower ASSERT( me.siso_tsuffix == 0 ); 178136381Ssklower /* 178236381Ssklower * We treat this rather like we do for CLNP. 178336381Ssklower * TP can't tell which socket 178436381Ssklower * wants this until the TP header comes in, so there's no way 178536381Ssklower * to associate this channel with a tpcb/isopcb. 178636381Ssklower * We assume data will arrive (a CR TPDU) and be given to TP along with 178736381Ssklower * the channel number. We can then expect TP to call us with 178836381Ssklower * the channel number and pcb ptr, telling us to keep this connection 178936381Ssklower * or clear it. 179036381Ssklower * Now, tp will have created an isopcb in the tp_isopcb list. 179136381Ssklower * We will have to keep another copcb though, because there is no 179236381Ssklower * 1-1 correspondence between socket and copcb when multiplexing 179336381Ssklower * is allowed. 179436381Ssklower * But we want to save the peer address, ifp, and state, proto. 179536381Ssklower * If the channel should clear before TP responds, we need 179636381Ssklower * to know that also, so we create a tp-pending list... 179736381Ssklower */ 179836381Ssklower if( cons_pcballoc(&dummysocket, &tp_incoming_pending, 179936381Ssklower CONSF_ICRE, TP_proto, &copcb) != EOK ) { 180036381Ssklower copcb = (struct cons_pcb *)0; 180136381Ssklower } else { 180236381Ssklower copcb->co_peer_dte = peer_dte; 180336381Ssklower } 180436381Ssklower break; 180536381Ssklower 180636381Ssklower 180736381Ssklower case ISOPROTO_CLNP: 180836381Ssklower if( cons_pcballoc(&dummysocket, &cons_isopcb, 180936381Ssklower CONSF_ICRE | CONSF_DGM, CLNP_proto, &copcb ) != EOK ) { 181036381Ssklower /* choke */ 181136381Ssklower copcb = (struct cons_pcb *)0; 181236381Ssklower } else { 181336381Ssklower copcb->co_peer_dte = peer_dte; 181436381Ssklower } 181536381Ssklower break; 181636381Ssklower 181736381Ssklower default: 181836381Ssklower panic("cons_incoming"); 181936381Ssklower } /* end switch */ 182036381Ssklower 182136381Ssklower if(copcb) { 182236381Ssklower touch(copcb); 182336381Ssklower copcb->co_channel = (int)ecnrq->e_vc; 182436381Ssklower ASSERT( copcb->co_channel != 0); 182536381Ssklower copcb->co_state = OPEN; 182636381Ssklower copcb->co_ifp = ifp; 182736381Ssklower copcb->co_laddr = me; 182836381Ssklower copcb->co_faddr = peer; 182936381Ssklower if(loop) 183036381Ssklower copcb->co_flags |= CONSF_LOOPBACK; 183136381Ssklower IFDEBUG(D_CADDR) 183236381Ssklower printf("cons_incoming found XPCB 0x%x, loop 0x%x\n", 183336381Ssklower copcb, loop); 183436381Ssklower printf("\nco_laddr: "); 183536381Ssklower dump_buf(&copcb->co_laddr, sizeof(copcb->co_laddr)); 183636381Ssklower printf("\nco_faddr: "); 183736381Ssklower dump_buf(&copcb->co_faddr, sizeof(copcb->co_faddr)); 183836381Ssklower printf("\n"); 183936381Ssklower ENDDEBUG 184036381Ssklower } else { 184136381Ssklower ifp->if_ierrors ++; 184236381Ssklower (void) issue_clear_req(ecnrq->e_vc, E_CO_OSI_UNSAP, ifp, loop); 184336381Ssklower IncStat(co_no_copcb); 184436381Ssklower IncStat(co_Rdrops); 184536381Ssklower } 184636381Ssklower } 184736381Ssklower /* caller frees the mbuf so we don't have to do any such thing */ 184836381Ssklower } 184936381Ssklower 185036381Ssklower /* 185136381Ssklower **************************** DEVICE cons *************************** 185236381Ssklower */ 185336381Ssklower 185436381Ssklower /* 185536381Ssklower * NAME: cosns_output() 185636381Ssklower * CALLED FROM: 185736381Ssklower * clnp - this routine is given as the device-output routine 185836381Ssklower * for the adcom driver. 185936381Ssklower * FUNCTION and ARGUMENTS: 186036381Ssklower * (ifp) is the cons/adcom, found by routing function. 186136381Ssklower * (m0) is the clnp datagram. 186236381Ssklower * (dst) is the destination address 186336381Ssklower * This routine finds an x.25 connection for datagram use and 186436381Ssklower * sends the packet. 186536381Ssklower */ 186636381Ssklower int 186736381Ssklower cosns_output(ifp, m0, dst) 186836381Ssklower { 186936381Ssklower return cosns_output1(ifp, m0, dst, CLNP_proto, NULL); 187036381Ssklower } 187136381Ssklower 187236381Ssklower /* DEBUGGING ONLY? */ 187336381Ssklower int total_cosns_len = 0; 187436381Ssklower int total_cosns_cnt = 0; 187536381Ssklower int total_pkts_to_clnp = 0; 187636381Ssklower 187736381Ssklower /* 187836381Ssklower * The isop is passed here so that if we have set x25crud in the 187936381Ssklower * pcb, it can be passed down to cons_connect. It could be null 188036381Ssklower * however, in the case of tp4/x25/clnp 188136381Ssklower */ 188236381Ssklower Static int 188336381Ssklower cosns_output1(ifp, m0, dst, proto, isop) 188436381Ssklower struct ifnet *ifp; 188536381Ssklower register struct mbuf *m0; 188636381Ssklower struct sockaddr_iso *dst; 188736381Ssklower struct protosw *proto; 188836381Ssklower struct isopcb *isop; /* NULL if coming from clnp */ 188936381Ssklower { 189036381Ssklower register struct cons_pcb *copcb; 189136381Ssklower int s = splnet(); 189236381Ssklower int error = 0; 189336381Ssklower 189436381Ssklower { register struct mbuf *n=m0; 189536381Ssklower register int len = 0; 189636381Ssklower 189736381Ssklower for(;;) { 189836381Ssklower len += n->m_len; 189936381Ssklower if (n->m_next == MNULL ) { 190036381Ssklower break; 190136381Ssklower } 190236381Ssklower n = n->m_next; 190336381Ssklower } 190436381Ssklower total_cosns_len += len; 190536381Ssklower total_cosns_cnt ++; 190636381Ssklower 190736381Ssklower } 190836381Ssklower 190936381Ssklower IFDEBUG(D_CCONS) 191036381Ssklower printf("cosns_output1( ifp 0x%x, m 0x%x, dst 0x%x )\n", ifp, m0, dst ); 191136381Ssklower ENDDEBUG 191236381Ssklower if ( ! (copcb = cons_find( CONSF_DGM, dst, proto, 0, 0) )) { 191336381Ssklower struct cons_pcb *newcopcb; /* so we can pass addr of this to pcballoc */ 191436381Ssklower 191536381Ssklower if( (error = cons_pcballoc(&dummysocket, &cons_isopcb, 191636381Ssklower CONSF_DGM | CONSF_OCRE, proto, &newcopcb) ) != EOK ) { 191736381Ssklower IFDEBUG(D_CCONS) 191836381Ssklower printf("cosns_output: no copcb; returns \n"); 191936381Ssklower ENDDEBUG 192036381Ssklower (void) m_freem(m0); 192136381Ssklower goto done; 192236381Ssklower } 192336381Ssklower copcb = newcopcb; 192436381Ssklower 192536381Ssklower /* abbreviated form of iso_pcbconnect(): */ 192636381Ssklower bcopy((caddr_t)dst, (caddr_t)&copcb->co_faddr, 192736381Ssklower sizeof(struct sockaddr_iso)); 192836381Ssklower 192936381Ssklower /* copy x25crud into copcb if necessary */ 193036381Ssklower if ((isop != NULL) && (isop->isop_x25crud_len > 0)) { 193136381Ssklower bcopy(isop->isop_x25crud, copcb->co_x25crud, 193236381Ssklower isop->isop_x25crud_len); 193336381Ssklower copcb->co_x25crud_len = isop->isop_x25crud_len; 193436381Ssklower } 193536381Ssklower 193636381Ssklower copcb->co_ifp = ifp; /* NULL IF COMING FROM TP4! */ 193736381Ssklower 193836381Ssklower if ( error = cons_connect( copcb ) ) { /* if it doesn't work */ 193936381Ssklower /* oh, dear, throw packet away */ 194036381Ssklower remque((struct isopcb *)copcb); 194136381Ssklower (void) m_free(dtom(copcb)); 194236381Ssklower (void) m_freem(m0); 194336381Ssklower goto done; 194436381Ssklower } 194536381Ssklower } 194636381Ssklower IFDEBUG(D_CDATA) 194736381Ssklower printf("cosns_output1 @ senddata: state 0x%x flags 0x%x channel 0x%x\n", 194836381Ssklower copcb->co_state, copcb->co_flags, copcb->co_channel); 194936381Ssklower ENDDEBUG 195036381Ssklower ASSERT(copcb->co_channel != X_NOCHANNEL); 195136381Ssklower error = cons_senddata(copcb, m0); 195236381Ssklower done: 195336381Ssklower splx(s); 195436381Ssklower return error; 195536381Ssklower } 195636381Ssklower 195736381Ssklower 195836381Ssklower /* 195936381Ssklower **************************** TRANSPORT cons *************************** 196036381Ssklower */ 196136381Ssklower 196236381Ssklower 196336381Ssklower /* 196436381Ssklower * NAME: cons_detach() 196536381Ssklower * CALLED FROM: 196636381Ssklower * cons_usrreq() on PRU_DETACH 196736381Ssklower * cons_netcmd() when TP releases a net connection 196836381Ssklower * cons_slowtimo() when timeout releases a net connection 196936381Ssklower * FUNCTION and ARGUMENT: 197036381Ssklower * removes the copcb from the list of copcbs in use, and frees the mbufs. 197136381Ssklower * detaches the pcb from the socket, where a socket exists. 197236381Ssklower * RETURN VALUE: 197336381Ssklower * ENOTCONN if it couldn't find the copcb in the list of connections. 197436381Ssklower */ 197536381Ssklower 197636381Ssklower Static int 197736381Ssklower cons_detach( copcb ) 197836381Ssklower register struct cons_pcb *copcb; 197936381Ssklower { 198036381Ssklower struct socket *so = copcb->co_socket; 198136381Ssklower 198236381Ssklower IFDEBUG(D_CCONN) 198336381Ssklower printf("cons_detach( copcb 0x%x )\n", copcb); 198436381Ssklower ENDDEBUG 198536381Ssklower if(so) { 198636381Ssklower if (so->so_head) { 198736381Ssklower if (!soqremque(so, 0) && !soqremque(so, 1)) 198836381Ssklower panic("sofree dq"); 198936381Ssklower so->so_head = 0; 199036381Ssklower } 199136381Ssklower ((struct isopcb *)copcb)->isop_options = 0; /* kludge */ 199236381Ssklower iso_pcbdetach(copcb); /* detaches from so */ 199336381Ssklower } else { 199436381Ssklower remque((struct isopcb *)copcb); 199536381Ssklower (void) m_free(dtom(copcb)); 199636381Ssklower } 199736381Ssklower } 199836381Ssklower 199936381Ssklower Static int 200036381Ssklower cons_clear_and_detach(copcb, clearreason, ctlcmd) 200136381Ssklower register struct cons_pcb *copcb; 200236381Ssklower int clearreason; 200336381Ssklower int ctlcmd; 200436381Ssklower { 200536381Ssklower IFDEBUG(D_CCONN) 200636381Ssklower printf("Clear and Detach (0x%x, 0x%x, 0x%x)\n", 200736381Ssklower copcb, clearreason, ctlcmd); 200836381Ssklower ENDDEBUG 200936381Ssklower if( clearreason != DONTCLEAR ) { 201036381Ssklower (void) cons_clear( copcb , clearreason ); 201136381Ssklower } 201236381Ssklower if( copcb->co_proto && copcb->co_proto->pr_ctlinput ) 201336381Ssklower (*copcb->co_proto->pr_ctlinput)(ctlcmd, 201436381Ssklower (struct sockaddr_iso *)&copcb->co_faddr, (caddr_t)copcb); 201536381Ssklower 201636381Ssklower if( copcb->co_socket == (struct socket *)0 ) { 201736381Ssklower /* tp4, clnp users only */ 201836381Ssklower (void) cons_detach( copcb ); 201936381Ssklower } /* else detach will be called by the socket's closing */ 202036381Ssklower else { 202136381Ssklower ASSERT( copcb->co_socket != &dummysocket ); 202236381Ssklower ASSERT( (copcb->co_flags & CONSF_DGM) == 0 ); 202336381Ssklower } 202436381Ssklower IFDEBUG(D_CCONN) 202536381Ssklower printf("END OF Clear and Detach (0x%x, 0x%x, 0x%x)\n", 202636381Ssklower copcb, clearreason, ctlcmd); 202736381Ssklower ENDDEBUG 202836381Ssklower } 202936381Ssklower 203036381Ssklower Static int 203136381Ssklower cons_pcbbind( copcb, nam ) 203236381Ssklower register struct cons_pcb *copcb; 203336381Ssklower struct mbuf *nam; 203436381Ssklower { 203536381Ssklower int error; 203636381Ssklower 203736381Ssklower if( error = iso_pcbbind( copcb, nam) ) 203836381Ssklower return error; 203936381Ssklower 204036381Ssklower /* iso_pcbbind already ensured that if port < 1024 it's superuser */ 204136381Ssklower /* Now we check: must be in range 0 .. 23 or in range 1024 .. 99 */ 204236381Ssklower 204336381Ssklower if( (copcb->co_lport < X25_PORT_RESERVED) || 204436381Ssklower ((copcb->co_lport >= ISO_PORT_RESERVED) && 204536381Ssklower (copcb->co_lport <= X25_PORT_USERMAX))) { 204636381Ssklower munge( copcb->co_lport, (&copcb->co_laddr)->siso_addr.t37_idi + 204736381Ssklower ADDR37_IDI_LEN, 1 /* nibble */); 204836381Ssklower munge( copcb->co_fport, (&copcb->co_faddr)->siso_addr.t37_idi + 204936381Ssklower ADDR37_IDI_LEN, 1 /* nibble */); 205036381Ssklower return 0; 205136381Ssklower } else 205236381Ssklower return EADDRNOTAVAIL; 205336381Ssklower } 205436381Ssklower /* 205536381Ssklower * NAME: cons_usrreq() 205636381Ssklower * CALLED FROM: 205736381Ssklower * user level via proto switch 205836381Ssklower * FUNCTION and ARGUMENTS: 205936381Ssklower * so : socket 206036381Ssklower * req: which PRU* request 206136381Ssklower * m : data or mbuf ptr into which to stash data 206236381Ssklower * nam: mbuf ptr which is really a sockaddr_iso 206336381Ssklower * ifq: in PRU_CONTROL case, an ifnet structure 206436381Ssklower * RETURN VALUE: 206536381Ssklower * ENOTCONN if trying to do something which requires a connection 206636381Ssklower * and it's not yet connected 206736381Ssklower * EISCONN if trying to do something which cannot be done to a connection 206836381Ssklower * but it's connected 206936381Ssklower * ENOBUFS if ran out of mbufs 207036381Ssklower * EWOULDBLOCK if in nonblocking mode & can't send right away 207136381Ssklower * EOPNOSUPP if req isn't supported 207236381Ssklower * E* other passed up from lower layers or from other routines 207336381Ssklower */ 207436381Ssklower 207536381Ssklower cons_usrreq(so, req, m, nam, ifp) 207636381Ssklower struct socket *so; 207736381Ssklower u_int req; 207836381Ssklower struct mbuf *m, *nam; 207936381Ssklower int *ifp; 208036381Ssklower { 208136381Ssklower struct cons_pcb *copcb = (struct cons_pcb *)so->so_pcb; 208236381Ssklower int s = splnet(); 208336381Ssklower int error = 0; 208436381Ssklower 208536381Ssklower IFDEBUG(D_CCONS) 208636381Ssklower printf("cons_usrreq 0x%x so 0x%x copcb 0x%x\n", req, so, copcb); 208736381Ssklower ENDDEBUG 208836381Ssklower if (req == PRU_CONTROL) { 208936381Ssklower error = iso_control(so, (int)m, (caddr_t)nam, (struct ifnet *)ifp); 209036381Ssklower splx(s); 209136381Ssklower return error; 209236381Ssklower } 209336381Ssklower if (copcb == (struct cons_pcb *)0 && req != PRU_ATTACH) { 209436381Ssklower splx(s); 209536381Ssklower return ENOTCONN; 209636381Ssklower } 209736381Ssklower 209836381Ssklower switch (req) { 209936381Ssklower 210036381Ssklower case PRU_ATTACH: 210136381Ssklower if (copcb) { 210236381Ssklower error = EISCONN; 210336381Ssklower break; 210436381Ssklower } 210536381Ssklower soreserve(so, X25_SBSIZE, X25_SBSIZE); /* CONS size */ 210636381Ssklower error = cons_pcballoc(so, &cons_isopcb, CONSF_XTS, X25_proto, &copcb ); 210736381Ssklower break; 210836381Ssklower 210936381Ssklower case PRU_ABORT: /* called from close() */ 211036381Ssklower /* called for each incoming connect queued on the parent (accepting) 211136381Ssklower * socket (SO_ACCEPTCONN); 211236381Ssklower */ 211336381Ssklower error = cons_detach ( copcb ); 211436381Ssklower break; 211536381Ssklower 211636381Ssklower case PRU_DETACH: /* called from close() */ 211736381Ssklower /* called after disconnect was called iff was connected at the time 211836381Ssklower * of the close, or directly if socket never got connected */ 211936381Ssklower error = cons_detach ( copcb ); 212036381Ssklower break; 212136381Ssklower 212236381Ssklower case PRU_SHUTDOWN: 212336381Ssklower /* recv end may have been released; local credit might be zero */ 212436381Ssklower case PRU_DISCONNECT: 212536381Ssklower soisdisconnected(so); 212636381Ssklower error = cons_clear(copcb, E_CO_HLI_DISCN); 212736381Ssklower break; 212836381Ssklower 212936381Ssklower case PRU_BIND: 213036381Ssklower error = cons_pcbbind( copcb, nam); 213136381Ssklower break; 213236381Ssklower 213336381Ssklower case PRU_LISTEN: 213436381Ssklower if (copcb->co_lport == 0) 213536381Ssklower error = cons_pcbbind( copcb, 0 ); 213636381Ssklower break; 213736381Ssklower 213836381Ssklower 213936381Ssklower case PRU_SOCKADDR: { 214036381Ssklower struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *); 214136381Ssklower 214236381Ssklower nam->m_len = sizeof (struct sockaddr_iso); 214336381Ssklower if(copcb->co_ifp) 214436381Ssklower bcopy( (caddr_t)&copcb->co_laddr, 214536381Ssklower (caddr_t)siso, sizeof(struct sockaddr_iso) ); 214636381Ssklower 214736381Ssklower ((struct sockaddr_iso *)siso)->siso_tsuffix = copcb->co_lport; 214836381Ssklower } 214936381Ssklower break; 215036381Ssklower 215136381Ssklower case PRU_PEERADDR: 215236381Ssklower if( (so->so_state & SS_ISCONNECTED) && 215336381Ssklower (so->so_state & SS_ISDISCONNECTING) == 0) { 215436381Ssklower struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *); 215536381Ssklower 215636381Ssklower nam->m_len = sizeof (struct sockaddr_iso); 215736381Ssklower bcopy( (caddr_t)&copcb->co_faddr, (caddr_t)siso, 215836381Ssklower sizeof(struct sockaddr_iso) ); 215936381Ssklower } else 216036381Ssklower error = ENOTCONN; 216136381Ssklower break; 216236381Ssklower 216336381Ssklower case PRU_CONNECT: 216436381Ssklower /* TODO: We need to bind to the RIGHT interface. 216536381Ssklower * The only way to have the right interface is to have 216636381Ssklower * the right route. 216736381Ssklower */ 216836381Ssklower IFDEBUG(D_CCONN) 216936381Ssklower printf("PRU_CONNECT 1: local tsuffix 0x%x so->so_head 0x%x nam:\n", 217036381Ssklower copcb->co_lport, so->so_head); 217136381Ssklower dump_isoaddr( mtod(nam, struct sockaddr_iso *) ); 217236381Ssklower ENDDEBUG 217336381Ssklower if (copcb->co_lport == 0) { 217436381Ssklower if( error = cons_pcbbind( copcb, 0 )) 217536381Ssklower break; 217636381Ssklower } 217736381Ssklower IFDEBUG(D_CCONN) 217836381Ssklower printf("PRU_CONNECT 2: local tsuffix 0x%x so->so_head 0x%x nam:\n", 217936381Ssklower copcb->co_lport, so->so_head); 218036381Ssklower dump_isoaddr( mtod(nam, struct sockaddr_iso *) ); 218136381Ssklower ENDDEBUG 218236381Ssklower 218336381Ssklower { /* change the destination address so the last 2 digits 218436381Ssklower * are the port/suffix/selector (whatever you want to call it) 218536381Ssklower */ 218636381Ssklower register struct sockaddr_iso *siso = 218736381Ssklower mtod(nam, struct sockaddr_iso *); 218836381Ssklower if( (siso->siso_tsuffix < X25_PORT_RESERVED) || 218936381Ssklower ((siso->siso_tsuffix >= ISO_PORT_RESERVED) && 219036381Ssklower (siso->siso_tsuffix <= X25_PORT_USERMAX))) 219136381Ssklower munge( siso->siso_tsuffix, 219236381Ssklower siso->siso_addr.t37_idi + ADDR37_IDI_LEN, 219336381Ssklower 1 /* nibble */); 219436381Ssklower } 219536381Ssklower 219636381Ssklower soisconnecting(so); 219736381Ssklower if (error = iso_pcbconnect(copcb, nam)) 219836381Ssklower break; 219936381Ssklower error = cons_connect( copcb ); 220036381Ssklower if ( error ) { 220136381Ssklower /* 220236381Ssklower remque((struct isopcb *)copcb); 220336381Ssklower (void) m_free(dtom(copcb)); 220436381Ssklower */ 220536381Ssklower break; 220636381Ssklower } 220736381Ssklower while( (copcb->co_state != OPEN)&&(copcb->co_socket->so_error == 0) ) { 220836381Ssklower IFDEBUG(D_CCONN) 220936381Ssklower printf("PRU_CONNECT: error 0x%x sleeping on 0x%x\n", 221036381Ssklower copcb->co_socket->so_error, 221136381Ssklower (caddr_t)&copcb->co_state ); 221236381Ssklower ENDDEBUG 2213*40783Smarc sleep((caddr_t)&copcb->co_state, PZERO+3, SLP_ISO_CONS, 0 ); 221436381Ssklower } 221536381Ssklower 221636381Ssklower ASSERT( copcb->co_channel != 0); 221736381Ssklower 221836381Ssklower SET_CHANMASK ( (struct isopcb *)copcb, copcb->co_channel); 221936381Ssklower break; 222036381Ssklower 222136381Ssklower case PRU_ACCEPT: 222236381Ssklower /* so here is the NEW socket */ 222336381Ssklower so->so_error = 0; 222436381Ssklower if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTED)== 0) { 222536381Ssklower error = EWOULDBLOCK; 222636381Ssklower break; 222736381Ssklower } 222836381Ssklower { 222936381Ssklower struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *); 223036381Ssklower 223136381Ssklower /* copy the peer's address into the return argument */ 223236381Ssklower nam->m_len = sizeof (struct sockaddr_iso); 223336381Ssklower bcopy( (caddr_t)&copcb->co_faddr, (caddr_t)siso, 223436381Ssklower sizeof(struct sockaddr_iso)); 223536381Ssklower } 223636381Ssklower break; 223736381Ssklower 223836381Ssklower case PRU_SEND: 223936381Ssklower case PRU_SENDEOT: 224036381Ssklower /* 224136381Ssklower * sosend calls this until sbspace goes negative. 224236381Ssklower * Sbspace may be made negative by appending this mbuf chain, 224336381Ssklower * possibly by a whole cluster. 224436381Ssklower */ 224536381Ssklower { 224636381Ssklower /* no need to actually queue this stuff and dequeue it, 224736381Ssklower * just bump the pointers in so_snd so that higher 224836381Ssklower * layer of socket code will cause it to sleep when 224936381Ssklower * we've run out of socket space 225036381Ssklower * TODO: 225136381Ssklower * Unfortunately that makes sbflush vomit so we have 225236381Ssklower * to allocate a single real mbuf (say size 240) 225336381Ssklower * and sballoc it and sbfree it upon CONS_SEND_DONE. 225436381Ssklower * Oh, my, is this sickening or what? 225536381Ssklower */ 225636381Ssklower { 225736381Ssklower struct mbuf *mx; 225836381Ssklower 225936381Ssklower MGET(mx, M_DONTWAIT, MT_DATA); 226036381Ssklower mx->m_len = MLEN; 226136381Ssklower sbappend((caddr_t)&copcb->co_socket->so_snd, mx); 226236381Ssklower } 226336381Ssklower if( m ) { 226436381Ssklower IFDEBUG(D_CDATA) 226536381Ssklower printf("X.25 Usrreq calling cons_senddata(0x%x, 0x%x)\n", 226636381Ssklower copcb, m); 226736381Ssklower ENDDEBUG 226836381Ssklower error = cons_senddata(copcb, m); 226936381Ssklower } 227036381Ssklower IFDEBUG(D_CCONS) 227136381Ssklower printf("PRU_SEND sent tsuffix 0x%x, m 0x%x error 0x%x\n", 227236381Ssklower copcb->co_lport, m, error); 227336381Ssklower ENDDEBUG 227436381Ssklower 227536381Ssklower if( req == PRU_SENDEOT ) { 227636381Ssklower while(copcb->co_socket->so_snd.sb_cc > 0) 227736381Ssklower sbwait(&copcb->co_socket->so_snd); 227836381Ssklower } 227936381Ssklower } 228036381Ssklower break; 228136381Ssklower 228236381Ssklower case PRU_CONTROL: 228336381Ssklower error = cons_ioctl(so, m, (caddr_t)nam); 228436381Ssklower break; 228536381Ssklower 228636381Ssklower 228736381Ssklower case PRU_RCVD: 228836381Ssklower case PRU_RCVOOB: 228936381Ssklower case PRU_SENDOOB: 229036381Ssklower /* COULD support INTERRUPT packets as oob */ 229136381Ssklower case PRU_PROTOSEND: 229236381Ssklower case PRU_PROTORCV: 229336381Ssklower case PRU_SENSE: 229436381Ssklower case PRU_SLOWTIMO: 229536381Ssklower case PRU_CONNECT2: 229636381Ssklower case PRU_FASTTIMO: 229736381Ssklower default: 229836381Ssklower error = EOPNOTSUPP; 229936381Ssklower } 230036381Ssklower 230136381Ssklower IFDEBUG(D_CCONS) 230236381Ssklower printf("cons_usrreq cmd 0x%x copcb 0x%x returned error 0x%x\n", 230336381Ssklower req, copcb, error); 230436381Ssklower ENDDEBUG 230536381Ssklower splx(s); 230636381Ssklower return error; 230736381Ssklower } 230836381Ssklower 230936381Ssklower /* 231036381Ssklower * NAME: cons_input() 231136381Ssklower * CALLED FROM: 231236381Ssklower * consintr() through the isosw protosw for "transport" version of X25 231336381Ssklower * FUNCTION & ARGUMENTS: 231436381Ssklower * process incoming data 231536381Ssklower */ 231636381Ssklower cons_input(m, faddr, laddr, so) 231736381Ssklower register struct mbuf *m; 231836381Ssklower struct sockaddr_iso *faddr, *laddr; /* not used */ 231936381Ssklower register struct socket *so; 232036381Ssklower { 232136381Ssklower IFDEBUG(D_CCONS) 232236381Ssklower printf("cons_input( m 0x%x, so 0x%x)\n", m,so); 232336381Ssklower ENDDEBUG 232436381Ssklower sbappend(&so->so_rcv, m); 232536381Ssklower sbwakeup(&so->so_rcv); 232636381Ssklower } 232736381Ssklower 232836381Ssklower #ifdef notdef 232936381Ssklower /* 233036381Ssklower * NAME: cons_ctloutput() 233136381Ssklower * CALLED FROM: 233236381Ssklower * set/get sockopts() 233336381Ssklower * Presently the protosw has 0 in the ctloutput spot 233436381Ssklower * because we haven't inplemented anything yet. 233536381Ssklower * If there's reason to put some options in here, 233636381Ssklower * be sure to stick this routine name in the protosw in iso_proto.c 233736381Ssklower */ 233836381Ssklower cons_ctloutput(cmd, so, level, optname, mp) 233936381Ssklower int cmd, level, optname; 234036381Ssklower struct socket *so; 234136381Ssklower struct mbuf **mp; 234236381Ssklower { 234336381Ssklower int s = splnet(); 234436381Ssklower 234536381Ssklower splx(s); 234636381Ssklower return EOPNOTSUPP; 234736381Ssklower } 234836381Ssklower #endif notdef 234936381Ssklower 235036381Ssklower 235136381Ssklower /* 235236381Ssklower * NAME: cons_ctlinput() 235336381Ssklower * CALLED FROM: 235436381Ssklower * lower layer when ECN_CLEAR occurs : this routine is here 235536381Ssklower * for consistency - cons subnet service calls its higher layer 235636381Ssklower * through the protosw entry. 235736381Ssklower * FUNCTION & ARGUMENTS: 235837536Smckusick * cmd is a PRC_* command, list found in ../sys/protosw.h 235936381Ssklower * copcb is the obvious. 236036381Ssklower * This serves the higher-layer cons service. 236136381Ssklower * NOTE: this takes 3rd arg. because cons uses it to inform itself 236236381Ssklower * of things (timeouts, etc) but has a pcb instead of an address. 236336381Ssklower */ 236436381Ssklower cons_ctlinput(cmd, sa, copcb) 236536381Ssklower int cmd; 236636381Ssklower struct sockaddr *sa; 236736381Ssklower register struct cons_pcb *copcb; 236836381Ssklower { 236936381Ssklower int error = 0; 237036381Ssklower int s = splnet(); 237136381Ssklower extern u_char inetctlerrmap[]; 237236381Ssklower extern int iso_rtchange(); 237336381Ssklower 237436381Ssklower IFDEBUG(D_CCONS) 237536381Ssklower printf("cons_ctlinput( cmd 0x%x, copcb 0x%x)\n", cmd, copcb); 237636381Ssklower ENDDEBUG 237736381Ssklower /* co_socket had better exist */ 237836381Ssklower switch (cmd) { 237936381Ssklower case PRC_CONS_SEND_DONE: 238036381Ssklower ASSERT( copcb->co_socket ); 238136381Ssklower ASSERT( copcb->co_flags & CONSF_XTS ); 238236381Ssklower sbdrop((caddr_t)&copcb->co_socket->so_snd, MLEN); 238336381Ssklower sbwakeup((caddr_t)&copcb->co_socket->so_snd); 238436381Ssklower break; 238536381Ssklower 238636381Ssklower case PRC_ROUTEDEAD: 238736381Ssklower error = ENETUNREACH; 238836381Ssklower break; 238936381Ssklower 239036381Ssklower case PRC_TIMXCEED_REASS: 239136381Ssklower error = ETIMEDOUT; 239236381Ssklower break; 239336381Ssklower 239436381Ssklower /* 239536381Ssklower case PRC_QUENCH: 239636381Ssklower iso_pcbnotify(&cons_pcb, sa, 239736381Ssklower (int)inetctlerrmap[cmd], iso_rtchange); 239836381Ssklower iso_pcbnotify(&tp_incoming_pending, sa, 239936381Ssklower (int)inetctlerrmap[cmd], tpiso_quench); 240036381Ssklower iso_pcbnotify(&tp_isopcb, sa, 240136381Ssklower (int)inetctlerrmap[cmd], tpiso_quench); 240236381Ssklower */ 240336381Ssklower 240436381Ssklower case PRC_IFDOWN: 240536381Ssklower iso_pcbnotify(&cons_isopcb, sa, 240636381Ssklower (int)inetctlerrmap[cmd], iso_rtchange); 240736381Ssklower iso_pcbnotify(&tp_incoming_pending, sa, 240836381Ssklower (int)inetctlerrmap[cmd], iso_rtchange); 240936381Ssklower iso_pcbnotify(&tp_isopcb, sa, 241036381Ssklower (int)inetctlerrmap[cmd], iso_rtchange); 241136381Ssklower break; 241236381Ssklower 241336381Ssklower 241436381Ssklower default: 241536381Ssklower printf("cons_ctlinput: unknown cmd 0x%x\n", cmd); 241636381Ssklower } 241736381Ssklower if(error) { 241836381Ssklower soisdisconnected(copcb->co_socket); 241936381Ssklower sohasoutofband(copcb->co_socket); 242036381Ssklower } 242136381Ssklower splx(s); 242236381Ssklower } 242336381Ssklower 242436381Ssklower /* 242536381Ssklower *********************** SERVES ALL cons embodiments ******************* 242636381Ssklower */ 242736381Ssklower 242836381Ssklower /* 242936381Ssklower * NAME: cons_chan_to_pcb() 243036381Ssklower * CALLED FROM: 243136381Ssklower * cons_chan_to_tpcb() in tp_cons.c 243236381Ssklower * and in this file: incoming requests that give only a channel number, i.e., 243336381Ssklower * ECN_ACCEPT, ECN_RECEIVE, ECN_CLEAR 243436381Ssklower * FUNCTION: 243536381Ssklower * identify the pcb assoc with that channel 243636381Ssklower * RETURN: 243736381Ssklower * ptr to the pcb 243836381Ssklower */ 243936381Ssklower struct cons_pcb * 244036381Ssklower #ifdef ARGO_DEBUG 244136381Ssklower cons_chan_to_pcb( channel, linenumber ) 244236381Ssklower int linenumber; 244336381Ssklower #else ARGO_DEBUG 244436381Ssklower cons_chan_to_pcb( channel) 244536381Ssklower #endif ARGO_DEBUG 244636381Ssklower register int channel; 244736381Ssklower { 244836381Ssklower register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist; 244936381Ssklower register struct cons_pcb *copcb; 245036381Ssklower 245136381Ssklower /* just to be sure */ 245236381Ssklower channel = channel & 0xff; 245336381Ssklower 245436381Ssklower for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) { 245536381Ssklower copcb = (struct cons_pcb *)copcb->co_next; 245636381Ssklower while (copcb != *copcblist) { 245736381Ssklower if ( copcb->co_channel == channel ) 245836381Ssklower goto found; /* want to break out of both loops */ 245936381Ssklower 246036381Ssklower copcb = (struct cons_pcb *)copcb->co_next; 246136381Ssklower } 246236381Ssklower } 246336381Ssklower found: /* or maybe not... */ 246436381Ssklower IFDEBUG(D_CCONS) 246536381Ssklower printf("cons_chan_to_pcb( 0x%x, %d ) %s 0x%x\n", channel, linenumber, 246636381Ssklower copcb?"FOUND":"FAILED", copcb); 246736381Ssklower ENDDEBUG 246836381Ssklower 246936381Ssklower return copcb; 247036381Ssklower } 247136381Ssklower 247236381Ssklower 247336381Ssklower /* 247436381Ssklower * NAME: is_me() 247536381Ssklower * CALLED FROM: 247636381Ssklower * cons_incoming(). Perhaps could just expand in line. 247736381Ssklower * FUNCTION and ARGUMENTS: 247836381Ssklower * for the given remote address (remadr) if it exactly matches 247936381Ssklower * one of the addresses of ME, and I am up as loopback, 248036381Ssklower * return TRUE, else return FALSE. 248136381Ssklower * RETURNS: 248236381Ssklower * Boolean 248336381Ssklower */ 248436381Ssklower Static int 248536381Ssklower is_me(remaddr) 248636381Ssklower struct sockaddr_iso *remaddr; 248736381Ssklower { 248836381Ssklower struct ifnet *ifp = consif; 248936381Ssklower /* PHASE2: this is ok */ 249036381Ssklower struct ifaddr *ifa = ifa_ifwithaddr(remaddr); 249136381Ssklower 249236381Ssklower IFDEBUG(D_CADDR) 249336381Ssklower printf("is_me: withaddr returns %s\n", 249436381Ssklower ifa?ifa->ifa_ifp->if_name:"NONE"); 249536381Ssklower ENDDEBUG 249636381Ssklower if( ifa ) { 249736381Ssklower /* remaddr matches one of my interfaces exactly */ 249836381Ssklower if( ifa->ifa_ifp->if_flags & IFF_LOOPBACK ) { 249936381Ssklower ASSERT( ifp == ifa->ifa_ifp ); 250036381Ssklower return 1; 250136381Ssklower } 250236381Ssklower } 250336381Ssklower return 0; 250436381Ssklower } 250536381Ssklower 250636381Ssklower find_error_reason( ecnrq ) 250736381Ssklower register struct eicon_request *ecnrq; 250836381Ssklower { 250936381Ssklower extern u_char x25_error_stats[]; 251036381Ssklower int error; 251136381Ssklower struct mbuf *cdm; 251236381Ssklower struct e_clear_data *ecd; 251336381Ssklower 251436381Ssklower cdm = e_data(ecnrq); 251536381Ssklower if( cdm && cdm->m_len > 0 ) { 251636381Ssklower ecd = mtod(cdm, struct e_clear_data *); 251736381Ssklower switch( ecd->ecd_cause ) { 251836381Ssklower case 0x00: 251936381Ssklower case 0x80: 252036381Ssklower /* DTE originated; look at the diagnostic */ 252136381Ssklower error = (CONL_ERROR_MASK | ecd->ecd_diagnostic); 252236381Ssklower goto done; 252336381Ssklower 252436381Ssklower case 0x01: /* number busy */ 252536381Ssklower case 0x81: 252636381Ssklower case 0x09: /* Out of order */ 252736381Ssklower case 0x89: 252836381Ssklower case 0x11: /* Remot Procedure Error */ 252936381Ssklower case 0x91: 253036381Ssklower case 0x19: /* reverse charging accept not subscribed */ 253136381Ssklower case 0x99: 253236381Ssklower case 0x21: /* Incampat destination */ 253336381Ssklower case 0xa1: 253436381Ssklower case 0x29: /* fast select accept not subscribed */ 253536381Ssklower case 0xa9: 253636381Ssklower case 0x39: /* ship absent */ 253736381Ssklower case 0xb9: 253836381Ssklower case 0x03: /* invalid facil request */ 253936381Ssklower case 0x83: 254036381Ssklower case 0x0b: /* access barred */ 254136381Ssklower case 0x8b: 254236381Ssklower case 0x13: /* local procedure error */ 254336381Ssklower case 0x93: 254436381Ssklower case 0x05: /* network congestion */ 254536381Ssklower case 0x85: 254636381Ssklower case 0x8d: /* not obtainable */ 254736381Ssklower case 0x0d: 254836381Ssklower case 0x95: /* RPOA out of order */ 254936381Ssklower case 0x15: 255036381Ssklower /* take out bit 8 255136381Ssklower * so we don't have to have so many perror entries 255236381Ssklower */ 255336381Ssklower error = (CONL_ERROR_MASK | 0x100 | (ecd->ecd_cause & ~0x80)); 255436381Ssklower goto done; 255536381Ssklower 255636381Ssklower case 0xc1: /* gateway-detected proc error */ 255736381Ssklower case 0xc3: /* gateway congestion */ 255836381Ssklower 255936381Ssklower error = (CONL_ERROR_MASK | 0x100 | ecd->ecd_cause); 256036381Ssklower goto done; 256136381Ssklower } 256236381Ssklower } 256336381Ssklower /* otherwise, a *hopefully* valid perror exists in the e_reason field */ 256436381Ssklower error = ecnrq->e_reason; 256536381Ssklower if (error = 0) { 256636381Ssklower printf("Incoming PKT TYPE 0x%x with reason 0x%x\n", 256736381Ssklower ecnrq->e_cmd, 256836381Ssklower ecnrq->e_reason); 256936381Ssklower error = E_CO_HLI_DISCA; 257036381Ssklower } 257136381Ssklower 257236381Ssklower done: 257336381Ssklower if(error & 0x1ff == 0) { 257436381Ssklower error = 0; 257536381Ssklower } else if( error & 0x1ff > sizeof(x25_error_stats)) { 257636381Ssklower ASSERT(0); 257736381Ssklower } else { 257836381Ssklower x25_error_stats[error& 0x1ff] ++; 257936381Ssklower } 258036381Ssklower return error; 258136381Ssklower } 258236381Ssklower 258336381Ssklower /* 258436381Ssklower * NAME: consintr() 258536381Ssklower * CALLED FROM: 258636381Ssklower * the eicon driver via software interrupt 258736381Ssklower * FUNCTION and ARGUMENTS: 258836381Ssklower * processes incoming indications, passing them 258936381Ssklower * along to clnp, tp, or x.25-transport as appropriate. 259036381Ssklower */ 259136381Ssklower consintr() 259236381Ssklower { 259336381Ssklower struct ifnet *ifp = consif; 259436381Ssklower register struct eicon_request *ecnrq; 259536381Ssklower register struct cons_pcb *copcb = (struct cons_pcb *)0; 259636381Ssklower register struct mbuf *m; 259736381Ssklower int s, s0 = splnet(); 259836381Ssklower 259936381Ssklower IncStat(co_intr); 260036381Ssklower ifp->if_ipackets ++; 260136381Ssklower 260236381Ssklower for(;;) { 260336381Ssklower /* 260436381Ssklower * Get next request off input queue 260536381Ssklower */ 260636381Ssklower s = splimp(); 260736381Ssklower IF_DEQUEUE(&consintrq, m); 260836381Ssklower splx(s); 260936381Ssklower IFDEBUG(D_INCOMING) 261036381Ssklower printf("cons intr() 0x%x m_off 0x%x m_len 0x%x dequeued\n", 261136381Ssklower m, m?m->m_off:0, m?m->m_len:0); 261236381Ssklower ENDDEBUG 261336381Ssklower 261436381Ssklower if (m == 0) { 261536381Ssklower splx(s0); 261636381Ssklower return; 261736381Ssklower } 261836381Ssklower 261936381Ssklower if((m->m_off != MMINOFF)||(m->m_len != sizeof (struct eicon_request))){ 262036381Ssklower ifp->if_ierrors ++; 262136381Ssklower IncStat(co_Rdrops); 262236381Ssklower printf("Cons R DROP! BAD MBUF FROM LL 0x%x sizeof(...) 0x%x\n", 262336381Ssklower m, sizeof(struct eicon_request)); 262436381Ssklower continue; 262536381Ssklower } 262636381Ssklower 262736381Ssklower ecnrq = mtod(m, struct eicon_request *); 262836381Ssklower 262936381Ssklower 263036381Ssklower IFDEBUG(D_INCOMING) 263136381Ssklower printf("INTR: e_cmd 0x%x, e_data 0x%x\n", ecnrq->e_cmd, 263236381Ssklower e_data(ecnrq)); 263336381Ssklower if( e_data(ecnrq) != 0 ) { 263436381Ssklower /* let's just look at the first few bytes */ 263536381Ssklower /* 263636381Ssklower dump_buf( e_data(ecnrq), (e_data(ecnrq))->m_len + 12); 263736381Ssklower */ 263836381Ssklower dump_buf( e_data(ecnrq), 20 + 12); 263936381Ssklower } 264036381Ssklower ENDDEBUG 264136381Ssklower IFTRACE(D_CDATA) 264236381Ssklower tptrace( TPPTmisc, "INTR: req_type m lun\n", 264336381Ssklower ecnrq->e_cmd, m, ecnrq->e_vc, 0); 264436381Ssklower ENDTRACE 264536381Ssklower 264636381Ssklower switch( ecnrq->e_cmd ) { 264736381Ssklower 264836381Ssklower case ECN_ACK: /* data put on the board */ 264936381Ssklower IncStat(co_ack); 265036381Ssklower ASSERT( ecnrq->e_vc != 0); 265136381Ssklower /* from ACKWAIT to OPEN */ 265236381Ssklower if ( (copcb = 265336381Ssklower #ifdef ARGO_DEBUG 265436381Ssklower cons_chan_to_pcb( (int)ecnrq->e_vc, __LINE__ ) 265536381Ssklower #else ARGO_DEBUG 265636381Ssklower cons_chan_to_pcb( (int)ecnrq->e_vc ) 265736381Ssklower #endif ARGO_DEBUG 265836381Ssklower ) == (struct cons_pcb *)0 ) 265936381Ssklower break; 266036381Ssklower copcb->co_state = OPEN; 266136381Ssklower /* 266236381Ssklower * Anything on the pending queue for this connection? 266336381Ssklower */ 266436381Ssklower if( copcb->co_pending.ifq_len == 0 ) { 266536381Ssklower if( copcb->co_proto->pr_ctlinput ) 266636381Ssklower /* for the sake of higher layer protocol (tp) */ 266736381Ssklower (*copcb->co_proto->pr_ctlinput) 266836381Ssklower (PRC_CONS_SEND_DONE, 266936381Ssklower (struct sockaddr_iso *)&copcb->co_faddr, 267036381Ssklower (caddr_t)copcb); 267136381Ssklower } else { 267236381Ssklower register struct mbuf *m0; 267336381Ssklower 267436381Ssklower s = splimp(); 267536381Ssklower IF_DEQUEUE( &copcb->co_pending, m0 ); 267636381Ssklower splx(s); 267736381Ssklower /* CAN ONLY DO 1 item here 267836381Ssklower * if you change this if to while, HA HA 267936381Ssklower * it'll go right back onto 268036381Ssklower * the pending queue (which means things will 268136381Ssklower * be reordered on the queue!) 268236381Ssklower */ 268336381Ssklower if( m0 ) { 268436381Ssklower IFDEBUG(D_CDATA) 268536381Ssklower printf("ACK sending pending queue 0x%x len 0x%x\n", 268636381Ssklower m0, m0->m_len); 268736381Ssklower ENDDEBUG 268836381Ssklower ASSERT( m0->m_len != 0); 268936381Ssklower (void) cons_senddata(copcb, m0); 269036381Ssklower } 269136381Ssklower } 269236381Ssklower 269336381Ssklower /* send more? */ 269436381Ssklower break; 269536381Ssklower 269636381Ssklower case ECN_ACCEPT: /* call accepted at other end */ 269736381Ssklower /* adr_src, adr_dst are as given in the ECN_CALL 269836381Ssklower * pcb field is copied from our ECN_CALL 269936381Ssklower * request, confirm gives me a channel number 270036381Ssklower */ 270136381Ssklower ASSERT( ecnrq->e_vc != 0); 270236381Ssklower 270336381Ssklower IncStat(co_accept); 270436381Ssklower if(copcb = 270536381Ssklower #ifdef ARGO_DEBUG 270636381Ssklower cons_chan_to_pcb((int)ecnrq->e_vc, __LINE__ ) 270736381Ssklower #else ARGO_DEBUG 270836381Ssklower cons_chan_to_pcb((int)ecnrq->e_vc) 270936381Ssklower #endif ARGO_DEBUG 271036381Ssklower ) { 271136381Ssklower /* error: already exists */ 271236381Ssklower printf("cons PANIC: dbl confirm for channel 0x%x\n", 271336381Ssklower ecnrq->e_vc); 271436381Ssklower break; 271536381Ssklower } 271636381Ssklower copcb = (struct cons_pcb *)ecnrq->e_pcb; 271736381Ssklower if( copcb->co_myself != copcb ) { 271836381Ssklower struct mbuf *mm; 271936381Ssklower /* TODO: REMOVE */ 272036381Ssklower ASSERT(0); 272136381Ssklower printf("BAD e_pcb from ecn (0x%x) cmd 0x%x\n", 272236381Ssklower ecnrq->e_pcb, ecnrq->e_cmd); 272336381Ssklower mm = dtom( copcb ); 272436381Ssklower if(mm->m_type == MT_FREE) 272536381Ssklower printf("FREED MBUF!\n"); 272636381Ssklower dump_buf (ecnrq, sizeof (*ecnrq)); 272736381Ssklower panic("BAD ecnrq"); 272836381Ssklower break; 272936381Ssklower } 273036381Ssklower touch(copcb); 273136381Ssklower copcb->co_state = OPEN; 273236381Ssklower copcb->co_channel = (int)ecnrq->e_vc; 273336381Ssklower if(copcb->co_socket) { 273436381Ssklower /* tp0 will take care of itself */ 273536381Ssklower if( copcb->co_flags & CONSF_XTS) 273636381Ssklower soisconnected(copcb->co_socket); /* wake 'em up */ 273736381Ssklower } 273836381Ssklower wakeup( (caddr_t)&copcb->co_state ); 273936381Ssklower 274036381Ssklower /* 274136381Ssklower * Anything on the pending queue for this connection? 274236381Ssklower */ 274336381Ssklower if( copcb->co_pending.ifq_len > 0 ) { 274436381Ssklower register struct mbuf *m0; 274536381Ssklower 274636381Ssklower s = splimp(); 274736381Ssklower IF_DEQUEUE( &copcb->co_pending, m0 ); 274836381Ssklower splx(s); 274936381Ssklower /* CAN ONLY DO 1 item here 275036381Ssklower * if you change this if to while, HA HA 275136381Ssklower * it'll go right back onto 275236381Ssklower * the pending queue (which means things will 275336381Ssklower * be reordered on the queue!) 275436381Ssklower */ 275536381Ssklower if( m0 ) { 275636381Ssklower IFDEBUG(D_CDATA) 275736381Ssklower printf("ACPT sending pending queue 0x%x len 0x%x\n", 275836381Ssklower m0, m0->m_len); 275936381Ssklower ENDDEBUG 276036381Ssklower ASSERT( m0->m_len != 0); 276136381Ssklower (void) cons_senddata(copcb, m0); 276236381Ssklower } 276336381Ssklower } 276436381Ssklower break; 276536381Ssklower 276636381Ssklower case ECN_REFUSE: 276736381Ssklower /* other end refused our connect request */ 276836381Ssklower /* src, dst are as given in the ECN_CALL */ 276936381Ssklower 277036381Ssklower IncStat(co_refuse); 277136381Ssklower copcb = (struct cons_pcb *)ecnrq->e_pcb; 277236381Ssklower if( copcb->co_myself != copcb ) { 277336381Ssklower struct mbuf *mm; 277436381Ssklower /* TODO: REMOVE */ 277536381Ssklower ASSERT(0); 277636381Ssklower printf("BAD e_pcb from ecn (0x%x) cmd 0x%x\n", 277736381Ssklower ecnrq->e_pcb, ecnrq->e_cmd); 277836381Ssklower mm = dtom( copcb ); 277936381Ssklower if(mm->m_type == MT_FREE) 278036381Ssklower printf("FREED MBUF!\n"); 278136381Ssklower dump_buf (ecnrq, sizeof (*ecnrq)); 278236381Ssklower dump_buf (copcb, sizeof (*copcb)); 278336381Ssklower panic("BAD ecnrq"); 278436381Ssklower break; 278536381Ssklower } 278636381Ssklower touch(copcb); 278736381Ssklower copcb->co_state = CLOSED; /* do we have to do a clear?? */ 278836381Ssklower copcb->co_channel = X_NOCHANNEL; 278936381Ssklower if(copcb->co_socket) { 279036381Ssklower copcb->co_socket->so_error = ECONNREFUSED; 279136381Ssklower /* TODO: if there's diagnostic info in the 279236381Ssklower * packet, and it's more useful than this E*, 279336381Ssklower * get it 279436381Ssklower */ 279536381Ssklower soisdisconnected(copcb->co_socket); /* wake 'em up */ 279636381Ssklower IFDEBUG(D_INCOMING) 279736381Ssklower printf("ECN_REFUSE: waking up 0x%x\n", 279836381Ssklower (caddr_t)&copcb->co_state ); 279936381Ssklower ENDDEBUG 280036381Ssklower wakeup( (caddr_t)&copcb->co_state ); 280136381Ssklower } 280236381Ssklower /* 280336381Ssklower * Anything on the pending queue for this connection? 280436381Ssklower */ 280536381Ssklower while( copcb->co_pending.ifq_len > 0 ) { 280636381Ssklower register struct mbuf *m0; 280736381Ssklower 280836381Ssklower s = splimp(); 280936381Ssklower IF_DEQUEUE( &copcb->co_pending, m0 ); 281036381Ssklower splx(s); 281136381Ssklower m_freem(m0); 281236381Ssklower } 281336381Ssklower if ( ecnrq->e_reason == E_CO_NORESOURCES ) { 281436381Ssklower IncStat(co_noresources); 281536381Ssklower cons_clear_and_detach( copcb, DONTCLEAR, PRC_QUENCH ); 281636381Ssklower } else if(copcb->co_socket ) { 281736381Ssklower copcb->co_socket->so_error = find_error_reason( ecnrq ); 281836381Ssklower } 281936381Ssklower break; 282036381Ssklower 282136381Ssklower case ECN_CONNECT: /* incoming call */ 282236381Ssklower /* 282336381Ssklower * ECN_CONNECT indication gives adc_src, adc_dst and channel 282436381Ssklower */ 282536381Ssklower ASSERT( ecnrq->e_vc != 0); 282636381Ssklower 282736381Ssklower IncStat(co_connect); 282836381Ssklower cons_incoming(ifp, ecnrq); 282936381Ssklower break; 283036381Ssklower 283136381Ssklower case ECN_RESET: 283236381Ssklower case ECN_CLEAR: 283336381Ssklower /* 283436381Ssklower * ECN_CLEAR(indication) (if we can construct such a beast) 283536381Ssklower * gives e_vc, 283636381Ssklower * Throw away anything queued pending on this connection 283736381Ssklower * give a reset indication to the upper layer if TP 283836381Ssklower * free the mbufs 283936381Ssklower */ 284036381Ssklower ASSERT( ecnrq->e_vc != 0); 284136381Ssklower if( ecnrq->e_cmd == ECN_CLEAR ) 284236381Ssklower IncStat(co_clear_in); 284336381Ssklower else 284436381Ssklower IncStat(co_reset_in); 284536381Ssklower #ifdef ARGO_DEBUG 284636381Ssklower if( ! (copcb=cons_chan_to_pcb((int)ecnrq->e_vc, __LINE__)) ) 284736381Ssklower #else ARGO_DEBUG 284836381Ssklower if( ! (copcb=cons_chan_to_pcb((int)ecnrq->e_vc)) ) 284936381Ssklower #endif ARGO_DEBUG 285036381Ssklower 285136381Ssklower break; 285236381Ssklower while( copcb->co_pending.ifq_len ) { 285336381Ssklower register struct mbuf *m0; 285436381Ssklower 285536381Ssklower s = splimp(); 285636381Ssklower IF_DEQUEUE( &copcb->co_pending, m0 ); 285736381Ssklower splx(s); 285836381Ssklower m_freem(m0); 285936381Ssklower } 286036381Ssklower copcb->co_state = CLOSED; /* do we have to do a clear? */ 286136381Ssklower copcb->co_channel = X_NOCHANNEL; 286236381Ssklower 286336381Ssklower cons_clear_and_detach( copcb, DONTCLEAR, PRC_ROUTEDEAD ); 286436381Ssklower if (copcb->co_socket ) { 286536381Ssklower copcb->co_socket->so_error = find_error_reason( ecnrq ); 286636381Ssklower } 286736381Ssklower break; 286836381Ssklower 286936381Ssklower case ECN_RECEIVE: 287036381Ssklower /* 287136381Ssklower * ECN_RECEIVE (read) 287236381Ssklower */ 287336381Ssklower ASSERT( ecnrq->e_vc != 0); 287436381Ssklower IncStat(co_receive); 287536381Ssklower { 287636381Ssklower /* TODO: REMOVE */ 287736381Ssklower struct mbuf *thedata = e_data(ecnrq); 287836381Ssklower u_int *firstint = mtod( thedata, u_int *); 287936381Ssklower 288036381Ssklower if( (*firstint & 0xff000000) != 0x81000000 ) { 288136381Ssklower /* not clnp */ 288236381Ssklower switch( ((*firstint) & 0x00ff0000) >> 20 ) { 288336381Ssklower case 0x1: 288436381Ssklower case 0x2: 288536381Ssklower case 0x3: 288636381Ssklower case 0x6: 288736381Ssklower case 0x7: 288836381Ssklower case 0x8: 288936381Ssklower case 0xc: 289036381Ssklower case 0xd: 289136381Ssklower case 0xe: 289236381Ssklower case 0xf: 289336381Ssklower break; 289436381Ssklower default: 289536381Ssklower printf(" ECN_RECEIVE! BAD DATA\n" ); 289636381Ssklower dump_buf( thedata, 20 + 12 ); 289736381Ssklower m_freem( m ); 289836381Ssklower splx(s0); 289936381Ssklower } 290036381Ssklower } 290136381Ssklower } 290236381Ssklower if ( (copcb = 290336381Ssklower #ifdef ARGO_DEBUG 290436381Ssklower cons_chan_to_pcb( (int)ecnrq->e_vc, __LINE__ ) 290536381Ssklower #else ARGO_DEBUG 290636381Ssklower cons_chan_to_pcb( (int)ecnrq->e_vc ) 290736381Ssklower #endif ARGO_DEBUG 290836381Ssklower ) == (struct cons_pcb *)0 ) { 290936381Ssklower ifp->if_ierrors ++; 291036381Ssklower IFTRACE(D_CDATA) 291136381Ssklower tptrace(TPPTmisc, "ECN_RECEIVE DROPPED chan \n", 291236381Ssklower ecnrq->e_vc, 0, 0, 0); 291336381Ssklower ENDTRACE 291436381Ssklower break; 291536381Ssklower } 291636381Ssklower 291736381Ssklower touch(copcb); 291836381Ssklower if( ecnrq->e_info & ECN_INFO_RCVD_INT ) { 291936381Ssklower /* interrupt packet */ 292036381Ssklower printf("consintr: interrupt pkttype : DROPPED\n"); 292136381Ssklower IncStat(co_intrpt_pkts_in); 292236381Ssklower IncStat(co_Rdrops); 292336381Ssklower break; 292436381Ssklower } 292536381Ssklower /* new way */ 292636381Ssklower if( copcb->co_proto == CLNP_proto ) 292736381Ssklower { 292836381Ssklower /* IP: put it on the queue and set soft interrupt */ 292936381Ssklower struct ifqueue *ifq; 293036381Ssklower extern struct ifqueue clnlintrq; 293136381Ssklower register struct mbuf *ifpp; /* for ptr to ifp */ 293236381Ssklower register struct mbuf *data = e_data(ecnrq); 293336381Ssklower 293436381Ssklower total_pkts_to_clnp ++; 293536381Ssklower 293636381Ssklower /* when acting as a subnet service, have to prepend a 293736381Ssklower * pointer to the ifnet before handing this to clnp 293836381Ssklower * GAG 293936381Ssklower */ 294036381Ssklower if( ( data->m_off > MMINOFF + sizeof(struct snpa_hdr)) && 294136381Ssklower ( data->m_off <= MMAXOFF )) { 294236381Ssklower data->m_off -= sizeof(struct snpa_hdr); 294336381Ssklower data->m_len += sizeof(struct snpa_hdr); 294436381Ssklower } else { 294536381Ssklower MGET(ifpp, M_DONTWAIT, MT_XHEADER); 294636381Ssklower if( !ifpp ) { 294736381Ssklower ifp->if_ierrors ++; 294836381Ssklower splx(s0); 294936381Ssklower m_freem(m); /* frees everything */ 295036381Ssklower return; 295136381Ssklower } 295236381Ssklower ifpp->m_len = sizeof(struct snpa_hdr); 295336381Ssklower ifpp->m_act = 0; 295436381Ssklower ifpp->m_next = data; 295536381Ssklower data = ifpp; 295636381Ssklower } 295736381Ssklower IFTRACE(D_CDATA) 295836381Ssklower tptrace(TPPTmisc, "-->CLNP copcb\n", copcb, 0, 0, 0); 295936381Ssklower ENDTRACE 296036381Ssklower { 296136381Ssklower /* 296236381Ssklower * TODO: if we ever use esis/cons we have to 296336381Ssklower * think of something reasonable to stick in the 296436381Ssklower * snh_shost,snh_dhost fields. I guess 296536381Ssklower * the x.121 address is what we want. 296636381Ssklower * 296736381Ssklower * That would also require length fields in the 296836381Ssklower * snpa_hdr structure. 296936381Ssklower */ 297036381Ssklower struct snpa_hdr *snh = 297136381Ssklower mtod(data, struct snpa_hdr *); 297236381Ssklower bzero((caddr_t)&snh, sizeof(struct snpa_hdr)); 297336381Ssklower bcopy((caddr_t)&ifp, (caddr_t)&snh->snh_ifp, 297436381Ssklower sizeof(struct ifnet *)); 297536381Ssklower } 297636381Ssklower *( mtod(data, struct ifnet **) ) = ifp; /* KLUDGE */ 297736381Ssklower 297836381Ssklower ifq = &clnlintrq; 297936381Ssklower splimp(); 298036381Ssklower if (IF_QFULL(ifq)) { 298136381Ssklower IF_DROP(ifq); 298236381Ssklower m_freem(m); 298336381Ssklower IFDEBUG(D_INCOMING) 298436381Ssklower printf("DROPPED! ecnrq 0x%x, data 0x%x\n", m,data); 298536381Ssklower ENDDEBUG 298636381Ssklower splx(s0); 298736381Ssklower ifp->if_ierrors ++; 298836381Ssklower return; 298936381Ssklower } 299036381Ssklower IF_ENQUEUE(ifq, data); 299136381Ssklower IFDEBUG(D_INCOMING) 299236381Ssklower printf( 299336381Ssklower "0x%x enqueued on ip Q: m_len 0x%x m_type 0x%x m_off 0x%x\n", 299436381Ssklower data, data->m_len, data->m_type, data->m_off); 299536381Ssklower dump_buf(mtod(data, caddr_t), data->m_len); 299636381Ssklower ENDDEBUG 299736381Ssklower e_data(ecnrq) = (struct mbuf *)0; 299836381Ssklower schednetisr(NETISR_CLNP); 299936381Ssklower } else { 300036381Ssklower /* HL is NOT clnp */ 300136381Ssklower IFTRACE(D_CDATA) 300236381Ssklower tptrace(TPPTmisc, 300336381Ssklower "-->HL pr_input so copcb channel\n", 300436381Ssklower copcb->co_proto->pr_input, 300536381Ssklower copcb->co_socket, copcb, 300636381Ssklower copcb->co_channel); 300736381Ssklower ENDTRACE 300836381Ssklower IFDEBUG(D_INCOMING) 300936381Ssklower printf( "0x%x --> HL proto 0x%x chan 0x%x\n", 301036381Ssklower e_data(ecnrq), copcb->co_proto, copcb->co_channel ); 301136381Ssklower ENDDEBUG 301236381Ssklower 301336381Ssklower (*copcb->co_proto->pr_input)(e_data(ecnrq), 301436381Ssklower &copcb->co_faddr, 301536381Ssklower &copcb->co_laddr, 301636381Ssklower copcb->co_socket, /* used by cons-transport interface */ 301736381Ssklower (copcb->co_flags & CONSF_DGM)?0: 301836381Ssklower copcb->co_channel);/* used by tp-cons interface */ 301936381Ssklower 302036381Ssklower /* 302136381Ssklower * the pr_input will free the data chain, so we must 302236381Ssklower * zero the ptr to is so that m_free doesn't panic 302336381Ssklower */ 302436381Ssklower e_data(ecnrq) = (struct mbuf *)0; 302536381Ssklower } 302636381Ssklower break; 302736381Ssklower 302836381Ssklower default: 302936381Ssklower /* error */ 303036381Ssklower ifp->if_ierrors ++; 303136381Ssklower printf("consintr: unknown request\n"); 303236381Ssklower } 303336381Ssklower IFDEBUG(D_INCOMING) 303436381Ssklower printf("consintr: m_freem( 0x%x )\n", m); 303536381Ssklower ENDDEBUG 303636381Ssklower m_freem( m ); 303736381Ssklower } 303836381Ssklower splx(s0); 303936381Ssklower } 304036381Ssklower 304136381Ssklower /* 304236381Ssklower * Process an ioctl request. 304336381Ssklower * also set-time-limit, extend-time-limit 304436381Ssklower * for ALL channels, the time-limit ioctls will be done by open-a-dummy-socket, 304536381Ssklower * do ioctl with the channel number, close the socket (dumb!). 304636381Ssklower */ 304736381Ssklower /* ARGSUSED */ 304836381Ssklower cons_ioctl(so, cmd, data) 304936381Ssklower struct socket *so; 305036381Ssklower int cmd; 305136381Ssklower caddr_t data; 305236381Ssklower { 305336381Ssklower int s = splnet(); 305436381Ssklower int error = 0; 305536381Ssklower 305636381Ssklower IFDEBUG(D_CCONS) 305736381Ssklower printf("cons_ioctl( cmd 0x%x )\n", cmd); 305836381Ssklower ENDDEBUG 305936381Ssklower 306036381Ssklower #ifdef notdef 306136381Ssklower switch (cmd) { 306236381Ssklower 306336381Ssklower default: 306436381Ssklower #endif notdef 306536381Ssklower error = EOPNOTSUPP; 306636381Ssklower #ifdef notdef 306736381Ssklower } 306836381Ssklower #endif notdef 306936381Ssklower 307036381Ssklower splx(s); 307136381Ssklower return (error); 307236381Ssklower } 307336381Ssklower 307436381Ssklower 307536381Ssklower /* 307636381Ssklower ************************************************************* 307736381Ssklower * * 307836381Ssklower * * 307936381Ssklower * Interface to CO Subnetwork service from CLNP * 308036381Ssklower * Must be a device interface. ***** 308136381Ssklower * *** 308236381Ssklower * * 308336381Ssklower * Poof! 308436381Ssklower */ 308536381Ssklower 308636381Ssklower /* 308736381Ssklower * NAME: consioctl() 308836381Ssklower * CALLED FROM: 308936381Ssklower * called through the ifnet structure. 309036381Ssklower * FUNCTION and ARGUMENTS: 309136381Ssklower * the usual ioctl stuff 309236381Ssklower * RETURNS: 309336381Ssklower * E* 309436381Ssklower * SIDE EFFECTS: 309536381Ssklower * NOTES: 309636381Ssklower */ 309736381Ssklower consioctl(ifp, cmd, data) 309836381Ssklower register struct ifnet *ifp; 309936381Ssklower register int cmd; 310036381Ssklower register caddr_t data; 310136381Ssklower { 310236381Ssklower register struct ifaddr *ifa = (struct ifaddr *)data; 310336381Ssklower register int s = splimp(); 310436381Ssklower register struct ifreq *ifr = (struct ifreq *)data; 310536381Ssklower register int error = 0; 310636381Ssklower void consshutdown(); 310736381Ssklower 310836381Ssklower switch (cmd) { 310936381Ssklower case SIOCSIFADDR: 311036381Ssklower switch (ifa->ifa_addr.sa_family) { 311136381Ssklower case AF_ISO: 311236381Ssklower if( (ifp->if_flags & IFF_UP ) == 0) 311336381Ssklower consinit(ifp->if_unit); 311436381Ssklower break; 311536381Ssklower default: 311636381Ssklower printf("CANNOT config cons with address family %d\n", 311736381Ssklower ifa->ifa_addr.sa_family); 311836381Ssklower break; 311936381Ssklower } 312036381Ssklower break; 312136381Ssklower case SIOCSIFFLAGS: 312236381Ssklower IFDEBUG(D_CCONS) 312336381Ssklower printf("consioctl: set flags to x%x\n", ifr->ifr_flags); 312436381Ssklower printf("consioctl: ifp flags are x%x\n", ifp->if_flags); 312536381Ssklower ENDDEBUG 312636381Ssklower if( ifr->ifr_flags & IFF_LOOPBACK ) 312736381Ssklower ifp->if_flags |= IFF_LOOPBACK; 312836381Ssklower else 312936381Ssklower ifp->if_flags &= ~IFF_LOOPBACK; 313036381Ssklower 313136381Ssklower /* if board is down but request takes it up, init the board */ 313236381Ssklower if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) 313336381Ssklower consinit(ifp->if_unit); 313436381Ssklower 313536381Ssklower /* if board is up but request takes it down, shut the board down */ 313636381Ssklower if (((ifr->ifr_flags & IFF_UP) == 0) && (ifp->if_flags & IFF_UP)) { 313736381Ssklower consshutdown(ifp->if_unit); 313836381Ssklower } 313936381Ssklower IFDEBUG(D_CCONS) 314036381Ssklower printf("consioctl: flags are x%x\n", ifp->if_flags); 314136381Ssklower ENDDEBUG 314236381Ssklower break; 314336381Ssklower case SIOCGSTATUS: 314436381Ssklower /* warning: must coerse ifp to (struct ifstatus *) in order to use */ 314536381Ssklower IFDEBUG(D_CCONS) 314636381Ssklower printf("consioctl: EICON status request\n"); 314736381Ssklower ENDDEBUG 314836381Ssklower #if NECN>0 314936381Ssklower ecnioctl(ifp, cmd, data); 315036381Ssklower #else 315136381Ssklower error = ENODEV; 315236381Ssklower #endif NECN>0 315336381Ssklower break; 315436381Ssklower default: 315536381Ssklower error = EINVAL; 315636381Ssklower } 315736381Ssklower splx(s); 315836381Ssklower return error; 315936381Ssklower } 316036381Ssklower 316136381Ssklower /* 316236381Ssklower * NAME: consattach() 316336381Ssklower * CALLED FROM: 316436381Ssklower * cons_init() (which comes from autoconf) 316536381Ssklower * FUNCTION and ARGUMENTS: 316636381Ssklower * creates an ifp and fills it in; calls ifattach() on it. 316736381Ssklower * RETURNS: 316836381Ssklower * no return value 316936381Ssklower * SIDE EFFECTS: 317036381Ssklower * NOTES: 317136381Ssklower */ 317236381Ssklower consattach() 317336381Ssklower { 317436381Ssklower register struct ifnet *ifp; 317536381Ssklower register struct mbuf *m; 317636381Ssklower 317736381Ssklower if(sizeof(struct ifnet) > MLEN) { 317836381Ssklower printf("Can't attach cons! sizeof(struct ifnet) > MLEN\n"); 317936381Ssklower return; 318036381Ssklower } 318136381Ssklower MGET(m, M_DONTWAIT, MT_IFADDR); 318236381Ssklower if( !m ) { 318336381Ssklower printf("Can't attach cons! NO MBUFS!\n"); 318436381Ssklower return; 318536381Ssklower } 318636381Ssklower m->m_len = sizeof(struct ifnet); 318736381Ssklower ifp = consif = mtod(m, struct ifnet *); 318836381Ssklower ifp->if_unit = 0; 318936381Ssklower ifp->if_name = "cons"; 319036381Ssklower ifp->if_mtu = ECN_MTU; 319136381Ssklower ifp->if_init = consinit; 319236381Ssklower ifp->if_ioctl = consioctl; 319336381Ssklower ifp->if_output = cosns_output; /* called by clnp */ 319436381Ssklower ifp->if_flags = IFF_LOOPBACK; /* default */ 319536381Ssklower if_attach(ifp); 319636381Ssklower printf("cons%d: pseudo device attached \n", ifp->if_unit); 319736381Ssklower } 319836381Ssklower 319936381Ssklower /* 320036381Ssklower * NAME: consinit() 320136381Ssklower * CALLED FROM: 320236381Ssklower * consioctl() 320336381Ssklower * FUNCTION and ARGUMENTS: 320436381Ssklower * Initializes apropos data structures, etc. 320536381Ssklower * Marks the device as up. 320636381Ssklower * Zaps the address list. 320736381Ssklower * Calls device layer restart on the device if necessary. 320836381Ssklower */ 320936381Ssklower Static 321036381Ssklower consinit(_unit) 321136381Ssklower register int _unit; /* unit to initialize */ 321236381Ssklower { 321336381Ssklower struct ifnet *ecnifp(); 321436381Ssklower struct ifnet *ifp; 321536381Ssklower int s; 321636381Ssklower 321736381Ssklower if ((ifp = ecnifp(_unit)) != (struct ifnet *)0 ) { 321836381Ssklower ecnrestart(ifp); 321936381Ssklower IncStat(co_restart); 322036381Ssklower } 322136381Ssklower if (consif->if_addrlist == (struct ifaddr *)0) 322236381Ssklower return; 322336381Ssklower if ((consif->if_flags & IFF_UP) == 0) { 322436381Ssklower s = splimp(); 322536381Ssklower consif->if_flags |= IFF_UP; 322636381Ssklower splx(s); 322736381Ssklower } 322836381Ssklower 322936381Ssklower } 323036381Ssklower 323136381Ssklower /* 323236381Ssklower * NAME: consshutdown() 323336381Ssklower * CALLED FROM: 323436381Ssklower * cons_ioctl() when user takes down an interface w/ SIOCSIFFLAGS 323536381Ssklower * FUNCTION and ARGUMENTS: 323636381Ssklower * calls lower layer shutdown routine on the device. 323736381Ssklower * and marks the if as down if the if is the sw loopback pseudodevice. 323836381Ssklower * RETURNS: 323936381Ssklower * no return value 324036381Ssklower */ 324136381Ssklower void 324236381Ssklower consshutdown(_unit) 324336381Ssklower register int _unit; /* unit to shutdown */ 324436381Ssklower { 324536381Ssklower extern struct ifnet *ecnifp(); 324636381Ssklower struct ifnet *ifp; 324736381Ssklower int s; 324836381Ssklower 324936381Ssklower if ((ifp = ecnifp(_unit)) != (struct ifnet *)0 ) { 325036381Ssklower ecnshutdown(ifp); 325136381Ssklower } 325236381Ssklower if ((consif->if_flags & IFF_UP) ) { 325336381Ssklower s = splimp(); 325436381Ssklower consif->if_flags &= ~IFF_UP; 325536381Ssklower splx(s); 325636381Ssklower } 325736381Ssklower } 325836381Ssklower #endif KERNEL 325936381Ssklower 326036381Ssklower /* 326136381Ssklower * NAME: munge() 326236381Ssklower * CALLED FROM: 326336381Ssklower * cons_pcbbind(), cons_usrreq() 326436381Ssklower * FUNCTION and ARGUMENTS: 326536381Ssklower * Takes the argument (value) and stashes it into the last two 326636381Ssklower * nibbles of an X.121 address. Does this in the two nibbles beginning 326736381Ssklower * at the location defined by the character pointer (dst_octet) and the 326836381Ssklower * integer (dst_nibble). Nibble 0 is the lower nibble (high 326936381Ssklower * order 4 bits); nibble 1 is the low order 4 bits of *(dst_octet). 327036381Ssklower * 327136381Ssklower * RETURNS: 327236381Ssklower * no return value 327336381Ssklower */ 327436381Ssklower Static 327536381Ssklower munge( value, dst_octet, dst_nibble) 327636381Ssklower int value; 327736381Ssklower caddr_t dst_octet; 327836381Ssklower int dst_nibble; 327936381Ssklower { 328036381Ssklower IFDEBUG(D_CCONN) 328136381Ssklower printf("MUNGE: value 0x%x dst_octet 0x%x, nibble 0x%x)\n", 328236381Ssklower value, dst_octet, dst_nibble); 328336381Ssklower ENDDEBUG 328436381Ssklower if (value >= ISO_PORT_RESERVED) 328536381Ssklower value -= 1000; 328636381Ssklower 328736381Ssklower { 328836381Ssklower /* convert so it looks like a decimal number */ 328936381Ssklower register int tens, ones; 329036381Ssklower 329136381Ssklower tens = value/10; 329236381Ssklower ASSERT( tens <= 9 ); 329336381Ssklower ones = value - (tens * 10); 329436381Ssklower 329536381Ssklower value = tens * 16 + ones; 329636381Ssklower } 329736381Ssklower 329836381Ssklower dst_octet --; 329936381Ssklower /* leave nibble same 'cause it's one after the last set nibble */ 330036381Ssklower 330136381Ssklower *dst_octet &= ~(0xff<<(dst_nibble << 2)); /* zero it */ 330236381Ssklower *dst_octet |= ((value>>4) << (dst_nibble<<2)); 330336381Ssklower dst_nibble = 1-dst_nibble; 330436381Ssklower dst_octet += dst_nibble; 330536381Ssklower 330636381Ssklower *dst_octet &= ~(0xff<<(dst_nibble << 2)); /* zero it */ 330736381Ssklower *dst_octet |= ((value&0xff) << (dst_nibble<<2)); 330836381Ssklower } 330936381Ssklower 331036381Ssklower /* 331136381Ssklower * NAME: unmunge() 331236381Ssklower * CALLED FROM: 331336381Ssklower * DTEtoNSAP(), FACILtoNSAP() 331436381Ssklower * FUNCTION and ARGUMENTS: 331536381Ssklower * return the port/tsuffix represented by the two digits found in a 331636381Ssklower * bcd string beginning at the (dst_nibble)th nibble of the 331736381Ssklower * octet BEFORE (dst_octet). 331836381Ssklower * 331936381Ssklower * dst_octet,dst_nibble is the nibble after the one we'll look at 332036381Ssklower * RETURNS: 332136381Ssklower * an integer, the port/tsuffix 332236381Ssklower * Note- converts to a port > 1000 if necessary. 332336381Ssklower */ 332436381Ssklower Static int 332536381Ssklower unmunge( dst_octet, dst_nibble ) 332636381Ssklower caddr_t dst_octet; 332736381Ssklower int dst_nibble; 332836381Ssklower { 332936381Ssklower register u_short last = 0; 333036381Ssklower 333136381Ssklower dst_octet --; 333236381Ssklower /* leave nibble same 'cause it's one after the last set nibble */ 333336381Ssklower IFDEBUG(D_CADDR) 333436381Ssklower printf("unmunge: *octet 0x%x, nibble 0x%x\n", *dst_octet, 333536381Ssklower dst_nibble); 333636381Ssklower ENDDEBUG 333736381Ssklower 333836381Ssklower last = ((*dst_octet) & (0xff<<(dst_nibble<<2))); 333936381Ssklower dst_nibble = 1-dst_nibble; 334036381Ssklower dst_octet += dst_nibble; 334136381Ssklower 334236381Ssklower last |= ((*dst_octet) & (0xff<<(dst_nibble << 2))); 334336381Ssklower { 334436381Ssklower /* convert to a decimal number */ 334536381Ssklower register int tens, ones; 334636381Ssklower 334736381Ssklower tens = (last&0xf0)>>4; 334836381Ssklower ones = last&0xf; 334936381Ssklower 335036381Ssklower last = tens * 10 + ones; 335136381Ssklower } 335236381Ssklower 335336381Ssklower IFDEBUG(D_CADDR) 335436381Ssklower printf("unmunge computes 0x%x\n", last); 335536381Ssklower ENDDEBUG 335636381Ssklower if((int)last+1000 >= ISO_PORT_RESERVED) 335736381Ssklower last += 1000; 335836381Ssklower IFDEBUG(D_CADDR) 335936381Ssklower printf("unmunge returns 0x%x\n", last); 336036381Ssklower ENDDEBUG 336136381Ssklower return last; 336236381Ssklower } 336336381Ssklower 336436381Ssklower /* 336536381Ssklower * NAME: make_partial_x25_packet() 336636381Ssklower * 336736381Ssklower * FUNCTION and ARGUMENTS: 336836381Ssklower * Makes part of an X.25 call packet, for use by the eicon board. 336936381Ssklower * (src) and (dst) are the NSAP-addresses of source and destination. 337036381Ssklower * (proto) is the higher-layer protocol number (in iso.h) 337136381Ssklower * (buf) is a ptr to a buffer into which to write this partial header. 337236381Ssklower * 337336381Ssklower * The partial header looks like (choke): 337436381Ssklower * octet meaning 337536381Ssklower * 1 calling DTE len | called DTE len (lengths in nibbles) 337636381Ssklower * 2..n-1 called DTE addr | (<-- boundary may be middle of an octet) 337736381Ssklower * calling DTE addr | zero nibble to round to octet boundary. 337836381Ssklower * n Facility length (in octets) 337936381Ssklower * n+1 Facility field, which is a set of: 338036381Ssklower * m facil code 338136381Ssklower * m+1 facil param len (for >2-byte facilities) in octets 338236381Ssklower * m+2..p facil param field 338336381Ssklower * q user data (protocol identification octet) 338436381Ssklower * 338536381Ssklower * 338636381Ssklower * RETURNS: 338736381Ssklower * 0 if OK 338836381Ssklower * E* if failed. 338936381Ssklower */ 339036381Ssklower 339136381Ssklower #ifdef X25_1984 339236381Ssklower int cons_use_facils = 1; 339336381Ssklower #else X25_1984 339436381Ssklower int cons_use_facils = 0; 339536381Ssklower #endif X25_1984 339636381Ssklower 339736381Ssklower int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */ 339836381Ssklower 339936381Ssklower Static int 340036381Ssklower make_partial_x25_packet(copcb, m) 340136381Ssklower struct cons_pcb *copcb; 340236381Ssklower struct mbuf *m; 340336381Ssklower { 340436381Ssklower struct sockaddr_iso *src, *dst; 340536381Ssklower u_int proto; 340636381Ssklower int flag; 340736381Ssklower caddr_t buf = mtod(m, caddr_t); 340836381Ssklower register caddr_t ptr = buf + 1; /* make room for 2 length nibbles */ 340936381Ssklower register int len = 0; 341036381Ssklower int buflen =0; 341136381Ssklower caddr_t facil_len; 341236381Ssklower int oddness = 0; 341336381Ssklower 341436381Ssklower src = &copcb->co_laddr; 341536381Ssklower dst = &copcb->co_faddr; 341636381Ssklower proto = copcb->co_proto->pr_protocol, 341736381Ssklower flag = copcb->co_flags & CONSF_XTS; 341836381Ssklower 341936381Ssklower 342036381Ssklower IFDEBUG(D_CCONN) 342136381Ssklower printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", 342236381Ssklower src, dst, proto, m, flag); 342336381Ssklower ENDDEBUG 342436381Ssklower 342536381Ssklower /* 342636381Ssklower * Note - order of addrs in x25 pkt hdr is wierd: 342736381Ssklower * calling len/called len/called addr/calling addr (p.40 ISO 8202) 342836381Ssklower */ 342936381Ssklower if( (len = copcb->co_peer_dte.dtea_niblen) > 0 ) { 343036381Ssklower nibble_copy( (char *)(copcb->co_peer_dte.dtea_addr), HIGH_NIBBLE, 343136381Ssklower ptr, HIGH_NIBBLE, len); 343236381Ssklower } else { 343336381Ssklower if ((len = NSAPtoDTE( ptr, HIGH_NIBBLE, dst)) <=0 ) { 343436381Ssklower return E_CO_OSI_UNSAP; 343536381Ssklower } 343636381Ssklower } 343736381Ssklower *buf = len; /* fill in called dte addr length */ 343836381Ssklower ptr += len>>1; /* len is in nibbles */ 343936381Ssklower oddness += len&0x1; 344036381Ssklower 344136381Ssklower if ((len = NSAPtoDTE( ptr, 1-(len&0x1), src)) <=0 ) { 344236381Ssklower return E_CO_OSI_UNSAP; 344336381Ssklower } 344436381Ssklower ptr += len>>1; /* len is in nibbles */ 344536381Ssklower *buf |= len << 4; /* fill in calling dte addr length */ 344636381Ssklower oddness += len&0x1; 344736381Ssklower 344836381Ssklower IFDEBUG(D_CADDR) 344936381Ssklower printf("make_partial 2: ptr 0x%x, len 0x%x oddness 0x%x\n", 345036381Ssklower ptr, len, oddness ); 345136381Ssklower ENDDEBUG 345236381Ssklower /* if either of the addresses were an odd length, the count is off by 1 */ 345336381Ssklower if( oddness ) { 345436381Ssklower ptr ++; 345536381Ssklower } 345636381Ssklower 345736381Ssklower /* ptr now points to facil length (len of whole facil field in OCTETS */ 345836381Ssklower facil_len = ptr ++; 345936381Ssklower 346036381Ssklower IFDEBUG(D_CADDR) 346136381Ssklower printf("make_partial calling: ptr 0x%x, len 0x%x\n", ptr, 346236381Ssklower src->siso_addr.isoa_len); 346336381Ssklower ENDDEBUG 346436381Ssklower if( cons_use_facils ) { 346536381Ssklower *ptr = 0xcb; /* calling facility code */ 346636381Ssklower ptr ++; 346736381Ssklower ptr ++; /* leave room for facil param len (in OCTETS + 1) */ 346836381Ssklower ptr ++; /* leave room for the facil param len (in nibbles), 346936381Ssklower * high two bits of which indicate full/partial NSAP 347036381Ssklower */ 347136381Ssklower len = src->siso_addr.isoa_len; 347236381Ssklower bcopy( &src->siso_addr.isoa_afi, ptr, len); 347336381Ssklower *(ptr-2) = len+2; /* facil param len in octets */ 347436381Ssklower *(ptr-1) = len<<1; /* facil param len in nibbles */ 347536381Ssklower ptr += len; 347636381Ssklower 347736381Ssklower IFDEBUG(D_CADDR) 347836381Ssklower printf("make_partial called: ptr 0x%x, len 0x%x\n", ptr, 347936381Ssklower dst->siso_addr.isoa_len); 348036381Ssklower ENDDEBUG 348136381Ssklower *ptr = 0xc9; /* called facility code */ 348236381Ssklower ptr ++; 348336381Ssklower ptr ++; /* leave room for facil param len (in OCTETS + 1) */ 348436381Ssklower ptr ++; /* leave room for the facil param len (in nibbles), 348536381Ssklower * high two bits of which indicate full/partial NSAP 348636381Ssklower */ 348736381Ssklower len = dst->siso_addr.isoa_len; 348836381Ssklower bcopy( &dst->siso_addr.isoa_afi, ptr, len); 348936381Ssklower *(ptr-2) = len+2; /* facil param len = addr len + 1 for each of these 349036381Ssklower * two length fields, in octets */ 349136381Ssklower *(ptr-1) = len<<1; /* facil param len in nibbles */ 349236381Ssklower ptr += len; 349336381Ssklower 349436381Ssklower } 349536381Ssklower *facil_len = ptr - facil_len - 1; 349636381Ssklower if(*facil_len > X25_FACIL_LEN_MAX ) 349736381Ssklower return E_CO_PNA_LONG; 349836381Ssklower 349936381Ssklower if( cons_use_udata ) { 350036381Ssklower if (copcb->co_x25crud_len > 0) { 350136381Ssklower /* 350236381Ssklower * The user specified something. Stick it in 350336381Ssklower */ 350436381Ssklower bcopy(copcb->co_x25crud, ptr, copcb->co_x25crud_len); 350536381Ssklower ptr += copcb->co_x25crud_len; 350636381Ssklower } else { 350736381Ssklower /* protocol identifier */ 350836381Ssklower switch (proto) { 350936381Ssklower /* unfortunately all are considered 1 protocol */ 351036381Ssklower case ISOPROTO_TP0: 351136381Ssklower case ISOPROTO_TP1: 351236381Ssklower case ISOPROTO_TP2: 351336381Ssklower case ISOPROTO_TP3: 351436381Ssklower case ISOPROTO_TP4: 351536381Ssklower case ISOPROTO_CLTP: 351636381Ssklower /* no user data for TP */ 351736381Ssklower break; 351836381Ssklower 351936381Ssklower case ISOPROTO_CLNP: 352036381Ssklower *ptr = 0x81; 352136381Ssklower ptr++; /* count the proto id byte! */ 352236381Ssklower break; 352336381Ssklower case ISOPROTO_INACT_NL: 352436381Ssklower *ptr = 0x0; 352536381Ssklower ptr++; /* count the proto id byte! */ 352636381Ssklower break; 352736381Ssklower case ISOPROTO_X25: 352836381Ssklower *ptr = 0xff; /* reserved for future extensions */ 352936381Ssklower /* we're stealing this value for local use */ 353036381Ssklower ptr++; /* count the proto id byte! */ 353136381Ssklower break; 353236381Ssklower default: 353336381Ssklower return EPROTONOSUPPORT; 353436381Ssklower } 353536381Ssklower } 353636381Ssklower } 353736381Ssklower 353836381Ssklower buflen = (int)(ptr - buf); 353936381Ssklower 354036381Ssklower IFDEBUG(D_CDUMP_REQ) 354136381Ssklower register int i; 354236381Ssklower 354336381Ssklower printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n", 354436381Ssklower buf, buflen, buflen); 354536381Ssklower for( i=0; i < buflen; ) { 354636381Ssklower printf("+%d: %x %x %x %x %x %x %x %x\n", 354736381Ssklower i, 354836381Ssklower *(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3), 354936381Ssklower *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7)); 355036381Ssklower i+=8; 355136381Ssklower } 355236381Ssklower ENDDEBUG 355336381Ssklower IFDEBUG(D_CADDR) 355436381Ssklower printf("make_partial returns buf 0x%x size 0x%x bytes\n", 355536381Ssklower mtod(m, caddr_t), buflen); 355636381Ssklower ENDDEBUG 355736381Ssklower 355836381Ssklower ASSERT( X25_PARTIAL_PKT_LEN_MAX < MLEN ); 355936381Ssklower 356036381Ssklower if(buflen > X25_PARTIAL_PKT_LEN_MAX) 356136381Ssklower return E_CO_PNA_LONG; 356236381Ssklower 356336381Ssklower m->m_len = buflen; 356436381Ssklower return 0; 356536381Ssklower } 356636381Ssklower 356736381Ssklower /* 356836381Ssklower * NAME: NSAPtoDTE() 356936381Ssklower * CALLED FROM: 357036381Ssklower * make_partial_x25_packet() 357136381Ssklower * FUNCTION and ARGUMENTS: 357236381Ssklower * get a DTE address from an NSAP-address (struct sockaddr_iso) 357336381Ssklower * (dst_octet) is the octet into which to begin stashing the DTE addr 357436381Ssklower * (dst_nibble) takes 0 or 1. 1 means begin filling in the DTE addr 357536381Ssklower * in the high-order nibble of dst_octet. 0 means low-order nibble. 357636381Ssklower * (addr) is the NSAP-address 357736381Ssklower * (flag) is true if the transport suffix is to become the 357836381Ssklower * last two digits of the DTE address 357936381Ssklower * A DTE address is a series of BCD digits 358036381Ssklower * 358136381Ssklower * A DTE address may have leading zeros. The are significant. 358236381Ssklower * 1 digit per nibble, may be an odd number of nibbles. 358336381Ssklower * 358436381Ssklower * An NSAP-address has the DTE address in the IDI. Leading zeros are 358536381Ssklower * significant. Trailing hex f indicates the end of the DTE address. 358636381Ssklower * Also is a series of BCD digits, one per nibble. 358736381Ssklower * 358836381Ssklower * RETURNS 358936381Ssklower * # significant digits in the DTE address, -1 if error. 359036381Ssklower */ 359136381Ssklower 359236381Ssklower Static int 359336381Ssklower NSAPtoDTE( dst_octet, dst_nibble, addr) 359436381Ssklower caddr_t dst_octet; 359536381Ssklower int dst_nibble; 359636381Ssklower register struct sockaddr_iso *addr; 359736381Ssklower { 359836381Ssklower int error; 359936381Ssklower u_char x121string[7]; /* maximum is 14 digits */ 360036381Ssklower int x121strlen; 360136381Ssklower struct dte_addr *dtea; 360236381Ssklower 360336381Ssklower IFDEBUG(D_CADDR) 360436381Ssklower printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&addr->siso_addr)); 360536381Ssklower ENDDEBUG 360636381Ssklower 360736381Ssklower error = iso_8208snparesolve(addr, x121string, &x121strlen); 360836381Ssklower ASSERT(error == 0); 360936381Ssklower if( error != 0 ) { 361036381Ssklower /* no snpa - cannot send */ 361136381Ssklower IFDEBUG(D_CADDR) 361236381Ssklower printf("NSAPtoDTE: 8208resolve: %d\n", error ); 361336381Ssklower ENDDEBUG 361436381Ssklower return 0; 361536381Ssklower } 361636381Ssklower ASSERT(x121strlen == sizeof(struct dte_addr)); 361736381Ssklower dtea = (struct dte_addr *)x121string; 361836381Ssklower x121strlen = dtea->dtea_niblen; 361936381Ssklower 362036381Ssklower nibble_copy((char *)x121string, HIGH_NIBBLE, 362136381Ssklower dst_octet, dst_nibble, x121strlen); 362236381Ssklower return x121strlen; 362336381Ssklower } 362436381Ssklower 362536381Ssklower /* 362636381Ssklower * NAME: FACILtoNSAP() 362736381Ssklower * CALLED FROM: 362836381Ssklower * parse_facil() 362936381Ssklower * FUNCTION and ARGUMENTS: 363036381Ssklower * Creates and NSAP in the sockaddr_iso (addr) from the 363136381Ssklower * x.25 facility found at (buf), of length (buf_len). 363236381Ssklower * RETURNS: 363336381Ssklower * 0 if ok, non-zero if error; 363436381Ssklower */ 363536381Ssklower 363636381Ssklower Static int 363736381Ssklower FACILtoNSAP( buf, buf_len, addr) 363836381Ssklower caddr_t buf; 363936381Ssklower u_char buf_len; /* in bytes */ 364036381Ssklower register struct sockaddr_iso *addr; 364136381Ssklower { 364236381Ssklower int len_in_nibbles; 364336381Ssklower 364436381Ssklower IFDEBUG(D_CADDR) 364536381Ssklower printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n", 364636381Ssklower buf, buf_len, addr ); 364736381Ssklower ENDDEBUG 364836381Ssklower 364936381Ssklower len_in_nibbles = *buf; 365036381Ssklower /* despite the fact that X.25 makes us put a length in nibbles 365136381Ssklower * here, the NSAP-addrs are always in full octets 365236381Ssklower */ 365336381Ssklower buf ++; 365436381Ssklower 365536381Ssklower bzero( addr, sizeof (struct sockaddr_iso) ); 365636381Ssklower 365736381Ssklower ASSERT(buf_len <= 1+sizeof (struct iso_addr)); 365836381Ssklower if(buf_len > 1+sizeof (struct iso_addr)) { 365936381Ssklower return -1; /* error */ 366036381Ssklower } 366136381Ssklower ASSERT(len_in_nibbles == (buf_len - 1)<<1); 366236381Ssklower if(len_in_nibbles != (buf_len - 1)<<1) { 366336381Ssklower return -2; /* error */ 366436381Ssklower } 366536381Ssklower bcopy(buf, &addr->siso_addr.isoa_afi, buf_len-1); 366636381Ssklower addr->siso_addr.isoa_len = buf_len-1; 366736381Ssklower IFDEBUG(D_CADDR) 366836381Ssklower printf("FACILtoNSAP: isoa_len 0x%x\n", 366936381Ssklower addr->siso_addr.isoa_len); 367036381Ssklower ENDDEBUG 367136381Ssklower addr->siso_family = AF_ISO; 367236381Ssklower 367336381Ssklower addr->siso_tsuffix = 367436381Ssklower unmunge( ((caddr_t)&addr->siso_addr.t37_idi) + ADDR37_IDI_LEN , 1 ); 367536381Ssklower return 0; 367636381Ssklower } 367736381Ssklower 367836381Ssklower /* 367936381Ssklower * NAME: DTEtoNSAP() 368036381Ssklower * CALLED FROM: 368136381Ssklower * parse_facil() 368236381Ssklower * FUNCTION and ARGUMENTS: 368336381Ssklower * Creates a type 37 NSAP in the sockaddr_iso (addr) 368436381Ssklower * from a DTE address found at the (src_nibble)th nibble of 368536381Ssklower * the octet (src_octet), of length (src_nib_len). 368636381Ssklower * 368736381Ssklower * RETURNS: 368836381Ssklower * 0 if ok; E* otherwise. 368936381Ssklower */ 369036381Ssklower 369136381Ssklower Static int 369236381Ssklower DTEtoNSAP(addr, src_octet, src_nibble, src_nib_len) 369336381Ssklower struct sockaddr_iso *addr; 369436381Ssklower caddr_t src_octet; 369536381Ssklower int src_nibble, src_nib_len; 369636381Ssklower { 369736381Ssklower caddr_t dst_octet; 369836381Ssklower int pad_len; 369936381Ssklower int dst_nibble; 370036381Ssklower char first_nib; 370136381Ssklower static char *z_pad = "\0\0\0\0\0\0\0"; 370236381Ssklower static char *f_pad = "\021\021\021\021\021\021\021"; 370336381Ssklower 370436381Ssklower IFDEBUG(D_CADDR) 370536381Ssklower printf("DTEtoNSAP( 0x%x, 0x%x, 0x%x, 0x%x )\n", 370636381Ssklower src_octet, src_nibble, src_nib_len, addr ); 370736381Ssklower ENDDEBUG 370836381Ssklower 370936381Ssklower bzero( addr, sizeof(*addr)); 371036381Ssklower addr->siso_family = AF_ISO; 371136381Ssklower /* 371236381Ssklower * Coming from a DTE addr it's always type 37. 371336381Ssklower * src_octet <-- starting place in the NSAP-address of 371436381Ssklower * the embedded SNPA-address (x.121 addr or DTE addr). 371536381Ssklower */ 371636381Ssklower addr->siso_addr.isoa_afi = 0x37; 371736381Ssklower 371836381Ssklower /* first, figure out what pad to use and pad */ 371936381Ssklower 372036381Ssklower first_nib = (*src_octet) >> (SHIFT*(1-src_nibble)); 372136381Ssklower pad_len = (ADDR37_IDI_LEN<<1 - src_nib_len); 372236381Ssklower nibble_copy(first_nib? z_pad : f_pad, HIGH_NIBBLE, 372336381Ssklower (caddr_t) addr->siso_addr.t37_idi, HIGH_NIBBLE, pad_len); 372436381Ssklower 372536381Ssklower dst_octet += (pad_len>>1); 372636381Ssklower dst_nibble = 1-(pad_len & 0x1); 372736381Ssklower IFDEBUG(D_CADDR) 372836381Ssklower printf("DTEtoNSAP 2( 0x%x, 0x%x, 0x%x, 0x%x )\n", 372936381Ssklower dst_octet, dst_nibble, pad_len, src_nib_len ); 373036381Ssklower ENDDEBUG 373136381Ssklower 373236381Ssklower /* now copy the dte address */ 373336381Ssklower nibble_copy( src_octet, src_nibble, dst_octet, dst_nibble, src_nib_len); 373436381Ssklower 373536381Ssklower addr->siso_addr.isoa_len = ADDR37_IDI_LEN + ADDR37_DSP_LEN +1 /* for afi */; 373636381Ssklower /* kludge */ 373736381Ssklower 373836381Ssklower addr->siso_tsuffix = unmunge( 373936381Ssklower (caddr_t) &(addr->siso_addr.t37_idi[ADDR37_IDI_LEN]), HIGH_NIBBLE); 374036381Ssklower 374136381Ssklower IFDEBUG(D_CADDR) 374236381Ssklower printf("DTEtoNSAP 3 returning 0 tsuffix 0x%x\n", addr->siso_tsuffix); 374336381Ssklower ENDDEBUG 374436381Ssklower 374536381Ssklower return 0; /* ok */ 374636381Ssklower } 374736381Ssklower 374836381Ssklower /* 374936381Ssklower * FUNCTION and ARGUMENTS: 375036381Ssklower * parses (buf_len) bytes beginning at (buf) and finds 375136381Ssklower * a called nsap, a calling nsap, and protocol identifier. 375236381Ssklower * RETURNS: 375336381Ssklower * 0 if ok, E* otherwise. 375436381Ssklower */ 375536381Ssklower 375636381Ssklower Static int 375736381Ssklower parse_facil( buf, buf_len, called, calling, proto, peer_dte) 375836381Ssklower caddr_t buf; 375936381Ssklower u_char buf_len; /* in bytes */ 376036381Ssklower register struct sockaddr_iso *called, *calling; 376136381Ssklower int *proto; 376236381Ssklower struct dte_addr *peer_dte; 376336381Ssklower { 376436381Ssklower register int i; 376536381Ssklower caddr_t ptr; 376636381Ssklower caddr_t facil_len; 376736381Ssklower int facil_param_len; 376836381Ssklower struct sockaddr_iso *addr; 376936381Ssklower int addrs_not_parsed = (int)0xcb + (int)0xc9; 377036381Ssklower 377136381Ssklower IFDEBUG(D_CADDR) 377236381Ssklower printf("parse_facil( 0x%x, 0x%x, 0x%x, 0x%x, 0x%x )\n", 377336381Ssklower buf, buf_len, called, calling, *proto); 377436381Ssklower dump_buf(buf, buf_len); 377536381Ssklower ENDDEBUG 377636381Ssklower 377736381Ssklower /* find the beginnings of the facility fields in buf 377836381Ssklower * by skipping over the called & calling DTE addresses 377936381Ssklower * i <- # nibbles in called + # nibbles in calling 378036381Ssklower * i += 1 so that an odd nibble gets rounded up to even 378136381Ssklower * before dividing by 2, then divide by two to get # octets 378236381Ssklower */ 378336381Ssklower i = (int)(*buf >> 4) + (int)(*buf&0xf); 378436381Ssklower i++; 378536381Ssklower ptr = (caddr_t) (buf + (i>>1)); 378636381Ssklower /* now i is number of octets */ 378736381Ssklower 378836381Ssklower ptr ++; /* plus one for the DTE lengths byte */ 378936381Ssklower 379036381Ssklower /* ptr now is at facil_length field */ 379136381Ssklower facil_len = ptr++; 379236381Ssklower IFDEBUG(D_CADDR) 379336381Ssklower printf("parse_facils: facil length is 0x%x\n", (int) *facil_len); 379436381Ssklower ENDDEBUG 379536381Ssklower 379636381Ssklower while( ptr <= (caddr_t)(facil_len + (int)*facil_len) ) { 379736381Ssklower /* get NSAP addresses from facilities */ 379836381Ssklower switch (*ptr) { 379936381Ssklower case 0xcb: 380036381Ssklower facil_param_len = 0; 380136381Ssklower addr = calling; 380236381Ssklower addrs_not_parsed -= 0xcb; 380336381Ssklower break; 380436381Ssklower case 0xc9: 380536381Ssklower facil_param_len = 0; 380636381Ssklower addr = called; 380736381Ssklower addrs_not_parsed -= 0xc9; 380836381Ssklower break; 380936381Ssklower 381036381Ssklower /* from here to default are legit cases that I ignore */ 381136381Ssklower 381236381Ssklower /* variable length */ 381336381Ssklower case 0xca: /* end-to-end transit delay negot */ 381436381Ssklower case 0xc6: /* network user id */ 381536381Ssklower case 0xc5: /* charging info : indicating monetary unit */ 381636381Ssklower case 0xc2: /* charging info : indicating segment count */ 381736381Ssklower case 0xc1: /* charging info : indicating call duration */ 381836381Ssklower case 0xc4: /* RPOA extended format */ 381936381Ssklower case 0xc3: /* call redirection notification */ 382036381Ssklower facil_param_len = 0; 382136381Ssklower addr = (struct sockaddr_iso *)0; 382236381Ssklower break; 382336381Ssklower 382436381Ssklower /* 1 octet */ 382536381Ssklower case 0x0a: /* min. throughput class negot */ 382636381Ssklower case 0x02: /* throughput class */ 382736381Ssklower case 0x03: case 0x47: /* CUG shit */ 382836381Ssklower case 0x0b: /* expedited data negot */ 382936381Ssklower case 0x01: /* Fast select or reverse charging 383036381Ssklower (example of intelligent protocol design) */ 383136381Ssklower case 0x04: /* charging info : requesting service */ 383236381Ssklower case 0x08: /* called line addr modified notification */ 383336381Ssklower facil_param_len = 1; 383436381Ssklower addr = (struct sockaddr_iso *)0; 383536381Ssklower break; 383636381Ssklower 383736381Ssklower /* any 2 octets */ 383836381Ssklower case 0x42: /* pkt size */ 383936381Ssklower case 0x43: /* win size */ 384036381Ssklower case 0x44: /* RPOA basic format */ 384136381Ssklower case 0x41: /* bilateral CUG shit */ 384236381Ssklower case 0x49: /* transit delay selection and indication */ 384336381Ssklower facil_param_len = 2; 384436381Ssklower addr = (struct sockaddr_iso *)0; 384536381Ssklower break; 384636381Ssklower 384736381Ssklower /* don't have any 3 octets */ 384836381Ssklower /* 384936381Ssklower facil_param_len = 3; 385036381Ssklower */ 385136381Ssklower default: 385236381Ssklower ASSERT(0); 385336381Ssklower printf( 385436381Ssklower "BOGUS FACILITY CODE facil_len 0x%x *facil_len 0x%x, ptr 0x%x *ptr 0x%x\n", 385536381Ssklower facil_len, *facil_len, 385636381Ssklower ptr, *ptr); 385736381Ssklower addr = (struct sockaddr_iso *)0; 385836381Ssklower /* facil that we don't handle */ 385936381Ssklower return E_CO_HLI_REJI; 386036381Ssklower } 386136381Ssklower ptr++; /* one for facil code */ 386236381Ssklower if(facil_param_len == 0) /* variable length */ 386336381Ssklower facil_param_len = (int)*ptr; /* 1 + the real facil param */ 386436381Ssklower if( addr && FACILtoNSAP(ptr+1, facil_param_len-1, addr) ) { 386536381Ssklower return E_CO_OSI_UNSAP; 386636381Ssklower } 386736381Ssklower ptr += facil_param_len; 386836381Ssklower } 386936381Ssklower if( addrs_not_parsed ) { 387036381Ssklower /* no facilities, get NSAP addresses from DTE addresses */ 387136381Ssklower register int ed, ing; 387236381Ssklower 387336381Ssklower ed = (int)(*buf&0xf); 387436381Ssklower if( ed == 0 ) { 387536381Ssklower panic("Called DTE address absent"); 387636381Ssklower } 387736381Ssklower DTEtoNSAP(called, (buf + 1)/*octet*/, 387836381Ssklower 1/*nibble*/, ed); 387936381Ssklower 388036381Ssklower ing = (int)(*buf >> 4); 388136381Ssklower if( ing == 0 ) { 388236381Ssklower printf("cons: panic: Calling DTE address absent"); 388336381Ssklower return E_CO_HLI_REJI; 388436381Ssklower } 388536381Ssklower nibble_copy((buf + (ed>>1)+1)/*octet*/, 1-(ed&0x1)/*nibble*/, 388636381Ssklower peer_dte->dtea_addr, HIGH_NIBBLE, ing); 388736381Ssklower DTEtoNSAP(calling, (buf + (ed>>1)+1)/*octet*/, 388836381Ssklower 1-(ed&0x1)/*nibble*/, ing); 388936381Ssklower 389036381Ssklower } 389136381Ssklower 389236381Ssklower ASSERT( ptr == (caddr_t)(facil_len + 1 + (int)*facil_len) ); 389336381Ssklower 389436381Ssklower /* 389536381Ssklower * now look for user data to find protocol identifier 389636381Ssklower */ 389736381Ssklower if( ptr == buf + buf_len ) { 389836381Ssklower /* no user data */ 389936381Ssklower *proto = ISOPROTO_TP; /* to proto id --> use TP */ 390036381Ssklower IFDEBUG(D_CADDR) 390136381Ssklower printf("NO USER DATA: use TP\n"); 390236381Ssklower ENDDEBUG 390336381Ssklower } else { 390436381Ssklower ASSERT ( ptr < buf + buf_len ); 390536381Ssklower if ( ptr >= buf + buf_len ) { 390636381Ssklower printf("ptr 0x%x buf 0x%x buf_len 0x%x buf+buf_len 0x%x\n", 390736381Ssklower ptr, buf, buf_len, buf+buf_len); 390836381Ssklower } 390936381Ssklower IFDEBUG(D_CADDR) 391036381Ssklower printf("proto byte 0x%x, value 0x%x\n", ptr, *ptr); 391136381Ssklower ENDDEBUG 391236381Ssklower switch(*ptr) { 391336381Ssklower case 0x81: 391436381Ssklower *proto = ISOPROTO_CLNP; 391536381Ssklower break; 391636381Ssklower case 0x0: 391736381Ssklower *proto = ISOPROTO_INACT_NL; 391836381Ssklower break; 391936381Ssklower case 'e': /* for EAN */ 392036381Ssklower *proto = ISOPROTO_TP; 392136381Ssklower /* can check for "an2" or can ignore the rest of the u data */ 392236381Ssklower break; 392336381Ssklower case 0xff: /* reserved for future extensions */ 392436381Ssklower *proto = ISOPROTO_X25; 392536381Ssklower break; 392636381Ssklower case 0x82: /* 9542 not implemented */ 392736381Ssklower case 0x84: /* 8878/A SNDCP not implemented */ 392836381Ssklower default: 392936381Ssklower *proto = -1; 393036381Ssklower return E_CO_HLI_PROTOID; 393136381Ssklower } 393236381Ssklower } 393336381Ssklower return 0; 393436381Ssklower } 393536381Ssklower 393636381Ssklower #endif NARGOXTWENTYFIVE > 0 3937