isis_dlpi.c 17 KB

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