Coverage Report

Created: 2026-05-14 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-udpcp.c
Line
Count
Source
1
/* packet-udpcp.c
2
 *
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)
6
 *
7
 * Wireshark - Network traffic analyzer
8
 * By Gerald Combs <gerald@wireshark.org>
9
 * Copyright 1998 Gerald Combs
10
 *
11
 *
12
 * SPDX-License-Identifier: GPL-2.0-or-later
13
 */
14
15
/* TODO:
16
 * - Calculate/verify Checksum field
17
  */
18
19
#include "config.h"
20
21
#include <epan/conversation.h>
22
#include <epan/reassemble.h>
23
#include <epan/expert.h>
24
#include <epan/prefs.h>
25
26
27
void proto_register_udpcp(void);
28
29
static int proto_udpcp;
30
31
static int hf_udpcp_checksum;
32
static int hf_udpcp_msg_type;
33
static int hf_udpcp_version;
34
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;
41
42
static int hf_udpcp_fragment_amount;
43
static int hf_udpcp_fragment_number;
44
45
static int hf_udpcp_message_id;
46
static int hf_udpcp_message_data_length;
47
48
static int hf_udpcp_payload;
49
50
static int hf_udpcp_ack_frame;
51
static int hf_udpcp_sn_frame;
52
53
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;
66
67
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;
73
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"
89
};
90
91
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;
100
101
static dissector_handle_t udpcp_handle;
102
103
104
void proto_reg_handoff_udpcp (void);
105
106
/* User definable values */
107
static range_t *global_udpcp_port_range;
108
109
0
#define DATA_FORMAT 0x01
110
0
#define ACK_FORMAT  0x02
111
112
113
static const value_string msg_type_vals[] = {
114
  { DATA_FORMAT,   "Data Packet" },
115
  { ACK_FORMAT,    "Ack Packet" },
116
  { 0,     NULL }
117
};
118
119
typedef struct {
120
    /* Protocol is bi-directional, so need to distinguish */
121
    uint16_t first_dest_port;
122
    address first_dest_address;
123
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;
129
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;
134
135
136
/* Framenum -> expected_sequence_number */
137
static wmem_tree_t *sequence_number_result_table;
138
139
140
/* Reassembly table. */
141
static reassembly_table udpcp_reassembly_table;
142
143
static void *udpcp_temporary_key(const packet_info *pinfo _U_, const uint32_t id _U_, const void *data)
144
0
{
145
0
    return (void *)data;
146
0
}
147
148
static void *udpcp_persistent_key(const packet_info *pinfo _U_, const uint32_t id _U_,
149
                                     const void *data)
150
0
{
151
0
    return (void *)data;
152
0
}
153
154
static void udpcp_free_temporary_key(void *ptr _U_)
155
0
{
156
0
}
157
158
static void udpcp_free_persistent_key(void *ptr _U_)
159
0
{
160
0
}
161
162
static reassembly_table_functions udpcp_reassembly_table_functions =
163
{
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
170
};
171
172
173
/**************************************************************************/
174
/* Preferences state                                                      */
175
/**************************************************************************/
176
177
/* Reassemble by default */
178
static bool global_udpcp_reassemble = true;
179
180
/* By default do try to decode payload as XML/SOAP */
181
static bool global_udpcp_decode_payload_as_soap = true;
182
183
184
static dissector_handle_t xml_handle;
185
186
/******************************/
187
/* Main dissection function.  */
188
static int
189
dissect_udpcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
190
0
{
191
0
    proto_tree *udpcp_tree;
192
0
    proto_item *root_ti;
193
0
    int offset = 0;
194
195
    /* Must be at least 12 bytes */
196
0
    if (tvb_reported_length(tvb) < 12) {
197
0
        return 0;
198
0
    }
199
200
    /* Has to be Data or Ack format. */
201
0
    uint32_t msg_type = tvb_get_uint8(tvb, 4) >> 6;
202
0
    if ((msg_type != DATA_FORMAT) && (msg_type != ACK_FORMAT)) {
203
0
        return 0;
204
0
    }
205
206
    /* Protocol column */
207
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "UDPCP");
208
209
    /* Protocol root */
210
0
    root_ti = proto_tree_add_item(tree, proto_udpcp, tvb, offset, -1, ENC_NA);
211
0
    udpcp_tree = proto_item_add_subtree(root_ti, ett_udpcp);
212
213
    /* Checksum */
214
0
    uint32_t checksum;
215
0
    proto_item *checksum_ti = proto_tree_add_item_ret_uint(udpcp_tree, hf_udpcp_checksum, tvb, offset, 4, ENC_BIG_ENDIAN, &checksum);
216
0
    offset += 4;
217
218
    /* Msg-type */
219
0
    proto_tree_add_item_ret_uint(udpcp_tree, hf_udpcp_msg_type, tvb, offset, 1, ENC_BIG_ENDIAN, &msg_type);
220
0
    col_add_str(pinfo->cinfo, COL_INFO,
221
0
                (msg_type == DATA_FORMAT) ? "[Data] " : "[Ack]  ");
222
0
    proto_item_append_text(root_ti, (msg_type == DATA_FORMAT) ? " [Data]" : " [Ack]");
223
224
    /* Version */
225
0
    proto_tree_add_item(udpcp_tree, hf_udpcp_version, tvb, offset, 1, ENC_BIG_ENDIAN);
226
227
228
    /***************************/
229
    /* Packet Transfer Options */
230
0
    proto_item *packet_transfer_options_ti =
231
0
            proto_tree_add_string_format(udpcp_tree, hf_udpcp_packet_transfer_options, tvb, offset, 2,
232
0
                                         "", "Packet Transfer Options (");
233
0
    proto_tree *packet_transfer_options_tree =
234
0
            proto_item_add_subtree(packet_transfer_options_ti, ett_udpcp_packet_transfer_options);
235
0
    uint32_t n, c, s, d;
236
237
    /* N */
238
0
    proto_tree_add_item_ret_uint(packet_transfer_options_tree, hf_udpcp_n, tvb, offset, 1, ENC_BIG_ENDIAN, &n);
239
0
    if (n) {
240
0
        proto_item_append_text(packet_transfer_options_ti, "N");
241
0
    }
242
243
    /* C */
244
0
    proto_tree_add_item_ret_uint(packet_transfer_options_tree, hf_udpcp_c, tvb, offset, 1, ENC_BIG_ENDIAN, &c);
245
0
    if (c) {
246
0
       proto_item_append_text(packet_transfer_options_ti, "C");
247
0
    }
248
0
    if (!c && checksum) {
249
        /* Expert info warning that checksum should be 0 if !c */
250
0
        expert_add_info(pinfo, checksum_ti, &ei_udpcp_checksum_should_be_zero);
251
0
    }
252
253
    /* S */
254
0
    proto_tree_add_item_ret_uint(packet_transfer_options_tree, hf_udpcp_s, tvb, offset, 1, ENC_BIG_ENDIAN, &s);
255
0
    offset++;
256
0
    if (s) {
257
0
        proto_item_append_text(packet_transfer_options_ti, "S");
258
0
    }
259
260
    /* D */
261
0
    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
0
    if (d) {
263
0
        proto_item_append_text(packet_transfer_options_ti, "D");
264
0
    }
265
    /* Expert info if D not zero for data */
266
0
    if ((msg_type == DATA_FORMAT) && d) {
267
0
        expert_add_info(pinfo, d_ti, &ei_udpcp_d_not_zero_for_data);
268
0
    }
269
270
    /* Reserved */
271
0
    uint32_t reserved;
272
0
    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
0
    offset++;
274
    /* Expert info if reserved not 0 */
275
0
    if (reserved) {
276
0
        expert_add_info(pinfo, reserved_ti, &ei_udpcp_reserved_not_zero);
277
0
    }
278
279
0
    proto_item_append_text(packet_transfer_options_ti, ")");
280
    /*************************/
281
282
283
    /* Fragment Amount & Fragment Number */
284
0
    uint32_t fragment_amount, fragment_number;
285
0
    proto_tree_add_item_ret_uint(udpcp_tree, hf_udpcp_fragment_amount, tvb, offset, 1, ENC_BIG_ENDIAN, &fragment_amount);
286
0
    offset++;
287
0
    proto_tree_add_item_ret_uint(udpcp_tree, hf_udpcp_fragment_number, tvb, offset, 1, ENC_BIG_ENDIAN, &fragment_number);
288
0
    offset++;
289
290
    /* Message ID & Message Data Length */
291
0
    uint32_t message_id;
292
0
    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
0
    col_append_fstr(pinfo->cinfo, COL_INFO, " Msg_ID=%3u", message_id);
294
0
    offset += 2;
295
0
    uint32_t data_length;
296
0
    proto_tree_add_item_ret_uint(udpcp_tree, hf_udpcp_message_data_length, tvb, offset, 2, ENC_BIG_ENDIAN, &data_length);
297
0
    offset += 2;
298
299
0
    if (msg_type == DATA_FORMAT) {
300
0
        if (!data_length) {
301
            /* This could just be a sync frame */
302
0
            if (!message_id && !n && !s) {
303
0
                col_append_str(pinfo->cinfo, COL_INFO, "  [Sync]");
304
0
            }
305
0
        }
306
307
        /* Show if/when this frame should be acknowledged */
308
0
        if (!n && !s) {
309
0
            proto_item_append_text(packet_transfer_options_ti, " (All packets ACKd)");
310
0
        }
311
0
        else if (!n && s) {
312
0
            proto_item_append_text(packet_transfer_options_ti, " (Last fragment ACKd)");
313
0
        }
314
0
        if (n) {
315
0
            proto_item_append_text(packet_transfer_options_ti, " (Not ACKd)");
316
0
        }
317
318
        /* Show fragment numbering.  Ignore confusing 0-based fragment numbering.. */
319
0
        col_append_fstr(pinfo->cinfo, COL_INFO, "  [Frag %u/%u]",
320
0
                        fragment_number+1, fragment_amount);
321
322
        /* There is data */
323
0
        if ((fragment_amount == 1) && (fragment_number == 0) && data_length) {
324
            /* Not fragmented - show payload now */
325
0
            proto_item *data_ti = proto_tree_add_item(udpcp_tree, hf_udpcp_payload, tvb, offset, -1, ENC_NA);
326
0
            col_append_fstr(pinfo->cinfo, COL_INFO, "  Data (%u bytes)", data_length);
327
328
            /* Check length is as signalled */
329
0
            if (data_length != (uint32_t)tvb_reported_length_remaining(tvb, offset)) {
330
0
                expert_add_info_format(pinfo, data_ti, &ei_udpcp_payload_wrong_size, "Data length field was %u but %u bytes found",
331
0
                                       data_length, tvb_reported_length_remaining(tvb, offset));
332
0
            }
333
334
0
            if (global_udpcp_decode_payload_as_soap) {
335
                /* Send to XML dissector */
336
0
                tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, offset);
337
0
                call_dissector_only(xml_handle, next_tvb, pinfo, tree, NULL);
338
0
            }
339
0
        }
340
0
        else {
341
            /* Fragmented */
342
0
            if (global_udpcp_reassemble && data_length) {
343
                /* Reassembly */
344
                /* Set fragmented flag. */
345
0
                bool save_fragmented = pinfo->fragmented;
346
0
                pinfo->fragmented = true;
347
0
                fragment_head *fh;
348
0
                unsigned frag_data_len = tvb_reported_length_remaining(tvb, offset);
349
350
                /* Add this fragment into reassembly */
351
0
                fh = fragment_add_seq_check(&udpcp_reassembly_table, tvb, offset, pinfo,
352
0
                                            message_id,                                    /* id */
353
0
                                            GUINT_TO_POINTER(message_id),                  /* data */
354
0
                                            fragment_number,                               /* frag_number */
355
0
                                            frag_data_len,                                 /* frag_data_len */
356
0
                                            (fragment_number < (fragment_amount-1))        /* more_frags */
357
0
                                            );
358
359
0
                bool update_col_info = true;
360
                /* See if this completes an SDU */
361
0
                tvbuff_t *next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled UDPCP Payload",
362
0
                                                              fh, &udpcp_frag_items,
363
0
                                                              &update_col_info, udpcp_tree);
364
0
                if (next_tvb) {
365
                    /* Have reassembled data */
366
0
                    proto_item *data_ti = proto_tree_add_item(udpcp_tree, hf_udpcp_payload, next_tvb, 0, -1, ENC_NA);
367
0
                    col_append_fstr(pinfo->cinfo, COL_INFO, "  Reassembled Data (%u bytes)", data_length);
368
369
                    /* Check length is as signalled */
370
0
                    if (data_length != (uint32_t)tvb_reported_length_remaining(next_tvb, 0)) {
371
0
                        expert_add_info_format(pinfo, data_ti, &ei_udpcp_payload_wrong_size, "Data length field was %u but %u bytes found (reassembled)",
372
0
                                               data_length, tvb_reported_length_remaining(next_tvb, 0));
373
0
                    }
374
375
0
                    if (global_udpcp_decode_payload_as_soap) {
376
                        /* Send to XML dissector */
377
0
                        call_dissector_only(xml_handle, next_tvb, pinfo, tree, NULL);
378
0
                    }
379
0
                }
380
381
                /* Restore fragmented flag */
382
0
                pinfo->fragmented = save_fragmented;
383
0
            }
384
0
        }
