2 * WiMax Protocol and dissectors
4 * Copyright (c) 2007 by Intel Corporation.
6 * Author: Lu Pan <lu.pan@intel.com>
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1999 Gerald Combs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
35 #include <epan/packet.h>
36 #include <epan/prefs.h>
37 #include <epan/address.h>
38 #include <epan/wmem/wmem.h>
39 #include "wimax_tlv.h"
40 #include "wimax_bits.h"
42 /* Global variables */
43 gint proto_wimax
= -1;
44 gint8 arq_enabled
= 0;
45 gint scheduling_service_type
= 0;
46 gint mac_sdu_length
= 49; /* default SDU size is 49 bytes (11.13.16) */
47 extern guint global_cid_max_basic
;
48 extern gboolean include_cor2_changes
;
50 address bs_address
= {AT_NONE
, -1, 0, NULL
};
53 static int hf_tlv_type
= -1;
54 static int hf_tlv_length
= -1;
55 static int hf_tlv_length_size
= -1;
57 #define MAX_NUM_TLVS 256
58 /* Global TLV array to retrieve unique subtree identifiers */
59 static gint ett_tlv
[MAX_NUM_TLVS
];
61 static const gchar tlv_val_1byte
[] = "TLV value: %s (0x%02x)";
62 static const gchar tlv_val_2byte
[] = "TLV value: %s (0x%04x)";
63 static const gchar tlv_val_3byte
[] = "TLV value: %s (0x%06x)";
64 static const gchar tlv_val_4byte
[] = "TLV value: %s (0x%08x)";
65 static const gchar tlv_val_5byte
[] = "TLV value: %s (0x%08x...)";
67 /*************************************************************/
68 /* add_tlv_subtree() */
69 /* Return a pointer to a proto_item of a TLV value that */
70 /* already contains the type and length of the given TLV. */
71 /* tree - the parent to which the new tree will */
73 /* hfindex - the index of the item to be attached */
74 /* tvb - a pointer to the packet data */
75 /* start - offset within the packet */
76 /* length - length of this item */
77 /* encoding - encoding for proto_tree_add_item */
79 /* pointer to a proto_item */
80 /*************************************************************/
81 proto_item
*add_tlv_subtree(tlv_info_t
*self
, proto_tree
*tree
, int hfindex
, tvbuff_t
*tvb
, gint start
, const guint encoding
)
83 header_field_info
*hf
;
86 gint tlv_value_length
, tlv_val_offset
;
87 guint8 size_of_tlv_length_field
;
90 /* Make sure we're dealing with a valid TLV here */
91 if (get_tlv_type(self
) < 0)
94 /* Retrieve the necessary TLV information */
95 tlv_val_offset
= get_tlv_value_offset(self
);
96 tlv_value_length
= get_tlv_length(self
);
97 size_of_tlv_length_field
= get_tlv_size_of_length(self
);
98 tlv_type
= get_tlv_type(self
);
100 hf
= proto_registrar_get_nth(hfindex
);
102 tlv_item
= proto_tree_add_text(tree
, tvb
, start
, tlv_value_length
+tlv_val_offset
, "%s", hf
->name
);
103 tlv_tree
= proto_item_add_subtree(tlv_item
, ett_tlv
[tlv_type
]);
105 proto_tree_add_uint(tlv_tree
, hf_tlv_type
, tvb
, start
, 1, tlv_type
);
106 if (size_of_tlv_length_field
> 0) /* It is */
108 /* display the length of the length field TLV */
109 proto_tree_add_uint(tlv_tree
, hf_tlv_length_size
, tvb
, start
+1, 1, size_of_tlv_length_field
);
110 /* display the TLV length */
111 proto_tree_add_uint(tlv_tree
, hf_tlv_length
, tvb
, start
+2, size_of_tlv_length_field
, tlv_value_length
);
112 } else { /* It is not */
113 /* display the TLV length */
114 proto_tree_add_uint(tlv_tree
, hf_tlv_length
, tvb
, start
+1, 1, tlv_value_length
);
117 tlv_item
= proto_tree_add_item(tlv_tree
, hfindex
, tvb
, start
+tlv_val_offset
, tlv_value_length
, encoding
);
119 /* Return a pointer to the value level */
123 /*************************************************************/
124 /* add_tlv_subtree_no_item() */
125 /* Return a pointer to a proto_tree of a TLV value that */
126 /* already contains the type and length, but no value */
127 /* tree - the parent to which the new tree will */
129 /* hfindex - the index of the item to be attached */
130 /* tvb - a pointer to the packet data */
131 /* start - offset within the packet */
132 /* length - length of this item */
134 /* pointer to a proto_tree (to then add value) */
135 /*************************************************************/
136 proto_tree
*add_tlv_subtree_no_item(tlv_info_t
*self
, proto_tree
*tree
, int hfindex
, tvbuff_t
*tvb
, gint start
)
138 header_field_info
*hf
;
139 proto_tree
*tlv_tree
;
140 proto_item
*tlv_item
;
141 gint tlv_value_length
, tlv_val_offset
;
142 guint8 size_of_tlv_length_field
;
145 /* Make sure we're dealing with a valid TLV here */
146 if (get_tlv_type(self
) < 0)
149 /* Retrieve the necessary TLV information */
150 tlv_val_offset
= get_tlv_value_offset(self
);
151 tlv_value_length
= get_tlv_length(self
);
152 size_of_tlv_length_field
= get_tlv_size_of_length(self
);
153 tlv_type
= get_tlv_type(self
);
155 hf
= proto_registrar_get_nth(hfindex
);
157 tlv_item
= proto_tree_add_text(tree
, tvb
, start
, tlv_value_length
+tlv_val_offset
, "%s", hf
->name
);
158 tlv_tree
= proto_item_add_subtree(tlv_item
, ett_tlv
[tlv_type
]);
160 proto_tree_add_uint(tlv_tree
, hf_tlv_type
, tvb
, start
, 1, tlv_type
);
161 if (size_of_tlv_length_field
> 0) /* It is */
163 /* display the length of the length field TLV */
164 proto_tree_add_uint(tlv_tree
, hf_tlv_length_size
, tvb
, start
+1, 1, size_of_tlv_length_field
);
165 /* display the TLV length */
166 proto_tree_add_uint(tlv_tree
, hf_tlv_length
, tvb
, start
+2, size_of_tlv_length_field
, tlv_value_length
);
167 } else { /* It is not */
168 /* display the TLV length */
169 proto_tree_add_uint(tlv_tree
, hf_tlv_length
, tvb
, start
+1, 1, tlv_value_length
);
172 /* Return a pointer to the tree level (to manually add item) */
176 /*************************************************************/
177 /* add_protocol_subtree() */
178 /* Return a pointer to a proto_tree that already contains */
179 /* the type and length of a given TLV. */
180 /* tree - the parent to which the new tree will */
182 /* hfindex - the index of the item to be attached */
183 /* tvb - a pointer to the packet data */
184 /* start - offset within the packet */
185 /* length - length of this item */
186 /* format - printf style formatting string */
187 /* ... - arguments to format */
189 /* pointer to a proto_tree */
190 /*************************************************************/
191 proto_tree
*add_protocol_subtree(tlv_info_t
*self
, gint idx
, proto_tree
*tree
, int hfindex
, tvbuff_t
*tvb
, gint start
, gint length _U_
, const char *label
)
193 /* Declare local variables */
194 proto_tree
*tlv_tree
;
195 proto_item
*tlv_item
;
196 gint tlv_value_length
, tlv_val_offset
;
197 guint8 size_of_tlv_length_field
;
200 const gchar
*hex_fmt
;
202 /* Make sure we're dealing with a valid TLV here */
203 if (get_tlv_type(self
) < 0)
206 /* Retrieve the necessary TLV information */
207 tlv_val_offset
= get_tlv_value_offset(self
);
208 tlv_value_length
= get_tlv_length(self
);
209 size_of_tlv_length_field
= get_tlv_size_of_length(self
);
210 tlv_type
= get_tlv_type(self
);
212 /* display the TLV name and display the value in hex. Highlight type, length, and value. */
213 tlv_item
= proto_tree_add_protocol_format(tree
, hfindex
, tvb
, start
, tlv_value_length
+tlv_val_offset
, "%s (%u byte(s))", label
, tlv_value_length
);
214 tlv_tree
= proto_item_add_subtree(tlv_item
, ett_tlv
[tlv_type
]);
216 proto_tree_add_uint(tlv_tree
, hf_tlv_type
, tvb
, start
, 1, tlv_type
);
217 if (size_of_tlv_length_field
> 0) /* It is */
219 /* display the length of the length field TLV */
220 proto_tree_add_uint(tlv_tree
, hf_tlv_length_size
, tvb
, start
+1, 1, size_of_tlv_length_field
);
221 /* display the TLV length */
222 proto_tree_add_uint(tlv_tree
, hf_tlv_length
, tvb
, start
+2, size_of_tlv_length_field
, tlv_value_length
);
223 } else { /* It is not */
224 /* display the TLV length */
225 proto_tree_add_uint(tlv_tree
, hf_tlv_length
, tvb
, start
+1, 1, tlv_value_length
);
228 /* display the TLV value and make it a subtree */
229 switch (tlv_value_length
)
232 tlv_value
= tvb_get_guint8(tvb
, start
+tlv_val_offset
);
233 hex_fmt
= tlv_val_1byte
;
236 tlv_value
= tvb_get_ntohs(tvb
, start
+tlv_val_offset
);
237 hex_fmt
= tlv_val_2byte
;
240 tlv_value
= tvb_get_ntoh24(tvb
, start
+tlv_val_offset
);
241 hex_fmt
= tlv_val_3byte
;
244 tlv_value
= tvb_get_ntohl(tvb
, start
+tlv_val_offset
);
245 hex_fmt
= tlv_val_4byte
;
248 tlv_value
= tvb_get_ntohl(tvb
, start
+tlv_val_offset
);
249 hex_fmt
= tlv_val_5byte
;
252 /* Show "TLV value: " */
253 tlv_item
= proto_tree_add_text(tlv_tree
, tvb
, start
+tlv_val_offset
, tlv_value_length
, hex_fmt
, label
, tlv_value
);
254 tlv_tree
= proto_item_add_subtree(tlv_item
, idx
);
256 /* Return a pointer to the value level */
262 /* WiMax protocol dissector */
263 static void dissect_wimax(tvbuff_t
*tvb _U_
, packet_info
*pinfo
, proto_tree
*tree _U_
)
265 /* display the WiMax protocol name */
266 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "WiMax");
267 /* Clear out stuff in the info column */
268 col_clear(pinfo
->cinfo
, COL_INFO
);
271 gboolean
is_down_link(packet_info
*pinfo
)
273 if (pinfo
->p2p_dir
== P2P_DIR_RECV
)
275 if (pinfo
->p2p_dir
== P2P_DIR_UNKNOWN
)
276 if(bs_address
.len
&& !CMP_ADDRESS(&bs_address
, &pinfo
->src
))
282 /* Register Wimax Protocol */
283 void proto_register_wimax(void)
286 module_t
*wimax_module
;
288 static hf_register_info hf
[] = {
289 { &hf_tlv_type
, { "TLV type", "wmx.tlv_type", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
290 { &hf_tlv_length
, { "TLV length", "wmx.tlv_length", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
291 { &hf_tlv_length_size
, { "Size of TLV length field", "wmx.tlv_length_size", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
294 gint
*ett_reg
[MAX_NUM_TLVS
];
296 /* Register the WiMax protocols here */
297 proto_wimax
= proto_register_protocol (
298 "WiMax Protocol", /* name */
299 "WiMax (wmx)", /* short name */
303 proto_register_field_array(proto_wimax
, hf
, array_length(hf
));
305 /* Register the ett TLV array to retrieve unique subtree identifiers */
306 for (i
= 0; i
< MAX_NUM_TLVS
; i
++)
309 ett_reg
[i
] = &ett_tlv
[i
];
312 proto_register_subtree_array(ett_reg
, array_length(ett_reg
));
314 /* Register the WiMax dissector */
315 register_dissector("wmx", dissect_wimax
, proto_wimax
);
317 wimax_module
= prefs_register_protocol(proto_wimax
, NULL
);
319 prefs_register_uint_preference(wimax_module
, "basic_cid_max",
321 "Set the maximum Basic CID"
322 " used in the Wimax decoder"
323 " (if other than the default of 320)."
324 " Note: The maximum Primary CID is"
325 " double the maximum Basic CID.",
326 10, &global_cid_max_basic
);
328 prefs_register_bool_preference(wimax_module
, "corrigendum_2_version",
329 "Corrigendum 2 Version",
330 "Set to TRUE to use the Corrigendum"
331 " 2 version of Wimax message decoding."
332 " Set to FALSE to use the 802.16e-2005"
334 &include_cor2_changes
);
335 prefs_register_obsolete_preference(wimax_module
, "wimax.basic_cid_max");
336 prefs_register_obsolete_preference(wimax_module
, "wimax.corrigendum_2_version");