Coverage Report

Created: 2025-12-05 06:31

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
72.4k
#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
4
{
118
4
  uint8_t *start = buf;
119
120
4
  *buf++ = PIM_MSG_ADDRESS_FAMILY;
121
4
  *buf++ = 0;
122
4
  memcpy(buf, &addr, sizeof(addr));
123
4
  buf += sizeof(addr);
124
125
4
  return buf - start;
126
4
}
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
4
{
201
4
  uint8_t *start = buf;
202
4
  uint8_t flags = 0;
203
204
4
  flags |= bidir << 8;
205
4
  flags |= scope;
206
207
4
  *buf++ = PIM_MSG_ADDRESS_FAMILY;
208
4
  *buf++ = 0;
209
4
  *buf++ = flags;
210
4
  *buf++ = sizeof(group) * 8;
211
4
  memcpy(buf, &group, sizeof(group));
212
4
  buf += sizeof(group);
213
214
4
  return buf - start;
215
4
}
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
1.65k
{
288
1.65k
  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.58k
  return 0;
297
1.65k
}
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
758
{
306
758
  if (PIM_OPTION_IS_SET(options, opt_mask))
307
675
    zlog_warn(
308
758
      "%s: PIM hello TLV redefined %s=%u old=%u from %pPAs on interface %s",
309
758
      label, tlv_name, new, old, &src_addr, ifname);
310
758
}
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
371
{
319
371
  if (PIM_OPTION_IS_SET(options, opt_mask))
320
330
    zlog_warn(
321
371
      "%s: PIM hello TLV redefined %s=%u old=%u from %pPAs on interface %s",
322
371
      label, tlv_name, new, old, &src_addr, ifname);
323
371
}
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
454
{
330
454
  if (PIM_OPTION_IS_SET(options, opt_mask))
331
294
    zlog_warn(
332
454
      "%s: PIM hello TLV redefined %s=%08x old=%08x from %pPAs on interface %s",
333
454
      label, tlv_name, new, old, &src_addr, ifname);
334
454
}
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
229
{
341
229
  const char *label = "holdtime";
342
343
229
  if (check_tlv_length(__func__, label, ifname, src_addr,
344
229
           sizeof(uint16_t), option_len)) {
345
8
    return -1;
346
8
  }
347
348
221
  check_tlv_redefinition_uint16(__func__, label, ifname, src_addr,
349
221
              *hello_options, PIM_OPTION_MASK_HOLDTIME,
350
221
              PIM_TLV_GET_HOLDTIME(tlv_curr),
351
221
              *hello_option_holdtime);
352
353
221
  PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME);
354
355
221
  *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr);
356
357
221
  return 0;
358
229
}
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
560
{
366
560
  if (check_tlv_length(__func__, "lan_prune_delay", ifname, src_addr,
367
560
           sizeof(uint32_t), option_len)) {
368
23
    return -1;
369
23
  }
370
371
537
  check_tlv_redefinition_uint16(__func__, "propagation_delay", ifname,
372
537
              src_addr, *hello_options,
373
537
              PIM_OPTION_MASK_LAN_PRUNE_DELAY,
374
537
              PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr),
375
537
              *hello_option_propagation_delay);
376
377
537
  PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY);
378
379
537
  *hello_option_propagation_delay =
380
537
    PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr);
381
537
  if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr)) {
382
273
    PIM_OPTION_SET(*hello_options,
383
273
             PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
384
273
  } else {
385
264
    PIM_OPTION_UNSET(*hello_options,
386
264
         PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
387
264
  }
388
537
  ++tlv_curr;
389
537
  ++tlv_curr;
390
537
  *hello_option_override_interval =
391
537
    PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr);
392
393
537
  return 0;
394
560
}
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
395
{
401
395
  const char *label = "dr_priority";
402
403
395
  if (check_tlv_length(__func__, label, ifname, src_addr,
404
395
           sizeof(uint32_t), option_len)) {
405
24
    return -1;
406
24
  }
407
408
371
  check_tlv_redefinition_uint32(
409
371
    __func__, label, ifname, src_addr, *hello_options,
410
371
    PIM_OPTION_MASK_DR_PRIORITY, PIM_TLV_GET_DR_PRIORITY(tlv_curr),
411
371
    *hello_option_dr_priority);
412
413
371
  PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY);
414
415
371
  *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr);
416
417
371
  return 0;
418
395
}
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
470
{
425
470
  const char *label = "generation_id";
426
427
470
  if (check_tlv_length(__func__, label, ifname, src_addr,
428
470
           sizeof(uint32_t), option_len)) {
429
16
    return -1;
430
16
  }
431
432
454
  check_tlv_redefinition_uint32_hex(__func__, label, ifname, src_addr,
433
454
            *hello_options,
434
454
            PIM_OPTION_MASK_GENERATION_ID,
435
454
            PIM_TLV_GET_GENERATION_ID(tlv_curr),
436
454
            *hello_option_generation_id);
437
438
454
  PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID);
