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
*
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
2012-09-20 02:03:38 +00:00
# include "config.h"
1999-11-11 05:36:16 +00:00
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>
2013-12-21 17:23:17 +00:00
# include <wiretap/wtap.h>
2005-09-17 00:02:31 +00:00
# include <epan/lapd_sapi.h>
2013-04-05 05:09:31 +00:00
# include <epan/expert.h>
2015-04-03 03:11:51 +00:00
# include "packet-l2tp.h"
2013-12-03 06:20:18 +00:00
void proto_register_lapd ( void ) ;
2015-07-11 21:33:26 +00:00
void proto_reg_handoff_lapd ( void ) ;
2013-12-03 06:20:18 +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
2013-05-27 17:30:43 +00:00
static expert_field ei_lapd_abort = EI_INIT ;
static expert_field ei_lapd_checksum_bad = EI_INIT ;
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
} ;
2013-04-05 05:09:31 +00:00
# define MAX_LAPD_PACKET_LEN 1024
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 */
2013-04-05 05:09:31 +00:00
char data [ MAX_LAPD_PACKET_LEN ] ;
int data_len ;
2008-05-26 20:52:38 +00:00
} 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
2013-04-05 05:09:31 +00:00
fill_lapd_byte_state ( lapd_byte_state_t * ptr , enum lapd_bitstream_states state , char full_byte , char bit_offset , int ones , char * data , int data_len )
2008-05-26 20:52:38 +00:00
{
ptr - > state = state ;
ptr - > full_byte = full_byte ;
ptr - > bit_offset = bit_offset ;
ptr - > ones = ones ;
2013-04-05 05:09:31 +00:00
2013-12-13 02:58:34 +00:00
ptr - > data_len = MIN ( ( int ) sizeof ( ptr - > data ) , data_len ) ;
2013-12-13 02:35:26 +00:00
memcpy ( ptr - > data , data , ptr - > data_len ) ;
2008-05-26 20:52:38 +00:00
}
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 ;
static void
dissect_lapd ( tvbuff_t * , packet_info * , proto_tree * ) ;
2013-04-05 05:09:31 +00:00
static void
dissect_lapd_full ( tvbuff_t * , packet_info * , proto_tree * , gboolean ) ;
2008-05-26 20:52:38 +00:00
/* 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 */
}
}
2013-04-05 05:09:31 +00:00
static void
lapd_log_abort ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , guint offset , const char * msg )
2013-07-03 23:43:26 +00:00
{
proto_item * ti ;
2013-04-05 05:09:31 +00:00
2013-07-03 23:43:26 +00:00
ti = proto_tree_add_item ( tree , proto_lapd , tvb , offset , 1 , ENC_NA ) ;
2013-09-09 00:44:09 +00:00
expert_add_info_format ( pinfo , ti , & ei_lapd_abort , " %s " , msg ) ;
2013-04-05 05:09:31 +00:00
}
2008-05-26 20:52:38 +00:00
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 ;
2013-01-23 06:11:18 +00:00
gint 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 */
2013-04-05 05:09:31 +00:00
conversation = find_or_create_conversation ( pinfo ) ;
2013-11-23 02:20:13 +00:00
lapd_ppi = ( lapd_ppi_t * ) p_get_proto_data ( wmem_file_scope ( ) , pinfo , proto_lapd , 0 ) ;
2008-05-26 20:52:38 +00:00
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 ;
2013-04-05 05:09:31 +00:00
memcpy ( data , prev_byte_state - > data , prev_byte_state - > data_len ) ;
data_len = prev_byte_state - > data_len ;
2008-05-26 20:52:38 +00:00
}
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 ) {
2015-10-21 19:04:16 +00:00
if ( addresses_equal ( & convo_data - > addr_a , & pinfo - > src )
& & addresses_equal ( & convo_data - > addr_b , & pinfo - > dst )
2008-05-26 20:52:38 +00:00
& & 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 ;
2015-10-21 19:04:16 +00:00
} else if ( addresses_equal ( & convo_data - > addr_b , & pinfo - > src )
& & addresses_equal ( & convo_data - > addr_a , & pinfo - > dst )
2008-05-26 20:52:38 +00:00
& & 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 ;
2013-04-05 05:09:31 +00:00
memcpy ( data , prev_byte_state - > data , prev_byte_state - > data_len ) ;
data_len = prev_byte_state - > data_len ;
2008-05-26 20:52:38 +00:00
}
}
/* Consume tvb bytes */
2014-11-20 15:07:55 +00:00
available = tvb_reported_length_remaining ( tvb , offset ) ;
2008-05-26 20:52:38 +00:00
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 */
2013-03-19 19:28:57 +00:00
buff = ( guint8 * ) g_memdup ( data , data_len ) ;
2008-05-26 20:52:38 +00:00
/* 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 " ) ;
data_len = 0 ;
state = FLAGS ;
bit_offset + + ;
2013-04-05 05:09:31 +00:00
if ( full_byte ! = 0x7E ) {
data_len = 0 ;
state = OUT_OF_SYNC ;
lapd_log_abort ( tvb , pinfo , tree , offset , " Abort! 6 ones that don't match 0x7e! " ) ;
}
dissect_lapd_full ( new_tvb , pinfo , tree , TRUE ) ;
2008-05-26 20:52:38 +00:00
} else if ( ones > = 7 ) { /* frame reset or 11111111 flag byte */
data_len = 0 ;
state = OUT_OF_SYNC ;
bit_offset + + ;
2013-10-13 19:56:52 +00:00
2013-04-05 05:09:31 +00:00
lapd_log_abort ( tvb , pinfo , tree , offset , " Abort! 7 ones! " ) ;
2008-05-26 20:52:38 +00:00
} 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 ;
}
}
}
}
2013-04-05 05:09:31 +00:00
{
2013-11-23 02:20:13 +00:00
if ( NULL = = p_get_proto_data ( wmem_file_scope ( ) , pinfo , proto_lapd , 0 ) ) {
2008-05-26 20:52:38 +00:00
/* Per packet information */
2013-09-15 13:46:13 +00:00
lapd_ppi = wmem_new ( wmem_file_scope ( ) , lapd_ppi_t ) ;
2008-05-26 20:52:38 +00:00
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 ,
2013-04-05 05:09:31 +00:00
prev_byte_state - > ones , prev_byte_state - > data , prev_byte_state - > data_len ) ;
2010-09-23 21:46:31 +00:00
else
2013-04-05 05:09:31 +00:00
fill_lapd_byte_state ( & lapd_ppi - > start_byte_state , OUT_OF_SYNC , 0x00 , 0 , 0 , data , 0 ) ;
2008-05-26 20:52:38 +00:00
2013-11-23 02:20:13 +00:00
p_add_proto_data ( wmem_file_scope ( ) , pinfo , proto_lapd , 0 , 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 )
2013-04-05 05:09:31 +00:00
fill_lapd_byte_state ( convo_data - > byte_state_a , state , full_byte , bit_offset , ones , data , data_len ) ;
2008-05-26 20:52:38 +00:00
else {
if ( ! convo_data - > byte_state_b )
2013-09-15 13:46:13 +00:00
convo_data - > byte_state_b = wmem_new ( wmem_file_scope ( ) , lapd_byte_state_t ) ;
2013-04-05 05:09:31 +00:00
fill_lapd_byte_state ( convo_data - > byte_state_b , state , full_byte , bit_offset , ones , data , data_len ) ;
2008-05-26 20:52:38 +00:00
}
} else { /* lapd convo data has to be created */
2013-09-15 13:46:13 +00:00
lapd_byte_state = wmem_new ( wmem_file_scope ( ) , lapd_byte_state_t ) ;
2013-04-05 05:09:31 +00:00
fill_lapd_byte_state ( lapd_byte_state , state , full_byte , bit_offset , ones , data , data_len ) ;
2013-09-15 13:46:13 +00:00
convo_data = wmem_new ( wmem_file_scope ( ) , lapd_convo_data_t ) ;
2015-10-21 19:04:16 +00:00
copy_address ( & convo_data - > addr_a , & pinfo - > src ) ;
copy_address ( & convo_data - > addr_b , & pinfo - > dst ) ;
2008-05-26 20:52:38 +00:00
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 )
2013-04-05 05:09:31 +00:00
{
dissect_lapd_full ( tvb , pinfo , tree , FALSE ) ;
}
static void
dissect_lapd_full ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , gboolean has_crc )
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
2013-06-14 17:49:53 +00:00
col_add_fstr ( pinfo - > cinfo , COL_TEI , " %u " , tei ) ;
2006-03-02 21:31:33 +00:00
2012-11-09 15:11:45 +00:00
/* Append TEI to info field */
col_append_fstr ( pinfo - > cinfo , COL_INFO , " TEI:%02u " , tei ) ;
col_set_fence ( pinfo - > cinfo , COL_INFO ) ;
2006-03-02 21:31:33 +00:00
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 ) ;
2013-04-05 05:09:31 +00:00
if ( has_crc ) {
2010-09-23 21:46:31 +00:00
2008-05-26 20:52:38 +00:00
/* check checksum */
2014-11-20 15:07:55 +00:00
checksum_offset = tvb_reported_length ( tvb ) - 2 ;
2008-05-26 20:52:38 +00:00
checksum = tvb_get_guint8 ( tvb , checksum_offset ) ; /* high byte */
checksum < < = 8 ;
checksum | = tvb_get_guint8 ( tvb , checksum_offset + 1 ) & 0x00FF ; /* low byte */
2014-11-20 15:07:55 +00:00
checksum_calculated = crc16_ccitt_tvb ( tvb , tvb_reported_length ( tvb ) - 2 ) ;
2012-01-12 20:40:23 +00:00
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 ) {
2013-09-15 01:48:30 +00:00
checksum_ti = proto_tree_add_uint_format_value ( lapd_tree , hf_lapd_checksum , tvb , checksum_offset , 2 , 0 , " 0x%04x [correct] " , checksum ) ;
2008-05-26 20:52:38 +00:00
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 {
2013-04-05 05:09:31 +00:00
proto_item * pi ;
2013-09-15 01:48:30 +00:00
checksum_ti = proto_tree_add_uint_format_value ( lapd_tree , hf_lapd_checksum , tvb , checksum_offset , 2 , 0 , " 0x%04x [incorrect, should be 0x%04x] " , checksum , checksum_calculated ) ;
2008-05-26 20:52:38 +00:00
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 ) ;
2013-04-05 05:09:31 +00:00
pi = proto_tree_add_boolean ( checksum_tree , hf_lapd_checksum_bad , tvb , checksum_offset , 2 , TRUE ) ;
2013-05-27 17:30:43 +00:00
expert_add_info ( pinfo , pi , & ei_lapd_checksum_bad ) ;
2008-05-26 20:52:38 +00:00
}
2010-09-23 21:46:31 +00:00
2014-11-20 15:07:55 +00:00
next_tvb = tvb_new_subset_length ( tvb , lapd_header_len , tvb_reported_length_remaining ( tvb , lapd_header_len ) - 2 ) ;
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
2013-05-27 17:30:43 +00:00
/* Dissection done, append " | " to COL_INFO */
2013-10-29 14:09:20 +00:00
col_append_str ( pinfo - > cinfo , COL_INFO , " | " ) ;
2012-11-09 15:11:45 +00:00
col_set_fence ( pinfo - > cinfo , COL_INFO ) ;
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
}
2015-07-11 21:33:26 +00:00
static gboolean
dissect_udp_lapd ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * tree , void * data _U_ )
{
if ( pinfo - > srcport < 3001 | | pinfo - > srcport > 3015
| | pinfo - > destport < 3001 | | pinfo - > destport > 3015
| | pinfo - > destport ! = pinfo - > srcport )
return FALSE ;
/*
* XXX - check for a valid LAPD address field .
*/
/*
* OK , check whether the control field looks valid .
*/
if ( ! check_xdlc_control ( tvb , 2 , NULL , NULL , FALSE , FALSE ) )
return FALSE ;
dissect_lapd ( tvb , pinfo , tree ) ;
return TRUE ;
}
2007-09-19 21:02:41 +00:00
1999-11-11 05:36:16 +00:00
void
proto_register_lapd ( void )
{
2014-10-03 14:13:07 +00:00
static hf_register_info hf [ ] = {
{ & hf_lapd_direction ,
{ " Direction " , " lapd.direction " , FT_UINT8 , BASE_DEC , VALS ( lapd_direction_vals ) , 0x0 ,
NULL , HFILL } } ,
{ & hf_lapd_address ,
{ " Address Field " , " lapd.address " , FT_UINT16 , BASE_HEX , NULL , 0x0 ,
" Address " , HFILL } } ,
{ & hf_lapd_sapi ,
{ " SAPI " , " lapd.sapi " , FT_UINT16 , BASE_DEC , VALS ( lapd_sapi_vals ) , LAPD_SAPI ,
" Service Access Point Identifier " , HFILL } } ,
{ & hf_lapd_gsm_sapi ,
{ " SAPI " , " lapd.sapi " , FT_UINT16 , BASE_DEC , VALS ( lapd_gsm_sapi_vals ) , LAPD_SAPI ,
" Service Access Point Identifier " , HFILL } } ,
{ & hf_lapd_cr ,
{ " C/R " , " lapd.cr " , FT_UINT16 , BASE_DEC , NULL , LAPD_CR ,
" Command/Response bit " , HFILL } } ,
{ & hf_lapd_ea1 ,
{ " EA1 " , " lapd.ea1 " , FT_UINT16 , BASE_DEC , NULL , LAPD_EA1 ,
" First Address Extension bit " , HFILL } } ,
{ & hf_lapd_tei ,
{ " TEI " , " lapd.tei " , FT_UINT16 , BASE_DEC , NULL , LAPD_TEI ,
" Terminal Endpoint Identifier " , HFILL } } ,
{ & hf_lapd_ea2 ,
{ " EA2 " , " lapd.ea2 " , FT_UINT16 , BASE_DEC , NULL , LAPD_EA2 ,
" Second Address Extension bit " , HFILL } } ,
{ & hf_lapd_control ,
{ " Control Field " , " lapd.control " , FT_UINT16 , BASE_HEX , NULL , 0x0 ,
NULL , HFILL } } ,
{ & hf_lapd_n_r ,
{ " N(R) " , " lapd.control.n_r " , FT_UINT16 , BASE_DEC ,
NULL , XDLC_N_R_EXT_MASK , NULL , HFILL } } ,
{ & hf_lapd_n_s ,
{ " N(S) " , " lapd.control.n_s " , FT_UINT16 , BASE_DEC ,
NULL , XDLC_N_S_EXT_MASK , NULL , HFILL } } ,
{ & hf_lapd_p ,
{ " Poll " , " lapd.control.p " , FT_BOOLEAN , 8 ,
TFS ( & tfs_set_notset ) , XDLC_P_F , NULL , HFILL } } ,
{ & hf_lapd_p_ext ,
{ " Poll " , " lapd.control.p " , FT_BOOLEAN , 16 ,
TFS ( & tfs_set_notset ) , XDLC_P_F_EXT , NULL , HFILL } } ,
{ & hf_lapd_f ,
{ " Final " , " lapd.control.f " , FT_BOOLEAN , 8 ,
TFS ( & tfs_set_notset ) , XDLC_P_F , NULL , HFILL } } ,
{ & hf_lapd_f_ext ,
{ " Final " , " lapd.control.f " , FT_BOOLEAN , 16 ,
TFS ( & tfs_set_notset ) , XDLC_P_F_EXT , NULL , HFILL } } ,
{ & hf_lapd_s_ftype ,
{ " Supervisory frame type " , " lapd.control.s_ftype " , FT_UINT16 , BASE_HEX ,
VALS ( stype_vals ) , XDLC_S_FTYPE_MASK , NULL , HFILL } } ,
{ & hf_lapd_u_modifier_cmd ,
{ " Command " , " lapd.control.u_modifier_cmd " , FT_UINT8 , BASE_HEX ,
VALS ( modifier_vals_cmd ) , XDLC_U_MODIFIER_MASK , NULL , HFILL } } ,
{ & hf_lapd_u_modifier_resp ,
{ " Response " , " lapd.control.u_modifier_resp " , FT_UINT8 , BASE_HEX ,
VALS ( modifier_vals_resp ) , XDLC_U_MODIFIER_MASK , NULL , HFILL } } ,
{ & hf_lapd_ftype_i ,
{ " Frame type " , " lapd.control.ftype " , FT_UINT16 , BASE_HEX ,
VALS ( ftype_vals ) , XDLC_I_MASK , NULL , HFILL } } ,
{ & hf_lapd_ftype_s_u ,
{ " Frame type " , " lapd.control.ftype " , FT_UINT8 , BASE_HEX ,
VALS ( ftype_vals ) , XDLC_S_U_MASK , NULL , HFILL } } ,
{ & hf_lapd_ftype_s_u_ext ,
{ " Frame type " , " lapd.control.ftype " , FT_UINT16 , BASE_HEX ,
VALS ( ftype_vals ) , XDLC_S_U_MASK , NULL , HFILL } } ,
{ & hf_lapd_checksum ,
{ " Checksum " , " lapd.checksum " , FT_UINT16 , BASE_HEX ,
NULL , 0x0 , " Details at: http://www.wireshark.org/docs/wsug_html_chunked/ChAdvChecksums.html " , HFILL } } ,
{ & hf_lapd_checksum_good ,
{ " Good Checksum " , " lapd.checksum_good " , FT_BOOLEAN , BASE_NONE ,
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 } } ,
} ;
static gint * ett [ ] = {
& ett_lapd ,
& ett_lapd_address ,
& ett_lapd_control ,
& ett_lapd_checksum
} ;
1999-11-11 05:36:16 +00:00
2013-05-27 17:30:43 +00:00
static ei_register_info ei [ ] = {
{ & ei_lapd_abort , { " lapd.abort.expert " , PI_PROTOCOL , PI_ERROR , " Formatted message " , EXPFILL } } ,
{ & ei_lapd_checksum_bad , { " lapd.checksum_bad.expert " , PI_CHECKSUM , PI_WARN , " Bad FCS " , EXPFILL } } ,
} ;
2007-09-19 21:02:41 +00:00
module_t * lapd_module ;
2013-05-27 17:30:43 +00:00
expert_module_t * expert_lapd ;
2007-09-19 21:02:41 +00:00
2008-09-30 14:46:48 +00:00
proto_lapd = proto_register_protocol ( " Link Access Procedure, Channel D (LAPD) " ,
2014-10-03 14:13:07 +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 ) ) ;
2013-05-27 17:30:43 +00:00
expert_lapd = expert_register_protocol ( proto_lapd ) ;
expert_register_field_array ( expert_lapd , ei , array_length ( ei ) ) ;
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 " ,
2015-10-29 13:23:55 +00:00
" LAPD SAPI " , FT_UINT16 , BASE_DEC , DISSECTOR_TABLE_NOT_ALLOW_DUPLICATE ) ;
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 " ,
2015-10-29 13:23:55 +00:00
" LAPD GSM SAPI " , FT_UINT16 , BASE_DEC , DISSECTOR_TABLE_NOT_ALLOW_DUPLICATE ) ;
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 " ,
2014-10-03 14:13:07 +00:00
" 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 " ,
2014-10-03 14:13:07 +00:00
" 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 ) ;
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 ) ;
2015-04-03 03:11:51 +00:00
dissector_add_uint ( " l2tp.pw_type " , L2TPv3_PROTOCOL_LAPD , lapd_handle ) ;
2015-07-13 00:40:31 +00:00
heur_dissector_add ( " udp " , dissect_udp_lapd , " LAPD over UDP " , " lapd_udp " , proto_lapd , HEURISTIC_ENABLE ) ;
2009-03-29 22:16:26 +00:00
2013-04-05 05:09:31 +00:00
register_dissector ( " lapd-bitstream " , dissect_lapd_bitstream , proto_lapd ) ;
lapd_bitstream_handle = find_dissector ( " lapd-bitstream " ) ;
2009-03-29 22:16:26 +00:00
data_handle = find_dissector ( " data " ) ;
2013-04-05 05:09:31 +00:00
2009-03-29 22:16:26 +00:00
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
}
2014-10-03 14:13:07 +00:00
/*
* Editor modelines - http : //www.wireshark.org/tools/modelines.html
*
* Local variables :
* c - basic - offset : 8
* tab - width : 8
* indent - tabs - mode : t
* End :
*
* vi : set shiftwidth = 8 tabstop = 8 noexpandtab :
* : indentSize = 8 : tabSize = 8 : noTabs = false :
*/