]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_tlv.c
259ed44c714de11767994c9d148b912822eca4b0
[mirror_frr.git] / pimd / pim_tlv.c
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
21 #include <zebra.h>
22
23 #include "log.h"
24 #include "prefix.h"
25 #include "if.h"
26
27 #include "pimd.h"
28 #include "pim_int.h"
29 #include "pim_tlv.h"
30 #include "pim_str.h"
31 #include "pim_msg.h"
32
33 uint8_t *pim_tlv_append_uint16(uint8_t *buf,
34 const uint8_t *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 return NULL;
42
43 *(uint16_t *) buf = htons(option_type);
44 buf += 2;
45 *(uint16_t *) buf = htons(option_len);
46 buf += 2;
47 *(uint16_t *) buf = htons(option_value);
48 buf += option_len;
49
50 return buf;
51 }
52
53 uint8_t *pim_tlv_append_2uint16(uint8_t *buf,
54 const uint8_t *buf_pastend,
55 uint16_t option_type,
56 uint16_t option_value1,
57 uint16_t option_value2)
58 {
59 uint16_t option_len = 4;
60
61 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
62 return NULL;
63
64 *(uint16_t *) buf = htons(option_type);
65 buf += 2;
66 *(uint16_t *) buf = htons(option_len);
67 buf += 2;
68 *(uint16_t *) buf = htons(option_value1);
69 buf += 2;
70 *(uint16_t *) buf = htons(option_value2);
71 buf += 2;
72
73 return buf;
74 }
75
76 uint8_t *pim_tlv_append_uint32(uint8_t *buf,
77 const uint8_t *buf_pastend,
78 uint16_t option_type,
79 uint32_t option_value)
80 {
81 uint16_t option_len = 4;
82
83 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
84 return NULL;
85
86 *(uint16_t *) buf = htons(option_type);
87 buf += 2;
88 *(uint16_t *) buf = htons(option_len);
89 buf += 2;
90 pim_write_uint32(buf, option_value);
91 buf += option_len;
92
93 return buf;
94 }
95
96 #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
97 #define ucast_ipv6_encoding_len (2 + sizeof(struct in6_addr))
98
99 /*
100 * An Encoded-Unicast address takes the following format:
101 *
102 * 0 1 2 3
103 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
104 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
105 * | Addr Family | Encoding Type | Unicast Address
106 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
107 *
108 * Addr Family
109 * The PIM address family of the 'Unicast Address' field of this
110 * address.
111 *
112 * Values 0-127 are as assigned by the IANA for Internet Address * Families in [7]. Values 128-250 are reserved to be assigned by
113 * the IANA for PIM-specific Address Families. Values 251 though
114 * 255 are designated for private use. As there is no assignment
115 * authority for this space, collisions should be expected.
116 *
117 * Encoding Type
118 * The type of encoding used within a specific Address Family. The
119 * value '0' is reserved for this field and represents the native
120 * encoding of the Address Family.
121 *
122 * Unicast Address
123 * The unicast address as represented by the given Address Family
124 * and Encoding Type.
125 */
126 int
127 pim_encode_addr_ucast (uint8_t *buf, struct prefix *p)
128 {
129 switch (p->family)
130 {
131 case AF_INET:
132 *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
133 ++buf;
134 *(uint8_t *)buf = 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */
135 ++buf;
136 memcpy (buf, &p->u.prefix4, sizeof (struct in_addr));
137 return ucast_ipv4_encoding_len;
138 break;
139 case AF_INET6:
140 *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV6;
141 ++buf;
142 *(uint8_t *)buf = 0;
143 ++buf;
144 memcpy (buf, &p->u.prefix6, sizeof (struct in6_addr));
145 return ucast_ipv6_encoding_len;
146 break;
147 default:
148 return 0;
149 break;
150 }
151 }
152
153 #define group_ipv4_encoding_len (4 + sizeof (struct in_addr))
154
155 /*
156 * Encoded-Group addresses take the following format:
157 *
158 * 0 1 2 3
159 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
160 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
161 * | Addr Family | Encoding Type |B| Reserved |Z| Mask Len |
162 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
163 * | Group multicast Address
164 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
165 *
166 * Addr Family
167 * Described above.
168 *
169 * Encoding Type
170 * Described above.
171 *
172 * [B]idirectional PIM
173 * Indicates the group range should use Bidirectional PIM [13].
174 * For PIM-SM defined in this specification, this bit MUST be zero.
175 *
176 * Reserved
177 * Transmitted as zero. Ignored upon receipt.
178 *
179 * Admin Scope [Z]one
180 * indicates the group range is an admin scope zone. This is used
181 * in the Bootstrap Router Mechanism [11] only. For all other
182 * purposes, this bit is set to zero and ignored on receipt.
183 *
184 * Mask Len
185 * The Mask length field is 8 bits. The value is the number of
186 * contiguous one bits that are left justified and used as a mask;
187 * when combined with the group address, it describes a range of
188 * groups. It is less than or equal to the address length in bits
189 * for the given Address Family and Encoding Type. If the message
190 * is sent for a single group, then the Mask length must equal the
191 * address length in bits for the given Address Family and Encoding
192 * Type (e.g., 32 for IPv4 native encoding, 128 for IPv6 native
193 * encoding).
194 *
195 * Group multicast Address
196 * Contains the group address.
197 */
198 int
199 pim_encode_addr_group (uint8_t *buf, afi_t afi, int bidir, int scope, struct in_addr group)
200 {
201 uint8_t flags = 0;
202
203 flags |= bidir << 8;
204 flags |= scope;
205
206 switch (afi)
207 {
208 case AFI_IP:
209 *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV4;
210 ++buf;
211 *(uint8_t *)buf = 0;
212 ++buf;
213 *(uint8_t *)buf = flags;
214 ++buf;
215 *(uint8_t *)buf = 32;
216 ++buf;
217 memcpy (buf, &group, sizeof (struct in_addr));
218 return group_ipv4_encoding_len;
219 break;
220 default:
221 return 0;
222 break;
223 }
224 }
225
226 uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
227 const uint8_t *buf_pastend,
228 struct list *ifconnected,
229 int family)
230 {
231 struct listnode *node;
232 uint16_t option_len = 0;
233 uint8_t *curr;
234 size_t uel;
235
236 node = listhead(ifconnected);
237
238 /* Empty address list ? */
239 if (!node) {
240 return buf;
241 }
242
243 if (family == AF_INET)
244 uel = ucast_ipv4_encoding_len;
245 else
246 uel = ucast_ipv6_encoding_len;
247
248 /* Scan secondary address list */
249 curr = buf + 4; /* skip T and L */
250 for (; node; node = listnextnode(node)) {
251 struct connected *ifc = listgetdata(node);
252 struct prefix *p = ifc->address;
253 int l_encode;
254
255 if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
256 continue;
257
258 if ((curr + uel) > buf_pastend)
259 return 0;
260
261 if (p->family != family)
262 continue;
263
264 l_encode = pim_encode_addr_ucast (curr, p);
265 curr += l_encode;
266 option_len += l_encode;
267 }
268
269 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
270 zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu",
271 __PRETTY_FUNCTION__,
272 option_len / uel);
273 }
274
275 if (option_len < 1) {
276 /* Empty secondary unicast IPv4 address list */
277 return buf;
278 }
279
280 /*
281 * Write T and L
282 */
283 *(uint16_t *) buf = htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST);
284 *(uint16_t *) (buf + 2) = htons(option_len);
285
286 return curr;
287 }
288
289 static int check_tlv_length(const char *label, const char *tlv_name,
290 const char *ifname, struct in_addr src_addr,
291 int correct_len, int option_len)
292 {
293 if (option_len != correct_len) {
294 char src_str[INET_ADDRSTRLEN];
295 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
296 zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s",
297 label, tlv_name,
298 option_len, correct_len,
299 src_str, ifname);
300 return -1;
301 }
302
303 return 0;
304 }
305
306 static void check_tlv_redefinition_uint16(const char *label, const char *tlv_name,
307 const char *ifname, struct in_addr src_addr,
308 pim_hello_options options,
309 pim_hello_options opt_mask,
310 uint16_t new, uint16_t old)
311 {
312 if (PIM_OPTION_IS_SET(options, opt_mask)) {
313 char src_str[INET_ADDRSTRLEN];
314 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
315 zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
316 label, tlv_name,
317 new, old,
318 src_str, ifname);
319 }
320 }
321
322 static void check_tlv_redefinition_uint32(const char *label, const char *tlv_name,
323 const char *ifname, struct in_addr src_addr,
324 pim_hello_options options,
325 pim_hello_options opt_mask,
326 uint32_t new, uint32_t old)
327 {
328 if (PIM_OPTION_IS_SET(options, opt_mask)) {
329 char src_str[INET_ADDRSTRLEN];
330 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
331 zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
332 label, tlv_name,
333 new, old,
334 src_str, ifname);
335 }
336 }
337
338 static void check_tlv_redefinition_uint32_hex(const char *label, const char *tlv_name,
339 const char *ifname, struct in_addr src_addr,
340 pim_hello_options options,
341 pim_hello_options opt_mask,
342 uint32_t new, uint32_t old)
343 {
344 if (PIM_OPTION_IS_SET(options, opt_mask)) {
345 char src_str[INET_ADDRSTRLEN];
346 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
347 zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s",
348 label, tlv_name,
349 new, old,
350 src_str, ifname);
351 }
352 }
353
354 int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr,
355 pim_hello_options *hello_options,
356 uint16_t *hello_option_holdtime,
357 uint16_t option_len,
358 const uint8_t *tlv_curr)
359 {
360 const char *label = "holdtime";
361
362 if (check_tlv_length(__PRETTY_FUNCTION__, label,
363 ifname, src_addr,
364 sizeof(uint16_t), option_len)) {
365 return -1;
366 }
367
368 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, label,
369 ifname, src_addr,
370 *hello_options, PIM_OPTION_MASK_HOLDTIME,
371 PIM_TLV_GET_HOLDTIME(tlv_curr),
372 *hello_option_holdtime);
373
374 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME);
375
376 *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr);
377
378 return 0;
379 }
380
381 int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr,
382 pim_hello_options *hello_options,
383 uint16_t *hello_option_propagation_delay,
384 uint16_t *hello_option_override_interval,
385 uint16_t option_len,
386 const uint8_t *tlv_curr)
387 {
388 if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay",
389 ifname, src_addr,
390 sizeof(uint32_t), option_len)) {
391 return -1;
392 }
393
394 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, "propagation_delay",
395 ifname, src_addr,
396 *hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY,
397 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr),
398 *hello_option_propagation_delay);
399
400 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY);
401
402 *hello_option_propagation_delay = PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr);
403 if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr)) {
404 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
405 }
406 else {
407 PIM_OPTION_UNSET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
408 }
409 ++tlv_curr;
410 ++tlv_curr;
411 *hello_option_override_interval = PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr);
412
413 return 0;
414 }
415
416 int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr,
417 pim_hello_options *hello_options,
418 uint32_t *hello_option_dr_priority,
419 uint16_t option_len,
420 const uint8_t *tlv_curr)
421 {
422 const char *label = "dr_priority";
423
424 if (check_tlv_length(__PRETTY_FUNCTION__, label,
425 ifname, src_addr,
426 sizeof(uint32_t), option_len)) {
427 return -1;
428 }
429
430 check_tlv_redefinition_uint32(__PRETTY_FUNCTION__, label,
431 ifname, src_addr,
432 *hello_options, PIM_OPTION_MASK_DR_PRIORITY,
433 PIM_TLV_GET_DR_PRIORITY(tlv_curr),
434 *hello_option_dr_priority);
435
436 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY);
437
438 *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr);
439
440 return 0;
441 }
442
443 int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr,
444 pim_hello_options *hello_options,
445 uint32_t *hello_option_generation_id,
446 uint16_t option_len,
447 const uint8_t *tlv_curr)
448 {
449 const char *label = "generation_id";
450
451 if (check_tlv_length(__PRETTY_FUNCTION__, label,
452 ifname, src_addr,
453 sizeof(uint32_t), option_len)) {
454 return -1;
455 }
456
457 check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__, label,
458 ifname, src_addr,
459 *hello_options, PIM_OPTION_MASK_GENERATION_ID,
460 PIM_TLV_GET_GENERATION_ID(tlv_curr),
461 *hello_option_generation_id);
462
463 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID);
464
465 *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr);
466
467 return 0;
468 }
469
470 int
471 pim_parse_addr_ucast (struct prefix *p,
472 const uint8_t *buf,
473 int buf_size)
474 {
475 const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */
476 const uint8_t *addr;
477 const uint8_t *pastend;
478 int family;
479 int type;
480
481 if (buf_size < ucast_encoding_min_len) {
482 zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d",
483 __PRETTY_FUNCTION__,
484 buf_size, ucast_encoding_min_len);
485 return -1;
486 }
487
488 addr = buf;
489 pastend = buf + buf_size;
490
491 family = *addr++;
492 type = *addr++;
493
494 if (type) {
495 zlog_warn("%s: unknown unicast address encoding type=%d",
496 __PRETTY_FUNCTION__,
497 type);
498 return -2;
499 }
500
501 switch (family) {
502 case PIM_MSG_ADDRESS_FAMILY_IPV4:
503 if ((addr + sizeof(struct in_addr)) > pastend) {
504 zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu",
505 __PRETTY_FUNCTION__,
506 pastend - addr, sizeof(struct in_addr));
507 return -3;
508 }
509
510 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
511 memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
512 p->prefixlen = IPV4_MAX_PREFIXLEN;
513 addr += sizeof(struct in_addr);
514
515 break;
516 case PIM_MSG_ADDRESS_FAMILY_IPV6:
517 if ((addr + sizeof(struct in6_addr)) > pastend) {
518 zlog_warn ("%s: IPv6 unicast address overflow: left=%zd needed %zu",
519 __PRETTY_FUNCTION__,
520 pastend - addr, sizeof(struct in6_addr));
521 return -3;
522 }
523
524 p->family = AF_INET6;
525 p->prefixlen = IPV6_MAX_PREFIXLEN;
526 memcpy(&p->u.prefix6, addr, sizeof(struct in6_addr));
527 addr += sizeof(struct in6_addr);
528
529 break;
530 default:
531 {
532 zlog_warn("%s: unknown unicast address encoding family=%d from",
533 __PRETTY_FUNCTION__,
534 family);
535 return -4;
536 }
537 }
538
539 return addr - buf;
540 }
541
542 int
543 pim_parse_addr_group (struct prefix_sg *sg,
544 const uint8_t *buf,
545 int buf_size)
546 {
547 const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
548 const uint8_t *addr;
549 const uint8_t *pastend;
550 int family;
551 int type;
552 int mask_len;
553
554 if (buf_size < grp_encoding_min_len) {
555 zlog_warn("%s: group address encoding overflow: left=%d needed=%d",
556 __PRETTY_FUNCTION__,
557 buf_size, grp_encoding_min_len);
558 return -1;
559 }
560
561 addr = buf;
562 pastend = buf + buf_size;
563
564 family = *addr++;
565 type = *addr++;
566 //++addr;
567 ++addr; /* skip b_reserved_z fields */
568 mask_len = *addr++;
569
570 switch (family) {
571 case PIM_MSG_ADDRESS_FAMILY_IPV4:
572 if (type) {
573 zlog_warn("%s: unknown group address encoding type=%d from",
574 __PRETTY_FUNCTION__, type);
575 return -2;
576 }
577
578 if ((addr + sizeof(struct in_addr)) > pastend) {
579 zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from",
580 __PRETTY_FUNCTION__,
581 pastend - addr, sizeof(struct in_addr));
582 return -3;
583 }
584
585 memcpy(&sg->grp.s_addr, addr, sizeof(struct in_addr));
586
587 addr += sizeof(struct in_addr);
588
589 break;
590 default:
591 {
592 zlog_warn("%s: unknown group address encoding family=%d mask_len=%d from",
593 __PRETTY_FUNCTION__, family, mask_len);
594 return -4;
595 }
596 }
597
598 return addr - buf;
599 }
600
601 int
602 pim_parse_addr_source(struct prefix_sg *sg,
603 uint8_t *flags,
604 const uint8_t *buf,
605 int buf_size)
606 {
607 const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
608 const uint8_t *addr;
609 const uint8_t *pastend;
610 int family;
611 int type;
612 int mask_len;
613
614 if (buf_size < src_encoding_min_len) {
615 zlog_warn("%s: source address encoding overflow: left=%d needed=%d",
616 __PRETTY_FUNCTION__,
617 buf_size, src_encoding_min_len);
618 return -1;
619 }
620
621 addr = buf;
622 pastend = buf + buf_size;
623
624 family = *addr++;
625 type = *addr++;
626 *flags = *addr++;
627 mask_len = *addr++;
628
629 if (type) {
630 zlog_warn("%s: unknown source address encoding type=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
631 __PRETTY_FUNCTION__,
632 type,
633 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
634 return -2;
635 }
636
637 switch (family) {
638 case PIM_MSG_ADDRESS_FAMILY_IPV4:
639 if ((addr + sizeof(struct in_addr)) > pastend) {
640 zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu",
641 __PRETTY_FUNCTION__,
642 pastend - addr, sizeof(struct in_addr));
643 return -3;
644 }
645
646 memcpy(&sg->src, addr, sizeof(struct in_addr));
647
648 /*
649 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
650
651 Encoded-Source Address
652
653 The mask length MUST be equal to the mask length in bits for
654 the given Address Family and Encoding Type (32 for IPv4 native
655 and 128 for IPv6 native). A router SHOULD ignore any messages
656 received with any other mask length.
657 */
658 if (mask_len != 32) {
659 zlog_warn("%s: IPv4 bad source address mask: %d",
660 __PRETTY_FUNCTION__, mask_len);
661 return -4;
662 }
663
664 addr += sizeof(struct in_addr);
665
666 break;
667 default:
668 {
669 zlog_warn("%s: unknown source address encoding family=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
670 __PRETTY_FUNCTION__,
671 family,
672 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
673 return -5;
674 }
675 }
676
677 return addr - buf;
678 }
679
680 #define FREE_ADDR_LIST(hello_option_addr_list) \
681 { \
682 if (hello_option_addr_list) { \
683 list_delete(hello_option_addr_list); \
684 hello_option_addr_list = 0; \
685 } \
686 }
687
688 int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
689 pim_hello_options *hello_options,
690 struct list **hello_option_addr_list,
691 uint16_t option_len,
692 const uint8_t *tlv_curr)
693 {
694 const uint8_t *addr;
695 const uint8_t *pastend;
696
697 zassert(hello_option_addr_list);
698
699 /*
700 Scan addr list
701 */
702 addr = tlv_curr;
703 pastend = tlv_curr + option_len;
704 while (addr < pastend) {
705 struct prefix tmp;
706 int addr_offset;
707
708 /*
709 Parse ucast addr
710 */
711 addr_offset = pim_parse_addr_ucast(&tmp, addr, pastend - addr);
712 if (addr_offset < 1) {
713 char src_str[INET_ADDRSTRLEN];
714 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
715 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
716 __PRETTY_FUNCTION__,
717 src_str, ifname);
718 FREE_ADDR_LIST(*hello_option_addr_list);
719 return -1;
720 }
721 addr += addr_offset;
722
723 /*
724 Debug
725 */
726 if (PIM_DEBUG_PIM_TRACE) {
727 switch (tmp.family) {
728 case AF_INET:
729 {
730 char addr_str[INET_ADDRSTRLEN];
731 char src_str[INET_ADDRSTRLEN];
732 pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str));
733 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
734 zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
735 __PRETTY_FUNCTION__,
736 *hello_option_addr_list ?
737 ((int) listcount(*hello_option_addr_list)) : -1,
738 addr_str, src_str, ifname);
739 }
740 break;
741 case AF_INET6:
742 break;
743 default:
744 {
745 char src_str[INET_ADDRSTRLEN];
746 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
747 zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
748 __PRETTY_FUNCTION__,
749 *hello_option_addr_list ?
750 ((int) listcount(*hello_option_addr_list)) : -1,
751 src_str, ifname);
752 }
753 }
754 }
755
756 /*
757 Exclude neighbor's primary address if incorrectly included in
758 the secondary address list
759 */
760 if (tmp.family == AF_INET) {
761 if (tmp.u.prefix4.s_addr == src_addr.s_addr) {
762 char src_str[INET_ADDRSTRLEN];
763 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
764 zlog_warn("%s: ignoring primary address in secondary list from %s on %s",
765 __PRETTY_FUNCTION__,
766 src_str, ifname);
767 continue;
768 }
769 }
770
771 /*
772 Allocate list if needed
773 */
774 if (!*hello_option_addr_list) {
775 *hello_option_addr_list = list_new();
776 if (!*hello_option_addr_list) {
777 zlog_err("%s %s: failure: hello_option_addr_list=list_new()",
778 __FILE__, __PRETTY_FUNCTION__);
779 return -2;
780 }
781 (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free;
782 }
783
784 /*
785 Attach addr to list
786 */
787 {
788 struct prefix *p;
789 p = prefix_new();
790 if (!p) {
791 zlog_err("%s %s: failure: prefix_new()",
792 __FILE__, __PRETTY_FUNCTION__);
793 FREE_ADDR_LIST(*hello_option_addr_list);
794 return -3;
795 }
796 prefix_copy(p, &tmp);
797 listnode_add(*hello_option_addr_list, p);
798 }
799
800 } /* while (addr < pastend) */
801
802 /*
803 Mark hello option
804 */
805 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST);
806
807 return 0;
808 }