149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*49937Ssklower * @(#)if_cons.c 7.10 (Berkeley) 05/29/91 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 5436381Ssklower 5536381Ssklower 5645899Ssklower #ifndef SOCK_STREAM 5736381Ssklower #include "param.h" 5836381Ssklower #include "systm.h" 5936381Ssklower #include "mbuf.h" 6036381Ssklower #include "protosw.h" 6136381Ssklower #include "socket.h" 6236381Ssklower #include "socketvar.h" 6336381Ssklower #include "errno.h" 6436381Ssklower #include "ioctl.h" 6540783Smarc #include "tsleep.h" 6636381Ssklower 6736381Ssklower #include "../net/if.h" 6836381Ssklower #include "../net/netisr.h" 6936381Ssklower #include "../net/route.h" 7036381Ssklower 7145899Ssklower #include "iso_errno.h" 7245899Ssklower #include "argo_debug.h" 7345899Ssklower #include "tp_trace.h" 7445899Ssklower #include "iso.h" 7545899Ssklower #include "cons.h" 7645899Ssklower #include "iso_pcb.h" 7736381Ssklower 7845899Ssklower #include "../netccitt/x25.h" 7945899Ssklower #include "../netccitt/pk.h" 8045899Ssklower #include "../netccitt/pk_var.h" 8145899Ssklower #endif 8245899Ssklower 8336381Ssklower #ifdef ARGO_DEBUG 8436381Ssklower #define MT_XCONN 0x50 8536381Ssklower #define MT_XCLOSE 0x51 8636381Ssklower #define MT_XCONFIRM 0x52 8736381Ssklower #define MT_XDATA 0x53 8836381Ssklower #define MT_XHEADER 0x54 8936381Ssklower #else 9036381Ssklower #define MT_XCONN MT_DATA 9136381Ssklower #define MT_XCLOSE MT_DATA 9236381Ssklower #define MT_XCONFIRM MT_DATA 9336381Ssklower #define MT_XDATA MT_DATA 9436381Ssklower #define MT_XHEADER MT_HEADER 9536381Ssklower #endif ARGO_DEBUG 9636381Ssklower 9736381Ssklower #define DONTCLEAR -1 9836381Ssklower 9936381Ssklower /********************************************************************* 10045899Ssklower * cons.c - CONS interface to the x.25 layer 10136381Ssklower * 10236381Ssklower * TODO: figure out what resources we might run out of besides mbufs. 10336381Ssklower * If we run out of any of them (including mbufs) close and recycle 10436381Ssklower * lru x% of the connections, for some parameter x. 10536381Ssklower * 10645899Ssklower * There are 2 interfaces from above: 10736381Ssklower * 1) from TP0: 10836381Ssklower * cons CO network service 10936381Ssklower * TP associates a transport connection with a network connection. 11036381Ssklower * cons_output( isop, m, len, isdgm==0 ) 11136381Ssklower * co_flags == 0 11245899Ssklower * 2) from TP4: 11336381Ssklower * It's a datagram service, like clnp is. - even though it calls 11436381Ssklower * cons_output( isop, m, len, isdgm==1 ) 11536381Ssklower * it eventually goes through 11636381Ssklower * cosns_output(ifp, m, dst). 11736381Ssklower * TP4 permits multiplexing (reuse, possibly simultaneously) of the 11836381Ssklower * network connections. 11936381Ssklower * This means that many sockets (many tpcbs) may be associated with 12045899Ssklower * this pklcd, hence cannot have a back ptr from pklcd to a tpcb. 12136381Ssklower * co_flags & CONSF_DGM 12245899Ssklower * co_socket is null since there may be many sockets that use this pklcd. 12336381Ssklower * 12436381Ssklower NOTE: 12536381Ssklower streams would really be nice. sigh. 12636381Ssklower NOTE: 12736381Ssklower PVCs could be handled by config-ing a cons with an address and with the 12836381Ssklower IFF_POINTTOPOINT flag on. This code would then have to skip the 12936381Ssklower connection setup stuff for pt-to-pt links. 13036381Ssklower 13136381Ssklower 13236381Ssklower *********************************************************************/ 13336381Ssklower 13436381Ssklower 13536381Ssklower #define CONS_IFQMAXLEN 5 13636381Ssklower 13736381Ssklower 13836381Ssklower /* protosw pointers for getting to higher layer */ 13936381Ssklower Static struct protosw *CLNP_proto; 14036381Ssklower Static struct protosw *TP_proto; 14136381Ssklower Static struct protosw *X25_proto; 14236381Ssklower Static int issue_clear_req(); 14336381Ssklower 14436381Ssklower #ifndef PHASEONE 14536381Ssklower extern struct ifaddr *ifa_ifwithnet(); 14636381Ssklower #endif PHASEONE 14736381Ssklower 14836381Ssklower extern struct ifaddr *ifa_ifwithaddr(); 14936381Ssklower 15036381Ssklower Static struct socket dummysocket; /* for use by cosns */ 15136381Ssklower 15236381Ssklower extern struct isopcb tp_isopcb; /* chain of all TP pcbs */ 15336381Ssklower struct isopcb tp_incoming_pending; /* incoming connections 15436381Ssklower for TP, pending */ 15536381Ssklower 15636381Ssklower struct isopcb *Xpcblist[] = { 15736381Ssklower &tp_incoming_pending, 15836381Ssklower &tp_isopcb, 15936381Ssklower (struct isopcb *)0 16036381Ssklower }; 16136381Ssklower 16236381Ssklower Static int parse_facil(), NSAPtoDTE(), make_partial_x25_packet(); 16336381Ssklower Static int FACILtoNSAP(), DTEtoNSAP(); 16445899Ssklower Static struct pklcd *cons_chan_to_pcb(); 16536381Ssklower 16636381Ssklower #define HIGH_NIBBLE 1 16736381Ssklower #define LOW_NIBBLE 0 16836381Ssklower 16936381Ssklower /* 17036381Ssklower * NAME: nibble_copy() 17136381Ssklower * FUNCTION and ARGUMENTS: 17236381Ssklower * copies (len) nibbles from (src_octet), high or low nibble 17336381Ssklower * to (dst_octet), high or low nibble, 17436381Ssklower * src_nibble & dst_nibble should be: 17536381Ssklower * HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble 17636381Ssklower * LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble 17736381Ssklower * RETURNS: VOID 17836381Ssklower */ 17936381Ssklower void 18045899Ssklower nibble_copy(src_octet, src_nibble, dst_octet, dst_nibble, len) 18136381Ssklower register char *src_octet; 18236381Ssklower register char *dst_octet; 18336381Ssklower register unsigned src_nibble; 18436381Ssklower register unsigned dst_nibble; 18536381Ssklower int len; 18636381Ssklower { 18736381Ssklower 18836381Ssklower register i; 18936381Ssklower register unsigned dshift, sshift; 19036381Ssklower 19136381Ssklower IFDEBUG(D_CADDR) 19236381Ssklower printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", 19336381Ssklower src_octet, src_nibble, dst_octet, dst_nibble, len); 19436381Ssklower ENDDEBUG 19536381Ssklower #define SHIFT 0x4 19636381Ssklower 19736381Ssklower dshift = dst_nibble << 2; 19836381Ssklower sshift = src_nibble << 2; 19936381Ssklower 20036381Ssklower for (i=0; i<len; i++) { 20136381Ssklower /* clear dst_nibble */ 20236381Ssklower *dst_octet &= ~(0xf<< dshift); 20336381Ssklower 20436381Ssklower /* set dst nibble */ 20536381Ssklower *dst_octet |= ( 0xf & (*src_octet >> sshift))<< dshift; 20636381Ssklower 20736381Ssklower dshift ^= SHIFT; 20836381Ssklower sshift ^= SHIFT; 20936381Ssklower src_nibble = 1-src_nibble; 21036381Ssklower dst_nibble = 1-dst_nibble; 21136381Ssklower src_octet += src_nibble; 21236381Ssklower dst_octet += dst_nibble; 21336381Ssklower } 21436381Ssklower IFDEBUG(D_CADDR) 21536381Ssklower printf("nibble_copy DONE\n"); 21636381Ssklower ENDDEBUG 21736381Ssklower } 21836381Ssklower 21936381Ssklower /* 22036381Ssklower * NAME: nibble_match() 22136381Ssklower * FUNCTION and ARGUMENTS: 22236381Ssklower * compares src_octet/src_nibble and dst_octet/dst_nibble for len nibbles. 22336381Ssklower * RETURNS: 0 if they differ, 1 if they are the same. 22436381Ssklower */ 22536381Ssklower int 22636381Ssklower nibble_match( src_octet, src_nibble, dst_octet, dst_nibble, len) 22736381Ssklower register char *src_octet; 22836381Ssklower register char *dst_octet; 22936381Ssklower register unsigned src_nibble; 23036381Ssklower register unsigned dst_nibble; 23136381Ssklower int len; 23236381Ssklower { 23336381Ssklower 23436381Ssklower register i; 23536381Ssklower register unsigned dshift, sshift; 23636381Ssklower u_char nibble_a, nibble_b; 23736381Ssklower 23836381Ssklower IFDEBUG(D_CADDR) 23936381Ssklower printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", 24036381Ssklower src_octet, src_nibble, dst_octet, dst_nibble, len); 24136381Ssklower ENDDEBUG 24236381Ssklower #define SHIFT 0x4 24336381Ssklower 24436381Ssklower dshift = dst_nibble << 2; 24536381Ssklower sshift = src_nibble << 2; 24636381Ssklower 24736381Ssklower for (i=0; i<len; i++) { 24836381Ssklower nibble_b = ((*dst_octet)>>dshift) & 0xf; 24936381Ssklower nibble_a = ( 0xf & (*src_octet >> sshift)); 25045899Ssklower if (nibble_b != nibble_a) 25136381Ssklower return 0; 25236381Ssklower 25336381Ssklower dshift ^= SHIFT; 25436381Ssklower sshift ^= SHIFT; 25536381Ssklower src_nibble = 1-src_nibble; 25636381Ssklower dst_nibble = 1-dst_nibble; 25736381Ssklower src_octet += src_nibble; 25836381Ssklower dst_octet += dst_nibble; 25936381Ssklower } 26036381Ssklower IFDEBUG(D_CADDR) 26136381Ssklower printf("nibble_match DONE\n"); 26236381Ssklower ENDDEBUG 26336381Ssklower return 1; 26436381Ssklower } 26536381Ssklower 26636381Ssklower /* 26736381Ssklower **************************** NET PROTOCOL cons *************************** 26836381Ssklower */ 26936381Ssklower /* 27036381Ssklower * NAME: cons_init() 27136381Ssklower * CALLED FROM: 27236381Ssklower * autoconf 27336381Ssklower * FUNCTION: 27436381Ssklower * initialize the protocol 27536381Ssklower */ 27636381Ssklower cons_init() 27736381Ssklower { 27845899Ssklower int tp_incoming(), clnp_incoming(); 27936381Ssklower 28036381Ssklower 28136381Ssklower CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM); 28236381Ssklower X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM); 28336381Ssklower TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET); 28436381Ssklower IFDEBUG(D_CCONS) 28536381Ssklower printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n", 28636381Ssklower CLNP_proto, X25_proto, TP_proto); 28736381Ssklower ENDDEBUG 28845899Ssklower #ifdef notdef 28945899Ssklower pk_protolisten(0x81, 0, clnp_incoming); 29045899Ssklower pk_protolisten(0x82, 0, esis_incoming); 29145899Ssklower pk_protolisten(0x84, 0, tp8878_A_incoming); 29249041Ssklower pk_protolisten(0, 0, tp_incoming); 29345899Ssklower #endif 29436381Ssklower } 29536381Ssklower 296*49937Ssklower tp_incoming(lcp, m) 29745899Ssklower struct pklcd *lcp; 298*49937Ssklower register struct mbuf *m; 29936381Ssklower { 30045899Ssklower register struct isopcb *isop; 30145899Ssklower extern struct isopcb tp_isopcb; 30245899Ssklower int cons_tpinput(); 30336381Ssklower 30445899Ssklower if (iso_pcballoc((struct socket *)0, &tp_incoming_pending)) { 305*49937Ssklower pk_close(lcp); 30645899Ssklower return; 30736381Ssklower } 30845899Ssklower isop = tp_incoming_pending.isop_next; 30945899Ssklower lcp->lcd_upper = cons_tpinput; 31045899Ssklower lcp->lcd_upnext = (caddr_t)isop; 311*49937Ssklower lcp->lcd_send(lcp); /* Confirms call */ 31245899Ssklower isop->isop_chan = (caddr_t)lcp; 31345899Ssklower isop->isop_laddr = &isop->isop_sladdr; 31445899Ssklower isop->isop_faddr = &isop->isop_sfaddr; 31545899Ssklower DTEtoNSAP(isop->isop_laddr, &lcp->lcd_laddr); 31645899Ssklower DTEtoNSAP(isop->isop_faddr, &lcp->lcd_faddr); 31745899Ssklower parse_facil(isop, lcp, &(mtod(m, struct x25_packet *)->packet_data), 31845899Ssklower m->m_pkthdr.len - PKHEADERLN); 31936381Ssklower } 32036381Ssklower 32145899Ssklower cons_tpinput(lcp, m0) 32245899Ssklower struct mbuf *m0; 32345899Ssklower struct pklcd *lcp; 32436381Ssklower { 32545899Ssklower register struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext; 32645899Ssklower register struct x25_packet *xp; 32745899Ssklower int cmd; 32836381Ssklower 32949265Ssklower if (isop == 0) 33049265Ssklower return; 33149265Ssklower if (m0 == 0) { 33249265Ssklower isop->isop_chan = 0; 33349265Ssklower isop->isop_refcnt = 0; 33449265Ssklower lcp->lcd_upnext = 0; 33549265Ssklower lcp->lcd_upper = 0; 33649041Ssklower goto dead; 33749265Ssklower } 33845899Ssklower switch(m0->m_type) { 33945899Ssklower case MT_DATA: 34045899Ssklower case MT_OOBDATA: 34145899Ssklower tpcons_input(m0, isop->isop_faddr, isop->isop_laddr, 34245899Ssklower (struct socket *)0, (caddr_t)lcp); 34349584Ssklower return; 34436381Ssklower 34545899Ssklower case MT_CONTROL: 34645899Ssklower switch (pk_decode(mtod(m0, struct x25_packet *))) { 34736381Ssklower 34845899Ssklower case RR: 34945899Ssklower cmd = PRC_CONS_SEND_DONE; 35045899Ssklower break; 35136381Ssklower 35249265Ssklower case CALL_ACCEPTED: 35349265Ssklower if (lcp->lcd_sb.sb_mb) 35449265Ssklower lcp->lcd_send(lcp); /* XXX - fix this */ 35549584Ssklower /*FALLTHROUGH*/ 35649584Ssklower default: 35749584Ssklower return; 35849265Ssklower 35949041Ssklower dead: 36045899Ssklower case RESET: 36149041Ssklower case CLEAR: 36249041Ssklower case CLEAR_CONF: 36345899Ssklower cmd = PRC_ROUTEDEAD; 36436381Ssklower } 36545899Ssklower tpcons_ctlinput(cmd, isop->isop_faddr, isop); 36636381Ssklower } 36736381Ssklower } 36836381Ssklower 36936381Ssklower /* 37036381Ssklower * NAME: cons_connect() 37136381Ssklower * CALLED FROM: 37245899Ssklower * tpcons_pcbconnect() when opening a new connection. 37336381Ssklower * FUNCTION anD ARGUMENTS: 37436381Ssklower * Figures out which device to use, finding a route if one doesn't 37536381Ssklower * already exist. 37636381Ssklower * RETURN VALUE: 37736381Ssklower * returns E* 37836381Ssklower */ 37945899Ssklower cons_connect(isop) 38045899Ssklower register struct isopcb *isop; 38136381Ssklower { 38245899Ssklower register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 38336381Ssklower register struct mbuf *m; 38436381Ssklower struct ifaddr *ifa; 385*49937Ssklower int error; 38636381Ssklower 38736381Ssklower IFDEBUG(D_CCONN) 38845899Ssklower printf("cons_connect(0x%x): ", isop); 38945899Ssklower dump_isoaddr(isop->isop_faddr); 39045899Ssklower printf("myaddr: "); 39145899Ssklower dump_isoaddr(isop->isop_laddr); 39236381Ssklower printf("\n" ); 39336381Ssklower ENDDEBUG 39445899Ssklower NSAPtoDTE(isop->isop_faddr, &lcp->lcd_faddr); 39549265Ssklower lcp->lcd_upper = cons_tpinput; 39649265Ssklower lcp->lcd_upnext = (caddr_t)isop; 39736381Ssklower IFDEBUG(D_CCONN) 39836381Ssklower printf( 39945899Ssklower "calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x)\n", 40045899Ssklower &lcp->lcd_faddr, &lcp->lcd_laddr, 40145899Ssklower isop->isop_socket->so_proto->pr_protocol); 40236381Ssklower ENDDEBUG 403*49937Ssklower if ((error = make_partial_x25_packet(isop, lcp, m)) == 0) 404*49937Ssklower error = pk_connect(lcp, &lcp->lcd_faddr); 405*49937Ssklower return error; 40636381Ssklower } 40736381Ssklower 40836381Ssklower /* 40936381Ssklower **************************** DEVICE cons *************************** 41036381Ssklower */ 41136381Ssklower 41236381Ssklower 41336381Ssklower /* 41436381Ssklower * NAME: cons_ctlinput() 41536381Ssklower * CALLED FROM: 41636381Ssklower * lower layer when ECN_CLEAR occurs : this routine is here 41736381Ssklower * for consistency - cons subnet service calls its higher layer 41836381Ssklower * through the protosw entry. 41936381Ssklower * FUNCTION & ARGUMENTS: 42037536Smckusick * cmd is a PRC_* command, list found in ../sys/protosw.h 42136381Ssklower * copcb is the obvious. 42236381Ssklower * This serves the higher-layer cons service. 42336381Ssklower * NOTE: this takes 3rd arg. because cons uses it to inform itself 42436381Ssklower * of things (timeouts, etc) but has a pcb instead of an address. 42536381Ssklower */ 42636381Ssklower cons_ctlinput(cmd, sa, copcb) 42736381Ssklower int cmd; 42836381Ssklower struct sockaddr *sa; 42945899Ssklower register struct pklcd *copcb; 43036381Ssklower { 43136381Ssklower } 43236381Ssklower 43336381Ssklower 43445899Ssklower find_error_reason( xp ) 43545899Ssklower register struct x25_packet *xp; 43636381Ssklower { 43736381Ssklower extern u_char x25_error_stats[]; 43845899Ssklower int error, cause; 43936381Ssklower 44045899Ssklower if (xp) { 44145899Ssklower cause = 4[(char *)xp]; 44245899Ssklower switch (cause) { 44336381Ssklower case 0x00: 44436381Ssklower case 0x80: 44536381Ssklower /* DTE originated; look at the diagnostic */ 44645899Ssklower error = (CONL_ERROR_MASK | cause); 44736381Ssklower goto done; 44836381Ssklower 44936381Ssklower case 0x01: /* number busy */ 45036381Ssklower case 0x81: 45136381Ssklower case 0x09: /* Out of order */ 45236381Ssklower case 0x89: 45336381Ssklower case 0x11: /* Remot Procedure Error */ 45436381Ssklower case 0x91: 45536381Ssklower case 0x19: /* reverse charging accept not subscribed */ 45636381Ssklower case 0x99: 45736381Ssklower case 0x21: /* Incampat destination */ 45836381Ssklower case 0xa1: 45936381Ssklower case 0x29: /* fast select accept not subscribed */ 46036381Ssklower case 0xa9: 46136381Ssklower case 0x39: /* ship absent */ 46236381Ssklower case 0xb9: 46336381Ssklower case 0x03: /* invalid facil request */ 46436381Ssklower case 0x83: 46536381Ssklower case 0x0b: /* access barred */ 46636381Ssklower case 0x8b: 46736381Ssklower case 0x13: /* local procedure error */ 46836381Ssklower case 0x93: 46936381Ssklower case 0x05: /* network congestion */ 47036381Ssklower case 0x85: 47136381Ssklower case 0x8d: /* not obtainable */ 47236381Ssklower case 0x0d: 47336381Ssklower case 0x95: /* RPOA out of order */ 47436381Ssklower case 0x15: 47536381Ssklower /* take out bit 8 47636381Ssklower * so we don't have to have so many perror entries 47736381Ssklower */ 47845899Ssklower error = (CONL_ERROR_MASK | 0x100 | (cause & ~0x80)); 47936381Ssklower goto done; 48036381Ssklower 48136381Ssklower case 0xc1: /* gateway-detected proc error */ 48236381Ssklower case 0xc3: /* gateway congestion */ 48336381Ssklower 48445899Ssklower error = (CONL_ERROR_MASK | 0x100 | cause); 48536381Ssklower goto done; 48636381Ssklower } 48736381Ssklower } 48836381Ssklower /* otherwise, a *hopefully* valid perror exists in the e_reason field */ 48945899Ssklower error = xp->packet_data; 49036381Ssklower if (error = 0) { 49136381Ssklower printf("Incoming PKT TYPE 0x%x with reason 0x%x\n", 49245899Ssklower pk_decode(xp), 49345899Ssklower cause); 49436381Ssklower error = E_CO_HLI_DISCA; 49536381Ssklower } 49636381Ssklower 49736381Ssklower done: 49836381Ssklower return error; 49936381Ssklower } 50036381Ssklower 50136381Ssklower 50236381Ssklower 50336381Ssklower #endif KERNEL 50436381Ssklower 50536381Ssklower /* 50636381Ssklower * NAME: make_partial_x25_packet() 50736381Ssklower * 50836381Ssklower * FUNCTION and ARGUMENTS: 50945899Ssklower * Makes part of an X.25 call packet, for use by x25. 51036381Ssklower * (src) and (dst) are the NSAP-addresses of source and destination. 51136381Ssklower * (buf) is a ptr to a buffer into which to write this partial header. 51236381Ssklower * 51345899Ssklower * 0 Facility length (in octets) 51445899Ssklower * 1 Facility field, which is a set of: 51536381Ssklower * m facil code 51636381Ssklower * m+1 facil param len (for >2-byte facilities) in octets 51736381Ssklower * m+2..p facil param field 51836381Ssklower * q user data (protocol identification octet) 51936381Ssklower * 52036381Ssklower * 52136381Ssklower * RETURNS: 52236381Ssklower * 0 if OK 52336381Ssklower * E* if failed. 52445899Ssklower * 52545899Ssklower * SIDE EFFECTS: 52645899Ssklower * Stores facilites mbuf in X.25 control block, where the connect 52745899Ssklower * routine knows where to look for it. 52836381Ssklower */ 52936381Ssklower 53036381Ssklower #ifdef X25_1984 53136381Ssklower int cons_use_facils = 1; 53236381Ssklower #else X25_1984 53336381Ssklower int cons_use_facils = 0; 53436381Ssklower #endif X25_1984 53536381Ssklower 53636381Ssklower int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */ 53736381Ssklower 53836381Ssklower Static int 53945899Ssklower make_partial_x25_packet(isop, lcp) 54045899Ssklower struct isopcb *isop; 54145899Ssklower struct pklcd *lcp; 54236381Ssklower { 54336381Ssklower u_int proto; 54436381Ssklower int flag; 54545899Ssklower caddr_t buf; 54649041Ssklower register caddr_t ptr; 54736381Ssklower register int len = 0; 54836381Ssklower int buflen =0; 54936381Ssklower caddr_t facil_len; 55036381Ssklower int oddness = 0; 55145899Ssklower struct mbuf *m; 55236381Ssklower 55336381Ssklower 55449584Ssklower IFDEBUG(D_CCONN) 55549584Ssklower printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", 55649584Ssklower isop->isop_laddr, isop->isop_faddr, proto, m, flag); 55749584Ssklower ENDDEBUG 55849584Ssklower if (cons_use_udata) { 55949584Ssklower if (isop->isop_x25crud_len > 0) { 56049584Ssklower /* 56149584Ssklower * The user specified something. Stick it in 56249584Ssklower */ 56349584Ssklower bcopy(isop->isop_x25crud, lcp->lcd_faddr.x25_udata, 56449584Ssklower isop->isop_x25crud_len); 56549584Ssklower lcp->lcd_faddr.x25_udlen = isop->isop_x25crud_len; 56649584Ssklower } 56749584Ssklower } 56849584Ssklower 56949584Ssklower if (cons_use_facils == 0) { 57049584Ssklower lcp->lcd_facilities = 0; 57149584Ssklower return 0; 57249584Ssklower } 573*49937Ssklower MGETHDR(m, MT_DATA, M_WAITOK); 57445899Ssklower if (m == 0) 57545899Ssklower return ENOBUFS; 57645899Ssklower buf = mtod(m, caddr_t); 57749041Ssklower ptr = buf; 57836381Ssklower 57936381Ssklower /* ptr now points to facil length (len of whole facil field in OCTETS */ 58036381Ssklower facil_len = ptr ++; 581*49937Ssklower m->m_len = 0; 582*49937Ssklower pk_build_facilities(m, &lcp->lcd_faddr, 0); 58336381Ssklower 58436381Ssklower IFDEBUG(D_CADDR) 58536381Ssklower printf("make_partial calling: ptr 0x%x, len 0x%x\n", ptr, 58645899Ssklower isop->isop_laddr->siso_addr.isoa_len); 58736381Ssklower ENDDEBUG 58845899Ssklower if (cons_use_facils) { 589*49937Ssklower *ptr++ = 0; /* Marker to separate X.25 facitilies from CCITT ones */ 590*49937Ssklower *ptr++ = 0x0f; 59136381Ssklower *ptr = 0xcb; /* calling facility code */ 59236381Ssklower ptr ++; 59336381Ssklower ptr ++; /* leave room for facil param len (in OCTETS + 1) */ 59436381Ssklower ptr ++; /* leave room for the facil param len (in nibbles), 595*49937Ssklower * high two bits of which indicate full/partial NSAP 596*49937Ssklower */ 59745899Ssklower len = isop->isop_laddr->siso_addr.isoa_len; 59845899Ssklower bcopy( isop->isop_laddr->siso_data, ptr, len); 59949584Ssklower *(ptr-2) = len+1; /* facil param len in octets */ 60036381Ssklower *(ptr-1) = len<<1; /* facil param len in nibbles */ 60136381Ssklower ptr += len; 60236381Ssklower 60336381Ssklower IFDEBUG(D_CADDR) 60436381Ssklower printf("make_partial called: ptr 0x%x, len 0x%x\n", ptr, 60545899Ssklower isop->isop_faddr->siso_addr.isoa_len); 60636381Ssklower ENDDEBUG 60736381Ssklower *ptr = 0xc9; /* called facility code */ 60836381Ssklower ptr ++; 60936381Ssklower ptr ++; /* leave room for facil param len (in OCTETS + 1) */ 61036381Ssklower ptr ++; /* leave room for the facil param len (in nibbles), 611*49937Ssklower * high two bits of which indicate full/partial NSAP 612*49937Ssklower */ 61345899Ssklower len = isop->isop_faddr->siso_nlen; 61445899Ssklower bcopy(isop->isop_faddr->siso_data, ptr, len); 61549584Ssklower *(ptr-2) = len+1; /* facil param len = addr len + 1 for each of these 61636381Ssklower * two length fields, in octets */ 61736381Ssklower *(ptr-1) = len<<1; /* facil param len in nibbles */ 61836381Ssklower ptr += len; 61936381Ssklower 62036381Ssklower } 62136381Ssklower *facil_len = ptr - facil_len - 1; 62245899Ssklower if (*facil_len > MAX_FACILITIES) 62336381Ssklower return E_CO_PNA_LONG; 62436381Ssklower 62536381Ssklower buflen = (int)(ptr - buf); 62636381Ssklower 62736381Ssklower IFDEBUG(D_CDUMP_REQ) 62836381Ssklower register int i; 62936381Ssklower 63036381Ssklower printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n", 63136381Ssklower buf, buflen, buflen); 63236381Ssklower for( i=0; i < buflen; ) { 63336381Ssklower printf("+%d: %x %x %x %x %x %x %x %x\n", 63436381Ssklower i, 63536381Ssklower *(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3), 63636381Ssklower *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7)); 63736381Ssklower i+=8; 63836381Ssklower } 63936381Ssklower ENDDEBUG 64036381Ssklower IFDEBUG(D_CADDR) 64136381Ssklower printf("make_partial returns buf 0x%x size 0x%x bytes\n", 64236381Ssklower mtod(m, caddr_t), buflen); 64336381Ssklower ENDDEBUG 64436381Ssklower 64545899Ssklower if (buflen > MHLEN) 64636381Ssklower return E_CO_PNA_LONG; 64736381Ssklower 648*49937Ssklower m->m_pkthdr.len = m->m_len = buflen; 64945899Ssklower lcp->lcd_facilities = m; 65036381Ssklower return 0; 65136381Ssklower } 65236381Ssklower 65336381Ssklower /* 65436381Ssklower * NAME: NSAPtoDTE() 65536381Ssklower * CALLED FROM: 65636381Ssklower * make_partial_x25_packet() 65736381Ssklower * FUNCTION and ARGUMENTS: 65836381Ssklower * get a DTE address from an NSAP-address (struct sockaddr_iso) 65936381Ssklower * (dst_octet) is the octet into which to begin stashing the DTE addr 66036381Ssklower * (dst_nibble) takes 0 or 1. 1 means begin filling in the DTE addr 66136381Ssklower * in the high-order nibble of dst_octet. 0 means low-order nibble. 66236381Ssklower * (addr) is the NSAP-address 66336381Ssklower * (flag) is true if the transport suffix is to become the 66436381Ssklower * last two digits of the DTE address 66545899Ssklower * A DTE address is a series of ASCII digits 66636381Ssklower * 66736381Ssklower * A DTE address may have leading zeros. The are significant. 66836381Ssklower * 1 digit per nibble, may be an odd number of nibbles. 66936381Ssklower * 67036381Ssklower * An NSAP-address has the DTE address in the IDI. Leading zeros are 67136381Ssklower * significant. Trailing hex f indicates the end of the DTE address. 67245899Ssklower * The IDI is a series of BCD digits, one per nibble. 67336381Ssklower * 67436381Ssklower * RETURNS 67536381Ssklower * # significant digits in the DTE address, -1 if error. 67636381Ssklower */ 67736381Ssklower 67836381Ssklower Static int 67945899Ssklower NSAPtoDTE(siso, sx25) 68045899Ssklower register struct sockaddr_iso *siso; 68145899Ssklower register struct sockaddr_x25 *sx25; 68236381Ssklower { 68345899Ssklower int dtelen = -1; 68436381Ssklower 68536381Ssklower IFDEBUG(D_CADDR) 68645899Ssklower printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&siso->siso_addr)); 68736381Ssklower ENDDEBUG 68836381Ssklower 68945899Ssklower if (siso->siso_data[0] == AFI_37) { 69045899Ssklower register char *out = sx25->x25_addr; 69145899Ssklower register char *in = siso->siso_data + 1; 69245899Ssklower register int nibble; 69349041Ssklower char *lim = siso->siso_data + siso->siso_nlen; 69449041Ssklower char *olim = out+15; 69545899Ssklower int lowNibble = 0; 69645899Ssklower 69745899Ssklower while (in < lim) { 69845899Ssklower nibble = ((lowNibble ? *in++ : (*in >> 4)) & 0xf) | 0x30; 69945899Ssklower lowNibble ^= 1; 70049041Ssklower if (nibble != 0x3f && out < olim) 70145899Ssklower *out++ = nibble; 70245899Ssklower } 70345899Ssklower dtelen = out - sx25->x25_addr; 70445899Ssklower *out++ = 0; 70545899Ssklower } else { 70645899Ssklower register struct rtentry *rt = rtalloc1(siso, 1); 70745899Ssklower /* error = iso_8208snparesolve(addr, x121string, &x121strlen);*/ 70845899Ssklower 70945899Ssklower if (rt) { 71045899Ssklower register struct sockaddr_x25 *sxx = 71145899Ssklower (struct sockaddr_x25 *)rt->rt_gateway; 71245899Ssklower register char *in = sxx->x25_addr; 71345899Ssklower 71445899Ssklower rt->rt_use--; 71545899Ssklower if (sxx && sxx->x25_family == AF_CCITT) { 71645899Ssklower bcopy(sx25->x25_addr, sxx->x25_addr, sizeof(sx25->x25_addr)); 71745899Ssklower while (*in++) {} 71845899Ssklower dtelen = in - sxx->x25_addr; 71945899Ssklower } 72045899Ssklower } 72136381Ssklower } 72245899Ssklower return dtelen; 72336381Ssklower } 72436381Ssklower 72536381Ssklower /* 72636381Ssklower * NAME: FACILtoNSAP() 72736381Ssklower * CALLED FROM: 72836381Ssklower * parse_facil() 72936381Ssklower * FUNCTION and ARGUMENTS: 73036381Ssklower * Creates and NSAP in the sockaddr_iso (addr) from the 73145899Ssklower * x.25 facility found at buf - 1. 73236381Ssklower * RETURNS: 73345899Ssklower * length of parameter if ok, -1 if error. 73436381Ssklower */ 73536381Ssklower 73636381Ssklower Static int 73745899Ssklower FACILtoNSAP(addr, buf) 73845899Ssklower u_char *buf; 73936381Ssklower register struct sockaddr_iso *addr; 74036381Ssklower { 74145899Ssklower int len_in_nibbles, param_len = *buf++; 74245899Ssklower u_char buf_len; /* in bytes */ 74336381Ssklower 74436381Ssklower IFDEBUG(D_CADDR) 74536381Ssklower printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n", 74636381Ssklower buf, buf_len, addr ); 74736381Ssklower ENDDEBUG 74836381Ssklower 74945899Ssklower len_in_nibbles = *buf & 0x3f; 75045899Ssklower buf_len = (len_in_nibbles + 1) >> 1; 75136381Ssklower /* despite the fact that X.25 makes us put a length in nibbles 75236381Ssklower * here, the NSAP-addrs are always in full octets 75336381Ssklower */ 75445899Ssklower switch (*buf++ & 0xc0) { 75545899Ssklower case 0: 75645899Ssklower /* Entire OSI NSAP address */ 75745899Ssklower bcopy((caddr_t)buf, addr->siso_data, addr->siso_nlen = buf_len); 75845899Ssklower break; 75936381Ssklower 76045899Ssklower case 40: 76145899Ssklower /* Partial OSI NSAP address, assume trailing */ 76245899Ssklower if (buf_len + addr->siso_nlen > sizeof(addr->siso_addr)) 76345899Ssklower return -1; 76445899Ssklower bcopy((caddr_t)buf, TSEL(addr), buf_len); 76545899Ssklower addr->siso_nlen += buf_len; 76645899Ssklower break; 76736381Ssklower 76845899Ssklower default: 76945899Ssklower /* Rather than blow away the connection, just ignore and use 77045899Ssklower NSAP from DTE */; 77136381Ssklower } 77245899Ssklower return param_len; 77345899Ssklower } 77436381Ssklower 77545899Ssklower static 77645899Ssklower init_siso(siso) 77745899Ssklower register struct sockaddr_iso *siso; 77845899Ssklower { 77945899Ssklower siso->siso_len = sizeof (*siso); 78045899Ssklower siso->siso_family = AF_ISO; 78145899Ssklower siso->siso_data[0] = AFI_37; 78245899Ssklower siso->siso_nlen = 8; 78336381Ssklower } 78436381Ssklower 78536381Ssklower /* 78636381Ssklower * NAME: DTEtoNSAP() 78736381Ssklower * CALLED FROM: 78836381Ssklower * parse_facil() 78936381Ssklower * FUNCTION and ARGUMENTS: 79036381Ssklower * Creates a type 37 NSAP in the sockaddr_iso (addr) 79145899Ssklower * from a DTE address found in a sockaddr_x25. 79236381Ssklower * 79336381Ssklower * RETURNS: 79436381Ssklower * 0 if ok; E* otherwise. 79536381Ssklower */ 79636381Ssklower 79736381Ssklower Static int 79845899Ssklower DTEtoNSAP(addr, sx) 79936381Ssklower struct sockaddr_iso *addr; 80045899Ssklower struct sockaddr_x25 *sx; 80136381Ssklower { 80245899Ssklower register char *in, *out; 80345899Ssklower register int first; 80445899Ssklower int pad_tail = 0; 80545899Ssklower int src_len; 80636381Ssklower 80736381Ssklower 80845899Ssklower init_siso(addr); 80945899Ssklower src_len = strlen(sx->x25_addr); 81045899Ssklower in = sx->x25_addr; 81145899Ssklower out = addr->siso_data + 1; 81245899Ssklower if (*in == '0' && (src_len & 1 == 0)) { 81345899Ssklower pad_tail = 0xf; 81445899Ssklower src_len++; 81545899Ssklower } 81645899Ssklower for (first = 0; src_len > 0; src_len --) { 81745899Ssklower first |= *in++; 81845899Ssklower if (src_len & 1) { 81945899Ssklower *out++ = first; 82045899Ssklower first = 0; 82145899Ssklower } 82245899Ssklower else first <<= 4; 82345899Ssklower } 82445899Ssklower if (pad_tail) 82545899Ssklower out[-1] |= 0xf; 82636381Ssklower return 0; /* ok */ 82736381Ssklower } 82836381Ssklower 82936381Ssklower /* 83036381Ssklower * FUNCTION and ARGUMENTS: 83136381Ssklower * parses (buf_len) bytes beginning at (buf) and finds 83236381Ssklower * a called nsap, a calling nsap, and protocol identifier. 83336381Ssklower * RETURNS: 83436381Ssklower * 0 if ok, E* otherwise. 83536381Ssklower */ 83636381Ssklower 83745899Ssklower static int 83845899Ssklower parse_facil(lcp, isop, buf, buf_len) 83936381Ssklower caddr_t buf; 84036381Ssklower u_char buf_len; /* in bytes */ 84145899Ssklower struct isopcb *isop; 84245899Ssklower struct pklcd *lcp; 84336381Ssklower { 84445899Ssklower register struct sockaddr_iso *called = isop->isop_laddr; 84545899Ssklower register struct sockaddr_iso *calling = isop->isop_faddr; 84636381Ssklower register int i; 84745899Ssklower register u_char *ptr = (u_char *)buf; 84845899Ssklower u_char *ptr_lim, *facil_lim; 84945899Ssklower int facil_param_len, facil_len; 85036381Ssklower 85136381Ssklower IFDEBUG(D_CADDR) 85245899Ssklower printf("parse_facil(0x%x, 0x%x, 0x%x, 0x%x)\n", 85345899Ssklower buf, buf_len, called, calling); 85436381Ssklower dump_buf(buf, buf_len); 85536381Ssklower ENDDEBUG 85636381Ssklower 85736381Ssklower /* find the beginnings of the facility fields in buf 85836381Ssklower * by skipping over the called & calling DTE addresses 85936381Ssklower * i <- # nibbles in called + # nibbles in calling 86036381Ssklower * i += 1 so that an odd nibble gets rounded up to even 86136381Ssklower * before dividing by 2, then divide by two to get # octets 86236381Ssklower */ 86345899Ssklower i = (int)(*ptr >> 4) + (int)(*ptr&0xf); 86436381Ssklower i++; 86545899Ssklower ptr += i >> 1; 86636381Ssklower ptr ++; /* plus one for the DTE lengths byte */ 86736381Ssklower 86836381Ssklower /* ptr now is at facil_length field */ 86945899Ssklower facil_len = *ptr++; 87045899Ssklower facil_lim = ptr + facil_len; 87136381Ssklower IFDEBUG(D_CADDR) 87245899Ssklower printf("parse_facils: facil length is 0x%x\n", (int) facil_len); 87336381Ssklower ENDDEBUG 87436381Ssklower 87545899Ssklower while (ptr <= facil_lim) { 87636381Ssklower /* get NSAP addresses from facilities */ 87745899Ssklower switch (*ptr++) { 87836381Ssklower case 0xcb: 87945899Ssklower /* calling NSAP */ 88045899Ssklower facil_param_len = FACILtoNSAP(isop->isop_faddr, ptr); 88136381Ssklower break; 88236381Ssklower case 0xc9: 88345899Ssklower /* called NSAP */ 88445899Ssklower facil_param_len = FACILtoNSAP(isop->isop_laddr, ptr); 88536381Ssklower break; 88636381Ssklower 88736381Ssklower /* from here to default are legit cases that I ignore */ 88836381Ssklower /* variable length */ 88936381Ssklower case 0xca: /* end-to-end transit delay negot */ 89036381Ssklower case 0xc6: /* network user id */ 89136381Ssklower case 0xc5: /* charging info : indicating monetary unit */ 89236381Ssklower case 0xc2: /* charging info : indicating segment count */ 89336381Ssklower case 0xc1: /* charging info : indicating call duration */ 89436381Ssklower case 0xc4: /* RPOA extended format */ 89536381Ssklower case 0xc3: /* call redirection notification */ 89636381Ssklower facil_param_len = 0; 89736381Ssklower break; 89836381Ssklower 89936381Ssklower /* 1 octet */ 90036381Ssklower case 0x0a: /* min. throughput class negot */ 90136381Ssklower case 0x02: /* throughput class */ 90236381Ssklower case 0x03: case 0x47: /* CUG shit */ 90336381Ssklower case 0x0b: /* expedited data negot */ 90436381Ssklower case 0x01: /* Fast select or reverse charging 90536381Ssklower (example of intelligent protocol design) */ 90636381Ssklower case 0x04: /* charging info : requesting service */ 90736381Ssklower case 0x08: /* called line addr modified notification */ 90836381Ssklower facil_param_len = 1; 90936381Ssklower break; 91036381Ssklower 91136381Ssklower /* any 2 octets */ 91236381Ssklower case 0x42: /* pkt size */ 91336381Ssklower case 0x43: /* win size */ 91436381Ssklower case 0x44: /* RPOA basic format */ 91536381Ssklower case 0x41: /* bilateral CUG shit */ 91636381Ssklower case 0x49: /* transit delay selection and indication */ 91736381Ssklower facil_param_len = 2; 91836381Ssklower break; 91936381Ssklower 92036381Ssklower /* don't have any 3 octets */ 92136381Ssklower /* 92236381Ssklower facil_param_len = 3; 92336381Ssklower */ 92436381Ssklower default: 92536381Ssklower printf( 92636381Ssklower "BOGUS FACILITY CODE facil_len 0x%x *facil_len 0x%x, ptr 0x%x *ptr 0x%x\n", 92745899Ssklower ptr, facil_len, ptr - 1, ptr[-1]); 92836381Ssklower /* facil that we don't handle */ 92936381Ssklower return E_CO_HLI_REJI; 93036381Ssklower } 93145899Ssklower if (facil_param_len == -1) 93245899Ssklower return E_CO_REG_ICDA; 93345899Ssklower if (facil_param_len == 0) /* variable length */ 93436381Ssklower facil_param_len = (int)*ptr; /* 1 + the real facil param */ 93536381Ssklower ptr += facil_param_len; 93636381Ssklower } 93736381Ssklower return 0; 93836381Ssklower } 93936381Ssklower 94045899Ssklower #endif TPCONS 941