MAC LTE: upgrade dissector to v13.1.0
[metze/wireshark/wip.git] / epan / radius_dict.l
1 /*
2  * We don't use input, so don't generate code for it.
3  */
4 %option noinput
5
6 /*
7  * We don't use unput, so don't generate code for it.
8  */
9 %option nounput
10
11 /*
12  * We don't read interactively from the terminal.
13  */
14 %option never-interactive
15
16 /*
17  * We want to stop processing when we get to the end of the input.
18  */
19 %option noyywrap
20
21 /*
22  * The language we're scanning is case-insensitive.
23  */
24 %option caseless
25
26 /*
27  * Prefix scanner routines with "Radius" rather than "yy", so this scanner
28  * can coexist with other scanners.
29  */
30 %option prefix="Radius"
31
32 %option outfile="radius_dict.c"
33
34 %{
35         /* radius_dict.l
36         *
37         * RADIUS dictionary parser
38         *
39         * Wireshark - Network traffic analyzer
40         * By Gerald Combs <gerald@wireshark.org>
41         * Copyright 1998 Gerald Combs
42         *
43         * This program is free software; you can redistribute it and/or
44         * modify it under the terms of the GNU General Public License
45         * as published by the Free Software Foundation; either version 2
46         * of the License, or (at your option) any later version.
47         *
48         * This program is distributed in the hope that it will be useful,
49         * but WITHOUT ANY WARRANTY; without even the implied warranty of
50         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
51         * GNU General Public License for more details.
52         *
53         * You should have received a copy of the GNU General Public License
54         * along with this program; if not, write to the Free Software
55         * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
56         */
57
58 #include "config.h"
59
60 #include <glib.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <errno.h>
65 #include <epan/packet.h>
66 #include <epan/dissectors/packet-radius.h>
67 #include "radius_dict_lex.h"
68 #include <wsutil/file_util.h>
69
70 #ifdef _WIN32
71 /* disable Windows VC compiler warning "signed/unsigned mismatch" associated  */
72 /* with YY_INPUT code generated by flex versions such as 2.5.35.              */
73 #pragma warning (disable:4018)
74 #endif
75
76 #define ECHO
77 #define MAX_INCLUDE_DEPTH 10
78
79         static void add_vendor(const gchar* name, guint32 id, guint type_octets, guint length_octets, gboolean has_flags);
80         static void add_value(const gchar* attrib_name,const  gchar* repr, guint32 value);
81         static void add_tlv(const gchar* name, const  gchar* code, radius_attr_dissector_t type, const gchar* attr);
82         static void add_attribute(const gchar*,const  gchar*, radius_attr_dissector_t,const  gchar*, guint, gboolean, const gchar*);
83
84         static YY_BUFFER_STATE include_stack[10];
85         static int include_stack_ptr = 0;
86
87         static radius_dictionary_t* dict = NULL;
88         static GHashTable* value_strings = NULL; /* GArray(value_string) by attribute name */
89
90         static gchar* attr_name = NULL;
91         static gchar* attr_id = NULL;
92         static radius_attr_dissector_t* attr_type = NULL;
93         static gchar* attr_vendor = NULL;
94         static gchar* vendor_name = NULL;
95         static guint32 vendor_id = 0;
96         static guint vendor_type_octets = 1;
97         static guint vendor_length_octets = 1;
98         static gboolean vendor_has_flags = FALSE;
99         static gchar* value_repr = NULL;
100         static guint encrypted = 0;
101         static gboolean has_tag = FALSE;
102         static gchar* current_vendor = NULL;
103         static gchar* current_attr = NULL;
104
105         static GString* error = NULL;
106         static gchar* directory = NULL;
107         static int linenums[] = {1,1,1,1,1,1,1,1,1,1};
108         static gchar* fullpaths[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
109
110 %}
111
112 /* Note: FreeRadius allows VENDOR, ATTRIBUTE and VALUE names to contain any non-blank character.
113  *       Using a negated "blank character class" pattern below for those names fails for some reason
114  *       so for now the patterns for each name type include those characters found for the corresponding
115  *       name types in the FreeRadius dictionaries.
116  */
117
118 %START WS_OUT VENDOR VENDOR_W_NAME ATTR ATTR_W_NAME ATTR_W_ID ATTR_W_TYPE ATTR_W_VENDOR VALUE VALUE_W_ATTR VALUE_W_NAME INCLUDE JUNK BEGIN_VENDOR END_VENDOR VENDOR_W_ID VENDOR_W_FORMAT VENDOR_W_TYPE_OCTETS VENDOR_W_LENGTH_OCTETS VENDOR_W_CONTINUATION BEGIN_TLV END_TLV
119 %%
120 [:blank:]   ;
121 #[^\n]*         ;
122
123 <JUNK>.*\qn             ;
124
125 <WS_OUT>VENDOR { BEGIN VENDOR; }
126 <WS_OUT>ATTRIBUTE { BEGIN ATTR; }
127 <WS_OUT>VALUE { BEGIN VALUE; }
128 <WS_OUT>\$INCLUDE { BEGIN INCLUDE; }
129 <WS_OUT>BEGIN-VENDOR { BEGIN BEGIN_VENDOR; }
130 <WS_OUT>END-VENDOR { BEGIN END_VENDOR; }
131 <WS_OUT>BEGIN-TLV { BEGIN BEGIN_TLV; }
132 <WS_OUT>END-TLV { BEGIN END_TLV; }
133
134 <BEGIN_VENDOR>[0-9a-z_-]+ {
135     if (current_vendor) {
136         g_free(current_vendor);
137     }
138     current_vendor = g_strdup(yytext);
139     BEGIN WS_OUT;
140 }
141 <END_VENDOR>[^\n]* {
142     if (current_vendor) {
143         g_free(current_vendor);
144         current_vendor = NULL;
145     }
146     BEGIN WS_OUT;
147 }
148
149 <BEGIN_TLV>[0-9a-z_-]+ {
150     if (current_attr) {
151         g_free(current_attr);
152     }
153     current_attr = g_strdup(yytext);
154     BEGIN WS_OUT;
155 }
156 <END_TLV>[^\n]* {
157     if (current_attr) {
158         g_free(current_attr);
159         current_attr = NULL;
160     }
161     BEGIN WS_OUT;
162 }
163
164 <VENDOR>[0-9a-z_-]+   {
165     vendor_name = g_strdup(yytext);
166     vendor_type_octets = 1;
167     vendor_length_octets = 1;
168     vendor_has_flags = FALSE;
169     BEGIN VENDOR_W_NAME;
170 }
171 <VENDOR_W_NAME>[0-9]+   {
172     vendor_id = (guint32) strtoul(yytext,NULL,10);
173     BEGIN VENDOR_W_ID;
174 }
175 <VENDOR_W_NAME>0x[0-9a-f]+   {
176     vendor_id = (guint32) strtoul(yytext,NULL,16);
177     BEGIN VENDOR_W_ID;
178 }
179 <VENDOR_W_ID>format= {
180     BEGIN VENDOR_W_FORMAT;
181 }
182 <VENDOR_W_FORMAT>[124] {
183     vendor_type_octets = (guint) strtoul(yytext,NULL,10);
184     BEGIN VENDOR_W_TYPE_OCTETS;
185 }
186 <VENDOR_W_TYPE_OCTETS>,[012] {
187     vendor_length_octets = (guint) strtoul(yytext+1,NULL,10);
188     BEGIN VENDOR_W_LENGTH_OCTETS;
189 }
190 <VENDOR_W_LENGTH_OCTETS>,c {
191     vendor_has_flags = TRUE;
192     BEGIN VENDOR_W_CONTINUATION;
193 }
194 <VENDOR_W_FORMAT>\n |
195 <VENDOR_W_TYPE_OCTETS>\n |
196 <VENDOR_W_LENGTH_OCTETS>\n |
197 <VENDOR_W_CONTINUATION>\n |
198 <VENDOR_W_ID>\n {
199     add_vendor(vendor_name, vendor_id, vendor_type_octets, vendor_length_octets, vendor_has_flags);
200     g_free(vendor_name);
201     BEGIN WS_OUT;
202 }
203
204 <ATTR>[0-9a-z_/.-]+                     { attr_name = g_strdup(yytext); encrypted = 0; has_tag = FALSE; BEGIN ATTR_W_NAME; }
205 <ATTR_W_NAME>[0-9]+                     { attr_id = g_strdup(yytext);  BEGIN ATTR_W_ID;}
206 <ATTR_W_NAME>0x[0-9a-f]+                { attr_id = g_strdup_printf("%u",(int)strtoul(yytext,NULL,16)); BEGIN ATTR_W_ID;}
207 <ATTR_W_ID>integer                      { attr_type = radius_integer;  BEGIN ATTR_W_TYPE; }
208 <ATTR_W_ID>string                       { attr_type = radius_string;  BEGIN ATTR_W_TYPE; }
209 <ATTR_W_ID>octets                       { attr_type = radius_octets;  BEGIN ATTR_W_TYPE; }
210 <ATTR_W_ID>ipaddr                       { attr_type = radius_ipaddr;  BEGIN ATTR_W_TYPE; }
211 <ATTR_W_ID>ipv6addr                     { attr_type = radius_ipv6addr;  BEGIN ATTR_W_TYPE; }
212 <ATTR_W_ID>ipv6prefix                   { attr_type = radius_ipv6prefix;  BEGIN ATTR_W_TYPE; }
213 <ATTR_W_ID>ipxnet                       { attr_type = radius_ipxnet;  BEGIN ATTR_W_TYPE; }
214 <ATTR_W_ID>date                         { attr_type = radius_date;  BEGIN ATTR_W_TYPE; }
215 <ATTR_W_ID>abinary                      { attr_type = radius_abinary;  BEGIN ATTR_W_TYPE; }
216 <ATTR_W_ID>ether                        { attr_type = radius_ether;  BEGIN ATTR_W_TYPE; }
217 <ATTR_W_ID>ifid                         { attr_type = radius_ifid;  BEGIN ATTR_W_TYPE; }
218 <ATTR_W_ID>byte                         { attr_type = radius_integer;  BEGIN ATTR_W_TYPE; }
219 <ATTR_W_ID>short                        { attr_type = radius_integer;  BEGIN ATTR_W_TYPE; }
220 <ATTR_W_ID>signed                       { attr_type = radius_signed;  BEGIN ATTR_W_TYPE; }
221 <ATTR_W_ID>combo-ip                     { attr_type = radius_combo_ip;  BEGIN ATTR_W_TYPE; }
222 <ATTR_W_ID>tlv                          { attr_type = radius_tlv;  BEGIN ATTR_W_TYPE; }
223 <ATTR_W_ID>[0-9a-z_-]+                  { attr_type = radius_octets;  BEGIN ATTR_W_TYPE; }
224 <ATTR_W_TYPE>has_tag[,]?                { has_tag = TRUE; }
225 <ATTR_W_TYPE>encrypt=[123][,]?          { encrypted = (guint) strtoul(yytext+8,NULL,10); }
226 <ATTR_W_TYPE>[0-9a-z_-]+=([^\n]*)       ;
227 <ATTR_W_TYPE>[0-9a-z_-]+                {
228     attr_vendor = g_strdup(yytext);
229     add_attribute(attr_name,attr_id,attr_type,attr_vendor,encrypted,has_tag,current_attr);
230     g_free(attr_id);
231     g_free(attr_vendor);
232     g_free(attr_name);
233     attr_id = NULL;
234     attr_vendor = NULL;
235     attr_name = NULL;
236     BEGIN WS_OUT;
237 }
238 <ATTR_W_TYPE>\n                                         {
239     add_attribute(attr_name,attr_id,attr_type,current_vendor,encrypted,has_tag,current_attr);
240     g_free(attr_id);
241     g_free(attr_name);
242     linenums[include_stack_ptr]++;
243     has_tag = FALSE;
244     encrypted=FALSE;
245     BEGIN WS_OUT;
246 }
247 <ATTR_W_VENDOR>\n                                       {
248     add_attribute(attr_name,attr_id,attr_type,attr_vendor,encrypted,has_tag,current_attr);
249     g_free(attr_id);
250     g_free(attr_vendor);
251     g_free(attr_name);
252     linenums[include_stack_ptr]++;
253     BEGIN WS_OUT;
254 };
255
256 <VALUE>[0-9a-z_/-]+                             { attr_name = g_strdup(yytext); BEGIN VALUE_W_ATTR; }
257 <VALUE_W_ATTR>[^[:blank:]]+                     { value_repr = g_strdup(yytext); BEGIN VALUE_W_NAME; }
258 <VALUE_W_NAME>[0-9]+                            { add_value(attr_name,value_repr, (guint32) strtoul(yytext,NULL,10));  g_free(attr_name); g_free(value_repr); BEGIN WS_OUT;}
259 <VALUE_W_NAME>0x[0-9a-f]+                       { add_value(attr_name,value_repr, (guint32) strtoul(yytext,NULL,16));  g_free(attr_name); g_free(value_repr); BEGIN WS_OUT;}
260
261 <INCLUDE>[^[:blank:]\n]+   {
262         if ( include_stack_ptr >= MAX_INCLUDE_DEPTH ) {
263                 g_string_append_printf(error, "$INCLUDE files nested to deeply\n");
264                 yyterminate();
265         }
266
267         include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
268
269         fullpaths[include_stack_ptr] = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
270             directory,yytext);
271
272         yyin = ws_fopen( fullpaths[include_stack_ptr], "r" );
273
274         if (!yyin) {
275                 if (errno) {
276                         g_string_append_printf(error,
277                                         "Could not open file: '%s', error: %s\n",
278                                         fullpaths[include_stack_ptr],
279                                         g_strerror(errno) );
280                 } else {
281                         g_string_append_printf(error,
282                                         "Could not open file: '%s', no errno\n",
283                                         fullpaths[include_stack_ptr]);
284                 }
285                 g_free(fullpaths[include_stack_ptr]);
286                 fullpaths[include_stack_ptr] = NULL;
287                 include_stack_ptr--;
288         } else {
289                 linenums[include_stack_ptr] = 1;
290                 yy_switch_to_buffer(yy_create_buffer( yyin, YY_BUF_SIZE ) );
291         }
292
293
294         BEGIN WS_OUT;
295 }
296
297 <<EOF>> {
298
299         fclose(yyin);
300         yyin = NULL;
301
302         if ( --include_stack_ptr < 0 ) {
303                 yyterminate();
304         } else {
305                 g_free(fullpaths[include_stack_ptr+1]);
306                 fullpaths[include_stack_ptr+1] = NULL;
307
308                 yy_delete_buffer( YY_CURRENT_BUFFER );
309                 yy_switch_to_buffer(include_stack[include_stack_ptr]);
310         }
311
312         BEGIN WS_OUT;
313 }
314
315 \n      { linenums[include_stack_ptr]++; BEGIN WS_OUT; }
316
317
318 %%
319
320 static void add_vendor(const gchar* name, guint32 id, guint type_octets, guint length_octets, gboolean has_flags) {
321         radius_vendor_info_t* v;
322
323         v = (radius_vendor_info_t *)g_hash_table_lookup(dict->vendors_by_id, GUINT_TO_POINTER(id));
324
325         if (!v) {
326                 /*
327                  * New vendor.
328                  * Allocate a new entry and insert it into the by-ID and
329                  * by-name hash tables.
330                  */
331                 v = g_new(radius_vendor_info_t,1);
332                 v->attrs_by_id = g_hash_table_new(g_direct_hash,g_direct_equal);
333                 v->code = id;
334                 v->ett = -1;
335                 v->name = g_strdup(name);
336                 v->type_octets = type_octets;
337                 v->length_octets = length_octets;
338                 v->has_flags = has_flags;
339
340                 g_hash_table_insert(dict->vendors_by_id,GUINT_TO_POINTER(v->code),v);
341                 g_hash_table_insert(dict->vendors_by_name, (gpointer) v->name, v);
342         } else {
343                 /*
344                  * This vendor is already in the table.
345                  *
346                  * Assume that the dictionary knows the 'ground truth' about
347                  * the type/length/has_flags information and thus allow the
348                  * dictionary to overwrite these values even for vendors that
349                  * have already been loaded.
350                  *
351                  * XXX - this could be due to the vendor being in multiple
352                  * dictionary files, rather than having been specially
353                  * entered by the RADIUS dissector, as a side effect of
354                  * specially entering an attribute; should we report vendors
355                  * that appear in different dictionaries with different
356                  * properties?
357                  */
358                 v->type_octets = type_octets;
359                 v->length_octets = length_octets;
360                 v->has_flags = has_flags;
361
362                 /*
363                  * Did the name change?
364                  */
365                 if (g_strcmp0(v->name, name) != 0) {
366                         /*
367                          * Yes.  Remove the entry from the by-name hash table
368                          * and re-insert it with the new name.
369                          */
370                         g_hash_table_remove(dict->vendors_by_name, (gpointer) v->name);
371                         g_free((gpointer) v->name);
372                         v->name = g_strdup(name);
373                         g_hash_table_insert(dict->vendors_by_name, (gpointer) v->name, v);
374                 }
375         }
376 }
377
378 static void add_attribute(const gchar* name, const  gchar* codestr, radius_attr_dissector_t type, const  gchar* vendor, guint encrypted_flag, gboolean tagged, const gchar* attr) {
379         radius_attr_info_t* a;
380         GHashTable* by_id;
381         guint32 code;
382
383         if (attr){
384                 add_tlv(name, codestr, type, attr);
385                 return;
386         }
387
388
389         if (vendor) {
390                 radius_vendor_info_t* v;
391                 v = (radius_vendor_info_t *)g_hash_table_lookup(dict->vendors_by_name,vendor);
392
393                 if (! v) {
394                         g_string_append_printf(error, "Vendor: '%s', does not exist in %s:%i \n", vendor, fullpaths[include_stack_ptr], linenums[include_stack_ptr] );
395                         BEGIN JUNK;
396                         return;
397                 } else {
398                         by_id = v->attrs_by_id;
399                 }
400         } else {
401                 by_id = dict->attrs_by_id;
402         }
403
404         code= (guint32) strtoul(codestr, NULL, 10);
405
406         a=(radius_attr_info_t*)g_hash_table_lookup(by_id, GUINT_TO_POINTER(code));
407
408         if (!a) {
409                 /*
410                  * New attribute.
411                  * Allocate a new entry and insert it into the by-ID and
412                  * by-name hash tables.
413                  */
414                 a = g_new(radius_attr_info_t,1);
415                 a->code = code;
416                 a->name = g_strdup(name);
417                 a->dissector = NULL;
418                 a->encrypt = encrypted_flag;
419                 a->tagged =  tagged;
420                 a->type = type;
421                 a->vs = NULL;
422                 a->hf = -1;
423                 a->hf_alt = -1;
424                 a->hf_tag = -1;
425                 a->hf_len = -1;
426                 a->ett = -1;
427                 a->tlvs_by_id = NULL;
428                 g_hash_table_insert(by_id, GUINT_TO_POINTER(code),a);
429                 g_hash_table_insert(dict->attrs_by_name,(gpointer) (a->name),a);
430         } else {
431                 /*
432                  * This attribute is already in the table.
433                  *
434                  * Overwrite the encrypted flag, tagged property, and type;
435                  * the other properties don't get set until after we've
436                  * finished reading the dictionaries.
437                  *
438                  * XXX - this could be due to the attribute being in
439                  * multiple dictionary files, rather than having been
440                  * specially entered by the RADIUS dissector to give it
441                  * a special dissection routine; should we report attributes
442                  * that appear in different dictionaries with different
443                  * properties?
444                  */
445                 a->encrypt = encrypted_flag;
446                 a->tagged =  tagged;
447                 a->type = type;
448
449                 /*
450                  * Did the name change?
451                  */
452                 if (g_strcmp0(a->name, name) != 0) {
453                         /*
454                          * Yes.  Remove the entry from the by-name hash table
455                          * and re-insert it with the new name.
456                          */
457                         g_hash_table_remove(dict->attrs_by_name, (gpointer) (a->name));
458                         g_free((gpointer) a->name);
459                         a->name = g_strdup(name);
460                         g_hash_table_insert(dict->attrs_by_name, (gpointer) (a->name),a);
461                 }
462         }
463 }
464
465 static void add_tlv(const gchar* name, const  gchar* codestr, radius_attr_dissector_t type, const gchar* attr) {
466         radius_attr_info_t* a;
467         radius_attr_info_t* s;
468         guint32 code;
469
470         a = (radius_attr_info_t*)g_hash_table_lookup(dict->attrs_by_name, attr);
471
472         if (! a) {
473                 g_string_append_printf(error, "Attr: '%s', does not exist in %s:%i \n", attr, fullpaths[include_stack_ptr], linenums[include_stack_ptr]);
474                 BEGIN JUNK;
475                 return;
476         }
477
478         if (type == radius_tlv) {
479                 g_string_append_printf(error, "sub-TLV: '%s', sub-TLV's type is specified as tlv in %s:%i \n", name, fullpaths[include_stack_ptr], linenums[include_stack_ptr]);
480                 BEGIN JUNK;
481                 return;
482         }
483
484
485         if (! a->tlvs_by_id) {
486                 a->tlvs_by_id = g_hash_table_new(g_direct_hash,g_direct_equal);
487         }
488
489         code = (guint32) strtoul(codestr, NULL, 10);
490
491         s = (radius_attr_info_t*)g_hash_table_lookup(a->tlvs_by_id, GUINT_TO_POINTER(code));
492
493         if (!s) {
494                 /*
495                  * This TLV doesn't yet exist in this attribute's TLVs-by-ID
496                  * hash table.  Add it.
497                  */
498                 s = g_new(radius_attr_info_t,1);
499                 s->name = g_strdup(name);
500                 s->dissector = NULL;
501                 s->code = code;
502                 s->type = type;
503                 s->encrypt = FALSE;
504                 s->tagged = FALSE;
505                 s->dissector = NULL;
506                 s->vs = NULL;
507                 s->hf = -1;
508                 s->hf_alt = -1;
509                 s->hf_tag = -1;
510                 s->hf_len = -1;
511                 s->ett = -1;
512                 s->tlvs_by_id = NULL;
513
514                 g_hash_table_insert(a->tlvs_by_id,GUINT_TO_POINTER(s->code),s);
515                 g_hash_table_insert(dict->tlvs_by_name,(gpointer) (s->name),s);
516         }
517
518         /*
519          * If it *does* exist, leave it alone; there shouldn't be duplicate
520          * entries by name in the dictionaries (even if there might be
521          * multiple entries for a given attribute in the dictionaries, each
522          * one adding some TLV values), and we don't directly add entries
523          * for TLVs in the RADIUS dissector.
524          *
525          * XXX - report the duplicate entries? 
526          */
527 }
528
529 void add_value(const gchar* attrib_name, const gchar* repr, guint32 value) {
530         value_string v;
531         GArray* a = (GArray*)g_hash_table_lookup(value_strings,attrib_name);
532
533         if (! a) {
534                 a = g_array_new(TRUE,TRUE,sizeof(value_string));
535                 g_hash_table_insert(value_strings,g_strdup(attrib_name),a);
536         }
537
538         v.value = value;
539         v.strptr = g_strdup(repr);
540
541         g_array_append_val(a,v);
542 }
543
544 static void setup_tlvs(gpointer k _U_, gpointer v, gpointer p _U_) {
545         radius_attr_info_t* s = (radius_attr_info_t*)v;
546         gpointer key;
547
548         union {
549                 GArray* a;
550                 gpointer p;
551         } vs;
552
553         if (g_hash_table_lookup_extended(value_strings, s->name, &key, &vs.p)) {
554                 s->vs = (value_string*)(void *)vs.a->data;
555                 g_array_free(vs.a, FALSE);
556                 g_hash_table_remove(value_strings, key);
557                 g_free(key);
558         }
559 }
560
561 static void setup_attrs(gpointer k _U_, gpointer v, gpointer p _U_) {
562         radius_attr_info_t* a = (radius_attr_info_t*)v;
563         gpointer key;
564
565         union {
566                 GArray* a;
567                 gpointer p;
568         } vs;
569
570         if (g_hash_table_lookup_extended(value_strings,a->name,&key,&vs.p) ) {
571                 a->vs = (value_string*)(void *)vs.a->data;
572                 g_array_free(vs.a,FALSE);
573                 g_hash_table_remove(value_strings,key);
574                 g_free(key);
575         }
576
577         if (a->tlvs_by_id) {
578                 g_hash_table_foreach(a->tlvs_by_id, setup_tlvs, p);
579         }
580 }
581
582 static void setup_vendors(gpointer k _U_, gpointer v, gpointer p) {
583         radius_vendor_info_t* vnd = (radius_vendor_info_t*)v;
584
585         g_hash_table_foreach(vnd->attrs_by_id,setup_attrs,p);
586 }
587
588 static gboolean destroy_value_strings(gpointer k, gpointer v, gpointer p _U_) {
589         value_string* vs = (value_string*)(void *)(((GArray*)v)->data);
590
591         g_free(k);
592
593         for (;vs->strptr;vs++) {
594                 g_free((void*)vs->strptr);
595         }
596
597         g_array_free((GArray*)v,TRUE);
598         return TRUE;
599 }
600
601 gboolean radius_load_dictionary (radius_dictionary_t* d, gchar* dir, const gchar* filename, gchar** err_str) {
602         int i;
603
604         dict = d;
605         directory = dir;
606
607         fullpaths[include_stack_ptr] = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
608             directory,filename);
609
610         error = g_string_new("");
611
612         yyin = ws_fopen(fullpaths[include_stack_ptr],"r");
613
614         if (!yyin) {
615                 g_string_append_printf(error, "Could not open file: '%s', error: %s\n", fullpaths[include_stack_ptr], g_strerror(errno) );
616                 g_free(fullpaths[include_stack_ptr]);
617                 *err_str = g_string_free(error,FALSE);
618                 return FALSE;
619         }
620
621         value_strings = g_hash_table_new(g_str_hash,g_str_equal);
622
623         BEGIN WS_OUT;
624
625         yylex();
626
627         if (yyin != NULL) fclose(yyin);
628         yyin = NULL;
629
630         for (i=0; i < 10; i++) {
631                 if (fullpaths[i]) g_free(fullpaths[i]);
632         }
633
634         g_hash_table_foreach(dict->attrs_by_id,setup_attrs,NULL);
635         g_hash_table_foreach(dict->vendors_by_id,setup_vendors,NULL);
636         g_hash_table_foreach_remove(value_strings,destroy_value_strings,NULL);
637
638         if (error->len > 0) {
639                 *err_str = g_string_free(error,FALSE);
640                 return FALSE;
641         } else {
642                 *err_str = NULL;
643                 g_string_free(error,TRUE);
644                 return TRUE;
645         }
646 }
647
648 /*
649  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
650  *
651  * Local variables:
652  * c-basic-offset: 8
653  * tab-width: 8
654  * indent-tabs-mode: t
655  * End:
656  *
657  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
658  * :indentSize=8:tabSize=8:noTabs=false:
659  */