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
32 uint8_t *pim_tlv_append_uint16(uint8_t *buf
, const uint8_t *buf_pastend
,
33 uint16_t option_type
, uint16_t option_value
)
35 uint16_t option_len
= 2;
37 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
40 *(uint16_t *)buf
= htons(option_type
);
42 *(uint16_t *)buf
= htons(option_len
);
44 *(uint16_t *)buf
= htons(option_value
);
50 uint8_t *pim_tlv_append_2uint16(uint8_t *buf
, const uint8_t *buf_pastend
,
51 uint16_t option_type
, uint16_t option_value1
,
52 uint16_t option_value2
)
54 uint16_t option_len
= 4;
56 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
59 *(uint16_t *)buf
= htons(option_type
);
61 *(uint16_t *)buf
= htons(option_len
);
63 *(uint16_t *)buf
= htons(option_value1
);
65 *(uint16_t *)buf
= htons(option_value2
);
71 uint8_t *pim_tlv_append_uint32(uint8_t *buf
, const uint8_t *buf_pastend
,
72 uint16_t option_type
, uint32_t option_value
)
74 uint16_t option_len
= 4;
76 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
79 *(uint16_t *)buf
= htons(option_type
);
81 *(uint16_t *)buf
= htons(option_len
);
83 pim_write_uint32(buf
, option_value
);
89 #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
90 #define ucast_ipv6_encoding_len (2 + sizeof(struct in6_addr))
93 * An Encoded-Unicast address takes the following format:
96 * 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
97 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
98 * | Addr Family | Encoding Type | Unicast Address
99 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
102 * The PIM address family of the 'Unicast Address' field of this
105 * Values 0-127 are as assigned by the IANA for Internet Address *
106 * Families in [7]. Values 128-250 are reserved to be assigned by
107 * the IANA for PIM-specific Address Families. Values 251 though
108 * 255 are designated for private use. As there is no assignment
109 * authority for this space, collisions should be expected.
112 * The type of encoding used within a specific Address Family. The
113 * value '0' is reserved for this field and represents the native
114 * encoding of the Address Family.
117 * The unicast address as represented by the given Address Family
120 int pim_encode_addr_ucast(uint8_t *buf
, struct prefix
*p
)
125 PIM_MSG_ADDRESS_FAMILY_IPV4
; /* notice: AF_INET !=
126 PIM_MSG_ADDRESS_FAMILY_IPV4
129 *(uint8_t *)buf
= 0; /* ucast IPv4 native encoding type (RFC
132 memcpy(buf
, &p
->u
.prefix4
, sizeof(struct in_addr
));
133 return ucast_ipv4_encoding_len
;
135 *(uint8_t *)buf
= PIM_MSG_ADDRESS_FAMILY_IPV6
;
139 memcpy(buf
, &p
->u
.prefix6
, sizeof(struct in6_addr
));
140 return ucast_ipv6_encoding_len
;
146 #define group_ipv4_encoding_len (4 + sizeof(struct in_addr))
149 * Encoded-Group addresses take the following format:
152 * 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
153 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
154 * | Addr Family | Encoding Type |B| Reserved |Z| Mask Len |
155 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
156 * | Group multicast Address
157 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
165 * [B]idirectional PIM
166 * Indicates the group range should use Bidirectional PIM [13].
167 * For PIM-SM defined in this specification, this bit MUST be zero.
170 * Transmitted as zero. Ignored upon receipt.
173 * indicates the group range is an admin scope zone. This is used
174 * in the Bootstrap Router Mechanism [11] only. For all other
175 * purposes, this bit is set to zero and ignored on receipt.
178 * The Mask length field is 8 bits. The value is the number of
179 * contiguous one bits that are left justified and used as a mask;
180 * when combined with the group address, it describes a range of
181 * groups. It is less than or equal to the address length in bits
182 * for the given Address Family and Encoding Type. If the message
183 * is sent for a single group, then the Mask length must equal the
184 * address length in bits for the given Address Family and Encoding
185 * Type (e.g., 32 for IPv4 native encoding, 128 for IPv6 native
188 * Group multicast Address
189 * Contains the group address.
191 int pim_encode_addr_group(uint8_t *buf
, afi_t afi
, int bidir
, int scope
,
192 struct in_addr group
)
201 *(uint8_t *)buf
= PIM_MSG_ADDRESS_FAMILY_IPV4
;
205 *(uint8_t *)buf
= flags
;
207 *(uint8_t *)buf
= 32;
209 memcpy(buf
, &group
, sizeof(struct in_addr
));
210 return group_ipv4_encoding_len
;
216 uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf
, const uint8_t *buf_pastend
,
217 struct list
*ifconnected
, int family
)
219 struct listnode
*node
;
220 uint16_t option_len
= 0;
224 node
= listhead(ifconnected
);
226 /* Empty address list ? */
231 if (family
== AF_INET
)
232 uel
= ucast_ipv4_encoding_len
;
234 uel
= ucast_ipv6_encoding_len
;
236 /* Scan secondary address list */
237 curr
= buf
+ 4; /* skip T and L */
238 for (; node
; node
= listnextnode(node
)) {
239 struct connected
*ifc
= listgetdata(node
);
240 struct prefix
*p
= ifc
->address
;
243 if (!CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
246 if ((curr
+ uel
) > buf_pastend
)
249 if (p
->family
!= family
)
252 l_encode
= pim_encode_addr_ucast(curr
, p
);
254 option_len
+= l_encode
;
257 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
259 "%s: number of encoded secondary unicast IPv4 addresses: %zu",
260 __func__
, option_len
/ uel
);
263 if (option_len
< 1) {
264 /* Empty secondary unicast IPv4 address list */
271 *(uint16_t *)buf
= htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST
);
272 *(uint16_t *)(buf
+ 2) = htons(option_len
);
277 static int check_tlv_length(const char *label
, const char *tlv_name
,
278 const char *ifname
, struct in_addr src_addr
,
279 int correct_len
, int option_len
)
281 if (option_len
!= correct_len
) {
282 char src_str
[INET_ADDRSTRLEN
];
283 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
285 "%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s",
286 label
, tlv_name
, option_len
, correct_len
, src_str
,
294 static void check_tlv_redefinition_uint16(
295 const char *label
, const char *tlv_name
, const char *ifname
,
296 struct in_addr src_addr
, pim_hello_options options
,
297 pim_hello_options opt_mask
, uint16_t new, uint16_t old
)
299 if (PIM_OPTION_IS_SET(options
, opt_mask
)) {
300 char src_str
[INET_ADDRSTRLEN
];
301 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
303 "%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
304 label
, tlv_name
, new, old
, src_str
, ifname
);
308 static void check_tlv_redefinition_uint32(
309 const char *label
, const char *tlv_name
, const char *ifname
,
310 struct in_addr src_addr
, pim_hello_options options
,
311 pim_hello_options opt_mask
, uint32_t new, uint32_t old
)
313 if (PIM_OPTION_IS_SET(options
, opt_mask
)) {
314 char src_str
[INET_ADDRSTRLEN
];
315 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
317 "%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
318 label
, tlv_name
, new, old
, src_str
, ifname
);
322 static void check_tlv_redefinition_uint32_hex(
323 const char *label
, const char *tlv_name
, const char *ifname
,
324 struct in_addr src_addr
, pim_hello_options options
,
325 pim_hello_options opt_mask
, uint32_t new, uint32_t old
)
327 if (PIM_OPTION_IS_SET(options
, opt_mask
)) {
328 char src_str
[INET_ADDRSTRLEN
];
329 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
331 "%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s",
332 label
, tlv_name
, new, old
, src_str
, ifname
);
336 int pim_tlv_parse_holdtime(const char *ifname
, struct in_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
, struct in_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
, struct in_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
, struct in_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(struct prefix
*p
, const uint8_t *buf
, int buf_size
)
447 const int ucast_encoding_min_len
= 3; /* 1 family + 1 type + 1 addr */
449 const uint8_t *pastend
;
453 if (buf_size
< ucast_encoding_min_len
) {
455 "%s: unicast address encoding overflow: left=%d needed=%d",
456 __func__
, buf_size
, ucast_encoding_min_len
);
461 pastend
= buf
+ buf_size
;
467 zlog_warn("%s: unknown unicast address encoding type=%d",
473 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
474 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
476 "%s: IPv4 unicast address overflow: left=%zd needed=%zu",
477 __func__
, pastend
- addr
,
478 sizeof(struct in_addr
));
482 p
->family
= AF_INET
; /* notice: AF_INET !=
483 PIM_MSG_ADDRESS_FAMILY_IPV4 */
484 memcpy(&p
->u
.prefix4
, addr
, sizeof(struct in_addr
));
485 p
->prefixlen
= IPV4_MAX_PREFIXLEN
;
486 addr
+= sizeof(struct in_addr
);
489 case PIM_MSG_ADDRESS_FAMILY_IPV6
:
490 if ((addr
+ sizeof(struct in6_addr
)) > pastend
) {
492 "%s: IPv6 unicast address overflow: left=%zd needed %zu",
493 __func__
, pastend
- addr
,
494 sizeof(struct in6_addr
));
498 p
->family
= AF_INET6
;
499 p
->prefixlen
= IPV6_MAX_PREFIXLEN
;
500 memcpy(&p
->u
.prefix6
, addr
, sizeof(struct in6_addr
));
501 addr
+= sizeof(struct in6_addr
);
505 zlog_warn("%s: unknown unicast address encoding family=%d from",
514 int pim_parse_addr_group(struct prefix_sg
*sg
, const uint8_t *buf
, int buf_size
)
516 const int grp_encoding_min_len
=
517 4; /* 1 family + 1 type + 1 reserved + 1 addr */
519 const uint8_t *pastend
;
524 if (buf_size
< grp_encoding_min_len
) {
526 "%s: group address encoding overflow: left=%d needed=%d",
527 __func__
, buf_size
, grp_encoding_min_len
);
532 pastend
= buf
+ buf_size
;
537 ++addr
; /* skip b_reserved_z fields */
541 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
544 "%s: unknown group address encoding type=%d from",
549 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
551 "%s: IPv4 group address overflow: left=%zd needed=%zu from",
552 __func__
, pastend
- addr
,
553 sizeof(struct in_addr
));
557 memcpy(&sg
->grp
.s_addr
, addr
, sizeof(struct in_addr
));
559 addr
+= sizeof(struct in_addr
);
564 "%s: unknown group address encoding family=%d mask_len=%d from",
565 __func__
, family
, mask_len
);
573 int pim_parse_addr_source(struct prefix_sg
*sg
, uint8_t *flags
,
574 const uint8_t *buf
, int buf_size
)
576 const int src_encoding_min_len
=
577 4; /* 1 family + 1 type + 1 reserved + 1 addr */
579 const uint8_t *pastend
;
584 if (buf_size
< src_encoding_min_len
) {
586 "%s: source address encoding overflow: left=%d needed=%d",
587 __func__
, buf_size
, src_encoding_min_len
);
592 pastend
= buf
+ buf_size
;
601 "%s: unknown source address encoding type=%d: %02x%02x%02x%02x",
602 __func__
, type
, buf
[0], buf
[1], buf
[2], buf
[3]);
607 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
608 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
610 "%s: IPv4 source address overflow: left=%zd needed=%zu",
611 __func__
, pastend
- addr
,
612 sizeof(struct in_addr
));
616 memcpy(&sg
->src
, addr
, sizeof(struct in_addr
));
619 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
621 Encoded-Source Address
623 The mask length MUST be equal to the mask length in bits for
624 the given Address Family and Encoding Type (32 for IPv4
626 and 128 for IPv6 native). A router SHOULD ignore any
628 received with any other mask length.
630 if (mask_len
!= 32) {
631 zlog_warn("%s: IPv4 bad source address mask: %d",
636 addr
+= sizeof(struct in_addr
);
641 "%s: unknown source address encoding family=%d: %02x%02x%02x%02x",
642 __func__
, family
, buf
[0], buf
[1], buf
[2], buf
[3]);
650 #define FREE_ADDR_LIST(hello_option_addr_list) \
652 if (hello_option_addr_list) { \
653 list_delete(&hello_option_addr_list); \
654 hello_option_addr_list = 0; \
658 int pim_tlv_parse_addr_list(const char *ifname
, struct in_addr src_addr
,
659 pim_hello_options
*hello_options
,
660 struct list
**hello_option_addr_list
,
661 uint16_t option_len
, const uint8_t *tlv_curr
)
664 const uint8_t *pastend
;
666 zassert(hello_option_addr_list
);
672 pastend
= tlv_curr
+ option_len
;
673 while (addr
< pastend
) {
680 addr_offset
= pim_parse_addr_ucast(&tmp
, addr
, pastend
- addr
);
681 if (addr_offset
< 1) {
682 char src_str
[INET_ADDRSTRLEN
];
683 pim_inet4_dump("<src?>", src_addr
, src_str
,
686 "%s: pim_parse_addr_ucast() failure: from %s on %s",
687 __func__
, src_str
, ifname
);
688 FREE_ADDR_LIST(*hello_option_addr_list
);
696 if (PIM_DEBUG_PIM_TRACE
) {
697 switch (tmp
.family
) {
699 char addr_str
[INET_ADDRSTRLEN
];
700 char src_str
[INET_ADDRSTRLEN
];
701 pim_inet4_dump("<addr?>", tmp
.u
.prefix4
,
702 addr_str
, sizeof(addr_str
));
703 pim_inet4_dump("<src?>", src_addr
, src_str
,
706 "%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
708 *hello_option_addr_list
710 *hello_option_addr_list
))
712 addr_str
, src_str
, ifname
);
717 char src_str
[INET_ADDRSTRLEN
];
718 pim_inet4_dump("<src?>", src_addr
, src_str
,
721 "%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
723 *hello_option_addr_list
725 *hello_option_addr_list
))
733 Exclude neighbor's primary address if incorrectly included in
734 the secondary address list
736 if (tmp
.family
== AF_INET
) {
737 if (tmp
.u
.prefix4
.s_addr
== src_addr
.s_addr
) {
738 char src_str
[INET_ADDRSTRLEN
];
739 pim_inet4_dump("<src?>", src_addr
, src_str
,
742 "%s: ignoring primary address in secondary list from %s on %s",
743 __func__
, src_str
, ifname
);
749 Allocate list if needed
751 if (!*hello_option_addr_list
) {
752 *hello_option_addr_list
= list_new();
753 (*hello_option_addr_list
)->del
= prefix_free_lists
;
762 prefix_copy(p
, &tmp
);
763 listnode_add(*hello_option_addr_list
, p
);
766 } /* while (addr < pastend) */
771 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_ADDRESS_LIST
);