From sangaran:
[obnox/wireshark/wip.git] / plugins / wimaxasncp / packet-wimaxasncp.c
1 /* packet-wimaxasncp.c
2  *
3  * Routines for WiMAX ASN Control Plane packet dissection dissection
4  *
5  * Copyright 2007, Mobile Metrics - http://mobilemetrics.net/
6  *
7  * Author: Stephen Croll <croll@mobilemetrics.net>
8  *
9  * $Id$
10  *
11  * Wireshark - Network traffic analyzer
12  * By Gerald Combs <gerald@wireshark.org>
13  * Copyright 1998 Gerald Combs
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
28  */
29
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <ctype.h>
38
39 #include <glib.h>
40
41 #include <epan/packet.h>
42 #include <epan/prefs.h>
43 #include <epan/sminmpec.h>
44 #include <epan/addr_resolv.h>
45 #include <epan/ipproto.h>
46 #include <epan/expert.h>
47 #include <epan/filesystem.h>
48 #include <epan/report_err.h>
49 #include <epan/eap.h>
50
51 #include "wimaxasncp_dict.h"
52
53 /* Forward declarations we need below */
54 void proto_register_wimaxasncp(void);
55 void proto_reg_handoff_wimaxasncp(void);
56
57 /* Initialize the protocol and registered fields */
58 static int proto_wimaxasncp                     = -1;
59 static int hf_wimaxasncp_version                = -1;
60 static int hf_wimaxasncp_flags                  = -1;
61 static int hf_wimaxasncp_function_type          = -1;
62 static int hf_wimaxasncp_op_id                  = -1;
63 static int hf_wimaxasncp_message_type           = -1;
64 static int hf_wimaxasncp_qos_msg                = -1;
65 static int hf_wimaxasncp_ho_control_msg         = -1;
66 static int hf_wimaxasncp_data_path_control_msg  = -1;
67 static int hf_wimaxasncp_context_delivery_msg   = -1;
68 static int hf_wimaxasncp_r3_mobility_msg        = -1;
69 static int hf_wimaxasncp_paging_msg             = -1;
70 static int hf_wimaxasncp_rrm_msg                = -1;
71 static int hf_wimaxasncp_authentication_msg     = -1;
72 static int hf_wimaxasncp_ms_state_msg           = -1;
73 static int hf_wimaxasncp_reauthentication_msg   = -1;
74 static int hf_wimaxasncp_session_msg            = -1;
75 static int hf_wimaxasncp_length                 = -1;
76 static int hf_wimaxasncp_msid                   = -1;
77 static int hf_wimaxasncp_reserved1              = -1;
78 static int hf_wimaxasncp_transaction_id         = -1;
79 static int hf_wimaxasncp_reserved2              = -1;
80 static int hf_wimaxasncp_tlv                    = -1;
81 static int hf_wimaxasncp_tlv_type               = -1;
82 static int hf_wimaxasncp_tlv_length             = -1;
83 static int hf_wimaxasncp_tlv_value_bytes        = -1;
84 static int hf_wimaxasncp_tlv_value_bitflags8    = -1;
85 static int hf_wimaxasncp_tlv_value_bitflags16   = -1;
86 static int hf_wimaxasncp_tlv_value_bitflags32   = -1;
87 static int hf_wimaxasncp_tlv_value_protocol     = -1;
88 static int hf_wimaxasncp_tlv_value_vendor_id    = -1;
89
90 /* Preferences */
91 static gboolean show_transaction_id_d_bit      = FALSE;
92 static gboolean debug_enabled                  = FALSE;
93
94 /* Default WiMAX ASN control protocol port */
95 #define WIMAXASNCP_DEF_UDP_PORT     2231
96 static guint global_wimaxasncp_udp_port = WIMAXASNCP_DEF_UDP_PORT;
97
98
99 /* Initialize the subtree pointers */
100 static gint ett_wimaxasncp                                       = -1;
101 static gint ett_wimaxasncp_flags                                 = -1;
102 static gint ett_wimaxasncp_tlv                                   = -1;
103 static gint ett_wimaxasncp_tlv_value_bitflags8                   = -1;
104 static gint ett_wimaxasncp_tlv_value_bitflags16                  = -1;
105 static gint ett_wimaxasncp_tlv_value_bitflags32                  = -1;
106 static gint ett_wimaxasncp_tlv_protocol_list                     = -1;
107 static gint ett_wimaxasncp_tlv_port_range_list                   = -1;
108 static gint ett_wimaxasncp_tlv_ip_address_mask_list              = -1;
109 static gint ett_wimaxasncp_tlv_ip_address_mask                   = -1;
110 static gint ett_wimaxasncp_tlv_eap                               = -1;
111 static gint ett_wimaxasncp_tlv_vendor_specific_information_field = -1;
112
113 /* Header size, up to, but not including, the TLV fields. */
114 #define WIMAXASNCP_HEADER_SIZE       20
115
116 /* Offset to end of the length field in the headder. */
117 #define WIMAXASNCP_HEADER_LENGTH_END 6
118
119 #define WIMAXASNCP_BIT32(n) (1 << (31 - (n)))
120 #define WIMAXASNCP_BIT16(n) (1 << (15 - (n)))
121 #define WIMAXASNCP_BIT8(n)  (1 << ( 7 - (n)))
122
123 #define WIMAXASNCP_FLAGS_T  WIMAXASNCP_BIT8(6)
124 #define WIMAXASNCP_FLAGS_R  WIMAXASNCP_BIT8(7)
125
126 typedef struct {
127     GArray* hf;
128     GArray* ett;
129 } wimaxasncp_build_dict_t;
130
131 static wimaxasncp_dict_t *wimaxasncp_dict = NULL;
132
133 wimaxasncp_build_dict_t wimaxasncp_build_dict;
134
135 static wimaxasncp_dict_tlv_t wimaxasncp_tlv_not_found =
136 {
137     0, "Unknown", NULL, WIMAXASNCP_TLV_UNKNOWN,
138     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
139     NULL, NULL, NULL
140 };
141
142 static dissector_handle_t eap_handle;
143
144 /* ------------------------------------------------------------------------- */
145
146 static const value_string wimaxasncp_flag_vals[] =
147 {
148     { WIMAXASNCP_BIT8(0), "Reserved" },
149     { WIMAXASNCP_BIT8(1), "Reserved" },
150     { WIMAXASNCP_BIT8(2), "Reserved" },
151     { WIMAXASNCP_BIT8(3), "Reserved" },
152     { WIMAXASNCP_BIT8(4), "Reserved" },
153     { WIMAXASNCP_BIT8(5), "Reserved" },
154     { WIMAXASNCP_FLAGS_T, "T - Source and Destination Identifier TLVs"},
155     { WIMAXASNCP_FLAGS_R, "R - Reset Next Expected Transaction ID"},
156     { 0,                  NULL}
157 };
158
159 /* ------------------------------------------------------------------------- */
160
161 static const value_string wimaxasncp_op_id_vals[] =
162 {
163     { 0,   "Invalid"},
164     { 1,   "Request/Initiation"},
165     { 2,   "Response"},
166     { 3,   "Ack"},
167     { 4,   "Indication"},
168     { 5,   "Reserved"},
169     { 6,   "Reserved"},
170     { 7,   "Reserved"},
171     { 0,   NULL}
172 };
173
174 /* ------------------------------------------------------------------------- */
175
176 #define WIMAXASNCP_FT_QOS                 1
177 #define WIMAXASNCP_FT_HO_CONTROL          2
178 #define WIMAXASNCP_FT_DATA_PATH_CONTROL   3
179 #define WIMAXASNCP_FT_CONTEXT_DELIVERY    4
180 #define WIMAXASNCP_FT_R3_MOBILITY         5
181 #define WIMAXASNCP_FT_PAGING              6
182 #define WIMAXASNCP_FT_RRM                 7
183 #define WIMAXASNCP_FT_AUTHENTICATION      8
184 #define WIMAXASNCP_FT_MS_STATE            9
185 #define WIMAXASNCP_FT_REAUTHENTICATION    10
186 #define WIMAXASNCP_FT_SESSION             11    /* Nokia recommended value */
187
188 /* ------------------------------------------------------------------------- */
189
190 static const value_string wimaxasncp_function_type_vals[] =
191 {
192     { WIMAXASNCP_FT_QOS,               "QoS"},
193     { WIMAXASNCP_FT_HO_CONTROL,        "HO Control"},
194     { WIMAXASNCP_FT_DATA_PATH_CONTROL, "Data Path Control"},
195     { WIMAXASNCP_FT_CONTEXT_DELIVERY,  "Context Delivery"},
196     { WIMAXASNCP_FT_R3_MOBILITY,       "R3 Mobility"},
197     { WIMAXASNCP_FT_PAGING,            "Paging"},
198     { WIMAXASNCP_FT_RRM,               "RRM"},
199     { WIMAXASNCP_FT_AUTHENTICATION,    "Authentication"},
200     { WIMAXASNCP_FT_MS_STATE,          "MS State"},
201     { WIMAXASNCP_FT_REAUTHENTICATION,  "Re-Authentication"},
202     { WIMAXASNCP_FT_SESSION,           "Session"},
203     { 0,    NULL}
204 };
205
206 /* ------------------------------------------------------------------------- */
207
208 static const value_string wimaxasncp_qos_msg_vals[] =
209 {
210     { 1,  "RR_Req"},
211     { 2,  "RR_Rsp"},
212     { 3,  "RR_Ack"},
213     { 0,   NULL}
214 };
215
216 /* ------------------------------------------------------------------------- */
217
218 static const value_string wimaxasncp_ho_control_msg_vals[] =
219 {
220     { 1,  "HO_Req"},
221     { 2,  "HO_Rsp"},
222     { 3,  "HO_Ack"},
223     { 4,  "HO_Cnf"},
224     { 5,  "HO_Complete"},
225     { 6,  "HO_Directive"},
226     { 7,  "HO_Directive_Rsp"},
227     /* TODO: Add others */
228     { 0,   NULL}
229 };
230
231 /* ------------------------------------------------------------------------- */
232
233 static const value_string wimaxasncp_data_path_control_msg_vals[] =
234 {
235     { 1,   "Path_Dereg_Req"},
236     { 2,   "Path_Dereg_Rsp"},
237     { 3,   "Path_Dereg_Ack"},
238     { 4,   "Path_Modification_Req"},
239     { 5,   "Path_Modification_Rsp"},
240     { 6,   "Path_Modification_Ack"},
241     { 7,   "Path_Prereg_Req"},
242     { 8,   "Path_Prereg_Rsp"},
243     { 9,   "Path_Prereg_Ack"},
244     { 10,  "Path_Reg_Req"},
245     { 11,  "Path_Reg_Rsp"},
246     { 12,  "Path_Reg_Ack"},
247     { 13,  "IM_Exit_State_Ind"},
248     { 14,  "IM_Exit_State_Ind_Ack"},
249     { 0,   NULL}
250
251 };
252
253 /* ------------------------------------------------------------------------- */
254
255 static const value_string wimaxasncp_context_delivery_msg_vals[] =
256 {
257     { 1,  "Context_Req"},
258     { 2,  "Context_Rpt"},
259     { 3,  "Context_Ack"},
260     { 4,  "CMAC_Key_Count_Update"},
261     { 5,  "CMAC_Key_Count_Update_ACK"},
262     { 0,   NULL}
263 };
264
265 /* ------------------------------------------------------------------------- */
266
267 static const value_string wimaxasncp_r3_mobility_msg_vals[] =
268 {
269     { 1,  "Anchor_DPF_HO_Req"},
270     { 2,  "Anchor_DPF_HO_Trigger"},
271     { 3,  "Anchor_DPF_HO_Rsp"},
272     { 4,  "Anchor_DPF_Relocate_Req"},
273     { 5,  "FA_Register_Req"},
274     { 6,  "FA_Register_Rsp"},
275     { 7,  "Anchor_DPF_Relocate_Rsp"},
276     { 8,  "FA_Revoke_Req"},
277     { 9,  "FA_Revoke_Rsp"},
278     { 0,   NULL}
279 };
280
281 /* ------------------------------------------------------------------------- */
282
283 static const value_string wimaxasncp_paging_msg_vals[] =
284 {
285     { 1,  "Paging_Announce"},
286     { 2,  "Delete_MS_Entry_Req"},
287     { 5,  "Delete_MS_Entry_Rsp"},
288     { 0,   NULL}
289 };
290
291 /* ------------------------------------------------------------------------- */
292
293 static const value_string wimaxasncp_rrm_msg_vals[] =
294 {
295     { 1,  "R6 PHY_Parameters_Req"},
296     { 2,  "R6 PHY_Parameters_Rpt"},
297     { 3,  "R4/R6 Spare_Capacity_Req"},
298     { 4,  "R4/R6 Spare_Capacity_Rpt"},
299     { 5,  "R6 Neighbor_BS_Resource_Status_Update"},
300     { 6,  "R4/R6 Radio_Config_Update_Req"},
301     { 7,  "R4/R6 Radio_Config_Update_Rpt"},
302     { 8,  "R4/R6 Radio_Config_Update_Ack"},
303     { 0,   NULL}
304 };
305
306 /* ------------------------------------------------------------------------- */
307
308 static const value_string wimaxasncp_authentication_msg_vals[] =
309 {
310     { 1,  "AR_EAP_Start"},
311     { 2,  "AR_EAP_Transfer"},
312     { 3,  "Bulk_Interim_Update"},
313     { 4,  "Bulk_Interim_Update_Ack"},
314     { 0,   NULL}
315 };
316
317 /* ------------------------------------------------------------------------- */
318
319 static const value_string wimaxasncp_ms_state_msg_vals[] =
320 {
321     { 1,  "MS_PreAttachment_Req"},
322     { 2,  "MS_PreAttachment_Rsp"},
323     { 3,  "MS_PreAttachment_Ack"},
324     { 4,  "MS_Attachment_Req"},
325     { 5,  "MS_Attachment_Rsp"},
326     { 6,  "MS_Attachment_Ack"},
327     { 7,  "Key_Change_Directive"},
328     { 8,  "Key_Change_Cnf"},
329     { 9,  "Key_Change_Ack"},
330     { 0,   NULL}
331 };
332
333 /* ------------------------------------------------------------------------- */
334
335 static const value_string wimaxasncp_reauthentication_msg_vals[] =
336 {
337 /* IM */
338     { 1,  "IM_Entry_State_Change_Req"},
339     { 2,  "IM_Entry_State_Change_Rsp"},
340     { 3,  "IM_Entry_State_Change_Ack"},
341     { 4,  "IM_Exit_State_Change_Req"},
342     { 5,  "IM_Exit_State_Change_Rsp"},
343     { 6,  "Initiate_Paging_Req"},
344     { 7,  "Initiate_Paging_Rsp"},
345     { 8,  "LU_Req"},
346     { 9,  "LU_Rsp"},
347     { 10,  "LU_Cnf"},
348     { 0,   NULL}
349 };
350
351 /* ------------------------------------------------------------------------- */
352
353 static const value_string wimaxasncp_session_msg_vals[] =
354 {
355     { 1,  "Session_Release_Req"},  /* Nokia recommended value */
356     { 2,  "Session_Release_Rsp"},  /* Nokia recommended value */
357     { 3,  "Session_Release_Ack"},  /* Nokia recommended value */
358     { 4,  "Session_Failure_Rpt"},  /* Nokia recommended value */
359     { 5,  "Session_Failure_Rsp"},  /* Nokia recommended value */
360     { 0,   NULL}
361 };
362
363 /* ========================================================================= */
364
365 typedef struct {
366     guint8 function_type;
367     const value_string *vals;
368 } wimaxasncp_func_msg_t;
369
370 /* ------------------------------------------------------------------------ */
371
372 static const wimaxasncp_func_msg_t wimaxasncp_func_to_msg_vals_map[] =
373 {
374     { WIMAXASNCP_FT_QOS,               wimaxasncp_qos_msg_vals },
375     { WIMAXASNCP_FT_HO_CONTROL,        wimaxasncp_ho_control_msg_vals },
376     { WIMAXASNCP_FT_DATA_PATH_CONTROL, wimaxasncp_data_path_control_msg_vals },
377     { WIMAXASNCP_FT_CONTEXT_DELIVERY,  wimaxasncp_context_delivery_msg_vals },
378     { WIMAXASNCP_FT_R3_MOBILITY,       wimaxasncp_r3_mobility_msg_vals },
379     { WIMAXASNCP_FT_PAGING,            wimaxasncp_paging_msg_vals },
380     { WIMAXASNCP_FT_RRM,               wimaxasncp_rrm_msg_vals },
381     { WIMAXASNCP_FT_AUTHENTICATION,    wimaxasncp_authentication_msg_vals },
382     { WIMAXASNCP_FT_MS_STATE,          wimaxasncp_ms_state_msg_vals },
383     { WIMAXASNCP_FT_REAUTHENTICATION,  wimaxasncp_reauthentication_msg_vals },
384     { WIMAXASNCP_FT_SESSION,           wimaxasncp_session_msg_vals }
385 };
386
387 /* ========================================================================= */
388
389 static const wimaxasncp_dict_tlv_t *wimaxasncp_get_tlv_info(
390     guint16 type)
391 {
392     if (wimaxasncp_dict)
393     {
394         wimaxasncp_dict_tlv_t *tlv;
395
396         for (tlv = wimaxasncp_dict->tlvs; tlv; tlv = tlv->next)
397         {
398             if (tlv->type == type)
399             {
400                 return tlv;
401             }
402         }
403     }
404
405     if (debug_enabled)
406     {
407         g_print("fix-me: unknown TLV type: %u\n", type);
408     }
409
410     return &wimaxasncp_tlv_not_found;
411 }
412
413 /* ========================================================================= */
414
415 static const gchar *wimaxasncp_get_enum_name(
416     const wimaxasncp_dict_tlv_t *tlv_info,
417     guint32 code)
418 {
419     if (tlv_info->enum_vs)
420     {
421         return val_to_str(code, tlv_info->enum_vs, "Unknown");
422     }
423     else
424     {
425         return "Unknown";
426     }
427 }
428
429 /* ========================================================================= */
430
431 static const value_string wimaxasncp_decode_type_vals[] =
432 {
433   { WIMAXASNCP_TLV_UNKNOWN,             "WIMAXASNCP_TLV_UNKNOWN"},
434   { WIMAXASNCP_TLV_TBD,                 "WIMAXASNCP_TLV_TBD"},
435   { WIMAXASNCP_TLV_COMPOUND,            "WIMAXASNCP_TLV_COMPOUND"},
436   { WIMAXASNCP_TLV_BYTES,               "WIMAXASNCP_TLV_BYTES"},
437   { WIMAXASNCP_TLV_ENUM8,               "WIMAXASNCP_TLV_ENUM8"},
438   { WIMAXASNCP_TLV_ENUM16,              "WIMAXASNCP_TLV_ENUM16"},
439   { WIMAXASNCP_TLV_ENUM32,              "WIMAXASNCP_TLV_ENUM32"},
440   { WIMAXASNCP_TLV_ETHER,               "WIMAXASNCP_TLV_ETHER"},
441   { WIMAXASNCP_TLV_ASCII_STRING,        "WIMAXASNCP_TLV_ASCII_STRING"},
442   { WIMAXASNCP_TLV_FLAG0,               "WIMAXASNCP_TLV_FLAG0"},
443   { WIMAXASNCP_TLV_BITFLAGS8,           "WIMAXASNCP_TLV_BITFLAGS8"},  
444   { WIMAXASNCP_TLV_BITFLAGS16,          "WIMAXASNCP_TLV_BITFLAGS16"},
445   { WIMAXASNCP_TLV_BITFLAGS32,          "WIMAXASNCP_TLV_BITFLAGS32"},
446   { WIMAXASNCP_TLV_ID,                  "WIMAXASNCP_TLV_ID"},
447   { WIMAXASNCP_TLV_HEX8,                "WIMAXASNCP_TLV_HEX8"},
448   { WIMAXASNCP_TLV_HEX16,               "WIMAXASNCP_TLV_HEX16"},
449   { WIMAXASNCP_TLV_HEX32,               "WIMAXASNCP_TLV_HEX32"},
450   { WIMAXASNCP_TLV_DEC8,                "WIMAXASNCP_TLV_DEC8"},
451   { WIMAXASNCP_TLV_DEC16,               "WIMAXASNCP_TLV_DEC16"},
452   { WIMAXASNCP_TLV_DEC32,               "WIMAXASNCP_TLV_DEC32"},
453   { WIMAXASNCP_TLV_IP_ADDRESS,          "WIMAXASNCP_TLV_IP_ADDRESS"},
454   { WIMAXASNCP_TLV_IPV4_ADDRESS,        "WIMAXASNCP_TLV_IPV4_ADDRESS"},
455   { WIMAXASNCP_TLV_PROTOCOL_LIST,       "WIMAXASNCP_TLV_PROTOCOL_LIST"},
456   { WIMAXASNCP_TLV_PORT_RANGE_LIST,     "WIMAXASNCP_TLV_PORT_RANGE_LIST"},
457   { WIMAXASNCP_TLV_IP_ADDRESS_MASK_LIST,"WIMAXASNCP_TLV_IP_ADDRESS_MASK_LIST"},
458   { WIMAXASNCP_TLV_VENDOR_SPECIFIC,     "WIMAXASNCP_TLV_VENDOR_SPECIFIC"},
459   { 0, NULL}
460 };
461
462 /* ========================================================================= */
463
464 static void wimaxasncp_proto_tree_add_tlv_ipv4_value(
465     tvbuff_t *tvb,
466     proto_tree *tree,
467     proto_item *tlv_item,
468     guint offset,
469     const wimaxasncp_dict_tlv_t *tlv_info)
470 {
471     int hf_value;
472     guint32 ip;
473     const gchar *hostname;
474     const gchar *ip_str;
475
476     if (tlv_info->hf_ipv4 != -1)
477     {
478         hf_value = tlv_info->hf_ipv4;
479     }
480     else
481     {
482         hf_value = tlv_info->hf_value;
483     }
484
485     ip = tvb_get_ipv4(tvb, offset);
486     hostname = get_hostname(ip);
487     ip_str = ip_to_str((guint8 *)&ip);
488
489     proto_tree_add_ipv4_format(
490         tree, hf_value,
491         tvb, offset, 4, ip,
492         "Value: %s (%s)", hostname, ip_str);
493
494     proto_item_append_text(
495         tlv_item, " - %s (%s)",
496         hostname, ip_str);
497 }
498
499 /* ========================================================================= */
500
501 static void wimaxasncp_proto_tree_add_tlv_ipv6_value(
502     tvbuff_t *tvb,
503     proto_tree *tree,
504     proto_item *tlv_item,
505     guint offset,
506     const wimaxasncp_dict_tlv_t *tlv_info)
507 {
508     int hf_value;
509     struct e_in6_addr ip;
510     const gchar *hostname;
511     const gchar *ip_str;
512
513     if (tlv_info->hf_ipv4 != -1)
514     {
515         hf_value = tlv_info->hf_ipv6;
516     }
517     else
518     {
519         hf_value = tlv_info->hf_value;
520     }
521
522     tvb_get_ipv6(tvb, offset, &ip);
523     hostname = get_hostname6(&ip);
524     ip_str = ip6_to_str(&ip);
525
526     proto_tree_add_ipv6_format(
527         tree, hf_value,
528         tvb, offset, 16, (guint8 *)&ip,
529         "Value: %s (%s)", hostname, ip_str);
530
531     proto_item_append_text(
532         tlv_item, " - %s (%s)",
533         hostname, ip_str);
534 }
535
536 /* ========================================================================= */
537
538 static void wimaxasncp_proto_tree_add_ether_value(
539     tvbuff_t *tvb,
540     proto_tree *tree,
541     proto_item *tlv_item,
542     guint offset,
543     guint length,
544     const wimaxasncp_dict_tlv_t *tlv_info)
545 {
546     int hf_value;
547     const guint8 *p;
548     const gchar *ether_name;
549     const gchar *ether_str;
550
551     if (tlv_info->hf_bsid != -1)
552     {
553         hf_value = tlv_info->hf_bsid;
554     }
555     else
556     {
557         hf_value = tlv_info->hf_value;
558     }
559
560     p = tvb_get_ptr(tvb, offset, length);
561     ether_name = get_ether_name(p);
562     ether_str = ether_to_str(p);
563
564     proto_tree_add_ether_format(
565         tree, hf_value,
566         tvb, offset, length, p,
567         "Value: %s (%s)",
568         ether_name, ether_str);
569     
570     proto_item_append_text(
571         tlv_item, " - %s (%s)",
572         ether_name, ether_str);
573 }
574
575 /* ========================================================================= */
576
577 static void wimaxasncp_dissect_tlv_value(
578     tvbuff_t *tvb,
579     packet_info *pinfo _U_,
580     proto_tree *tree,
581     proto_item *tlv_item,
582     const wimaxasncp_dict_tlv_t *tlv_info)
583 {
584     guint offset = 0;
585     guint length;
586     const guint max_show_bytes = 24; /* arbitrary */
587     const gchar *hex_note = "[hex]";
588
589     length = tvb_reported_length(tvb);
590
591     switch(tlv_info->decoder)
592     {
593     case WIMAXASNCP_TLV_ENUM8:
594     {
595         if (length != 1)
596         {
597             /* encoding error */
598             break;
599         }
600
601         if (tlv_info->enums == NULL)
602         {
603             if (debug_enabled)
604             {
605                 g_print("fix-me: enum values missing for TLV %s (%u)\n",
606                         tlv_info->name, tlv_info->type);
607             }
608         }
609
610         if (tree)
611         {
612             guint8 value;
613             const gchar *s;
614
615             value = tvb_get_guint8(tvb, offset);
616
617             s = wimaxasncp_get_enum_name(tlv_info, value);
618
619             proto_tree_add_uint_format(
620                 tree, tlv_info->hf_value,
621                 tvb, offset, length, value,
622                 "Value: %s (%u)", s, value);
623
624             proto_item_append_text(tlv_item, " - %s", s);
625         }
626
627         return;
628     }
629     case WIMAXASNCP_TLV_ENUM16:
630     {
631         if (length != 2)
632         {
633             /* encoding error */
634             break;
635         }
636
637         if (tlv_info->enums == NULL)
638         {
639             if (debug_enabled)
640             {
641                 g_print("fix-me: enum values missing for TLV %s (%u)\n",
642                         tlv_info->name, tlv_info->type);
643             }
644         }
645
646         if (tree)
647         {
648             guint16 value;
649             const gchar *s;
650
651             value = tvb_get_ntohs(tvb, offset);
652
653             s = wimaxasncp_get_enum_name(tlv_info, value);
654
655             proto_tree_add_uint_format(
656                 tree, tlv_info->hf_value,
657                 tvb, offset, length, value,
658                 "Value: %s (%u)", s, value);
659
660             proto_item_append_text(tlv_item, " - %s", s);
661         }
662
663         return;
664     }
665     case WIMAXASNCP_TLV_ENUM32:
666     {
667         if (length != 4)
668         {
669             /* encoding error */
670             break;
671         }
672
673         if (tlv_info->enums == NULL)
674         {
675             if (debug_enabled)
676             {
677                 g_print("fix-me: enum values missing for TLV %s (%u)\n",
678                         tlv_info->name, tlv_info->type);
679             }
680         }
681
682         if (tree)
683         {
684             guint32 value;
685             const gchar *s;
686
687             value = tvb_get_ntohl(tvb, offset);
688
689             s = wimaxasncp_get_enum_name(tlv_info, value);
690
691             proto_tree_add_uint_format(
692                 tree, tlv_info->hf_value,
693                 tvb, offset, length, value,
694                 "Value: %s (%u)", s, value);
695
696             proto_item_append_text(tlv_item, " - %s", s);
697         }
698
699         return;
700     }
701     case WIMAXASNCP_TLV_ETHER:
702     {
703         if (length != 6)
704         {
705             /* encoding error */
706             break;
707         }
708
709         if (tree)
710         {
711             wimaxasncp_proto_tree_add_ether_value(
712                 tvb, tree, tlv_item, offset, length, tlv_info);
713         }
714
715         return;
716     }
717     case WIMAXASNCP_TLV_ASCII_STRING:
718     {
719         if (tree)
720         {
721             const guint8 *p;
722             const gchar *s = tvb_get_ephemeral_string(tvb, offset, length);
723
724             p = tvb_get_ptr(tvb, offset, length);
725
726             proto_tree_add_string_format(
727                 tree, tlv_info->hf_value,
728                 tvb, offset, length, p,
729                 "Value: %s", s);
730
731             proto_item_append_text(
732                 tlv_item, " - %s", s);
733         }
734
735         return;
736     }
737     case WIMAXASNCP_TLV_FLAG0:
738     {
739         if (length != 0)
740         {
741             /* encoding error */
742             break;
743         }
744
745         return;
746     }
747     case WIMAXASNCP_TLV_BITFLAGS8:
748     {
749         if (length != 1)
750         {
751             /* encoding error */
752             break;
753         }
754
755         if (tlv_info->enums == NULL)
756         {
757             /* enum values missing */
758         }
759
760         if (tree)
761         {
762             proto_tree *flags_tree;
763             proto_item *item;
764             guint8 value;
765             guint i;
766
767             value = tvb_get_guint8(tvb, offset);
768
769             item = proto_tree_add_uint_format(
770                 tree, tlv_info->hf_value,
771                 tvb, offset, length, value,
772                 "Value: %s",
773                 decode_numeric_bitfield(value, 0xff, 8, "0x%02x"));
774
775             proto_item_append_text(tlv_item, " - 0x%02x", value);
776
777             if (value != 0)
778             {
779                 flags_tree = proto_item_add_subtree(
780                     item, ett_wimaxasncp_tlv_value_bitflags8);
781
782                 for (i = 0; i < 8; ++i)
783                 {
784                     guint8 mask;
785                     mask = 1 << (7 - i);
786
787                     if (value & mask)
788                     {
789                         const gchar *s;
790                             
791                         s = wimaxasncp_get_enum_name(tlv_info, value & mask);
792
793                         proto_tree_add_uint_format(
794                             flags_tree, hf_wimaxasncp_tlv_value_bitflags8,
795                             tvb, offset, length, value,
796                             "Bit #%u is set: %s", i, s);
797                     }
798                 }
799             }
800         }
801   
802         return;
803     }    
804     case WIMAXASNCP_TLV_BITFLAGS16:
805     {
806         if (length != 2)
807         {
808             /* encoding error */
809             break;
810         }
811
812         if (tlv_info->enums == NULL)
813         {
814             /* enum values missing */
815         }
816
817         if (tree)
818         {
819             proto_tree *flags_tree;
820             proto_item *item;
821             guint16 value;
822             guint i;
823
824             value = tvb_get_ntohs(tvb, offset);
825
826             item = proto_tree_add_uint_format(
827                 tree, tlv_info->hf_value,
828                 tvb, offset, length, value,
829                 "Value: %s",
830                 decode_numeric_bitfield(value, 0xffff, 16, "0x%04x"));
831
832             proto_item_append_text(tlv_item, " - 0x%04x", value);
833
834             if (value != 0)
835             {
836                 flags_tree = proto_item_add_subtree(
837                     item, ett_wimaxasncp_tlv_value_bitflags16);
838
839                 for (i = 0; i < 16; ++i)
840                 {
841                     guint16 mask;
842                     mask = 1 << (15 - i);
843
844                     if (value & mask)
845                     {
846                         const gchar *s;
847
848                         s = wimaxasncp_get_enum_name(tlv_info, value & mask);
849
850                         proto_tree_add_uint_format(
851                             flags_tree, hf_wimaxasncp_tlv_value_bitflags16,
852                             tvb, offset, length, value,
853                             "Bit #%u is set: %s", i, s);
854                     }
855                 }
856             }
857         }
858
859         return;
860     }
861     case WIMAXASNCP_TLV_BITFLAGS32:
862     {
863         if (length != 4)
864         {
865             /* encoding error */
866             break;
867         }
868
869         if (tlv_info->enums == NULL)
870         {
871             /* enum values missing */
872         }
873
874         if (tree)
875         {
876             proto_tree *flags_tree;
877             proto_item *item;
878             guint32 value;
879             guint i;
880
881             value = tvb_get_ntohl(tvb, offset);
882
883             item = proto_tree_add_uint_format(
884                 tree, tlv_info->hf_value,
885                 tvb, offset, length, value,
886                 "Value: %s",
887                 decode_numeric_bitfield(value, 0xffffffff, 32, "0x%08x"));
888
889             proto_item_append_text(tlv_item, " - 0x%08x", value);
890
891             if (value != 0)
892             {
893                 flags_tree = proto_item_add_subtree(
894                     item, ett_wimaxasncp_tlv_value_bitflags32);
895
896                 for (i = 0; i < 32; ++i)
897                 {
898                     guint32 mask;
899                     mask = 1 << (31 - i);
900
901                     if (value & mask)
902                     {
903                         const gchar *s;
904                         s = wimaxasncp_get_enum_name(tlv_info, value & mask);
905
906                         proto_tree_add_uint_format(
907                             flags_tree, hf_wimaxasncp_tlv_value_bitflags32,
908                             tvb, offset, length, value,
909                             "Bit #%u is set: %s", i, s);
910                     }
911                 }
912             }
913         }
914
915         return;
916     }
917     case WIMAXASNCP_TLV_ID:
918     {
919         if (length == 4)
920         {
921             if (tree)
922             {
923                 wimaxasncp_proto_tree_add_tlv_ipv4_value(
924                     tvb, tree, tlv_item, offset, tlv_info);
925             }
926
927             return;
928         }
929         else if (length == 6)
930         {
931             if (tree)
932             {
933                 wimaxasncp_proto_tree_add_ether_value(
934                     tvb, tree, tlv_item, offset, length, tlv_info);
935             }
936
937             return;
938         }
939         else if (length == 16)
940         {
941             if (tree)
942             {
943                 wimaxasncp_proto_tree_add_tlv_ipv6_value(
944                     tvb, tree, tlv_item, offset, tlv_info);
945             }
946
947             return;
948         }
949         else
950         {
951             /* encoding error */
952             break;
953         }
954     }
955     case WIMAXASNCP_TLV_BYTES:
956     {
957         if (tree)
958         {
959             const gchar *format1;
960             const gchar *format2;
961             const guint8 *p = tvb_get_ptr(tvb, offset, length);
962             const gchar *s = 
963                 bytestring_to_str(p, MIN(length, max_show_bytes), 0);
964
965             if (length <= max_show_bytes)
966             {
967                 format1 = "Value: %s";
968                 format2 = " - %s";
969             }
970             else
971             {
972                 format1 = "Value: %s...";
973                 format2 = " - %s...";
974             }
975
976             proto_tree_add_bytes_format(
977                 tree, tlv_info->hf_value,
978                 tvb, offset, length, p,
979                 format1, s);
980
981             proto_item_append_text(
982                 tlv_item, format2, s);
983         }
984
985         return;
986     }
987     case WIMAXASNCP_TLV_HEX8:
988     {
989         if (length != 1)
990         {
991             /* encoding error */
992             break;
993         }
994
995         if (tree)
996         {
997             guint8 value;
998
999             value = tvb_get_guint8(tvb, offset);
1000
1001             proto_tree_add_uint_format(
1002                 tree, tlv_info->hf_value,
1003                 tvb, offset, length, value,
1004                 "Value: 0x%02x", value);
1005
1006             proto_item_append_text(tlv_item, " - 0x%02x", value);
1007         }
1008
1009         return;
1010     }
1011     case WIMAXASNCP_TLV_HEX16:
1012     {
1013         if (length != 2)
1014         {
1015             /* encoding error */
1016             break;
1017         }
1018
1019         if (tree)
1020         {
1021             guint16 value;
1022
1023             value = tvb_get_ntohs(tvb, offset);
1024
1025             proto_tree_add_uint_format(
1026                 tree, tlv_info->hf_value,
1027                 tvb, offset, length, value,
1028                 "Value: 0x%04x", value);
1029
1030             proto_item_append_text(tlv_item, " - 0x%04x", value);
1031         }
1032
1033         return;
1034     }
1035     case WIMAXASNCP_TLV_HEX32:
1036     {
1037         if (length != 4)
1038         {
1039             /* encoding error */
1040             break;
1041         }
1042
1043         if (tree)
1044         {
1045             guint32 value;
1046
1047             value = tvb_get_ntohl(tvb, offset);
1048
1049             proto_tree_add_uint_format(
1050                 tree, tlv_info->hf_value,
1051                 tvb, offset, length, value,
1052                 "Value: 0x%08x", value);
1053
1054             proto_item_append_text(tlv_item, " - 0x%08x", value);
1055         }
1056
1057         return;
1058     }
1059     case WIMAXASNCP_TLV_DEC8:
1060     {
1061         if (length != 1)
1062         {
1063             /* encoding error */
1064             break;
1065         }
1066
1067         if (tree)
1068         {
1069             guint8 value;
1070
1071             value = tvb_get_guint8(tvb, offset);
1072
1073             proto_tree_add_uint_format(
1074                 tree, tlv_info->hf_value,
1075                 tvb, offset, length, value,
1076                 "Value: %u", value);
1077
1078             proto_item_append_text(tlv_item, " - %u", value);
1079         }
1080
1081         return;
1082     }
1083     case WIMAXASNCP_TLV_DEC16:
1084     {
1085         if (length != 2)
1086         {
1087             /* encoding error */
1088             break;
1089         }
1090
1091         if (tree)
1092         {
1093             guint16 value;
1094
1095             value = tvb_get_ntohs(tvb, offset);
1096
1097             proto_tree_add_uint_format(
1098                 tree, tlv_info->hf_value,
1099                 tvb, offset, length, value,
1100                 "Value: %u", value);
1101
1102             proto_item_append_text(tlv_item, " - %u", value);
1103         }
1104
1105         return;
1106     }
1107     case WIMAXASNCP_TLV_DEC32:
1108     {
1109         if (length != 4)
1110         {
1111             /* encoding error */
1112             break;
1113         }
1114
1115         if (tree)
1116         {
1117             guint32 value;
1118
1119             value = tvb_get_ntohl(tvb, offset);
1120
1121             proto_tree_add_uint_format(
1122                 tree, tlv_info->hf_value,
1123                 tvb, offset, length, value,
1124                 "Value: %u", value);
1125
1126             proto_item_append_text(tlv_item, " - %u", value);
1127         }
1128
1129         return;
1130     }
1131     case WIMAXASNCP_TLV_TBD:
1132     {
1133         if (debug_enabled)
1134         {
1135             g_print(
1136                 "fix-me: TBD: TLV %s (%u)\n", tlv_info->name, tlv_info->type);
1137         }
1138
1139         if (tree)
1140         {
1141             const gchar *format;
1142             const guint8 *p = tvb_get_ptr(tvb, offset, length);
1143             const gchar *s = 
1144                 bytestring_to_str(p, MIN(length, max_show_bytes), 0);
1145
1146             if (length <= max_show_bytes)
1147             {
1148                 format = "Value: %s %s";
1149             }
1150             else
1151             {
1152                 format = "Value: %s %s...";
1153             }
1154             
1155             proto_tree_add_bytes_format(
1156                 tree, tlv_info->hf_value,
1157                 tvb, offset, length, p,
1158                 format, hex_note, s);
1159
1160             proto_item_append_text(tlv_item, " - TBD");
1161         }
1162
1163         return;
1164     }
1165     case WIMAXASNCP_TLV_IP_ADDRESS:
1166     {
1167         if (length == 4)
1168         {
1169             if (tree)
1170             {
1171                 wimaxasncp_proto_tree_add_tlv_ipv4_value(
1172                     tvb, tree, tlv_item, offset, tlv_info);
1173             }
1174
1175             return;
1176         }
1177         else if (length == 16)
1178         {
1179             if (tree)
1180             {
1181                 wimaxasncp_proto_tree_add_tlv_ipv6_value(
1182                     tvb, tree, tlv_item, offset, tlv_info);
1183             }
1184
1185             return;
1186         }
1187         else
1188         {
1189             /* encoding error */
1190             break;
1191         }
1192     }
1193     case WIMAXASNCP_TLV_IPV4_ADDRESS:
1194     {
1195         if (length != 4)
1196         {
1197             /* encoding error */
1198             break;
1199         }
1200
1201         if (tree)
1202         {
1203             wimaxasncp_proto_tree_add_tlv_ipv4_value(
1204                 tvb, tree, tlv_item, offset, tlv_info);
1205         }
1206
1207         return;
1208     }
1209     case WIMAXASNCP_TLV_PROTOCOL_LIST:
1210     {
1211         if (length % 2 != 0)
1212         {
1213             /* encoding error */
1214             break;
1215         }
1216
1217         if (tree && length > 0)
1218         {
1219             proto_tree *protocol_list_tree;
1220             proto_item *item;
1221             const guint max_protocols_in_tlv_item = 8; /* arbitrary */
1222
1223             item = proto_tree_add_text(
1224                 tree, tvb, offset, length,
1225                 "Value");
1226
1227             protocol_list_tree = proto_item_add_subtree(
1228                 item, ett_wimaxasncp_tlv_protocol_list);
1229
1230             /* hidden item for filtering */
1231             item = proto_tree_add_item(
1232                 protocol_list_tree, tlv_info->hf_value,
1233                 tvb, offset, length, FALSE);
1234
1235             PROTO_ITEM_SET_HIDDEN(item);
1236
1237             while (offset < tvb_length(tvb))
1238             {
1239                 guint16 protocol;
1240                 const gchar *protocol_name;
1241
1242                 protocol = tvb_get_ntohs(tvb, offset);
1243                 protocol_name = ipprotostr(protocol);
1244
1245                 proto_tree_add_uint_format(
1246                     protocol_list_tree, tlv_info->hf_protocol,
1247                     tvb, offset, 2, protocol,
1248                     "Protocol: %s (%u)", protocol_name, protocol);
1249
1250                 if (offset == 0)
1251                 {
1252                     proto_item_append_text(tlv_item, " - %s", protocol_name);
1253                 }
1254                 else if (offset < 2 * max_protocols_in_tlv_item)
1255                 {
1256                     proto_item_append_text(tlv_item, ", %s", protocol_name);
1257                 }
1258                 else if (offset == 2 * max_protocols_in_tlv_item)
1259                 {
1260                     proto_item_append_text(tlv_item, ", ...");
1261                 }
1262
1263                 offset += 2;
1264             }
1265         }
1266
1267         return;
1268     }
1269     case WIMAXASNCP_TLV_PORT_RANGE_LIST:
1270     {
1271         if (length % 4 != 0)
1272         {
1273             /* encoding error */
1274             break;
1275         }
1276
1277         if (tree && length > 0)
1278         {
1279             proto_tree *port_range_list_tree;
1280             proto_item *item;
1281             const guint max_port_ranges_in_tlv_item = 3; /* arbitrary */
1282
1283             item = proto_tree_add_text(
1284                 tree, tvb, offset, length,
1285                 "Value");
1286
1287             port_range_list_tree = proto_item_add_subtree(
1288                 item, ett_wimaxasncp_tlv_port_range_list);
1289
1290             /* hidden item for filtering */
1291             item = proto_tree_add_item(
1292                 port_range_list_tree, tlv_info->hf_value,
1293                 tvb, offset, length, FALSE);
1294
1295             PROTO_ITEM_SET_HIDDEN(item);
1296
1297             while (offset < tvb_length(tvb))
1298             {
1299                 guint16 portLow;
1300                 guint16 portHigh;
1301
1302                 portLow = tvb_get_ntohs(tvb, offset);
1303                 portHigh = tvb_get_ntohs(tvb, offset + 2);
1304
1305                 proto_tree_add_text(
1306                     port_range_list_tree, tvb, offset, 4,
1307                     "Port Range: %u-%u", portLow, portHigh);
1308
1309                 /* hidden items are for filtering */
1310
1311                 item = proto_tree_add_item(
1312                     port_range_list_tree, tlv_info->hf_port_low,
1313                     tvb, offset, 2, FALSE);
1314
1315                 PROTO_ITEM_SET_HIDDEN(item);
1316
1317                 item = proto_tree_add_item(
1318                     port_range_list_tree, tlv_info->hf_port_high,
1319                     tvb, offset + 2, 2, FALSE);
1320
1321                 PROTO_ITEM_SET_HIDDEN(item);
1322
1323                 if (offset == 0)
1324                 {
1325                     proto_item_append_text(
1326                         tlv_item, " - %u-%u", portLow, portHigh);
1327                 }
1328                 else if (offset < 4 * max_port_ranges_in_tlv_item)
1329                 {
1330                     proto_item_append_text(
1331                         tlv_item, ", %u-%u", portLow, portHigh);
1332                 }
1333                 else if (offset == 4 * max_port_ranges_in_tlv_item)
1334                 {
1335                     proto_item_append_text(tlv_item, ", ...");
1336                 }
1337
1338                 offset += 4;
1339             }
1340         }
1341
1342         return;
1343     }
1344     case WIMAXASNCP_TLV_IP_ADDRESS_MASK_LIST:
1345     {
1346         /* --------------------------------------------------------------------
1347          * The definion of these TLVs are ambiguous. The length in octets is
1348          * described as Nx8 (IPv4) or Nx32 (IPv6), but this function cannot
1349          * always differentiate between IPv4 and IPv6. For example, if length
1350          * = 32, then is it IPv4 where N=4 (4x8) or IPv6 where N=1 (1x32)?
1351          *
1352          * For now, we presume lengths that *can* indicate an IPv6 address and
1353          * mask list *do* denote an IPv6 address and mask list.
1354          * --------------------------------------------------------------------
1355          */
1356
1357         if (length % 8 != 0)
1358         {
1359             /* encoding error */
1360             break;
1361         }
1362
1363         if (tree && length > 0)
1364         {
1365             proto_tree *ip_address_mask_list_tree;
1366             proto_item *item;
1367
1368             item = proto_tree_add_text(
1369                 tree, tvb, offset, length,
1370                 "Value");
1371
1372             ip_address_mask_list_tree = proto_item_add_subtree(
1373                 item, ett_wimaxasncp_tlv_ip_address_mask_list);
1374
1375             /* hidden item for filtering */
1376             item = proto_tree_add_item(
1377                 ip_address_mask_list_tree, tlv_info->hf_value,
1378                 tvb, offset, length, FALSE);
1379
1380             PROTO_ITEM_SET_HIDDEN(item);
1381
1382             if (length % 32 == 0)
1383             {
1384                 /* ------------------------------------------------------------
1385                  * presume IPv6
1386                  * ------------------------------------------------------------
1387                  */
1388
1389                 while (offset < tvb_length(tvb))
1390                 {
1391                     proto_tree *ip_address_mask_tree;
1392                     struct e_in6_addr ip;
1393                     const gchar *s;
1394
1395                     item = proto_tree_add_text(
1396                         ip_address_mask_list_tree, tvb, offset, 32,
1397                         "IPv6 Address and Mask");
1398
1399                     ip_address_mask_tree = proto_item_add_subtree(
1400                         item, ett_wimaxasncp_tlv_ip_address_mask);
1401
1402                     /* --------------------------------------------------------
1403                      * address
1404                      * --------------------------------------------------------
1405                      */
1406
1407                     tvb_get_ipv6(tvb, offset, &ip);
1408
1409                     proto_tree_add_item(
1410                         ip_address_mask_tree,
1411                         tlv_info->hf_ipv6,
1412                         tvb, offset, 16, FALSE);
1413
1414                     /* too long to display ?
1415                     proto_item_append_text(
1416                         item, " - %s (%s)",
1417                         get_hostname6(&ip), ip6_to_str(&ip));
1418                     */
1419
1420                     offset += 16;
1421
1422                     /* --------------------------------------------------------
1423                      * mask
1424                      * --------------------------------------------------------
1425                      */
1426
1427                     tvb_get_ipv6(tvb, offset, &ip);
1428
1429                     s = ip6_to_str(&ip);
1430
1431                     proto_tree_add_ipv6_format_value(
1432                         ip_address_mask_tree,
1433                         tlv_info->hf_ipv6_mask,
1434                         tvb, offset, 16, (const guint8*)&ip,
1435                         "%s", s);
1436
1437                     /* too long to display ?
1438                     proto_item_append_text(
1439                         item, " / %s", s);
1440                     */
1441
1442                     offset += 16;
1443                 }
1444             }
1445             else
1446             {
1447                 /* ------------------------------------------------------------
1448                  * IPv4
1449                  * ------------------------------------------------------------
1450                  */
1451
1452                 while (offset < tvb_length(tvb))
1453                 {
1454                     proto_tree *ip_address_mask_tree;
1455                     guint32 ip;
1456                     const gchar *s;
1457
1458                     item = proto_tree_add_text(
1459                         ip_address_mask_list_tree, tvb, offset, 8,
1460                         "IPv4 Address and Mask");
1461
1462                     ip_address_mask_tree = proto_item_add_subtree(
1463                         item, ett_wimaxasncp_tlv_ip_address_mask);
1464
1465                     /* --------------------------------------------------------
1466                      * address
1467                      * --------------------------------------------------------
1468                      */
1469
1470                     ip = tvb_get_ipv4(tvb, offset);
1471
1472                     proto_tree_add_item(
1473                         ip_address_mask_tree,
1474                         tlv_info->hf_ipv4,
1475                         tvb, offset, 4, FALSE);
1476
1477                     proto_item_append_text(
1478                         item, " - %s (%s)",
1479                         get_hostname(ip), ip_to_str((guint8 *)&ip));
1480
1481                     offset += 4;
1482
1483                     /* --------------------------------------------------------
1484                      * mask
1485                      * --------------------------------------------------------
1486                      */
1487
1488                     ip = tvb_get_ipv4(tvb, offset);
1489
1490                     s = ip_to_str((guint8 *)&ip);
1491
1492                     proto_tree_add_ipv4_format_value(
1493                         ip_address_mask_tree,
1494                         tlv_info->hf_ipv4_mask,
1495                         tvb, offset, 4, ip,
1496                         "%s", s);
1497
1498                     proto_item_append_text(
1499                         item, " / %s", s);
1500
1501                     offset += 4;
1502                 }
1503             }
1504         }
1505
1506         return;
1507     }
1508     case WIMAXASNCP_TLV_EAP:
1509     {
1510         /*
1511          *   EAP payload, call eap dissector to dissect eap payload
1512          */
1513         guint8 eap_code;
1514         guint8 eap_type = 0;
1515
1516         /* Get code */
1517         eap_code = tvb_get_guint8(tvb, offset);
1518         if (eap_code == EAP_REQUEST || eap_code == EAP_RESPONSE)
1519         {
1520             /* Get type */
1521             eap_type = tvb_get_guint8(tvb, offset + 4);
1522         }
1523
1524         /* Add code and type to info column */
1525         if (check_col(pinfo->cinfo, COL_INFO))
1526         {
1527             col_append_str(pinfo->cinfo, COL_INFO, " [");
1528             col_append_str(pinfo->cinfo, COL_INFO,
1529                             val_to_str(eap_code, eap_code_vals, "Unknown code (0x%02X)"));
1530
1531             if (eap_code == EAP_REQUEST || eap_code == EAP_RESPONSE)
1532             {
1533                 col_append_str(pinfo->cinfo, COL_INFO, ", ");
1534                 col_append_str(pinfo->cinfo, COL_INFO,
1535                                 val_to_str(eap_type, eap_type_vals, "Unknown type (0x%02X)"));
1536             }
1537
1538             col_append_str(pinfo->cinfo, COL_INFO, "]");
1539         }
1540
1541
1542         {
1543             proto_tree *eap_tree;
1544             proto_item *item;
1545             gboolean save_writable;
1546             tvbuff_t *eap_tvb;
1547
1548             /* Create EAP subtree */
1549             item = proto_tree_add_item(tree, tlv_info->hf_value, tvb,
1550                                        offset, length, FALSE);
1551             proto_item_set_text(item, "Value");
1552             eap_tree = proto_item_add_subtree(item, ett_wimaxasncp_tlv_eap);
1553
1554             /* Also show high-level details in this root item */
1555             proto_item_append_text(item, " (%s",
1556                                    val_to_str(eap_code, eap_code_vals,
1557                                               "Unknown code (0x%02X)"));
1558             if (eap_code == EAP_REQUEST || eap_code == EAP_RESPONSE)
1559             {
1560                 proto_item_append_text(item, ", %s",
1561                                        val_to_str(eap_type, eap_type_vals,
1562                                        "Unknown type (0x%02X)"));
1563             }
1564             proto_item_append_text(item, ")");
1565
1566
1567             /* Extract remaining bytes into new tvb */
1568             eap_tvb = tvb_new_subset(tvb, offset, length,
1569                                      tvb_length_remaining(tvb, offset));
1570
1571             /* Disable writing to info column while calling eap dissector */
1572             save_writable = col_get_writable(pinfo->cinfo);
1573             col_set_writable(pinfo->cinfo, FALSE);
1574
1575             /* Call the EAP dissector. */
1576             call_dissector(eap_handle, eap_tvb, pinfo, eap_tree);
1577
1578             /* Restore previous writable state of info column */
1579             col_set_writable(pinfo->cinfo, save_writable);
1580         }
1581
1582         return;
1583     }
1584
1585     case WIMAXASNCP_TLV_VENDOR_SPECIFIC:
1586     {
1587         /* --------------------------------------------------------------------
1588          *  The format of the vendor specific information field (VSIF) is not
1589          *  clearly defined.  It appears to be compound as the spec states
1590          *  that the vendor ID field shall be the first TLV embedded inside
1591          *  the VSIF.  However, the vendor ID is shown as a 24-bit value. Does
1592          *  this mean the field is 24-bits?  If so, how is alignment/padding
1593          *  handled?
1594          *
1595          * For now, we decode the vendor ID as a non-padded 24-bit value and
1596          * dump the rest as hex.
1597          * --------------------------------------------------------------------
1598          */
1599
1600         if (length < 3)
1601         {
1602             /* encoding error */
1603             break;
1604         }
1605
1606         if (tree)
1607         {
1608             proto_tree *vsif_tree;
1609             proto_item *item;
1610             guint32 vendorId;
1611             const gchar *vendorName;
1612
1613             item = proto_tree_add_text(
1614                 tree, tvb, offset, length,
1615                 "Value");
1616
1617             vsif_tree = proto_item_add_subtree(
1618                 item, ett_wimaxasncp_tlv_vendor_specific_information_field);
1619
1620             /* hidden item for filtering */
1621             item = proto_tree_add_item(
1622                 vsif_tree, tlv_info->hf_value,
1623                 tvb, offset, length, FALSE);
1624
1625             PROTO_ITEM_SET_HIDDEN(item);
1626
1627             /* ----------------------------------------------------------------
1628              * vendor ID (24-bit)
1629              * ----------------------------------------------------------------
1630              */
1631
1632             vendorId = tvb_get_ntoh24(tvb, offset);
1633
1634             vendorName = val_to_str(vendorId, sminmpec_values, "Unknown");
1635             proto_tree_add_uint_format(
1636                 vsif_tree, tlv_info->hf_vendor_id,
1637                 tvb, offset, 3, vendorId,
1638                 "Vendor ID: %s (%u)", vendorName, vendorId);
1639
1640             proto_item_append_text(tlv_item, " - %s", vendorName);
1641
1642             offset += 3;
1643
1644             /* ----------------------------------------------------------------
1645              * hex dump the rest
1646              * ----------------------------------------------------------------
1647              */
1648
1649             if (offset < tvb_length(tvb))
1650             {
1651                 proto_tree_add_item(
1652                     vsif_tree, tlv_info->hf_vendor_rest_of_info,
1653                     tvb, offset, length - offset, FALSE);
1654             }
1655         }
1656
1657         return;
1658     }
1659     case WIMAXASNCP_TLV_UNKNOWN:
1660     {
1661         if (tree)
1662         {
1663             const gchar *format1;
1664             const gchar *format2;
1665             const guint8 *p = tvb_get_ptr(tvb, offset, length);
1666             const gchar *s = 
1667                 bytestring_to_str(p, MIN(length, max_show_bytes), 0);
1668
1669             if (length <= max_show_bytes)
1670             {
1671                 format1 = "Value: %s %s";
1672                 format2 = " - %s %s";
1673             }
1674             else
1675             {
1676                 format1 = "Value: %s %s...";
1677                 format2 = " - %s %s...";
1678             }
1679
1680             proto_tree_add_bytes_format(
1681                 tree, tlv_info->hf_value,
1682                 tvb, offset, length, p,
1683                 format1, hex_note, s);
1684
1685             proto_item_append_text(
1686                 tlv_item, format2, hex_note, s);
1687
1688         }
1689
1690         return;
1691     }
1692     default:
1693         if (debug_enabled)
1694         {
1695             g_print(
1696                 "fix-me: unknown decoder: %d\n", tlv_info->decoder);
1697         }
1698         break;
1699     }
1700
1701     /* default is hex dump */
1702
1703     if (tree)
1704     {
1705         const gchar *format;
1706         const guint8 *p = tvb_get_ptr(tvb, offset, length);
1707         const gchar *s = bytestring_to_str(p, MIN(length, max_show_bytes), 0);
1708
1709         if (length <= max_show_bytes)
1710         {
1711             format = "Value: %s %s";
1712         }
1713         else
1714         {
1715             format = "Value: %s %s...";
1716         }
1717
1718         proto_tree_add_bytes_format(
1719             tree, hf_wimaxasncp_tlv_value_bytes,
1720             tvb, offset, length, p,
1721             format, hex_note, s);
1722     }
1723 }
1724
1725 /* ========================================================================= */
1726
1727 static guint dissect_wimaxasncp_tlvs(
1728     tvbuff_t *tvb,
1729     packet_info *pinfo,
1730     proto_tree *tree)
1731 {
1732     guint offset;
1733
1734     offset = 0;
1735     while (offset < tvb_reported_length(tvb))
1736     {
1737         proto_tree *tlv_tree = NULL;
1738         proto_item *tlv_item = NULL;
1739         const wimaxasncp_dict_tlv_t *tlv_info;
1740
1741         guint16 type;
1742         guint16 length;
1743         guint pad;
1744
1745         /* --------------------------------------------------------------------
1746          * type and length
1747          * --------------------------------------------------------------------
1748          */
1749
1750         type = tvb_get_ntohs(tvb, offset);
1751         tlv_info = wimaxasncp_get_tlv_info(type);
1752
1753         length = tvb_get_ntohs(tvb, offset + 2);
1754         /* Commented out padding; As there is no mention of padding in
1755            the Latest specification
1756         pad = 4 - (length % 4);
1757         if (pad == 4)
1758         {
1759             pad = 0;
1760         }
1761         */
1762         pad = 0;
1763         if (tree)
1764         {
1765             proto_item *type_item;
1766
1767             gint tree_length = MIN(
1768                 (gint)(4 + length + pad), tvb_length_remaining(tvb, offset));
1769
1770             tlv_item = proto_tree_add_item(
1771                 tree, tlv_info->hf_root,
1772                 tvb, offset, tree_length, FALSE);
1773
1774             /* Set label for tlv item */
1775             proto_item_set_text(tlv_item, "TLV: %s", tlv_info->name);
1776
1777             /* Show code number if unknown */
1778             if (tlv_info->decoder == WIMAXASNCP_TLV_UNKNOWN)
1779             {
1780                 proto_item_append_text(tlv_item, " (%u)", type);
1781             }
1782
1783             /* Indicate if a compound tlv */
1784             if (tlv_info->decoder == WIMAXASNCP_TLV_COMPOUND)
1785             {
1786                 proto_item_append_text(tlv_item, " [Compound]");
1787             }
1788
1789             /* Create TLV subtree */
1790             tlv_tree = proto_item_add_subtree(
1791                 tlv_item, ett_wimaxasncp_tlv);
1792
1793             /* Type (expert item if unknown) */
1794             type_item = proto_tree_add_uint_format(
1795                 tlv_tree, hf_wimaxasncp_tlv_type,
1796                 tvb, offset, 2, type,
1797                 "Type: %s (%u)", tlv_info->name, type);
1798
1799             if (tlv_info->decoder == WIMAXASNCP_TLV_UNKNOWN)
1800             {
1801                 expert_add_info_format(pinfo, type_item,
1802                                        PI_UNDECODED, PI_WARN,
1803                                        "Unknown TLV type (%u)",
1804                                        type);
1805             }
1806
1807             /* Length */
1808             proto_tree_add_uint(
1809                 tlv_tree, hf_wimaxasncp_tlv_length,
1810                 tvb, offset + 2, 2, length);
1811
1812         }
1813
1814         offset += 4;
1815
1816         /* --------------------------------------------------------------------
1817          * value
1818          * --------------------------------------------------------------------
1819          */
1820
1821         if (tlv_info->decoder == WIMAXASNCP_TLV_COMPOUND)
1822         {
1823             if (length == 0)
1824             {
1825                 /* error? compound, but no TLVs inside */
1826             }
1827             else if (tvb_length_remaining(tvb, offset) > 0)
1828             {
1829                 tvbuff_t *tlv_tvb;
1830
1831                 /* N.B.  Not padding out tvb length */
1832                 tlv_tvb = tvb_new_subset(
1833                     tvb, offset,
1834                     MIN(length, tvb_length_remaining(tvb, offset)),
1835                     length);
1836
1837                 /* N.B.  This is a recursive call... */
1838                 dissect_wimaxasncp_tlvs(tlv_tvb, pinfo, tlv_tree);
1839             }
1840             else
1841             {
1842                 /* this should throw */
1843                 tvb_ensure_bytes_exist(tvb, offset, length + pad);
1844             }
1845         }
1846         else
1847         {
1848             tvbuff_t *tlv_tvb;
1849
1850             tvb_ensure_bytes_exist(tvb, offset, length + pad);
1851
1852             tlv_tvb = tvb_new_subset(
1853                 tvb, offset,
1854                 MIN(length, tvb_length_remaining(tvb, offset)),
1855                 length);
1856
1857             wimaxasncp_dissect_tlv_value(
1858                 tlv_tvb, pinfo, tlv_tree, tlv_item, tlv_info);
1859         }
1860
1861         offset += length + pad;
1862     }
1863
1864     return offset;
1865 }
1866
1867 /* ========================================================================= */
1868
1869 static guint dissect_wimaxasncp_backend(
1870     tvbuff_t *tvb,
1871     packet_info *pinfo,
1872     proto_tree *tree)
1873 {
1874     guint offset = 0;
1875     guint16 ui16;
1876     guint32 ui32;
1877     const guint8 *p;
1878     guint8 *pmsid = NULL;
1879     guint16 tid = 0;
1880     gboolean dbit_show;
1881
1882
1883     /* ------------------------------------------------------------------------
1884      * MSID
1885      * ------------------------------------------------------------------------
1886      */
1887
1888     p = tvb_get_ptr(tvb, offset, 6);
1889
1890     if (tree)
1891     {
1892         proto_tree_add_ether(
1893             tree, hf_wimaxasncp_msid,
1894             tvb, offset, 6, p);
1895     }
1896     pmsid = ether_to_str(p);
1897
1898     offset += 6;
1899
1900     /* ------------------------------------------------------------------------
1901      * reserved
1902      * ------------------------------------------------------------------------
1903      */
1904
1905     ui32 = tvb_get_ntohl(tvb, offset);
1906
1907     if (tree)
1908     {
1909         proto_tree_add_uint(
1910             tree, hf_wimaxasncp_reserved1,
1911             tvb, offset, 4, ui32);
1912     }
1913
1914     offset += 4;
1915
1916     /* ------------------------------------------------------------------------
1917      * transaction ID
1918      * ------------------------------------------------------------------------
1919      */
1920
1921     dbit_show = FALSE;
1922     ui16 = tvb_get_ntohs(tvb, offset);
1923
1924     if (show_transaction_id_d_bit)
1925     {
1926         const guint16 mask = 0x7fff;
1927
1928         if (ui16 & 0x8000)
1929         {
1930             proto_tree_add_uint_format(
1931                 tree, hf_wimaxasncp_transaction_id,
1932                 tvb, offset, 2, ui16,
1933                 "Transaction ID: D + 0x%04x (0x%04x)", mask & ui16, ui16);
1934
1935             tid = ui16 & mask;
1936             dbit_show = TRUE;
1937         }
1938         else
1939         {
1940             proto_tree_add_uint_format(
1941                 tree, hf_wimaxasncp_transaction_id,
1942                 tvb, offset, 2, ui16,
1943                 "Transaction ID: 0x%04x", ui16);
1944
1945             tid = ui16;
1946         }
1947     }
1948     else
1949     {
1950         proto_tree_add_uint(
1951             tree, hf_wimaxasncp_transaction_id,
1952             tvb, offset, 2, ui16);
1953
1954         tid = ui16;
1955     }
1956
1957     offset += 2;
1958
1959     /* ------------------------------------------------------------------------
1960      * reserved
1961      * ------------------------------------------------------------------------
1962      */
1963
1964     ui16 = tvb_get_ntohs(tvb, offset);
1965
1966     if (tree)
1967     {
1968         proto_tree_add_uint(
1969             tree, hf_wimaxasncp_reserved2,
1970             tvb, offset, 2, ui16);
1971     }
1972
1973     offset += 2;
1974
1975     /* ------------------------------------------------------------------------
1976      * TLVs
1977      * ------------------------------------------------------------------------
1978      */
1979
1980     if (offset < tvb_length(tvb))
1981     {
1982         tvbuff_t *tlv_tvb;
1983
1984         tlv_tvb = tvb_new_subset(
1985             tvb, offset,
1986             tvb_length(tvb) - offset,
1987             tvb_length(tvb) - offset);
1988
1989         offset += dissect_wimaxasncp_tlvs(tlv_tvb, pinfo, tree);
1990     }
1991
1992     if (check_col(pinfo->cinfo, COL_INFO))
1993     {
1994         col_append_fstr(pinfo->cinfo, COL_INFO, " - MSID:%s", pmsid);
1995         if (dbit_show)
1996         {
1997             col_append_fstr(pinfo->cinfo, COL_INFO, ", TID:D+0x%04x", tid);
1998         }
1999         else
2000         {
2001             col_append_fstr(pinfo->cinfo, COL_INFO, ", TID:0x%04x", tid);
2002         }
2003     }
2004
2005     return offset;
2006 }
2007
2008 /* ========================================================================= */
2009
2010 static void register_wimaxasncp_fields(const char*);
2011
2012
2013 static int
2014 dissect_wimaxasncp(
2015     tvbuff_t *tvb,
2016     packet_info *pinfo,
2017     proto_tree *tree)
2018 {
2019     const gchar *unknown = "Unknown";
2020
2021     /* Set up structures needed to add the protocol subtree and manage it */
2022     proto_item *packet_item = NULL;
2023     proto_item *item = NULL;
2024     proto_tree *wimaxasncp_tree = NULL;
2025     tvbuff_t *subtree;
2026
2027     guint offset;
2028     guint8 ui8;
2029
2030     guint8 function_type;
2031     proto_item *function_type_item;
2032     guint16 length;
2033
2034     const gchar *message_name;
2035     const wimaxasncp_func_msg_t *p = NULL;
2036     gsize i;
2037
2038     /* ------------------------------------------------------------------------
2039      * First, we do some heuristics to check if the packet cannot be our
2040      * protocol.
2041      * ------------------------------------------------------------------------
2042      */
2043
2044     /* Should we check a minimum size?  If so, uncomment out the following
2045      * code. */
2046     /*
2047     if (tvb_reported_length(tvb) < WIMAXASNCP_HEADER_SIZE)
2048     {
2049         return 0;
2050     }
2051     */
2052
2053     /* We currently only support version 1. */
2054     if (tvb_bytes_exist(tvb, 0, 1) && tvb_get_guint8(tvb, 0) != 1)
2055     {
2056         return 0;
2057     }
2058
2059     /* ------------------------------------------------------------------------
2060      * Initialize the protocol and info column.
2061      * ------------------------------------------------------------------------
2062      */
2063
2064     /* Make entries in Protocol column and Info column on summary display */
2065     col_set_str(pinfo->cinfo, COL_PROTOCOL, "WiMAX");
2066
2067     /* We'll fill in the "Info" column after fetch data, so we clear the
2068        column first in case calls to fetch data from the packet throw an
2069        exception. */
2070     col_clear(pinfo->cinfo, COL_INFO);
2071
2072     /* ========================================================================
2073      * Disesction starts here
2074      * ========================================================================
2075      */
2076
2077     /* ------------------------------------------------------------------------
2078      * total packet, we'll adjust after we read the length field
2079      * ------------------------------------------------------------------------
2080      */
2081
2082     offset = 0;
2083
2084     /* Register protocol fields, etc if haven't done yet. */
2085     if (wimaxasncp_dict == NULL)
2086     {
2087         register_wimaxasncp_fields(NULL);
2088     }
2089
2090     if (tree)
2091     {
2092         packet_item = proto_tree_add_item(
2093             tree, proto_wimaxasncp,
2094             tvb, 0, MIN(WIMAXASNCP_HEADER_LENGTH_END, tvb_length(tvb)), FALSE);
2095
2096         wimaxasncp_tree = proto_item_add_subtree(
2097             packet_item, ett_wimaxasncp);
2098     }
2099
2100     /* ------------------------------------------------------------------------
2101      * version
2102      * ------------------------------------------------------------------------
2103      */
2104
2105     if (tree)
2106     {
2107         proto_tree_add_item(
2108             wimaxasncp_tree, hf_wimaxasncp_version,
2109             tvb, offset, 1, FALSE);
2110     }
2111
2112     offset += 1;
2113
2114     /* ------------------------------------------------------------------------
2115      * flags
2116      * ------------------------------------------------------------------------
2117      */
2118
2119     ui8 = tvb_get_guint8(tvb, offset);
2120
2121     if (tree)
2122     {
2123         proto_tree *flags_tree;
2124
2125         if (ui8 == 0)
2126         {
2127             item = proto_tree_add_uint_format(
2128                 wimaxasncp_tree, hf_wimaxasncp_flags,
2129                 tvb, offset, 1, ui8,
2130                 "Flags: 0x%02x", ui8);
2131         }
2132         else
2133         {
2134             guint j;
2135             item = proto_tree_add_uint_format(
2136                 wimaxasncp_tree, hf_wimaxasncp_flags,
2137                 tvb, offset, 1, ui8,
2138                 "Flags: ");
2139
2140             if (ui8 & (WIMAXASNCP_FLAGS_T | WIMAXASNCP_FLAGS_R))
2141             {
2142                 if (ui8 & WIMAXASNCP_FLAGS_T)
2143                 {
2144                     proto_item_append_text(item, "T");
2145                 }
2146
2147                 if (ui8 & WIMAXASNCP_FLAGS_R)
2148                 {
2149                     proto_item_append_text(item, "R");
2150                 }
2151
2152                 proto_item_append_text(item, " - ");
2153             }
2154
2155             proto_item_append_text(
2156                 item, "%s", decode_numeric_bitfield(ui8, 0xff, 8, "0x%02x"));
2157
2158             flags_tree = proto_item_add_subtree(
2159                 item, ett_wimaxasncp_flags);
2160
2161             for (j = 0; j < 8; ++j)
2162             {
2163                 guint8 mask;
2164                 mask = 1 << (7 - j);
2165
2166                 /* Only add flags that are set */
2167                 if (ui8 & mask)
2168                 {
2169                     proto_tree_add_uint_format(
2170                         flags_tree, hf_wimaxasncp_flags,
2171                         tvb, offset, 1, ui8,
2172                         "Bit #%u is set: %s",
2173                         j,
2174                         val_to_str(
2175                             ui8 & mask, wimaxasncp_flag_vals, "Unknown"));
2176                 }
2177             }
2178         }
2179     }
2180
2181     offset += 1;
2182
2183     /* ------------------------------------------------------------------------
2184      * function type
2185      * ------------------------------------------------------------------------
2186      */
2187
2188     function_type = tvb_get_guint8(tvb, offset);
2189
2190     function_type_item = proto_tree_add_item(
2191         wimaxasncp_tree, hf_wimaxasncp_function_type,
2192         tvb, offset, 1, FALSE);
2193
2194     /* Add expert item if not matched */
2195     if (strcmp(val_to_str(function_type,
2196                           wimaxasncp_function_type_vals,
2197                           unknown),
2198                unknown) == 0)
2199     {
2200             expert_add_info_format(pinfo, function_type_item,
2201                                    PI_UNDECODED, PI_WARN,
2202                                    "Unknown function type (%u)",
2203                                    function_type);
2204     }
2205
2206     offset += 1;
2207
2208     /* ------------------------------------------------------------------------
2209      * OP ID and message type
2210      * ------------------------------------------------------------------------
2211      */
2212
2213     ui8 = tvb_get_guint8(tvb, offset);
2214
2215
2216     /* --------------------------------------------------------------------
2217      * OP ID
2218      * --------------------------------------------------------------------
2219      */
2220
2221     item = proto_tree_add_uint_format(
2222         wimaxasncp_tree, hf_wimaxasncp_op_id,
2223          tvb, offset, 1, ui8,
2224         "OP ID: %s", val_to_str(ui8 >> 5, wimaxasncp_op_id_vals, unknown));
2225
2226     proto_item_append_text(
2227         item, " (%s)", decode_numeric_bitfield(ui8, 0xe0, 8, "%u"));
2228
2229
2230     /* use the function type to find the message vals */
2231     for (i = 0; i < array_length(wimaxasncp_func_to_msg_vals_map); ++i)
2232     {
2233         p = &wimaxasncp_func_to_msg_vals_map[i];
2234
2235         if (function_type == p->function_type)
2236         {
2237             break;
2238         }
2239     }
2240
2241     /* --------------------------------------------------------------------
2242      * message type
2243      * --------------------------------------------------------------------
2244      */
2245
2246     message_name = p ? val_to_str(0x1f & ui8, p->vals, unknown) : unknown;
2247
2248     item = proto_tree_add_uint_format(
2249         wimaxasncp_tree, hf_wimaxasncp_op_id,
2250         tvb, offset, 1, ui8,
2251         "Message Type: %s", message_name);
2252
2253     proto_item_append_text(
2254         item, " (%s)", decode_numeric_bitfield(ui8, 0x1f, 8, "%u"));
2255
2256     /* Add expert item if not matched */
2257     if (strcmp(message_name, unknown) == 0)
2258     {
2259         expert_add_info_format(pinfo, item,
2260                                PI_UNDECODED, PI_WARN,
2261                                "Unknown message op (%u)",
2262                                0x1f & ui8);
2263     }
2264
2265     col_add_str(pinfo->cinfo, COL_INFO, message_name);
2266
2267     offset += 1;
2268
2269     /* ------------------------------------------------------------------------
2270      * length
2271      * ------------------------------------------------------------------------
2272      */
2273
2274     length = tvb_get_ntohs(tvb, offset);
2275
2276     if (tree)
2277     {
2278         proto_item_set_len(
2279             packet_item, MAX(WIMAXASNCP_HEADER_LENGTH_END, length));
2280
2281         item = proto_tree_add_uint(
2282             wimaxasncp_tree, hf_wimaxasncp_length,
2283             tvb, offset, 2, length);
2284     }
2285
2286     offset += 2;
2287
2288     if (length < WIMAXASNCP_HEADER_SIZE)
2289     {
2290         expert_add_info_format(
2291             pinfo, item, PI_MALFORMED, PI_ERROR, "Bad length");
2292
2293         if (tree)
2294         {
2295             proto_item_append_text(
2296                 item, " [error: specified length less than header size (20)]");
2297         }
2298
2299         if (length <= WIMAXASNCP_HEADER_LENGTH_END)
2300         {
2301             return offset;
2302         }
2303     }
2304
2305     /* ------------------------------------------------------------------------
2306      * remaining header fields and TLVs
2307      * ------------------------------------------------------------------------
2308      */
2309
2310     subtree = tvb_new_subset(
2311         tvb, offset,
2312         MIN(length, tvb_length(tvb) - offset),
2313         length - WIMAXASNCP_HEADER_LENGTH_END);
2314
2315     offset += dissect_wimaxasncp_backend(
2316         subtree, pinfo, wimaxasncp_tree);
2317
2318     /* ------------------------------------------------------------------------
2319      * done, return the amount of data this dissector was able to dissect
2320      * ------------------------------------------------------------------------
2321      */
2322
2323     return offset;
2324 }
2325
2326 /* ========================================================================= */
2327 /* Modify the given string to make a suitable display filter                 */
2328 static char *alnumerize(
2329     char *name)
2330 {
2331     char *r = name;  /* read pointer */
2332     char *w = name;  /* write pointer */
2333     char c;
2334
2335     for ( ; (c = *r); ++r) 
2336     {
2337         if (isalnum((unsigned char)c) || c == '_' || c == '.') 
2338         {
2339             /* These characters are fine - copy them */
2340             *(w++) = c;
2341         }
2342         else if (c == ' ' || c == '-' || c == '/')
2343         {
2344             /* Skip these others if haven't written any characters out yet */
2345             if (w == name)
2346             {
2347                 continue;
2348             }
2349
2350             /* Skip if we would produce multiple adjacent '_'s */
2351             if (*(w - 1) == '_')
2352             {
2353                 continue;
2354             }
2355
2356             /* OK, replace with underscore */
2357             *(w++) = '_';
2358         }
2359
2360         /* Other undesirable characters are just skipped */
2361     }
2362
2363     /* Terminate and return modified string */
2364     *w = '\0';
2365     return name;
2366 }
2367
2368 /* ========================================================================= */
2369
2370 static void add_reg_info(
2371     int *hf_ptr,
2372     const char *name,
2373     const char *abbrev,
2374     enum ftenum type,
2375     int  display,
2376     const char *blurb)
2377 {
2378     hf_register_info hf = { 
2379         hf_ptr, { name, abbrev, type, display, NULL, 0x0, blurb, HFILL } };
2380
2381     g_array_append_val(wimaxasncp_build_dict.hf, hf);
2382 }
2383
2384 /* ========================================================================= */
2385
2386 static void add_tlv_reg_info(
2387     wimaxasncp_dict_tlv_t *tlv)
2388 {
2389     const char *name;
2390     const char *abbrev;
2391     const char *blurb;
2392
2393     /* ------------------------------------------------------------------------
2394      * add root reg info
2395      * ------------------------------------------------------------------------
2396      */
2397
2398     name = g_strdup(tlv->name);
2399     abbrev = alnumerize(g_strdup_printf("wimaxasncp.tlv.%s", tlv->name));
2400
2401     switch (tlv->decoder)
2402     {
2403     case WIMAXASNCP_TLV_UNKNOWN:
2404         blurb = "type=Unknown";
2405         break;
2406     case WIMAXASNCP_TLV_TBD:
2407         blurb = g_strdup_printf("type=%u, TBD", tlv->type);
2408         break;
2409     case WIMAXASNCP_TLV_COMPOUND:
2410         blurb = g_strdup_printf("type=%u, Compound", tlv->type);
2411         break;
2412     case WIMAXASNCP_TLV_FLAG0:
2413         blurb = g_strdup_printf("type=%u, Value = Null", tlv->type);
2414         break;
2415     default:
2416         blurb = g_strdup_printf("type=%u", tlv->type);
2417         break;
2418     }
2419
2420     add_reg_info(
2421         &tlv->hf_root, name, abbrev, FT_BYTES, BASE_NONE, blurb);
2422
2423     /* ------------------------------------------------------------------------
2424      * add value(s) reg info
2425      * ------------------------------------------------------------------------
2426      */
2427
2428     name = g_strdup("Value");
2429     abbrev = alnumerize(g_strdup_printf("wimaxasncp.tlv.%s.value", tlv->name));
2430     blurb = g_strdup_printf("value for type=%u", tlv->type);
2431
2432     switch (tlv->decoder)
2433     {
2434     case WIMAXASNCP_TLV_UNKNOWN:
2435         g_free((gpointer*)blurb);
2436
2437         add_reg_info(
2438             &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE,
2439             "value for unknown type");
2440         break;
2441
2442     case WIMAXASNCP_TLV_TBD:
2443         add_reg_info(
2444             &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE, blurb);
2445         break;
2446
2447     case WIMAXASNCP_TLV_COMPOUND:
2448     case WIMAXASNCP_TLV_FLAG0:
2449         g_free((gpointer*)name);
2450         g_free((gpointer*)abbrev);
2451         g_free((gpointer*)blurb);
2452         break;
2453
2454     case WIMAXASNCP_TLV_BYTES:
2455         add_reg_info(
2456             &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE, blurb);
2457         break;
2458
2459     case WIMAXASNCP_TLV_ENUM8:
2460         add_reg_info(
2461             &tlv->hf_value, name, abbrev, FT_UINT8, BASE_DEC, blurb);
2462         break;
2463
2464     case WIMAXASNCP_TLV_ENUM16:
2465         add_reg_info(
2466             &tlv->hf_value, name, abbrev, FT_UINT16, BASE_DEC, blurb);
2467         break;
2468
2469     case WIMAXASNCP_TLV_ENUM32:
2470         add_reg_info(
2471             &tlv->hf_value, name, abbrev, FT_UINT32, BASE_DEC, blurb);
2472         break;
2473
2474     case WIMAXASNCP_TLV_ETHER:
2475         add_reg_info(
2476             &tlv->hf_value, name, abbrev, FT_ETHER, BASE_NONE, blurb);
2477         break;
2478
2479     case WIMAXASNCP_TLV_ASCII_STRING:
2480         add_reg_info(
2481             &tlv->hf_value, name, abbrev, FT_STRING, BASE_NONE, blurb);
2482         break;
2483     
2484     case WIMAXASNCP_TLV_BITFLAGS8:
2485         add_reg_info(
2486             &tlv->hf_value, name, abbrev, FT_UINT8, BASE_HEX, blurb);
2487         break;
2488
2489     case WIMAXASNCP_TLV_BITFLAGS16:
2490         add_reg_info(
2491             &tlv->hf_value, name, abbrev, FT_UINT16, BASE_HEX, blurb);
2492         break;
2493
2494     case WIMAXASNCP_TLV_BITFLAGS32:
2495         add_reg_info(
2496             &tlv->hf_value, name, abbrev, FT_UINT32, BASE_HEX, blurb);
2497         break;
2498
2499     case WIMAXASNCP_TLV_ID:
2500         g_free((gpointer*)name);
2501         g_free((gpointer*)abbrev);
2502
2503         name = "IPv4 Address";
2504
2505         abbrev = alnumerize(
2506             g_strdup_printf("wimaxasncp.tlv.%s.ipv4_value", tlv->name));
2507
2508         add_reg_info(
2509             &tlv->hf_ipv4, name, abbrev, FT_IPv4, BASE_NONE, blurb);
2510
2511         name = "IPv6 Address";
2512
2513         abbrev = alnumerize(
2514             g_strdup_printf("wimaxasncp.tlv.%s.ipv6_value", tlv->name));
2515
2516         add_reg_info(
2517             &tlv->hf_ipv6, name, abbrev, FT_IPv6, BASE_NONE, blurb);
2518
2519         name = "BS ID";
2520
2521         abbrev = alnumerize(
2522             g_strdup_printf("wimaxasncp.tlv.%s.bsid_value", tlv->name));
2523
2524         add_reg_info(
2525             &tlv->hf_bsid, name, abbrev, FT_ETHER, BASE_NONE, blurb);
2526
2527         break;
2528
2529     case WIMAXASNCP_TLV_HEX8:
2530         add_reg_info(
2531             &tlv->hf_value, name, abbrev, FT_UINT8, BASE_HEX, blurb);
2532         break;
2533
2534     case WIMAXASNCP_TLV_HEX16:
2535         add_reg_info(
2536             &tlv->hf_value, name, abbrev, FT_UINT16, BASE_HEX, blurb);
2537         break;
2538
2539     case WIMAXASNCP_TLV_HEX32:
2540         add_reg_info(
2541             &tlv->hf_value, name, abbrev, FT_UINT32, BASE_HEX, blurb);
2542         break;
2543
2544     case WIMAXASNCP_TLV_DEC8:
2545         add_reg_info(
2546             &tlv->hf_value, name, abbrev, FT_UINT8, BASE_DEC, blurb);
2547         break;
2548
2549     case WIMAXASNCP_TLV_DEC16:
2550         add_reg_info(
2551             &tlv->hf_value, name, abbrev, FT_UINT16, BASE_DEC, blurb);
2552         break;
2553
2554     case WIMAXASNCP_TLV_DEC32:
2555         add_reg_info(
2556             &tlv->hf_value, name, abbrev, FT_UINT32, BASE_DEC, blurb);
2557         break;
2558
2559     case WIMAXASNCP_TLV_IP_ADDRESS:
2560         g_free((gpointer*)name);
2561         g_free((gpointer*)abbrev);
2562
2563         name = "IPv4 Address";
2564
2565         abbrev = alnumerize(
2566             g_strdup_printf("wimaxasncp.tlv.%s.ipv4_value", tlv->name));
2567
2568         add_reg_info(
2569             &tlv->hf_ipv4, name, abbrev, FT_IPv4, BASE_NONE, blurb);
2570
2571         name = "IPv6 Address";
2572
2573         abbrev = alnumerize(
2574             g_strdup_printf("wimaxasncp.tlv.%s.ipv6_value", tlv->name));
2575
2576         add_reg_info(
2577             &tlv->hf_ipv6, name, abbrev, FT_IPv6, BASE_NONE, blurb);
2578
2579         break;
2580
2581     case WIMAXASNCP_TLV_IPV4_ADDRESS:
2582         add_reg_info(
2583             &tlv->hf_value, name, abbrev, FT_IPv4, BASE_NONE, blurb);
2584         break;
2585
2586     case WIMAXASNCP_TLV_PROTOCOL_LIST:
2587         add_reg_info(
2588             &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE, blurb);
2589
2590         blurb = g_strdup_printf("value component for type=%u", tlv->type);
2591
2592         name = "Protocol";
2593         
2594         abbrev = alnumerize(
2595             g_strdup_printf("wimaxasncp.tlv.%s.value.protocol", tlv->name));
2596
2597         add_reg_info(
2598             &tlv->hf_protocol, name, abbrev, FT_UINT16, BASE_DEC, blurb);
2599
2600         break;
2601
2602     case WIMAXASNCP_TLV_PORT_RANGE_LIST:
2603         add_reg_info(
2604             &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE, blurb);
2605
2606         blurb = g_strdup_printf("value component for type=%u", tlv->type);
2607
2608         name = "Port Low";
2609
2610         abbrev = alnumerize(
2611             g_strdup_printf("wimaxasncp.tlv.%s.value.port_low", tlv->name));
2612
2613         add_reg_info(
2614             &tlv->hf_port_low, name, abbrev, FT_UINT16, BASE_DEC, blurb);
2615
2616         name = "Port High";
2617
2618         abbrev = alnumerize(
2619             g_strdup_printf("wimaxasncp.tlv.%s.value.port_high", tlv->name));
2620
2621         add_reg_info(
2622             &tlv->hf_port_high, name, abbrev, FT_UINT16, BASE_DEC, blurb);
2623
2624         break;
2625
2626     case WIMAXASNCP_TLV_IP_ADDRESS_MASK_LIST:
2627         add_reg_info(
2628             &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE, blurb);
2629
2630         blurb = g_strdup_printf("value component for type=%u", tlv->type);
2631
2632         name = "IPv4 Address";
2633
2634         abbrev = alnumerize(
2635             g_strdup_printf("wimaxasncp.tlv.%s.value.ipv4", tlv->name));
2636
2637         add_reg_info(
2638             &tlv->hf_ipv4, name, abbrev, FT_IPv4, BASE_NONE, blurb);
2639
2640         name = "IPv4 Mask";
2641
2642         abbrev = alnumerize(
2643             g_strdup_printf("wimaxasncp.tlv.%s.value.ipv4_mask", tlv->name));
2644
2645         add_reg_info(
2646             &tlv->hf_ipv4_mask, name, abbrev, FT_IPv4, BASE_NONE, blurb);
2647
2648         name = "IPv6 Address";
2649
2650         abbrev = alnumerize(
2651             g_strdup_printf("wimaxasncp.tlv.%s.value.ipv6", tlv->name));
2652
2653         add_reg_info(
2654             &tlv->hf_ipv6, name, abbrev, FT_IPv6, BASE_NONE, blurb);
2655
2656         name = "IPv6 Mask";
2657
2658         abbrev = alnumerize(
2659             g_strdup_printf("wimaxasncp.tlv.%s.value.ipv6_mask", tlv->name));
2660
2661         add_reg_info(
2662             &tlv->hf_ipv6_mask, name, abbrev, FT_IPv6, BASE_NONE, blurb);
2663
2664         break;
2665
2666     case WIMAXASNCP_TLV_VENDOR_SPECIFIC:
2667         add_reg_info(
2668             &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE, blurb);
2669
2670         blurb = g_strdup_printf("value component for type=%u", tlv->type);
2671
2672         name = "Vendor ID";
2673
2674         abbrev = alnumerize(
2675             g_strdup_printf("wimaxasncp.tlv.%s.value.vendor_id", tlv->name));
2676
2677         add_reg_info(
2678             &tlv->hf_vendor_id, name, abbrev, FT_UINT24, BASE_DEC, blurb);
2679
2680         name = "Rest of Info";
2681
2682         abbrev = alnumerize(
2683             g_strdup_printf(
2684                 "wimaxasncp.tlv.%s.value.vendor_rest_of_info", tlv->name));
2685
2686         add_reg_info(
2687             &tlv->hf_vendor_rest_of_info, name, abbrev, FT_BYTES, BASE_NONE,
2688             blurb);
2689
2690         break;
2691
2692     case WIMAXASNCP_TLV_EAP:
2693         blurb = g_strdup_printf("EAP payload embedded in %s", name);
2694
2695         add_reg_info(
2696             &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE, blurb);
2697         break;
2698
2699
2700     default:
2701         add_reg_info(
2702             &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE, blurb);
2703
2704         if (debug_enabled)
2705         {
2706             g_print(
2707                 "fix-me: unknown decoder: %d\n", tlv->decoder);
2708         }
2709
2710         break;
2711     }
2712 }
2713
2714 /* ========================================================================= */
2715 /* Register the protocol fields and subtrees with Wireshark */
2716 static void
2717 register_wimaxasncp_fields(const char* unused _U_)
2718 {
2719     gboolean debug_parser;
2720     gboolean dump_dict;
2721     gchar *dir;
2722     gchar* dict_error;
2723
2724     /* ------------------------------------------------------------------------
2725      * List of header fields
2726      * ------------------------------------------------------------------------
2727      */
2728
2729     static hf_register_info hf_base[] = {
2730             {
2731                 &hf_wimaxasncp_version,      /* ID */
2732                 {
2733                     "Version",               /* FIELDNAME */
2734                     "wimaxasncp.version",    /* PROTOABBREV.FIELDABBRE */
2735                     FT_UINT8,                /* FIELDTYPE */
2736                     BASE_DEC,                /* FIELDBASE */
2737                     NULL,                    /* FIELDCONVERT */
2738                     0x0,                     /* BITMASK */
2739                     NULL,                      /* FIELDDESCR */
2740                     HFILL                    /* HFILL */
2741                 }
2742             },
2743             {
2744                 &hf_wimaxasncp_flags,
2745                 {
2746                     "Flags",
2747                     "wimaxasncp.flags",
2748                     FT_UINT8,
2749                     BASE_HEX,
2750                     NULL,
2751                     0xff,
2752                     NULL,
2753                     HFILL
2754                 }
2755             },
2756             {
2757                 &hf_wimaxasncp_function_type,
2758                 {
2759                     "Function Type",
2760                     "wimaxasncp.function_type",
2761                     FT_UINT8,
2762                     BASE_DEC,
2763                     VALS(wimaxasncp_function_type_vals),
2764                     0x0,
2765                     NULL,
2766                     HFILL
2767                 }
2768             },
2769             {
2770                 &hf_wimaxasncp_op_id,
2771                 {
2772                     "OP ID",
2773                     "wimaxasncp.opid",
2774                     FT_UINT8,
2775                     BASE_HEX,
2776                     VALS(wimaxasncp_op_id_vals),
2777                     0xE0,
2778                     NULL,
2779                     HFILL
2780                 }
2781             },
2782             {
2783                 &hf_wimaxasncp_message_type,
2784                 {
2785                     "Message Type",
2786                     "wimaxasncp.message_type",
2787                     FT_UINT8,
2788                     BASE_HEX,
2789                     NULL,
2790                     0x1F,
2791                     NULL,
2792                     HFILL
2793                 }
2794             },
2795             {
2796                 &hf_wimaxasncp_qos_msg,
2797                 {
2798                     "Message Type",
2799                     "wimaxasncp.qos_msg",
2800                     FT_UINT8,
2801                     BASE_HEX,
2802                     VALS(wimaxasncp_qos_msg_vals),
2803                     0x1F,
2804                     NULL,
2805                     HFILL
2806                 }
2807             },
2808             {
2809                 &hf_wimaxasncp_ho_control_msg,
2810                 {
2811                     "Message Type",
2812                     "wimaxasncp.ho_control_msg",
2813                     FT_UINT8,
2814                     BASE_HEX,
2815                     VALS(wimaxasncp_ho_control_msg_vals),
2816                     0x1F,
2817                     NULL,
2818                     HFILL
2819                 }
2820             },
2821             {
2822                 &hf_wimaxasncp_data_path_control_msg,
2823                 {
2824                     "Message Type",
2825                     "wimaxasncp.data_path_control_msg",
2826                     FT_UINT8,
2827                     BASE_HEX,
2828                     VALS(wimaxasncp_data_path_control_msg_vals),
2829                     0x1F,
2830                     NULL,
2831                     HFILL
2832                 }
2833             },
2834             {
2835                 &hf_wimaxasncp_context_delivery_msg,
2836                 {
2837                     "Message Type",
2838                     "wimaxasncp.context_delivery_msg",
2839                     FT_UINT8,
2840                     BASE_HEX,
2841                     VALS(wimaxasncp_context_delivery_msg_vals),
2842                     0x1F,
2843                     NULL,
2844                     HFILL
2845                 }
2846             },
2847             {
2848                 &hf_wimaxasncp_r3_mobility_msg,
2849                 {
2850                     "Message Type",
2851                     "wimaxasncp.r3_mobility_msg",
2852                     FT_UINT8,
2853                     BASE_HEX,
2854                     VALS(wimaxasncp_r3_mobility_msg_vals),
2855                     0x1F,
2856                     NULL,
2857                     HFILL
2858                 }
2859             },
2860             {
2861                 &hf_wimaxasncp_paging_msg,
2862                 {
2863                     "Message Type",
2864                     "wimaxasncp.paging_msg",
2865                     FT_UINT8,
2866                     BASE_HEX,
2867                     VALS(wimaxasncp_paging_msg_vals),
2868                     0x1F,
2869                     NULL,
2870                     HFILL
2871                 }
2872             },
2873             {
2874                 &hf_wimaxasncp_rrm_msg,
2875                 {
2876                     "Message Type",
2877                     "wimaxasncp.rrm_msg",
2878                     FT_UINT8,
2879                     BASE_HEX,
2880                     VALS(wimaxasncp_rrm_msg_vals),
2881                     0x1F,
2882                     NULL,
2883                     HFILL
2884                 }
2885             },
2886             {
2887                 &hf_wimaxasncp_authentication_msg,
2888                 {
2889                     "Message Type",
2890                     "wimaxasncp.authentication_msg",
2891                     FT_UINT8,
2892                     BASE_HEX,
2893                     VALS(wimaxasncp_authentication_msg_vals),
2894                     0x1F,
2895                     NULL,
2896                     HFILL
2897                 }
2898             },
2899             {
2900                 &hf_wimaxasncp_ms_state_msg,
2901                 {
2902                     "Message Type",
2903                     "wimaxasncp.ms_state_msg",
2904                     FT_UINT8,
2905                     BASE_HEX,
2906                     VALS(wimaxasncp_ms_state_msg_vals),
2907                     0x1F,
2908                     NULL,
2909                     HFILL
2910                 }
2911             },
2912             {
2913                 &hf_wimaxasncp_reauthentication_msg,
2914                 {
2915                     "Message Type",
2916                     "wimaxasncp.reauthentication_msg",
2917                     FT_UINT8,
2918                     BASE_HEX,
2919                     VALS(wimaxasncp_reauthentication_msg_vals),
2920                     0x1F,
2921                     NULL,
2922                     HFILL
2923                 }
2924             },
2925             {
2926                 &hf_wimaxasncp_session_msg,
2927                 {
2928                     "Message Type",
2929                     "wimaxasncp.session_msg",
2930                     FT_UINT8,
2931                     BASE_HEX,
2932                     VALS(wimaxasncp_session_msg_vals),
2933                     0x1F,
2934                     NULL,
2935                     HFILL
2936                 }
2937             },
2938             {
2939                 &hf_wimaxasncp_length,
2940                 {
2941                     "Length",
2942                     "wimaxasncp.length",
2943                     FT_UINT16,
2944                     BASE_DEC,
2945                     NULL,
2946                     0x0,
2947                     NULL,
2948                     HFILL
2949                 }
2950             },
2951             {
2952                 &hf_wimaxasncp_msid,
2953                 {
2954                     "MSID",
2955                     "wimaxasncp.msid",
2956                     FT_ETHER,
2957                     BASE_NONE,
2958                     NULL,
2959                     0x0,
2960                     NULL,
2961                     HFILL
2962                 }
2963             },
2964             {
2965                 &hf_wimaxasncp_reserved1,
2966                 {
2967                     "Reserved",
2968                     "wimaxasncp.reserved1",
2969                     FT_UINT32,
2970                     BASE_HEX,
2971                     NULL,
2972                     0x0,
2973                     NULL,
2974                     HFILL
2975                 }
2976             },
2977             {
2978                 &hf_wimaxasncp_transaction_id,
2979                 {
2980                     "Transaction ID",
2981                     "wimaxasncp.transaction_id",
2982                     FT_UINT16,
2983                     BASE_HEX,
2984                     NULL,
2985                     0x0,
2986                     NULL,
2987                     HFILL
2988                 }
2989             },
2990             {
2991                 &hf_wimaxasncp_reserved2,
2992                 {
2993                     "Reserved",
2994                     "wimaxasncp.reserved2",
2995                     FT_UINT16,
2996                     BASE_HEX,
2997                     NULL,
2998                     0x0,
2999                     NULL,
3000                     HFILL
3001                 }
3002             },
3003             {
3004                 &hf_wimaxasncp_tlv,
3005                 {
3006                     "TLV",
3007                     "wimaxasncp.tlv",
3008                     FT_BYTES,
3009                     BASE_NONE,
3010                     NULL,
3011                     0x0,
3012                     NULL,
3013                     HFILL
3014                 }
3015             },
3016             {
3017                 &hf_wimaxasncp_tlv_type,
3018                 {
3019                     "Type",
3020                     "wimaxasncp.tlv.type",
3021                     FT_UINT16,
3022                     BASE_DEC,
3023                     NULL,
3024                     0x0,
3025                     NULL,
3026                     HFILL
3027                 }
3028             },
3029             {
3030                 &hf_wimaxasncp_tlv_length,
3031                 {
3032                     "Length",
3033                     "wimaxasncp.tlv.length",
3034                     FT_UINT16,
3035                     BASE_DEC,
3036                     NULL,
3037                     0x0,
3038                     NULL,
3039                     HFILL
3040                 }
3041             },
3042             {
3043                 &hf_wimaxasncp_tlv_value_bytes,
3044                 {
3045                     "Value",
3046                     "wimaxasncp.tlv_value_bytes",
3047                     FT_BYTES,
3048                     BASE_NONE,
3049                     NULL,
3050                     0x0,
3051                     NULL,
3052                     HFILL
3053                 }
3054             },
3055             {
3056                 &hf_wimaxasncp_tlv_value_bitflags8,
3057                 {
3058                     "Value",
3059                     "wimaxasncp.tlv_value_bitflags8",
3060                     FT_UINT8,
3061                     BASE_HEX,
3062                     NULL,
3063                     0xff,
3064                     NULL,
3065                     HFILL
3066                 }
3067             },          
3068             {
3069                 &hf_wimaxasncp_tlv_value_bitflags16,
3070                 {
3071                     "Value",
3072                     "wimaxasncp.tlv_value_bitflags16",
3073                     FT_UINT16,
3074                     BASE_HEX,
3075                     NULL,
3076                     0xffff,
3077                     NULL,
3078                     HFILL
3079                 }
3080             },
3081             {
3082                 &hf_wimaxasncp_tlv_value_bitflags32,
3083                 {
3084                     "Value",
3085                     "wimaxasncp.tlv_value_bitflags32",
3086                     FT_UINT32,
3087                     BASE_HEX,
3088                     NULL,
3089                     0xffffffff,
3090                     NULL,
3091                     HFILL
3092                 }
3093             },
3094             {
3095                 &hf_wimaxasncp_tlv_value_protocol,
3096                 {
3097                     "Value",
3098                     "wimaxasncp.tlv_value_protocol",
3099                     FT_UINT16,
3100                     BASE_DEC,
3101                     NULL,
3102                     0x0,
3103                     NULL,
3104                     HFILL
3105                 }
3106             },
3107             {
3108                 &hf_wimaxasncp_tlv_value_vendor_id,
3109                 {
3110                     "Vendor ID",
3111                     "wimaxasncp.tlv_value_vendor_id",
3112                     FT_UINT24,
3113                     BASE_DEC,
3114                     NULL,
3115                     0x0,
3116                     NULL,
3117                     HFILL
3118                 }
3119             }
3120         };
3121
3122     /* ------------------------------------------------------------------------
3123      * Protocol subtree array
3124      * ------------------------------------------------------------------------
3125      */
3126
3127     static gint *ett_base[] = {
3128             &ett_wimaxasncp,
3129             &ett_wimaxasncp_flags,
3130             &ett_wimaxasncp_tlv,
3131             &ett_wimaxasncp_tlv_value_bitflags8,            
3132             &ett_wimaxasncp_tlv_value_bitflags16,
3133             &ett_wimaxasncp_tlv_value_bitflags32,
3134             &ett_wimaxasncp_tlv_protocol_list,
3135             &ett_wimaxasncp_tlv_port_range_list,
3136             &ett_wimaxasncp_tlv_ip_address_mask_list,
3137             &ett_wimaxasncp_tlv_ip_address_mask,
3138             &ett_wimaxasncp_tlv_eap,
3139             &ett_wimaxasncp_tlv_vendor_specific_information_field
3140     };
3141
3142     /* ------------------------------------------------------------------------
3143      * load the XML dictionary
3144      * ------------------------------------------------------------------------
3145      */
3146
3147     debug_parser = getenv("WIRESHARK_DEBUG_WIMAXASNCP_DICT_PARSER") != NULL;
3148     dump_dict    = getenv("WIRESHARK_DUMP_WIMAXASNCP_DICT") != NULL;
3149
3150     dir = ep_strdup_printf(
3151         "%s" G_DIR_SEPARATOR_S "wimaxasncp",
3152         get_datafile_dir());
3153
3154     wimaxasncp_dict = 
3155         wimaxasncp_dict_scan(dir, "dictionary.xml", debug_parser, &dict_error);
3156
3157     if (dict_error)
3158     {
3159         report_failure("wimaxasncp - %s", dict_error);
3160         g_free(dict_error);
3161     }
3162
3163     if (wimaxasncp_dict && dump_dict)
3164     {
3165         wimaxasncp_dict_print(stdout, wimaxasncp_dict);
3166     }
3167
3168     /* ------------------------------------------------------------------------
3169      * build the hf and ett dictionary entries
3170      * ------------------------------------------------------------------------
3171      */
3172
3173     wimaxasncp_build_dict.hf = 
3174         g_array_new(FALSE, TRUE, sizeof(hf_register_info));
3175
3176     g_array_append_vals(
3177         wimaxasncp_build_dict.hf, hf_base, array_length(hf_base));
3178
3179     wimaxasncp_build_dict.ett = 
3180         g_array_new(FALSE, TRUE, sizeof(gint*));
3181
3182     g_array_append_vals(
3183         wimaxasncp_build_dict.ett, ett_base, array_length(ett_base));
3184
3185     if (wimaxasncp_dict)
3186     {
3187         wimaxasncp_dict_tlv_t *tlv;
3188
3189         /* For each TLV found in XML file */
3190         for (tlv = wimaxasncp_dict->tlvs; tlv; tlv = tlv->next)
3191         {
3192             if (tlv->enums)
3193             {
3194                 /* Create array for enums */
3195                 wimaxasncp_dict_enum_t *e;
3196                 GArray* array = g_array_new(TRUE, TRUE, sizeof(value_string));
3197
3198                 /* Copy each entry into value_string array */
3199                 for (e = tlv->enums; e; e = e->next)
3200                 {
3201                     value_string item = { e->code, e->name };
3202                     g_array_append_val(array, item);
3203                 }
3204
3205                 /* Set enums to use with this TLV */
3206                 tlv->enum_vs = (value_string*)array->data;
3207             }
3208
3209             add_tlv_reg_info(tlv);
3210         }
3211     }
3212
3213     /* add an entry for unknown TLVs */
3214     add_tlv_reg_info(&wimaxasncp_tlv_not_found);
3215
3216     /* The following debug will only be printed if the debug_enabled variable
3217      * is set programmatically.  Setting the value via preferences will not
3218      * work as it will be set too late to affect this code path.
3219      */
3220     if (debug_enabled)
3221     {
3222         if (wimaxasncp_dict)
3223         {
3224             wimaxasncp_dict_tlv_t *tlv;
3225
3226             for (tlv = wimaxasncp_dict->tlvs; tlv; tlv = tlv->next)
3227             {
3228                 printf(
3229                     "%s\n"
3230                     "  type                   = %d\n"
3231                     "  description            = %s\n"
3232                     "  decoder                = %s\n"
3233                     "  hf_root                = %d\n"
3234                     "  hf_value               = %d\n"
3235                     "  hf_ipv4                = %d\n"
3236                     "  hf_ipv6                = %d\n"
3237                     "  hf_bsid                = %d\n"
3238                     "  hf_protocol            = %d\n"
3239                     "  hf_port_low            = %d\n"
3240                     "  hf_port_high           = %d\n"
3241                     "  hf_ipv4_mask           = %d\n"
3242                     "  hf_ipv6_mask           = %d\n"
3243                     "  hf_vendor_id           = %d\n"
3244                     "  hf_vendor_rest_of_info = %d\n",
3245                     tlv->name,
3246                     tlv->type,
3247                     tlv->description,
3248                     val_to_str(
3249                         tlv->decoder, wimaxasncp_decode_type_vals, "Unknown"),
3250                     tlv->hf_root,
3251                     tlv->hf_value,
3252                     tlv->hf_ipv4,
3253                     tlv->hf_ipv6,
3254                     tlv->hf_bsid,
3255                     tlv->hf_protocol,
3256                     tlv->hf_port_low,
3257                     tlv->hf_port_high,
3258                     tlv->hf_ipv4_mask,
3259                     tlv->hf_ipv6_mask,
3260                     tlv->hf_vendor_id,
3261                     tlv->hf_vendor_rest_of_info);
3262             }
3263         }
3264     }
3265
3266         /* Required function calls to register the header fields and subtrees
3267          * used */
3268     proto_register_field_array(
3269         proto_wimaxasncp,
3270         (hf_register_info*)wimaxasncp_build_dict.hf->data, 
3271         wimaxasncp_build_dict.hf->len);
3272
3273     proto_register_subtree_array(
3274         (gint**)wimaxasncp_build_dict.ett->data,
3275         wimaxasncp_build_dict.ett->len);
3276 }
3277
3278
3279
3280
3281 /* ========================================================================= */
3282 /* Register the protocol with Wireshark */
3283
3284 /* this format is require because a script is used to build the C function
3285    that calls all the protocol registration.
3286 */
3287
3288 void
3289 proto_register_wimaxasncp(void)
3290 {
3291     module_t *wimaxasncp_module;
3292
3293     /* ------------------------------------------------------------------------
3294      * complete registration
3295      * ------------------------------------------------------------------------
3296      */
3297
3298         /* Register the protocol name and description */
3299     proto_wimaxasncp = proto_register_protocol(
3300             "WiMAX ASN Control Plane Protocol",
3301             "WiMAX ASN CP",
3302             "wimaxasncp");
3303
3304
3305         /* Register this dissector by name */
3306     new_register_dissector("wimaxasncp", dissect_wimaxasncp, proto_wimaxasncp);
3307
3308         /* Register preferences module (See Section 2.6 for more on
3309          * preferences) */
3310     wimaxasncp_module = prefs_register_protocol(
3311             proto_wimaxasncp,
3312             proto_reg_handoff_wimaxasncp);
3313
3314         /* Register preferences */
3315     prefs_register_bool_preference(
3316             wimaxasncp_module,
3317             "show_transaction_id_d_bit",
3318             "Show transaction ID direction bit",
3319             "Show transaction ID direction bit separately from the rest of "
3320             "the transaction ID field.",
3321             &show_transaction_id_d_bit);
3322
3323     prefs_register_bool_preference(
3324             wimaxasncp_module,
3325             "debug_enabled",
3326             "Enable debug output",
3327             "Print debug output to the console.",
3328             &debug_enabled);
3329
3330     prefs_register_uint_preference(
3331         wimaxasncp_module, 
3332         "udp.wimax_port",
3333         "UDP Port for WiMAX ASN Control Plane Protocol",
3334         "Set UDP port for WiMAX ASN Control Plane Protocol",
3335         10, &global_wimaxasncp_udp_port);
3336
3337     proto_register_prefix("wimaxasncp", register_wimaxasncp_fields);
3338 }
3339
3340 /* ========================================================================= */
3341 /* If this dissector uses sub-dissector registration add a registration
3342    routine.  This exact format is required because a script is used to find
3343    these routines and create the code that calls these routines.
3344
3345    This function is also called by preferences whenever "Apply" is pressed
3346    (see prefs_register_protocol above) so it should accommodate being called
3347    more than once.
3348 */
3349 void
3350 proto_reg_handoff_wimaxasncp(void)
3351 {
3352     static gboolean inited = FALSE;
3353     static dissector_handle_t wimaxasncp_handle;
3354     static int currentPort = -1;
3355
3356     if (!inited)
3357     {
3358
3359         /*  Use new_create_dissector_handle() to indicate that
3360          *  dissect_wimaxasncp() returns the number of bytes it dissected (or
3361          *  0 if it thinks the packet does not belong to WiMAX ASN Control
3362          *  Plane).
3363          */
3364         wimaxasncp_handle = new_create_dissector_handle(
3365              dissect_wimaxasncp,
3366              proto_wimaxasncp);
3367
3368
3369         inited = TRUE;
3370     }
3371
3372     if (currentPort != -1)
3373     {
3374         /* Remove any previous registered port */
3375         dissector_delete("udp.port", currentPort, wimaxasncp_handle);
3376     }
3377
3378     /* Add the new one from preferences */
3379     currentPort = global_wimaxasncp_udp_port;
3380     dissector_add("udp.port", currentPort, wimaxasncp_handle);
3381
3382     /* Find the EAP dissector */
3383     eap_handle = find_dissector("eap");
3384 }
3385