3 Copyright (C) 2008 Everton da Silva Marques
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.
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.
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,
33 uint8_t *pim_tlv_append_uint16(uint8_t *buf
,
34 const uint8_t *buf_pastend
,
36 uint16_t option_value
)
38 uint16_t option_len
= 2;
40 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
43 *(uint16_t *) buf
= htons(option_type
);
45 *(uint16_t *) buf
= htons(option_len
);
47 *(uint16_t *) buf
= htons(option_value
);
53 uint8_t *pim_tlv_append_2uint16(uint8_t *buf
,
54 const uint8_t *buf_pastend
,
56 uint16_t option_value1
,
57 uint16_t option_value2
)
59 uint16_t option_len
= 4;
61 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
64 *(uint16_t *) buf
= htons(option_type
);
66 *(uint16_t *) buf
= htons(option_len
);
68 *(uint16_t *) buf
= htons(option_value1
);
70 *(uint16_t *) buf
= htons(option_value2
);
76 uint8_t *pim_tlv_append_uint32(uint8_t *buf
,
77 const uint8_t *buf_pastend
,
79 uint32_t option_value
)
81 uint16_t option_len
= 4;
83 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
86 *(uint16_t *) buf
= htons(option_type
);
88 *(uint16_t *) buf
= htons(option_len
);
90 pim_write_uint32(buf
, option_value
);
96 #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
97 #define ucast_ipv6_encoding_len (2 + sizeof(struct in6_addr))
100 * An Encoded-Unicast address takes the following format:
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
109 * The PIM address family of the 'Unicast Address' field of this
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.
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.
123 * The unicast address as represented by the given Address Family
127 pim_encode_addr_ucast (uint8_t *buf
, struct prefix
*p
)
132 *(uint8_t *)buf
= PIM_MSG_ADDRESS_FAMILY_IPV4
; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
134 *(uint8_t *)buf
= 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */
136 memcpy (buf
, &p
->u
.prefix4
, sizeof (struct in_addr
));
137 return ucast_ipv4_encoding_len
;
140 *(uint8_t *)buf
= PIM_MSG_ADDRESS_FAMILY_IPV6
;
144 memcpy (buf
, &p
->u
.prefix6
, sizeof (struct in6_addr
));
145 return ucast_ipv6_encoding_len
;
153 #define group_ipv4_encoding_len (4 + sizeof (struct in_addr))
156 * Encoded-Group addresses take the following format:
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
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.
177 * Transmitted as zero. Ignored upon receipt.
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.
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
195 * Group multicast Address
196 * Contains the group address.
199 pim_encode_addr_group (uint8_t *buf
, afi_t afi
, int bidir
, int scope
, struct in_addr group
)
209 *(uint8_t *)buf
= PIM_MSG_ADDRESS_FAMILY_IPV4
;
213 *(uint8_t *)buf
= flags
;
215 *(uint8_t *)buf
= 32;
217 memcpy (buf
, &group
, sizeof (struct in_addr
));
218 return group_ipv4_encoding_len
;
226 uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf
,
227 const uint8_t *buf_pastend
,
228 struct list
*ifconnected
,
231 struct listnode
*node
;
232 uint16_t option_len
= 0;
236 node
= listhead(ifconnected
);
238 /* Empty address list ? */
243 if (family
== AF_INET
)
244 uel
= ucast_ipv4_encoding_len
;
246 uel
= ucast_ipv6_encoding_len
;
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
;
255 if (!CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
258 if ((curr
+ uel
) > buf_pastend
)
261 if (p
->family
!= family
)
264 l_encode
= pim_encode_addr_ucast (curr
, p
);
266 option_len
+= l_encode
;
269 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
270 zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu",
275 if (option_len
< 1) {
276 /* Empty secondary unicast IPv4 address list */
283 *(uint16_t *) buf
= htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST
);
284 *(uint16_t *) (buf
+ 2) = htons(option_len
);
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
)
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",
298 option_len
, correct_len
,
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
)
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",
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
)
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",
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
)
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",
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
,
358 const uint8_t *tlv_curr
)
360 const char *label
= "holdtime";
362 if (check_tlv_length(__PRETTY_FUNCTION__
, label
,
364 sizeof(uint16_t), option_len
)) {
368 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__
, label
,
370 *hello_options
, PIM_OPTION_MASK_HOLDTIME
,
371 PIM_TLV_GET_HOLDTIME(tlv_curr
),
372 *hello_option_holdtime
);
374 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_HOLDTIME
);
376 *hello_option_holdtime
= PIM_TLV_GET_HOLDTIME(tlv_curr
);
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
,
386 const uint8_t *tlv_curr
)
388 if (check_tlv_length(__PRETTY_FUNCTION__
, "lan_prune_delay",
390 sizeof(uint32_t), option_len
)) {
394 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__
, "propagation_delay",
396 *hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
,
397 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr
),
398 *hello_option_propagation_delay
);
400 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
);
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
);
407 PIM_OPTION_UNSET(*hello_options
, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
);
411 *hello_option_override_interval
= PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr
);
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
,
420 const uint8_t *tlv_curr
)
422 const char *label
= "dr_priority";
424 if (check_tlv_length(__PRETTY_FUNCTION__
, label
,
426 sizeof(uint32_t), option_len
)) {
430 check_tlv_redefinition_uint32(__PRETTY_FUNCTION__
, label
,
432 *hello_options
, PIM_OPTION_MASK_DR_PRIORITY
,
433 PIM_TLV_GET_DR_PRIORITY(tlv_curr
),
434 *hello_option_dr_priority
);
436 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_DR_PRIORITY
);
438 *hello_option_dr_priority
= PIM_TLV_GET_DR_PRIORITY(tlv_curr
);
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
,
447 const uint8_t *tlv_curr
)
449 const char *label
= "generation_id";
451 if (check_tlv_length(__PRETTY_FUNCTION__
, label
,
453 sizeof(uint32_t), option_len
)) {
457 check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__
, label
,
459 *hello_options
, PIM_OPTION_MASK_GENERATION_ID
,
460 PIM_TLV_GET_GENERATION_ID(tlv_curr
),
461 *hello_option_generation_id
);
463 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_GENERATION_ID
);
465 *hello_option_generation_id
= PIM_TLV_GET_GENERATION_ID(tlv_curr
);
471 pim_parse_addr_ucast (struct prefix
*p
,
475 const int ucast_encoding_min_len
= 3; /* 1 family + 1 type + 1 addr */
477 const uint8_t *pastend
;
481 if (buf_size
< ucast_encoding_min_len
) {
482 zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d",
484 buf_size
, ucast_encoding_min_len
);
489 pastend
= buf
+ buf_size
;
495 zlog_warn("%s: unknown unicast address encoding type=%d",
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",
506 pastend
- addr
, sizeof(struct in_addr
));
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
);
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",
520 pastend
- addr
, sizeof(struct in6_addr
));
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
);
532 zlog_warn("%s: unknown unicast address encoding family=%d from",
543 pim_parse_addr_group (struct prefix_sg
*sg
,
547 const int grp_encoding_min_len
= 4; /* 1 family + 1 type + 1 reserved + 1 addr */
549 const uint8_t *pastend
;
554 if (buf_size
< grp_encoding_min_len
) {
555 zlog_warn("%s: group address encoding overflow: left=%d needed=%d",
557 buf_size
, grp_encoding_min_len
);
562 pastend
= buf
+ buf_size
;
567 ++addr
; /* skip b_reserved_z fields */
571 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
573 zlog_warn("%s: unknown group address encoding type=%d from",
574 __PRETTY_FUNCTION__
, type
);
578 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
579 zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from",
581 pastend
- addr
, sizeof(struct in_addr
));
585 memcpy(&sg
->grp
.s_addr
, addr
, sizeof(struct in_addr
));
587 addr
+= sizeof(struct in_addr
);
592 zlog_warn("%s: unknown group address encoding family=%d mask_len=%d from",
593 __PRETTY_FUNCTION__
, family
, mask_len
);
602 pim_parse_addr_source(struct prefix_sg
*sg
,
607 const int src_encoding_min_len
= 4; /* 1 family + 1 type + 1 reserved + 1 addr */
609 const uint8_t *pastend
;
614 if (buf_size
< src_encoding_min_len
) {
615 zlog_warn("%s: source address encoding overflow: left=%d needed=%d",
617 buf_size
, src_encoding_min_len
);
622 pastend
= buf
+ buf_size
;
630 zlog_warn("%s: unknown source address encoding type=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
633 buf
[0], buf
[1], buf
[2], buf
[3], buf
[4], buf
[5], buf
[6], buf
[7]);
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",
642 pastend
- addr
, sizeof(struct in_addr
));
646 memcpy(&sg
->src
, addr
, sizeof(struct in_addr
));
649 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
651 Encoded-Source Address
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.
658 if (mask_len
!= 32) {
659 zlog_warn("%s: IPv4 bad source address mask: %d",
660 __PRETTY_FUNCTION__
, mask_len
);
664 addr
+= sizeof(struct in_addr
);
669 zlog_warn("%s: unknown source address encoding family=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
672 buf
[0], buf
[1], buf
[2], buf
[3], buf
[4], buf
[5], buf
[6], buf
[7]);
680 #define FREE_ADDR_LIST(hello_option_addr_list) \
682 if (hello_option_addr_list) { \
683 list_delete(hello_option_addr_list); \
684 hello_option_addr_list = 0; \
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
,
692 const uint8_t *tlv_curr
)
695 const uint8_t *pastend
;
697 zassert(hello_option_addr_list
);
703 pastend
= tlv_curr
+ option_len
;
704 while (addr
< pastend
) {
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",
718 FREE_ADDR_LIST(*hello_option_addr_list
);
726 if (PIM_DEBUG_PIM_TRACE
) {
727 switch (tmp
.family
) {
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",
736 *hello_option_addr_list
?
737 ((int) listcount(*hello_option_addr_list
)) : -1,
738 addr_str
, src_str
, ifname
);
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",
749 *hello_option_addr_list
?
750 ((int) listcount(*hello_option_addr_list
)) : -1,
757 Exclude neighbor's primary address if incorrectly included in
758 the secondary address list
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",
772 Allocate list if needed
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__
);
781 (*hello_option_addr_list
)->del
= (void (*)(void *)) prefix_free
;
791 zlog_err("%s %s: failure: prefix_new()",
792 __FILE__
, __PRETTY_FUNCTION__
);
793 FREE_ADDR_LIST(*hello_option_addr_list
);
796 prefix_copy(p
, &tmp
);
797 listnode_add(*hello_option_addr_list
, p
);
800 } /* while (addr < pastend) */
805 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_ADDRESS_LIST
);