The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
decode.c
Go to the documentation of this file.
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: c33c13905743cf91838d25153f9429fb7908e23b $
19  *
20  * @file protocols/dhcpv6/decode.c
21  * @brief Functions to decode DHCP options.
22  *
23  * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24  *
25  * @copyright 2018 The FreeRADIUS server project
26  * @copyright 2018 NetworkRADIUS SARL (legal@networkradius.com)
27  */
28 #include <stdint.h>
29 #include <stddef.h>
30 
31 #include <freeradius-devel/io/test_point.h>
32 #include <freeradius-devel/util/dns.h>
33 #include <freeradius-devel/util/proto.h>
34 #include <freeradius-devel/util/struct.h>
35 
36 #include "dhcpv6.h"
37 #include "attrs.h"
38 
39 static ssize_t decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out,
40  fr_dict_attr_t const *parent,
41  uint8_t const *data, size_t const data_len, void *decode_ctx);
42 
44  fr_dict_attr_t const *parent,
45  uint8_t const *data, size_t const data_len, void *decode_ctx)
46 {
47  return fr_pair_tlvs_from_network(ctx, out, parent, data, data_len, decode_ctx, decode_option, NULL, true);
48 }
49 
50 static ssize_t decode_value(TALLOC_CTX *ctx, fr_pair_list_t *out,
51  fr_dict_attr_t const *parent,
52  uint8_t const *data, size_t const data_len, void *decode_ctx);
53 
54 /** Handle arrays of DNS labels for fr_struct_from_network()
55  *
56  */
58  fr_dict_attr_t const *parent,
59  uint8_t const *data, size_t const data_len, void *decode_ctx)
60 {
62  return fr_pair_dns_labels_from_network(ctx, out, parent, data, data, data_len, NULL, false);
63  }
64 
65  return decode_value(ctx, out, parent, data, data_len, decode_ctx);
66 }
67 
68 
69 static ssize_t decode_value(TALLOC_CTX *ctx, fr_pair_list_t *out,
70  fr_dict_attr_t const *parent,
71  uint8_t const *data, size_t const data_len, void *decode_ctx)
72 {
73  ssize_t slen;
74  fr_pair_t *vp = NULL;
75  uint8_t prefix_len;
76  fr_dict_attr_t const *ref;
77 
78  FR_PROTO_HEX_DUMP(data, data_len, "decode_value");
79 
80  switch (parent->type) {
81  /*
82  * Address MAY be shorter than 16 bytes.
83  */
85  if (data_len == 0) {
86  raw:
87  return fr_pair_raw_from_network(ctx, out, parent, data, data_len);
88 
89  }
90 
91  /*
92  * Structs used fixed length IPv6 addressews.
93  */
94  if (parent->parent->type == FR_TYPE_STRUCT) {
95  if (data_len != (1 + sizeof(vp->vp_ipv6addr))) {
96  goto raw;
97  }
98 
99  vp = fr_pair_afrom_da(ctx, parent);
100  if (!vp) return PAIR_DECODE_OOM;
101 
102  vp->vp_ip.af = AF_INET6;
103  vp->vp_ip.scope_id = 0;
104  vp->vp_ip.prefix = data[0];
105  memcpy(&vp->vp_ipv6addr, data + 1, sizeof(vp->vp_ipv6addr));
106  slen = 1 + sizeof(vp->vp_ipv6addr);
107  break;
108  }
109 
110  /*
111  * No address, the prefix length MUST be zero.
112  */
113  if (data_len == 1) {
114  if (data[0] != 0) goto raw;
115 
116  vp = fr_pair_afrom_da(ctx, parent);
117  if (!vp) return PAIR_DECODE_OOM;
118 
119  vp->vp_ip.af = AF_INET6;
120  slen = 1;
121  break;
122  }
123 
124  prefix_len = data[0];
125 
126  /*
127  * If we have a /64 prefix but only 7 bytes of
128  * address, that's an error.
129  */
130  slen = fr_bytes_from_bits(prefix_len);
131  if ((size_t) slen > (data_len - 1)) {
132  goto raw;
133  }
134 
135  vp = fr_pair_afrom_da(ctx, parent);
136  if (!vp) return PAIR_DECODE_OOM;
137 
138  vp->vp_ip.af = AF_INET6;
139  vp->vp_ip.prefix = prefix_len;
140  memcpy(&vp->vp_ipv6addr, data + 1, slen);
141 
142  slen++;
143  break;
144 
145  /*
146  * A bool is encoded as an empty option if it's
147  * true. A bool is omitted entirely if it's
148  * false.
149  */
150  case FR_TYPE_BOOL:
151  if (data_len != 0) goto raw;
152  vp = fr_pair_afrom_da(ctx, parent);
153  if (!vp) return PAIR_DECODE_OOM;
154  vp->vp_bool = true;
155  slen = 0;
156  break;
157 
158  /*
159  * A standard 32bit integer, but unlike normal UNIX timestamps
160  * starts from the 1st of January 2000.
161  *
162  * In the encoder we subtract 30 years to any values, so
163  * here we need to add that to the time here.
164  */
165  case FR_TYPE_DATE:
166  vp = fr_pair_afrom_da(ctx, parent);
167  if (!vp) return PAIR_DECODE_OOM;
168 
169  slen = fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
170  &FR_DBUFF_TMP(data, data_len), data_len, true);
171  if (slen < 0) {
172  talloc_free(vp);
173  goto raw;
174  }
176  break;
177 
178  case FR_TYPE_STRUCT:
179  slen = fr_struct_from_network(ctx, out, parent, data, data_len,
181  if (slen < 0) goto raw;
182 
183  if (parent->flags.array) return slen;
184  return data_len;
185 
186  case FR_TYPE_GROUP:
187  vp = fr_pair_afrom_da(ctx, parent);
188  if (!vp) return PAIR_DECODE_OOM;
189 
190  ref = fr_dict_attr_ref(parent);
191  if (ref && (ref->dict != dict_dhcpv6)) {
192  fr_dict_protocol_t const *proto;
193 
194  proto = fr_dict_protocol(ref->dict);
195  fr_assert(proto != NULL);
196 
197  if (!proto->decode) {
198  raw_free:
199  talloc_free(vp);
200  goto raw;
201  }
202 
203  slen = proto->decode(vp, &vp->vp_group, data, data_len);
204  if (slen < 0) goto raw_free;
205 
206  vp->vp_tainted = true;
207 
208  } else {
209  /*
210  * Child VPs go into the child group, not in the main parent list. BUT, we start
211  * decoding attributes from the dictionary root, not from this parent.
212  */
213  slen = fr_pair_tlvs_from_network(vp, &vp->vp_group, fr_dict_root(dict_dhcpv6), data, data_len, decode_ctx, decode_option, NULL, false);
214  if (slen < 0) goto raw_free;
215  }
216 
218  return data_len;
219 
220  case FR_TYPE_IPV6_ADDR:
221  vp = fr_pair_afrom_da(ctx, parent);
222  if (!vp) return PAIR_DECODE_OOM;
223 
224  /*
225  * Limit the IPv6 address to 16 octets, with no scope.
226  */
227  if (data_len < sizeof(vp->vp_ipv6addr)) goto raw;
228 
229  slen = fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
230  &FR_DBUFF_TMP(data, sizeof(vp->vp_ipv6addr)), sizeof(vp->vp_ipv6addr), true);
231  if (slen < 0) goto raw_free;
232  break;
233 
234  default:
235  vp = fr_pair_afrom_da(ctx, parent);
236  if (!vp) return PAIR_DECODE_OOM;
237 
238  slen = fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
239  &FR_DBUFF_TMP(data, data_len), data_len, true);
240  if (slen < 0) goto raw_free;
241  break;
242  }
243 
244  /*
245  * The input is larger than the decoded value, re-do it as a raw attribute.
246  */
247  if (!parent->flags.array && ((size_t) slen < data_len)) {
248  talloc_free(vp);
249  goto raw;
250  }
251 
252  fr_assert(vp != NULL);
253 
254  vp->vp_tainted = true;
256 
257  if (parent->flags.array) return slen;
258 
259  return data_len;
260 }
261 
262 
263 static ssize_t decode_vsa(TALLOC_CTX *ctx, fr_pair_list_t *out,
264  fr_dict_attr_t const *parent,
265  uint8_t const *data, size_t const data_len, void *decode_ctx)
266 {
267  uint32_t pen;
268  fr_dict_attr_t const *da;
269  fr_pair_t *vp;
270  fr_dhcpv6_decode_ctx_t *packet_ctx = decode_ctx;
271 
272  FR_PROTO_HEX_DUMP(data, data_len, "decode_vsa");
273 
274  if (!fr_cond_assert_msg(parent->type == FR_TYPE_VSA,
275  "%s: Internal sanity check failed, attribute \"%s\" is not of type 'vsa'",
276  __FUNCTION__, parent->name)) return PAIR_DECODE_FATAL_ERROR;
277 
278  /*
279  * Enterprise code plus at least one option header
280  */
281  if (data_len < 8) return fr_pair_raw_from_network(ctx, out, parent, data, data_len);
282 
283  memcpy(&pen, data, sizeof(pen));
284  pen = htonl(pen);
285 
286  /*
287  * Verify that the parent (which should be a VSA)
288  * contains a fake attribute representing the vendor.
289  *
290  * If it doesn't then this vendor is unknown, but we know
291  * vendor attributes have a standard format, so we can
292  * decode the data anyway.
293  */
295  if (!da) {
296  fr_dict_attr_t *n;
297 
299  if (!n) return PAIR_DECODE_OOM;
300  da = n;
301  }
302 
303  FR_PROTO_TRACE("decode context %s -> %s", parent->name, da->name);
304 
305  vp = fr_pair_find_by_da(out, NULL, da);
306  if (vp) {
307  return fr_pair_tlvs_from_network(vp, &vp->vp_group, da, data + 4, data_len - 4, decode_ctx, decode_option, NULL, false);
308  }
309 
310  return fr_pair_tlvs_from_network(ctx, out, da, data + 4, data_len - 4, decode_ctx, decode_option, NULL, true);
311 }
312 
313 static ssize_t decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out,
314  fr_dict_attr_t const *parent,
315  uint8_t const *data, size_t const data_len, void *decode_ctx)
316 {
317  unsigned int option;
318  size_t len;
319  ssize_t slen;
320  fr_dict_attr_t const *da;
321  fr_dhcpv6_decode_ctx_t *packet_ctx = decode_ctx;
322 
323 #ifdef STATIC_ANALYZER
324  if (!packet_ctx || !packet_ctx->tmp_ctx) return PAIR_DECODE_FATAL_ERROR;
325 #endif
326 
327  /*
328  * Must have at least an option header.
329  */
330  if (data_len < 4) {
331  fr_strerror_printf("%s: Insufficient data", __FUNCTION__);
332  return -(data_len);
333  }
334 
335  option = DHCPV6_GET_OPTION_NUM(data);
337  if (len > (data_len - 4)) {
338  fr_strerror_printf("%s: Option overflows input. "
339  "Optional length must be less than %zu bytes, got %zu bytes",
340  __FUNCTION__, data_len - 4, len);
342  }
343 
344  da = fr_dict_attr_child_by_num(parent, option);
345  if (!da) {
346  da = fr_dict_attr_unknown_raw_afrom_num(packet_ctx->tmp_ctx, parent, option);
347  if (!da) return PAIR_DECODE_FATAL_ERROR;
348  }
349  FR_PROTO_TRACE("decode context changed %s -> %s",da->parent->name, da->name);
350 
351  /*
352  * Relay messages are weird, and contain complete DHCPv6
353  * packets, copied verbatim from the DHCPv6 client.
354  */
355  if (da == attr_relay_message) {
356  fr_pair_t *vp;
357 
359  if (!vp) return PAIR_DECODE_FATAL_ERROR;
360 
361  slen = fr_dhcpv6_decode(vp, &vp->vp_group, data + 4, len);
362  if (slen < 0) {
363  talloc_free(vp);
364  raw:
365  slen = fr_pair_raw_from_network(ctx, out, da, data + 4, len);
366  if (slen < 0) return slen;
367  return 4 + slen;
368  }
369 
371 
372  } else if ((da->type == FR_TYPE_STRING) && fr_dhcpv6_flag_any_dns_label(da)) {
373  slen = fr_pair_dns_labels_from_network(ctx, out, da, data + 4, data + 4, len, NULL, true);
374  if (slen < 0) return slen;
375 
376  } else if (da->flags.array) {
377  slen = fr_pair_array_from_network(ctx, out, da, data + 4, len, decode_ctx, decode_value);
378 
379  } else if (da->type == FR_TYPE_VSA) {
380  bool append = false;
381  fr_pair_t *vp;
382 
383  vp = fr_pair_find_by_da(out, NULL, da);
384  if (!vp) {
385  vp = fr_pair_afrom_da(ctx, da);
386  if (!vp) return PAIR_DECODE_FATAL_ERROR;
387 
388  append = true;
389  }
390 
391  slen = decode_vsa(vp, &vp->vp_group, da, data + 4, len, decode_ctx);
392  if (append) {
393  if (slen < 0) {
394  TALLOC_FREE(vp);
395  } else {
397  }
398  }
399 
400  } else if (da->type == FR_TYPE_TLV) {
401  slen = fr_pair_tlvs_from_network(ctx, out, da, data + 4, len, decode_ctx, decode_option, NULL, true);
402 
403  } else {
404  slen = decode_value(ctx, out, da, data + 4, len, decode_ctx);
405  }
406 
407  if (slen < 0) goto raw;
408 
409  return len + 4;
410 }
411 
412 
413 /** Create a "normal" fr_pair_t from the given data
414  *
415  * 0 1 2 3
416  * 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
417  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
418  * | option-code | option-len |
419  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
420  */
422  uint8_t const *data, size_t data_len, void *decode_ctx)
423 {
424  FR_PROTO_HEX_DUMP(data, data_len, "fr_dhcpv6_decode_pair");
425 
426  /*
427  * The API changes, so we just bounce directly to the
428  * decode_option() function.
429  *
430  * All options including VSAs in DHCPv6 MUST follow the
431  * standard format.
432  */
433  return decode_option(ctx, out, fr_dict_root(dict_dhcpv6), data, data_len, decode_ctx);
434 }
435 
437  uint8_t const *data, size_t data_len)
438 {
439  ssize_t slen;
440  uint8_t const *attr, *end;
441 
442  fr_dhcpv6_decode_ctx_t decode_ctx = {};
443 
444  fr_assert(dict_dhcpv6 != NULL);
445 
446  decode_ctx.tmp_ctx = talloc(ctx, uint8_t);
447 
448  attr = data;
449  end = data + data_len;
450 
451  while (attr < end) {
452  slen = fr_dhcpv6_decode_option(ctx, out, attr, (end - attr), &decode_ctx);
453  if (slen < 0) {
454  talloc_free(decode_ctx.tmp_ctx);
455  return slen;
456  }
457 
458  /*
459  * If slen is larger than the room in the packet,
460  * all kinds of bad things happen.
461  */
462  if (!fr_cond_assert(slen <= (end - attr))) {
463  talloc_free(decode_ctx.tmp_ctx);
464  return -slen - (attr - data);
465  }
466 
467  attr += slen;
468  talloc_free_children(decode_ctx.tmp_ctx);
469  }
470 
471  talloc_free(decode_ctx.tmp_ctx);
472  return data_len;
473 }
474 
475 static int decode_test_ctx(void **out, TALLOC_CTX *ctx)
476 {
477  fr_dhcpv6_decode_ctx_t *test_ctx;
478 
479  test_ctx = talloc_zero(ctx, fr_dhcpv6_decode_ctx_t);
480  if (!test_ctx) return -1;
481 
482  test_ctx->tmp_ctx = talloc(test_ctx, uint8_t);
483 
484  *out = test_ctx;
485 
486  return 0;
487 }
488 
489 static ssize_t fr_dhcpv6_decode_proto(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, UNUSED void *proto_ctx)
490 {
491  size_t packet_len = data_len;
492 // fr_dhcpv6_decode_ctx_t *test_ctx = talloc_get_type_abort(proto_ctx, fr_dhcpv6_decode_ctx_t);
493 
494  if (!fr_dhcpv6_ok(data, packet_len, 200)) return -1;
495 
496  return fr_dhcpv6_decode(ctx, out, data, packet_len);
497 }
498 
499 
501  uint8_t const *data, size_t data_len, void *decode_ctx)
502 {
504 
505  return decode_option(ctx, out, fr_dict_root(dict_dhcpv6), data, data_len, decode_ctx);
506 }
507 
508 /*
509  * Test points
510  */
514  .func = decode_pair,
515 };
516 
520  .func = fr_dhcpv6_decode_proto
521 };
int n
Definition: acutest.h:577
#define NDEBUG_UNUSED
Definition: build.h:324
#define UNUSED
Definition: build.h:313
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition: dbuff.h:514
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:139
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:156
Implementation of the DHCPv6 protocol.
#define DHCPV6_GET_OPTION_NUM(_x)
Definition: dhcpv6.h:47
#define DHCPV6_GET_OPTION_LEN(_x)
Definition: dhcpv6.h:48
static bool fr_dhcpv6_flag_any_dns_label(fr_dict_attr_t const *da)
Definition: dhcpv6.h:152
#define DHCPV6_DATE_OFFSET
Definition: dhcpv6.h:124
TALLOC_CTX * tmp_ctx
for temporary things cleaned up during decoding
Definition: dhcpv6.h:133
static fr_dict_attr_t * fr_dict_attr_unknown_vendor_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int vendor)
Definition: dict.h:570
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict_util.c:2400
static fr_dict_attr_t * fr_dict_attr_unknown_raw_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
Definition: dict.h:577
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition: dict_util.c:3328
fr_dict_protocol_t const * fr_dict_protocol(fr_dict_t const *dict)
Return the protocol descriptor for the dictionary.
Definition: dict_util.c:4948
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition: dict.h:427
static fr_dict_attr_t const * fr_dict_attr_ref(fr_dict_attr_t const *da)
Return the reference associated with a group type attribute.
Definition: dict_ext.h:184
#define PAIR_DECODE_OOM
Fatal error - Out of memory.
Definition: pair.h:45
#define PAIR_DECODE_FATAL_ERROR
Fatal error - Failed decoding the packet.
Definition: pair.h:49
ssize_t fr_pair_tlvs_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx, fr_pair_decode_value_t decode_tlv, fr_pair_tlvs_verify_t verify_tlvs, bool nested)
Decode a list of pairs from the network.
Definition: decode.c:148
ssize_t fr_pair_dns_labels_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *start, uint8_t const *data, size_t const data_len, fr_dns_labels_t *lb, bool exact)
Decode a DNS label or a list of DNS labels from the network.
Definition: decode.c:237
ssize_t fr_pair_array_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx, fr_pair_decode_value_t decode_value)
Decode an array of values from the network.
Definition: decode.c:41
ssize_t fr_pair_raw_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len)
Create a "raw" pair from the network data.
Definition: decode.c:79
talloc_free(reap)
@ FR_TYPE_TLV
Contains nested attributes.
Definition: merged_model.c:118
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
Definition: merged_model.c:89
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
Definition: merged_model.c:111
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
Definition: merged_model.c:119
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
Definition: merged_model.c:88
@ FR_TYPE_BOOL
A truth value.
Definition: merged_model.c:95
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
Definition: merged_model.c:121
@ FR_TYPE_GROUP
A grouping of other attributes.
Definition: merged_model.c:124
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
static unsigned int fr_bytes_from_bits(unsigned int bits)
Convert bits (as in prefix length) to bytes, rounding up.
Definition: nbo.h:235
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition: pair.c:693
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition: pair.c:283
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition: pair.c:1345
static fr_dict_t const * dict_dhcpv6
Definition: proto_dhcpv6.c:87
static fr_dict_attr_t const * attr_relay_message
bool fr_dhcpv6_ok(uint8_t const *packet, size_t packet_len, uint32_t max_attributes)
See if the data pointed to by PTR is a valid DHCPv6 packet.
Definition: base.c:230
ssize_t fr_dhcpv6_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *packet, size_t packet_len)
Decode a DHCPv6 packet.
Definition: base.c:581
static ssize_t decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx)
Definition: decode.c:313
ssize_t fr_dhcpv6_decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, void *decode_ctx)
Create a "normal" fr_pair_t from the given data.
Definition: decode.c:421
fr_test_point_pair_decode_t dhcpv6_tp_decode_pair
Definition: decode.c:512
static int decode_test_ctx(void **out, TALLOC_CTX *ctx)
Definition: decode.c:475
fr_test_point_proto_decode_t dhcpv6_tp_decode_proto
Definition: decode.c:518
static ssize_t decode_value(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx)
Definition: decode.c:69
static ssize_t decode_value_trampoline(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx)
Handle arrays of DNS labels for fr_struct_from_network()
Definition: decode.c:57
static ssize_t decode_vsa(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx)
Definition: decode.c:263
static ssize_t decode_tlv_trampoline(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx)
Definition: decode.c:43
ssize_t fr_dhcpv6_decode_foreign(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len)
Definition: decode.c:436
static ssize_t fr_dhcpv6_decode_proto(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, UNUSED void *proto_ctx)
Definition: decode.c:489
static ssize_t decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *out, NDEBUG_UNUSED fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx)
Definition: decode.c:500
VQP attributes.
static char const * proto(int id, int porttype)
Definition: radwho.c:85
fr_assert(0)
fr_pair_t * vp
ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx, fr_pair_decode_value_t decode_value, fr_pair_decode_value_t decode_tlv)
Convert a STRUCT to one or more VPs.
Definition: struct.c:33
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition: test_point.h:104
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition: test_point.h:86
Entry point for pair decoders.
Definition: test_point.h:103
Entry point for protocol decoders.
Definition: test_point.h:85
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition: time.h:590
#define fr_unix_time_add(_a, _b)
Add a time/time delta together.
Definition: time.h:324
static fr_slen_t parent
Definition: pair.h:851
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
Definition: proto.h:41
#define FR_PROTO_TRACE(_fmt,...)
Definition: proto.h:40
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
ssize_t fr_value_box_from_network(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv, fr_dbuff_t *dbuff, size_t len, bool tainted)
Decode a fr_value_box_t from serialized binary data.
Definition: value.c:1754
static fr_slen_t data
Definition: value.h:1265
static size_t char ** out
Definition: value.h:997