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
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
33 uint8_t *pim_tlv_append_uint16(uint8_t *buf
,
34 const uint8_t *buf_pastend
,
36 uint16_t option_value
)
38 uint16_t option_len
= 2;
40 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
43 *(uint16_t *) buf
= htons(option_type
);
45 *(uint16_t *) buf
= htons(option_len
);
47 *(uint16_t *) buf
= htons(option_value
);
53 uint8_t *pim_tlv_append_2uint16(uint8_t *buf
,
54 const uint8_t *buf_pastend
,
56 uint16_t option_value1
,
57 uint16_t option_value2
)
59 uint16_t option_len
= 4;
61 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
64 *(uint16_t *) buf
= htons(option_type
);
66 *(uint16_t *) buf
= htons(option_len
);
68 *(uint16_t *) buf
= htons(option_value1
);
70 *(uint16_t *) buf
= htons(option_value2
);
76 uint8_t *pim_tlv_append_uint32(uint8_t *buf
,
77 const uint8_t *buf_pastend
,
79 uint32_t option_value
)
81 uint16_t option_len
= 4;
83 if ((buf
+ PIM_TLV_OPTION_SIZE(option_len
)) > buf_pastend
)
86 *(uint16_t *) buf
= htons(option_type
);
88 *(uint16_t *) buf
= htons(option_len
);
90 pim_write_uint32(buf
, option_value
);
96 #define ucast_ipv4_encoding_len (2 + sizeof(struct in_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
;
144 #define group_ipv4_encoding_len (4 + sizeof (struct in_addr))
147 * Encoded-Group addresses take the following format:
150 * 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
151 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
152 * | Addr Family | Encoding Type |B| Reserved |Z| Mask Len |
153 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
154 * | Group multicast Address
155 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
163 * [B]idirectional PIM
164 * Indicates the group range should use Bidirectional PIM [13].
165 * For PIM-SM defined in this specification, this bit MUST be zero.
168 * Transmitted as zero. Ignored upon receipt.
171 * indicates the group range is an admin scope zone. This is used
172 * in the Bootstrap Router Mechanism [11] only. For all other
173 * purposes, this bit is set to zero and ignored on receipt.
176 * The Mask length field is 8 bits. The value is the number of
177 * contiguous one bits that are left justified and used as a mask;
178 * when combined with the group address, it describes a range of
179 * groups. It is less than or equal to the address length in bits
180 * for the given Address Family and Encoding Type. If the message
181 * is sent for a single group, then the Mask length must equal the
182 * address length in bits for the given Address Family and Encoding
183 * Type (e.g., 32 for IPv4 native encoding, 128 for IPv6 native
186 * Group multicast Address
187 * Contains the group address.
190 pim_encode_addr_group (uint8_t *buf
, afi_t afi
, int bidir
, int scope
, struct in_addr group
)
200 *(uint8_t *)buf
= PIM_MSG_ADDRESS_FAMILY_IPV4
;
204 *(uint8_t *)buf
= flags
;
206 *(uint8_t *)buf
= 32;
208 memcpy (buf
, &group
, sizeof (struct in_addr
));
209 return group_ipv4_encoding_len
;
217 uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf
,
218 const uint8_t *buf_pastend
,
219 struct list
*ifconnected
)
221 struct listnode
*node
;
222 uint16_t option_len
= 0;
226 node
= listhead(ifconnected
);
228 /* Empty address list ? */
233 /* Skip first address (primary) */
234 node
= listnextnode(node
);
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 ((curr
+ ucast_ipv4_encoding_len
) > buf_pastend
)
246 l_encode
= pim_encode_addr_ucast (curr
, p
);
248 option_len
+= l_encode
;
251 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
252 zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu",
254 option_len
/ ucast_ipv4_encoding_len
);
257 if (option_len
< 1) {
258 /* Empty secondary unicast IPv4 address list */
265 *(uint16_t *) buf
= htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST
);
266 *(uint16_t *) (buf
+ 2) = htons(option_len
);
271 static int check_tlv_length(const char *label
, const char *tlv_name
,
272 const char *ifname
, struct in_addr src_addr
,
273 int correct_len
, int option_len
)
275 if (option_len
!= correct_len
) {
276 char src_str
[INET_ADDRSTRLEN
];
277 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
278 zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s",
280 option_len
, correct_len
,
288 static void check_tlv_redefinition_uint16(const char *label
, const char *tlv_name
,
289 const char *ifname
, struct in_addr src_addr
,
290 pim_hello_options options
,
291 pim_hello_options opt_mask
,
292 uint16_t new, uint16_t old
)
294 if (PIM_OPTION_IS_SET(options
, opt_mask
)) {
295 char src_str
[INET_ADDRSTRLEN
];
296 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
297 zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
304 static void check_tlv_redefinition_uint32(const char *label
, const char *tlv_name
,
305 const char *ifname
, struct in_addr src_addr
,
306 pim_hello_options options
,
307 pim_hello_options opt_mask
,
308 uint32_t new, uint32_t old
)
310 if (PIM_OPTION_IS_SET(options
, opt_mask
)) {
311 char src_str
[INET_ADDRSTRLEN
];
312 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
313 zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
320 static void check_tlv_redefinition_uint32_hex(const char *label
, const char *tlv_name
,
321 const char *ifname
, struct in_addr src_addr
,
322 pim_hello_options options
,
323 pim_hello_options opt_mask
,
324 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
));
329 zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s",
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
,
340 const uint8_t *tlv_curr
)
342 const char *label
= "holdtime";
344 if (check_tlv_length(__PRETTY_FUNCTION__
, label
,
346 sizeof(uint16_t), option_len
)) {
350 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__
, label
,
352 *hello_options
, PIM_OPTION_MASK_HOLDTIME
,
353 PIM_TLV_GET_HOLDTIME(tlv_curr
),
354 *hello_option_holdtime
);
356 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_HOLDTIME
);
358 *hello_option_holdtime
= PIM_TLV_GET_HOLDTIME(tlv_curr
);
363 int pim_tlv_parse_lan_prune_delay(const char *ifname
, struct in_addr src_addr
,
364 pim_hello_options
*hello_options
,
365 uint16_t *hello_option_propagation_delay
,
366 uint16_t *hello_option_override_interval
,
368 const uint8_t *tlv_curr
)
370 if (check_tlv_length(__PRETTY_FUNCTION__
, "lan_prune_delay",
372 sizeof(uint32_t), option_len
)) {
376 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__
, "propagation_delay",
378 *hello_options
, 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
= PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr
);
385 if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr
)) {
386 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
);
389 PIM_OPTION_UNSET(*hello_options
, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
);
393 *hello_option_override_interval
= PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr
);
398 int pim_tlv_parse_dr_priority(const char *ifname
, struct in_addr src_addr
,
399 pim_hello_options
*hello_options
,
400 uint32_t *hello_option_dr_priority
,
402 const uint8_t *tlv_curr
)
404 const char *label
= "dr_priority";
406 if (check_tlv_length(__PRETTY_FUNCTION__
, label
,
408 sizeof(uint32_t), option_len
)) {
412 check_tlv_redefinition_uint32(__PRETTY_FUNCTION__
, label
,
414 *hello_options
, PIM_OPTION_MASK_DR_PRIORITY
,
415 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
,
429 const uint8_t *tlv_curr
)
431 const char *label
= "generation_id";
433 if (check_tlv_length(__PRETTY_FUNCTION__
, label
,
435 sizeof(uint32_t), option_len
)) {
439 check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__
, label
,
441 *hello_options
, PIM_OPTION_MASK_GENERATION_ID
,
442 PIM_TLV_GET_GENERATION_ID(tlv_curr
),
443 *hello_option_generation_id
);
445 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_GENERATION_ID
);
447 *hello_option_generation_id
= PIM_TLV_GET_GENERATION_ID(tlv_curr
);
453 pim_parse_addr_ucast (struct prefix
*p
,
457 const int ucast_encoding_min_len
= 3; /* 1 family + 1 type + 1 addr */
459 const uint8_t *pastend
;
463 if (buf_size
< ucast_encoding_min_len
) {
464 zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d",
466 buf_size
, ucast_encoding_min_len
);
471 pastend
= buf
+ buf_size
;
477 zlog_warn("%s: unknown unicast address encoding type=%d",
484 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
485 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
486 zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu",
488 pastend
- addr
, sizeof(struct in_addr
));
492 p
->family
= AF_INET
; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
493 memcpy(&p
->u
.prefix4
, addr
, sizeof(struct in_addr
));
495 addr
+= sizeof(struct in_addr
);
500 zlog_warn("%s: unknown unicast address encoding family=%d from",
511 pim_parse_addr_group (struct prefix_sg
*sg
,
515 const int grp_encoding_min_len
= 4; /* 1 family + 1 type + 1 reserved + 1 addr */
517 const uint8_t *pastend
;
522 if (buf_size
< grp_encoding_min_len
) {
523 zlog_warn("%s: group address encoding overflow: left=%d needed=%d",
525 buf_size
, grp_encoding_min_len
);
530 pastend
= buf
+ buf_size
;
535 ++addr
; /* skip b_reserved_z fields */
539 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
541 zlog_warn("%s: unknown group address encoding type=%d from",
542 __PRETTY_FUNCTION__
, type
);
546 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
547 zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from",
549 pastend
- addr
, sizeof(struct in_addr
));
553 memcpy(&sg
->grp
.s_addr
, addr
, sizeof(struct in_addr
));
555 addr
+= sizeof(struct in_addr
);
560 zlog_warn("%s: unknown group address encoding family=%d mask_len=%d from",
561 __PRETTY_FUNCTION__
, family
, mask_len
);
570 pim_parse_addr_source(struct prefix_sg
*sg
,
575 const int src_encoding_min_len
= 4; /* 1 family + 1 type + 1 reserved + 1 addr */
577 const uint8_t *pastend
;
582 if (buf_size
< src_encoding_min_len
) {
583 zlog_warn("%s: source address encoding overflow: left=%d needed=%d",
585 buf_size
, src_encoding_min_len
);
590 pastend
= buf
+ buf_size
;
598 zlog_warn("%s: unknown source address encoding type=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
601 buf
[0], buf
[1], buf
[2], buf
[3], buf
[4], buf
[5], buf
[6], buf
[7]);
606 case PIM_MSG_ADDRESS_FAMILY_IPV4
:
607 if ((addr
+ sizeof(struct in_addr
)) > pastend
) {
608 zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu",
610 pastend
- addr
, sizeof(struct in_addr
));
614 memcpy(&sg
->src
, addr
, sizeof(struct in_addr
));
617 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
619 Encoded-Source Address
621 The mask length MUST be equal to the mask length in bits for
622 the given Address Family and Encoding Type (32 for IPv4 native
623 and 128 for IPv6 native). A router SHOULD ignore any messages
624 received with any other mask length.
626 if (mask_len
!= 32) {
627 zlog_warn("%s: IPv4 bad source address mask: %d",
628 __PRETTY_FUNCTION__
, mask_len
);
632 addr
+= sizeof(struct in_addr
);
637 zlog_warn("%s: unknown source address encoding family=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
640 buf
[0], buf
[1], buf
[2], buf
[3], buf
[4], buf
[5], buf
[6], buf
[7]);
648 #define FREE_ADDR_LIST(hello_option_addr_list) \
650 if (hello_option_addr_list) { \
651 list_delete(hello_option_addr_list); \
652 hello_option_addr_list = 0; \
656 int pim_tlv_parse_addr_list(const char *ifname
, struct in_addr src_addr
,
657 pim_hello_options
*hello_options
,
658 struct list
**hello_option_addr_list
,
660 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
, sizeof(src_str
));
683 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
686 FREE_ADDR_LIST(*hello_option_addr_list
);
694 if (PIM_DEBUG_PIM_TRACE
) {
695 switch (tmp
.family
) {
698 char addr_str
[INET_ADDRSTRLEN
];
699 char src_str
[INET_ADDRSTRLEN
];
700 pim_inet4_dump("<addr?>", tmp
.u
.prefix4
, addr_str
, sizeof(addr_str
));
701 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
702 zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
704 *hello_option_addr_list
?
705 ((int) listcount(*hello_option_addr_list
)) : -1,
706 addr_str
, src_str
, ifname
);
711 char src_str
[INET_ADDRSTRLEN
];
712 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
713 zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
715 *hello_option_addr_list
?
716 ((int) listcount(*hello_option_addr_list
)) : -1,
723 Exclude neighbor's primary address if incorrectly included in
724 the secondary address list
726 if (tmp
.family
== AF_INET
) {
727 if (tmp
.u
.prefix4
.s_addr
== src_addr
.s_addr
) {
728 char src_str
[INET_ADDRSTRLEN
];
729 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
730 zlog_warn("%s: ignoring primary address in secondary list from %s on %s",
738 Allocate list if needed
740 if (!*hello_option_addr_list
) {
741 *hello_option_addr_list
= list_new();
742 if (!*hello_option_addr_list
) {
743 zlog_err("%s %s: failure: hello_option_addr_list=list_new()",
744 __FILE__
, __PRETTY_FUNCTION__
);
747 (*hello_option_addr_list
)->del
= (void (*)(void *)) prefix_free
;
757 zlog_err("%s %s: failure: prefix_new()",
758 __FILE__
, __PRETTY_FUNCTION__
);
759 FREE_ADDR_LIST(*hello_option_addr_list
);
762 p
->family
= tmp
.family
;
763 p
->u
.prefix4
= tmp
.u
.prefix4
;
764 listnode_add(*hello_option_addr_list
, p
);
767 } /* while (addr < pastend) */
772 PIM_OPTION_SET(*hello_options
, PIM_OPTION_MASK_ADDRESS_LIST
);