]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_tlv.c
Merge branch 'stable/3.0'
[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
32uint8_t *pim_tlv_append_uint16(uint8_t *buf,
33 const uint8_t *buf_pastend,
34 uint16_t option_type,
35 uint16_t option_value)
36{
37 uint16_t option_len = 2;
38
aea6cb94
DS
39 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
40 return NULL;
12e41d03
DL
41
42 *(uint16_t *) buf = htons(option_type);
43 buf += 2;
44 *(uint16_t *) buf = htons(option_len);
45 buf += 2;
46 *(uint16_t *) buf = htons(option_value);
47 buf += option_len;
48
49 return buf;
50}
51
52uint8_t *pim_tlv_append_2uint16(uint8_t *buf,
53 const uint8_t *buf_pastend,
54 uint16_t option_type,
55 uint16_t option_value1,
56 uint16_t option_value2)
57{
58 uint16_t option_len = 4;
59
aea6cb94
DS
60 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
61 return NULL;
12e41d03
DL
62
63 *(uint16_t *) buf = htons(option_type);
64 buf += 2;
65 *(uint16_t *) buf = htons(option_len);
66 buf += 2;
67 *(uint16_t *) buf = htons(option_value1);
68 buf += 2;
69 *(uint16_t *) buf = htons(option_value2);
70 buf += 2;
71
72 return buf;
73}
74
75uint8_t *pim_tlv_append_uint32(uint8_t *buf,
76 const uint8_t *buf_pastend,
77 uint16_t option_type,
78 uint32_t option_value)
79{
80 uint16_t option_len = 4;
81
aea6cb94
DS
82 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
83 return NULL;
12e41d03
DL
84
85 *(uint16_t *) buf = htons(option_type);
86 buf += 2;
87 *(uint16_t *) buf = htons(option_len);
88 buf += 2;
89 pim_write_uint32(buf, option_value);
90 buf += option_len;
91
92 return buf;
93}
94
95#define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
0f4b1d2d 96#define ucast_ipv6_encoding_len (2 + sizeof(struct in6_addr))
12e41d03 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;
0f4b1d2d
DS
138 case AF_INET6:
139 *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV6;
140 ++buf;
141 *(uint8_t *)buf = 0;
142 ++buf;
143 memcpy (buf, &p->u.prefix6, sizeof (struct in6_addr));
144 return ucast_ipv6_encoding_len;
145 break;
4416b1f6
DS
146 default:
147 return 0;
148 break;
149 }
150}
151
8f483f92
DS
152#define group_ipv4_encoding_len (4 + sizeof (struct in_addr))
153
154/*
155 * Encoded-Group addresses take the following format:
156 *
157 * 0 1 2 3
158 * 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
159 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
160 * | Addr Family | Encoding Type |B| Reserved |Z| Mask Len |
161 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
162 * | Group multicast Address
163 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
164 *
165 * Addr Family
166 * Described above.
167 *
168 * Encoding Type
169 * Described above.
170 *
171 * [B]idirectional PIM
172 * Indicates the group range should use Bidirectional PIM [13].
173 * For PIM-SM defined in this specification, this bit MUST be zero.
174 *
175 * Reserved
176 * Transmitted as zero. Ignored upon receipt.
177 *
178 * Admin Scope [Z]one
179 * indicates the group range is an admin scope zone. This is used
180 * in the Bootstrap Router Mechanism [11] only. For all other
181 * purposes, this bit is set to zero and ignored on receipt.
182 *
183 * Mask Len
184 * The Mask length field is 8 bits. The value is the number of
185 * contiguous one bits that are left justified and used as a mask;
186 * when combined with the group address, it describes a range of
187 * groups. It is less than or equal to the address length in bits
188 * for the given Address Family and Encoding Type. If the message
189 * is sent for a single group, then the Mask length must equal the
190 * address length in bits for the given Address Family and Encoding
191 * Type (e.g., 32 for IPv4 native encoding, 128 for IPv6 native
192 * encoding).
193 *
194 * Group multicast Address
195 * Contains the group address.
196 */
197int
198pim_encode_addr_group (uint8_t *buf, afi_t afi, int bidir, int scope, struct in_addr group)
199{
200 uint8_t flags = 0;
201
202 flags |= bidir << 8;
203 flags |= scope;
204
205 switch (afi)
206 {
207 case AFI_IP:
208 *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV4;
209 ++buf;
210 *(uint8_t *)buf = 0;
211 ++buf;
212 *(uint8_t *)buf = flags;
213 ++buf;
214 *(uint8_t *)buf = 32;
215 ++buf;
216 memcpy (buf, &group, sizeof (struct in_addr));
217 return group_ipv4_encoding_len;
218 break;
219 default:
220 return 0;
221 break;
222 }
223}
224
12e41d03
DL
225uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
226 const uint8_t *buf_pastend,
0f4b1d2d
DS
227 struct list *ifconnected,
228 int family)
12e41d03
DL
229{
230 struct listnode *node;
231 uint16_t option_len = 0;
12e41d03 232 uint8_t *curr;
0f4b1d2d 233 size_t uel;
12e41d03
DL
234
235 node = listhead(ifconnected);
236
237 /* Empty address list ? */
238 if (!node) {
239 return buf;
240 }
241
0f4b1d2d
DS
242 if (family == AF_INET)
243 uel = ucast_ipv4_encoding_len;
244 else
245 uel = ucast_ipv6_encoding_len;
12e41d03
DL
246
247 /* Scan secondary address list */
248 curr = buf + 4; /* skip T and L */
249 for (; node; node = listnextnode(node)) {
250 struct connected *ifc = listgetdata(node);
251 struct prefix *p = ifc->address;
4416b1f6 252 int l_encode;
12e41d03 253
0f4b1d2d
DS
254 if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
255 continue;
256
257 if ((curr + uel) > buf_pastend)
258 return 0;
259
260 if (p->family != family)
261 continue;
12e41d03 262
8f483f92 263 l_encode = pim_encode_addr_ucast (curr, p);
4416b1f6
DS
264 curr += l_encode;
265 option_len += l_encode;
12e41d03
DL
266 }
267
169edb7f 268 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
aea6cb94
DS
269 zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu",
270 __PRETTY_FUNCTION__,
0f4b1d2d 271 option_len / uel);
12e41d03
DL
272 }
273
274 if (option_len < 1) {
275 /* Empty secondary unicast IPv4 address list */
276 return buf;
277 }
278
279 /*
280 * Write T and L
281 */
282 *(uint16_t *) buf = htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST);
283 *(uint16_t *) (buf + 2) = htons(option_len);
284
285 return curr;
286}
287
288static int check_tlv_length(const char *label, const char *tlv_name,
289 const char *ifname, struct in_addr src_addr,
290 int correct_len, int option_len)
291{
292 if (option_len != correct_len) {
eaa54bdb 293 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
294 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
295 zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s",
296 label, tlv_name,
297 option_len, correct_len,
298 src_str, ifname);
299 return -1;
300 }
301
302 return 0;
303}
304
305static void check_tlv_redefinition_uint16(const char *label, const char *tlv_name,
306 const char *ifname, struct in_addr src_addr,
307 pim_hello_options options,
308 pim_hello_options opt_mask,
309 uint16_t new, uint16_t old)
310{
311 if (PIM_OPTION_IS_SET(options, opt_mask)) {
eaa54bdb 312 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
313 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
314 zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
315 label, tlv_name,
316 new, old,
317 src_str, ifname);
318 }
319}
320
321static void check_tlv_redefinition_uint32(const char *label, const char *tlv_name,
322 const char *ifname, struct in_addr src_addr,
323 pim_hello_options options,
324 pim_hello_options opt_mask,
325 uint32_t new, uint32_t old)
326{
327 if (PIM_OPTION_IS_SET(options, opt_mask)) {
eaa54bdb 328 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
329 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
330 zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
331 label, tlv_name,
332 new, old,
333 src_str, ifname);
334 }
335}
336
337static void check_tlv_redefinition_uint32_hex(const char *label, const char *tlv_name,
338 const char *ifname, struct in_addr src_addr,
339 pim_hello_options options,
340 pim_hello_options opt_mask,
341 uint32_t new, uint32_t old)
342{
343 if (PIM_OPTION_IS_SET(options, opt_mask)) {
eaa54bdb 344 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
345 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
346 zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s",
347 label, tlv_name,
348 new, old,
349 src_str, ifname);
350 }
351}
352
353int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr,
354 pim_hello_options *hello_options,
355 uint16_t *hello_option_holdtime,
356 uint16_t option_len,
357 const uint8_t *tlv_curr)
358{
359 const char *label = "holdtime";
360
361 if (check_tlv_length(__PRETTY_FUNCTION__, label,
362 ifname, src_addr,
363 sizeof(uint16_t), option_len)) {
364 return -1;
365 }
366
367 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, label,
368 ifname, src_addr,
369 *hello_options, PIM_OPTION_MASK_HOLDTIME,
370 PIM_TLV_GET_HOLDTIME(tlv_curr),
371 *hello_option_holdtime);
372
373 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME);
374
375 *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr);
376
377 return 0;
378}
379
380int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr,
381 pim_hello_options *hello_options,
382 uint16_t *hello_option_propagation_delay,
383 uint16_t *hello_option_override_interval,
384 uint16_t option_len,
385 const uint8_t *tlv_curr)
386{
387 if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay",
388 ifname, src_addr,
389 sizeof(uint32_t), option_len)) {
390 return -1;
391 }
392
393 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, "propagation_delay",
394 ifname, src_addr,
395 *hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY,
396 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr),
397 *hello_option_propagation_delay);
398
399 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY);
400
401 *hello_option_propagation_delay = PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr);
402 if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr)) {
403 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
404 }
405 else {
406 PIM_OPTION_UNSET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
407 }
408 ++tlv_curr;
409 ++tlv_curr;
410 *hello_option_override_interval = PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr);
411
412 return 0;
413}
414
415int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr,
416 pim_hello_options *hello_options,
417 uint32_t *hello_option_dr_priority,
418 uint16_t option_len,
419 const uint8_t *tlv_curr)
420{
421 const char *label = "dr_priority";
422
423 if (check_tlv_length(__PRETTY_FUNCTION__, label,
424 ifname, src_addr,
425 sizeof(uint32_t), option_len)) {
426 return -1;
427 }
428
429 check_tlv_redefinition_uint32(__PRETTY_FUNCTION__, label,
430 ifname, src_addr,
431 *hello_options, PIM_OPTION_MASK_DR_PRIORITY,
432 PIM_TLV_GET_DR_PRIORITY(tlv_curr),
433 *hello_option_dr_priority);
434
435 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY);
436
437 *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr);
438
439 return 0;
440}
441
442int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr,
443 pim_hello_options *hello_options,
444 uint32_t *hello_option_generation_id,
445 uint16_t option_len,
446 const uint8_t *tlv_curr)
447{
448 const char *label = "generation_id";
449
450 if (check_tlv_length(__PRETTY_FUNCTION__, label,
451 ifname, src_addr,
452 sizeof(uint32_t), option_len)) {
453 return -1;
454 }
455
456 check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__, label,
457 ifname, src_addr,
458 *hello_options, PIM_OPTION_MASK_GENERATION_ID,
459 PIM_TLV_GET_GENERATION_ID(tlv_curr),
460 *hello_option_generation_id);
461
462 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID);
463
464 *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr);
465
466 return 0;
467}
468
4416b1f6
DS
469int
470pim_parse_addr_ucast (struct prefix *p,
471 const uint8_t *buf,
472 int buf_size)
12e41d03
DL
473{
474 const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */
475 const uint8_t *addr;
476 const uint8_t *pastend;
477 int family;
478 int type;
479
480 if (buf_size < ucast_encoding_min_len) {
4416b1f6 481 zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d",
12e41d03 482 __PRETTY_FUNCTION__,
4416b1f6 483 buf_size, ucast_encoding_min_len);
12e41d03
DL
484 return -1;
485 }
486
487 addr = buf;
488 pastend = buf + buf_size;
489
490 family = *addr++;
491 type = *addr++;
492
4416b1f6
DS
493 if (type) {
494 zlog_warn("%s: unknown unicast address encoding type=%d",
495 __PRETTY_FUNCTION__,
496 type);
497 return -2;
498 }
499
12e41d03
DL
500 switch (family) {
501 case PIM_MSG_ADDRESS_FAMILY_IPV4:
12e41d03 502 if ((addr + sizeof(struct in_addr)) > pastend) {
4416b1f6 503 zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu",
12e41d03 504 __PRETTY_FUNCTION__,
4416b1f6 505 pastend - addr, sizeof(struct in_addr));
12e41d03
DL
506 return -3;
507 }
508
509 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
510 memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
0f4b1d2d 511 p->prefixlen = IPV4_MAX_PREFIXLEN;
12e41d03
DL
512 addr += sizeof(struct in_addr);
513
0f4b1d2d
DS
514 break;
515 case PIM_MSG_ADDRESS_FAMILY_IPV6:
516 if ((addr + sizeof(struct in6_addr)) > pastend) {
517 zlog_warn ("%s: IPv6 unicast address overflow: left=%zd needed %zu",
518 __PRETTY_FUNCTION__,
519 pastend - addr, sizeof(struct in6_addr));
520 return -3;
521 }
522
523 p->family = AF_INET6;
524 p->prefixlen = IPV6_MAX_PREFIXLEN;
4390fb99 525 memcpy(&p->u.prefix6, addr, sizeof(struct in6_addr));
0f4b1d2d
DS
526 addr += sizeof(struct in6_addr);
527
12e41d03
DL
528 break;
529 default:
530 {
4416b1f6 531 zlog_warn("%s: unknown unicast address encoding family=%d from",
12e41d03 532 __PRETTY_FUNCTION__,
4416b1f6 533 family);
12e41d03
DL
534 return -4;
535 }
536 }
537
538 return addr - buf;
539}
540
4416b1f6 541int
bce0e645 542pim_parse_addr_group (struct prefix_sg *sg,
4416b1f6
DS
543 const uint8_t *buf,
544 int buf_size)
12e41d03
DL
545{
546 const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
547 const uint8_t *addr;
548 const uint8_t *pastend;
549 int family;
550 int type;
551 int mask_len;
552
553 if (buf_size < grp_encoding_min_len) {
4416b1f6 554 zlog_warn("%s: group address encoding overflow: left=%d needed=%d",
12e41d03 555 __PRETTY_FUNCTION__,
4416b1f6 556 buf_size, grp_encoding_min_len);
12e41d03
DL
557 return -1;
558 }
559
560 addr = buf;
561 pastend = buf + buf_size;
562
563 family = *addr++;
564 type = *addr++;
565 //++addr;
566 ++addr; /* skip b_reserved_z fields */
567 mask_len = *addr++;
568
569 switch (family) {
570 case PIM_MSG_ADDRESS_FAMILY_IPV4:
571 if (type) {
4416b1f6
DS
572 zlog_warn("%s: unknown group address encoding type=%d from",
573 __PRETTY_FUNCTION__, type);
12e41d03
DL
574 return -2;
575 }
576
577 if ((addr + sizeof(struct in_addr)) > pastend) {
4416b1f6 578 zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from",
12e41d03 579 __PRETTY_FUNCTION__,
4416b1f6 580 pastend - addr, sizeof(struct in_addr));
12e41d03
DL
581 return -3;
582 }
583
bce0e645 584 memcpy(&sg->grp.s_addr, addr, sizeof(struct in_addr));
12e41d03
DL
585
586 addr += sizeof(struct in_addr);
587
588 break;
589 default:
590 {
bce0e645
DS
591 zlog_warn("%s: unknown group address encoding family=%d mask_len=%d from",
592 __PRETTY_FUNCTION__, family, mask_len);
12e41d03
DL
593 return -4;
594 }
595 }
596
597 return addr - buf;
598}
599
4416b1f6 600int
a7762e07 601pim_parse_addr_source(struct prefix_sg *sg,
4416b1f6
DS
602 uint8_t *flags,
603 const uint8_t *buf,
604 int buf_size)
12e41d03
DL
605{
606 const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
607 const uint8_t *addr;
608 const uint8_t *pastend;
609 int family;
610 int type;
611 int mask_len;
612
613 if (buf_size < src_encoding_min_len) {
4416b1f6 614 zlog_warn("%s: source address encoding overflow: left=%d needed=%d",
12e41d03 615 __PRETTY_FUNCTION__,
4416b1f6 616 buf_size, src_encoding_min_len);
12e41d03
DL
617 return -1;
618 }
619
620 addr = buf;
621 pastend = buf + buf_size;
622
623 family = *addr++;
624 type = *addr++;
625 *flags = *addr++;
626 mask_len = *addr++;
627
4416b1f6
DS
628 if (type) {
629 zlog_warn("%s: unknown source address encoding type=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
630 __PRETTY_FUNCTION__,
631 type,
632 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
633 return -2;
634 }
635
12e41d03
DL
636 switch (family) {
637 case PIM_MSG_ADDRESS_FAMILY_IPV4:
12e41d03 638 if ((addr + sizeof(struct in_addr)) > pastend) {
4416b1f6 639 zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu",
12e41d03 640 __PRETTY_FUNCTION__,
4416b1f6 641 pastend - addr, sizeof(struct in_addr));
12e41d03
DL
642 return -3;
643 }
644
a7762e07 645 memcpy(&sg->src, addr, sizeof(struct in_addr));
12e41d03
DL
646
647 /*
648 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
649
650 Encoded-Source Address
651
652 The mask length MUST be equal to the mask length in bits for
653 the given Address Family and Encoding Type (32 for IPv4 native
654 and 128 for IPv6 native). A router SHOULD ignore any messages
655 received with any other mask length.
656 */
a7762e07 657 if (mask_len != 32) {
4416b1f6 658 zlog_warn("%s: IPv4 bad source address mask: %d",
a7762e07 659 __PRETTY_FUNCTION__, mask_len);
12e41d03
DL
660 return -4;
661 }
662
663 addr += sizeof(struct in_addr);
664
665 break;
666 default:
667 {
4416b1f6 668 zlog_warn("%s: unknown source address encoding family=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
12e41d03 669 __PRETTY_FUNCTION__,
4416b1f6 670 family,
12e41d03
DL
671 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
672 return -5;
673 }
674 }
675
676 return addr - buf;
677}
678
679#define FREE_ADDR_LIST(hello_option_addr_list) \
680{ \
681 if (hello_option_addr_list) { \
682 list_delete(hello_option_addr_list); \
683 hello_option_addr_list = 0; \
684 } \
685}
686
687int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
688 pim_hello_options *hello_options,
689 struct list **hello_option_addr_list,
690 uint16_t option_len,
691 const uint8_t *tlv_curr)
692{
693 const uint8_t *addr;
694 const uint8_t *pastend;
695
696 zassert(hello_option_addr_list);
697
698 /*
699 Scan addr list
700 */
701 addr = tlv_curr;
702 pastend = tlv_curr + option_len;
703 while (addr < pastend) {
704 struct prefix tmp;
705 int addr_offset;
706
707 /*
708 Parse ucast addr
709 */
4416b1f6 710 addr_offset = pim_parse_addr_ucast(&tmp, addr, pastend - addr);
12e41d03 711 if (addr_offset < 1) {
eaa54bdb 712 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
713 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
714 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
715 __PRETTY_FUNCTION__,
716 src_str, ifname);
717 FREE_ADDR_LIST(*hello_option_addr_list);
718 return -1;
719 }
720 addr += addr_offset;
721
722 /*
723 Debug
724 */
725 if (PIM_DEBUG_PIM_TRACE) {
726 switch (tmp.family) {
727 case AF_INET:
728 {
eaa54bdb
DW
729 char addr_str[INET_ADDRSTRLEN];
730 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
731 pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str));
732 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
733 zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
734 __PRETTY_FUNCTION__,
735 *hello_option_addr_list ?
736 ((int) listcount(*hello_option_addr_list)) : -1,
737 addr_str, src_str, ifname);
738 }
739 break;
0f4b1d2d
DS
740 case AF_INET6:
741 break;
12e41d03
DL
742 default:
743 {
eaa54bdb 744 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
745 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
746 zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
747 __PRETTY_FUNCTION__,
748 *hello_option_addr_list ?
749 ((int) listcount(*hello_option_addr_list)) : -1,
750 src_str, ifname);
751 }
752 }
753 }
754
755 /*
756 Exclude neighbor's primary address if incorrectly included in
757 the secondary address list
758 */
759 if (tmp.family == AF_INET) {
760 if (tmp.u.prefix4.s_addr == src_addr.s_addr) {
eaa54bdb 761 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
762 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
763 zlog_warn("%s: ignoring primary address in secondary list from %s on %s",
764 __PRETTY_FUNCTION__,
765 src_str, ifname);
766 continue;
767 }
768 }
769
770 /*
771 Allocate list if needed
772 */
773 if (!*hello_option_addr_list) {
774 *hello_option_addr_list = list_new();
775 if (!*hello_option_addr_list) {
776 zlog_err("%s %s: failure: hello_option_addr_list=list_new()",
777 __FILE__, __PRETTY_FUNCTION__);
778 return -2;
779 }
780 (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free;
781 }
782
783 /*
784 Attach addr to list
785 */
786 {
787 struct prefix *p;
788 p = prefix_new();
789 if (!p) {
790 zlog_err("%s %s: failure: prefix_new()",
791 __FILE__, __PRETTY_FUNCTION__);
792 FREE_ADDR_LIST(*hello_option_addr_list);
793 return -3;
794 }
0f4b1d2d 795 prefix_copy(p, &tmp);
12e41d03
DL
796 listnode_add(*hello_option_addr_list, p);
797 }
798
799 } /* while (addr < pastend) */
800
801 /*
802 Mark hello option
803 */
804 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST);
805
806 return 0;
807}