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 $ 30*49265Ssklower * @(#)if_cons.c 7.7 (Berkeley) 05/06/91 3136381Ssklower * 3236381Ssklower * cons.c - Connection Oriented Network Service: 3336381Ssklower * including support for a) user transport-level service, 3436381Ssklower * b) COSNS below CLNP, and c) CONS below TP. 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 3945899Ssklower */ 4036381Ssklower 4145899Ssklower #ifdef TPCONS 4245899Ssklower #ifdef KERNEL 4336381Ssklower #ifdef ARGO_DEBUG 4436381Ssklower #define Static 4536381Ssklower unsigned LAST_CALL_PCB; 4636381Ssklower #else ARGO_DEBUG 4736381Ssklower #define Static static 4836381Ssklower #endif ARGO_DEBUG 4936381Ssklower 5036381Ssklower 5136381Ssklower 5245899Ssklower #ifndef SOCK_STREAM 5336381Ssklower #include "param.h" 5436381Ssklower #include "systm.h" 5536381Ssklower #include "mbuf.h" 5636381Ssklower #include "protosw.h" 5736381Ssklower #include "socket.h" 5836381Ssklower #include "socketvar.h" 5936381Ssklower #include "errno.h" 6036381Ssklower #include "ioctl.h" 6140783Smarc #include "tsleep.h" 6236381Ssklower 6336381Ssklower #include "../net/if.h" 6436381Ssklower #include "../net/netisr.h" 6536381Ssklower #include "../net/route.h" 6636381Ssklower 6745899Ssklower #include "iso_errno.h" 6845899Ssklower #include "argo_debug.h" 6945899Ssklower #include "tp_trace.h" 7045899Ssklower #include "iso.h" 7145899Ssklower #include "cons.h" 7245899Ssklower #include "iso_pcb.h" 7336381Ssklower 7445899Ssklower #include "../netccitt/x25.h" 7545899Ssklower #include "../netccitt/pk.h" 7645899Ssklower #include "../netccitt/pk_var.h" 7745899Ssklower #endif 7845899Ssklower 7936381Ssklower #ifdef ARGO_DEBUG 8036381Ssklower #define MT_XCONN 0x50 8136381Ssklower #define MT_XCLOSE 0x51 8236381Ssklower #define MT_XCONFIRM 0x52 8336381Ssklower #define MT_XDATA 0x53 8436381Ssklower #define MT_XHEADER 0x54 8536381Ssklower #else 8636381Ssklower #define MT_XCONN MT_DATA 8736381Ssklower #define MT_XCLOSE MT_DATA 8836381Ssklower #define MT_XCONFIRM MT_DATA 8936381Ssklower #define MT_XDATA MT_DATA 9036381Ssklower #define MT_XHEADER MT_HEADER 9136381Ssklower #endif ARGO_DEBUG 9236381Ssklower 9336381Ssklower #define DONTCLEAR -1 9436381Ssklower 9536381Ssklower /********************************************************************* 9645899Ssklower * cons.c - CONS interface to the x.25 layer 9736381Ssklower * 9836381Ssklower * TODO: figure out what resources we might run out of besides mbufs. 9936381Ssklower * If we run out of any of them (including mbufs) close and recycle 10036381Ssklower * lru x% of the connections, for some parameter x. 10136381Ssklower * 10245899Ssklower * There are 2 interfaces from above: 10336381Ssklower * 1) from TP0: 10436381Ssklower * cons CO network service 10536381Ssklower * TP associates a transport connection with a network connection. 10636381Ssklower * cons_output( isop, m, len, isdgm==0 ) 10736381Ssklower * co_flags == 0 10845899Ssklower * 2) from TP4: 10936381Ssklower * It's a datagram service, like clnp is. - even though it calls 11036381Ssklower * cons_output( isop, m, len, isdgm==1 ) 11136381Ssklower * it eventually goes through 11236381Ssklower * cosns_output(ifp, m, dst). 11336381Ssklower * TP4 permits multiplexing (reuse, possibly simultaneously) of the 11436381Ssklower * network connections. 11536381Ssklower * This means that many sockets (many tpcbs) may be associated with 11645899Ssklower * this pklcd, hence cannot have a back ptr from pklcd to a tpcb. 11736381Ssklower * co_flags & CONSF_DGM 11845899Ssklower * co_socket is null since there may be many sockets that use this pklcd. 11936381Ssklower * 12036381Ssklower NOTE: 12136381Ssklower streams would really be nice. sigh. 12236381Ssklower NOTE: 12336381Ssklower PVCs could be handled by config-ing a cons with an address and with the 12436381Ssklower IFF_POINTTOPOINT flag on. This code would then have to skip the 12536381Ssklower connection setup stuff for pt-to-pt links. 12636381Ssklower 12736381Ssklower 12836381Ssklower *********************************************************************/ 12936381Ssklower 13036381Ssklower 13136381Ssklower #define CONS_IFQMAXLEN 5 13236381Ssklower 13336381Ssklower 13436381Ssklower /* protosw pointers for getting to higher layer */ 13536381Ssklower Static struct protosw *CLNP_proto; 13636381Ssklower Static struct protosw *TP_proto; 13736381Ssklower Static struct protosw *X25_proto; 13836381Ssklower Static int issue_clear_req(); 13936381Ssklower 14036381Ssklower #ifndef PHASEONE 14136381Ssklower extern struct ifaddr *ifa_ifwithnet(); 14236381Ssklower #endif PHASEONE 14336381Ssklower 14436381Ssklower extern struct ifaddr *ifa_ifwithaddr(); 14536381Ssklower 14636381Ssklower Static struct socket dummysocket; /* for use by cosns */ 14736381Ssklower 14836381Ssklower extern struct isopcb tp_isopcb; /* chain of all TP pcbs */ 14936381Ssklower struct isopcb tp_incoming_pending; /* incoming connections 15036381Ssklower for TP, pending */ 15136381Ssklower 15236381Ssklower struct isopcb *Xpcblist[] = { 15336381Ssklower &tp_incoming_pending, 15436381Ssklower &tp_isopcb, 15536381Ssklower (struct isopcb *)0 15636381Ssklower }; 15736381Ssklower 15836381Ssklower Static int parse_facil(), NSAPtoDTE(), make_partial_x25_packet(); 15936381Ssklower Static int FACILtoNSAP(), DTEtoNSAP(); 16045899Ssklower Static struct pklcd *cons_chan_to_pcb(); 16136381Ssklower 16236381Ssklower #define HIGH_NIBBLE 1 16336381Ssklower #define LOW_NIBBLE 0 16436381Ssklower 16536381Ssklower /* 16636381Ssklower * NAME: nibble_copy() 16736381Ssklower * FUNCTION and ARGUMENTS: 16836381Ssklower * copies (len) nibbles from (src_octet), high or low nibble 16936381Ssklower * to (dst_octet), high or low nibble, 17036381Ssklower * src_nibble & dst_nibble should be: 17136381Ssklower * HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble 17236381Ssklower * LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble 17336381Ssklower * RETURNS: VOID 17436381Ssklower */ 17536381Ssklower void 17645899Ssklower nibble_copy(src_octet, src_nibble, dst_octet, dst_nibble, len) 17736381Ssklower register char *src_octet; 17836381Ssklower register char *dst_octet; 17936381Ssklower register unsigned src_nibble; 18036381Ssklower register unsigned dst_nibble; 18136381Ssklower int len; 18236381Ssklower { 18336381Ssklower 18436381Ssklower register i; 18536381Ssklower register unsigned dshift, sshift; 18636381Ssklower 18736381Ssklower IFDEBUG(D_CADDR) 18836381Ssklower printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", 18936381Ssklower src_octet, src_nibble, dst_octet, dst_nibble, len); 19036381Ssklower ENDDEBUG 19136381Ssklower #define SHIFT 0x4 19236381Ssklower 19336381Ssklower dshift = dst_nibble << 2; 19436381Ssklower sshift = src_nibble << 2; 19536381Ssklower 19636381Ssklower for (i=0; i<len; i++) { 19736381Ssklower /* clear dst_nibble */ 19836381Ssklower *dst_octet &= ~(0xf<< dshift); 19936381Ssklower 20036381Ssklower /* set dst nibble */ 20136381Ssklower *dst_octet |= ( 0xf & (*src_octet >> sshift))<< dshift; 20236381Ssklower 20336381Ssklower dshift ^= SHIFT; 20436381Ssklower sshift ^= SHIFT; 20536381Ssklower src_nibble = 1-src_nibble; 20636381Ssklower dst_nibble = 1-dst_nibble; 20736381Ssklower src_octet += src_nibble; 20836381Ssklower dst_octet += dst_nibble; 20936381Ssklower } 21036381Ssklower IFDEBUG(D_CADDR) 21136381Ssklower printf("nibble_copy DONE\n"); 21236381Ssklower ENDDEBUG 21336381Ssklower } 21436381Ssklower 21536381Ssklower /* 21636381Ssklower * NAME: nibble_match() 21736381Ssklower * FUNCTION and ARGUMENTS: 21836381Ssklower * compares src_octet/src_nibble and dst_octet/dst_nibble for len nibbles. 21936381Ssklower * RETURNS: 0 if they differ, 1 if they are the same. 22036381Ssklower */ 22136381Ssklower int 22236381Ssklower nibble_match( src_octet, src_nibble, dst_octet, dst_nibble, len) 22336381Ssklower register char *src_octet; 22436381Ssklower register char *dst_octet; 22536381Ssklower register unsigned src_nibble; 22636381Ssklower register unsigned dst_nibble; 22736381Ssklower int len; 22836381Ssklower { 22936381Ssklower 23036381Ssklower register i; 23136381Ssklower register unsigned dshift, sshift; 23236381Ssklower u_char nibble_a, nibble_b; 23336381Ssklower 23436381Ssklower IFDEBUG(D_CADDR) 23536381Ssklower printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", 23636381Ssklower src_octet, src_nibble, dst_octet, dst_nibble, len); 23736381Ssklower ENDDEBUG 23836381Ssklower #define SHIFT 0x4 23936381Ssklower 24036381Ssklower dshift = dst_nibble << 2; 24136381Ssklower sshift = src_nibble << 2; 24236381Ssklower 24336381Ssklower for (i=0; i<len; i++) { 24436381Ssklower nibble_b = ((*dst_octet)>>dshift) & 0xf; 24536381Ssklower nibble_a = ( 0xf & (*src_octet >> sshift)); 24645899Ssklower if (nibble_b != nibble_a) 24736381Ssklower return 0; 24836381Ssklower 24936381Ssklower dshift ^= SHIFT; 25036381Ssklower sshift ^= SHIFT; 25136381Ssklower src_nibble = 1-src_nibble; 25236381Ssklower dst_nibble = 1-dst_nibble; 25336381Ssklower src_octet += src_nibble; 25436381Ssklower dst_octet += dst_nibble; 25536381Ssklower } 25636381Ssklower IFDEBUG(D_CADDR) 25736381Ssklower printf("nibble_match DONE\n"); 25836381Ssklower ENDDEBUG 25936381Ssklower return 1; 26036381Ssklower } 26136381Ssklower 26236381Ssklower /* 26336381Ssklower **************************** NET PROTOCOL cons *************************** 26436381Ssklower */ 26536381Ssklower /* 26636381Ssklower * NAME: cons_init() 26736381Ssklower * CALLED FROM: 26836381Ssklower * autoconf 26936381Ssklower * FUNCTION: 27036381Ssklower * initialize the protocol 27136381Ssklower */ 27236381Ssklower cons_init() 27336381Ssklower { 27445899Ssklower int tp_incoming(), clnp_incoming(); 27536381Ssklower 27636381Ssklower 27736381Ssklower CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM); 27836381Ssklower X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM); 27936381Ssklower TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET); 28036381Ssklower IFDEBUG(D_CCONS) 28136381Ssklower printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n", 28236381Ssklower CLNP_proto, X25_proto, TP_proto); 28336381Ssklower ENDDEBUG 28445899Ssklower #ifdef notdef 28545899Ssklower pk_protolisten(0x81, 0, clnp_incoming); 28645899Ssklower pk_protolisten(0x82, 0, esis_incoming); 28745899Ssklower pk_protolisten(0x84, 0, tp8878_A_incoming); 28849041Ssklower pk_protolisten(0, 0, tp_incoming); 28945899Ssklower #endif 29036381Ssklower } 29136381Ssklower 29245899Ssklower tp_incoming(lcp, m0) 29345899Ssklower struct pklcd *lcp; 29445899Ssklower struct mbuf *m0; 29536381Ssklower { 29645899Ssklower register struct mbuf *m = m0->m_next; /* m0 has calling sockaddr_x25 */ 29745899Ssklower register struct isopcb *isop; 29845899Ssklower extern struct isopcb tp_isopcb; 29945899Ssklower int cons_tpinput(); 30036381Ssklower 30145899Ssklower if (iso_pcballoc((struct socket *)0, &tp_incoming_pending)) { 30245899Ssklower m_freem(m); 30345899Ssklower pk_clear(lcp); 30445899Ssklower return; 30536381Ssklower } 30645899Ssklower isop = tp_incoming_pending.isop_next; 30745899Ssklower pk_output(lcp); /* Confirms call */ 30845899Ssklower lcp->lcd_upper = cons_tpinput; 30945899Ssklower lcp->lcd_upnext = (caddr_t)isop; 31045899Ssklower isop->isop_chan = (caddr_t)lcp; 31145899Ssklower isop->isop_laddr = &isop->isop_sladdr; 31245899Ssklower isop->isop_faddr = &isop->isop_sfaddr; 31345899Ssklower DTEtoNSAP(isop->isop_laddr, &lcp->lcd_laddr); 31445899Ssklower DTEtoNSAP(isop->isop_faddr, &lcp->lcd_faddr); 31545899Ssklower parse_facil(isop, lcp, &(mtod(m, struct x25_packet *)->packet_data), 31645899Ssklower m->m_pkthdr.len - PKHEADERLN); 31745899Ssklower m_freem(m); 31836381Ssklower } 31936381Ssklower 32045899Ssklower cons_tpinput(lcp, m0) 32145899Ssklower struct mbuf *m0; 32245899Ssklower struct pklcd *lcp; 32336381Ssklower { 32445899Ssklower register struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext; 32545899Ssklower register struct x25_packet *xp; 32645899Ssklower int cmd; 32736381Ssklower 328*49265Ssklower if (isop == 0) 329*49265Ssklower return; 330*49265Ssklower if (m0 == 0) { 331*49265Ssklower isop->isop_chan = 0; 332*49265Ssklower isop->isop_refcnt = 0; 333*49265Ssklower lcp->lcd_upnext = 0; 334*49265Ssklower lcp->lcd_upper = 0; 33549041Ssklower goto dead; 336*49265Ssklower } 33745899Ssklower switch(m0->m_type) { 33845899Ssklower case MT_DATA: 33945899Ssklower case MT_OOBDATA: 34045899Ssklower tpcons_input(m0, isop->isop_faddr, isop->isop_laddr, 34145899Ssklower (struct socket *)0, (caddr_t)lcp); 34236381Ssklower 34345899Ssklower case MT_CONTROL: 34445899Ssklower switch (pk_decode(mtod(m0, struct x25_packet *))) { 34545899Ssklower default: 34645899Ssklower return; 34736381Ssklower 34845899Ssklower case RR: 34945899Ssklower cmd = PRC_CONS_SEND_DONE; 35045899Ssklower break; 35136381Ssklower 352*49265Ssklower case CALL_ACCEPTED: 353*49265Ssklower if (lcp->lcd_sb.sb_mb) 354*49265Ssklower lcp->lcd_send(lcp); /* XXX - fix this */ 355*49265Ssklower break; 356*49265Ssklower 35749041Ssklower dead: 35845899Ssklower case RESET: 35949041Ssklower case CLEAR: 36049041Ssklower case CLEAR_CONF: 36145899Ssklower cmd = PRC_ROUTEDEAD; 36236381Ssklower } 36345899Ssklower tpcons_ctlinput(cmd, isop->isop_faddr, isop); 36436381Ssklower } 36536381Ssklower } 36636381Ssklower 36736381Ssklower /* 36836381Ssklower * NAME: cons_connect() 36936381Ssklower * CALLED FROM: 37045899Ssklower * tpcons_pcbconnect() when opening a new connection. 37136381Ssklower * FUNCTION anD ARGUMENTS: 37236381Ssklower * Figures out which device to use, finding a route if one doesn't 37336381Ssklower * already exist. 37436381Ssklower * RETURN VALUE: 37536381Ssklower * returns E* 37636381Ssklower */ 37745899Ssklower cons_connect(isop) 37845899Ssklower register struct isopcb *isop; 37936381Ssklower { 38045899Ssklower register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 38136381Ssklower register struct mbuf *m; 38236381Ssklower struct ifaddr *ifa; 38336381Ssklower 38436381Ssklower IFDEBUG(D_CCONN) 38545899Ssklower printf("cons_connect(0x%x): ", isop); 38645899Ssklower dump_isoaddr(isop->isop_faddr); 38745899Ssklower printf("myaddr: "); 38845899Ssklower dump_isoaddr(isop->isop_laddr); 38936381Ssklower printf("\n" ); 39036381Ssklower ENDDEBUG 39145899Ssklower NSAPtoDTE(isop->isop_faddr, &lcp->lcd_faddr); 392*49265Ssklower lcp->lcd_upper = cons_tpinput; 393*49265Ssklower lcp->lcd_upnext = (caddr_t)isop; 39436381Ssklower IFDEBUG(D_CCONN) 39536381Ssklower printf( 39645899Ssklower "calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x)\n", 39745899Ssklower &lcp->lcd_faddr, &lcp->lcd_laddr, 39845899Ssklower isop->isop_socket->so_proto->pr_protocol); 39936381Ssklower ENDDEBUG 40045899Ssklower return (make_partial_x25_packet(isop, lcp, m) || 40145899Ssklower pk_connect(lcp, &lcp->lcd_faddr)); 40236381Ssklower } 40336381Ssklower 40436381Ssklower /* 40536381Ssklower **************************** DEVICE cons *************************** 40636381Ssklower */ 40736381Ssklower 40836381Ssklower 40936381Ssklower /* 41036381Ssklower * NAME: cons_ctlinput() 41136381Ssklower * CALLED FROM: 41236381Ssklower * lower layer when ECN_CLEAR occurs : this routine is here 41336381Ssklower * for consistency - cons subnet service calls its higher layer 41436381Ssklower * through the protosw entry. 41536381Ssklower * FUNCTION & ARGUMENTS: 41637536Smckusick * cmd is a PRC_* command, list found in ../sys/protosw.h 41736381Ssklower * copcb is the obvious. 41836381Ssklower * This serves the higher-layer cons service. 41936381Ssklower * NOTE: this takes 3rd arg. because cons uses it to inform itself 42036381Ssklower * of things (timeouts, etc) but has a pcb instead of an address. 42136381Ssklower */ 42236381Ssklower cons_ctlinput(cmd, sa, copcb) 42336381Ssklower int cmd; 42436381Ssklower struct sockaddr *sa; 42545899Ssklower register struct pklcd *copcb; 42636381Ssklower { 42736381Ssklower } 42836381Ssklower 42936381Ssklower 43045899Ssklower find_error_reason( xp ) 43145899Ssklower register struct x25_packet *xp; 43236381Ssklower { 43336381Ssklower extern u_char x25_error_stats[]; 43445899Ssklower int error, cause; 43536381Ssklower 43645899Ssklower if (xp) { 43745899Ssklower cause = 4[(char *)xp]; 43845899Ssklower switch (cause) { 43936381Ssklower case 0x00: 44036381Ssklower case 0x80: 44136381Ssklower /* DTE originated; look at the diagnostic */ 44245899Ssklower error = (CONL_ERROR_MASK | cause); 44336381Ssklower goto done; 44436381Ssklower 44536381Ssklower case 0x01: /* number busy */ 44636381Ssklower case 0x81: 44736381Ssklower case 0x09: /* Out of order */ 44836381Ssklower case 0x89: 44936381Ssklower case 0x11: /* Remot Procedure Error */ 45036381Ssklower case 0x91: 45136381Ssklower case 0x19: /* reverse charging accept not subscribed */ 45236381Ssklower case 0x99: 45336381Ssklower case 0x21: /* Incampat destination */ 45436381Ssklower case 0xa1: 45536381Ssklower case 0x29: /* fast select accept not subscribed */ 45636381Ssklower case 0xa9: 45736381Ssklower case 0x39: /* ship absent */ 45836381Ssklower case 0xb9: 45936381Ssklower case 0x03: /* invalid facil request */ 46036381Ssklower case 0x83: 46136381Ssklower case 0x0b: /* access barred */ 46236381Ssklower case 0x8b: 46336381Ssklower case 0x13: /* local procedure error */ 46436381Ssklower case 0x93: 46536381Ssklower case 0x05: /* network congestion */ 46636381Ssklower case 0x85: 46736381Ssklower case 0x8d: /* not obtainable */ 46836381Ssklower case 0x0d: 46936381Ssklower case 0x95: /* RPOA out of order */ 47036381Ssklower case 0x15: 47136381Ssklower /* take out bit 8 47236381Ssklower * so we don't have to have so many perror entries 47336381Ssklower */ 47445899Ssklower error = (CONL_ERROR_MASK | 0x100 | (cause & ~0x80)); 47536381Ssklower goto done; 47636381Ssklower 47736381Ssklower case 0xc1: /* gateway-detected proc error */ 47836381Ssklower case 0xc3: /* gateway congestion */ 47936381Ssklower 48045899Ssklower error = (CONL_ERROR_MASK | 0x100 | cause); 48136381Ssklower goto done; 48236381Ssklower } 48336381Ssklower } 48436381Ssklower /* otherwise, a *hopefully* valid perror exists in the e_reason field */ 48545899Ssklower error = xp->packet_data; 48636381Ssklower if (error = 0) { 48736381Ssklower printf("Incoming PKT TYPE 0x%x with reason 0x%x\n", 48845899Ssklower pk_decode(xp), 48945899Ssklower cause); 49036381Ssklower error = E_CO_HLI_DISCA; 49136381Ssklower } 49236381Ssklower 49336381Ssklower done: 49436381Ssklower return error; 49536381Ssklower } 49636381Ssklower 49736381Ssklower 49836381Ssklower 49936381Ssklower #endif KERNEL 50036381Ssklower 50136381Ssklower /* 50236381Ssklower * NAME: make_partial_x25_packet() 50336381Ssklower * 50436381Ssklower * FUNCTION and ARGUMENTS: 50545899Ssklower * Makes part of an X.25 call packet, for use by x25. 50636381Ssklower * (src) and (dst) are the NSAP-addresses of source and destination. 50736381Ssklower * (buf) is a ptr to a buffer into which to write this partial header. 50836381Ssklower * 50945899Ssklower * 0 Facility length (in octets) 51045899Ssklower * 1 Facility field, which is a set of: 51136381Ssklower * m facil code 51236381Ssklower * m+1 facil param len (for >2-byte facilities) in octets 51336381Ssklower * m+2..p facil param field 51436381Ssklower * q user data (protocol identification octet) 51536381Ssklower * 51636381Ssklower * 51736381Ssklower * RETURNS: 51836381Ssklower * 0 if OK 51936381Ssklower * E* if failed. 52045899Ssklower * 52145899Ssklower * SIDE EFFECTS: 52245899Ssklower * Stores facilites mbuf in X.25 control block, where the connect 52345899Ssklower * routine knows where to look for it. 52436381Ssklower */ 52536381Ssklower 52636381Ssklower #ifdef X25_1984 52736381Ssklower int cons_use_facils = 1; 52836381Ssklower #else X25_1984 52936381Ssklower int cons_use_facils = 0; 53036381Ssklower #endif X25_1984 53136381Ssklower 53236381Ssklower int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */ 53336381Ssklower 53436381Ssklower Static int 53545899Ssklower make_partial_x25_packet(isop, lcp) 53645899Ssklower struct isopcb *isop; 53745899Ssklower struct pklcd *lcp; 53836381Ssklower { 53936381Ssklower u_int proto; 54036381Ssklower int flag; 54145899Ssklower caddr_t buf; 54249041Ssklower register caddr_t ptr; 54336381Ssklower register int len = 0; 54436381Ssklower int buflen =0; 54536381Ssklower caddr_t facil_len; 54636381Ssklower int oddness = 0; 54745899Ssklower struct mbuf *m; 54836381Ssklower 54936381Ssklower 55045899Ssklower MGET(m, MT_DATA, M_WAITOK); 55145899Ssklower if (m == 0) 55245899Ssklower return ENOBUFS; 55345899Ssklower buf = mtod(m, caddr_t); 55449041Ssklower ptr = buf; 55536381Ssklower IFDEBUG(D_CCONN) 55636381Ssklower printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", 55745899Ssklower isop->isop_laddr, isop->isop_faddr, proto, m, flag); 55836381Ssklower ENDDEBUG 55936381Ssklower 56036381Ssklower /* ptr now points to facil length (len of whole facil field in OCTETS */ 56136381Ssklower facil_len = ptr ++; 56236381Ssklower 56336381Ssklower IFDEBUG(D_CADDR) 56436381Ssklower printf("make_partial calling: ptr 0x%x, len 0x%x\n", ptr, 56545899Ssklower isop->isop_laddr->siso_addr.isoa_len); 56636381Ssklower ENDDEBUG 56745899Ssklower if (cons_use_facils) { 56836381Ssklower *ptr = 0xcb; /* calling facility code */ 56936381Ssklower ptr ++; 57036381Ssklower ptr ++; /* leave room for facil param len (in OCTETS + 1) */ 57136381Ssklower ptr ++; /* leave room for the facil param len (in nibbles), 57236381Ssklower * high two bits of which indicate full/partial NSAP 57336381Ssklower */ 57445899Ssklower len = isop->isop_laddr->siso_addr.isoa_len; 57545899Ssklower bcopy( isop->isop_laddr->siso_data, ptr, len); 57636381Ssklower *(ptr-2) = len+2; /* facil param len in octets */ 57736381Ssklower *(ptr-1) = len<<1; /* facil param len in nibbles */ 57836381Ssklower ptr += len; 57936381Ssklower 58036381Ssklower IFDEBUG(D_CADDR) 58136381Ssklower printf("make_partial called: ptr 0x%x, len 0x%x\n", ptr, 58245899Ssklower isop->isop_faddr->siso_addr.isoa_len); 58336381Ssklower ENDDEBUG 58436381Ssklower *ptr = 0xc9; /* called facility code */ 58536381Ssklower ptr ++; 58636381Ssklower ptr ++; /* leave room for facil param len (in OCTETS + 1) */ 58736381Ssklower ptr ++; /* leave room for the facil param len (in nibbles), 58836381Ssklower * high two bits of which indicate full/partial NSAP 58936381Ssklower */ 59045899Ssklower len = isop->isop_faddr->siso_nlen; 59145899Ssklower bcopy(isop->isop_faddr->siso_data, ptr, len); 59236381Ssklower *(ptr-2) = len+2; /* facil param len = addr len + 1 for each of these 59336381Ssklower * two length fields, in octets */ 59436381Ssklower *(ptr-1) = len<<1; /* facil param len in nibbles */ 59536381Ssklower ptr += len; 59636381Ssklower 59736381Ssklower } 59836381Ssklower *facil_len = ptr - facil_len - 1; 59945899Ssklower if (*facil_len > MAX_FACILITIES) 60036381Ssklower return E_CO_PNA_LONG; 60136381Ssklower 60245899Ssklower if (cons_use_udata) { 60345899Ssklower if (isop->isop_x25crud_len > 0) { 60436381Ssklower /* 60536381Ssklower * The user specified something. Stick it in 60636381Ssklower */ 60745899Ssklower bcopy(isop->isop_x25crud, lcp->lcd_faddr.x25_udata, 60845899Ssklower isop->isop_x25crud_len); 60945899Ssklower lcp->lcd_faddr.x25_udlen = isop->isop_x25crud_len; 61036381Ssklower } 61136381Ssklower } 61236381Ssklower 61336381Ssklower buflen = (int)(ptr - buf); 61436381Ssklower 61536381Ssklower IFDEBUG(D_CDUMP_REQ) 61636381Ssklower register int i; 61736381Ssklower 61836381Ssklower printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n", 61936381Ssklower buf, buflen, buflen); 62036381Ssklower for( i=0; i < buflen; ) { 62136381Ssklower printf("+%d: %x %x %x %x %x %x %x %x\n", 62236381Ssklower i, 62336381Ssklower *(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3), 62436381Ssklower *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7)); 62536381Ssklower i+=8; 62636381Ssklower } 62736381Ssklower ENDDEBUG 62836381Ssklower IFDEBUG(D_CADDR) 62936381Ssklower printf("make_partial returns buf 0x%x size 0x%x bytes\n", 63036381Ssklower mtod(m, caddr_t), buflen); 63136381Ssklower ENDDEBUG 63236381Ssklower 63345899Ssklower if (buflen > MHLEN) 63436381Ssklower return E_CO_PNA_LONG; 63536381Ssklower 63636381Ssklower m->m_len = buflen; 63745899Ssklower lcp->lcd_facilities = m; 63836381Ssklower return 0; 63936381Ssklower } 64036381Ssklower 64136381Ssklower /* 64236381Ssklower * NAME: NSAPtoDTE() 64336381Ssklower * CALLED FROM: 64436381Ssklower * make_partial_x25_packet() 64536381Ssklower * FUNCTION and ARGUMENTS: 64636381Ssklower * get a DTE address from an NSAP-address (struct sockaddr_iso) 64736381Ssklower * (dst_octet) is the octet into which to begin stashing the DTE addr 64836381Ssklower * (dst_nibble) takes 0 or 1. 1 means begin filling in the DTE addr 64936381Ssklower * in the high-order nibble of dst_octet. 0 means low-order nibble. 65036381Ssklower * (addr) is the NSAP-address 65136381Ssklower * (flag) is true if the transport suffix is to become the 65236381Ssklower * last two digits of the DTE address 65345899Ssklower * A DTE address is a series of ASCII digits 65436381Ssklower * 65536381Ssklower * A DTE address may have leading zeros. The are significant. 65636381Ssklower * 1 digit per nibble, may be an odd number of nibbles. 65736381Ssklower * 65836381Ssklower * An NSAP-address has the DTE address in the IDI. Leading zeros are 65936381Ssklower * significant. Trailing hex f indicates the end of the DTE address. 66045899Ssklower * The IDI is a series of BCD digits, one per nibble. 66136381Ssklower * 66236381Ssklower * RETURNS 66336381Ssklower * # significant digits in the DTE address, -1 if error. 66436381Ssklower */ 66536381Ssklower 66636381Ssklower Static int 66745899Ssklower NSAPtoDTE(siso, sx25) 66845899Ssklower register struct sockaddr_iso *siso; 66945899Ssklower register struct sockaddr_x25 *sx25; 67036381Ssklower { 67145899Ssklower int dtelen = -1; 67236381Ssklower 67336381Ssklower IFDEBUG(D_CADDR) 67445899Ssklower printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&siso->siso_addr)); 67536381Ssklower ENDDEBUG 67636381Ssklower 67745899Ssklower if (siso->siso_data[0] == AFI_37) { 67845899Ssklower register char *out = sx25->x25_addr; 67945899Ssklower register char *in = siso->siso_data + 1; 68045899Ssklower register int nibble; 68149041Ssklower char *lim = siso->siso_data + siso->siso_nlen; 68249041Ssklower char *olim = out+15; 68345899Ssklower int lowNibble = 0; 68445899Ssklower 68545899Ssklower while (in < lim) { 68645899Ssklower nibble = ((lowNibble ? *in++ : (*in >> 4)) & 0xf) | 0x30; 68745899Ssklower lowNibble ^= 1; 68849041Ssklower if (nibble != 0x3f && out < olim) 68945899Ssklower *out++ = nibble; 69045899Ssklower } 69145899Ssklower dtelen = out - sx25->x25_addr; 69245899Ssklower *out++ = 0; 69345899Ssklower } else { 69445899Ssklower register struct rtentry *rt = rtalloc1(siso, 1); 69545899Ssklower /* error = iso_8208snparesolve(addr, x121string, &x121strlen);*/ 69645899Ssklower 69745899Ssklower if (rt) { 69845899Ssklower register struct sockaddr_x25 *sxx = 69945899Ssklower (struct sockaddr_x25 *)rt->rt_gateway; 70045899Ssklower register char *in = sxx->x25_addr; 70145899Ssklower 70245899Ssklower rt->rt_use--; 70345899Ssklower if (sxx && sxx->x25_family == AF_CCITT) { 70445899Ssklower bcopy(sx25->x25_addr, sxx->x25_addr, sizeof(sx25->x25_addr)); 70545899Ssklower while (*in++) {} 70645899Ssklower dtelen = in - sxx->x25_addr; 70745899Ssklower } 70845899Ssklower } 70936381Ssklower } 71045899Ssklower return dtelen; 71136381Ssklower } 71236381Ssklower 71336381Ssklower /* 71436381Ssklower * NAME: FACILtoNSAP() 71536381Ssklower * CALLED FROM: 71636381Ssklower * parse_facil() 71736381Ssklower * FUNCTION and ARGUMENTS: 71836381Ssklower * Creates and NSAP in the sockaddr_iso (addr) from the 71945899Ssklower * x.25 facility found at buf - 1. 72036381Ssklower * RETURNS: 72145899Ssklower * length of parameter if ok, -1 if error. 72236381Ssklower */ 72336381Ssklower 72436381Ssklower Static int 72545899Ssklower FACILtoNSAP(addr, buf) 72645899Ssklower u_char *buf; 72736381Ssklower register struct sockaddr_iso *addr; 72836381Ssklower { 72945899Ssklower int len_in_nibbles, param_len = *buf++; 73045899Ssklower u_char buf_len; /* in bytes */ 73136381Ssklower 73236381Ssklower IFDEBUG(D_CADDR) 73336381Ssklower printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n", 73436381Ssklower buf, buf_len, addr ); 73536381Ssklower ENDDEBUG 73636381Ssklower 73745899Ssklower len_in_nibbles = *buf & 0x3f; 73845899Ssklower buf_len = (len_in_nibbles + 1) >> 1; 73936381Ssklower /* despite the fact that X.25 makes us put a length in nibbles 74036381Ssklower * here, the NSAP-addrs are always in full octets 74136381Ssklower */ 74245899Ssklower switch (*buf++ & 0xc0) { 74345899Ssklower case 0: 74445899Ssklower /* Entire OSI NSAP address */ 74545899Ssklower bcopy((caddr_t)buf, addr->siso_data, addr->siso_nlen = buf_len); 74645899Ssklower break; 74736381Ssklower 74845899Ssklower case 40: 74945899Ssklower /* Partial OSI NSAP address, assume trailing */ 75045899Ssklower if (buf_len + addr->siso_nlen > sizeof(addr->siso_addr)) 75145899Ssklower return -1; 75245899Ssklower bcopy((caddr_t)buf, TSEL(addr), buf_len); 75345899Ssklower addr->siso_nlen += buf_len; 75445899Ssklower break; 75536381Ssklower 75645899Ssklower default: 75745899Ssklower /* Rather than blow away the connection, just ignore and use 75845899Ssklower NSAP from DTE */; 75936381Ssklower } 76045899Ssklower return param_len; 76145899Ssklower } 76236381Ssklower 76345899Ssklower static 76445899Ssklower init_siso(siso) 76545899Ssklower register struct sockaddr_iso *siso; 76645899Ssklower { 76745899Ssklower siso->siso_len = sizeof (*siso); 76845899Ssklower siso->siso_family = AF_ISO; 76945899Ssklower siso->siso_data[0] = AFI_37; 77045899Ssklower siso->siso_nlen = 8; 77136381Ssklower } 77236381Ssklower 77336381Ssklower /* 77436381Ssklower * NAME: DTEtoNSAP() 77536381Ssklower * CALLED FROM: 77636381Ssklower * parse_facil() 77736381Ssklower * FUNCTION and ARGUMENTS: 77836381Ssklower * Creates a type 37 NSAP in the sockaddr_iso (addr) 77945899Ssklower * from a DTE address found in a sockaddr_x25. 78036381Ssklower * 78136381Ssklower * RETURNS: 78236381Ssklower * 0 if ok; E* otherwise. 78336381Ssklower */ 78436381Ssklower 78536381Ssklower Static int 78645899Ssklower DTEtoNSAP(addr, sx) 78736381Ssklower struct sockaddr_iso *addr; 78845899Ssklower struct sockaddr_x25 *sx; 78936381Ssklower { 79045899Ssklower register char *in, *out; 79145899Ssklower register int first; 79245899Ssklower int pad_tail = 0; 79345899Ssklower int src_len; 79436381Ssklower 79536381Ssklower 79645899Ssklower init_siso(addr); 79745899Ssklower src_len = strlen(sx->x25_addr); 79845899Ssklower in = sx->x25_addr; 79945899Ssklower out = addr->siso_data + 1; 80045899Ssklower if (*in == '0' && (src_len & 1 == 0)) { 80145899Ssklower pad_tail = 0xf; 80245899Ssklower src_len++; 80345899Ssklower } 80445899Ssklower for (first = 0; src_len > 0; src_len --) { 80545899Ssklower first |= *in++; 80645899Ssklower if (src_len & 1) { 80745899Ssklower *out++ = first; 80845899Ssklower first = 0; 80945899Ssklower } 81045899Ssklower else first <<= 4; 81145899Ssklower } 81245899Ssklower if (pad_tail) 81345899Ssklower out[-1] |= 0xf; 81436381Ssklower return 0; /* ok */ 81536381Ssklower } 81636381Ssklower 81736381Ssklower /* 81836381Ssklower * FUNCTION and ARGUMENTS: 81936381Ssklower * parses (buf_len) bytes beginning at (buf) and finds 82036381Ssklower * a called nsap, a calling nsap, and protocol identifier. 82136381Ssklower * RETURNS: 82236381Ssklower * 0 if ok, E* otherwise. 82336381Ssklower */ 82436381Ssklower 82545899Ssklower static int 82645899Ssklower parse_facil(lcp, isop, buf, buf_len) 82736381Ssklower caddr_t buf; 82836381Ssklower u_char buf_len; /* in bytes */ 82945899Ssklower struct isopcb *isop; 83045899Ssklower struct pklcd *lcp; 83136381Ssklower { 83245899Ssklower register struct sockaddr_iso *called = isop->isop_laddr; 83345899Ssklower register struct sockaddr_iso *calling = isop->isop_faddr; 83436381Ssklower register int i; 83545899Ssklower register u_char *ptr = (u_char *)buf; 83645899Ssklower u_char *ptr_lim, *facil_lim; 83745899Ssklower int facil_param_len, facil_len; 83836381Ssklower 83936381Ssklower IFDEBUG(D_CADDR) 84045899Ssklower printf("parse_facil(0x%x, 0x%x, 0x%x, 0x%x)\n", 84145899Ssklower buf, buf_len, called, calling); 84236381Ssklower dump_buf(buf, buf_len); 84336381Ssklower ENDDEBUG 84436381Ssklower 84536381Ssklower /* find the beginnings of the facility fields in buf 84636381Ssklower * by skipping over the called & calling DTE addresses 84736381Ssklower * i <- # nibbles in called + # nibbles in calling 84836381Ssklower * i += 1 so that an odd nibble gets rounded up to even 84936381Ssklower * before dividing by 2, then divide by two to get # octets 85036381Ssklower */ 85145899Ssklower i = (int)(*ptr >> 4) + (int)(*ptr&0xf); 85236381Ssklower i++; 85345899Ssklower ptr += i >> 1; 85436381Ssklower ptr ++; /* plus one for the DTE lengths byte */ 85536381Ssklower 85636381Ssklower /* ptr now is at facil_length field */ 85745899Ssklower facil_len = *ptr++; 85845899Ssklower facil_lim = ptr + facil_len; 85936381Ssklower IFDEBUG(D_CADDR) 86045899Ssklower printf("parse_facils: facil length is 0x%x\n", (int) facil_len); 86136381Ssklower ENDDEBUG 86236381Ssklower 86345899Ssklower while (ptr <= facil_lim) { 86436381Ssklower /* get NSAP addresses from facilities */ 86545899Ssklower switch (*ptr++) { 86636381Ssklower case 0xcb: 86745899Ssklower /* calling NSAP */ 86845899Ssklower facil_param_len = FACILtoNSAP(isop->isop_faddr, ptr); 86936381Ssklower break; 87036381Ssklower case 0xc9: 87145899Ssklower /* called NSAP */ 87245899Ssklower facil_param_len = FACILtoNSAP(isop->isop_laddr, ptr); 87336381Ssklower break; 87436381Ssklower 87536381Ssklower /* from here to default are legit cases that I ignore */ 87636381Ssklower /* variable length */ 87736381Ssklower case 0xca: /* end-to-end transit delay negot */ 87836381Ssklower case 0xc6: /* network user id */ 87936381Ssklower case 0xc5: /* charging info : indicating monetary unit */ 88036381Ssklower case 0xc2: /* charging info : indicating segment count */ 88136381Ssklower case 0xc1: /* charging info : indicating call duration */ 88236381Ssklower case 0xc4: /* RPOA extended format */ 88336381Ssklower case 0xc3: /* call redirection notification */ 88436381Ssklower facil_param_len = 0; 88536381Ssklower break; 88636381Ssklower 88736381Ssklower /* 1 octet */ 88836381Ssklower case 0x0a: /* min. throughput class negot */ 88936381Ssklower case 0x02: /* throughput class */ 89036381Ssklower case 0x03: case 0x47: /* CUG shit */ 89136381Ssklower case 0x0b: /* expedited data negot */ 89236381Ssklower case 0x01: /* Fast select or reverse charging 89336381Ssklower (example of intelligent protocol design) */ 89436381Ssklower case 0x04: /* charging info : requesting service */ 89536381Ssklower case 0x08: /* called line addr modified notification */ 89636381Ssklower facil_param_len = 1; 89736381Ssklower break; 89836381Ssklower 89936381Ssklower /* any 2 octets */ 90036381Ssklower case 0x42: /* pkt size */ 90136381Ssklower case 0x43: /* win size */ 90236381Ssklower case 0x44: /* RPOA basic format */ 90336381Ssklower case 0x41: /* bilateral CUG shit */ 90436381Ssklower case 0x49: /* transit delay selection and indication */ 90536381Ssklower facil_param_len = 2; 90636381Ssklower break; 90736381Ssklower 90836381Ssklower /* don't have any 3 octets */ 90936381Ssklower /* 91036381Ssklower facil_param_len = 3; 91136381Ssklower */ 91236381Ssklower default: 91336381Ssklower printf( 91436381Ssklower "BOGUS FACILITY CODE facil_len 0x%x *facil_len 0x%x, ptr 0x%x *ptr 0x%x\n", 91545899Ssklower ptr, facil_len, ptr - 1, ptr[-1]); 91636381Ssklower /* facil that we don't handle */ 91736381Ssklower return E_CO_HLI_REJI; 91836381Ssklower } 91945899Ssklower if (facil_param_len == -1) 92045899Ssklower return E_CO_REG_ICDA; 92145899Ssklower if (facil_param_len == 0) /* variable length */ 92236381Ssklower facil_param_len = (int)*ptr; /* 1 + the real facil param */ 92336381Ssklower ptr += facil_param_len; 92436381Ssklower } 92536381Ssklower return 0; 92636381Ssklower } 92736381Ssklower 92845899Ssklower #endif TPCONS 929