2 * Routines for GSM CBCH dissection - A.K.A. 3GPP 44.012 (GSM 04.12)
4 * Copyright 2011, Mike Morrin <mike.morrin [AT] ipaccess.com>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #include <epan/packet.h>
32 #include <epan/reassemble.h>
33 #include "packet-cell_broadcast.h"
35 #define CBCH_FRAGMENT_SIZE 22
37 const value_string block_type_lpd_strings[] = {
38 { 0x00, "NOT Cell Broadcast"},
39 { 0x01, "Cell Broadcast"},
40 { 0x02, "NOT Cell Broadcast"},
41 { 0x03, "NOT Cell Broadcast"},
45 const value_string block_type_seq_num_values[] = {
46 { 0x00, "First Block"},
47 { 0x01, "Second Block"},
48 { 0x02, "Third Block"},
49 { 0x03, "Fourth Block"},
50 { 0x08, "First Schedule Block"},
51 { 0xFF, "Null message"},
55 const value_string sched_type_values[] = {
56 { 0x00, "messages formatted as specified in subclause 3.5 of 3GPP 44.012"},
57 { 0xFF, "Unknown schedule message format"},
61 /* Initialize the protocol and registered fields */
62 static int proto_cbch = -1;
64 static int hf_gsm_cbch_spare_bit = -1;
65 static int hf_gsm_cbch_lpd = -1;
66 static int hf_gsm_cbch_lb = -1;
67 static int hf_gsm_cbch_seq_num = -1;
68 static int hf_gsm_cbch_sched_type = -1;
69 static int hf_gsm_cbch_sched_begin_slot = -1;
70 static int hf_gsm_cbch_sched_spare = -1;
71 static int hf_gsm_cbch_sched_end_slot = -1;
72 static int hf_gsm_cbch_sched_msg_id = -1;
74 /* These fields are used when reassembling cbch fragments
76 static int hf_cbch_fragments = -1;
77 static int hf_cbch_fragment = -1;
78 static int hf_cbch_fragment_overlap = -1;
79 static int hf_cbch_fragment_overlap_conflict = -1;
80 static int hf_cbch_fragment_multiple_tails = -1;
81 static int hf_cbch_fragment_too_long_fragment = -1;
82 static int hf_cbch_fragment_error = -1;
83 static int hf_cbch_fragment_count = -1;
84 static int hf_cbch_reassembled_in = -1;
85 static int hf_cbch_reassembled_length = -1;
87 /* Initialize the subtree pointers */
88 static gint ett_cbch_msg = -1;
89 static gint ett_schedule_msg = -1;
90 static gint ett_schedule_new_msg = -1;
91 static gint ett_cbch_fragment = -1;
92 static gint ett_cbch_fragments = -1;
94 static dissector_handle_t data_handle;
95 static dissector_handle_t cbs_handle;
97 /* reassembly of CHCH blocks */
98 static GHashTable *fragment_block_table = NULL;
99 static GHashTable *reassembled_message_table = NULL;
101 /* Structure needed for the fragmentation routines in reassemble.c
103 static const fragment_items cbch_frag_items = {
108 &hf_cbch_fragment_overlap,
109 &hf_cbch_fragment_overlap_conflict,
110 &hf_cbch_fragment_multiple_tails,
111 &hf_cbch_fragment_too_long_fragment,
112 &hf_cbch_fragment_error,
113 &hf_cbch_fragment_count,
114 &hf_cbch_reassembled_in,
115 &hf_cbch_reassembled_length,
120 cbch_defragment_init(void)
122 fragment_table_init(&fragment_block_table);
123 reassembled_table_init(&reassembled_message_table);
127 dissect_schedule_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *top_tree)
129 guint8 octet1, i, j, k = 0;
130 guint8 len, sched_begin, sched_end, new_slots[48];
132 gboolean valid_message = TRUE;
133 guint16 other_slots[48];
134 proto_item *item = NULL, *schedule_item = NULL;
135 proto_tree *sched_tree = NULL, *sched_subtree = NULL;
137 len = tvb_length(tvb);
139 col_append_str(pinfo->cinfo, COL_INFO, " CBCH Schedule Message ");
141 schedule_item = proto_tree_add_protocol_format(top_tree, proto_cbch, tvb, 0, len,
142 "GSM CBCH Schedule Message");
144 sched_tree = proto_item_add_subtree(schedule_item, ett_schedule_msg);
146 proto_tree_add_item(sched_tree, hf_gsm_cbch_sched_type, tvb, offset, 1, ENC_BIG_ENDIAN);
147 octet1 = tvb_get_guint8(tvb, offset);
148 if (0 == (octet1 & 0xC0))
150 sched_begin = octet1 & 0x3F;
151 proto_tree_add_item(sched_tree, hf_gsm_cbch_sched_begin_slot, tvb, offset++, 1, ENC_BIG_ENDIAN);
152 if (1 == sched_begin)
154 proto_tree_add_text(sched_tree, tvb, offset - 1, 1, "(apparently) Scheduled Scheduling Message");
156 else if ((2 <= sched_begin) && (48 >= sched_begin))
158 proto_tree_add_text(sched_tree, tvb, offset - 1, 1, "(apparently) Unscheduled Scheduling Message");
162 proto_tree_add_text(sched_tree, tvb, offset - 1, 1, "Begin Slot Number out of range: ignoring message");
163 valid_message = FALSE;
165 proto_tree_add_item(sched_tree, hf_gsm_cbch_sched_spare, tvb, offset, 1, ENC_BIG_ENDIAN);
166 sched_end = tvb_get_guint8(tvb, offset);
167 proto_tree_add_item(sched_tree, hf_gsm_cbch_sched_end_slot, tvb, offset++, 1, ENC_BIG_ENDIAN);
168 if (sched_end < sched_begin)
170 proto_tree_add_text(sched_tree, tvb, offset - 1, 1, "End Slot Number less than Begin Slot Number: ignoring message");
171 valid_message = FALSE;
176 /* build an array of new messages */
177 memset(&new_slots, 0xFF, sizeof(new_slots));
178 memset(&other_slots, 0xFF, sizeof(other_slots));
180 /* iterate over the octets */
183 octet1 = tvb_get_guint8(tvb, offset++);
185 /* iterate over the bits */
188 if (octet1 & (0x80>>j))
190 new_slots[k++] = (i<<3) + j + 1;
194 /* print the array of new messages */
195 item = proto_tree_add_text(sched_tree, tvb, offset-6, 6, "This schedule contains %d slots with new messages", k);
196 sched_subtree = proto_item_add_subtree(item, ett_schedule_new_msg);
199 DISSECTOR_ASSERT(new_slots[i] < 48);
200 octet1 = tvb_get_guint8(tvb, offset);
201 if ((octet1 & 0x80) == 0x80)
207 octet2 = tvb_get_guint8(tvb, offset + 1);
208 msg_id = ((octet1 &0x7F) << 8) + octet2;
209 proto_tree_add_text(sched_subtree, tvb, offset, 2,
210 "Slot: %d, Message ID: %d, First transmission of an SMSCB within the Schedule Period",
211 new_slots[i], msg_id);
213 other_slots[new_slots[i] - 1] = msg_id;
215 else if ((octet1 & 0xC0) == 0)
218 if (octet1 < new_slots[i])
220 proto_tree_add_text(sched_subtree, tvb, offset++, 1,
221 "Slot: %d, Message ID: %d, Repeat of Slot %d",
222 new_slots[i], other_slots[octet1 - 1], octet1);
223 other_slots[new_slots[i] - 1] = other_slots[octet1 - 1];
227 proto_tree_add_text(sched_subtree, tvb, offset++, 1,
228 "Slot: %d, Apparent forward reference to slot %d",
229 new_slots[i], octet1);
232 else if (octet1 == 0x40)
235 proto_tree_add_text(sched_subtree, tvb, offset++, 1, "Slot: %d Free Message Slot, optional reading", new_slots[k]);
236 other_slots[new_slots[i] - 1] = 0xFFFE;
238 else if (octet1 == 0x41)
241 proto_tree_add_text(sched_subtree, tvb, offset++, 1, "Slot: %d Free Message Slot, reading advised", new_slots[k]);
242 other_slots[new_slots[i] - 1] = 0xFFFE;
247 proto_tree_add_text(sched_subtree, tvb, offset, 1, "Slot: %d reseved MDT: %x", new_slots[k], octet1);
248 other_slots[new_slots[i] - 1] = 0xFFFE;
251 proto_item_set_end(item, tvb, offset);
253 /* print schedule of other messages */
254 item = proto_tree_add_text(sched_tree, tvb, offset, 0, "Other message slots in this schedule");
255 sched_subtree = proto_item_add_subtree(item, ett_schedule_new_msg);
256 for (k=0; offset<len; j++)
258 while ((other_slots[k]!=0xFFFF) && (k<sched_end))
265 octet1 = tvb_get_guint8(tvb, offset);
266 if ((octet1 & 0x80) == 0x80)
274 octet2 = tvb_get_guint8(tvb, offset + 1);
275 msg_id = ((octet1 &0x7F) << 8) + octet2;
276 other_slots[k] = msg_id;
277 proto_tree_add_text(sched_subtree, tvb, offset, 2,
278 "Slot: %d, Message: %d, First transmission of an SMSCB within the Schedule Period",
283 else if ((octet1 & 0xC0) == 0)
288 other_slots[k] = other_slots[octet1 - 1];
289 proto_tree_add_text(sched_subtree, tvb, offset++, 1,
290 "Slot: %d, Message ID: %d, Repeat of Slot %d",
291 ++k, other_slots[octet1 - 1], octet1);
295 proto_tree_add_text(sched_subtree, tvb, offset++, 1,
296 "Slot: %d, Apparent forward reference to slot %d",
300 else if (octet1 == 0x40)
303 proto_tree_add_text(sched_subtree, tvb, offset++, 1, "Slot: %d Free Message Slot, optional reading", ++k);
305 else if (octet1 == 0x41)
308 proto_tree_add_text(sched_subtree, tvb, offset++, 1, "Slot: %d Free Message Slot, reading advised", ++k);
313 proto_tree_add_text(sched_subtree, tvb, offset, 1, "Slot: %d reserved MDT: %x", ++k, octet1);
316 proto_item_set_end(item, tvb, offset);
317 proto_tree_add_text(sched_tree, tvb, offset, -1, "Padding");
323 dissect_cbch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
325 fragment_data *frag_data = NULL;
326 guint8 octet, lb, lpd, seq_num;
329 proto_item *cbch_item = NULL;
330 proto_tree *cbch_tree = NULL;
331 tvbuff_t *reass_tvb = NULL, *msg_tvb = NULL;
333 len = tvb_length(tvb);
335 octet = tvb_get_guint8(tvb, offset);
338 * create the protocol tree
340 cbch_item = proto_tree_add_protocol_format(tree, proto_cbch, tvb, 0, len,
341 "GSM CBCH - Block (0x%02x)", octet&3);
343 col_append_str(pinfo->cinfo, COL_PROTOCOL, " CBCH");
345 cbch_tree = proto_item_add_subtree(cbch_item, ett_cbch_msg);
347 proto_tree_add_text(cbch_tree, tvb, offset, 1, "CBCH Block");
349 proto_tree_add_uint(cbch_tree, hf_gsm_cbch_spare_bit, tvb, offset, 1, octet);
350 proto_tree_add_uint(cbch_tree, hf_gsm_cbch_lpd, tvb, offset, 1, octet);
351 proto_tree_add_uint(cbch_tree, hf_gsm_cbch_lb, tvb, offset, 1, octet);
352 proto_tree_add_uint(cbch_tree, hf_gsm_cbch_seq_num, tvb, offset, 1, octet);
353 seq_num = octet & 0x0F;
354 lpd = (octet & 0x60) >> 5;
355 lb = (octet & 0x10) >> 4;
363 pinfo->fragmented = TRUE;
364 /* we should have a unique ID for the reassembled page, but we don't really have anything from the protocol...
365 The GSM frame number div 4 might be used for this, but it has not been passed to this layer and does not
366 exist at all if the message is being passed over the RSL interface.
367 So we just use 0... */
369 /* after reassembly we will need to know if this is a scheduling message,
370 this information is carried in the initial sequence number, not the payload,
371 so we prepend the reassembly with the octet containing the initial sequence number
372 to allow later dissection of the payload */
373 frag_data = fragment_add_seq_check(tvb, offset, pinfo, 0,
374 fragment_block_table, reassembled_message_table,
375 seq_num & 0x03, CBCH_FRAGMENT_SIZE + 1, !lb);
376 reass_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CBCH message",
377 frag_data, &cbch_frag_items, NULL, cbch_tree);
383 pinfo->fragmented = TRUE;
384 offset++; /* step to beginning of payload */
385 frag_data = fragment_add_seq_check(tvb, offset, pinfo, 0,
386 fragment_block_table, reassembled_message_table, seq_num,
387 CBCH_FRAGMENT_SIZE, !lb);
388 reass_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CBCH message",
389 frag_data, &cbch_frag_items, NULL, cbch_tree);
393 proto_tree_add_text(cbch_tree, tvb, offset, 1, "NULL message");
394 call_dissector(data_handle, tvb, pinfo, cbch_tree);
398 proto_tree_add_text(cbch_tree, tvb, offset, 1, "reserved Sequence Number");
399 call_dissector(data_handle, tvb, pinfo, cbch_tree);
406 /* the tvb contains the reassmbled message prepended with the sequence number octet from the first block
407 We use this to determine whether this is a normal message or a scheduling message */
410 octet = tvb_get_guint8(reass_tvb, offset++);
411 msg_tvb = tvb_new_subset_remaining(reass_tvb, offset);
415 dissect_schedule_message(msg_tvb, pinfo, tree);
419 call_dissector(cbs_handle, msg_tvb, pinfo, tree);
425 proto_tree_add_text(cbch_tree, tvb, offset, 1, "invalid Link Protocol Discriminator");
426 call_dissector(data_handle, tvb, pinfo, cbch_tree);
430 /* Register the protocol with Wireshark */
432 proto_register_gsm_cbch(void)
434 /* Setup list of header fields */
435 static hf_register_info hf_smscb[] =
437 { &hf_gsm_cbch_spare_bit,
438 { "GSM CBCH spare bit", "gsm_cbch_block_type.spare",
439 FT_UINT8, BASE_HEX, NULL, 0x80,
443 { "GSM CBCH Link Protocol Discriminator", "gsm_cbch_block_type.lpd",
444 FT_UINT8, BASE_DEC, VALS(block_type_lpd_strings), 0x60,
448 { "GSM CBCH Last Block", "gsm_cbch_block_type.lb",
449 FT_UINT8, BASE_DEC, NULL, 0x10,
452 { &hf_gsm_cbch_seq_num,
453 { "GSM CBCH Sequence Number", "gsm_cbch_block_type.seq_num",
454 FT_UINT8, BASE_DEC, VALS(block_type_seq_num_values), 0x0F,
457 { &hf_gsm_cbch_sched_type,
458 { "GSM CBCH Schedule Type", "gsm_cbch.sched_type",
459 FT_UINT8, BASE_DEC, VALS(sched_type_values), 0xC0,
462 { &hf_gsm_cbch_sched_begin_slot,
463 { "GSM CBCH Schedule Begin slot", "gsm_cbch.schedule_begin",
464 FT_UINT8, BASE_DEC, NULL, 0x3F,
467 { &hf_gsm_cbch_sched_spare,
468 { "GSM CBCH Schedule Spare Bits", "gsm_cbch.sched_spare",
469 FT_UINT8, BASE_DEC, NULL, 0xC0,
472 { &hf_gsm_cbch_sched_end_slot,
473 { "GSM CBCH Schedule End Slot", "gsm_cbch.sched_end",
474 FT_UINT8, BASE_DEC, NULL, 0x3F,
477 { &hf_gsm_cbch_sched_msg_id,
478 { "GSM CBCH Schedule Message ID", "gsm_cbch.sched_msg_id",
479 FT_UINT16, BASE_DEC, NULL, 0x0,
484 { &hf_cbch_fragment_overlap,
485 { "Fragment overlap",
486 "gsm_cbch.fragment.overlap",
487 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
488 "Fragment overlaps with other fragments", HFILL
491 { &hf_cbch_fragment_overlap_conflict,
492 { "Conflicting data in fragment overlap",
493 "gsm_cbch.fragment.overlap.conflict",
494 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
495 "Overlapping fragments contained conflicting data", HFILL
498 { &hf_cbch_fragment_multiple_tails,
499 { "Multiple tail fragments found",
500 "gsm_cbch.fragment.multipletails",
501 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
502 "Several tails were found when defragmenting the packet", HFILL
505 { &hf_cbch_fragment_too_long_fragment,
506 { "Fragment too long",
507 "gsm_cbch.fragment.toolongfragment",
508 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
509 "Fragment contained data past end of packet", HFILL
512 { &hf_cbch_fragment_error,
513 { "Defragmentation error",
514 "gsm_cbch.fragment.error",
515 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
516 "Defragmentation error due to illegal fragments", HFILL
519 { &hf_cbch_fragment_count,
520 { "Fragmentation count",
521 "gsm_cbch.fragment.count",
522 FT_UINT32, BASE_DEC, NULL, 0x0,
523 "Count of CBCH Fragments", HFILL
526 { &hf_cbch_reassembled_in,
528 "gsm_cbch.reassembled.in",
529 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
530 "CBCH fragments are reassembled in the given packet", HFILL
533 { &hf_cbch_reassembled_length,
534 { "Reassembled message length is one less than indicated here",
535 "gsm_cbch.reassembled.length",
536 FT_UINT32, BASE_DEC, NULL, 0x0,
537 "The total length of the reassembled message", HFILL
543 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
547 { &hf_cbch_fragments,
549 "gsm_cbch.fragments",
550 FT_NONE, BASE_NONE, NULL, 0x0,
556 /* Setup protocol subtree array */
557 static gint *ett[] = {
560 &ett_schedule_new_msg,
565 /* Register the protocol name and description */
566 proto_cbch = proto_register_protocol("GSM Cell Broadcast Channel", "GSM CBCH", "gsm_cbch");
567 proto_register_field_array(proto_cbch, hf_smscb, array_length(hf_smscb));
569 /* subdissector code */
570 register_dissector("gsm_cbch", dissect_cbch, proto_cbch);
571 register_init_routine(cbch_defragment_init);
574 proto_register_subtree_array(ett, array_length(ett));
578 proto_reg_handoff_gsm_cbch(void)
580 data_handle = find_dissector("data");
581 cbs_handle = find_dissector("gsm_cell_broadcast");