Annotation of embedaddon/quagga/isisd/isis_dlpi.c, revision 1.1.1.4
1.1 misho 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"
1.1.1.4 ! misho 36: #include "network.h"
1.1 misho 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:
1.1.1.4 ! misho 94: static int
1.1 misho 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;
1.1.1.4 ! misho 101: int rv;
1.1 misho 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 */
1.1.1.4 ! misho 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;
1.1 misho 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);
1.1.1.4 ! misho 187: if (retv < (ssize_t)DL_OK_ACK_SIZE || doa->dl_primitive != DL_OK_ACK ||
1.1 misho 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);
1.1.1.4 ! misho 209: if (retv < (ssize_t)DL_INFO_ACK_SIZE || dlpi_ctl[0] != DL_INFO_ACK)
1.1 misho 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);
1.1.1.4 ! misho 264: if (retv < (ssize_t)DL_BIND_ACK_SIZE || dba->dl_primitive != DL_BIND_ACK)
1.1 misho 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);
1.1.1.4 ! misho 300: if (retv < (ssize_t)DL_PHYS_ADDR_ACK_SIZE
! 301: || dpaa->dl_primitive != DL_PHYS_ADDR_ACK)
1.1 misho 302: return -1;
303:
304: if (dpaa->dl_addr_offset < DL_PHYS_ADDR_ACK_SIZE ||
305: dpaa->dl_addr_length != ETHERADDRL ||
1.1.1.4 ! misho 306: dpaa->dl_addr_offset + dpaa->dl_addr_length > (size_t)retv)
1.1 misho 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: {
1.1.1.4 ! misho 316: int fd = -1, unit, retval;
1.1 misho 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:
1.1.1.4 ! misho 417: zlog_warn ("%s: unexpected mac type on %s: %lld", __func__,
! 418: circuit->interface->name, (long long)dia->dl_mac_type);
1.1 misho 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;
1.1.1.3 misho 456: retval |= dlpimcast (fd, ALL_L1_ISS);
457: retval |= dlpimcast (fd, ALL_ISS);
458: retval |= dlpimcast (fd, ALL_L2_ISS);
1.1 misho 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:
1.1.1.4 ! misho 570: if (ctlbuf.len < (ssize_t)DL_UNITDATA_IND_SIZE ||
1.1 misho 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 ||
1.1.1.4 ! misho 576: dui->dl_src_addr_offset + dui->dl_src_addr_length > (size_t)ctlbuf.len)
1.1 misho 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;
1.1.1.2 misho 599: int buflen;
1.1.1.4 ! misho 600: int rv;
1.1.1.2 misho 601:
602: buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN;
1.1.1.4 ! misho 603: if ((size_t)buflen > sizeof (sock_buff))
1.1.1.2 misho 604: {
1.1.1.4 ! misho 605: zlog_warn ("isis_send_pdu_bcast: sock_buff size %zu is less than "
1.1.1.2 misho 606: "output pdu size %d on circuit %s",
607: sizeof (sock_buff), buflen, circuit->interface->name);
608: return ISIS_WARNING;
609: }
1.1 misho 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 */
1.1.1.2 misho 633: *dstsap = buflen;
1.1 misho 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));
1.1.1.4 ! misho 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:
1.1 misho 651: return ISIS_OK;
652: }
653:
654: #endif /* ISIS_METHOD == ISIS_METHOD_DLPI */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>