385
0
    }
386
0
    else if (msg_type == ACK_FORMAT) {
387
        /* N and S should be set - complain if not */
388
0
        if (!n || !s) {
389
0
            expert_add_info(pinfo, packet_transfer_options_ti, &ei_udpcp_n_s_ack);
390
0
        }
391
392
0
        if (d) {
393
            /* Duplicate data detected */
394
0
            proto_item_append_text(packet_transfer_options_ti, " (duplicate)");
395
0
            col_append_str(pinfo->cinfo, COL_INFO, " (duplicate)");
396
0
        }
397
398
0
        col_append_fstr(pinfo->cinfo, COL_INFO, "  ACK for Msg_ID=%3u", message_id);
399
0
    }
400
401
    /* Look up conversation */
402
0
    if (!PINFO_FD_VISITED(pinfo)) {
403
        /* First pass */
404
0
        conversation_t *p_conv;
405
0
        udpcp_conversation_t *p_conv_data;
406
407
0
        p_conv = find_conversation(pinfo->num, &pinfo->net_dst, &pinfo->net_src,
408
0
                                   conversation_pt_to_conversation_type(pinfo->ptype),
409
0
                                   pinfo->destport, pinfo->srcport,
410
0
                                   0 /* options */);
411
412
        /* Look up data from conversation */
413
0
        p_conv_data = (udpcp_conversation_t *)conversation_get_proto_data(p_conv, proto_udpcp);
414
415
        /* Create new data for conversation data if not found */
416
0
        if (!p_conv_data) {
417
0
            p_conv_data = wmem_new(wmem_file_scope(), udpcp_conversation_t);
418
419
            /* Set initial values */
420
0
            p_conv_data->first_dest_port = pinfo->destport;
421
0
            copy_address(&p_conv_data->first_dest_address, &pinfo->dst);
422
0
            p_conv_data->next_message_id_first = 0;
423
0
            p_conv_data->next_message_id_second = 0;
424
425
            /* SN and ACK tables */
426
0
            p_conv_data->sn_table_first = wmem_tree_new(wmem_file_scope());
427
0
            p_conv_data->ack_table_first = wmem_tree_new(wmem_file_scope());
428
0
            p_conv_data->sn_table_second = wmem_tree_new(wmem_file_scope());
429
0
            p_conv_data->ack_table_second = wmem_tree_new(wmem_file_scope());
430
431
            /* Store in conversation */
432
0
            conversation_add_proto_data(p_conv, proto_udpcp, p_conv_data);
433
0
        }
434
435
        /* Check which direction this is in */
436
0
        bool first_dir = (pinfo->destport == p_conv_data->first_dest_port) &&
437
0
                             addresses_equal(&pinfo->dst, &p_conv_data->first_dest_address);
438
439
        /* Check for expected sequence number */
440
0
        if (msg_type == DATA_FORMAT) {
441
0
            if (first_dir) {
442
0
                if (message_id != p_conv_data->next_message_id_first) {
443
0
                    wmem_tree_insert32(sequence_number_result_table, pinfo->num, GUINT_TO_POINTER(p_conv_data->next_message_id_first));
444
0
                }
445
                /* Only inc when have seen last fragment */
446
0
                if (fragment_number == fragment_amount-1) {
447
0
                    p_conv_data->next_message_id_first = message_id + 1;
448
0
                }
449
450
                /* Store SN entry in table */
451
0
                wmem_tree_insert32(p_conv_data->sn_table_first, message_id, GUINT_TO_POINTER(pinfo->num));
452
0
            }
453
            /* 2nd Direction */
454
0
            else {
455
0
                if (message_id != p_conv_data->next_message_id_second) {
456
0
                    wmem_tree_insert32(sequence_number_result_table, pinfo->num, GUINT_TO_POINTER(p_conv_data->next_message_id_second));
457
0
                }
458
                /* Only inc when have seen last fragment */
459
0
                if (fragment_number == fragment_amount-1) {
460
0
                    p_conv_data->next_message_id_second = message_id + 1;
461
0
                }
462
463
                /* Store SN entry in table */
464
0
                wmem_tree_insert32(p_conv_data->sn_table_second, message_id, GUINT_TO_POINTER(pinfo->num));
465
0
            }
466
0
        }
467
468
0
        if (msg_type == ACK_FORMAT) {
469
            /* N.B., directions reversed here to apply to data direction */
470
0
            if (first_dir) {
471
0
                wmem_tree_insert32(p_conv_data->ack_table_first, message_id, GUINT_TO_POINTER(pinfo->num));
472
0
            }
473
0
            else {
474
0
                wmem_tree_insert32(p_conv_data->ack_table_second, message_id, GUINT_TO_POINTER(pinfo->num));
475
0
            }
476
0
        }
477
0
    }
