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
;
136 *(uint8_t *)buf
= PIM_MSG_ADDRESS_FAMILY_IPV6
;
140 memcpy(buf
, &p
->u
.prefix6
, sizeof(struct in6_addr
));
141 return ucast_ipv6_encoding_len
;
149 #define group_ipv4_encoding_len (4 + sizeof (struct in_addr))
152 * Encoded-Group addresses take the following format:
155 * 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
156 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
157 * | Addr Family | Encoding Type |B| Reserved |Z| Mask Len |
158 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
159 * | Group multicast Address
160 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
168 * [B]idirectional PIM
169 * Indicates the group range should use Bidirectional PIM [13].
170 * For PIM-SM defined in this specification, this bit MUST be zero.
173 * Transmitted as zero. Ignored upon receipt.
176 * indicates the group range is an admin scope zone. This is used
177 * in the Bootstrap Router Mechanism [11] only. For all other
178 * purposes, this bit is set to zero and ignored on receipt.
181 * The Mask length field is 8 bits. The value is the number of
182 * contiguous one bits that are left justified and used as a mask;
183 * when combined with the group address, it describes a range of
184 * groups. It is less than or equal to the address length in bits
185 * for the given Address Family and Encoding Type. If the message
186 * is sent for a single group, then the Mask length must equal the
187 * address length in bits for the given Address Family and Encoding
188 * Type (e.g., 32 for IPv4 native encoding, 128 for IPv6 native
191 * Group multicast Address
192 * Contains the group address.
194 int pim_encode_addr_group(uint8_t *buf
, afi_t afi
, int bidir
, int scope
,
195 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
, const uint8_t *buf_pastend
,
222 struct list
*ifconnected
, int family
)
224 struct listnode
*node
;
225 uint16_t option_len
= 0;
229 node
= listhead(ifconnected
);
231 /* Empty address list ? */
236 if (family
== AF_INET
)
237 uel
= ucast_ipv4_encoding_len
;
239 uel
= ucast_ipv6_encoding_len
;
241 /* Scan secondary address list */
242 curr
= buf
+ 4; /* skip T and L */
243 for (; node
; node
= listnextnode(node
)) {
244 struct connected
*ifc
= listgetdata(node
);
245 struct prefix
*p
= ifc
->address
;
248 if (!CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
251 if ((curr
+ uel
) > buf_pastend
)
254 if (p
->family
!= family
)
257 l_encode
= pim_encode_addr_ucast(curr
, p
);
259 option_len
+= l_encode
;
262 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
264 "%s: number of encoded secondary unicast IPv4 addresses: %zu",
265 __PRETTY_FUNCTION__
, option_len
/ uel
);
268 if (option_len
< 1) {
269 /* Empty secondary unicast IPv4 address list */
276 *(uint16_t *)buf
= htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST
);
277 *(uint16_t *)(buf
+ 2) = htons(option_len
);
282 static int check_tlv_length(const char *label
, const char *tlv_name
,
283 const char *ifname
, struct in_addr src_addr
,
284 int correct_len
, int option_len
)
286 if (option_len
!= correct_len
) {
287 char src_str
[INET_ADDRSTRLEN
];
288 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
290 "%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s",
291 label
, tlv_name
, option_len
, correct_len
, src_str
,
299 static void check_tlv_redefinition_uint16(
300 const char *label
, const char *tlv_name
, const char *ifname
,
301 struct in_addr src_addr
, pim_hello_options options
,
302 pim_hello_options opt_mask
, uint16_t new, uint16_t old
)
304 if (PIM_OPTION_IS_SET(options
, opt_mask
)) {
305 char src_str
[INET_ADDRSTRLEN
];
306 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
308 "%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
309 label
, tlv_name
, new, old
, src_str
, ifname
);
313 static void check_tlv_redefinition_uint32(
314 const char *label
, const char *tlv_name
, const char *ifname
,
315 struct in_addr src_addr
, pim_hello_options options
,
316 pim_hello_options opt_mask
, uint32_t new, uint32_t old
)
318 if (PIM_OPTION_IS_SET(options
, opt_mask
)) {
319 char src_str
[INET_ADDRSTRLEN
];
320 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
322 "%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
323 label
, tlv_name
, new, old
, src_str
, ifname
);
327 static void check_tlv_redefinition_uint32_hex(
328 const char *label
, const char *tlv_name
, const char *ifname
,
329 struct in_addr src_addr
, pim_hello_options options
,
330 pim_hello_options opt_mask
, uint32_t new, uint32_t old
)
332 if (PIM_OPTION_IS_SET(options
, opt_mask
)) {
333 char src_str
[INET_ADDRSTRLEN
];
334 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
336 "%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s",
337 label
, tlv_name
, new, old
, src_str
, ifname
);
341 int pim_tlv_parse_holdtime(const char *ifname
, struct in_addr src_addr
,
342 pim_hello_options
*hello_options
,
343 uint16_t *hello_option_holdtime
, uint16_t option_len
,
344 const uint8_t *tlv_curr
)
346 const char *label
= "holdtime";
348 if (check_tlv_length(__PRETTY_FUNCTION__
, label
, ifname
, src_addr
,
349 sizeof(uint16_t), option_len
)) {
353 check_tlv_redefinition_uint16(
354 __PRETTY_FUNCTION__
, label
, ifname
, src_addr
, *hello_options
,
355 PIM_OPTION_MASK_HOLDTIME
, PIM_TLV_GET_HOLDTIME(tlv_curr
),
356 *hello_option_holdtime
);
358 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_HOLDTIME
);
360 *hello_option_holdtime
= PIM_TLV_GET_HOLDTIME(tlv_curr
);
365 int pim_tlv_parse_lan_prune_delay(const char *ifname
, struct in_addr src_addr
,
366 pim_hello_options
*hello_options
,
367 uint16_t *hello_option_propagation_delay
,
368 uint16_t *hello_option_override_interval
,
369 uint16_t option_len
, const uint8_t *tlv_curr
)
371 if (check_tlv_length(__PRETTY_FUNCTION__
, "lan_prune_delay", ifname
,
372 src_addr
, sizeof(uint32_t), option_len
)) {
376 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__
, "propagation_delay",
377 ifname
, src_addr
, *hello_options
,
378 PIM_OPTION_MASK_LAN_PRUNE_DELAY
,
379 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr
),
380 *hello_option_propagation_delay
);
382 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
);
384 *hello_option_propagation_delay
=
385 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr
);
386 if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr
)) {
387 PIM_OPTION_SET(*hello_options
,
388 PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
);
390 PIM_OPTION_UNSET(*hello_options
,
391 PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
);
395 *hello_option_override_interval
=
396 PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr
);
401 int pim_tlv_parse_dr_priority(const char *ifname
, struct in_addr src_addr
,
402 pim_hello_options
*hello_options
,
403 uint32_t *hello_option_dr_priority
,
404 uint16_t option_len
, const uint8_t *tlv_curr
)
406 const char *label
= "dr_priority";
408 if (check_tlv_length(__PRETTY_FUNCTION__
, label
, ifname
, src_addr
,
409 sizeof(uint32_t), option_len
)) {
413 check_tlv_redefinition_uint32(
414 __PRETTY_FUNCTION__
, label
, ifname
, src_addr
, *hello_options
,
415 PIM_OPTION_MASK_DR_PRIORITY
, PIM_TLV_GET_DR_PRIORITY(tlv_curr
),
416 *hello_option_dr_priority
);
418 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_DR_PRIORITY
);
420 *hello_option_dr_priority
= PIM_TLV_GET_DR_PRIORITY(tlv_curr
);
425 int pim_tlv_parse_generation_id(const char *ifname
, struct in_addr src_addr
,
426 pim_hello_options
*hello_options
,
427 uint32_t *hello_option_generation_id
,
428 uint16_t option_len
, const uint8_t *tlv_curr
)
430 const char *label
= "generation_id";
432 if (check_tlv_length(__PRETTY_FUNCTION__
, label
, ifname
, src_addr
,
433 sizeof(uint32_t), option_len
)) {
437 check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__
, label
, ifname
,
438 src_addr
, *hello_options
,
439 PIM_OPTION_MASK_GENERATION_ID
,
440 PIM_TLV_GET_GENERATION_ID(tlv_curr
),
441 *hello_option_generation_id
);
443 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_GENERATION_ID
);
445 *hello_option_generation_id
= PIM_TLV_GET_GENERATION_ID(tlv_curr
);
450 int pim_parse_addr_ucast(struct prefix
*p
, const uint8_t *buf
, int buf_size
)
452 const int ucast_encoding_min_len
= 3; /* 1 family + 1 type + 1 addr */
454 const uint8_t *pastend
;
458 if (buf_size
< ucast_encoding_min_len
) {
460 "%s: unicast address encoding overflow: left=%d needed=%d",
461 __PRETTY_FUNCTION__
, buf_size
, ucast_encoding_min_len
);
466 pastend
= buf
+ buf_size
;
472 zlog_warn("%s: unknown unicast address encoding type=%d",
473 __PRETTY_FUNCTION__
, type
);
478 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
479 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
481 "%s: IPv4 unicast address overflow: left=%zd needed=%zu",
482 __PRETTY_FUNCTION__
, pastend
- addr
,
483 sizeof(struct in_addr
));
487 p
->family
= AF_INET
; /* notice: AF_INET !=
488 PIM_MSG_ADDRESS_FAMILY_IPV4 */
489 memcpy(&p
->u
.prefix4
, addr
, sizeof(struct in_addr
));
490 p
->prefixlen
= IPV4_MAX_PREFIXLEN
;
491 addr
+= sizeof(struct in_addr
);
494 case PIM_MSG_ADDRESS_FAMILY_IPV6
:
495 if ((addr
+ sizeof(struct in6_addr
)) > pastend
) {
497 "%s: IPv6 unicast address overflow: left=%zd needed %zu",
498 __PRETTY_FUNCTION__
, pastend
- addr
,
499 sizeof(struct in6_addr
));
503 p
->family
= AF_INET6
;
504 p
->prefixlen
= IPV6_MAX_PREFIXLEN
;
505 memcpy(&p
->u
.prefix6
, addr
, sizeof(struct in6_addr
));
506 addr
+= sizeof(struct in6_addr
);
510 zlog_warn("%s: unknown unicast address encoding family=%d from",
511 __PRETTY_FUNCTION__
, family
);
519 int pim_parse_addr_group(struct prefix_sg
*sg
, const uint8_t *buf
, int buf_size
)
521 const int grp_encoding_min_len
=
522 4; /* 1 family + 1 type + 1 reserved + 1 addr */
524 const uint8_t *pastend
;
529 if (buf_size
< grp_encoding_min_len
) {
531 "%s: group address encoding overflow: left=%d needed=%d",
532 __PRETTY_FUNCTION__
, buf_size
, grp_encoding_min_len
);
537 pastend
= buf
+ buf_size
;
542 ++addr
; /* skip b_reserved_z fields */
546 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
549 "%s: unknown group address encoding type=%d from",
550 __PRETTY_FUNCTION__
, type
);
554 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
556 "%s: IPv4 group address overflow: left=%zd needed=%zu from",
557 __PRETTY_FUNCTION__
, pastend
- addr
,
558 sizeof(struct in_addr
));
562 memcpy(&sg
->grp
.s_addr
, addr
, sizeof(struct in_addr
));
564 addr
+= sizeof(struct in_addr
);
569 "%s: unknown group address encoding family=%d mask_len=%d from",
570 __PRETTY_FUNCTION__
, family
, mask_len
);
578 int pim_parse_addr_source(struct prefix_sg
*sg
, uint8_t *flags
,
579 const uint8_t *buf
, int buf_size
)
581 const int src_encoding_min_len
=
582 4; /* 1 family + 1 type + 1 reserved + 1 addr */
584 const uint8_t *pastend
;
589 if (buf_size
< src_encoding_min_len
) {
591 "%s: source address encoding overflow: left=%d needed=%d",
592 __PRETTY_FUNCTION__
, buf_size
, src_encoding_min_len
);
597 pastend
= buf
+ buf_size
;
606 "%s: unknown source address encoding type=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
607 __PRETTY_FUNCTION__
, type
, buf
[0], buf
[1], buf
[2],
608 buf
[3], buf
[4], buf
[5], buf
[6], buf
[7]);
613 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
614 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
616 "%s: IPv4 source address overflow: left=%zd needed=%zu",
617 __PRETTY_FUNCTION__
, pastend
- addr
,
618 sizeof(struct in_addr
));
622 memcpy(&sg
->src
, addr
, sizeof(struct in_addr
));
625 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
627 Encoded-Source Address
629 The mask length MUST be equal to the mask length in bits for
630 the given Address Family and Encoding Type (32 for IPv4
632 and 128 for IPv6 native). A router SHOULD ignore any
634 received with any other mask length.
636 if (mask_len
!= 32) {
637 zlog_warn("%s: IPv4 bad source address mask: %d",
638 __PRETTY_FUNCTION__
, mask_len
);
642 addr
+= sizeof(struct in_addr
);
647 "%s: unknown source address encoding family=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
648 __PRETTY_FUNCTION__
, family
, buf
[0], buf
[1], buf
[2],
649 buf
[3], buf
[4], buf
[5], buf
[6], buf
[7]);
657 #define FREE_ADDR_LIST(hello_option_addr_list) \
659 if (hello_option_addr_list) { \
660 list_delete(&hello_option_addr_list); \
661 hello_option_addr_list = 0; \
665 int pim_tlv_parse_addr_list(const char *ifname
, struct in_addr src_addr
,
666 pim_hello_options
*hello_options
,
667 struct list
**hello_option_addr_list
,
668 uint16_t option_len
, const uint8_t *tlv_curr
)
671 const uint8_t *pastend
;
673 zassert(hello_option_addr_list
);
679 pastend
= tlv_curr
+ option_len
;
680 while (addr
< pastend
) {
687 addr_offset
= pim_parse_addr_ucast(&tmp
, addr
, pastend
- addr
);
688 if (addr_offset
< 1) {
689 char src_str
[INET_ADDRSTRLEN
];
690 pim_inet4_dump("<src?>", src_addr
, src_str
,
693 "%s: pim_parse_addr_ucast() failure: from %s on %s",
694 __PRETTY_FUNCTION__
, src_str
, ifname
);
695 FREE_ADDR_LIST(*hello_option_addr_list
);
703 if (PIM_DEBUG_PIM_TRACE
) {
704 switch (tmp
.family
) {
706 char addr_str
[INET_ADDRSTRLEN
];
707 char src_str
[INET_ADDRSTRLEN
];
708 pim_inet4_dump("<addr?>", tmp
.u
.prefix4
,
709 addr_str
, sizeof(addr_str
));
710 pim_inet4_dump("<src?>", src_addr
, src_str
,
713 "%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
715 *hello_option_addr_list
717 *hello_option_addr_list
))
719 addr_str
, src_str
, ifname
);
724 char src_str
[INET_ADDRSTRLEN
];
725 pim_inet4_dump("<src?>", src_addr
, src_str
,
728 "%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
730 *hello_option_addr_list
732 *hello_option_addr_list
))
740 Exclude neighbor's primary address if incorrectly included in
741 the secondary address list
743 if (tmp
.family
== AF_INET
) {
744 if (tmp
.u
.prefix4
.s_addr
== src_addr
.s_addr
) {
745 char src_str
[INET_ADDRSTRLEN
];
746 pim_inet4_dump("<src?>", src_addr
, src_str
,
749 "%s: ignoring primary address in secondary list from %s on %s",
750 __PRETTY_FUNCTION__
, src_str
, 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
=
761 (void (*)(void *))prefix_free
;
770 prefix_copy(p
, &tmp
);
771 listnode_add(*hello_option_addr_list
, p
);
774 } /* while (addr < pastend) */
779 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_ADDRESS_LIST
);