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
)
124 *buf
= PIM_MSG_ADDRESS_FAMILY_IPV4
; /* notice: AF_INET !=
125 PIM_MSG_ADDRESS_FAMILY_IPV4
128 *buf
= 0; /* ucast IPv4 native encoding type (RFC
131 memcpy(buf
, &p
->u
.prefix4
, sizeof(struct in_addr
));
132 return ucast_ipv4_encoding_len
;
134 *buf
= PIM_MSG_ADDRESS_FAMILY_IPV6
;
138 memcpy(buf
, &p
->u
.prefix6
, sizeof(struct in6_addr
));
139 return ucast_ipv6_encoding_len
;
145 #define group_ipv4_encoding_len (4 + sizeof(struct in_addr))
148 * Encoded-Group addresses take the following format:
151 * 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
152 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
153 * | Addr Family | Encoding Type |B| Reserved |Z| Mask Len |
154 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
155 * | Group multicast Address
156 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
164 * [B]idirectional PIM
165 * Indicates the group range should use Bidirectional PIM [13].
166 * For PIM-SM defined in this specification, this bit MUST be zero.
169 * Transmitted as zero. Ignored upon receipt.
172 * indicates the group range is an admin scope zone. This is used
173 * in the Bootstrap Router Mechanism [11] only. For all other
174 * purposes, this bit is set to zero and ignored on receipt.
177 * The Mask length field is 8 bits. The value is the number of
178 * contiguous one bits that are left justified and used as a mask;
179 * when combined with the group address, it describes a range of
180 * groups. It is less than or equal to the address length in bits
181 * for the given Address Family and Encoding Type. If the message
182 * is sent for a single group, then the Mask length must equal the
183 * address length in bits for the given Address Family and Encoding
184 * Type (e.g., 32 for IPv4 native encoding, 128 for IPv6 native
187 * Group multicast Address
188 * Contains the group address.
190 int pim_encode_addr_group(uint8_t *buf
, afi_t afi
, int bidir
, int scope
,
191 struct in_addr group
)
200 *buf
= PIM_MSG_ADDRESS_FAMILY_IPV4
;
208 memcpy(buf
, &group
, sizeof(struct in_addr
));
209 return group_ipv4_encoding_len
;
215 uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf
, const uint8_t *buf_pastend
,
216 struct list
*ifconnected
, int family
)
218 struct listnode
*node
;
219 uint16_t option_len
= 0;
223 node
= listhead(ifconnected
);
225 /* Empty address list ? */
230 if (family
== AF_INET
)
231 uel
= ucast_ipv4_encoding_len
;
233 uel
= ucast_ipv6_encoding_len
;
235 /* Scan secondary address list */
236 curr
= buf
+ 4; /* skip T and L */
237 for (; node
; node
= listnextnode(node
)) {
238 struct connected
*ifc
= listgetdata(node
);
239 struct prefix
*p
= ifc
->address
;
242 if (!CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
245 if ((curr
+ uel
) > buf_pastend
)
248 if (p
->family
!= family
)
251 l_encode
= pim_encode_addr_ucast(curr
, p
);
253 option_len
+= l_encode
;
256 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
258 "%s: number of encoded secondary unicast IPv4 addresses: %zu",
259 __func__
, option_len
/ uel
);
262 if (option_len
< 1) {
263 /* Empty secondary unicast IPv4 address list */
270 *(uint16_t *)buf
= htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST
);
271 *(uint16_t *)(buf
+ 2) = htons(option_len
);
276 static int check_tlv_length(const char *label
, const char *tlv_name
,
277 const char *ifname
, struct in_addr src_addr
,
278 int correct_len
, int option_len
)
280 if (option_len
!= correct_len
) {
281 char src_str
[INET_ADDRSTRLEN
];
282 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
284 "%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s",
285 label
, tlv_name
, option_len
, correct_len
, src_str
,
293 static void check_tlv_redefinition_uint16(
294 const char *label
, const char *tlv_name
, const char *ifname
,
295 struct in_addr src_addr
, pim_hello_options options
,
296 pim_hello_options opt_mask
, uint16_t new, uint16_t old
)
298 if (PIM_OPTION_IS_SET(options
, opt_mask
)) {
299 char src_str
[INET_ADDRSTRLEN
];
300 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
302 "%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
303 label
, tlv_name
, new, old
, src_str
, ifname
);
307 static void check_tlv_redefinition_uint32(
308 const char *label
, const char *tlv_name
, const char *ifname
,
309 struct in_addr src_addr
, pim_hello_options options
,
310 pim_hello_options opt_mask
, uint32_t new, uint32_t old
)
312 if (PIM_OPTION_IS_SET(options
, opt_mask
)) {
313 char src_str
[INET_ADDRSTRLEN
];
314 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
316 "%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
317 label
, tlv_name
, new, old
, src_str
, ifname
);
321 static void check_tlv_redefinition_uint32_hex(
322 const char *label
, const char *tlv_name
, const char *ifname
,
323 struct in_addr src_addr
, pim_hello_options options
,
324 pim_hello_options opt_mask
, uint32_t new, uint32_t old
)
326 if (PIM_OPTION_IS_SET(options
, opt_mask
)) {
327 char src_str
[INET_ADDRSTRLEN
];
328 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
330 "%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s",
331 label
, tlv_name
, new, old
, src_str
, ifname
);
335 int pim_tlv_parse_holdtime(const char *ifname
, struct in_addr src_addr
,
336 pim_hello_options
*hello_options
,
337 uint16_t *hello_option_holdtime
, uint16_t option_len
,
338 const uint8_t *tlv_curr
)
340 const char *label
= "holdtime";
342 if (check_tlv_length(__func__
, label
, ifname
, src_addr
,
343 sizeof(uint16_t), option_len
)) {
347 check_tlv_redefinition_uint16(__func__
, label
, ifname
, src_addr
,
348 *hello_options
, PIM_OPTION_MASK_HOLDTIME
,
349 PIM_TLV_GET_HOLDTIME(tlv_curr
),
350 *hello_option_holdtime
);
352 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_HOLDTIME
);
354 *hello_option_holdtime
= PIM_TLV_GET_HOLDTIME(tlv_curr
);
359 int pim_tlv_parse_lan_prune_delay(const char *ifname
, struct in_addr src_addr
,
360 pim_hello_options
*hello_options
,
361 uint16_t *hello_option_propagation_delay
,
362 uint16_t *hello_option_override_interval
,
363 uint16_t option_len
, const uint8_t *tlv_curr
)
365 if (check_tlv_length(__func__
, "lan_prune_delay", ifname
, src_addr
,
366 sizeof(uint32_t), option_len
)) {
370 check_tlv_redefinition_uint16(__func__
, "propagation_delay", ifname
,
371 src_addr
, *hello_options
,
372 PIM_OPTION_MASK_LAN_PRUNE_DELAY
,
373 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr
),
374 *hello_option_propagation_delay
);
376 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
);
378 *hello_option_propagation_delay
=
379 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr
);
380 if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr
)) {
381 PIM_OPTION_SET(*hello_options
,
382 PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
);
384 PIM_OPTION_UNSET(*hello_options
,
385 PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
);
389 *hello_option_override_interval
=
390 PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr
);
395 int pim_tlv_parse_dr_priority(const char *ifname
, struct in_addr src_addr
,
396 pim_hello_options
*hello_options
,
397 uint32_t *hello_option_dr_priority
,
398 uint16_t option_len
, const uint8_t *tlv_curr
)
400 const char *label
= "dr_priority";
402 if (check_tlv_length(__func__
, label
, ifname
, src_addr
,
403 sizeof(uint32_t), option_len
)) {
407 check_tlv_redefinition_uint32(
408 __func__
, label
, ifname
, src_addr
, *hello_options
,
409 PIM_OPTION_MASK_DR_PRIORITY
, PIM_TLV_GET_DR_PRIORITY(tlv_curr
),
410 *hello_option_dr_priority
);
412 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_DR_PRIORITY
);
414 *hello_option_dr_priority
= PIM_TLV_GET_DR_PRIORITY(tlv_curr
);
419 int pim_tlv_parse_generation_id(const char *ifname
, struct in_addr src_addr
,
420 pim_hello_options
*hello_options
,
421 uint32_t *hello_option_generation_id
,
422 uint16_t option_len
, const uint8_t *tlv_curr
)
424 const char *label
= "generation_id";
426 if (check_tlv_length(__func__
, label
, ifname
, src_addr
,
427 sizeof(uint32_t), option_len
)) {
431 check_tlv_redefinition_uint32_hex(__func__
, label
, ifname
, src_addr
,
433 PIM_OPTION_MASK_GENERATION_ID
,
434 PIM_TLV_GET_GENERATION_ID(tlv_curr
),
435 *hello_option_generation_id
);
437 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_GENERATION_ID
);
439 *hello_option_generation_id
= PIM_TLV_GET_GENERATION_ID(tlv_curr
);
444 int pim_parse_addr_ucast(struct prefix
*p
, const uint8_t *buf
, int buf_size
)
446 const int ucast_encoding_min_len
= 3; /* 1 family + 1 type + 1 addr */
448 const uint8_t *pastend
;
452 if (buf_size
< ucast_encoding_min_len
) {
454 "%s: unicast address encoding overflow: left=%d needed=%d",
455 __func__
, buf_size
, ucast_encoding_min_len
);
460 pastend
= buf
+ buf_size
;
466 zlog_warn("%s: unknown unicast address encoding type=%d",
472 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
473 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
475 "%s: IPv4 unicast address overflow: left=%td needed=%zu",
476 __func__
, pastend
- addr
,
477 sizeof(struct in_addr
));
481 p
->family
= AF_INET
; /* notice: AF_INET !=
482 PIM_MSG_ADDRESS_FAMILY_IPV4 */
483 memcpy(&p
->u
.prefix4
, addr
, sizeof(struct in_addr
));
484 p
->prefixlen
= IPV4_MAX_PREFIXLEN
;
485 addr
+= sizeof(struct in_addr
);
488 case PIM_MSG_ADDRESS_FAMILY_IPV6
:
489 if ((addr
+ sizeof(struct in6_addr
)) > pastend
) {
491 "%s: IPv6 unicast address overflow: left=%td needed %zu",
492 __func__
, pastend
- addr
,
493 sizeof(struct in6_addr
));
497 p
->family
= AF_INET6
;
498 p
->prefixlen
= IPV6_MAX_PREFIXLEN
;
499 memcpy(&p
->u
.prefix6
, addr
, sizeof(struct in6_addr
));
500 addr
+= sizeof(struct in6_addr
);
504 zlog_warn("%s: unknown unicast address encoding family=%d from",
513 int pim_parse_addr_group(struct prefix_sg
*sg
, const uint8_t *buf
, int buf_size
)
515 const int grp_encoding_min_len
=
516 4; /* 1 family + 1 type + 1 reserved + 1 addr */
518 const uint8_t *pastend
;
523 if (buf_size
< grp_encoding_min_len
) {
525 "%s: group address encoding overflow: left=%d needed=%d",
526 __func__
, buf_size
, grp_encoding_min_len
);
531 pastend
= buf
+ buf_size
;
536 ++addr
; /* skip b_reserved_z fields */
540 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
543 "%s: unknown group address encoding type=%d from",
548 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
550 "%s: IPv4 group address overflow: left=%td needed=%zu from",
551 __func__
, pastend
- addr
,
552 sizeof(struct in_addr
));
556 memcpy(&sg
->grp
.s_addr
, addr
, sizeof(struct in_addr
));
558 addr
+= sizeof(struct in_addr
);
563 "%s: unknown group address encoding family=%d mask_len=%d from",
564 __func__
, family
, mask_len
);
572 int pim_parse_addr_source(struct prefix_sg
*sg
, uint8_t *flags
,
573 const uint8_t *buf
, int buf_size
)
575 const int src_encoding_min_len
=
576 4; /* 1 family + 1 type + 1 reserved + 1 addr */
578 const uint8_t *pastend
;
583 if (buf_size
< src_encoding_min_len
) {
585 "%s: source address encoding overflow: left=%d needed=%d",
586 __func__
, buf_size
, src_encoding_min_len
);
591 pastend
= buf
+ buf_size
;
600 "%s: unknown source address encoding type=%d: %02x%02x%02x%02x",
601 __func__
, type
, buf
[0], buf
[1], buf
[2], buf
[3]);
606 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
607 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
609 "%s: IPv4 source address overflow: left=%td needed=%zu",
610 __func__
, pastend
- addr
,
611 sizeof(struct in_addr
));
615 memcpy(&sg
->src
, addr
, sizeof(struct in_addr
));
618 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
620 Encoded-Source Address
622 The mask length MUST be equal to the mask length in bits for
623 the given Address Family and Encoding Type (32 for IPv4
625 and 128 for IPv6 native). A router SHOULD ignore any
627 received with any other mask length.
629 if (mask_len
!= 32) {
630 zlog_warn("%s: IPv4 bad source address mask: %d",
635 addr
+= sizeof(struct in_addr
);
640 "%s: unknown source address encoding family=%d: %02x%02x%02x%02x",
641 __func__
, family
, buf
[0], buf
[1], buf
[2], buf
[3]);
649 #define FREE_ADDR_LIST(hello_option_addr_list) \
651 if (hello_option_addr_list) { \
652 list_delete(&hello_option_addr_list); \
653 hello_option_addr_list = 0; \
657 int pim_tlv_parse_addr_list(const char *ifname
, struct in_addr src_addr
,
658 pim_hello_options
*hello_options
,
659 struct list
**hello_option_addr_list
,
660 uint16_t option_len
, const uint8_t *tlv_curr
)
663 const uint8_t *pastend
;
665 zassert(hello_option_addr_list
);
671 pastend
= tlv_curr
+ option_len
;
672 while (addr
< pastend
) {
679 addr_offset
= pim_parse_addr_ucast(&tmp
, addr
, pastend
- addr
);
680 if (addr_offset
< 1) {
681 char src_str
[INET_ADDRSTRLEN
];
682 pim_inet4_dump("<src?>", src_addr
, src_str
,
685 "%s: pim_parse_addr_ucast() failure: from %s on %s",
686 __func__
, src_str
, ifname
);
687 FREE_ADDR_LIST(*hello_option_addr_list
);
695 if (PIM_DEBUG_PIM_TRACE
) {
696 switch (tmp
.family
) {
698 char addr_str
[INET_ADDRSTRLEN
];
699 char src_str
[INET_ADDRSTRLEN
];
700 pim_inet4_dump("<addr?>", tmp
.u
.prefix4
,
701 addr_str
, sizeof(addr_str
));
702 pim_inet4_dump("<src?>", src_addr
, src_str
,
705 "%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
707 *hello_option_addr_list
709 *hello_option_addr_list
))
711 addr_str
, src_str
, ifname
);
716 char src_str
[INET_ADDRSTRLEN
];
717 pim_inet4_dump("<src?>", src_addr
, src_str
,
720 "%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
722 *hello_option_addr_list
724 *hello_option_addr_list
))
732 Exclude neighbor's primary address if incorrectly included in
733 the secondary address list
735 if (tmp
.family
== AF_INET
) {
736 if (tmp
.u
.prefix4
.s_addr
== src_addr
.s_addr
) {
737 char src_str
[INET_ADDRSTRLEN
];
738 pim_inet4_dump("<src?>", src_addr
, src_str
,
741 "%s: ignoring primary address in secondary list from %s on %s",
742 __func__
, src_str
, ifname
);
748 Allocate list if needed
750 if (!*hello_option_addr_list
) {
751 *hello_option_addr_list
= list_new();
752 (*hello_option_addr_list
)->del
= prefix_free_lists
;
761 prefix_copy(p
, &tmp
);
762 listnode_add(*hello_option_addr_list
, p
);
765 } /* while (addr < pastend) */
770 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_ADDRESS_LIST
);