]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_tlv.c
lib: enforce vrf_name_to_id by returning default_vrf when name is null
[mirror_frr.git] / pimd / pim_tlv.c
CommitLineData
12e41d03 1/*
896014f4
DL
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 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
18 */
12e41d03
DL
19
20#include <zebra.h>
21
22#include "log.h"
23#include "prefix.h"
744d91b3 24#include "if.h"
12e41d03
DL
25
26#include "pimd.h"
27#include "pim_int.h"
28#include "pim_tlv.h"
29#include "pim_str.h"
30#include "pim_msg.h"
31
d62a17ae 32uint8_t *pim_tlv_append_uint16(uint8_t *buf, const uint8_t *buf_pastend,
33 uint16_t option_type, uint16_t option_value)
12e41d03 34{
d62a17ae 35 uint16_t option_len = 2;
12e41d03 36
d62a17ae 37 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
38 return NULL;
12e41d03 39
d62a17ae 40 *(uint16_t *)buf = htons(option_type);
41 buf += 2;
42 *(uint16_t *)buf = htons(option_len);
43 buf += 2;
44 *(uint16_t *)buf = htons(option_value);
45 buf += option_len;
12e41d03 46
d62a17ae 47 return buf;
12e41d03
DL
48}
49
d62a17ae 50uint8_t *pim_tlv_append_2uint16(uint8_t *buf, const uint8_t *buf_pastend,
51 uint16_t option_type, uint16_t option_value1,
12e41d03
DL
52 uint16_t option_value2)
53{
d62a17ae 54 uint16_t option_len = 4;
12e41d03 55
d62a17ae 56 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
57 return NULL;
12e41d03 58
d62a17ae 59 *(uint16_t *)buf = htons(option_type);
60 buf += 2;
61 *(uint16_t *)buf = htons(option_len);
62 buf += 2;
63 *(uint16_t *)buf = htons(option_value1);
64 buf += 2;
65 *(uint16_t *)buf = htons(option_value2);
66 buf += 2;
12e41d03 67
d62a17ae 68 return buf;
12e41d03
DL
69}
70
d62a17ae 71uint8_t *pim_tlv_append_uint32(uint8_t *buf, const uint8_t *buf_pastend,
72 uint16_t option_type, uint32_t option_value)
12e41d03 73{
d62a17ae 74 uint16_t option_len = 4;
12e41d03 75
d62a17ae 76 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
77 return NULL;
12e41d03 78
d62a17ae 79 *(uint16_t *)buf = htons(option_type);
80 buf += 2;
81 *(uint16_t *)buf = htons(option_len);
82 buf += 2;
83 pim_write_uint32(buf, option_value);
84 buf += option_len;
12e41d03 85
d62a17ae 86 return buf;
12e41d03
DL
87}
88
89#define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
0f4b1d2d 90#define ucast_ipv6_encoding_len (2 + sizeof(struct in6_addr))
12e41d03 91
984c84f4
DS
92/*
93 * An Encoded-Unicast address takes the following format:
94 *
95 * 0 1 2 3
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
100 *
101 * Addr Family
102 * The PIM address family of the 'Unicast Address' field of this
103 * address.
104 *
d62a17ae 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
984c84f4
DS
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.
110 *
111 * Encoding Type
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.
115 *
116 * Unicast Address
117 * The unicast address as represented by the given Address Family
118 * and Encoding Type.
119 */
d62a17ae 120int pim_encode_addr_ucast(uint8_t *buf, struct prefix *p)
4416b1f6 121{
d62a17ae 122 switch (p->family) {
123 case AF_INET:
124 *(uint8_t *)buf =
125 PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET !=
126 PIM_MSG_ADDRESS_FAMILY_IPV4
127 */
128 ++buf;
129 *(uint8_t *)buf = 0; /* ucast IPv4 native encoding type (RFC
130 4601: 4.9.1) */
131 ++buf;
132 memcpy(buf, &p->u.prefix4, sizeof(struct in_addr));
133 return ucast_ipv4_encoding_len;
134 break;
135 case AF_INET6:
136 *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV6;
137 ++buf;
138 *(uint8_t *)buf = 0;
139 ++buf;
140 memcpy(buf, &p->u.prefix6, sizeof(struct in6_addr));
141 return ucast_ipv6_encoding_len;
142 break;
143 default:
144 return 0;
145 break;
146 }
4416b1f6
DS
147}
148
8f483f92
DS
149#define group_ipv4_encoding_len (4 + sizeof (struct in_addr))
150
151/*
152 * Encoded-Group addresses take the following format:
153 *
154 * 0 1 2 3
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
161 *
162 * Addr Family
163 * Described above.
164 *
165 * Encoding Type
166 * Described above.
167 *
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.
171 *
172 * Reserved
173 * Transmitted as zero. Ignored upon receipt.
174 *
175 * Admin Scope [Z]one
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.
179 *
180 * Mask Len
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
189 * encoding).
190 *
191 * Group multicast Address
192 * Contains the group address.
193 */
d62a17ae 194int pim_encode_addr_group(uint8_t *buf, afi_t afi, int bidir, int scope,
195 struct in_addr group)
8f483f92 196{
d62a17ae 197 uint8_t flags = 0;
198
199 flags |= bidir << 8;
200 flags |= scope;
201
202 switch (afi) {
203 case AFI_IP:
204 *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV4;
205 ++buf;
206 *(uint8_t *)buf = 0;
207 ++buf;
208 *(uint8_t *)buf = flags;
209 ++buf;
210 *(uint8_t *)buf = 32;
211 ++buf;
212 memcpy(buf, &group, sizeof(struct in_addr));
213 return group_ipv4_encoding_len;
214 break;
215 default:
216 return 0;
217 break;
218 }
8f483f92
DS
219}
220
d62a17ae 221uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend,
222 struct list *ifconnected, int family)
12e41d03 223{
d62a17ae 224 struct listnode *node;
225 uint16_t option_len = 0;
226 uint8_t *curr;
227 size_t uel;
228
229 node = listhead(ifconnected);
230
231 /* Empty address list ? */
232 if (!node) {
233 return buf;
234 }
235
236 if (family == AF_INET)
237 uel = ucast_ipv4_encoding_len;
238 else
239 uel = ucast_ipv6_encoding_len;
240
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;
246 int l_encode;
247
248 if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
249 continue;
250
251 if ((curr + uel) > buf_pastend)
252 return 0;
253
254 if (p->family != family)
255 continue;
256
257 l_encode = pim_encode_addr_ucast(curr, p);
258 curr += l_encode;
259 option_len += l_encode;
260 }
261
262 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
263 zlog_debug(
264 "%s: number of encoded secondary unicast IPv4 addresses: %zu",
265 __PRETTY_FUNCTION__, option_len / uel);
266 }
267
268 if (option_len < 1) {
269 /* Empty secondary unicast IPv4 address list */
270 return buf;
271 }
272
273 /*
274 * Write T and L
275 */
276 *(uint16_t *)buf = htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST);
277 *(uint16_t *)(buf + 2) = htons(option_len);
278
279 return curr;
12e41d03
DL
280}
281
282static 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)
285{
d62a17ae 286 if (option_len != correct_len) {
287 char src_str[INET_ADDRSTRLEN];
288 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
289 zlog_warn(
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,
292 ifname);
293 return -1;
294 }
295
296 return 0;
12e41d03
DL
297}
298
d62a17ae 299static 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)
12e41d03 303{
d62a17ae 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));
307 zlog_warn(
308 "%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
309 label, tlv_name, new, old, src_str, ifname);
310 }
12e41d03
DL
311}
312
d62a17ae 313static 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)
12e41d03 317{
d62a17ae 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));
321 zlog_warn(
322 "%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
323 label, tlv_name, new, old, src_str, ifname);
324 }
12e41d03
DL
325}
326
d62a17ae 327static 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)
12e41d03 331{
d62a17ae 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));
335 zlog_warn(
336 "%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s",
337 label, tlv_name, new, old, src_str, ifname);
338 }
12e41d03
DL
339}
340
341int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr,
342 pim_hello_options *hello_options,
d62a17ae 343 uint16_t *hello_option_holdtime, uint16_t option_len,
344 const uint8_t *tlv_curr)
12e41d03 345{
d62a17ae 346 const char *label = "holdtime";
347
348 if (check_tlv_length(__PRETTY_FUNCTION__, label, ifname, src_addr,
349 sizeof(uint16_t), option_len)) {
350 return -1;
351 }
352
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);
357
358 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME);
359
360 *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr);
361
362 return 0;
12e41d03
DL
363}
364
365int 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,
d62a17ae 369 uint16_t option_len, const uint8_t *tlv_curr)
12e41d03 370{
d62a17ae 371 if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay", ifname,
372 src_addr, sizeof(uint32_t), option_len)) {
373 return -1;
374 }
375
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);
381
382 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY);
383
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);
389 } else {
390 PIM_OPTION_UNSET(*hello_options,
391 PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
392 }
393 ++tlv_curr;
394 ++tlv_curr;
395 *hello_option_override_interval =
396 PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr);
397
398 return 0;
12e41d03
DL
399}
400
401int 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,
d62a17ae 404 uint16_t option_len, const uint8_t *tlv_curr)
12e41d03 405{
d62a17ae 406 const char *label = "dr_priority";
407
408 if (check_tlv_length(__PRETTY_FUNCTION__, label, ifname, src_addr,
409 sizeof(uint32_t), option_len)) {
410 return -1;
411 }
412
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);
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;
12e41d03
DL
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,
d62a17ae 428 uint16_t option_len, const uint8_t *tlv_curr)
12e41d03 429{
d62a17ae 430 const char *label = "generation_id";
431
432 if (check_tlv_length(__PRETTY_FUNCTION__, label, ifname, src_addr,
433 sizeof(uint32_t), option_len)) {
434 return -1;
435 }
436
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);
442
443 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID);
444
445 *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr);
446
447 return 0;
12e41d03
DL
448}
449
d62a17ae 450int pim_parse_addr_ucast(struct prefix *p, const uint8_t *buf, int buf_size)
12e41d03 451{
d62a17ae 452 const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */
453 const uint8_t *addr;
454 const uint8_t *pastend;
455 int family;
456 int type;
457
458 if (buf_size < ucast_encoding_min_len) {
459 zlog_warn(
460 "%s: unicast address encoding overflow: left=%d needed=%d",
461 __PRETTY_FUNCTION__, buf_size, ucast_encoding_min_len);
462 return -1;
463 }
464
465 addr = buf;
466 pastend = buf + buf_size;
467
468 family = *addr++;
469 type = *addr++;
470
471 if (type) {
472 zlog_warn("%s: unknown unicast address encoding type=%d",
473 __PRETTY_FUNCTION__, type);
474 return -2;
475 }
476
477 switch (family) {
478 case PIM_MSG_ADDRESS_FAMILY_IPV4:
479 if ((addr + sizeof(struct in_addr)) > pastend) {
480 zlog_warn(
481 "%s: IPv4 unicast address overflow: left=%zd needed=%zu",
482 __PRETTY_FUNCTION__, pastend - addr,
483 sizeof(struct in_addr));
484 return -3;
485 }
486
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);
492
493 break;
494 case PIM_MSG_ADDRESS_FAMILY_IPV6:
495 if ((addr + sizeof(struct in6_addr)) > pastend) {
496 zlog_warn(
497 "%s: IPv6 unicast address overflow: left=%zd needed %zu",
498 __PRETTY_FUNCTION__, pastend - addr,
499 sizeof(struct in6_addr));
500 return -3;
501 }
502
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);
507
508 break;
509 default: {
510 zlog_warn("%s: unknown unicast address encoding family=%d from",
511 __PRETTY_FUNCTION__, family);
512 return -4;
513 }
514 }
515
516 return addr - buf;
12e41d03
DL
517}
518
d62a17ae 519int pim_parse_addr_group(struct prefix_sg *sg, const uint8_t *buf, int buf_size)
12e41d03 520{
d62a17ae 521 const int grp_encoding_min_len =
522 4; /* 1 family + 1 type + 1 reserved + 1 addr */
523 const uint8_t *addr;
524 const uint8_t *pastend;
525 int family;
526 int type;
527 int mask_len;
528
529 if (buf_size < grp_encoding_min_len) {
530 zlog_warn(
531 "%s: group address encoding overflow: left=%d needed=%d",
532 __PRETTY_FUNCTION__, buf_size, grp_encoding_min_len);
533 return -1;
534 }
535
536 addr = buf;
537 pastend = buf + buf_size;
538
539 family = *addr++;
540 type = *addr++;
541 //++addr;
542 ++addr; /* skip b_reserved_z fields */
543 mask_len = *addr++;
544
545 switch (family) {
546 case PIM_MSG_ADDRESS_FAMILY_IPV4:
547 if (type) {
548 zlog_warn(
549 "%s: unknown group address encoding type=%d from",
550 __PRETTY_FUNCTION__, type);
551 return -2;
552 }
553
554 if ((addr + sizeof(struct in_addr)) > pastend) {
555 zlog_warn(
556 "%s: IPv4 group address overflow: left=%zd needed=%zu from",
557 __PRETTY_FUNCTION__, pastend - addr,
558 sizeof(struct in_addr));
559 return -3;
560 }
561
562 memcpy(&sg->grp.s_addr, addr, sizeof(struct in_addr));
563
564 addr += sizeof(struct in_addr);
565
566 break;
567 default: {
568 zlog_warn(
569 "%s: unknown group address encoding family=%d mask_len=%d from",
570 __PRETTY_FUNCTION__, family, mask_len);
571 return -4;
572 }
573 }
574
575 return addr - buf;
12e41d03
DL
576}
577
d62a17ae 578int pim_parse_addr_source(struct prefix_sg *sg, uint8_t *flags,
579 const uint8_t *buf, int buf_size)
12e41d03 580{
d62a17ae 581 const int src_encoding_min_len =
582 4; /* 1 family + 1 type + 1 reserved + 1 addr */
583 const uint8_t *addr;
584 const uint8_t *pastend;
585 int family;
586 int type;
587 int mask_len;
588
589 if (buf_size < src_encoding_min_len) {
590 zlog_warn(
591 "%s: source address encoding overflow: left=%d needed=%d",
592 __PRETTY_FUNCTION__, buf_size, src_encoding_min_len);
593 return -1;
594 }
595
596 addr = buf;
597 pastend = buf + buf_size;
598
599 family = *addr++;
600 type = *addr++;
601 *flags = *addr++;
602 mask_len = *addr++;
12e41d03 603
d62a17ae 604 if (type) {
605 zlog_warn(
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]);
609 return -2;
610 }
611
612 switch (family) {
613 case PIM_MSG_ADDRESS_FAMILY_IPV4:
614 if ((addr + sizeof(struct in_addr)) > pastend) {
615 zlog_warn(
616 "%s: IPv4 source address overflow: left=%zd needed=%zu",
617 __PRETTY_FUNCTION__, pastend - addr,
618 sizeof(struct in_addr));
619 return -3;
620 }
621
622 memcpy(&sg->src, addr, sizeof(struct in_addr));
623
624 /*
625 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
626
627 Encoded-Source Address
628
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
631 native
632 and 128 for IPv6 native). A router SHOULD ignore any
633 messages
634 received with any other mask length.
635 */
636 if (mask_len != 32) {
637 zlog_warn("%s: IPv4 bad source address mask: %d",
638 __PRETTY_FUNCTION__, mask_len);
639 return -4;
640 }
641
642 addr += sizeof(struct in_addr);
643
644 break;
645 default: {
646 zlog_warn(
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]);
650 return -5;
651 }
652 }
653
654 return addr - buf;
12e41d03
DL
655}
656
996c9314
LB
657#define FREE_ADDR_LIST(hello_option_addr_list) \
658 { \
659 if (hello_option_addr_list) { \
6a154c88 660 list_delete(&hello_option_addr_list); \
996c9314
LB
661 hello_option_addr_list = 0; \
662 } \
d62a17ae 663 }
664
12e41d03
DL
665int 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,
d62a17ae 668 uint16_t option_len, const uint8_t *tlv_curr)
12e41d03 669{
d62a17ae 670 const uint8_t *addr;
671 const uint8_t *pastend;
672
673 zassert(hello_option_addr_list);
674
675 /*
676 Scan addr list
677 */
678 addr = tlv_curr;
679 pastend = tlv_curr + option_len;
680 while (addr < pastend) {
681 struct prefix tmp;
682 int addr_offset;
683
684 /*
685 Parse ucast addr
686 */
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,
691 sizeof(src_str));
692 zlog_warn(
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);
696 return -1;
697 }
698 addr += addr_offset;
699
700 /*
701 Debug
702 */
703 if (PIM_DEBUG_PIM_TRACE) {
704 switch (tmp.family) {
705 case AF_INET: {
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,
711 sizeof(src_str));
712 zlog_debug(
713 "%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
714 __PRETTY_FUNCTION__,
715 *hello_option_addr_list
716 ? ((int)listcount(
717 *hello_option_addr_list))
718 : -1,
719 addr_str, src_str, ifname);
720 } break;
721 case AF_INET6:
722 break;
723 default: {
724 char src_str[INET_ADDRSTRLEN];
725 pim_inet4_dump("<src?>", src_addr, src_str,
726 sizeof(src_str));
727 zlog_debug(
728 "%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
729 __PRETTY_FUNCTION__,
730 *hello_option_addr_list
731 ? ((int)listcount(
732 *hello_option_addr_list))
733 : -1,
734 src_str, ifname);
735 }
736 }
737 }
738
739 /*
740 Exclude neighbor's primary address if incorrectly included in
741 the secondary address list
742 */
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,
747 sizeof(src_str));
748 zlog_warn(
749 "%s: ignoring primary address in secondary list from %s on %s",
750 __PRETTY_FUNCTION__, src_str, ifname);
751 continue;
752 }
753 }
754
755 /*
756 Allocate list if needed
757 */
758 if (!*hello_option_addr_list) {
759 *hello_option_addr_list = list_new();
d62a17ae 760 (*hello_option_addr_list)->del =
761 (void (*)(void *))prefix_free;
762 }
763
764 /*
765 Attach addr to list
766 */
767 {
768 struct prefix *p;
769 p = prefix_new();
d62a17ae 770 prefix_copy(p, &tmp);
771 listnode_add(*hello_option_addr_list, p);
772 }
773
774 } /* while (addr < pastend) */
775
776 /*
777 Mark hello option
778 */
779 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST);
780
781 return 0;
12e41d03 782}