478
0
    else {
479
        /* Later passes - look up conversation here */
480
0
        conversation_t *p_conv;
481
0
        udpcp_conversation_t *p_conv_data;
482
483
0
        p_conv = find_conversation(pinfo->num, &pinfo->net_dst, &pinfo->net_src,
484
0
                                   conversation_pt_to_conversation_type(pinfo->ptype),
485
0
                                   pinfo->destport, pinfo->srcport,
486
0
                                   0 /* options */);
487
488
        /* Look up data from conversation */
489
0
        p_conv_data = (udpcp_conversation_t *)conversation_get_proto_data(p_conv, proto_udpcp);
490
0
        if (!p_conv_data) {
491
            /* TODO: error if not found? */
492
0
            return offset;
493
0
        }
494
495
        /* Check which direction this is in */
496
0
        bool first_dir = (pinfo->destport == p_conv_data->first_dest_port) &&
497
0
                             addresses_equal(&pinfo->dst, &p_conv_data->first_dest_address);
498
499
500
0
        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
0
            if (message_id > 1) {
503
0
                if (wmem_tree_contains32(sequence_number_result_table, pinfo->num)) {
504
0
                    uint32_t seqno = GPOINTER_TO_UINT(wmem_tree_lookup32(sequence_number_result_table, pinfo->num));
505
0
                    expert_add_info_format(pinfo, message_id_ti, &ei_udpcp_wrong_sequence_number, "SN %u expected, but found %u instead",
506
0
                                           seqno, message_id);
507
0
                }
508
0
            }
509
510
            /* Look for ACK for this data PDU, link or expert info */
511
0
            wmem_tree_t *ack_table = (first_dir) ? p_conv_data->ack_table_second : p_conv_data->ack_table_first;
512
0
            if (wmem_tree_contains32(ack_table, message_id)) {
513
0
                uint32_t ack = GPOINTER_TO_UINT(wmem_tree_lookup32(ack_table, message_id));
514
0
                proto_tree_add_uint(udpcp_tree,  hf_udpcp_ack_frame, tvb, 0, 0, ack);
515
0
            }
516
0
            else {
517
0
                expert_add_info_format(pinfo, message_id_ti, &ei_udpcp_no_ack, "No ACK seen for this data frame (message_id=%u",
518
0
                                       message_id);
519
520
0
            }
521
522
0
        }
