Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-udpcp.c
blobd032eeea1cfddbb44525cd8f8a098accca6df549
1 /* packet-udpcp.c
3 * Routines for UDPCP packet dissection (UDP-based reliable communication protocol).
4 * Described in the Open Base Station Initiative Reference Point 1 Specification
5 * (see https://web.archive.org/web/20171206005927/http://www.obsai.com/specs/RP1%20Spec%20v2_1.pdf, Appendix A)
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
12 * SPDX-License-Identifier: GPL-2.0-or-later
15 /* TODO:
16 * - Calculate/verify Checksum field
19 #include "config.h"
21 #include <epan/conversation.h>
22 #include <epan/reassemble.h>
23 #include <epan/expert.h>
24 #include <epan/prefs.h>
27 void proto_register_udpcp(void);
29 static int proto_udpcp;
31 static int hf_udpcp_checksum;
32 static int hf_udpcp_msg_type;
33 static int hf_udpcp_version;
35 static int hf_udpcp_packet_transfer_options;
36 static int hf_udpcp_n;
37 static int hf_udpcp_c;
38 static int hf_udpcp_s;
39 static int hf_udpcp_d;
40 static int hf_udpcp_reserved;
42 static int hf_udpcp_fragment_amount;
43 static int hf_udpcp_fragment_number;
45 static int hf_udpcp_message_id;
46 static int hf_udpcp_message_data_length;
48 static int hf_udpcp_payload;
50 static int hf_udpcp_ack_frame;
51 static int hf_udpcp_sn_frame;
54 /* For reassembly */
55 static int hf_udpcp_fragments;
56 static int hf_udpcp_fragment;
57 static int hf_udpcp_fragment_overlap;
58 static int hf_udpcp_fragment_overlap_conflict;
59 static int hf_udpcp_fragment_multiple_tails;
60 static int hf_udpcp_fragment_too_long_fragment;
61 static int hf_udpcp_fragment_error;
62 static int hf_udpcp_fragment_count;
63 static int hf_udpcp_reassembled_in;
64 static int hf_udpcp_reassembled_length;
65 static int hf_udpcp_reassembled_data;
68 /* Subtrees */
69 static int ett_udpcp;
70 static int ett_udpcp_packet_transfer_options;
71 static int ett_udpcp_fragments;
72 static int ett_udpcp_fragment;
74 static const fragment_items udpcp_frag_items = {
75 &ett_udpcp_fragment,
76 &ett_udpcp_fragments,
77 &hf_udpcp_fragments,
78 &hf_udpcp_fragment,
79 &hf_udpcp_fragment_overlap,
80 &hf_udpcp_fragment_overlap_conflict,
81 &hf_udpcp_fragment_multiple_tails,
82 &hf_udpcp_fragment_too_long_fragment,
83 &hf_udpcp_fragment_error,
84 &hf_udpcp_fragment_count,
85 &hf_udpcp_reassembled_in,
86 &hf_udpcp_reassembled_length,
87 &hf_udpcp_reassembled_data,
88 "UDPCP fragments"
92 static expert_field ei_udpcp_checksum_should_be_zero;
93 static expert_field ei_udpcp_d_not_zero_for_data;
94 static expert_field ei_udpcp_reserved_not_zero;
95 static expert_field ei_udpcp_n_s_ack;
96 static expert_field ei_udpcp_payload_wrong_size;
97 static expert_field ei_udpcp_wrong_sequence_number;
98 static expert_field ei_udpcp_no_ack;
99 static expert_field ei_udpcp_no_sn_frame;
101 static dissector_handle_t udpcp_handle;
104 void proto_reg_handoff_udpcp (void);
106 /* User definable values */
107 static range_t *global_udpcp_port_range;
109 #define DATA_FORMAT 0x01
110 #define ACK_FORMAT 0x02
113 static const value_string msg_type_vals[] = {
114 { DATA_FORMAT, "Data Packet" },
115 { ACK_FORMAT, "Ack Packet" },
116 { 0, NULL }
119 typedef struct {
120 /* Protocol is bi-directional, so need to distinguish */
121 uint16_t first_dest_port;
122 address first_dest_address;
124 /* Main these so can link between SN frames and ACKs */
125 wmem_tree_t *sn_table_first;
126 wmem_tree_t *ack_table_first;
127 wmem_tree_t *sn_table_second;
128 wmem_tree_t *ack_table_second;
130 /* Remember next expected message-id in each direction */
131 uint32_t next_message_id_first;
132 uint32_t next_message_id_second;
133 } udpcp_conversation_t;
136 /* Framenum -> expected_sequence_number */
137 static wmem_tree_t *sequence_number_result_table;
140 /* Reassembly table. */
141 static reassembly_table udpcp_reassembly_table;
143 static void *udpcp_temporary_key(const packet_info *pinfo _U_, const uint32_t id _U_, const void *data)
145 return (void *)data;
148 static void *udpcp_persistent_key(const packet_info *pinfo _U_, const uint32_t id _U_,
149 const void *data)
151 return (void *)data;
154 static void udpcp_free_temporary_key(void *ptr _U_)
158 static void udpcp_free_persistent_key(void *ptr _U_)
162 static reassembly_table_functions udpcp_reassembly_table_functions =
164 g_direct_hash,
165 g_direct_equal,
166 udpcp_temporary_key,
167 udpcp_persistent_key,
168 udpcp_free_temporary_key,
169 udpcp_free_persistent_key
173 /**************************************************************************/
174 /* Preferences state */
175 /**************************************************************************/
177 /* Reassemble by default */
178 static bool global_udpcp_reassemble = true;
180 /* By default do try to decode payload as XML/SOAP */
181 static bool global_udpcp_decode_payload_as_soap = true;
184 static dissector_handle_t xml_handle;
186 /******************************/
187 /* Main dissection function. */
188 static int
189 dissect_udpcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
191 proto_tree *udpcp_tree;
192 proto_item *root_ti;
193 int offset = 0;
195 /* Must be at least 12 bytes */
196 if (tvb_reported_length(tvb) < 12) {
197 return 0;
200 /* Has to be Data or Ack format. */
201 uint32_t msg_type = tvb_get_uint8(tvb, 4) >> 6;
202 if ((msg_type != DATA_FORMAT) && (msg_type != ACK_FORMAT)) {
203 return 0;
206 /* Protocol column */
207 col_set_str(pinfo->cinfo, COL_PROTOCOL, "UDPCP");
209 /* Protocol root */
210 root_ti = proto_tree_add_item(tree, proto_udpcp, tvb, offset, -1, ENC_NA);
211 udpcp_tree = proto_item_add_subtree(root_ti, ett_udpcp);
213 /* Checksum */
214 uint32_t checksum;
215 proto_item *checksum_ti = proto_tree_add_item_ret_uint(udpcp_tree, hf_udpcp_checksum, tvb, offset, 4, ENC_BIG_ENDIAN, &checksum);
216 offset += 4;
218 /* Msg-type */
219 proto_tree_add_item_ret_uint(udpcp_tree, hf_udpcp_msg_type, tvb, offset, 1, ENC_BIG_ENDIAN, &msg_type);
220 col_add_str(pinfo->cinfo, COL_INFO,
221 (msg_type == DATA_FORMAT) ? "[Data] " : "[Ack] ");
222 proto_item_append_text(root_ti, (msg_type == DATA_FORMAT) ? " [Data]" : " [Ack]");
224 /* Version */
225 proto_tree_add_item(udpcp_tree, hf_udpcp_version, tvb, offset, 1, ENC_BIG_ENDIAN);
228 /***************************/
229 /* Packet Transfer Options */
230 proto_item *packet_transfer_options_ti =
231 proto_tree_add_string_format(udpcp_tree, hf_udpcp_packet_transfer_options, tvb, offset, 2,
232 "", "Packet Transfer Options (");
233 proto_tree *packet_transfer_options_tree =
234 proto_item_add_subtree(packet_transfer_options_ti, ett_udpcp_packet_transfer_options);
235 uint32_t n, c, s, d;
237 /* N */
238 proto_tree_add_item_ret_uint(packet_transfer_options_tree, hf_udpcp_n, tvb, offset, 1, ENC_BIG_ENDIAN, &n);
239 if (n) {
240 proto_item_append_text(packet_transfer_options_ti, "N");
243 /* C */
244 proto_tree_add_item_ret_uint(packet_transfer_options_tree, hf_udpcp_c, tvb, offset, 1, ENC_BIG_ENDIAN, &c);
245 if (c) {
246 proto_item_append_text(packet_transfer_options_ti, "C");
248 if (!c && checksum) {
249 /* Expert info warning that checksum should be 0 if !c */
250 expert_add_info(pinfo, checksum_ti, &ei_udpcp_checksum_should_be_zero);
253 /* S */
254 proto_tree_add_item_ret_uint(packet_transfer_options_tree, hf_udpcp_s, tvb, offset, 1, ENC_BIG_ENDIAN, &s);
255 offset++;
256 if (s) {
257 proto_item_append_text(packet_transfer_options_ti, "S");
260 /* D */
261 proto_item *d_ti = proto_tree_add_item_ret_uint(packet_transfer_options_tree, hf_udpcp_d, tvb, offset, 1, ENC_BIG_ENDIAN, &d);
262 if (d) {
263 proto_item_append_text(packet_transfer_options_ti, "D");
265 /* Expert info if D not zero for data */
266 if ((msg_type == DATA_FORMAT) && d) {
267 expert_add_info(pinfo, d_ti, &ei_udpcp_d_not_zero_for_data);
270 /* Reserved */
271 uint32_t reserved;
272 proto_item *reserved_ti = proto_tree_add_item_ret_uint(packet_transfer_options_tree, hf_udpcp_reserved, tvb, offset, 1, ENC_BIG_ENDIAN, &reserved);
273 offset++;
274 /* Expert info if reserved not 0 */
275 if (reserved) {
276 expert_add_info(pinfo, reserved_ti, &ei_udpcp_reserved_not_zero);
279 proto_item_append_text(packet_transfer_options_ti, ")");
280 /*************************/
283 /* Fragment Amount & Fragment Number */
284 uint32_t fragment_amount, fragment_number;
285 proto_tree_add_item_ret_uint(udpcp_tree, hf_udpcp_fragment_amount, tvb, offset, 1, ENC_BIG_ENDIAN, &fragment_amount);
286 offset++;
287 proto_tree_add_item_ret_uint(udpcp_tree, hf_udpcp_fragment_number, tvb, offset, 1, ENC_BIG_ENDIAN, &fragment_number);
288 offset++;
290 /* Message ID & Message Data Length */
291 uint32_t message_id;
292 proto_item *message_id_ti = proto_tree_add_item_ret_uint(udpcp_tree, hf_udpcp_message_id, tvb, offset, 2, ENC_BIG_ENDIAN, &message_id);
293 col_append_fstr(pinfo->cinfo, COL_INFO, " Msg_ID=%3u", message_id);
294 offset += 2;
295 uint32_t data_length;
296 proto_tree_add_item_ret_uint(udpcp_tree, hf_udpcp_message_data_length, tvb, offset, 2, ENC_BIG_ENDIAN, &data_length);
297 offset += 2;
299 if (msg_type == DATA_FORMAT) {
300 if (!data_length) {
301 /* This could just be a sync frame */
302 if (!message_id && !n && !s) {
303 col_append_str(pinfo->cinfo, COL_INFO, " [Sync]");
307 /* Show if/when this frame should be acknowledged */
308 if (!n && !s) {
309 proto_item_append_text(packet_transfer_options_ti, " (All packets ACKd)");
311 else if (!n && s) {
312 proto_item_append_text(packet_transfer_options_ti, " (Last fragment ACKd)");
314 if (n) {
315 proto_item_append_text(packet_transfer_options_ti, " (Not ACKd)");
318 /* Show fragment numbering. Ignore confusing 0-based fragment numbering.. */
319 col_append_fstr(pinfo->cinfo, COL_INFO, " [Frag %u/%u]",
320 fragment_number+1, fragment_amount);
322 /* There is data */
323 if ((fragment_amount == 1) && (fragment_number == 0) && data_length) {
324 /* Not fragmented - show payload now */
325 proto_item *data_ti = proto_tree_add_item(udpcp_tree, hf_udpcp_payload, tvb, offset, -1, ENC_ASCII);
326 col_append_fstr(pinfo->cinfo, COL_INFO, " Data (%u bytes)", data_length);
328 /* Check length is as signalled */
329 if (data_length != (uint32_t)tvb_reported_length_remaining(tvb, offset)) {
330 expert_add_info_format(pinfo, data_ti, &ei_udpcp_payload_wrong_size, "Data length field was %u but %u bytes found",
331 data_length, tvb_reported_length_remaining(tvb, offset));
334 if (global_udpcp_decode_payload_as_soap) {
335 /* Send to XML dissector */
336 tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, offset);
337 call_dissector_only(xml_handle, next_tvb, pinfo, tree, NULL);
340 else {
341 /* Fragmented */
342 if (global_udpcp_reassemble && data_length) {
343 /* Reassembly */
344 /* Set fragmented flag. */
345 bool save_fragmented = pinfo->fragmented;
346 pinfo->fragmented = true;
347 fragment_head *fh;
348 unsigned frag_data_len = tvb_reported_length_remaining(tvb, offset);
350 /* Add this fragment into reassembly */
351 fh = fragment_add_seq_check(&udpcp_reassembly_table, tvb, offset, pinfo,
352 message_id, /* id */
353 GUINT_TO_POINTER(message_id), /* data */
354 fragment_number, /* frag_number */
355 frag_data_len, /* frag_data_len */
356 (fragment_number < (fragment_amount-1)) /* more_frags */
359 bool update_col_info = true;
360 /* See if this completes an SDU */
361 tvbuff_t *next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled UDPCP Payload",
362 fh, &udpcp_frag_items,
363 &update_col_info, udpcp_tree);
364 if (next_tvb) {
365 /* Have reassembled data */
366 proto_item *data_ti = proto_tree_add_item(udpcp_tree, hf_udpcp_payload, next_tvb, 0, -1, ENC_ASCII);
367 col_append_fstr(pinfo->cinfo, COL_INFO, " Reassembled Data (%u bytes)", data_length);
369 /* Check length is as signalled */
370 if (data_length != (uint32_t)tvb_reported_length_remaining(next_tvb, 0)) {
371 expert_add_info_format(pinfo, data_ti, &ei_udpcp_payload_wrong_size, "Data length field was %u but %u bytes found (reassembled)",
372 data_length, tvb_reported_length_remaining(next_tvb, 0));
375 if (global_udpcp_decode_payload_as_soap) {
376 /* Send to XML dissector */
377 call_dissector_only(xml_handle, next_tvb, pinfo, tree, NULL);
381 /* Restore fragmented flag */
382 pinfo->fragmented = save_fragmented;
386 else if (msg_type == ACK_FORMAT) {
387 /* N and S should be set - complain if not */
388 if (!n || !s) {
389 expert_add_info(pinfo, packet_transfer_options_ti, &ei_udpcp_n_s_ack);
392 if (d) {
393 /* Duplicate data detected */
394 proto_item_append_text(packet_transfer_options_ti, " (duplicate)");
395 col_append_str(pinfo->cinfo, COL_INFO, " (duplicate)");
398 col_append_fstr(pinfo->cinfo, COL_INFO, " ACK for Msg_ID=%3u", message_id);
401 /* Look up conversation */
402 if (!PINFO_FD_VISITED(pinfo)) {
403 /* First pass */
404 conversation_t *p_conv;
405 udpcp_conversation_t *p_conv_data;
407 p_conv = find_conversation(pinfo->num, &pinfo->net_dst, &pinfo->net_src,
408 conversation_pt_to_conversation_type(pinfo->ptype),
409 pinfo->destport, pinfo->srcport,
410 0 /* options */);
412 /* Look up data from conversation */
413 p_conv_data = (udpcp_conversation_t *)conversation_get_proto_data(p_conv, proto_udpcp);
415 /* Create new data for conversation data if not found */
416 if (!p_conv_data) {
417 p_conv_data = wmem_new(wmem_file_scope(), udpcp_conversation_t);
419 /* Set initial values */
420 p_conv_data->first_dest_port = pinfo->destport;
421 copy_address(&p_conv_data->first_dest_address, &pinfo->dst);
422 p_conv_data->next_message_id_first = 0;
423 p_conv_data->next_message_id_second = 0;
425 /* SN and ACK tables */
426 p_conv_data->sn_table_first = wmem_tree_new(wmem_file_scope());
427 p_conv_data->ack_table_first = wmem_tree_new(wmem_file_scope());
428 p_conv_data->sn_table_second = wmem_tree_new(wmem_file_scope());
429 p_conv_data->ack_table_second = wmem_tree_new(wmem_file_scope());
431 /* Store in conversation */
432 conversation_add_proto_data(p_conv, proto_udpcp, p_conv_data);
435 /* Check which direction this is in */
436 bool first_dir = (pinfo->destport == p_conv_data->first_dest_port) &&
437 addresses_equal(&pinfo->dst, &p_conv_data->first_dest_address);
439 /* Check for expected sequence number */
440 if (msg_type == DATA_FORMAT) {
441 if (first_dir) {
442 if (message_id != p_conv_data->next_message_id_first) {
443 wmem_tree_insert32(sequence_number_result_table, pinfo->num, GUINT_TO_POINTER(p_conv_data->next_message_id_first));
445 /* Only inc when have seen last fragment */
446 if (fragment_number == fragment_amount-1) {
447 p_conv_data->next_message_id_first = message_id + 1;
450 /* Store SN entry in table */
451 wmem_tree_insert32(p_conv_data->sn_table_first, message_id, GUINT_TO_POINTER(pinfo->num));
453 /* 2nd Direction */
454 else {
455 if (message_id != p_conv_data->next_message_id_second) {
456 wmem_tree_insert32(sequence_number_result_table, pinfo->num, GUINT_TO_POINTER(p_conv_data->next_message_id_second));
458 /* Only inc when have seen last fragment */
459 if (fragment_number == fragment_amount-1) {
460 p_conv_data->next_message_id_second = message_id + 1;
463 /* Store SN entry in table */
464 wmem_tree_insert32(p_conv_data->sn_table_second, message_id, GUINT_TO_POINTER(pinfo->num));
468 if (msg_type == ACK_FORMAT) {
469 /* N.B., directions reversed here to apply to data direction */
470 if (first_dir) {
471 wmem_tree_insert32(p_conv_data->ack_table_first, message_id, GUINT_TO_POINTER(pinfo->num));
473 else {
474 wmem_tree_insert32(p_conv_data->ack_table_second, message_id, GUINT_TO_POINTER(pinfo->num));
478 else {
479 /* Later passes - look up conversation here */
480 conversation_t *p_conv;
481 udpcp_conversation_t *p_conv_data;
483 p_conv = find_conversation(pinfo->num, &pinfo->net_dst, &pinfo->net_src,
484 conversation_pt_to_conversation_type(pinfo->ptype),
485 pinfo->destport, pinfo->srcport,
486 0 /* options */);
488 /* Look up data from conversation */
489 p_conv_data = (udpcp_conversation_t *)conversation_get_proto_data(p_conv, proto_udpcp);
490 if (!p_conv_data) {
491 /* TODO: error if not found? */
492 return offset;
495 /* Check which direction this is in */
496 bool first_dir = (pinfo->destport == p_conv_data->first_dest_port) &&
497 addresses_equal(&pinfo->dst, &p_conv_data->first_dest_address);
500 if (msg_type == DATA_FORMAT) {
501 /* Check for unexpected sequence number, but not if message_id is still 0 (as it may be repeated) */
502 if (message_id > 1) {
503 if (wmem_tree_contains32(sequence_number_result_table, pinfo->num)) {
504 uint32_t seqno = GPOINTER_TO_UINT(wmem_tree_lookup32(sequence_number_result_table, pinfo->num));
505 expert_add_info_format(pinfo, message_id_ti, &ei_udpcp_wrong_sequence_number, "SN %u expected, but found %u instead",
506 seqno, message_id);
510 /* Look for ACK for this data PDU, link or expert info */
511 wmem_tree_t *ack_table = (first_dir) ? p_conv_data->ack_table_second : p_conv_data->ack_table_first;
512 if (wmem_tree_contains32(ack_table, message_id)) {
513 uint32_t ack = GPOINTER_TO_UINT(wmem_tree_lookup32(ack_table, message_id));
514 proto_tree_add_uint(udpcp_tree, hf_udpcp_ack_frame, tvb, 0, 0, ack);
516 else {
517 expert_add_info_format(pinfo, message_id_ti, &ei_udpcp_no_ack, "No ACK seen for this data frame (message_id=%u",
518 message_id);
523 else if (msg_type == ACK_FORMAT) {
524 /* Look up corresponding Data frame, link or expert info */
525 wmem_tree_t *sn_table = (first_dir) ? p_conv_data->sn_table_second : p_conv_data->sn_table_first;
526 if (wmem_tree_contains32(sn_table, message_id)) {
527 uint32_t sn_frame = GPOINTER_TO_UINT(wmem_tree_lookup32(sn_table, message_id));
528 proto_tree_add_uint(udpcp_tree, hf_udpcp_sn_frame, tvb, 0, 0, sn_frame);
530 else {
531 expert_add_info_format(pinfo, message_id_ti, &ei_udpcp_no_sn_frame, "No SN frame seen corresponding to this ACK (message_id=%u",
532 message_id);
537 return offset;
540 void
541 proto_register_udpcp(void)
543 static hf_register_info hf[] = {
544 { &hf_udpcp_checksum,
545 { "Checksum", "udpcp.checksum", FT_UINT32, BASE_HEX,
546 NULL, 0x0, "Adler32 checksum", HFILL }},
547 { &hf_udpcp_msg_type,
548 { "Msg Type", "udpcp.msg-type", FT_UINT8, BASE_HEX,
549 VALS(msg_type_vals), 0xc0, NULL, HFILL }},
550 { &hf_udpcp_version,
551 { "Version", "udpcp.version", FT_UINT8, BASE_HEX,
552 NULL, 0x38, NULL, HFILL }},
554 { &hf_udpcp_packet_transfer_options,
555 { "Packet Transport Options", "udpcp.pto", FT_STRING, BASE_NONE,
556 NULL, 0x0, NULL, HFILL }},
557 { &hf_udpcp_n,
558 { "N", "udpcp.n", FT_UINT8, BASE_HEX,
559 NULL, 0x04, "Along with S bit, indicates whether acknowledgements should be sent", HFILL }},
560 { &hf_udpcp_c,
561 { "C", "udpcp.c", FT_UINT8, BASE_HEX,
562 NULL, 0x02, "When set, the checksum should be valid", HFILL }},
563 { &hf_udpcp_s,
564 { "S", "udpcp.s", FT_UINT8, BASE_HEX,
565 NULL, 0x01, "Along with N bit, indicates whether acknowledgements should be sent", HFILL }},
566 { &hf_udpcp_d,
567 { "D", "udpcp.d", FT_UINT8, BASE_HEX,
568 NULL, 0x80, "For ACK, indicates duplicate ACK", HFILL }},
569 { &hf_udpcp_reserved,
570 { "Reserved", "udpcp.reserved", FT_UINT8, BASE_HEX,
571 NULL, 0x7f, "Shall be set to 0", HFILL }},
573 { &hf_udpcp_fragment_amount,
574 { "Fragment Amount", "udpcp.fragment-amount", FT_UINT8, BASE_DEC,
575 NULL, 0x0, "Total number of fragments of a message", HFILL }},
576 { &hf_udpcp_fragment_number,
577 { "Fragment Number", "udpcp.fragment-number", FT_UINT8, BASE_DEC,
578 NULL, 0x0, "Fragment number of current packet within msg. Starts at 0", HFILL }},
580 { &hf_udpcp_message_id,
581 { "Message ID", "udpcp.message-id", FT_UINT16, BASE_DEC,
582 NULL, 0x0, NULL, HFILL }},
583 { &hf_udpcp_message_data_length,
584 { "Message Data Length", "udpcp.message-data-length", FT_UINT16, BASE_DEC,
585 NULL, 0x0, NULL, HFILL }},
587 { &hf_udpcp_payload,
588 { "Payload", "udpcp.payload", FT_BYTES, BASE_SHOW_ASCII_PRINTABLE,
589 NULL, 0x0, "Complete or reassembled payload", HFILL }},
591 /* Reassembly */
592 { &hf_udpcp_fragment,
593 { "Fragment", "udpcp.fragment", FT_FRAMENUM, BASE_NONE,
594 NULL, 0x0, NULL, HFILL }},
595 { &hf_udpcp_fragments,
596 { "Fragments", "udpcp.fragments", FT_BYTES, BASE_NONE,
597 NULL, 0x0, NULL, HFILL }},
598 { &hf_udpcp_fragment_overlap,
599 { "Fragment overlap", "udpcp.fragment.overlap", FT_BOOLEAN, BASE_NONE,
600 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
601 { &hf_udpcp_fragment_overlap_conflict,
602 { "Conflicting data in fragment overlap", "udpcp.fragment.overlap.conflict",
603 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
604 "Overlapping fragments contained conflicting data", HFILL }},
605 { &hf_udpcp_fragment_multiple_tails,
606 { "Multiple tail fragments found", "udpcp.fragment.multipletails",
607 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
608 "Several tails were found when defragmenting the packet", HFILL }},
609 { &hf_udpcp_fragment_too_long_fragment,
610 { "Fragment too long", "udpcp.fragment.toolongfragment",
611 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
612 "Fragment contained data past end of packet", HFILL }},
613 { &hf_udpcp_fragment_error,
614 { "Defragmentation error", "udpcp.fragment.error", FT_FRAMENUM, BASE_NONE,
615 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
616 { &hf_udpcp_fragment_count,
617 { "Fragment count", "udpcp.fragment.count", FT_UINT32, BASE_DEC,
618 NULL, 0x0, NULL, HFILL }},
619 { &hf_udpcp_reassembled_in,
620 { "Reassembled payload in frame", "udpcp.reassembled_in", FT_FRAMENUM, BASE_NONE,
621 NULL, 0x0, "This payload packet is reassembled in this frame", HFILL }},
622 { &hf_udpcp_reassembled_length,
623 { "Reassembled payload length", "udpcp.reassembled.length", FT_UINT32, BASE_DEC,
624 NULL, 0x0, "The total length of the reassembled payload", HFILL }},
625 { &hf_udpcp_reassembled_data,
626 { "Reassembled data", "udpcp.reassembled.data", FT_BYTES, BASE_NONE,
627 NULL, 0x0, "The reassembled payload", HFILL }},
629 { &hf_udpcp_ack_frame,
630 { "Ack Frame", "udpcp.ack-frame", FT_FRAMENUM, BASE_NONE,
631 NULL, 0x0, "Frame that ACKs this data", HFILL }},
632 { &hf_udpcp_sn_frame,
633 { "SN Frame", "udpcp.sn-frame", FT_FRAMENUM, BASE_NONE,
634 NULL, 0x0, "Data frame ACKd by this one", HFILL }},
637 static int *ett[] = {
638 &ett_udpcp,
639 &ett_udpcp_packet_transfer_options,
640 &ett_udpcp_fragments,
641 &ett_udpcp_fragment
644 static ei_register_info ei[] = {
645 { &ei_udpcp_checksum_should_be_zero, { "udpcp.checksum-not-zero", PI_CHECKSUM, PI_WARN, "Checksum should be zero if !C.", EXPFILL }},
646 { &ei_udpcp_d_not_zero_for_data, { "udpcp.d-not-zero-data", PI_SEQUENCE, PI_ERROR, "D should be zero for data frames", EXPFILL }},
647 { &ei_udpcp_reserved_not_zero, { "udpcp.reserved-not-zero", PI_MALFORMED, PI_WARN, "Reserved bits not zero", EXPFILL }},
648 { &ei_udpcp_n_s_ack, { "udpcp.n-s-set-ack", PI_MALFORMED, PI_ERROR, "N or S set for ACK frame", EXPFILL }},
649 { &ei_udpcp_payload_wrong_size, { "udpcp.payload-wrong-size", PI_MALFORMED, PI_ERROR, "Payload seen does not match size field", EXPFILL }},
650 { &ei_udpcp_wrong_sequence_number, { "udpcp.sequence-number-wrong", PI_SEQUENCE, PI_WARN, "Unexpected sequence number", EXPFILL }},
651 { &ei_udpcp_no_ack, { "udpcp.no-ack", PI_SEQUENCE, PI_WARN, "No ACK seen for data frame", EXPFILL }},
652 { &ei_udpcp_no_sn_frame, { "udpcp.no-sn-frame", PI_SEQUENCE, PI_WARN, "No SN frame seen for ACK", EXPFILL }},
655 module_t *udpcp_module;
656 expert_module_t *expert_udpcp;
658 proto_udpcp = proto_register_protocol("UDPCP", "UDPCP", "udpcp");
659 proto_register_field_array(proto_udpcp, hf, array_length(hf));
660 proto_register_subtree_array(ett, array_length(ett));
661 expert_udpcp = expert_register_protocol(proto_udpcp);
662 expert_register_field_array(expert_udpcp, ei, array_length(ei));
664 udpcp_handle = register_dissector("udpcp", dissect_udpcp, proto_udpcp);
666 /* Register reassembly table. */
667 reassembly_table_register(&udpcp_reassembly_table,
668 &udpcp_reassembly_table_functions);
670 /* Preferences */
671 udpcp_module = prefs_register_protocol(proto_udpcp, NULL);
673 /* Payload reassembly */
674 prefs_register_bool_preference(udpcp_module, "attempt_reassembly",
675 "Reassemble payload",
677 &global_udpcp_reassemble);
679 /* Whether to try XML dissector on payload.
680 * TODO: are there any other payload types we might see? */
681 prefs_register_bool_preference(udpcp_module, "attempt_xml_decode",
682 "Call XML dissector for payload",
684 &global_udpcp_decode_payload_as_soap);
686 sequence_number_result_table = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
689 static void
690 apply_udpcp_prefs(void)
692 global_udpcp_port_range = prefs_get_range_value("udpcp", "udp.port");
695 void
696 proto_reg_handoff_udpcp(void)
698 dissector_add_uint_range_with_preference("udp.port", "", udpcp_handle);
699 apply_udpcp_prefs();
701 xml_handle = find_dissector("xml");
705 * Editor modelines - https://www.wireshark.org/tools/modelines.html
707 * Local variables:
708 * c-basic-offset: 4
709 * tab-width: 8
710 * indent-tabs-mode: nil
711 * End:
713 * vi: set shiftwidth=4 tabstop=8 expandtab:
714 * :indentSize=4:tabSize=8:noTabs=true: