home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / netiso / esis.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-27  |  26.9 KB  |  1,064 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.  *    @(#)esis.c    7.19 (Berkeley) 6/27/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. #ifdef ISO
  64.  
  65. #include "types.h"
  66. #include "param.h"
  67. #include "systm.h"
  68. #include "mbuf.h"
  69. #include "domain.h"
  70. #include "protosw.h"
  71. #include "socket.h"
  72. #include "socketvar.h"
  73. #include "errno.h"
  74.  
  75. #include "../net/if.h"
  76. #include "../net/if_dl.h"
  77. #include "../net/route.h"
  78. #include "../net/raw_cb.h"
  79.  
  80. #include "iso.h"
  81. #include "iso_pcb.h"
  82. #include "iso_var.h"
  83. #include "iso_snpac.h"
  84. #include "clnl.h"
  85. #include "clnp.h"
  86. #include "clnp_stat.h"
  87. #include "esis.h"
  88. #include "argo_debug.h"
  89. #include "kernel.h"
  90.  
  91. /*
  92.  *    Global variables to esis implementation
  93.  *
  94.  *    esis_holding_time - the holding time (sec) parameter for outgoing pdus
  95.  *    esis_config_time  - the frequency (sec) that hellos are generated
  96.  *    esis_esconfig_time - suggested es configuration time placed in the
  97.  *                        ish.
  98.  *
  99.  */
  100. struct rawcb    esis_pcb;
  101. int                esis_config(), snpac_age();
  102. int                esis_sendspace = 2048;
  103. int                esis_recvspace = 2048;
  104. short            esis_holding_time = ESIS_HT;
  105. short            esis_config_time = ESIS_CONFIG;
  106. short            esis_esconfig_time = ESIS_CONFIG;
  107. extern int        iso_systype;
  108. struct sockaddr_dl    esis_dl = { sizeof(esis_dl), AF_LINK };
  109. extern char        all_es_snpa[], all_is_snpa[];
  110.  
  111. #define EXTEND_PACKET(m, mhdr, cp)\
  112.     if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\
  113.         esis_stat.es_nomem++;\
  114.         m_freem(mhdr);\
  115.         return;\
  116.     } else {\
  117.         (m) = (m)->m_next;\
  118.         (cp) = mtod((m), caddr_t);\
  119.     }
  120. /*
  121.  * FUNCTION:        esis_init
  122.  *
  123.  * PURPOSE:            Initialize the kernel portion of esis protocol
  124.  *
  125.  * RETURNS:            nothing
  126.  *
  127.  * SIDE EFFECTS:    
  128.  *
  129.  * NOTES:            
  130.  */
  131. esis_init()
  132. {
  133.     extern struct clnl_protosw clnl_protox[256];
  134.     int    esis_input(), isis_input();
  135. #ifdef    ISO_X25ESIS
  136.     int    x25esis_input();
  137. #endif    ISO_X25ESIS
  138.  
  139.     esis_pcb.rcb_next = esis_pcb.rcb_prev = &esis_pcb;
  140.     llinfo_llc.lc_next = llinfo_llc.lc_prev = &llinfo_llc;
  141.  
  142.     timeout(snpac_age, (caddr_t)0, hz);
  143.     timeout(esis_config, (caddr_t)0, hz);
  144.  
  145.     clnl_protox[ISO9542_ESIS].clnl_input = esis_input;
  146.     clnl_protox[ISO10589_ISIS].clnl_input = isis_input;
  147. #ifdef    ISO_X25ESIS
  148.     clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input;
  149. #endif    ISO_X25ESIS
  150. }
  151.  
  152. /*
  153.  * FUNCTION:        esis_usrreq
  154.  *
  155.  * PURPOSE:            Handle user level esis requests
  156.  *
  157.  * RETURNS:            0 or appropriate errno
  158.  *
  159.  * SIDE EFFECTS:    
  160.  *
  161.  */
  162. /*ARGSUSED*/
  163. esis_usrreq(so, req, m, nam, control)
  164. struct socket    *so;        /* socket: used only to get to this code */
  165. int                req;        /* request */
  166. struct mbuf        *m;            /* data for request */
  167. struct mbuf        *nam;        /* optional name */
  168. struct mbuf        *control;    /* optional control */
  169. {
  170.     struct rawcb *rp = sotorawcb(so);
  171.     int error = 0;
  172.  
  173.     if ((so->so_state & SS_PRIV) == 0) {
  174.         error = EACCES;
  175.         goto release;
  176.     }
  177.     if (rp == NULL && req != PRU_ATTACH) {
  178.         error = EINVAL;
  179.         goto release;
  180.     }
  181.  
  182.     switch (req) {
  183.     case PRU_ATTACH:
  184.         if (rp != NULL) {
  185.             error = EINVAL;
  186.             break;
  187.         }
  188.         MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
  189.         if (so->so_pcb = (caddr_t)rp) {
  190.             bzero(so->so_pcb, sizeof(*rp));
  191.             insque(rp, &esis_pcb);
  192.             rp->rcb_socket = so;
  193.             error = soreserve(so, esis_sendspace, esis_recvspace);
  194.         } else
  195.             error = ENOBUFS;
  196.         break;
  197.  
  198.     case PRU_SEND:
  199.         if (nam == NULL) {
  200.             error = EINVAL;
  201.             break;
  202.         }
  203.         /* error checking here */
  204.         error = isis_output(mtod(nam,struct sockaddr_dl *), m);
  205.         m = NULL;
  206.         break;
  207.  
  208.     case PRU_DETACH:
  209.         raw_detach(rp);
  210.         break;
  211.  
  212.     case PRU_SHUTDOWN:
  213.         socantsendmore(so);
  214.         break;
  215.  
  216.     case PRU_ABORT:
  217.         soisdisconnected(so);
  218.         raw_detach(rp);
  219.         break;
  220.  
  221.     case PRU_SENSE:
  222.         return (0);
  223.  
  224.     default:
  225.         return (EOPNOTSUPP);
  226.     }
  227. release:
  228.     if (m != NULL)
  229.         m_freem(m);
  230.  
  231.     return (error);
  232. }
  233.  
  234. /*
  235.  * FUNCTION:        esis_input
  236.  *
  237.  * PURPOSE:            Process an incoming esis packet
  238.  *
  239.  * RETURNS:            nothing
  240.  *
  241.  * SIDE EFFECTS:    
  242.  *
  243.  * NOTES:            
  244.  */
  245. esis_input(m0, shp)
  246. struct mbuf        *m0;        /* ptr to first mbuf of pkt */
  247. struct snpa_hdr    *shp;    /* subnetwork header */
  248. {
  249.     register struct esis_fixed    *pdu = mtod(m0, struct esis_fixed *);
  250.     register int type;
  251.  
  252.     /*
  253.      *    check checksum if necessary
  254.      */
  255.     if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, (int)pdu->esis_hdr_len)) {
  256.         esis_stat.es_badcsum++;
  257.         goto bad;
  258.     }
  259.  
  260.     /* check version */
  261.     if (pdu->esis_vers != ESIS_VERSION) {
  262.         esis_stat.es_badvers++;
  263.         goto bad;
  264.     }
  265.     type = pdu->esis_type & 0x1f;
  266.     switch (type) {
  267.         case ESIS_ESH:
  268.             esis_eshinput(m0, shp);
  269.             break;
  270.  
  271.         case ESIS_ISH:
  272.             esis_ishinput(m0, shp);
  273.             break;
  274.  
  275.         case ESIS_RD:
  276.             esis_rdinput(m0, shp);
  277.             break;
  278.  
  279.         default:
  280.             esis_stat.es_badtype++;
  281.     }
  282.  
  283. bad:
  284.     if (esis_pcb.rcb_next != &esis_pcb)
  285.         isis_input(m0, shp);
  286.     else
  287.         m_freem(m0);
  288. }
  289.  
  290. /*
  291.  * FUNCTION:        esis_rdoutput
  292.  *
  293.  * PURPOSE:            Transmit a redirect pdu
  294.  *
  295.  * RETURNS:            nothing
  296.  *
  297.  * SIDE EFFECTS:    
  298.  *
  299.  * NOTES:            Assumes there is enough space for fixed part of header,
  300.  *                    DA, BSNPA and NET in first mbuf.
  301.  */
  302. esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, rt)
  303. struct snpa_hdr        *inbound_shp;    /* snpa hdr from incoming packet */
  304. struct mbuf            *inbound_m;        /* incoming pkt itself */
  305. struct clnp_optidx    *inbound_oidx;    /* clnp options assoc with incoming pkt */
  306. struct iso_addr        *rd_dstnsap;    /* ultimate destination of pkt */
  307. struct rtentry        *rt;            /* snpa cache info regarding next hop of
  308.                                         pkt */
  309. {
  310.     struct mbuf            *m, *m0;
  311.     caddr_t                cp;
  312.     struct esis_fixed    *pdu;
  313.     int                    len, total_len = 0;
  314.     struct sockaddr_iso    siso;
  315.     struct ifnet         *ifp = inbound_shp->snh_ifp;
  316.     struct sockaddr_dl *sdl;
  317.     struct iso_addr *rd_gwnsap;
  318.  
  319.     if (rt->rt_flags & RTF_GATEWAY) {
  320.         rd_gwnsap = &((struct sockaddr_iso *)rt->rt_gateway)->siso_addr;
  321.         rt = rtalloc1(rt->rt_gateway, 0);
  322.     } else
  323.         rd_gwnsap = &((struct sockaddr_iso *)rt_key(rt))->siso_addr;
  324.     if (rt == 0 || (sdl = (struct sockaddr_dl *)rt->rt_gateway) == 0 ||
  325.         sdl->sdl_family != AF_LINK) {
  326.         /* maybe we should have a function that you
  327.            could put in the iso_ifaddr structure
  328.            which could translate iso_addrs into snpa's
  329.            where there is a known mapping for that address type */
  330.         esis_stat.es_badtype++;
  331.         return;
  332.     }
  333.     esis_stat.es_rdsent++;
  334.     IFDEBUG(D_ESISOUTPUT)
  335.         printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n",
  336.             ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m,
  337.             inbound_oidx);
  338.         printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap));
  339.         printf("\tredirected toward:%s\n", clnp_iso_addrp(rd_gwnsap));
  340.     ENDDEBUG
  341.  
  342.     if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
  343.         esis_stat.es_nomem++;
  344.         return;
  345.     }
  346.     bzero(mtod(m, caddr_t), MHLEN);
  347.  
  348.     pdu = mtod(m, struct esis_fixed *);
  349.     cp = (caddr_t)(pdu + 1); /*pointer arith.; 1st byte after header */
  350.     len = sizeof(struct esis_fixed);
  351.  
  352.     /*
  353.      *    Build fixed part of header
  354.      */
  355.     pdu->esis_proto_id = ISO9542_ESIS;
  356.     pdu->esis_vers = ESIS_VERSION;
  357.     pdu->esis_type = ESIS_RD;
  358.     HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time);
  359.  
  360.     /* Insert destination address */
  361.     (void) esis_insert_addr(&cp, &len, rd_dstnsap, m, 0);
  362.  
  363.     /* Insert the snpa of better next hop */
  364.     *cp++ = sdl->sdl_alen;
  365.     bcopy(LLADDR(sdl), cp, sdl->sdl_alen);
  366.     cp += sdl->sdl_alen;
  367.     len += (sdl->sdl_alen + 1);
  368.  
  369.     /* 
  370.      *    If the next hop is not the destination, then it ought to be
  371.      *    an IS and it should be inserted next. Else, set the
  372.      *    NETL to 0
  373.      */
  374.     /* PHASE2 use mask from ifp of outgoing interface */
  375.     if (!iso_addrmatch1(rd_dstnsap, rd_gwnsap)) {
  376.         /* this should not happen: 
  377.         if ((nhop_sc->sc_flags & SNPA_IS) == 0) {
  378.             printf("esis_rdoutput: next hop is not dst and not an IS\n");
  379.             m_freem(m0);
  380.             return;
  381.         } */
  382.         (void) esis_insert_addr(&cp, &len, rd_gwnsap, m, 0);
  383.     } else {
  384.         *cp++ = 0;    /* NETL */
  385.         len++;
  386.     }
  387.     m->m_len = len;
  388.  
  389.     /*
  390.      *    PHASE2
  391.      *    If redirect is to an IS, add an address mask. The mask to be
  392.      *    used should be the mask present in the routing entry used to
  393.      *    forward the original data packet.
  394.      */
  395.     
  396.     /*
  397.      *    Copy Qos, priority, or security options present in original npdu
  398.      */
  399.     if (inbound_oidx) {
  400.         /* THIS CODE IS CURRENTLY (mostly) UNTESTED */
  401.         int optlen = 0;
  402.         if (inbound_oidx->cni_qos_formatp)
  403.             optlen += (inbound_oidx->cni_qos_len + 2);
  404.         if (inbound_oidx->cni_priorp)    /* priority option is 1 byte long */
  405.             optlen += 3;
  406.         if (inbound_oidx->cni_securep)
  407.             optlen += (inbound_oidx->cni_secure_len + 2);
  408.         if (M_TRAILINGSPACE(m) < optlen) {
  409.             EXTEND_PACKET(m, m0, cp);
  410.             m->m_len = 0;
  411.             /* assumes MLEN > optlen */
  412.         }
  413.         /* assume MLEN-len > optlen */
  414.         /* 
  415.          *    When copying options, copy from ptr - 2 in order to grab
  416.          *    the option code and length
  417.          */
  418.         if (inbound_oidx->cni_qos_formatp) {
  419.             bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_qos_formatp - 2,
  420.                 cp, (unsigned)(inbound_oidx->cni_qos_len + 2));
  421.             cp += inbound_oidx->cni_qos_len + 2;
  422.         }
  423.         if (inbound_oidx->cni_priorp) {
  424.             bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_priorp - 2,
  425.                     cp, 3);
  426.             cp += 3;
  427.         }
  428.         if (inbound_oidx->cni_securep) {
  429.             bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_securep - 2, cp, 
  430.                 (unsigned)(inbound_oidx->cni_secure_len + 2));
  431.             cp += inbound_oidx->cni_secure_len + 2;
  432.         }
  433.         m->m_len += optlen;
  434.         len += optlen;
  435.     }
  436.  
  437.     pdu->esis_hdr_len = m0->m_pkthdr.len = len;
  438.     iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
  439.  
  440.     bzero((caddr_t)&siso, sizeof(siso));
  441.     siso.siso_family = AF_ISO;
  442.     siso.siso_data[0] = AFI_SNA;
  443.     siso.siso_nlen = 6 + 1;    /* should be taken from snpa_hdr */
  444.                                         /* +1 is for AFI */
  445.     bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6);
  446.     (ifp->if_output)(ifp, m0, &siso, 0);
  447. }
  448.  
  449. /*
  450.  * FUNCTION:        esis_insert_addr
  451.  *
  452.  * PURPOSE:            Insert an iso_addr into a buffer
  453.  *
  454.  * RETURNS:            true if buffer was big enough, else false
  455.  *
  456.  * SIDE EFFECTS:    Increment buf & len according to size of iso_addr
  457.  *
  458.  * NOTES:            Plus 1 here is for length byte
  459.  */
  460. esis_insert_addr(buf, len, isoa, m, nsellen)
  461. register caddr_t            *buf;        /* ptr to buffer to put address into */
  462. int                            *len;        /* ptr to length of buffer so far */
  463. register struct iso_addr    *isoa;        /* ptr to address */
  464. register struct mbuf        *m;            /* determine if there remains space */
  465. int                            nsellen;
  466. {
  467.     register int newlen, result = 0;
  468.  
  469.     isoa->isoa_len -= nsellen;
  470.     newlen = isoa->isoa_len + 1;
  471.     if (newlen <=  M_TRAILINGSPACE(m)) {
  472.         bcopy((caddr_t)isoa, *buf, newlen);
  473.         *len += newlen;
  474.         *buf += newlen;
  475.         m->m_len += newlen;
  476.         result = 1;
  477.     }
  478.     isoa->isoa_len += nsellen;
  479.     return (result);
  480. }
  481.  
  482. #define ESIS_EXTRACT_ADDR(d, b) { d = (struct iso_addr *)(b); b += (1 + *b); \
  483.         if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
  484. #define ESIS_NEXT_OPTION(b)    { b += (2 + b[1]); \
  485.         if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
  486. int ESHonly = 0;
  487. /*
  488.  
  489. /*
  490.  * FUNCTION:        esis_eshinput
  491.  *
  492.  * PURPOSE:            Process an incoming ESH pdu
  493.  *
  494.  * RETURNS:            nothing
  495.  *
  496.  * SIDE EFFECTS:    
  497.  *
  498.  * NOTES:            
  499.  */
  500. esis_eshinput(m, shp)
  501. struct mbuf        *m;    /* esh pdu */
  502. struct snpa_hdr    *shp;    /* subnetwork header */
  503. {
  504.     struct    esis_fixed    *pdu = mtod(m, struct esis_fixed *);
  505.     u_short                ht;        /* holding time */
  506.     struct    iso_addr    *nsap;
  507.     int                    naddr;
  508.     u_char                *buf = (u_char *)(pdu + 1);
  509.     u_char                *buflim = pdu->esis_hdr_len + (u_char *)pdu;
  510.     int                    new_entry = 0;
  511.  
  512.     esis_stat.es_eshrcvd++;
  513.  
  514.     CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
  515.  
  516.     naddr = *buf++;
  517.     if (buf >= buflim)
  518.         goto bad;
  519.     if (naddr == 1) {
  520.         ESIS_EXTRACT_ADDR(nsap, buf);
  521.         new_entry = snpac_add(shp->snh_ifp,
  522.                                  nsap, shp->snh_shost, SNPA_ES, ht, 0);
  523.     } else {
  524.         int nsellength = 0, nlen = 0;
  525.         {
  526.         /* See if we want to compress out multiple nsaps differing
  527.            only by nsel */
  528.             register struct ifaddr *ifa = shp->snh_ifp->if_addrlist;
  529.             for (; ifa; ifa = ifa->ifa_next)
  530.                 if (ifa->ifa_addr->sa_family == AF_ISO) {
  531.                     nsellength = ((struct iso_ifaddr *)ifa)->ia_addr.siso_tlen;
  532.                     break;
  533.             }
  534.         }
  535.         IFDEBUG(D_ESISINPUT)
  536.             printf("esis_eshinput: esh: ht %d, naddr %d nsellength %d\n",
  537.                     ht, naddr, nsellength);
  538.         ENDDEBUG
  539.         while (naddr-- > 0) {
  540.             struct iso_addr *nsap2; u_char *buf2;
  541.             ESIS_EXTRACT_ADDR(nsap, buf);
  542.             /* see if there is at least one more nsap in ESH differing
  543.                only by nsel */
  544.             if (nsellength != 0) for (buf2 = buf; buf2 < buflim;) {
  545.                 ESIS_EXTRACT_ADDR(nsap2, buf2);
  546.                 IFDEBUG(D_ESISINPUT)
  547.                     printf("esis_eshinput: comparing %s ", 
  548.                         clnp_iso_addrp(nsap));
  549.                     printf("and %s\n", clnp_iso_addrp(nsap2));
  550.                 ENDDEBUG
  551.                 if (Bcmp(nsap->isoa_genaddr, nsap2->isoa_genaddr,
  552.                          nsap->isoa_len - nsellength) == 0) {
  553.                     nlen = nsellength;
  554.                     break;
  555.                 }
  556.             }
  557.             new_entry |= snpac_add(shp->snh_ifp,
  558.                                     nsap, shp->snh_shost, SNPA_ES, ht, nlen);
  559.             nlen = 0;
  560.         }
  561.     }
  562.     IFDEBUG(D_ESISINPUT)
  563.         printf("esis_eshinput: nsap %s is %s\n", 
  564.             clnp_iso_addrp(nsap), new_entry ? "new" : "old");
  565.     ENDDEBUG
  566.     if (new_entry && (iso_systype & SNPA_IS))
  567.         esis_shoutput(shp->snh_ifp, ESIS_ISH, esis_holding_time,
  568.                         shp->snh_shost, 6, (struct iso_addr *)0);
  569. bad:
  570.     return;
  571. }
  572.  
  573. /*
  574.  * FUNCTION:        esis_ishinput
  575.  *
  576.  * PURPOSE:            process an incoming ISH pdu
  577.  *
  578.  * RETURNS:            
  579.  *
  580.  * SIDE EFFECTS:    
  581.  *
  582.  * NOTES:            
  583.  */
  584. esis_ishinput(m, shp)
  585. struct mbuf        *m;    /* esh pdu */
  586. struct snpa_hdr    *shp;    /* subnetwork header */
  587. {
  588.     struct esis_fixed    *pdu = mtod(m, struct esis_fixed *);
  589.     u_short                ht, newct;            /* holding time */
  590.     struct iso_addr        *nsap;                 /* Network Entity Title */
  591.     register u_char        *buf = (u_char *) (pdu + 1);
  592.     register u_char        *buflim = pdu->esis_hdr_len + (u_char *)pdu;
  593.     int                    new_entry;
  594.  
  595.     esis_stat.es_ishrcvd++;
  596.     CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
  597.  
  598.     IFDEBUG(D_ESISINPUT)
  599.         printf("esis_ishinput: ish: ht %d\n", ht);
  600.     ENDDEBUG
  601.     if (ESHonly)
  602.         goto bad;
  603.  
  604.     ESIS_EXTRACT_ADDR(nsap, buf);
  605.  
  606.     while (buf < buflim) {
  607.         switch (*buf) {
  608.         case ESISOVAL_ESCT:
  609.             if (iso_systype & SNPA_IS)
  610.                 break;
  611.             if (buf[1] != 2)
  612.                 goto bad;
  613.             CTOH(buf[2], buf[3], newct);
  614.             if (esis_config_time != newct) {
  615.                 untimeout(esis_config,0);
  616.                 esis_config_time = newct;
  617.                 esis_config();
  618.             }
  619.             break;
  620.         
  621.         default:
  622.             printf("Unknown ISH option: %x\n", *buf);
  623.         }
  624.         ESIS_NEXT_OPTION(buf);
  625.     }
  626.     new_entry = snpac_add(shp->snh_ifp, nsap, shp->snh_shost, SNPA_IS, ht, 0);
  627.     IFDEBUG(D_ESISINPUT)
  628.         printf("esis_ishinput: nsap %s is %s\n", 
  629.             clnp_iso_addrp(nsap), new_entry ? "new" : "old");
  630.     ENDDEBUG
  631.  
  632.     if (new_entry)
  633.         esis_shoutput(shp->snh_ifp, 
  634.             iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
  635.             esis_holding_time, shp->snh_shost, 6, (struct iso_addr *)0);
  636. bad:
  637.     return;
  638. }
  639.  
  640. /*
  641.  * FUNCTION:        esis_rdinput
  642.  *
  643.  * PURPOSE:            Process an incoming RD pdu
  644.  *
  645.  * RETURNS:            
  646.  *
  647.  * SIDE EFFECTS:    
  648.  *
  649.  * NOTES:            
  650.  */
  651. esis_rdinput(m0, shp)
  652. struct mbuf        *m0;    /* esh pdu */
  653. struct snpa_hdr    *shp;    /* subnetwork header */
  654. {
  655.     struct esis_fixed    *pdu = mtod(m0, struct esis_fixed *);
  656.     u_short                ht;        /* holding time */
  657.     struct iso_addr        *da, *net = 0, *netmask = 0, *snpamask = 0;
  658.     register struct iso_addr *bsnpa;
  659.     register u_char        *buf = (u_char *)(pdu + 1);
  660.     register u_char        *buflim = pdu->esis_hdr_len + (u_char *)pdu;
  661.  
  662.     esis_stat.es_rdrcvd++;
  663.  
  664.     /* intermediate systems ignore redirects */
  665.     if (iso_systype & SNPA_IS)
  666.         return;
  667.     if (ESHonly)
  668.         return;
  669.  
  670.     CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
  671.     if (buf >= buflim)
  672.         return;
  673.  
  674.     /* Extract DA */
  675.     ESIS_EXTRACT_ADDR(da, buf);
  676.  
  677.     /* Extract better snpa */
  678.     ESIS_EXTRACT_ADDR(bsnpa, buf);
  679.  
  680.     /* Extract NET if present */
  681.     if (buf < buflim) {
  682.         if (*buf == 0)
  683.             buf++; /* no NET present, skip NETL anyway */
  684.         else
  685.             ESIS_EXTRACT_ADDR(net, buf);
  686.     }
  687.  
  688.     /* process options */
  689.     while (buf < buflim) {
  690.         switch (*buf) {
  691.         case ESISOVAL_SNPAMASK:
  692.             if (snpamask) /* duplicate */
  693.                 return;
  694.             snpamask = (struct iso_addr *)(buf + 1);
  695.             break;
  696.  
  697.         case ESISOVAL_NETMASK:
  698.             if (netmask) /* duplicate */
  699.                 return;
  700.             netmask = (struct iso_addr *)(buf + 1);
  701.             break;
  702.  
  703.         default:
  704.             printf("Unknown option in ESIS RD (0x%x)\n", buf[-1]);
  705.         }
  706.         ESIS_NEXT_OPTION(buf);
  707.     }
  708.  
  709.     IFDEBUG(D_ESISINPUT)
  710.         printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da));
  711.         if (net)
  712.             printf("\t: net %s\n", clnp_iso_addrp(net));
  713.     ENDDEBUG
  714.     /*
  715.      *    If netl is zero, then redirect is to an ES. We need to add an entry
  716.      *    to the snpa cache for (destination, better snpa).
  717.      *    If netl is not zero, then the redirect is to an IS. In this
  718.      *    case, add an snpa cache entry for (net, better snpa).
  719.      *
  720.      *    If the redirect is to an IS, add a route entry towards that
  721.      *    IS.
  722.      */
  723.     if (net == 0 || net->isoa_len == 0 || snpamask) {
  724.         /* redirect to an ES */
  725.         snpac_add(shp->snh_ifp, da,
  726.                 bsnpa->isoa_genaddr, SNPA_ES, ht, 0);
  727.     } else {
  728.         snpac_add(shp->snh_ifp, net,
  729.                 bsnpa->isoa_genaddr, SNPA_IS, ht, 0);
  730.         snpac_addrt(shp->snh_ifp, da, net, netmask);
  731.     }
  732. bad: ;    /* Needed by ESIS_NEXT_OPTION */
  733. }
  734.  
  735. /*
  736.  * FUNCTION:        esis_config
  737.  *
  738.  * PURPOSE:            Report configuration
  739.  *
  740.  * RETURNS:            
  741.  *
  742.  * SIDE EFFECTS:    
  743.  *
  744.  * NOTES:            Called every esis_config_time seconds
  745.  */
  746. esis_config()
  747. {
  748.     register struct ifnet    *ifp;
  749.  
  750.     timeout(esis_config, (caddr_t)0, hz * esis_config_time);
  751.  
  752.     /* 
  753.      *    Report configuration for each interface that 
  754.      *    - is UP
  755.      *    - has BROADCAST capability
  756.      *    - has an ISO address
  757.      */
  758.     /* Todo: a better way would be to construct the esh or ish
  759.      * once and copy it out for all devices, possibly calling
  760.      * a method in the iso_ifaddr structure to encapsulate and
  761.      * transmit it.  This could work to advantage for non-broadcast media
  762.      */
  763.     
  764.     for (ifp = ifnet; ifp; ifp = ifp->if_next) {
  765.         if ((ifp->if_flags & IFF_UP) &&
  766.             (ifp->if_flags & IFF_BROADCAST)) {
  767.             /* search for an ISO address family */
  768.             struct ifaddr    *ia;
  769.  
  770.             for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) {
  771.                 if (ia->ifa_addr->sa_family == AF_ISO) {
  772.                     esis_shoutput(ifp, 
  773.                         iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
  774.                         esis_holding_time,
  775.                         (caddr_t)(iso_systype & SNPA_ES ? all_is_snpa : 
  776.                         all_es_snpa), 6, (struct iso_addr *)0);
  777.                     break;
  778.                 }
  779.             }
  780.         }
  781.     }
  782. }
  783.  
  784. /*
  785.  * FUNCTION:        esis_shoutput
  786.  *
  787.  * PURPOSE:            Transmit an esh or ish pdu
  788.  *
  789.  * RETURNS:            nothing
  790.  *
  791.  * SIDE EFFECTS:    
  792.  *
  793.  * NOTES:            
  794.  */
  795. esis_shoutput(ifp, type, ht, sn_addr, sn_len, isoa)
  796. struct ifnet    *ifp;
  797. int                type;
  798. short            ht;
  799. caddr_t         sn_addr;
  800. int                sn_len;
  801. struct    iso_addr *isoa;
  802. {
  803.     struct mbuf            *m, *m0;
  804.     caddr_t                cp, naddrp;
  805.     int                    naddr = 0;
  806.     struct esis_fixed    *pdu;
  807.     struct iso_ifaddr    *ia;
  808.     int                    len;
  809.     struct sockaddr_iso    siso;
  810.  
  811.     if (type == ESIS_ESH)
  812.         esis_stat.es_eshsent++;
  813.     else if (type == ESIS_ISH) 
  814.         esis_stat.es_ishsent++;
  815.     else {
  816.         printf("esis_shoutput: bad pdu type\n");
  817.         return;
  818.     }
  819.  
  820.     IFDEBUG(D_ESISOUTPUT)
  821.         int    i;
  822.         printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ",
  823.             ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish",
  824.             ht, sn_len);
  825.         for (i=0; i<sn_len; i++)
  826.             printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' ');
  827.         printf("\n");
  828.     ENDDEBUG
  829.  
  830.     if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
  831.         esis_stat.es_nomem++;
  832.         return;
  833.     }
  834.     bzero(mtod(m, caddr_t), MHLEN);
  835.  
  836.     pdu = mtod(m, struct esis_fixed *);
  837.     naddrp = cp = (caddr_t)(pdu + 1);
  838.     len = sizeof(struct esis_fixed);
  839.  
  840.     /*
  841.      *    Build fixed part of header
  842.      */
  843.     pdu->esis_proto_id = ISO9542_ESIS;
  844.     pdu->esis_vers = ESIS_VERSION;
  845.     pdu->esis_type = type;
  846.     HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
  847.  
  848.     if (type == ESIS_ESH) {
  849.         cp++;
  850.         len++;
  851.     }
  852.  
  853.     m->m_len = len;
  854.     if (isoa) {
  855.         /*
  856.          * Here we are responding to a clnp packet sent to an NSAP
  857.          * that is ours which was sent to the MAC addr all_es's.
  858.          * It is possible that we did not specifically advertise this
  859.          * NSAP, even though it is ours, so we will respond
  860.          * directly to the sender that we are here.  If we do have
  861.          * multiple NSEL's we'll tack them on so he can compress them out.
  862.          */
  863.         (void) esis_insert_addr(&cp, &len, isoa, m, 0);
  864.         naddr = 1;
  865.     }
  866.     for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
  867.         int nsellen = (type == ESIS_ISH ? ia->ia_addr.siso_tlen : 0); 
  868.         int n = ia->ia_addr.siso_nlen;
  869.         register struct iso_ifaddr *ia2;
  870.  
  871.         if (type == ESIS_ISH && naddr > 0)
  872.             break;
  873.         for (ia2 = iso_ifaddr; ia2 != ia; ia2 = ia2->ia_next)
  874.             if (Bcmp(ia->ia_addr.siso_data, ia2->ia_addr.siso_data, n) == 0)
  875.                     break;
  876.         if (ia2 != ia)
  877.             continue;    /* Means we have previously copied this nsap */
  878.         if (isoa && Bcmp(ia->ia_addr.siso_data, isoa->isoa_genaddr, n) == 0) {
  879.             isoa = 0;
  880.             continue;    /* Ditto */
  881.         }
  882.         IFDEBUG(D_ESISOUTPUT)
  883.             printf("esis_shoutput: adding NSAP %s\n", 
  884.                 clnp_iso_addrp(&ia->ia_addr.siso_addr));
  885.         ENDDEBUG
  886.         if (!esis_insert_addr(&cp, &len,
  887.                               &ia->ia_addr.siso_addr, m, nsellen)) {
  888.             EXTEND_PACKET(m, m0, cp);
  889.             (void) esis_insert_addr(&cp, &len, &ia->ia_addr.siso_addr, m,
  890.                                     nsellen);
  891.         }
  892.         naddr++;
  893.     }
  894.  
  895.     if (type == ESIS_ESH)
  896.         *naddrp = naddr;
  897.     else {
  898.         /* add suggested es config timer option to ISH */
  899.         if (M_TRAILINGSPACE(m) < 4) {
  900.             printf("esis_shoutput: extending packet\n");
  901.             EXTEND_PACKET(m, m0, cp);
  902.         }
  903.         *cp++ = ESISOVAL_ESCT;
  904.         *cp++ = 2;
  905.         HTOC(*cp, *(cp+1), esis_esconfig_time);
  906.         len += 4;
  907.         m->m_len += 4;
  908.         IFDEBUG(D_ESISOUTPUT)
  909.             printf("m0 0x%x, m 0x%x, data 0x%x, len %d, cp 0x%x\n",
  910.             m0, m, m->m_data, m->m_len, cp);
  911.         ENDDEBUG
  912.     }
  913.  
  914.     m0->m_pkthdr.len = len;
  915.     pdu->esis_hdr_len = len;
  916.     iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
  917.  
  918.     bzero((caddr_t)&siso, sizeof(siso));
  919.     siso.siso_family = AF_ISO;
  920.     siso.siso_data[0] = AFI_SNA;
  921.     siso.siso_nlen = sn_len + 1;
  922.     bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len);
  923.     (ifp->if_output)(ifp, m0, &siso, 0);
  924. }
  925.  
  926. /*
  927.  * FUNCTION:        isis_input
  928.  *
  929.  * PURPOSE:            Process an incoming isis packet
  930.  *
  931.  * RETURNS:            nothing
  932.  *
  933.  * SIDE EFFECTS:    
  934.  *
  935.  * NOTES:            
  936.  */
  937. isis_input(m0, shp)
  938. struct mbuf        *m0;        /* ptr to first mbuf of pkt */
  939. struct snpa_hdr    *shp;    /* subnetwork header */
  940. {
  941.     register int type;
  942.     register struct rawcb *rp, *first_rp = 0;
  943.     struct ifnet *ifp = shp->snh_ifp;
  944.     char workbuf[16];
  945.     struct mbuf *mm;
  946.  
  947.     IFDEBUG(D_ISISINPUT)
  948.         int i;
  949.  
  950.         printf("isis_input: pkt on ifp x%x (%s%d): from:", ifp, 
  951.             ifp->if_name, ifp->if_unit);
  952.         for (i=0; i<6; i++)
  953.             printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' ');
  954.         printf(" to:");
  955.         for (i=0; i<6; i++)
  956.             printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' ');
  957.         printf("\n");
  958.     ENDDEBUG
  959.     esis_dl.sdl_alen = ifp->if_addrlen;
  960.     esis_dl.sdl_index = ifp->if_index;
  961.     bcopy(shp->snh_shost, (caddr_t)esis_dl.sdl_data, esis_dl.sdl_alen);
  962.     for (rp = esis_pcb.rcb_next; rp != &esis_pcb; rp = rp->rcb_next) {
  963.         if (first_rp == 0) {
  964.             first_rp = rp;
  965.             continue;
  966.         }
  967.         if (mm = m_copy(m0, 0, M_COPYALL)) { /*can't block at interrupt level */
  968.             if (sbappendaddr(&rp->rcb_socket->so_rcv,
  969.                               &esis_dl, mm, (struct mbuf *)0) != 0)
  970.                 sorwakeup(rp->rcb_socket);
  971.             else {
  972.                 IFDEBUG(D_ISISINPUT)
  973.                     printf("Error in sbappenaddr, mm = 0x%x\n", mm);
  974.                 ENDDEBUG
  975.                 m_freem(mm);
  976.             }
  977.         }
  978.     }
  979.     if (first_rp && sbappendaddr(&first_rp->rcb_socket->so_rcv,
  980.                               &esis_dl, m0, (struct mbuf *)0) != 0) {
  981.         sorwakeup(first_rp->rcb_socket);
  982.         return;
  983.     }
  984.     m_freem(m0);
  985. }
  986.  
  987. isis_output(sdl, m)
  988. register struct sockaddr_dl    *sdl;
  989. struct mbuf *m;
  990. {
  991.     register struct ifnet *ifp;
  992.     struct ifaddr *ifa, *ifa_ifwithnet();
  993.     struct sockaddr_iso siso;
  994.     int error = 0;
  995.     unsigned sn_len;
  996.  
  997.     ifa = ifa_ifwithnet(sdl);    /* extract ifp from sockaddr_dl */
  998.     if (ifa == 0) {
  999.         IFDEBUG(D_ISISOUTPUT)
  1000.             printf("isis_output: interface not found\n");
  1001.         ENDDEBUG
  1002.         error = EINVAL;
  1003.         goto release;
  1004.     }
  1005.     ifp = ifa->ifa_ifp;
  1006.     sn_len = sdl->sdl_alen;
  1007.     IFDEBUG(D_ISISOUTPUT)
  1008.         u_char *cp = (u_char *)LLADDR(sdl), *cplim = cp + sn_len;
  1009.         printf("isis_output: ifp 0x%x (%s%d), to: ",
  1010.             ifp, ifp->if_name, ifp->if_unit);
  1011.         while (cp < cplim) {
  1012.             printf("%x", *cp++);
  1013.             printf("%c", (cp < cplim) ? ':' : ' ');
  1014.         }
  1015.         printf("\n");
  1016.     ENDDEBUG
  1017.     bzero((caddr_t)&siso, sizeof(siso));
  1018.     siso.siso_family = AF_ISO; /* This convention may be useful for X.25 */
  1019.     siso.siso_data[0] = AFI_SNA;
  1020.     siso.siso_nlen = sn_len + 1;
  1021.     bcopy(LLADDR(sdl), siso.siso_data + 1, sn_len);
  1022.     error = (ifp->if_output)(ifp, m, (struct sockaddr *)&siso, 0);
  1023.     if (error) {
  1024.         IFDEBUG(D_ISISOUTPUT)
  1025.             printf("isis_output: error from ether_output is %d\n", error);
  1026.         ENDDEBUG
  1027.     }
  1028.     return (error);
  1029.  
  1030. release:
  1031.     if (m != NULL)
  1032.         m_freem(m);
  1033.     return(error);
  1034. }
  1035.  
  1036.  
  1037. /*
  1038.  * FUNCTION:        esis_ctlinput
  1039.  *
  1040.  * PURPOSE:            Handle the PRC_IFDOWN transition
  1041.  *
  1042.  * RETURNS:            nothing
  1043.  *
  1044.  * SIDE EFFECTS:    
  1045.  *
  1046.  * NOTES:            Calls snpac_flush for interface specified.
  1047.  *                    The loop through iso_ifaddr is stupid because
  1048.  *                    back in if_down, we knew the ifp...
  1049.  */
  1050. esis_ctlinput(req, siso)
  1051. int                        req;        /* request: we handle only PRC_IFDOWN */
  1052. struct sockaddr_iso        *siso;        /* address of ifp */
  1053. {
  1054.     register struct iso_ifaddr *ia;    /* scan through interface addresses */
  1055.  
  1056.     if (req == PRC_IFDOWN)
  1057.         for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
  1058.             if (iso_addrmatch(IA_SIS(ia), siso))
  1059.                 snpac_flushifp(ia->ia_ifp);
  1060.         }
  1061. }
  1062.  
  1063. #endif    ISO
  1064.