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