Coverage Report

Created: 2026-01-25 06:17

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
63.2k
#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
149
{
31
149
  uint16_t option_len = 2;
32
33
149
  if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
34
0
    return NULL;
35
36
149
  *(uint16_t *)buf = htons(option_type);
37
149
  buf += 2;
38
149
  *(uint16_t *)buf = htons(option_len);
39
149
  buf += 2;
40
149
  *(uint16_t *)buf = htons(option_value);
41
149
  buf += option_len;
42
43
149
  return buf;
44
149
}
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
149
{
50
149
  uint16_t option_len = 4;
51
52
149
  if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
53
0
    return NULL;
54
55
149
  *(uint16_t *)buf = htons(option_type);
56
149
  buf += 2;
57
149
  *(uint16_t *)buf = htons(option_len);
58
149
  buf += 2;
59
149
  *(uint16_t *)buf = htons(option_value1);
60
149
  buf += 2;
61
149
  *(uint16_t *)buf = htons(option_value2);
62
149
  buf += 2;
63
64
149
  return buf;
65
149
}
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
298
{
70
298
  uint16_t option_len = 4;
71
72
298
  if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
73
0
    return NULL;
74
75
298
  *(uint16_t *)buf = htons(option_type);
76
298
  buf += 2;
77
298
  *(uint16_t *)buf = htons(option_len);
78
298
  buf += 2;
79
298
  pim_write_uint32(buf, option_value);
80
298
  buf += option_len;
81
82
298
  return buf;
83
298
}
84
85
149
#define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
86
149
#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
5
{
118
5
  uint8_t *start = buf;
119
120
5
  *buf++ = PIM_MSG_ADDRESS_FAMILY;
121
5
  *buf++ = 0;
122
5
  memcpy(buf, &addr, sizeof(addr));
123
5
  buf += sizeof(addr);
124
125
5
  return buf - start;
126
5
}
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
5
{
201
5
  uint8_t *start = buf;
202
5
  uint8_t flags = 0;
203
204
5
  flags |= bidir << 8;
205
5
  flags |= scope;
206
207
5
  *buf++ = PIM_MSG_ADDRESS_FAMILY;
208
5
  *buf++ = 0;
209
5
  *buf++ = flags;
210
5
  *buf++ = sizeof(group) * 8;
211
5
  memcpy(buf, &group, sizeof(group));
212
5
  buf += sizeof(group);
213
214
5
  return buf - start;
215
5
}
216
217
uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend,
218
               struct interface *ifp, int family)
219
298
{
220
298
  struct listnode *node;
221
298
  uint16_t option_len = 0;
222
298
  uint8_t *curr;
223
298
  size_t uel;
224
298
  struct list *ifconnected = ifp->connected;
225
298
  struct pim_interface *pim_ifp = ifp->info;
226
298
  pim_addr addr;
227
228
298
  node = listhead(ifconnected);
229
230
  /* Empty address list ? */
231
298
  if (!node) {
232
0
    return buf;
233
0
  }
234
235
298
  if (family == AF_INET)
236
149
    uel = ucast_ipv4_encoding_len;
237
149
  else
238
149
    uel = ucast_ipv6_encoding_len;
239
240
  /* Scan secondary address list */
241
298
  curr = buf + 4; /* skip T and L */
242
596
  for (; node; node = listnextnode(node)) {
243
596
    struct connected *ifc = listgetdata(node);
244
596
    struct prefix *p = ifc->address;
245
596
    int l_encode;
246
247
596
    addr = pim_addr_from_prefix(p);
248
596
    if (!pim_addr_cmp(pim_ifp->primary_address, addr))
249
      /* don't add the primary address
250
       * into the secondary address list */
251
298
      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
298
  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
298
  if (option_len < 1) {
271
    /* Empty secondary unicast IPv4 address list */
272
298
    return buf;
273
298
  }
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
298
}
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.73k
{
288
1.73k
  if (option_len != correct_len) {
289
75
    zlog_warn(
290
75
      "%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %pPAs on interface %s",
291
75
      label, tlv_name, option_len, correct_len, &src_addr,
292
75
      ifname);
293
75
    return -1;
294
75
  }
295
296
1.65k
  return 0;
297
1.73k
}
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
894
{
306
894
  if (PIM_OPTION_IS_SET(options, opt_mask))
307
836
    zlog_warn(
308
894
      "%s: PIM hello TLV redefined %s=%u old=%u from %pPAs on interface %s",
309
894
      label, tlv_name, new, old, &src_addr, ifname);
310
894
}
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
357
{
319
357
  if (PIM_OPTION_IS_SET(options, opt_mask))
320
314
    zlog_warn(
321
357
      "%s: PIM hello TLV redefined %s=%u old=%u from %pPAs on interface %s",
322
357
      label, tlv_name, new, old, &src_addr, ifname);
323
357
}
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
407
{
330
407
  if (PIM_OPTION_IS_SET(options, opt_mask))
331
322
    zlog_warn(
332
407
      "%s: PIM hello TLV redefined %s=%08x old=%08x from %pPAs on interface %s",
333
407
      label, tlv_name, new, old, &src_addr, ifname);
334
407
}
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
219
{
341
219
  const char *label = "holdtime";
342
343
219
  if (check_tlv_length(__func__, label, ifname, src_addr,
344
219
           sizeof(uint16_t), option_len)) {
345
8
    return -1;
346
8
  }
347
348
211
  check_tlv_redefinition_uint16(__func__, label, ifname, src_addr,
349
211
              *hello_options, PIM_OPTION_MASK_HOLDTIME,
350
211
              PIM_TLV_GET_HOLDTIME(tlv_curr),
351
211
              *hello_option_holdtime);
352
353
211
  PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME);
354
355
211
  *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr);
