Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-fp_mux.c
blobef44f584e3421a791e801f10ca51a0c2aed86df8
1 /* Routines for Huawei's FP Mux Header disassembly
2 * Protocol reference: EU Patent publication No. EP2053798
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
11 #include "config.h"
13 #include <epan/packet.h>
14 #include <epan/tfs.h>
15 #include <epan/conversation.h>
16 #include <epan/expert.h>
17 #include <epan/proto_data.h>
18 #include "packet-umts_fp.h"
19 #include "packet-umts_mac.h"
20 #include "packet-umts_rlc.h"
22 /* Externals */
23 extern int proto_fp;
24 extern int proto_umts_mac;
25 extern int proto_umts_rlc;
27 void proto_register_fp_mux(void);
28 void proto_reg_handoff_fp_mux(void);
30 static int proto_fp_mux;
31 static dissector_handle_t fp_mux_handle;
32 static heur_dissector_list_t heur_subdissector_list;
34 /* Constants */
35 #define MAX_PAYLOADS 64
37 /* Trees */
38 static int ett_fpmux;
40 /* Fields */
41 static int hf_fpmux_uid;
42 static int hf_fpmux_extension_flag;
43 static int hf_fpmux_length;
45 /* Expert Fields */
46 static expert_field ei_fpm_length_needlessly_extended;
47 static expert_field ei_fpm_too_many_payloads;
48 static expert_field ei_fpm_bad_length;
50 /* Preferences */
51 /* Place UID in proto tree */
52 static bool fp_mux_uid_in_tree = true;
53 /* Call heuristic FP dissectors on payload */
54 static bool call_fp_heur = true;
56 /* Enum Values */
57 static const true_false_string fpmux_extension_flag_vals = {
58 "Extension Present", "No Extension"
62 /* Per-packet info */
63 typedef struct fp_mux_info_t {
64 uint32_t srcport;
65 uint32_t destport;
66 fp_info* fpinfos[MAX_PAYLOADS];
67 umts_mac_info* macinfos[MAX_PAYLOADS];
68 rlc_info* rlcinfos[MAX_PAYLOADS];
69 } fp_mux_info_t;
71 static void dissect_payload(tvbuff_t *next_tvb, packet_info *pinfo, proto_tree *tree, struct fp_mux_info_t* fp_mux_info, uint16_t payload_index, uint16_t uid)
73 heur_dtbl_entry_t *hdtbl_entry;
74 bool conv_dissected; /* If the TVB was dissected using the conversation dissector*/
75 bool heur_dissected; /* If the TVB was dissected using a heuristic dissector*/
76 uint32_t current_destport,current_srcport;
78 /* Saving old ports */
79 current_destport = pinfo->destport;
80 current_srcport = pinfo->srcport;
82 /* Replacing ports with UID (ports are used by the FP dissector) */
83 pinfo->destport = uid;
84 pinfo->srcport = 0;
86 /* Adding previously created FP/MAC/RLC info */
87 p_add_proto_data(wmem_file_scope(), pinfo, proto_fp, 0, fp_mux_info->fpinfos[payload_index]);
88 p_add_proto_data(wmem_file_scope(), pinfo, proto_umts_mac, 0, fp_mux_info->macinfos[payload_index]);
89 p_add_proto_data(wmem_file_scope(), pinfo, proto_umts_rlc, 0, fp_mux_info->rlcinfos[payload_index]);
91 /* Trying a dissector assigned to the conversation (Usually from NBAP) */
92 conv_dissected = try_conversation_dissector(&pinfo->dst, &pinfo->src, CONVERSATION_UDP,
93 pinfo->destport, pinfo->srcport, next_tvb, pinfo, tree, NULL, 0);
94 if (!conv_dissected) {
95 /* No conversation dissector / TVB was rejected, try other options */
96 if(call_fp_heur) {
97 /* Trying heuristic dissector */
98 heur_dissected = dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree, &hdtbl_entry, NULL);
99 if(!heur_dissected) {
100 /* No heuristic dissector / TVB was rejected, show as data */
101 call_data_dissector(next_tvb,pinfo,tree);
104 else {
105 /* Trying heuristic dissectors disabled, show as data */
106 call_data_dissector(next_tvb,pinfo,tree);
110 /* Saving FP/MAC/RLC Info which the sub dissector might have attached */
111 fp_mux_info->fpinfos[payload_index] = (fp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp, 0);
112 fp_mux_info->macinfos[payload_index] = (umts_mac_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_umts_mac, 0);
113 fp_mux_info->rlcinfos[payload_index] = (rlc_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_umts_rlc, 0);
115 /* Removing FP/MAC/RLC info from the packet */
116 /* to allow other packets to be dissected correctly */
117 p_remove_proto_data(wmem_file_scope(), pinfo, proto_fp, 0);
118 p_remove_proto_data(wmem_file_scope(), pinfo, proto_umts_mac, 0);
119 p_remove_proto_data(wmem_file_scope(), pinfo, proto_umts_rlc, 0);
121 /* Setting a fence in the info column to aggregate all payloads' descriptions */
122 const char* info = col_get_text(pinfo->cinfo, COL_INFO);
123 if (info != NULL && *info != '\0') {
124 /* Only creating fence if the column's current text isn't NULL or an empty string */
125 col_append_str(pinfo->cinfo, COL_INFO, " ");
126 col_set_fence(pinfo->cinfo, COL_INFO);
129 /* Restoring ports */
130 pinfo->destport = current_destport;
131 pinfo->srcport = current_srcport;
134 static int dissect_fp_mux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
136 uint16_t uid;
137 bool ext_flag;
138 uint8_t length_field_size;
139 uint16_t length;
140 uint32_t header_length;
141 uint32_t total_length;
142 uint32_t offset = 0;
143 uint32_t out_value = 0;
144 uint32_t payload_index = 0;
145 tvbuff_t *next_tvb;
146 proto_item *ti;
147 proto_tree *fpmux_tree = NULL;
148 struct fp_mux_info_t* fp_mux_info;
150 total_length = tvb_captured_length(tvb);
152 /* Adding FP MUX info*/
153 fp_mux_info = (fp_mux_info_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp_mux, 0);
154 if (!fp_mux_info) {
155 fp_mux_info = wmem_new0(wmem_file_scope(), struct fp_mux_info_t);
156 /* remember 'lower' UDP layer port information so we can later
157 * differentiate 'lower' UDP layer from 'user data' UDP layer */
158 fp_mux_info->srcport = pinfo->srcport;
159 fp_mux_info->destport = pinfo->destport;
160 p_add_proto_data(wmem_file_scope(), pinfo, proto_fp_mux, 0, fp_mux_info);
163 col_set_str(pinfo->cinfo, COL_PROTOCOL, "FP Mux");
164 col_clear(pinfo->cinfo, COL_INFO);
166 while (offset != total_length) {
167 ext_flag = tvb_get_bits(tvb, (offset+2)*8, 1, ENC_NA) == 0x01;
168 header_length = ext_flag ? 4 : 3;
170 /* Adding another FP Mux tree */
171 ti = proto_tree_add_item(tree, proto_fp_mux, tvb, offset, header_length, ENC_NA);
172 fpmux_tree = proto_item_add_subtree(ti, ett_fpmux);
174 /* Adding User Identifier field */
175 proto_tree_add_item_ret_uint(fpmux_tree, hf_fpmux_uid, tvb, offset, 2, ENC_BIG_ENDIAN, &out_value);
176 uid = (uint16_t)out_value;
177 offset += 2;
178 /* Appending User Identifier to FP Mux tree label */
179 if (fp_mux_uid_in_tree) {
180 proto_item_append_text(ti, ", Uid: %d", uid);
183 /* Adding Extension Flag */
184 ti = proto_tree_add_boolean(fpmux_tree, hf_fpmux_extension_flag, tvb, offset, 1, ext_flag);
185 proto_item_append_text(ti," (%d)", ext_flag ? 1 : 0);
187 /* Adding Length field */
188 if(ext_flag) {
189 /* Extended - Length is 15 bits */
190 length = tvb_get_ntohs(tvb, offset) & 0x7FFF;
191 length_field_size = 2;
193 else {
194 /* Not extended - Length is 7 bits */
195 length = tvb_get_uint8(tvb, offset) & 0x7F;
196 length_field_size = 1;
198 proto_tree_add_uint(fpmux_tree, hf_fpmux_length, tvb, offset, length_field_size, length);
199 if(length == 0) {
200 /* Length is zero. Showing error and aborting dissection*/
201 proto_tree_add_expert_format(fpmux_tree, pinfo, &ei_fpm_bad_length, tvb, offset, length_field_size,
202 "Bad length: payload length can't be 0");
203 return total_length;
205 if (length > total_length - offset) {
206 /* Length value too big. Showing error and aborting dissection*/
207 proto_tree_add_expert_format(fpmux_tree, pinfo, &ei_fpm_bad_length, tvb, offset, length_field_size,
208 "Bad length: payload length exceeds remaining data length (%d) ", (total_length - offset));
209 return total_length;
211 if (length < 128 && ext_flag) {
212 /* Length could fit in 7 bits yet the length field was extended */
213 proto_tree_add_expert(fpmux_tree, pinfo, &ei_fpm_length_needlessly_extended, tvb, offset, length_field_size);
215 offset += length_field_size;
217 /* Dissecting Payload */
218 next_tvb = tvb_new_subset_length(tvb,offset,length);
219 if(payload_index >= MAX_PAYLOADS) {
220 /* Too many FP payloads. Showing error and aboring dissection*/
221 proto_tree_add_expert_format(fpmux_tree, pinfo, &ei_fpm_too_many_payloads, tvb, offset, -1,
222 "Too many FP packets muxed in a single packet ( Maximum expected: %d )", MAX_PAYLOADS);
223 return total_length;
225 dissect_payload(next_tvb,pinfo,tree,fp_mux_info,payload_index,uid);
226 offset += length;
228 payload_index++;
231 return total_length;
235 static bool heur_dissect_fp_mux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
237 bool ext_flag;
238 uint8_t length_field_size;
239 uint16_t length;
240 uint32_t header_length;
241 uint32_t total_length;
242 uint32_t offset = 0;
243 uint32_t chunks = 0;
244 conversation_t *conversation;
245 struct fp_mux_info_t* fp_mux_info;
247 total_length = tvb_captured_length(tvb);
248 if (total_length == 0) {
249 return false;
252 fp_mux_info = (fp_mux_info_t* )p_get_proto_data(wmem_file_scope(), pinfo, proto_fp_mux, 0);
253 if (fp_mux_info) {
254 if (fp_mux_info->srcport == pinfo->srcport &&
255 fp_mux_info->destport == pinfo->destport) {
256 /* Already framed as FP Mux*/
257 dissect_fp_mux(tvb, pinfo, tree, data);
258 return true;
260 else {
261 return false;
265 while(offset < total_length)
267 if(total_length < offset + 2) {
268 return false;
270 ext_flag = ((tvb_get_uint8(tvb, offset + 2)&0x80)==0x80);
271 header_length = ext_flag ? 4 : 3;
273 if(total_length < offset + header_length) {
274 return false;
277 offset = offset + 2; /* Skipping UID */
278 if(ext_flag) {
279 /* Extended - Length is 15 bits */
280 length = tvb_get_ntohs(tvb, offset) & 0x7FFF;
281 length_field_size = 2;
283 else {
284 /* Not extended - Length is 7 bits */
285 length = tvb_get_uint8(tvb, offset) & 0x7F;
286 length_field_size = 1;
289 if(length < 3) { /* Minimal FP frame length is 3 bytes*/
290 return false;
293 offset += length_field_size;
294 offset += length;
296 chunks++;
299 if(offset > total_length) {
300 return false;
303 if(chunks == 1) {
304 /* Might be coincidental, let's hope other packets with more payloads arrive */
305 return false;
308 /* This is FP Mux! */
309 /* Set conversation dissector and dissect */
310 conversation = find_or_create_conversation(pinfo);
311 conversation_set_dissector(conversation, fp_mux_handle);
312 dissect_fp_mux(tvb, pinfo, tree, data);
314 return true;
318 void
319 proto_register_fp_mux(void)
321 module_t *fp_mux_module;
322 expert_module_t* expert_fp_mux;
324 static hf_register_info hf[] = {
325 { &hf_fpmux_uid, { "User Identifier", "fp_mux.uid", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
326 { &hf_fpmux_extension_flag, { "Extension", "fp_mux.ef", FT_BOOLEAN, BASE_NONE, TFS(&fpmux_extension_flag_vals), 0, "Extension Flag", HFILL } },
327 { &hf_fpmux_length, { "Length", "fp_mux.length", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
330 static int *ett[] = {
331 &ett_fpmux
334 static ei_register_info ei[] = {
335 { &ei_fpm_length_needlessly_extended, { "fp_mux.needlessly_extended_length", PI_PROTOCOL, PI_WARN, "Length field needlessly extended", EXPFILL }},
336 { &ei_fpm_too_many_payloads, { "fp_mux.too_many_payloads", PI_PROTOCOL, PI_ERROR, "Too many FP packets muxed in a single packet", EXPFILL }},
337 { &ei_fpm_bad_length, { "fp_mux.bad_length", PI_PROTOCOL, PI_ERROR, "Bad length", EXPFILL }},
340 /* Register protocol */
341 proto_fp_mux = proto_register_protocol("Huawei FP Multiplexing Header", "FP Mux", "fp_mux");
342 fp_mux_handle =register_dissector("fp_mux", dissect_fp_mux, proto_fp_mux);
344 proto_register_field_array(proto_fp_mux, hf, array_length(hf));
345 proto_register_subtree_array(ett, array_length(ett));
346 expert_fp_mux = expert_register_protocol(proto_fp_mux);
347 expert_register_field_array(expert_fp_mux, ei, array_length(ei));
349 /* Register heuristic table */
350 heur_subdissector_list = register_heur_dissector_list_with_description("fp_mux", "Huawei FP Mux payload", proto_fp_mux);
352 /* Register configuration preferences */
353 fp_mux_module = prefs_register_protocol(proto_fp_mux, NULL);
354 prefs_register_bool_preference(fp_mux_module, "uid_in_tree",
355 "Show UID in protocol tree",
356 "Whether the UID value should be appended in the protocol tree",
357 &fp_mux_uid_in_tree);
358 prefs_register_bool_preference(fp_mux_module, "call_heur_fp",
359 "Call Heuristic FP Dissectors",
360 "Whether to try heuristic FP dissectors for the muxed payloads",
361 &call_fp_heur);
364 void
365 proto_reg_handoff_fp_mux(void)
367 dissector_add_uint_range_with_preference("udp.port", "", fp_mux_handle);
368 heur_dissector_add("udp", heur_dissect_fp_mux, "FP Mux over UDP", "fp_mux_udp", proto_fp_mux, HEURISTIC_DISABLE);
373 * Editor modelines - https://www.wireshark.org/tools/modelines.html
375 * Local variables:
376 * c-basic-offset: 4
377 * tab-width: 8
378 * indent-tabs-mode: nil
379 * End:
381 * vi: set shiftwidth=4 tabstop=8 expandtab:
382 * :indentSize=4:tabSize=8:noTabs=true: