]>
Commit | Line | Data |
---|---|---|
8bc98059 PJ |
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> | |
745bf05f | 24 | #if ISIS_METHOD == ISIS_METHOD_DLPI |
8bc98059 PJ |
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" | |
cfd1f27b | 36 | #include "network.h" |
8bc98059 PJ |
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" | |
8bc98059 PJ |
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 | ||
cfd1f27b | 94 | static int |
8bc98059 PJ |
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; | |
cfd1f27b | 101 | int rv; |
8bc98059 PJ |
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 */ | |
cfd1f27b CF |
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; | |
8bc98059 PJ |
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); | |
3e3a83b2 | 187 | if (retv < (ssize_t)DL_OK_ACK_SIZE || doa->dl_primitive != DL_OK_ACK || |
8bc98059 PJ |
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); | |
3e3a83b2 | 209 | if (retv < (ssize_t)DL_INFO_ACK_SIZE || dlpi_ctl[0] != DL_INFO_ACK) |
8bc98059 PJ |
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); | |
3e3a83b2 | 264 | if (retv < (ssize_t)DL_BIND_ACK_SIZE || dba->dl_primitive != DL_BIND_ACK) |
8bc98059 PJ |
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); | |
3e3a83b2 DL |
300 | if (retv < (ssize_t)DL_PHYS_ADDR_ACK_SIZE |
301 | || dpaa->dl_primitive != DL_PHYS_ADDR_ACK) | |
8bc98059 PJ |
302 | return -1; |
303 | ||
304 | if (dpaa->dl_addr_offset < DL_PHYS_ADDR_ACK_SIZE || | |
305 | dpaa->dl_addr_length != ETHERADDRL || | |
3e3a83b2 | 306 | dpaa->dl_addr_offset + dpaa->dl_addr_length > (size_t)retv) |
8bc98059 PJ |
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 | { | |
ca248d8b | 316 | int fd = -1, unit, retval; |
8bc98059 PJ |
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 | } | |
69954565 JD |
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 | } | |
8bc98059 PJ |
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: | |
3e3a83b2 DL |
417 | zlog_warn ("%s: unexpected mac type on %s: %lld", __func__, |
418 | circuit->interface->name, (long long)dia->dl_mac_type); | |
8bc98059 PJ |
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; | |
318c8040 DL |
456 | retval |= dlpimcast (fd, ALL_L1_ISS); |
457 | retval |= dlpimcast (fd, ALL_ISS); | |
458 | retval |= dlpimcast (fd, ALL_L2_ISS); | |
8bc98059 PJ |
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; | |
3e40282f | 472 | struct strioctl sioc; |
8bc98059 PJ |
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)); | |
3e40282f JD |
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); | |
8bc98059 PJ |
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 | ||
3e3a83b2 | 570 | if (ctlbuf.len < (ssize_t)DL_UNITDATA_IND_SIZE || |
8bc98059 PJ |
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 || | |
3e3a83b2 | 576 | dui->dl_src_addr_offset + dui->dl_src_addr_length > (size_t)ctlbuf.len) |
8bc98059 PJ |
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; | |
3f045a08 | 599 | int buflen; |
cfd1f27b | 600 | int rv; |
3f045a08 JB |
601 | |
602 | buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN; | |
3e3a83b2 | 603 | if ((size_t)buflen > sizeof (sock_buff)) |
3f045a08 | 604 | { |
3e3a83b2 | 605 | zlog_warn ("isis_send_pdu_bcast: sock_buff size %zu is less than " |
3f045a08 JB |
606 | "output pdu size %d on circuit %s", |
607 | sizeof (sock_buff), buflen, circuit->interface->name); | |
608 | return ISIS_WARNING; | |
609 | } | |
8bc98059 PJ |
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 */ | |
3f045a08 | 633 | *dstsap = buflen; |
8bc98059 PJ |
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)); | |
cfd1f27b CF |
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 | ||
8bc98059 PJ |
651 | return ISIS_OK; |
652 | } | |
745bf05f DL |
653 | |
654 | #endif /* ISIS_METHOD == ISIS_METHOD_DLPI */ |