439
440
454
  *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr);
441
442
454
  return 0;
443
470
}
444
445
int pim_parse_addr_ucast_prefix(struct prefix *p, const uint8_t *buf,
446
        int buf_size)
447
16.8k
{
448
16.8k
  const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */
449
16.8k
  const uint8_t *addr;
450
16.8k
  const uint8_t *pastend;
451
16.8k
  int family;
452
16.8k
  int type;
453
454
16.8k
  if (buf_size < ucast_encoding_min_len) {
455
34
    zlog_warn(
456
34
      "%s: unicast address encoding overflow: left=%d needed=%d",
457
34
      __func__, buf_size, ucast_encoding_min_len);
458
34
    return -1;
459
34
  }
460
461
16.8k
  addr = buf;
462
16.8k
  pastend = buf + buf_size;
463
464
16.8k
  family = *addr++;
465
16.8k
  type = *addr++;
466
467
16.8k
  if (type) {
468
85
    zlog_warn("%s: unknown unicast address encoding type=%d",
469
85
        __func__, type);
470
85
    return -2;
471
85
  }
472
473
16.7k
  switch (family) {
474
16.4k
  case PIM_MSG_ADDRESS_FAMILY_IPV4:
475
16.4k
    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
16.4k
    p->family = AF_INET; /* notice: AF_INET !=
484
          PIM_MSG_ADDRESS_FAMILY_IPV4 */
485
16.4k
    memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
486
16.4k
    p->prefixlen = IPV4_MAX_BITLEN;
487
16.4k
    addr += sizeof(struct in_addr);
488
489
16.4k
    break;
490
252
  case PIM_MSG_ADDRESS_FAMILY_IPV6:
491
252
    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
238
    p->family = AF_INET6;
500
238
    p->prefixlen = IPV6_MAX_BITLEN;
501
238
    memcpy(&p->u.prefix6, addr, sizeof(struct in6_addr));
502
238
    addr += sizeof(struct in6_addr);
503
504
238
    break;
505
54
  default: {
506
54
    zlog_warn("%s: unknown unicast address encoding family=%d from",
507
54
        __func__, family);
508
54
    return -4;
509
252
  }
510
16.7k
  }
511
512
16.6k
  return addr - buf;
513
16.7k
}
514
515
int pim_parse_addr_ucast(pim_addr *out, const uint8_t *buf, int buf_size,
516
       bool *wrong_af)
517
1.09k
{
518
1.09k
  struct prefix p;
519
1.09k
  int ret;
520
521
1.09k
  ret = pim_parse_addr_ucast_prefix(&p, buf, buf_size);
522
1.09k
  if (ret < 0)
523
132
    return ret;
524
525
960
  if (p.family != PIM_AF) {
526
19
    *wrong_af = true;
527
19
    return -5;
528
19
  }
529
530
941
  memcpy(out, &p.u.val, sizeof(*out));
531
941
  return ret;
532
960
}
533
534
int pim_parse_addr_group(pim_sgaddr *sg, const uint8_t *buf, int buf_size)
535
5.55k
{
536
5.55k
  const int grp_encoding_min_len =
537
5.55k
    4; /* 1 family + 1 type + 1 reserved + 1 addr */
538
5.55k
  const uint8_t *addr;
539
5.55k
  const uint8_t *pastend;
540
5.55k
  int family;
541
5.55k
  int type;
542
5.55k
  int mask_len;
543
544
5.55k
  if (buf_size < grp_encoding_min_len) {
545
101
    zlog_warn(
546
101
      "%s: group address encoding overflow: left=%d needed=%d",
547
101
      __func__, buf_size, grp_encoding_min_len);
548
101
    return -1;
549
101
  }
550
551
5.45k
  addr = buf;
552
5.45k
  pastend = buf + buf_size;
553
554
5.45k
  family = *addr++;
555
5.45k
  type = *addr++;
556
5.45k
  ++addr; /* skip b_reserved_z fields */
557
5.45k
  mask_len = *addr++;
558
559
5.45k
  if (type) {
560
51
    zlog_warn("%s: unknown group address encoding type=%d from",
561
51
        __func__, type);
562
51
    return -2;
563
51
  }
564
565
5.40k
  if (family != PIM_MSG_ADDRESS_FAMILY) {
566
25
    zlog_warn(
567
25
      "%s: unknown group address encoding family=%d mask_len=%d from",
568
25
      __func__, family, mask_len);
569
25
    return -4;
570
25
  }
571
572
5.37k
  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
5.36k
  memcpy(&sg->grp, addr, sizeof(sg->grp));
580
5.36k
  addr += sizeof(sg->grp);
581
582
5.36k
  return addr - buf;
583
5.37k
}
584
585
int pim_parse_addr_source(pim_sgaddr *sg, uint8_t *flags, const uint8_t *buf,
586
        int buf_size)
