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 along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 #define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV4
35 #define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV6
38 uint8_t *pim_tlv_append_uint16(uint8_t *buf
, const uint8_t *buf_pastend
,
39 uint16_t option_type
, uint16_t option_value
)
41 uint16_t option_len
= 2;
43 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
46 *(uint16_t *)buf
= htons(option_type
);
48 *(uint16_t *)buf
= htons(option_len
);
50 *(uint16_t *)buf
= htons(option_value
);
56 uint8_t *pim_tlv_append_2uint16(uint8_t *buf
, const uint8_t *buf_pastend
,
57 uint16_t option_type
, uint16_t option_value1
,
58 uint16_t option_value2
)
60 uint16_t option_len
= 4;
62 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
65 *(uint16_t *)buf
= htons(option_type
);
67 *(uint16_t *)buf
= htons(option_len
);
69 *(uint16_t *)buf
= htons(option_value1
);
71 *(uint16_t *)buf
= htons(option_value2
);
77 uint8_t *pim_tlv_append_uint32(uint8_t *buf
, const uint8_t *buf_pastend
,
78 uint16_t option_type
, uint32_t option_value
)
80 uint16_t option_len
= 4;
82 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
85 *(uint16_t *)buf
= htons(option_type
);
87 *(uint16_t *)buf
= htons(option_len
);
89 pim_write_uint32(buf
, option_value
);
95 #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
96 #define ucast_ipv6_encoding_len (2 + sizeof(struct in6_addr))
99 * An Encoded-Unicast address takes the following format:
102 * 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
103 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104 * | Addr Family | Encoding Type | Unicast Address
105 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
108 * The PIM address family of the 'Unicast Address' field of this
111 * Values 0-127 are as assigned by the IANA for Internet Address *
112 * 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
126 int pim_encode_addr_ucast(uint8_t *buf
, pim_addr addr
)
128 uint8_t *start
= buf
;
131 *buf
++ = PIM_MSG_ADDRESS_FAMILY_IPV4
;
133 *buf
++ = PIM_MSG_ADDRESS_FAMILY_IPV6
;
136 memcpy(buf
, &addr
, sizeof(addr
));
142 int pim_encode_addr_ucast_prefix(uint8_t *buf
, struct prefix
*p
)
146 *buf
= PIM_MSG_ADDRESS_FAMILY_IPV4
; /* notice: AF_INET !=
147 PIM_MSG_ADDRESS_FAMILY_IPV4
150 *buf
= 0; /* ucast IPv4 native encoding type (RFC
153 memcpy(buf
, &p
->u
.prefix4
, sizeof(struct in_addr
));
154 return ucast_ipv4_encoding_len
;
156 *buf
= PIM_MSG_ADDRESS_FAMILY_IPV6
;
160 memcpy(buf
, &p
->u
.prefix6
, sizeof(struct in6_addr
));
161 return ucast_ipv6_encoding_len
;
167 #define group_ipv4_encoding_len (4 + sizeof(struct in_addr))
170 * Encoded-Group addresses take the following format:
173 * 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
174 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
175 * | Addr Family | Encoding Type |B| Reserved |Z| Mask Len |
176 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
177 * | Group multicast Address
178 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
186 * [B]idirectional PIM
187 * Indicates the group range should use Bidirectional PIM [13].
188 * For PIM-SM defined in this specification, this bit MUST be zero.
191 * Transmitted as zero. Ignored upon receipt.
194 * indicates the group range is an admin scope zone. This is used
195 * in the Bootstrap Router Mechanism [11] only. For all other
196 * purposes, this bit is set to zero and ignored on receipt.
199 * The Mask length field is 8 bits. The value is the number of
200 * contiguous one bits that are left justified and used as a mask;
201 * when combined with the group address, it describes a range of
202 * groups. It is less than or equal to the address length in bits
203 * for the given Address Family and Encoding Type. If the message
204 * is sent for a single group, then the Mask length must equal the
205 * address length in bits for the given Address Family and Encoding
206 * Type (e.g., 32 for IPv4 native encoding, 128 for IPv6 native
209 * Group multicast Address
210 * Contains the group address.
212 int pim_encode_addr_group(uint8_t *buf
, afi_t afi
, int bidir
, int scope
,
215 uint8_t *start
= buf
;
221 *buf
++ = PIM_MSG_ADDRESS_FAMILY
;
224 *buf
++ = sizeof(group
) / 8;
225 memcpy(buf
, &group
, sizeof(group
));
226 buf
+= sizeof(group
);
231 uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf
, const uint8_t *buf_pastend
,
232 struct list
*ifconnected
, int family
)
234 struct listnode
*node
;
235 uint16_t option_len
= 0;
239 node
= listhead(ifconnected
);
241 /* Empty address list ? */
246 if (family
== AF_INET
)
247 uel
= ucast_ipv4_encoding_len
;
249 uel
= ucast_ipv6_encoding_len
;
251 /* Scan secondary address list */
252 curr
= buf
+ 4; /* skip T and L */
253 for (; node
; node
= listnextnode(node
)) {
254 struct connected
*ifc
= listgetdata(node
);
255 struct prefix
*p
= ifc
->address
;
258 if (!CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
261 if ((curr
+ uel
) > buf_pastend
)
264 if (p
->family
!= family
)
267 l_encode
= pim_encode_addr_ucast_prefix(curr
, p
);
269 option_len
+= l_encode
;
272 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
274 "%s: number of encoded secondary unicast IPv4 addresses: %zu",
275 __func__
, option_len
/ uel
);
278 if (option_len
< 1) {
279 /* Empty secondary unicast IPv4 address list */
286 *(uint16_t *)buf
= htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST
);
287 *(uint16_t *)(buf
+ 2) = htons(option_len
);
292 static int check_tlv_length(const char *label
, const char *tlv_name
,
293 const char *ifname
, pim_addr src_addr
,
294 int correct_len
, int option_len
)
296 if (option_len
!= correct_len
) {
298 "%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %pPAs on interface %s",
299 label
, tlv_name
, option_len
, correct_len
, &src_addr
,
307 static void check_tlv_redefinition_uint16(const char *label
,
308 const char *tlv_name
,
309 const char *ifname
, pim_addr src_addr
,
310 pim_hello_options options
,
311 pim_hello_options opt_mask
,
312 uint16_t new, uint16_t old
)
314 if (PIM_OPTION_IS_SET(options
, opt_mask
))
316 "%s: PIM hello TLV redefined %s=%u old=%u from %pPAs on interface %s",
317 label
, tlv_name
, new, old
, &src_addr
, ifname
);
320 static void check_tlv_redefinition_uint32(const char *label
,
321 const char *tlv_name
,
322 const char *ifname
, pim_addr src_addr
,
323 pim_hello_options options
,
324 pim_hello_options opt_mask
,
325 uint32_t new, uint32_t old
)
327 if (PIM_OPTION_IS_SET(options
, opt_mask
))
329 "%s: PIM hello TLV redefined %s=%u old=%u from %pPAs on interface %s",
330 label
, tlv_name
, new, old
, &src_addr
, ifname
);
333 static void check_tlv_redefinition_uint32_hex(
334 const char *label
, const char *tlv_name
, const char *ifname
,
335 pim_addr src_addr
, pim_hello_options options
,
336 pim_hello_options opt_mask
, uint32_t new, uint32_t old
)
338 if (PIM_OPTION_IS_SET(options
, opt_mask
))
340 "%s: PIM hello TLV redefined %s=%08x old=%08x from %pPAs on interface %s",
341 label
, tlv_name
, new, old
, &src_addr
, ifname
);
344 int pim_tlv_parse_holdtime(const char *ifname
, pim_addr src_addr
,
345 pim_hello_options
*hello_options
,
346 uint16_t *hello_option_holdtime
, uint16_t option_len
,
347 const uint8_t *tlv_curr
)
349 const char *label
= "holdtime";
351 if (check_tlv_length(__func__
, label
, ifname
, src_addr
,
352 sizeof(uint16_t), option_len
)) {
356 check_tlv_redefinition_uint16(__func__
, label
, ifname
, src_addr
,
357 *hello_options
, PIM_OPTION_MASK_HOLDTIME
,
358 PIM_TLV_GET_HOLDTIME(tlv_curr
),
359 *hello_option_holdtime
);
361 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_HOLDTIME
);
363 *hello_option_holdtime
= PIM_TLV_GET_HOLDTIME(tlv_curr
);
368 int pim_tlv_parse_lan_prune_delay(const char *ifname
, pim_addr src_addr
,
369 pim_hello_options
*hello_options
,
370 uint16_t *hello_option_propagation_delay
,
371 uint16_t *hello_option_override_interval
,
372 uint16_t option_len
, const uint8_t *tlv_curr
)
374 if (check_tlv_length(__func__
, "lan_prune_delay", ifname
, src_addr
,
375 sizeof(uint32_t), option_len
)) {
379 check_tlv_redefinition_uint16(__func__
, "propagation_delay", ifname
,
380 src_addr
, *hello_options
,
381 PIM_OPTION_MASK_LAN_PRUNE_DELAY
,
382 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr
),
383 *hello_option_propagation_delay
);
385 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
);
387 *hello_option_propagation_delay
=
388 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr
);
389 if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr
)) {
390 PIM_OPTION_SET(*hello_options
,
391 PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
);
393 PIM_OPTION_UNSET(*hello_options
,
394 PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
);
398 *hello_option_override_interval
=
399 PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr
);
404 int pim_tlv_parse_dr_priority(const char *ifname
, pim_addr src_addr
,
405 pim_hello_options
*hello_options
,
406 uint32_t *hello_option_dr_priority
,
407 uint16_t option_len
, const uint8_t *tlv_curr
)
409 const char *label
= "dr_priority";
411 if (check_tlv_length(__func__
, label
, ifname
, src_addr
,
412 sizeof(uint32_t), option_len
)) {
416 check_tlv_redefinition_uint32(
417 __func__
, label
, ifname
, src_addr
, *hello_options
,
418 PIM_OPTION_MASK_DR_PRIORITY
, PIM_TLV_GET_DR_PRIORITY(tlv_curr
),
419 *hello_option_dr_priority
);
421 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_DR_PRIORITY
);
423 *hello_option_dr_priority
= PIM_TLV_GET_DR_PRIORITY(tlv_curr
);
428 int pim_tlv_parse_generation_id(const char *ifname
, pim_addr src_addr
,
429 pim_hello_options
*hello_options
,
430 uint32_t *hello_option_generation_id
,
431 uint16_t option_len
, const uint8_t *tlv_curr
)
433 const char *label
= "generation_id";
435 if (check_tlv_length(__func__
, label
, ifname
, src_addr
,
436 sizeof(uint32_t), option_len
)) {
440 check_tlv_redefinition_uint32_hex(__func__
, label
, ifname
, src_addr
,
442 PIM_OPTION_MASK_GENERATION_ID
,
443 PIM_TLV_GET_GENERATION_ID(tlv_curr
),
444 *hello_option_generation_id
);
446 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_GENERATION_ID
);
448 *hello_option_generation_id
= PIM_TLV_GET_GENERATION_ID(tlv_curr
);
453 int pim_parse_addr_ucast_prefix(struct prefix
*p
, const uint8_t *buf
,
456 const int ucast_encoding_min_len
= 3; /* 1 family + 1 type + 1 addr */
458 const uint8_t *pastend
;
462 if (buf_size
< ucast_encoding_min_len
) {
464 "%s: unicast address encoding overflow: left=%d needed=%d",
465 __func__
, buf_size
, ucast_encoding_min_len
);
470 pastend
= buf
+ buf_size
;
476 zlog_warn("%s: unknown unicast address encoding type=%d",
482 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
483 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
485 "%s: IPv4 unicast address overflow: left=%td needed=%zu",
486 __func__
, pastend
- addr
,
487 sizeof(struct in_addr
));
491 p
->family
= AF_INET
; /* notice: AF_INET !=
492 PIM_MSG_ADDRESS_FAMILY_IPV4 */
493 memcpy(&p
->u
.prefix4
, addr
, sizeof(struct in_addr
));
494 p
->prefixlen
= IPV4_MAX_BITLEN
;
495 addr
+= sizeof(struct in_addr
);
498 case PIM_MSG_ADDRESS_FAMILY_IPV6
:
499 if ((addr
+ sizeof(struct in6_addr
)) > pastend
) {
501 "%s: IPv6 unicast address overflow: left=%td needed %zu",
502 __func__
, pastend
- addr
,
503 sizeof(struct in6_addr
));
507 p
->family
= AF_INET6
;
508 p
->prefixlen
= IPV6_MAX_BITLEN
;
509 memcpy(&p
->u
.prefix6
, addr
, sizeof(struct in6_addr
));
510 addr
+= sizeof(struct in6_addr
);
514 zlog_warn("%s: unknown unicast address encoding family=%d from",
523 int pim_parse_addr_ucast(pim_addr
*out
, const uint8_t *buf
, int buf_size
,
529 ret
= pim_parse_addr_ucast_prefix(&p
, buf
, buf_size
);
533 if (p
.family
!= PIM_AF
) {
538 memcpy(out
, &p
.u
.val
, sizeof(*out
));
542 int pim_parse_addr_group(pim_sgaddr
*sg
, const uint8_t *buf
, int buf_size
)
544 const int grp_encoding_min_len
=
545 4; /* 1 family + 1 type + 1 reserved + 1 addr */
547 const uint8_t *pastend
;
552 if (buf_size
< grp_encoding_min_len
) {
554 "%s: group address encoding overflow: left=%d needed=%d",
555 __func__
, buf_size
, grp_encoding_min_len
);
560 pastend
= buf
+ buf_size
;
564 ++addr
; /* skip b_reserved_z fields */
568 zlog_warn("%s: unknown group address encoding type=%d from",
573 if (family
!= PIM_MSG_ADDRESS_FAMILY
) {
575 "%s: unknown group address encoding family=%d mask_len=%d from",
576 __func__
, family
, mask_len
);
580 if ((addr
+ sizeof(sg
->grp
)) > pastend
) {
582 "%s: group address overflow: left=%td needed=%zu from",
583 __func__
, pastend
- addr
, sizeof(sg
->grp
));
587 memcpy(&sg
->grp
, addr
, sizeof(sg
->grp
));
588 addr
+= sizeof(sg
->grp
);
593 int pim_parse_addr_source(pim_sgaddr
*sg
, uint8_t *flags
, const uint8_t *buf
,
596 const int src_encoding_min_len
=
597 4; /* 1 family + 1 type + 1 reserved + 1 addr */
599 const uint8_t *pastend
;
604 if (buf_size
< src_encoding_min_len
) {
606 "%s: source address encoding overflow: left=%d needed=%d",
607 __func__
, buf_size
, src_encoding_min_len
);
612 pastend
= buf
+ buf_size
;
621 "%s: unknown source address encoding type=%d: %02x%02x%02x%02x",
622 __func__
, type
, buf
[0], buf
[1], buf
[2], buf
[3]);
627 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
628 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
630 "%s: IPv4 source address overflow: left=%td needed=%zu",
631 __func__
, pastend
- addr
,
632 sizeof(struct in_addr
));
636 memcpy(&sg
->src
, addr
, sizeof(struct in_addr
));
639 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
641 Encoded-Source Address
643 The mask length MUST be equal to the mask length in bits for
644 the given Address Family and Encoding Type (32 for IPv4
646 and 128 for IPv6 native). A router SHOULD ignore any
648 received with any other mask length.
650 if (mask_len
!= IPV4_MAX_BITLEN
) {
651 zlog_warn("%s: IPv4 bad source address mask: %d",
656 addr
+= sizeof(struct in_addr
);
661 "%s: unknown source address encoding family=%d: %02x%02x%02x%02x",
662 __func__
, family
, buf
[0], buf
[1], buf
[2], buf
[3]);
670 #define FREE_ADDR_LIST(hello_option_addr_list) \
672 if (hello_option_addr_list) { \
673 list_delete(&hello_option_addr_list); \
674 hello_option_addr_list = 0; \
678 int pim_tlv_parse_addr_list(const char *ifname
, pim_addr src_addr
,
679 pim_hello_options
*hello_options
,
680 struct list
**hello_option_addr_list
,
681 uint16_t option_len
, const uint8_t *tlv_curr
)
684 const uint8_t *pastend
;
686 assert(hello_option_addr_list
);
692 pastend
= tlv_curr
+ option_len
;
693 while (addr
< pastend
) {
694 struct prefix tmp
, src_pfx
;
701 pim_parse_addr_ucast_prefix(&tmp
, addr
, pastend
- addr
);
702 if (addr_offset
< 1) {
704 "%s: pim_parse_addr_ucast() failure: from %pPAs on %s",
705 __func__
, &src_addr
, ifname
);
706 FREE_ADDR_LIST(*hello_option_addr_list
);
714 if (PIM_DEBUG_PIM_TRACE
) {
715 switch (tmp
.family
) {
717 char addr_str
[INET_ADDRSTRLEN
];
718 pim_inet4_dump("<addr?>", tmp
.u
.prefix4
,
719 addr_str
, sizeof(addr_str
));
721 "%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %pPAs on %s",
723 *hello_option_addr_list
725 *hello_option_addr_list
))
727 addr_str
, &src_addr
, ifname
);
733 "%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %pPAs on %s",
735 *hello_option_addr_list
737 *hello_option_addr_list
))
744 Exclude neighbor's primary address if incorrectly included in
745 the secondary address list
747 pim_addr_to_prefix(&src_pfx
, src_addr
);
748 if (!prefix_cmp(&tmp
, &src_pfx
)) {
750 "%s: ignoring primary address in secondary list from %pPAs on %s",
751 __func__
, &src_addr
, ifname
);
756 Allocate list if needed
758 if (!*hello_option_addr_list
) {
759 *hello_option_addr_list
= list_new();
760 (*hello_option_addr_list
)->del
= prefix_free_lists
;
769 prefix_copy(p
, &tmp
);
770 listnode_add(*hello_option_addr_list
, p
);
773 } /* while (addr < pastend) */
778 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_ADDRESS_LIST
);