523
0
        else if (msg_type == ACK_FORMAT) {
524
            /* Look up corresponding Data frame, link or expert info */
525
0
            wmem_tree_t *sn_table = (first_dir) ? p_conv_data->sn_table_second : p_conv_data->sn_table_first;
526
0
            if (wmem_tree_contains32(sn_table, message_id)) {
527
0
                uint32_t sn_frame = GPOINTER_TO_UINT(wmem_tree_lookup32(sn_table, message_id));
528
0
                proto_tree_add_uint(udpcp_tree,  hf_udpcp_sn_frame, tvb, 0, 0, sn_frame);
529
0
            }
530
0
            else {
531
0
                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
0
                                       message_id);
533
0
            }
534
0
        }
535
0
    }
536
537
0
    return offset;
538
0
}
539
540
void
541
proto_register_udpcp(void)
542
15
{
543
15
  static hf_register_info hf[] = {
544
15
      { &hf_udpcp_checksum,
545
15
        { "Checksum", "udpcp.checksum", FT_UINT32, BASE_HEX,
546
15
          NULL, 0x0, "Adler32 checksum", HFILL }},
547
15
      { &hf_udpcp_msg_type,
548
15
        { "Msg Type", "udpcp.msg-type", FT_UINT8, BASE_HEX,
549
15
          VALS(msg_type_vals), 0xc0, NULL, HFILL }},
550
15
      { &hf_udpcp_version,
551
15
        { "Version", "udpcp.version", FT_UINT8, BASE_HEX,
552
15
          NULL, 0x38, NULL, HFILL }},
553
554
15
      { &hf_udpcp_packet_transfer_options,
555
15
        { "Packet Transport Options", "udpcp.pto", FT_STRING, BASE_NONE,
556
15
        NULL, 0x0, NULL, HFILL }},
557
15
      { &hf_udpcp_n,
558
15
        { "N", "udpcp.n", FT_UINT8, BASE_HEX,
559
15
          NULL, 0x04, "Along with S bit, indicates whether acknowledgements should be sent", HFILL }},
560
15
      { &hf_udpcp_c,
561
15
        { "C", "udpcp.c", FT_UINT8, BASE_HEX,
562
15
          NULL, 0x02, "When set, the checksum should be valid", HFILL }},
563
15
      { &hf_udpcp_s,
564
15
        { "S", "udpcp.s", FT_UINT8, BASE_HEX,
565
15
          NULL, 0x01, "Along with N bit, indicates whether acknowledgements should be sent", HFILL }},
566
15
      { &hf_udpcp_d,
567
15
        { "D", "udpcp.d", FT_UINT8, BASE_HEX,
568
15
          NULL, 0x80, "For ACK, indicates duplicate ACK", HFILL }},
569
15
      { &hf_udpcp_reserved,
570
15
        { "Reserved", "udpcp.reserved", FT_UINT8, BASE_HEX,
571
15
          NULL, 0x7f, "Shall be set to 0", HFILL }},
572
573
15
      { &hf_udpcp_fragment_amount,
574
15
        { "Fragment Amount", "udpcp.fragment-amount", FT_UINT8, BASE_DEC,
575
15
          NULL, 0x0, "Total number of fragments of a message", HFILL }},
576
15
      { &hf_udpcp_fragment_number,
577
15
        { "Fragment Number", "udpcp.fragment-number", FT_UINT8, BASE_DEC,
578
15
          NULL, 0x0, "Fragment number of current packet within msg.  Starts at 0", HFILL }},
579
580
15
      { &hf_udpcp_message_id,
581
15
        { "Message ID", "udpcp.message-id", FT_UINT16, BASE_DEC,
582
15
          NULL, 0x0, NULL, HFILL }},
583
15
      { &hf_udpcp_message_data_length,
584
15
        { "Message Data Length", "udpcp.message-data-length", FT_UINT16, BASE_DEC,
585
15
          NULL, 0x0, NULL, HFILL }},
586
587
15
      { &hf_udpcp_payload,
588
15
        { "Payload", "udpcp.payload", FT_BYTES, BASE_SHOW_ASCII_PRINTABLE,
589
15
          NULL, 0x0, "Complete or reassembled payload", HFILL }},
590
591
      /* Reassembly */
592
15
      { &hf_udpcp_fragment,
593
15
        { "Fragment", "udpcp.fragment", FT_FRAMENUM, BASE_NONE,
594
15
          NULL, 0x0, NULL, HFILL }},
595
15
      { &hf_udpcp_fragments,
596
15
        { "Fragments", "udpcp.fragments", FT_BYTES, BASE_NONE,
597
15
          NULL, 0x0, NULL, HFILL }},
598
15
      { &hf_udpcp_fragment_overlap,
599
15
        { "Fragment overlap", "udpcp.fragment.overlap", FT_BOOLEAN, BASE_NONE,
600
15
          NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
601
15
      { &hf_udpcp_fragment_overlap_conflict,
602
15
        { "Conflicting data in fragment overlap", "udpcp.fragment.overlap.conflict",
603
15
          FT_BOOLEAN, BASE_NONE, NULL, 0x0,
604
15
          "Overlapping fragments contained conflicting data", HFILL }},
605
15
      { &hf_udpcp_fragment_multiple_tails,
606
15
        { "Multiple tail fragments found", "udpcp.fragment.multipletails",
607
15
          FT_BOOLEAN, BASE_NONE, NULL, 0x0,
608
15
          "Several tails were found when defragmenting the packet", HFILL }},
609
15
      { &hf_udpcp_fragment_too_long_fragment,
610
15
        { "Fragment too long", "udpcp.fragment.toolongfragment",
611
15
          FT_BOOLEAN, BASE_NONE, NULL, 0x0,
612
15
          "Fragment contained data past end of packet", HFILL }},
613
15
      { &hf_udpcp_fragment_error,
614
15
        { "Defragmentation error", "udpcp.fragment.error", FT_FRAMENUM, BASE_NONE,
615
15
          NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
616
15
      { &hf_udpcp_fragment_count,
617
15
        { "Fragment count", "udpcp.fragment.count", FT_UINT32, BASE_DEC,
618
15
          NULL, 0x0, NULL, HFILL }},
619
15
      { &hf_udpcp_reassembled_in,
620
15
        { "Reassembled payload in frame", "udpcp.reassembled_in", FT_FRAMENUM, BASE_NONE,
621
15
        NULL, 0x0, "This payload packet is reassembled in this frame", HFILL }},
622
15
      { &hf_udpcp_reassembled_length,
623
15
        { "Reassembled payload length", "udpcp.reassembled.length", FT_UINT32, BASE_DEC,
624
15
          NULL, 0x0, "The total length of the reassembled payload", HFILL }},
625
15
      { &hf_udpcp_reassembled_data,
626
15
        { "Reassembled data", "udpcp.reassembled.data", FT_BYTES, BASE_NONE,
627
15
          NULL, 0x0, "The reassembled payload", HFILL }},
628
629
15
      { &hf_udpcp_ack_frame,
630
15
        { "Ack Frame", "udpcp.ack-frame", FT_FRAMENUM, BASE_NONE,
631
15
          NULL, 0x0, "Frame that ACKs this data", HFILL }},
632
15
      { &hf_udpcp_sn_frame,
633
15
        { "SN Frame", "udpcp.sn-frame", FT_FRAMENUM, BASE_NONE,
634
15
          NULL, 0x0, "Data frame ACKd by this one", HFILL }},
635
15
    };
636
637
15
    static int *ett[] = {
638
15
        &ett_udpcp,
639
15
        &ett_udpcp_packet_transfer_options,
640
15
        &ett_udpcp_fragments,
641
15
        &ett_udpcp_fragment
642
15
    };
643
644
15
    static ei_register_info ei[] = {
645
15
        { &ei_udpcp_checksum_should_be_zero, { "udpcp.checksum-not-zero", PI_CHECKSUM, PI_WARN, "Checksum should be zero if !C.", EXPFILL }},
646
15
        { &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
15
        { &ei_udpcp_reserved_not_zero,       { "udpcp.reserved-not-zero", PI_MALFORMED, PI_WARN, "Reserved bits not zero", EXPFILL }},
648
15
        { &ei_udpcp_n_s_ack,                 { "udpcp.n-s-set-ack", PI_MALFORMED, PI_ERROR, "N or S set for ACK frame", EXPFILL }},
649
15
        { &ei_udpcp_payload_wrong_size,      { "udpcp.payload-wrong-size", PI_MALFORMED, PI_ERROR, "Payload seen does not match size field", EXPFILL }},
650
15
        { &ei_udpcp_wrong_sequence_number,   { "udpcp.sequence-number-wrong", PI_SEQUENCE, PI_WARN, "Unexpected sequence number", EXPFILL }},
651
15
        { &ei_udpcp_no_ack,                  { "udpcp.no-ack", PI_SEQUENCE, PI_WARN, "No ACK seen for data frame", EXPFILL }},
652
15
        { &ei_udpcp_no_sn_frame,             { "udpcp.no-sn-frame", PI_SEQUENCE, PI_WARN, "No SN frame seen for ACK", EXPFILL }},
653
15
    };
654
655
15
    module_t *udpcp_module;
656
15
    expert_module_t *expert_udpcp;
657
658
15
    proto_udpcp = proto_register_protocol("UDPCP", "UDPCP", "udpcp");
659
15
    proto_register_field_array(proto_udpcp, hf, array_length(hf));
660
15
    proto_register_subtree_array(ett, array_length(ett));
661
15
    expert_udpcp = expert_register_protocol(proto_udpcp);
662
15
    expert_register_field_array(expert_udpcp, ei, array_length(ei));
663
664
15
    udpcp_handle = register_dissector("udpcp", dissect_udpcp, proto_udpcp);
665
666
    /* Register reassembly table. */
667
15
    reassembly_table_register(&udpcp_reassembly_table,
668
15
                              &udpcp_reassembly_table_functions);
669
670
    /* Preferences */
671
15
    udpcp_module = prefs_register_protocol(proto_udpcp, NULL);
672
673
    /* Payload reassembly */
674
15
    prefs_register_bool_preference(udpcp_module, "attempt_reassembly",
675
15
                                   "Reassemble payload",
676
15
                                   "",
677
15
                                   &global_udpcp_reassemble);
678
679
    /* Whether to try XML dissector on payload.
680
     * TODO: are there any other payload types we might see? */
681
15
    prefs_register_bool_preference(udpcp_module, "attempt_xml_decode",
682
15
        "Call XML dissector for payload",
683
15
        "",
684
15
        &global_udpcp_decode_payload_as_soap);
685
686
15
    sequence_number_result_table = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
687
15
}
688
689
static void
690
apply_udpcp_prefs(void)
691
15
{
692
15
    global_udpcp_port_range = prefs_get_range_value("udpcp", "udp.port");
693
15
}
694
695
void
696
proto_reg_handoff_udpcp(void)
697
15
{
698
15
    dissector_add_uint_range_with_preference("udp.port", "", udpcp_handle);
699
15
    apply_udpcp_prefs();
700
701
15
    xml_handle = find_dissector("xml");
702
15
}
703
704
/*
705
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
706
 *
707
 * Local variables:
708
 * c-basic-offset: 4
709
 * tab-width: 8
710
 * indent-tabs-mode: nil
711
 * End:
712
 *
713
 * vi: set shiftwidth=4 tabstop=8 expandtab:
714
 * :indentSize=4:tabSize=8:noTabs=true:
715
 */