Coverage Report

Created: 2025-08-26 06:20

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