Coverage Report

Created: 2026-07-12 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-gsm_cbch.c
Line
Count
Source
1
/* packet-gsm_cbch.c
2
 * Routines for GSM CBCH dissection - A.K.A. 3GPP 44.012 (GSM 04.12)
3
 *
4
 * Copyright 2011, Mike Morrin <mike.morrin [AT] ipaccess.com>
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
#include "config.h"
14
15
#include <epan/packet.h>
16
#include <epan/reassemble.h>
17
#include <epan/expert.h>
18
19
void proto_register_gsm_cbch(void);
20
void proto_reg_handoff_gsm_cbch(void);
21
22
6
#define CBCH_FRAGMENT_SIZE 22
23
24
static const value_string block_type_lpd_strings[] = {
25
    { 0x00, "NOT Cell Broadcast"},
26
    { 0x01, "Cell Broadcast"},
27
    { 0x02, "NOT Cell Broadcast"},
28
    { 0x03, "NOT Cell Broadcast"},
29
    {    0, NULL}
30
};
31
32
static const value_string block_type_seq_num_values[] = {
33
    { 0x00, "First Block"},
34
    { 0x01, "Second Block"},
35
    { 0x02, "Third Block"},
36
    { 0x03, "Fourth Block"},
37
    { 0x08, "First Schedule Block"},
38
    { 0x0F, "Null message"},
39
    {    0, NULL}
40
};
41
42
static const value_string sched_type_values[] = {
43
    { 0x00, "messages formatted as specified in subclause 3.5 of 3GPP 44.012"},
44
    {    0, NULL}
45
};
46
47
/* Initialize the protocol and registered fields */
48
static int proto_cbch;
49
50
static int hf_gsm_cbch_spare_bit;
51
static int hf_gsm_cbch_lpd;
52
static int hf_gsm_cbch_lb;
53
static int hf_gsm_cbch_seq_num;
54
static int hf_gsm_cbch_sched_type;
55
static int hf_gsm_cbch_sched_begin_slot;
56
static int hf_gsm_cbch_sched_spare;
57
static int hf_gsm_cbch_sched_end_slot;
58
static int hf_gsm_cbch_slot;
59
/* static int hf_gsm_cbch_sched_msg_id; */
60
static int hf_gsm_cbch_padding;
61
static int hf_gsm_cbch_block;
62
63
/* These fields are used when reassembling cbch fragments
64
 */
65
static int hf_cbch_fragments;
66
static int hf_cbch_fragment;
67
static int hf_cbch_fragment_overlap;
68
static int hf_cbch_fragment_overlap_conflict;
69
static int hf_cbch_fragment_multiple_tails;
70
static int hf_cbch_fragment_too_long_fragment;
71
static int hf_cbch_fragment_error;
72
static int hf_cbch_fragment_count;
73
static int hf_cbch_reassembled_in;
74
static int hf_cbch_reassembled_length;
75
76
/* Initialize the subtree pointers */
77
static int ett_cbch_msg;
78
static int ett_schedule_msg;
79
static int ett_schedule_new_msg;
80
static int ett_cbch_fragment;
81
static int ett_cbch_fragments;
82
83
static expert_field ei_gsm_cbch_sched_end_slot;
84
static expert_field ei_gsm_cbch_seq_num_null;
85
static expert_field ei_gsm_cbch_seq_num_reserved;
86
static expert_field ei_gsm_cbch_lpd;
87
88
static dissector_handle_t cbs_handle;
89
90
/* reassembly of CHCH blocks */
91
static reassembly_table cbch_block_reassembly_table;
92
93
/* Structure needed for the fragmentation routines in reassemble.c
94
 */
