The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
vmps.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program 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
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; 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: 98a2abde5c439177da657b055c9e4bc445d6983d $
19 *
20 * @file src/protocols/vmps/vmps.c
21 * @brief Functions to send/receive VQP packets.
22 *
23 * @copyright 2007 Alan DeKok (aland@deployingradius.com)
24 */
25
26RCSID("$Id: 98a2abde5c439177da657b055c9e4bc445d6983d $")
27
28#include <freeradius-devel/io/test_point.h>
29#include <freeradius-devel/protocol/vmps/vmps.h>
30#include <freeradius-devel/util/dbuff.h>
31#include <freeradius-devel/util/proto.h>
32#include <freeradius-devel/util/udp.h>
33
34#include "vmps.h"
35#include "attrs.h"
36
37/** Used as the decoder ctx
38 *
39 */
40typedef struct {
43
44/*
45 * http://www.openbsd.org/cgi-bin/cvsweb/src/usr.sbin/tcpdump/print-vqp.c
46 *
47 * Chapter 12 of Hacking Cisco Networks Exposed (Vladimirov, Gavrilenko,
48 * and Mikhailovsky, McGraw-Hill 2005) describes some of how it works.
49 *
50 * VLAN Query Protocol (VQP)
51 *
52 * 0 1 2 3
53 * 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
54 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55 * | Version | Opcode | Response Code | Data Count |
56 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57 * | Transaction ID |
58 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59 * | Type (1) |
60 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
61 * | Length | Data /
62 * / /
63 * / /
64 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65 * | Type (n) |
66 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
67 * | Length | Data /
68 * / /
69 * / /
70 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
71 *
72 * VQP is layered over UDP. The default destination port is 1589.
73 *
74 */
76 [FR_PACKET_TYPE_VALUE_JOIN_REQUEST] = "Join-Request",
77 [FR_PACKET_TYPE_VALUE_JOIN_RESPONSE] = "Join-Response",
78 [FR_PACKET_TYPE_VALUE_RECONFIRM_REQUEST] = "Reconfirm-Request",
79 [FR_PACKET_TYPE_VALUE_RECONFIRM_RESPONSE] = "Reconfirm-Response",
80};
81
82
83bool fr_vmps_ok(uint8_t const *packet, size_t *packet_len)
84{
85 uint8_t const *ptr;
86 ssize_t data_len;
87 int attrlen;
88
89 if (*packet_len == FR_VQP_HDR_LEN) return true;
90
91 /*
92 * Skip the header.
93 */
94 ptr = packet + FR_VQP_HDR_LEN;
95 data_len = *packet_len - FR_VQP_HDR_LEN;
96
97 while (data_len > 0) {
98 if (data_len < 7) {
99 fr_strerror_const("Packet contains malformed attribute");
100 return false;
101 }
102
103 /*
104 * Attributes are 4 bytes
105 * 0x00000c01 ... 0x00000c08
106 */
107 if ((ptr[0] != 0) || (ptr[1] != 0) ||
108 (ptr[2] != 0x0c) || (ptr[3] < 1) || (ptr[3] > 8)) {
109 fr_strerror_const("Packet contains invalid attribute");
110 return false;
111 }
112
113 /*
114 * Length is 2 bytes
115 */
116 attrlen = fr_nbo_to_uint16(ptr + 4);
117
118 /*
119 * Total of attribute lengths shouldn't exceed *packet_len - header length,
120 * which happens iff at some point, attrlen exceeds data_lan.
121 */
122 if (attrlen > data_len) {
123 fr_strerror_printf("Packet attributes cause total length "
124 "plus header length to exceed packet length %lx",
125 *packet_len);
126 return false;
127 }
128
129 /*
130 * We support short lengths, as there's no reason
131 * for bigger lengths to exist... admins won't be
132 * typing in a 32K vlan name.
133 *
134 * It's OK for ethernet frames to be longer.
135 */
136 if ((ptr[3] != 5) && (attrlen > 250)) {
137 fr_strerror_printf("Packet contains attribute with invalid length %02x %02x", ptr[4], ptr[5]);
138 return false;
139 }
140
141 ptr += 6 + attrlen;
142 data_len -= (6 + attrlen);
143 }
144
145 /*
146 * UDP reads may return too much data, so we truncate it.
147 */
148 *packet_len = ptr - packet;
149
150 return true;
151}
152
153
154int fr_vmps_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, unsigned int *code)
155{
156 uint8_t const *ptr, *end;
157 int attr;
158 size_t attr_len;
159 fr_pair_t *vp;
160
161 if (data_len < FR_VQP_HDR_LEN) return -1;
162
164 if (!vp) {
165 oom:
166 fr_strerror_const("Out of Memory");
167 return -1;
168 }
169 vp->vp_uint32 = data[1];
170 if (code) *code = data[1];
171 vp->vp_tainted = true;
173
175 if (!vp) goto oom;
176 vp->vp_uint32 = data[2];
177 vp->vp_tainted = true;
179
181 if (!vp) goto oom;
182
183 vp->vp_uint32 = fr_nbo_to_uint32(data + 4);
184 vp->vp_tainted = true;
186
187 ptr = data + FR_VQP_HDR_LEN;
188 end = data + data_len;
189
190 /*
191 * Note that fr_vmps_ok() MUST ensure that the packet is
192 * formatted in a way we expect, and that fr_vmps_ok() MUST
193 * be called before fr_vmps_decode().
194 */
195 while (ptr < end) {
196 if ((end - ptr) < 6) {
197 fr_strerror_printf("Packet is too small. (%ld < 6)", (end - ptr));
198 return -1;
199 }
200
201 attr = fr_nbo_to_uint16(ptr + 2);
202 attr_len = fr_nbo_to_uint16(ptr + 4);
203 ptr += 6;
204
205 if (!attr_len) continue;
206
207 /*
208 * fr_vmps_ok() should have checked this already,
209 * but it doesn't hurt to do it again.
210 */
211 if (attr_len > (size_t) (end - ptr)) {
212 fr_strerror_const("Attribute length exceeds received data");
213 return -1;
214 }
215
216 /*
217 * Create the VP.
218 */
220 if (!vp) {
221 fr_strerror_const("No memory");
222 return -1;
223 }
224
225 /*
226 * Rely on value_box to do the work.
227 *
228 * @todo - if the attribute is malformed, create a "raw" one.
229 */
230 if (fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
231 &FR_DBUFF_TMP(ptr, attr_len), attr_len, true) < 0) {
233 return -1;
234 }
235
236 ptr += attr_len;
237 vp->vp_tainted = true;
239 }
240
241 /*
242 * FIXME: Map attributes to Calling-Station-Id, etc...
243 */
244
245 return data_len;
246}
247
248#if 0
249/*
250 * These are the MUST HAVE contents for a VQP packet.
251 *
252 * We don't allow the caller to give less than these, because
253 * it won't work. We don't encode more than these, because the
254 * clients will ignore it.
255 *
256 * FIXME: Be more generous? Look for CISCO + VQP attributes?
257 *
258 * @todo - actually use these again...
259 */
260static int contents[5][VQP_MAX_ATTRIBUTES] = {
261 { 0, 0, 0, 0, 0, 0 },
262 { 0x0c01, 0x0c02, 0x0c03, 0x0c04, 0x0c07, 0x0c05 }, /* Join request */
263 { 0x0c03, 0x0c08, 0, 0, 0, 0 }, /* Join Response */
264 { 0x0c01, 0x0c02, 0x0c03, 0x0c04, 0x0c07, 0x0c08 }, /* Reconfirm */
265 { 0x0c03, 0x0c08, 0, 0, 0, 0 }
266};
267#endif
268
269ssize_t fr_vmps_encode(fr_dbuff_t *dbuff, uint8_t const *original,
270 int code, uint32_t seq_no, fr_dcursor_t *cursor)
271{
272 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
273 fr_pair_t *vp;
274 fr_dbuff_marker_t hdr, m;
275 uint8_t data_count = 0;
276
277 /*
278 * Let's keep a reference for packet header, and another
279 * to let us write to to the encoding as needed.
280 */
281 fr_dbuff_marker(&hdr, &work_dbuff);
282 fr_dbuff_marker(&m, &work_dbuff);
283
284 /*
285 * Create the header
286 */
287 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_VQP_VERSION, /* Version */
288 code, /* Opcode */
289 FR_ERROR_CODE_VALUE_NO_ERROR, /* Response Code */
290 data_count); /* Data Count */
291
292 if (original) {
293 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, original + 4, 4);
294 } else {
295 FR_DBUFF_IN_RETURN(&work_dbuff, seq_no);
296 }
297
298 /*
299 * Encode the VP's.
300 */
301 while ((vp = fr_dcursor_current(cursor))) {
302 ssize_t slen;
303
304 if (vp->da == attr_packet_type) {
305 fr_dbuff_set(&m, fr_dbuff_current(&hdr) + 1);
306 FR_DBUFF_IN_RETURN(&m, (uint8_t)vp->vp_uint32);
307 fr_dcursor_next(cursor);
308 continue;
309 }
310
311 if (vp->da == attr_error_code) {
312 fr_dbuff_set(&m, fr_dbuff_current(&hdr) + 2);
313 FR_DBUFF_IN_RETURN(&m, vp->vp_uint8);
314 fr_dcursor_next(cursor);
315 continue;
316 }
317
318 if (!original && (vp->da == attr_sequence_number)) {
319 fr_dbuff_set(&m, fr_dbuff_current(&hdr) + 4);
320 FR_DBUFF_IN_RETURN(&m, vp->vp_uint32);
321 fr_dcursor_next(cursor);
322 continue;
323 }
324
325 if (!fr_type_is_leaf(vp->vp_type)) continue;
326
327 /*
328 * Type. Note that we look at only the lower 8
329 * bits, as the upper 8 bits have been hacked.
330 * See also dictionary.vmps
331 */
332
333 /* Type */
334 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, 0x00, 0x00, 0x0c, (vp->da->attr & 0xff));
335
336 /* Length */
337 fr_dbuff_set(&m, fr_dbuff_current(&work_dbuff));
338 FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t) 0);
339
340 /* Data */
341 slen = fr_value_box_to_network(&work_dbuff, &vp->data);
342 if (slen < 0) return slen;
343
344 FR_DBUFF_IN_RETURN(&m, (uint16_t) slen);
345
346 data_count++;
347
348 fr_dcursor_next(cursor);
349 }
350
351 /*
352 * Update the Data Count
353 */
354 fr_dbuff_set(&m, fr_dbuff_current(&hdr) + 3);
355 FR_DBUFF_IN_RETURN(&m, data_count);
356
357 return fr_dbuff_set(dbuff, &work_dbuff);
358}
359
360
361/** See how big of a packet is in the buffer.
362 *
363 * Packet is not 'const * const' because we may update data_len, if there's more data
364 * in the UDP packet than in the VMPS packet.
365 *
366 * @param data pointer to the packet buffer
367 * @param data_len length of the packet buffer
368 * @return
369 * <= 0 packet is bad.
370 * >0 how much of the data is a packet (can be larger than data_len)
371 */
372ssize_t fr_vmps_packet_size(uint8_t const *data, size_t data_len)
373{
374 int attributes;
375 uint8_t const *ptr, *end;
376
377 if (data_len < FR_VQP_HDR_LEN) return FR_VQP_HDR_LEN;
378
379 /*
380 * No attributes.
381 */
382 if (data[3] == 0) return FR_VQP_HDR_LEN;
383
384 /*
385 * Too many attributes. Return an error indicating that
386 * there's a problem with octet 3.
387 */
388 if (data[3] > 30) return -3;
389
390 /*
391 * Look for attributes.
392 */
393 ptr = data + FR_VQP_HDR_LEN;
394 attributes = data[3];
395
396 end = data + data_len;
397
398 while (attributes > 0) {
399 size_t attr_len;
400
401 /*
402 * Not enough room for the attribute headers, we
403 * want at least those.
404 */
405 if ((end - ptr) < 6) {
406 return 6 * attributes;
407 }
408
409 /*
410 * Length of the data NOT including the header.
411 */
412 attr_len = fr_nbo_to_uint16(ptr + 4);
413
414 ptr += 6 + attr_len;
415
416 /*
417 * We don't want to read infinite amounts of data.
418 *
419 * Return an error indicating that there's a
420 * problem with the final octet
421 */
422 if ((ptr - data) > 4096) {
423 return -(ptr - data);
424 }
425
426 /*
427 * This attribute has been checked.
428 */
429 attributes--;
430
431 /*
432 * The packet we want is larger than the input
433 * buffer, so we return the length of the current
434 * attribute, plus the length of the remaining
435 * headers.
436 */
437 if (ptr > end) return (6 * attributes) + ptr - data;
438 }
439
440 /*
441 * We've reached the end of the packet.
442 */
443 return ptr - data;
444}
445
446static void print_hex_data(uint8_t const *ptr, int attrlen, int depth)
447{
448 int i;
449 static char const tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
450
451 for (i = 0; i < attrlen; i++) {
452 if ((i > 0) && ((i & 0x0f) == 0x00))
453 fprintf(fr_log_fp, "%.*s", depth, tabs);
454 fprintf(fr_log_fp, "%02x ", ptr[i]);
455 if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
456 }
457 if ((i & 0x0f) != 0) fprintf(fr_log_fp, "\n");
458}
459
460
461/** Print a raw VMPS packet as hex.
462 *
463 */
464void fr_vmps_print_hex(FILE *fp, uint8_t const *packet, size_t packet_len)
465{
466 uint32_t length;
467 uint8_t const *attr, *end;
468 uint32_t id;
469
470 if (packet_len < 8) return;
471
472 fprintf(fp, " Version:\t\t%u\n", packet[0]);
473
474 if ((packet[1] > 0) && (packet[1] < FR_VMPS_CODE_MAX) && fr_vmps_packet_names[packet[1]]) {
475 fprintf(fp, " OpCode:\t\t%s\n", fr_vmps_packet_names[packet[1]]);
476 } else {
477 fprintf(fp, " OpCode:\t\t%u\n", packet[1]);
478 }
479
480 if ((packet[2] > 0) && (packet[2] < FR_VMPS_CODE_MAX) && fr_vmps_packet_names[packet[2]]) {
481 fprintf(fp, " OpCode:\t\t%s\n", fr_vmps_packet_names[packet[2]]);
482 } else {
483 fprintf(fp, " OpCode:\t\t%u\n", packet[2]);
484 }
485
486 fprintf(fp, " Data Count:\t\t%u\n", packet[3]);
487
488 memcpy(&id, packet + 4, 4);
489 id = ntohl(id);
490
491 fprintf(fp, " ID:\t%08x\n", id);
492
493 if (packet_len == 8) return;
494
495 for (attr = packet + 8, end = packet + packet_len;
496 attr < end;
497 attr += length) {
498 memcpy(&id, attr, 4);
499 id = ntohl(id);
500
501 length = fr_nbo_to_uint16(attr + 4);
502 if (length > (end - attr)) break;
503
504 fprintf(fp, "\t\t%08x %04x ", id, length);
505
506 print_hex_data(attr + 6, length - 6, 3);
507 }
508}
509
510/*
511 * Test points for protocol decode
512 */
514 uint8_t const *data, size_t data_len, void *proto_ctx)
515{
516 return fr_vmps_decode(ctx, out, data, data_len, proto_ctx);
517}
518
520{
522
523 return 0;
524}
525
526static int decode_test_ctx(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict,
527 UNUSED fr_dict_attr_t const *root_da)
528{
529 fr_vmps_ctx_t *test_ctx;
530
531 if (fr_vmps_global_init() < 0) return -1;
532
533 test_ctx = talloc_zero(ctx, fr_vmps_ctx_t);
534 if (!test_ctx) return -1;
535
536 talloc_set_destructor(test_ctx, _decode_test_ctx);
537
538 *out = test_ctx;
539
540 return 0;
541}
542
548
549/*
550 * Test points for protocol encode
551 */
552static ssize_t fr_vmps_encode_proto(UNUSED TALLOC_CTX *ctx, fr_pair_list_t *vps, uint8_t *data, size_t data_len, UNUSED void *proto_ctx)
553{
554 fr_dcursor_t cursor;
555
557
558 return fr_vmps_encode(&FR_DBUFF_TMP(data, data_len), NULL, -1, -1, &cursor);
559}
560
562{
564
565 return 0;
566}
567
568static int encode_test_ctx(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict,
569 UNUSED fr_dict_attr_t const *root_da)
570{
571 fr_vmps_ctx_t *test_ctx;
572
573 if (fr_vmps_global_init() < 0) return -1;
574
575 test_ctx = talloc_zero(ctx, fr_vmps_ctx_t);
576 if (!test_ctx) return -1;
577
578 talloc_set_destructor(test_ctx, _encode_test_ctx);
579
580 *out = test_ctx;
581
582 return 0;
583}
584
#define RCSID(id)
Definition build.h:487
#define UNUSED
Definition build.h:317
static const char * tabs
Definition command.c:1589
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
Definition dbuff.h:83
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition dbuff.h:921
#define fr_dbuff_set(_dst, _src)
Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer,...
Definition dbuff.h:1014
static uint8_t * fr_dbuff_marker(fr_dbuff_marker_t *m, fr_dbuff_t *dbuff)
Initialises a new marker pointing to the 'current' position of the dbuff.
Definition dbuff.h:1203
#define FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into dbuff or marker returning if there's insufficient space.
Definition dbuff.h:1393
#define FR_DBUFF_IN_RETURN(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff returning if there is insufficient space.
Definition dbuff.h:1596
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:232
#define FR_DBUFF_IN_BYTES_RETURN(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker returning if there's insufficient space.
Definition dbuff.h:1483
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:524
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:290
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition dcursor.h:339
static fr_dict_attr_t const * attr_packet_type
Definition dhcpclient.c:89
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2669
talloc_free(reap)
FILE * fr_log_fp
Definition log.c:39
unsigned short uint16_t
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
static uint16_t fr_nbo_to_uint16(uint8_t const data[static sizeof(uint16_t)])
Read an unsigned 16bit integer from wire format (big endian)
Definition nbo.h:146
static uint32_t fr_nbo_to_uint32(uint8_t const data[static sizeof(uint32_t)])
Read an unsigned 32bit integer from wire format (big endian)
Definition nbo.h:167
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:1348
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:289
fr_pair_t * fr_pair_afrom_child_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
Create a new valuepair.
Definition pair.c:378
void * fr_proto_next_encodable(fr_dcursor_t *cursor, void *current, void *uctx)
Implements the default iterator to encode pairs belonging to a specific dictionary that are not inter...
Definition proto.c:100
static fr_dict_t const * dict_vmps
Definition proto_vmps.c:75
VQP attributes.
HIDDEN fr_dict_attr_t const * attr_error_code
Definition base.c:42
HIDDEN fr_dict_attr_t const * attr_sequence_number
Definition base.c:44
int fr_vmps_global_init(void)
Definition base.c:55
void fr_vmps_global_free(void)
Definition base.c:79
fr_pair_t * vp
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:76
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition test_point.h:68
Entry point for protocol decoders.
Definition test_point.h:67
Entry point for protocol encoders.
Definition test_point.h:75
#define fr_pair_dcursor_iter_init(_cursor, _list, _iter, _uctx)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition pair.h:585
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
#define fr_type_is_leaf(_x)
Definition types.h:394
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:1914
ssize_t fr_value_box_to_network(fr_dbuff_t *dbuff, fr_value_box_t const *value)
Encode a single value box, serializing its contents in generic network format.
Definition value.c:1517
static fr_slen_t data
Definition value.h:1326
static size_t char ** out
Definition value.h:1023
static ssize_t fr_vmps_decode_proto(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, void *proto_ctx)
Definition vmps.c:513
static int decode_test_ctx(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict, UNUSED fr_dict_attr_t const *root_da)
Definition vmps.c:526
static void print_hex_data(uint8_t const *ptr, int attrlen, int depth)
Definition vmps.c:446
int nothing
Definition vmps.c:41
int fr_vmps_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, unsigned int *code)
Definition vmps.c:154
ssize_t fr_vmps_encode(fr_dbuff_t *dbuff, uint8_t const *original, int code, uint32_t seq_no, fr_dcursor_t *cursor)
Definition vmps.c:269
static int _encode_test_ctx(UNUSED fr_vmps_ctx_t *proto_ctx)
Definition vmps.c:561
char const * fr_vmps_packet_names[FR_VMPS_CODE_MAX]
Definition vmps.c:75
static int _decode_test_ctx(UNUSED fr_vmps_ctx_t *proto_ctx)
Definition vmps.c:519
static ssize_t fr_vmps_encode_proto(UNUSED TALLOC_CTX *ctx, fr_pair_list_t *vps, uint8_t *data, size_t data_len, UNUSED void *proto_ctx)
Definition vmps.c:552
bool fr_vmps_ok(uint8_t const *packet, size_t *packet_len)
Definition vmps.c:83
ssize_t fr_vmps_packet_size(uint8_t const *data, size_t data_len)
See how big of a packet is in the buffer.
Definition vmps.c:372
static int encode_test_ctx(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict, UNUSED fr_dict_attr_t const *root_da)
Definition vmps.c:568
fr_test_point_proto_decode_t vmps_tp_decode_proto
Definition vmps.c:544
void fr_vmps_print_hex(FILE *fp, uint8_t const *packet, size_t packet_len)
Print a raw VMPS packet as hex.
Definition vmps.c:464
fr_test_point_proto_encode_t vmps_tp_encode_proto
Definition vmps.c:586
Used as the decoder ctx.
Definition vmps.c:40
Structures and prototypes for Cisco's VLAN Query Protocol.
@ FR_VMPS_CODE_MAX
Definition vmps.h:54
#define FR_VQP_VERSION
Definition vmps.h:35
#define FR_VQP_HDR_LEN
Definition vmps.h:34