587
67.6k
{
588
67.6k
  const int src_encoding_min_len =
589
67.6k
    4; /* 1 family + 1 type + 1 reserved + 1 addr */
590
67.6k
  const uint8_t *addr;
591
67.6k
  const uint8_t *pastend;
592
67.6k
  int family;
593
67.6k
  int type;
594
67.6k
  int mask_len;
595
596
67.6k
  if (buf_size < src_encoding_min_len) {
597
346
    zlog_warn(
598
346
      "%s: source address encoding overflow: left=%d needed=%d",
599
346
      __func__, buf_size, src_encoding_min_len);
600
346
    return -1;
601
346
  }
602
603
67.2k
  addr = buf;
604
67.2k
  pastend = buf + buf_size;
605
606
67.2k
  family = *addr++;
607
67.2k
  type = *addr++;
608
67.2k
  *flags = *addr++;
609
67.2k
  mask_len = *addr++;
610
611
67.2k
  if (type) {
612
216
    zlog_warn(
613
216
      "%s: unknown source address encoding type=%d: %02x%02x%02x%02x",
614
216
      __func__, type, buf[0], buf[1], buf[2], buf[3]);
615
216
    return -2;
616
216
  }
617
618
67.0k
  switch (family) {
619
67.0k
  case PIM_MSG_ADDRESS_FAMILY:
620
67.0k
    if ((addr + sizeof(sg->src)) > pastend) {
621
37
      zlog_warn(
622
37
        "%s: IP source address overflow: left=%td needed=%zu",
623
37
        __func__, pastend - addr, sizeof(sg->src));
624
37
      return -3;
625
37
    }
626
627
67.0k
    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
67.0k
    if (mask_len != PIM_MAX_BITLEN) {
640
66
      zlog_warn("%s: IP bad source address mask: %d",
641
66
          __func__, mask_len);
642
66
      return -4;
643
66
    }
644
645
66.9k
    addr += sizeof(sg->src);
646
647
66.9k
    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
67.0k
  }
654
655
66.9k
  return addr - buf;
656
67.0k
}
657
658
#define FREE_ADDR_LIST(hello_option_addr_list)                                 \
659
61
  {                                                                      \
660
61
    if (hello_option_addr_list) {                                  \
661
28
      list_delete(&hello_option_addr_list);                  \
662
28
      hello_option_addr_list = 0;                            \
663
28
    }                                                              \
664
61
  }
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
5.18k
{
671
5.18k
  const uint8_t *addr;
672
5.18k
  const uint8_t *pastend;
673
674
5.18k
  assert(hello_option_addr_list);
675
676
  /*
677
    Scan addr list
678
   */
679
5.18k
  addr = tlv_curr;
680
5.18k
  pastend = tlv_curr + option_len;
681
20.8k
  while (addr < pastend) {
682
15.7k
    struct prefix tmp, src_pfx;
683
15.7k
    int addr_offset;
684
685
    /*
686
      Parse ucast addr
687
     */
688
15.7k
    addr_offset =
689
15.7k
      pim_parse_addr_ucast_prefix(&tmp, addr, pastend - addr);
690
15.7k
    if (addr_offset < 1) {
691
61
      zlog_warn(
692
61
        "%s: pim_parse_addr_ucast() failure: from %pPAs on %s",
693
61
        __func__, &src_addr, ifname);
694
61
      FREE_ADDR_LIST(*hello_option_addr_list);
695
61
      return -1;
696
61
    }
697
15.7k
    addr += addr_offset;
698
699
    /*
700
      Debug
701
     */
702
15.7k
    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
15.7k
    pim_addr_to_prefix(&src_pfx, src_addr);
736
15.7k
    if (!prefix_cmp(&tmp, &src_pfx)) {
737
235
      zlog_warn(
738
235
        "%s: ignoring primary address in secondary list from %pPAs on %s",
739
235
        __func__, &src_addr, ifname);
740
235
      continue;
741
235
    }
742
743
    /*
744
      Allocate list if needed
745
     */
746
15.4k
    if (!*hello_option_addr_list) {
747
202
      *hello_option_addr_list = list_new();
748
202
      (*hello_option_addr_list)->del = prefix_free_lists;
749
202
    }
750
751
    /*
752
      Attach addr to list
753
     */
754
15.4k
    {
755
15.4k
      struct prefix *p;
756
15.4k
      p = prefix_new();
757
15.4k
      prefix_copy(p, &tmp);
758
15.4k
      listnode_add(*hello_option_addr_list, p);
759
15.4k
    }
760
761
15.4k
  } /* while (addr < pastend) */
762
763
  /*
764
    Mark hello option
765
   */
766
5.12k
  PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST);
767
768
5.12k
  return 0;
769
5.18k
}