wireshark/epan/dissectors/packet-gsm_cbsp.c
João Valverde 19dcb725b6 epan: Remove STR_ASCII and STR_UNICODE
These display bases work to replace unprintable characters so the
name is a misnomer. In addition they are the same option and this
display behaviour is not something that is configurable.

This does not affect encodings because all our internal text strings
need to be valid UTF-8 and the source encoding is specified using
ENC_*.

Remove the assertion for valid UTF-8 in proto.c because
tvb_get_*_string() must return a valid UTF-8 string, always, and we
don't need to assert that, it is expensive.
2021-12-03 04:35:56 +00:00

936 lines
32 KiB
C

/* packet-gsm_cbsp.c
* Dissector for GSM / 3GPP TS 48.049 Cell Broadcast Service Protocol (CBSP)
*
* (C) 2018-2019 by Harald Welte <laforge@gnumonks.org>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
*/
#include "config.h"
#include <epan/packet.h>
#include <epan/conversation.h>
#include <epan/asn1.h>
#include "packet-e164.h"
#include "packet-e212.h"
#include "packet-gsm_map.h"
#include "packet-cell_broadcast.h"
/***********************************************************************
* TLV related definitions
***********************************************************************/
/*! Entry in a TLV parser array */
struct tlv_p_entry {
guint16 len; /*!< length */
const guint8 *val; /*!< pointer to value */
};
/*! TLV type */
enum tlv_type {
TLV_TYPE_NONE, /*!< no type */
TLV_TYPE_FIXED, /*!< fixed-length value-only */
TLV_TYPE_TV, /*!< tag-value (8bit) */
TLV_TYPE_TLV, /*!< tag-length-value */
TLV_TYPE_TL16V, /*!< tag, 16 bit length, value */
};
/*! Definition of a single IE (Information Element) */
struct tlv_def {
enum tlv_type type; /*!< TLV type */
guint8 fixed_len; /*!< length in case of TLV_TYPE_FIXED */
};
/*! Definition of All 256 IE / TLV */
struct tlv_definition {
struct tlv_def def[256];
};
/***********************************************************************
* CBSP Protocol Definitions, see libosmocore/include/gsm/protocol/gsm_48_049.h
***********************************************************************/
#define CBSP_TCP_PORT 48049
/* 8.2.1 Information Element Identifiers */
enum cbsp_iei {
CBSP_IEI_MSG_CONTENT = 0x01,
CBSP_IEI_OLD_SERIAL_NR = 0x02,
CBSP_IEI_NEW_SERIAL_NR = 0x03,
CBSP_IEI_CELL_LIST = 0x04,
CBSP_IEI_CATEGORY = 0x05,
CBSP_IEI_REP_PERIOD = 0x06,
CBSP_IEI_NUM_BCAST_REQ = 0x07,
CBSP_IEI_NUM_BCAST_COMPL_LIST = 0x08,
CBSP_IEI_FAILURE_LIST = 0x09,
CBSP_IEI_RR_LOADING_LIST = 0x0a,
CBSP_IEI_CAUSE = 0x0b,
CBSP_IEI_DCS = 0x0c,
CBSP_IEI_RECOVERY_IND = 0x0d,
CBSP_IEI_MSG_ID = 0x0e,
CBSP_IEI_EMERG_IND = 0x0f,
CBSP_IEI_WARN_TYPE = 0x10,
CBSP_IEI_WARN_SEC_INFO = 0x11,
CBSP_IEI_CHANNEL_IND = 0x12,
CBSP_IEI_NUM_OF_PAGES = 0x13,
CBSP_IEI_SCHEDULE_PERIOD = 0x14,
CBSP_IEI_NUM_OF_RES_SLOTS = 0x15,
CBSP_IEI_BCAST_MSG_TYPE = 0x16,
CBSP_IEI_WARNING_PERIOD = 0x17,
CBSP_IEI_KEEP_ALIVE_REP_PERIOD = 0x18,
};
/* 8.2.2 Message Type */
enum cbsp_msg_type {
CBSP_MSGT_WRITE_REPLACE = 0x01,
CBSP_MSGT_WRITE_REPLACE_COMPL = 0x02,
CBSP_MSGT_WRITE_REPLACE_FAIL = 0x03,
CBSP_MSGT_KILL = 0x04,
CBSP_MSGT_KILL_COMPL = 0x05,
CBSP_MSGT_KILL_FAIL = 0x06,
CBSP_MSGT_LOAD_QUERY = 0x07,
CBSP_MSGT_LOAD_QUERY_COMPL = 0x08,
CBSP_MSGT_LOAD_QUERY_FAIL = 0x09,
CBSP_MSGT_MSG_STATUS_QUERY = 0x0a,
CBSP_MSGT_MSG_STATUS_QUERY_COMPL= 0x0b,
CBSP_MSGT_MSG_STATUS_QUERY_FAIL = 0x0c,
CBSP_MSGT_SET_DRX = 0x0d,
CBSP_MSGT_SET_DRX_COMPL = 0x0e,
CBSP_MSGT_SET_DRX_FAIL = 0x0f,
CBSP_MSGT_RESET = 0x10,
CBSP_MSGT_RESET_COMPL = 0x11,
CBSP_MSGT_RESET_FAIL = 0x12,
CBSP_MSGT_RESTART = 0x13,
CBSP_MSGT_FAILURE = 0x14,
CBSP_MSGT_ERROR_IND = 0x15,
CBSP_MSGT_KEEP_ALIVE = 0x16,
CBSP_MSGT_KEEP_ALIVE_COMPL = 0x17,
};
/* 8.2.7 Category */
enum cbsp_category {
CBSP_CATEG_HIGH_PRIO = 0x00,
CBSP_CATEG_BACKGROUND = 0x01,
CBSP_CATEG_NORMAL = 0x02,
};
/* 8.2.9 Number of Brodacast Info */
enum cbsp_num_bcast_info {
CBSP_NUM_BCAST_INFO_VALID = 0x0,
CBSP_NUM_BCAST_INFO_OVERFLOW = 0x1,
CBSP_NUM_BCAST_INFO_UNKNOWN = 0x2,
};
static const value_string cbsp_num_bcast_info_vals[] = {
{ CBSP_NUM_BCAST_INFO_VALID, "Number of Broadcasts Complete is Valid" },
{ CBSP_NUM_BCAST_INFO_OVERFLOW, "Number of Broadcasts Complete has Overflown" },
{ CBSP_NUM_BCAST_INFO_UNKNOWN, "Number of Broadcasts Complete is undefined" },
{ 0, NULL }
};
static const value_string cbsp_num_bcast_shortinfo_vals[] = {
{ CBSP_NUM_BCAST_INFO_VALID, "Valid" },
{ CBSP_NUM_BCAST_INFO_OVERFLOW, "Overflow" },
{ CBSP_NUM_BCAST_INFO_UNKNOWN, "Unknown" },
{ 0, NULL }
};
/* Cell ID Discriminator (8.2.11, ...) */
enum cbsp_cell_id_disc {
CBSP_CIDD_WHOLE_CGI = 0x0,
CBSP_CIDD_LAC_CI = 0x1,
CBSP_CIDD_CI = 0x2,
CBSP_CIDD_LAI = 0x4,
CBSP_CIDD_LAC = 0x5,
CBSP_CIDD_ALL_IN_BSC = 0x6,
};
/* 8.2.13 Cause */
enum cbsp_cause {
CBSP_CAUSE_PARAM_NOT_RECOGNISED = 0x00,
CBSP_CAUSE_PARAM_VAL_INVALID = 0x01,
CBSP_CAUSE_MSG_REF_NOT_IDENTIFIED = 0x02,
CBSP_CAUSE_CELL_ID_NOT_VALID = 0x03,
CBSP_CAUSE_UNRECOGNISED_MSG = 0x04,
CBSP_CAUSE_MISSING_MAND_IE = 0x05,
CBSP_CAUSE_BSC_CAPACITY_EXCEEDED = 0x06,
CBSP_CAUSE_CELL_MEMORY_EXCEEDED = 0x07,
CBSP_CAUSE_BSC_MEMORY_EXCEEDED = 0x08,
CBSP_CAUSE_CB_NOT_SUPPORTED = 0x09,
CBSP_CAUSE_CB_NOT_OPERATIONAL = 0x0a,
CBSP_CAUSE_INCOMPATIBLE_DRX_PARAM = 0x0b,
CBSP_CAUSE_EXT_CHAN_NOT_SUPPORTED = 0x0c,
CBSP_CAUSE_MSG_REF_ALREADY_USED = 0x0d,
CBSP_CAUSE_UNSPECIFIED_ERROR = 0x0e,
CBSP_CAUSE_LAI_OR_LAC_NPT_VALID = 0x0f,
};
/* 8.2.15 */
static const value_string cbsp_recov_ind_vals[] = {
{ 0x0, "CBS/emergency message data available" },
{ 0x1, "CBS/emergency message data lost" },
{ 0, NULL }
};
/* 8.2.17 */
static const value_string cbsp_emerg_ind_vals[] = {
{ 0x0, "reserved" },
{ 0x1, "ETWS information available" },
{ 0, NULL }
};
/* 8.2.20 */
static const value_string cbsp_chan_ind_vals[] = {
{ 0x0, "basic channel" },
{ 0x1, "extended channel" },
{ 0, NULL }
};
/* 8.2.24 */
static const value_string cbsp_bcast_msg_type_vals[] = {
{ 0x0, "CBS message broadcasting" },
{ 0x1, "emergency message broadcasting" },
{ 0, NULL }
};
/* conversion function from 8.2.25 warning period to seconds */
static int cbsp_warn_period_to_secs(guint8 warn_per)
{
if (warn_per <= 0x0a)
return warn_per;
else if (warn_per <= 0x14)
return 10 + (warn_per-0x0a)*2;
else if (warn_per <= 0x26)
return 30 + (warn_per-0x14)*5;
else if (warn_per <= 0x56)
return 120 + (warn_per-0x26)*10;
else if (warn_per <= 0xba)
return 600 + (warn_per-0x56)*60;
else
return -1;
}
static const value_string cbsp_cell_id_disc_vals[] = {
{ CBSP_CIDD_WHOLE_CGI, "CGI" },
{ CBSP_CIDD_LAC_CI, "LAC+CI" },
{ CBSP_CIDD_CI, "CI" },
{ CBSP_CIDD_LAI, "LAI" },
{ CBSP_CIDD_LAC, "LAC" },
{ CBSP_CIDD_ALL_IN_BSC, "BSS" },
{ 0, NULL }
};
static const value_string cbsp_iei_names[] = {
{ CBSP_IEI_MSG_CONTENT, "Message Content" },
{ CBSP_IEI_OLD_SERIAL_NR, "Old Serial Number" },
{ CBSP_IEI_NEW_SERIAL_NR, "New Serial Number" },
{ CBSP_IEI_CELL_LIST, "Cell List" },
{ CBSP_IEI_CATEGORY, "Category" },
{ CBSP_IEI_REP_PERIOD, "Repetition Period" },
{ CBSP_IEI_NUM_BCAST_REQ, "Number of Broadcasts Requested" },
{ CBSP_IEI_NUM_BCAST_COMPL_LIST,"Number of Broadcasts Completed List" },
{ CBSP_IEI_FAILURE_LIST, "Failure List" },
{ CBSP_IEI_RR_LOADING_LIST, "Radio Resource Loading List" },
{ CBSP_IEI_CAUSE, "Cause" },
{ CBSP_IEI_DCS, "Data Coding Scheme" },
{ CBSP_IEI_RECOVERY_IND, "Recovery Indication" },
{ CBSP_IEI_MSG_ID, "Message Identifier" },
{ CBSP_IEI_EMERG_IND, "Emergency Indicator" },
{ CBSP_IEI_WARN_TYPE, "Warning Type" },
{ CBSP_IEI_WARN_SEC_INFO, "Warning Security Information" },
{ CBSP_IEI_CHANNEL_IND, "Channel Indicator" },
{ CBSP_IEI_NUM_OF_PAGES, "Number of Pages" },
{ CBSP_IEI_SCHEDULE_PERIOD, "Schedule Period" },
{ CBSP_IEI_NUM_OF_RES_SLOTS, "Number of Reserved Slots" },
{ CBSP_IEI_BCAST_MSG_TYPE, "Broadcast Message Type" },
{ CBSP_IEI_WARNING_PERIOD, "Waring Period" },
{ CBSP_IEI_KEEP_ALIVE_REP_PERIOD, "Keep Alive Repetition Period" },
{ 0, NULL }
};
static const value_string cbsp_msg_type_names[] = {
{ CBSP_MSGT_WRITE_REPLACE, "WRITE-REPLACE" },
{ CBSP_MSGT_WRITE_REPLACE_COMPL, "WRITE-REPLACE COMPLETE" },
{ CBSP_MSGT_WRITE_REPLACE_FAIL, "WRITE-REPLACE FAILURE" },
{ CBSP_MSGT_KILL, "KILL" },
{ CBSP_MSGT_KILL_COMPL, "KILL COMPLETE" },
{ CBSP_MSGT_KILL_FAIL, "KILL FAILURE" },
{ CBSP_MSGT_LOAD_QUERY, "LOAD QUERY" },
{ CBSP_MSGT_LOAD_QUERY_COMPL, "LOAD QUERY COMPLETE" },
{ CBSP_MSGT_LOAD_QUERY_FAIL, "LOAD QUERY FAILURE" },
{ CBSP_MSGT_MSG_STATUS_QUERY, "MESSAGE STATUS QUERY" },
{ CBSP_MSGT_MSG_STATUS_QUERY_COMPL, "MESSAGE STATUS QUERY COMPLETE" },
{ CBSP_MSGT_MSG_STATUS_QUERY_FAIL, "MESSAGE STATUS QUERY FAILURE" },
{ CBSP_MSGT_SET_DRX, "SET-DRX" },
{ CBSP_MSGT_SET_DRX_COMPL, "SET-DRX COMPLETE" },
{ CBSP_MSGT_SET_DRX_FAIL, "SET-DRX FAILURE" },
{ CBSP_MSGT_RESET, "RESET" },
{ CBSP_MSGT_RESET_COMPL, "RESET COMPLETE" },
{ CBSP_MSGT_RESET_FAIL, "RESET FAILURE" },
{ CBSP_MSGT_RESTART, "RESTART" },
{ CBSP_MSGT_FAILURE, "FAILURE" },
{ CBSP_MSGT_ERROR_IND, "ERROR INDICATION" },
{ CBSP_MSGT_KEEP_ALIVE, "KEEP-ALIVE" },
{ CBSP_MSGT_KEEP_ALIVE_COMPL, "KEEP-ALIVE COMPLETE" },
{ 0, NULL }
};
static const value_string cbsp_category_names[] = {
{ CBSP_CATEG_HIGH_PRIO, "High Priority" },
{ CBSP_CATEG_BACKGROUND, "Background" },
{ CBSP_CATEG_NORMAL, "Normal" },
{ 0, NULL }
};
/* 8.2.13 */
static const value_string cbsp_cause_vals[] = {
{ CBSP_CAUSE_PARAM_NOT_RECOGNISED, "Parameter-not-recognized" },
{ CBSP_CAUSE_PARAM_VAL_INVALID, "Parameter-value-invalid" },
{ CBSP_CAUSE_MSG_REF_NOT_IDENTIFIED, "Message-reference-not-identified" },
{ CBSP_CAUSE_CELL_ID_NOT_VALID, "Cell-identity-not-valid" },
{ CBSP_CAUSE_UNRECOGNISED_MSG, "Unrecognised-message" },
{ CBSP_CAUSE_MISSING_MAND_IE, "Missing-mandatory-element" },
{ CBSP_CAUSE_BSC_CAPACITY_EXCEEDED, "BSC-capacity-exceeded" },
{ CBSP_CAUSE_CELL_MEMORY_EXCEEDED, "Cell-memory-exceeded" },
{ CBSP_CAUSE_BSC_MEMORY_EXCEEDED, "BSC-memory-exceeded" },
{ CBSP_CAUSE_CB_NOT_SUPPORTED, "Cell-broadcast-not-supported" },
{ CBSP_CAUSE_CB_NOT_OPERATIONAL, "Cell-broadcast-not-operational" },
{ CBSP_CAUSE_INCOMPATIBLE_DRX_PARAM, "Incompatible-DRX-parameter" },
{ CBSP_CAUSE_EXT_CHAN_NOT_SUPPORTED, "Extended-channel-not-supported" },
{ CBSP_CAUSE_MSG_REF_ALREADY_USED, "Message-reference-already-used" },
{ CBSP_CAUSE_UNSPECIFIED_ERROR, "Unspecified-error" },
{ CBSP_CAUSE_LAI_OR_LAC_NPT_VALID, "LAI-or-LAC-not-valid" },
{ 0, NULL }
};
static const struct tlv_definition cbsp_att_tlvdef = {
.def = {
[CBSP_IEI_MSG_CONTENT] = { TLV_TYPE_FIXED, 83 },
[CBSP_IEI_OLD_SERIAL_NR] = { TLV_TYPE_FIXED, 2 },
[CBSP_IEI_NEW_SERIAL_NR] = { TLV_TYPE_FIXED, 2 },
[CBSP_IEI_CELL_LIST] = { TLV_TYPE_TL16V, 0 },
[CBSP_IEI_CATEGORY] = { TLV_TYPE_TV, 0 },
[CBSP_IEI_REP_PERIOD] = { TLV_TYPE_FIXED, 2 },
[CBSP_IEI_NUM_BCAST_REQ] = { TLV_TYPE_FIXED, 2 },
[CBSP_IEI_NUM_BCAST_COMPL_LIST] = { TLV_TYPE_TL16V, 0 },
[CBSP_IEI_FAILURE_LIST] = { TLV_TYPE_TL16V, 0 },
[CBSP_IEI_RR_LOADING_LIST] = { TLV_TYPE_TL16V, 0 },
[CBSP_IEI_CAUSE] = { TLV_TYPE_TV, 0 },
[CBSP_IEI_DCS] = { TLV_TYPE_TV, 0 },
[CBSP_IEI_RECOVERY_IND] = { TLV_TYPE_TV, 0 },
[CBSP_IEI_MSG_ID] = { TLV_TYPE_FIXED, 2 },
[CBSP_IEI_EMERG_IND] = { TLV_TYPE_TV, 0 },
[CBSP_IEI_WARN_TYPE] = { TLV_TYPE_FIXED, 2 },
[CBSP_IEI_WARN_SEC_INFO] = { TLV_TYPE_FIXED, 50 },
[CBSP_IEI_CHANNEL_IND] = { TLV_TYPE_TV, 0 },
[CBSP_IEI_NUM_OF_PAGES] = { TLV_TYPE_TV, 0 },
[CBSP_IEI_SCHEDULE_PERIOD] = { TLV_TYPE_TV, 0 },
[CBSP_IEI_NUM_OF_RES_SLOTS] = { TLV_TYPE_TV, 0 },
[CBSP_IEI_BCAST_MSG_TYPE] = { TLV_TYPE_TV, 0 },
[CBSP_IEI_WARNING_PERIOD] = { TLV_TYPE_TV, 0 },
[CBSP_IEI_KEEP_ALIVE_REP_PERIOD] = { TLV_TYPE_TV, 0 },
},
};
/***********************************************************************
* Wireshark Dissector Implementation
***********************************************************************/
void proto_register_cbsp(void);
void proto_reg_handoff_cbsp(void);
static int proto_cbsp = -1;
static int hf_cbsp_msg_type = -1;
static int hf_cbsp_msg_len = -1;
static int hf_cbsp_iei = -1;
static int hf_cbsp_ie_len = -1;
static int hf_cbsp_ie_payload = -1;
static int hf_cbsp_old_serial_nr = -1;
static int hf_cbsp_new_serial_nr = -1;
static int hf_cbsp_category = -1;
static int hf_cbsp_rep_period = -1;
static int hf_cbsp_num_bcast_req = -1;
static int hf_cbsp_cause = -1;
static int hf_cbsp_dcs = -1;
static int hf_cbsp_recovery_ind = -1;
static int hf_cbsp_msg_id = -1;
static int hf_cbsp_emerg_ind = -1;
static int hf_cbsp_warn_type = -1;
static int hf_cbsp_channel_ind = -1;
static int hf_cbsp_num_of_pages = -1;
static int hf_cbsp_cb_msg_page = -1;
static int hf_cbsp_cbs_page_content = -1;
static int hf_cbsp_sched_period = -1;
static int hf_cbsp_num_of_res_slots = -1;
static int hf_cbsp_bcast_msg_type = -1;
static int hf_cbsp_warning_period = -1;
static int hf_cbsp_keepalive_period = -1;
static int hf_cbsp_user_info_length = -1;
static int hf_cbsp_cell_id_disc = -1;
static int hf_cbsp_cell_load1 = -1;
static int hf_cbsp_cell_load2 = -1;
static int hf_cbsp_num_bcast_compl = -1;
static int hf_cbsp_num_bcast_info = -1;
static int hf_cbsp_lac = -1;
static int hf_cbsp_ci = -1;
static gint ett_cbsp = -1;
static gint ett_cbsp_ie = -1;
static gint ett_cbsp_cbs_data_coding = -1;
static gint ett_cbsp_cbs_page_content = -1;
static gint ett_cbsp_cell_list = -1;
static gint ett_cbsp_fail_list = -1;
static gint ett_cbsp_load_list = -1;
static gint ett_cbsp_num_bcast_compl_list = -1;
static void
dissect_cbsp_content_ie(tvbuff_t *tvb, packet_info *pinfo, guint offset, gint len, proto_tree *tree,
guint8 sms_encoding, proto_item *ti)
{
proto_item *cbs_page_item;
tvbuff_t *next_tvb, *unpacked_tvb;
const guint8 *pstr;
proto_tree_add_item(tree, hf_cbsp_user_info_length, tvb, offset, 1, ENC_NA);
cbs_page_item = proto_tree_add_item(tree, hf_cbsp_cb_msg_page, tvb, offset+1, len-1, ENC_NA);
next_tvb = tvb_new_subset_length(tvb, offset+1, len-1);
unpacked_tvb = dissect_cbs_data(sms_encoding, next_tvb, tree, pinfo, 0);
if (tree) {
guint captured_len = tvb_captured_length(unpacked_tvb);
proto_tree *cbs_page_subtree = proto_item_add_subtree(cbs_page_item, ett_cbsp_cbs_page_content);
proto_tree_add_item_ret_string(cbs_page_subtree, hf_cbsp_cbs_page_content, unpacked_tvb,
0, captured_len, ENC_UTF_8|ENC_NA, pinfo->pool,
&pstr);
proto_item_append_text(ti, ": '%s'", pstr);
}
}
/* Section 8.2.6 Cell List */
static gint
dissect_cell_id_elem(guint8 discr, tvbuff_t *tvb, packet_info *pinfo, guint offset, gint len _U_,
proto_tree *tree, proto_item *ti)
{
guint base_offs = offset;
gchar *mcc_mnc;
guint32 lac, ci;
switch (discr) {
case CBSP_CIDD_WHOLE_CGI:
mcc_mnc = dissect_e212_mcc_mnc_wmem_packet_str(tvb, pinfo, tree, offset, E212_NONE, TRUE);
offset += 3;
proto_tree_add_item_ret_uint(tree, hf_cbsp_lac, tvb, offset, 2, ENC_NA, &lac);
offset += 2;
proto_tree_add_item_ret_uint(tree, hf_cbsp_ci, tvb, offset, 2, ENC_NA, &ci);
offset += 2;
proto_item_append_text(ti, ": %s, LAC 0x%04x, CI 0x%04x", mcc_mnc, lac, ci);
break;
case CBSP_CIDD_LAC_CI:
proto_tree_add_item_ret_uint(tree, hf_cbsp_lac, tvb, offset, 2, ENC_NA, &lac);
offset += 2;
proto_tree_add_item_ret_uint(tree, hf_cbsp_ci, tvb, offset, 2, ENC_NA, &ci);
offset += 2;
proto_item_append_text(ti, ": LAC 0%04x, CI 0x%04x", lac, ci);
break;
case CBSP_CIDD_CI:
proto_tree_add_item_ret_uint(tree, hf_cbsp_ci, tvb, offset, 2, ENC_NA, &ci);
offset += 2;
proto_item_append_text(ti, ": CI 0x%04x", ci);
break;
case CBSP_CIDD_LAI:
mcc_mnc = dissect_e212_mcc_mnc_wmem_packet_str(tvb, pinfo, tree, offset, E212_NONE, TRUE);
offset += 3;
proto_tree_add_item_ret_uint(tree, hf_cbsp_lac, tvb, offset, 2, ENC_NA, &lac);
offset += 2;
proto_item_append_text(ti, ": %s, LAC 0x%04x", mcc_mnc, lac);
break;
case CBSP_CIDD_LAC:
proto_tree_add_item_ret_uint(tree, hf_cbsp_lac, tvb, offset, 2, ENC_NA, &lac);
offset += 2;
proto_item_append_text(ti, ": LAC 0x%04x", lac);
break;
case CBSP_CIDD_ALL_IN_BSC:
break;
default:
return -1;
}
return offset - base_offs;
}
/* return the length of a single list element of the given discriminator/type */
static gint cell_id_len(guint8 discr)
{
switch (discr) {
case CBSP_CIDD_WHOLE_CGI:
return 7;
case CBSP_CIDD_LAC_CI:
return 4;
case CBSP_CIDD_CI:
return 2;
case CBSP_CIDD_LAI:
return 5;
case CBSP_CIDD_LAC:
return 2;
case CBSP_CIDD_ALL_IN_BSC:
return 0;
default:
return -1;
}
}
static void
dissect_cell_id_list_ie(tvbuff_t *tvb, packet_info *pinfo, guint offset, guint len, proto_tree *tree,
proto_item *parent_ti)
{
guint base_offs = offset;
guint32 discr;
guint count = 0;
/* list-global discriminator */
proto_tree_add_item_ret_uint(tree, hf_cbsp_cell_id_disc, tvb, offset, 1, ENC_NA, &discr);
discr &= 0x0f;
offset++;
/* iterate over list items */
while (offset - base_offs < len) {
proto_tree *elem_tree;
proto_item *ti;
int rc;
guint remain_len = len - (offset - base_offs);
elem_tree = proto_tree_add_subtree(tree, tvb, offset, cell_id_len(discr),
ett_cbsp_cell_list, &ti,
"Cell List Item");
rc = dissect_cell_id_elem(discr, tvb, pinfo, offset, remain_len, elem_tree, ti);
if (rc <= 0)
break;
offset += rc;
count++;
}
proto_item_append_text(parent_ti, " (%s): %u items",
val_to_str_const(discr, cbsp_cell_id_disc_vals, ""), count);
}
static void
dissect_rr_load_list_ie(tvbuff_t *tvb, packet_info *pinfo, guint offset, guint len, proto_tree *tree,
proto_item *parent_ti)
{
guint base_offs = offset;
guint32 discr;
guint count = 0;
/* list-global discriminator */
proto_tree_add_item_ret_uint(tree, hf_cbsp_cell_id_disc, tvb, offset, 1, ENC_NA, &discr);
discr &= 0x0f;
offset++;
/* iterate over list items */
while (offset - base_offs < len) {
proto_tree *elem_tree;
guint32 load1, load2;
proto_item *ti;
int rc;
guint remain_len = len - (offset - base_offs);
elem_tree = proto_tree_add_subtree(tree, tvb, offset, cell_id_len(discr)+2,
ett_cbsp_load_list, &ti,
"RR Load List Item");
rc = dissect_cell_id_elem(discr, tvb, pinfo, offset, remain_len, elem_tree, ti);
if (rc <= 0)
break;
offset += rc;
proto_tree_add_item_ret_uint(elem_tree, hf_cbsp_cell_load1, tvb, offset++, 1,
ENC_NA, &load1);
proto_tree_add_item_ret_uint(elem_tree, hf_cbsp_cell_load2, tvb, offset++, 1,
ENC_NA, &load2);
proto_item_append_text(ti, ": L1=%u%%, L2=%u%%", load1, load2);
count++;
}
proto_item_append_text(parent_ti, " (%s): %u items",
val_to_str_const(discr, cbsp_cell_id_disc_vals, ""), count);
}
static void
dissect_failure_list_ie(tvbuff_t *tvb, packet_info *pinfo, guint offset, guint len, proto_tree *tree,
proto_item *parent_ti)
{
guint base_offs = offset;
guint count = 0;
/* iterate over list items, each with its own discriminator */
while (offset - base_offs < len) {
proto_tree *elem_tree;
proto_item *ti;
guint remain_len, cause;
int rc;
guint8 discr = tvb_get_guint8(tvb, offset) & 0x0f;
elem_tree = proto_tree_add_subtree(tree, tvb, offset, cell_id_len(discr)+2,
ett_cbsp_fail_list, &ti,
"Failure List Item");
proto_tree_add_item(elem_tree, hf_cbsp_cell_id_disc, tvb, offset++, 1, ENC_NA);
remain_len = len - (offset - base_offs);
rc = dissect_cell_id_elem(discr, tvb, pinfo, offset, remain_len, elem_tree, ti);
if (rc <= 0)
break;
offset += rc;
proto_tree_add_item_ret_uint(elem_tree, hf_cbsp_cause, tvb, offset++, 1, ENC_NA, &cause);
proto_item_append_text(ti, ": Cause %s",
val_to_str_const(cause, cbsp_cause_vals, "Undefined"));
count++;
}
proto_item_append_text(parent_ti, ": %u items", count);
}
static void
dissect_bc_compl_list_ie(tvbuff_t *tvb, packet_info *pinfo, guint offset, guint len, proto_tree *tree,
proto_item *parent_ti)
{
guint base_offs = offset;
guint32 discr;
guint count = 0;
/* list-global discriminator */
proto_tree_add_item_ret_uint(tree, hf_cbsp_cell_id_disc, tvb, offset, 1, ENC_NA, &discr);
discr &= 0x0f;
offset++;
/* iterate over list items */
while (offset - base_offs < len) {
proto_tree *elem_tree;
proto_item *ti;
guint32 num_bc, num_bi;
int rc;
guint remain_len = len - (offset - base_offs);
elem_tree = proto_tree_add_subtree(tree, tvb, offset, cell_id_len(discr)+3,
ett_cbsp_num_bcast_compl_list, &ti,
"Number of Broadcasts completed");
rc = dissect_cell_id_elem(discr, tvb, pinfo, offset, remain_len, elem_tree, ti);
if (rc <= 0)
break;
offset += rc;
proto_tree_add_item_ret_uint(elem_tree, hf_cbsp_num_bcast_compl, tvb, offset, 2, ENC_NA,
&num_bc);
offset += 2;
proto_tree_add_item_ret_uint(elem_tree, hf_cbsp_num_bcast_info, tvb, offset++, 1, ENC_NA,
&num_bi);
proto_item_append_text(ti, ": NumBC=%u (%s)", num_bc,
val_to_str_const(num_bi, cbsp_num_bcast_shortinfo_vals, ""));
count++;
}
proto_item_append_text(parent_ti, " (%s): %u items",
val_to_str_const(discr, cbsp_cell_id_disc_vals, ""), count);
}
static gint
dissect_cbsp_tlvs(tvbuff_t *tvb, int base_offs, int length, packet_info *pinfo, proto_tree *tree)
{
guint8 sms_encoding = SMS_ENCODING_7BIT;
int offset = base_offs;
while (offset - base_offs < length) {
guint8 tag; /* Information Element Identifier */
unsigned int len; /* Length of payload */
unsigned int len_len = 0;/* Length of "length" field (may be 0) */
proto_item *ti;
proto_tree *att_tree, *subtree;
guint32 tmp_u;
int secs;
tag = tvb_get_guint8(tvb, offset);
offset++;
switch (cbsp_att_tlvdef.def[tag].type) {
case TLV_TYPE_TV:
len = 1;
len_len = 0;
break;
case TLV_TYPE_FIXED:
len = cbsp_att_tlvdef.def[tag].fixed_len;
len_len = 0;
break;
case TLV_TYPE_TLV:
len = tvb_get_guint8(tvb, offset);
break;
case TLV_TYPE_TL16V:
len = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN);
len_len = 2;
break;
default:
return length;
}
att_tree = proto_tree_add_subtree_format(tree, tvb, offset-1, 1+len_len+len,
ett_cbsp_ie, &ti, "IE: %s",
val_to_str(tag, cbsp_iei_names, "Unknown 0x%02x"));
proto_tree_add_item(att_tree, hf_cbsp_iei, tvb, offset-1, 1, ENC_NA);
if (len_len)
proto_tree_add_uint(att_tree, hf_cbsp_ie_len, tvb, offset, len_len, len);
offset += len_len;
switch (tag) {
case CBSP_IEI_MSG_CONTENT:
dissect_cbsp_content_ie(tvb, pinfo, offset, len, att_tree, sms_encoding, ti);
break;
case CBSP_IEI_OLD_SERIAL_NR:
proto_tree_add_item_ret_uint(att_tree, hf_cbsp_old_serial_nr, tvb, offset, len, ENC_BIG_ENDIAN, &tmp_u);
proto_item_append_text(ti, ": 0x%04x", tmp_u);
break;
case CBSP_IEI_NEW_SERIAL_NR:
proto_tree_add_item_ret_uint(att_tree, hf_cbsp_new_serial_nr, tvb, offset, len, ENC_BIG_ENDIAN, &tmp_u);
proto_item_append_text(ti, ": 0x%04x", tmp_u);
break;
case CBSP_IEI_CATEGORY:
proto_tree_add_item_ret_uint(att_tree, hf_cbsp_category, tvb, offset, len, ENC_NA,&tmp_u);
proto_item_append_text(ti, ": %s", val_to_str_const(tmp_u, cbsp_category_names, ""));
break;
case CBSP_IEI_REP_PERIOD:
proto_tree_add_item_ret_uint(att_tree, hf_cbsp_rep_period, tvb, offset, len, ENC_BIG_ENDIAN, &tmp_u);
proto_item_append_text(ti, ": %u", tmp_u);
break;
case CBSP_IEI_NUM_BCAST_REQ:
proto_tree_add_item_ret_uint(att_tree, hf_cbsp_num_bcast_req, tvb, offset, len, ENC_BIG_ENDIAN, &tmp_u);
proto_item_append_text(ti, ": %u", tmp_u);
break;
case CBSP_IEI_CAUSE:
proto_tree_add_item_ret_uint(att_tree, hf_cbsp_cause, tvb, offset, len, ENC_NA, &tmp_u);
proto_item_append_text(ti, ": %s", val_to_str_const(tmp_u, cbsp_cause_vals, ""));
break;
case CBSP_IEI_DCS:
proto_tree_add_item_ret_uint(att_tree, hf_cbsp_dcs, tvb, offset, len, ENC_NA, &tmp_u);
subtree = proto_item_add_subtree(att_tree, ett_cbsp_cbs_data_coding);
sms_encoding = dissect_cbs_data_coding_scheme(tvb, pinfo, subtree, offset);
proto_item_append_text(ti, ": 0x%02x", tmp_u);
break;
case CBSP_IEI_RECOVERY_IND:
proto_tree_add_item(att_tree, hf_cbsp_recovery_ind, tvb, offset, len, ENC_NA);
break;
case CBSP_IEI_MSG_ID:
proto_tree_add_item_ret_uint(att_tree, hf_cbsp_msg_id, tvb, offset, len, ENC_BIG_ENDIAN, &tmp_u);
proto_item_append_text(ti, ": 0x%04x", tmp_u);
break;
case CBSP_IEI_EMERG_IND:
proto_tree_add_item_ret_uint(att_tree, hf_cbsp_emerg_ind, tvb, offset, len, ENC_NA, &tmp_u);
proto_item_append_text(ti, ": %s", val_to_str_const(tmp_u, cbsp_emerg_ind_vals, ""));
break;
case CBSP_IEI_WARN_TYPE:
proto_tree_add_item(att_tree, hf_cbsp_warn_type, tvb, offset, len, ENC_NA);
break;
case CBSP_IEI_CHANNEL_IND:
proto_tree_add_item_ret_uint(att_tree, hf_cbsp_channel_ind, tvb, offset, len, ENC_NA, &tmp_u);
proto_item_append_text(ti, ": %s", val_to_str_const(tmp_u, cbsp_chan_ind_vals, ""));
break;
case CBSP_IEI_NUM_OF_PAGES:
proto_tree_add_item_ret_uint(att_tree, hf_cbsp_num_of_pages, tvb, offset, len, ENC_NA, &tmp_u);
proto_item_append_text(ti, ": %u", tmp_u);
break;
case CBSP_IEI_SCHEDULE_PERIOD:
proto_tree_add_item(att_tree, hf_cbsp_sched_period, tvb, offset, len, ENC_NA);
break;
case CBSP_IEI_NUM_OF_RES_SLOTS:
proto_tree_add_item(att_tree, hf_cbsp_num_of_res_slots, tvb, offset, len, ENC_NA);
break;
case CBSP_IEI_BCAST_MSG_TYPE:
proto_tree_add_item_ret_uint(att_tree, hf_cbsp_bcast_msg_type, tvb, offset, len, ENC_NA, &tmp_u);
proto_item_append_text(ti, ": %s", val_to_str_const(tmp_u, cbsp_bcast_msg_type_vals, ""));
break;
case CBSP_IEI_WARNING_PERIOD:
secs = cbsp_warn_period_to_secs(tvb_get_guint8(tvb, offset));
proto_tree_add_uint(att_tree, hf_cbsp_warning_period, tvb, offset, len, secs);
proto_item_append_text(ti, ": %u (s)", secs);
break;
case CBSP_IEI_KEEP_ALIVE_REP_PERIOD:
secs = cbsp_warn_period_to_secs(tvb_get_guint8(tvb, offset));
proto_tree_add_uint(att_tree, hf_cbsp_keepalive_period, tvb, offset, len, secs);
proto_item_append_text(ti, ": %u (s)", secs);
break;
case CBSP_IEI_CELL_LIST:
dissect_cell_id_list_ie(tvb, pinfo, offset, len, att_tree, ti);
break;
case CBSP_IEI_NUM_BCAST_COMPL_LIST:
dissect_bc_compl_list_ie(tvb, pinfo, offset, len, att_tree, ti);
break;
case CBSP_IEI_FAILURE_LIST:
dissect_failure_list_ie(tvb, pinfo, offset, len, att_tree, ti);
break;
case CBSP_IEI_RR_LOADING_LIST:
dissect_rr_load_list_ie(tvb, pinfo, offset, len, att_tree, ti);
break;
case CBSP_IEI_WARN_SEC_INFO:
/* this element is bogus / not used anyway, no need for a dissector */
default:
/* Unknown/unsupported IE: Print raw payload in addition to IEI + Length printed above */
proto_tree_add_item(att_tree, hf_cbsp_ie_payload, tvb, offset, len, ENC_NA);
break;
}
offset += len;
}
return offset;
}
static int
dissect_cbsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
int len_ind, offset = 0;
proto_item *ti;
proto_tree *cbsp_tree = NULL;
guint8 msg_type;
const char *str;
//len = tvb_reported_length(tvb);
msg_type = tvb_get_guint8(tvb, offset + 0);
len_ind = tvb_get_guint24(tvb, offset + 1, ENC_BIG_ENDIAN);
col_set_str(pinfo->cinfo, COL_PROTOCOL, "CBSP");
col_clear(pinfo->cinfo, COL_INFO);
str = val_to_str(msg_type, cbsp_msg_type_names, "Unknown CBSP Message Type 0x%02x");
col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", str);
if (tree) {
ti = proto_tree_add_protocol_format(tree, proto_cbsp, tvb, 0, len_ind+4, "CBSP %s", str);
cbsp_tree = proto_item_add_subtree(ti, ett_cbsp);
proto_tree_add_item(cbsp_tree, hf_cbsp_msg_type,
tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
proto_tree_add_item(cbsp_tree, hf_cbsp_msg_len, tvb, offset, 3, ENC_BIG_ENDIAN);
offset += 3;
dissect_cbsp_tlvs(tvb, offset, tvb_reported_length_remaining(tvb, offset), pinfo,
cbsp_tree);
}
return tvb_captured_length(tvb);
}
void
proto_register_cbsp(void)
{
static hf_register_info hf[] = {
{ &hf_cbsp_msg_type, { "Message Type", "cbsp.msg_type",
FT_UINT8, BASE_DEC, VALS(cbsp_msg_type_names), 0, NULL, HFILL } },
{ &hf_cbsp_msg_len, { "Message Length", "cbsp.msg_len",
FT_UINT24, BASE_DEC, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_iei, { "Information Element Identifier", "cbsp.ie.iei",
FT_UINT8, BASE_DEC, VALS(cbsp_iei_names), 0, NULL, HFILL } },
{ &hf_cbsp_ie_len, { "Information Element Length", "cbsp.ie.len",
FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_ie_payload, { "Information Element Payload", "cbsp.ie.payload",
FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_old_serial_nr, { "Old Serial Number", "cbsp.old_serial_nr",
FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_new_serial_nr, { "New Serial Number", "cbsp.new_serial_nr",
FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_category, { "Category", "cbsp.category",
FT_UINT8, BASE_HEX, VALS(cbsp_category_names), 0, NULL, HFILL } },
{ &hf_cbsp_rep_period, { "Repetition Period (units of 1.883s)", "cbsp.rep_period",
FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_num_bcast_req, { "Number of Broadcasts Requested", "cbsp.num_bcast_req",
FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_cause, { "Cause", "cbsp.cause",
FT_UINT8, BASE_HEX, VALS(cbsp_cause_vals), 0, NULL, HFILL } },
{ &hf_cbsp_dcs, { "Data Coding Scheme", "cbsp.dcs",
FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_recovery_ind, { "Recovery Indication", "cbsp.recovery_ind",
FT_UINT8, BASE_HEX, VALS(cbsp_recov_ind_vals), 0, NULL, HFILL } },
{ &hf_cbsp_msg_id, { "Message Identifier", "cbsp.message_id",
FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_emerg_ind, { "Emergency Indicator", "cbsp.emergency_ind",
FT_UINT8, BASE_HEX, VALS(cbsp_emerg_ind_vals), 0, NULL, HFILL } },
{ &hf_cbsp_warn_type, { "Warning Type", "cbsp.warn_type",
FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_channel_ind, { "Channel Indicator", "cbsp.channel_ind",
FT_UINT8, BASE_HEX, VALS(cbsp_chan_ind_vals), 0, NULL, HFILL } },
{ &hf_cbsp_num_of_pages, { "Number of Pages", "cbsp.num_of_pages",
FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_cb_msg_page, { "CBS Message Information Page", "cbsp.cb_msg_page",
FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_cbs_page_content, { "CBS Page Content", "cbsp.cb_page_content",
FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_sched_period, { "Schedule Period", "cbsp.sched_period",
FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_num_of_res_slots, { "Number of Reserved Slots", "cbsp.num_of_res_slots",
FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_bcast_msg_type, { "Broadcast Message Type", "cbsp.bcast_msg_type",
FT_UINT8, BASE_DEC, VALS(cbsp_bcast_msg_type_vals), 0, NULL, HFILL } },
{ &hf_cbsp_warning_period, { "Warning Period", "cbsp.warning_period",
FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_keepalive_period, { "Keepalive Repetition Period", "cbsp.keepalive_rep_period",
FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_user_info_length, { "User Information Length", "cbsp.user_info_len",
FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_cell_id_disc, { "Cell ID Discriminator", "cbsp.cell_id_disc",
FT_UINT8, BASE_DEC, VALS(cbsp_cell_id_disc_vals), 0, NULL, HFILL } },
{ &hf_cbsp_cell_load1, { "Radio Resource Load 1", "cbsp.rr_load1",
FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_cell_load2, { "Radio Resource Load 2", "cbsp.rr_load2",
FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_num_bcast_compl, { "Number of Broadcasts Completed", "cbsp.num_bcast_compl",
FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_num_bcast_info, { "Number of Broadcasts Info", "cbsp.num_bcast_info",
FT_UINT8, BASE_HEX, VALS(cbsp_num_bcast_info_vals), 0, NULL, HFILL } },
{ &hf_cbsp_lac, { "Location Area Code (LAC)", "cbsp.lac",
FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } },
{ &hf_cbsp_ci, { "Cell Identifier (CI)", "cbsp.ci",
FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } },
};
static gint *ett[] = {
&ett_cbsp,
&ett_cbsp_ie,
&ett_cbsp_cbs_data_coding,
&ett_cbsp_cbs_page_content,
&ett_cbsp_cell_list,
&ett_cbsp_fail_list,
&ett_cbsp_load_list,
&ett_cbsp_num_bcast_compl_list,
};
proto_cbsp = proto_register_protocol("3GPP/GSM Cell Broadcast Service Protocol", "cbsp", "cbsp");
proto_register_field_array(proto_cbsp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
}
void
proto_reg_handoff_cbsp(void)
{
dissector_handle_t cbsp_handle;
cbsp_handle = create_dissector_handle(dissect_cbsp, proto_cbsp);
dissector_add_uint_with_preference("tcp.port", CBSP_TCP_PORT, cbsp_handle);
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
* :indentSize=8:tabSize=8:noTabs=false:
*/