95
static const fragment_items cbch_frag_items = {
96
    &ett_cbch_fragment,
97
    &ett_cbch_fragments,
98
    &hf_cbch_fragments,
99
    &hf_cbch_fragment,
100
    &hf_cbch_fragment_overlap,
101
    &hf_cbch_fragment_overlap_conflict,
102
    &hf_cbch_fragment_multiple_tails,
103
    &hf_cbch_fragment_too_long_fragment,
104
    &hf_cbch_fragment_error,
105
    &hf_cbch_fragment_count,
106
    &hf_cbch_reassembled_in,
107
    &hf_cbch_reassembled_length,
108
    /* Reassembled data field */
109
    NULL,
110
    "blocks"
111
};
112
113
static const range_string gsm_cbch_sched_begin_slot_rvals[] = {
114
    { 0,     0,     "Out of range (ignoring message)" },
115
    { 1,     1,     "(apparently) Scheduled Scheduling Message" },
116
    { 2,     48,    "(apparently) Unscheduled Scheduling Message" },
117
    { 49,    0xFF,  "Out of range (ignoring message)" },
118
119
    { 0x00, 0x00,  NULL },
120
};
121
122
static void
123
dissect_schedule_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *top_tree)
124
0
{
125
0
    unsigned    len, offset  = 0;
126
0
    uint8_t     octet1, i, k = 0;
127
0
    uint8_t     sched_begin, sched_end, new_slots[48];
128
0
    bool        valid_message   = true;
129
0
    uint16_t    other_slots[48];
130
0
    proto_item *item            = NULL, *schedule_item = NULL;
131
0
    proto_tree *sched_tree      = NULL, *sched_subtree = NULL;
132
133
0
    len = tvb_reported_length(tvb);
134
135
0
    col_append_str(pinfo->cinfo, COL_INFO, " CBCH Schedule Message ");
136
137
0
    schedule_item = proto_tree_add_protocol_format(top_tree, proto_cbch, tvb, 0, -1,
138
0
                                                   "GSM CBCH Schedule Message");
139
140
0
    sched_tree = proto_item_add_subtree(schedule_item, ett_schedule_msg);
141
142
0
    proto_tree_add_item(sched_tree, hf_gsm_cbch_sched_type, tvb, offset, 1, ENC_BIG_ENDIAN);
143
0
    octet1 = tvb_get_uint8(tvb, offset);
144
0
    if (0 == (octet1 & 0xC0))
145
0
    {
146
0
        proto_item* slot_item;
147
0
        sched_begin = octet1 & 0x3F;
148
0
        proto_tree_add_item(sched_tree, hf_gsm_cbch_sched_begin_slot, tvb, offset++, 1, ENC_BIG_ENDIAN);
149
0
        if ((sched_begin < 1) || (sched_begin > 48))
150
0
        {
151
0
            valid_message = false;
152
0
        }
153
0
        proto_tree_add_item(sched_tree, hf_gsm_cbch_sched_spare, tvb, offset, 1, ENC_BIG_ENDIAN);
154
0
        sched_end = tvb_get_uint8(tvb, offset);
155
0
        slot_item = proto_tree_add_item(sched_tree, hf_gsm_cbch_sched_end_slot, tvb, offset++, 1, ENC_BIG_ENDIAN);
156
0
        if (sched_end < sched_begin)
157
0
        {
158
0
            expert_add_info(pinfo, slot_item, &ei_gsm_cbch_sched_end_slot);
159
0
            valid_message = false;
160
0
        }
161
162
0
        if (valid_message)
163
0
        {
164
            /* build an array of new messages */
165
0
            memset(&new_slots,   0xFF, sizeof(new_slots));
166
0
            memset(&other_slots, 0xFF, sizeof(other_slots));
167
168
            /* iterate over the octets */
169
0
            for (i=0; i<6; i++)
170
0
            {
171
0
                uint8_t j;
172
0
                octet1 = tvb_get_uint8(tvb, offset++);
173
174
                /* iterate over the bits */
175
0
                for (j=0; j<8; j++)
176
0
                {
177
0
                    if (octet1 & (0x80>>j))
178
0
                    {
179
0
                        new_slots[k++] = (i<<3) + j + 1;
180
0
                    }
181
0
                }
182
0
            }
183
            /* print the array of new messages */
184
0
            sched_subtree = proto_tree_add_subtree_format(sched_tree, tvb, offset-6, 6, ett_schedule_new_msg, &item,
185
0
                                                            "This schedule contains %d slots with new messages", k);
186
0
            for (i=0; i<k; i++)
187
0
            {
188
0
                DISSECTOR_ASSERT(new_slots[i] <= 48);
189
0
                octet1 = tvb_get_uint8(tvb, offset);
190
0
                if ((octet1 & 0x80) == 0x80)
191
0
                {
192
                    /* MDT 1 */
193
0
                    uint8_t octet2;
194
0
                    uint16_t msg_id;
195
196
0
                    octet2 = tvb_get_uint8(tvb, offset + 1);
197
0
                    msg_id = ((octet1 &0x7F) << 8) + octet2;
198
0
                    proto_tree_add_uint_format_value(sched_subtree, hf_gsm_cbch_slot, tvb, offset, 2, new_slots[i],
199
0
                                        "%d, Message ID: %d, First transmission of an SMSCB within the Schedule Period",
200
0
                                        new_slots[i], msg_id);
201
0
                    offset +=2;
202
0
                    other_slots[new_slots[i] - 1] = msg_id;
203
0
                }
204
0
                else if ((octet1 & 0xC0) == 0)
205
0
                {
206
                    /* MDT 00 */
207
0
                    if (octet1 == 0)
208
0
                    {
209
0
                        proto_tree_add_uint_format_value(sched_subtree, hf_gsm_cbch_slot, tvb, offset++, 1, new_slots[i],
210
0
                                            "%d, Repeat of non-existent slot %d",
211
0
                                            new_slots[i], octet1);
212
0
                    }
213
0
                    else if (octet1 < new_slots[i])
214
0
                    {
215
0
                        proto_tree_add_uint_format_value(sched_subtree, hf_gsm_cbch_slot, tvb, offset++, 1, new_slots[i],
216
0
                                            "%d, Message ID: %d, Repeat of Slot %d",
217
0
                                            new_slots[i], other_slots[octet1 - 1], octet1);
218
0
                        other_slots[new_slots[i] - 1] = other_slots[octet1 - 1];
219
0
                    }
220
0
                    else
221
0
                    {
222
0
                        proto_tree_add_uint_format_value(sched_subtree, hf_gsm_cbch_slot, tvb, offset++, 1, new_slots[i],
223
0
                                            "%d, Apparent forward reference to slot %d",
224
0
                                            new_slots[i], octet1);
225
0
                    }
226
0
                }
227
0
                else if (octet1 == 0x40)
228
0
                {
229
                    /* MDT 010000000 */
230
0
                    proto_tree_add_uint_format_value(sched_subtree, hf_gsm_cbch_slot, tvb, offset++, 1, new_slots[i],
231
0
                                    "%d Free Message Slot, optional reading", new_slots[i]);
232
0
                    other_slots[new_slots[i] - 1] = 0xFFFE;
233
0
                }
234
0
                else if (octet1 == 0x41)
235
0
                {
236
                    /* MDT 010000001 */
237
0
                    proto_tree_add_uint_format_value(sched_subtree, hf_gsm_cbch_slot, tvb, offset++, 1, new_slots[i],
238
0
                                     "%d Free Message Slot, reading advised", new_slots[i]);
239
0
                    other_slots[new_slots[i] - 1] = 0xFFFE;
240
0
                }
241
0
                else
242
0
                {
243
                    /* reserved MDT */
244
0
                    proto_tree_add_uint_format_value(sched_subtree, hf_gsm_cbch_slot, tvb, offset, 1, new_slots[i],
245
0
                                     "%d reserved MDT: %x", new_slots[i], octet1);
246
0
                    other_slots[new_slots[i] - 1] = 0xFFFE;
247
0
                }
248
0
            }
249
0
            proto_item_set_end(item, tvb, offset);
250
251
            /* print schedule of other messages */
252
0
            sched_subtree = proto_tree_add_subtree(sched_tree, tvb, offset, 0,
253
0
                                ett_schedule_new_msg, &item, "Other message slots in this schedule");
254
0
            for (k=0; offset < len; )
255
0
            {
256
                /* XXX I don't know if a message can validly contain more than
257
                 * 48 slots, but that's the size of the array we create so cap
258
                 * it there to avoid uninitialized memory errors (see bug
259
                 * https://gitlab.com/wireshark/wireshark/-/issues/9270) */
260
0
                if (sched_end > 48)
261
0
                    sched_end = 48;
262
0
                while ((k<sched_end) && (other_slots[k]!=0xFFFF))
263
0
                {
264
0
                    k++;
265
0
                }
266
0
                if (k >= sched_end)
267
0
                    break;
268
269
0
                octet1 = tvb_get_uint8(tvb, offset);
270
0
                if ((octet1 & 0x80) == 0x80)
271
0
                {
272
0
                    if ((offset+1)<len)
273
0
                    {
274
                        /* MDT 1 */
275
0
                        uint8_t octet2;
276
0
                        uint16_t msg_id;
277
278
0
                        octet2 = tvb_get_uint8(tvb, offset + 1);
279
0
                        msg_id = ((octet1 &0x7F) << 8) + octet2;
280
0
                        other_slots[k] = msg_id;
281
0
                        k++;
282
0
                        proto_tree_add_uint_format_value(sched_subtree, hf_gsm_cbch_slot, tvb, offset, 2, k,
283
0
                                            "%d, Message: %d, First transmission of an SMSCB within the Schedule Period",
284
0
                                            k, msg_id);
285
0
                        offset +=2;
286
0
                    }
287
0
                    else
288
0
                    {
289
                        /* I'm not sure what's supposed to be dissected in this
290
                         * case. Perhaps just an expert info is appropriate?
291
                         * Regardless, we need to increment k to prevent an
292
                         * infinite loop, see
293
                         * https://gitlab.com/wireshark/wireshark/-/issues/8730
294
                         */
295
0
                        ++k;
296
0
                    }
297
0
                }
298
0
                else if (octet1 && ((octet1 & 0xC0) == 0))
299
0
                {
300
                    /* MDT 00 */
301
0
                    if (octet1 < k)
302
0
                    {
303
0
                        other_slots[k] = other_slots[octet1 - 1];
304
0
                        k++;
305
0
                        proto_tree_add_uint_format_value(sched_subtree, hf_gsm_cbch_slot, tvb, offset++, 1, k,
306
0
                                            "%d, Message ID: %d, Repeat of Slot %d",
307
0
                                            k, other_slots[octet1 - 1], octet1);
308
0
                    }
309
0
                    else
310
0
                    {
311
0
                        k++;
312
0
                        proto_tree_add_uint_format_value(sched_subtree, hf_gsm_cbch_slot, tvb, offset++, 1, k,
313
0
                                            "%d, Apparent forward reference to slot %d",
314
0
                                            k, octet1);
315
0
                    }
316
0
                }
317
0
                else if (octet1 == 0x40)
318
0
                {
319
                    /* MDT 010000000 */
320
0
                    k++;
321
0
                    proto_tree_add_uint_format_value(sched_subtree, hf_gsm_cbch_slot, tvb, offset++, 1, k,
322
0
                            "%d Free Message Slot, optional reading", k);
323
0
                }
324
0
                else if (octet1 == 0x41)
325
0
                {
326
                    /* MDT 010000001 */
327
0
                    k++;
328
0
                    proto_tree_add_uint_format_value(sched_subtree, hf_gsm_cbch_slot, tvb, offset++, 1, k,
329
0
                            "%d Free Message Slot, reading advised", k);
330
0
                }
331
0
                else
332
0
                {
333
                    /* reserved MDT */
334
0
                    k++;
335
0
                    proto_tree_add_uint_format_value(sched_subtree, hf_gsm_cbch_slot, tvb, offset, 1, k,
336
0
                            "%d reserved MDT: %x", k, octet1);
337
0
                }
338
0
            }
339
0
            proto_item_set_end(item, tvb, offset);
340
0
            proto_tree_add_item(sched_tree, hf_gsm_cbch_padding, tvb, offset, -1, ENC_NA);
341
0
        }
342
0
    }
343
0
}
344
345
static int
346
dissect_cbch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data  _U_)
347
13
{
348
13
    fragment_head *frag_data = NULL;
349
13
    uint8_t        octet, lb, lpd, seq_num;
350
13
    uint32_t       offset;
351
13
    proto_item    *cbch_item, *lpd_item, *seq_item;
352
13
    proto_tree    *cbch_tree;
353
13
    tvbuff_t      *reass_tvb = NULL, *msg_tvb = NULL;
354
355
13
    offset = 0;
356
13
    octet  = tvb_get_uint8(tvb, offset);
357
358
    /*
359
     * create the protocol tree
360
     */
361
13
    cbch_item = proto_tree_add_protocol_format(tree, proto_cbch, tvb, 0, -1,
362
13
                                               "GSM CBCH - Block (0x%02x)", octet&3);
363
364
13
    col_append_str(pinfo->cinfo, COL_PROTOCOL, " CBCH");
365
366
13
    cbch_tree = proto_item_add_subtree(cbch_item, ett_cbch_msg);
367
368
13
    proto_tree_add_uint(cbch_tree, hf_gsm_cbch_block, tvb, offset, 1, octet);
369
370
13
    proto_tree_add_uint(cbch_tree, hf_gsm_cbch_spare_bit, tvb, offset, 1, octet);
371
13
    lpd_item = proto_tree_add_uint(cbch_tree, hf_gsm_cbch_lpd,       tvb, offset, 1, octet);
372
13
    proto_tree_add_uint(cbch_tree, hf_gsm_cbch_lb,        tvb, offset, 1, octet);
373
13
    seq_item = proto_tree_add_uint(cbch_tree, hf_gsm_cbch_seq_num,   tvb, offset, 1, octet);
374
13
    seq_num =  octet & 0x0F;
375
13
    lpd     = (octet & 0x60) >> 5;
376
13
    lb      = (octet & 0x10) >> 4;
377
378
13
    if (lpd == 1)
379
9
    {
380
9
        switch (seq_num)
381
9
        {
382
4
        case 0x00:
383
4
        case 0x08:
384
4
            pinfo->fragmented = true;
385
            /* we should have a unique ID for the reassembled page, but we don't really have anything from the protocol...
386
               The GSM frame number div 4 might be used for this, but it has not been passed to this layer and does not
387
               exist at all if the message is being passed over the RSL interface.
388
               So we just use 0... */
389
390
            /* after reassembly we will need to know if this is a scheduling message,
391
               this information is carried in the initial sequence number, not the payload,
392
               so we prepend the reassembly with the octet containing the initial sequence number
393
               to allow later dissection of the payload */
394
4
            frag_data = fragment_add_seq_check(&cbch_block_reassembly_table,
395
4
                                               tvb, offset, pinfo, 0, NULL,
396
4
                                               seq_num & 0x03, CBCH_FRAGMENT_SIZE + 1, !lb);
397
4
            reass_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CBCH message",
398
4
                                                 frag_data, &cbch_frag_items, NULL, cbch_tree);
399
4
            break;
400
401
1
        case 0x01:
402
2
        case 0x02:
403
2
        case 0x03:
404
2
            pinfo->fragmented = true;
405
2
            offset++; /* step to beginning of payload */
406
2
            frag_data = fragment_add_seq_check(&cbch_block_reassembly_table,
407
2
                                               tvb, offset, pinfo, 0, NULL,
408
2
                                               seq_num, CBCH_FRAGMENT_SIZE, !lb);
409
2
            reass_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CBCH message",
410
2
                                                 frag_data, &cbch_frag_items, NULL, cbch_tree);
411
2
            break;
412
413
1
        case 0x0F:
414
1
            expert_add_info(pinfo, seq_item, &ei_gsm_cbch_seq_num_null);
415
1
            call_data_dissector(tvb, pinfo, cbch_tree);
416
1
            break;
417
418
2
        default:
419
2
            expert_add_info(pinfo, seq_item, &ei_gsm_cbch_seq_num_reserved);
420
2
            call_data_dissector(tvb, pinfo, cbch_tree);
421
2
            break;
422
9
        }
