1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2008 Everton da Silva Marques
14 #include "pim_instance.h"
19 #include "pim_iface.h"
23 #define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV4
25 #define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV6
28 uint8_t *pim_tlv_append_uint16(uint8_t *buf
, const uint8_t *buf_pastend
,
29 uint16_t option_type
, uint16_t option_value
)
31 uint16_t option_len
= 2;
33 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
36 *(uint16_t *)buf
= htons(option_type
);
38 *(uint16_t *)buf
= htons(option_len
);
40 *(uint16_t *)buf
= htons(option_value
);
46 uint8_t *pim_tlv_append_2uint16(uint8_t *buf
, const uint8_t *buf_pastend
,
47 uint16_t option_type
, uint16_t option_value1
,
48 uint16_t option_value2
)
50 uint16_t option_len
= 4;
52 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
55 *(uint16_t *)buf
= htons(option_type
);
57 *(uint16_t *)buf
= htons(option_len
);
59 *(uint16_t *)buf
= htons(option_value1
);
61 *(uint16_t *)buf
= htons(option_value2
);
67 uint8_t *pim_tlv_append_uint32(uint8_t *buf
, const uint8_t *buf_pastend
,
68 uint16_t option_type
, uint32_t option_value
)
70 uint16_t option_len
= 4;
72 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
75 *(uint16_t *)buf
= htons(option_type
);
77 *(uint16_t *)buf
= htons(option_len
);
79 pim_write_uint32(buf
, option_value
);
85 #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
86 #define ucast_ipv6_encoding_len (2 + sizeof(struct in6_addr))
89 * An Encoded-Unicast address takes the following format:
92 * 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
93 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
94 * | Addr Family | Encoding Type | Unicast Address
95 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
98 * The PIM address family of the 'Unicast Address' field of this
101 * Values 0-127 are as assigned by the IANA for Internet Address *
102 * Families in [7]. Values 128-250 are reserved to be assigned by
103 * the IANA for PIM-specific Address Families. Values 251 though
104 * 255 are designated for private use. As there is no assignment
105 * authority for this space, collisions should be expected.
108 * The type of encoding used within a specific Address Family. The
109 * value '0' is reserved for this field and represents the native
110 * encoding of the Address Family.
113 * The unicast address as represented by the given Address Family
116 int pim_encode_addr_ucast(uint8_t *buf
, pim_addr addr
)
118 uint8_t *start
= buf
;
120 *buf
++ = PIM_MSG_ADDRESS_FAMILY
;
122 memcpy(buf
, &addr
, sizeof(addr
));
128 int pim_encode_addr_ucast_prefix(uint8_t *buf
, struct prefix
*p
)
132 *buf
= PIM_MSG_ADDRESS_FAMILY_IPV4
; /* notice: AF_INET !=
133 PIM_MSG_ADDRESS_FAMILY_IPV4
136 *buf
= 0; /* ucast IPv4 native encoding type (RFC
139 memcpy(buf
, &p
->u
.prefix4
, sizeof(struct in_addr
));
140 return ucast_ipv4_encoding_len
;
142 *buf
= PIM_MSG_ADDRESS_FAMILY_IPV6
;
146 memcpy(buf
, &p
->u
.prefix6
, sizeof(struct in6_addr
));
147 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.
198 int pim_encode_addr_group(uint8_t *buf
, afi_t afi
, int bidir
, int scope
,
201 uint8_t *start
= buf
;
207 *buf
++ = PIM_MSG_ADDRESS_FAMILY
;
210 *buf
++ = sizeof(group
) * 8;
211 memcpy(buf
, &group
, sizeof(group
));
212 buf
+= sizeof(group
);
217 uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf
, const uint8_t *buf_pastend
,
218 struct interface
*ifp
, int family
)
220 struct listnode
*node
;
221 uint16_t option_len
= 0;
224 struct list
*ifconnected
= ifp
->connected
;
225 struct pim_interface
*pim_ifp
= ifp
->info
;
228 node
= listhead(ifconnected
);
230 /* Empty address list ? */
235 if (family
== AF_INET
)
236 uel
= ucast_ipv4_encoding_len
;
238 uel
= ucast_ipv6_encoding_len
;
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 addr
= pim_addr_from_prefix(p
);
248 if (!pim_addr_cmp(pim_ifp
->primary_address
, addr
))
249 /* don't add the primary address
250 * into the secondary address list */
253 if ((curr
+ uel
) > buf_pastend
)
256 if (p
->family
!= family
)
259 l_encode
= pim_encode_addr_ucast_prefix(curr
, p
);
261 option_len
+= l_encode
;
264 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
266 "%s: number of encoded secondary unicast IPv4 addresses: %zu",
267 __func__
, option_len
/ uel
);
270 if (option_len
< 1) {
271 /* Empty secondary unicast IPv4 address list */
278 *(uint16_t *)buf
= htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST
);
279 *(uint16_t *)(buf
+ 2) = htons(option_len
);
284 static int check_tlv_length(const char *label
, const char *tlv_name
,
285 const char *ifname
, pim_addr src_addr
,
286 int correct_len
, int option_len
)
288 if (option_len
!= correct_len
) {
290 "%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %pPAs on interface %s",
291 label
, tlv_name
, option_len
, correct_len
, &src_addr
,
299 static void check_tlv_redefinition_uint16(const char *label
,
300 const char *tlv_name
,
301 const char *ifname
, pim_addr src_addr
,
302 pim_hello_options options
,
303 pim_hello_options opt_mask
,
304 uint16_t new, uint16_t old
)
306 if (PIM_OPTION_IS_SET(options
, opt_mask
))
308 "%s: PIM hello TLV redefined %s=%u old=%u from %pPAs on interface %s",
309 label
, tlv_name
, new, old
, &src_addr
, ifname
);
312 static void check_tlv_redefinition_uint32(const char *label
,
313 const char *tlv_name
,
314 const char *ifname
, pim_addr src_addr
,
315 pim_hello_options options
,
316 pim_hello_options opt_mask
,
317 uint32_t new, uint32_t old
)
319 if (PIM_OPTION_IS_SET(options
, opt_mask
))
321 "%s: PIM hello TLV redefined %s=%u old=%u from %pPAs on interface %s",
322 label
, tlv_name
, new, old
, &src_addr
, ifname
);
325 static void check_tlv_redefinition_uint32_hex(
326 const char *label
, const char *tlv_name
, const char *ifname
,
327 pim_addr src_addr
, pim_hello_options options
,
328 pim_hello_options opt_mask
, uint32_t new, uint32_t old
)
330 if (PIM_OPTION_IS_SET(options
, opt_mask
))
332 "%s: PIM hello TLV redefined %s=%08x old=%08x from %pPAs on interface %s",
333 label
, tlv_name
, new, old
, &src_addr
, ifname
);
336 int pim_tlv_parse_holdtime(const char *ifname
, pim_addr src_addr
,
337 pim_hello_options
*hello_options
,
338 uint16_t *hello_option_holdtime
, uint16_t option_len
,
339 const uint8_t *tlv_curr
)
341 const char *label
= "holdtime";
343 if (check_tlv_length(__func__
, label
, ifname
, src_addr
,
344 sizeof(uint16_t), option_len
)) {
348 check_tlv_redefinition_uint16(__func__
, label
, ifname
, src_addr
,
349 *hello_options
, PIM_OPTION_MASK_HOLDTIME
,
350 PIM_TLV_GET_HOLDTIME(tlv_curr
),
351 *hello_option_holdtime
);
353 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_HOLDTIME
);
355 *hello_option_holdtime
= PIM_TLV_GET_HOLDTIME(tlv_curr
);
360 int pim_tlv_parse_lan_prune_delay(const char *ifname
, pim_addr src_addr
,
361 pim_hello_options
*hello_options
,
362 uint16_t *hello_option_propagation_delay
,
363 uint16_t *hello_option_override_interval
,
364 uint16_t option_len
, const uint8_t *tlv_curr
)
366 if (check_tlv_length(__func__
, "lan_prune_delay", ifname
, src_addr
,
367 sizeof(uint32_t), option_len
)) {
371 check_tlv_redefinition_uint16(__func__
, "propagation_delay", ifname
,
372 src_addr
, *hello_options
,
373 PIM_OPTION_MASK_LAN_PRUNE_DELAY
,
374 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr
),
375 *hello_option_propagation_delay
);
377 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
);
379 *hello_option_propagation_delay
=
380 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr
);
381 if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr
)) {
382 PIM_OPTION_SET(*hello_options
,
383 PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
);
385 PIM_OPTION_UNSET(*hello_options
,
386 PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
);
390 *hello_option_override_interval
=
391 PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr
);
396 int pim_tlv_parse_dr_priority(const char *ifname
, pim_addr src_addr
,
397 pim_hello_options
*hello_options
,
398 uint32_t *hello_option_dr_priority
,
399 uint16_t option_len
, const uint8_t *tlv_curr
)
401 const char *label
= "dr_priority";
403 if (check_tlv_length(__func__
, label
, ifname
, src_addr
,
404 sizeof(uint32_t), option_len
)) {
408 check_tlv_redefinition_uint32(
409 __func__
, label
, ifname
, src_addr
, *hello_options
,
410 PIM_OPTION_MASK_DR_PRIORITY
, PIM_TLV_GET_DR_PRIORITY(tlv_curr
),
411 *hello_option_dr_priority
);
413 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_DR_PRIORITY
);
415 *hello_option_dr_priority
= PIM_TLV_GET_DR_PRIORITY(tlv_curr
);
420 int pim_tlv_parse_generation_id(const char *ifname
, pim_addr src_addr
,
421 pim_hello_options
*hello_options
,
422 uint32_t *hello_option_generation_id
,
423 uint16_t option_len
, const uint8_t *tlv_curr
)
425 const char *label
= "generation_id";
427 if (check_tlv_length(__func__
, label
, ifname
, src_addr
,
428 sizeof(uint32_t), option_len
)) {
432 check_tlv_redefinition_uint32_hex(__func__
, label
, ifname
, src_addr
,
434 PIM_OPTION_MASK_GENERATION_ID
,
435 PIM_TLV_GET_GENERATION_ID(tlv_curr
),
436 *hello_option_generation_id
);
438 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_GENERATION_ID
);
440 *hello_option_generation_id
= PIM_TLV_GET_GENERATION_ID(tlv_curr
);
445 int pim_parse_addr_ucast_prefix(struct prefix
*p
, const uint8_t *buf
,
448 const int ucast_encoding_min_len
= 3; /* 1 family + 1 type + 1 addr */
450 const uint8_t *pastend
;
454 if (buf_size
< ucast_encoding_min_len
) {
456 "%s: unicast address encoding overflow: left=%d needed=%d",
457 __func__
, buf_size
, ucast_encoding_min_len
);
462 pastend
= buf
+ buf_size
;
468 zlog_warn("%s: unknown unicast address encoding type=%d",
474 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
475 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
477 "%s: IPv4 unicast address overflow: left=%td needed=%zu",
478 __func__
, pastend
- addr
,
479 sizeof(struct in_addr
));
483 p
->family
= AF_INET
; /* notice: AF_INET !=
484 PIM_MSG_ADDRESS_FAMILY_IPV4 */
485 memcpy(&p
->u
.prefix4
, addr
, sizeof(struct in_addr
));
486 p
->prefixlen
= IPV4_MAX_BITLEN
;
487 addr
+= sizeof(struct in_addr
);
490 case PIM_MSG_ADDRESS_FAMILY_IPV6
:
491 if ((addr
+ sizeof(struct in6_addr
)) > pastend
) {
493 "%s: IPv6 unicast address overflow: left=%td needed %zu",
494 __func__
, pastend
- addr
,
495 sizeof(struct in6_addr
));
499 p
->family
= AF_INET6
;
500 p
->prefixlen
= IPV6_MAX_BITLEN
;
501 memcpy(&p
->u
.prefix6
, addr
, sizeof(struct in6_addr
));
502 addr
+= sizeof(struct in6_addr
);
506 zlog_warn("%s: unknown unicast address encoding family=%d from",
515 int pim_parse_addr_ucast(pim_addr
*out
, const uint8_t *buf
, int buf_size
,
521 ret
= pim_parse_addr_ucast_prefix(&p
, buf
, buf_size
);
525 if (p
.family
!= PIM_AF
) {
530 memcpy(out
, &p
.u
.val
, sizeof(*out
));
534 int pim_parse_addr_group(pim_sgaddr
*sg
, const uint8_t *buf
, int buf_size
)
536 const int grp_encoding_min_len
=
537 4; /* 1 family + 1 type + 1 reserved + 1 addr */
539 const uint8_t *pastend
;
544 if (buf_size
< grp_encoding_min_len
) {
546 "%s: group address encoding overflow: left=%d needed=%d",
547 __func__
, buf_size
, grp_encoding_min_len
);
552 pastend
= buf
+ buf_size
;
556 ++addr
; /* skip b_reserved_z fields */
560 zlog_warn("%s: unknown group address encoding type=%d from",
565 if (family
!= PIM_MSG_ADDRESS_FAMILY
) {
567 "%s: unknown group address encoding family=%d mask_len=%d from",
568 __func__
, family
, mask_len
);
572 if ((addr
+ sizeof(sg
->grp
)) > pastend
) {
574 "%s: group address overflow: left=%td needed=%zu from",
575 __func__
, pastend
- addr
, sizeof(sg
->grp
));
579 memcpy(&sg
->grp
, addr
, sizeof(sg
->grp
));
580 addr
+= sizeof(sg
->grp
);
585 int pim_parse_addr_source(pim_sgaddr
*sg
, uint8_t *flags
, const uint8_t *buf
,
588 const int src_encoding_min_len
=
589 4; /* 1 family + 1 type + 1 reserved + 1 addr */
591 const uint8_t *pastend
;
596 if (buf_size
< src_encoding_min_len
) {
598 "%s: source address encoding overflow: left=%d needed=%d",
599 __func__
, buf_size
, src_encoding_min_len
);
604 pastend
= buf
+ buf_size
;
613 "%s: unknown source address encoding type=%d: %02x%02x%02x%02x",
614 __func__
, type
, buf
[0], buf
[1], buf
[2], buf
[3]);
619 case PIM_MSG_ADDRESS_FAMILY
:
620 if ((addr
+ sizeof(sg
->src
)) > pastend
) {
622 "%s: IP source address overflow: left=%td needed=%zu",
623 __func__
, pastend
- addr
, sizeof(sg
->src
));
627 memcpy(&sg
->src
, addr
, sizeof(sg
->src
));
630 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
632 Encoded-Source Address
634 The mask length MUST be equal to the mask length in bits for
635 the given Address Family and Encoding Type (32 for IPv4
636 native and 128 for IPv6 native). A router SHOULD ignore any
637 messages received with any other mask length.
639 if (mask_len
!= PIM_MAX_BITLEN
) {
640 zlog_warn("%s: IP bad source address mask: %d",
645 addr
+= sizeof(sg
->src
);
650 "%s: unknown source address encoding family=%d: %02x%02x%02x%02x",
651 __func__
, family
, buf
[0], buf
[1], buf
[2], buf
[3]);
658 #define FREE_ADDR_LIST(hello_option_addr_list) \
660 if (hello_option_addr_list) { \
661 list_delete(&hello_option_addr_list); \
662 hello_option_addr_list = 0; \
666 int pim_tlv_parse_addr_list(const char *ifname
, pim_addr src_addr
,
667 pim_hello_options
*hello_options
,
668 struct list
**hello_option_addr_list
,
669 uint16_t option_len
, const uint8_t *tlv_curr
)
672 const uint8_t *pastend
;
674 assert(hello_option_addr_list
);
680 pastend
= tlv_curr
+ option_len
;
681 while (addr
< pastend
) {
682 struct prefix tmp
, src_pfx
;
689 pim_parse_addr_ucast_prefix(&tmp
, addr
, pastend
- addr
);
690 if (addr_offset
< 1) {
692 "%s: pim_parse_addr_ucast() failure: from %pPAs on %s",
693 __func__
, &src_addr
, ifname
);
694 FREE_ADDR_LIST(*hello_option_addr_list
);
702 if (PIM_DEBUG_PIM_TRACE
) {
703 switch (tmp
.family
) {
705 char addr_str
[INET_ADDRSTRLEN
];
706 pim_inet4_dump("<addr?>", tmp
.u
.prefix4
,
707 addr_str
, sizeof(addr_str
));
709 "%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %pPAs on %s",
711 *hello_option_addr_list
713 *hello_option_addr_list
))
715 addr_str
, &src_addr
, ifname
);
721 "%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %pPAs on %s",
723 *hello_option_addr_list
725 *hello_option_addr_list
))
732 Exclude neighbor's primary address if incorrectly included in
733 the secondary address list
735 pim_addr_to_prefix(&src_pfx
, src_addr
);
736 if (!prefix_cmp(&tmp
, &src_pfx
)) {
738 "%s: ignoring primary address in secondary list from %pPAs on %s",
739 __func__
, &src_addr
, ifname
);
744 Allocate list if needed
746 if (!*hello_option_addr_list
) {
747 *hello_option_addr_list
= list_new();
748 (*hello_option_addr_list
)->del
= prefix_free_lists
;
757 prefix_copy(p
, &tmp
);
758 listnode_add(*hello_option_addr_list
, p
);
761 } /* while (addr < pastend) */
766 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_ADDRESS_LIST
);