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,
37 uint8_t *pim_tlv_append_uint16(uint8_t *buf
,
38 const uint8_t *buf_pastend
,
40 uint16_t option_value
)
42 uint16_t option_len
= 2;
44 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
47 *(uint16_t *) buf
= htons(option_type
);
49 *(uint16_t *) buf
= htons(option_len
);
51 *(uint16_t *) buf
= htons(option_value
);
57 uint8_t *pim_tlv_append_2uint16(uint8_t *buf
,
58 const uint8_t *buf_pastend
,
60 uint16_t option_value1
,
61 uint16_t option_value2
)
63 uint16_t option_len
= 4;
65 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
68 *(uint16_t *) buf
= htons(option_type
);
70 *(uint16_t *) buf
= htons(option_len
);
72 *(uint16_t *) buf
= htons(option_value1
);
74 *(uint16_t *) buf
= htons(option_value2
);
80 uint8_t *pim_tlv_append_uint32(uint8_t *buf
,
81 const uint8_t *buf_pastend
,
83 uint32_t option_value
)
85 uint16_t option_len
= 4;
87 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
90 *(uint16_t *) buf
= htons(option_type
);
92 *(uint16_t *) buf
= htons(option_len
);
94 pim_write_uint32(buf
, option_value
);
100 #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
103 * An Encoded-Unicast address takes the following format:
106 * 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
107 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
108 * | Addr Family | Encoding Type | Unicast Address
109 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
112 * The PIM address family of the 'Unicast Address' field of this
115 * Values 0-127 are as assigned by the IANA for Internet Address * Families in [7]. Values 128-250 are reserved to be assigned by
116 * the IANA for PIM-specific Address Families. Values 251 though
117 * 255 are designated for private use. As there is no assignment
118 * authority for this space, collisions should be expected.
121 * The type of encoding used within a specific Address Family. The
122 * value '0' is reserved for this field and represents the native
123 * encoding of the Address Family.
126 * The unicast address as represented by the given Address Family
130 pim_encode_addr_ucast (uint8_t *buf
, struct prefix
*p
)
135 *(uint8_t *)buf
= PIM_MSG_ADDRESS_FAMILY_IPV4
; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
137 *(uint8_t *)buf
= 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */
139 memcpy (buf
, &p
->u
.prefix4
, sizeof (struct in_addr
));
140 return ucast_ipv4_encoding_len
;
148 #define group_ipv4_encoding_len (4 + sizeof (struct in_addr))
151 * Encoded-Group addresses take the following format:
154 * 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
155 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
156 * | Addr Family | Encoding Type |B| Reserved |Z| Mask Len |
157 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
158 * | Group multicast Address
159 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
167 * [B]idirectional PIM
168 * Indicates the group range should use Bidirectional PIM [13].
169 * For PIM-SM defined in this specification, this bit MUST be zero.
172 * Transmitted as zero. Ignored upon receipt.
175 * indicates the group range is an admin scope zone. This is used
176 * in the Bootstrap Router Mechanism [11] only. For all other
177 * purposes, this bit is set to zero and ignored on receipt.
180 * The Mask length field is 8 bits. The value is the number of
181 * contiguous one bits that are left justified and used as a mask;
182 * when combined with the group address, it describes a range of
183 * groups. It is less than or equal to the address length in bits
184 * for the given Address Family and Encoding Type. If the message
185 * is sent for a single group, then the Mask length must equal the
186 * address length in bits for the given Address Family and Encoding
187 * Type (e.g., 32 for IPv4 native encoding, 128 for IPv6 native
190 * Group multicast Address
191 * Contains the group address.
194 pim_encode_addr_group (uint8_t *buf
, afi_t afi
, int bidir
, int scope
, struct in_addr group
)
204 *(uint8_t *)buf
= PIM_MSG_ADDRESS_FAMILY_IPV4
;
208 *(uint8_t *)buf
= flags
;
210 *(uint8_t *)buf
= 32;
212 memcpy (buf
, &group
, sizeof (struct in_addr
));
213 return group_ipv4_encoding_len
;
221 uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf
,
222 const uint8_t *buf_pastend
,
223 struct list
*ifconnected
)
225 struct listnode
*node
;
226 uint16_t option_len
= 0;
230 node
= listhead(ifconnected
);
232 /* Empty address list ? */
237 /* Skip first address (primary) */
238 node
= listnextnode(node
);
240 /* Scan secondary address list */
241 curr
= buf
+ 4; /* skip T and L */
242 for (; node
; node
= listnextnode(node
)) {
243 struct connected
*ifc
= listgetdata(node
);
244 struct prefix
*p
= ifc
->address
;
247 if ((curr
+ ucast_ipv4_encoding_len
) > buf_pastend
)
250 l_encode
= pim_encode_addr_ucast (curr
, p
);
252 option_len
+= l_encode
;
255 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
256 zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu",
258 option_len
/ ucast_ipv4_encoding_len
);
261 if (option_len
< 1) {
262 /* Empty secondary unicast IPv4 address list */
269 *(uint16_t *) buf
= htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST
);
270 *(uint16_t *) (buf
+ 2) = htons(option_len
);
275 static int check_tlv_length(const char *label
, const char *tlv_name
,
276 const char *ifname
, struct in_addr src_addr
,
277 int correct_len
, int option_len
)
279 if (option_len
!= correct_len
) {
280 char src_str
[INET_ADDRSTRLEN
];
281 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
282 zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s",
284 option_len
, correct_len
,
292 static void check_tlv_redefinition_uint16(const char *label
, const char *tlv_name
,
293 const char *ifname
, struct in_addr src_addr
,
294 pim_hello_options options
,
295 pim_hello_options opt_mask
,
296 uint16_t new, uint16_t old
)
298 if (PIM_OPTION_IS_SET(options
, opt_mask
)) {
299 char src_str
[INET_ADDRSTRLEN
];
300 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
301 zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
308 static void check_tlv_redefinition_uint32(const char *label
, const char *tlv_name
,
309 const char *ifname
, struct in_addr src_addr
,
310 pim_hello_options options
,
311 pim_hello_options opt_mask
,
312 uint32_t new, uint32_t old
)
314 if (PIM_OPTION_IS_SET(options
, opt_mask
)) {
315 char src_str
[INET_ADDRSTRLEN
];
316 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
317 zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
324 static void check_tlv_redefinition_uint32_hex(const char *label
, const char *tlv_name
,
325 const char *ifname
, struct in_addr src_addr
,
326 pim_hello_options options
,
327 pim_hello_options opt_mask
,
328 uint32_t new, uint32_t old
)
330 if (PIM_OPTION_IS_SET(options
, opt_mask
)) {
331 char src_str
[INET_ADDRSTRLEN
];
332 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
333 zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s",
340 int pim_tlv_parse_holdtime(const char *ifname
, struct in_addr src_addr
,
341 pim_hello_options
*hello_options
,
342 uint16_t *hello_option_holdtime
,
344 const uint8_t *tlv_curr
)
346 const char *label
= "holdtime";
348 if (check_tlv_length(__PRETTY_FUNCTION__
, label
,
350 sizeof(uint16_t), option_len
)) {
354 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__
, label
,
356 *hello_options
, PIM_OPTION_MASK_HOLDTIME
,
357 PIM_TLV_GET_HOLDTIME(tlv_curr
),
358 *hello_option_holdtime
);
360 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_HOLDTIME
);
362 *hello_option_holdtime
= PIM_TLV_GET_HOLDTIME(tlv_curr
);
367 int pim_tlv_parse_lan_prune_delay(const char *ifname
, struct in_addr src_addr
,
368 pim_hello_options
*hello_options
,
369 uint16_t *hello_option_propagation_delay
,
370 uint16_t *hello_option_override_interval
,
372 const uint8_t *tlv_curr
)
374 if (check_tlv_length(__PRETTY_FUNCTION__
, "lan_prune_delay",
376 sizeof(uint32_t), option_len
)) {
380 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__
, "propagation_delay",
382 *hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
,
383 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr
),
384 *hello_option_propagation_delay
);
386 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
);
388 *hello_option_propagation_delay
= PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr
);
389 if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr
)) {
390 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
);
393 PIM_OPTION_UNSET(*hello_options
, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
);
397 *hello_option_override_interval
= PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr
);
402 int pim_tlv_parse_dr_priority(const char *ifname
, struct in_addr src_addr
,
403 pim_hello_options
*hello_options
,
404 uint32_t *hello_option_dr_priority
,
406 const uint8_t *tlv_curr
)
408 const char *label
= "dr_priority";
410 if (check_tlv_length(__PRETTY_FUNCTION__
, label
,
412 sizeof(uint32_t), option_len
)) {
416 check_tlv_redefinition_uint32(__PRETTY_FUNCTION__
, label
,
418 *hello_options
, PIM_OPTION_MASK_DR_PRIORITY
,
419 PIM_TLV_GET_DR_PRIORITY(tlv_curr
),
420 *hello_option_dr_priority
);
422 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_DR_PRIORITY
);
424 *hello_option_dr_priority
= PIM_TLV_GET_DR_PRIORITY(tlv_curr
);
429 int pim_tlv_parse_generation_id(const char *ifname
, struct in_addr src_addr
,
430 pim_hello_options
*hello_options
,
431 uint32_t *hello_option_generation_id
,
433 const uint8_t *tlv_curr
)
435 const char *label
= "generation_id";
437 if (check_tlv_length(__PRETTY_FUNCTION__
, label
,
439 sizeof(uint32_t), option_len
)) {
443 check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__
, label
,
445 *hello_options
, PIM_OPTION_MASK_GENERATION_ID
,
446 PIM_TLV_GET_GENERATION_ID(tlv_curr
),
447 *hello_option_generation_id
);
449 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_GENERATION_ID
);
451 *hello_option_generation_id
= PIM_TLV_GET_GENERATION_ID(tlv_curr
);
457 pim_parse_addr_ucast (struct prefix
*p
,
461 const int ucast_encoding_min_len
= 3; /* 1 family + 1 type + 1 addr */
463 const uint8_t *pastend
;
467 if (buf_size
< ucast_encoding_min_len
) {
468 zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d",
470 buf_size
, ucast_encoding_min_len
);
475 pastend
= buf
+ buf_size
;
481 zlog_warn("%s: unknown unicast address encoding type=%d",
488 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
489 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
490 zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu",
492 pastend
- addr
, sizeof(struct in_addr
));
496 p
->family
= AF_INET
; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
497 memcpy(&p
->u
.prefix4
, addr
, sizeof(struct in_addr
));
499 addr
+= sizeof(struct in_addr
);
504 zlog_warn("%s: unknown unicast address encoding family=%d from",
515 pim_parse_addr_group (struct prefix_sg
*sg
,
519 const int grp_encoding_min_len
= 4; /* 1 family + 1 type + 1 reserved + 1 addr */
521 const uint8_t *pastend
;
526 if (buf_size
< grp_encoding_min_len
) {
527 zlog_warn("%s: group address encoding overflow: left=%d needed=%d",
529 buf_size
, grp_encoding_min_len
);
534 pastend
= buf
+ buf_size
;
539 ++addr
; /* skip b_reserved_z fields */
543 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
545 zlog_warn("%s: unknown group address encoding type=%d from",
546 __PRETTY_FUNCTION__
, type
);
550 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
551 zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from",
553 pastend
- addr
, sizeof(struct in_addr
));
557 memcpy(&sg
->grp
.s_addr
, addr
, sizeof(struct in_addr
));
559 addr
+= sizeof(struct in_addr
);
564 zlog_warn("%s: unknown group address encoding family=%d mask_len=%d from",
565 __PRETTY_FUNCTION__
, family
, mask_len
);
574 pim_parse_addr_source(struct prefix_sg
*sg
,
579 const int src_encoding_min_len
= 4; /* 1 family + 1 type + 1 reserved + 1 addr */
581 const uint8_t *pastend
;
586 if (buf_size
< src_encoding_min_len
) {
587 zlog_warn("%s: source address encoding overflow: left=%d needed=%d",
589 buf_size
, src_encoding_min_len
);
594 pastend
= buf
+ buf_size
;
602 zlog_warn("%s: unknown source address encoding type=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
605 buf
[0], buf
[1], buf
[2], buf
[3], buf
[4], buf
[5], buf
[6], buf
[7]);
610 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
611 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
612 zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu",
614 pastend
- addr
, sizeof(struct in_addr
));
618 memcpy(&sg
->src
, addr
, sizeof(struct in_addr
));
621 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
623 Encoded-Source Address
625 The mask length MUST be equal to the mask length in bits for
626 the given Address Family and Encoding Type (32 for IPv4 native
627 and 128 for IPv6 native). A router SHOULD ignore any messages
628 received with any other mask length.
630 if (mask_len
!= 32) {
631 zlog_warn("%s: IPv4 bad source address mask: %d",
632 __PRETTY_FUNCTION__
, mask_len
);
636 addr
+= sizeof(struct in_addr
);
641 zlog_warn("%s: unknown source address encoding family=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
644 buf
[0], buf
[1], buf
[2], buf
[3], buf
[4], buf
[5], buf
[6], buf
[7]);
652 #define FREE_ADDR_LIST(hello_option_addr_list) \
654 if (hello_option_addr_list) { \
655 list_delete(hello_option_addr_list); \
656 hello_option_addr_list = 0; \
660 int pim_tlv_parse_addr_list(const char *ifname
, struct in_addr src_addr
,
661 pim_hello_options
*hello_options
,
662 struct list
**hello_option_addr_list
,
664 const uint8_t *tlv_curr
)
667 const uint8_t *pastend
;
669 zassert(hello_option_addr_list
);
675 pastend
= tlv_curr
+ option_len
;
676 while (addr
< pastend
) {
683 addr_offset
= pim_parse_addr_ucast(&tmp
, addr
, pastend
- addr
);
684 if (addr_offset
< 1) {
685 char src_str
[INET_ADDRSTRLEN
];
686 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
687 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
690 FREE_ADDR_LIST(*hello_option_addr_list
);
698 if (PIM_DEBUG_PIM_TRACE
) {
699 switch (tmp
.family
) {
702 char addr_str
[INET_ADDRSTRLEN
];
703 char src_str
[INET_ADDRSTRLEN
];
704 pim_inet4_dump("<addr?>", tmp
.u
.prefix4
, addr_str
, sizeof(addr_str
));
705 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
706 zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
708 *hello_option_addr_list
?
709 ((int) listcount(*hello_option_addr_list
)) : -1,
710 addr_str
, src_str
, ifname
);
715 char src_str
[INET_ADDRSTRLEN
];
716 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
717 zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
719 *hello_option_addr_list
?
720 ((int) listcount(*hello_option_addr_list
)) : -1,
727 Exclude neighbor's primary address if incorrectly included in
728 the secondary address list
730 if (tmp
.family
== AF_INET
) {
731 if (tmp
.u
.prefix4
.s_addr
== src_addr
.s_addr
) {
732 char src_str
[INET_ADDRSTRLEN
];
733 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
734 zlog_warn("%s: ignoring primary address in secondary list from %s on %s",
742 Allocate list if needed
744 if (!*hello_option_addr_list
) {
745 *hello_option_addr_list
= list_new();
746 if (!*hello_option_addr_list
) {
747 zlog_err("%s %s: failure: hello_option_addr_list=list_new()",
748 __FILE__
, __PRETTY_FUNCTION__
);
751 (*hello_option_addr_list
)->del
= (void (*)(void *)) prefix_free
;
761 zlog_err("%s %s: failure: prefix_new()",
762 __FILE__
, __PRETTY_FUNCTION__
);
763 FREE_ADDR_LIST(*hello_option_addr_list
);
766 p
->family
= tmp
.family
;
767 p
->u
.prefix4
= tmp
.u
.prefix4
;
768 listnode_add(*hello_option_addr_list
, p
);
771 } /* while (addr < pastend) */
776 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_ADDRESS_LIST
);