aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-umts_mac.c
diff options
context:
space:
mode:
authorAnders Broman <anders.broman@ericsson.com>2009-10-09 06:37:48 +0000
committerAnders Broman <anders.broman@ericsson.com>2009-10-09 06:37:48 +0000
commit46aa5c44de5b62cc061840b29903a63bc3790445 (patch)
tree64ab8ab30cfec2b204cd625f538cf1345b443aee /epan/dissectors/packet-umts_mac.c
parent0659b21e03316a01da5b2ed845064f57d76380f4 (diff)
From Tobias Witek:
New protocols: UMTS RLC (ETSI TS 125 322), UMTS MAC (ETSI TS 125 321). This does not currently compile cleanly but checking it in to be worked on. https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=3495 svn path=/trunk/; revision=30414
Diffstat (limited to 'epan/dissectors/packet-umts_mac.c')
-rw-r--r--epan/dissectors/packet-umts_mac.c609
1 files changed, 609 insertions, 0 deletions
diff --git a/epan/dissectors/packet-umts_mac.c b/epan/dissectors/packet-umts_mac.c
new file mode 100644
index 0000000000..c59aa1f5ce
--- /dev/null
+++ b/epan/dissectors/packet-umts_mac.c
@@ -0,0 +1,609 @@
+/* Routines for UMTS FP disassembly
+ *
+ * $Id$
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <epan/packet.h>
+
+#include "packet-umts_fp.h"
+#include "packet-umts_mac.h"
+
+int proto_umts_mac = -1;
+extern int proto_fp;
+
+/* dissector fields */
+static int hf_mac_fach_fdd_tctf = -1;
+static int hf_mac_rach_fdd_tctf = -1;
+static int hf_mac_ct = -1;
+static int hf_mac_ueid_type = -1;
+static int hf_mac_crnti = -1;
+static int hf_mac_urnti = -1;
+static int hf_mac_channel = -1;
+
+/* subtrees */
+static int ett_mac = -1;
+static int ett_mac_fach = -1;
+static int ett_mac_rach = -1;
+static int ett_mac_dch = -1;
+static int ett_mac_pch = -1;
+static int ett_mac_edch = -1;
+static int ett_mac_hsdsch = -1;
+
+static dissector_handle_t rlc_pcch_handle;
+static dissector_handle_t rlc_ccch_handle;
+static dissector_handle_t rlc_dcch_handle;
+static dissector_handle_t rlc_ps_dtch_handle;
+
+static const value_string rach_fdd_tctf_vals[] = {
+ { TCTF_CCCH_RACH_FDD, "CCCH over RACH (FDD)" },
+ { TCTF_DCCH_DTCH_RACH_FDD, "DCCH/DTCH over RACH (FDD)" },
+ { 0, NULL }
+};
+
+static const value_string fach_fdd_tctf_vals[] = {
+ { TCTF_BCCH_FACH_FDD, "BCCH over FACH (FDD)" },
+ { TCTF_DCCH_DTCH_FACH_FDD, "DCCH/DTCH over FACH (FDD)" },
+ { TCTF_MTCH_FACH_FDD, "MTCH over FACH (FDD)" },
+ { TCTF_CCCH_FACH_FDD, "CCCH over FACH (FDD)" },
+ { TCTF_MCCH_FACH_FDD, "MCCH over FACH (FDD)" },
+ { TCTF_MSCH_FACH_FDD, "MSCH over FACH (FDD)" },
+ { TCTF_CTCH_FACH_FDD, "CTCH over FACH (FDD)" },
+ { 0, NULL }
+};
+
+static const value_string ueid_type_vals[] = {
+ { MAC_UEID_TYPE_URNTI, "U-RNTI" },
+ { MAC_UEID_TYPE_CRNTI, "C-RNTI" },
+ { 0, NULL }
+};
+
+#define MAC_PCCH 0
+#define MAC_CCCH 1
+#define MAC_CTCH 2
+#define MAC_DCCH 3
+#define MAC_DTCH 4
+#define MAC_BCCH 5
+#define MAC_MCCH 6
+#define MAC_MSCH 7
+#define MAC_MTCH 8
+static const value_string mac_logical_channel_vals[] = {
+ { MAC_PCCH, "PCCH" },
+ { MAC_CCCH, "CCCH" },
+ { MAC_CTCH, "CTCH" },
+ { MAC_DCCH, "DCCH" },
+ { MAC_DTCH, "DTCH" },
+ { MAC_BCCH, "BCCH" },
+ { MAC_MCCH, "MCCH" },
+ { MAC_MSCH, "MSCH" },
+ { MAC_MTCH, "MTCH" },
+ { 0, NULL }
+};
+
+static tvbuff_t *
+tvb_new_octet_aligned(tvbuff_t *tvb, guint32 bit_offset, gint32 no_of_bits)
+{
+ tvbuff_t *sub_tvb = NULL;
+ guint32 byte_offset;
+ gint32 datalen, i;
+ guint8 left, right, *buf;
+ const guint8 *data;
+
+ byte_offset = bit_offset >> 3;
+ left = bit_offset % 8; /* for left-shifting */
+ right = 8 - left; /* for right-shifting */
+
+ if (no_of_bits == -1) {
+ datalen = tvb_length_remaining(tvb, byte_offset);
+ } else {
+ datalen = no_of_bits >> 3;
+ if (no_of_bits % 8) datalen++;
+ }
+
+ /* already aligned -> shortcut */
+ if (left == 0) {
+ return tvb_new_subset(tvb, byte_offset, datalen, -1);
+ }
+
+ buf = ep_alloc0(datalen);
+
+ /* if at least one trailing byte is available, we must use the content
+ * of that byte for the last shift (i.e. tvb_get_ptr() must use datalen + 1
+ * if non extra byte is available, the last shifted byte requires
+ * special treatment
+ */
+ if (tvb_length_remaining(tvb, byte_offset) > datalen) {
+ data = tvb_get_ptr(tvb, byte_offset, datalen + 1);
+ } else {
+ data = tvb_get_ptr(tvb, byte_offset, datalen);
+ datalen--; /* correct 'datalen' for 'for' loop */
+ buf[datalen] = data[datalen] << left; /* set last octet */
+ }
+ /* shift tvb data bit_offset bits to the left */
+ for (i = 0; i < datalen; i++)
+ buf[i] = (data[i] << left) | (data[i+1] >> right);
+
+ sub_tvb = tvb_new_real_data(buf, datalen, datalen);
+ tvb_set_child_real_data_tvbuff(tvb, sub_tvb);
+
+ return sub_tvb;
+}
+
+static guint8 fach_fdd_tctf(guint8 hdr, guint16 *bit_offs)
+{
+ guint8 tctf;
+ /* first, test for valid 2-bit combinations */
+ tctf = hdr >> 6;
+ switch (tctf) {
+ case TCTF_BCCH_FACH_FDD:
+ case TCTF_DCCH_DTCH_FACH_FDD:
+ *bit_offs = 2;
+ return tctf;
+ }
+ /* 4-bit combinations */
+ tctf = hdr >> 4;
+ switch (tctf) {
+ case TCTF_MTCH_FACH_FDD:
+ *bit_offs = 4;
+ return tctf;
+ }
+ /* just return the 8-bit combination */
+ *bit_offs = 8;
+ tctf = hdr;
+ switch (tctf) {
+ case TCTF_CCCH_FACH_FDD:
+ case TCTF_MCCH_FACH_FDD:
+ case TCTF_MSCH_FACH_FDD:
+ case TCTF_CTCH_FACH_FDD:
+ return tctf;
+ default:
+ return tctf; /* TODO */
+ }
+}
+
+static guint16 tree_add_common_dcch_dtch_fields(tvbuff_t *tvb, packet_info *pinfo _U_,
+ proto_tree *tree, guint16 bitoffs, fp_info *fpinf, umts_mac_info *macinf)
+{
+ guint8 ueid_type;
+
+ ueid_type = tvb_get_bits8(tvb, bitoffs, 2);
+ proto_tree_add_bits_item(tree, hf_mac_ueid_type, tvb, bitoffs, 2, FALSE);
+ bitoffs += 2;
+ if (ueid_type == MAC_UEID_TYPE_URNTI) {
+ proto_tree_add_bits_item(tree, hf_mac_urnti, tvb, bitoffs, 32, FALSE);
+ bitoffs += 32;
+ } else if (ueid_type == MAC_UEID_TYPE_CRNTI) {
+ proto_tree_add_bits_item(tree, hf_mac_crnti, tvb, 4, 16, FALSE);
+ bitoffs += 16;
+ }
+
+ if (macinf->ctmux[fpinf->cur_tb]) {
+ proto_tree_add_bits_item(tree, hf_mac_ct, tvb, bitoffs, 4, FALSE);
+ bitoffs += 4;
+ }
+ return bitoffs;
+}
+
+static void dissect_mac_fdd_pch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_tree *pch_tree = NULL;
+ proto_item *channel_type;
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "MAC");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "PCCH");
+
+ if (tree) {
+ proto_item *ti;
+ ti = proto_tree_add_item(tree, proto_umts_mac, tvb, 0, -1, FALSE);
+ pch_tree = proto_item_add_subtree(ti, ett_mac_pch);
+ proto_item_append_text(ti, " (PCCH)");
+ channel_type = proto_tree_add_uint(pch_tree, hf_mac_channel, tvb, 0, 0, MAC_PCCH);
+ PROTO_ITEM_SET_GENERATED(channel_type);
+ }
+ call_dissector(rlc_pcch_handle, tvb, pinfo, tree);
+}
+
+static void dissect_mac_fdd_rach(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ guint8 tctf;
+ guint8 chan;
+ guint16 bitoffs = 0;
+ tvbuff_t *next_tvb;
+ proto_tree *rach_tree = NULL;
+ proto_item *channel_type;
+ umts_mac_info *macinf;
+ fp_info *fpinf;
+ proto_item *ti = NULL;
+
+ /* RACH TCTF is always 2 bit */
+ tctf = tvb_get_bits8(tvb, 0, 2);
+ bitoffs += 2;
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "MAC");
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_str(pinfo->cinfo, COL_INFO,
+ val_to_str(tctf, rach_fdd_tctf_vals, "Unknown TCTF"));
+
+ ti = proto_tree_add_item(tree, proto_umts_mac, tvb, 0, -1, FALSE);
+ rach_tree = proto_item_add_subtree(ti, ett_mac_rach);
+
+ macinf = p_get_proto_data(pinfo->fd, proto_umts_mac);
+ fpinf = p_get_proto_data(pinfo->fd, proto_fp);
+ if (!macinf || !fpinf) {
+ proto_tree_add_text(rach_tree, tvb, 0, -1,
+ "Cannot dissect MAC frame because per-frame info is missing");
+ return;
+ }
+
+ proto_tree_add_bits_item(rach_tree, hf_mac_rach_fdd_tctf, tvb, 0, 2, FALSE);
+ if (tctf == TCTF_DCCH_DTCH_RACH_FDD) {
+ macinf->ctmux[fpinf->cur_tb] = 1; /* DCCH/DTCH on RACH *always* has a C/T */
+ bitoffs = tree_add_common_dcch_dtch_fields(tvb, pinfo, rach_tree, bitoffs, fpinf, macinf);
+ }
+
+ chan = fpinf->cur_chan;
+ /* handoff to next dissector */
+ switch (tctf) {
+ case TCTF_CCCH_RACH_FDD:
+ proto_item_append_text(ti, " (CCCH)");
+ channel_type = proto_tree_add_uint(rach_tree, hf_mac_channel, tvb, 0, 0, MAC_CCCH);
+ PROTO_ITEM_SET_GENERATED(channel_type);
+ next_tvb = tvb_new_octet_aligned(tvb, bitoffs, fpinf->chan_tf_size[chan] - bitoffs);
+ add_new_data_source(pinfo, next_tvb, "Octet-Aligned CCCH Data");
+ call_dissector(rlc_ccch_handle, next_tvb, pinfo, tree);
+ break;
+ case TCTF_DCCH_DTCH_RACH_FDD:
+ switch (macinf->content[chan]) {
+ case MAC_CONTENT_DCCH:
+ proto_item_append_text(ti, " (DCCH)");
+ channel_type = proto_tree_add_uint(rach_tree, hf_mac_channel, tvb, 0, 0, MAC_DCCH);
+ PROTO_ITEM_SET_GENERATED(channel_type);
+ next_tvb = tvb_new_octet_aligned(tvb, bitoffs, fpinf->chan_tf_size[chan] - bitoffs);
+ add_new_data_source(pinfo, next_tvb, "Octet-Aligned DCCH Data");
+ call_dissector(rlc_dcch_handle, next_tvb, pinfo, tree);
+ break;
+ case MAC_CONTENT_PS_DTCH:
+ proto_item_append_text(ti, " (PS DTCH)");
+ channel_type = proto_tree_add_uint(rach_tree, hf_mac_channel, tvb, 0, 0, MAC_DTCH);
+ PROTO_ITEM_SET_GENERATED(channel_type);
+ next_tvb = tvb_new_octet_aligned(tvb, bitoffs, fpinf->chan_tf_size[chan] - bitoffs);
+ add_new_data_source(pinfo, next_tvb, "Octet-Aligned DTCH Data");
+ call_dissector(rlc_ps_dtch_handle, next_tvb, pinfo, tree);
+ break;
+ case MAC_CONTENT_CS_DTCH:
+ proto_item_append_text(ti, " (CS DTCH)");
+ /* TODO */
+ break;
+ default:
+ proto_item_append_text(ti, " (Unknown RACH DCCH/DTCH Content)");
+ }
+ break;
+ default:
+ proto_item_append_text(ti, " (Unknown RACH TCTF)");
+ }
+}
+
+static void dissect_mac_fdd_fach(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ guint8 hdr, tctf;
+ guint16 bitoffs = 0;
+ guint16 tctf_len, chan;
+ proto_tree *fach_tree = NULL;
+ proto_item *channel_type;
+ umts_mac_info *macinf;
+ fp_info *fpinf;
+ proto_item *ti = NULL;
+
+ hdr = tvb_get_guint8(tvb, 0);
+
+ /* get target channel type field */
+ tctf = fach_fdd_tctf(hdr, &bitoffs);
+ tctf_len = bitoffs;
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "MAC");
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_str(pinfo->cinfo, COL_INFO,
+ val_to_str(tctf, fach_fdd_tctf_vals, "Unknown TCTF"));
+
+ ti = proto_tree_add_item(tree, proto_umts_mac, tvb, 0, -1, FALSE);
+ fach_tree = proto_item_add_subtree(ti, ett_mac_fach);
+
+ macinf = p_get_proto_data(pinfo->fd, proto_umts_mac);
+ fpinf = p_get_proto_data(pinfo->fd, proto_fp);
+ if (!macinf || !fpinf) {
+ proto_tree_add_text(fach_tree, tvb, 0, -1,
+ "Cannot dissect MAC frame because per-frame info is missing");
+ return;
+ }
+
+ proto_tree_add_bits_item(fach_tree, hf_mac_fach_fdd_tctf, tvb, 0, tctf_len, FALSE);
+ if (tctf == TCTF_DCCH_DTCH_FACH_FDD) {
+ macinf->ctmux[fpinf->cur_tb] = 1; /* DCCH/DTCH on FACH *always* has a C/T */
+ bitoffs = tree_add_common_dcch_dtch_fields(tvb, pinfo, fach_tree, bitoffs, fpinf, macinf);
+ }
+
+ chan = fpinf->cur_chan;
+ switch (tctf) {
+ tvbuff_t *next_tvb;
+ case TCTF_CCCH_FACH_FDD:
+ proto_item_append_text(ti, " (CCCH)");
+ channel_type = proto_tree_add_uint(fach_tree, hf_mac_channel, tvb, 0, 0, MAC_CCCH);
+ PROTO_ITEM_SET_GENERATED(channel_type);
+ /* CCCH over FACH is always octet aligned */
+ next_tvb = tvb_new_subset(tvb, 1, tvb_length_remaining(tvb, 1), -1);
+ call_dissector(rlc_ccch_handle, next_tvb, pinfo, tree);
+ break;
+ case TCTF_DCCH_DTCH_FACH_FDD:
+ switch (macinf->content[fpinf->cur_tb]) {
+ case MAC_CONTENT_DCCH:
+ proto_item_append_text(ti, " (DCCH)");
+ channel_type = proto_tree_add_uint(fach_tree, hf_mac_channel, tvb, 0, 0, MAC_DCCH);
+ PROTO_ITEM_SET_GENERATED(channel_type);
+ next_tvb = tvb_new_octet_aligned(tvb, bitoffs, fpinf->chan_tf_size[chan] - bitoffs);
+ add_new_data_source(pinfo, next_tvb, "Octet-Aligned DCCH Data");
+ call_dissector(rlc_dcch_handle, next_tvb, pinfo, tree);
+ break;
+ case MAC_CONTENT_PS_DTCH:
+ proto_item_append_text(ti, " (PS DTCH)");
+ channel_type = proto_tree_add_uint(fach_tree, hf_mac_channel, tvb, 0, 0, MAC_DTCH);
+ PROTO_ITEM_SET_GENERATED(channel_type);
+ next_tvb = tvb_new_octet_aligned(tvb, bitoffs, fpinf->chan_tf_size[chan] - bitoffs);
+ add_new_data_source(pinfo, next_tvb, "Octet-Aligned DCCH Data");
+ call_dissector(rlc_ps_dtch_handle, next_tvb, pinfo, tree);
+ break;
+ case MAC_CONTENT_CS_DTCH:
+ proto_item_append_text(ti, " (CS DTCH)");
+ /* TODO */
+ break;
+ default:
+ proto_item_append_text(ti, " (Unknown FACH Content");
+ }
+ break;
+ default:
+ proto_item_append_text(ti, " (Unknown FACH Content");
+ }
+}
+
+static void dissect_mac_fdd_dch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ guint16 pos;
+ guint8 bitoffs = 0;
+ umts_mac_info *macinf;
+ fp_info *fpinf;
+ proto_tree *dch_tree = NULL;
+ proto_item *channel_type;
+ tvbuff_t *next_tvb;
+ proto_item *ti = NULL;
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "MAC");
+
+ ti = proto_tree_add_item(tree, proto_umts_mac, tvb, 0, -1, FALSE);
+ dch_tree = proto_item_add_subtree(ti, ett_mac_dch);
+
+ macinf = p_get_proto_data(pinfo->fd, proto_umts_mac);
+ fpinf = p_get_proto_data(pinfo->fd, proto_fp);
+ pos = fpinf->cur_tb;
+ if (!macinf || !fpinf) {
+ proto_tree_add_text(dch_tree, tvb, 0, -1,
+ "Cannot dissect MAC frame because per-frame info is missing");
+ return;
+ }
+ if (macinf->ctmux[pos]) {
+ proto_tree_add_bits_item(dch_tree, hf_mac_ct, tvb, 0, 4, FALSE);
+ bitoffs = 4;
+ }
+
+ if (bitoffs) {
+ next_tvb = tvb_new_octet_aligned(tvb, bitoffs, fpinf->chan_tf_size[pos] - bitoffs);
+ add_new_data_source(pinfo, next_tvb, "Octet-Aligned DCCH Data");
+ } else
+ next_tvb = tvb;
+ switch (macinf->content[pos]) {
+ case MAC_CONTENT_DCCH:
+ proto_item_append_text(ti, " (DCCH)");
+ channel_type = proto_tree_add_uint(dch_tree, hf_mac_channel, tvb, 0, 0, MAC_DCCH);
+ PROTO_ITEM_SET_GENERATED(channel_type);
+ call_dissector(rlc_dcch_handle, next_tvb, pinfo, tree);
+ break;
+ case MAC_CONTENT_PS_DTCH:
+ proto_item_append_text(ti, " (PS DTCH)");
+ channel_type = proto_tree_add_uint(dch_tree, hf_mac_channel, tvb, 0, 0, MAC_DTCH);
+ PROTO_ITEM_SET_GENERATED(channel_type);
+ call_dissector(rlc_ps_dtch_handle, next_tvb, pinfo, tree);
+ break;
+ case MAC_CONTENT_CS_DTCH:
+ proto_item_append_text(ti, " (CS DTCH)");
+ /* TODO */
+ break;
+ default:
+ proto_item_append_text(ti, " (Unknown DCH Content)");
+ ;
+ }
+}
+
+static void dissect_mac_fdd_edch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_tree *edch_tree = NULL;
+ proto_item *channel_type;
+ umts_mac_info *macinf;
+ fp_info *fpinf;
+ guint16 pos;
+ proto_item *ti = NULL;
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "MAC");
+
+ ti = proto_tree_add_item(tree, proto_umts_mac, tvb, 0, -1, FALSE);
+ edch_tree = proto_item_add_subtree(ti, ett_mac_edch);
+
+ fpinf = p_get_proto_data(pinfo->fd, proto_fp);
+ macinf = p_get_proto_data(pinfo->fd, proto_umts_mac);
+ pos = fpinf->cur_tb;
+ if (!macinf) {
+ proto_tree_add_text(edch_tree, tvb, 0, -1,
+ "Cannot dissect MAC frame because per-frame info is missing");
+ return;
+ }
+
+ switch (macinf->content[pos]) {
+ case MAC_CONTENT_DCCH:
+ proto_item_append_text(ti, " (DCCH)");
+ channel_type = proto_tree_add_uint(edch_tree, hf_mac_channel, tvb, 0, 0, MAC_DCCH);
+ PROTO_ITEM_SET_GENERATED(channel_type);
+ call_dissector(rlc_dcch_handle, tvb, pinfo, tree);
+ break;
+ case MAC_CONTENT_PS_DTCH:
+ proto_item_append_text(ti, " (PS DTCH)");
+ channel_type = proto_tree_add_uint(edch_tree, hf_mac_channel, tvb, 0, 0, MAC_DTCH);
+ PROTO_ITEM_SET_GENERATED(channel_type);
+ call_dissector(rlc_ps_dtch_handle, tvb, pinfo, tree);
+ break;
+ case MAC_CONTENT_CS_DTCH:
+ proto_item_append_text(ti, " (CS DTCH)");
+ /* TODO */
+ break;
+ default:
+ proto_item_append_text(ti, " (Unknown EDCH Content)");
+ }
+}
+
+/* to avoid unnecessary re-alignment, the 4 bit padding prepended to the HSDSCH in FP
+ * are handled in the MAC layer
+ * If the C/T field is present, 'bitoffs' will be 8 (4 bit padding and 4 bit C/T) and
+ * no re-alignment is necessary
+ * If no C/T is present, the whole payload will be left-shifted by 4 bit
+ */
+static void dissect_mac_fdd_hsdsch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_tree *hsdsch_tree = NULL;
+ proto_item *channel_type;
+ fp_info *fpinf;
+ umts_mac_info *macinf;
+ guint16 pos;
+ guint8 bitoffs = 4;
+ tvbuff_t *next_tvb;
+ proto_item *ti = NULL;
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "MAC");
+
+ ti = proto_tree_add_item(tree, proto_umts_mac, tvb, 0, -1, FALSE);
+ hsdsch_tree = proto_item_add_subtree(ti, ett_mac_hsdsch);
+
+ fpinf = p_get_proto_data(pinfo->fd, proto_fp);
+ macinf = p_get_proto_data(pinfo->fd, proto_umts_mac);
+ pos = fpinf->cur_tb;
+
+ if (!macinf) {
+ proto_tree_add_text(hsdsch_tree, tvb, 0, -1,
+ "Cannot dissect MAC frame because per-frame info is missing");
+ return;
+ }
+ if (macinf->ctmux[pos]) {
+ proto_tree_add_bits_item(hsdsch_tree, hf_mac_ct, tvb, 0, 4, FALSE);
+ bitoffs += 4;
+ }
+
+ if ((bitoffs % 8) == 0) {
+ next_tvb = tvb_new_subset(tvb, bitoffs/8, -1, -1);
+ } else {
+ next_tvb = tvb_new_octet_aligned(tvb, bitoffs, -1);
+ add_new_data_source(pinfo, next_tvb, "Octet-Aligned HSDSCH Data");
+ }
+ switch (macinf->content[pos]) {
+ case MAC_CONTENT_DCCH:
+ proto_item_append_text(ti, " (DCCH)");
+ channel_type = proto_tree_add_uint(hsdsch_tree, hf_mac_channel, tvb, 0, 0, MAC_DCCH);
+ PROTO_ITEM_SET_GENERATED(channel_type);
+ call_dissector(rlc_dcch_handle, next_tvb, pinfo, tree);
+ break;
+ case MAC_CONTENT_PS_DTCH:
+ proto_item_append_text(ti, " (PS DTCH)");
+ channel_type = proto_tree_add_uint(hsdsch_tree, hf_mac_channel, tvb, 0, 0, MAC_DTCH);
+ PROTO_ITEM_SET_GENERATED(channel_type);
+ call_dissector(rlc_ps_dtch_handle, next_tvb, pinfo, tree);
+ break;
+ case MAC_CONTENT_CS_DTCH:
+ proto_item_append_text(ti, " (CS DTCH)");
+ break;
+ default:
+ proto_item_append_text(ti, " (Unknown HSDSCH Content)");
+ }
+}
+
+void
+proto_register_umts_mac(void)
+{
+ static gint *ett[] = {
+ &ett_mac,
+ &ett_mac_fach,
+ &ett_mac_rach,
+ &ett_mac_dch,
+ &ett_mac_pch,
+ &ett_mac_edch,
+ &ett_mac_hsdsch,
+ };
+ static hf_register_info hf[] = {
+ { &hf_mac_rach_fdd_tctf, { "Target Channel Type Field", "mac.tctf", FT_UINT8, BASE_HEX, VALS(rach_fdd_tctf_vals), 0, "Target Channel Type Field", HFILL } },
+ { &hf_mac_fach_fdd_tctf, { "Target Channel Type Field", "mac.tctf", FT_UINT8, BASE_HEX, VALS(fach_fdd_tctf_vals), 0, "Target Channel Type Field", HFILL } },
+ { &hf_mac_ct, { "C/T", "mac.ct", FT_UINT8, BASE_HEX, NULL, 0, "C/T", HFILL } },
+ { &hf_mac_ueid_type, { "UEID Type", "mac.ueid_type", FT_UINT8, BASE_DEC, VALS(ueid_type_vals), 0, "UEID Type", HFILL } },
+ { &hf_mac_crnti, { "C-RNTI (UEID)", "mac.ueid", FT_UINT16, BASE_HEX, NULL, 0x0, "C-RNTI (UEID)", HFILL } },
+ { &hf_mac_urnti, { "U-RNTI (UEID)", "mac.ueid", FT_UINT32, BASE_HEX, NULL, 0x0, "U-RNTI (UEID)", HFILL } },
+ { &hf_mac_channel, { "Logical Channel", "mac.logical_channel", FT_UINT16, BASE_DEC, VALS(mac_logical_channel_vals), 0, "Logical Channel", HFILL } },
+ };
+
+ proto_umts_mac = proto_register_protocol("MAC", "MAC", "mac");
+ proto_register_field_array(proto_umts_mac, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ register_dissector("mac.fdd.rach", dissect_mac_fdd_rach, proto_umts_mac);
+ register_dissector("mac.fdd.fach", dissect_mac_fdd_fach, proto_umts_mac);
+ register_dissector("mac.fdd.pch", dissect_mac_fdd_pch, proto_umts_mac);
+ register_dissector("mac.fdd.dch", dissect_mac_fdd_dch, proto_umts_mac);
+ register_dissector("mac.fdd.edch", dissect_mac_fdd_edch, proto_umts_mac);
+ register_dissector("mac.fdd.hsdsch", dissect_mac_fdd_hsdsch, proto_umts_mac);
+}
+
+void
+proto_reg_handoff_umts_mac(void)
+{
+ rlc_pcch_handle = find_dissector("rlc.pcch");
+ rlc_ccch_handle = find_dissector("rlc.ccch");
+ rlc_dcch_handle = find_dissector("rlc.dcch");
+ rlc_ps_dtch_handle = find_dissector("rlc.ps_dtch");
+}
+