The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netiso/esis.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: esis.c,v 1.30 2003/08/07 16:33:35 agc Exp $    */
    2 
    3 /*-
    4  * Copyright (c) 1991, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the University nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  *      @(#)esis.c      8.3 (Berkeley) 3/20/95
   32  */
   33 
   34 /***********************************************************
   35                 Copyright IBM Corporation 1987
   36 
   37                       All Rights Reserved
   38 
   39 Permission to use, copy, modify, and distribute this software and its
   40 documentation for any purpose and without fee is hereby granted,
   41 provided that the above copyright notice appear in all copies and that
   42 both that copyright notice and this permission notice appear in
   43 supporting documentation, and that the name of IBM not be
   44 used in advertising or publicity pertaining to distribution of the
   45 software without specific, written prior permission.
   46 
   47 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   48 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
   49 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   50 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
   51 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
   52 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
   53 SOFTWARE.
   54 
   55 ******************************************************************/
   56 
   57 /*
   58  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
   59  */
   60 
   61 #include <sys/cdefs.h>
   62 __KERNEL_RCSID(0, "$NetBSD: esis.c,v 1.30 2003/08/07 16:33:35 agc Exp $");
   63 
   64 #include "opt_iso.h"
   65 #ifdef ISO
   66 
   67 #include <sys/param.h>
   68 #include <sys/systm.h>
   69 #include <sys/callout.h>
   70 #include <sys/mbuf.h>
   71 #include <sys/domain.h>
   72 #include <sys/protosw.h>
   73 #include <sys/socket.h>
   74 #include <sys/socketvar.h>
   75 #include <sys/errno.h>
   76 #include <sys/kernel.h>
   77 #include <sys/proc.h>
   78 
   79 #include <net/if.h>
   80 #include <net/if_dl.h>
   81 #include <net/route.h>
   82 #include <net/raw_cb.h>
   83 
   84 #include <netiso/iso.h>
   85 #include <netiso/iso_pcb.h>
   86 #include <netiso/iso_var.h>
   87 #include <netiso/iso_snpac.h>
   88 #include <netiso/clnl.h>
   89 #include <netiso/clnp.h>
   90 #include <netiso/clnp_stat.h>
   91 #include <netiso/esis.h>
   92 #include <netiso/argo_debug.h>
   93 
   94 #include <machine/stdarg.h>
   95 
   96 /*
   97  *      Global variables to esis implementation
   98  *
   99  *      esis_holding_time - the holding time (sec) parameter for outgoing pdus
  100  *      esis_config_time  - the frequency (sec) that hellos are generated
  101  *      esis_esconfig_time - suggested es configuration time placed in the ish.
  102  *
  103  */
  104 LIST_HEAD(, rawcb) esis_pcb;
  105 struct esis_stat esis_stat;
  106 int             esis_sendspace = 2048;
  107 int             esis_recvspace = 2048;
  108 short           esis_holding_time = ESIS_HT;
  109 short           esis_config_time = ESIS_CONFIG;
  110 short           esis_esconfig_time = ESIS_CONFIG;
  111 struct sockaddr_dl esis_dl = {sizeof(esis_dl), AF_LINK};
  112 
  113 struct callout  esis_config_ch;
  114 
  115 #define EXTEND_PACKET(m, mhdr, cp)\
  116         if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\
  117                 esis_stat.es_nomem++;\
  118                 m_freem(mhdr);\
  119                 return;\
  120         } else {\
  121                 (m) = (m)->m_next;\
  122                 (cp) = mtod((m), caddr_t);\
  123                 (m)->m_len = 0;\
  124         }
  125 
  126 /*
  127  * FUNCTION:            esis_init
  128  *
  129  * PURPOSE:             Initialize the kernel portion of esis protocol
  130  *
  131  * RETURNS:             nothing
  132  *
  133  * SIDE EFFECTS:
  134  *
  135  * NOTES:
  136  */
  137 void
  138 esis_init()
  139 {
  140         extern struct clnl_protosw clnl_protox[256];
  141 
  142         LIST_INIT(&esis_pcb);
  143 
  144         callout_init(&snpac_age_ch);
  145         callout_init(&esis_config_ch);
  146 
  147         callout_reset(&snpac_age_ch, hz, snpac_age, NULL);
  148         callout_reset(&esis_config_ch, hz, esis_config, NULL);
  149 
  150         clnl_protox[ISO9542_ESIS].clnl_input = esis_input;
  151         clnl_protox[ISO10589_ISIS].clnl_input = isis_input;
  152 #ifdef  ISO_X25ESIS
  153         clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input;
  154 #endif                          /* ISO_X25ESIS */
  155 }
  156 
  157 /*
  158  * FUNCTION:            esis_usrreq
  159  *
  160  * PURPOSE:             Handle user level esis requests
  161  *
  162  * RETURNS:             0 or appropriate errno
  163  *
  164  * SIDE EFFECTS:
  165  *
  166  */
  167 /* ARGSUSED */
  168 int
  169 esis_usrreq(so, req, m, nam, control, p)
  170         struct socket *so;
  171         int req;
  172         struct mbuf *m, *nam, *control;
  173         struct proc *p;
  174 {
  175         struct rawcb *rp;
  176         int error = 0;
  177 
  178         if (req == PRU_CONTROL)
  179                 return (EOPNOTSUPP);
  180 
  181         rp = sotorawcb(so);
  182 #ifdef DIAGNOSTIC
  183         if (req != PRU_SEND && req != PRU_SENDOOB && control)
  184                 panic("esis_usrreq: unexpected control mbuf");
  185 #endif
  186         if (rp == 0 && req != PRU_ATTACH) {
  187                 error = EINVAL;
  188                 goto release;
  189         }
  190 
  191         switch (req) {
  192 
  193         case PRU_ATTACH:
  194                 if (rp != 0) {
  195                         error = EISCONN;
  196                         break;
  197                 }
  198                 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))) {
  199                         error = EACCES;
  200                         break;
  201                 }
  202                 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
  203                         error = soreserve(so, esis_sendspace, esis_recvspace);
  204                         if (error)
  205                                 break;
  206                 }
  207                 MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
  208                 if (rp == 0) {
  209                         error = ENOBUFS;
  210                         break;
  211                 }
  212                 bzero(rp, sizeof(*rp));
  213                 rp->rcb_socket = so;
  214                 LIST_INSERT_HEAD(&esis_pcb, rp, rcb_list);
  215                 so->so_pcb = rp;
  216                 break;
  217 
  218         case PRU_SEND:
  219                 if (control && control->m_len) {
  220                         m_freem(control);
  221                         m_freem(m);
  222                         error = EINVAL;
  223                         break;
  224                 }
  225                 if (nam == NULL) {
  226                         m_freem(m);
  227                         error = EINVAL;
  228                         break;
  229                 }
  230                 /* error checking here */
  231                 error = isis_output(m, mtod(nam, struct sockaddr_dl *));
  232                 break;
  233 
  234         case PRU_SENDOOB:
  235                 m_freem(control);
  236                 m_freem(m);
  237                 error = EOPNOTSUPP;
  238                 break;
  239 
  240         case PRU_DETACH:
  241                 raw_detach(rp);
  242                 break;
  243 
  244         case PRU_SHUTDOWN:
  245                 socantsendmore(so);
  246                 break;
  247 
  248         case PRU_SENSE:
  249                 /*
  250                  * stat: don't bother with a blocksize.
  251                  */
  252                 return (0);
  253 
  254         default:
  255                 error = EOPNOTSUPP;
  256                 break;
  257         }
  258 
  259 release:
  260         return (error);
  261 }
  262 
  263 /*
  264  * FUNCTION:            esis_input
  265  *
  266  * PURPOSE:             Process an incoming esis packet
  267  *
  268  * RETURNS:             nothing
  269  *
  270  * SIDE EFFECTS:
  271  *
  272  * NOTES:
  273  */
  274 void
  275 #if __STDC__
  276 esis_input(struct mbuf *m0, ...)
  277 #else
  278 esis_input(m0, va_alist)
  279         struct mbuf    *m0;
  280         va_dcl
  281 #endif
  282 {
  283         struct snpa_hdr *shp;   /* subnetwork header */
  284         struct esis_fixed *pdu = mtod(m0, struct esis_fixed *);
  285         int    type;
  286         struct ifaddr *ifa;
  287         va_list ap;
  288 
  289         va_start(ap, m0);
  290         shp = va_arg(ap, struct snpa_hdr *);
  291         va_end(ap);
  292 
  293         for (ifa = shp->snh_ifp->if_addrlist.tqh_first; ifa != 0;
  294              ifa = ifa->ifa_list.tqe_next)
  295                 if (ifa->ifa_addr->sa_family == AF_ISO)
  296                         break;
  297         /* if we have no iso address just send it to the sockets */
  298         if (ifa == 0)
  299                 goto bad;
  300 
  301         /*
  302          *      check checksum if necessary
  303          */
  304         if (ESIS_CKSUM_REQUIRED(pdu) &&
  305             iso_check_csum(m0, (int) pdu->esis_hdr_len)) {
  306                 esis_stat.es_badcsum++;
  307                 goto bad;
  308         }
  309         /* check version */
  310         if (pdu->esis_vers != ESIS_VERSION) {
  311                 esis_stat.es_badvers++;
  312                 goto bad;
  313         }
  314         type = pdu->esis_type & 0x1f;
  315         switch (type) {
  316         case ESIS_ESH:
  317                 esis_eshinput(m0, shp);
  318                 break;
  319 
  320         case ESIS_ISH:
  321                 esis_ishinput(m0, shp);
  322                 break;
  323 
  324         case ESIS_RD:
  325                 esis_rdinput(m0, shp);
  326                 break;
  327 
  328         default:
  329                 esis_stat.es_badtype++;
  330         }
  331 
  332 bad:
  333         if (esis_pcb.lh_first != 0)
  334                 isis_input(m0, shp);
  335         else
  336                 m_freem(m0);
  337 }
  338 
  339 /*
  340  * FUNCTION:            esis_rdoutput
  341  *
  342  * PURPOSE:             Transmit a redirect pdu
  343  *
  344  * RETURNS:             nothing
  345  *
  346  * SIDE EFFECTS:
  347  *
  348  * NOTES:               Assumes there is enough space for fixed part of header,
  349  *                      DA, BSNPA and NET in first mbuf.
  350  */
  351 void
  352 esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, rt)
  353         struct snpa_hdr *inbound_shp;   /* snpa hdr from incoming packet */
  354         struct mbuf    *inbound_m;      /* incoming pkt itself */
  355         struct clnp_optidx *inbound_oidx;       /* clnp options assoc with
  356                                                  * incoming pkt */
  357         struct iso_addr *rd_dstnsap;    /* ultimate destination of pkt */
  358         struct rtentry *rt;     /* snpa cache info regarding next hop of pkt */
  359 {
  360         struct mbuf    *m, *m0;
  361         caddr_t         cp;
  362         struct esis_fixed *pdu;
  363         int             len;
  364         struct sockaddr_iso siso;
  365         struct ifnet   *ifp = inbound_shp->snh_ifp;
  366         struct sockaddr_dl *sdl;
  367         struct iso_addr *rd_gwnsap;
  368 
  369         if (rt->rt_flags & RTF_GATEWAY) {
  370                 rd_gwnsap = &satosiso(rt->rt_gateway)->siso_addr;
  371                 rt = rtalloc1(rt->rt_gateway, 0);
  372         } else
  373                 rd_gwnsap = &satosiso(rt_key(rt))->siso_addr;
  374         if (rt == 0 || (sdl = (struct sockaddr_dl *) rt->rt_gateway) == 0 ||
  375             sdl->sdl_family != AF_LINK) {
  376                 /*
  377                  * maybe we should have a function that you could put in the
  378                  * iso_ifaddr structure which could translate iso_addrs into
  379                  * snpa's where there is a known mapping for that address
  380                  * type
  381                  */
  382                 esis_stat.es_badtype++;
  383                 return;
  384         }
  385         esis_stat.es_rdsent++;
  386 #ifdef ARGO_DEBUG
  387         if (argo_debug[D_ESISOUTPUT]) {
  388                 printf(
  389                     "esis_rdoutput: ifp %p (%s), ht %d, m %p, oidx %p\n",
  390                     ifp, ifp->if_xname, esis_holding_time,
  391                     inbound_m, inbound_oidx);
  392                 printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap));
  393                 printf("\tredirected toward:%s\n", clnp_iso_addrp(rd_gwnsap));
  394         }
  395 #endif
  396 
  397         if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
  398                 esis_stat.es_nomem++;
  399                 return;
  400         }
  401         bzero(mtod(m, caddr_t), MHLEN);
  402 
  403         pdu = mtod(m, struct esis_fixed *);
  404         cp = (caddr_t) (pdu + 1);       /* pointer arith.; 1st byte after
  405                                          * header */
  406         len = sizeof(struct esis_fixed);
  407 
  408         /*
  409          *      Build fixed part of header
  410          */
  411         pdu->esis_proto_id = ISO9542_ESIS;
  412         pdu->esis_vers = ESIS_VERSION;
  413         pdu->esis_type = ESIS_RD;
  414         HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time);
  415 
  416         /* Insert destination address */
  417         (void) esis_insert_addr(&cp, &len, rd_dstnsap, m, 0);
  418 
  419         /* Insert the snpa of better next hop */
  420         *cp++ = sdl->sdl_alen;
  421         bcopy(LLADDR(sdl), cp, sdl->sdl_alen);
  422         cp += sdl->sdl_alen;
  423         len += (sdl->sdl_alen + 1);
  424 
  425         /*
  426          * If the next hop is not the destination, then it ought to be an IS
  427          * and it should be inserted next. Else, set the NETL to 0
  428          */
  429         /* PHASE2 use mask from ifp of outgoing interface */
  430         if (!iso_addrmatch1(rd_dstnsap, rd_gwnsap)) {
  431 #if 0
  432                 /* this should not happen: */
  433                 if ((nhop_sc->sc_flags & SNPA_IS) == 0) {
  434                         printf(
  435                     "esis_rdoutput: next hop is not dst and not an IS\n");
  436                         m_freem(m0);
  437                         return;
  438                 }
  439 #endif
  440                 (void) esis_insert_addr(&cp, &len, rd_gwnsap, m, 0);
  441         } else {
  442                 *cp++ = 0;      /* NETL */
  443                 len++;
  444         }
  445         m->m_len = len;
  446 
  447         /*
  448          * PHASE2
  449          * If redirect is to an IS, add an address mask. The mask to be
  450          * used should be the mask present in the routing entry used to
  451          * forward the original data packet.
  452          */
  453 
  454         /*
  455          * Copy Qos, priority, or security options present in original npdu
  456          */
  457         if (inbound_oidx) {
  458                 /* THIS CODE IS CURRENTLY (mostly) UNTESTED */
  459                 int             optlen = 0;
  460                 if (inbound_oidx->cni_qos_formatp)
  461                         optlen += (inbound_oidx->cni_qos_len + 2);
  462                 if (inbound_oidx->cni_priorp)   /* priority option is 1 byte
  463                                                  * long */
  464                         optlen += 3;
  465                 if (inbound_oidx->cni_securep)
  466                         optlen += (inbound_oidx->cni_secure_len + 2);
  467                 if (M_TRAILINGSPACE(m) < optlen) {
  468                         EXTEND_PACKET(m, m0, cp);
  469                         m->m_len = 0;
  470                         /* assumes MLEN > optlen */
  471                 }
  472                 /* assume MLEN-len > optlen */
  473                 /*
  474                  * When copying options, copy from ptr - 2 in order to grab
  475                  * the option code and length
  476                  */
  477                 if (inbound_oidx->cni_qos_formatp) {
  478                         bcopy(mtod(inbound_m, caddr_t) +
  479                                 inbound_oidx->cni_qos_formatp - 2,
  480                               cp, (unsigned) (inbound_oidx->cni_qos_len + 2));
  481                         cp += inbound_oidx->cni_qos_len + 2;
  482                 }
  483                 if (inbound_oidx->cni_priorp) {
  484                         bcopy(mtod(inbound_m, caddr_t) +
  485                                 inbound_oidx->cni_priorp - 2, cp, 3);
  486                         cp += 3;
  487                 }
  488                 if (inbound_oidx->cni_securep) {
  489                         bcopy(mtod(inbound_m, caddr_t) +
  490                                 inbound_oidx->cni_securep - 2, cp,
  491                               (unsigned) (inbound_oidx->cni_secure_len + 2));
  492                         cp += inbound_oidx->cni_secure_len + 2;
  493                 }
  494                 m->m_len += optlen;
  495                 len += optlen;
  496         }
  497         pdu->esis_hdr_len = m0->m_pkthdr.len = len;
  498         iso_gen_csum(m0, ESIS_CKSUM_OFF, (int) pdu->esis_hdr_len);
  499 
  500         bzero((caddr_t) & siso, sizeof(siso));
  501         siso.siso_family = AF_ISO;
  502         siso.siso_data[0] = AFI_SNA;
  503         siso.siso_nlen = 6 + 1; /* should be taken from snpa_hdr */
  504         /* +1 is for AFI */
  505         bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6);
  506         (ifp->if_output) (ifp, m0, sisotosa(&siso), 0);
  507 }
  508 
  509 /*
  510  * FUNCTION:            esis_insert_addr
  511  *
  512  * PURPOSE:             Insert an iso_addr into a buffer
  513  *
  514  * RETURNS:             true if buffer was big enough, else false
  515  *
  516  * SIDE EFFECTS:        Increment buf & len according to size of iso_addr
  517  *
  518  * NOTES:               Plus 1 here is for length byte
  519  */
  520 int
  521 esis_insert_addr(buf, len, isoa, m, nsellen)
  522         caddr_t *buf;   /* ptr to buffer to put address into */
  523         int            *len;    /* ptr to length of buffer so far */
  524         struct iso_addr *isoa;  /* ptr to address */
  525         struct mbuf *m;/* determine if there remains space */
  526         int             nsellen;
  527 {
  528         int    newlen, result = 0;
  529 
  530         isoa->isoa_len -= nsellen;
  531         newlen = isoa->isoa_len + 1;
  532         if (newlen <= M_TRAILINGSPACE(m)) {
  533                 bcopy((caddr_t) isoa, *buf, newlen);
  534                 *len += newlen;
  535                 *buf += newlen;
  536                 m->m_len += newlen;
  537                 result = 1;
  538         }
  539         isoa->isoa_len += nsellen;
  540         return (result);
  541 }
  542 
  543 #define ESIS_EXTRACT_ADDR(d, b) { d = (struct iso_addr *)(b); b += (1 + *b); \
  544             if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
  545 #define ESIS_NEXT_OPTION(b)     { b += (2 + b[1]); \
  546             if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
  547 int             ESHonly = 0;
  548 
  549 /*
  550  * FUNCTION:            esis_eshinput
  551  *
  552  * PURPOSE:             Process an incoming ESH pdu
  553  *
  554  * RETURNS:             nothing
  555  *
  556  * SIDE EFFECTS:
  557  *
  558  * NOTES:
  559  */
  560 void
  561 esis_eshinput(m, shp)
  562         struct mbuf    *m;      /* esh pdu */
  563         struct snpa_hdr *shp;   /* subnetwork header */
  564 {
  565         struct esis_fixed *pdu = mtod(m, struct esis_fixed *);
  566         u_short         ht;     /* holding time */
  567         struct iso_addr *nsap = NULL;
  568         int             naddr;
  569         u_char         *buf = (u_char *) (pdu + 1);
  570         u_char         *buflim = pdu->esis_hdr_len + (u_char *) pdu;
  571         int             new_entry = 0;
  572 
  573         esis_stat.es_eshrcvd++;
  574 
  575         CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
  576 
  577         naddr = *buf++;
  578         if (buf >= buflim)
  579                 goto bad;
  580         if (naddr == 1) {
  581                 ESIS_EXTRACT_ADDR(nsap, buf);
  582                 new_entry = snpac_add(shp->snh_ifp,
  583                                       nsap, shp->snh_shost, SNPA_ES, ht, 0);
  584         } else {
  585                 int             nsellength = 0, nlen = 0;
  586                 struct ifaddr *ifa;
  587                 /*
  588                  * See if we want to compress out multiple nsaps
  589                  * differing only by nsel
  590                  */
  591                 for (ifa = shp->snh_ifp->if_addrlist.tqh_first; ifa != 0;
  592                      ifa = ifa->ifa_list.tqe_next)
  593                         if (ifa->ifa_addr->sa_family == AF_ISO) {
  594                                 nsellength =
  595                                 ((struct iso_ifaddr *) ifa)->ia_addr.siso_tlen;
  596                                 break;
  597                         }
  598 #ifdef ARGO_DEBUG
  599                 if (argo_debug[D_ESISINPUT]) {
  600                         printf(
  601                         "esis_eshinput: esh: ht %d, naddr %d nsellength %d\n",
  602                                ht, naddr, nsellength);
  603                 }
  604 #endif
  605                 while (naddr-- > 0) {
  606                         struct iso_addr *nsap2;
  607                         u_char         *buf2;
  608                         ESIS_EXTRACT_ADDR(nsap, buf);
  609                         /*
  610                          * see if there is at least one more nsap in ESH
  611                          * differing only by nsel
  612                          */
  613                         if (nsellength != 0)
  614                                 for (buf2 = buf; buf2 < buflim;) {
  615                                         ESIS_EXTRACT_ADDR(nsap2, buf2);
  616 #ifdef ARGO_DEBUG
  617                                         if (argo_debug[D_ESISINPUT]) {
  618                                                 printf(
  619                                                 "esis_eshinput: comparing %s ",
  620                                                        clnp_iso_addrp(nsap));
  621                                                 printf("and %s\n",
  622                                                        clnp_iso_addrp(nsap2));
  623                                         }
  624 #endif
  625                                         if (Bcmp(nsap->isoa_genaddr,
  626                                                  nsap2->isoa_genaddr,
  627                                                  nsap->isoa_len - nsellength)
  628                                              == 0) {
  629                                                 nlen = nsellength;
  630                                                 break;
  631                                         }
  632                                 }
  633                         new_entry |= snpac_add(shp->snh_ifp,
  634                                    nsap, shp->snh_shost, SNPA_ES, ht, nlen);
  635                         nlen = 0;
  636                 }
  637         }
  638 #ifdef ARGO_DEBUG
  639         if (argo_debug[D_ESISINPUT]) {
  640                 printf("esis_eshinput: nsap %s is %s\n",
  641                        clnp_iso_addrp(nsap), new_entry ? "new" : "old");
  642         }
  643 #endif
  644         if (new_entry && (iso_systype & SNPA_IS))
  645                 esis_shoutput(shp->snh_ifp, ESIS_ISH, esis_holding_time,
  646                               shp->snh_shost, 6, (struct iso_addr *) 0);
  647 bad:
  648         return;
  649 }
  650 
  651 /*
  652  * FUNCTION:            esis_ishinput
  653  *
  654  * PURPOSE:             process an incoming ISH pdu
  655  *
  656  * RETURNS:
  657  *
  658  * SIDE EFFECTS:
  659  *
  660  * NOTES:
  661  */
  662 void
  663 esis_ishinput(m, shp)
  664         struct mbuf    *m;      /* esh pdu */
  665         struct snpa_hdr *shp;   /* subnetwork header */
  666 {
  667         struct esis_fixed *pdu = mtod(m, struct esis_fixed *);
  668         u_short         ht, newct;      /* holding time */
  669         struct iso_addr *nsap;  /* Network Entity Title */
  670         u_char *buf = (u_char *) (pdu + 1);
  671         u_char *buflim = pdu->esis_hdr_len + (u_char *) pdu;
  672         int             new_entry;
  673 
  674         esis_stat.es_ishrcvd++;
  675         CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
  676 
  677 #ifdef ARGO_DEBUG
  678         if (argo_debug[D_ESISINPUT]) {
  679                 printf("esis_ishinput: ish: ht %d\n", ht);
  680         }
  681 #endif
  682         if (ESHonly)
  683                 goto bad;
  684 
  685         ESIS_EXTRACT_ADDR(nsap, buf);
  686 
  687         while (buf < buflim) {
  688                 switch (*buf) {
  689                 case ESISOVAL_ESCT:
  690                         if (iso_systype & SNPA_IS)
  691                                 break;
  692                         if (buf[1] != 2)
  693                                 goto bad;
  694                         CTOH(buf[2], buf[3], newct);
  695                         if ((u_short) esis_config_time != newct) {
  696                                 callout_stop(&esis_config_ch);
  697                                 esis_config_time = newct;
  698                                 esis_config(NULL);
  699                         }
  700                         break;
  701 
  702                 default:
  703                         printf("Unknown ISH option: %x\n", *buf);
  704                 }
  705                 ESIS_NEXT_OPTION(buf);
  706         }
  707         new_entry = snpac_add(shp->snh_ifp, nsap, shp->snh_shost, SNPA_IS,
  708                               ht, 0);
  709 #ifdef ARGO_DEBUG
  710         if (argo_debug[D_ESISINPUT]) {
  711                 printf("esis_ishinput: nsap %s is %s\n",
  712                    clnp_iso_addrp(nsap), new_entry ? "new" : "old");
  713         }
  714 #endif
  715 
  716         if (new_entry)
  717                 esis_shoutput(shp->snh_ifp,
  718                               iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
  719                 esis_holding_time, shp->snh_shost, 6, (struct iso_addr *) 0);
  720 bad:
  721         return;
  722 }
  723 
  724 /*
  725  * FUNCTION:            esis_rdinput
  726  *
  727  * PURPOSE:             Process an incoming RD pdu
  728  *
  729  * RETURNS:
  730  *
  731  * SIDE EFFECTS:
  732  *
  733  * NOTES:
  734  */
  735 void
  736 esis_rdinput(m0, shp)
  737         struct mbuf    *m0;     /* esh pdu */
  738         struct snpa_hdr *shp;   /* subnetwork header */
  739 {
  740         struct esis_fixed *pdu = mtod(m0, struct esis_fixed *);
  741         u_short         ht;     /* holding time */
  742         struct iso_addr *da, *net = 0, *netmask = 0, *snpamask = 0;
  743         struct iso_addr *bsnpa;
  744         u_char *buf = (u_char *) (pdu + 1);
  745         u_char *buflim = pdu->esis_hdr_len + (u_char *) pdu;
  746 
  747         esis_stat.es_rdrcvd++;
  748 
  749         /* intermediate systems ignore redirects */
  750         if (iso_systype & SNPA_IS)
  751                 return;
  752         if (ESHonly)
  753                 return;
  754 
  755         CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
  756         if (buf >= buflim)
  757                 return;
  758 
  759         /* Extract DA */
  760         ESIS_EXTRACT_ADDR(da, buf);
  761 
  762         /* Extract better snpa */
  763         ESIS_EXTRACT_ADDR(bsnpa, buf);
  764 
  765         /* Extract NET if present */
  766         if (buf < buflim) {
  767                 if (*buf == 0)
  768                         buf++;  /* no NET present, skip NETL anyway */
  769                 else
  770                         ESIS_EXTRACT_ADDR(net, buf);
  771         }
  772         /* process options */
  773         while (buf < buflim) {
  774                 switch (*buf) {
  775                 case ESISOVAL_SNPAMASK:
  776                         if (snpamask)   /* duplicate */
  777                                 return;
  778                         snpamask = (struct iso_addr *) (buf + 1);
  779                         break;
  780 
  781                 case ESISOVAL_NETMASK:
  782                         if (netmask)    /* duplicate */
  783                                 return;
  784                         netmask = (struct iso_addr *) (buf + 1);
  785                         break;
  786 
  787                 default:
  788                         printf("Unknown option in ESIS RD (0x%x)\n", buf[-1]);
  789                 }
  790                 ESIS_NEXT_OPTION(buf);
  791         }
  792 
  793 #ifdef ARGO_DEBUG
  794         if (argo_debug[D_ESISINPUT]) {
  795                 printf("esis_rdinput: rd: ht %d, da %s\n", ht,
  796                     clnp_iso_addrp(da));
  797                 if (net)
  798                         printf("\t: net %s\n", clnp_iso_addrp(net));
  799         }
  800 #endif
  801         /*
  802          * If netl is zero, then redirect is to an ES. We need to add an entry
  803          * to the snpa cache for (destination, better snpa).
  804          * If netl is not zero, then the redirect is to an IS. In this
  805          * case, add an snpa cache entry for (net, better snpa).
  806          *
  807          * If the redirect is to an IS, add a route entry towards that
  808          * IS.
  809          */
  810         if (net == 0 || net->isoa_len == 0 || snpamask) {
  811                 /* redirect to an ES */
  812                 snpac_add(shp->snh_ifp, da,
  813                           bsnpa->isoa_genaddr, SNPA_ES, ht, 0);
  814         } else {
  815                 snpac_add(shp->snh_ifp, net,
  816                           bsnpa->isoa_genaddr, SNPA_IS, ht, 0);
  817                 snpac_addrt(shp->snh_ifp, da, net, netmask);
  818         }
  819 bad:    ;       /* Needed by ESIS_NEXT_OPTION */
  820 }
  821 
  822 /*
  823  * FUNCTION:            esis_config
  824  *
  825  * PURPOSE:             Report configuration
  826  *
  827  * RETURNS:
  828  *
  829  * SIDE EFFECTS:
  830  *
  831  * NOTES:               Called every esis_config_time seconds
  832  */
  833 /*ARGSUSED*/
  834 void
  835 esis_config(v)
  836         void *v;
  837 {
  838         struct ifnet *ifp;
  839 
  840         callout_reset(&esis_config_ch, hz * esis_config_time,
  841             esis_config, NULL);
  842 
  843         /*
  844          * Report configuration for each interface that - is UP - has
  845          * BROADCAST capability - has an ISO address
  846          */
  847         /*
  848          * Todo: a better way would be to construct the esh or ish once and
  849          * copy it out for all devices, possibly calling a method in the
  850          * iso_ifaddr structure to encapsulate and transmit it.  This could
  851          * work to advantage for non-broadcast media
  852          */
  853 
  854         for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next) {
  855                 if ((ifp->if_flags & IFF_UP) &&
  856                     (ifp->if_flags & IFF_BROADCAST)) {
  857                         /* search for an ISO address family */
  858                         struct ifaddr  *ifa;
  859 
  860                         for (ifa = ifp->if_addrlist.tqh_first; ifa != 0;
  861                              ifa = ifa->ifa_list.tqe_next) {
  862                                 if (ifa->ifa_addr->sa_family == AF_ISO) {
  863                                         esis_shoutput(ifp,
  864                               iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
  865                               esis_holding_time,
  866                               (caddr_t) (iso_systype & SNPA_ES ? all_is_snpa :
  867                                      all_es_snpa), 6, (struct iso_addr *) 0);
  868                                         break;
  869                                 }
  870                         }
  871                 }
  872         }
  873 }
  874 
  875 /*
  876  * FUNCTION:            esis_shoutput
  877  *
  878  * PURPOSE:             Transmit an esh or ish pdu
  879  *
  880  * RETURNS:             nothing
  881  *
  882  * SIDE EFFECTS:
  883  *
  884  * NOTES:
  885  */
  886 void
  887 esis_shoutput(ifp, type, ht, sn_addr, sn_len, isoa)
  888         struct ifnet   *ifp;
  889         int             type;
  890         short           ht;
  891         caddr_t         sn_addr;
  892         int             sn_len;
  893         struct iso_addr *isoa;
  894 {
  895         struct mbuf    *m, *m0;
  896         caddr_t         cp, naddrp;
  897         int             naddr = 0;
  898         struct esis_fixed *pdu;
  899         struct iso_ifaddr *ia;
  900         int             len;
  901         struct sockaddr_iso siso;
  902 
  903         if (type == ESIS_ESH)
  904                 esis_stat.es_eshsent++;
  905         else if (type == ESIS_ISH)
  906                 esis_stat.es_ishsent++;
  907         else {
  908                 printf("esis_shoutput: bad pdu type\n");
  909                 return;
  910         }
  911 
  912 #ifdef ARGO_DEBUG
  913         if (argo_debug[D_ESISOUTPUT]) {
  914                 int             i;
  915                 printf("esis_shoutput: ifp %p (%s), %s, ht %d, to: [%d] ",
  916                     ifp, ifp->if_xname,
  917                     type == ESIS_ESH ? "esh" : "ish",
  918                     ht, sn_len);
  919                 for (i = 0; i < sn_len; i++)
  920                         printf("%x%c", *(sn_addr + i),
  921                             i < (sn_len - 1) ? ':' : ' ');
  922                 printf("\n");
  923         }
  924 #endif
  925 
  926         if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
  927                 esis_stat.es_nomem++;
  928                 return;
  929         }
  930         bzero(mtod(m, caddr_t), MHLEN);
  931 
  932         pdu = mtod(m, struct esis_fixed *);
  933         naddrp = cp = (caddr_t) (pdu + 1);
  934         len = sizeof(struct esis_fixed);
  935 
  936         /*
  937          *      Build fixed part of header
  938          */
  939         pdu->esis_proto_id = ISO9542_ESIS;
  940         pdu->esis_vers = ESIS_VERSION;
  941         pdu->esis_type = type;
  942         HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
  943 
  944         if (type == ESIS_ESH) {
  945                 cp++;
  946                 len++;
  947         }
  948         m->m_len = len;
  949         if (isoa) {
  950                 /*
  951                  * Here we are responding to a clnp packet sent to an NSAP
  952                  * that is ours which was sent to the MAC addr all_es's.
  953                  * It is possible that we did not specifically advertise this
  954                  * NSAP, even though it is ours, so we will respond
  955                  * directly to the sender that we are here.  If we do have
  956                  * multiple NSEL's we'll tack them on so he can compress
  957                  * them out.
  958                  */
  959                 (void) esis_insert_addr(&cp, &len, isoa, m, 0);
  960                 naddr = 1;
  961         }
  962         for (ia = iso_ifaddr.tqh_first; ia != 0; ia = ia->ia_list.tqe_next) {
  963                 int nsellen = (type == ESIS_ISH ? ia->ia_addr.siso_tlen : 0);
  964                 int n = ia->ia_addr.siso_nlen;
  965                 struct iso_ifaddr *ia2;
  966 
  967                 if (type == ESIS_ISH && naddr > 0)
  968                         break;
  969                 for (ia2 = iso_ifaddr.tqh_first; ia2 != ia;
  970                      ia2 = ia2->ia_list.tqe_next)
  971                         if (Bcmp(ia->ia_addr.siso_data,
  972                                  ia2->ia_addr.siso_data, n) == 0)
  973                                 break;
  974                 if (ia2 != ia)
  975                         continue;       /* Means we have previously copied
  976                                          * this nsap */
  977                 if (isoa && Bcmp(ia->ia_addr.siso_data,
  978                                  isoa->isoa_genaddr, n) == 0) {
  979                         isoa = 0;
  980                         continue;       /* Ditto */
  981                 }
  982 #ifdef ARGO_DEBUG
  983                 if (argo_debug[D_ESISOUTPUT]) {
  984                         printf("esis_shoutput: adding NSAP %s\n",
  985                             clnp_iso_addrp(&ia->ia_addr.siso_addr));
  986                 }
  987 #endif
  988                 if (!esis_insert_addr(&cp, &len,
  989                                       &ia->ia_addr.siso_addr, m, nsellen)) {
  990                         EXTEND_PACKET(m, m0, cp);
  991                         (void) esis_insert_addr(&cp, &len,
  992                                                 &ia->ia_addr.siso_addr, m,
  993                                                 nsellen);
  994                 }
  995                 naddr++;
  996         }
  997 
  998         if (type == ESIS_ESH)
  999                 *naddrp = naddr;
 1000         else {
 1001                 /* add suggested es config timer option to ISH */
 1002                 if (M_TRAILINGSPACE(m) < 4) {
 1003                         printf("esis_shoutput: extending packet\n");
 1004                         EXTEND_PACKET(m, m0, cp);
 1005                 }
 1006                 *cp++ = ESISOVAL_ESCT;
 1007                 *cp++ = 2;
 1008                 HTOC(*cp, *(cp + 1), esis_esconfig_time);
 1009                 len += 4;
 1010                 m->m_len += 4;
 1011 #ifdef ARGO_DEBUG
 1012                 if (argo_debug[D_ESISOUTPUT]) {
 1013                         printf("m0 %p, m %p, data %p, len %d, cp %p\n",
 1014                             m0, m, m->m_data, m->m_len, cp);
 1015                 }
 1016 #endif
 1017         }
 1018 
 1019         m0->m_pkthdr.len = len;
 1020         pdu->esis_hdr_len = len;
 1021         iso_gen_csum(m0, ESIS_CKSUM_OFF, (int) pdu->esis_hdr_len);
 1022 
 1023         bzero((caddr_t) & siso, sizeof(siso));
 1024         siso.siso_family = AF_ISO;
 1025         siso.siso_data[0] = AFI_SNA;
 1026         siso.siso_nlen = sn_len + 1;
 1027         bcopy(sn_addr, siso.siso_data + 1, (unsigned) sn_len);
 1028         (ifp->if_output) (ifp, m0, sisotosa(&siso), 0);
 1029 }
 1030 
 1031 /*
 1032  * FUNCTION:            isis_input
 1033  *
 1034  * PURPOSE:             Process an incoming isis packet
 1035  *
 1036  * RETURNS:             nothing
 1037  *
 1038  * SIDE EFFECTS:
 1039  *
 1040  * NOTES:
 1041  */
 1042 void
 1043 #if __STDC__
 1044 isis_input(struct mbuf *m0, ...)
 1045 #else
 1046 isis_input(m0, va_alist)
 1047         struct mbuf    *m0;
 1048         va_dcl
 1049 #endif
 1050 {
 1051         struct snpa_hdr *shp;   /* subnetwork header */
 1052         struct rawcb *rp, *first_rp = 0;
 1053         struct ifnet   *ifp;
 1054         struct mbuf    *mm;
 1055         va_list ap;
 1056 
 1057         va_start(ap, m0);
 1058         shp = va_arg(ap, struct snpa_hdr *);
 1059         va_end(ap);
 1060         ifp = shp->snh_ifp;
 1061 
 1062 #ifdef ARGO_DEBUG
 1063         if (argo_debug[D_ISISINPUT]) {
 1064                 int             i;
 1065 
 1066                 printf("isis_input: pkt on ifp %p (%s): from:",
 1067                     ifp, ifp->if_xname);
 1068                 for (i = 0; i < 6; i++)
 1069                         printf("%x%c", shp->snh_shost[i] & 0xff,
 1070                             (i < 5) ? ':' : ' ');
 1071                 printf(" to:");
 1072                 for (i = 0; i < 6; i++)
 1073                         printf("%x%c", shp->snh_dhost[i] & 0xff, 
 1074                             (i < 5) ? ':' : ' ');
 1075                 printf("\n");
 1076         }
 1077 #endif
 1078         esis_dl.sdl_alen = ifp->if_addrlen;
 1079         esis_dl.sdl_index = ifp->if_index;
 1080         bcopy(shp->snh_shost, (caddr_t) esis_dl.sdl_data, esis_dl.sdl_alen);
 1081         for (rp = esis_pcb.lh_first; rp != 0; rp = rp->rcb_list.le_next) {
 1082                 if (first_rp == 0) {
 1083                         first_rp = rp;
 1084                         continue;
 1085                 }
 1086                 /* can't block at interrupt level */
 1087                 if ((mm = m_copy(m0, 0, M_COPYALL)) != NULL) {
 1088                         if (sbappendaddr(&rp->rcb_socket->so_rcv,
 1089                                          (struct sockaddr *) &esis_dl, mm,
 1090                                          (struct mbuf *) 0) != 0) {
 1091                                 sorwakeup(rp->rcb_socket);
 1092                         } else {
 1093 #ifdef ARGO_DEBUG
 1094                                 if (argo_debug[D_ISISINPUT]) {
 1095                                         printf(
 1096                                     "Error in sbappenaddr, mm = %p\n", mm);
 1097                                 }
 1098 #endif
 1099                                 m_freem(mm);
 1100                         }
 1101                 }
 1102         }
 1103         if (first_rp && sbappendaddr(&first_rp->rcb_socket->so_rcv,
 1104                (struct sockaddr *) &esis_dl, m0, (struct mbuf *) 0) != 0) {
 1105                 sorwakeup(first_rp->rcb_socket);
 1106                 return;
 1107         }
 1108         m_freem(m0);
 1109 }
 1110 
 1111 int
 1112 #if __STDC__
 1113 isis_output(struct mbuf *m, ...)
 1114 #else
 1115 isis_output(m, va_alist)
 1116         struct mbuf    *m;
 1117         va_dcl
 1118 #endif
 1119 {
 1120         struct sockaddr_dl *sdl;
 1121         struct ifnet *ifp;
 1122         struct ifaddr  *ifa;
 1123         struct sockaddr_iso siso;
 1124         int             error = 0;
 1125         unsigned        sn_len;
 1126         va_list ap;
 1127 
 1128         va_start(ap, m);
 1129         sdl = va_arg(ap, struct sockaddr_dl *);
 1130         va_end(ap);
 1131 
 1132         ifa = ifa_ifwithnet((struct sockaddr *) sdl);   /* get ifp from sdl */
 1133         if (ifa == 0) {
 1134 #ifdef ARGO_DEBUG
 1135                 if (argo_debug[D_ISISOUTPUT]) {
 1136                         printf("isis_output: interface not found\n");
 1137                 }
 1138 #endif
 1139                 error = EINVAL;
 1140                 goto release;
 1141         }
 1142         ifp = ifa->ifa_ifp;
 1143         sn_len = sdl->sdl_alen;
 1144 #ifdef ARGO_DEBUG
 1145         if (argo_debug[D_ISISOUTPUT]) {
 1146                 u_char *cp = (u_char *) LLADDR(sdl), *cplim = cp + sn_len;
 1147                 printf("isis_output: ifp %p (%s), to: ",
 1148                     ifp, ifp->if_xname);
 1149                 while (cp < cplim) {
 1150                         printf("%x", *cp++);
 1151                         printf("%c", (cp < cplim) ? ':' : ' ');
 1152                 }
 1153                 printf("\n");
 1154         }
 1155 #endif
 1156         bzero((caddr_t) & siso, sizeof(siso));
 1157         siso.siso_family = AF_ISO;      /* This convention may be useful for
 1158                                          * X.25 */
 1159         if (sn_len == 0)
 1160                 siso.siso_nlen = 0;
 1161         else {
 1162                 siso.siso_data[0] = AFI_SNA;
 1163                 siso.siso_nlen = sn_len + 1;
 1164                 bcopy(LLADDR(sdl), siso.siso_data + 1, sn_len);
 1165         }
 1166         error = (ifp->if_output) (ifp, m, sisotosa(&siso), 0);
 1167         if (error) {
 1168 #ifdef ARGO_DEBUG
 1169                 if (argo_debug[D_ISISOUTPUT]) {
 1170                         printf("isis_output: error from if_output is %d\n",
 1171                             error);
 1172                 }
 1173 #endif
 1174         }
 1175         return (error);
 1176 
 1177 release:
 1178         if (m != NULL)
 1179                 m_freem(m);
 1180         return (error);
 1181 }
 1182 
 1183 
 1184 /*
 1185  * FUNCTION:            esis_ctlinput
 1186  *
 1187  * PURPOSE:             Handle the PRC_IFDOWN transition
 1188  *
 1189  * RETURNS:             nothing
 1190  *
 1191  * SIDE EFFECTS:
 1192  *
 1193  * NOTES:               Calls snpac_flush for interface specified.
 1194  *                      The loop through iso_ifaddr is stupid because
 1195  *                      back in if_down, we knew the ifp...
 1196  */
 1197 void *
 1198 esis_ctlinput(req, siso, dummy)
 1199         int             req;    /* request: we handle only PRC_IFDOWN */
 1200         struct sockaddr *siso;  /* address of ifp */
 1201         void *dummy;
 1202 {
 1203         struct iso_ifaddr *ia;  /* scan through interface addresses */
 1204 
 1205         /*XXX correct? */
 1206         if (siso->sa_family != AF_ISO)
 1207                 return NULL;
 1208         if (req == PRC_IFDOWN)
 1209                 for (ia = iso_ifaddr.tqh_first; ia != 0;
 1210                      ia = ia->ia_list.tqe_next) {
 1211                         if (iso_addrmatch(IA_SIS(ia),
 1212                                           (struct sockaddr_iso *) siso))
 1213                                 snpac_flushifp(ia->ia_ifp);
 1214                 }
 1215         return NULL;
 1216 }
 1217 
 1218 #endif /* ISO */

Cache object: 04cf7578e5657607fd3993d563f53a07


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.