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
,
33 const uint8_t *buf_pastend
,
35 uint16_t option_value
)
37 uint16_t option_len
= 2;
39 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
42 *(uint16_t *) buf
= htons(option_type
);
44 *(uint16_t *) buf
= htons(option_len
);
46 *(uint16_t *) buf
= htons(option_value
);
52 uint8_t *pim_tlv_append_2uint16(uint8_t *buf
,
53 const uint8_t *buf_pastend
,
55 uint16_t option_value1
,
56 uint16_t option_value2
)
58 uint16_t option_len
= 4;
60 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
63 *(uint16_t *) buf
= htons(option_type
);
65 *(uint16_t *) buf
= htons(option_len
);
67 *(uint16_t *) buf
= htons(option_value1
);
69 *(uint16_t *) buf
= htons(option_value2
);
75 uint8_t *pim_tlv_append_uint32(uint8_t *buf
,
76 const uint8_t *buf_pastend
,
78 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 * Families in [7]. Values 128-250 are reserved to be assigned by
112 * the IANA for PIM-specific Address Families. Values 251 though
113 * 255 are designated for private use. As there is no assignment
114 * authority for this space, collisions should be expected.
117 * The type of encoding used within a specific Address Family. The
118 * value '0' is reserved for this field and represents the native
119 * encoding of the Address Family.
122 * The unicast address as represented by the given Address Family
126 pim_encode_addr_ucast (uint8_t *buf
, struct prefix
*p
)
131 *(uint8_t *)buf
= PIM_MSG_ADDRESS_FAMILY_IPV4
; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
133 *(uint8_t *)buf
= 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */
135 memcpy (buf
, &p
->u
.prefix4
, sizeof (struct in_addr
));
136 return ucast_ipv4_encoding_len
;
139 *(uint8_t *)buf
= PIM_MSG_ADDRESS_FAMILY_IPV6
;
143 memcpy (buf
, &p
->u
.prefix6
, sizeof (struct in6_addr
));
144 return ucast_ipv6_encoding_len
;
152 #define group_ipv4_encoding_len (4 + sizeof (struct in_addr))
155 * Encoded-Group addresses take the following format:
158 * 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
159 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
160 * | Addr Family | Encoding Type |B| Reserved |Z| Mask Len |
161 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
162 * | Group multicast Address
163 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
171 * [B]idirectional PIM
172 * Indicates the group range should use Bidirectional PIM [13].
173 * For PIM-SM defined in this specification, this bit MUST be zero.
176 * Transmitted as zero. Ignored upon receipt.
179 * indicates the group range is an admin scope zone. This is used
180 * in the Bootstrap Router Mechanism [11] only. For all other
181 * purposes, this bit is set to zero and ignored on receipt.
184 * The Mask length field is 8 bits. The value is the number of
185 * contiguous one bits that are left justified and used as a mask;
186 * when combined with the group address, it describes a range of
187 * groups. It is less than or equal to the address length in bits
188 * for the given Address Family and Encoding Type. If the message
189 * is sent for a single group, then the Mask length must equal the
190 * address length in bits for the given Address Family and Encoding
191 * Type (e.g., 32 for IPv4 native encoding, 128 for IPv6 native
194 * Group multicast Address
195 * Contains the group address.
198 pim_encode_addr_group (uint8_t *buf
, afi_t afi
, int bidir
, int scope
, struct in_addr group
)
208 *(uint8_t *)buf
= PIM_MSG_ADDRESS_FAMILY_IPV4
;
212 *(uint8_t *)buf
= flags
;
214 *(uint8_t *)buf
= 32;
216 memcpy (buf
, &group
, sizeof (struct in_addr
));
217 return group_ipv4_encoding_len
;
225 uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf
,
226 const uint8_t *buf_pastend
,
227 struct list
*ifconnected
,
230 struct listnode
*node
;
231 uint16_t option_len
= 0;
235 node
= listhead(ifconnected
);
237 /* Empty address list ? */
242 if (family
== AF_INET
)
243 uel
= ucast_ipv4_encoding_len
;
245 uel
= ucast_ipv6_encoding_len
;
247 /* Scan secondary address list */
248 curr
= buf
+ 4; /* skip T and L */
249 for (; node
; node
= listnextnode(node
)) {
250 struct connected
*ifc
= listgetdata(node
);
251 struct prefix
*p
= ifc
->address
;
254 if (!CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
257 if ((curr
+ uel
) > buf_pastend
)
260 if (p
->family
!= family
)
263 l_encode
= pim_encode_addr_ucast (curr
, p
);
265 option_len
+= l_encode
;
268 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
269 zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu",
274 if (option_len
< 1) {
275 /* Empty secondary unicast IPv4 address list */
282 *(uint16_t *) buf
= htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST
);
283 *(uint16_t *) (buf
+ 2) = htons(option_len
);
288 static int check_tlv_length(const char *label
, const char *tlv_name
,
289 const char *ifname
, struct in_addr src_addr
,
290 int correct_len
, int option_len
)
292 if (option_len
!= correct_len
) {
293 char src_str
[INET_ADDRSTRLEN
];
294 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
295 zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s",
297 option_len
, correct_len
,
305 static void check_tlv_redefinition_uint16(const char *label
, const char *tlv_name
,
306 const char *ifname
, struct in_addr src_addr
,
307 pim_hello_options options
,
308 pim_hello_options opt_mask
,
309 uint16_t new, uint16_t old
)
311 if (PIM_OPTION_IS_SET(options
, opt_mask
)) {
312 char src_str
[INET_ADDRSTRLEN
];
313 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
314 zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
321 static void check_tlv_redefinition_uint32(const char *label
, const char *tlv_name
,
322 const char *ifname
, struct in_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
)) {
328 char src_str
[INET_ADDRSTRLEN
];
329 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
330 zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
337 static void check_tlv_redefinition_uint32_hex(const char *label
, const char *tlv_name
,
338 const char *ifname
, struct in_addr src_addr
,
339 pim_hello_options options
,
340 pim_hello_options opt_mask
,
341 uint32_t new, uint32_t old
)
343 if (PIM_OPTION_IS_SET(options
, opt_mask
)) {
344 char src_str
[INET_ADDRSTRLEN
];
345 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
346 zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s",
353 int pim_tlv_parse_holdtime(const char *ifname
, struct in_addr src_addr
,
354 pim_hello_options
*hello_options
,
355 uint16_t *hello_option_holdtime
,
357 const uint8_t *tlv_curr
)
359 const char *label
= "holdtime";
361 if (check_tlv_length(__PRETTY_FUNCTION__
, label
,
363 sizeof(uint16_t), option_len
)) {
367 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__
, label
,
369 *hello_options
, PIM_OPTION_MASK_HOLDTIME
,
370 PIM_TLV_GET_HOLDTIME(tlv_curr
),
371 *hello_option_holdtime
);
373 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_HOLDTIME
);
375 *hello_option_holdtime
= PIM_TLV_GET_HOLDTIME(tlv_curr
);
380 int pim_tlv_parse_lan_prune_delay(const char *ifname
, struct in_addr src_addr
,
381 pim_hello_options
*hello_options
,
382 uint16_t *hello_option_propagation_delay
,
383 uint16_t *hello_option_override_interval
,
385 const uint8_t *tlv_curr
)
387 if (check_tlv_length(__PRETTY_FUNCTION__
, "lan_prune_delay",
389 sizeof(uint32_t), option_len
)) {
393 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__
, "propagation_delay",
395 *hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
,
396 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr
),
397 *hello_option_propagation_delay
);
399 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
);
401 *hello_option_propagation_delay
= PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr
);
402 if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr
)) {
403 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
);
406 PIM_OPTION_UNSET(*hello_options
, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
);
410 *hello_option_override_interval
= PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr
);
415 int pim_tlv_parse_dr_priority(const char *ifname
, struct in_addr src_addr
,
416 pim_hello_options
*hello_options
,
417 uint32_t *hello_option_dr_priority
,
419 const uint8_t *tlv_curr
)
421 const char *label
= "dr_priority";
423 if (check_tlv_length(__PRETTY_FUNCTION__
, label
,
425 sizeof(uint32_t), option_len
)) {
429 check_tlv_redefinition_uint32(__PRETTY_FUNCTION__
, label
,
431 *hello_options
, PIM_OPTION_MASK_DR_PRIORITY
,
432 PIM_TLV_GET_DR_PRIORITY(tlv_curr
),
433 *hello_option_dr_priority
);
435 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_DR_PRIORITY
);
437 *hello_option_dr_priority
= PIM_TLV_GET_DR_PRIORITY(tlv_curr
);
442 int pim_tlv_parse_generation_id(const char *ifname
, struct in_addr src_addr
,
443 pim_hello_options
*hello_options
,
444 uint32_t *hello_option_generation_id
,
446 const uint8_t *tlv_curr
)
448 const char *label
= "generation_id";
450 if (check_tlv_length(__PRETTY_FUNCTION__
, label
,
452 sizeof(uint32_t), option_len
)) {
456 check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__
, label
,
458 *hello_options
, PIM_OPTION_MASK_GENERATION_ID
,
459 PIM_TLV_GET_GENERATION_ID(tlv_curr
),
460 *hello_option_generation_id
);
462 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_GENERATION_ID
);
464 *hello_option_generation_id
= PIM_TLV_GET_GENERATION_ID(tlv_curr
);
470 pim_parse_addr_ucast (struct prefix
*p
,
474 const int ucast_encoding_min_len
= 3; /* 1 family + 1 type + 1 addr */
476 const uint8_t *pastend
;
480 if (buf_size
< ucast_encoding_min_len
) {
481 zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d",
483 buf_size
, ucast_encoding_min_len
);
488 pastend
= buf
+ buf_size
;
494 zlog_warn("%s: unknown unicast address encoding type=%d",
501 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
502 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
503 zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu",
505 pastend
- addr
, sizeof(struct in_addr
));
509 p
->family
= AF_INET
; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
510 memcpy(&p
->u
.prefix4
, addr
, sizeof(struct in_addr
));
511 p
->prefixlen
= IPV4_MAX_PREFIXLEN
;
512 addr
+= sizeof(struct in_addr
);
515 case PIM_MSG_ADDRESS_FAMILY_IPV6
:
516 if ((addr
+ sizeof(struct in6_addr
)) > pastend
) {
517 zlog_warn ("%s: IPv6 unicast address overflow: left=%zd needed %zu",
519 pastend
- addr
, sizeof(struct in6_addr
));
523 p
->family
= AF_INET6
;
524 p
->prefixlen
= IPV6_MAX_PREFIXLEN
;
525 memcpy(&p
->u
.prefix6
, addr
, sizeof(struct in6_addr
));
526 addr
+= sizeof(struct in6_addr
);
531 zlog_warn("%s: unknown unicast address encoding family=%d from",
542 pim_parse_addr_group (struct prefix_sg
*sg
,
546 const int grp_encoding_min_len
= 4; /* 1 family + 1 type + 1 reserved + 1 addr */
548 const uint8_t *pastend
;
553 if (buf_size
< grp_encoding_min_len
) {
554 zlog_warn("%s: group address encoding overflow: left=%d needed=%d",
556 buf_size
, grp_encoding_min_len
);
561 pastend
= buf
+ buf_size
;
566 ++addr
; /* skip b_reserved_z fields */
570 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
572 zlog_warn("%s: unknown group address encoding type=%d from",
573 __PRETTY_FUNCTION__
, type
);
577 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
578 zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from",
580 pastend
- addr
, sizeof(struct in_addr
));
584 memcpy(&sg
->grp
.s_addr
, addr
, sizeof(struct in_addr
));
586 addr
+= sizeof(struct in_addr
);
591 zlog_warn("%s: unknown group address encoding family=%d mask_len=%d from",
592 __PRETTY_FUNCTION__
, family
, mask_len
);
601 pim_parse_addr_source(struct prefix_sg
*sg
,
606 const int src_encoding_min_len
= 4; /* 1 family + 1 type + 1 reserved + 1 addr */
608 const uint8_t *pastend
;
613 if (buf_size
< src_encoding_min_len
) {
614 zlog_warn("%s: source address encoding overflow: left=%d needed=%d",
616 buf_size
, src_encoding_min_len
);
621 pastend
= buf
+ buf_size
;
629 zlog_warn("%s: unknown source address encoding type=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
632 buf
[0], buf
[1], buf
[2], buf
[3], buf
[4], buf
[5], buf
[6], buf
[7]);
637 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
638 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
639 zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu",
641 pastend
- addr
, sizeof(struct in_addr
));
645 memcpy(&sg
->src
, addr
, sizeof(struct in_addr
));
648 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
650 Encoded-Source Address
652 The mask length MUST be equal to the mask length in bits for
653 the given Address Family and Encoding Type (32 for IPv4 native
654 and 128 for IPv6 native). A router SHOULD ignore any messages
655 received with any other mask length.
657 if (mask_len
!= 32) {
658 zlog_warn("%s: IPv4 bad source address mask: %d",
659 __PRETTY_FUNCTION__
, mask_len
);
663 addr
+= sizeof(struct in_addr
);
668 zlog_warn("%s: unknown source address encoding family=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
671 buf
[0], buf
[1], buf
[2], buf
[3], buf
[4], buf
[5], buf
[6], buf
[7]);
679 #define FREE_ADDR_LIST(hello_option_addr_list) \
681 if (hello_option_addr_list) { \
682 list_delete(hello_option_addr_list); \
683 hello_option_addr_list = 0; \
687 int pim_tlv_parse_addr_list(const char *ifname
, struct in_addr src_addr
,
688 pim_hello_options
*hello_options
,
689 struct list
**hello_option_addr_list
,
691 const uint8_t *tlv_curr
)
694 const uint8_t *pastend
;
696 zassert(hello_option_addr_list
);
702 pastend
= tlv_curr
+ option_len
;
703 while (addr
< pastend
) {
710 addr_offset
= pim_parse_addr_ucast(&tmp
, addr
, pastend
- addr
);
711 if (addr_offset
< 1) {
712 char src_str
[INET_ADDRSTRLEN
];
713 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
714 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
717 FREE_ADDR_LIST(*hello_option_addr_list
);
725 if (PIM_DEBUG_PIM_TRACE
) {
726 switch (tmp
.family
) {
729 char addr_str
[INET_ADDRSTRLEN
];
730 char src_str
[INET_ADDRSTRLEN
];
731 pim_inet4_dump("<addr?>", tmp
.u
.prefix4
, addr_str
, sizeof(addr_str
));
732 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
733 zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
735 *hello_option_addr_list
?
736 ((int) listcount(*hello_option_addr_list
)) : -1,
737 addr_str
, src_str
, ifname
);
744 char src_str
[INET_ADDRSTRLEN
];
745 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
746 zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
748 *hello_option_addr_list
?
749 ((int) listcount(*hello_option_addr_list
)) : -1,
756 Exclude neighbor's primary address if incorrectly included in
757 the secondary address list
759 if (tmp
.family
== AF_INET
) {
760 if (tmp
.u
.prefix4
.s_addr
== src_addr
.s_addr
) {
761 char src_str
[INET_ADDRSTRLEN
];
762 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
763 zlog_warn("%s: ignoring primary address in secondary list from %s on %s",
771 Allocate list if needed
773 if (!*hello_option_addr_list
) {
774 *hello_option_addr_list
= list_new();
775 if (!*hello_option_addr_list
) {
776 zlog_err("%s %s: failure: hello_option_addr_list=list_new()",
777 __FILE__
, __PRETTY_FUNCTION__
);
780 (*hello_option_addr_list
)->del
= (void (*)(void *)) prefix_free
;
790 zlog_err("%s %s: failure: prefix_new()",
791 __FILE__
, __PRETTY_FUNCTION__
);
792 FREE_ADDR_LIST(*hello_option_addr_list
);
795 prefix_copy(p
, &tmp
);
796 listnode_add(*hello_option_addr_list
, p
);
799 } /* while (addr < pastend) */
804 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_ADDRESS_LIST
);