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 #ifndef lint 3636381Ssklower static char *rcsid = "$Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $"; 3736381Ssklower #endif lint 38*45899Ssklower */ 3936381Ssklower 40*45899Ssklower #ifdef TPCONS 41*45899Ssklower #ifdef KERNEL 4236381Ssklower #ifdef ARGO_DEBUG 4336381Ssklower #define Static 4436381Ssklower unsigned LAST_CALL_PCB; 4536381Ssklower #else ARGO_DEBUG 4636381Ssklower #define Static static 4736381Ssklower #endif ARGO_DEBUG 4836381Ssklower 4936381Ssklower 5036381Ssklower 51*45899Ssklower #ifndef SOCK_STREAM 5236381Ssklower #include "param.h" 5336381Ssklower #include "systm.h" 5436381Ssklower #include "mbuf.h" 5536381Ssklower #include "protosw.h" 5636381Ssklower #include "socket.h" 5736381Ssklower #include "socketvar.h" 5836381Ssklower #include "errno.h" 5936381Ssklower #include "ioctl.h" 6040783Smarc #include "tsleep.h" 6136381Ssklower 6236381Ssklower #include "../net/if.h" 6336381Ssklower #include "../net/netisr.h" 6436381Ssklower #include "../net/route.h" 6536381Ssklower 66*45899Ssklower #include "iso_errno.h" 67*45899Ssklower #include "argo_debug.h" 68*45899Ssklower #include "tp_trace.h" 69*45899Ssklower #include "iso.h" 70*45899Ssklower #include "cons.h" 71*45899Ssklower #include "iso_pcb.h" 7236381Ssklower 73*45899Ssklower #include "../netccitt/x25.h" 74*45899Ssklower #include "../netccitt/pk.h" 75*45899Ssklower #include "../netccitt/pk_var.h" 76*45899Ssklower #endif 77*45899Ssklower 7836381Ssklower #ifdef ARGO_DEBUG 7936381Ssklower #define MT_XCONN 0x50 8036381Ssklower #define MT_XCLOSE 0x51 8136381Ssklower #define MT_XCONFIRM 0x52 8236381Ssklower #define MT_XDATA 0x53 8336381Ssklower #define MT_XHEADER 0x54 8436381Ssklower #else 8536381Ssklower #define MT_XCONN MT_DATA 8636381Ssklower #define MT_XCLOSE MT_DATA 8736381Ssklower #define MT_XCONFIRM MT_DATA 8836381Ssklower #define MT_XDATA MT_DATA 8936381Ssklower #define MT_XHEADER MT_HEADER 9036381Ssklower #endif ARGO_DEBUG 9136381Ssklower 9236381Ssklower #define DONTCLEAR -1 9336381Ssklower 9436381Ssklower /********************************************************************* 95*45899Ssklower * cons.c - CONS interface to the x.25 layer 9636381Ssklower * 9736381Ssklower * TODO: figure out what resources we might run out of besides mbufs. 9836381Ssklower * If we run out of any of them (including mbufs) close and recycle 9936381Ssklower * lru x% of the connections, for some parameter x. 10036381Ssklower * 101*45899Ssklower * There are 2 interfaces from above: 10236381Ssklower * 1) from TP0: 10336381Ssklower * cons CO network service 10436381Ssklower * TP associates a transport connection with a network connection. 10536381Ssklower * cons_output( isop, m, len, isdgm==0 ) 10636381Ssklower * co_flags == 0 107*45899Ssklower * 2) from TP4: 10836381Ssklower * It's a datagram service, like clnp is. - even though it calls 10936381Ssklower * cons_output( isop, m, len, isdgm==1 ) 11036381Ssklower * it eventually goes through 11136381Ssklower * cosns_output(ifp, m, dst). 11236381Ssklower * TP4 permits multiplexing (reuse, possibly simultaneously) of the 11336381Ssklower * network connections. 11436381Ssklower * This means that many sockets (many tpcbs) may be associated with 115*45899Ssklower * this pklcd, hence cannot have a back ptr from pklcd to a tpcb. 11636381Ssklower * co_flags & CONSF_DGM 117*45899Ssklower * co_socket is null since there may be many sockets that use this pklcd. 11836381Ssklower * 11936381Ssklower NOTE: 12036381Ssklower streams would really be nice. sigh. 12136381Ssklower NOTE: 12236381Ssklower PVCs could be handled by config-ing a cons with an address and with the 12336381Ssklower IFF_POINTTOPOINT flag on. This code would then have to skip the 12436381Ssklower connection setup stuff for pt-to-pt links. 12536381Ssklower 12636381Ssklower 12736381Ssklower *********************************************************************/ 12836381Ssklower 12936381Ssklower 13036381Ssklower #define CONS_IFQMAXLEN 5 13136381Ssklower 13236381Ssklower 13336381Ssklower /* protosw pointers for getting to higher layer */ 13436381Ssklower Static struct protosw *CLNP_proto; 13536381Ssklower Static struct protosw *TP_proto; 13636381Ssklower Static struct protosw *X25_proto; 13736381Ssklower Static int issue_clear_req(); 13836381Ssklower 13936381Ssklower #ifndef PHASEONE 14036381Ssklower extern struct ifaddr *ifa_ifwithnet(); 14136381Ssklower #endif PHASEONE 14236381Ssklower 14336381Ssklower extern struct ifaddr *ifa_ifwithaddr(); 14436381Ssklower 14536381Ssklower Static struct socket dummysocket; /* for use by cosns */ 14636381Ssklower 14736381Ssklower extern struct isopcb tp_isopcb; /* chain of all TP pcbs */ 14836381Ssklower struct isopcb tp_incoming_pending; /* incoming connections 14936381Ssklower for TP, pending */ 15036381Ssklower 15136381Ssklower struct isopcb *Xpcblist[] = { 15236381Ssklower &tp_incoming_pending, 15336381Ssklower &tp_isopcb, 15436381Ssklower (struct isopcb *)0 15536381Ssklower }; 15636381Ssklower 15736381Ssklower Static int parse_facil(), NSAPtoDTE(), make_partial_x25_packet(); 15836381Ssklower Static int FACILtoNSAP(), DTEtoNSAP(); 159*45899Ssklower Static struct pklcd *cons_chan_to_pcb(); 16036381Ssklower 16136381Ssklower #define HIGH_NIBBLE 1 16236381Ssklower #define LOW_NIBBLE 0 16336381Ssklower 16436381Ssklower /* 16536381Ssklower * NAME: nibble_copy() 16636381Ssklower * FUNCTION and ARGUMENTS: 16736381Ssklower * copies (len) nibbles from (src_octet), high or low nibble 16836381Ssklower * to (dst_octet), high or low nibble, 16936381Ssklower * src_nibble & dst_nibble should be: 17036381Ssklower * HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble 17136381Ssklower * LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble 17236381Ssklower * RETURNS: VOID 17336381Ssklower */ 17436381Ssklower void 175*45899Ssklower nibble_copy(src_octet, src_nibble, dst_octet, dst_nibble, len) 17636381Ssklower register char *src_octet; 17736381Ssklower register char *dst_octet; 17836381Ssklower register unsigned src_nibble; 17936381Ssklower register unsigned dst_nibble; 18036381Ssklower int len; 18136381Ssklower { 18236381Ssklower 18336381Ssklower register i; 18436381Ssklower register unsigned dshift, sshift; 18536381Ssklower 18636381Ssklower IFDEBUG(D_CADDR) 18736381Ssklower printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", 18836381Ssklower src_octet, src_nibble, dst_octet, dst_nibble, len); 18936381Ssklower ENDDEBUG 19036381Ssklower #define SHIFT 0x4 19136381Ssklower 19236381Ssklower dshift = dst_nibble << 2; 19336381Ssklower sshift = src_nibble << 2; 19436381Ssklower 19536381Ssklower for (i=0; i<len; i++) { 19636381Ssklower /* clear dst_nibble */ 19736381Ssklower *dst_octet &= ~(0xf<< dshift); 19836381Ssklower 19936381Ssklower /* set dst nibble */ 20036381Ssklower *dst_octet |= ( 0xf & (*src_octet >> sshift))<< dshift; 20136381Ssklower 20236381Ssklower dshift ^= SHIFT; 20336381Ssklower sshift ^= SHIFT; 20436381Ssklower src_nibble = 1-src_nibble; 20536381Ssklower dst_nibble = 1-dst_nibble; 20636381Ssklower src_octet += src_nibble; 20736381Ssklower dst_octet += dst_nibble; 20836381Ssklower } 20936381Ssklower IFDEBUG(D_CADDR) 21036381Ssklower printf("nibble_copy DONE\n"); 21136381Ssklower ENDDEBUG 21236381Ssklower } 21336381Ssklower 21436381Ssklower /* 21536381Ssklower * NAME: nibble_match() 21636381Ssklower * FUNCTION and ARGUMENTS: 21736381Ssklower * compares src_octet/src_nibble and dst_octet/dst_nibble for len nibbles. 21836381Ssklower * RETURNS: 0 if they differ, 1 if they are the same. 21936381Ssklower */ 22036381Ssklower int 22136381Ssklower nibble_match( src_octet, src_nibble, dst_octet, dst_nibble, len) 22236381Ssklower register char *src_octet; 22336381Ssklower register char *dst_octet; 22436381Ssklower register unsigned src_nibble; 22536381Ssklower register unsigned dst_nibble; 22636381Ssklower int len; 22736381Ssklower { 22836381Ssklower 22936381Ssklower register i; 23036381Ssklower register unsigned dshift, sshift; 23136381Ssklower u_char nibble_a, nibble_b; 23236381Ssklower 23336381Ssklower IFDEBUG(D_CADDR) 23436381Ssklower printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", 23536381Ssklower src_octet, src_nibble, dst_octet, dst_nibble, len); 23636381Ssklower ENDDEBUG 23736381Ssklower #define SHIFT 0x4 23836381Ssklower 23936381Ssklower dshift = dst_nibble << 2; 24036381Ssklower sshift = src_nibble << 2; 24136381Ssklower 24236381Ssklower for (i=0; i<len; i++) { 24336381Ssklower nibble_b = ((*dst_octet)>>dshift) & 0xf; 24436381Ssklower nibble_a = ( 0xf & (*src_octet >> sshift)); 245*45899Ssklower if (nibble_b != nibble_a) 24636381Ssklower return 0; 24736381Ssklower 24836381Ssklower dshift ^= SHIFT; 24936381Ssklower sshift ^= SHIFT; 25036381Ssklower src_nibble = 1-src_nibble; 25136381Ssklower dst_nibble = 1-dst_nibble; 25236381Ssklower src_octet += src_nibble; 25336381Ssklower dst_octet += dst_nibble; 25436381Ssklower } 25536381Ssklower IFDEBUG(D_CADDR) 25636381Ssklower printf("nibble_match DONE\n"); 25736381Ssklower ENDDEBUG 25836381Ssklower return 1; 25936381Ssklower } 26036381Ssklower 26136381Ssklower /* 26236381Ssklower **************************** NET PROTOCOL cons *************************** 26336381Ssklower */ 26436381Ssklower /* 26536381Ssklower * NAME: cons_init() 26636381Ssklower * CALLED FROM: 26736381Ssklower * autoconf 26836381Ssklower * FUNCTION: 26936381Ssklower * initialize the protocol 27036381Ssklower */ 27136381Ssklower cons_init() 27236381Ssklower { 273*45899Ssklower int tp_incoming(), clnp_incoming(); 27436381Ssklower 27536381Ssklower 27636381Ssklower CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM); 27736381Ssklower X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM); 27836381Ssklower TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET); 27936381Ssklower IFDEBUG(D_CCONS) 28036381Ssklower printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n", 28136381Ssklower CLNP_proto, X25_proto, TP_proto); 28236381Ssklower ENDDEBUG 283*45899Ssklower #ifdef notdef 284*45899Ssklower pk_protolisten(0x81, 0, clnp_incoming); 285*45899Ssklower pk_protolisten(0x82, 0, esis_incoming); 286*45899Ssklower pk_protolisten(0x84, 0, tp8878_A_incoming); 287*45899Ssklower #endif 288*45899Ssklower pk_protolisten(0, 0, tp_incoming); 28936381Ssklower } 29036381Ssklower 291*45899Ssklower tp_incoming(lcp, m0) 292*45899Ssklower struct pklcd *lcp; 293*45899Ssklower struct mbuf *m0; 29436381Ssklower { 295*45899Ssklower register struct mbuf *m = m0->m_next; /* m0 has calling sockaddr_x25 */ 296*45899Ssklower register struct isopcb *isop; 297*45899Ssklower extern struct isopcb tp_isopcb; 298*45899Ssklower int cons_tpinput(); 29936381Ssklower 300*45899Ssklower if (iso_pcballoc((struct socket *)0, &tp_incoming_pending)) { 301*45899Ssklower m_freem(m); 302*45899Ssklower pk_clear(lcp); 303*45899Ssklower return; 30436381Ssklower } 305*45899Ssklower isop = tp_incoming_pending.isop_next; 306*45899Ssklower pk_output(lcp); /* Confirms call */ 307*45899Ssklower lcp->lcd_upper = cons_tpinput; 308*45899Ssklower lcp->lcd_upnext = (caddr_t)isop; 309*45899Ssklower isop->isop_chan = (caddr_t)lcp; 310*45899Ssklower isop->isop_laddr = &isop->isop_sladdr; 311*45899Ssklower isop->isop_faddr = &isop->isop_sfaddr; 312*45899Ssklower DTEtoNSAP(isop->isop_laddr, &lcp->lcd_laddr); 313*45899Ssklower DTEtoNSAP(isop->isop_faddr, &lcp->lcd_faddr); 314*45899Ssklower parse_facil(isop, lcp, &(mtod(m, struct x25_packet *)->packet_data), 315*45899Ssklower m->m_pkthdr.len - PKHEADERLN); 316*45899Ssklower m_freem(m); 31736381Ssklower } 31836381Ssklower 319*45899Ssklower cons_tpinput(lcp, m0) 320*45899Ssklower struct mbuf *m0; 321*45899Ssklower struct pklcd *lcp; 32236381Ssklower { 323*45899Ssklower register struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext; 324*45899Ssklower register struct x25_packet *xp; 325*45899Ssklower int cmd; 32636381Ssklower 327*45899Ssklower switch(m0->m_type) { 328*45899Ssklower case MT_DATA: 329*45899Ssklower case MT_OOBDATA: 330*45899Ssklower tpcons_input(m0, isop->isop_faddr, isop->isop_laddr, 331*45899Ssklower (struct socket *)0, (caddr_t)lcp); 33236381Ssklower 333*45899Ssklower case MT_CONTROL: 334*45899Ssklower switch (pk_decode(mtod(m0, struct x25_packet *))) { 335*45899Ssklower default: 336*45899Ssklower return; 33736381Ssklower 338*45899Ssklower case RR: 339*45899Ssklower cmd = PRC_CONS_SEND_DONE; 340*45899Ssklower break; 34136381Ssklower 342*45899Ssklower case RESET: 343*45899Ssklower cmd = PRC_ROUTEDEAD; 34436381Ssklower } 345*45899Ssklower tpcons_ctlinput(cmd, isop->isop_faddr, isop); 34636381Ssklower } 34736381Ssklower } 34836381Ssklower 34936381Ssklower /* 35036381Ssklower * NAME: cons_connect() 35136381Ssklower * CALLED FROM: 352*45899Ssklower * tpcons_pcbconnect() when opening a new connection. 35336381Ssklower * FUNCTION anD ARGUMENTS: 35436381Ssklower * Figures out which device to use, finding a route if one doesn't 35536381Ssklower * already exist. 35636381Ssklower * RETURN VALUE: 35736381Ssklower * returns E* 35836381Ssklower */ 359*45899Ssklower cons_connect(isop) 360*45899Ssklower register struct isopcb *isop; 36136381Ssklower { 362*45899Ssklower register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 36336381Ssklower register struct mbuf *m; 36436381Ssklower struct ifaddr *ifa; 36536381Ssklower 36636381Ssklower IFDEBUG(D_CCONN) 367*45899Ssklower printf("cons_connect(0x%x): ", isop); 368*45899Ssklower dump_isoaddr(isop->isop_faddr); 369*45899Ssklower printf("myaddr: "); 370*45899Ssklower dump_isoaddr(isop->isop_laddr); 37136381Ssklower printf("\n" ); 37236381Ssklower ENDDEBUG 373*45899Ssklower NSAPtoDTE(isop->isop_faddr, &lcp->lcd_faddr); 37436381Ssklower IFDEBUG(D_CCONN) 37536381Ssklower printf( 376*45899Ssklower "calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x)\n", 377*45899Ssklower &lcp->lcd_faddr, &lcp->lcd_laddr, 378*45899Ssklower isop->isop_socket->so_proto->pr_protocol); 37936381Ssklower ENDDEBUG 380*45899Ssklower return (make_partial_x25_packet(isop, lcp, m) || 381*45899Ssklower pk_connect(lcp, &lcp->lcd_faddr)); 38236381Ssklower } 38336381Ssklower 38436381Ssklower /* 38536381Ssklower **************************** DEVICE cons *************************** 38636381Ssklower */ 38736381Ssklower 38836381Ssklower 38936381Ssklower /* 39036381Ssklower * NAME: cons_ctlinput() 39136381Ssklower * CALLED FROM: 39236381Ssklower * lower layer when ECN_CLEAR occurs : this routine is here 39336381Ssklower * for consistency - cons subnet service calls its higher layer 39436381Ssklower * through the protosw entry. 39536381Ssklower * FUNCTION & ARGUMENTS: 39637536Smckusick * cmd is a PRC_* command, list found in ../sys/protosw.h 39736381Ssklower * copcb is the obvious. 39836381Ssklower * This serves the higher-layer cons service. 39936381Ssklower * NOTE: this takes 3rd arg. because cons uses it to inform itself 40036381Ssklower * of things (timeouts, etc) but has a pcb instead of an address. 40136381Ssklower */ 40236381Ssklower cons_ctlinput(cmd, sa, copcb) 40336381Ssklower int cmd; 40436381Ssklower struct sockaddr *sa; 405*45899Ssklower register struct pklcd *copcb; 40636381Ssklower { 40736381Ssklower } 40836381Ssklower 40936381Ssklower 410*45899Ssklower find_error_reason( xp ) 411*45899Ssklower register struct x25_packet *xp; 41236381Ssklower { 41336381Ssklower extern u_char x25_error_stats[]; 414*45899Ssklower int error, cause; 41536381Ssklower 416*45899Ssklower if (xp) { 417*45899Ssklower cause = 4[(char *)xp]; 418*45899Ssklower switch (cause) { 41936381Ssklower case 0x00: 42036381Ssklower case 0x80: 42136381Ssklower /* DTE originated; look at the diagnostic */ 422*45899Ssklower error = (CONL_ERROR_MASK | cause); 42336381Ssklower goto done; 42436381Ssklower 42536381Ssklower case 0x01: /* number busy */ 42636381Ssklower case 0x81: 42736381Ssklower case 0x09: /* Out of order */ 42836381Ssklower case 0x89: 42936381Ssklower case 0x11: /* Remot Procedure Error */ 43036381Ssklower case 0x91: 43136381Ssklower case 0x19: /* reverse charging accept not subscribed */ 43236381Ssklower case 0x99: 43336381Ssklower case 0x21: /* Incampat destination */ 43436381Ssklower case 0xa1: 43536381Ssklower case 0x29: /* fast select accept not subscribed */ 43636381Ssklower case 0xa9: 43736381Ssklower case 0x39: /* ship absent */ 43836381Ssklower case 0xb9: 43936381Ssklower case 0x03: /* invalid facil request */ 44036381Ssklower case 0x83: 44136381Ssklower case 0x0b: /* access barred */ 44236381Ssklower case 0x8b: 44336381Ssklower case 0x13: /* local procedure error */ 44436381Ssklower case 0x93: 44536381Ssklower case 0x05: /* network congestion */ 44636381Ssklower case 0x85: 44736381Ssklower case 0x8d: /* not obtainable */ 44836381Ssklower case 0x0d: 44936381Ssklower case 0x95: /* RPOA out of order */ 45036381Ssklower case 0x15: 45136381Ssklower /* take out bit 8 45236381Ssklower * so we don't have to have so many perror entries 45336381Ssklower */ 454*45899Ssklower error = (CONL_ERROR_MASK | 0x100 | (cause & ~0x80)); 45536381Ssklower goto done; 45636381Ssklower 45736381Ssklower case 0xc1: /* gateway-detected proc error */ 45836381Ssklower case 0xc3: /* gateway congestion */ 45936381Ssklower 460*45899Ssklower error = (CONL_ERROR_MASK | 0x100 | cause); 46136381Ssklower goto done; 46236381Ssklower } 46336381Ssklower } 46436381Ssklower /* otherwise, a *hopefully* valid perror exists in the e_reason field */ 465*45899Ssklower error = xp->packet_data; 46636381Ssklower if (error = 0) { 46736381Ssklower printf("Incoming PKT TYPE 0x%x with reason 0x%x\n", 468*45899Ssklower pk_decode(xp), 469*45899Ssklower cause); 47036381Ssklower error = E_CO_HLI_DISCA; 47136381Ssklower } 47236381Ssklower 47336381Ssklower done: 47436381Ssklower return error; 47536381Ssklower } 47636381Ssklower 47736381Ssklower 47836381Ssklower 47936381Ssklower #endif KERNEL 48036381Ssklower 48136381Ssklower /* 48236381Ssklower * NAME: make_partial_x25_packet() 48336381Ssklower * 48436381Ssklower * FUNCTION and ARGUMENTS: 485*45899Ssklower * Makes part of an X.25 call packet, for use by x25. 48636381Ssklower * (src) and (dst) are the NSAP-addresses of source and destination. 48736381Ssklower * (buf) is a ptr to a buffer into which to write this partial header. 48836381Ssklower * 489*45899Ssklower * 0 Facility length (in octets) 490*45899Ssklower * 1 Facility field, which is a set of: 49136381Ssklower * m facil code 49236381Ssklower * m+1 facil param len (for >2-byte facilities) in octets 49336381Ssklower * m+2..p facil param field 49436381Ssklower * q user data (protocol identification octet) 49536381Ssklower * 49636381Ssklower * 49736381Ssklower * RETURNS: 49836381Ssklower * 0 if OK 49936381Ssklower * E* if failed. 500*45899Ssklower * 501*45899Ssklower * SIDE EFFECTS: 502*45899Ssklower * Stores facilites mbuf in X.25 control block, where the connect 503*45899Ssklower * routine knows where to look for it. 50436381Ssklower */ 50536381Ssklower 50636381Ssklower #ifdef X25_1984 50736381Ssklower int cons_use_facils = 1; 50836381Ssklower #else X25_1984 50936381Ssklower int cons_use_facils = 0; 51036381Ssklower #endif X25_1984 51136381Ssklower 51236381Ssklower int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */ 51336381Ssklower 51436381Ssklower Static int 515*45899Ssklower make_partial_x25_packet(isop, lcp) 516*45899Ssklower struct isopcb *isop; 517*45899Ssklower struct pklcd *lcp; 51836381Ssklower { 51936381Ssklower u_int proto; 52036381Ssklower int flag; 521*45899Ssklower caddr_t buf; 522*45899Ssklower register caddr_t ptr = buf; 52336381Ssklower register int len = 0; 52436381Ssklower int buflen =0; 52536381Ssklower caddr_t facil_len; 52636381Ssklower int oddness = 0; 527*45899Ssklower struct mbuf *m; 52836381Ssklower 52936381Ssklower 530*45899Ssklower MGET(m, MT_DATA, M_WAITOK); 531*45899Ssklower if (m == 0) 532*45899Ssklower return ENOBUFS; 533*45899Ssklower buf = mtod(m, caddr_t); 53436381Ssklower IFDEBUG(D_CCONN) 53536381Ssklower printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", 536*45899Ssklower isop->isop_laddr, isop->isop_faddr, proto, m, flag); 53736381Ssklower ENDDEBUG 53836381Ssklower 53936381Ssklower /* ptr now points to facil length (len of whole facil field in OCTETS */ 54036381Ssklower facil_len = ptr ++; 54136381Ssklower 54236381Ssklower IFDEBUG(D_CADDR) 54336381Ssklower printf("make_partial calling: ptr 0x%x, len 0x%x\n", ptr, 544*45899Ssklower isop->isop_laddr->siso_addr.isoa_len); 54536381Ssklower ENDDEBUG 546*45899Ssklower if (cons_use_facils) { 54736381Ssklower *ptr = 0xcb; /* calling facility code */ 54836381Ssklower ptr ++; 54936381Ssklower ptr ++; /* leave room for facil param len (in OCTETS + 1) */ 55036381Ssklower ptr ++; /* leave room for the facil param len (in nibbles), 55136381Ssklower * high two bits of which indicate full/partial NSAP 55236381Ssklower */ 553*45899Ssklower len = isop->isop_laddr->siso_addr.isoa_len; 554*45899Ssklower bcopy( isop->isop_laddr->siso_data, ptr, len); 55536381Ssklower *(ptr-2) = len+2; /* facil param len in octets */ 55636381Ssklower *(ptr-1) = len<<1; /* facil param len in nibbles */ 55736381Ssklower ptr += len; 55836381Ssklower 55936381Ssklower IFDEBUG(D_CADDR) 56036381Ssklower printf("make_partial called: ptr 0x%x, len 0x%x\n", ptr, 561*45899Ssklower isop->isop_faddr->siso_addr.isoa_len); 56236381Ssklower ENDDEBUG 56336381Ssklower *ptr = 0xc9; /* called facility code */ 56436381Ssklower ptr ++; 56536381Ssklower ptr ++; /* leave room for facil param len (in OCTETS + 1) */ 56636381Ssklower ptr ++; /* leave room for the facil param len (in nibbles), 56736381Ssklower * high two bits of which indicate full/partial NSAP 56836381Ssklower */ 569*45899Ssklower len = isop->isop_faddr->siso_nlen; 570*45899Ssklower bcopy(isop->isop_faddr->siso_data, ptr, len); 57136381Ssklower *(ptr-2) = len+2; /* facil param len = addr len + 1 for each of these 57236381Ssklower * two length fields, in octets */ 57336381Ssklower *(ptr-1) = len<<1; /* facil param len in nibbles */ 57436381Ssklower ptr += len; 57536381Ssklower 57636381Ssklower } 57736381Ssklower *facil_len = ptr - facil_len - 1; 578*45899Ssklower if (*facil_len > MAX_FACILITIES) 57936381Ssklower return E_CO_PNA_LONG; 58036381Ssklower 581*45899Ssklower if (cons_use_udata) { 582*45899Ssklower if (isop->isop_x25crud_len > 0) { 58336381Ssklower /* 58436381Ssklower * The user specified something. Stick it in 58536381Ssklower */ 586*45899Ssklower bcopy(isop->isop_x25crud, lcp->lcd_faddr.x25_udata, 587*45899Ssklower isop->isop_x25crud_len); 588*45899Ssklower lcp->lcd_faddr.x25_udlen = isop->isop_x25crud_len; 58936381Ssklower } 59036381Ssklower } 59136381Ssklower 59236381Ssklower buflen = (int)(ptr - buf); 59336381Ssklower 59436381Ssklower IFDEBUG(D_CDUMP_REQ) 59536381Ssklower register int i; 59636381Ssklower 59736381Ssklower printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n", 59836381Ssklower buf, buflen, buflen); 59936381Ssklower for( i=0; i < buflen; ) { 60036381Ssklower printf("+%d: %x %x %x %x %x %x %x %x\n", 60136381Ssklower i, 60236381Ssklower *(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3), 60336381Ssklower *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7)); 60436381Ssklower i+=8; 60536381Ssklower } 60636381Ssklower ENDDEBUG 60736381Ssklower IFDEBUG(D_CADDR) 60836381Ssklower printf("make_partial returns buf 0x%x size 0x%x bytes\n", 60936381Ssklower mtod(m, caddr_t), buflen); 61036381Ssklower ENDDEBUG 61136381Ssklower 612*45899Ssklower if (buflen > MHLEN) 61336381Ssklower return E_CO_PNA_LONG; 61436381Ssklower 61536381Ssklower m->m_len = buflen; 616*45899Ssklower lcp->lcd_facilities = m; 61736381Ssklower return 0; 61836381Ssklower } 61936381Ssklower 62036381Ssklower /* 62136381Ssklower * NAME: NSAPtoDTE() 62236381Ssklower * CALLED FROM: 62336381Ssklower * make_partial_x25_packet() 62436381Ssklower * FUNCTION and ARGUMENTS: 62536381Ssklower * get a DTE address from an NSAP-address (struct sockaddr_iso) 62636381Ssklower * (dst_octet) is the octet into which to begin stashing the DTE addr 62736381Ssklower * (dst_nibble) takes 0 or 1. 1 means begin filling in the DTE addr 62836381Ssklower * in the high-order nibble of dst_octet. 0 means low-order nibble. 62936381Ssklower * (addr) is the NSAP-address 63036381Ssklower * (flag) is true if the transport suffix is to become the 63136381Ssklower * last two digits of the DTE address 632*45899Ssklower * A DTE address is a series of ASCII digits 63336381Ssklower * 63436381Ssklower * A DTE address may have leading zeros. The are significant. 63536381Ssklower * 1 digit per nibble, may be an odd number of nibbles. 63636381Ssklower * 63736381Ssklower * An NSAP-address has the DTE address in the IDI. Leading zeros are 63836381Ssklower * significant. Trailing hex f indicates the end of the DTE address. 639*45899Ssklower * The IDI is a series of BCD digits, one per nibble. 64036381Ssklower * 64136381Ssklower * RETURNS 64236381Ssklower * # significant digits in the DTE address, -1 if error. 64336381Ssklower */ 64436381Ssklower 64536381Ssklower Static int 646*45899Ssklower NSAPtoDTE(siso, sx25) 647*45899Ssklower register struct sockaddr_iso *siso; 648*45899Ssklower register struct sockaddr_x25 *sx25; 64936381Ssklower { 650*45899Ssklower int dtelen = -1; 65136381Ssklower 65236381Ssklower IFDEBUG(D_CADDR) 653*45899Ssklower printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&siso->siso_addr)); 65436381Ssklower ENDDEBUG 65536381Ssklower 656*45899Ssklower if (siso->siso_data[0] == AFI_37) { 657*45899Ssklower register char *out = sx25->x25_addr; 658*45899Ssklower register char *in = siso->siso_data + 1; 659*45899Ssklower register int nibble; 660*45899Ssklower char *lim = in + 15; 661*45899Ssklower int lowNibble = 0; 662*45899Ssklower 663*45899Ssklower while (in < lim) { 664*45899Ssklower nibble = ((lowNibble ? *in++ : (*in >> 4)) & 0xf) | 0x30; 665*45899Ssklower lowNibble ^= 1; 666*45899Ssklower if (nibble != 0x3f) 667*45899Ssklower *out++ = nibble; 668*45899Ssklower } 669*45899Ssklower dtelen = out - sx25->x25_addr; 670*45899Ssklower *out++ = 0; 671*45899Ssklower } else { 672*45899Ssklower register struct rtentry *rt = rtalloc1(siso, 1); 673*45899Ssklower /* error = iso_8208snparesolve(addr, x121string, &x121strlen);*/ 674*45899Ssklower 675*45899Ssklower if (rt) { 676*45899Ssklower register struct sockaddr_x25 *sxx = 677*45899Ssklower (struct sockaddr_x25 *)rt->rt_gateway; 678*45899Ssklower register char *in = sxx->x25_addr; 679*45899Ssklower 680*45899Ssklower rt->rt_use--; 681*45899Ssklower if (sxx && sxx->x25_family == AF_CCITT) { 682*45899Ssklower bcopy(sx25->x25_addr, sxx->x25_addr, sizeof(sx25->x25_addr)); 683*45899Ssklower while (*in++) {} 684*45899Ssklower dtelen = in - sxx->x25_addr; 685*45899Ssklower } 686*45899Ssklower } 68736381Ssklower } 688*45899Ssklower return dtelen; 68936381Ssklower } 69036381Ssklower 69136381Ssklower /* 69236381Ssklower * NAME: FACILtoNSAP() 69336381Ssklower * CALLED FROM: 69436381Ssklower * parse_facil() 69536381Ssklower * FUNCTION and ARGUMENTS: 69636381Ssklower * Creates and NSAP in the sockaddr_iso (addr) from the 697*45899Ssklower * x.25 facility found at buf - 1. 69836381Ssklower * RETURNS: 699*45899Ssklower * length of parameter if ok, -1 if error. 70036381Ssklower */ 70136381Ssklower 70236381Ssklower Static int 703*45899Ssklower FACILtoNSAP(addr, buf) 704*45899Ssklower u_char *buf; 70536381Ssklower register struct sockaddr_iso *addr; 70636381Ssklower { 707*45899Ssklower int len_in_nibbles, param_len = *buf++; 708*45899Ssklower u_char buf_len; /* in bytes */ 70936381Ssklower 71036381Ssklower IFDEBUG(D_CADDR) 71136381Ssklower printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n", 71236381Ssklower buf, buf_len, addr ); 71336381Ssklower ENDDEBUG 71436381Ssklower 715*45899Ssklower len_in_nibbles = *buf & 0x3f; 716*45899Ssklower buf_len = (len_in_nibbles + 1) >> 1; 71736381Ssklower /* despite the fact that X.25 makes us put a length in nibbles 71836381Ssklower * here, the NSAP-addrs are always in full octets 71936381Ssklower */ 720*45899Ssklower switch (*buf++ & 0xc0) { 721*45899Ssklower case 0: 722*45899Ssklower /* Entire OSI NSAP address */ 723*45899Ssklower bcopy((caddr_t)buf, addr->siso_data, addr->siso_nlen = buf_len); 724*45899Ssklower break; 72536381Ssklower 726*45899Ssklower case 40: 727*45899Ssklower /* Partial OSI NSAP address, assume trailing */ 728*45899Ssklower if (buf_len + addr->siso_nlen > sizeof(addr->siso_addr)) 729*45899Ssklower return -1; 730*45899Ssklower bcopy((caddr_t)buf, TSEL(addr), buf_len); 731*45899Ssklower addr->siso_nlen += buf_len; 732*45899Ssklower break; 73336381Ssklower 734*45899Ssklower default: 735*45899Ssklower /* Rather than blow away the connection, just ignore and use 736*45899Ssklower NSAP from DTE */; 73736381Ssklower } 738*45899Ssklower return param_len; 739*45899Ssklower } 74036381Ssklower 741*45899Ssklower static 742*45899Ssklower init_siso(siso) 743*45899Ssklower register struct sockaddr_iso *siso; 744*45899Ssklower { 745*45899Ssklower siso->siso_len = sizeof (*siso); 746*45899Ssklower siso->siso_family = AF_ISO; 747*45899Ssklower siso->siso_data[0] = AFI_37; 748*45899Ssklower siso->siso_nlen = 8; 74936381Ssklower } 75036381Ssklower 75136381Ssklower /* 75236381Ssklower * NAME: DTEtoNSAP() 75336381Ssklower * CALLED FROM: 75436381Ssklower * parse_facil() 75536381Ssklower * FUNCTION and ARGUMENTS: 75636381Ssklower * Creates a type 37 NSAP in the sockaddr_iso (addr) 757*45899Ssklower * from a DTE address found in a sockaddr_x25. 75836381Ssklower * 75936381Ssklower * RETURNS: 76036381Ssklower * 0 if ok; E* otherwise. 76136381Ssklower */ 76236381Ssklower 76336381Ssklower Static int 764*45899Ssklower DTEtoNSAP(addr, sx) 76536381Ssklower struct sockaddr_iso *addr; 766*45899Ssklower struct sockaddr_x25 *sx; 76736381Ssklower { 768*45899Ssklower register char *in, *out; 769*45899Ssklower register int first; 770*45899Ssklower int pad_tail = 0; 771*45899Ssklower int src_len; 77236381Ssklower 77336381Ssklower 774*45899Ssklower init_siso(addr); 775*45899Ssklower src_len = strlen(sx->x25_addr); 776*45899Ssklower in = sx->x25_addr; 777*45899Ssklower out = addr->siso_data + 1; 778*45899Ssklower if (*in == '0' && (src_len & 1 == 0)) { 779*45899Ssklower pad_tail = 0xf; 780*45899Ssklower src_len++; 781*45899Ssklower } 782*45899Ssklower for (first = 0; src_len > 0; src_len --) { 783*45899Ssklower first |= *in++; 784*45899Ssklower if (src_len & 1) { 785*45899Ssklower *out++ = first; 786*45899Ssklower first = 0; 787*45899Ssklower } 788*45899Ssklower else first <<= 4; 789*45899Ssklower } 790*45899Ssklower if (pad_tail) 791*45899Ssklower out[-1] |= 0xf; 79236381Ssklower return 0; /* ok */ 79336381Ssklower } 79436381Ssklower 79536381Ssklower /* 79636381Ssklower * FUNCTION and ARGUMENTS: 79736381Ssklower * parses (buf_len) bytes beginning at (buf) and finds 79836381Ssklower * a called nsap, a calling nsap, and protocol identifier. 79936381Ssklower * RETURNS: 80036381Ssklower * 0 if ok, E* otherwise. 80136381Ssklower */ 80236381Ssklower 803*45899Ssklower static int 804*45899Ssklower parse_facil(lcp, isop, buf, buf_len) 80536381Ssklower caddr_t buf; 80636381Ssklower u_char buf_len; /* in bytes */ 807*45899Ssklower struct isopcb *isop; 808*45899Ssklower struct pklcd *lcp; 80936381Ssklower { 810*45899Ssklower register struct sockaddr_iso *called = isop->isop_laddr; 811*45899Ssklower register struct sockaddr_iso *calling = isop->isop_faddr; 81236381Ssklower register int i; 813*45899Ssklower register u_char *ptr = (u_char *)buf; 814*45899Ssklower u_char *ptr_lim, *facil_lim; 815*45899Ssklower int facil_param_len, facil_len; 81636381Ssklower 81736381Ssklower IFDEBUG(D_CADDR) 818*45899Ssklower printf("parse_facil(0x%x, 0x%x, 0x%x, 0x%x)\n", 819*45899Ssklower buf, buf_len, called, calling); 82036381Ssklower dump_buf(buf, buf_len); 82136381Ssklower ENDDEBUG 82236381Ssklower 82336381Ssklower /* find the beginnings of the facility fields in buf 82436381Ssklower * by skipping over the called & calling DTE addresses 82536381Ssklower * i <- # nibbles in called + # nibbles in calling 82636381Ssklower * i += 1 so that an odd nibble gets rounded up to even 82736381Ssklower * before dividing by 2, then divide by two to get # octets 82836381Ssklower */ 829*45899Ssklower i = (int)(*ptr >> 4) + (int)(*ptr&0xf); 83036381Ssklower i++; 831*45899Ssklower ptr += i >> 1; 83236381Ssklower ptr ++; /* plus one for the DTE lengths byte */ 83336381Ssklower 83436381Ssklower /* ptr now is at facil_length field */ 835*45899Ssklower facil_len = *ptr++; 836*45899Ssklower facil_lim = ptr + facil_len; 83736381Ssklower IFDEBUG(D_CADDR) 838*45899Ssklower printf("parse_facils: facil length is 0x%x\n", (int) facil_len); 83936381Ssklower ENDDEBUG 84036381Ssklower 841*45899Ssklower while (ptr <= facil_lim) { 84236381Ssklower /* get NSAP addresses from facilities */ 843*45899Ssklower switch (*ptr++) { 84436381Ssklower case 0xcb: 845*45899Ssklower /* calling NSAP */ 846*45899Ssklower facil_param_len = FACILtoNSAP(isop->isop_faddr, ptr); 84736381Ssklower break; 84836381Ssklower case 0xc9: 849*45899Ssklower /* called NSAP */ 850*45899Ssklower facil_param_len = FACILtoNSAP(isop->isop_laddr, ptr); 85136381Ssklower break; 85236381Ssklower 85336381Ssklower /* from here to default are legit cases that I ignore */ 85436381Ssklower /* variable length */ 85536381Ssklower case 0xca: /* end-to-end transit delay negot */ 85636381Ssklower case 0xc6: /* network user id */ 85736381Ssklower case 0xc5: /* charging info : indicating monetary unit */ 85836381Ssklower case 0xc2: /* charging info : indicating segment count */ 85936381Ssklower case 0xc1: /* charging info : indicating call duration */ 86036381Ssklower case 0xc4: /* RPOA extended format */ 86136381Ssklower case 0xc3: /* call redirection notification */ 86236381Ssklower facil_param_len = 0; 86336381Ssklower break; 86436381Ssklower 86536381Ssklower /* 1 octet */ 86636381Ssklower case 0x0a: /* min. throughput class negot */ 86736381Ssklower case 0x02: /* throughput class */ 86836381Ssklower case 0x03: case 0x47: /* CUG shit */ 86936381Ssklower case 0x0b: /* expedited data negot */ 87036381Ssklower case 0x01: /* Fast select or reverse charging 87136381Ssklower (example of intelligent protocol design) */ 87236381Ssklower case 0x04: /* charging info : requesting service */ 87336381Ssklower case 0x08: /* called line addr modified notification */ 87436381Ssklower facil_param_len = 1; 87536381Ssklower break; 87636381Ssklower 87736381Ssklower /* any 2 octets */ 87836381Ssklower case 0x42: /* pkt size */ 87936381Ssklower case 0x43: /* win size */ 88036381Ssklower case 0x44: /* RPOA basic format */ 88136381Ssklower case 0x41: /* bilateral CUG shit */ 88236381Ssklower case 0x49: /* transit delay selection and indication */ 88336381Ssklower facil_param_len = 2; 88436381Ssklower break; 88536381Ssklower 88636381Ssklower /* don't have any 3 octets */ 88736381Ssklower /* 88836381Ssklower facil_param_len = 3; 88936381Ssklower */ 89036381Ssklower default: 89136381Ssklower printf( 89236381Ssklower "BOGUS FACILITY CODE facil_len 0x%x *facil_len 0x%x, ptr 0x%x *ptr 0x%x\n", 893*45899Ssklower ptr, facil_len, ptr - 1, ptr[-1]); 89436381Ssklower /* facil that we don't handle */ 89536381Ssklower return E_CO_HLI_REJI; 89636381Ssklower } 897*45899Ssklower if (facil_param_len == -1) 898*45899Ssklower return E_CO_REG_ICDA; 899*45899Ssklower if (facil_param_len == 0) /* variable length */ 90036381Ssklower facil_param_len = (int)*ptr; /* 1 + the real facil param */ 90136381Ssklower ptr += facil_param_len; 90236381Ssklower } 90336381Ssklower return 0; 90436381Ssklower } 90536381Ssklower 906*45899Ssklower #endif TPCONS 907