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

Cache object: 73da53a2eb47e65f00eeeec7c9f21d8c


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