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