blob: c578a70d72637b33df485a01708db31939756cb7 [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
562 addr += sizeof(struct in_addr);
563
564 break;
565 default:
566 {
567 char src_str[100];
568 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
569 zlog_warn("%s: unknown source address encoding family=%d from %s on %s",
570 __PRETTY_FUNCTION__,
571 family, src_str, ifname);
572 return -4;
573 }
574 }
575
576 return addr - buf;
577}
578
579#define FREE_ADDR_LIST(hello_option_addr_list) \
580{ \
581 if (hello_option_addr_list) { \
582 list_delete(hello_option_addr_list); \
583 hello_option_addr_list = 0; \
584 } \
585}
586
587int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
588 pim_hello_options *hello_options,
589 struct list **hello_option_addr_list,
590 uint16_t option_len,
591 const char *tlv_curr)
592{
593 const char *addr;
594 const char *pastend;
595
596 zassert(hello_option_addr_list);
597
598 /*
599 Scan addr list
600 */
601 addr = tlv_curr;
602 pastend = tlv_curr + option_len;
603 while (addr < pastend) {
604 struct prefix tmp;
605 int addr_offset;
606
607 /*
608 Parse ucast addr
609 */
610 addr_offset = pim_parse_addr_ucast(ifname, src_addr, &tmp,
611 addr, pastend - addr);
612 if (addr_offset < 1) {
613 char src_str[100];
614 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
615 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
616 __PRETTY_FUNCTION__,
617 src_str, ifname);
618 FREE_ADDR_LIST(*hello_option_addr_list);
619 return -1;
620 }
621 addr += addr_offset;
622
623 /*
624 Debug
625 */
626 if (PIM_DEBUG_PIM_TRACE) {
627 switch (tmp.family) {
628 case AF_INET:
629 {
630 char addr_str[100];
631 char src_str[100];
632 pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str));
633 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
634 zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
635 __PRETTY_FUNCTION__,
636 *hello_option_addr_list ?
637 ((int) listcount(*hello_option_addr_list)) : -1,
638 addr_str, src_str, ifname);
639 }
640 break;
641 default:
642 {
643 char src_str[100];
644 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
645 zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
646 __PRETTY_FUNCTION__,
647 *hello_option_addr_list ?
648 ((int) listcount(*hello_option_addr_list)) : -1,
649 src_str, ifname);
650 }
651 }
652 }
653
654 /*
655 Exclude neighbor's primary address if incorrectly included in
656 the secondary address list
657 */
658 if (tmp.family == AF_INET) {
659 if (tmp.u.prefix4.s_addr == src_addr.s_addr) {
660 char src_str[100];
661 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
662 zlog_warn("%s: ignoring primary address in secondary list from %s on %s",
663 __PRETTY_FUNCTION__,
664 src_str, ifname);
665 continue;
666 }
667 }
668
669 /*
670 Allocate list if needed
671 */
672 if (!*hello_option_addr_list) {
673 *hello_option_addr_list = list_new();
674 if (!*hello_option_addr_list) {
675 zlog_err("%s %s: failure: hello_option_addr_list=list_new()",
676 __FILE__, __PRETTY_FUNCTION__);
677 return -2;
678 }
679 (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free;
680 }
681
682 /*
683 Attach addr to list
684 */
685 {
686 struct prefix *p;
687 p = prefix_new();
688 if (!p) {
689 zlog_err("%s %s: failure: prefix_new()",
690 __FILE__, __PRETTY_FUNCTION__);
691 FREE_ADDR_LIST(*hello_option_addr_list);
692 return -3;
693 }
694 p->family = tmp.family;
695 p->u.prefix4 = tmp.u.prefix4;
696 listnode_add(*hello_option_addr_list, p);
697 }
698
699 } /* while (addr < pastend) */
700
701 /*
702 Mark hello option
703 */
704 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST);
705
706 return 0;
707}