blob: fc48c888391e4aec7726d66f4382d163a83f24a2 [file] [log] [blame]
Everton Marques871dbcf2009-08-11 15:43:05 -03001/*
2 PIM for Quagga
3 Copyright (C) 2008 Everton da Silva Marques
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
18 MA 02110-1301 USA
19
20 $QuaggaId: $Format:%an, %ai, %h$ $
21*/
22
23#include <zebra.h>
24
25#include "log.h"
26#include "prefix.h"
27
28#include "pimd.h"
29#include "pim_tlv.h"
30#include "pim_str.h"
31#include "pim_msg.h"
32
33char *pim_tlv_append_uint16(char *buf,
34 const char *buf_pastend,
35 uint16_t option_type,
36 uint16_t option_value)
37{
38 uint16_t option_len = 2;
39
40 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) {
41 zlog_warn("%s: buffer overflow: left=%d needed=%d",
42 __PRETTY_FUNCTION__,
43 buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len));
44 return 0;
45 }
46
47 *(uint16_t *) buf = htons(option_type);
48 buf += 2;
49 *(uint16_t *) buf = htons(option_len);
50 buf += 2;
51 *(uint16_t *) buf = htons(option_value);
52 buf += option_len;
53
54 return buf;
55}
56
57char *pim_tlv_append_2uint16(char *buf,
58 const char *buf_pastend,
59 uint16_t option_type,
60 uint16_t option_value1,
61 uint16_t option_value2)
62{
63 uint16_t option_len = 4;
64
65 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) {
66 zlog_warn("%s: buffer overflow: left=%d needed=%d",
67 __PRETTY_FUNCTION__,
68 buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len));
69 return 0;
70 }
71
72 *(uint16_t *) buf = htons(option_type);
73 buf += 2;
74 *(uint16_t *) buf = htons(option_len);
75 buf += 2;
76 *(uint16_t *) buf = htons(option_value1);
77 buf += 2;
78 *(uint16_t *) buf = htons(option_value2);
79 buf += 2;
80
81 return buf;
82}
83
84char *pim_tlv_append_uint32(char *buf,
85 const char *buf_pastend,
86 uint16_t option_type,
87 uint32_t option_value)
88{
89 uint16_t option_len = 4;
90
91 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) {
92 zlog_warn("%s: buffer overflow: left=%d needed=%d",
93 __PRETTY_FUNCTION__,
94 buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len));
95 return 0;
96 }
97
98 *(uint16_t *) buf = htons(option_type);
99 buf += 2;
100 *(uint16_t *) buf = htons(option_len);
101 buf += 2;
102 *(uint32_t *) buf = htonl(option_value);
103 buf += option_len;
104
105 return buf;
106}
107
108#define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
109
110char *pim_tlv_append_addrlist_ucast(char *buf,
111 const char *buf_pastend,
112 struct list *ifconnected)
113{
114 struct listnode *node;
115 uint16_t option_len = 0;
116
117 char *curr;
118
119 node = listhead(ifconnected);
120
121 /* Empty address list ? */
122 if (!node) {
123 return buf;
124 }
125
126 /* Skip first address (primary) */
127 node = listnextnode(node);
128
129 /* Scan secondary address list */
130 curr = buf + 4; /* skip T and L */
131 for (; node; node = listnextnode(node)) {
132 struct connected *ifc = listgetdata(node);
133 struct prefix *p = ifc->address;
134
135 if (p->family != AF_INET)
136 continue;
137
138 if ((curr + ucast_ipv4_encoding_len) > buf_pastend) {
139 zlog_warn("%s: buffer overflow: left=%d needed=%d",
140 __PRETTY_FUNCTION__,
141 buf_pastend - curr, ucast_ipv4_encoding_len);
142 return 0;
143 }
144
145 /* Write encoded unicast IPv4 address */
146 *(uint8_t *) curr = PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
147 ++curr;
148 *(uint8_t *) curr = 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */
149 ++curr;
150 *(struct in_addr *) curr = p->u.prefix4;
151 curr += sizeof(struct in_addr);
152
153 option_len += ucast_ipv4_encoding_len;
154 }
155
156 if (PIM_DEBUG_PIM_TRACE) {
157 zlog_warn("%s: number of encoded secondary unicast IPv4 addresses: %d",
158 __PRETTY_FUNCTION__,
159 option_len / ucast_ipv4_encoding_len);
160 }
161
162 if (option_len < 1) {
163 /* Empty secondary unicast IPv4 address list */
164 return buf;
165 }
166
167 /*
168 * Write T and L
169 */
170 *(uint16_t *) buf = htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST);
171 *(uint16_t *) (buf + 2) = htons(option_len);
172
173 return curr;
174}
175
176static int check_tlv_length(const char *label, const char *tlv_name,
177 const char *ifname, struct in_addr src_addr,
178 int correct_len, int option_len)
179{
180 if (option_len != correct_len) {
181 char src_str[100];
182 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
183 zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s",
184 label, tlv_name,
185 option_len, correct_len,
186 src_str, ifname);
187 return -1;
188 }
189
190 return 0;
191}
192
193static void check_tlv_redefinition_uint16(const char *label, const char *tlv_name,
194 const char *ifname, struct in_addr src_addr,
195 pim_hello_options options,
196 pim_hello_options opt_mask,
197 uint16_t new, uint16_t old)
198{
199 if (PIM_OPTION_IS_SET(options, opt_mask)) {
200 char src_str[100];
201 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
202 zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
203 label, tlv_name,
204 new, old,
205 src_str, ifname);
206 }
207}
208
209static void check_tlv_redefinition_uint32(const char *label, const char *tlv_name,
210 const char *ifname, struct in_addr src_addr,
211 pim_hello_options options,
212 pim_hello_options opt_mask,
213 uint32_t new, uint32_t old)
214{
215 if (PIM_OPTION_IS_SET(options, opt_mask)) {
216 char src_str[100];
217 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
218 zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
219 label, tlv_name,
220 new, old,
221 src_str, ifname);
222 }
223}
224
225static void check_tlv_redefinition_uint32_hex(const char *label, const char *tlv_name,
226 const char *ifname, struct in_addr src_addr,
227 pim_hello_options options,
228 pim_hello_options opt_mask,
229 uint32_t new, uint32_t old)
230{
231 if (PIM_OPTION_IS_SET(options, opt_mask)) {
232 char src_str[100];
233 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
234 zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s",
235 label, tlv_name,
236 new, old,
237 src_str, ifname);
238 }
239}
240
241int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr,
242 pim_hello_options *hello_options,
243 uint16_t *hello_option_holdtime,
244 uint16_t option_len,
245 const char *tlv_curr)
246{
247 const char *label = "holdtime";
248
249 if (check_tlv_length(__PRETTY_FUNCTION__, label,
250 ifname, src_addr,
251 sizeof(uint16_t), option_len)) {
252 return -1;
253 }
254
255 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, label,
256 ifname, src_addr,
257 *hello_options, PIM_OPTION_MASK_HOLDTIME,
258 PIM_TLV_GET_HOLDTIME(tlv_curr),
259 *hello_option_holdtime);
260
261 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME);
262
263 *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr);
264
265 return 0;
266}
267
268int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr,
269 pim_hello_options *hello_options,
270 uint16_t *hello_option_propagation_delay,
271 uint16_t *hello_option_override_interval,
272 uint16_t option_len,
273 const char *tlv_curr)
274{
275 if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay",
276 ifname, src_addr,
277 sizeof(uint32_t), option_len)) {
278 return -1;
279 }
280
281 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, "propagation_delay",
282 ifname, src_addr,
283 *hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY,
284 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr),
285 *hello_option_propagation_delay);
286
287 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY);
288
289 *hello_option_propagation_delay = PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr);
290 if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr)) {
291 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
292 }
293 else {
294 PIM_OPTION_UNSET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
295 }
296 ++tlv_curr;
297 ++tlv_curr;
298 *hello_option_override_interval = PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr);
299
300 return 0;
301}
302
303int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr,
304 pim_hello_options *hello_options,
305 uint32_t *hello_option_dr_priority,
306 uint16_t option_len,
307 const char *tlv_curr)
308{
309 const char *label = "dr_priority";
310
311 if (check_tlv_length(__PRETTY_FUNCTION__, label,
312 ifname, src_addr,
313 sizeof(uint32_t), option_len)) {
314 return -1;
315 }
316
317 check_tlv_redefinition_uint32(__PRETTY_FUNCTION__, label,
318 ifname, src_addr,
319 *hello_options, PIM_OPTION_MASK_DR_PRIORITY,
320 PIM_TLV_GET_DR_PRIORITY(tlv_curr),
321 *hello_option_dr_priority);
322
323 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY);
324
325 *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr);
326
327 return 0;
328}
329
330int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr,
331 pim_hello_options *hello_options,
332 uint32_t *hello_option_generation_id,
333 uint16_t option_len,
334 const char *tlv_curr)
335{
336 const char *label = "generation_id";
337
338 if (check_tlv_length(__PRETTY_FUNCTION__, label,
339 ifname, src_addr,
340 sizeof(uint32_t), option_len)) {
341 return -1;
342 }
343
344 check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__, label,
345 ifname, src_addr,
346 *hello_options, PIM_OPTION_MASK_GENERATION_ID,
347 PIM_TLV_GET_GENERATION_ID(tlv_curr),
348 *hello_option_generation_id);
349
350 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID);
351
352 *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr);
353
354 return 0;
355}
356
357int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr,
358 struct prefix *p,
359 const char *buf,
360 int buf_size)
361{
362 const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */
363 const char *addr;
364 const char *pastend;
365 int family;
366 int type;
367
368 if (buf_size < ucast_encoding_min_len) {
369 char src_str[100];
370 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
371 zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d from %s on %s",
372 __PRETTY_FUNCTION__,
373 buf_size, ucast_encoding_min_len,
374 src_str, ifname);
375 return -1;
376 }
377
378 addr = buf;
379 pastend = buf + buf_size;
380
381 family = *(const uint8_t *) addr;
382 ++addr;
383 type = *(const uint8_t *) addr;
384 ++addr;
385
386 switch (family) {
387 case PIM_MSG_ADDRESS_FAMILY_IPV4:
388 if (type) {
389 char src_str[100];
390 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
391 zlog_warn("%s: unknown unicast address encoding type=%d from %s on %s",
392 __PRETTY_FUNCTION__,
393 type, src_str, ifname);
394 return -2;
395 }
396
397 if ((addr + sizeof(struct in_addr)) > pastend) {
398 char src_str[100];
399 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
400 zlog_warn("%s: IPv4 unicast address overflow: left=%d needed=%d from %s on %s",
401 __PRETTY_FUNCTION__,
402 pastend - addr, sizeof(struct in_addr),
403 src_str, ifname);
404 return -3;
405 }
406
407 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
408 p->u.prefix4 = *(const struct in_addr *) addr;
409 addr += sizeof(struct in_addr);
410
411 break;
412 default:
413 {
414 char src_str[100];
415 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
416 zlog_warn("%s: unknown unicast address encoding family=%d from %s on %s",
417 __PRETTY_FUNCTION__,
418 family, src_str, ifname);
419 return -4;
420 }
421 }
422
423 return addr - buf;
424}
425
426int pim_parse_addr_group(const char *ifname, struct in_addr src_addr,
427 struct prefix *p,
428 const char *buf,
429 int buf_size)
430{
431 const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
432 const char *addr;
433 const char *pastend;
434 int family;
435 int type;
436 int mask_len;
437
438 if (buf_size < grp_encoding_min_len) {
439 char src_str[100];
440 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
441 zlog_warn("%s: group address encoding overflow: left=%d needed=%d from %s on %s",
442 __PRETTY_FUNCTION__,
443 buf_size, grp_encoding_min_len,
444 src_str, ifname);
445 return -1;
446 }
447
448 addr = buf;
449 pastend = buf + buf_size;
450
451 family = *(const uint8_t *) addr;
452 ++addr;
453 type = *(const uint8_t *) addr;
454 ++addr;
455 ++addr; /* skip b_reserved_z fields */
456 mask_len = *(const uint8_t *) addr;
457 ++addr;
458
459 switch (family) {
460 case PIM_MSG_ADDRESS_FAMILY_IPV4:
461 if (type) {
462 char src_str[100];
463 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
464 zlog_warn("%s: unknown group address encoding type=%d from %s on %s",
465 __PRETTY_FUNCTION__,
466 type, src_str, ifname);
467 return -2;
468 }
469
470 if ((addr + sizeof(struct in_addr)) > pastend) {
471 char src_str[100];
472 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
473 zlog_warn("%s: IPv4 group address overflow: left=%d needed=%d from %s on %s",
474 __PRETTY_FUNCTION__,
475 pastend - addr, sizeof(struct in_addr),
476 src_str, ifname);
477 return -3;
478 }
479
480 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
481 p->u.prefix4 = *(const struct in_addr *) addr;
482 p->prefixlen = mask_len;
483
484 addr += sizeof(struct in_addr);
485
486 break;
487 default:
488 {
489 char src_str[100];
490 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
491 zlog_warn("%s: unknown group address encoding family=%d from %s on %s",
492 __PRETTY_FUNCTION__,
493 family, src_str, ifname);
494 return -4;
495 }
496 }
497
498 return addr - buf;
499}
500
501int pim_parse_addr_source(const char *ifname,
502 struct in_addr src_addr,
503 struct prefix *p,
504 uint8_t *flags,
505 const char *buf,
506 int buf_size)
507{
508 const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
509 const char *addr;
510 const char *pastend;
511 int family;
512 int type;
513 int mask_len;
514
515 if (buf_size < src_encoding_min_len) {
516 char src_str[100];
517 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
518 zlog_warn("%s: source address encoding overflow: left=%d needed=%d from %s on %s",
519 __PRETTY_FUNCTION__,
520 buf_size, src_encoding_min_len,
521 src_str, ifname);
522 return -1;
523 }
524
525 addr = buf;
526 pastend = buf + buf_size;
527
528 family = *(const uint8_t *) addr;
529 ++addr;
530 type = *(const uint8_t *) addr;
531 ++addr;
532 *flags = *(const uint8_t *) addr;
533 ++addr;
534 mask_len = *(const uint8_t *) addr;
535 ++addr;
536
537 switch (family) {
538 case PIM_MSG_ADDRESS_FAMILY_IPV4:
539 if (type) {
540 char src_str[100];
541 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
542 zlog_warn("%s: unknown source address encoding type=%d from %s on %s",
543 __PRETTY_FUNCTION__,
544 type, src_str, ifname);
545 return -2;
546 }
547
548 if ((addr + sizeof(struct in_addr)) > pastend) {
549 char src_str[100];
550 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
551 zlog_warn("%s: IPv4 source address overflow: left=%d needed=%d from %s on %s",
552 __PRETTY_FUNCTION__,
553 pastend - addr, sizeof(struct in_addr),
554 src_str, ifname);
555 return -3;
556 }
557
558 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
559 p->u.prefix4 = *(const struct in_addr *) addr;
560 p->prefixlen = mask_len;
561
Everton Marquesd12beab2009-08-12 10:52:22 -0300562 /*
563 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
564
565 Encoded-Source Address
566
567 The mask length MUST be equal to the mask length in bits for
568 the given Address Family and Encoding Type (32 for IPv4 native
569 and 128 for IPv6 native). A router SHOULD ignore any messages
570 received with any other mask length.
571 */
572 if (p->prefixlen != 32) {
573 char src_str[100];
574 pim_inet4_dump("<src?>", p->u.prefix4, src_str, sizeof(src_str));
575 zlog_warn("%s: IPv4 bad source address mask: %s/%d",
576 __PRETTY_FUNCTION__, src_str, p->prefixlen);
577 return -4;
578 }
579
Everton Marques871dbcf2009-08-11 15:43:05 -0300580 addr += sizeof(struct in_addr);
581
582 break;
583 default:
584 {
585 char src_str[100];
586 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
587 zlog_warn("%s: unknown source address encoding family=%d from %s on %s",
588 __PRETTY_FUNCTION__,
589 family, src_str, ifname);
Everton Marquesd12beab2009-08-12 10:52:22 -0300590 return -5;
Everton Marques871dbcf2009-08-11 15:43:05 -0300591 }
592 }
593
594 return addr - buf;
595}
596
597#define FREE_ADDR_LIST(hello_option_addr_list) \
598{ \
599 if (hello_option_addr_list) { \
600 list_delete(hello_option_addr_list); \
601 hello_option_addr_list = 0; \
602 } \
603}
604
605int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
606 pim_hello_options *hello_options,
607 struct list **hello_option_addr_list,
608 uint16_t option_len,
609 const char *tlv_curr)
610{
611 const char *addr;
612 const char *pastend;
613
614 zassert(hello_option_addr_list);
615
616 /*
617 Scan addr list
618 */
619 addr = tlv_curr;
620 pastend = tlv_curr + option_len;
621 while (addr < pastend) {
622 struct prefix tmp;
623 int addr_offset;
624
625 /*
626 Parse ucast addr
627 */
628 addr_offset = pim_parse_addr_ucast(ifname, src_addr, &tmp,
629 addr, pastend - addr);
630 if (addr_offset < 1) {
631 char src_str[100];
632 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
633 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
634 __PRETTY_FUNCTION__,
635 src_str, ifname);
636 FREE_ADDR_LIST(*hello_option_addr_list);
637 return -1;
638 }
639 addr += addr_offset;
640
641 /*
642 Debug
643 */
644 if (PIM_DEBUG_PIM_TRACE) {
645 switch (tmp.family) {
646 case AF_INET:
647 {
648 char addr_str[100];
649 char src_str[100];
650 pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str));
651 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
652 zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
653 __PRETTY_FUNCTION__,
654 *hello_option_addr_list ?
655 ((int) listcount(*hello_option_addr_list)) : -1,
656 addr_str, src_str, ifname);
657 }
658 break;
659 default:
660 {
661 char src_str[100];
662 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
663 zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
664 __PRETTY_FUNCTION__,
665 *hello_option_addr_list ?
666 ((int) listcount(*hello_option_addr_list)) : -1,
667 src_str, ifname);
668 }
669 }
670 }
671
672 /*
673 Exclude neighbor's primary address if incorrectly included in
674 the secondary address list
675 */
676 if (tmp.family == AF_INET) {
677 if (tmp.u.prefix4.s_addr == src_addr.s_addr) {
678 char src_str[100];
679 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
680 zlog_warn("%s: ignoring primary address in secondary list from %s on %s",
681 __PRETTY_FUNCTION__,
682 src_str, ifname);
683 continue;
684 }
685 }
686
687 /*
688 Allocate list if needed
689 */
690 if (!*hello_option_addr_list) {
691 *hello_option_addr_list = list_new();
692 if (!*hello_option_addr_list) {
693 zlog_err("%s %s: failure: hello_option_addr_list=list_new()",
694 __FILE__, __PRETTY_FUNCTION__);
695 return -2;
696 }
697 (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free;
698 }
699
700 /*
701 Attach addr to list
702 */
703 {
704 struct prefix *p;
705 p = prefix_new();
706 if (!p) {
707 zlog_err("%s %s: failure: prefix_new()",
708 __FILE__, __PRETTY_FUNCTION__);
709 FREE_ADDR_LIST(*hello_option_addr_list);
710 return -3;
711 }
712 p->family = tmp.family;
713 p->u.prefix4 = tmp.u.prefix4;
714 listnode_add(*hello_option_addr_list, p);
715 }
716
717 } /* while (addr < pastend) */
718
719 /*
720 Mark hello option
721 */
722 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST);
723
724 return 0;
725}