356
357
211
  return 0;
358
219
}
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
708
{
366
708
  if (check_tlv_length(__func__, "lan_prune_delay", ifname, src_addr,
367
708
           sizeof(uint32_t), option_len)) {
368
25
    return -1;
369
25
  }
370
371
683
  check_tlv_redefinition_uint16(__func__, "propagation_delay", ifname,
372
683
              src_addr, *hello_options,
373
683
              PIM_OPTION_MASK_LAN_PRUNE_DELAY,
374
683
              PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr),
375
683
              *hello_option_propagation_delay);
376
377
683
  PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY);
378
379
683
  *hello_option_propagation_delay =
380
683
    PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr);
381
683
  if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr)) {
382
243
    PIM_OPTION_SET(*hello_options,
383
243
             PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
384
440
  } else {
385
440
    PIM_OPTION_UNSET(*hello_options,
386
440
         PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
387
440
  }
388
683
  ++tlv_curr;
389
683
  ++tlv_curr;
390
683
  *hello_option_override_interval =
391
683
    PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr);
392
393
683
  return 0;
394
708
}
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
381
{
401
381
  const char *label = "dr_priority";
402
403
381
  if (check_tlv_length(__func__, label, ifname, src_addr,
404
381
           sizeof(uint32_t), option_len)) {
405
24
    return -1;
406
24
  }
407
408
357
  check_tlv_redefinition_uint32(
409
357
    __func__, label, ifname, src_addr, *hello_options,
410
357
    PIM_OPTION_MASK_DR_PRIORITY, PIM_TLV_GET_DR_PRIORITY(tlv_curr),
411
357
    *hello_option_dr_priority);
412
413
357
  PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY);
414
415
357
  *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr);
416
417
357
  return 0;
418
381
}
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
425
{
425
425
  const char *label = "generation_id";
426
427
425
  if (check_tlv_length(__func__, label, ifname, src_addr,
428
425
           sizeof(uint32_t), option_len)) {
429
18
    return -1;
430
18
  }
431
432
407
  check_tlv_redefinition_uint32_hex(__func__, label, ifname, src_addr,
433
407
            *hello_options,
434
407
            PIM_OPTION_MASK_GENERATION_ID,
435
407
            PIM_TLV_GET_GENERATION_ID(tlv_curr),
436
407
            *hello_option_generation_id);
437
438
407
  PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID);
439
440
407
  *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr);
441
442
407
  return 0;
443
425
}
444
445
int pim_parse_addr_ucast_prefix(struct prefix *p, const uint8_t *buf,
446
        int buf_size)
