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

Cache object: 809cccce7c77f6fd791c035609ead1b6


[ 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.