home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / netiso / if_cons.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-29  |  25.3 KB  |  967 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  *    @(#)if_cons.c    7.10 (Berkeley) 5/29/91
  34.  */
  35.  
  36. /***********************************************************
  37.         Copyright IBM Corporation 1987
  38.  
  39.                       All Rights Reserved
  40.  
  41. Permission to use, copy, modify, and distribute this software and its 
  42. documentation for any purpose and without fee is hereby granted, 
  43. provided that the above copyright notice appear in all copies and that
  44. both that copyright notice and this permission notice appear in 
  45. supporting documentation, and that the name of IBM not be
  46. used in advertising or publicity pertaining to distribution of the
  47. software without specific, written prior permission.  
  48.  
  49. IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  50. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  51. IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  52. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  53. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  54. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  55. SOFTWARE.
  56.  
  57. ******************************************************************/
  58.  
  59. /*
  60.  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
  61.  */
  62. /*
  63.  * $Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $
  64.  * $Source: /usr/argo/sys/netiso/RCS/if_cons.c,v $
  65.  *
  66.  * cons.c - Connection Oriented Network Service:
  67.  * including support for a) user transport-level service, 
  68.  *    b) COSNS below CLNP, and c) CONS below TP.
  69.  */
  70.  
  71. #ifdef TPCONS
  72. #ifdef KERNEL
  73. #ifdef ARGO_DEBUG
  74. #define Static  
  75. unsigned LAST_CALL_PCB;
  76. #else ARGO_DEBUG
  77. #define Static static
  78. #endif ARGO_DEBUG
  79.  
  80.  
  81.  
  82. #ifndef SOCK_STREAM
  83. #include "param.h"
  84. #include "systm.h"
  85. #include "mbuf.h"
  86. #include "protosw.h"
  87. #include "socket.h"
  88. #include "socketvar.h"
  89. #include "errno.h"
  90. #include "ioctl.h"
  91. #include "tsleep.h"
  92.  
  93. #include "../net/if.h"
  94. #include "../net/netisr.h"
  95. #include "../net/route.h"
  96.  
  97. #include "iso_errno.h"
  98. #include "argo_debug.h"
  99. #include "tp_trace.h"
  100. #include "iso.h"
  101. #include "cons.h"
  102. #include "iso_pcb.h"
  103.  
  104. #include "../netccitt/x25.h"
  105. #include "../netccitt/pk.h"
  106. #include "../netccitt/pk_var.h"
  107. #endif
  108.  
  109. #ifdef ARGO_DEBUG
  110. #define MT_XCONN    0x50
  111. #define MT_XCLOSE    0x51
  112. #define MT_XCONFIRM    0x52
  113. #define MT_XDATA    0x53
  114. #define MT_XHEADER    0x54
  115. #else
  116. #define MT_XCONN    MT_DATA
  117. #define MT_XCLOSE    MT_DATA
  118. #define MT_XCONFIRM    MT_DATA
  119. #define MT_XDATA    MT_DATA
  120. #define MT_XHEADER    MT_HEADER
  121. #endif ARGO_DEBUG
  122.  
  123. #define DONTCLEAR     -1
  124.  
  125. /*********************************************************************    
  126.  * cons.c - CONS interface to the x.25 layer
  127.  *
  128.  * TODO: figure out what resources we might run out of besides mbufs.
  129.  *  If we run out of any of them (including mbufs) close and recycle
  130.  *  lru x% of the connections, for some parameter x.
  131.  *
  132.  * There are 2 interfaces from above:
  133.  * 1) from TP0: 
  134.  *    cons CO network service
  135.  *    TP associates a transport connection with a network connection.
  136.  *       cons_output( isop, m, len, isdgm==0 ) 
  137.  *        co_flags == 0
  138.  * 2) from TP4:
  139.  *      It's a datagram service, like clnp is. - even though it calls
  140.  *            cons_output( isop, m, len, isdgm==1 ) 
  141.  *      it eventually goes through
  142.  *            cosns_output(ifp, m, dst).
  143.  *    TP4 permits multiplexing (reuse, possibly simultaneously) of the 
  144.  *      network connections.
  145.  *    This means that many sockets (many tpcbs) may be associated with
  146.  *    this pklcd, hence cannot have a back ptr from pklcd to a tpcb.
  147.  *        co_flags & CONSF_DGM 
  148.  *    co_socket is null since there may be many sockets that use this pklcd.
  149.  *
  150. NOTE:
  151.     streams would really be nice. sigh.
  152. NOTE:
  153.     PVCs could be handled by config-ing a cons with an address and with the
  154.     IFF_POINTTOPOINT flag on.  This code would then have to skip the
  155.     connection setup stuff for pt-to-pt links.  
  156.  
  157.  
  158.  *********************************************************************/
  159.  
  160.  
  161. #define CONS_IFQMAXLEN 5
  162.  
  163.  
  164. /* protosw pointers for getting to higher layer */
  165. Static     struct protosw    *CLNP_proto;
  166. Static     struct protosw    *TP_proto;
  167. Static     struct protosw    *X25_proto;
  168. Static     int                issue_clear_req();
  169.  
  170. #ifndef    PHASEONE
  171. extern    struct ifaddr    *ifa_ifwithnet();
  172. #endif    PHASEONE
  173.  
  174. extern    struct ifaddr    *ifa_ifwithaddr();
  175.  
  176. Static  struct socket    dummysocket; /* for use by cosns */
  177.  
  178. extern struct    isopcb    tp_isopcb; /* chain of all TP pcbs */
  179. struct    isopcb            tp_incoming_pending;  /* incoming connections
  180.                                         for TP, pending */
  181.  
  182. struct isopcb     *Xpcblist[] =  {
  183.     &tp_incoming_pending,
  184.     &tp_isopcb,
  185.     (struct isopcb *)0
  186. };
  187.  
  188. Static     int parse_facil(), NSAPtoDTE(), make_partial_x25_packet();
  189. Static    int FACILtoNSAP(), DTEtoNSAP();
  190. Static    struct pklcd *cons_chan_to_pcb();
  191.  
  192. #define HIGH_NIBBLE 1
  193. #define LOW_NIBBLE 0
  194.  
  195. /*
  196.  * NAME:    nibble_copy()
  197.  * FUNCTION and ARGUMENTS:
  198.  *     copies (len) nibbles from (src_octet), high or low nibble
  199.  *  to (dst_octet), high or low nibble,
  200.  * src_nibble & dst_nibble should be:
  201.  *     HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble
  202.  *     LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble
  203.  * RETURNS: VOID
  204.  */
  205. void
  206. nibble_copy(src_octet, src_nibble, dst_octet, dst_nibble, len)
  207.     register char      *src_octet;
  208.     register char      *dst_octet;
  209.     register unsigned        src_nibble;
  210.     register unsigned         dst_nibble;
  211.     int        len;
  212. {
  213.  
  214.     register     i;
  215.     register     unsigned dshift, sshift;
  216.  
  217.     IFDEBUG(D_CADDR)
  218.         printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", 
  219.          src_octet, src_nibble, dst_octet, dst_nibble, len);
  220.     ENDDEBUG
  221. #define SHIFT 0x4
  222.  
  223.     dshift = dst_nibble << 2;
  224.     sshift = src_nibble << 2;
  225.  
  226.     for (i=0; i<len; i++) {
  227.         /* clear dst_nibble  */
  228.         *dst_octet     &= ~(0xf<< dshift);
  229.  
  230.         /* set dst nibble */
  231.         *dst_octet     |= ( 0xf & (*src_octet >> sshift))<< dshift;
  232.  
  233.         dshift        ^= SHIFT;
  234.         sshift        ^= SHIFT;
  235.         src_nibble     = 1-src_nibble;
  236.         dst_nibble     = 1-dst_nibble;
  237.         src_octet    += src_nibble;
  238.         dst_octet     += dst_nibble;
  239.     }
  240.     IFDEBUG(D_CADDR)
  241.         printf("nibble_copy DONE\n");
  242.     ENDDEBUG
  243. }
  244.  
  245. /*
  246.  * NAME:    nibble_match()
  247.  * FUNCTION and ARGUMENTS:
  248.  *     compares src_octet/src_nibble and dst_octet/dst_nibble  for len nibbles.
  249.  * RETURNS: 0 if they differ, 1 if they are the same.
  250.  */
  251. int
  252. nibble_match( src_octet, src_nibble, dst_octet, dst_nibble, len)
  253.     register char      *src_octet;
  254.     register char      *dst_octet;
  255.     register unsigned        src_nibble;
  256.     register unsigned         dst_nibble;
  257.     int        len;
  258. {
  259.  
  260.     register     i;
  261.     register     unsigned dshift, sshift;
  262.     u_char        nibble_a, nibble_b;
  263.  
  264.     IFDEBUG(D_CADDR)
  265.         printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", 
  266.          src_octet, src_nibble, dst_octet, dst_nibble, len);
  267.     ENDDEBUG
  268. #define SHIFT 0x4
  269.  
  270.     dshift = dst_nibble << 2;
  271.     sshift = src_nibble << 2;
  272.  
  273.     for (i=0; i<len; i++) {
  274.         nibble_b = ((*dst_octet)>>dshift) & 0xf;
  275.         nibble_a = ( 0xf & (*src_octet >> sshift));
  276.         if (nibble_b != nibble_a)
  277.             return 0;
  278.  
  279.         dshift        ^= SHIFT;
  280.         sshift        ^= SHIFT;
  281.         src_nibble     = 1-src_nibble;
  282.         dst_nibble     = 1-dst_nibble;
  283.         src_octet    += src_nibble;
  284.         dst_octet     += dst_nibble;
  285.     }
  286.     IFDEBUG(D_CADDR)
  287.         printf("nibble_match DONE\n");
  288.     ENDDEBUG
  289.     return 1;
  290. }
  291.  
  292. /*
  293.  **************************** NET PROTOCOL cons ***************************
  294.  */
  295. /*
  296.  * NAME:    cons_init()
  297.  * CALLED FROM:
  298.  *    autoconf
  299.  * FUNCTION:
  300.  *    initialize the protocol
  301.  */
  302. cons_init()
  303. {
  304.     int tp_incoming(), clnp_incoming();
  305.  
  306.  
  307.     CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM); 
  308.     X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM);
  309.     TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET);
  310.     IFDEBUG(D_CCONS)
  311.         printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n",
  312.             CLNP_proto, X25_proto, TP_proto);
  313.     ENDDEBUG
  314. #ifdef notdef
  315.     pk_protolisten(0x81, 0, clnp_incoming);
  316.     pk_protolisten(0x82, 0, esis_incoming);
  317.     pk_protolisten(0x84, 0, tp8878_A_incoming);
  318.     pk_protolisten(0, 0, tp_incoming);
  319. #endif
  320. }
  321.  
  322. tp_incoming(lcp, m)
  323. struct pklcd *lcp;
  324. register struct mbuf *m;
  325. {
  326.     register struct isopcb *isop;
  327.     extern struct isopcb tp_isopcb;
  328.     int cons_tpinput();
  329.  
  330.     if (iso_pcballoc((struct socket *)0, &tp_incoming_pending)) {
  331.         pk_close(lcp);
  332.         return;
  333.     }
  334.     isop = tp_incoming_pending.isop_next;
  335.     lcp->lcd_upper = cons_tpinput;
  336.     lcp->lcd_upnext = (caddr_t)isop;
  337.     lcp->lcd_send(lcp); /* Confirms call */
  338.     isop->isop_chan = (caddr_t)lcp;
  339.     isop->isop_laddr = &isop->isop_sladdr;
  340.     isop->isop_faddr = &isop->isop_sfaddr;
  341.     DTEtoNSAP(isop->isop_laddr, &lcp->lcd_laddr);
  342.     DTEtoNSAP(isop->isop_faddr, &lcp->lcd_faddr);
  343.     parse_facil(isop, lcp, &(mtod(m, struct x25_packet *)->packet_data),
  344.         m->m_pkthdr.len - PKHEADERLN);
  345. }
  346.  
  347. cons_tpinput(lcp, m0)
  348. struct mbuf *m0;
  349. struct pklcd *lcp;
  350. {
  351.     register struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext;
  352.     register struct x25_packet *xp;
  353.     int cmd;
  354.  
  355.     if (isop == 0)
  356.         return;
  357.     if (m0 == 0) {
  358.         isop->isop_chan = 0;
  359.         isop->isop_refcnt = 0;
  360.         lcp->lcd_upnext = 0;
  361.         lcp->lcd_upper = 0;
  362.         goto dead;
  363.     }
  364.     switch(m0->m_type) {
  365.     case MT_DATA:
  366.     case MT_OOBDATA:
  367.         tpcons_input(m0, isop->isop_faddr, isop->isop_laddr,
  368.             (struct socket *)0, (caddr_t)lcp);
  369.         return;
  370.  
  371.     case MT_CONTROL:
  372.         switch (pk_decode(mtod(m0, struct x25_packet *))) {
  373.  
  374.         case RR:
  375.             cmd = PRC_CONS_SEND_DONE;
  376.             break;
  377.  
  378.         case CALL_ACCEPTED:
  379.             if (lcp->lcd_sb.sb_mb)
  380.                 lcp->lcd_send(lcp); /* XXX - fix this */
  381.             /*FALLTHROUGH*/
  382.         default:
  383.             return;
  384.  
  385.         dead:
  386.         case RESET:
  387.         case CLEAR:
  388.         case CLEAR_CONF:
  389.             cmd = PRC_ROUTEDEAD;
  390.         }
  391.         tpcons_ctlinput(cmd, isop->isop_faddr, isop);
  392.     }
  393. }
  394.  
  395. /*
  396.  * NAME:    cons_connect()
  397.  * CALLED FROM:
  398.  *    tpcons_pcbconnect() when opening a new connection.  
  399.  * FUNCTION anD ARGUMENTS:
  400.  *  Figures out which device to use, finding a route if one doesn't
  401.  *  already exist.
  402.  * RETURN VALUE:
  403.  *  returns E*
  404.  */
  405. cons_connect(isop)
  406.     register struct isopcb *isop;
  407. {
  408.     register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
  409.     register struct mbuf     *m;
  410.     struct ifaddr             *ifa;
  411.     int error;
  412.  
  413.     IFDEBUG(D_CCONN)
  414.         printf("cons_connect(0x%x): ", isop);
  415.         dump_isoaddr(isop->isop_faddr);
  416.         printf("myaddr: ");
  417.         dump_isoaddr(isop->isop_laddr);
  418.         printf("\n" );
  419.     ENDDEBUG
  420.     NSAPtoDTE(isop->isop_faddr, &lcp->lcd_faddr);
  421.     lcp->lcd_upper = cons_tpinput;
  422.     lcp->lcd_upnext = (caddr_t)isop;
  423.     IFDEBUG(D_CCONN)
  424.         printf(
  425.         "calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x)\n",
  426.             &lcp->lcd_faddr, &lcp->lcd_laddr, 
  427.             isop->isop_socket->so_proto->pr_protocol); 
  428.     ENDDEBUG
  429.     if ((error = make_partial_x25_packet(isop, lcp, m)) == 0)
  430.         error = pk_connect(lcp, &lcp->lcd_faddr);
  431.     return error;
  432. }
  433.  
  434. /*
  435.  **************************** DEVICE cons ***************************
  436.  */
  437.  
  438.  
  439. /* 
  440.  * NAME:    cons_ctlinput()
  441.  * CALLED FROM:
  442.  *  lower layer when ECN_CLEAR occurs : this routine is here
  443.  *  for consistency - cons subnet service calls its higher layer
  444.  *  through the protosw entry.
  445.  * FUNCTION & ARGUMENTS:
  446.  *  cmd is a PRC_* command, list found in ../sys/protosw.h
  447.  *  copcb is the obvious.
  448.  *  This serves the higher-layer cons service.
  449.  * NOTE: this takes 3rd arg. because cons uses it to inform itself
  450.  *  of things (timeouts, etc) but has a pcb instead of an address.
  451.  */
  452. cons_ctlinput(cmd, sa, copcb)
  453.     int cmd;
  454.     struct sockaddr *sa;
  455.     register struct pklcd *copcb;
  456. {
  457. }
  458.  
  459.  
  460. find_error_reason( xp )
  461.     register struct x25_packet *xp;
  462. {
  463.     extern u_char x25_error_stats[];
  464.     int error, cause;
  465.  
  466.     if (xp) {
  467.         cause = 4[(char *)xp];
  468.         switch (cause) {
  469.             case 0x00:
  470.             case 0x80:
  471.                 /* DTE originated; look at the diagnostic */
  472.                 error = (CONL_ERROR_MASK | cause);
  473.                 goto done;
  474.  
  475.             case 0x01: /* number busy */
  476.             case 0x81:
  477.             case 0x09: /* Out of order */
  478.             case 0x89:
  479.             case 0x11: /* Remot Procedure Error */
  480.             case 0x91:
  481.             case 0x19: /* reverse charging accept not subscribed */
  482.             case 0x99:
  483.             case 0x21: /* Incampat destination */
  484.             case 0xa1:
  485.             case 0x29: /* fast select accept not subscribed */
  486.             case 0xa9:
  487.             case 0x39: /* ship absent */
  488.             case 0xb9:
  489.             case 0x03: /* invalid facil request */
  490.             case 0x83:
  491.             case 0x0b: /* access barred */
  492.             case 0x8b:
  493.             case 0x13: /* local procedure error */
  494.             case 0x93:
  495.             case 0x05: /* network congestion */
  496.             case 0x85:
  497.             case 0x8d: /* not obtainable */
  498.             case 0x0d:
  499.             case 0x95: /* RPOA out of order */
  500.             case 0x15:
  501.                 /* take out bit 8 
  502.                  * so we don't have to have so many perror entries 
  503.                  */
  504.                 error = (CONL_ERROR_MASK | 0x100 | (cause & ~0x80));
  505.                 goto done;
  506.  
  507.             case 0xc1: /* gateway-detected proc error */
  508.             case 0xc3: /* gateway congestion */
  509.  
  510.                 error = (CONL_ERROR_MASK | 0x100 | cause);
  511.                 goto done;
  512.         } 
  513.     } 
  514.     /* otherwise, a *hopefully* valid perror exists in the e_reason field */
  515.     error = xp->packet_data;
  516.     if (error = 0) {
  517.         printf("Incoming PKT TYPE 0x%x with reason 0x%x\n",
  518.             pk_decode(xp),
  519.             cause);
  520.         error = E_CO_HLI_DISCA;
  521.     } 
  522.  
  523. done:
  524.     return error;
  525. }
  526.  
  527.  
  528.  
  529. #endif KERNEL
  530.  
  531. /*
  532.  * NAME:    make_partial_x25_packet()
  533.  *
  534.  * FUNCTION and ARGUMENTS:
  535.  *    Makes part of an X.25 call packet, for use by x25.
  536.  *  (src) and (dst) are the NSAP-addresses of source and destination.
  537.  *    (buf) is a ptr to a buffer into which to write this partial header.
  538.  *
  539.  *     0            Facility length (in octets)
  540.  *     1            Facility field, which is a set of:
  541.  *      m            facil code
  542.  *      m+1        facil param len (for >2-byte facilities) in octets
  543.  *      m+2..p    facil param field
  544.  *  q            user data (protocol identification octet)
  545.  * 
  546.  *
  547.  * RETURNS: 
  548.  *  0 if OK
  549.  *  E* if failed.
  550.  *
  551.  * SIDE EFFECTS:
  552.  * Stores facilites mbuf in X.25 control block, where the connect
  553.  * routine knows where to look for it.
  554.  */
  555.  
  556. #ifdef X25_1984 
  557. int cons_use_facils = 1;
  558. #else X25_1984 
  559. int cons_use_facils = 0;
  560. #endif X25_1984 
  561.  
  562. int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */
  563.  
  564. Static int
  565. make_partial_x25_packet(isop, lcp)
  566.     struct isopcb *isop;
  567.     struct pklcd *lcp;
  568. {
  569.     u_int                proto;
  570.     int                    flag;
  571.     caddr_t             buf;
  572.     register caddr_t    ptr;
  573.     register int        len    = 0;
  574.     int                 buflen    =0;
  575.     caddr_t                facil_len;
  576.     int                 oddness    = 0;
  577.     struct mbuf *m;
  578.  
  579.  
  580.     IFDEBUG(D_CCONN)
  581.         printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
  582.             isop->isop_laddr, isop->isop_faddr, proto, m, flag);
  583.     ENDDEBUG
  584.     if (cons_use_udata) {
  585.         if (isop->isop_x25crud_len > 0) {
  586.             /*
  587.              *    The user specified something. Stick it in
  588.              */
  589.             bcopy(isop->isop_x25crud, lcp->lcd_faddr.x25_udata,
  590.                     isop->isop_x25crud_len);
  591.             lcp->lcd_faddr.x25_udlen = isop->isop_x25crud_len;
  592.         }
  593.     }
  594.  
  595.     if (cons_use_facils == 0) {
  596.         lcp->lcd_facilities = 0;
  597.         return 0;
  598.     }
  599.     MGETHDR(m, MT_DATA, M_WAITOK);
  600.     if (m == 0)
  601.         return ENOBUFS;
  602.     buf = mtod(m, caddr_t);
  603.     ptr = buf;
  604.     
  605.     /* ptr now points to facil length (len of whole facil field in OCTETS */
  606.     facil_len = ptr ++;
  607.     m->m_len = 0;
  608.     pk_build_facilities(m, &lcp->lcd_faddr, 0);
  609.  
  610.     IFDEBUG(D_CADDR)
  611.         printf("make_partial  calling: ptr 0x%x, len 0x%x\n", ptr, 
  612.                 isop->isop_laddr->siso_addr.isoa_len);
  613.     ENDDEBUG
  614.     if (cons_use_facils) {
  615.         *ptr++ = 0;     /* Marker to separate X.25 facitilies from CCITT ones */
  616.         *ptr++ = 0x0f;
  617.         *ptr = 0xcb; /* calling facility code */
  618.         ptr ++;
  619.         ptr ++; /* leave room for facil param len (in OCTETS + 1) */
  620.         ptr ++; /* leave room for the facil param len (in nibbles),
  621.                  * high two bits of which indicate full/partial NSAP
  622.                  */
  623.         len = isop->isop_laddr->siso_addr.isoa_len;
  624.         bcopy( isop->isop_laddr->siso_data, ptr, len);
  625.         *(ptr-2) = len+1; /* facil param len in octets */
  626.         *(ptr-1) = len<<1; /* facil param len in nibbles */
  627.         ptr += len;
  628.  
  629.         IFDEBUG(D_CADDR)
  630.             printf("make_partial  called: ptr 0x%x, len 0x%x\n", ptr, 
  631.                     isop->isop_faddr->siso_addr.isoa_len);
  632.         ENDDEBUG
  633.         *ptr = 0xc9; /* called facility code */
  634.         ptr ++;
  635.         ptr ++; /* leave room for facil param len (in OCTETS + 1) */
  636.         ptr ++; /* leave room for the facil param len (in nibbles),
  637.                  * high two bits of which indicate full/partial NSAP
  638.                  */
  639.         len = isop->isop_faddr->siso_nlen;
  640.         bcopy(isop->isop_faddr->siso_data, ptr, len);
  641.         *(ptr-2) = len+1; /* facil param len = addr len + 1 for each of these
  642.                           * two length fields, in octets */
  643.         *(ptr-1) = len<<1; /* facil param len in nibbles */
  644.         ptr += len;
  645.  
  646.     }
  647.     *facil_len = ptr - facil_len - 1;
  648.     if (*facil_len > MAX_FACILITIES)
  649.         return E_CO_PNA_LONG;
  650.  
  651.     buflen = (int)(ptr - buf);
  652.  
  653.     IFDEBUG(D_CDUMP_REQ)
  654.         register int i;
  655.  
  656.         printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n", 
  657.             buf, buflen, buflen);
  658.         for( i=0; i < buflen; ) {
  659.             printf("+%d: %x %x %x %x    %x %x %x %x\n",
  660.                 i,
  661.                 *(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3),
  662.                 *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7));
  663.             i+=8;
  664.         }
  665.     ENDDEBUG
  666.     IFDEBUG(D_CADDR)
  667.         printf("make_partial returns buf 0x%x size 0x%x bytes\n", 
  668.             mtod(m, caddr_t), buflen);
  669.     ENDDEBUG
  670.  
  671.     if (buflen > MHLEN)
  672.         return E_CO_PNA_LONG;
  673.  
  674.     m->m_pkthdr.len = m->m_len = buflen;
  675.     lcp->lcd_facilities = m;
  676.     return  0;
  677. }
  678.  
  679. /*
  680.  * NAME:    NSAPtoDTE()
  681.  * CALLED FROM:
  682.  *  make_partial_x25_packet()
  683.  * FUNCTION and ARGUMENTS: 
  684.  *  get a DTE address from an NSAP-address (struct sockaddr_iso)
  685.  *  (dst_octet) is the octet into which to begin stashing the DTE addr
  686.  *  (dst_nibble) takes 0 or 1.  1 means begin filling in the DTE addr
  687.  *         in the high-order nibble of dst_octet.  0 means low-order nibble.
  688.  *  (addr) is the NSAP-address
  689.  *  (flag) is true if the transport suffix is to become the
  690.  *        last two digits of the DTE address
  691.  *  A DTE address is a series of ASCII digits
  692.  *
  693.  *    A DTE address may have leading zeros. The are significant.
  694.  *        1 digit per nibble, may be an odd number of nibbles.
  695.  *
  696.  *  An NSAP-address has the DTE address in the IDI. Leading zeros are
  697.  *        significant. Trailing hex f indicates the end of the DTE address.
  698.  *      The IDI is a series of BCD digits, one per nibble.
  699.  *
  700.  * RETURNS
  701.  *  # significant digits in the DTE address, -1 if error.
  702.  */
  703.  
  704. Static int
  705. NSAPtoDTE(siso, sx25)
  706.     register struct sockaddr_iso *siso;
  707.     register struct sockaddr_x25 *sx25;
  708. {
  709.     int        dtelen = -1;
  710.  
  711.     IFDEBUG(D_CADDR)
  712.         printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&siso->siso_addr));
  713.     ENDDEBUG
  714.  
  715.     if (siso->siso_data[0] == AFI_37) {
  716.         register char *out = sx25->x25_addr;
  717.         register char *in = siso->siso_data + 1;
  718.         register int nibble;
  719.         char *lim = siso->siso_data + siso->siso_nlen;
  720.         char *olim = out+15;
  721.         int lowNibble = 0;
  722.  
  723.         while (in < lim) {
  724.             nibble = ((lowNibble ? *in++ : (*in >> 4)) & 0xf) | 0x30;
  725.             lowNibble ^= 1;
  726.             if (nibble != 0x3f && out < olim)
  727.                 *out++ = nibble;
  728.         }
  729.         dtelen = out - sx25->x25_addr;
  730.         *out++ = 0;
  731.     } else {
  732.         register struct rtentry *rt = rtalloc1(siso, 1);
  733.         /* error = iso_8208snparesolve(addr, x121string, &x121strlen);*/
  734.  
  735.         if (rt) {
  736.             register struct sockaddr_x25 *sxx =
  737.                             (struct sockaddr_x25 *)rt->rt_gateway;
  738.             register char *in = sxx->x25_addr;
  739.  
  740.             rt->rt_use--;
  741.             if (sxx && sxx->x25_family == AF_CCITT) {
  742.                 bcopy(sx25->x25_addr, sxx->x25_addr, sizeof(sx25->x25_addr));
  743.                 while (*in++) {}
  744.                 dtelen = in - sxx->x25_addr;
  745.             }
  746.         }
  747.     }
  748.     return dtelen;
  749. }
  750.  
  751. /*
  752.  * NAME:    FACILtoNSAP()
  753.  * CALLED FROM:
  754.  *  parse_facil()
  755.  * FUNCTION and ARGUMENTS:
  756.  *     Creates and NSAP in the sockaddr_iso (addr) from the
  757.  *  x.25 facility found at buf - 1.
  758.  * RETURNS:
  759.  *  length of parameter if ok, -1 if error.
  760.  */
  761.  
  762. Static int
  763. FACILtoNSAP(addr, buf)
  764.     u_char         *buf;
  765.     register struct sockaddr_iso *addr;
  766. {
  767.     int len_in_nibbles, param_len = *buf++;
  768.     u_char            buf_len; /* in bytes */
  769.  
  770.     IFDEBUG(D_CADDR)
  771.         printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n", 
  772.             buf, buf_len, addr );
  773.     ENDDEBUG
  774.  
  775.     len_in_nibbles = *buf & 0x3f;
  776.     buf_len = (len_in_nibbles + 1) >> 1;
  777.     /* despite the fact that X.25 makes us put a length in nibbles
  778.      * here, the NSAP-addrs are always in full octets
  779.      */
  780.     switch (*buf++ & 0xc0) {
  781.     case 0:
  782.         /* Entire OSI NSAP address */
  783.         bcopy((caddr_t)buf, addr->siso_data, addr->siso_nlen = buf_len);
  784.         break;
  785.  
  786.     case 40:
  787.         /* Partial OSI NSAP address, assume trailing */
  788.         if (buf_len + addr->siso_nlen > sizeof(addr->siso_addr))
  789.             return -1;
  790.         bcopy((caddr_t)buf, TSEL(addr), buf_len);
  791.         addr->siso_nlen += buf_len;
  792.         break;
  793.  
  794.     default:
  795.         /* Rather than blow away the connection, just ignore and use
  796.            NSAP from DTE */;
  797.     }
  798.     return param_len;
  799. }
  800.  
  801. static
  802. init_siso(siso)
  803. register struct sockaddr_iso *siso;
  804. {
  805.     siso->siso_len = sizeof (*siso);
  806.     siso->siso_family = AF_ISO;
  807.     siso->siso_data[0] = AFI_37;
  808.     siso->siso_nlen = 8;
  809. }
  810.  
  811. /*
  812.  * NAME:    DTEtoNSAP()
  813.  * CALLED FROM:
  814.  *  parse_facil()
  815.  * FUNCTION and ARGUMENTS:
  816.  *  Creates a type 37 NSAP in the sockaddr_iso (addr)
  817.  *     from a DTE address found in a sockaddr_x25.
  818.  *  
  819.  * RETURNS:
  820.  *  0 if ok; E* otherwise.
  821.  */
  822.  
  823. Static  int
  824. DTEtoNSAP(addr, sx)
  825.     struct sockaddr_iso *addr;
  826.     struct sockaddr_x25 *sx;
  827. {
  828.     register char        *in, *out;
  829.     register int        first;
  830.     int                    pad_tail = 0;
  831.     int                 src_len;
  832.  
  833.  
  834.     init_siso(addr);
  835.     src_len = strlen(sx->x25_addr);
  836.     in = sx->x25_addr;
  837.     out = addr->siso_data + 1;
  838.     if (*in == '0' && (src_len & 1 == 0)) {
  839.         pad_tail = 0xf;
  840.         src_len++;
  841.     }
  842.     for (first = 0; src_len > 0; src_len --) {
  843.         first |= *in++;
  844.         if (src_len & 1) {
  845.             *out++ = first;
  846.             first = 0;
  847.         }
  848.         else first <<= 4;
  849.     }
  850.     if (pad_tail)
  851.         out[-1] |= 0xf;
  852.     return 0; /* ok */
  853. }
  854.  
  855. /*
  856.  * FUNCTION and ARGUMENTS:
  857.  *    parses (buf_len) bytes beginning at (buf) and finds
  858.  *  a called nsap, a calling nsap, and protocol identifier.
  859.  * RETURNS:
  860.  *  0 if ok, E* otherwise.
  861.  */
  862.  
  863. static int
  864. parse_facil(lcp, isop, buf, buf_len)
  865.     caddr_t         buf;
  866.     u_char            buf_len; /* in bytes */
  867.     struct            isopcb *isop;
  868.     struct            pklcd *lcp;
  869. {
  870.     register struct sockaddr_iso *called = isop->isop_laddr;
  871.     register struct sockaddr_iso *calling = isop->isop_faddr;
  872.     register int     i;
  873.     register u_char     *ptr = (u_char *)buf;
  874.     u_char            *ptr_lim, *facil_lim;
  875.     int             facil_param_len, facil_len;
  876.  
  877.     IFDEBUG(D_CADDR)
  878.         printf("parse_facil(0x%x, 0x%x, 0x%x, 0x%x)\n", 
  879.             buf, buf_len, called, calling);
  880.         dump_buf(buf, buf_len);
  881.     ENDDEBUG
  882.  
  883.     /* find the beginnings of the facility fields in buf 
  884.      * by skipping over the called & calling DTE addresses
  885.      * i <- # nibbles in called + # nibbles in calling
  886.      * i += 1 so that an odd nibble gets rounded up to even  
  887.      * before dividing by 2, then divide by two to get # octets
  888.      */
  889.     i = (int)(*ptr >> 4) + (int)(*ptr&0xf);
  890.     i++;
  891.     ptr += i >> 1;
  892.     ptr ++; /* plus one for the DTE lengths byte */
  893.  
  894.     /* ptr now is at facil_length field */
  895.     facil_len = *ptr++;
  896.     facil_lim = ptr + facil_len;
  897.     IFDEBUG(D_CADDR)
  898.         printf("parse_facils: facil length is  0x%x\n", (int) facil_len);
  899.     ENDDEBUG
  900.  
  901.     while (ptr <= facil_lim) {
  902.         /* get NSAP addresses from facilities */
  903.         switch (*ptr++) {
  904.             case 0xcb:
  905.                 /* calling NSAP */
  906.                 facil_param_len = FACILtoNSAP(isop->isop_faddr, ptr);
  907.                 break;
  908.             case 0xc9:
  909.                 /* called NSAP */
  910.                 facil_param_len = FACILtoNSAP(isop->isop_laddr, ptr);
  911.                 break;
  912.  
  913.                 /* from here to default are legit cases that I ignore */
  914.                 /* variable length */
  915.             case 0xca:  /* end-to-end transit delay negot */
  916.             case 0xc6:  /* network user id */
  917.             case 0xc5:     /* charging info : indicating monetary unit */
  918.             case 0xc2:     /* charging info : indicating segment count */
  919.             case 0xc1:     /* charging info : indicating call duration */
  920.             case 0xc4:     /* RPOA extended format */
  921.             case 0xc3:     /* call redirection notification */
  922.                 facil_param_len = 0;
  923.                 break;
  924.  
  925.                 /* 1 octet */
  926.             case 0x0a:  /* min. throughput class negot */
  927.             case 0x02:  /* throughput class */
  928.             case 0x03:  case 0x47:  /* CUG shit */
  929.             case 0x0b:  /* expedited data negot */
  930.             case 0x01:  /* Fast select or reverse charging 
  931.                         (example of intelligent protocol design) */
  932.             case 0x04:     /* charging info : requesting service */
  933.             case 0x08:     /* called line addr modified notification */
  934.                 facil_param_len = 1;
  935.                 break;
  936.  
  937.                 /* any 2 octets */
  938.             case 0x42:  /* pkt size */
  939.             case 0x43:  /* win size */
  940.             case 0x44:  /* RPOA basic format */
  941.             case 0x41:  /* bilateral CUG shit */
  942.             case 0x49:     /* transit delay selection and indication */
  943.                 facil_param_len = 2;
  944.                 break;
  945.  
  946.                 /* don't have any 3 octets */
  947.                 /*
  948.                 facil_param_len = 3;
  949.                 */
  950.             default:
  951.                 printf(
  952. "BOGUS FACILITY CODE facil_len 0x%x *facil_len 0x%x, ptr 0x%x *ptr 0x%x\n",
  953.                     ptr, facil_len, ptr - 1, ptr[-1]);
  954.                 /* facil that we don't handle */
  955.                 return E_CO_HLI_REJI;
  956.         }
  957.         if (facil_param_len == -1)
  958.             return E_CO_REG_ICDA;
  959.         if (facil_param_len == 0) /* variable length */ 
  960.             facil_param_len = (int)*ptr; /* 1 + the real facil param */
  961.         ptr += facil_param_len;
  962.     }
  963.     return 0;
  964. }
  965.  
  966. #endif TPCONS
  967.