Coverage Report

Created: 2026-01-01 06:18

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