149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*56533Sbostic * @(#)if_cons.c 7.12 (Berkeley) 10/11/92 849268Sbostic */ 949268Sbostic 1036381Ssklower /*********************************************************** 1136381Ssklower Copyright IBM Corporation 1987 1236381Ssklower 1336381Ssklower All Rights Reserved 1436381Ssklower 1536381Ssklower Permission to use, copy, modify, and distribute this software and its 1636381Ssklower documentation for any purpose and without fee is hereby granted, 1736381Ssklower provided that the above copyright notice appear in all copies and that 1836381Ssklower both that copyright notice and this permission notice appear in 1936381Ssklower supporting documentation, and that the name of IBM not be 2036381Ssklower used in advertising or publicity pertaining to distribution of the 2136381Ssklower software without specific, written prior permission. 2236381Ssklower 2336381Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 2436381Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 2536381Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 2636381Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 2736381Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2836381Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2936381Ssklower SOFTWARE. 3036381Ssklower 3136381Ssklower ******************************************************************/ 3236381Ssklower 3336381Ssklower /* 3436381Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 3536381Ssklower */ 3636381Ssklower /* 3736381Ssklower * $Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $ 3836381Ssklower * $Source: /usr/argo/sys/netiso/RCS/if_cons.c,v $ 3936381Ssklower * 4036381Ssklower * cons.c - Connection Oriented Network Service: 4136381Ssklower * including support for a) user transport-level service, 4236381Ssklower * b) COSNS below CLNP, and c) CONS below TP. 4345899Ssklower */ 4436381Ssklower 4545899Ssklower #ifdef TPCONS 4645899Ssklower #ifdef KERNEL 4736381Ssklower #ifdef ARGO_DEBUG 4836381Ssklower #define Static 4936381Ssklower unsigned LAST_CALL_PCB; 5036381Ssklower #else ARGO_DEBUG 5136381Ssklower #define Static static 5236381Ssklower #endif ARGO_DEBUG 5336381Ssklower 5445899Ssklower #ifndef SOCK_STREAM 55*56533Sbostic #include <sys/param.h> 56*56533Sbostic #include <sys/systm.h> 57*56533Sbostic #include <sys/mbuf.h> 58*56533Sbostic #include <sys/protosw.h> 59*56533Sbostic #include <sys/socket.h> 60*56533Sbostic #include <sys/socketvar.h> 61*56533Sbostic #include <sys/errno.h> 62*56533Sbostic #include <sys/ioctl.h> 63*56533Sbostic #include <sys/tsleep.h> 6436381Ssklower 65*56533Sbostic #include <net/if.h> 66*56533Sbostic #include <net/netisr.h> 67*56533Sbostic #include <net/route.h> 6836381Ssklower 69*56533Sbostic #include <netiso/iso_errno.h> 70*56533Sbostic #include <netiso/argo_debug.h> 71*56533Sbostic #include <netiso/tp_trace.h> 72*56533Sbostic #include <netiso/iso.h> 73*56533Sbostic #include <netiso/cons.h> 74*56533Sbostic #include <netiso/iso_pcb.h> 7536381Ssklower 76*56533Sbostic #include <netccitt/x25.h> 77*56533Sbostic #include <netccitt/pk.h> 78*56533Sbostic #include <netccitt/pk_var.h> 7945899Ssklower #endif 8045899Ssklower 8136381Ssklower #ifdef ARGO_DEBUG 8236381Ssklower #define MT_XCONN 0x50 8336381Ssklower #define MT_XCLOSE 0x51 8436381Ssklower #define MT_XCONFIRM 0x52 8536381Ssklower #define MT_XDATA 0x53 8636381Ssklower #define MT_XHEADER 0x54 8736381Ssklower #else 8836381Ssklower #define MT_XCONN MT_DATA 8936381Ssklower #define MT_XCLOSE MT_DATA 9036381Ssklower #define MT_XCONFIRM MT_DATA 9136381Ssklower #define MT_XDATA MT_DATA 9236381Ssklower #define MT_XHEADER MT_HEADER 9336381Ssklower #endif ARGO_DEBUG 9436381Ssklower 9536381Ssklower #define DONTCLEAR -1 9636381Ssklower 9736381Ssklower /********************************************************************* 9845899Ssklower * cons.c - CONS interface to the x.25 layer 9936381Ssklower * 10036381Ssklower * TODO: figure out what resources we might run out of besides mbufs. 10136381Ssklower * If we run out of any of them (including mbufs) close and recycle 10236381Ssklower * lru x% of the connections, for some parameter x. 10336381Ssklower * 10445899Ssklower * There are 2 interfaces from above: 10536381Ssklower * 1) from TP0: 10636381Ssklower * cons CO network service 10736381Ssklower * TP associates a transport connection with a network connection. 10836381Ssklower * cons_output( isop, m, len, isdgm==0 ) 10936381Ssklower * co_flags == 0 11045899Ssklower * 2) from TP4: 11136381Ssklower * It's a datagram service, like clnp is. - even though it calls 11236381Ssklower * cons_output( isop, m, len, isdgm==1 ) 11336381Ssklower * it eventually goes through 11436381Ssklower * cosns_output(ifp, m, dst). 11536381Ssklower * TP4 permits multiplexing (reuse, possibly simultaneously) of the 11636381Ssklower * network connections. 11736381Ssklower * This means that many sockets (many tpcbs) may be associated with 11845899Ssklower * this pklcd, hence cannot have a back ptr from pklcd to a tpcb. 11936381Ssklower * co_flags & CONSF_DGM 12045899Ssklower * co_socket is null since there may be many sockets that use this pklcd. 12136381Ssklower * 12236381Ssklower NOTE: 12336381Ssklower streams would really be nice. sigh. 12436381Ssklower NOTE: 12536381Ssklower PVCs could be handled by config-ing a cons with an address and with the 12636381Ssklower IFF_POINTTOPOINT flag on. This code would then have to skip the 12736381Ssklower connection setup stuff for pt-to-pt links. 12836381Ssklower 12936381Ssklower 13036381Ssklower *********************************************************************/ 13136381Ssklower 13236381Ssklower 13336381Ssklower #define CONS_IFQMAXLEN 5 13436381Ssklower 13536381Ssklower 13636381Ssklower /* protosw pointers for getting to higher layer */ 13736381Ssklower Static struct protosw *CLNP_proto; 13836381Ssklower Static struct protosw *TP_proto; 13936381Ssklower Static struct protosw *X25_proto; 14036381Ssklower Static int issue_clear_req(); 14136381Ssklower 14236381Ssklower #ifndef PHASEONE 14336381Ssklower extern struct ifaddr *ifa_ifwithnet(); 14436381Ssklower #endif PHASEONE 14536381Ssklower 14636381Ssklower extern struct ifaddr *ifa_ifwithaddr(); 14736381Ssklower 14836381Ssklower extern struct isopcb tp_isopcb; /* chain of all TP pcbs */ 14936381Ssklower 15036381Ssklower 15136381Ssklower Static int parse_facil(), NSAPtoDTE(), make_partial_x25_packet(); 15236381Ssklower Static int FACILtoNSAP(), DTEtoNSAP(); 15345899Ssklower Static struct pklcd *cons_chan_to_pcb(); 15436381Ssklower 15536381Ssklower #define HIGH_NIBBLE 1 15636381Ssklower #define LOW_NIBBLE 0 15736381Ssklower 15836381Ssklower /* 15936381Ssklower * NAME: nibble_copy() 16036381Ssklower * FUNCTION and ARGUMENTS: 16136381Ssklower * copies (len) nibbles from (src_octet), high or low nibble 16236381Ssklower * to (dst_octet), high or low nibble, 16336381Ssklower * src_nibble & dst_nibble should be: 16436381Ssklower * HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble 16536381Ssklower * LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble 16636381Ssklower * RETURNS: VOID 16736381Ssklower */ 16836381Ssklower void 16945899Ssklower nibble_copy(src_octet, src_nibble, dst_octet, dst_nibble, len) 17036381Ssklower register char *src_octet; 17136381Ssklower register char *dst_octet; 17236381Ssklower register unsigned src_nibble; 17336381Ssklower register unsigned dst_nibble; 17436381Ssklower int len; 17536381Ssklower { 17636381Ssklower 17736381Ssklower register i; 17836381Ssklower register unsigned dshift, sshift; 17936381Ssklower 18036381Ssklower IFDEBUG(D_CADDR) 18136381Ssklower printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", 18236381Ssklower src_octet, src_nibble, dst_octet, dst_nibble, len); 18336381Ssklower ENDDEBUG 18436381Ssklower #define SHIFT 0x4 18536381Ssklower 18636381Ssklower dshift = dst_nibble << 2; 18736381Ssklower sshift = src_nibble << 2; 18836381Ssklower 18936381Ssklower for (i=0; i<len; i++) { 19036381Ssklower /* clear dst_nibble */ 19136381Ssklower *dst_octet &= ~(0xf<< dshift); 19236381Ssklower 19336381Ssklower /* set dst nibble */ 19436381Ssklower *dst_octet |= ( 0xf & (*src_octet >> sshift))<< dshift; 19536381Ssklower 19636381Ssklower dshift ^= SHIFT; 19736381Ssklower sshift ^= SHIFT; 19836381Ssklower src_nibble = 1-src_nibble; 19936381Ssklower dst_nibble = 1-dst_nibble; 20036381Ssklower src_octet += src_nibble; 20136381Ssklower dst_octet += dst_nibble; 20236381Ssklower } 20336381Ssklower IFDEBUG(D_CADDR) 20436381Ssklower printf("nibble_copy DONE\n"); 20536381Ssklower ENDDEBUG 20636381Ssklower } 20736381Ssklower 20836381Ssklower /* 20936381Ssklower * NAME: nibble_match() 21036381Ssklower * FUNCTION and ARGUMENTS: 21136381Ssklower * compares src_octet/src_nibble and dst_octet/dst_nibble for len nibbles. 21236381Ssklower * RETURNS: 0 if they differ, 1 if they are the same. 21336381Ssklower */ 21436381Ssklower int 21536381Ssklower nibble_match( 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 u_char nibble_a, nibble_b; 22636381Ssklower 22736381Ssklower IFDEBUG(D_CADDR) 22836381Ssklower printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", 22936381Ssklower src_octet, src_nibble, dst_octet, dst_nibble, len); 23036381Ssklower ENDDEBUG 23136381Ssklower #define SHIFT 0x4 23236381Ssklower 23336381Ssklower dshift = dst_nibble << 2; 23436381Ssklower sshift = src_nibble << 2; 23536381Ssklower 23636381Ssklower for (i=0; i<len; i++) { 23736381Ssklower nibble_b = ((*dst_octet)>>dshift) & 0xf; 23836381Ssklower nibble_a = ( 0xf & (*src_octet >> sshift)); 23945899Ssklower if (nibble_b != nibble_a) 24036381Ssklower return 0; 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_match DONE\n"); 25136381Ssklower ENDDEBUG 25236381Ssklower return 1; 25336381Ssklower } 25436381Ssklower 25536381Ssklower /* 25636381Ssklower **************************** NET PROTOCOL cons *************************** 25736381Ssklower */ 25836381Ssklower /* 25936381Ssklower * NAME: cons_init() 26036381Ssklower * CALLED FROM: 26136381Ssklower * autoconf 26236381Ssklower * FUNCTION: 26336381Ssklower * initialize the protocol 26436381Ssklower */ 26536381Ssklower cons_init() 26636381Ssklower { 26745899Ssklower int tp_incoming(), clnp_incoming(); 26836381Ssklower 26936381Ssklower 27036381Ssklower CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM); 27136381Ssklower X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM); 27236381Ssklower TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET); 27336381Ssklower IFDEBUG(D_CCONS) 27436381Ssklower printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n", 27536381Ssklower CLNP_proto, X25_proto, TP_proto); 27636381Ssklower ENDDEBUG 27745899Ssklower #ifdef notdef 27845899Ssklower pk_protolisten(0x81, 0, clnp_incoming); 27945899Ssklower pk_protolisten(0x82, 0, esis_incoming); 28045899Ssklower pk_protolisten(0x84, 0, tp8878_A_incoming); 28149041Ssklower pk_protolisten(0, 0, tp_incoming); 28245899Ssklower #endif 28336381Ssklower } 28436381Ssklower 28549937Ssklower tp_incoming(lcp, m) 28645899Ssklower struct pklcd *lcp; 28749937Ssklower register struct mbuf *m; 28836381Ssklower { 28945899Ssklower register struct isopcb *isop; 29045899Ssklower int cons_tpinput(); 29136381Ssklower 29250648Ssklower if (iso_pcballoc((struct socket *)0, &tp_isopcb)) { 29349937Ssklower pk_close(lcp); 29445899Ssklower return; 29536381Ssklower } 29650648Ssklower isop = tp_isopcb.isop_next; 29745899Ssklower lcp->lcd_upper = cons_tpinput; 29845899Ssklower lcp->lcd_upnext = (caddr_t)isop; 29949937Ssklower lcp->lcd_send(lcp); /* Confirms call */ 30045899Ssklower isop->isop_chan = (caddr_t)lcp; 30145899Ssklower isop->isop_laddr = &isop->isop_sladdr; 30245899Ssklower isop->isop_faddr = &isop->isop_sfaddr; 30345899Ssklower DTEtoNSAP(isop->isop_laddr, &lcp->lcd_laddr); 30445899Ssklower DTEtoNSAP(isop->isop_faddr, &lcp->lcd_faddr); 30550648Ssklower parse_facil(lcp, isop, &(mtod(m, struct x25_packet *)->packet_data), 30645899Ssklower m->m_pkthdr.len - PKHEADERLN); 30736381Ssklower } 30836381Ssklower 30945899Ssklower cons_tpinput(lcp, m0) 31045899Ssklower struct mbuf *m0; 31145899Ssklower struct pklcd *lcp; 31236381Ssklower { 31345899Ssklower register struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext; 31445899Ssklower register struct x25_packet *xp; 31550648Ssklower int cmd, ptype = CLEAR; 31636381Ssklower 31749265Ssklower if (isop == 0) 31849265Ssklower return; 31950648Ssklower if (m0 == 0) 32049041Ssklower goto dead; 32145899Ssklower switch(m0->m_type) { 32245899Ssklower case MT_DATA: 32345899Ssklower case MT_OOBDATA: 32450648Ssklower tpcons_input(m0, isop->isop_faddr, isop->isop_laddr, (caddr_t)lcp); 32549584Ssklower return; 32636381Ssklower 32745899Ssklower case MT_CONTROL: 32850648Ssklower switch (ptype = pk_decode(mtod(m0, struct x25_packet *))) { 32936381Ssklower 33045899Ssklower case RR: 33145899Ssklower cmd = PRC_CONS_SEND_DONE; 33245899Ssklower break; 33336381Ssklower 33449265Ssklower case CALL_ACCEPTED: 33549265Ssklower if (lcp->lcd_sb.sb_mb) 33649265Ssklower lcp->lcd_send(lcp); /* XXX - fix this */ 33749584Ssklower /*FALLTHROUGH*/ 33849584Ssklower default: 33949584Ssklower return; 34049265Ssklower 34149041Ssklower dead: 34249041Ssklower case CLEAR: 34349041Ssklower case CLEAR_CONF: 34450648Ssklower lcp->lcd_upper = 0; 34550648Ssklower lcp->lcd_upnext = 0; 34650648Ssklower isop->isop_chan = 0; 34750648Ssklower case RESET: 34845899Ssklower cmd = PRC_ROUTEDEAD; 34936381Ssklower } 35045899Ssklower tpcons_ctlinput(cmd, isop->isop_faddr, isop); 35150648Ssklower if (cmd = PRC_ROUTEDEAD && isop->isop_refcnt == 0) 35250648Ssklower iso_pcbdetach(isop); 35336381Ssklower } 35436381Ssklower } 35536381Ssklower 35636381Ssklower /* 35736381Ssklower * NAME: cons_connect() 35836381Ssklower * CALLED FROM: 35945899Ssklower * tpcons_pcbconnect() when opening a new connection. 36036381Ssklower * FUNCTION anD ARGUMENTS: 36136381Ssklower * Figures out which device to use, finding a route if one doesn't 36236381Ssklower * already exist. 36336381Ssklower * RETURN VALUE: 36436381Ssklower * returns E* 36536381Ssklower */ 36645899Ssklower cons_connect(isop) 36745899Ssklower register struct isopcb *isop; 36836381Ssklower { 36945899Ssklower register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 37036381Ssklower register struct mbuf *m; 37136381Ssklower struct ifaddr *ifa; 37249937Ssklower int error; 37336381Ssklower 37436381Ssklower IFDEBUG(D_CCONN) 37545899Ssklower printf("cons_connect(0x%x): ", isop); 37645899Ssklower dump_isoaddr(isop->isop_faddr); 37745899Ssklower printf("myaddr: "); 37845899Ssklower dump_isoaddr(isop->isop_laddr); 37936381Ssklower printf("\n" ); 38036381Ssklower ENDDEBUG 38145899Ssklower NSAPtoDTE(isop->isop_faddr, &lcp->lcd_faddr); 38249265Ssklower lcp->lcd_upper = cons_tpinput; 38349265Ssklower lcp->lcd_upnext = (caddr_t)isop; 38436381Ssklower IFDEBUG(D_CCONN) 38536381Ssklower printf( 38645899Ssklower "calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x)\n", 38745899Ssklower &lcp->lcd_faddr, &lcp->lcd_laddr, 38845899Ssklower isop->isop_socket->so_proto->pr_protocol); 38936381Ssklower ENDDEBUG 39049937Ssklower if ((error = make_partial_x25_packet(isop, lcp, m)) == 0) 39149937Ssklower error = pk_connect(lcp, &lcp->lcd_faddr); 39249937Ssklower return error; 39336381Ssklower } 39436381Ssklower 39536381Ssklower /* 39636381Ssklower **************************** DEVICE cons *************************** 39736381Ssklower */ 39836381Ssklower 39936381Ssklower 40036381Ssklower /* 40136381Ssklower * NAME: cons_ctlinput() 40236381Ssklower * CALLED FROM: 40336381Ssklower * lower layer when ECN_CLEAR occurs : this routine is here 40436381Ssklower * for consistency - cons subnet service calls its higher layer 40536381Ssklower * through the protosw entry. 40636381Ssklower * FUNCTION & ARGUMENTS: 40737536Smckusick * cmd is a PRC_* command, list found in ../sys/protosw.h 40836381Ssklower * copcb is the obvious. 40936381Ssklower * This serves the higher-layer cons service. 41036381Ssklower * NOTE: this takes 3rd arg. because cons uses it to inform itself 41136381Ssklower * of things (timeouts, etc) but has a pcb instead of an address. 41236381Ssklower */ 41336381Ssklower cons_ctlinput(cmd, sa, copcb) 41436381Ssklower int cmd; 41536381Ssklower struct sockaddr *sa; 41645899Ssklower register struct pklcd *copcb; 41736381Ssklower { 41836381Ssklower } 41936381Ssklower 42036381Ssklower 42145899Ssklower find_error_reason( xp ) 42245899Ssklower register struct x25_packet *xp; 42336381Ssklower { 42436381Ssklower extern u_char x25_error_stats[]; 42545899Ssklower int error, cause; 42636381Ssklower 42745899Ssklower if (xp) { 42845899Ssklower cause = 4[(char *)xp]; 42945899Ssklower switch (cause) { 43036381Ssklower case 0x00: 43136381Ssklower case 0x80: 43236381Ssklower /* DTE originated; look at the diagnostic */ 43345899Ssklower error = (CONL_ERROR_MASK | cause); 43436381Ssklower goto done; 43536381Ssklower 43636381Ssklower case 0x01: /* number busy */ 43736381Ssklower case 0x81: 43836381Ssklower case 0x09: /* Out of order */ 43936381Ssklower case 0x89: 44036381Ssklower case 0x11: /* Remot Procedure Error */ 44136381Ssklower case 0x91: 44236381Ssklower case 0x19: /* reverse charging accept not subscribed */ 44336381Ssklower case 0x99: 44436381Ssklower case 0x21: /* Incampat destination */ 44536381Ssklower case 0xa1: 44636381Ssklower case 0x29: /* fast select accept not subscribed */ 44736381Ssklower case 0xa9: 44836381Ssklower case 0x39: /* ship absent */ 44936381Ssklower case 0xb9: 45036381Ssklower case 0x03: /* invalid facil request */ 45136381Ssklower case 0x83: 45236381Ssklower case 0x0b: /* access barred */ 45336381Ssklower case 0x8b: 45436381Ssklower case 0x13: /* local procedure error */ 45536381Ssklower case 0x93: 45636381Ssklower case 0x05: /* network congestion */ 45736381Ssklower case 0x85: 45836381Ssklower case 0x8d: /* not obtainable */ 45936381Ssklower case 0x0d: 46036381Ssklower case 0x95: /* RPOA out of order */ 46136381Ssklower case 0x15: 46236381Ssklower /* take out bit 8 46336381Ssklower * so we don't have to have so many perror entries 46436381Ssklower */ 46545899Ssklower error = (CONL_ERROR_MASK | 0x100 | (cause & ~0x80)); 46636381Ssklower goto done; 46736381Ssklower 46836381Ssklower case 0xc1: /* gateway-detected proc error */ 46936381Ssklower case 0xc3: /* gateway congestion */ 47036381Ssklower 47145899Ssklower error = (CONL_ERROR_MASK | 0x100 | cause); 47236381Ssklower goto done; 47336381Ssklower } 47436381Ssklower } 47536381Ssklower /* otherwise, a *hopefully* valid perror exists in the e_reason field */ 47645899Ssklower error = xp->packet_data; 47736381Ssklower if (error = 0) { 47836381Ssklower printf("Incoming PKT TYPE 0x%x with reason 0x%x\n", 47945899Ssklower pk_decode(xp), 48045899Ssklower cause); 48136381Ssklower error = E_CO_HLI_DISCA; 48236381Ssklower } 48336381Ssklower 48436381Ssklower done: 48536381Ssklower return error; 48636381Ssklower } 48736381Ssklower 48836381Ssklower 48936381Ssklower 49036381Ssklower #endif KERNEL 49136381Ssklower 49236381Ssklower /* 49336381Ssklower * NAME: make_partial_x25_packet() 49436381Ssklower * 49536381Ssklower * FUNCTION and ARGUMENTS: 49645899Ssklower * Makes part of an X.25 call packet, for use by x25. 49736381Ssklower * (src) and (dst) are the NSAP-addresses of source and destination. 49836381Ssklower * (buf) is a ptr to a buffer into which to write this partial header. 49936381Ssklower * 50045899Ssklower * 0 Facility length (in octets) 50145899Ssklower * 1 Facility field, which is a set of: 50236381Ssklower * m facil code 50336381Ssklower * m+1 facil param len (for >2-byte facilities) in octets 50436381Ssklower * m+2..p facil param field 50536381Ssklower * q user data (protocol identification octet) 50636381Ssklower * 50736381Ssklower * 50836381Ssklower * RETURNS: 50936381Ssklower * 0 if OK 51036381Ssklower * E* if failed. 51145899Ssklower * 51245899Ssklower * SIDE EFFECTS: 51345899Ssklower * Stores facilites mbuf in X.25 control block, where the connect 51445899Ssklower * routine knows where to look for it. 51536381Ssklower */ 51636381Ssklower 51736381Ssklower #ifdef X25_1984 51836381Ssklower int cons_use_facils = 1; 51936381Ssklower #else X25_1984 52036381Ssklower int cons_use_facils = 0; 52136381Ssklower #endif X25_1984 52236381Ssklower 52336381Ssklower int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */ 52436381Ssklower 52536381Ssklower Static int 52645899Ssklower make_partial_x25_packet(isop, lcp) 52745899Ssklower struct isopcb *isop; 52845899Ssklower struct pklcd *lcp; 52936381Ssklower { 53036381Ssklower u_int proto; 53136381Ssklower int flag; 53245899Ssklower caddr_t buf; 53349041Ssklower register caddr_t ptr; 53436381Ssklower register int len = 0; 53536381Ssklower int buflen =0; 53636381Ssklower caddr_t facil_len; 53736381Ssklower int oddness = 0; 53845899Ssklower struct mbuf *m; 53936381Ssklower 54036381Ssklower 54149584Ssklower IFDEBUG(D_CCONN) 54249584Ssklower printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", 54349584Ssklower isop->isop_laddr, isop->isop_faddr, proto, m, flag); 54449584Ssklower ENDDEBUG 54549584Ssklower if (cons_use_udata) { 54649584Ssklower if (isop->isop_x25crud_len > 0) { 54749584Ssklower /* 54849584Ssklower * The user specified something. Stick it in 54949584Ssklower */ 55049584Ssklower bcopy(isop->isop_x25crud, lcp->lcd_faddr.x25_udata, 55149584Ssklower isop->isop_x25crud_len); 55249584Ssklower lcp->lcd_faddr.x25_udlen = isop->isop_x25crud_len; 55349584Ssklower } 55449584Ssklower } 55549584Ssklower 55649584Ssklower if (cons_use_facils == 0) { 55749584Ssklower lcp->lcd_facilities = 0; 55849584Ssklower return 0; 55949584Ssklower } 56049937Ssklower MGETHDR(m, MT_DATA, M_WAITOK); 56145899Ssklower if (m == 0) 56245899Ssklower return ENOBUFS; 56345899Ssklower buf = mtod(m, caddr_t); 56449041Ssklower ptr = buf; 56536381Ssklower 56636381Ssklower /* ptr now points to facil length (len of whole facil field in OCTETS */ 56736381Ssklower facil_len = ptr ++; 56849937Ssklower m->m_len = 0; 56949937Ssklower pk_build_facilities(m, &lcp->lcd_faddr, 0); 57036381Ssklower 57136381Ssklower IFDEBUG(D_CADDR) 57236381Ssklower printf("make_partial calling: ptr 0x%x, len 0x%x\n", ptr, 57345899Ssklower isop->isop_laddr->siso_addr.isoa_len); 57436381Ssklower ENDDEBUG 57545899Ssklower if (cons_use_facils) { 57649937Ssklower *ptr++ = 0; /* Marker to separate X.25 facitilies from CCITT ones */ 57749937Ssklower *ptr++ = 0x0f; 57836381Ssklower *ptr = 0xcb; /* calling facility code */ 57936381Ssklower ptr ++; 58036381Ssklower ptr ++; /* leave room for facil param len (in OCTETS + 1) */ 58136381Ssklower ptr ++; /* leave room for the facil param len (in nibbles), 58249937Ssklower * high two bits of which indicate full/partial NSAP 58349937Ssklower */ 58445899Ssklower len = isop->isop_laddr->siso_addr.isoa_len; 58545899Ssklower bcopy( isop->isop_laddr->siso_data, ptr, len); 58649584Ssklower *(ptr-2) = len+1; /* facil param len in octets */ 58736381Ssklower *(ptr-1) = len<<1; /* facil param len in nibbles */ 58836381Ssklower ptr += len; 58936381Ssklower 59036381Ssklower IFDEBUG(D_CADDR) 59136381Ssklower printf("make_partial called: ptr 0x%x, len 0x%x\n", ptr, 59245899Ssklower isop->isop_faddr->siso_addr.isoa_len); 59336381Ssklower ENDDEBUG 59436381Ssklower *ptr = 0xc9; /* called facility code */ 59536381Ssklower ptr ++; 59636381Ssklower ptr ++; /* leave room for facil param len (in OCTETS + 1) */ 59736381Ssklower ptr ++; /* leave room for the facil param len (in nibbles), 59849937Ssklower * high two bits of which indicate full/partial NSAP 59949937Ssklower */ 60045899Ssklower len = isop->isop_faddr->siso_nlen; 60145899Ssklower bcopy(isop->isop_faddr->siso_data, ptr, len); 60249584Ssklower *(ptr-2) = len+1; /* facil param len = addr len + 1 for each of these 60336381Ssklower * two length fields, in octets */ 60436381Ssklower *(ptr-1) = len<<1; /* facil param len in nibbles */ 60536381Ssklower ptr += len; 60636381Ssklower 60736381Ssklower } 60836381Ssklower *facil_len = ptr - facil_len - 1; 60945899Ssklower if (*facil_len > MAX_FACILITIES) 61036381Ssklower return E_CO_PNA_LONG; 61136381Ssklower 61236381Ssklower buflen = (int)(ptr - buf); 61336381Ssklower 61436381Ssklower IFDEBUG(D_CDUMP_REQ) 61536381Ssklower register int i; 61636381Ssklower 61736381Ssklower printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n", 61836381Ssklower buf, buflen, buflen); 61936381Ssklower for( i=0; i < buflen; ) { 62036381Ssklower printf("+%d: %x %x %x %x %x %x %x %x\n", 62136381Ssklower i, 62236381Ssklower *(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3), 62336381Ssklower *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7)); 62436381Ssklower i+=8; 62536381Ssklower } 62636381Ssklower ENDDEBUG 62736381Ssklower IFDEBUG(D_CADDR) 62836381Ssklower printf("make_partial returns buf 0x%x size 0x%x bytes\n", 62936381Ssklower mtod(m, caddr_t), buflen); 63036381Ssklower ENDDEBUG 63136381Ssklower 63245899Ssklower if (buflen > MHLEN) 63336381Ssklower return E_CO_PNA_LONG; 63436381Ssklower 63549937Ssklower m->m_pkthdr.len = m->m_len = buflen; 63645899Ssklower lcp->lcd_facilities = m; 63736381Ssklower return 0; 63836381Ssklower } 63936381Ssklower 64036381Ssklower /* 64136381Ssklower * NAME: NSAPtoDTE() 64236381Ssklower * CALLED FROM: 64336381Ssklower * make_partial_x25_packet() 64436381Ssklower * FUNCTION and ARGUMENTS: 64536381Ssklower * get a DTE address from an NSAP-address (struct sockaddr_iso) 64636381Ssklower * (dst_octet) is the octet into which to begin stashing the DTE addr 64736381Ssklower * (dst_nibble) takes 0 or 1. 1 means begin filling in the DTE addr 64836381Ssklower * in the high-order nibble of dst_octet. 0 means low-order nibble. 64936381Ssklower * (addr) is the NSAP-address 65036381Ssklower * (flag) is true if the transport suffix is to become the 65136381Ssklower * last two digits of the DTE address 65245899Ssklower * A DTE address is a series of ASCII digits 65336381Ssklower * 65436381Ssklower * A DTE address may have leading zeros. The are significant. 65536381Ssklower * 1 digit per nibble, may be an odd number of nibbles. 65636381Ssklower * 65736381Ssklower * An NSAP-address has the DTE address in the IDI. Leading zeros are 65836381Ssklower * significant. Trailing hex f indicates the end of the DTE address. 65945899Ssklower * The IDI is a series of BCD digits, one per nibble. 66036381Ssklower * 66136381Ssklower * RETURNS 66236381Ssklower * # significant digits in the DTE address, -1 if error. 66336381Ssklower */ 66436381Ssklower 66536381Ssklower Static int 66645899Ssklower NSAPtoDTE(siso, sx25) 66745899Ssklower register struct sockaddr_iso *siso; 66845899Ssklower register struct sockaddr_x25 *sx25; 66936381Ssklower { 67045899Ssklower int dtelen = -1; 67136381Ssklower 67236381Ssklower IFDEBUG(D_CADDR) 67345899Ssklower printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&siso->siso_addr)); 67436381Ssklower ENDDEBUG 67536381Ssklower 67645899Ssklower if (siso->siso_data[0] == AFI_37) { 67745899Ssklower register char *out = sx25->x25_addr; 67845899Ssklower register char *in = siso->siso_data + 1; 67945899Ssklower register int nibble; 68049041Ssklower char *lim = siso->siso_data + siso->siso_nlen; 68149041Ssklower char *olim = out+15; 68245899Ssklower int lowNibble = 0; 68345899Ssklower 68445899Ssklower while (in < lim) { 68545899Ssklower nibble = ((lowNibble ? *in++ : (*in >> 4)) & 0xf) | 0x30; 68645899Ssklower lowNibble ^= 1; 68749041Ssklower if (nibble != 0x3f && out < olim) 68845899Ssklower *out++ = nibble; 68945899Ssklower } 69045899Ssklower dtelen = out - sx25->x25_addr; 69145899Ssklower *out++ = 0; 69245899Ssklower } else { 69345899Ssklower /* error = iso_8208snparesolve(addr, x121string, &x121strlen);*/ 69450648Ssklower register struct rtentry *rt; 69550648Ssklower extern struct sockaddr_iso blank_siso; 69650648Ssklower struct sockaddr_iso nsiso; 69745899Ssklower 69850648Ssklower nsiso = blank_siso; 69950648Ssklower bcopy(nsiso.siso_data, siso->siso_data, 70050648Ssklower nsiso.siso_nlen = siso->siso_nlen); 70150648Ssklower if (rt = rtalloc1(&nsiso, 1)) { 70245899Ssklower register struct sockaddr_x25 *sxx = 70345899Ssklower (struct sockaddr_x25 *)rt->rt_gateway; 70445899Ssklower register char *in = sxx->x25_addr; 70545899Ssklower 70645899Ssklower rt->rt_use--; 70745899Ssklower if (sxx && sxx->x25_family == AF_CCITT) { 70845899Ssklower bcopy(sx25->x25_addr, sxx->x25_addr, sizeof(sx25->x25_addr)); 70945899Ssklower while (*in++) {} 71045899Ssklower dtelen = in - sxx->x25_addr; 71145899Ssklower } 71245899Ssklower } 71336381Ssklower } 71445899Ssklower return dtelen; 71536381Ssklower } 71636381Ssklower 71736381Ssklower /* 71836381Ssklower * NAME: FACILtoNSAP() 71936381Ssklower * CALLED FROM: 72036381Ssklower * parse_facil() 72136381Ssklower * FUNCTION and ARGUMENTS: 72236381Ssklower * Creates and NSAP in the sockaddr_iso (addr) from the 72345899Ssklower * x.25 facility found at buf - 1. 72436381Ssklower * RETURNS: 72550648Ssklower * 0 if ok, -1 if error. 72636381Ssklower */ 72736381Ssklower 72836381Ssklower Static int 72945899Ssklower FACILtoNSAP(addr, buf) 73050648Ssklower register u_char *buf; 73136381Ssklower register struct sockaddr_iso *addr; 73236381Ssklower { 73350648Ssklower int len_in_nibbles = *++buf & 0x3f; 73450648Ssklower u_char buf_len = (len_in_nibbles + 1) >> 1;; /* in bytes */ 73536381Ssklower 73636381Ssklower IFDEBUG(D_CADDR) 73736381Ssklower printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n", 73836381Ssklower buf, buf_len, addr ); 73936381Ssklower ENDDEBUG 74036381Ssklower 74145899Ssklower len_in_nibbles = *buf & 0x3f; 74236381Ssklower /* despite the fact that X.25 makes us put a length in nibbles 74336381Ssklower * here, the NSAP-addrs are always in full octets 74436381Ssklower */ 74545899Ssklower switch (*buf++ & 0xc0) { 74645899Ssklower case 0: 74745899Ssklower /* Entire OSI NSAP address */ 74845899Ssklower bcopy((caddr_t)buf, addr->siso_data, addr->siso_nlen = buf_len); 74945899Ssklower break; 75036381Ssklower 75145899Ssklower case 40: 75245899Ssklower /* Partial OSI NSAP address, assume trailing */ 75345899Ssklower if (buf_len + addr->siso_nlen > sizeof(addr->siso_addr)) 75445899Ssklower return -1; 75545899Ssklower bcopy((caddr_t)buf, TSEL(addr), buf_len); 75645899Ssklower addr->siso_nlen += buf_len; 75745899Ssklower break; 75836381Ssklower 75945899Ssklower default: 76045899Ssklower /* Rather than blow away the connection, just ignore and use 76145899Ssklower NSAP from DTE */; 76236381Ssklower } 76350648Ssklower return 0; 76445899Ssklower } 76536381Ssklower 76650648Ssklower Static 76745899Ssklower init_siso(siso) 76845899Ssklower register struct sockaddr_iso *siso; 76945899Ssklower { 77045899Ssklower siso->siso_len = sizeof (*siso); 77145899Ssklower siso->siso_family = AF_ISO; 77245899Ssklower siso->siso_data[0] = AFI_37; 77345899Ssklower siso->siso_nlen = 8; 77436381Ssklower } 77536381Ssklower 77636381Ssklower /* 77736381Ssklower * NAME: DTEtoNSAP() 77836381Ssklower * CALLED FROM: 77936381Ssklower * parse_facil() 78036381Ssklower * FUNCTION and ARGUMENTS: 78136381Ssklower * Creates a type 37 NSAP in the sockaddr_iso (addr) 78245899Ssklower * from a DTE address found in a sockaddr_x25. 78336381Ssklower * 78436381Ssklower * RETURNS: 78536381Ssklower * 0 if ok; E* otherwise. 78636381Ssklower */ 78736381Ssklower 78836381Ssklower Static int 78945899Ssklower DTEtoNSAP(addr, sx) 79036381Ssklower struct sockaddr_iso *addr; 79145899Ssklower struct sockaddr_x25 *sx; 79236381Ssklower { 79345899Ssklower register char *in, *out; 79445899Ssklower register int first; 79545899Ssklower int pad_tail = 0; 79645899Ssklower int src_len; 79736381Ssklower 79836381Ssklower 79945899Ssklower init_siso(addr); 80045899Ssklower in = sx->x25_addr; 80150648Ssklower src_len = strlen(in); 80250648Ssklower addr->siso_nlen = (src_len + 3) / 2; 80350648Ssklower out = addr->siso_data; 80450648Ssklower *out++ = 0x37; 80550648Ssklower if (src_len & 1) { 80645899Ssklower pad_tail = 0xf; 80745899Ssklower src_len++; 80845899Ssklower } 80950648Ssklower for (first = 0; src_len > 0; src_len--) { 81050648Ssklower first |= 0xf & *in++; 81145899Ssklower if (src_len & 1) { 81245899Ssklower *out++ = first; 81345899Ssklower first = 0; 81445899Ssklower } 81545899Ssklower else first <<= 4; 81645899Ssklower } 81745899Ssklower if (pad_tail) 81845899Ssklower out[-1] |= 0xf; 81936381Ssklower return 0; /* ok */ 82036381Ssklower } 82136381Ssklower 82236381Ssklower /* 82336381Ssklower * FUNCTION and ARGUMENTS: 82436381Ssklower * parses (buf_len) bytes beginning at (buf) and finds 82536381Ssklower * a called nsap, a calling nsap, and protocol identifier. 82636381Ssklower * RETURNS: 82736381Ssklower * 0 if ok, E* otherwise. 82836381Ssklower */ 82936381Ssklower 83050648Ssklower Static int 83145899Ssklower parse_facil(lcp, isop, buf, buf_len) 83236381Ssklower caddr_t buf; 83336381Ssklower u_char buf_len; /* in bytes */ 83445899Ssklower struct isopcb *isop; 83545899Ssklower struct pklcd *lcp; 83636381Ssklower { 83736381Ssklower register int i; 83845899Ssklower register u_char *ptr = (u_char *)buf; 83945899Ssklower u_char *ptr_lim, *facil_lim; 84045899Ssklower int facil_param_len, facil_len; 84136381Ssklower 84236381Ssklower IFDEBUG(D_CADDR) 84345899Ssklower printf("parse_facil(0x%x, 0x%x, 0x%x, 0x%x)\n", 84450648Ssklower lcp, isop, buf, buf_len); 84536381Ssklower dump_buf(buf, buf_len); 84636381Ssklower ENDDEBUG 84736381Ssklower 84836381Ssklower /* find the beginnings of the facility fields in buf 84936381Ssklower * by skipping over the called & calling DTE addresses 85036381Ssklower * i <- # nibbles in called + # nibbles in calling 85136381Ssklower * i += 1 so that an odd nibble gets rounded up to even 85236381Ssklower * before dividing by 2, then divide by two to get # octets 85336381Ssklower */ 85445899Ssklower i = (int)(*ptr >> 4) + (int)(*ptr&0xf); 85536381Ssklower i++; 85645899Ssklower ptr += i >> 1; 85736381Ssklower ptr ++; /* plus one for the DTE lengths byte */ 85836381Ssklower 85936381Ssklower /* ptr now is at facil_length field */ 86045899Ssklower facil_len = *ptr++; 86145899Ssklower facil_lim = ptr + facil_len; 86236381Ssklower IFDEBUG(D_CADDR) 86345899Ssklower printf("parse_facils: facil length is 0x%x\n", (int) facil_len); 86436381Ssklower ENDDEBUG 86536381Ssklower 86650648Ssklower while (ptr < facil_lim) { 86736381Ssklower /* get NSAP addresses from facilities */ 86845899Ssklower switch (*ptr++) { 86936381Ssklower case 0xcb: 87045899Ssklower /* calling NSAP */ 87145899Ssklower facil_param_len = FACILtoNSAP(isop->isop_faddr, ptr); 87236381Ssklower break; 87336381Ssklower case 0xc9: 87445899Ssklower /* called NSAP */ 87545899Ssklower facil_param_len = FACILtoNSAP(isop->isop_laddr, ptr); 87636381Ssklower break; 87736381Ssklower 87836381Ssklower /* from here to default are legit cases that I ignore */ 87936381Ssklower /* variable length */ 88036381Ssklower case 0xca: /* end-to-end transit delay negot */ 88136381Ssklower case 0xc6: /* network user id */ 88236381Ssklower case 0xc5: /* charging info : indicating monetary unit */ 88336381Ssklower case 0xc2: /* charging info : indicating segment count */ 88436381Ssklower case 0xc1: /* charging info : indicating call duration */ 88536381Ssklower case 0xc4: /* RPOA extended format */ 88636381Ssklower case 0xc3: /* call redirection notification */ 88736381Ssklower facil_param_len = 0; 88836381Ssklower break; 88936381Ssklower 89036381Ssklower /* 1 octet */ 89136381Ssklower case 0x0a: /* min. throughput class negot */ 89236381Ssklower case 0x02: /* throughput class */ 89336381Ssklower case 0x03: case 0x47: /* CUG shit */ 89436381Ssklower case 0x0b: /* expedited data negot */ 89536381Ssklower case 0x01: /* Fast select or reverse charging 89636381Ssklower (example of intelligent protocol design) */ 89736381Ssklower case 0x04: /* charging info : requesting service */ 89836381Ssklower case 0x08: /* called line addr modified notification */ 89950648Ssklower case 0x00: /* marker to indicate beginning of CCITT facils */ 90036381Ssklower facil_param_len = 1; 90136381Ssklower break; 90236381Ssklower 90336381Ssklower /* any 2 octets */ 90436381Ssklower case 0x42: /* pkt size */ 90536381Ssklower case 0x43: /* win size */ 90636381Ssklower case 0x44: /* RPOA basic format */ 90736381Ssklower case 0x41: /* bilateral CUG shit */ 90836381Ssklower case 0x49: /* transit delay selection and indication */ 90936381Ssklower facil_param_len = 2; 91036381Ssklower break; 91136381Ssklower 91236381Ssklower default: 91336381Ssklower printf( 91450648Ssklower "BOGUS FACILITY CODE facil_lim 0x%x facil_len %d, ptr 0x%x *ptr 0x%x\n", 91550648Ssklower facil_lim, facil_len, ptr - 1, ptr[-1]); 91650648Ssklower /* facil that we don't handle 91750648Ssklower return E_CO_HLI_REJI; */ 91850648Ssklower switch (ptr[-1] & 0xc0) { 91950648Ssklower case 0x00: facil_param_len = 1; break; 92050648Ssklower case 0x40: facil_param_len = 2; break; 92150648Ssklower case 0x80: facil_param_len = 3; break; 92250648Ssklower case 0xc0: facil_param_len = 0; break; 92350648Ssklower } 92436381Ssklower } 92545899Ssklower if (facil_param_len == -1) 92645899Ssklower return E_CO_REG_ICDA; 92745899Ssklower if (facil_param_len == 0) /* variable length */ 92850648Ssklower facil_param_len = (int)*ptr++; /* 1 + the real facil param */ 92936381Ssklower ptr += facil_param_len; 93036381Ssklower } 93136381Ssklower return 0; 93236381Ssklower } 93336381Ssklower 93445899Ssklower #endif TPCONS 935