447
8.04k
{
448
8.04k
  const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */
449
8.04k
  const uint8_t *addr;
450
8.04k
  const uint8_t *pastend;
451
8.04k
  int family;
452
8.04k
  int type;
453
454
8.04k
  if (buf_size < ucast_encoding_min_len) {
455
30
    zlog_warn(
456
30
      "%s: unicast address encoding overflow: left=%d needed=%d",
457
30
      __func__, buf_size, ucast_encoding_min_len);
458
30
    return -1;
459
30
  }
460
461
8.01k
  addr = buf;
462
8.01k
  pastend = buf + buf_size;
463
464
8.01k
  family = *addr++;
465
8.01k
  type = *addr++;
466
467
8.01k
  if (type) {
468
81
    zlog_warn("%s: unknown unicast address encoding type=%d",
469
81
        __func__, type);
470
81
    return -2;
471
81
  }
472
473
7.93k
  switch (family) {
474
7.20k
  case PIM_MSG_ADDRESS_FAMILY_IPV4:
475
7.20k
    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
7.19k
    p->family = AF_INET; /* notice: AF_INET !=
484
          PIM_MSG_ADDRESS_FAMILY_IPV4 */
485
7.19k
    memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
486
7.19k
    p->prefixlen = IPV4_MAX_BITLEN;
487
7.19k
    addr += sizeof(struct in_addr);
488
489
7.19k
    break;
490
679
  case PIM_MSG_ADDRESS_FAMILY_IPV6:
491
679
    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
665
    p->family = AF_INET6;
500
665
    p->prefixlen = IPV6_MAX_BITLEN;
501
665
    memcpy(&p->u.prefix6, addr, sizeof(struct in6_addr));
502
665
    addr += sizeof(struct in6_addr);
503
504
665
    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
679
  }
510
7.93k
  }
511
512
7.86k
  return addr - buf;
513
7.93k
}
514
515
int pim_parse_addr_ucast(pim_addr *out, const uint8_t *buf, int buf_size,
516
       bool *wrong_af)
517
1.05k
{
518
1.05k
  struct prefix p;
519
1.05k
  int ret;
520
521
1.05k
  ret = pim_parse_addr_ucast_prefix(&p, buf, buf_size);
522
1.05k
  if (ret < 0)
523
123
    return ret;
524
525
929
  if (p.family != PIM_AF) {
526
17
    *wrong_af = true;
527
17
    return -5;
528
17
  }
529
530
912
  memcpy(out, &p.u.val, sizeof(*out));
531
912
  return ret;
532
929
}
533
534
int pim_parse_addr_group(pim_sgaddr *sg, const uint8_t *buf, int buf_size)
535
5.12k
{
536
5.12k
  const int grp_encoding_min_len =
537
5.12k
    4; /* 1 family + 1 type + 1 reserved + 1 addr */
538
5.12k
  const uint8_t *addr;
539
5.12k
  const uint8_t *pastend;
540
5.12k
  int family;
541
5.12k
  int type;
542
5.12k
  int mask_len;
543
544
5.12k
  if (buf_size < grp_encoding_min_len) {
545
97
    zlog_warn(
546
97
      "%s: group address encoding overflow: left=%d needed=%d",
547
97
      __func__, buf_size, grp_encoding_min_len);
548
97
    return -1;
549
97
  }
550
551
5.02k
  addr = buf;
552
5.02k
  pastend = buf + buf_size;
553
554
5.02k
  family = *addr++;
555
5.02k
  type = *addr++;
556
5.02k
  ++addr; /* skip b_reserved_z fields */
557
5.02k
  mask_len = *addr++;
558
559
5.02k
  if (type) {
560
46
    zlog_warn("%s: unknown group address encoding type=%d from",
561
46
        __func__, type);
562
46
    return -2;
563
46
  }
564
565
4.98k
  if (family != PIM_MSG_ADDRESS_FAMILY) {
566
37
    zlog_warn(
567
37
      "%s: unknown group address encoding family=%d mask_len=%d from",
568
37
      __func__, family, mask_len);
569
37
    return -4;
570
37
  }
571
572
4.94k
  if ((addr + sizeof(sg->grp)) > pastend) {
573
14
    zlog_warn(
574
14
      "%s: group address overflow: left=%td needed=%zu from",
575
14
      __func__, pastend - addr, sizeof(sg->grp));
576
14
    return -3;
577
14
  }
578
579
4.93k
  memcpy(&sg->grp, addr, sizeof(sg->grp));
580
4.93k
  addr += sizeof(sg->grp);
581
582
4.93k
  return addr - buf;
583
4.94k
}
584
585
int pim_parse_addr_source(pim_sgaddr *sg, uint8_t *flags, const uint8_t *buf,
586
        int buf_size)
