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