Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-pdu-transport.c
blob0df42471a55771187113884e851bab5171435e01
1 /* packet-pdu_transport.c
2 * PDU Transport dissector for FDN and others.
3 * By <lars.voelker@technica-engineering.de>
4 * Copyright 2020-2023 Dr. Lars Voelker
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
14 * This is a dissector for PDUs transported over UDP or TCP.
15 * The transported PDUs are typically CAN, FlexRay, LIN, or other protocols.
17 * The format is as follows:
18 * uint32 ID
19 * uint32 length
20 * uint8[length] data
21 * (restart with ID, if more data exists)
23 * One known implementation of this protocol is the AUTOSAR Socket Adaptor
24 * with Header Option turned on.
25 * See AUTOSAR "Specification of Socket Adaptor" (SWS), Section 7.3 PDU Header option:
26 * https://www.autosar.org/fileadmin/user_upload/standards/classic/20-11/AUTOSAR_SWS_SocketAdaptor.pdf
29 #include <config.h>
31 #include <epan/packet.h>
32 #include <epan/prefs.h>
33 #include <epan/expert.h>
34 #include <epan/uat.h>
35 #include "packet-tcp.h"
36 #include <epan/reassemble.h>
37 #include "packet-udp.h"
38 #include "packet-pdu-transport.h"
39 #include <epan/decode_as.h>
40 #include <epan/proto_data.h>
42 void proto_register_pdu_transport(void);
43 void proto_reg_handoff_pdu_transport(void);
45 static int proto_pdu_transport;
46 static dissector_handle_t pdu_transport_handle_udp;
47 static dissector_handle_t pdu_transport_handle_tcp;
49 static dissector_table_t subdissector_table;
51 #define PDU_TRANSPORT_NAME "PDU Transport"
52 #define PDU_TRANSPORT_HDR_LEN 8
54 /* header field */
55 static int hf_pdu_transport_id;
56 static int hf_pdu_transport_length;
57 static int hf_pdu_transport_payload;
59 /* protocol tree items */
60 static int ett_pdu_transport;
62 /* expert info items */
63 static expert_field ei_pdu_transport_message_truncated;
65 /********* UATs *********/
67 typedef struct _generic_one_id_string {
68 unsigned id;
69 char *name;
70 } generic_one_id_string_t;
72 static void
73 pdu_transport_free_key(void *key) {
74 wmem_free(wmem_epan_scope(), key);
77 static void
78 simple_free(void *data) {
79 /* we need to free because of the g_strdup in post_update*/
80 g_free(data);
83 /* ID -> Name */
84 static void *
85 copy_generic_one_id_string_cb(void *n, const void *o, size_t size _U_) {
86 generic_one_id_string_t *new_rec = (generic_one_id_string_t *)n;
87 const generic_one_id_string_t *old_rec = (const generic_one_id_string_t *)o;
89 new_rec->name = g_strdup(old_rec->name);
90 new_rec->id = old_rec->id;
91 return new_rec;
94 static bool
95 update_generic_one_identifier_32bit(void *r, char **err) {
96 generic_one_id_string_t *rec = (generic_one_id_string_t *)r;
98 if (rec->name == NULL || rec->name[0] == 0) {
99 *err = g_strdup("Name cannot be empty");
100 return false;
103 return true;
106 static void
107 free_generic_one_id_string_cb(void *r) {
108 generic_one_id_string_t *rec = (generic_one_id_string_t *)r;
109 /* freeing result of g_strdup */
110 g_free(rec->name);
111 rec->name = NULL;
114 static void
115 post_update_one_id_string_template_cb(generic_one_id_string_t *data, unsigned data_num, GHashTable *ht) {
116 unsigned i;
117 int *key = NULL;
119 for (i = 0; i < data_num; i++) {
120 key = wmem_new(wmem_epan_scope(), int);
121 *key = data[i].id;
123 g_hash_table_insert(ht, key, g_strdup(data[i].name));
127 static char *
128 ht_lookup_name(GHashTable *ht, unsigned int identifier) {
129 char *tmp = NULL;
130 unsigned int *id = NULL;
132 if (ht == NULL) {
133 return NULL;
136 id = wmem_new(wmem_epan_scope(), unsigned int);
137 *id = (unsigned int)identifier;
138 tmp = (char *)g_hash_table_lookup(ht, id);
139 wmem_free(wmem_epan_scope(), id);
141 return tmp;
144 /*** UAT pdu_transport_CM_IDs ***/
145 #define DATAFILE_PDU_IDS "PDU_Transport_identifiers"
147 static GHashTable *data_pdu_transport_pdus;
148 static generic_one_id_string_t *pdu_transport_pdus;
149 static unsigned pdu_transport_pdus_num;
151 UAT_HEX_CB_DEF(pdu_transport_pdus, id, generic_one_id_string_t)
152 UAT_CSTRING_CB_DEF(pdu_transport_pdus, name, generic_one_id_string_t)
154 static void
155 post_update_pdu_transport_pdus_cb(void) {
156 /* destroy old hash table, if it exists */
157 if (data_pdu_transport_pdus) {
158 g_hash_table_destroy(data_pdu_transport_pdus);
159 data_pdu_transport_pdus = NULL;
162 /* create new hash table */
163 data_pdu_transport_pdus = g_hash_table_new_full(g_int_hash, g_int_equal, &pdu_transport_free_key, &simple_free);
164 post_update_one_id_string_template_cb(pdu_transport_pdus, pdu_transport_pdus_num, data_pdu_transport_pdus);
167 static int
168 dissect_pdu_transport(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
169 proto_item *ti_top = NULL;
170 proto_item *ti = NULL;
171 proto_tree *pdu_transport_tree = NULL;
172 unsigned offset = 0;
173 tvbuff_t *subtvb = NULL;
174 int tmp = 0;
176 uint32_t length = 0;
177 uint32_t pdu_id = 0;
178 const char *descr;
180 if (p_get_proto_data(pinfo->pool, pinfo, proto_pdu_transport, pinfo->curr_proto_layer_num) != NULL) {
181 col_append_str(pinfo->cinfo, COL_INFO, ", ");
182 col_set_fence(pinfo->cinfo, COL_INFO);
185 col_set_str(pinfo->cinfo, COL_INFO, "PDU");
186 col_set_str(pinfo->cinfo, COL_PROTOCOL, PDU_TRANSPORT_NAME);
187 ti_top = proto_tree_add_item(tree, proto_pdu_transport, tvb, 0, -1, ENC_NA);
188 pdu_transport_tree = proto_item_add_subtree(ti_top, ett_pdu_transport);
190 if (tvb_captured_length_remaining(tvb, offset) < 8) {
191 expert_add_info(pinfo, ti_top, &ei_pdu_transport_message_truncated);
194 /* taken from packet-ip.c
195 * if pdu_transport is not referenced from any filters we don't need to worry about
196 * generating any tree items. We must do this after we created the actual
197 * protocol above so that proto hier stat still works though.
198 * XXX: Note that because of the following optimization expert items must
199 * not be generated inside of an 'if (tree) ...'
200 * so that Analyze ! Expert ... will work.
203 if (!proto_field_is_referenced(tree, proto_pdu_transport)) {
204 pdu_transport_tree = NULL;
207 ti = proto_tree_add_item_ret_uint(pdu_transport_tree, hf_pdu_transport_id, tvb, offset, 4, ENC_BIG_ENDIAN, &pdu_id);
208 offset += 4;
210 proto_tree_add_item_ret_uint(pdu_transport_tree, hf_pdu_transport_length, tvb, offset, 4, ENC_BIG_ENDIAN, &length);
211 offset += 4;
213 descr = ht_lookup_name(data_pdu_transport_pdus, pdu_id);
215 if (descr != NULL) {
216 proto_item_append_text(ti_top, ", ID 0x%x (%s), Length: %d", pdu_id, descr, length);
217 proto_item_append_text(ti, " (%s)", descr);
218 col_append_fstr(pinfo->cinfo, COL_INFO, " (ID: 0x%x, %s)", pdu_id, descr);
219 } else {
220 proto_item_append_text(ti_top, ", ID 0x%x, Length: %d", pdu_id, length);
221 col_append_fstr(pinfo->cinfo, COL_INFO, " (ID: 0x%x)", pdu_id);
224 p_add_proto_data(pinfo->pool, pinfo, proto_pdu_transport, pinfo->curr_proto_layer_num, GUINT_TO_POINTER(pdu_id));
226 tmp = tvb_captured_length_remaining(tvb, offset);
227 if ((int)length <= tmp) {
228 proto_tree_add_item(pdu_transport_tree, hf_pdu_transport_payload, tvb, offset, length, ENC_NA);
229 subtvb = tvb_new_subset_length_caplen(tvb, offset, length, length);
230 } else {
231 proto_tree_add_item(pdu_transport_tree, hf_pdu_transport_payload, tvb, offset, tmp, ENC_NA);
232 subtvb = tvb_new_subset_length_caplen(tvb, offset, tmp, length);
233 expert_add_info(pinfo, ti_top, &ei_pdu_transport_message_truncated);
235 if (subtvb != NULL) {
236 pdu_transport_info_t pdu_t_info;
237 pdu_t_info.id = pdu_id;
239 dissector_try_uint_with_data(subdissector_table, pdu_id, subtvb, pinfo, tree, false, (void *)(&pdu_t_info));
241 offset += (int)length;
243 col_set_fence(pinfo->cinfo, COL_INFO);
244 return offset;
247 static unsigned
248 get_pdu_transport_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_) {
249 return PDU_TRANSPORT_HDR_LEN + (unsigned)tvb_get_ntohl(tvb, offset + 4);
252 static int
253 dissect_pdu_transport_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
254 tcp_dissect_pdus(tvb, pinfo, tree, true, PDU_TRANSPORT_HDR_LEN, get_pdu_transport_message_len, dissect_pdu_transport, data);
255 return tvb_reported_length(tvb);
258 static int
259 dissect_pdu_transport_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
260 return udp_dissect_pdus(tvb, pinfo, tree, PDU_TRANSPORT_HDR_LEN, NULL, get_pdu_transport_message_len, dissect_pdu_transport, data);
264 static void
265 pdu_transport_id_prompt(packet_info *pinfo, char *result) {
266 snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "PDU Transport ID 0x%08x as",
267 GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_pdu_transport, pinfo->curr_proto_layer_num)));
270 static void *
271 pdu_transport_id_value(packet_info *pinfo) {
272 /* Limitation: This only returns the last proto_data, since udp_dissect_pdus gives us the same layer for all. */
273 return p_get_proto_data(pinfo->pool, pinfo, proto_pdu_transport, pinfo->curr_proto_layer_num);
276 void
277 proto_register_pdu_transport(void) {
278 module_t *pdu_transport_module = NULL;
279 expert_module_t *expert_module_pdu_transport = NULL;
280 uat_t *pdu_transport_pduid_uat = NULL;
282 static hf_register_info hf[] = {
283 { &hf_pdu_transport_id,
284 { "ID", "pdu_transport.id", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
285 { &hf_pdu_transport_length,
286 { "Length", "pdu_transport.length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
287 { &hf_pdu_transport_payload,
288 { "Payload", "pdu_transport.payload", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
291 static int *ett[] = {
292 &ett_pdu_transport,
295 static ei_register_info ei[] = {
296 { &ei_pdu_transport_message_truncated,{ "pdu_transport.message_truncated",
297 PI_MALFORMED, PI_ERROR, "PDU Transport Truncated message!", EXPFILL } },
300 /* Decode As handling */
301 static build_valid_func pdu_transport_da_build_value[1] = {pdu_transport_id_value};
302 static decode_as_value_t pdu_transport_da_values = {pdu_transport_id_prompt, 1, pdu_transport_da_build_value};
304 static decode_as_t pdu_transport_da = { "pdu_transport", "pdu_transport.id", 1, 0, &pdu_transport_da_values,
305 NULL, NULL, decode_as_default_populate_list,
306 decode_as_default_reset, decode_as_default_change, NULL };
308 proto_pdu_transport = proto_register_protocol("PDU Transport Protocol", PDU_TRANSPORT_NAME, "pdu_transport");
310 proto_register_field_array(proto_pdu_transport, hf, array_length(hf));
311 proto_register_subtree_array(ett, array_length(ett));
313 pdu_transport_module = prefs_register_protocol(proto_pdu_transport, NULL);
314 expert_module_pdu_transport = expert_register_protocol(proto_pdu_transport);
315 expert_register_field_array(expert_module_pdu_transport, ei, array_length(ei));
317 static uat_field_t pdu_transport_cm_id_uat_fields[] = {
318 UAT_FLD_HEX(pdu_transport_pdus, id, "ID", "ID (hex uint32)"),
319 UAT_FLD_CSTRING(pdu_transport_pdus, name, "Name", "Name of the PDU (string)"),
320 UAT_END_FIELDS
323 pdu_transport_pduid_uat = uat_new("pdu_transport Capture Modules",
324 sizeof(generic_one_id_string_t), /* record size */
325 DATAFILE_PDU_IDS, /* filename */
326 true, /* from profile */
327 (void**)&pdu_transport_pdus, /* data_ptr */
328 &pdu_transport_pdus_num, /* numitems_ptr */
329 UAT_AFFECTS_DISSECTION, /* but not fields */
330 NULL, /* help */
331 copy_generic_one_id_string_cb, /* copy callback */
332 update_generic_one_identifier_32bit, /* update callback */
333 free_generic_one_id_string_cb, /* free callback */
334 post_update_pdu_transport_pdus_cb, /* post update callback */
335 NULL, /* reset callback */
336 pdu_transport_cm_id_uat_fields /* UAT field definitions */
339 prefs_register_uat_preference(pdu_transport_module, "_udf_pdu_transport_pdus", "PDUs",
340 "A table to define names and IDs of PDUs", pdu_transport_pduid_uat);
342 subdissector_table = register_dissector_table("pdu_transport.id", "PDU Transport ID", proto_pdu_transport, FT_UINT32, BASE_HEX);
343 register_decode_as(&pdu_transport_da);
346 void
347 proto_reg_handoff_pdu_transport(void) {
348 pdu_transport_handle_udp = register_dissector("pdu_transport_over_udp", dissect_pdu_transport_udp, proto_pdu_transport);
349 pdu_transport_handle_tcp = register_dissector("pdu_transport_over_tcp", dissect_pdu_transport_tcp, proto_pdu_transport);
351 dissector_add_uint_range_with_preference("udp.port", "", pdu_transport_handle_udp);
352 dissector_add_uint_range_with_preference("tcp.port", "", pdu_transport_handle_tcp);
356 * Editor modelines - https://www.wireshark.org/tools/modelines.html
358 * Local variables:
359 * c-basic-offset: 4
360 * tab-width: 8
361 * indent-tabs-mode: nil
362 * End:
364 * vi: set shiftwidth=4 tabstop=8 expandtab:
365 * :indentSize=4:tabSize=8:noTabs=true: