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