]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_tlv.c
pimd: Only debug in the unusual case
[mirror_frr.git] / pimd / pim_tlv.c
CommitLineData
12e41d03
DL
1/*
2 PIM for Quagga
3 Copyright (C) 2008 Everton da Silva Marques
4
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.
9
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.
14
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,
18 MA 02110-1301 USA
12e41d03
DL
19*/
20
21#include <zebra.h>
22
23#include "log.h"
24#include "prefix.h"
744d91b3 25#include "if.h"
12e41d03
DL
26
27#include "pimd.h"
28#include "pim_int.h"
29#include "pim_tlv.h"
30#include "pim_str.h"
31#include "pim_msg.h"
32
33uint8_t *pim_tlv_append_uint16(uint8_t *buf,
34 const uint8_t *buf_pastend,
35 uint16_t option_type,
36 uint16_t option_value)
37{
38 uint16_t option_len = 2;
39
aea6cb94
DS
40 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
41 return NULL;
12e41d03
DL
42
43 *(uint16_t *) buf = htons(option_type);
44 buf += 2;
45 *(uint16_t *) buf = htons(option_len);
46 buf += 2;
47 *(uint16_t *) buf = htons(option_value);
48 buf += option_len;
49
50 return buf;
51}
52
53uint8_t *pim_tlv_append_2uint16(uint8_t *buf,
54 const uint8_t *buf_pastend,
55 uint16_t option_type,
56 uint16_t option_value1,
57 uint16_t option_value2)
58{
59 uint16_t option_len = 4;
60
aea6cb94
DS
61 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
62 return NULL;
12e41d03
DL
63
64 *(uint16_t *) buf = htons(option_type);
65 buf += 2;
66 *(uint16_t *) buf = htons(option_len);
67 buf += 2;
68 *(uint16_t *) buf = htons(option_value1);
69 buf += 2;
70 *(uint16_t *) buf = htons(option_value2);
71 buf += 2;
72
73 return buf;
74}
75
76uint8_t *pim_tlv_append_uint32(uint8_t *buf,
77 const uint8_t *buf_pastend,
78 uint16_t option_type,
79 uint32_t option_value)
80{
81 uint16_t option_len = 4;
82
aea6cb94
DS
83 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
84 return NULL;
12e41d03
DL
85
86 *(uint16_t *) buf = htons(option_type);
87 buf += 2;
88 *(uint16_t *) buf = htons(option_len);
89 buf += 2;
90 pim_write_uint32(buf, option_value);
91 buf += option_len;
92
93 return buf;
94}
95
96#define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
97
984c84f4
DS
98/*
99 * An Encoded-Unicast address takes the following format:
100 *
101 * 0 1 2 3
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
106 *
107 * Addr Family
108 * The PIM address family of the 'Unicast Address' field of this
109 * address.
110 *
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.
115 *
116 * Encoding Type
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.
120 *
121 * Unicast Address
122 * The unicast address as represented by the given Address Family
123 * and Encoding Type.
124 */
8f483f92
DS
125int
126pim_encode_addr_ucast (uint8_t *buf, struct prefix *p)
4416b1f6
DS
127{
128 switch (p->family)
129 {
130 case AF_INET:
131 *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
132 ++buf;
133 *(uint8_t *)buf = 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */
134 ++buf;
135 memcpy (buf, &p->u.prefix4, sizeof (struct in_addr));
136 return ucast_ipv4_encoding_len;
137 break;
138 default:
139 return 0;
140 break;
141 }
142}
143
8f483f92
DS
144#define group_ipv4_encoding_len (4 + sizeof (struct in_addr))
145
146/*
147 * Encoded-Group addresses take the following format:
148 *
149 * 0 1 2 3
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
156 *
157 * Addr Family
158 * Described above.
159 *
160 * Encoding Type
161 * Described above.
162 *
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.
166 *
167 * Reserved
168 * Transmitted as zero. Ignored upon receipt.
169 *
170 * Admin Scope [Z]one
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.
174 *
175 * Mask Len
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
184 * encoding).
185 *
186 * Group multicast Address
187 * Contains the group address.
188 */
189int
190pim_encode_addr_group (uint8_t *buf, afi_t afi, int bidir, int scope, struct in_addr group)
191{
192 uint8_t flags = 0;
193
194 flags |= bidir << 8;
195 flags |= scope;
196
197 switch (afi)
198 {
199 case AFI_IP:
200 *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV4;
201 ++buf;
202 *(uint8_t *)buf = 0;
203 ++buf;
204 *(uint8_t *)buf = flags;
205 ++buf;
206 *(uint8_t *)buf = 32;
207 ++buf;
208 memcpy (buf, &group, sizeof (struct in_addr));
209 return group_ipv4_encoding_len;
210 break;
211 default:
212 return 0;
213 break;
214 }
215}
216
12e41d03
DL
217uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
218 const uint8_t *buf_pastend,
219 struct list *ifconnected)
220{
221 struct listnode *node;
222 uint16_t option_len = 0;
223
224 uint8_t *curr;
225
226 node = listhead(ifconnected);
227
228 /* Empty address list ? */
229 if (!node) {
230 return buf;
231 }
232
233 /* Skip first address (primary) */
234 node = listnextnode(node);
235
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;
4416b1f6 241 int l_encode;
12e41d03 242
aea6cb94 243 if ((curr + ucast_ipv4_encoding_len) > buf_pastend)
12e41d03 244 return 0;
12e41d03 245
8f483f92 246 l_encode = pim_encode_addr_ucast (curr, p);
4416b1f6
DS
247 curr += l_encode;
248 option_len += l_encode;
12e41d03
DL
249 }
250
169edb7f 251 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
aea6cb94
DS
252 zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu",
253 __PRETTY_FUNCTION__,
254 option_len / ucast_ipv4_encoding_len);
12e41d03
DL
255 }
256
257 if (option_len < 1) {
258 /* Empty secondary unicast IPv4 address list */
259 return buf;
260 }
261
262 /*
263 * Write T and L
264 */
265 *(uint16_t *) buf = htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST);
266 *(uint16_t *) (buf + 2) = htons(option_len);
267
268 return curr;
269}
270
271static 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)
274{
275 if (option_len != correct_len) {
eaa54bdb 276 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
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",
279 label, tlv_name,
280 option_len, correct_len,
281 src_str, ifname);
282 return -1;
283 }
284
285 return 0;
286}
287
288static 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)
293{
294 if (PIM_OPTION_IS_SET(options, opt_mask)) {
eaa54bdb 295 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
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",
298 label, tlv_name,
299 new, old,
300 src_str, ifname);
301 }
302}
303
304static 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)
309{
310 if (PIM_OPTION_IS_SET(options, opt_mask)) {
eaa54bdb 311 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
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",
314 label, tlv_name,
315 new, old,
316 src_str, ifname);
317 }
318}
319
320static 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)
325{
326 if (PIM_OPTION_IS_SET(options, opt_mask)) {
eaa54bdb 327 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
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",
330 label, tlv_name,
331 new, old,
332 src_str, ifname);
333 }
334}
335
336int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr,
337 pim_hello_options *hello_options,
338 uint16_t *hello_option_holdtime,
339 uint16_t option_len,
340 const uint8_t *tlv_curr)
341{
342 const char *label = "holdtime";
343
344 if (check_tlv_length(__PRETTY_FUNCTION__, label,
345 ifname, src_addr,
346 sizeof(uint16_t), option_len)) {
347 return -1;
348 }
349
350 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, label,
351 ifname, src_addr,
352 *hello_options, PIM_OPTION_MASK_HOLDTIME,
353 PIM_TLV_GET_HOLDTIME(tlv_curr),
354 *hello_option_holdtime);
355
356 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME);
357
358 *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr);
359
360 return 0;
361}
362
363int 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,
367 uint16_t option_len,
368 const uint8_t *tlv_curr)
369{
370 if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay",
371 ifname, src_addr,
372 sizeof(uint32_t), option_len)) {
373 return -1;
374 }
375
376 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, "propagation_delay",
377 ifname, src_addr,
378 *hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY,
379 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr),
380 *hello_option_propagation_delay);
381
382 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY);
383
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);
387 }
388 else {
389 PIM_OPTION_UNSET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
390 }
391 ++tlv_curr;
392 ++tlv_curr;
393 *hello_option_override_interval = PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr);
394
395 return 0;
396}
397
398int 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,
401 uint16_t option_len,
402 const uint8_t *tlv_curr)
403{
404 const char *label = "dr_priority";
405
406 if (check_tlv_length(__PRETTY_FUNCTION__, label,
407 ifname, src_addr,
408 sizeof(uint32_t), option_len)) {
409 return -1;
410 }
411
412 check_tlv_redefinition_uint32(__PRETTY_FUNCTION__, label,
413 ifname, src_addr,
414 *hello_options, PIM_OPTION_MASK_DR_PRIORITY,
415 PIM_TLV_GET_DR_PRIORITY(tlv_curr),
416 *hello_option_dr_priority);
417
418 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY);
419
420 *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr);
421
422 return 0;
423}
424
425int 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,
429 const uint8_t *tlv_curr)
430{
431 const char *label = "generation_id";
432
433 if (check_tlv_length(__PRETTY_FUNCTION__, label,
434 ifname, src_addr,
435 sizeof(uint32_t), option_len)) {
436 return -1;
437 }
438
439 check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__, label,
440 ifname, src_addr,
441 *hello_options, PIM_OPTION_MASK_GENERATION_ID,
442 PIM_TLV_GET_GENERATION_ID(tlv_curr),
443 *hello_option_generation_id);
444
445 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID);
446
447 *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr);
448
449 return 0;
450}
451
4416b1f6
DS
452int
453pim_parse_addr_ucast (struct prefix *p,
454 const uint8_t *buf,
455 int buf_size)
12e41d03
DL
456{
457 const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */
458 const uint8_t *addr;
459 const uint8_t *pastend;
460 int family;
461 int type;
462
463 if (buf_size < ucast_encoding_min_len) {
4416b1f6 464 zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d",
12e41d03 465 __PRETTY_FUNCTION__,
4416b1f6 466 buf_size, ucast_encoding_min_len);
12e41d03
DL
467 return -1;
468 }
469
470 addr = buf;
471 pastend = buf + buf_size;
472
473 family = *addr++;
474 type = *addr++;
475
4416b1f6
DS
476 if (type) {
477 zlog_warn("%s: unknown unicast address encoding type=%d",
478 __PRETTY_FUNCTION__,
479 type);
480 return -2;
481 }
482
12e41d03
DL
483 switch (family) {
484 case PIM_MSG_ADDRESS_FAMILY_IPV4:
12e41d03 485 if ((addr + sizeof(struct in_addr)) > pastend) {
4416b1f6 486 zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu",
12e41d03 487 __PRETTY_FUNCTION__,
4416b1f6 488 pastend - addr, sizeof(struct in_addr));
12e41d03
DL
489 return -3;
490 }
491
492 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
493 memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
494
495 addr += sizeof(struct in_addr);
496
497 break;
498 default:
499 {
4416b1f6 500 zlog_warn("%s: unknown unicast address encoding family=%d from",
12e41d03 501 __PRETTY_FUNCTION__,
4416b1f6 502 family);
12e41d03
DL
503 return -4;
504 }
505 }
506
507 return addr - buf;
508}
509
4416b1f6 510int
bce0e645 511pim_parse_addr_group (struct prefix_sg *sg,
4416b1f6
DS
512 const uint8_t *buf,
513 int buf_size)
12e41d03
DL
514{
515 const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
516 const uint8_t *addr;
517 const uint8_t *pastend;
518 int family;
519 int type;
520 int mask_len;
521
522 if (buf_size < grp_encoding_min_len) {
4416b1f6 523 zlog_warn("%s: group address encoding overflow: left=%d needed=%d",
12e41d03 524 __PRETTY_FUNCTION__,
4416b1f6 525 buf_size, grp_encoding_min_len);
12e41d03
DL
526 return -1;
527 }
528
529 addr = buf;
530 pastend = buf + buf_size;
531
532 family = *addr++;
533 type = *addr++;
534 //++addr;
535 ++addr; /* skip b_reserved_z fields */
536 mask_len = *addr++;
537
538 switch (family) {
539 case PIM_MSG_ADDRESS_FAMILY_IPV4:
540 if (type) {
4416b1f6
DS
541 zlog_warn("%s: unknown group address encoding type=%d from",
542 __PRETTY_FUNCTION__, type);
12e41d03
DL
543 return -2;
544 }
545
546 if ((addr + sizeof(struct in_addr)) > pastend) {
4416b1f6 547 zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from",
12e41d03 548 __PRETTY_FUNCTION__,
4416b1f6 549 pastend - addr, sizeof(struct in_addr));
12e41d03
DL
550 return -3;
551 }
552
bce0e645 553 memcpy(&sg->grp.s_addr, addr, sizeof(struct in_addr));
12e41d03
DL
554
555 addr += sizeof(struct in_addr);
556
557 break;
558 default:
559 {
bce0e645
DS
560 zlog_warn("%s: unknown group address encoding family=%d mask_len=%d from",
561 __PRETTY_FUNCTION__, family, mask_len);
12e41d03
DL
562 return -4;
563 }
564 }
565
566 return addr - buf;
567}
568
4416b1f6 569int
a7762e07 570pim_parse_addr_source(struct prefix_sg *sg,
4416b1f6
DS
571 uint8_t *flags,
572 const uint8_t *buf,
573 int buf_size)
12e41d03
DL
574{
575 const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
576 const uint8_t *addr;
577 const uint8_t *pastend;
578 int family;
579 int type;
580 int mask_len;
581
582 if (buf_size < src_encoding_min_len) {
4416b1f6 583 zlog_warn("%s: source address encoding overflow: left=%d needed=%d",
12e41d03 584 __PRETTY_FUNCTION__,
4416b1f6 585 buf_size, src_encoding_min_len);
12e41d03
DL
586 return -1;
587 }
588
589 addr = buf;
590 pastend = buf + buf_size;
591
592 family = *addr++;
593 type = *addr++;
594 *flags = *addr++;
595 mask_len = *addr++;
596
4416b1f6
DS
597 if (type) {
598 zlog_warn("%s: unknown source address encoding type=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
599 __PRETTY_FUNCTION__,
600 type,
601 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
602 return -2;
603 }
604
12e41d03
DL
605 switch (family) {
606 case PIM_MSG_ADDRESS_FAMILY_IPV4:
12e41d03 607 if ((addr + sizeof(struct in_addr)) > pastend) {
4416b1f6 608 zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu",
12e41d03 609 __PRETTY_FUNCTION__,
4416b1f6 610 pastend - addr, sizeof(struct in_addr));
12e41d03
DL
611 return -3;
612 }
613
a7762e07 614 memcpy(&sg->src, addr, sizeof(struct in_addr));
12e41d03
DL
615
616 /*
617 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
618
619 Encoded-Source Address
620
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.
625 */
a7762e07 626 if (mask_len != 32) {
4416b1f6 627 zlog_warn("%s: IPv4 bad source address mask: %d",
a7762e07 628 __PRETTY_FUNCTION__, mask_len);
12e41d03
DL
629 return -4;
630 }
631
632 addr += sizeof(struct in_addr);
633
634 break;
635 default:
636 {
4416b1f6 637 zlog_warn("%s: unknown source address encoding family=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
12e41d03 638 __PRETTY_FUNCTION__,
4416b1f6 639 family,
12e41d03
DL
640 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
641 return -5;
642 }
643 }
644
645 return addr - buf;
646}
647
648#define FREE_ADDR_LIST(hello_option_addr_list) \
649{ \
650 if (hello_option_addr_list) { \
651 list_delete(hello_option_addr_list); \
652 hello_option_addr_list = 0; \
653 } \
654}
655
656int 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,
659 uint16_t option_len,
660 const uint8_t *tlv_curr)
661{
662 const uint8_t *addr;
663 const uint8_t *pastend;
664
665 zassert(hello_option_addr_list);
666
667 /*
668 Scan addr list
669 */
670 addr = tlv_curr;
671 pastend = tlv_curr + option_len;
672 while (addr < pastend) {
673 struct prefix tmp;
674 int addr_offset;
675
676 /*
677 Parse ucast addr
678 */
4416b1f6 679 addr_offset = pim_parse_addr_ucast(&tmp, addr, pastend - addr);
12e41d03 680 if (addr_offset < 1) {
eaa54bdb 681 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
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",
684 __PRETTY_FUNCTION__,
685 src_str, ifname);
686 FREE_ADDR_LIST(*hello_option_addr_list);
687 return -1;
688 }
689 addr += addr_offset;
690
691 /*
692 Debug
693 */
694 if (PIM_DEBUG_PIM_TRACE) {
695 switch (tmp.family) {
696 case AF_INET:
697 {
eaa54bdb
DW
698 char addr_str[INET_ADDRSTRLEN];
699 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
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",
703 __PRETTY_FUNCTION__,
704 *hello_option_addr_list ?
705 ((int) listcount(*hello_option_addr_list)) : -1,
706 addr_str, src_str, ifname);
707 }
708 break;
709 default:
710 {
eaa54bdb 711 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
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",
714 __PRETTY_FUNCTION__,
715 *hello_option_addr_list ?
716 ((int) listcount(*hello_option_addr_list)) : -1,
717 src_str, ifname);
718 }
719 }
720 }
721
722 /*
723 Exclude neighbor's primary address if incorrectly included in
724 the secondary address list
725 */
726 if (tmp.family == AF_INET) {
727 if (tmp.u.prefix4.s_addr == src_addr.s_addr) {
eaa54bdb 728 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
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",
731 __PRETTY_FUNCTION__,
732 src_str, ifname);
733 continue;
734 }
735 }
736
737 /*
738 Allocate list if needed
739 */
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__);
745 return -2;
746 }
747 (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free;
748 }
749
750 /*
751 Attach addr to list
752 */
753 {
754 struct prefix *p;
755 p = prefix_new();
756 if (!p) {
757 zlog_err("%s %s: failure: prefix_new()",
758 __FILE__, __PRETTY_FUNCTION__);
759 FREE_ADDR_LIST(*hello_option_addr_list);
760 return -3;
761 }
762 p->family = tmp.family;
763 p->u.prefix4 = tmp.u.prefix4;
764 listnode_add(*hello_option_addr_list, p);
765 }
766
767 } /* while (addr < pastend) */
768
769 /*
770 Mark hello option
771 */
772 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST);
773
774 return 0;
775}