File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / isisd / isis_dlpi.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:10 2016 UTC (7 years, 9 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    1: /*
    2:  * IS-IS Rout(e)ing protocol - isis_dlpi.c
    3:  *
    4:  * Copyright (C) 2001,2002    Sampo Saaristo
    5:  *                            Tampere University of Technology      
    6:  *                            Institute of Communications Engineering
    7:  *
    8:  * This program is free software; you can redistribute it and/or modify it 
    9:  * under the terms of the GNU General Public Licenseas published by the Free 
   10:  * Software Foundation; either version 2 of the License, or (at your option) 
   11:  * any later version.
   12:  *
   13:  * This program is distributed in the hope that it will be useful,but WITHOUT 
   14:  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
   15:  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
   16:  * more details.
   17: 
   18:  * You should have received a copy of the GNU General Public License along 
   19:  * with this program; if not, write to the Free Software Foundation, Inc., 
   20:  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   21:  */
   22: 
   23: #include <zebra.h>
   24: #if ISIS_METHOD == ISIS_METHOD_DLPI
   25: #include <net/if.h>
   26: #include <netinet/if_ether.h>
   27: #include <sys/types.h>
   28: #include <unistd.h>
   29: #include <fcntl.h>
   30: #include <stropts.h>
   31: #include <poll.h>
   32: #include <sys/dlpi.h>
   33: #include <sys/pfmod.h>
   34: 
   35: #include "log.h"
   36: #include "network.h"
   37: #include "stream.h"
   38: #include "if.h"
   39: 
   40: #include "isisd/dict.h"
   41: #include "isisd/include-netbsd/iso.h"
   42: #include "isisd/isis_constants.h"
   43: #include "isisd/isis_common.h"
   44: #include "isisd/isis_circuit.h"
   45: #include "isisd/isis_flags.h"
   46: #include "isisd/isisd.h"
   47: #include "isisd/isis_network.h"
   48: 
   49: #include "privs.h"
   50: 
   51: extern struct zebra_privs_t isisd_privs;
   52: 
   53: static t_uscalar_t dlpi_ctl[1024];	/* DLPI control messages */
   54: 
   55: /*
   56:  * Table 9 - Architectural constants for use with ISO 8802 subnetworks
   57:  * ISO 10589 - 8.4.8
   58:  */
   59: 
   60: u_char ALL_L1_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x14 };
   61: u_char ALL_L2_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 };
   62: u_char ALL_ISS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 };
   63: u_char ALL_ESS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 };
   64: 
   65: static u_char sock_buff[8192];
   66: 
   67: static u_short pf_filter[] =
   68: {
   69:   ENF_PUSHWORD + 0,		/* Get the SSAP/DSAP values */
   70:   ENF_PUSHLIT | ENF_CAND,	/* Check them */
   71:   ISO_SAP | (ISO_SAP << 8),
   72:   ENF_PUSHWORD + 1,		/* Get the control value */
   73:   ENF_PUSHLIT | ENF_AND,	/* Isolate it */
   74: #ifdef _BIG_ENDIAN
   75:   0xFF00,
   76: #else
   77:   0x00FF,
   78: #endif
   79:   ENF_PUSHLIT | ENF_CAND,	/* Test for expected value */
   80: #ifdef _BIG_ENDIAN
   81:   0x0300
   82: #else
   83:   0x0003
   84: #endif
   85: };
   86: 
   87: /*
   88:  * We would like to use something like libdlpi here, but that's not present on
   89:  * all versions of Solaris or on any non-Solaris system, so it's nowhere near
   90:  * as portable as we'd like.  Thus, we use the standards-conformant DLPI
   91:  * interfaces plus the (optional; not needed) Solaris packet filter module.
   92:  */
   93: 
   94: static int
   95: dlpisend (int fd, const void *cbuf, size_t cbuflen,
   96:   const void *dbuf, size_t dbuflen, int flags)
   97: {
   98:   const struct strbuf *ctlptr = NULL;
   99:   const struct strbuf *dataptr = NULL;
  100:   struct strbuf ctlbuf, databuf;
  101:   int rv;
  102: 
  103:   if (cbuf != NULL)
  104:     {
  105:       memset (&ctlbuf, 0, sizeof (ctlbuf));
  106:       ctlbuf.len = cbuflen;
  107:       ctlbuf.buf = (void *)cbuf;
  108:       ctlptr = &ctlbuf;
  109:     }
  110: 
  111:   if (dbuf != NULL)
  112:     {
  113:       memset (&databuf, 0, sizeof (databuf));
  114:       databuf.len = dbuflen;
  115:       databuf.buf = (void *)dbuf;
  116:       dataptr = &databuf;
  117:     }
  118: 
  119:   /* We assume this doesn't happen often and isn't operationally significant */
  120:   rv = putmsg(fd, ctlptr, dataptr, flags);
  121:   if (rv == -1 && dbuf == NULL)
  122:     {
  123:       /*
  124:        * For actual PDU transmission - recognizable buf dbuf != NULL,
  125:        * the error is passed upwards and should not be printed here.
  126:        */
  127:       zlog_debug ("%s: putmsg: %s", __func__, safe_strerror (errno));
  128:     }
  129:   return rv;
  130: }
  131: 
  132: static ssize_t
  133: dlpirctl (int fd)
  134: {
  135:   struct pollfd fds[1];
  136:   struct strbuf ctlbuf, databuf;
  137:   int flags, retv;
  138: 
  139:   do
  140:     {
  141:       /* Poll is used here in case the device doesn't speak DLPI correctly */
  142:       memset (fds, 0, sizeof (fds));
  143:       fds[0].fd = fd;
  144:       fds[0].events = POLLIN | POLLPRI;
  145:       if (poll (fds, 1, 1000) <= 0)
  146: 	return -1;
  147: 
  148:       memset (&ctlbuf, 0, sizeof (ctlbuf));
  149:       memset (&databuf, 0, sizeof (databuf));
  150:       ctlbuf.maxlen = sizeof (dlpi_ctl);
  151:       ctlbuf.buf = (void *)dlpi_ctl;
  152:       databuf.maxlen = sizeof (sock_buff);
  153:       databuf.buf = (void *)sock_buff;
  154:       flags = 0;
  155:       retv = getmsg (fd, &ctlbuf, &databuf, &flags);
  156: 
  157:       if (retv < 0)
  158: 	return -1;
  159:     }
  160:   while (ctlbuf.len == 0);
  161: 
  162:   if (!(retv & MORECTL))
  163:     {
  164:       while (retv & MOREDATA)
  165: 	{
  166: 	  flags = 0;
  167: 	  retv = getmsg (fd, NULL, &databuf, &flags);
  168: 	}
  169:       return ctlbuf.len;
  170:     }
  171: 
  172:   while (retv & MORECTL)
  173:     {
  174:       flags = 0;
  175:       retv = getmsg (fd, &ctlbuf, &databuf, &flags);
  176:     }
  177:   return -1;
  178: }
  179: 
  180: static int
  181: dlpiok (int fd, t_uscalar_t oprim)
  182: {
  183:   int retv;
  184:   dl_ok_ack_t *doa = (dl_ok_ack_t *)dlpi_ctl;
  185: 
  186:   retv = dlpirctl (fd);
  187:   if (retv < (ssize_t)DL_OK_ACK_SIZE || doa->dl_primitive != DL_OK_ACK ||
  188:     doa->dl_correct_primitive != oprim)
  189:     {
  190:       return -1;
  191:     }
  192:   else
  193:     {
  194:       return 0;
  195:     }
  196: }
  197: 
  198: static int
  199: dlpiinfo (int fd)
  200: {
  201:   dl_info_req_t dir;
  202:   ssize_t retv;
  203: 
  204:   memset (&dir, 0, sizeof (dir));
  205:   dir.dl_primitive = DL_INFO_REQ;
  206:   /* Info_req uses M_PCPROTO. */
  207:   dlpisend (fd, &dir, sizeof (dir), NULL, 0, RS_HIPRI);
  208:   retv = dlpirctl (fd);
  209:   if (retv < (ssize_t)DL_INFO_ACK_SIZE || dlpi_ctl[0] != DL_INFO_ACK)
  210:     return -1;
  211:   else
  212:     return retv;
  213: }
  214: 
  215: static int
  216: dlpiopen (const char *devpath, ssize_t *acklen)
  217: {
  218:   int fd, flags;
  219: 
  220:   fd = open (devpath, O_RDWR | O_NONBLOCK | O_NOCTTY);
  221:   if (fd == -1)
  222:     return -1;
  223: 
  224:   /* All that we want is for the open itself to be non-blocking, not I/O. */
  225:   flags = fcntl (fd, F_GETFL, 0);
  226:   if (flags != -1)
  227:     fcntl (fd, F_SETFL, flags & ~O_NONBLOCK);
  228: 
  229:   /* After opening, ask for information */
  230:   if ((*acklen = dlpiinfo (fd)) == -1)
  231:     {
  232:       close (fd);
  233:       return -1;
  234:     }
  235: 
  236:   return fd;
  237: }
  238: 
  239: static int
  240: dlpiattach (int fd, int unit)
  241: {
  242:   dl_attach_req_t dar;
  243: 
  244:   memset (&dar, 0, sizeof (dar));
  245:   dar.dl_primitive = DL_ATTACH_REQ;
  246:   dar.dl_ppa = unit;
  247:   dlpisend (fd, &dar, sizeof (dar), NULL, 0, 0);
  248:   return dlpiok (fd, dar.dl_primitive);
  249: }
  250: 
  251: static int
  252: dlpibind (int fd)
  253: {
  254:   dl_bind_req_t dbr;
  255:   int retv;
  256:   dl_bind_ack_t *dba = (dl_bind_ack_t *)dlpi_ctl;
  257: 
  258:   memset (&dbr, 0, sizeof (dbr));
  259:   dbr.dl_primitive = DL_BIND_REQ;
  260:   dbr.dl_service_mode = DL_CLDLS;
  261:   dlpisend (fd, &dbr, sizeof (dbr), NULL, 0, 0);
  262: 
  263:   retv = dlpirctl (fd);
  264:   if (retv < (ssize_t)DL_BIND_ACK_SIZE || dba->dl_primitive != DL_BIND_ACK)
  265:     return -1;
  266:   else
  267:     return 0;
  268: }
  269: 
  270: static int
  271: dlpimcast (int fd, const u_char *mcaddr)
  272: {
  273:   struct {
  274:     dl_enabmulti_req_t der;
  275:     u_char addr[ETHERADDRL];
  276:   } dler;
  277: 
  278:   memset (&dler, 0, sizeof (dler));
  279:   dler.der.dl_primitive = DL_ENABMULTI_REQ;
  280:   dler.der.dl_addr_length = sizeof (dler.addr);
  281:   dler.der.dl_addr_offset = dler.addr - (u_char *)&dler;
  282:   memcpy (dler.addr, mcaddr, sizeof (dler.addr));
  283:   dlpisend (fd, &dler, sizeof (dler), NULL, 0, 0);
  284:   return dlpiok (fd, dler.der.dl_primitive);
  285: }
  286: 
  287: static int
  288: dlpiaddr (int fd, u_char *addr)
  289: {
  290:   dl_phys_addr_req_t dpar;
  291:   dl_phys_addr_ack_t *dpaa = (dl_phys_addr_ack_t *)dlpi_ctl;
  292:   int retv;
  293: 
  294:   memset (&dpar, 0, sizeof (dpar));
  295:   dpar.dl_primitive = DL_PHYS_ADDR_REQ;
  296:   dpar.dl_addr_type = DL_CURR_PHYS_ADDR;
  297:   dlpisend (fd, &dpar, sizeof (dpar), NULL, 0, 0);
  298: 
  299:   retv = dlpirctl (fd);
  300:   if (retv < (ssize_t)DL_PHYS_ADDR_ACK_SIZE
  301:       || dpaa->dl_primitive != DL_PHYS_ADDR_ACK)
  302:     return -1;
  303: 
  304:   if (dpaa->dl_addr_offset < DL_PHYS_ADDR_ACK_SIZE ||
  305:     dpaa->dl_addr_length != ETHERADDRL ||
  306:     dpaa->dl_addr_offset + dpaa->dl_addr_length > (size_t)retv)
  307:     return -1;
  308: 
  309:   bcopy((char *)dpaa + dpaa->dl_addr_offset, addr, ETHERADDRL);
  310:   return 0;
  311: }
  312: 
  313: static int
  314: open_dlpi_dev (struct isis_circuit *circuit)
  315: {
  316:   int fd = -1, unit, retval;
  317:   char devpath[MAXPATHLEN];
  318:   dl_info_ack_t *dia = (dl_info_ack_t *)dlpi_ctl;
  319:   ssize_t acklen;
  320: 
  321:   /* Only broadcast-type are supported at the moment */
  322:   if (circuit->circ_type != CIRCUIT_T_BROADCAST)
  323:     {
  324:       zlog_warn ("%s: non-broadcast interface %s", __func__,
  325: 	circuit->interface->name);
  326:       return ISIS_WARNING;
  327:     }
  328:   
  329:   /* Try the vanity node first, if permitted */
  330:   if (getenv("DLPI_DEVONLY") == NULL)
  331:     {
  332:       (void) snprintf (devpath, sizeof(devpath), "/dev/net/%s",
  333:                       circuit->interface->name);
  334:       fd = dlpiopen (devpath, &acklen);
  335:     }
  336:   
  337:   /* Now try as an ordinary Style 1 node */
  338:   if (fd == -1)
  339:     {
  340:       (void) snprintf (devpath, sizeof (devpath), "/dev/%s",
  341:                       circuit->interface->name);
  342:       unit = -1;
  343:       fd = dlpiopen (devpath, &acklen);
  344:     }
  345: 
  346:   /* If that fails, try again as Style 2 */
  347:   if (fd == -1)
  348:     {
  349:       char *cp;
  350: 
  351:       cp = devpath + strlen (devpath);
  352:       while (--cp >= devpath && isdigit(*cp))
  353: 	;
  354:       unit = strtol(cp, NULL, 0);
  355:       *cp = '\0';
  356:       fd = dlpiopen (devpath, &acklen);
  357: 
  358:       /* If that too fails, then the device really doesn't exist */
  359:       if (fd == -1)
  360: 	{
  361: 	  zlog_warn ("%s: unknown interface %s", __func__,
  362: 	    circuit->interface->name);
  363: 	  return ISIS_WARNING;
  364: 	}
  365: 
  366:       /* Double check the DLPI style */
  367:       if (dia->dl_provider_style != DL_STYLE2)
  368: 	{
  369: 	  zlog_warn ("open_dlpi_dev(): interface %s: %s is not style 2",
  370: 	    circuit->interface->name, devpath);
  371: 	  close (fd);
  372: 	  return ISIS_WARNING;
  373: 	}
  374: 
  375:       /* If it succeeds, then we need to attach to the unit specified */
  376:       dlpiattach (fd, unit);
  377: 
  378:       /* Reget the information, as it may be different per node */
  379:       if ((acklen = dlpiinfo (fd)) == -1)
  380: 	{
  381: 	  close (fd);
  382: 	  return ISIS_WARNING;
  383: 	}
  384:     }
  385:   else
  386:     {
  387:       /* Double check the DLPI style */
  388:       if (dia->dl_provider_style != DL_STYLE1)
  389: 	{
  390: 	  zlog_warn ("open_dlpi_dev(): interface %s: %s is not style 1",
  391: 	    circuit->interface->name, devpath);
  392: 	  close (fd);
  393: 	  return ISIS_WARNING;
  394: 	}
  395:     }
  396: 
  397:   /* Check that the interface we've got is the kind we expect */
  398:   if ((dia->dl_sap_length != 2 && dia->dl_sap_length != -2) ||
  399:     dia->dl_service_mode != DL_CLDLS || dia->dl_addr_length != ETHERADDRL + 2 ||
  400:     dia->dl_brdcst_addr_length != ETHERADDRL)
  401:     {
  402:       zlog_warn ("%s: unsupported interface type for %s", __func__,
  403: 	circuit->interface->name);
  404:       close (fd);
  405:       return ISIS_WARNING;
  406:     }
  407:   switch (dia->dl_mac_type)
  408:     {
  409:     case DL_CSMACD:
  410:     case DL_ETHER:
  411:     case DL_100VG:
  412:     case DL_100VGTPR:
  413:     case DL_ETH_CSMA:
  414:     case DL_100BT:
  415:       break;
  416:     default:
  417:       zlog_warn ("%s: unexpected mac type on %s: %lld", __func__,
  418: 	circuit->interface->name, (long long)dia->dl_mac_type);
  419:       close (fd);
  420:       return ISIS_WARNING;
  421:     }
  422: 
  423:   circuit->sap_length = dia->dl_sap_length;
  424: 
  425:   /*
  426:    * The local hardware address is something that should be provided by way of
  427:    * sockaddr_dl for the interface, but isn't on Solaris.  We set it here based
  428:    * on DLPI's reported address to avoid roto-tilling the world.
  429:    * (Note that isis_circuit_if_add on Solaris doesn't set the snpa.)
  430:    *
  431:    * Unfortunately, GLD is broken and doesn't provide the address after attach,
  432:    * so we need to be careful and use DL_PHYS_ADDR_REQ instead.
  433:    */
  434:   if (dlpiaddr (fd, circuit->u.bc.snpa) == -1)
  435:     {
  436:       zlog_warn ("open_dlpi_dev(): interface %s: unable to get MAC address",
  437: 	circuit->interface->name);
  438:       close (fd);
  439:       return ISIS_WARNING;
  440:     }
  441: 
  442:   /* Now bind to SAP 0.  This gives us 802-type traffic. */
  443:   if (dlpibind (fd) == -1)
  444:     {
  445:       zlog_warn ("%s: cannot bind SAP 0 on %s", __func__,
  446: 	circuit->interface->name);
  447:       close (fd);
  448:       return ISIS_WARNING;
  449:     }
  450: 
  451:   /*
  452:    * Join to multicast groups according to
  453:    * 8.4.2 - Broadcast subnetwork IIH PDUs
  454:    */
  455:   retval = 0;
  456:   retval |= dlpimcast (fd, ALL_L1_ISS);
  457:   retval |= dlpimcast (fd, ALL_ISS);
  458:   retval |= dlpimcast (fd, ALL_L2_ISS);
  459: 
  460:   if (retval != 0)
  461:     {
  462:       zlog_warn ("%s: unable to join multicast on %s", __func__,
  463: 	circuit->interface->name);
  464:       close (fd);
  465:       return ISIS_WARNING;
  466:     }
  467: 
  468:   /* Push on the packet filter to avoid stray 802 packets */
  469:   if (ioctl (fd, I_PUSH, "pfmod") == 0)
  470:     {
  471:       struct packetfilt pfil;
  472:       struct strioctl sioc;
  473: 
  474:       pfil.Pf_Priority = 0;
  475:       pfil.Pf_FilterLen = sizeof (pf_filter) / sizeof (u_short);
  476:       memcpy (pfil.Pf_Filter, pf_filter, sizeof (pf_filter));
  477:       /* pfmod does not support transparent ioctls */
  478:       sioc.ic_cmd = PFIOCSETF;
  479:       sioc.ic_timout = 5;
  480:       sioc.ic_len = sizeof (struct packetfilt);
  481:       sioc.ic_dp = (char *)&pfil;
  482:       if (ioctl (fd, I_STR, &sioc) == -1)
  483:          zlog_warn("%s: could not perform PF_IOCSETF on %s",
  484:            __func__, circuit->interface->name); 
  485:     }
  486: 
  487:   circuit->fd = fd;
  488: 
  489:   return ISIS_OK;
  490: }
  491: 
  492: /*
  493:  * Create the socket and set the tx/rx funcs
  494:  */
  495: int
  496: isis_sock_init (struct isis_circuit *circuit)
  497: {
  498:   int retval = ISIS_OK;
  499: 
  500:   if (isisd_privs.change (ZPRIVS_RAISE))
  501:     zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno));
  502: 
  503:   retval = open_dlpi_dev (circuit);
  504: 
  505:   if (retval != ISIS_OK)
  506:     {
  507:       zlog_warn ("%s: could not initialize the socket", __func__);
  508:       goto end;
  509:     }
  510: 
  511:   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
  512:     {
  513:       circuit->tx = isis_send_pdu_bcast;
  514:       circuit->rx = isis_recv_pdu_bcast;
  515:     }
  516:   else
  517:     {
  518:       zlog_warn ("isis_sock_init(): unknown circuit type");
  519:       retval = ISIS_WARNING;
  520:       goto end;
  521:     }
  522: 
  523: end:
  524:   if (isisd_privs.change (ZPRIVS_LOWER))
  525:     zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno));
  526: 
  527:   return retval;
  528: }
  529: 
  530: int
  531: isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
  532: {
  533:   struct pollfd fds[1];
  534:   struct strbuf ctlbuf, databuf;
  535:   int flags, retv;
  536:   dl_unitdata_ind_t *dui = (dl_unitdata_ind_t *)dlpi_ctl;
  537: 
  538:   memset (fds, 0, sizeof (fds));
  539:   fds[0].fd = circuit->fd;
  540:   fds[0].events = POLLIN | POLLPRI;
  541:   if (poll (fds, 1, 0) <= 0)
  542:     return ISIS_WARNING;
  543: 
  544:   memset (&ctlbuf, 0, sizeof (ctlbuf));
  545:   memset (&databuf, 0, sizeof (databuf));
  546:   ctlbuf.maxlen = sizeof (dlpi_ctl);
  547:   ctlbuf.buf = (void *)dlpi_ctl;
  548:   databuf.maxlen = sizeof (sock_buff);
  549:   databuf.buf = (void *)sock_buff;
  550:   flags = 0;
  551:   retv = getmsg (circuit->fd, &ctlbuf, &databuf, &flags);
  552: 
  553:   if (retv < 0)
  554:     {
  555:       zlog_warn ("isis_recv_pdu_bcast: getmsg failed: %s",
  556: 		 safe_strerror (errno));
  557:       return ISIS_WARNING;
  558:     }
  559: 
  560:   if (retv & (MORECTL | MOREDATA))
  561:     {
  562:       while (retv & (MORECTL | MOREDATA))
  563: 	{
  564: 	  flags = 0;
  565: 	  retv = getmsg (circuit->fd, &ctlbuf, &databuf, &flags);
  566: 	}
  567:       return ISIS_WARNING;
  568:     }
  569: 
  570:   if (ctlbuf.len < (ssize_t)DL_UNITDATA_IND_SIZE ||
  571:     dui->dl_primitive != DL_UNITDATA_IND)
  572:     return ISIS_WARNING;
  573: 
  574:   if (dui->dl_src_addr_length != ETHERADDRL + 2 ||
  575:     dui->dl_src_addr_offset < DL_UNITDATA_IND_SIZE ||
  576:     dui->dl_src_addr_offset + dui->dl_src_addr_length > (size_t)ctlbuf.len)
  577:     return ISIS_WARNING;
  578: 
  579:   memcpy (ssnpa, (char *)dui + dui->dl_src_addr_offset +
  580:     (circuit->sap_length > 0 ? circuit->sap_length : 0), ETHERADDRL);
  581: 
  582:   if (databuf.len < LLC_LEN || sock_buff[0] != ISO_SAP ||
  583:     sock_buff[1] != ISO_SAP || sock_buff[2] != 3)
  584:     return ISIS_WARNING;
  585: 
  586:   stream_write (circuit->rcv_stream, sock_buff + LLC_LEN,
  587:                 databuf.len - LLC_LEN);
  588:   stream_set_getp (circuit->rcv_stream, 0);
  589: 
  590:   return ISIS_OK;
  591: }
  592: 
  593: int
  594: isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
  595: {
  596:   dl_unitdata_req_t *dur = (dl_unitdata_req_t *)dlpi_ctl;
  597:   char *dstaddr;
  598:   u_short *dstsap;
  599:   int buflen;
  600:   int rv;
  601: 
  602:   buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN;
  603:   if ((size_t)buflen > sizeof (sock_buff))
  604:     {
  605:       zlog_warn ("isis_send_pdu_bcast: sock_buff size %zu is less than "
  606: 		 "output pdu size %d on circuit %s",
  607: 		 sizeof (sock_buff), buflen, circuit->interface->name);
  608:       return ISIS_WARNING;
  609:     }
  610: 
  611:   stream_set_getp (circuit->snd_stream, 0);
  612: 
  613:   memset (dur, 0, sizeof (*dur));
  614:   dur->dl_primitive = DL_UNITDATA_REQ;
  615:   dur->dl_dest_addr_length = ETHERADDRL + 2;
  616:   dur->dl_dest_addr_offset = sizeof (*dur);
  617: 
  618:   dstaddr = (char *)(dur + 1);
  619:   if (circuit->sap_length < 0)
  620:     {
  621:       dstsap = (u_short *)(dstaddr + ETHERADDRL);
  622:     }
  623:   else
  624:     {
  625:       dstsap = (u_short *)dstaddr;
  626:       dstaddr += circuit->sap_length;
  627:     }
  628:   if (level == 1)
  629:     memcpy (dstaddr, ALL_L1_ISS, ETHERADDRL);
  630:   else
  631:     memcpy (dstaddr, ALL_L2_ISS, ETHERADDRL);
  632:   /* Note: DLPI SAP values are in host byte order */
  633:   *dstsap = buflen;
  634: 
  635:   sock_buff[0] = ISO_SAP;
  636:   sock_buff[1] = ISO_SAP;
  637:   sock_buff[2] = 0x03;
  638:   memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data,
  639: 	  stream_get_endp (circuit->snd_stream));
  640:   rv = dlpisend(circuit->fd, dur, sizeof (*dur) + dur->dl_dest_addr_length,
  641:                 sock_buff, buflen, 0);
  642:   if (rv < 0)
  643:     {
  644:       zlog_warn("IS-IS dlpi: could not transmit packet on %s: %s",
  645:                 circuit->interface->name, safe_strerror(errno));
  646:       if (ERRNO_IO_RETRY(errno))
  647:         return ISIS_WARNING;
  648:       return ISIS_ERROR;
  649:     }
  650: 
  651:   return ISIS_OK;
  652: }
  653: 
  654: #endif /* ISIS_METHOD == ISIS_METHOD_DLPI */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>