587
58.8k
{
588
58.8k
  const int src_encoding_min_len =
589
58.8k
    4; /* 1 family + 1 type + 1 reserved + 1 addr */
590
58.8k
  const uint8_t *addr;
591
58.8k
  const uint8_t *pastend;
592
58.8k
  int family;
593
58.8k
  int type;
594
58.8k
  int mask_len;
595
596
58.8k
  if (buf_size < src_encoding_min_len) {
597
334
    zlog_warn(
598
334
      "%s: source address encoding overflow: left=%d needed=%d",
599
334
      __func__, buf_size, src_encoding_min_len);
600
334
    return -1;
601
334
  }
602
603
58.4k
  addr = buf;
604
58.4k
  pastend = buf + buf_size;
605
606
58.4k
  family = *addr++;
607
58.4k
  type = *addr++;
608
58.4k
  *flags = *addr++;
609
58.4k
  mask_len = *addr++;
610
611
58.4k
  if (type) {
612
196
    zlog_warn(
613
196
      "%s: unknown source address encoding type=%d: %02x%02x%02x%02x",
614
196
      __func__, type, buf[0], buf[1], buf[2], buf[3]);
615
196
    return -2;
616
196
  }
617
618
58.2k
  switch (family) {
619
58.2k
  case PIM_MSG_ADDRESS_FAMILY:
620
58.2k
    if ((addr + sizeof(sg->src)) > pastend) {
621
42
      zlog_warn(
622
42
        "%s: IP source address overflow: left=%td needed=%zu",
623
42
        __func__, pastend - addr, sizeof(sg->src));
624
42
      return -3;
625
42
    }
626
627
58.2k
    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
58.2k
    if (mask_len != PIM_MAX_BITLEN) {
640
49
      zlog_warn("%s: IP bad source address mask: %d",
641
49
          __func__, mask_len);
642
49
      return -4;
643
49
    }
644
645
58.1k
    addr += sizeof(sg->src);
646
647
58.1k
    break;
648
25
  default:
649
25
    zlog_warn(
650
25
      "%s: unknown source address encoding family=%d: %02x%02x%02x%02x",
651
25
      __func__, family, buf[0], buf[1], buf[2], buf[3]);
652
25
    return -5;
653
58.2k
  }
654
655
58.1k
  return addr - buf;
656
58.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
3.50k
{
671
3.50k
  const uint8_t *addr;
672
3.50k
  const uint8_t *pastend;
673
674
3.50k
  assert(hello_option_addr_list);
675
676
  /*
677
    Scan addr list
678
   */
679
3.50k
  addr = tlv_curr;
680
3.50k
  pastend = tlv_curr + option_len;
681
10.4k
  while (addr < pastend) {
682
6.99k
    struct prefix tmp, src_pfx;
683
6.99k
    int addr_offset;
684
685
    /*
686
      Parse ucast addr
687
     */
688
6.99k
    addr_offset =
689
6.99k
      pim_parse_addr_ucast_prefix(&tmp, addr, pastend - addr);
690
6.99k
    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
6.93k
    addr += addr_offset;
698
699
    /*
700
      Debug
701
     */
702
6.93k
    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
6.93k
    pim_addr_to_prefix(&src_pfx, src_addr);
736
6.93k
    if (!prefix_cmp(&tmp, &src_pfx)) {
737
1.13k
      zlog_warn(
738
1.13k
        "%s: ignoring primary address in secondary list from %pPAs on %s",
739
1.13k
        __func__, &src_addr, ifname);
740
1.13k
      continue;
741
1.13k
    }
742
743
    /*
744
      Allocate list if needed
745
     */
746
5.79k
    if (!*hello_option_addr_list) {
747
141
      *hello_option_addr_list = list_new();
748
141
      (*hello_option_addr_list)->del = prefix_free_lists;
749
141
    }
750
751
    /*
752
      Attach addr to list
753
     */
754
5.79k
    {
755
5.79k
      struct prefix *p;
756
5.79k
      p = prefix_new();
757
5.79k
      prefix_copy(p, &tmp);
758
5.79k
      listnode_add(*hello_option_addr_list, p);
759
5.79k
    }
760
761
5.79k
  } /* while (addr < pastend) */
762
763
  /*
764
    Mark hello option
765
   */
766
3.44k
  PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST);
767
768
3.44k
  return 0;
769
3.50k
}