The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: cadd09910a18e6a496a7e905c91acd7a2668af9d $
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 
26 RCSID("$Id: cadd09910a18e6a496a7e905c91acd7a2668af9d $")
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  */
40 typedef struct {
41  int nothing;
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 
83 bool 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 
154 int 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;
172  DEBUG2("&%pP", vp);
174 
176  if (!vp) goto oom;
177  vp->vp_uint32 = data[2];
178  vp->vp_tainted = true;
179  DEBUG2("&%pP", vp);
181 
183  if (!vp) goto oom;
184 
185  vp->vp_uint32 = fr_nbo_to_uint32(data + 4);
186  vp->vp_tainted = true;
187  DEBUG2("&%pP", vp);
189 
190  ptr = data + FR_VQP_HDR_LEN;
191  end = data + data_len;
192 
193  /*
194  * Note that vmps_recv() MUST ensure that the packet is
195  * formatted in a way we expect, and that vmps_recv() MUST
196  * be called before vmps_decode().
197  */
198  while (ptr < end) {
199  if ((end - ptr) < 6) {
200  fr_strerror_printf("Packet is too small. (%ld < 6)", (end - ptr));
201  return -1;
202  }
203 
204  attr = fr_nbo_to_uint16(ptr + 2);
205  attr_len = fr_nbo_to_uint16(ptr + 4);
206  ptr += 6;
207 
208  /*
209  * fr_vmps_ok() should have checked this already,
210  * but it doesn't hurt to do it again.
211  */
212  if (attr_len > (size_t) (end - ptr)) {
213  fr_strerror_const("Attribute length exceeds received data");
214  return -1;
215  }
216 
217  /*
218  * Create the VP.
219  */
221  if (!vp) {
222  fr_strerror_const("No memory");
223  return -1;
224  }
225 
226  /*
227  * Rely on value_box to do the work.
228  *
229  * @todo - if the attribute is malformed, create a "raw" one.
230  */
231  if (fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
232  &FR_DBUFF_TMP(ptr, attr_len), attr_len, true) < 0) {
233  talloc_free(vp);
234  return -1;
235  }
236 
237  ptr += attr_len;
238  vp->vp_tainted = true;
239  DEBUG2("&%pP", vp);
241  }
242 
243  /*
244  * FIXME: Map attributes to Calling-Station-Id, etc...
245  */
246 
247  return data_len;
248 }
249 
250 #if 0
251 /*
252  * These are the MUST HAVE contents for a VQP packet.
253  *
254  * We don't allow the caller to give less than these, because
255  * it won't work. We don't encode more than these, because the
256  * clients will ignore it.
257  *
258  * FIXME: Be more generous? Look for CISCO + VQP attributes?
259  *
260  * @todo - actually use these again...
261  */
262 static int contents[5][VQP_MAX_ATTRIBUTES] = {
263  { 0, 0, 0, 0, 0, 0 },
264  { 0x0c01, 0x0c02, 0x0c03, 0x0c04, 0x0c07, 0x0c05 }, /* Join request */
265  { 0x0c03, 0x0c08, 0, 0, 0, 0 }, /* Join Response */
266  { 0x0c01, 0x0c02, 0x0c03, 0x0c04, 0x0c07, 0x0c08 }, /* Reconfirm */
267  { 0x0c03, 0x0c08, 0, 0, 0, 0 }
268 };
269 #endif
270 
271 ssize_t fr_vmps_encode(fr_dbuff_t *dbuff, uint8_t const *original,
272  int code, uint32_t seq_no, fr_dcursor_t *cursor)
273 {
274  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
275  fr_pair_t *vp;
276  fr_dbuff_marker_t hdr, m;
277  uint8_t data_count = 0;
278 
279  /*
280  * Let's keep a reference for packet header, and another
281  * to let us write to to the encoding as needed.
282  */
283  fr_dbuff_marker(&hdr, &work_dbuff);
284  fr_dbuff_marker(&m, &work_dbuff);
285 
286  /*
287  * Create the header
288  */
289  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_VQP_VERSION, /* Version */
290  code, /* Opcode */
291  FR_ERROR_CODE_VALUE_NO_ERROR, /* Response Code */
292  data_count); /* Data Count */
293 
294  if (original) {
295  FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, original + 4, 4);
296  } else {
297  FR_DBUFF_IN_RETURN(&work_dbuff, seq_no);
298  }
299 
300  /*
301  * Encode the VP's.
302  */
303  while ((vp = fr_dcursor_current(cursor))) {
304  ssize_t slen;
305 
306  if (vp->da == attr_packet_type) {
307  fr_dbuff_set(&m, fr_dbuff_current(&hdr) + 1);
308  FR_DBUFF_IN_RETURN(&m, (uint8_t)vp->vp_uint32);
309  fr_dcursor_next(cursor);
310  continue;
311  }
312 
313  if (vp->da == attr_error_code) {
314  fr_dbuff_set(&m, fr_dbuff_current(&hdr) + 2);
315  FR_DBUFF_IN_RETURN(&m, vp->vp_uint8);
316  fr_dcursor_next(cursor);
317  continue;
318  }
319 
320  if (!original && (vp->da == attr_sequence_number)) {
321  fr_dbuff_set(&m, fr_dbuff_current(&hdr) + 4);
322  FR_DBUFF_IN_RETURN(&m, vp->vp_uint32);
323  fr_dcursor_next(cursor);
324  continue;
325  }
326 
327  if (!fr_type_is_leaf(vp->vp_type)) continue;
328 
329  DEBUG2("&%pP", vp);
330 
331  /*
332  * Type. Note that we look at only the lower 8
333  * bits, as the upper 8 bits have been hacked.
334  * See also dictionary.vmps
335  */
336 
337  /* Type */
338  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, 0x00, 0x00, 0x0c, (vp->da->attr & 0xff));
339 
340  /* Length */
341  fr_dbuff_set(&m, fr_dbuff_current(&work_dbuff));
342  FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t) 0);
343 
344  /* Data */
345  slen = fr_value_box_to_network(&work_dbuff, &vp->data);
346  if (slen < 0) return slen;
347 
348  FR_DBUFF_IN_RETURN(&m, (uint16_t) slen);
349 
350  data_count++;
351 
352  fr_dcursor_next(cursor);
353  }
354 
355  /*
356  * Update the Data Count
357  */
358  fr_dbuff_set(&m, fr_dbuff_current(&hdr) + 3);
359  FR_DBUFF_IN_RETURN(&m, data_count);
360 
361  return fr_dbuff_set(dbuff, &work_dbuff);
362 }
363 
364 
365 /** See how big of a packet is in the buffer.
366  *
367  * Packet is not 'const * const' because we may update data_len, if there's more data
368  * in the UDP packet than in the VMPS packet.
369  *
370  * @param data pointer to the packet buffer
371  * @param data_len length of the packet buffer
372  * @return
373  * <= 0 packet is bad.
374  * >0 how much of the data is a packet (can be larger than data_len)
375  */
376 ssize_t fr_vmps_packet_size(uint8_t const *data, size_t data_len)
377 {
378  int attributes;
379  uint8_t const *ptr, *end;
380 
381  if (data_len < FR_VQP_HDR_LEN) return FR_VQP_HDR_LEN;
382 
383  /*
384  * No attributes.
385  */
386  if (data[3] == 0) return FR_VQP_HDR_LEN;
387 
388  /*
389  * Too many attributes. Return an error indicating that
390  * there's a problem with octet 3.
391  */
392  if (data[3] > 30) return -3;
393 
394  /*
395  * Look for attributes.
396  */
397  ptr = data + FR_VQP_HDR_LEN;
398  attributes = data[3];
399 
400  end = data + data_len;
401 
402  while (attributes > 0) {
403  size_t attr_len;
404 
405  /*
406  * Not enough room for the attribute headers, we
407  * want at least those.
408  */
409  if ((end - ptr) < 6) {
410  return 6 * attributes;
411  }
412 
413  /*
414  * Length of the data NOT including the header.
415  */
416  attr_len = fr_nbo_to_uint16(ptr + 4);
417 
418  ptr += 6 + attr_len;
419 
420  /*
421  * We don't want to read infinite amounts of data.
422  *
423  * Return an error indicating that there's a
424  * problem with the final octet
425  */
426  if ((ptr - data) > 4096) {
427  return -(ptr - data);
428  }
429 
430  /*
431  * This attribute has been checked.
432  */
433  attributes--;
434 
435  /*
436  * The packet we want is larger than the input
437  * buffer, so we return the length of the current
438  * attribute, plus the length of the remaining
439  * headers.
440  */
441  if (ptr > end) return (6 * attributes) + ptr - data;
442  }
443 
444  /*
445  * We've reached the end of the packet.
446  */
447  return ptr - data;
448 }
449 
450 static void print_hex_data(uint8_t const *ptr, int attrlen, int depth)
451 {
452  int i;
453  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";
454 
455  for (i = 0; i < attrlen; i++) {
456  if ((i > 0) && ((i & 0x0f) == 0x00))
457  fprintf(fr_log_fp, "%.*s", depth, tabs);
458  fprintf(fr_log_fp, "%02x ", ptr[i]);
459  if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
460  }
461  if ((i & 0x0f) != 0) fprintf(fr_log_fp, "\n");
462 }
463 
464 
465 /** Print a raw VMPS packet as hex.
466  *
467  */
468 void fr_vmps_print_hex(FILE *fp, uint8_t const *packet, size_t packet_len)
469 {
470  int length;
471  uint8_t const *attr, *end;
472  uint32_t id;
473 
474  if (packet_len < 8) return;
475 
476  fprintf(fp, " Version:\t\t%u\n", packet[0]);
477 
478  if ((packet[1] > 0) && (packet[1] < FR_VMPS_CODE_MAX) && fr_vmps_packet_names[packet[1]]) {
479  fprintf(fp, " OpCode:\t\t%s\n", fr_vmps_packet_names[packet[1]]);
480  } else {
481  fprintf(fp, " OpCode:\t\t%u\n", packet[1]);
482  }
483 
484  if ((packet[2] > 0) && (packet[2] < FR_VMPS_CODE_MAX) && fr_vmps_packet_names[packet[2]]) {
485  fprintf(fp, " OpCode:\t\t%s\n", fr_vmps_packet_names[packet[2]]);
486  } else {
487  fprintf(fp, " OpCode:\t\t%u\n", packet[2]);
488  }
489 
490  fprintf(fp, " Data Count:\t\t%u\n", packet[3]);
491 
492  memcpy(&id, packet + 4, 4);
493  id = ntohl(id);
494 
495  fprintf(fp, " ID:\t%08x\n", id);
496 
497  if (packet_len == 8) return;
498 
499  for (attr = packet + 8, end = packet + packet_len;
500  attr < end;
501  attr += length) {
502  memcpy(&id, attr, 4);
503  id = ntohl(id);
504 
505  length = fr_nbo_to_uint16(attr + 4);
506  if (length > (end - attr)) break;
507 
508  fprintf(fp, "\t\t%08x %04x ", id, length);
509 
510  print_hex_data(attr + 6, length - 6, 3);
511  }
512 }
513 
514 /*
515  * Test points for protocol decode
516  */
518  uint8_t const *data, size_t data_len, void *proto_ctx)
519 {
520  return fr_vmps_decode(ctx, out, data, data_len, proto_ctx);
521 }
522 
523 static int _decode_test_ctx(UNUSED fr_vmps_ctx_t *proto_ctx)
524 {
526 
527  return 0;
528 }
529 
530 static int decode_test_ctx(void **out, TALLOC_CTX *ctx)
531 {
532  fr_vmps_ctx_t *test_ctx;
533 
534  if (fr_vmps_global_init() < 0) return -1;
535 
536  test_ctx = talloc_zero(ctx, fr_vmps_ctx_t);
537  if (!test_ctx) return -1;
538 
539  talloc_set_destructor(test_ctx, _decode_test_ctx);
540 
541  *out = test_ctx;
542 
543  return 0;
544 }
545 
549  .func = fr_vmps_decode_proto
550 };
551 
552 /*
553  * Test points for protocol encode
554  */
555 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)
556 {
557  fr_dcursor_t cursor;
558 
560 
561  return fr_vmps_encode(&FR_DBUFF_TMP(data, data_len), NULL, -1, -1, &cursor);
562 }
563 
564 static int _encode_test_ctx(UNUSED fr_vmps_ctx_t *proto_ctx)
565 {
567 
568  return 0;
569 }
570 
571 static int encode_test_ctx(void **out, TALLOC_CTX *ctx)
572 {
573  fr_vmps_ctx_t *test_ctx;
574 
575  if (fr_vmps_global_init() < 0) return -1;
576 
577  test_ctx = talloc_zero(ctx, fr_vmps_ctx_t);
578  if (!test_ctx) return -1;
579 
580  talloc_set_destructor(test_ctx, _encode_test_ctx);
581 
582  *out = test_ctx;
583 
584  return 0;
585 }
586 
590  .func = fr_vmps_encode_proto
591 };
#define RCSID(id)
Definition: build.h:444
#define UNUSED
Definition: build.h:313
static const char * tabs
Definition: command.c:1581
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
Definition: dbuff.h:81
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition: dbuff.h:906
#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:1377
#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:1580
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition: dbuff.h:222
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:1187
#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:1467
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition: dbuff.h:509
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:287
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition: dcursor.h:336
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:1997
talloc_free(reap)
FILE * fr_log_fp
Definition: log.c:41
unsigned short uint16_t
Definition: merged_model.c:31
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 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:137
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:158
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:278
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:1340
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:366
void * fr_proto_next_encodable(fr_dlist_head_t *list, 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:76
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
#define DEBUG2(fmt,...)
Definition: radclient.h:43
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:74
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition: test_point.h:66
Entry point for protocol decoders.
Definition: test_point.h:65
Entry point for protocol encoders.
Definition: test_point.h:73
#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:568
#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:372
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:1709
return fr_dbuff_set(dbuff, &our_dbuff)
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:1359
static fr_slen_t data
Definition: value.h:1259
static size_t char ** out
Definition: value.h:984
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:517
static void print_hex_data(uint8_t const *ptr, int attrlen, int depth)
Definition: vmps.c:450
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
static int decode_test_ctx(void **out, TALLOC_CTX *ctx)
Definition: vmps.c:530
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:271
static int _encode_test_ctx(UNUSED fr_vmps_ctx_t *proto_ctx)
Definition: vmps.c:564
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:523
static int encode_test_ctx(void **out, TALLOC_CTX *ctx)
Definition: vmps.c:571
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:555
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:376
fr_test_point_proto_decode_t vmps_tp_decode_proto
Definition: vmps.c:547
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:468
fr_test_point_proto_encode_t vmps_tp_encode_proto
Definition: vmps.c:588
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