Coverage Report

Created: 2026-08-31 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/strongswan/src/libcharon/encoding/parser.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2005-2009 Martin Willi
3
 * Copyright (C) 2005 Jan Hutter
4
 *
5
 * Copyright (C) secunet Security Networks AG
6
 *
7
 * This program is free software; you can redistribute it and/or modify it
8
 * under the terms of the GNU General Public License as published by the
9
 * Free Software Foundation; either version 2 of the License, or (at your
10
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
11
 *
12
 * This program is distributed in the hope that it will be useful, but
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15
 * for more details.
16
 */
17
18
#include <stdlib.h>
19
#include <string.h>
20
21
#include "parser.h"
22
23
#include <library.h>
24
#include <daemon.h>
25
#include <collections/linked_list.h>
26
#include <encoding/payloads/encodings.h>
27
#include <encoding/payloads/payload.h>
28
#include <encoding/payloads/sa_payload.h>
29
#include <encoding/payloads/proposal_substructure.h>
30
#include <encoding/payloads/transform_substructure.h>
31
#include <encoding/payloads/transform_attribute.h>
32
#include <encoding/payloads/ke_payload.h>
33
#include <encoding/payloads/nonce_payload.h>
34
#include <encoding/payloads/id_payload.h>
35
#include <encoding/payloads/notify_payload.h>
36
#include <encoding/payloads/encrypted_payload.h>
37
#include <encoding/payloads/auth_payload.h>
38
#include <encoding/payloads/cert_payload.h>
39
#include <encoding/payloads/certreq_payload.h>
40
#include <encoding/payloads/ts_payload.h>
41
#include <encoding/payloads/delete_payload.h>
42
#include <encoding/payloads/vendor_id_payload.h>
43
#include <encoding/payloads/cp_payload.h>
44
#include <encoding/payloads/configuration_attribute.h>
45
#include <encoding/payloads/eap_payload.h>
46
#include <encoding/payloads/unknown_payload.h>
47
48
49
typedef struct private_parser_t private_parser_t;
50
51
/**
52
 * Private data stored in a context.
53
 *
54
 * Contains pointers and counters to store current state.
55
 */
56
struct private_parser_t {
57
  /**
58
   * Public members, see parser_t.
59
   */
60
  parser_t public;
61
62
  /**
63
   * major IKE version
64
   */
65
  uint8_t major_version;
66
67
  /**
68
   * Current bit for reading in input data.
69
   */
70
  uint8_t bit_pos;
71
72
  /**
73
   * Current byte for reading in input data.
74
   */
75
  uint8_t *byte_pos;
76
77
  /**
78
   * Input data to parse.
79
   */
80
  uint8_t *input;
81
82
  /**
83
   * Roof of input, used for length-checking.
84
   */
85
  uint8_t *input_roof;
86
87
  /**
88
   * Set of encoding rules for this parsing session.
89
   */
90
  encoding_rule_t *rules;
91
};
92
93
/**
94
 * Log invalid length error
95
 */
96
static bool short_input(private_parser_t *this, int number)
97
1.48k
{
98
1.48k
  DBG1(DBG_ENC, "  not enough input to parse rule %d %N",
99
1.48k
     number, encoding_type_names, this->rules[number].type);
100
1.48k
  return FALSE;
101
1.48k
}
102
103
/**
104
 * Log unaligned rules
105
 */
106
static bool bad_bitpos(private_parser_t *this, int number)
107
0
{
108
0
  DBG1(DBG_ENC, "  found rule %d %N on bitpos %d",
109
0
     number, encoding_type_names, this->rules[number].type, this->bit_pos);
110
0
  return FALSE;
111
0
}
112
113
/**
114
 * Parse a 4-Bit unsigned integer from the current parsing position.
115
 */
116
static bool parse_uint4(private_parser_t *this, int rule_number,
117
            uint8_t *output_pos)
118
5.34k
{
119
5.34k
  if (this->byte_pos + sizeof(uint8_t) > this->input_roof)
120
0
  {
121
0
    return short_input(this, rule_number);
122
0
  }
123
5.34k
  switch (this->bit_pos)
124
5.34k
  {
125
2.67k
    case 0:
126
2.67k
      if (output_pos)
127
2.67k
      {
128
2.67k
        *output_pos = *(this->byte_pos) >> 4;
129
2.67k
      }
130
2.67k
      this->bit_pos = 4;
131
2.67k
      break;
132
2.67k
    case 4:
133
2.67k
      if (output_pos)
134
2.67k
      {
135
2.67k
        *output_pos = *(this->byte_pos) & 0x0F;
136
2.67k
      }
137
2.67k
      this->bit_pos = 0;
138
2.67k
      this->byte_pos++;
139
2.67k
      break;
140
0
    default:
141
0
      return bad_bitpos(this, rule_number);
142
5.34k
  }
143
5.34k
  if (output_pos)
144
5.34k
  {
145
5.34k
    DBG3(DBG_ENC, "   => %hhu", *output_pos);
146
5.34k
  }
147
5.34k
  return TRUE;
148
5.34k
}
149
150
/**
151
 * Parse a 8-Bit unsigned integer from the current parsing position.
152
 */
153
static bool parse_uint8(private_parser_t *this, int rule_number,
154
            uint8_t *output_pos)
155
576k
{
156
576k
  if (this->byte_pos + sizeof(uint8_t) > this->input_roof)
157
1.16k
  {
158
1.16k
    return short_input(this, rule_number);
159
1.16k
  }
160
575k
  if (this->bit_pos)
161
0
  {
162
0
    return bad_bitpos(this, rule_number);
163
0
  }
164
575k
  if (output_pos)
165
575k
  {
166
575k
    *output_pos = *(this->byte_pos);
167
575k
    DBG3(DBG_ENC, "   => %hhu", *output_pos);
168
575k
  }
169
575k
  this->byte_pos++;
170
575k
  return TRUE;
171
575k
}
172
173
/**
174
 * Parse a 15-Bit unsigned integer from the current parsing position.
175
 */
176
static bool parse_uint15(private_parser_t *this, int rule_number,
177
             uint16_t *output_pos)
178
21.2k
{
179
21.2k
  if (this->byte_pos + sizeof(uint16_t) > this->input_roof)
180
24
  {
181
24
    return short_input(this, rule_number);
182
24
  }
183
21.2k
  if (this->bit_pos != 1)
184
0
  {
185
0
    return bad_bitpos(this, rule_number);
186
0
  }
187
21.2k
  if (output_pos)
188
21.2k
  {
189
21.2k
    memcpy(output_pos, this->byte_pos, sizeof(uint16_t));
190
21.2k
    *output_pos = ntohs(*output_pos) & ~0x8000;
191
21.2k
    DBG3(DBG_ENC, "   => %hu", *output_pos);
192
21.2k
  }
193
21.2k
  this->byte_pos += sizeof(uint16_t);
194
21.2k
  this->bit_pos = 0;
195
21.2k
  return TRUE;
196
21.2k
}
197
198
/**
199
 * Parse a 16-Bit unsigned integer from the current parsing position.
200
 */
201
static bool parse_uint16(private_parser_t *this, int rule_number,
202
             uint16_t *output_pos)
203
402k
{
204
402k
  if (this->byte_pos + sizeof(uint16_t) > this->input_roof)
205
120
  {
206
120
    return short_input(this, rule_number);
207
120
  }
208
401k
  if (this->bit_pos)
209
0
  {
210
0
    return bad_bitpos(this, rule_number);
211
0
  }
212
401k
  if (output_pos)
213
401k
  {
214
401k
    memcpy(output_pos, this->byte_pos, sizeof(uint16_t));
215
401k
    *output_pos = ntohs(*output_pos);
216
401k
    DBG3(DBG_ENC, "   => %hu", *output_pos);
217
401k
  }
218
401k
  this->byte_pos += sizeof(uint16_t);
219
401k
  return TRUE;
220
401k
}
221
/**
222
 * Parse a 32-Bit unsigned integer from the current parsing position.
223
 */
224
static bool parse_uint32(private_parser_t *this, int rule_number,
225
             uint32_t *output_pos)
226
8.64k
{
227
8.64k
  if (this->byte_pos + sizeof(uint32_t) > this->input_roof)
228
11
  {
229
11
    return short_input(this, rule_number);
230
11
  }
231
8.62k
  if (this->bit_pos)
232
0
  {
233
0
    return bad_bitpos(this, rule_number);
234
0
  }
235
8.62k
  if (output_pos)
236
8.62k
  {
237
8.62k
    memcpy(output_pos, this->byte_pos, sizeof(uint32_t));
238
8.62k
    *output_pos = ntohl(*output_pos);
239
8.62k
    DBG3(DBG_ENC, "   => %u", *output_pos);
240
8.62k
  }
241
8.62k
  this->byte_pos += sizeof(uint32_t);
242
8.62k
  return TRUE;
243
8.62k
}
244
245
/**
246
 * Parse a given amount of bytes and writes them to a specific location
247
 */
248
static bool parse_bytes(private_parser_t *this, int rule_number,
249
            uint8_t *output_pos, int bytes)
250
5.34k
{
251
5.34k
  if (this->byte_pos + bytes > this->input_roof)
252
0
  {
253
0
    return short_input(this, rule_number);
254
0
  }
255
5.34k
  if (this->bit_pos)
256
0
  {
257
0
    return bad_bitpos(this, rule_number);
258
0
  }
259
5.34k
  if (output_pos)
260
5.34k
  {
261
5.34k
    memcpy(output_pos, this->byte_pos, bytes);
262
5.34k
    DBG3(DBG_ENC, "   %b", output_pos, bytes);
263
5.34k
  }
264
5.34k
  this->byte_pos += bytes;
265
5.34k
  return TRUE;
266
5.34k
}
267
268
/**
269
 * Parse a single Bit from the current parsing position
270
 */
271
static bool parse_bit(private_parser_t *this, int rule_number,
272
            bool *output_pos)
273
1.82M
{
274
1.82M
  if (this->byte_pos + sizeof(uint8_t) > this->input_roof)
275
119
  {
276
119
    return short_input(this, rule_number);
277
119
  }
278
1.82M
  if (output_pos)
279
1.82M
  {
280
1.82M
    uint8_t mask;
281
1.82M
    mask = 0x01 << (7 - this->bit_pos);
282
1.82M
    *output_pos = *this->byte_pos & mask;
283
284
1.82M
    if (*output_pos)
285
525k
    { /* set to a "clean", comparable true */
286
525k
      *output_pos = TRUE;
287
525k
    }
288
1.82M
    DBG3(DBG_ENC, "   => %d", *output_pos);
289
1.82M
  }
290
1.82M
  this->bit_pos = (this->bit_pos + 1) % 8;
291
1.82M
  if (this->bit_pos == 0)
292
226k
  {
293
226k
    this->byte_pos++;
294
226k
  }
295
1.82M
  return TRUE;
296
1.82M
}
297
298
/**
299
 * Parse substructures in a list.
300
 */
301
static bool parse_list(private_parser_t *this, int rule_number,
302
      linked_list_t **output_pos, payload_type_t payload_type, int length)
303
174k
{
304
174k
  linked_list_t *list = *output_pos;
305
306
174k
  if (length < 0)
307
0
  {
308
0
    return short_input(this, rule_number);
309
0
  }
310
174k
  if (this->bit_pos)
311
0
  {
312
0
    return bad_bitpos(this, rule_number);
313
0
  }
314
240k
  while (length > 0)
315
66.8k
  {
316
66.8k
    uint8_t *pos_before = this->byte_pos;
317
66.8k
    payload_t *payload;
318
319
66.8k
    DBG2(DBG_ENC, "  %d bytes left, parsing recursively %N",
320
66.8k
       length, payload_type_names, payload_type);
321
322
66.8k
    if (this->public.parse_payload(&this->public, payload_type,
323
66.8k
                     &payload) != SUCCESS)
324
296
    {
325
296
      DBG1(DBG_ENC, "  parsing of a %N substructure failed",
326
296
         payload_type_names, payload_type);
327
296
      return FALSE;
328
296
    }
329
66.5k
    list->insert_last(list, payload);
330
66.5k
    length -= this->byte_pos - pos_before;
331
66.5k
  }
332
173k
  if (length != 0)
333
31
  { /* must yield exactly to zero */
334
31
    DBG1(DBG_ENC, "  length of %N substructure list invalid",
335
31
       payload_type_names, payload_type);
336
31
    return FALSE;
337
31
  }
338
173k
  *output_pos = list;
339
173k
  return TRUE;
340
173k
}
341
342
/**
343
 * Parse data from current parsing position in a chunk.
344
 */
345
static bool parse_chunk(private_parser_t *this, int rule_number,
346
            chunk_t *output_pos, int length)
347
219k
{
348
219k
  if (this->byte_pos + length > this->input_roof)
349
54
  {
350
54
    return short_input(this, rule_number);
351
54
  }
352
219k
  if (this->bit_pos)
353
0
  {
354
0
    return bad_bitpos(this, rule_number);
355
0
  }
356
219k
  if (output_pos)
357
219k
  {
358
219k
    *output_pos = chunk_alloc(length);
359
219k
    memcpy(output_pos->ptr, this->byte_pos, length);
360
219k
    DBG3(DBG_ENC, "   %b", output_pos->ptr, length);
361
219k
  }
362
219k
  this->byte_pos += length;
363
219k
  return TRUE;
364
219k
}
365
366
METHOD(parser_t, parse_payload, status_t,
367
  private_parser_t *this, payload_type_t payload_type, payload_t **payload)
368
392k
{
369
392k
  payload_t *pld;
370
392k
  void *output;
371
392k
  int payload_length = 0, spi_size = 0, attribute_length = 0, header_length;
372
392k
  bool attribute_format = FALSE;
373
392k
  int rule_number, rule_count;
374
392k
  encoding_rule_t *rule;
375
376
  /* create instance of the payload to parse */
377
392k
  if (payload_is_known(payload_type, this->major_version))
378
361k
  {
379
361k
    pld = payload_create(payload_type);
380
361k
  }
381
30.8k
  else
382
30.8k
  {
383
30.8k
    pld = (payload_t*)unknown_payload_create(payload_type);
384
30.8k
  }
385
386
392k
  DBG2(DBG_ENC, "parsing %N payload, %d bytes left",
387
392k
     payload_type_names, payload_type, this->input_roof - this->byte_pos);
388
389
392k
  DBG3(DBG_ENC, "parsing payload from %b",
390
392k
     this->byte_pos, (u_int)(this->input_roof - this->byte_pos));
391
392
  /* base pointer for output, avoids casting in every rule */
393
392k
  output = pld;
394
  /* parse the payload with its own rules */
395
392k
  rule_count = pld->get_encoding_rules(pld, &this->rules);
396
3.63M
  for (rule_number = 0; rule_number < rule_count; rule_number++)
397
3.24M
  {
398
    /* update header length for each rule, as it is dynamic (SPIs) */
399
3.24M
    header_length = pld->get_header_length(pld);
400
401
3.24M
    rule = &(this->rules[rule_number]);
402
3.24M
    if (rule->type < PAYLOAD_LIST)
403
3.07M
    {
404
3.07M
      DBG2(DBG_ENC, "  parsing rule %d %N",
405
3.07M
         rule_number, encoding_type_names, rule->type);
406
3.07M
    }
407
174k
    else
408
174k
    {
409
174k
      DBG2(DBG_ENC, "  parsing rule %d LIST of %N",
410
174k
         rule_number, payload_type_names, rule->type - PAYLOAD_LIST);
411
174k
    }
412
3.24M
    switch ((int)rule->type)
413
3.24M
    {
414
5.34k
      case U_INT_4:
415
5.34k
      {
416
5.34k
        if (!parse_uint4(this, rule_number, output + rule->offset))
417
0
        {
418
0
          pld->destroy(pld);
419
0
          return PARSE_ERROR;
420
0
        }
421
5.34k
        break;
422
5.34k
      }
423
447k
      case U_INT_8:
424
567k
      case RESERVED_BYTE:
425
567k
      {
426
567k
        if (!parse_uint8(this, rule_number, output + rule->offset))
427
1.15k
        {
428
1.15k
          pld->destroy(pld);
429
1.15k
          return PARSE_ERROR;
430
1.15k
        }
431
566k
        break;
432
567k
      }
433
566k
      case U_INT_16:
434
13.5k
      {
435
13.5k
        if (!parse_uint16(this, rule_number, output + rule->offset))
436
11
        {
437
11
          pld->destroy(pld);
438
11
          return PARSE_ERROR;
439
11
        }
440
13.5k
        break;
441
13.5k
      }
442
13.5k
      case U_INT_32:
443
8.64k
      case HEADER_LENGTH:
444
8.64k
      {
445
8.64k
        if (!parse_uint32(this, rule_number, output + rule->offset))
446
11
        {
447
11
          pld->destroy(pld);
448
11
          return PARSE_ERROR;
449
11
        }
450
8.62k
        break;
451
8.64k
      }
452
8.62k
      case IKE_SPI:
453
5.34k
      {
454
5.34k
        if (!parse_bytes(this, rule_number, output + rule->offset, 8))
455
0
        {
456
0
          pld->destroy(pld);
457
0
          return PARSE_ERROR;
458
0
        }
459
5.34k
        break;
460
5.34k
      }
461
1.57M
      case RESERVED_BIT:
462
1.81M
      case FLAG:
463
1.81M
      {
464
1.81M
        if (!parse_bit(this, rule_number, output + rule->offset))
465
74
        {
466
74
          pld->destroy(pld);
467
74
          return PARSE_ERROR;
468
74
        }
469
1.81M
        break;
470
1.81M
      }
471
1.81M
      case PAYLOAD_LENGTH:
472
367k
      {
473
367k
        if (!parse_uint16(this, rule_number, output + rule->offset))
474
98
        {
475
98
          pld->destroy(pld);
476
98
          return PARSE_ERROR;
477
98
        }
478
        /* parsed u_int16 should be aligned */
479
367k
        payload_length = *(uint16_t*)(output + rule->offset);
480
        /* all payloads must have at least 4 bytes header */
481
367k
        if (payload_length < 4)
482
15
        {
483
15
          pld->destroy(pld);
484
15
          return PARSE_ERROR;
485
15
        }
486
367k
        break;
487
367k
      }
488
367k
      case SPI_SIZE:
489
9.04k
      {
490
9.04k
        if (!parse_uint8(this, rule_number, output + rule->offset))
491
2
        {
492
2
          pld->destroy(pld);
493
2
          return PARSE_ERROR;
494
2
        }
495
9.03k
        spi_size = *(uint8_t*)(output + rule->offset);
496
9.03k
        break;
497
9.04k
      }
498
9.03k
      case SPI:
499
9.03k
      {
500
9.03k
        if (!parse_chunk(this, rule_number, output + rule->offset,
501
9.03k
                 spi_size))
502
4
        {
503
4
          pld->destroy(pld);
504
4
          return PARSE_ERROR;
505
4
        }
506
9.02k
        break;
507
9.03k
      }
508
163k
      case PAYLOAD_LIST + PLV2_PROPOSAL_SUBSTRUCTURE:
509
164k
      case PAYLOAD_LIST + PLV1_PROPOSAL_SUBSTRUCTURE:
510
166k
      case PAYLOAD_LIST + PLV2_TRANSFORM_SUBSTRUCTURE:
511
167k
      case PAYLOAD_LIST + PLV1_TRANSFORM_SUBSTRUCTURE:
512
168k
      case PAYLOAD_LIST + PLV2_TRANSFORM_ATTRIBUTE:
513
169k
      case PAYLOAD_LIST + PLV1_TRANSFORM_ATTRIBUTE:
514
169k
      case PAYLOAD_LIST + PLV2_CONFIGURATION_ATTRIBUTE:
515
172k
      case PAYLOAD_LIST + PLV1_CONFIGURATION_ATTRIBUTE:
516
174k
      case PAYLOAD_LIST + PLV2_TRAFFIC_SELECTOR_SUBSTRUCTURE:
517
174k
      {
518
174k
        if (payload_length < header_length ||
519
174k
          !parse_list(this, rule_number, output + rule->offset,
520
174k
                rule->type - PAYLOAD_LIST,
521
174k
                payload_length - header_length))
522
329
        {
523
329
          pld->destroy(pld);
524
329
          return PARSE_ERROR;
525
329
        }
526
173k
        break;
527
174k
      }
528
192k
      case CHUNK_DATA:
529
192k
      {
530
192k
        if (payload_length < header_length ||
531
192k
          !parse_chunk(this, rule_number, output + rule->offset,
532
192k
                 payload_length - header_length))
533
49
        {
534
49
          pld->destroy(pld);
535
49
          return PARSE_ERROR;
536
49
        }
537
192k
        break;
538
192k
      }
539
192k
      case ENCRYPTED_DATA:
540
22
      {
541
22
        if (!parse_chunk(this, rule_number, output + rule->offset,
542
22
                 this->input_roof - this->byte_pos))
543
0
        {
544
0
          pld->destroy(pld);
545
0
          return PARSE_ERROR;
546
0
        }
547
22
        break;
548
22
      }
549
16.1k
      case ATTRIBUTE_FORMAT:
550
16.1k
      {
551
16.1k
        if (!parse_bit(this, rule_number, output + rule->offset))
552
45
        {
553
45
          pld->destroy(pld);
554
45
          return PARSE_ERROR;
555
45
        }
556
16.0k
        attribute_format = *(bool*)(output + rule->offset);
557
16.0k
        break;
558
16.1k
      }
559
21.2k
      case ATTRIBUTE_TYPE:
560
21.2k
      {
561
21.2k
        if (!parse_uint15(this, rule_number, output + rule->offset))
562
24
        {
563
24
          pld->destroy(pld);
564
24
          return PARSE_ERROR;
565
24
        }
566
21.2k
        break;
567
21.2k
      }
568
21.2k
      case ATTRIBUTE_LENGTH:
569
5.16k
      {
570
5.16k
        if (!parse_uint16(this, rule_number, output + rule->offset))
571
3
        {
572
3
          pld->destroy(pld);
573
3
          return PARSE_ERROR;
574
3
        }
575
5.16k
        attribute_length = *(uint16_t*)(output + rule->offset);
576
5.16k
        break;
577
5.16k
      }
578
16.0k
      case ATTRIBUTE_LENGTH_OR_VALUE:
579
16.0k
      {
580
16.0k
        if (!parse_uint16(this, rule_number, output + rule->offset))
581
8
        {
582
8
          pld->destroy(pld);
583
8
          return PARSE_ERROR;
584
8
        }
585
16.0k
        attribute_length = *(uint16_t*)(output + rule->offset);
586
16.0k
        break;
587
16.0k
      }
588
21.2k
      case ATTRIBUTE_VALUE:
589
21.2k
      {
590
21.2k
        if (attribute_format == FALSE &&
591
17.6k
          !parse_chunk(this, rule_number, output + rule->offset,
592
17.6k
                 attribute_length))
593
5
        {
594
5
          pld->destroy(pld);
595
5
          return PARSE_ERROR;
596
5
        }
597
21.2k
        break;
598
21.2k
      }
599
21.2k
      default:
600
0
      {
601
0
        DBG1(DBG_ENC, "  no rule to parse rule %d %N",
602
0
           rule_number, encoding_type_names, rule->type);
603
0
        pld->destroy(pld);
604
0
        return PARSE_ERROR;
605
21.2k
      }
606
3.24M
    }
607
    /* process next rule */
608
3.24M
    rule++;
609
3.24M
  }
610
611
390k
  *payload = pld;
612
390k
  DBG2(DBG_ENC, "parsing %N payload finished",
613
390k
     payload_type_names, payload_type);
614
390k
  return SUCCESS;
615
392k
}
616
617
METHOD(parser_t, get_remaining_byte_count, int,
618
  private_parser_t *this)
619
0
{
620
0
  return this->input_roof - this->byte_pos;
621
0
}
622
623
METHOD(parser_t, reset_context, void,
624
  private_parser_t *this)
625
2.67k
{
626
2.67k
  this->byte_pos = this->input;
627
2.67k
  this->bit_pos = 0;
628
2.67k
}
629
630
METHOD(parser_t, set_major_version, void,
631
  private_parser_t *this, uint8_t major_version)
632
2.62k
{
633
2.62k
  this->major_version = major_version;
634
2.62k
}
635
636
METHOD(parser_t, destroy, void,
637
  private_parser_t *this)
638
2.67k
{
639
2.67k
  free(this);
640
2.67k
}
641
642
/*
643
 * Described in header.
644
 */
645
parser_t *parser_create(chunk_t data)
646
2.67k
{
647
2.67k
  private_parser_t *this;
648
649
2.67k
  INIT(this,
650
2.67k
    .public = {
651
2.67k
      .parse_payload = _parse_payload,
652
2.67k
      .reset_context = _reset_context,
653
2.67k
      .set_major_version = _set_major_version,
654
2.67k
      .get_remaining_byte_count = _get_remaining_byte_count,
655
2.67k
      .destroy = _destroy,
656
2.67k
    },
657
2.67k
    .input = data.ptr,
658
2.67k
    .byte_pos = data.ptr,
659
2.67k
    .input_roof = data.ptr + data.len,
660
2.67k
  );
661
662
2.67k
  return &this->public;
663
2.67k
}
664