2007-04-14 07:55:43 +00:00
/* packet-erspan.c
2007-04-14 01:07:36 +00:00
* Routines for the disassembly of Cisco ' s ERSPAN protocol
*
* Copyright 2005 Joerg Mayer ( see AUTHORS file )
2010-09-23 13:31:28 +00:00
* Updates for newer versions by Jason Masker < jason at masker . net >
2007-04-14 01:07:36 +00:00
*
* 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 .
2007-04-14 01:07:36 +00:00
*/
/*
* TODO :
* Find out the Unknown values
*
* Specs :
* No real specs exist . Some general description can be found at :
* http : //www.cisco.com/en/US/products/hw/routers/ps368/products_configuration_guide_chapter09186a008069952a.html
*
2010-09-23 19:42:20 +00:00
* Some information on ERSPAN type III can be found at :
2010-09-23 13:31:28 +00:00
* http : //www.cisco.com/en/US/docs/switches/datacenter/nexus1000/sw/4_0_4_s_v_1_3/system_management/configuration/guide/n1000v_system_9span.html
*
2008-01-23 20:12:23 +00:00
* For ERSPAN packets , the " protocol type " field value in the GRE header
2010-09-23 19:42:20 +00:00
* is 0x88BE ( version 1 ) or 0x22EB ( version 2 ) .
*
* ERSPAN type II is version 1
* ERSPAN type III is version 2
2007-04-14 01:07:36 +00:00
*
* 0000000 : d4c3 b2a1 0200 0400 0000 0000 0000 0000 < - - pcap header
* 0000010 : ffff 0000
* 0000010 : 7100 0000 < - - 0x71 ( DLT_TYPE ) = linux_cooked_capture ( of course not )
* 0000010 : 7507 f845 11 d1 0500 < - - pcap record header
* 0000020 : 7 a00 0000 7 a00 0000
* 0000020 : 0000 030 a 0000 0000 < - - unknown
* 0000030 : 0000 0000
2010-09-23 13:31:28 +00:00
* 0000030 : 0000 88 be < - - GRE header ( version 1 )
2007-04-14 01:07:36 +00:00
* 0000030 : 1002 0001 0000 03 80 < - - ERSPAN header ( 01 : erspan - id )
* 0000040 : 00 d0 b7a7 7480 0015 c721 75 c0 0800 4500 < - - Ethernet packet
* . . .
2011-10-21 02:10:19 +00:00
*
2007-04-14 01:07:36 +00:00
*
*/
2012-09-20 02:03:38 +00:00
# include "config.h"
2007-04-14 01:07:36 +00:00
# include <epan/packet.h>
2011-10-31 13:45:21 +00:00
# include <epan/prefs.h>
# include <epan/expert.h>
2015-01-24 23:55:55 +00:00
# include "packet-gre.h"
2007-04-14 01:07:36 +00:00
2013-12-15 23:44:12 +00:00
void proto_register_erspan ( void ) ;
void proto_reg_handoff_erspan ( void ) ;
2007-04-14 01:07:36 +00:00
static int proto_erspan = - 1 ;
static gint ett_erspan = - 1 ;
2010-09-23 13:31:28 +00:00
static int hf_erspan_version = - 1 ;
2007-04-14 01:07:36 +00:00
static int hf_erspan_vlan = - 1 ;
2007-08-25 00:29:40 +00:00
static int hf_erspan_priority = - 1 ;
2007-04-14 01:07:36 +00:00
static int hf_erspan_unknown2 = - 1 ;
2007-08-25 00:29:40 +00:00
static int hf_erspan_direction = - 1 ;
2007-04-14 01:07:36 +00:00
static int hf_erspan_unknown3 = - 1 ;
2010-09-23 20:44:11 +00:00
static int hf_erspan_truncated = - 1 ;
2007-08-25 00:29:40 +00:00
static int hf_erspan_spanid = - 1 ;
2010-09-23 13:31:28 +00:00
static int hf_erspan_timestamp = - 1 ;
2007-08-25 00:29:40 +00:00
static int hf_erspan_unknown4 = - 1 ;
2010-09-23 19:42:20 +00:00
static int hf_erspan_direction2 = - 1 ;
static int hf_erspan_unknown5 = - 1 ;
static int hf_erspan_unknown6 = - 1 ;
2010-09-24 18:12:45 +00:00
static int hf_erspan_unknown7 = - 1 ;
2007-04-14 01:07:36 +00:00
2013-05-25 17:06:40 +00:00
static expert_field ei_erspan_version_unknown = EI_INIT ;
2007-04-14 01:07:36 +00:00
# define PROTO_SHORT_NAME "ERSPAN"
2010-09-23 19:42:20 +00:00
# define PROTO_LONG_NAME "Encapsulated Remote Switch Packet ANalysis"
2007-04-14 01:07:36 +00:00
2011-10-31 13:45:21 +00:00
/* Global ERSPAN Preference */
static gboolean pref_fake_erspan = FALSE ;
2007-08-25 00:29:40 +00:00
# define ERSPAN_DIRECTION_INCOMING 0
# define ERSPAN_DIRECTION_OUTGOING 1
static const value_string erspan_direction_vals [ ] = {
{ ERSPAN_DIRECTION_INCOMING , " Incoming " } ,
{ ERSPAN_DIRECTION_OUTGOING , " Outgoing " } ,
{ 0 , NULL } ,
} ;
2010-09-23 20:44:11 +00:00
static const value_string erspan_truncated_vals [ ] = {
{ 0 , " Not truncated " } ,
2011-11-02 20:43:10 +00:00
{ 1 , " Truncated " } ,
2010-09-23 19:42:20 +00:00
{ 0 , NULL } ,
} ;
2010-09-23 20:44:11 +00:00
static const value_string erspan_version_vals [ ] = {
{ 1 , " Type II " } ,
{ 2 , " Type III " } ,
{ 0 , NULL } ,
} ;
2007-04-14 01:07:36 +00:00
static dissector_handle_t ethnofcs_handle ;
2010-09-23 13:31:28 +00:00
static void
erspan_fmt_timestamp ( gchar * result , guint32 timeval )
{
g_snprintf ( result , ITEM_LABEL_LENGTH , " %.4f " , ( ( ( gfloat ) timeval ) / 10000 ) ) ;
}
2007-04-14 01:07:36 +00:00
static void
dissect_erspan ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree )
{
proto_item * ti ;
2011-10-31 13:45:21 +00:00
proto_item * ti_ver ;
2007-04-14 01:07:36 +00:00
proto_tree * erspan_tree = NULL ;
tvbuff_t * eth_tvb ;
guint32 offset = 0 ;
2013-03-01 05:29:12 +00:00
guint16 version ;
2007-04-14 01:07:36 +00:00
2014-09-30 20:59:17 +00:00
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , PROTO_SHORT_NAME ) ;
col_set_str ( pinfo - > cinfo , COL_INFO , PROTO_SHORT_NAME " : " ) ;
2007-04-14 01:07:36 +00:00
2011-10-31 13:45:21 +00:00
2007-04-14 01:07:36 +00:00
if ( tree ) {
ti = proto_tree_add_item ( tree , proto_erspan , tvb , offset , - 1 ,
2011-10-21 02:10:19 +00:00
ENC_NA ) ;
2007-04-14 01:07:36 +00:00
erspan_tree = proto_item_add_subtree ( ti , ett_erspan ) ;
2011-10-31 13:45:21 +00:00
}
if ( pref_fake_erspan ) {
/* Some vendor don't include ERSPAN Header...*/
eth_tvb = tvb_new_subset_remaining ( tvb , offset ) ;
call_dissector ( ethnofcs_handle , eth_tvb , pinfo , tree ) ;
return ;
}
2007-04-14 01:07:36 +00:00
2013-03-01 05:29:12 +00:00
version = tvb_get_ntohs ( tvb , offset ) > > 12 ;
2011-10-31 13:45:21 +00:00
if ( tree ) {
ti_ver = proto_tree_add_item ( erspan_tree , hf_erspan_version , tvb , offset , 2 ,
2011-08-26 17:02:33 +00:00
ENC_BIG_ENDIAN ) ;
2010-09-23 20:44:11 +00:00
if ( ( version ! = 1 ) & & ( version ! = 2 ) ) {
2013-05-25 17:06:40 +00:00
expert_add_info ( pinfo , ti_ver , & ei_erspan_version_unknown ) ;
return ;
2010-09-23 20:44:11 +00:00
}
2007-04-14 01:07:36 +00:00
proto_tree_add_item ( erspan_tree , hf_erspan_vlan , tvb , offset , 2 ,
2011-08-26 17:02:33 +00:00
ENC_BIG_ENDIAN ) ;
2007-04-14 01:07:36 +00:00
offset + = 2 ;
2007-08-25 00:29:40 +00:00
proto_tree_add_item ( erspan_tree , hf_erspan_priority , tvb , offset , 2 ,
2011-08-26 17:02:33 +00:00
ENC_BIG_ENDIAN ) ;
2007-04-14 01:07:36 +00:00
proto_tree_add_item ( erspan_tree , hf_erspan_unknown2 , tvb , offset , 2 ,
2011-08-26 17:02:33 +00:00
ENC_BIG_ENDIAN ) ;
2010-09-23 19:42:20 +00:00
if ( version = = 1 )
proto_tree_add_item ( erspan_tree , hf_erspan_direction , tvb ,
2011-08-26 17:02:33 +00:00
offset , 2 , ENC_BIG_ENDIAN ) ;
2010-09-23 19:42:20 +00:00
else /* version = 2 */
proto_tree_add_item ( erspan_tree , hf_erspan_unknown3 , tvb ,
2011-08-26 17:02:33 +00:00
offset , 2 , ENC_BIG_ENDIAN ) ;
2010-09-23 20:44:11 +00:00
proto_tree_add_item ( erspan_tree , hf_erspan_truncated , tvb , offset , 2 ,
2011-08-26 17:02:33 +00:00
ENC_BIG_ENDIAN ) ;
2007-04-14 01:07:36 +00:00
proto_tree_add_item ( erspan_tree , hf_erspan_spanid , tvb , offset , 2 ,
2011-08-26 17:02:33 +00:00
ENC_BIG_ENDIAN ) ;
2007-04-14 01:07:36 +00:00
offset + = 2 ;
2010-09-24 18:12:45 +00:00
if ( version = = 2 ) {
2010-09-23 13:31:28 +00:00
proto_tree_add_item ( erspan_tree , hf_erspan_timestamp , tvb ,
2011-08-26 17:02:33 +00:00
offset , 4 , ENC_BIG_ENDIAN ) ;
2010-09-23 13:31:28 +00:00
offset + = 4 ;
proto_tree_add_item ( erspan_tree , hf_erspan_unknown4 , tvb ,
2011-10-04 22:44:31 +00:00
offset , 2 , ENC_NA ) ;
2010-09-23 19:42:20 +00:00
offset + = 2 ;
proto_tree_add_item ( erspan_tree , hf_erspan_direction2 , tvb ,
2011-08-26 17:02:33 +00:00
offset , 2 , ENC_BIG_ENDIAN ) ;
2010-09-23 19:42:20 +00:00
proto_tree_add_item ( erspan_tree , hf_erspan_unknown5 , tvb ,
2011-08-26 17:02:33 +00:00
offset , 2 , ENC_BIG_ENDIAN ) ;
2010-09-23 19:42:20 +00:00
offset + = 2 ;
proto_tree_add_item ( erspan_tree , hf_erspan_unknown6 , tvb ,
2011-10-04 22:44:31 +00:00
offset , 4 , ENC_NA ) ;
2010-09-24 18:12:45 +00:00
offset + = 4 ;
2010-09-23 13:31:28 +00:00
}
2010-09-24 18:12:45 +00:00
proto_tree_add_item ( erspan_tree , hf_erspan_unknown7 , tvb , offset , 4 ,
2011-10-04 22:44:31 +00:00
ENC_NA ) ;
2010-09-24 18:12:45 +00:00
offset + = 4 ;
2007-04-14 01:07:36 +00:00
}
2009-10-09 07:24:33 +00:00
else {
offset + = 8 ;
2010-09-23 13:31:28 +00:00
if ( version = = 2 )
offset + = 12 ;
2009-10-09 07:24:33 +00:00
}
2014-09-30 20:59:17 +00:00
eth_tvb = tvb_new_subset_remaining ( tvb , offset ) ;
call_dissector ( ethnofcs_handle , eth_tvb , pinfo , tree ) ;
2007-04-14 01:07:36 +00:00
}
void
proto_register_erspan ( void )
{
2011-10-31 13:45:21 +00:00
module_t * erspan_module ;
2013-05-25 17:06:40 +00:00
expert_module_t * expert_erspan ;
2011-10-31 13:45:21 +00:00
2007-04-14 01:07:36 +00:00
static hf_register_info hf [ ] = {
2010-09-23 13:31:28 +00:00
{ & hf_erspan_version ,
2010-09-23 20:44:11 +00:00
{ " Version " , " erspan.version " , FT_UINT16 , BASE_DEC , VALS ( erspan_version_vals ) ,
From Kovarththanan Rajaratnam via bug 3548:
(1) Trailing/leading spaces are removed from 'name's/'blurb's
(2) Duplicate 'blurb's are replaced with NULL
(3) Empty ("") 'blurb's are replaced with NULL
(4) BASE_NONE, NULL, 0x0 are used for 'display', 'strings' and 'bitmask' fields
for FT_NONE, FT_BYTES, FT_IPv4, FT_IPv6, FT_ABSOLUTE_TIME, FT_RELATIVE_TIME,
FT_PROTOCOL, FT_STRING and FT_STRINGZ field types
(5) Only allow non-zero value for 'display' if 'bitmask' is non-zero
svn path=/trunk/; revision=28770
2009-06-18 21:30:42 +00:00
0xf000 , NULL , HFILL } } ,
2007-04-14 01:07:36 +00:00
{ & hf_erspan_vlan ,
{ " Vlan " , " erspan.vlan " , FT_UINT16 , BASE_DEC , NULL ,
From Kovarththanan Rajaratnam via bug 3548:
(1) Trailing/leading spaces are removed from 'name's/'blurb's
(2) Duplicate 'blurb's are replaced with NULL
(3) Empty ("") 'blurb's are replaced with NULL
(4) BASE_NONE, NULL, 0x0 are used for 'display', 'strings' and 'bitmask' fields
for FT_NONE, FT_BYTES, FT_IPv4, FT_IPv6, FT_ABSOLUTE_TIME, FT_RELATIVE_TIME,
FT_PROTOCOL, FT_STRING and FT_STRINGZ field types
(5) Only allow non-zero value for 'display' if 'bitmask' is non-zero
svn path=/trunk/; revision=28770
2009-06-18 21:30:42 +00:00
0x0fff , NULL , HFILL } } ,
2007-04-14 01:07:36 +00:00
2007-08-25 00:29:40 +00:00
{ & hf_erspan_priority ,
{ " Priority " , " erspan.priority " , FT_UINT16 , BASE_DEC , NULL ,
From Kovarththanan Rajaratnam via bug 3548:
(1) Trailing/leading spaces are removed from 'name's/'blurb's
(2) Duplicate 'blurb's are replaced with NULL
(3) Empty ("") 'blurb's are replaced with NULL
(4) BASE_NONE, NULL, 0x0 are used for 'display', 'strings' and 'bitmask' fields
for FT_NONE, FT_BYTES, FT_IPv4, FT_IPv6, FT_ABSOLUTE_TIME, FT_RELATIVE_TIME,
FT_PROTOCOL, FT_STRING and FT_STRINGZ field types
(5) Only allow non-zero value for 'display' if 'bitmask' is non-zero
svn path=/trunk/; revision=28770
2009-06-18 21:30:42 +00:00
0xe000 , NULL , HFILL } } ,
2007-08-25 00:29:40 +00:00
2007-04-14 01:07:36 +00:00
{ & hf_erspan_unknown2 ,
2007-08-25 00:29:40 +00:00
{ " Unknown2 " , " erspan.unknown2 " , FT_UINT16 , BASE_DEC , NULL ,
From Kovarththanan Rajaratnam via bug 3548:
(1) Trailing/leading spaces are removed from 'name's/'blurb's
(2) Duplicate 'blurb's are replaced with NULL
(3) Empty ("") 'blurb's are replaced with NULL
(4) BASE_NONE, NULL, 0x0 are used for 'display', 'strings' and 'bitmask' fields
for FT_NONE, FT_BYTES, FT_IPv4, FT_IPv6, FT_ABSOLUTE_TIME, FT_RELATIVE_TIME,
FT_PROTOCOL, FT_STRING and FT_STRINGZ field types
(5) Only allow non-zero value for 'display' if 'bitmask' is non-zero
svn path=/trunk/; revision=28770
2009-06-18 21:30:42 +00:00
0x1000 , NULL , HFILL } } ,
2007-08-25 00:29:40 +00:00
{ & hf_erspan_direction ,
{ " Direction " , " erspan.direction " , FT_UINT16 , BASE_DEC , VALS ( erspan_direction_vals ) ,
From Kovarththanan Rajaratnam via bug 3548:
(1) Trailing/leading spaces are removed from 'name's/'blurb's
(2) Duplicate 'blurb's are replaced with NULL
(3) Empty ("") 'blurb's are replaced with NULL
(4) BASE_NONE, NULL, 0x0 are used for 'display', 'strings' and 'bitmask' fields
for FT_NONE, FT_BYTES, FT_IPv4, FT_IPv6, FT_ABSOLUTE_TIME, FT_RELATIVE_TIME,
FT_PROTOCOL, FT_STRING and FT_STRINGZ field types
(5) Only allow non-zero value for 'display' if 'bitmask' is non-zero
svn path=/trunk/; revision=28770
2009-06-18 21:30:42 +00:00
0x0800 , NULL , HFILL } } ,
2007-08-25 00:29:40 +00:00
{ & hf_erspan_unknown3 ,
{ " Unknown3 " , " erspan.unknown3 " , FT_UINT16 , BASE_DEC , NULL ,
2010-09-23 19:42:20 +00:00
0x0800 , NULL , HFILL } } ,
2010-09-23 20:44:11 +00:00
{ & hf_erspan_truncated ,
{ " Truncated " , " erspan.truncated " , FT_UINT16 , BASE_DEC , VALS ( erspan_truncated_vals ) ,
2010-09-23 19:42:20 +00:00
0x0400 , " ERSPAN packet exceeded the MTU size " , HFILL } } ,
2007-04-14 01:07:36 +00:00
{ & hf_erspan_spanid ,
{ " SpanID " , " erspan.spanid " , FT_UINT16 , BASE_DEC , NULL ,
From Kovarththanan Rajaratnam via bug 3548:
(1) Trailing/leading spaces are removed from 'name's/'blurb's
(2) Duplicate 'blurb's are replaced with NULL
(3) Empty ("") 'blurb's are replaced with NULL
(4) BASE_NONE, NULL, 0x0 are used for 'display', 'strings' and 'bitmask' fields
for FT_NONE, FT_BYTES, FT_IPv4, FT_IPv6, FT_ABSOLUTE_TIME, FT_RELATIVE_TIME,
FT_PROTOCOL, FT_STRING and FT_STRINGZ field types
(5) Only allow non-zero value for 'display' if 'bitmask' is non-zero
svn path=/trunk/; revision=28770
2009-06-18 21:30:42 +00:00
0x03ff , NULL , HFILL } } ,
2007-04-14 01:07:36 +00:00
2010-09-23 13:31:28 +00:00
{ & hf_erspan_timestamp ,
2015-02-16 01:58:12 +00:00
{ " Timestamp " , " erspan.timestamp " , FT_UINT32 , BASE_CUSTOM , CF_FUNC ( erspan_fmt_timestamp ) ,
2010-09-23 13:31:28 +00:00
0 , NULL , HFILL } } ,
2007-08-25 00:29:40 +00:00
{ & hf_erspan_unknown4 ,
{ " Unknown4 " , " erspan.unknown4 " , FT_BYTES , BASE_NONE , NULL ,
From Kovarththanan Rajaratnam via bug 3548:
(1) Trailing/leading spaces are removed from 'name's/'blurb's
(2) Duplicate 'blurb's are replaced with NULL
(3) Empty ("") 'blurb's are replaced with NULL
(4) BASE_NONE, NULL, 0x0 are used for 'display', 'strings' and 'bitmask' fields
for FT_NONE, FT_BYTES, FT_IPv4, FT_IPv6, FT_ABSOLUTE_TIME, FT_RELATIVE_TIME,
FT_PROTOCOL, FT_STRING and FT_STRINGZ field types
(5) Only allow non-zero value for 'display' if 'bitmask' is non-zero
svn path=/trunk/; revision=28770
2009-06-18 21:30:42 +00:00
0 , NULL , HFILL } } ,
2007-04-14 01:07:36 +00:00
2010-09-23 19:42:20 +00:00
{ & hf_erspan_direction2 ,
{ " Direction2 " , " erspan.direction2 " , FT_UINT16 , BASE_DEC , VALS ( erspan_direction_vals ) ,
0x0008 , NULL , HFILL } } ,
{ & hf_erspan_unknown5 ,
{ " Unknown5 " , " erspan.unknown5 " , FT_UINT16 , BASE_HEX , NULL ,
0xfff7 , NULL , HFILL } } ,
{ & hf_erspan_unknown6 ,
{ " Unknown6 " , " erspan.unknown6 " , FT_BYTES , BASE_NONE , NULL ,
0 , NULL , HFILL } } ,
2010-09-24 18:12:45 +00:00
{ & hf_erspan_unknown7 ,
{ " Unknown7 " , " erspan.unknown7 " , FT_BYTES , BASE_NONE , NULL ,
0 , NULL , HFILL } } ,
2013-05-25 17:06:40 +00:00
} ;
2007-04-14 01:07:36 +00:00
static gint * ett [ ] = {
& ett_erspan ,
} ;
2013-05-25 17:06:40 +00:00
static ei_register_info ei [ ] = {
{ & ei_erspan_version_unknown , { " erspan.version.unknown " , PI_UNDECODED , PI_WARN , " Unknown version, please report or test to use fake ERSPAN preference " , EXPFILL } } ,
} ;
proto_erspan = proto_register_protocol ( PROTO_LONG_NAME , PROTO_SHORT_NAME , " erspan " ) ;
proto_register_field_array ( proto_erspan , hf , array_length ( hf ) ) ;
2007-04-14 01:07:36 +00:00
proto_register_subtree_array ( ett , array_length ( ett ) ) ;
2013-05-25 17:06:40 +00:00
expert_erspan = expert_register_protocol ( proto_erspan ) ;
expert_register_field_array ( expert_erspan , ei , array_length ( ei ) ) ;
2011-10-31 13:45:21 +00:00
/* register dissection preferences */
erspan_module = prefs_register_protocol ( proto_erspan , NULL ) ;
prefs_register_bool_preference ( erspan_module , " fake_erspan " ,
" FORCE to decode fake ERSPAN frame " ,
" When set, dissector will FORCE to decode directly Ethernet Frame "
" Some vendor use fake ERSPAN frame (with not ERSPAN Header) " ,
& pref_fake_erspan ) ;
2007-04-14 01:07:36 +00:00
}
void
proto_reg_handoff_erspan ( void )
{
dissector_handle_t erspan_handle ;
2014-09-30 20:59:17 +00:00
ethnofcs_handle = find_dissector ( " eth_withoutfcs " ) ;
2007-04-14 01:07:36 +00:00
erspan_handle = create_dissector_handle ( dissect_erspan , proto_erspan ) ;
2014-09-30 20:59:17 +00:00
dissector_add_uint ( " gre.proto " , GRE_ERSPAN_88BE , erspan_handle ) ;
dissector_add_uint ( " gre.proto " , GRE_ERSPAN_22EB , erspan_handle ) ;
2007-04-14 01:07:36 +00:00
}
2014-09-30 20:59:17 +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 :
*/