Coverage Report

Created: 2025-10-08 06:07

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