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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include <epan/packet.h>
30 #include <epan/reassemble.h>
31 #include "packet-cell_broadcast.h"
33 #define CBCH_FRAGMENT_SIZE 22
35 const value_string block_type_lpd_strings[] = {
36 { 0x00, "NOT Cell Broadcast"},
37 { 0x01, "Cell Broadcast"},
38 { 0x02, "NOT Cell Broadcast"},
39 { 0x03, "NOT Cell Broadcast"},
43 const value_string block_type_seq_num_values[] = {
44 { 0x00, "First Block"},
45 { 0x01, "Second Block"},
46 { 0x02, "Third Block"},
47 { 0x03, "Fourth Block"},
48 { 0x08, "First Schedule Block"},
49 { 0xFF, "Null message"},
53 const value_string sched_type_values[] = {
54 { 0x00, "messages formatted as specified in subclause 3.5 of 3GPP 44.012"},
55 { 0xFF, "Unknown schedule message format"},
59 /* Initialize the protocol and registered fields */
60 static int proto_cbch = -1;
62 static int hf_gsm_cbch_spare_bit = -1;
63 static int hf_gsm_cbch_lpd = -1;
64 static int hf_gsm_cbch_lb = -1;
65 static int hf_gsm_cbch_seq_num = -1;
66 static int hf_gsm_cbch_sched_type = -1;
67 static int hf_gsm_cbch_sched_begin_slot = -1;
68 static int hf_gsm_cbch_sched_spare = -1;
69 static int hf_gsm_cbch_sched_end_slot = -1;
70 /* static int hf_gsm_cbch_sched_msg_id = -1; */
72 /* These fields are used when reassembling cbch fragments
74 static int hf_cbch_fragments = -1;
75 static int hf_cbch_fragment = -1;
76 static int hf_cbch_fragment_overlap = -1;
77 static int hf_cbch_fragment_overlap_conflict = -1;
78 static int hf_cbch_fragment_multiple_tails = -1;
79 static int hf_cbch_fragment_too_long_fragment = -1;
80 static int hf_cbch_fragment_error = -1;
81 static int hf_cbch_fragment_count = -1;
82 static int hf_cbch_reassembled_in = -1;
83 static int hf_cbch_reassembled_length = -1;
85 /* Initialize the subtree pointers */
86 static gint ett_cbch_msg = -1;
87 static gint ett_schedule_msg = -1;
88 static gint ett_schedule_new_msg = -1;
89 static gint ett_cbch_fragment = -1;
90 static gint ett_cbch_fragments = -1;
92 static dissector_handle_t data_handle;
93 static dissector_handle_t cbs_handle;
95 /* reassembly of CHCH blocks */
96 static reassembly_table cbch_block_reassembly_table;
98 /* Structure needed for the fragmentation routines in reassemble.c
100 static const fragment_items cbch_frag_items = {
105 &hf_cbch_fragment_overlap,
106 &hf_cbch_fragment_overlap_conflict,
107 &hf_cbch_fragment_multiple_tails,
108 &hf_cbch_fragment_too_long_fragment,
109 &hf_cbch_fragment_error,
110 &hf_cbch_fragment_count,
111 &hf_cbch_reassembled_in,
112 &hf_cbch_reassembled_length,
113 /* Reassembled data field */
119 cbch_defragment_init(void)
121 reassembly_table_init(&cbch_block_reassembly_table,
122 &addresses_reassembly_table_functions);
126 dissect_schedule_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *top_tree)
128 guint8 octet1, i, j, k = 0;
129 guint8 len, sched_begin, sched_end, new_slots[48];
131 gboolean valid_message = TRUE;
132 guint16 other_slots[48];
133 proto_item *item = NULL, *schedule_item = NULL;
134 proto_tree *sched_tree = NULL, *sched_subtree = NULL;
136 len = tvb_length(tvb);
138 col_append_str(pinfo->cinfo, COL_INFO, " CBCH Schedule Message ");
140 schedule_item = proto_tree_add_protocol_format(top_tree, proto_cbch, tvb, 0, len,
141 "GSM CBCH Schedule Message");
143 sched_tree = proto_item_add_subtree(schedule_item, ett_schedule_msg);
145 proto_tree_add_item(sched_tree, hf_gsm_cbch_sched_type, tvb, offset, 1, ENC_BIG_ENDIAN);
146 octet1 = tvb_get_guint8(tvb, offset);
147 if (0 == (octet1 & 0xC0))
149 sched_begin = octet1 & 0x3F;
150 proto_tree_add_item(sched_tree, hf_gsm_cbch_sched_begin_slot, tvb, offset++, 1, ENC_BIG_ENDIAN);
151 if (1 == sched_begin)
153 proto_tree_add_text(sched_tree, tvb, offset - 1, 1, "(apparently) Scheduled Scheduling Message");
155 else if ((2 <= sched_begin) && (48 >= sched_begin))
157 proto_tree_add_text(sched_tree, tvb, offset - 1, 1, "(apparently) Unscheduled Scheduling Message");
161 proto_tree_add_text(sched_tree, tvb, offset - 1, 1, "Begin Slot Number out of range: ignoring message");
162 valid_message = FALSE;
164 proto_tree_add_item(sched_tree, hf_gsm_cbch_sched_spare, tvb, offset, 1, ENC_BIG_ENDIAN);
165 sched_end = tvb_get_guint8(tvb, offset);
166 proto_tree_add_item(sched_tree, hf_gsm_cbch_sched_end_slot, tvb, offset++, 1, ENC_BIG_ENDIAN);
167 if (sched_end < sched_begin)
169 proto_tree_add_text(sched_tree, tvb, offset - 1, 1, "End Slot Number less than Begin Slot Number: ignoring message");
170 valid_message = FALSE;
175 /* build an array of new messages */
176 memset(&new_slots, 0xFF, sizeof(new_slots));
177 memset(&other_slots, 0xFF, sizeof(other_slots));
179 /* iterate over the octets */
182 octet1 = tvb_get_guint8(tvb, offset++);
184 /* iterate over the bits */
187 if (octet1 & (0x80>>j))
189 new_slots[k++] = (i<<3) + j + 1;
193 /* print the array of new messages */
194 item = proto_tree_add_text(sched_tree, tvb, offset-6, 6, "This schedule contains %d slots with new messages", k);
195 sched_subtree = proto_item_add_subtree(item, ett_schedule_new_msg);
198 DISSECTOR_ASSERT(new_slots[i] < 48);
199 octet1 = tvb_get_guint8(tvb, offset);
200 if ((octet1 & 0x80) == 0x80)
206 octet2 = tvb_get_guint8(tvb, offset + 1);
207 msg_id = ((octet1 &0x7F) << 8) + octet2;
208 proto_tree_add_text(sched_subtree, tvb, offset, 2,
209 "Slot: %d, Message ID: %d, First transmission of an SMSCB within the Schedule Period",
210 new_slots[i], msg_id);
212 other_slots[new_slots[i] - 1] = msg_id;
214 else if ((octet1 & 0xC0) == 0)
217 if (octet1 < new_slots[i])
219 proto_tree_add_text(sched_subtree, tvb, offset++, 1,
220 "Slot: %d, Message ID: %d, Repeat of Slot %d",
221 new_slots[i], other_slots[octet1 - 1], octet1);
222 other_slots[new_slots[i] - 1] = other_slots[octet1 - 1];
226 proto_tree_add_text(sched_subtree, tvb, offset++, 1,
227 "Slot: %d, Apparent forward reference to slot %d",
228 new_slots[i], octet1);
231 else if (octet1 == 0x40)
234 proto_tree_add_text(sched_subtree, tvb, offset++, 1, "Slot: %d Free Message Slot, optional reading", new_slots[k]);
235 other_slots[new_slots[i] - 1] = 0xFFFE;
237 else if (octet1 == 0x41)
240 proto_tree_add_text(sched_subtree, tvb, offset++, 1, "Slot: %d Free Message Slot, reading advised", new_slots[k]);
241 other_slots[new_slots[i] - 1] = 0xFFFE;
246 proto_tree_add_text(sched_subtree, tvb, offset, 1, "Slot: %d reserved MDT: %x", new_slots[k], octet1);
247 other_slots[new_slots[i] - 1] = 0xFFFE;
250 proto_item_set_end(item, tvb, offset);
252 /* print schedule of other messages */
253 item = proto_tree_add_text(sched_tree, tvb, offset, 0, "Other message slots in this schedule");
254 sched_subtree = proto_item_add_subtree(item, ett_schedule_new_msg);
255 for (k=0; offset<len; j++)
257 while ((other_slots[k]!=0xFFFF) && (k<sched_end))
264 octet1 = tvb_get_guint8(tvb, offset);
265 if ((octet1 & 0x80) == 0x80)
273 octet2 = tvb_get_guint8(tvb, offset + 1);
274 msg_id = ((octet1 &0x7F) << 8) + octet2;
275 other_slots[k] = msg_id;
276 proto_tree_add_text(sched_subtree, tvb, offset, 2,
277 "Slot: %d, Message: %d, First transmission of an SMSCB within the Schedule Period",
282 else if ((octet1 & 0xC0) == 0)
287 other_slots[k] = other_slots[octet1 - 1];
288 proto_tree_add_text(sched_subtree, tvb, offset++, 1,
289 "Slot: %d, Message ID: %d, Repeat of Slot %d",
290 ++k, other_slots[octet1 - 1], octet1);
294 proto_tree_add_text(sched_subtree, tvb, offset++, 1,
295 "Slot: %d, Apparent forward reference to slot %d",
299 else if (octet1 == 0x40)
302 proto_tree_add_text(sched_subtree, tvb, offset++, 1, "Slot: %d Free Message Slot, optional reading", ++k);
304 else if (octet1 == 0x41)
307 proto_tree_add_text(sched_subtree, tvb, offset++, 1, "Slot: %d Free Message Slot, reading advised", ++k);
312 proto_tree_add_text(sched_subtree, tvb, offset, 1, "Slot: %d reserved MDT: %x", ++k, octet1);
315 proto_item_set_end(item, tvb, offset);
316 proto_tree_add_text(sched_tree, tvb, offset, -1, "Padding");
322 dissect_cbch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
324 fragment_data *frag_data = NULL;
325 guint8 octet, lb, lpd, seq_num;
328 proto_item *cbch_item = NULL;
329 proto_tree *cbch_tree = NULL;
330 tvbuff_t *reass_tvb = NULL, *msg_tvb = NULL;
332 len = tvb_length(tvb);
334 octet = tvb_get_guint8(tvb, offset);
337 * create the protocol tree
339 cbch_item = proto_tree_add_protocol_format(tree, proto_cbch, tvb, 0, len,
340 "GSM CBCH - Block (0x%02x)", octet&3);
342 col_append_str(pinfo->cinfo, COL_PROTOCOL, " CBCH");
344 cbch_tree = proto_item_add_subtree(cbch_item, ett_cbch_msg);
346 proto_tree_add_text(cbch_tree, tvb, offset, 1, "CBCH Block");
348 proto_tree_add_uint(cbch_tree, hf_gsm_cbch_spare_bit, tvb, offset, 1, octet);
349 proto_tree_add_uint(cbch_tree, hf_gsm_cbch_lpd, tvb, offset, 1, octet);
350 proto_tree_add_uint(cbch_tree, hf_gsm_cbch_lb, tvb, offset, 1, octet);
351 proto_tree_add_uint(cbch_tree, hf_gsm_cbch_seq_num, tvb, offset, 1, octet);
352 seq_num = octet & 0x0F;
353 lpd = (octet & 0x60) >> 5;
354 lb = (octet & 0x10) >> 4;
362 pinfo->fragmented = TRUE;
363 /* we should have a unique ID for the reassembled page, but we don't really have anything from the protocol...
364 The GSM frame number div 4 might be used for this, but it has not been passed to this layer and does not
365 exist at all if the message is being passed over the RSL interface.
366 So we just use 0... */
368 /* after reassembly we will need to know if this is a scheduling message,
369 this information is carried in the initial sequence number, not the payload,
370 so we prepend the reassembly with the octet containing the initial sequence number
371 to allow later dissection of the payload */
372 frag_data = fragment_add_seq_check(&cbch_block_reassembly_table,
373 tvb, offset, pinfo, 0, NULL,
374 seq_num & 0x03, CBCH_FRAGMENT_SIZE + 1, !lb);
375 reass_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CBCH message",
376 frag_data, &cbch_frag_items, NULL, cbch_tree);
382 pinfo->fragmented = TRUE;
383 offset++; /* step to beginning of payload */
384 frag_data = fragment_add_seq_check(&cbch_block_reassembly_table,
385 tvb, offset, pinfo, 0, NULL,
386 seq_num, CBCH_FRAGMENT_SIZE, !lb);
387 reass_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CBCH message",
388 frag_data, &cbch_frag_items, NULL, cbch_tree);
392 proto_tree_add_text(cbch_tree, tvb, offset, 1, "NULL message");
393 call_dissector(data_handle, tvb, pinfo, cbch_tree);
397 proto_tree_add_text(cbch_tree, tvb, offset, 1, "reserved Sequence Number");
398 call_dissector(data_handle, tvb, pinfo, cbch_tree);
405 /* the tvb contains the reassmbled message prepended with the sequence number octet from the first block
406 We use this to determine whether this is a normal message or a scheduling message */
409 octet = tvb_get_guint8(reass_tvb, offset++);
410 msg_tvb = tvb_new_subset_remaining(reass_tvb, offset);
414 dissect_schedule_message(msg_tvb, pinfo, tree);
418 call_dissector(cbs_handle, msg_tvb, pinfo, tree);
424 proto_tree_add_text(cbch_tree, tvb, offset, 1, "invalid Link Protocol Discriminator");
425 call_dissector(data_handle, tvb, pinfo, cbch_tree);
429 /* Register the protocol with Wireshark */
431 proto_register_gsm_cbch(void)
433 /* Setup list of header fields */
434 static hf_register_info hf_smscb[] =
436 { &hf_gsm_cbch_spare_bit,
437 { "GSM CBCH spare bit", "gsm_cbch.block_type.spare",
438 FT_UINT8, BASE_HEX, NULL, 0x80,
442 { "GSM CBCH Link Protocol Discriminator", "gsm_cbch.block_type.lpd",
443 FT_UINT8, BASE_DEC, VALS(block_type_lpd_strings), 0x60,
447 { "GSM CBCH Last Block", "gsm_cbch.block_type.lb",
448 FT_UINT8, BASE_DEC, NULL, 0x10,
451 { &hf_gsm_cbch_seq_num,
452 { "GSM CBCH Sequence Number", "gsm_cbch.block_type.seq_num",
453 FT_UINT8, BASE_DEC, VALS(block_type_seq_num_values), 0x0F,
456 { &hf_gsm_cbch_sched_type,
457 { "GSM CBCH Schedule Type", "gsm_cbch.sched_type",
458 FT_UINT8, BASE_DEC, VALS(sched_type_values), 0xC0,
461 { &hf_gsm_cbch_sched_begin_slot,
462 { "GSM CBCH Schedule Begin slot", "gsm_cbch.schedule_begin",
463 FT_UINT8, BASE_DEC, NULL, 0x3F,
466 { &hf_gsm_cbch_sched_spare,
467 { "GSM CBCH Schedule Spare Bits", "gsm_cbch.sched_spare",
468 FT_UINT8, BASE_DEC, NULL, 0xC0,
471 { &hf_gsm_cbch_sched_end_slot,
472 { "GSM CBCH Schedule End Slot", "gsm_cbch.sched_end",
473 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,
485 { &hf_cbch_fragment_overlap,
486 { "Fragment overlap",
487 "gsm_cbch.fragment.overlap",
488 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
489 "Fragment overlaps with other fragments", HFILL
492 { &hf_cbch_fragment_overlap_conflict,
493 { "Conflicting data in fragment overlap",
494 "gsm_cbch.fragment.overlap.conflict",
495 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
496 "Overlapping fragments contained conflicting data", HFILL
499 { &hf_cbch_fragment_multiple_tails,
500 { "Multiple tail fragments found",
501 "gsm_cbch.fragment.multipletails",
502 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
503 "Several tails were found when defragmenting the packet", HFILL
506 { &hf_cbch_fragment_too_long_fragment,
507 { "Fragment too long",
508 "gsm_cbch.fragment.toolongfragment",
509 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
510 "Fragment contained data past end of packet", HFILL
513 { &hf_cbch_fragment_error,
514 { "Defragmentation error",
515 "gsm_cbch.fragment.error",
516 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
517 "Defragmentation error due to illegal fragments", HFILL
520 { &hf_cbch_fragment_count,
521 { "Fragmentation count",
522 "gsm_cbch.fragment.count",
523 FT_UINT32, BASE_DEC, NULL, 0x0,
524 "Count of CBCH Fragments", HFILL
527 { &hf_cbch_reassembled_in,
529 "gsm_cbch.reassembled.in",
530 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
531 "CBCH fragments are reassembled in the given packet", HFILL
534 { &hf_cbch_reassembled_length,
535 { "Reassembled message length is one less than indicated here",
536 "gsm_cbch.reassembled.length",
537 FT_UINT32, BASE_DEC, NULL, 0x0,
538 "The total length of the reassembled message", HFILL
544 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
548 { &hf_cbch_fragments,
550 "gsm_cbch.fragments",
551 FT_NONE, BASE_NONE, NULL, 0x0,
557 /* Setup protocol subtree array */
558 static gint *ett[] = {
561 &ett_schedule_new_msg,
566 /* Register the protocol name and description */
567 proto_cbch = proto_register_protocol("GSM Cell Broadcast Channel", "GSM CBCH", "gsm_cbch");
568 proto_register_field_array(proto_cbch, hf_smscb, array_length(hf_smscb));
570 /* subdissector code */
571 register_dissector("gsm_cbch", dissect_cbch, proto_cbch);
572 register_init_routine(cbch_defragment_init);
575 proto_register_subtree_array(ett, array_length(ett));
579 proto_reg_handoff_gsm_cbch(void)
581 data_handle = find_dissector("data");
582 cbs_handle = find_dissector("gsm_cbs");