/src/wireshark/epan/dissectors/packet-pdu-transport.c
Line | Count | Source |
1 | | /* packet-pdu-transport.c |
2 | | * PDU Transport dissector for FDN and others. |
3 | | * By <lars.voelker@technica-engineering.de> |
4 | | * Copyright 2020-2025 Dr. Lars Völker |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | */ |
12 | | |
13 | | /* |
14 | | * This is a dissector for PDUs transported over UDP or TCP. |
15 | | * The transported PDUs are typically CAN, FlexRay, LIN, or other protocols. |
16 | | * |
17 | | * The format is as follows: |
18 | | * ID (optional) [uint8, uint16, or uint32] |
19 | | * Length (optional) [uint8, uint16, or uint32] |
20 | | * Data uint8[length] |
21 | | * (restart with ID, if more data exists and Length field present) |
22 | | * |
23 | | * The dissector will try to match in this order: |
24 | | * Source and Destination port |
25 | | * Destination port and Any for Source port |
26 | | * Source port and Any for Destination port |
27 | | * Any for both ports |
28 | | * |
29 | | * |
30 | | * One known implementation of this protocol is the AUTOSAR Socket Adaptor: |
31 | | * With Header Option turned on: uint32 ID and uint32 Length. |
32 | | * With Header Option turned off: no ID and no Length. |
33 | | * |
34 | | * See AUTOSAR "Specification of Socket Adaptor" (SWS), Section 7.3 PDU Header option: |
35 | | * https://www.autosar.org/fileadmin/standards/R24-11/CP/AUTOSAR_CP_SWS_SocketAdaptor.pdf |
36 | | */ |
37 | | |
38 | | #include <config.h> |
39 | | |
40 | | #include <epan/packet.h> |
41 | | #include <epan/prefs.h> |
42 | | #include <epan/expert.h> |
43 | | #include <epan/uat.h> |
44 | | #include "packet-tcp.h" |
45 | | #include <epan/reassemble.h> |
46 | | #include "packet-udp.h" |
47 | | #include "packet-pdu-transport.h" |
48 | | #include <epan/decode_as.h> |
49 | | #include <epan/proto_data.h> |
50 | | |
51 | | void proto_register_pdu_transport(void); |
52 | | void proto_reg_handoff_pdu_transport(void); |
53 | | |
54 | | static int proto_pdu_transport; |
55 | | static dissector_handle_t pdu_transport_handle_udp; |
56 | | static dissector_handle_t pdu_transport_handle_tcp; |
57 | | |
58 | | static dissector_table_t subdissector_table; |
59 | | |
60 | 0 | #define PDU_TRANSPORT_HDR_LEN 8 |
61 | | |
62 | | /* header field */ |
63 | | static int hf_pdu_transport_id; |
64 | | static int hf_pdu_transport_name; |
65 | | static int hf_pdu_transport_impl_id; |
66 | | static int hf_pdu_transport_length; |
67 | | static int hf_pdu_transport_payload; |
68 | | |
69 | | /* protocol tree items */ |
70 | | static int ett_pdu_transport; |
71 | | |
72 | | /* expert info items */ |
73 | | static expert_field ei_pdu_transport_message_truncated; |
74 | | |
75 | | /********* UATs *********/ |
76 | | |
77 | | typedef struct _generic_one_id_string { |
78 | | unsigned id; |
79 | | char *name; |
80 | | } generic_one_id_string_t; |
81 | | |
82 | | /* ID -> Name */ |
83 | | static void * |
84 | 0 | copy_generic_one_id_string_cb(void *n, const void *o, size_t size _U_) { |
85 | 0 | generic_one_id_string_t *new_rec = (generic_one_id_string_t *)n; |
86 | 0 | const generic_one_id_string_t *old_rec = (const generic_one_id_string_t *)o; |
87 | |
|
88 | 0 | new_rec->name = g_strdup(old_rec->name); |
89 | 0 | new_rec->id = old_rec->id; |
90 | 0 | return new_rec; |
91 | 0 | } |
92 | | |
93 | | static bool |
94 | 0 | update_generic_one_identifier_32bit(void *r, char **err) { |
95 | 0 | generic_one_id_string_t *rec = (generic_one_id_string_t *)r; |
96 | |
|
97 | 0 | if (rec->name == NULL || rec->name[0] == 0) { |
98 | 0 | *err = g_strdup("Name cannot be empty"); |
99 | 0 | return false; |
100 | 0 | } |
101 | | |
102 | 0 | return true; |
103 | 0 | } |
104 | | |
105 | | static void |
106 | 0 | free_generic_one_id_string_cb(void *r) { |
107 | 0 | generic_one_id_string_t *rec = (generic_one_id_string_t *)r; |
108 | | /* freeing result of g_strdup */ |
109 | 0 | g_free(rec->name); |
110 | 0 | rec->name = NULL; |
111 | 0 | } |
112 | | |
113 | | /*** UAT PDU Transport PDUs - ID to Name lookup ***/ |
114 | 15 | #define DATAFILE_PDU_IDS "PDU_Transport_identifiers" |
115 | | |
116 | | static GHashTable *data_pdu_transport_pdus; |
117 | | static generic_one_id_string_t *pdu_transport_pdus; |
118 | | static unsigned pdu_transport_pdus_num; |
119 | | |
120 | 0 | UAT_HEX_CB_DEF(pdu_transport_pdus, id, generic_one_id_string_t) Unexecuted instantiation: packet-pdu-transport.c:pdu_transport_pdus_id_set_cb Unexecuted instantiation: packet-pdu-transport.c:pdu_transport_pdus_id_tostr_cb |
121 | 0 | UAT_CSTRING_CB_DEF(pdu_transport_pdus, name, generic_one_id_string_t) |
122 | | |
123 | | static void |
124 | 15 | post_update_pdu_transport_pdus_cb(void) { |
125 | | /* destroy old hash table, if it exists */ |
126 | 15 | if (data_pdu_transport_pdus) { |
127 | 0 | g_hash_table_destroy(data_pdu_transport_pdus); |
128 | 0 | } |
129 | | |
130 | | /* create new hash table */ |
131 | 15 | data_pdu_transport_pdus = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL); |
132 | | |
133 | 15 | for (unsigned i = 0; i < pdu_transport_pdus_num; i++) { |
134 | 0 | g_hash_table_insert(data_pdu_transport_pdus, GUINT_TO_POINTER(pdu_transport_pdus[i].id), pdu_transport_pdus[i].name); |
135 | 0 | } |
136 | 15 | } |
137 | | |
138 | | static void |
139 | 0 | reset_pdu_transport_pdus_cb(void) { |
140 | | /* destroy hash table, if it exists */ |
141 | 0 | if (data_pdu_transport_pdus) { |
142 | 0 | g_hash_table_destroy(data_pdu_transport_pdus); |
143 | 0 | data_pdu_transport_pdus = NULL; |
144 | 0 | } |
145 | 0 | } |
146 | | |
147 | | static char * |
148 | 0 | lookup_pdu_name(uint32_t identifier) { |
149 | 0 | if (data_pdu_transport_pdus == NULL) { |
150 | 0 | return NULL; |
151 | 0 | } |
152 | | |
153 | 0 | return (char *)g_hash_table_lookup(data_pdu_transport_pdus, GUINT_TO_POINTER(identifier)); |
154 | 0 | } |
155 | | |
156 | | |
157 | | /*** UAT pdu_transport_extended_config ***/ |
158 | 15 | #define DATAFILE_EXT_CFG "PDU_Transport_extended_config" |
159 | 0 | #define PORT_ANY 65536 |
160 | | |
161 | | typedef struct _pdu_transport_ext_cfg { |
162 | | bool tcp; |
163 | | uint32_t source_port; |
164 | | uint32_t destination_port; |
165 | | uint32_t size_of_id_field; |
166 | | uint32_t size_of_length_field; |
167 | | uint32_t default_id; |
168 | | } pdu_transport_ext_cfg_t; |
169 | | |
170 | | |
171 | | static GHashTable *data_pdu_transport_ext_cfg = NULL; |
172 | | static pdu_transport_ext_cfg_t *pdu_transport_ext_cfg; |
173 | | static unsigned pdu_transport_ext_cfg_num; |
174 | | |
175 | 0 | UAT_BOOL_CB_DEF(pdu_transport_ext_cfg, tcp, pdu_transport_ext_cfg_t) |
176 | 0 | UAT_DEC_CB_DEF(pdu_transport_ext_cfg, source_port, pdu_transport_ext_cfg_t) Unexecuted instantiation: packet-pdu-transport.c:pdu_transport_ext_cfg_source_port_set_cb Unexecuted instantiation: packet-pdu-transport.c:pdu_transport_ext_cfg_source_port_tostr_cb |
177 | 0 | UAT_DEC_CB_DEF(pdu_transport_ext_cfg, destination_port, pdu_transport_ext_cfg_t) Unexecuted instantiation: packet-pdu-transport.c:pdu_transport_ext_cfg_destination_port_set_cb Unexecuted instantiation: packet-pdu-transport.c:pdu_transport_ext_cfg_destination_port_tostr_cb |
178 | 0 | UAT_DEC_CB_DEF(pdu_transport_ext_cfg, size_of_id_field, pdu_transport_ext_cfg_t) Unexecuted instantiation: packet-pdu-transport.c:pdu_transport_ext_cfg_size_of_id_field_set_cb Unexecuted instantiation: packet-pdu-transport.c:pdu_transport_ext_cfg_size_of_id_field_tostr_cb |
179 | 0 | UAT_DEC_CB_DEF(pdu_transport_ext_cfg, size_of_length_field, pdu_transport_ext_cfg_t) Unexecuted instantiation: packet-pdu-transport.c:pdu_transport_ext_cfg_size_of_length_field_set_cb Unexecuted instantiation: packet-pdu-transport.c:pdu_transport_ext_cfg_size_of_length_field_tostr_cb |
180 | 0 | UAT_HEX_CB_DEF(pdu_transport_ext_cfg, default_id, pdu_transport_ext_cfg_t) Unexecuted instantiation: packet-pdu-transport.c:pdu_transport_ext_cfg_default_id_set_cb Unexecuted instantiation: packet-pdu-transport.c:pdu_transport_ext_cfg_default_id_tostr_cb |
181 | | |
182 | | static void * |
183 | 0 | copy_pdu_transport_ext_cfg_cb(void *n, const void *o, size_t size _U_) { |
184 | 0 | pdu_transport_ext_cfg_t *new_rec = (pdu_transport_ext_cfg_t *)n; |
185 | 0 | const pdu_transport_ext_cfg_t *old_rec = (const pdu_transport_ext_cfg_t *)o; |
186 | |
|
187 | 0 | new_rec->tcp = old_rec->tcp; |
188 | 0 | new_rec->source_port = old_rec->source_port; |
189 | 0 | new_rec->destination_port = old_rec->destination_port; |
190 | 0 | new_rec->size_of_id_field = old_rec->size_of_id_field; |
191 | 0 | new_rec->size_of_length_field = old_rec->size_of_length_field; |
192 | 0 | new_rec->default_id = old_rec->default_id; |
193 | 0 | return new_rec; |
194 | 0 | } |
195 | | |
196 | | static bool |
197 | 0 | update_pdu_transport_ext_cfg_cb(void *r, char **err) { |
198 | 0 | pdu_transport_ext_cfg_t *rec = (pdu_transport_ext_cfg_t *)r; |
199 | |
|
200 | 0 | if (rec->source_port > UINT16_MAX && rec->source_port != PORT_ANY) { |
201 | 0 | *err = g_strdup("Source Port can only be up to 65535 or Any (65536)!"); |
202 | 0 | return false; |
203 | 0 | } |
204 | | |
205 | 0 | if (rec->destination_port > UINT16_MAX && rec->destination_port != PORT_ANY) { |
206 | 0 | *err = g_strdup("Destination Port can only be up to 65535 or Any (65536)!"); |
207 | 0 | return false; |
208 | 0 | } |
209 | | |
210 | 0 | if (rec->size_of_id_field != 0 && rec->size_of_id_field != 8 && rec->size_of_id_field != 16 && rec->size_of_id_field != 32) { |
211 | 0 | *err = g_strdup("Size of the ID field can only be 0, 8, 16, or 32 bit!"); |
212 | 0 | return false; |
213 | 0 | } |
214 | | |
215 | 0 | if (rec->size_of_length_field != 0 && rec->size_of_length_field != 8 && rec->size_of_length_field != 16 && rec->size_of_length_field != 32) { |
216 | 0 | *err = g_strdup("Size of the Length field can only be 0, 8, 16, or 32 bit!"); |
217 | 0 | return false; |
218 | 0 | } |
219 | | |
220 | 0 | return true; |
221 | 0 | } |
222 | | |
223 | | |
224 | | static void |
225 | 15 | reset_pdu_transport_ext_cfg_cb(void) { |
226 | | /* destroy hash table, if it exists */ |
227 | 15 | if (data_pdu_transport_ext_cfg) { |
228 | 0 | g_hash_table_destroy(data_pdu_transport_ext_cfg); |
229 | 0 | data_pdu_transport_ext_cfg = NULL; |
230 | 0 | } |
231 | 15 | } |
232 | | |
233 | | static void |
234 | 15 | post_update_pdu_transport_ext_cfg_cb(void) { |
235 | 15 | reset_pdu_transport_ext_cfg_cb(); |
236 | | |
237 | | /* create new hash table */ |
238 | 15 | data_pdu_transport_ext_cfg = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL); |
239 | | |
240 | 15 | for (unsigned i = 0; i < pdu_transport_ext_cfg_num; i++) { |
241 | 0 | uint32_t key = 0; |
242 | 0 | if (pdu_transport_ext_cfg[i].destination_port != PORT_ANY) { |
243 | 0 | key |= pdu_transport_ext_cfg[i].destination_port; |
244 | 0 | } |
245 | |
|
246 | 0 | if (pdu_transport_ext_cfg[i].source_port != PORT_ANY) { |
247 | 0 | key |= (pdu_transport_ext_cfg[i].source_port << 16); |
248 | 0 | } |
249 | |
|
250 | 0 | g_hash_table_insert(data_pdu_transport_ext_cfg, GUINT_TO_POINTER(key), &(pdu_transport_ext_cfg[i])); |
251 | 0 | } |
252 | 15 | } |
253 | | |
254 | | static void |
255 | 0 | lookup_extended_config(packet_info *pinfo _U_, unsigned *size_of_id, unsigned *size_of_len, uint32_t *default_id) { |
256 | | /* Set backward compatible defaults, in case we find no entry */ |
257 | 0 | *size_of_id = 4; |
258 | 0 | *size_of_len = 4; |
259 | |
|
260 | 0 | if (data_pdu_transport_ext_cfg == NULL) { |
261 | 0 | return; |
262 | 0 | } |
263 | | |
264 | 0 | if (pinfo->ptype != PT_TCP && pinfo->ptype != PT_UDP) { |
265 | 0 | return; |
266 | 0 | } |
267 | | |
268 | 0 | bool tcp = (pinfo->ptype == PT_TCP); |
269 | 0 | pdu_transport_ext_cfg_t *entry = NULL; |
270 | | |
271 | | /* Try Source-Port / Dest-Port */ |
272 | 0 | uint32_t key = pinfo->srcport << 16 | pinfo->destport; |
273 | 0 | entry = (pdu_transport_ext_cfg_t *)g_hash_table_lookup(data_pdu_transport_ext_cfg, GUINT_TO_POINTER(key)); |
274 | | |
275 | | /* If not found, try Any / Dest-Port */ |
276 | 0 | if (entry == NULL || entry->tcp != tcp) { |
277 | 0 | key = pinfo->destport; |
278 | 0 | entry = (pdu_transport_ext_cfg_t *)g_hash_table_lookup(data_pdu_transport_ext_cfg, GUINT_TO_POINTER(key)); |
279 | 0 | } |
280 | | |
281 | | /* If not found, try Source-Port / Any */ |
282 | 0 | if (entry == NULL || entry->tcp != tcp) { |
283 | 0 | key = pinfo->srcport << 16; |
284 | 0 | entry = (pdu_transport_ext_cfg_t *)g_hash_table_lookup(data_pdu_transport_ext_cfg, GUINT_TO_POINTER(key)); |
285 | 0 | } |
286 | | |
287 | | /* If not found, try Any / Any */ |
288 | 0 | if (entry == NULL || entry->tcp != tcp) { |
289 | 0 | key = 0; |
290 | 0 | entry = (pdu_transport_ext_cfg_t *)g_hash_table_lookup(data_pdu_transport_ext_cfg, GUINT_TO_POINTER(key)); |
291 | 0 | } |
292 | |
|
293 | 0 | if (entry != NULL && entry->tcp == tcp) { |
294 | 0 | *size_of_id = entry->size_of_id_field / 8; |
295 | 0 | *size_of_len = entry->size_of_length_field / 8; |
296 | 0 | *default_id = entry->default_id; |
297 | 0 | } |
298 | 0 | } |
299 | | |
300 | | |
301 | | static int |
302 | 0 | dissect_pdu_transport(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { |
303 | 0 | proto_item *ti = NULL; |
304 | 0 | unsigned offset = 0; |
305 | |
|
306 | 0 | if (p_get_proto_data(pinfo->pool, pinfo, proto_pdu_transport, pinfo->curr_proto_layer_num) != NULL) { |
307 | 0 | col_append_str(pinfo->cinfo, COL_INFO, ", "); |
308 | 0 | col_set_fence(pinfo->cinfo, COL_INFO); |
309 | 0 | } |
310 | |
|
311 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "PDU"); |
312 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "PDU Transport"); |
313 | 0 | proto_item *ti_top = proto_tree_add_item(tree, proto_pdu_transport, tvb, 0, -1, ENC_NA); |
314 | 0 | proto_tree *pdu_transport_tree = proto_item_add_subtree(ti_top, ett_pdu_transport); |
315 | |
|
316 | 0 | unsigned size_of_id_field; |
317 | 0 | unsigned size_of_len_field; |
318 | 0 | uint32_t default_id; |
319 | |
|
320 | 0 | lookup_extended_config(pinfo, &size_of_id_field, &size_of_len_field, &default_id); |
321 | |
|
322 | 0 | if (tvb_captured_length_remaining(tvb, offset) < size_of_id_field + size_of_len_field) { |
323 | 0 | expert_add_info(pinfo, ti_top, &ei_pdu_transport_message_truncated); |
324 | 0 | } |
325 | | |
326 | | /* taken from packet-ip.c |
327 | | * if pdu_transport is not referenced from any filters we don't need to worry about |
328 | | * generating any tree items. We must do this after we created the actual |
329 | | * protocol above so that proto hier stat still works though. |
330 | | * XXX: Note that because of the following optimization expert items must |
331 | | * not be generated inside of an 'if (tree) ...' |
332 | | * so that Analyze ! Expert ... will work. |
333 | | */ |
334 | |
|
335 | 0 | if (!proto_field_is_referenced(tree, proto_pdu_transport)) { |
336 | 0 | pdu_transport_tree = NULL; |
337 | 0 | } |
338 | |
|
339 | 0 | uint32_t pdu_id; |
340 | 0 | if (size_of_id_field > 0) { |
341 | 0 | proto_tree_add_item_ret_uint(pdu_transport_tree, hf_pdu_transport_id, tvb, offset, size_of_id_field, ENC_BIG_ENDIAN, &pdu_id); |
342 | 0 | } else { |
343 | 0 | ti = proto_tree_add_uint(pdu_transport_tree, hf_pdu_transport_impl_id, tvb, 0, 0, default_id); |
344 | 0 | proto_item_set_generated(ti); |
345 | 0 | pdu_id = default_id; |
346 | 0 | } |
347 | 0 | const char *descr = lookup_pdu_name(pdu_id); |
348 | |
|
349 | 0 | if (descr != NULL) { |
350 | 0 | ti = proto_tree_add_string(pdu_transport_tree, hf_pdu_transport_name, tvb, offset, 4, descr); |
351 | 0 | proto_item_set_generated(ti); |
352 | 0 | } |
353 | 0 | offset += size_of_id_field; |
354 | |
|
355 | 0 | uint32_t length; |
356 | 0 | if (size_of_len_field > 0) { |
357 | 0 | proto_tree_add_item_ret_uint(pdu_transport_tree, hf_pdu_transport_length, tvb, offset, size_of_len_field, ENC_BIG_ENDIAN, &length); |
358 | 0 | offset += size_of_len_field; |
359 | 0 | } else { |
360 | 0 | length = tvb_captured_length_remaining(tvb, offset); |
361 | 0 | } |
362 | |
|
363 | 0 | if (descr != NULL) { |
364 | 0 | proto_item_append_text(ti_top, ", ID 0x%x (%s), Length: %d", pdu_id, descr, length); |
365 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, " (ID: 0x%x, %s)", pdu_id, descr); |
366 | 0 | } else { |
367 | 0 | proto_item_append_text(ti_top, ", ID 0x%x, Length: %d", pdu_id, length); |
368 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, " (ID: 0x%x)", pdu_id); |
369 | 0 | } |
370 | |
|
371 | 0 | p_add_proto_data(pinfo->pool, pinfo, proto_pdu_transport, pinfo->curr_proto_layer_num, GUINT_TO_POINTER(pdu_id)); |
372 | |
|
373 | 0 | int tmp = tvb_captured_length_remaining(tvb, offset); |
374 | 0 | tvbuff_t *subtvb = NULL; |
375 | 0 | if ((int)length <= tmp) { |
376 | 0 | proto_tree_add_item(pdu_transport_tree, hf_pdu_transport_payload, tvb, offset, length, ENC_NA); |
377 | 0 | } else { |
378 | 0 | proto_tree_add_item(pdu_transport_tree, hf_pdu_transport_payload, tvb, offset, tmp, ENC_NA); |
379 | 0 | expert_add_info(pinfo, ti_top, &ei_pdu_transport_message_truncated); |
380 | 0 | } |
381 | 0 | subtvb = tvb_new_subset_length(tvb, offset, length); |
382 | 0 | if (subtvb != NULL) { |
383 | 0 | pdu_transport_info_t pdu_t_info; |
384 | 0 | pdu_t_info.id = pdu_id; |
385 | 0 | dissector_try_uint_with_data(subdissector_table, pdu_id, subtvb, pinfo, tree, false, (void *)(&pdu_t_info)); |
386 | 0 | } |
387 | 0 | offset += (int)length; |
388 | |
|
389 | 0 | col_set_fence(pinfo->cinfo, COL_INFO); |
390 | 0 | return offset; |
391 | 0 | } |
392 | | |
393 | | static unsigned |
394 | 0 | get_pdu_transport_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_) { |
395 | 0 | return PDU_TRANSPORT_HDR_LEN + (unsigned)tvb_get_ntohl(tvb, offset + 4); |
396 | 0 | } |
397 | | |
398 | | static int |
399 | 0 | dissect_pdu_transport_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { |
400 | 0 | tcp_dissect_pdus(tvb, pinfo, tree, true, PDU_TRANSPORT_HDR_LEN, get_pdu_transport_message_len, dissect_pdu_transport, data); |
401 | 0 | return tvb_reported_length(tvb); |
402 | 0 | } |
403 | | |
404 | | static int |
405 | 0 | dissect_pdu_transport_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { |
406 | 0 | return udp_dissect_pdus(tvb, pinfo, tree, PDU_TRANSPORT_HDR_LEN, NULL, get_pdu_transport_message_len, dissect_pdu_transport, data); |
407 | 0 | } |
408 | | |
409 | | |
410 | | static void |
411 | 0 | pdu_transport_id_prompt(packet_info *pinfo, char *result) { |
412 | 0 | snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "PDU Transport ID 0x%08x as", |
413 | 0 | GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_pdu_transport, pinfo->curr_proto_layer_num))); |
414 | 0 | } |
415 | | |
416 | | static void * |
417 | 0 | pdu_transport_id_value(packet_info *pinfo) { |
418 | | /* Limitation: This only returns the last proto_data, since udp_dissect_pdus gives us the same layer for all. */ |
419 | 0 | return p_get_proto_data(pinfo->pool, pinfo, proto_pdu_transport, pinfo->curr_proto_layer_num); |
420 | 0 | } |
421 | | |
422 | | void |
423 | 15 | proto_register_pdu_transport(void) { |
424 | 15 | module_t *pdu_transport_module = NULL; |
425 | 15 | expert_module_t *expert_module_pdu_transport = NULL; |
426 | | |
427 | 15 | static hf_register_info hf[] = { |
428 | 15 | { &hf_pdu_transport_id, |
429 | 15 | { "ID", "pdu_transport.id", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
430 | 15 | { &hf_pdu_transport_impl_id, |
431 | 15 | { "ID (Implicit)", "pdu_transport.implicit_id", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
432 | 15 | { &hf_pdu_transport_name, |
433 | 15 | { "Name", "pdu_transport.name", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
434 | 15 | { &hf_pdu_transport_length, |
435 | 15 | { "Length", "pdu_transport.length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
436 | 15 | { &hf_pdu_transport_payload, |
437 | 15 | { "Payload", "pdu_transport.payload", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
438 | 15 | }; |
439 | | |
440 | 15 | static int *ett[] = { |
441 | 15 | &ett_pdu_transport, |
442 | 15 | }; |
443 | | |
444 | 15 | static ei_register_info ei[] = { |
445 | 15 | { &ei_pdu_transport_message_truncated,{ "pdu_transport.message_truncated", |
446 | 15 | PI_MALFORMED, PI_ERROR, "PDU Transport Truncated message!", EXPFILL } }, |
447 | 15 | }; |
448 | | |
449 | | /* Decode As handling */ |
450 | 15 | static build_valid_func pdu_transport_da_build_value[1] = {pdu_transport_id_value}; |
451 | 15 | static decode_as_value_t pdu_transport_da_values = {pdu_transport_id_prompt, 1, pdu_transport_da_build_value}; |
452 | | |
453 | 15 | static decode_as_t pdu_transport_da = { "pdu_transport", "pdu_transport.id", 1, 0, &pdu_transport_da_values, |
454 | 15 | NULL, NULL, decode_as_default_populate_list, |
455 | 15 | decode_as_default_reset, decode_as_default_change, NULL, NULL, NULL }; |
456 | | |
457 | 15 | proto_pdu_transport = proto_register_protocol("PDU Transport Protocol", "PDU Transport", "pdu_transport"); |
458 | | |
459 | 15 | proto_register_field_array(proto_pdu_transport, hf, array_length(hf)); |
460 | 15 | proto_register_subtree_array(ett, array_length(ett)); |
461 | | |
462 | 15 | pdu_transport_module = prefs_register_protocol(proto_pdu_transport, NULL); |
463 | 15 | expert_module_pdu_transport = expert_register_protocol(proto_pdu_transport); |
464 | 15 | expert_register_field_array(expert_module_pdu_transport, ei, array_length(ei)); |
465 | | |
466 | | |
467 | | /* UAT PDU-Transport PDUs */ |
468 | | |
469 | 15 | static uat_field_t pdu_transport_pdus_uat_fields[] = { |
470 | 15 | UAT_FLD_HEX(pdu_transport_pdus, id, "ID", "ID (hex uint32)"), |
471 | 15 | UAT_FLD_CSTRING(pdu_transport_pdus, name, "Name", "Name of the PDU (string)"), |
472 | 15 | UAT_END_FIELDS |
473 | 15 | }; |
474 | | |
475 | | |
476 | 15 | uat_t *pdu_transport_pduid_uat = uat_new("PDU Transport PDUs", |
477 | 15 | sizeof(generic_one_id_string_t), /* record size */ |
478 | 15 | DATAFILE_PDU_IDS, /* filename */ |
479 | 15 | true, /* from profile */ |
480 | 15 | (void**)&pdu_transport_pdus, /* data_ptr */ |
481 | 15 | &pdu_transport_pdus_num, /* numitems_ptr */ |
482 | 15 | UAT_AFFECTS_DISSECTION, /* but not fields */ |
483 | 15 | NULL, /* help */ |
484 | 15 | copy_generic_one_id_string_cb, /* copy callback */ |
485 | 15 | update_generic_one_identifier_32bit, /* update callback */ |
486 | 15 | free_generic_one_id_string_cb, /* free callback */ |
487 | 15 | post_update_pdu_transport_pdus_cb, /* post update callback */ |
488 | 15 | reset_pdu_transport_pdus_cb, /* reset callback */ |
489 | 15 | pdu_transport_pdus_uat_fields /* UAT field definitions */ |
490 | 15 | ); |
491 | | |
492 | 15 | prefs_register_uat_preference(pdu_transport_module, "_udf_pdu_transport_pdus", "PDUs", |
493 | 15 | "A table to define names and IDs of PDUs", pdu_transport_pduid_uat); |
494 | | |
495 | | |
496 | | /* UAT PDU-Transport Extended Config */ |
497 | | |
498 | 15 | static uat_field_t pdu_transport_ext_cfg_uat_fields[] = { |
499 | 15 | UAT_FLD_BOOL(pdu_transport_ext_cfg, tcp, "TCP?", "TCP (true) / UDP (false)"), |
500 | 15 | UAT_FLD_DEC(pdu_transport_ext_cfg, source_port, "Source Port", "Source Port (Dec 0..65535, 65536 means any)"), |
501 | 15 | UAT_FLD_DEC(pdu_transport_ext_cfg, destination_port, "Destination Port", "Destination Port (Dec 0..65535, 65536 means any)"), |
502 | 15 | UAT_FLD_DEC(pdu_transport_ext_cfg, size_of_id_field, "Size of ID", "Size of ID (0, 8, 16, 32 bit. 32 bit is default)"), |
503 | 15 | UAT_FLD_DEC(pdu_transport_ext_cfg, size_of_length_field, "Size of Length", "Size of Length (0, 8, 16, 32 bit. 32 bit is default)"), |
504 | 15 | UAT_FLD_HEX(pdu_transport_ext_cfg, default_id, "Default ID", "Default ID. Used, when no ID present in packet."), |
505 | 15 | UAT_END_FIELDS |
506 | 15 | }; |
507 | | |
508 | 15 | uat_t *pdu_transport_ext_cfg_uat = uat_new("PDU Transport Extended Config", |
509 | 15 | sizeof(pdu_transport_ext_cfg_t), /* record size */ |
510 | 15 | DATAFILE_EXT_CFG, /* filename */ |
511 | 15 | true, /* from profile */ |
512 | 15 | (void**)&pdu_transport_ext_cfg, /* data_ptr */ |
513 | 15 | &pdu_transport_ext_cfg_num, /* numitems_ptr */ |
514 | 15 | UAT_AFFECTS_DISSECTION, /* but not fields */ |
515 | 15 | NULL, /* help */ |
516 | 15 | copy_pdu_transport_ext_cfg_cb, /* copy callback */ |
517 | 15 | update_pdu_transport_ext_cfg_cb, /* update callback */ |
518 | 15 | NULL, /* free callback */ |
519 | 15 | post_update_pdu_transport_ext_cfg_cb, /* post update callback */ |
520 | 15 | reset_pdu_transport_ext_cfg_cb, /* reset callback */ |
521 | 15 | pdu_transport_ext_cfg_uat_fields /* UAT field definitions */ |
522 | 15 | ); |
523 | | |
524 | 15 | prefs_register_uat_preference(pdu_transport_module, "_udf_pdu_transport_ext_cfg", "Extended Config", |
525 | 15 | "A table to define the extended configuration", pdu_transport_ext_cfg_uat); |
526 | | |
527 | | |
528 | 15 | subdissector_table = register_dissector_table("pdu_transport.id", "PDU Transport ID", proto_pdu_transport, FT_UINT32, BASE_HEX); |
529 | 15 | register_decode_as(&pdu_transport_da); |
530 | 15 | } |
531 | | |
532 | | void |
533 | 15 | proto_reg_handoff_pdu_transport(void) { |
534 | 15 | pdu_transport_handle_udp = register_dissector("pdu_transport_over_udp", dissect_pdu_transport_udp, proto_pdu_transport); |
535 | 15 | pdu_transport_handle_tcp = register_dissector("pdu_transport_over_tcp", dissect_pdu_transport_tcp, proto_pdu_transport); |
536 | | |
537 | 15 | dissector_add_uint_range_with_preference("udp.port", "", pdu_transport_handle_udp); |
538 | 15 | dissector_add_uint_range_with_preference("tcp.port", "", pdu_transport_handle_tcp); |
539 | 15 | } |
540 | | |
541 | | /* |
542 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
543 | | * |
544 | | * Local variables: |
545 | | * c-basic-offset: 4 |
546 | | * tab-width: 8 |
547 | | * indent-tabs-mode: nil |
548 | | * End: |
549 | | * |
550 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
551 | | * :indentSize=4:tabSize=8:noTabs=true: |
552 | | */ |