423
9
        if (reass_tvb)
424
4
        {
425
            /* Reassembled */
426
427
            /* the tvb contains the reassembled message prepended with the sequence number octet from the first block
428
               We use this to determine whether this is a normal message or a scheduling message */
429
4
            offset = 0;
430
431
4
            octet = tvb_get_uint8(reass_tvb, offset++);
432
4
            msg_tvb = tvb_new_subset_remaining(reass_tvb, offset);
433
434
4
            if (octet & 0x08)
435
0
            {
436
0
                dissect_schedule_message(msg_tvb, pinfo, tree);
437
0
            }
438
4
            else
439
4
            {
440
4
                call_dissector(cbs_handle, msg_tvb, pinfo, tree);
441
4
            }
442
4
        }
443
9
    }
444
4
    else
445
4
    {
446
4
        expert_add_info(pinfo, lpd_item, &ei_gsm_cbch_lpd);
447
4
        call_data_dissector(tvb, pinfo, cbch_tree);
448
4
    }
449
13
    return tvb_captured_length(tvb);
450
13
}
451
452
/* Register the protocol with Wireshark */
453
void
454
proto_register_gsm_cbch(void)
455
15
{
456
    /* Setup list of header fields */
457
15
    static hf_register_info hf_smscb[] =
458
15
        {
459
15
            { &hf_gsm_cbch_spare_bit,
460
15
              { "GSM CBCH spare bit",  "gsm_cbch.block_type.spare",
461
15
                FT_UINT8, BASE_HEX, NULL, 0x80,
462
15
                NULL, HFILL}
463
15
            },
464
15
            { &hf_gsm_cbch_lpd,
465
15
              { "GSM CBCH Link Protocol Discriminator",  "gsm_cbch.block_type.lpd",
466
15
                FT_UINT8, BASE_DEC, VALS(block_type_lpd_strings), 0x60,
467
15
                NULL, HFILL}
468
15
            },
469
15
            { &hf_gsm_cbch_lb,
470
15
              { "GSM CBCH Last Block", "gsm_cbch.block_type.lb",
471
15
                FT_UINT8, BASE_DEC, NULL, 0x10,
472
15
                NULL, HFILL}
473
15
            },
474
15
            { &hf_gsm_cbch_seq_num,
475
15
              { "GSM CBCH Sequence Number",  "gsm_cbch.block_type.seq_num",
476
15
                FT_UINT8, BASE_DEC, VALS(block_type_seq_num_values), 0x0F,
477
15
                NULL, HFILL}
478
15
            },
479
15
            { &hf_gsm_cbch_sched_type,
480
15
              { "GSM CBCH Schedule Type", "gsm_cbch.sched_type",
481
15
                FT_UINT8, BASE_DEC, VALS(sched_type_values), 0xC0,
482
15
                NULL, HFILL}
483
15
            },
484
15
            { &hf_gsm_cbch_sched_begin_slot,
485
15
              { "GSM CBCH Schedule Begin slot", "gsm_cbch.schedule_begin",
486
15
              FT_UINT8, BASE_DEC|BASE_RANGE_STRING, RVALS(gsm_cbch_sched_begin_slot_rvals), 0x3F,
487
15
                NULL, HFILL}
488
15
            },
489
15
            { &hf_gsm_cbch_sched_spare,
490
15
              { "GSM CBCH Schedule Spare Bits", "gsm_cbch.sched_spare",
491
15
                FT_UINT8, BASE_DEC, NULL, 0xC0,
492
15
                NULL, HFILL}
493
15
            },
494
15
            { &hf_gsm_cbch_sched_end_slot,
495
15
              { "GSM CBCH Schedule End Slot",   "gsm_cbch.sched_end",
496
15
                FT_UINT8, BASE_DEC, NULL, 0x3F,
497
15
                NULL, HFILL}
498
15
            },
499
15
            { &hf_gsm_cbch_slot,
500
15
              { "Slot",   "gsm_cbch.slot",
501
15
                FT_UINT8, BASE_DEC, NULL, 0x0,
502
15
                NULL, HFILL}
503
15
            },
504
15
            { &hf_gsm_cbch_padding,
505
15
              { "Padding",   "gsm_cbch.padding",
506
15
                FT_BYTES, BASE_NONE, NULL, 0x0,
507
15
                NULL, HFILL}
508
15
            },
509
15
            { &hf_gsm_cbch_block,
510
15
              { "CBCH Block",   "gsm_cbch.block",
511
15
                FT_UINT8, BASE_HEX, NULL, 0x0,
512
15
                NULL, HFILL}
513
15
            },
514
515
#if 0
516
            { &hf_gsm_cbch_sched_msg_id,
517
              { "GSM CBCH Schedule Message ID", "gsm_cbch.sched_msg_id",
518
                FT_UINT16, BASE_DEC, NULL, 0x0,
519
                NULL, HFILL}
520
            },
521
#endif
522
            /* Fragment fields
523
             */
524
15
            { &hf_cbch_fragment_overlap,
525
15
              {   "Fragment overlap",
526
15
                  "gsm_cbch.fragment.overlap",
527
15
                  FT_BOOLEAN, BASE_NONE, NULL, 0x0,
528
15
                  "Fragment overlaps with other fragments", HFILL
529
15
              }
530
15
            },
531
15
            { &hf_cbch_fragment_overlap_conflict,
532
15
              {   "Conflicting data in fragment overlap",
533
15
                  "gsm_cbch.fragment.overlap.conflict",
534
15
                  FT_BOOLEAN, BASE_NONE, NULL, 0x0,
535
15
                  "Overlapping fragments contained conflicting data", HFILL
536
15
              }
537
15
            },
538
15
            { &hf_cbch_fragment_multiple_tails,
539
15
              {   "Multiple tail fragments found",
540
15
                  "gsm_cbch.fragment.multipletails",
541
15
                  FT_BOOLEAN, BASE_NONE, NULL, 0x0,
542
15
                  "Several tails were found when defragmenting the packet", HFILL
543
15
              }
544
15
            },
545
15
            { &hf_cbch_fragment_too_long_fragment,
546
15
              {   "Fragment too long",
547
15
                  "gsm_cbch.fragment.toolongfragment",
548
15
                  FT_BOOLEAN, BASE_NONE, NULL, 0x0,
549
15
                  "Fragment contained data past end of packet", HFILL
550
15
              }
551
15
            },
552
15
            { &hf_cbch_fragment_error,
553
15
              {   "Defragmentation error",
554
15
                  "gsm_cbch.fragment.error",
555
15
                  FT_FRAMENUM, BASE_NONE, NULL, 0x0,
556
15
                  "Defragmentation error due to illegal fragments", HFILL
557
15
              }
558
15
            },
559
15
            { &hf_cbch_fragment_count,
560
15
              {   "Fragmentation count",
561
15
                  "gsm_cbch.fragment.count",
562
15
                  FT_UINT32, BASE_DEC, NULL, 0x0,
563
15
                  "Count of CBCH Fragments", HFILL
564
15
              }
565
15
            },
566
15
            { &hf_cbch_reassembled_in,
567
15
              {   "Reassembled in",
568
15
                  "gsm_cbch.reassembled.in",
569
15
                  FT_FRAMENUM, BASE_NONE, NULL, 0x0,
570
15
                  "CBCH fragments are reassembled in the given packet", HFILL
571
15
              }
572
15
            },
573
15
            { &hf_cbch_reassembled_length,
574
15
              {   "Reassembled message length is one less than indicated here",
575
15
                  "gsm_cbch.reassembled.length",
576
15
                  FT_UINT32, BASE_DEC, NULL, 0x0,
577
15
                  "The total length of the reassembled message", HFILL
578
15
              }
579
15
            },
580
15
            { &hf_cbch_fragment,
581
15
              {   "CBCH Fragment",
582
15
                  "gsm_cbch.fragment",
583
15
                  FT_FRAMENUM, BASE_NONE, NULL, 0x0,
584
15
                  NULL, HFILL
585
15
              }
586
15
            },
587
15
            { &hf_cbch_fragments,
588
15
              {   "CBCH Fragments",
589
15
                  "gsm_cbch.fragments",
590
15
                  FT_NONE, BASE_NONE, NULL, 0x0,
591
15
                  NULL, HFILL
592
15
              }
593
15
            }
594
15
        };
595
596
/* Setup protocol subtree array */
597
15
    static int *ett[] = {
598
15
        &ett_cbch_msg,
599
15
        &ett_schedule_msg,
600
15
        &ett_schedule_new_msg,
601
15
        &ett_cbch_fragment,
602
15
        &ett_cbch_fragments,
603
15
    };
604
605
15
    expert_module_t* expert_cbch;
606
607
15
    static ei_register_info ei[] = {
608
15
        { &ei_gsm_cbch_sched_end_slot, { "gsm_cbch.sched_end.bad_range", PI_PROTOCOL, PI_WARN, "End Slot Number less than Begin Slot Number: ignoring message", EXPFILL }},
609
15
        { &ei_gsm_cbch_seq_num_null, { "gsm_cbch.block_type.seq_num.null", PI_PROTOCOL, PI_NOTE, "NULL message", EXPFILL }},
610
15
        { &ei_gsm_cbch_seq_num_reserved, { "gsm_cbch.block_type.seq_num.reserved", PI_PROTOCOL, PI_NOTE, "Reserved Sequence Number", EXPFILL }},
611
15
        { &ei_gsm_cbch_lpd, { "gsm_cbch.block_type.lpd.invalid", PI_PROTOCOL, PI_WARN, "Invalid Link Protocol Discriminator", EXPFILL }},
612
15
    };
613
614
    /* Register the protocol name and description */
615
15
    proto_cbch = proto_register_protocol("GSM Cell Broadcast Channel", "GSM CBCH", "gsm_cbch");
616
15
    proto_register_field_array(proto_cbch, hf_smscb, array_length(hf_smscb));
617
15
    expert_cbch = expert_register_protocol(proto_cbch);
618
15
    expert_register_field_array(expert_cbch, ei, array_length(ei));
619
620
    /* subdissector code */
621
15
    register_dissector("gsm_cbch", dissect_cbch, proto_cbch);
622
623
15
    reassembly_table_register(&cbch_block_reassembly_table,
624
15
                          &addresses_reassembly_table_functions);
625
626
    /* subtree array */
627
15
    proto_register_subtree_array(ett, array_length(ett));
628
15
}
629
630
void
631
proto_reg_handoff_gsm_cbch(void)
632
15
{
633
15
    cbs_handle  = find_dissector_add_dependency("gsm_cbs", proto_cbch);
634
15
}
635
636
/*
637
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
638
 *
639
 * Local variables:
640
 * c-basic-offset: 4
641
 * tab-width: 8
642
 * indent-tabs-mode: nil
643
 * End:
644
 *
645
 * vi: set shiftwidth=4 tabstop=8 expandtab:
646
 * :indentSize=4:tabSize=8:noTabs=true:
647
 */