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