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,
20 $QuaggaId: $Format:%an, %ai, %h$ $
34 uint8_t *pim_tlv_append_uint16(uint8_t *buf,
35 const uint8_t *buf_pastend,
37 uint16_t option_value)
39 uint16_t option_len = 2;
41 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
44 *(uint16_t *) buf = htons(option_type);
46 *(uint16_t *) buf = htons(option_len);
48 *(uint16_t *) buf = htons(option_value);
54 uint8_t *pim_tlv_append_2uint16(uint8_t *buf,
55 const uint8_t *buf_pastend,
57 uint16_t option_value1,
58 uint16_t option_value2)
60 uint16_t option_len = 4;
62 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
65 *(uint16_t *) buf = htons(option_type);
67 *(uint16_t *) buf = htons(option_len);
69 *(uint16_t *) buf = htons(option_value1);
71 *(uint16_t *) buf = htons(option_value2);
77 uint8_t *pim_tlv_append_uint32(uint8_t *buf,
78 const uint8_t *buf_pastend,
80 uint32_t option_value)
82 uint16_t option_len = 4;
84 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
87 *(uint16_t *) buf = htons(option_type);
89 *(uint16_t *) buf = htons(option_len);
91 pim_write_uint32(buf, option_value);
97 #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
99 uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
100 const uint8_t *buf_pastend,
101 struct list *ifconnected)
103 struct listnode *node;
104 uint16_t option_len = 0;
108 node = listhead(ifconnected);
110 /* Empty address list ? */
115 /* Skip first address (primary) */
116 node = listnextnode(node);
118 /* Scan secondary address list */
119 curr = buf + 4; /* skip T and L */
120 for (; node; node = listnextnode(node)) {
121 struct connected *ifc = listgetdata(node);
122 struct prefix *p = ifc->address;
124 if (p->family != AF_INET)
127 if ((curr + ucast_ipv4_encoding_len) > buf_pastend)
130 /* Write encoded unicast IPv4 address */
131 *(uint8_t *) curr = PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
133 *(uint8_t *) curr = 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */
135 memcpy(curr, &p->u.prefix4, sizeof(struct in_addr));
136 curr += sizeof(struct in_addr);
138 option_len += ucast_ipv4_encoding_len;
141 if (PIM_DEBUG_PIM_TRACE) {
142 zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu",
144 option_len / ucast_ipv4_encoding_len);
147 if (option_len < 1) {
148 /* Empty secondary unicast IPv4 address list */
155 *(uint16_t *) buf = htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST);
156 *(uint16_t *) (buf + 2) = htons(option_len);
161 static int check_tlv_length(const char *label, const char *tlv_name,
162 const char *ifname, struct in_addr src_addr,
163 int correct_len, int option_len)
165 if (option_len != correct_len) {
167 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
168 zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s",
170 option_len, correct_len,
178 static void check_tlv_redefinition_uint16(const char *label, const char *tlv_name,
179 const char *ifname, struct in_addr src_addr,
180 pim_hello_options options,
181 pim_hello_options opt_mask,
182 uint16_t new, uint16_t old)
184 if (PIM_OPTION_IS_SET(options, opt_mask)) {
186 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
187 zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
194 static void check_tlv_redefinition_uint32(const char *label, const char *tlv_name,
195 const char *ifname, struct in_addr src_addr,
196 pim_hello_options options,
197 pim_hello_options opt_mask,
198 uint32_t new, uint32_t old)
200 if (PIM_OPTION_IS_SET(options, opt_mask)) {
202 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
203 zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
210 static void check_tlv_redefinition_uint32_hex(const char *label, const char *tlv_name,
211 const char *ifname, struct in_addr src_addr,
212 pim_hello_options options,
213 pim_hello_options opt_mask,
214 uint32_t new, uint32_t old)
216 if (PIM_OPTION_IS_SET(options, opt_mask)) {
218 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
219 zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s",
226 int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr,
227 pim_hello_options *hello_options,
228 uint16_t *hello_option_holdtime,
230 const uint8_t *tlv_curr)
232 const char *label = "holdtime";
234 if (check_tlv_length(__PRETTY_FUNCTION__, label,
236 sizeof(uint16_t), option_len)) {
240 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, label,
242 *hello_options, PIM_OPTION_MASK_HOLDTIME,
243 PIM_TLV_GET_HOLDTIME(tlv_curr),
244 *hello_option_holdtime);
246 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME);
248 *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr);
253 int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr,
254 pim_hello_options *hello_options,
255 uint16_t *hello_option_propagation_delay,
256 uint16_t *hello_option_override_interval,
258 const uint8_t *tlv_curr)
260 if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay",
262 sizeof(uint32_t), option_len)) {
266 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, "propagation_delay",
268 *hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY,
269 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr),
270 *hello_option_propagation_delay);
272 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY);
274 *hello_option_propagation_delay = PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr);
275 if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr)) {
276 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
279 PIM_OPTION_UNSET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
283 *hello_option_override_interval = PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr);
288 int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr,
289 pim_hello_options *hello_options,
290 uint32_t *hello_option_dr_priority,
292 const uint8_t *tlv_curr)
294 const char *label = "dr_priority";
296 if (check_tlv_length(__PRETTY_FUNCTION__, label,
298 sizeof(uint32_t), option_len)) {
302 check_tlv_redefinition_uint32(__PRETTY_FUNCTION__, label,
304 *hello_options, PIM_OPTION_MASK_DR_PRIORITY,
305 PIM_TLV_GET_DR_PRIORITY(tlv_curr),
306 *hello_option_dr_priority);
308 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY);
310 *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr);
315 int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr,
316 pim_hello_options *hello_options,
317 uint32_t *hello_option_generation_id,
319 const uint8_t *tlv_curr)
321 const char *label = "generation_id";
323 if (check_tlv_length(__PRETTY_FUNCTION__, label,
325 sizeof(uint32_t), option_len)) {
329 check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__, label,
331 *hello_options, PIM_OPTION_MASK_GENERATION_ID,
332 PIM_TLV_GET_GENERATION_ID(tlv_curr),
333 *hello_option_generation_id);
335 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID);
337 *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr);
342 int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr,
347 const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */
349 const uint8_t *pastend;
353 if (buf_size < ucast_encoding_min_len) {
355 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
356 zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d from %s on %s",
358 buf_size, ucast_encoding_min_len,
364 pastend = buf + buf_size;
370 case PIM_MSG_ADDRESS_FAMILY_IPV4:
373 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
374 zlog_warn("%s: unknown unicast address encoding type=%d from %s on %s",
376 type, src_str, ifname);
380 if ((addr + sizeof(struct in_addr)) > pastend) {
382 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
383 zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu from %s on %s",
385 pastend - addr, sizeof(struct in_addr),
390 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
391 memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
393 addr += sizeof(struct in_addr);
399 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
400 zlog_warn("%s: unknown unicast address encoding family=%d from %s on %s",
402 family, src_str, ifname);
410 int pim_parse_addr_group(const char *ifname, struct in_addr src_addr,
415 const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
417 const uint8_t *pastend;
422 if (buf_size < grp_encoding_min_len) {
424 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
425 zlog_warn("%s: group address encoding overflow: left=%d needed=%d from %s on %s",
427 buf_size, grp_encoding_min_len,
433 pastend = buf + buf_size;
438 ++addr; /* skip b_reserved_z fields */
442 case PIM_MSG_ADDRESS_FAMILY_IPV4:
445 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
446 zlog_warn("%s: unknown group address encoding type=%d from %s on %s",
448 type, src_str, ifname);
452 if ((addr + sizeof(struct in_addr)) > pastend) {
454 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
455 zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from %s on %s",
457 pastend - addr, sizeof(struct in_addr),
462 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
463 memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
464 p->prefixlen = mask_len;
466 addr += sizeof(struct in_addr);
472 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
473 zlog_warn("%s: unknown group address encoding family=%d from %s on %s",
475 family, src_str, ifname);
483 int pim_parse_addr_source(const char *ifname,
484 struct in_addr src_addr,
490 const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
492 const uint8_t *pastend;
497 if (buf_size < src_encoding_min_len) {
499 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
500 zlog_warn("%s: source address encoding overflow: left=%d needed=%d from %s on %s",
502 buf_size, src_encoding_min_len,
508 pastend = buf + buf_size;
516 case PIM_MSG_ADDRESS_FAMILY_IPV4:
519 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
520 zlog_warn("%s: unknown source address encoding type=%d from %s on %s: %02x%02x%02x%02x%02x%02x%02x%02x",
522 type, src_str, ifname,
523 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
527 if ((addr + sizeof(struct in_addr)) > pastend) {
529 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
530 zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu from %s on %s",
532 pastend - addr, sizeof(struct in_addr),
537 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
538 memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
539 p->prefixlen = mask_len;
542 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
544 Encoded-Source Address
546 The mask length MUST be equal to the mask length in bits for
547 the given Address Family and Encoding Type (32 for IPv4 native
548 and 128 for IPv6 native). A router SHOULD ignore any messages
549 received with any other mask length.
551 if (p->prefixlen != 32) {
553 pim_inet4_dump("<src?>", p->u.prefix4, src_str, sizeof(src_str));
554 zlog_warn("%s: IPv4 bad source address mask: %s/%d",
555 __PRETTY_FUNCTION__, src_str, p->prefixlen);
559 addr += sizeof(struct in_addr);
565 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
566 zlog_warn("%s: unknown source address encoding family=%d from %s on %s: %02x%02x%02x%02x%02x%02x%02x%02x",
568 family, src_str, ifname,
569 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
577 #define FREE_ADDR_LIST(hello_option_addr_list) \
579 if (hello_option_addr_list) { \
580 list_delete(hello_option_addr_list); \
581 hello_option_addr_list = 0; \
585 int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
586 pim_hello_options *hello_options,
587 struct list **hello_option_addr_list,
589 const uint8_t *tlv_curr)
592 const uint8_t *pastend;
594 zassert(hello_option_addr_list);
600 pastend = tlv_curr + option_len;
601 while (addr < pastend) {
608 addr_offset = pim_parse_addr_ucast(ifname, src_addr, &tmp,
609 addr, pastend - addr);
610 if (addr_offset < 1) {
612 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
613 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
616 FREE_ADDR_LIST(*hello_option_addr_list);
624 if (PIM_DEBUG_PIM_TRACE) {
625 switch (tmp.family) {
630 pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str));
631 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
632 zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
634 *hello_option_addr_list ?
635 ((int) listcount(*hello_option_addr_list)) : -1,
636 addr_str, src_str, ifname);
642 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
643 zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
645 *hello_option_addr_list ?
646 ((int) listcount(*hello_option_addr_list)) : -1,
653 Exclude neighbor's primary address if incorrectly included in
654 the secondary address list
656 if (tmp.family == AF_INET) {
657 if (tmp.u.prefix4.s_addr == src_addr.s_addr) {
659 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
660 zlog_warn("%s: ignoring primary address in secondary list from %s on %s",
668 Allocate list if needed
670 if (!*hello_option_addr_list) {
671 *hello_option_addr_list = list_new();
672 if (!*hello_option_addr_list) {
673 zlog_err("%s %s: failure: hello_option_addr_list=list_new()",
674 __FILE__, __PRETTY_FUNCTION__);
677 (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free;
687 zlog_err("%s %s: failure: prefix_new()",
688 __FILE__, __PRETTY_FUNCTION__);
689 FREE_ADDR_LIST(*hello_option_addr_list);
692 p->family = tmp.family;
693 p->u.prefix4 = tmp.u.prefix4;
694 listnode_add(*hello_option_addr_list, p);
697 } /* while (addr < pastend) */
702 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST);