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