2011-12-26 23:00:33 +00:00
/* Routines for UMTS MAC (3GPP TS 25.321) disassembly
2009-10-09 06:37:48 +00:00
*
* $ 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
2012-06-28 22:56:06 +00:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
2009-10-09 06:37:48 +00:00
*/
# include "config.h"
# include <glib.h>
# include <epan/packet.h>
2012-05-07 16:41:03 +00:00
# include <epan/conversation.h>
2012-07-16 13:11:20 +00:00
# include <epan/expert.h>
2012-08-07 09:44:16 +00:00
# include <epan/prefs.h>
2009-10-09 06:37:48 +00:00
2012-07-16 13:11:20 +00:00
# include "packet-rrc.h"
2009-10-09 06:37:48 +00:00
# include "packet-umts_fp.h"
# include "packet-umts_mac.h"
2012-07-16 13:11:20 +00:00
# include "packet-rlc.h"
# include "packet-nbap.h"
2009-10-09 06:37:48 +00:00
int proto_umts_mac = - 1 ;
extern int proto_fp ;
2012-05-28 20:11:59 +00:00
extern int proto_rlc ;
2009-10-09 06:37:48 +00:00
/* 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 ;
2013-01-26 18:54:53 +00:00
/* static int hf_mac_channel_str = -1; */
2012-07-16 14:06:36 +00:00
static int hf_mac_lch_id = - 1 ;
static int hf_mac_macdflowd_id = - 1 ;
2013-01-26 18:54:53 +00:00
/* static int hf_mac_channel_hsdsch = -1; */
2012-07-16 14:06:36 +00:00
static int hf_mac_trch_id = - 1 ;
2009-10-09 06:37:48 +00:00
2013-01-26 18:54:53 +00:00
/* static int hf_mac_edch_type2_subframe_header = -1; */
/* static int hf_mac_edch_type2_descriptors = -1; */
/* static int hf_mac_edch_type2_lchid = -1; */
/* static int hf_mac_edch_type2_length = -1; */
/* static int hf_mac_edch_type2_flag = -1; */
2012-07-30 08:37:00 +00:00
static int hf_mac_edch_type2_tsn = - 1 ;
static int hf_mac_edch_type2_ss = - 1 ;
static int hf_mac_edch_type2_sdu = - 1 ;
static int hf_mac_edch_type2_sdu_data = - 1 ;
2012-08-02 14:03:17 +00:00
static int hf_mac_is_fraglink = - 1 ;
static int hf_mac_is_reasmin = - 1 ;
2012-07-30 08:37:00 +00:00
2009-10-09 06:37:48 +00:00
/* 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 ;
2012-07-30 08:37:00 +00:00
static int ett_mac_edch_type2 = - 1 ;
static int ett_mac_edch_type2_sdu = - 1 ;
2009-10-09 06:37:48 +00:00
static dissector_handle_t rlc_pcch_handle ;
static dissector_handle_t rlc_ccch_handle ;
2011-04-16 12:22:16 +00:00
static dissector_handle_t rlc_ctch_handle ;
2009-10-09 06:37:48 +00:00
static dissector_handle_t rlc_dcch_handle ;
static dissector_handle_t rlc_ps_dtch_handle ;
2012-07-16 13:11:20 +00:00
static dissector_handle_t rrc_handle ;
2009-10-09 06:37:48 +00:00
2012-07-24 07:31:46 +00:00
/* MAC-is reassembly */
2012-08-07 09:44:16 +00:00
static guint MAX_TSN = 64 ;
static guint16 mac_tsn_size = 6 ;
static gint global_mac_tsn_size = MAC_TSN_6BITS ;
gint get_mac_tsn_size ( void ) { return global_mac_tsn_size ; }
static const enum_val_t tsn_size_enumvals [ ] = {
{ " 6 bits " , " 6 bits " , MAC_TSN_6BITS } ,
{ " 14 bits " , " 14 bits " , MAC_TSN_14BITS } ,
{ NULL , NULL , - 1 } } ;
2012-08-02 14:03:17 +00:00
enum mac_is_fragment_type {
MAC_IS_HEAD ,
MAC_IS_MIDDLE ,
MAC_IS_TAIL
} ;
typedef struct _mac_is_fragment {
guint8 * data ;
guint32 length ;
2012-07-24 07:31:46 +00:00
guint32 frame_num ;
guint16 tsn ;
2012-08-02 14:03:17 +00:00
guint8 type ;
struct _mac_is_fragment * next ;
} mac_is_fragment ;
typedef struct {
guint32 frame_num ; /* Where reassembly was done (depends on order of arrival). */
guint16 tsn ; /* TSN for the tail fragment. */
2012-07-24 07:31:46 +00:00
guint8 * data ;
guint32 length ;
2012-08-02 14:03:17 +00:00
mac_is_fragment * fragments ;
2012-07-24 07:31:46 +00:00
} mac_is_sdu ;
typedef struct {
2012-08-02 14:03:17 +00:00
mac_is_fragment * head ;
mac_is_fragment * middle ;
mac_is_fragment * tail ;
} body_parts ;
typedef struct {
guint8 lchid ; /* Logical Channel Identifier. */
guint ueid ; /* User Equipment Identifier. */
} mac_is_channel ;
static GHashTable * mac_is_sdus = NULL ; /* channel -> (frag -> sdu) */
static GHashTable * mac_is_fragments = NULL ; /* channel -> body_parts[] */
static gboolean mac_is_channel_equal ( gconstpointer a , gconstpointer b )
2012-07-24 07:31:46 +00:00
{
2013-03-17 22:16:39 +00:00
const mac_is_channel * x = ( const mac_is_channel * ) a , * y = ( const mac_is_channel * ) b ;
2012-08-02 14:03:17 +00:00
return x - > lchid = = y - > lchid & & x - > ueid = = y - > ueid ;
2012-07-24 07:31:46 +00:00
}
2012-08-02 14:03:17 +00:00
static guint mac_is_channel_hash ( gconstpointer key )
2012-07-24 07:31:46 +00:00
{
2013-03-17 22:16:39 +00:00
const mac_is_channel * ch = ( const mac_is_channel * ) key ;
2012-08-02 14:03:17 +00:00
return ( ch - > ueid < < 4 ) | ch - > lchid ;
}
static gboolean mac_is_fragment_equal ( gconstpointer a , gconstpointer b )
{
2013-03-17 22:16:39 +00:00
const mac_is_fragment * x = ( const mac_is_fragment * ) a , * y = ( const mac_is_fragment * ) b ;
2012-08-02 14:03:17 +00:00
return x - > frame_num = = y - > frame_num & & x - > tsn = = y - > tsn & & x - > type = = y - > type ;
}
static guint mac_is_fragment_hash ( gconstpointer key )
{
2013-03-17 22:16:39 +00:00
const mac_is_fragment * frag = ( const mac_is_fragment * ) key ;
2012-08-02 14:03:17 +00:00
return ( frag - > frame_num < < 2 ) | frag - > type ;
2012-07-24 07:31:46 +00:00
}
2012-07-16 14:06:36 +00:00
2009-10-09 06:37:48 +00:00
static const value_string rach_fdd_tctf_vals [ ] = {
2012-03-06 17:11:01 +00:00
{ TCTF_CCCH_RACH_FDD , " CCCH over RACH (FDD) " } ,
{ TCTF_DCCH_DTCH_RACH_FDD , " DCCH/DTCH over RACH (FDD) " } ,
2012-08-07 09:44:16 +00:00
{ 0 , NULL } } ;
2009-10-09 06:37:48 +00:00
static const value_string fach_fdd_tctf_vals [ ] = {
2012-03-06 17:11:01 +00:00
{ 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) " } ,
2012-08-07 09:44:16 +00:00
{ 0 , NULL } } ;
2009-10-09 06:37:48 +00:00
static const value_string ueid_type_vals [ ] = {
2012-03-06 17:11:01 +00:00
{ MAC_UEID_TYPE_URNTI , " U-RNTI " } ,
{ MAC_UEID_TYPE_CRNTI , " C-RNTI " } ,
2012-08-07 09:44:16 +00:00
{ 0 , NULL } } ;
2009-10-09 06:37:48 +00:00
static const value_string mac_logical_channel_vals [ ] = {
2012-03-06 17:11:01 +00:00
{ 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 " } ,
2012-07-26 08:15:20 +00:00
{ MAC_N_A , " N/A " } ,
2012-08-07 09:44:16 +00:00
{ 0 , NULL } } ;
2009-10-09 06:37:48 +00:00
static guint8 fach_fdd_tctf ( guint8 hdr , guint16 * bit_offs )
{
2012-03-06 17:11:01 +00:00
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 */
}
2009-10-09 06:37:48 +00:00
}
static guint16 tree_add_common_dcch_dtch_fields ( tvbuff_t * tvb , packet_info * pinfo _U_ ,
2012-05-28 20:11:59 +00:00
proto_tree * tree , guint16 bitoffs , fp_info * fpinf , umts_mac_info * macinf , rlc_info * rlcinf )
2009-10-09 06:37:48 +00:00
{
2012-03-06 17:11:01 +00:00
guint8 ueid_type ;
2012-08-02 14:03:17 +00:00
2012-03-06 17:11:01 +00:00
ueid_type = tvb_get_bits8 ( tvb , bitoffs , 2 ) ;
proto_tree_add_bits_item ( tree , hf_mac_ueid_type , tvb , bitoffs , 2 , ENC_BIG_ENDIAN ) ;
bitoffs + = 2 ;
if ( ueid_type = = MAC_UEID_TYPE_URNTI ) {
proto_tree_add_bits_item ( tree , hf_mac_urnti , tvb , bitoffs , 32 , ENC_BIG_ENDIAN ) ;
2012-07-27 08:10:31 +00:00
rlcinf - > urnti [ fpinf - > cur_tb ] = tvb_get_bits32 ( tvb , bitoffs , 32 , FALSE ) ;
2012-03-06 17:11:01 +00:00
bitoffs + = 32 ;
} else if ( ueid_type = = MAC_UEID_TYPE_CRNTI ) {
proto_tree_add_bits_item ( tree , hf_mac_crnti , tvb , 4 , 16 , ENC_BIG_ENDIAN ) ;
2012-07-27 08:10:31 +00:00
rlcinf - > urnti [ fpinf - > cur_tb ] = tvb_get_bits16 ( tvb , bitoffs , 16 , FALSE ) ;
2012-03-06 17:11:01 +00:00
bitoffs + = 16 ;
}
if ( macinf - > ctmux [ fpinf - > cur_tb ] ) {
2012-08-02 14:03:17 +00:00
proto_item * temp ;
2012-06-05 15:05:17 +00:00
if ( rlcinf ) {
2012-07-27 08:10:31 +00:00
rlcinf - > rbid [ fpinf - > cur_tb ] = tvb_get_bits8 ( tvb , bitoffs , 4 ) + 1 ;
2012-06-05 15:05:17 +00:00
}
2012-03-06 17:11:01 +00:00
proto_tree_add_bits_item ( tree , hf_mac_ct , tvb , bitoffs , 4 , ENC_BIG_ENDIAN ) ;
bitoffs + = 4 ;
2012-08-08 17:24:14 +00:00
if ( rlcinf ) {
2012-08-04 19:06:16 +00:00
temp = proto_tree_add_uint ( tree , hf_mac_lch_id , tvb , 0 , 0 , rlcinf - > rbid [ fpinf - > cur_tb ] ) ;
PROTO_ITEM_SET_GENERATED ( temp ) ;
}
2012-03-06 17:11:01 +00:00
}
return bitoffs ;
2009-10-09 06:37:48 +00:00
}
static void dissect_mac_fdd_pch ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree )
{
2012-03-06 17:11:01 +00:00
proto_tree * pch_tree = NULL ;
proto_item * channel_type ;
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , " MAC " ) ;
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 , ENC_NA ) ;
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 ) ;
2009-10-09 06:37:48 +00:00
}
static void dissect_mac_fdd_rach ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree )
{
2012-03-06 17:11:01 +00:00
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 ;
2012-06-05 15:05:17 +00:00
rlc_info * rlcinf ;
2012-03-06 17:11:01 +00:00
proto_item * ti = NULL ;
2012-07-26 08:15:20 +00:00
guint8 c_t ;
2012-03-06 17:11:01 +00:00
/* RACH TCTF is always 2 bit */
tctf = tvb_get_bits8 ( tvb , 0 , 2 ) ;
bitoffs + = 2 ;
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , " MAC " ) ;
col_add_str ( pinfo - > cinfo , COL_INFO ,
2012-08-10 22:55:02 +00:00
val_to_str_const ( tctf , rach_fdd_tctf_vals , " Unknown TCTF " ) ) ;
2012-03-06 17:11:01 +00:00
ti = proto_tree_add_item ( tree , proto_umts_mac , tvb , 0 , - 1 , ENC_NA ) ;
rach_tree = proto_item_add_subtree ( ti , ett_mac_rach ) ;
2013-05-12 18:11:02 +00:00
macinf = ( umts_mac_info * ) p_get_proto_data ( pinfo - > fd , proto_umts_mac , 0 ) ;
fpinf = ( fp_info * ) p_get_proto_data ( pinfo - > fd , proto_fp , 0 ) ;
rlcinf = ( rlc_info * ) p_get_proto_data ( pinfo - > fd , proto_rlc , 0 ) ;
2012-03-06 17:11:01 +00:00
if ( ! macinf | | ! fpinf ) {
proto_tree_add_text ( rach_tree , tvb , 0 , - 1 ,
" Cannot dissect MAC frame because per-frame info is missing " ) ;
2012-07-16 14:06:36 +00:00
expert_add_info_format ( pinfo , ti , PI_MALFORMED , PI_ERROR , " Cannot dissect MAC frame because per-frame info is missing " ) ;
2012-03-06 17:11:01 +00:00
return ;
}
proto_tree_add_bits_item ( rach_tree , hf_mac_rach_fdd_tctf , tvb , 0 , 2 , ENC_BIG_ENDIAN ) ;
if ( tctf = = TCTF_DCCH_DTCH_RACH_FDD ) {
macinf - > ctmux [ fpinf - > cur_tb ] = 1 ; /* DCCH/DTCH on RACH *always* has a C/T */
2012-05-28 20:11:59 +00:00
bitoffs = tree_add_common_dcch_dtch_fields ( tvb , pinfo , rach_tree , bitoffs , fpinf , macinf , rlcinf ) ;
2012-03-06 17:11:01 +00:00
}
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 :
2012-07-26 08:15:20 +00:00
/*Set RLC Mode/MAC content based on the L-CHID derived from the C/T flag*/
c_t = tvb_get_bits8 ( tvb , bitoffs - 4 , 4 ) ;
2012-07-27 08:10:31 +00:00
rlcinf - > mode [ chan ] = lchId_rlc_map [ c_t + 1 ] ;
2012-07-26 08:15:20 +00:00
macinf - > content [ chan ] = lchId_type_table [ c_t + 1 ] ;
2012-07-27 08:10:31 +00:00
rlcinf - > rbid [ chan ] = c_t + 1 ;
2012-03-06 17:11:01 +00:00
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) " ) ;
2012-07-16 14:06:36 +00:00
expert_add_info_format ( pinfo , NULL , PI_MALFORMED , PI_ERROR , " Unknown RACH DCCH/DTCH Content " ) ;
2012-03-06 17:11:01 +00:00
}
break ;
default :
proto_item_append_text ( ti , " (Unknown RACH TCTF) " ) ;
2012-07-16 14:06:36 +00:00
expert_add_info_format ( pinfo , NULL , PI_MALFORMED , PI_ERROR , " Unknown RACH TCTF " ) ;
2012-03-06 17:11:01 +00:00
}
2009-10-09 06:37:48 +00:00
}
static void dissect_mac_fdd_fach ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree )
{
2012-07-16 14:06:36 +00:00
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 ;
rlc_info * rlcinf ;
2012-07-16 13:11:20 +00:00
struct rrc_info * rrcinf ;
2012-07-16 14:06:36 +00:00
proto_item * ti = NULL ;
2012-07-17 19:22:55 +00:00
gint c_t ;
2012-03-06 17:11:01 +00:00
hdr = tvb_get_guint8 ( tvb , 0 ) ;
/* get target channel type field */
tctf = fach_fdd_tctf ( hdr , & bitoffs ) ;
tctf_len = bitoffs ;
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , " MAC " ) ;
col_add_str ( pinfo - > cinfo , COL_INFO ,
2012-08-10 22:55:02 +00:00
val_to_str_const ( tctf , fach_fdd_tctf_vals , " Unknown TCTF " ) ) ;
2012-03-06 17:11:01 +00:00
ti = proto_tree_add_item ( tree , proto_umts_mac , tvb , 0 , - 1 , ENC_NA ) ;
fach_tree = proto_item_add_subtree ( ti , ett_mac_fach ) ;
2013-05-12 18:11:02 +00:00
macinf = ( umts_mac_info * ) p_get_proto_data ( pinfo - > fd , proto_umts_mac , 0 ) ;
fpinf = ( fp_info * ) p_get_proto_data ( pinfo - > fd , proto_fp , 0 ) ;
rlcinf = ( rlc_info * ) p_get_proto_data ( pinfo - > fd , proto_rlc , 0 ) ;
2012-07-17 19:22:55 +00:00
2012-03-06 17:11:01 +00:00
if ( ! macinf | | ! fpinf ) {
proto_tree_add_text ( fach_tree , tvb , 0 , - 1 ,
" Cannot dissect MAC frame because per-frame info is missing " ) ;
2012-07-16 14:06:36 +00:00
expert_add_info_format ( pinfo , ti , PI_MALFORMED , PI_ERROR , " Cannot dissect MAC frame because per-frame info is missing " ) ;
2012-03-06 17:11:01 +00:00
return ;
}
proto_tree_add_bits_item ( fach_tree , hf_mac_fach_fdd_tctf , tvb , 0 , tctf_len , ENC_BIG_ENDIAN ) ;
if ( tctf = = TCTF_DCCH_DTCH_FACH_FDD ) {
macinf - > ctmux [ fpinf - > cur_tb ] = 1 ; /* DCCH/DTCH on FACH *always* has a C/T */
2012-05-28 20:11:59 +00:00
bitoffs = tree_add_common_dcch_dtch_fields ( tvb , pinfo , fach_tree , bitoffs , fpinf , macinf , rlcinf ) ;
2012-03-06 17:11:01 +00:00
}
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 */
2013-02-19 23:17:07 +00:00
next_tvb = tvb_new_subset_remaining ( tvb , 1 ) ;
2012-03-06 17:11:01 +00:00
call_dissector ( rlc_ccch_handle , next_tvb , pinfo , tree ) ;
break ;
2012-07-16 14:06:36 +00:00
case TCTF_DCCH_DTCH_FACH_FDD :
2012-07-17 19:22:55 +00:00
/*Set RLC Mode based on the L-CHID derived from the C/T flag*/
c_t = tvb_get_bits8 ( tvb , bitoffs - 4 , 4 ) ;
rlcinf - > mode [ fpinf - > cur_tb ] = lchId_rlc_map [ c_t + 1 ] ;
2012-07-26 08:15:20 +00:00
macinf - > content [ fpinf - > cur_tb ] = lchId_type_table [ c_t + 1 ] ;
2012-07-17 19:22:55 +00:00
switch ( macinf - > content [ fpinf - > cur_tb ] ) {
2012-07-16 14:06:36 +00:00
case MAC_CONTENT_DCCH :
2012-03-06 17:11:01 +00:00
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 :
2012-07-17 19:22:55 +00:00
proto_item_append_text ( ti , " (PS DTCH) " ) ;
2012-03-06 17:11:01 +00:00
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) " ) ;
2012-07-16 14:06:36 +00:00
expert_add_info_format ( pinfo , NULL , PI_DEBUG , PI_ERROR , " CS DTCH Is not implemented " ) ;
2012-03-06 17:11:01 +00:00
/* TODO */
break ;
default :
proto_item_append_text ( ti , " (Unknown FACH Content " ) ;
2012-07-16 14:06:36 +00:00
expert_add_info_format ( pinfo , NULL , PI_MALFORMED , PI_ERROR , " Unknown FACH Content for this transportblock " ) ;
2012-03-06 17:11:01 +00:00
}
break ;
2011-04-16 12:22:16 +00:00
case TCTF_CTCH_FACH_FDD :
proto_item_append_text ( ti , " (CTCH) " ) ;
channel_type = proto_tree_add_uint ( fach_tree , hf_mac_channel , tvb , 0 , 0 , MAC_CTCH ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
/* CTCH over FACH is always octet aligned */
2013-02-19 23:17:07 +00:00
next_tvb = tvb_new_subset_remaining ( tvb , 1 ) ;
2011-04-16 12:22:16 +00:00
call_dissector ( rlc_ctch_handle , next_tvb , pinfo , tree ) ;
break ;
2012-07-16 14:06:36 +00:00
/* july 5: Added support for BCCH*/
case TCTF_BCCH_FACH_FDD :
proto_item_append_text ( ti , " (BCCH) " ) ;
channel_type = proto_tree_add_uint ( fach_tree , hf_mac_channel , tvb , 0 , 0 , MAC_BCCH ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
2012-07-17 19:22:55 +00:00
/*We need to skip the first two bits (the TCTF bits), and since there is no MAC header, send rest to RRC*/
2012-07-16 14:06:36 +00:00
next_tvb = tvb_new_octet_aligned ( tvb , 2 , ( tvb_length ( tvb ) * 8 ) - 2 ) ;
2012-07-17 19:22:55 +00:00
add_new_data_source ( pinfo , next_tvb , " Octet-Aligned BCCH Data " ) ;
/* In this case skip RLC and call RRC immediately subdissector */
2013-05-12 18:11:02 +00:00
rrcinf = ( rrc_info * ) p_get_proto_data ( pinfo - > fd , proto_rrc , 0 ) ;
2012-07-17 19:22:55 +00:00
if ( ! rrcinf ) {
2013-03-17 22:16:39 +00:00
rrcinf = se_new0 ( struct rrc_info ) ;
2013-05-12 18:11:02 +00:00
p_add_proto_data ( pinfo - > fd , proto_rrc , 0 , rrcinf ) ;
2012-07-17 19:22:55 +00:00
}
rrcinf - > msgtype [ fpinf - > cur_tb ] = RRC_MESSAGE_TYPE_BCCH_FACH ;
2012-07-30 08:37:00 +00:00
2012-07-17 19:22:55 +00:00
call_dissector ( rrc_handle , next_tvb , pinfo , tree ) ;
break ;
case TCTF_MSCH_FACH_FDD :
case TCTF_MCCH_FACH_FDD :
case TCTF_MTCH_FACH_FDD :
expert_add_info_format ( pinfo , NULL , PI_DEBUG , PI_ERROR , " Unimplemented FACH Content type! " ) ;
break ;
2012-07-16 14:06:36 +00:00
default :
proto_item_append_text ( ti , " (Unknown FACH Content) " ) ;
expert_add_info_format ( pinfo , NULL , PI_MALFORMED , PI_ERROR , " Unknown FACH Content " ) ;
2012-07-17 19:22:55 +00:00
break ;
2012-07-16 14:06:36 +00:00
}
2009-10-09 06:37:48 +00:00
}
static void dissect_mac_fdd_dch ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree )
{
2012-03-06 17:11:01 +00:00
guint16 pos ;
guint8 bitoffs = 0 ;
umts_mac_info * macinf ;
fp_info * fpinf ;
2012-06-05 15:05:17 +00:00
rlc_info * rlcinf ;
2012-03-06 17:11:01 +00:00
proto_tree * dch_tree = NULL ;
proto_item * channel_type ;
tvbuff_t * next_tvb ;
proto_item * ti = NULL ;
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , " MAC " ) ;
ti = proto_tree_add_item ( tree , proto_umts_mac , tvb , 0 , - 1 , ENC_NA ) ;
dch_tree = proto_item_add_subtree ( ti , ett_mac_dch ) ;
2013-05-12 18:11:02 +00:00
macinf = ( umts_mac_info * ) p_get_proto_data ( pinfo - > fd , proto_umts_mac , 0 ) ;
fpinf = ( fp_info * ) p_get_proto_data ( pinfo - > fd , proto_fp , 0 ) ;
rlcinf = ( rlc_info * ) p_get_proto_data ( pinfo - > fd , proto_rlc , 0 ) ;
2012-03-06 17:11:01 +00:00
if ( ! macinf | | ! fpinf ) {
2012-07-17 19:22:55 +00:00
if ( ! macinf ) {
g_warning ( " MACinf == NULL " ) ;
}
if ( ! fpinf ) {
g_warning ( " fpinf == NULL " ) ;
}
2012-07-16 14:06:36 +00:00
ti = proto_tree_add_text ( dch_tree , tvb , 0 , - 1 ,
2012-03-06 17:11:01 +00:00
" Cannot dissect MAC frame because per-frame info is missing " ) ;
2012-07-16 14:06:36 +00:00
expert_add_info_format ( pinfo , ti , PI_DEBUG , PI_ERROR , " MAC frame missing frame information! " ) ;
2012-03-06 17:11:01 +00:00
return ;
}
pos = fpinf - > cur_tb ;
2012-07-16 14:06:36 +00:00
2012-03-06 17:11:01 +00:00
if ( macinf - > ctmux [ pos ] ) {
2012-06-05 15:05:17 +00:00
if ( rlcinf ) {
2012-07-26 08:15:20 +00:00
rlcinf - > rbid [ fpinf - > cur_tb ] = tvb_get_bits8 ( tvb , bitoffs , 4 ) + 1 ;
2012-06-05 15:05:17 +00:00
}
2012-07-16 14:06:36 +00:00
/*Add CT flag to GUI*/
2012-03-06 17:11:01 +00:00
proto_tree_add_bits_item ( dch_tree , hf_mac_ct , tvb , 0 , 4 , ENC_BIG_ENDIAN ) ;
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) " ) ;
2012-07-17 19:22:55 +00:00
2012-07-16 14:06:36 +00:00
/*Show logical channel id*/
if ( macinf - > lchid [ pos ] ! = 255 ) {
2012-07-17 19:22:55 +00:00
channel_type = proto_tree_add_uint ( dch_tree , hf_mac_lch_id , tvb , 0 , 0 , macinf - > lchid [ pos ] ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
if ( macinf - > fake_chid [ pos ] ) {
channel_type = proto_tree_add_text ( dch_tree , tvb , 0 , 0 , " This is a faked logical channel id! " ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
}
} else {
channel_type = proto_tree_add_text ( dch_tree , tvb , 0 , 0 , " Frame is missing logical channel " ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
}
2012-03-06 17:11:01 +00:00
channel_type = proto_tree_add_uint ( dch_tree , hf_mac_channel , tvb , 0 , 0 , MAC_DCCH ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
2012-07-17 19:22:55 +00:00
/*Transport channel printout*/
channel_type = proto_tree_add_uint ( dch_tree , hf_mac_trch_id , tvb , 0 , 0 , macinf - > trchid [ pos ] ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
2012-03-06 17:11:01 +00:00
call_dissector ( rlc_dcch_handle , next_tvb , pinfo , tree ) ;
break ;
case MAC_CONTENT_PS_DTCH :
proto_item_append_text ( ti , " (PS DTCH) " ) ;
2012-07-16 14:06:36 +00:00
/*Show logical channel id*/
if ( macinf - > lchid [ pos ] ! = 255 ) {
2012-07-17 19:22:55 +00:00
channel_type = proto_tree_add_uint ( dch_tree , hf_mac_lch_id , tvb , 0 , 0 , macinf - > lchid [ pos ] ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
} else {
channel_type = proto_tree_add_text ( dch_tree , tvb , 0 , 0 , " Frame is missing logical channel " ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
}
2012-03-06 17:11:01 +00:00
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) " ) ;
2012-07-17 19:22:55 +00:00
/*Show logical channel id*/
2012-07-16 14:06:36 +00:00
if ( macinf - > lchid [ pos ] ! = 255 ) {
2012-07-17 19:22:55 +00:00
channel_type = proto_tree_add_uint ( dch_tree , hf_mac_lch_id , tvb , 0 , 0 , macinf - > lchid [ pos ] ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
if ( macinf - > fake_chid [ pos ] ) {
channel_type = proto_tree_add_text ( dch_tree , tvb , 0 , 0 , " This is a faked logical channel id! " ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
}
} else {
channel_type = proto_tree_add_text ( dch_tree , tvb , 0 , 0 , " Frame is missing logical channel " ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
}
2012-07-16 14:06:36 +00:00
channel_type = proto_tree_add_uint ( dch_tree , hf_mac_channel , tvb , 0 , 0 , MAC_DTCH ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
2012-07-17 19:22:55 +00:00
/*Transport channel printout*/
channel_type = proto_tree_add_uint ( dch_tree , hf_mac_trch_id , tvb , 0 , 0 , macinf - > trchid [ pos ] ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
2012-03-06 17:11:01 +00:00
break ;
default :
proto_item_append_text ( ti , " (Unknown DCH Content) " ) ;
2012-07-16 14:06:36 +00:00
expert_add_info_format ( pinfo , NULL , PI_MALFORMED , PI_ERROR , " Unknown DCH Content " ) ;
2012-03-06 17:11:01 +00:00
}
2009-10-09 06:37:48 +00:00
}
2012-08-02 14:03:17 +00:00
static void init_frag ( tvbuff_t * tvb , body_parts * bp , guint length , guint offset , guint32 frame_num , guint16 tsn , guint8 type )
2012-07-24 07:31:46 +00:00
{
2012-08-02 14:03:17 +00:00
mac_is_fragment * frag = se_new ( mac_is_fragment ) ;
frag - > type = type ;
frag - > length = length ;
2013-03-17 22:16:39 +00:00
frag - > data = ( guint8 * ) g_malloc ( length ) ;
2012-08-02 14:03:17 +00:00
frag - > frame_num = frame_num ;
frag - > tsn = tsn ;
frag - > next = NULL ;
switch ( type ) {
case MAC_IS_HEAD :
DISSECTOR_ASSERT ( bp - > head = = NULL ) ;
bp - > head = frag ;
break ;
case MAC_IS_MIDDLE :
DISSECTOR_ASSERT ( bp - > middle = = NULL ) ;
bp - > middle = frag ;
break ;
case MAC_IS_TAIL :
DISSECTOR_ASSERT ( bp - > tail = = NULL ) ;
bp - > tail = frag ;
break ;
}
tvb_memcpy ( tvb , frag - > data , offset , length ) ;
2012-07-24 07:31:46 +00:00
}
2012-08-02 14:03:17 +00:00
static void mac_is_copy ( mac_is_sdu * sdu , mac_is_fragment * frag , guint total_length , gboolean reverse )
2012-07-24 07:31:46 +00:00
{
2012-08-02 14:03:17 +00:00
DISSECTOR_ASSERT ( sdu - > length + frag - > length < = total_length ) ;
if ( reverse ) {
memcpy ( sdu - > data + total_length - frag - > length - sdu - > length , frag - > data , frag - > length ) ;
} else {
memcpy ( sdu - > data + sdu - > length , frag - > data , frag - > length ) ;
}
sdu - > length + = frag - > length ;
2012-08-07 09:44:16 +00:00
g_free ( frag - > data ) ;
2012-08-02 14:03:17 +00:00
}
2012-07-24 07:31:46 +00:00
2012-08-02 14:03:17 +00:00
/*
* @ param length Length of whole SDU , it will be verified .
*/
static tvbuff_t * reassemble ( tvbuff_t * tvb , body_parts * * body_parts_array , guint16 head_tsn , guint length , mac_is_channel * ch , guint frame_num )
{
mac_is_sdu * sdu ;
mac_is_fragment * f ;
guint16 i ;
GHashTable * sdus ;
2012-07-30 08:37:00 +00:00
2012-08-02 14:03:17 +00:00
/* Find frag->sdu hash table for this channel. */
2013-03-17 22:16:39 +00:00
sdus = ( GHashTable * ) g_hash_table_lookup ( mac_is_sdus , ch ) ;
2012-08-02 14:03:17 +00:00
/* If this is the first time we see this channel. */
if ( sdus = = NULL ) {
mac_is_channel * channel ;
sdus = g_hash_table_new ( mac_is_fragment_hash , mac_is_fragment_equal ) ;
channel = se_new ( mac_is_channel ) ;
* channel = * ch ;
g_hash_table_insert ( mac_is_sdus , channel , sdus ) ;
2012-07-24 07:31:46 +00:00
}
2012-07-30 08:37:00 +00:00
2012-08-02 14:03:17 +00:00
sdu = se_new ( mac_is_sdu ) ;
sdu - > length = 0 ;
2013-03-17 22:16:39 +00:00
sdu - > data = ( guint8 * ) se_alloc ( length ) ;
2012-08-02 14:03:17 +00:00
f = body_parts_array [ head_tsn ] - > head ; /* Start from head. */
g_hash_table_insert ( sdus , f , sdu ) ; /* Insert head->sdu mapping. */
body_parts_array [ head_tsn ] - > head = NULL ; /* Reset head. */
mac_is_copy ( sdu , f , length , FALSE ) ; /* Copy head data into SDU. */
sdu - > fragments = f ; /* Set up fragments list to point at head. */
sdu - > frame_num = frame_num ; /* Frame number where reassembly is being done. */
2012-08-07 09:44:16 +00:00
for ( i = ( head_tsn + 1 ) % MAX_TSN ; body_parts_array [ i ] - > middle ! = NULL ; i = ( i + 1 ) % MAX_TSN )
2012-08-02 14:03:17 +00:00
{
f = f - > next = body_parts_array [ i ] - > middle ; /* Iterate through. */
g_hash_table_insert ( sdus , f , sdu ) ; /* Insert middle->sdu mapping. */
body_parts_array [ i ] - > middle = NULL ; /* Reset. */
mac_is_copy ( sdu , f , length , FALSE ) ; /* Copy middle data into SDU. */
2012-07-24 07:31:46 +00:00
}
2012-08-02 14:03:17 +00:00
DISSECTOR_ASSERT ( body_parts_array [ i ] - > tail ! = NULL ) ;
f - > next = body_parts_array [ i ] - > tail ;
g_hash_table_insert ( sdus , f - > next , sdu ) ; /* Insert tail->sdu mapping. */
body_parts_array [ i ] - > tail = NULL ; /* Reset tail. */
sdu - > tsn = i ; /* Use TSN of tail as key for the SDU. */
mac_is_copy ( sdu , f - > next , length , FALSE ) ; /* Copy tail data into SDU. */
return tvb_new_child_real_data ( tvb , sdu - > data , sdu - > length , sdu - > length ) ;
2012-07-24 07:31:46 +00:00
}
2012-08-02 14:03:17 +00:00
static mac_is_sdu * get_sdu ( guint frame_num , guint16 tsn , guint8 type , mac_is_channel * ch )
2012-07-24 07:31:46 +00:00
{
2012-08-02 14:03:17 +00:00
mac_is_sdu * sdu = NULL ;
GHashTable * sdus = NULL ;
mac_is_fragment frag_lookup_key ;
2013-03-17 22:16:39 +00:00
sdus = ( GHashTable * ) g_hash_table_lookup ( mac_is_sdus , ch ) ;
2012-08-02 14:03:17 +00:00
if ( sdus ) {
frag_lookup_key . frame_num = frame_num ;
frag_lookup_key . tsn = tsn ;
frag_lookup_key . type = type ;
2013-03-17 22:16:39 +00:00
sdu = ( mac_is_sdu * ) g_hash_table_lookup ( sdus , & frag_lookup_key ) ;
2012-07-30 08:37:00 +00:00
return sdu ;
2012-07-24 07:31:46 +00:00
}
return NULL ;
}
2012-08-02 14:03:17 +00:00
static tvbuff_t * add_to_tree ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , mac_is_sdu * sdu , guint offset , guint16 maclength , guint8 type )
2012-07-30 08:37:00 +00:00
{
tvbuff_t * new_tvb = NULL ;
2012-08-02 14:03:17 +00:00
if ( sdu - > frame_num = = pinfo - > fd - > num ) {
mac_is_fragment * f = sdu - > fragments ;
guint counter = 0 ;
new_tvb = tvb_new_child_real_data ( tvb , sdu - > data , sdu - > length , sdu - > length ) ;
add_new_data_source ( pinfo , new_tvb , " Reassembled MAC-is SDU " ) ;
2012-07-30 08:37:00 +00:00
proto_tree_add_text ( tree , new_tvb , 0 , - 1 , " [Reassembled MAC-is SDU] " ) ;
2012-08-02 14:03:17 +00:00
while ( f ) {
proto_tree_add_uint_format ( tree , hf_mac_is_fraglink , new_tvb ,
counter , f - > length , f - > frame_num ,
" Frame: %u, payload: %u-%u (%u bytes) (TSN: %u) " ,
f - > frame_num , counter , counter + f - > length - 1 , f - > length ,
f - > tsn ) ;
counter + = f - > length ;
f = f - > next ;
}
2012-07-30 08:37:00 +00:00
return new_tvb ;
} else {
new_tvb = tvb_new_subset ( tvb , offset , maclength , - 1 ) ;
2012-08-02 14:03:17 +00:00
switch ( type ) {
case MAC_IS_HEAD :
proto_tree_add_text ( tree , new_tvb , 0 , - 1 , " [This MAC-is SDU is the first segment of a MAC-d PDU or MAC-c PDU.] " ) ;
break ;
case MAC_IS_MIDDLE :
proto_tree_add_text ( tree , new_tvb , 0 , - 1 , " [This MAC-is SDU is a middle segment of a MAC-d PDU or MAC-c PDU.] " ) ;
break ;
case MAC_IS_TAIL :
proto_tree_add_text ( tree , new_tvb , 0 , - 1 , " [This MAC-is SDU is the last segment of a MAC-d PDU or MAC-c PDU.] " ) ;
break ;
}
proto_tree_add_uint ( tree , hf_mac_is_reasmin , new_tvb , 0 , 0 , sdu - > frame_num ) ;
2012-07-30 08:37:00 +00:00
return NULL ; /* No data here. */
}
}
2012-08-02 14:03:17 +00:00
/*
* If return value > 0 then tsn is changed to be tsn of head .
* @ return return length of sequence tsn - 1 to head .
*/
static guint find_head ( body_parts * * body_parts_array , guint16 * tsn )
2012-07-24 07:31:46 +00:00
{
2012-08-02 14:03:17 +00:00
guint length = 0 ;
2012-08-07 09:44:16 +00:00
* tsn = ( * tsn = = 0 ) ? ( guint16 ) ( MAX_TSN - 1 ) : ( * tsn ) - 1 ;
for ( ; body_parts_array [ * tsn ] - > middle ! = NULL ; * tsn = ( * tsn = = 0 ) ? ( guint16 ) ( MAX_TSN - 1 ) : ( * tsn ) - 1 )
2012-08-02 14:03:17 +00:00
length + = body_parts_array [ * tsn ] - > middle - > length ;
if ( body_parts_array [ * tsn ] - > head ! = NULL )
return length + body_parts_array [ * tsn ] - > head - > length ;
return 0 ;
}
/*
* @ return return length of sequence tsn + 1 to tail .
*/
static guint find_tail ( body_parts * * body_parts_array , guint16 tsn )
{
guint length = 0 ;
2012-08-07 09:44:16 +00:00
for ( tsn = ( tsn + 1 ) % MAX_TSN ; body_parts_array [ tsn ] - > middle ! = NULL ; tsn = ( tsn + 1 ) % MAX_TSN )
2012-08-02 14:03:17 +00:00
length + = body_parts_array [ tsn ] - > middle - > length ;
if ( body_parts_array [ tsn ] - > tail ! = NULL )
return length + body_parts_array [ tsn ] - > tail - > length ;
return 0 ;
}
/*
* @ param ch Channel for which body parts are to be fetched .
* @ return Array of body_part * for channel ' ch ' .
*/
static body_parts * * get_body_parts ( mac_is_channel * ch )
{
2013-03-17 22:16:39 +00:00
body_parts * * bpa = ( body_parts * * ) g_hash_table_lookup ( mac_is_fragments , ch ) ;
2012-08-02 14:03:17 +00:00
/* If there was no body_part* array for this channel, create one. */
if ( bpa = = NULL ) {
mac_is_channel * channel ;
2012-08-07 09:44:16 +00:00
guint16 i ;
bpa = se_alloc_array ( body_parts * , MAX_TSN ) ; /* Create new body_parts-pointer array */
for ( i = 0 ; i < MAX_TSN ; i + + ) {
2012-08-02 14:03:17 +00:00
bpa [ i ] = se_new0 ( body_parts ) ; /* Fill it with body_parts. */
}
channel = se_new ( mac_is_channel ) ; /* Alloc new channel for use in hash table. */
* channel = * ch ;
g_hash_table_insert ( mac_is_fragments , channel , bpa ) ;
2012-07-24 07:31:46 +00:00
}
2012-08-02 14:03:17 +00:00
return bpa ;
}
tvbuff_t * mac_is_add_fragment ( tvbuff_t * tvb _U_ , packet_info * pinfo , proto_tree * tree _U_ , guint8 lchid , guint ueid , int offset , guint8 ss , guint16 tsn , int sdu_no , guint8 no_sdus , guint16 maclength )
{
mac_is_channel ch ; /* Channel for looking up in hash tables. */
ch . lchid = lchid ;
ch . ueid = ueid ;
2012-07-24 07:31:46 +00:00
/* If in first scan-through. */
if ( pinfo - > fd - > flags . visited = = FALSE ) {
2012-08-02 14:03:17 +00:00
/* Get body parts array for this channel. */
body_parts * * body_parts_array = get_body_parts ( & ch ) ;
/* Middle segment */
if ( no_sdus = = 1 & & ss = = 3 ) {
guint head_length , tail_length ;
init_frag ( tvb , body_parts_array [ tsn ] , maclength , offset , pinfo - > fd - > num , tsn , MAC_IS_MIDDLE ) ;
tail_length = find_tail ( body_parts_array , tsn ) ;
if ( tail_length > 0 ) {
head_length = find_head ( body_parts_array , & tsn ) ;
if ( head_length > 0 ) {
/* tsn is now TSN of head */
return reassemble ( tvb , body_parts_array , tsn , tail_length + head_length + maclength , & ch , pinfo - > fd - > num ) ;
}
}
/* XXX: haven't confirmed if case when middle segment comes last
* actually works or not . */
}
2012-07-24 07:31:46 +00:00
/* If first SDU is last segment of previous. A tail. */
2012-08-02 14:03:17 +00:00
else if ( sdu_no = = 0 & & ( ss & 1 ) = = 1 ) {
guint length = maclength ;
init_frag ( tvb , body_parts_array [ tsn ] , maclength , offset , pinfo - > fd - > num , tsn , MAC_IS_TAIL ) ;
length + = find_head ( body_parts_array , & tsn ) ;
if ( length > maclength ) {
/* tsn is now TSN of head */
return reassemble ( tvb , body_parts_array , tsn , length , & ch , pinfo - > fd - > num ) ;
2012-07-24 07:31:46 +00:00
}
}
/* If last SDU is first segment of next. A head. */
else if ( sdu_no = = no_sdus - 1 & & ( ss & 2 ) = = 2 ) {
2012-08-02 14:03:17 +00:00
guint length = maclength ;
init_frag ( tvb , body_parts_array [ tsn ] , maclength , offset , pinfo - > fd - > num , tsn , MAC_IS_HEAD ) ;
length + = find_tail ( body_parts_array , tsn ) ;
if ( length > maclength ) {
return reassemble ( tvb , body_parts_array , tsn , length , & ch , pinfo - > fd - > num ) ;
2012-07-24 07:31:46 +00:00
}
/* If our SDU is not fragmented. */
} else {
DISSECTOR_ASSERT ( ( sdu_no = = 0 ) ? ( ss & 1 ) = = 0 : ( ( sdu_no = = no_sdus - 1 ) ? ( ss & 2 ) = = 0 : TRUE ) ) ;
return tvb_new_subset ( tvb , offset , maclength , - 1 ) ;
}
/* If clicking on a packet. */
2012-07-30 08:37:00 +00:00
} else if ( tree ) {
2012-08-02 14:03:17 +00:00
tvbuff_t * new_tvb = NULL ;
/* Middle segment */
if ( no_sdus = = 1 & & ss = = 3 ) {
mac_is_sdu * sdu = get_sdu ( pinfo - > fd - > num , tsn , MAC_IS_MIDDLE , & ch ) ;
if ( sdu ) {
return add_to_tree ( tvb , pinfo , tree , sdu , offset , maclength , MAC_IS_MIDDLE ) ;
}
}
2012-07-24 07:31:46 +00:00
/* If first SDU is last segment of previous. A tail. */
2012-08-02 14:03:17 +00:00
else if ( sdu_no = = 0 & & ( ss & 1 ) = = 1 ) {
mac_is_sdu * sdu = get_sdu ( pinfo - > fd - > num , tsn , MAC_IS_TAIL , & ch ) ;
if ( sdu ) {
return add_to_tree ( tvb , pinfo , tree , sdu , offset , maclength , MAC_IS_TAIL ) ;
}
}
2012-07-24 07:31:46 +00:00
/* If last SDU is first segment of next. A head. */
2012-08-02 14:03:17 +00:00
else if ( sdu_no = = no_sdus - 1 & & ( ss & 2 ) = = 2 ) {
mac_is_sdu * sdu = get_sdu ( pinfo - > fd - > num , tsn , MAC_IS_HEAD , & ch ) ;
if ( sdu ) {
return add_to_tree ( tvb , pinfo , tree , sdu , offset , maclength , MAC_IS_HEAD ) ;
2012-07-30 08:37:00 +00:00
}
2012-07-24 07:31:46 +00:00
} else {
2012-08-02 14:03:17 +00:00
new_tvb = tvb_new_subset ( tvb , offset , maclength , - 1 ) ;
2012-07-30 08:37:00 +00:00
proto_tree_add_text ( tree , new_tvb , 0 , - 1 , " [This MAC-is SDU is a complete MAC-d PDU or MAC-c PDU] " ) ;
proto_tree_add_item ( tree , hf_mac_edch_type2_sdu_data , new_tvb , 0 , - 1 , ENC_NA ) ;
return new_tvb ;
2012-07-24 07:31:46 +00:00
}
}
return NULL ;
}
2012-07-30 08:37:00 +00:00
static void ss_interpretation ( tvbuff_t * tvb , proto_tree * tree , guint8 ss , guint number_of_mac_is_sdus , guint offset )
{
switch ( ss ) {
case 0 :
if ( number_of_mac_is_sdus > 1 ) {
proto_tree_add_text ( tree , tvb , offset , 1 , " SS interpretation: The first MAC-is SDU of the MAC-is PDU is a complete MAC-d PDU or MAC-c PDU. The last MAC-is SDU of the MAC-is PDU is a complete MAC-d PDU or MAC-c PDU. " ) ;
} else {
proto_tree_add_text ( tree , tvb , offset , 1 , " SS interpretation: The MAC-is SDU of the MAC-is PDU is a complete MAC-d PDU or MAC-c PDU. " ) ;
}
break ;
case 1 :
if ( number_of_mac_is_sdus > 1 ) {
proto_tree_add_text ( tree , tvb , offset , 1 , " SS interpretation: The last MAC-is SDU of the MAC-is PDU is a complete MAC-d PDU or MAC-c PDU. The first MAC-is SDU of the MAC-is PDU is the last segment of a MAC-d PDU or MAC-c PDU. " ) ;
} else {
proto_tree_add_text ( tree , tvb , offset , 1 , " SS interpretation: The MAC-is SDU of the MAC-is PDU is the last segment of a MAC-d PDU or MAC-c PDU. " ) ;
}
break ;
case 2 :
if ( number_of_mac_is_sdus > 1 ) {
proto_tree_add_text ( tree , tvb , offset , 1 , " SS interpretation: The first MAC-is SDU of the MAC-is PDU is a complete MAC-d PDU or MAC-c PDU. The last MAC-is SDU of the MAC-is PDU is the first segment of a MAC-d PDU or MAC-c PDU. " ) ;
} else {
proto_tree_add_text ( tree , tvb , offset , 1 , " SS interpretation: The MAC-is SDU of the MAC-is PDU is the first segment of a MAC-d PDU or MAC-c PDU. " ) ;
}
break ;
case 3 :
if ( number_of_mac_is_sdus > 1 ) {
proto_tree_add_text ( tree , tvb , offset , 1 , " SS interpretation: The first MAC-is SDU of the MAC-is PDU is the last segment of a MAC-d PDU or MAC-c PDU and the last MAC-is SDU of MAC-is PDU is the first segment of a MAC-d PDU or MAC-c PDU. " ) ;
} else {
proto_tree_add_text ( tree , tvb , offset , 1 , " SS interpretation: The MAC-is SDU is a middle segment of a MAC-d PDU or MAC-c PDU. " ) ;
}
break ;
}
}
static void call_rlc ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , proto_item * ti , guint8 lchid )
{
switch ( lchId_type_table [ lchid ] ) {
case MAC_CONTENT_DCCH :
proto_item_append_text ( ti , " (DCCH) " ) ;
call_dissector ( rlc_dcch_handle , tvb , pinfo , tree ) ;
break ;
case MAC_CONTENT_PS_DTCH :
proto_item_append_text ( ti , " (PS DTCH) " ) ;
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) " ) ;
expert_add_info_format ( pinfo , ti , PI_MALFORMED , PI_ERROR , " Unknown EDCH Content " ) ;
break ;
}
}
/*
* Dissect a MAC - is PDU .
*/
static void dissect_mac_fdd_edch_type2 ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree )
{
guint sdu_no , subframe_bytes = 0 , offset = 0 ;
guint8 ss ;
guint16 tsn ;
2012-08-02 14:03:17 +00:00
proto_item * pi , * temp ;
2012-07-30 08:37:00 +00:00
proto_tree * macis_pdu_tree , * macis_sdu_tree ;
2013-05-12 18:11:02 +00:00
umts_mac_is_info * mac_is_info = ( umts_mac_is_info * ) p_get_proto_data ( pinfo - > fd , proto_umts_mac , 0 ) ;
rlc_info * rlcinf = ( rlc_info * ) p_get_proto_data ( pinfo - > fd , proto_rlc , 0 ) ;
struct fp_info * p_fp_info = ( struct fp_info * ) p_get_proto_data ( pinfo - > fd , proto_fp , 0 ) ;
2012-07-30 08:37:00 +00:00
2012-08-02 14:03:17 +00:00
DISSECTOR_ASSERT ( mac_is_info ! = NULL & & rlcinf ! = NULL & & p_fp_info ! = NULL ) ;
2012-07-30 08:37:00 +00:00
pi = proto_tree_add_item ( tree , proto_umts_mac , tvb , 0 , - 1 , ENC_NA ) ;
macis_pdu_tree = proto_item_add_subtree ( pi , ett_mac_edch_type2 ) ;
/* SS */
ss = ( tvb_get_guint8 ( tvb , offset ) & 0xc0 ) > > 6 ;
proto_tree_add_item ( macis_pdu_tree , hf_mac_edch_type2_ss , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
ss_interpretation ( tvb , macis_pdu_tree , ss , mac_is_info - > number_of_mac_is_sdus , offset ) ;
/* TSN */
2012-08-07 09:44:16 +00:00
tsn = tvb_get_bits8 ( tvb , offset * 8 + 2 , mac_tsn_size ) ;
proto_tree_add_bits_item ( macis_pdu_tree , hf_mac_edch_type2_tsn , tvb , offset * 8 + 2 , mac_tsn_size , ENC_BIG_ENDIAN ) ;
2012-07-30 08:37:00 +00:00
2012-08-07 09:44:16 +00:00
offset + = ( 2 + mac_tsn_size ) / 8 ;
2012-07-30 08:37:00 +00:00
/* MAC-is SDUs (i.e. MACd PDUs) */
for ( sdu_no = 0 ; sdu_no < mac_is_info - > number_of_mac_is_sdus ; sdu_no + + ) {
proto_item * ti ;
tvbuff_t * asm_tvb ;
guint8 lchid = mac_is_info - > lchid [ sdu_no ] + 1 ;
guint sdulength = mac_is_info - > sdulength [ sdu_no ] ;
ti = proto_tree_add_item ( tree , hf_mac_edch_type2_sdu , tvb , offset , sdulength , ENC_NA ) ;
macis_sdu_tree = proto_item_add_subtree ( ti , ett_mac_edch_type2_sdu ) ;
proto_item_append_text ( ti , " (Logical channel=%u, Len=%u) " , lchid , sdulength ) ;
2012-08-02 14:03:17 +00:00
temp = proto_tree_add_uint ( ti , hf_mac_lch_id , tvb , 0 , 0 , lchid ) ;
PROTO_ITEM_SET_GENERATED ( temp ) ;
2012-07-30 08:37:00 +00:00
/*Set up information needed for MAC and lower layers*/
rlcinf - > mode [ sdu_no ] = lchId_rlc_map [ lchid ] ; /* Set RLC mode by lchid to RLC_MODE map in nbap.h */
2012-08-02 14:03:17 +00:00
rlcinf - > urnti [ sdu_no ] = p_fp_info - > com_context_id ;
2012-07-30 08:37:00 +00:00
rlcinf - > rbid [ sdu_no ] = lchid ;
rlcinf - > li_size [ sdu_no ] = RLC_LI_7BITS ;
rlcinf - > ciphered [ sdu_no ] = FALSE ;
rlcinf - > deciphered [ sdu_no ] = FALSE ;
2012-08-02 14:03:17 +00:00
asm_tvb = mac_is_add_fragment ( tvb , pinfo , macis_sdu_tree , lchid , p_fp_info - > com_context_id , offset , ss , tsn , sdu_no , mac_is_info - > number_of_mac_is_sdus , sdulength ) ;
2012-07-30 08:37:00 +00:00
if ( asm_tvb ! = NULL ) {
call_rlc ( asm_tvb , pinfo , tree , ti , lchid ) ;
}
offset + = sdulength ;
subframe_bytes + = sdulength ;
}
proto_item_append_text ( pi , " -is PDU (SS=%u, TSN=%u, %u bytes in %u SDU fragments) " ,
ss , tsn , subframe_bytes , mac_is_info - > number_of_mac_is_sdus ) ;
proto_item_set_len ( pi , 1 + subframe_bytes ) ;
2012-07-30 09:19:07 +00:00
/*total_bytes += subframe_bytes;*/
2012-07-30 08:37:00 +00:00
}
2009-10-09 06:37:48 +00:00
static void dissect_mac_fdd_edch ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree )
{
2012-03-06 17:11:01 +00:00
proto_tree * edch_tree = NULL ;
proto_item * channel_type ;
umts_mac_info * macinf ;
fp_info * fpinf ;
guint16 pos ;
proto_item * ti = NULL ;
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , " MAC " ) ;
ti = proto_tree_add_item ( tree , proto_umts_mac , tvb , 0 , - 1 , ENC_NA ) ;
edch_tree = proto_item_add_subtree ( ti , ett_mac_edch ) ;
2013-05-12 18:11:02 +00:00
fpinf = ( fp_info * ) p_get_proto_data ( pinfo - > fd , proto_fp , 0 ) ;
2012-07-17 19:22:55 +00:00
2013-05-12 18:11:02 +00:00
macinf = ( umts_mac_info * ) p_get_proto_data ( pinfo - > fd , proto_umts_mac , 0 ) ;
2012-05-29 14:34:34 +00:00
if ( ! macinf | | ! fpinf ) {
2012-07-16 14:06:36 +00:00
ti = proto_tree_add_text ( edch_tree , tvb , 0 , - 1 ,
2012-03-06 17:11:01 +00:00
" Cannot dissect MAC frame because per-frame info is missing " ) ;
2012-07-16 14:06:36 +00:00
expert_add_info_format ( pinfo , ti , PI_DEBUG , PI_ERROR , " MAC frame missing frame information! " ) ;
2012-03-06 17:11:01 +00:00
return ;
}
2012-06-05 15:05:17 +00:00
pos = fpinf - > cur_tb ;
2012-03-06 17:11:01 +00:00
switch ( macinf - > content [ pos ] ) {
case MAC_CONTENT_DCCH :
proto_item_append_text ( ti , " (DCCH) " ) ;
2012-07-17 19:22:55 +00:00
2012-07-16 14:06:36 +00:00
/*Show the logical channel id*/
channel_type = proto_tree_add_uint ( edch_tree , hf_mac_lch_id , tvb , 0 , 0 , macinf - > lchid [ pos ] ) ;
2012-07-17 19:22:55 +00:00
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
2012-03-06 17:11:01 +00:00
channel_type = proto_tree_add_uint ( edch_tree , hf_mac_channel , tvb , 0 , 0 , MAC_DCCH ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
2012-07-17 19:22:55 +00:00
2012-03-06 17:11:01 +00:00
call_dissector ( rlc_dcch_handle , tvb , pinfo , tree ) ;
break ;
case MAC_CONTENT_PS_DTCH :
proto_item_append_text ( ti , " (PS DTCH) " ) ;
2012-07-16 14:06:36 +00:00
/*Show the logical channel id*/
channel_type = proto_tree_add_uint ( edch_tree , hf_mac_lch_id , tvb , 0 , 0 , macinf - > lchid [ pos ] ) ;
2012-07-17 19:22:55 +00:00
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
2012-03-06 17:11:01 +00:00
channel_type = proto_tree_add_uint ( edch_tree , hf_mac_channel , tvb , 0 , 0 , MAC_DTCH ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
2012-07-16 14:06:36 +00:00
2012-03-06 17:11:01 +00:00
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) " ) ;
2012-07-17 19:22:55 +00:00
expert_add_info_format ( pinfo , ti , PI_MALFORMED , PI_ERROR , " Unknown EDCH Content " ) ;
break ;
2012-03-06 17:11:01 +00:00
}
2009-10-09 06:37:48 +00:00
}
2012-07-26 08:15:20 +00:00
/**
* Dissect hsdsch_common channel .
*
* This will dissect hsdsch common channels , we handle this seperately
2012-07-30 08:37:00 +00:00
* since we might have to deal with MAC - ehs and or MAC - c headers
2012-07-26 08:15:20 +00:00
* ( in the MAC PDU ) .
*
* @ param tvb
* @ param pinfo
* @ param tree
* @ return Void .
*/
#if 0
static void dissect_mac_fdd_hsdsch_common ( 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=0;
tvbuff_t * next_tvb ;
*/
proto_item * ti = NULL ;
2012-07-30 08:37:00 +00:00
2012-07-26 08:15:20 +00:00
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , " MAC " ) ;
2012-07-30 08:37:00 +00:00
2012-07-26 08:15:20 +00:00
ti = proto_tree_add_item ( tree , proto_umts_mac , tvb , 0 , - 1 , ENC_NA ) ;
hsdsch_tree = proto_item_add_subtree ( ti , ett_mac_hsdsch ) ;
2009-10-09 06:37:48 +00:00
2013-05-16 21:00:36 +00:00
fpinf = ( fp_info * ) p_get_proto_data ( pinfo - > fd , proto_fp , 0 ) ;
2012-07-26 08:15:20 +00:00
macinf = ( umts_mac_info * ) p_get_proto_data ( pinfo - > fd , proto_umts_mac ) ;
2012-07-30 08:37:00 +00:00
2012-07-26 08:15:20 +00:00
if ( ! macinf ) {
proto_tree_add_text ( hsdsch_tree , tvb , 0 , - 1 ,
" Cannot dissect MAC frame because per-frame info is missing " ) ;
expert_add_info_format ( pinfo , ti , PI_MALFORMED , PI_ERROR , " Cannot dissect MAC frame because per-frame info is missing " ) ;
return ;
}
pos = fpinf - > cur_tb ;
switch ( macinf - > content [ pos ] ) {
/*In this case we don't have a MAC-c header 9.2.1.4*/
2012-07-30 08:37:00 +00:00
2012-07-26 08:15:20 +00:00
/*
case MAC_CONTENT_CCCH :
2012-07-30 08:37:00 +00:00
2012-07-26 08:15:20 +00:00
break ;
case MAC_CONTENT_PCCH :
2012-07-30 08:37:00 +00:00
2012-07-26 08:15:20 +00:00
break ;
2012-07-30 08:37:00 +00:00
2012-07-26 08:15:20 +00:00
case MAC_CONTENT_BCCH :
2012-07-30 08:37:00 +00:00
2012-07-26 08:15:20 +00:00
break ;
*/
default :
2012-07-30 08:37:00 +00:00
2012-07-26 08:15:20 +00:00
proto_item_append_text ( ti , " (Unknown HSDSCH-Common Content) " ) ;
expert_add_info_format ( pinfo , NULL , PI_MALFORMED , PI_ERROR , " Unknown HSDSCH-Common Content " ) ;
break ;
}
}
# endif
2012-07-16 14:06:36 +00:00
/* to avoid unnecessary re-alignment, the 4 bit padding prepended to the HSDSCH in FP type 1
2009-10-09 06:37:48 +00:00
* 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 )
{
2012-03-06 17:11:01 +00:00
proto_tree * hsdsch_tree = NULL ;
proto_item * channel_type ;
fp_info * fpinf ;
umts_mac_info * macinf ;
guint16 pos ;
2012-07-26 08:15:20 +00:00
guint8 bitoffs = 0 ;
2012-03-06 17:11:01 +00:00
tvbuff_t * next_tvb ;
proto_item * ti = NULL ;
2012-07-26 08:15:20 +00:00
rlc_info * rlcinf ;
2012-07-30 08:37:00 +00:00
2012-07-26 08:15:20 +00:00
/*struct rrc_info *rrcinf = NULL;
*/
2012-03-06 17:11:01 +00:00
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , " MAC " ) ;
ti = proto_tree_add_item ( tree , proto_umts_mac , tvb , 0 , - 1 , ENC_NA ) ;
hsdsch_tree = proto_item_add_subtree ( ti , ett_mac_hsdsch ) ;
2013-05-12 18:11:02 +00:00
fpinf = ( fp_info * ) p_get_proto_data ( pinfo - > fd , proto_fp , 0 ) ;
macinf = ( umts_mac_info * ) p_get_proto_data ( pinfo - > fd , proto_umts_mac , 0 ) ;
2012-07-30 08:37:00 +00:00
2012-03-06 17:11:01 +00:00
pos = fpinf - > cur_tb ;
2012-07-26 08:15:20 +00:00
bitoffs = fpinf - > hsdsch_entity = = ehs ? 0 : 4 ; /*No MAC-d header for type 2*/
2012-03-06 17:11:01 +00:00
if ( ! macinf ) {
proto_tree_add_text ( hsdsch_tree , tvb , 0 , - 1 ,
" Cannot dissect MAC frame because per-frame info is missing " ) ;
2012-07-16 14:06:36 +00:00
expert_add_info_format ( pinfo , ti , PI_MALFORMED , PI_ERROR , " Cannot dissect MAC frame because per-frame info is missing " ) ;
2012-03-06 17:11:01 +00:00
return ;
}
2012-07-26 08:15:20 +00:00
if ( macinf - > ctmux [ pos ] ) { /*The 4'st bits are padding*/
proto_tree_add_bits_item ( hsdsch_tree , hf_mac_ct , tvb , bitoffs , 4 , ENC_BIG_ENDIAN ) ;
2012-07-30 08:37:00 +00:00
2012-07-26 08:15:20 +00:00
/*Sets the proper lchid, for later layers.*/
macinf - > lchid [ pos ] = tvb_get_bits8 ( tvb , bitoffs , 4 ) + 1 ;
macinf - > fake_chid [ pos ] = FALSE ;
macinf - > content [ pos ] = lchId_type_table [ macinf - > lchid [ pos ] ] ; /*Lookup MAC content*/
2012-07-30 08:37:00 +00:00
2013-05-12 18:11:02 +00:00
rlcinf = ( rlc_info * ) p_get_proto_data ( pinfo - > fd , proto_rlc , 0 ) ;
2012-07-26 08:15:20 +00:00
rlcinf - > rbid [ pos ] = macinf - > lchid [ pos ] ;
rlcinf - > mode [ pos ] = lchId_rlc_map [ macinf - > lchid [ pos ] ] ; /*Look up RLC mode*/
2012-03-06 17:11:01 +00:00
bitoffs + = 4 ;
}
2012-08-07 09:44:16 +00:00
if ( ( bitoffs % 8 ) = = 0 ) {
2012-03-06 17:11:01 +00:00
next_tvb = tvb_new_subset_remaining ( tvb , bitoffs / 8 ) ;
} else {
2012-07-17 19:22:55 +00:00
next_tvb = tvb_new_octet_aligned ( tvb , bitoffs , macinf - > pdu_len ) ; /*Get rid of possible padding in at the end?*/
2012-03-06 17:11:01 +00:00
add_new_data_source ( pinfo , next_tvb , " Octet-Aligned HSDSCH Data " ) ;
}
2012-07-26 08:15:20 +00:00
2012-03-06 17:11:01 +00:00
switch ( macinf - > content [ pos ] ) {
2012-08-07 09:44:16 +00:00
case MAC_CONTENT_CCCH :
proto_item_append_text ( ti , " (CCCH) " ) ;
/*Set the logical channel id if it exists */
if ( macinf - > lchid [ pos ] ! = 255 ) {
channel_type = proto_tree_add_uint ( hsdsch_tree , hf_mac_lch_id , tvb , 0 , 0 , macinf - > lchid [ pos ] ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
if ( macinf - > fake_chid [ pos ] ) {
channel_type = proto_tree_add_text ( hsdsch_tree , tvb , 0 , 0 , " This is a faked logical channel id! " ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
}
} else {
channel_type = proto_tree_add_text ( hsdsch_tree , tvb , 0 , 0 , " Frame is missing logical channel " ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
}
/*Set the type of channel*/
channel_type = proto_tree_add_uint ( hsdsch_tree , hf_mac_channel , tvb , 0 , 0 , MAC_DCCH ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
/*Set the MACd-Flow ID*/
channel_type = proto_tree_add_uint ( hsdsch_tree , hf_mac_macdflowd_id , tvb , 0 , 0 , macinf - > macdflow_id [ pos ] ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
call_dissector ( rlc_ccch_handle , next_tvb , pinfo , tree ) ;
break ;
2012-03-06 17:11:01 +00:00
case MAC_CONTENT_DCCH :
proto_item_append_text ( ti , " (DCCH) " ) ;
2012-07-16 14:06:36 +00:00
/* channel_type = proto_tree_add_uint(hsdsch_tree, hf_mac_channel_hsdsch, tvb, 0, 0, MAC_DCCH);
PROTO_ITEM_SET_GENERATED ( channel_type ) */
/*Set the logical channel id if it exists */
if ( macinf - > lchid [ pos ] ! = 255 ) {
2012-07-17 19:22:55 +00:00
channel_type = proto_tree_add_uint ( hsdsch_tree , hf_mac_lch_id , tvb , 0 , 0 , macinf - > lchid [ pos ] ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
if ( macinf - > fake_chid [ pos ] ) {
channel_type = proto_tree_add_text ( hsdsch_tree , tvb , 0 , 0 , " This is a faked logical channel id! " ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
}
} else {
channel_type = proto_tree_add_text ( hsdsch_tree , tvb , 0 , 0 , " Frame is missing logical channel " ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
}
2012-07-16 14:06:36 +00:00
/*Set the type of channel*/
/*channel_type = proto_tree_add_text(hsdsch_tree, tvb,0, 0, "Logcial Channel Type: PS DTCH");
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
*/
2012-03-06 17:11:01 +00:00
channel_type = proto_tree_add_uint ( hsdsch_tree , hf_mac_channel , tvb , 0 , 0 , MAC_DCCH ) ;
2012-07-16 14:06:36 +00:00
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
2012-07-17 19:22:55 +00:00
2012-07-16 14:06:36 +00:00
/*Set the MACd-Flow ID*/
2012-07-17 19:22:55 +00:00
channel_type = proto_tree_add_uint ( hsdsch_tree , hf_mac_macdflowd_id , tvb , 0 , 0 , macinf - > macdflow_id [ pos ] ) ;
2012-03-06 17:11:01 +00:00
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) " ) ;
2012-07-17 19:22:55 +00:00
/*Set the logical channel id if it exists */
2012-07-16 14:06:36 +00:00
if ( macinf - > lchid [ pos ] ! = 255 ) {
2012-07-17 19:22:55 +00:00
channel_type = proto_tree_add_uint ( hsdsch_tree , hf_mac_lch_id , tvb , 0 , 0 , macinf - > lchid [ pos ] ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
if ( macinf - > fake_chid [ pos ] ) {
channel_type = proto_tree_add_text ( hsdsch_tree , tvb , 0 , 0 , " This is a faked logical channel id! " ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
}
} else {
channel_type = proto_tree_add_text ( hsdsch_tree , tvb , 0 , 0 , " Frame is missing logical channel " ) ;
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
}
2012-07-16 14:06:36 +00:00
/*Sets the channel type*/
2012-03-06 17:11:01 +00:00
channel_type = proto_tree_add_uint ( hsdsch_tree , hf_mac_channel , tvb , 0 , 0 , MAC_DTCH ) ;
2012-07-16 14:06:36 +00:00
2012-03-06 17:11:01 +00:00
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
2012-07-17 19:22:55 +00:00
2012-07-16 14:06:36 +00:00
/*Set the MACd-Flow ID*/
2012-07-17 19:22:55 +00:00
channel_type = proto_tree_add_uint ( hsdsch_tree , hf_mac_macdflowd_id , tvb , 0 , 0 , macinf - > macdflow_id [ pos ] ) ;
2012-07-16 14:06:36 +00:00
PROTO_ITEM_SET_GENERATED ( channel_type ) ;
2012-07-17 19:22:55 +00:00
2012-03-06 17:11:01 +00:00
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) " ) ;
2012-07-16 14:06:36 +00:00
expert_add_info_format ( pinfo , NULL , PI_MALFORMED , PI_ERROR , " Unknown HSDSCH Content " ) ;
2012-03-06 17:11:01 +00:00
}
2009-10-09 06:37:48 +00:00
}
2012-08-02 14:03:17 +00:00
static void mac_is_sdus_hash_destroy ( gpointer data )
{
g_hash_table_destroy ( ( GHashTable * ) data ) ;
}
2012-07-24 07:31:46 +00:00
static void mac_init ( void )
{
2012-07-30 08:37:00 +00:00
if ( mac_is_sdus ! = NULL ) {
g_hash_table_destroy ( mac_is_sdus ) ;
}
2012-07-24 07:31:46 +00:00
if ( mac_is_fragments ! = NULL ) {
g_hash_table_destroy ( mac_is_fragments ) ;
}
2012-08-02 14:03:17 +00:00
mac_is_sdus = g_hash_table_new_full ( mac_is_channel_hash , mac_is_channel_equal , NULL , mac_is_sdus_hash_destroy ) ;
mac_is_fragments = g_hash_table_new_full ( mac_is_channel_hash , mac_is_channel_equal , NULL , NULL ) ;
2012-08-07 09:44:16 +00:00
if ( global_mac_tsn_size = = MAC_TSN_6BITS ) {
MAX_TSN = 64 ;
mac_tsn_size = 6 ;
} else {
MAX_TSN = 16384 ;
mac_tsn_size = 14 ;
}
2012-07-24 07:31:46 +00:00
}
2009-10-09 06:37:48 +00:00
void
proto_register_umts_mac ( void )
{
2012-08-07 09:44:16 +00:00
module_t * mac_module ;
2012-03-06 17:11:01 +00:00
static gint * ett [ ] = {
& ett_mac ,
& ett_mac_fach ,
& ett_mac_rach ,
& ett_mac_dch ,
& ett_mac_pch ,
& ett_mac_edch ,
& ett_mac_hsdsch ,
2012-07-30 08:37:00 +00:00
& ett_mac_edch_type2 ,
& ett_mac_edch_type2_sdu
2012-03-06 17:11:01 +00:00
} ;
/** XX: Looks like some duplicate filter names ?? **/
/** XX: May be OK: See doc/README.developer **/
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 , NULL , HFILL }
} ,
{ & hf_mac_fach_fdd_tctf ,
{ " Target Channel Type Field " , " mac.tctf " ,
FT_UINT8 , BASE_HEX , VALS ( fach_fdd_tctf_vals ) , 0 , NULL , HFILL }
} ,
{ & hf_mac_ct ,
{ " C/T " , " mac.ct " ,
FT_UINT8 , BASE_HEX , NULL , 0 , NULL , HFILL }
} ,
{ & hf_mac_ueid_type ,
{ " UEID Type " , " mac.ueid_type " ,
FT_UINT8 , BASE_DEC , VALS ( ueid_type_vals ) , 0 , NULL , HFILL }
} ,
{ & hf_mac_crnti ,
{ " C-RNTI (UEID) " , " mac.ueid " ,
FT_UINT16 , BASE_HEX , NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_mac_urnti ,
{ " U-RNTI (UEID) " , " mac.ueid " ,
FT_UINT32 , BASE_HEX , NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_mac_channel ,
2012-07-16 14:06:36 +00:00
{ " Logical Channel Type " , " mac.logical_channel " ,
2012-03-06 17:11:01 +00:00
FT_UINT16 , BASE_DEC , VALS ( mac_logical_channel_vals ) , 0 , NULL , HFILL }
} ,
2012-07-17 19:22:55 +00:00
2013-01-31 18:31:28 +00:00
#if 0
2012-07-16 14:06:36 +00:00
{ & hf_mac_channel_str ,
{ " Logical Channel " , " mac.logical_channel " ,
FT_STRING , BASE_NONE , NULL , 0 , NULL , HFILL }
} ,
2013-01-31 18:31:28 +00:00
# endif
#if 0
2013-01-26 18:54:53 +00:00
{ & hf_mac_channel_hsdsch ,
2012-07-17 19:22:55 +00:00
{ " MACd-FlowID " , " mac.macd_flowid " , FT_UINT16 , BASE_DEC , NULL , 0x0 , NULL , HFILL }
2012-07-16 14:06:36 +00:00
} ,
2013-01-31 18:31:28 +00:00
# endif
2012-07-17 19:22:55 +00:00
{ & hf_mac_macdflowd_id ,
{ " MACd-FlowID " , " mac.macd_flowid " , FT_UINT16 , BASE_DEC , NULL , 0x0 , NULL , HFILL }
2012-07-16 14:06:36 +00:00
} ,
2012-07-17 19:22:55 +00:00
{ & hf_mac_lch_id ,
{ " Logical Channel ID " , " mac.logical_channel_id " , FT_UINT16 , BASE_DEC , NULL , 0x0 , NULL , HFILL }
2012-07-16 14:06:36 +00:00
} ,
2012-07-17 19:22:55 +00:00
{ & hf_mac_trch_id ,
{ " Transport Channel ID " , " mac.transport_channel_id " , FT_UINT16 , BASE_DEC , NULL , 0x0 , NULL , HFILL }
2012-07-16 14:06:36 +00:00
} ,
2013-01-31 18:31:28 +00:00
#if 0
2012-07-30 08:37:00 +00:00
{ & hf_mac_edch_type2_descriptors ,
{ " MAC-is Descriptors " ,
" mac.edch.type2.descriptors " , FT_STRING , BASE_NONE , NULL , 0x0 ,
NULL , HFILL
}
} ,
2013-01-31 18:31:28 +00:00
# endif
#if 0
2012-07-30 08:37:00 +00:00
{ & hf_mac_edch_type2_lchid ,
{ " LCH-ID " ,
" mac.logical_channel_id " , FT_UINT8 , BASE_HEX , NULL , 0xf0 ,
NULL , HFILL
}
} ,
2013-01-31 18:31:28 +00:00
# endif
#if 0
2012-07-30 08:37:00 +00:00
{ & hf_mac_edch_type2_length ,
{ " Length " ,
" mac.edch.type2.length " , FT_UINT16 , BASE_DEC , NULL , 0x0ffe ,
NULL , HFILL
}
} ,
2013-01-31 18:31:28 +00:00
# endif
#if 0
2012-07-30 08:37:00 +00:00
{ & hf_mac_edch_type2_flag ,
{ " Flag " ,
" mac.edch.type2.lchid " , FT_UINT8 , BASE_HEX , NULL , 0x01 ,
" Indicates if another entry follows " , HFILL
}
} ,
2013-01-31 18:31:28 +00:00
# endif
2012-07-30 08:37:00 +00:00
{ & hf_mac_edch_type2_ss ,
{ " SS " ,
/* TODO: VALS */
2012-08-02 14:03:17 +00:00
" mac.edch.type2.ss " , FT_UINT8 , BASE_HEX , NULL , 0xc0 ,
2012-07-30 08:37:00 +00:00
" Segmentation Status " , HFILL
}
} ,
{ & hf_mac_edch_type2_tsn ,
{ " TSN " ,
2012-08-07 09:44:16 +00:00
" mac.edch.type2.tsn " , FT_UINT16 , BASE_DEC , NULL , 0 ,
2012-07-30 08:37:00 +00:00
" Transmission Sequence Number " , HFILL
}
} ,
{ & hf_mac_edch_type2_sdu ,
{ " MAC-is SDU " ,
" mac.edch.type2.sdu " , FT_NONE , BASE_NONE , NULL , 0x0 ,
NULL , HFILL
}
} ,
{ & hf_mac_edch_type2_sdu_data ,
{ " Data " ,
" mac.edch.type2.sdu.data " , FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL
}
} ,
2013-01-31 18:31:28 +00:00
#if 0
2012-07-30 08:37:00 +00:00
{ & hf_mac_edch_type2_subframe_header ,
{ " Subframe header " ,
" mac.edch.type2.subframeheader " , FT_STRING , BASE_NONE , NULL , 0x0 ,
" EDCH Subframe header " , HFILL
}
} ,
2013-01-31 18:31:28 +00:00
# endif
2012-08-02 14:03:17 +00:00
{ & hf_mac_is_reasmin ,
{ " Reassembled in frame " , " mac.is.reasmin " ,
2012-07-30 08:37:00 +00:00
FT_FRAMENUM , BASE_NONE , NULL , 0 , NULL , HFILL }
} ,
2012-08-02 14:03:17 +00:00
{ & hf_mac_is_fraglink ,
{ " Frame " , " mac.is.fraglink " ,
2012-07-30 08:37:00 +00:00
FT_FRAMENUM , BASE_NONE , NULL , 0 , NULL , HFILL }
}
2012-03-06 17:11:01 +00:00
} ;
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 ) ;
2012-07-30 08:37:00 +00:00
register_dissector ( " mac.fdd.edch.type2 " , dissect_mac_fdd_edch_type2 , proto_umts_mac ) ;
2012-03-06 17:11:01 +00:00
register_dissector ( " mac.fdd.hsdsch " , dissect_mac_fdd_hsdsch , proto_umts_mac ) ;
2012-07-24 07:31:46 +00:00
register_init_routine ( mac_init ) ;
2012-08-07 09:44:16 +00:00
/* Preferences */
mac_module = prefs_register_protocol ( proto_umts_mac , NULL ) ;
prefs_register_enum_preference ( mac_module , " tsn_size " , " TSN size " ,
" TSN size in bits, either 6 or 14 bit " ,
& global_mac_tsn_size , tsn_size_enumvals , FALSE ) ;
2009-10-09 06:37:48 +00:00
}
void
proto_reg_handoff_umts_mac ( void )
{
2012-03-06 17:11:01 +00:00
rlc_pcch_handle = find_dissector ( " rlc.pcch " ) ;
rlc_ccch_handle = find_dissector ( " rlc.ccch " ) ;
rlc_ctch_handle = find_dissector ( " rlc.ctch " ) ;
rlc_dcch_handle = find_dissector ( " rlc.dcch " ) ;
rlc_ps_dtch_handle = find_dissector ( " rlc.ps_dtch " ) ;
2012-07-16 13:11:20 +00:00
rrc_handle = find_dissector ( " rrc " ) ;
2009-10-09 06:37:48 +00:00
}