1999-11-11 05:36:16 +00:00
/* packet-lapd.c
* Routines for LAPD frame disassembly
2001-11-13 23:55:44 +00:00
* Gilbert Ramirez < gram @ alumni . rice . edu >
1999-11-11 05:36:16 +00:00
*
2004-07-18 00:24:25 +00:00
* $ Id $
1999-11-11 05:36:16 +00:00
*
2006-05-21 04:49:01 +00:00
* Wireshark - Network traffic analyzer
* By Gerald Combs < gerald @ wireshark . org >
1999-11-11 05:36:16 +00:00
* Copyright 1998
2002-08-28 21:04:11 +00:00
*
1999-11-11 05:36:16 +00:00
* 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 .
2002-08-28 21:04:11 +00:00
*
1999-11-11 05:36:16 +00:00
* 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 .
2002-08-28 21:04:11 +00:00
*
1999-11-11 05:36:16 +00:00
* 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 .
1999-11-11 05:36:16 +00:00
*/
2008-05-26 20:52:38 +00:00
/*
* LAPD bitstream over RTP handling
* Copyright 2008 , Ericsson AB
* Written by Balint Reczey < balint . reczey @ ericsson . com >
*
* ISDN / LAPD references :
*
* http : //www.cisco.com/univercd/cc/td/doc/cisintwk/ito_doc/isdn.htm
* http : //www.ece.wpi.edu/courses/ee535/hwk11cd95/agrebe/agrebe.html
* http : //www.acacia-net.com/Clarinet/Protocol/q9213o84.htm
* http : //www.itu.int/rec/T-REC-Q.921/en
* Base Station Controller - Base Transceiver Station ( BSC - BTS ) interface ; Layer 2 specification
2010-09-23 21:46:31 +00:00
* http : //www.3gpp.org/ftp/Specs/html-info/48056.htm
2008-05-26 20:52:38 +00:00
*/
1999-11-11 05:36:16 +00:00
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
# include <glib.h>
# include <string.h>
2002-01-21 07:37:49 +00:00
# include <epan/packet.h>
2008-05-26 20:52:38 +00:00
# include <epan/conversation.h>
2004-09-28 23:48:02 +00:00
# include <epan/xdlc.h>
2011-08-31 09:00:54 +00:00
# include <epan/crc16-tvb.h>
2007-09-19 21:02:41 +00:00
# include <epan/prefs.h>
2005-09-17 00:02:31 +00:00
# include <epan/lapd_sapi.h>
2004-01-26 20:48:39 +00:00
1999-11-16 11:44:20 +00:00
static int proto_lapd = - 1 ;
2007-11-15 18:37:50 +00:00
static int hf_lapd_direction = - 1 ;
1999-11-16 11:44:20 +00:00
static int hf_lapd_address = - 1 ;
static int hf_lapd_sapi = - 1 ;
2007-09-19 21:02:41 +00:00
static int hf_lapd_gsm_sapi = - 1 ;
1999-11-16 11:44:20 +00:00
static int hf_lapd_cr = - 1 ;
static int hf_lapd_ea1 = - 1 ;
static int hf_lapd_tei = - 1 ;
static int hf_lapd_ea2 = - 1 ;
static int hf_lapd_control = - 1 ;
2004-01-03 03:51:27 +00:00
static int hf_lapd_n_r = - 1 ;
static int hf_lapd_n_s = - 1 ;
static int hf_lapd_p = - 1 ;
static int hf_lapd_p_ext = - 1 ;
static int hf_lapd_f = - 1 ;
static int hf_lapd_f_ext = - 1 ;
static int hf_lapd_s_ftype = - 1 ;
static int hf_lapd_u_modifier_cmd = - 1 ;
static int hf_lapd_u_modifier_resp = - 1 ;
static int hf_lapd_ftype_i = - 1 ;
static int hf_lapd_ftype_s_u = - 1 ;
static int hf_lapd_ftype_s_u_ext = - 1 ;
2008-05-26 20:52:38 +00:00
static int hf_lapd_checksum = - 1 ;
static int hf_lapd_checksum_good = - 1 ;
static int hf_lapd_checksum_bad = - 1 ;
1999-11-16 11:44:20 +00:00
static gint ett_lapd = - 1 ;
static gint ett_lapd_address = - 1 ;
static gint ett_lapd_control = - 1 ;
2008-05-26 20:52:38 +00:00
static gint ett_lapd_checksum = - 1 ;
static gint pref_lapd_rtp_payload_type = 0 ;
1999-11-11 05:36:16 +00:00
2004-01-26 20:48:39 +00:00
static dissector_table_t lapd_sapi_dissector_table ;
2007-09-19 21:02:41 +00:00
static dissector_table_t lapd_gsm_sapi_dissector_table ;
2009-04-08 13:41:30 +00:00
/* Whether to use GSM SAPI vals or not */
2007-09-19 21:02:41 +00:00
static gboolean global_lapd_gsm_sapis = FALSE ;
2004-01-26 20:48:39 +00:00
2001-11-25 22:51:14 +00:00
static dissector_handle_t data_handle ;
2001-05-27 07:27:21 +00:00
1999-11-11 08:35:11 +00:00
/*
* Bits in the address field .
*/
2007-09-19 21:02:41 +00:00
# define LAPD_SAPI 0xfc00 /* Service Access Point Identifier */
2009-01-13 05:39:46 +00:00
# define LAPD_SAPI_SHIFT 10
2007-09-19 21:02:41 +00:00
# define LAPD_CR 0x0200 /* Command/Response bit */
# define LAPD_EA1 0x0100 /* First Address Extension bit */
# define LAPD_TEI 0x00fe /* Terminal Endpoint Identifier */
2009-01-13 05:39:46 +00:00
# define LAPD_TEI_SHIFT 1
2007-09-19 21:02:41 +00:00
# define LAPD_EA2 0x0001 /* Second Address Extension bit */
1999-11-11 08:35:11 +00:00
2007-11-15 18:37:50 +00:00
static const value_string lapd_direction_vals [ ] = {
2009-01-13 05:39:46 +00:00
{ P2P_DIR_RECV , " Network->User " } ,
{ P2P_DIR_SENT , " User->Network " } ,
2007-11-15 18:37:50 +00:00
{ 0 , NULL }
} ;
1999-11-11 05:36:16 +00:00
static const value_string lapd_sapi_vals [ ] = {
2009-01-13 05:39:46 +00:00
{ LAPD_SAPI_Q931 , " Q.931 Call control procedure " } ,
1999-11-11 08:35:11 +00:00
{ LAPD_SAPI_PM_Q931 , " Packet mode Q.931 Call control procedure " } ,
2009-01-13 05:39:46 +00:00
{ LAPD_SAPI_X25 , " X.25 Level 3 procedures " } ,
{ LAPD_SAPI_L2 , " Layer 2 management procedures " } ,
1999-11-11 08:35:11 +00:00
{ 0 , NULL }
1999-11-11 05:36:16 +00:00
} ;
2007-09-19 21:02:41 +00:00
static const value_string lapd_gsm_sapi_vals [ ] = {
2009-01-13 05:39:46 +00:00
{ LAPD_GSM_SAPI_RA_SIG_PROC , " Radio signalling procedures " } ,
{ LAPD_GSM_SAPI_NOT_USED_1 , " (Not used in GSM PLMN) " } ,
{ LAPD_GSM_SAPI_NOT_USED_16 , " (Not used in GSM PLMN) " } ,
{ LAPD_GSM_SAPI_OM_PROC , " Operation and maintenance procedure " } ,
{ LAPD_SAPI_L2 , " Layer 2 management procedures " } ,
{ 0 , NULL }
2007-09-19 21:02:41 +00:00
} ;
2004-01-03 03:51:27 +00:00
/* Used only for U frames */
static const xdlc_cf_items lapd_cf_items = {
NULL ,
NULL ,
& hf_lapd_p ,
& hf_lapd_f ,
NULL ,
& hf_lapd_u_modifier_cmd ,
& hf_lapd_u_modifier_resp ,
NULL ,
& hf_lapd_ftype_s_u
} ;
/* Used only for I and S frames */
static const xdlc_cf_items lapd_cf_items_ext = {
& hf_lapd_n_r ,
& hf_lapd_n_s ,
& hf_lapd_p_ext ,
& hf_lapd_f_ext ,
& hf_lapd_s_ftype ,
NULL ,
NULL ,
& hf_lapd_ftype_i ,
& hf_lapd_ftype_s_u_ext
} ;
2008-05-26 20:52:38 +00:00
2010-09-23 21:46:31 +00:00
/* LAPD frame detection state */
2008-05-26 20:52:38 +00:00
enum lapd_bitstream_states { OUT_OF_SYNC , FLAGS , DATA } ;
typedef struct lapd_byte_state {
enum lapd_bitstream_states state ; /* frame detection state */
char full_byte ; /* part of a full byte */
char bit_offset ; /* number of bits already got in the full byte */
int ones ; /* number of consecutive ones since the last zero */
} lapd_byte_state_t ;
typedef struct lapd_ppi {
gboolean has_crc ; /* CRC is captured with LAPD the frames */
lapd_byte_state_t start_byte_state ; /* LAPD bitstream byte state at the beginnigng of processing the packet */
} lapd_ppi_t ;
/* Fill values in lapd_byte_state struct */
2009-03-29 22:16:26 +00:00
static void
fill_lapd_byte_state ( lapd_byte_state_t * ptr , enum lapd_bitstream_states state , char full_byte , char bit_offset , int ones )
2008-05-26 20:52:38 +00:00
{
ptr - > state = state ;
ptr - > full_byte = full_byte ;
ptr - > bit_offset = bit_offset ;
ptr - > ones = ones ;
}
typedef struct lapd_convo_data {
address addr_a ;
address addr_b ;
guint32 port_a ;
guint32 port_b ;
lapd_byte_state_t * byte_state_a ;
lapd_byte_state_t * byte_state_b ;
} lapd_convo_data_t ;
# define MAX_LAPD_PACKET_LEN 1024
static void
dissect_lapd ( tvbuff_t * , packet_info * , proto_tree * ) ;
/* got new LAPD frame byte */
static void new_byte ( char full_byte , char data [ ] , int * data_len ) {
if ( * data_len < MAX_LAPD_PACKET_LEN ) {
data [ * data_len ] = full_byte ;
( * data_len ) + + ;
} else {
/* XXX : we are not prepared for that big messages, drop the last byte */
}
}
static void
dissect_lapd_bitstream ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree )
{
guint8 byte , full_byte = 0x00 , bit_offset = 0 ;
gboolean bit ;
guint8 i , ones = 0 , data [ MAX_LAPD_PACKET_LEN ] ;
int data_len = 0 ;
2011-06-19 18:47:35 +00:00
guint offset = 0 , available ;
2008-05-26 20:52:38 +00:00
guint8 * buff ;
tvbuff_t * new_tvb ;
2010-09-23 21:46:31 +00:00
2008-05-26 20:52:38 +00:00
enum lapd_bitstream_states state = OUT_OF_SYNC ;
lapd_ppi_t * lapd_ppi ;
conversation_t * conversation = NULL ;
lapd_convo_data_t * convo_data = NULL ;
lapd_byte_state_t * lapd_byte_state , * prev_byte_state = NULL ;
gboolean forward_stream = TRUE ;
/* get remaining data from previous packets */
conversation = find_conversation ( pinfo - > fd - > num , & pinfo - > src , & pinfo - > dst ,
pinfo - > ptype , pinfo - > srcport , pinfo - > destport , 0 ) ;
lapd_ppi = ( lapd_ppi_t * ) p_get_proto_data ( pinfo - > fd , proto_lapd ) ;
if ( lapd_ppi ) {
prev_byte_state = & lapd_ppi - > start_byte_state ;
if ( prev_byte_state ) {
state = prev_byte_state - > state ;
full_byte = prev_byte_state - > full_byte ;
bit_offset = prev_byte_state - > bit_offset ;
ones = prev_byte_state - > ones ;
}
2010-09-23 21:46:31 +00:00
2008-05-26 20:52:38 +00:00
} else if ( conversation ) {
convo_data = ( lapd_convo_data_t * ) conversation_get_proto_data ( conversation , proto_lapd ) ;
if ( NULL ! = convo_data ) {
if ( ADDRESSES_EQUAL ( & convo_data - > addr_a , & pinfo - > src )
& & ADDRESSES_EQUAL ( & convo_data - > addr_b , & pinfo - > dst )
& & convo_data - > port_a = = pinfo - > srcport
& & convo_data - > port_b = = pinfo - > destport ) {
/* "forward" direction */
forward_stream = TRUE ;
prev_byte_state = convo_data - > byte_state_a ;
} else if ( ADDRESSES_EQUAL ( & convo_data - > addr_b , & pinfo - > src )
& & ADDRESSES_EQUAL ( & convo_data - > addr_a , & pinfo - > dst )
& & convo_data - > port_b = = pinfo - > srcport
& & convo_data - > port_a = = pinfo - > destport ) {
/* "backward" direction */
forward_stream = FALSE ;
prev_byte_state = convo_data - > byte_state_b ;
}
}
if ( prev_byte_state ) {
state = prev_byte_state - > state ;
full_byte = prev_byte_state - > full_byte ;
bit_offset = prev_byte_state - > bit_offset ;
ones = prev_byte_state - > ones ;
}
}
/* Consume tvb bytes */
available = tvb_length_remaining ( tvb , offset ) ;
while ( offset < available ) {
byte = tvb_get_guint8 ( tvb , offset ) ;
offset + + ;
for ( i = 0 ; i < 8 ; i + + ) { /* cycle through bits */
bit = byte & ( 0x80 > > i ) ? TRUE : FALSE ;
/* consume a bit */
if ( bit ) {
ones + + ;
full_byte | = ( 1 < < bit_offset + + ) ;
} else {
if ( ones = = 5 & & state = = DATA ) {
/* we don't increase bit_offset, it is an inserted zero */
} else if ( ones = = 6 & & state = = DATA ) { /* probably starting flag sequence */
buff = g_memdup ( data , data_len ) ;
/* Allocate new tvb for the LAPD frame */
2009-05-13 19:46:11 +00:00
new_tvb = tvb_new_child_real_data ( tvb , buff , data_len , data_len ) ;
2008-05-26 20:52:38 +00:00
tvb_set_free_cb ( new_tvb , g_free ) ;
add_new_data_source ( pinfo , new_tvb , " Decoded LAPD bitstream " ) ;
dissect_lapd ( new_tvb , pinfo , tree ) ;
data_len = 0 ;
state = FLAGS ;
bit_offset + + ;
} else if ( ones > = 7 ) { /* frame reset or 11111111 flag byte */
data_len = 0 ;
state = OUT_OF_SYNC ;
bit_offset + + ;
} else {
bit_offset + + ;
}
ones = 0 ;
}
if ( bit_offset = = 8 ) { /* we have a new complete byte */
switch ( state ) {
case OUT_OF_SYNC :
if ( full_byte = = 0x7E ) { /* we have a flag byte */
state = FLAGS ;
full_byte = 0x00 ;
bit_offset = 0 ;
} else { /* no sync yet, wait for a new byte */
full_byte = ( full_byte > > 1 ) & 0x7F ;
bit_offset - - ;
}
break ;
2010-09-23 21:46:31 +00:00
2008-05-26 20:52:38 +00:00
case FLAGS :
if ( full_byte = = 0x7E ) { /* we have a flag byte */
full_byte = 0x00 ;
bit_offset = 0 ;
} else { /* we got the first data byte */
state = DATA ;
new_byte ( full_byte , data , & data_len ) ;
full_byte = 0x00 ;
bit_offset = 0 ;
}
break ;
2010-09-23 21:46:31 +00:00
2008-05-26 20:52:38 +00:00
case DATA :
/* we got a new data byte */
new_byte ( full_byte , data , & data_len ) ;
full_byte = 0x00 ;
bit_offset = 0 ;
break ;
}
}
}
}
if ( state = = DATA ) { /* we are in the middle of an LAPD frame, we need more bytes */
pinfo - > desegment_offset = 0 ;
pinfo - > desegment_len = DESEGMENT_ONE_MORE_SEGMENT ;
return ;
} else { /* finished processing LAPD frame(s) */
if ( NULL = = p_get_proto_data ( pinfo - > fd , proto_lapd ) ) {
/* Per packet information */
lapd_ppi = g_malloc ( sizeof ( lapd_ppi_t ) ) ;
lapd_ppi - > has_crc = TRUE ;
if ( prev_byte_state )
fill_lapd_byte_state ( & lapd_ppi - > start_byte_state , prev_byte_state - > state ,
prev_byte_state - > full_byte , prev_byte_state - > bit_offset ,
prev_byte_state - > ones ) ;
2010-09-23 21:46:31 +00:00
else
2008-05-26 20:52:38 +00:00
fill_lapd_byte_state ( & lapd_ppi - > start_byte_state , OUT_OF_SYNC , 0x00 , 0 , 0 ) ;
p_add_proto_data ( pinfo - > fd , proto_lapd , lapd_ppi ) ;
2010-09-23 21:46:31 +00:00
2008-05-26 20:52:38 +00:00
/* Conversation info*/
2010-09-23 21:46:31 +00:00
2008-05-26 20:52:38 +00:00
if ( conversation ) {
if ( convo_data ) { /* already have lapd convo data */
if ( forward_stream )
fill_lapd_byte_state ( convo_data - > byte_state_a , state , full_byte , bit_offset , ones ) ;
else {
if ( ! convo_data - > byte_state_b )
convo_data - > byte_state_b = g_malloc ( sizeof ( lapd_byte_state_t ) ) ;
fill_lapd_byte_state ( convo_data - > byte_state_b , state , full_byte , bit_offset , ones ) ;
}
} else { /* lapd convo data has to be created */
lapd_byte_state = g_malloc ( sizeof ( lapd_byte_state_t ) ) ;
fill_lapd_byte_state ( lapd_byte_state , state , full_byte , bit_offset , ones ) ;
convo_data = g_malloc ( sizeof ( lapd_convo_data_t ) ) ;
COPY_ADDRESS ( & convo_data - > addr_a , & pinfo - > src ) ;
COPY_ADDRESS ( & convo_data - > addr_b , & pinfo - > dst ) ;
convo_data - > port_a = pinfo - > srcport ;
convo_data - > port_b = pinfo - > destport ;
convo_data - > byte_state_a = lapd_byte_state ;
convo_data - > byte_state_b = NULL ;
conversation_add_proto_data ( conversation , proto_lapd , convo_data ) ;
}
}
}
}
}
2000-11-29 05:16:15 +00:00
static void
2000-05-31 03:58:56 +00:00
dissect_lapd ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree )
1999-11-11 05:36:16 +00:00
{
2008-05-26 20:52:38 +00:00
proto_tree * lapd_tree , * addr_tree , * checksum_tree ;
proto_item * lapd_ti , * addr_ti , * checksum_ti ;
2009-01-13 05:39:46 +00:00
int direction ;
2008-05-26 20:52:38 +00:00
guint16 control , checksum , checksum_calculated ;
int lapd_header_len , checksum_offset ;
2010-01-18 23:16:10 +00:00
guint16 addr , cr , sapi , tei ;
2006-03-02 21:31:33 +00:00
gboolean is_response = 0 ;
2000-05-31 03:58:56 +00:00
tvbuff_t * next_tvb ;
2008-06-25 09:12:35 +00:00
const char * srcname = " ? " ;
const char * dstname = " ? " ;
1999-11-11 05:36:16 +00:00
2009-08-09 06:26:46 +00:00
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , " LAPD " ) ;
2009-08-09 07:36:13 +00:00
col_clear ( pinfo - > cinfo , COL_INFO ) ;
1999-11-11 05:36:16 +00:00
2010-01-18 23:16:10 +00:00
addr = tvb_get_ntohs ( tvb , 0 ) ;
cr = addr & LAPD_CR ;
tei = ( addr & LAPD_TEI ) > > LAPD_TEI_SHIFT ;
sapi = ( addr & LAPD_SAPI ) > > LAPD_SAPI_SHIFT ;
lapd_header_len = 2 ; /* addr */
1999-11-11 05:36:16 +00:00
2006-03-02 21:31:33 +00:00
if ( check_col ( pinfo - > cinfo , COL_TEI ) )
col_add_fstr ( pinfo - > cinfo , COL_TEI , " %u " , tei ) ;
if ( pinfo - > fd - > lnk_t = = WTAP_ENCAP_LINUX_LAPD ) {
/* frame is captured via libpcap */
if ( pinfo - > pseudo_header - > lapd . pkttype = = 4 /*PACKET_OUTGOING*/ ) {
if ( pinfo - > pseudo_header - > lapd . we_network ) {
is_response = cr ? FALSE : TRUE ;
srcname = " Local Network " ;
dstname = " Remote User " ;
2009-01-13 05:39:46 +00:00
direction = P2P_DIR_RECV ; /* Network->User */
2006-03-02 21:31:33 +00:00
} else {
srcname = " Local User " ;
dstname = " Remote Network " ;
2009-01-13 05:39:46 +00:00
direction = P2P_DIR_SENT ; /* User->Network */
2006-03-02 21:31:33 +00:00
}
}
else if ( pinfo - > pseudo_header - > lapd . pkttype = = 3 /*PACKET_OTHERHOST*/ ) {
2006-06-20 05:57:29 +00:00
/* We must be a TE, sniffing what other TE transmit */
2006-03-02 21:31:33 +00:00
is_response = cr ? TRUE : FALSE ;
srcname = " Remote User " ;
dstname = " Remote Network " ;
2009-01-13 05:39:46 +00:00
direction = P2P_DIR_SENT ; /* User->Network */
2006-03-02 21:31:33 +00:00
}
else {
2006-06-20 05:57:29 +00:00
/* The frame is incoming */
2006-03-02 21:31:33 +00:00
if ( pinfo - > pseudo_header - > lapd . we_network ) {
is_response = cr ? TRUE : FALSE ;
srcname = " Remote User " ;
dstname = " Local Network " ;
2009-01-13 05:39:46 +00:00
direction = P2P_DIR_SENT ; /* User->Network */
2006-03-02 21:31:33 +00:00
} else {
is_response = cr ? FALSE : TRUE ;
srcname = " Remote Network " ;
dstname = " Local User " ;
2009-01-13 05:39:46 +00:00
direction = P2P_DIR_RECV ; /* Network->User */
2006-03-02 21:31:33 +00:00
}
}
2009-01-13 05:39:46 +00:00
} else {
direction = pinfo - > p2p_dir ;
if ( pinfo - > p2p_dir = = P2P_DIR_RECV ) {
is_response = cr ? FALSE : TRUE ;
srcname = " Network " ;
dstname = " User " ;
}
else if ( pinfo - > p2p_dir = = P2P_DIR_SENT ) {
is_response = cr ? TRUE : FALSE ;
srcname = " User " ;
dstname = " Network " ;
}
1999-11-11 05:36:16 +00:00
}
2010-01-13 20:32:01 +00:00
col_set_str ( pinfo - > cinfo , COL_RES_DL_SRC , srcname ) ;
col_set_str ( pinfo - > cinfo , COL_RES_DL_DST , dstname ) ;
2006-03-02 21:31:33 +00:00
1999-11-11 05:36:16 +00:00
if ( tree ) {
2007-11-15 18:37:50 +00:00
proto_item * direction_ti ;
2002-02-22 08:54:54 +00:00
lapd_ti = proto_tree_add_item ( tree , proto_lapd , tvb , 0 , - 1 ,
2011-10-21 02:10:19 +00:00
ENC_NA ) ;
2002-02-22 08:54:54 +00:00
lapd_tree = proto_item_add_subtree ( lapd_ti , ett_lapd ) ;
1999-11-11 05:36:16 +00:00
2009-01-13 05:39:46 +00:00
/*
* Don ' t show the direction if we don ' t know it .
*/
if ( direction ! = P2P_DIR_UNKNOWN ) {
direction_ti = proto_tree_add_uint ( lapd_tree , hf_lapd_direction ,
tvb , 0 , 0 , pinfo - > p2p_dir ) ;
PROTO_ITEM_SET_GENERATED ( direction_ti ) ;
}
2007-11-15 18:37:50 +00:00
2002-02-22 08:54:54 +00:00
addr_ti = proto_tree_add_uint ( lapd_tree , hf_lapd_address , tvb ,
2010-01-18 23:16:10 +00:00
0 , 2 , addr ) ;
2002-02-22 08:54:54 +00:00
addr_tree = proto_item_add_subtree ( addr_ti , ett_lapd_address ) ;
1999-11-11 05:36:16 +00:00
2007-09-19 21:02:41 +00:00
if ( global_lapd_gsm_sapis ) {
2010-01-18 23:16:10 +00:00
proto_tree_add_uint ( addr_tree , hf_lapd_gsm_sapi , tvb , 0 , 1 , addr ) ;
2007-09-19 21:02:41 +00:00
} else {
2010-01-18 23:16:10 +00:00
proto_tree_add_uint ( addr_tree , hf_lapd_sapi , tvb , 0 , 1 , addr ) ;
2007-09-19 21:02:41 +00:00
}
2010-01-18 23:16:10 +00:00
proto_tree_add_uint ( addr_tree , hf_lapd_cr , tvb , 0 , 1 , addr ) ;
proto_tree_add_uint ( addr_tree , hf_lapd_ea1 , tvb , 0 , 1 , addr ) ;
proto_tree_add_uint ( addr_tree , hf_lapd_tei , tvb , 1 , 1 , addr ) ;
proto_tree_add_uint ( addr_tree , hf_lapd_ea2 , tvb , 1 , 1 , addr ) ;
1999-11-11 05:36:16 +00:00
}
else {
2002-02-22 08:54:54 +00:00
lapd_ti = NULL ;
1999-11-11 05:36:16 +00:00
lapd_tree = NULL ;
}
2000-05-31 03:58:56 +00:00
control = dissect_xdlc_control ( tvb , 2 , pinfo , lapd_tree , hf_lapd_control ,
2004-01-18 08:32:46 +00:00
ett_lapd_control , & lapd_cf_items , & lapd_cf_items_ext , NULL , NULL ,
is_response , TRUE , FALSE ) ;
1999-11-11 08:35:11 +00:00
lapd_header_len + = XDLC_CONTROL_LEN ( control , TRUE ) ;
2002-02-22 08:54:54 +00:00
if ( tree )
proto_item_set_len ( lapd_ti , lapd_header_len ) ;
2008-05-26 20:52:38 +00:00
if ( NULL ! = p_get_proto_data ( pinfo - > fd , proto_lapd )
& & ( ( lapd_ppi_t * ) p_get_proto_data ( pinfo - > fd , proto_lapd ) ) - > has_crc ) {
2010-09-23 21:46:31 +00:00
2008-05-26 20:52:38 +00:00
/* check checksum */
checksum_offset = tvb_length ( tvb ) - 2 ;
checksum = tvb_get_guint8 ( tvb , checksum_offset ) ; /* high byte */
checksum < < = 8 ;
checksum | = tvb_get_guint8 ( tvb , checksum_offset + 1 ) & 0x00FF ; /* low byte */
2012-01-12 20:40:23 +00:00
checksum_calculated = crc16_ccitt_tvb ( tvb , tvb_length ( tvb ) - 2 ) ;
checksum_calculated = g_htons ( checksum_calculated ) ; /* Note: g_htons() macro may eval arg multiple times */
2010-09-23 21:46:31 +00:00
2008-05-26 20:52:38 +00:00
if ( checksum = = checksum_calculated ) {
checksum_ti = proto_tree_add_uint_format ( lapd_tree , hf_lapd_checksum , tvb , checksum_offset , 2 , 0 , " Checksum: 0x%04x [correct] " , checksum ) ;
checksum_tree = proto_item_add_subtree ( checksum_ti , ett_lapd_checksum ) ;
proto_tree_add_boolean ( checksum_tree , hf_lapd_checksum_good , tvb , checksum_offset , 2 , TRUE ) ;
proto_tree_add_boolean ( checksum_tree , hf_lapd_checksum_bad , tvb , checksum_offset , 2 , FALSE ) ;
} else {
checksum_ti = proto_tree_add_uint_format ( lapd_tree , hf_lapd_checksum , tvb , checksum_offset , 2 , 0 , " Checksum: 0x%04x [incorrect, should be 0x%04x] " , checksum , checksum_calculated ) ;
checksum_tree = proto_item_add_subtree ( checksum_ti , ett_lapd_checksum ) ;
proto_tree_add_boolean ( checksum_tree , hf_lapd_checksum_good , tvb , checksum_offset , 2 , FALSE ) ;
proto_tree_add_boolean ( checksum_tree , hf_lapd_checksum_bad , tvb , checksum_offset , 2 , TRUE ) ;
}
2010-09-23 21:46:31 +00:00
2008-05-26 20:52:38 +00:00
next_tvb = tvb_new_subset ( tvb , lapd_header_len , tvb_length_remaining ( tvb , lapd_header_len ) - 2 , - 1 ) ;
2010-09-23 21:46:31 +00:00
} else
2009-08-16 12:36:22 +00:00
next_tvb = tvb_new_subset_remaining ( tvb , lapd_header_len ) ;
2008-05-26 20:52:38 +00:00
2000-01-24 02:05:39 +00:00
if ( XDLC_IS_INFORMATION ( control ) ) {
1999-11-11 08:35:11 +00:00
/* call next protocol */
2007-09-19 21:02:41 +00:00
if ( global_lapd_gsm_sapis ) {
2010-12-20 05:35:29 +00:00
if ( ! dissector_try_uint ( lapd_gsm_sapi_dissector_table , sapi ,
2007-09-19 21:02:41 +00:00
next_tvb , pinfo , tree ) )
call_dissector ( data_handle , next_tvb , pinfo , tree ) ;
} else {
2010-12-20 05:35:29 +00:00
if ( ! dissector_try_uint ( lapd_sapi_dissector_table , sapi ,
2007-09-19 21:02:41 +00:00
next_tvb , pinfo , tree ) )
call_dissector ( data_handle , next_tvb , pinfo , tree ) ;
}
2000-01-24 02:05:39 +00:00
} else
2001-11-25 22:51:14 +00:00
call_dissector ( data_handle , next_tvb , pinfo , tree ) ;
1999-11-11 05:36:16 +00:00
}
2007-09-19 21:02:41 +00:00
void
2009-03-29 22:16:26 +00:00
proto_reg_handoff_lapd ( void ) ;
2007-09-19 21:02:41 +00:00
1999-11-11 05:36:16 +00:00
void
proto_register_lapd ( void )
{
static hf_register_info hf [ ] = {
2007-11-15 18:37:50 +00:00
{ & hf_lapd_direction ,
{ " Direction " , " lapd.direction " , FT_UINT8 , BASE_DEC , VALS ( lapd_direction_vals ) , 0x0 ,
2009-03-29 22:16:26 +00:00
NULL , HFILL } } ,
2007-11-15 18:37:50 +00:00
1999-11-11 05:36:16 +00:00
{ & hf_lapd_address ,
2002-08-28 21:04:11 +00:00
{ " Address Field " , " lapd.address " , FT_UINT16 , BASE_HEX , NULL , 0x0 ,
2001-06-18 02:18:27 +00:00
" Address " , HFILL } } ,
1999-11-11 05:36:16 +00:00
{ & hf_lapd_sapi ,
1999-11-11 08:35:11 +00:00
{ " SAPI " , " lapd.sapi " , FT_UINT16 , BASE_DEC , VALS ( lapd_sapi_vals ) , LAPD_SAPI ,
2001-06-18 02:18:27 +00:00
" Service Access Point Identifier " , HFILL } } ,
1999-11-11 05:36:16 +00:00
2007-09-19 21:02:41 +00:00
{ & hf_lapd_gsm_sapi ,
{ " SAPI " , " lapd.sapi " , FT_UINT16 , BASE_DEC , VALS ( lapd_gsm_sapi_vals ) , LAPD_SAPI ,
" Service Access Point Identifier " , HFILL } } ,
1999-11-11 05:36:16 +00:00
{ & hf_lapd_cr ,
1999-11-11 08:35:11 +00:00
{ " C/R " , " lapd.cr " , FT_UINT16 , BASE_DEC , NULL , LAPD_CR ,
2001-06-18 02:18:27 +00:00
" Command/Response bit " , HFILL } } ,
1999-11-11 05:36:16 +00:00
{ & hf_lapd_ea1 ,
1999-11-11 08:35:11 +00:00
{ " EA1 " , " lapd.ea1 " , FT_UINT16 , BASE_DEC , NULL , LAPD_EA1 ,
2001-06-18 02:18:27 +00:00
" First Address Extension bit " , HFILL } } ,
1999-11-11 05:36:16 +00:00
{ & hf_lapd_tei ,
1999-11-11 08:35:11 +00:00
{ " TEI " , " lapd.tei " , FT_UINT16 , BASE_DEC , NULL , LAPD_TEI ,
2001-06-18 02:18:27 +00:00
" Terminal Endpoint Identifier " , HFILL } } ,
1999-11-11 05:36:16 +00:00
{ & hf_lapd_ea2 ,
1999-11-11 08:35:11 +00:00
{ " EA2 " , " lapd.ea2 " , FT_UINT16 , BASE_DEC , NULL , LAPD_EA2 ,
2001-06-18 02:18:27 +00:00
" Second Address Extension bit " , HFILL } } ,
1999-11-11 05:36:16 +00:00
{ & hf_lapd_control ,
{ " Control Field " , " lapd.control " , FT_UINT16 , BASE_HEX , NULL , 0x0 ,
2010-09-23 21:46:31 +00:00
NULL , HFILL } } ,
2004-01-03 03:51:27 +00:00
{ & hf_lapd_n_r ,
{ " N(R) " , " lapd.control.n_r " , FT_UINT16 , BASE_DEC ,
2009-03-29 22:16:26 +00:00
NULL , XDLC_N_R_EXT_MASK , NULL , HFILL } } ,
2004-01-03 03:51:27 +00:00
{ & hf_lapd_n_s ,
{ " N(S) " , " lapd.control.n_s " , FT_UINT16 , BASE_DEC ,
2009-03-29 22:16:26 +00:00
NULL , XDLC_N_S_EXT_MASK , NULL , HFILL } } ,
2004-01-03 03:51:27 +00:00
{ & hf_lapd_p ,
{ " Poll " , " lapd.control.p " , FT_BOOLEAN , 8 ,
2009-07-07 14:54:15 +00:00
TFS ( & tfs_set_notset ) , XDLC_P_F , NULL , HFILL } } ,
2004-01-03 03:51:27 +00:00
{ & hf_lapd_p_ext ,
{ " Poll " , " lapd.control.p " , FT_BOOLEAN , 16 ,
2009-07-07 14:54:15 +00:00
TFS ( & tfs_set_notset ) , XDLC_P_F_EXT , NULL , HFILL } } ,
2004-01-03 03:51:27 +00:00
{ & hf_lapd_f ,
{ " Final " , " lapd.control.f " , FT_BOOLEAN , 8 ,
2009-07-07 14:54:15 +00:00
TFS ( & tfs_set_notset ) , XDLC_P_F , NULL , HFILL } } ,
2004-01-03 03:51:27 +00:00
{ & hf_lapd_f_ext ,
{ " Final " , " lapd.control.f " , FT_BOOLEAN , 16 ,
2009-07-07 14:54:15 +00:00
TFS ( & tfs_set_notset ) , XDLC_P_F_EXT , NULL , HFILL } } ,
2004-01-03 03:51:27 +00:00
{ & hf_lapd_s_ftype ,
{ " Supervisory frame type " , " lapd.control.s_ftype " , FT_UINT16 , BASE_HEX ,
2009-03-29 22:16:26 +00:00
VALS ( stype_vals ) , XDLC_S_FTYPE_MASK , NULL , HFILL } } ,
2004-01-03 03:51:27 +00:00
{ & hf_lapd_u_modifier_cmd ,
{ " Command " , " lapd.control.u_modifier_cmd " , FT_UINT8 , BASE_HEX ,
2009-03-29 22:16:26 +00:00
VALS ( modifier_vals_cmd ) , XDLC_U_MODIFIER_MASK , NULL , HFILL } } ,
2004-01-03 03:51:27 +00:00
{ & hf_lapd_u_modifier_resp ,
{ " Response " , " lapd.control.u_modifier_resp " , FT_UINT8 , BASE_HEX ,
2009-03-29 22:16:26 +00:00
VALS ( modifier_vals_resp ) , XDLC_U_MODIFIER_MASK , NULL , HFILL } } ,
2004-01-03 03:51:27 +00:00
{ & hf_lapd_ftype_i ,
{ " Frame type " , " lapd.control.ftype " , FT_UINT16 , BASE_HEX ,
2009-03-29 22:16:26 +00:00
VALS ( ftype_vals ) , XDLC_I_MASK , NULL , HFILL } } ,
2004-01-03 03:51:27 +00:00
{ & hf_lapd_ftype_s_u ,
{ " Frame type " , " lapd.control.ftype " , FT_UINT8 , BASE_HEX ,
2009-03-29 22:16:26 +00:00
VALS ( ftype_vals ) , XDLC_S_U_MASK , NULL , HFILL } } ,
2004-01-03 03:51:27 +00:00
{ & hf_lapd_ftype_s_u_ext ,
{ " Frame type " , " lapd.control.ftype " , FT_UINT16 , BASE_HEX ,
2009-03-29 22:16:26 +00:00
VALS ( ftype_vals ) , XDLC_S_U_MASK , NULL , HFILL } } ,
2008-05-26 20:52:38 +00:00
{ & hf_lapd_checksum ,
2010-09-23 21:46:31 +00:00
{ " Checksum " , " lapd.checksum " , FT_UINT16 , BASE_HEX ,
2008-05-26 20:52:38 +00:00
NULL , 0x0 , " Details at: http://www.wireshark.org/docs/wsug_html_chunked/ChAdvChecksums.html " , HFILL } } ,
{ & hf_lapd_checksum_good ,
2010-09-23 21:46:31 +00:00
{ " Good Checksum " , " lapd.checksum_good " , FT_BOOLEAN , BASE_NONE ,
2008-05-26 20:52:38 +00:00
NULL , 0x0 , " True: checksum matches packet content; False: doesn't match content or not checked " , HFILL } } ,
{ & hf_lapd_checksum_bad ,
{ " Bad Checksum " , " lapd.checksum_bad " , FT_BOOLEAN , BASE_NONE ,
NULL , 0x0 , " True: checksum doesn't match packet content; False: matches content or not checked " , HFILL } }
1999-11-11 05:36:16 +00:00
} ;
2008-05-26 20:52:38 +00:00
1999-11-16 11:44:20 +00:00
static gint * ett [ ] = {
& ett_lapd ,
& ett_lapd_address ,
& ett_lapd_control ,
2008-05-26 20:52:38 +00:00
& ett_lapd_checksum
1999-11-16 11:44:20 +00:00
} ;
1999-11-11 05:36:16 +00:00
2007-09-19 21:02:41 +00:00
module_t * lapd_module ;
2008-09-30 14:46:48 +00:00
proto_lapd = proto_register_protocol ( " Link Access Procedure, Channel D (LAPD) " ,
2001-01-03 06:56:03 +00:00
" LAPD " , " lapd " ) ;
2008-09-30 14:46:48 +00:00
proto_register_field_array ( proto_lapd , hf , array_length ( hf ) ) ;
proto_register_subtree_array ( ett , array_length ( ett ) ) ;
2002-10-31 07:12:42 +00:00
2008-09-30 14:46:48 +00:00
register_dissector ( " lapd " , dissect_lapd , proto_lapd ) ;
2004-01-26 20:48:39 +00:00
2008-09-30 14:46:48 +00:00
lapd_sapi_dissector_table = register_dissector_table ( " lapd.sapi " ,
" LAPD SAPI " , FT_UINT16 , BASE_DEC ) ;
2000-11-29 05:16:15 +00:00
2008-09-30 14:46:48 +00:00
lapd_gsm_sapi_dissector_table = register_dissector_table ( " lapd.gsm.sapi " ,
" LAPD GSM SAPI " , FT_UINT16 , BASE_DEC ) ;
2006-03-02 21:31:33 +00:00
2007-09-19 21:02:41 +00:00
lapd_module = prefs_register_protocol ( proto_lapd , proto_reg_handoff_lapd ) ;
2006-03-02 21:31:33 +00:00
2007-09-19 21:02:41 +00:00
prefs_register_bool_preference ( lapd_module , " use_gsm_sapi_values " ,
" Use GSM SAPI values " ,
" Use SAPI values as specified in TS 48 056 " ,
& global_lapd_gsm_sapis ) ;
2008-05-26 20:52:38 +00:00
prefs_register_uint_preference ( lapd_module , " rtp_payload_type " ,
" RTP payload type for embedded LAPD " ,
" RTP payload type for embedded LAPD. It must be one of the dynamic types "
" from 96 to 127. Set it to 0 to disable. " ,
10 , & pref_lapd_rtp_payload_type ) ;
2006-03-02 21:31:33 +00:00
2000-11-29 05:16:15 +00:00
}
2009-03-29 22:16:26 +00:00
void
proto_reg_handoff_lapd ( void )
{
static gboolean init = FALSE ;
static dissector_handle_t lapd_bitstream_handle ;
static gint lapd_rtp_payload_type ;
if ( ! init ) {
dissector_handle_t lapd_handle ;
lapd_handle = find_dissector ( " lapd " ) ;
2010-12-20 05:35:29 +00:00
dissector_add_uint ( " wtap_encap " , WTAP_ENCAP_LINUX_LAPD , lapd_handle ) ;
2011-02-02 22:49:40 +00:00
dissector_add_uint ( " wtap_encap " , WTAP_ENCAP_LAPD , lapd_handle ) ;
2009-03-29 22:16:26 +00:00
lapd_bitstream_handle = create_dissector_handle ( dissect_lapd_bitstream , proto_lapd ) ;
data_handle = find_dissector ( " data " ) ;
init = TRUE ;
} else {
if ( ( lapd_rtp_payload_type > 95 ) & & ( lapd_rtp_payload_type < 128 ) )
2010-12-20 05:35:29 +00:00
dissector_delete_uint ( " rtp.pt " , lapd_rtp_payload_type , lapd_bitstream_handle ) ;
2009-03-29 22:16:26 +00:00
}
lapd_rtp_payload_type = pref_lapd_rtp_payload_type ;
if ( ( lapd_rtp_payload_type > 95 ) & & ( lapd_rtp_payload_type < 128 ) )
2010-12-20 05:35:29 +00:00
dissector_add_uint ( " rtp.pt " , lapd_rtp_payload_type , lapd_bitstream_handle ) ;
2009-03-29 22:16:26 +00:00
}