All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vqp.c
Go to the documentation of this file.
1 /*
2  * vqp.c Functions to send/receive VQP packets.
3  *
4  * Version: $Id: 84304ca6ea5b6a3495f62403bd9af7f8c935dcc2 $
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2007 Alan DeKok <aland@deployingradius.com>
21  */
22 
23 RCSID("$Id: 84304ca6ea5b6a3495f62403bd9af7f8c935dcc2 $")
24 
25 #include <freeradius-devel/libradius.h>
26 #include <freeradius-devel/udp.h>
27 
28 #include "vqp.h"
29 
30 #define MAX_VMPS_LEN (MAX_STRING_LEN - 1)
31 
32 /* @todo: this is a hack */
33 # define debug_pair(vp) do { if (fr_debug_lvl && fr_log_fp) { \
34  fr_pair_fprint(fr_log_fp, vp); \
35  } \
36  } while(0)
37 /*
38  * http://www.openbsd.org/cgi-bin/cvsweb/src/usr.sbin/tcpdump/print-vqp.c
39  *
40  * Some of how it works:
41  *
42  * http://www.hackingciscoexposed.com/pdf/chapter12.pdf
43  *
44  * VLAN Query Protocol (VQP)
45  *
46  * 0 1 2 3
47  * 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
48  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49  * | Version | Opcode | Response Code | Data Count |
50  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51  * | Transaction ID |
52  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53  * | Type (1) |
54  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55  * | Length | Data /
56  * / /
57  * / /
58  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59  * | Type (n) |
60  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
61  * | Length | Data /
62  * / /
63  * / /
64  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65  *
66  * VQP is layered over UDP. The default destination port is 1589.
67  *
68  */
69 #define VQP_HDR_LEN (8)
70 #define VQP_VERSION (1)
71 #define VQP_MAX_ATTRIBUTES (12)
72 
73 
74 static ssize_t vqp_recv_header(int sockfd)
75 {
76  ssize_t data_len;
77  uint8_t header[VQP_HDR_LEN];
78 
79  /*
80  * Read the length of the packet, from the packet.
81  * This lets us allocate the buffer to use for
82  * reading the rest of the packet.
83  */
84  data_len = udp_recv_peek(sockfd, header, sizeof(header), UDP_FLAGS_PEEK, NULL, NULL);
85  if (data_len < 0) return -1;
86 
87  /*
88  * Too little data is available, discard the packet.
89  */
90  if (data_len < VQP_HDR_LEN) {
91  udp_recv_discard(sockfd);
92  return 0;
93  }
94 
95  /*
96  * Invalid version, packet type, or too many
97  * attributes. Die.
98  */
99  if ((header[0] != VQP_VERSION) ||
100  (header[1] < 1) ||
101  (header[1] > 4) ||
102  (header[3] > VQP_MAX_ATTRIBUTES)) {
103  udp_recv_discard(sockfd);
104  return 0;
105  }
106 
107  /*
108  * Hard-coded maximum size. Because the header doesn't
109  * have a packet length.
110  */
111  return (12 * (4 + 4 + MAX_VMPS_LEN));
112 }
113 
115 {
116  uint8_t *ptr;
117  ssize_t data_len;
118  uint32_t id;
119  int attrlen;
120  RADIUS_PACKET *packet;
121 
122  data_len = vqp_recv_header(sockfd);
123  if (data_len < 0) {
124  fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno));
125  return NULL;
126  }
127 
128  /*
129  * Allocate the new request data structure
130  */
131  packet = fr_radius_alloc(NULL, false);
132  if (!packet) {
133  fr_strerror_printf("out of memory");
134  return NULL;
135  }
136 
137  packet->data_len = data_len;
138  packet->data = talloc_array(packet, uint8_t, data_len);
139  if (!packet->data_len) {
140  fr_radius_free(&packet);
141  return NULL;
142  }
143 
144  data_len = udp_recv(sockfd, packet->data, packet->data_len, 0,
145  &packet->src_ipaddr, &packet->src_port,
146  &packet->dst_ipaddr, &packet->dst_port,
147  &packet->if_index, &packet->timestamp);
148  if (data_len <= 0) {
149  fr_radius_free(&packet);
150  return NULL;
151  }
152 
153  /*
154  * Save the real length of the packet.
155  */
156  packet->data_len = data_len;
157 
158  /*
159  * Set up the fields in the packet.
160  */
161  packet->sockfd = sockfd;
162  packet->vps = NULL;
163 
164  /*
165  * This is more than a bit of a hack.
166  */
167  packet->code = PW_CODE_ACCESS_REQUEST;
168 
169  memcpy(&id, packet->data + 4, 4);
170  packet->id = ntohl(id);
171 
172  if (packet->data_len == VQP_HDR_LEN) {
173  return packet;
174  }
175 
176  /*
177  * Skip the header.
178  */
179  ptr = packet->data + VQP_HDR_LEN;
180  data_len = packet->data_len - VQP_HDR_LEN;
181 
182  while (data_len > 0) {
183  if (data_len < 7) {
184  fr_strerror_printf("Packet contains malformed attribute");
185  fr_radius_free(&packet);
186  return NULL;
187  }
188 
189  /*
190  * Attributes are 4 bytes
191  * 0x00000c01 ... 0x00000c08
192  */
193  if ((ptr[0] != 0) || (ptr[1] != 0) ||
194  (ptr[2] != 0x0c) || (ptr[3] < 1) || (ptr[3] > 8)) {
195  fr_strerror_printf("Packet contains invalid attribute");
196  fr_radius_free(&packet);
197  return NULL;
198  }
199 
200  /*
201  * Length is 2 bytes
202  *
203  * We support short lengths, as there's no reason
204  * for bigger lengths to exist... admins won't be
205  * typing in a 32K vlan name.
206  *
207  * It's OK for ethernet frames to be longer.
208  */
209  if ((ptr[3] != 5) &&
210  ((ptr[4] != 0) || (ptr[5] > MAX_VMPS_LEN))) {
211  fr_strerror_printf("Packet contains attribute with invalid length %02x %02x", ptr[4], ptr[5]);
212  fr_radius_free(&packet);
213  return NULL;
214  }
215 
216  attrlen = (ptr[4] << 8) | ptr[5];
217  ptr += 6 + attrlen;
218  data_len -= (6 + attrlen);
219  }
220 
221  return packet;
222 }
223 
224 /*
225  * We do NOT mirror the old-style RADIUS code that does encode,
226  * sign && send in one function. For VQP, the caller MUST perform
227  * each task manually, and separately.
228  */
230 {
231  if (!packet || !packet->data || (packet->data_len < VQP_HDR_LEN)) return -1;
232 
233  /*
234  * Don't print out the attributes, they were printed out
235  * when it was encoded.
236  */
237 
238  /*
239  * And send it on it's way.
240  */
241  return udp_send(packet->sockfd, packet->data, packet->data_len, 0,
242  &packet->src_ipaddr, packet->src_port, packet->if_index,
243  &packet->dst_ipaddr, packet->dst_port);
244 }
245 
246 
248 {
249  uint8_t *ptr, *end;
250  int attr, attr_len;
251  vp_cursor_t cursor;
252  VALUE_PAIR *vp;
253 
254  if (!packet || !packet->data) return -1;
255 
256  if (packet->data_len < VQP_HDR_LEN) return -1;
257 
258  fr_cursor_init(&cursor, &packet->vps);
259  vp = fr_pair_afrom_num(packet, 0, PW_VQP_PACKET_TYPE);
260  if (!vp) {
261  fr_strerror_printf("No memory");
262  return -1;
263  }
264  vp->vp_integer = packet->data[1];
265  debug_pair(vp);
266  fr_cursor_insert(&cursor, vp);
267 
268  vp = fr_pair_afrom_num(packet, 0, PW_VQP_ERROR_CODE);
269  if (!vp) {
270  fr_strerror_printf("No memory");
271  return -1;
272  }
273  vp->vp_integer = packet->data[2];
274  debug_pair(vp);
275  fr_cursor_insert(&cursor, vp);
276 
277  vp = fr_pair_afrom_num(packet, 0, PW_VQP_SEQUENCE_NUMBER);
278  if (!vp) {
279  fr_strerror_printf("No memory");
280  return -1;
281  }
282  vp->vp_integer = packet->id; /* already set by vqp_recv */
283  debug_pair(vp);
284  fr_cursor_insert(&cursor, vp);
285 
286  ptr = packet->data + VQP_HDR_LEN;
287  end = packet->data + packet->data_len;
288 
289  /*
290  * Note that vqp_recv() MUST ensure that the packet is
291  * formatted in a way we expect, and that vqp_recv() MUST
292  * be called before vqp_decode().
293  */
294  while (ptr < end) {
295  attr = (ptr[2] << 8) | ptr[3];
296  attr_len = (ptr[4] << 8) | ptr[5];
297  ptr += 6;
298 
299  /*
300  * Hack to get the dictionaries to work correctly.
301  */
302  attr |= 0x2000;
303  vp = fr_pair_afrom_num(packet, 0, attr);
304  if (!vp) {
305  fr_pair_list_free(&packet->vps);
306 
307  fr_strerror_printf("No memory");
308  return -1;
309  }
310 
311  switch (vp->da->type) {
312  case PW_TYPE_ETHERNET:
313  if (attr_len != 6) goto unknown;
314 
315  memcpy(&vp->vp_ether, ptr, 6);
316  vp->vp_length = 6;
317  break;
318 
319  case PW_TYPE_IPV4_ADDR:
320  if (attr_len == 4) {
321  memcpy(&vp->vp_ipaddr, ptr, 4);
322  vp->vp_length = 4;
323  break;
324  }
325 
326  /*
327  * Value doesn't match the type we have for the
328  * valuepair so we must change it's da to an
329  * unknown attr.
330  */
331  unknown:
333  vp->da->attr);
334  /* FALL-THROUGH */
335 
336  default:
337  case PW_TYPE_OCTETS:
338  fr_pair_value_memcpy(vp, ptr, attr_len);
339  break;
340 
341  case PW_TYPE_STRING:
342  fr_pair_value_bstrncpy(vp, ptr, attr_len);
343  break;
344  }
345  ptr += attr_len;
346  debug_pair(vp);
347  fr_cursor_insert(&cursor, vp);
348  }
349 
350  /*
351  * FIXME: Map attributes to Calling-Station-Id, etc...
352  */
353 
354  return 0;
355 }
356 
357 /*
358  * These are the MUST HAVE contents for a VQP packet.
359  *
360  * We don't allow the caller to give less than these, because
361  * it won't work. We don't encode more than these, because the
362  * clients will ignore it.
363  *
364  * FIXME: Be more generous? Look for CISCO + VQP attributes?
365  */
366 static int contents[5][VQP_MAX_ATTRIBUTES] = {
367  { 0, 0, 0, 0, 0, 0 },
368  { 0x0c01, 0x0c02, 0x0c03, 0x0c04, 0x0c07, 0x0c05 }, /* Join request */
369  { 0x0c03, 0x0c08, 0, 0, 0, 0 }, /* Join Response */
370  { 0x0c01, 0x0c02, 0x0c03, 0x0c04, 0x0c07, 0x0c08 }, /* Reconfirm */
371  { 0x0c03, 0x0c08, 0, 0, 0, 0 }
372 };
373 
374 int vqp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
375 {
376  int i, code, length;
377  VALUE_PAIR *vp;
378  uint8_t *out;
380 
381  if (!packet) {
382  fr_strerror_printf("Failed encoding VQP");
383  return -1;
384  }
385 
386  if (packet->data) return 0;
387 
388  vp = fr_pair_find_by_num(packet->vps, 0, PW_VQP_PACKET_TYPE, TAG_ANY);
389  if (!vp) {
390  fr_strerror_printf("Failed to find VQP-Packet-Type in response packet");
391  return -1;
392  }
393 
394  code = vp->vp_integer;
395  if ((code < 1) || (code > 4)) {
396  fr_strerror_printf("Invalid value %d for VQP-Packet-Type", code);
397  return -1;
398  }
399 
400  length = VQP_HDR_LEN;
401 
402  vp = fr_pair_find_by_num(packet->vps, 0, PW_VQP_ERROR_CODE, TAG_ANY);
403  if (vp) {
404  packet->data = talloc_array(packet, uint8_t, length);
405  if (!packet->data) {
406  fr_strerror_printf("No memory");
407  return -1;
408  }
409  packet->data_len = length;
410 
411  out = packet->data;
412 
413  out[0] = VQP_VERSION;
414  out[1] = code;
415 
416  out[2] = vp->vp_integer & 0xff;
417  return 0;
418  }
419 
420  /*
421  * FIXME: Map attributes from calling-station-Id, etc.
422  *
423  * Maybe do this via rlm_vqp? That's probably the
424  * best place to add the code...
425  */
426 
427  memset(vps, 0, sizeof(vps));
428 
429  /*
430  * Determine how long the packet is.
431  */
432  for (i = 0; i < VQP_MAX_ATTRIBUTES; i++) {
433  if (!contents[code][i]) break;
434 
435  vps[i] = fr_pair_find_by_num(packet->vps, 0, contents[code][i] | 0x2000, TAG_ANY);
436 
437  /*
438  * FIXME: Print the name...
439  */
440  if (!vps[i]) {
441  fr_strerror_printf("Failed to find VQP attribute %02x",
442  contents[code][i]);
443  return -1;
444  }
445 
446  length += 6; /* header */
447  length += vps[i]->vp_length;
448  }
449 
450  packet->data = talloc_array(packet, uint8_t, length);
451  if (!packet->data) {
452  fr_strerror_printf("No memory");
453  return -1;
454  }
455  packet->data_len = length;
456 
457  out = packet->data;
458 
459  out[0] = VQP_VERSION;
460  out[1] = code;
461  out[2] = 0;
462 
463  /*
464  * The number of attributes is hard-coded.
465  */
466  if ((code == 1) || (code == 3)) {
467  uint32_t sequence;
468 
469  out[3] = VQP_MAX_ATTRIBUTES;
470 
471  sequence = htonl(packet->id);
472  memcpy(out + 4, &sequence, 4);
473  } else {
474  if (!original) {
475  fr_strerror_printf("Cannot send VQP response without request");
476  return -1;
477  }
478 
479  /*
480  * Packet Sequence Number
481  */
482  memcpy(out + 4, original->data + 4, 4);
483 
484  out[3] = 2;
485  }
486 
487  out += 8;
488 
489  /*
490  * Encode the VP's.
491  */
492  for (i = 0; i < VQP_MAX_ATTRIBUTES; i++) {
493  if (!vps[i]) break;
494  if (out >= (packet->data + packet->data_len)) break;
495 
496  vp = vps[i];
497 
498  debug_pair(vp);
499 
500  /*
501  * Type. Note that we look at only the lower 8
502  * bits, as the upper 8 bits have been hacked.
503  * See also dictionary.vqp
504  */
505  out[0] = 0;
506  out[1] = 0;
507  out[2] = 0x0c;
508  out[3] = vp->da->attr & 0xff;
509 
510  /* Length */
511  out[4] = 0;
512  out[5] = vp->vp_length & 0xff;
513 
514  out += 6;
515 
516  /* Data */
517  switch (vp->da->type) {
518  case PW_TYPE_IPV4_ADDR:
519  memcpy(out, &vp->vp_ipaddr, 4);
520  break;
521 
522  case PW_TYPE_ETHERNET:
523  memcpy(out, vp->vp_ether, vp->vp_length);
524  break;
525 
526  case PW_TYPE_OCTETS:
527  case PW_TYPE_STRING:
528  memcpy(out, vp->vp_octets, vp->vp_length);
529  break;
530 
531  default:
532  return -1;
533  }
534  out += vp->vp_length;
535  }
536 
537  return 0;
538 }
539 
540 /** See how big of a packet is in the buffer.
541  *
542  * Packet is not 'const * const' because we may update data_len, if there's more data
543  * in the UDP packet than in the VMPS packet.
544  *
545  * @param data pointer to the packet buffer
546  * @param data_len length of the packet buffer
547  * @return
548  * <= 0 packet is bad.
549  * >0 how much of the data is a packet (can be larger than data_len)
550  */
551 ssize_t vqp_packet_size(uint8_t const *data, size_t data_len)
552 {
553  int attributes;
554  uint8_t const *ptr, *end;
555 
556  if (data_len < VQP_HDR_LEN) return VQP_HDR_LEN;
557 
558  /*
559  * No attributes.
560  */
561  if (data[3] == 0) return VQP_HDR_LEN;
562 
563  /*
564  * Too many attributes. Return an error indicating that
565  * there's a problem with octet 3.
566  */
567  if (data[3] > VQP_MAX_ATTRIBUTES) return -3;
568 
569  /*
570  * Look for attributes.
571  */
572  ptr = data + VQP_HDR_LEN;
573  attributes = data[3];
574 
575  end = data + data_len;
576 
577  while (attributes > 0) {
578  size_t attr_len;
579 
580  /*
581  * Not enough room for the attribute headers, we
582  * want at least those.
583  */
584  if ((end - ptr) < 6) {
585  return 6 * attributes;
586  }
587 
588  /*
589  * Length of the data NOT including the header.
590  */
591  attr_len = (ptr[4] << 8) | ptr[5];
592 
593  ptr += 6 + attr_len;
594 
595  /*
596  * We don't want to read infinite amounts of data.
597  *
598  * Return an error indicating that there's a
599  * problem with the final octet
600  */
601  if ((ptr - data) > 4096) {
602  return -(ptr - data);
603  }
604 
605  /*
606  * This attribute has been checked.
607  */
608  attributes--;
609 
610  /*
611  * The packet we want is larger than the input
612  * buffer, so we return the length of the current
613  * attribute, plus the length of the remaining
614  * headers.
615  */
616  if (ptr > end) return (6 * attributes) + ptr - data;
617  }
618 
619  /*
620  * We've reached the end of the packet.
621  */
622  return ptr - data;
623 }
void fr_pair_list_free(VALUE_PAIR **)
Free memory used by a valuepair list.
Definition: pair.c:544
int sockfd
Socket this packet was read from.
Definition: libradius.h:147
static int sockfd
Definition: radclient.c:59
fr_dict_attr_t * fr_dict_unknown_afrom_fields(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int vendor, unsigned int attr) CC_HINT(nonnull)
Allocates an unknown attribute.
Definition: dict.c:2613
int id
Packet ID (used to link requests/responses).
Definition: libradius.h:154
struct timeval timestamp
When we received the packet.
Definition: libradius.h:159
ssize_t udp_recv_peek(int sockfd, void *data, size_t data_len, int flags, fr_ipaddr_t *src_ipaddr, uint16_t *src_port)
Peek at the header of a UDP packet.
Definition: udp.c:125
VALUE_PAIR * fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int vendor, unsigned int attr)
Create a new valuepair.
Definition: pair.c:106
fr_ipaddr_t src_ipaddr
Src IP address of packet.
Definition: libradius.h:149
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
Definition: cursor.c:60
uint8_t length
Definition: proto_bfd.c:203
uint8_t * data
Packet data (body).
Definition: libradius.h:160
uint16_t dst_port
DST Port of packet.
Definition: libradius.h:152
uint16_t src_port
Src port of packet.
Definition: libradius.h:151
fr_ipaddr_t dst_ipaddr
Dst IP address of packet.
Definition: libradius.h:150
int vqp_send(RADIUS_PACKET *packet)
Definition: vqp.c:229
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Definition: pair.h:144
#define VQP_VERSION
Definition: vqp.c:70
ssize_t vqp_packet_size(uint8_t const *data, size_t data_len)
See how big of a packet is in the buffer.
Definition: vqp.c:551
#define VQP_MAX_ATTRIBUTES
Definition: vqp.c:71
RFC2865 - Access-Request.
Definition: radius.h:92
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: log.c:238
static int contents[5][VQP_MAX_ATTRIBUTES]
Definition: vqp.c:366
void fr_cursor_insert(vp_cursor_t *cursor, VALUE_PAIR *vp)
Insert a single VALUE_PAIR at the end of the list.
Definition: cursor.c:321
RADIUS_PACKET * fr_radius_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new RADIUS_PACKET.
Definition: radius.c:1651
ssize_t udp_recv(int sockfd, void *data, size_t data_len, int flags, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, fr_ipaddr_t *dst_ipaddr, uint16_t *dst_port, int *if_index, struct timeval *when)
unsigned int attr
Attribute number.
Definition: dict.h:79
ssize_t udp_send(int sockfd, void *data, size_t data_len, int flags, fr_ipaddr_t *src_ipaddr, uint16_t src_port, int if_index, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port)
unsigned int code
Packet code (type).
Definition: libradius.h:155
unsigned int vendor
Vendor that defines this attribute.
Definition: dict.h:78
48 Bit Mac-Address.
Definition: radius.h:44
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
RADIUS_PACKET * vqp_recv(int sockfd)
Definition: vqp.c:114
#define MAX_VMPS_LEN
Definition: vqp.c:30
#define debug_pair(vp)
Definition: vqp.c:33
#define UDP_FLAGS_PEEK
Definition: udp.h:40
int if_index
Index of receiving interface.
Definition: libradius.h:148
static ssize_t vqp_recv_header(int sockfd)
Definition: vqp.c:74
uint8_t data[]
Definition: eap_pwd.h:625
#define TAG_ANY
Definition: pair.h:191
void fr_radius_free(RADIUS_PACKET **)
Free a RADIUS_PACKET.
Definition: radius.c:1727
size_t data_len
Length of packet data.
Definition: libradius.h:161
#define VQP_HDR_LEN
Definition: vqp.c:69
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
int vqp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
Definition: vqp.c:374
int vqp_decode(RADIUS_PACKET *packet)
Definition: vqp.c:247
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
void fr_pair_value_bstrncpy(VALUE_PAIR *vp, void const *src, size_t len)
Copy data into an "string" data type.
Definition: pair.c:2043
String of printable characters.
Definition: radius.h:33
Structures and prototypes for Cisco's VLAN Query Protocol.
PW_TYPE type
Value type.
Definition: dict.h:80
#define RCSID(id)
Definition: build.h:135
32 Bit IPv4 Address.
Definition: radius.h:35
fr_dict_t * fr_dict_internal
Internal server dictionary.
Definition: dict.c:81
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict.c:2339
void udp_recv_discard(int sockfd)
Discard the next UDP packet.
Definition: udp.c:105
Raw octets.
Definition: radius.h:38
void fr_pair_value_memcpy(VALUE_PAIR *vp, uint8_t const *src, size_t len)
Copy data into an "octets" data type.
Definition: pair.c:1905