1 /* packet-ethertype.c
2  * Routines for processing Ethernet payloads and payloads like Ethernet
3  * payloads (i.e., payloads when there could be an Ethernet trailer and
4  * possibly an FCS).
5  *
6  * Gilbert Ramirez <gram@alumni.rice.edu>
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * SPDX-License-Identifier: GPL-2.0-or-later
13  */
14 
15 #include "config.h"
16 
17 #include <epan/packet.h>
18 #include <epan/exceptions.h>
19 #include <epan/etypes.h>
20 #include <epan/ppptypes.h>
21 #include <epan/show_exception.h>
22 #include <epan/decode_as.h>
23 #include <epan/capture_dissectors.h>
24 #include <epan/proto_data.h>
25 #include "packet-eth.h"
26 
27 void proto_register_ethertype(void);
28 
29 static dissector_table_t ethertype_dissector_table;
30 
31 static int proto_ethertype = -1;
32 
33 const value_string etype_vals[] = {
34 	{ ETHERTYPE_IP,                   "IPv4" },
35 	{ ETHERTYPE_IPv6,                 "IPv6" },
36 	{ ETHERTYPE_VLAN,                 "802.1Q Virtual LAN" },
37 	{ ETHERTYPE_SLPP,                 "Simple Loop Protection Protocol" },
38 	{ ETHERTYPE_VLACP,                "Virtual LACP" }, /* Nortel/Avaya/Extremenetworks */
39 	{ ETHERTYPE_OLDSLPP,              "Simple Loop Protection Protocol (old)" },
40 	{ ETHERTYPE_ARP,                  "ARP" },
41 	{ ETHERTYPE_WLCCP,                "Cisco Wireless Lan Context Control Protocol" },
42 	{ ETHERTYPE_MINT,                 "Motorola Media Independent Network Transport" },
43 	{ ETHERTYPE_CENTRINO_PROMISC,     "IEEE 802.11 (Centrino promiscuous)" },
44 	{ ETHERTYPE_XNS_IDP,              "XNS Internet Datagram Protocol" },
45 	{ ETHERTYPE_X25L3,                "X.25 Layer 3" },
46 	{ ETHERTYPE_WOL,                  "Wake on LAN" },
47 	{ ETHERTYPE_WMX_M2M,              "WiMax Mac-to-Mac" },
48 	{ ETHERTYPE_EPL_V1,               "EPL_V1" },
49 	{ ETHERTYPE_REVARP,               "RARP" },
50 	{ ETHERTYPE_DEC_LB,               "DEC LanBridge" },
51 	{ ETHERTYPE_ATALK,                "AppleTalk LLAP bridging" },
52 	{ ETHERTYPE_SNA,                  "SNA-over-Ethernet" },
53 	{ ETHERTYPE_DLR,                  "EtherNet/IP Device Level Ring" },
54 	{ ETHERTYPE_AARP,                 "AARP" },
55 	{ ETHERTYPE_IPX,                  "Netware IPX/SPX" },
56 	{ ETHERTYPE_VINES_IP,             "Vines IP" },
57 	{ ETHERTYPE_VINES_ECHO,           "Vines Echo" },
58 	{ ETHERTYPE_TRAIN,                "Netmon Train" },
59 	/* Ethernet Loopback */
60 	{ ETHERTYPE_LOOP,                 "Loopback" },
61 	{ ETHERTYPE_FOUNDRY,              "Foundry proprietary" },
62 	{ ETHERTYPE_WCP,                  "Wellfleet Compression Protocol" },
63 	{ ETHERTYPE_STP,                  "Spanning Tree Protocol" },
64 	/* for ISMP, see RFC 2641, RFC 2642, RFC 2643 */
65 	{ ETHERTYPE_ISMP,                 "Cabletron Interswitch Message Protocol" },
66 	{ ETHERTYPE_ISMP_TBFLOOD,         "Cabletron SFVLAN 1.8 Tag-Based Flood" },
67 	/* In www.iana.org/assignments/ethernet-numbers, 8203-8205 description is
68 	 * Quantum Software.  Now the company is called QNX Software Systems. */
69 	{ ETHERTYPE_QNX_QNET6,            "QNX 6 QNET protocol" },
70 	{ ETHERTYPE_PPPOED,               "PPPoE Discovery" },
71 	{ ETHERTYPE_PPPOES,               "PPPoE Session" },
72 	{ ETHERTYPE_LINK_CTL,             "HomePNA, wlan link local tunnel" },
73 	{ ETHERTYPE_INTEL_ANS,            "Intel ANS probe" },
74 	{ ETHERTYPE_MS_NLB_HEARTBEAT,     "MS NLB heartbeat" },
75 	{ ETHERTYPE_JUMBO_LLC,            "Jumbo LLC" },
76 	{ ETHERTYPE_BRCM_TYPE,            "Broadcom tag" },
77 	{ ETHERTYPE_HOMEPLUG,             "Homeplug" },
78 	{ ETHERTYPE_HOMEPLUG_AV,          "Homeplug AV" },
79 	{ ETHERTYPE_MRP,                  "MRP" },
80 	{ ETHERTYPE_IEEE_802_1AD,         "802.1ad Provider Bridge (Q-in-Q)" },
81 	{ ETHERTYPE_MACSEC,               "802.1AE (MACsec)" },
82 	{ ETHERTYPE_IEEE_1905,            "1905.1a Convergent Digital Home Network for Heterogenous Technologies" },
83 	{ ETHERTYPE_IEEE_802_1AH,         "802.1ah Provider Backbone Bridge (mac-in-mac)" },
84 	{ ETHERTYPE_IEEE_802_1BR,         "802.1br Bridge Port Extension E-Tag" },
85 	{ ETHERTYPE_EAPOL,                "802.1X Authentication" },
86 	{ ETHERTYPE_RSN_PREAUTH,          "802.11i Pre-Authentication" },
87 	{ ETHERTYPE_MPLS,                 "MPLS label switched packet" },
88 	{ ETHERTYPE_MPLS_MULTI,           "MPLS multicast label switched packet" },
89 	{ ETHERTYPE_3C_NBP_DGRAM,         "3Com NBP Datagram" },
90 	{ ETHERTYPE_DEC,                  "DEC proto" },
91 	{ ETHERTYPE_DNA_DL,               "DEC DNA Dump/Load" },
92 	{ ETHERTYPE_DNA_RC,               "DEC DNA Remote Console" },
93 	{ ETHERTYPE_DNA_RT,               "DEC DNA Routing" },
94 	{ ETHERTYPE_LAT,                  "DEC LAT" },
95 	{ ETHERTYPE_DEC_DIAG,             "DEC Diagnostics" },
96 	{ ETHERTYPE_DEC_CUST,             "DEC Customer use" },
97 	{ ETHERTYPE_DEC_SCA,              "DEC LAVC/SCA" },
98 	{ ETHERTYPE_DEC_LAST,             "DEC LAST" },
99 	{ ETHERTYPE_ETHBRIDGE,            "Transparent Ethernet bridging" },
100 	{ ETHERTYPE_CGMP,                 "Cisco Group Management Protocol" },
101 	{ ETHERTYPE_GIGAMON,              "Gigamon Header" },
102 	{ ETHERTYPE_MSRP,                 "802.1Qat Multiple Stream Reservation Protocol" },
103 	{ ETHERTYPE_MMRP,                 "802.1ak Multiple Mac Registration Protocol" },
104 	{ ETHERTYPE_NSH,                  "Network Service Header" },
105 	{ ETHERTYPE_PA_HBBACKUP,          "PA HB Backup" },
106 	{ ETHERTYPE_AVTP,                 "IEEE 1722 Audio Video Transport Protocol" },
107 	{ ETHERTYPE_ROHC,                 "Robust Header Compression(RoHC)" },
108 	{ ETHERTYPE_TRILL,                "Transparent Interconnection of Lots of Links" },
109 	{ ETHERTYPE_L2ISIS,               "Intermediate System to Intermediate System" },
110 	{ ETHERTYPE_MAC_CONTROL,          "MAC Control" },
111 	{ ETHERTYPE_SLOW_PROTOCOLS,       "Slow Protocols" },
112 	{ ETHERTYPE_RTMAC,                "Real-Time Media Access Control" },
113 	{ ETHERTYPE_RTCFG,                "Real-Time Configuration Protocol" },
114 	{ ETHERTYPE_CDMA2000_A10_UBS,     "CDMA2000 A10 Unstructured byte stream" },
115 	{ ETHERTYPE_ATMOE,                "ATM over Ethernet" },
116 	{ ETHERTYPE_PROFINET,             "PROFINET" },
117 	{ ETHERTYPE_REALTEK,              "Realtek Layer 2 Protocols" },
118 	{ ETHERTYPE_AOE,                  "ATA over Ethernet" },
119 	{ ETHERTYPE_ECATF,                "EtherCAT frame" },
120 	{ ETHERTYPE_TELKONET,             "Telkonet powerline" },
121 	{ ETHERTYPE_EPL_V2,               "ETHERNET Powerlink v2" },
122 	{ ETHERTYPE_XIMETA,               "XiMeta Technology" },
123 	{ ETHERTYPE_CSM_ENCAPS,           "CSM_ENCAPS Protocol" },
124 	{ ETHERTYPE_EXPERIMENTAL_ETH1,    "Local Experimental Ethertype 1" },
125 	{ ETHERTYPE_EXPERIMENTAL_ETH2,    "Local Experimental Ethertype 2" },
126 	{ ETHERTYPE_IEEE802_OUI_EXTENDED, "IEEE 802a OUI Extended Ethertype" },
127 	{ ETHERTYPE_IEC61850_GOOSE,       "IEC 61850/GOOSE" },
128 	{ ETHERTYPE_IEC61850_GSE,         "IEC 61850/GSE management services" },
129 	{ ETHERTYPE_IEC61850_SV,          "IEC 61850/SV (Sampled Value Transmission" },
130 	{ ETHERTYPE_TIPC,                 "Transparent Inter Process Communication" },
131 	{ ETHERTYPE_LLDP,                 "802.1 Link Layer Discovery Protocol (LLDP)" },
132 	{ ETHERTYPE_3GPP2,                "CDMA2000 A10 3GPP2 Packet" },
133 	{ ETHERTYPE_TTE_PCF,              "TTEthernet Protocol Control Frame" },
134 	{ ETHERTYPE_CESOETH,              "Circuit Emulation Services over Ethernet (MEF8)" },
135 	{ ETHERTYPE_LLTD,                 "Link Layer Topology Discovery (LLTD)" },
136 	{ ETHERTYPE_WSMP,                 "(WAVE) Short Message Protocol (WSM)" },
137 	{ ETHERTYPE_VMLAB,                "VMware Lab Manager" },
138 	{ ETHERTYPE_COBRANET,             "Cirrus Cobranet Packet" },
139 	{ ETHERTYPE_NSRP,                 "Juniper Netscreen Redundant Protocol" },
140 	{ ETHERTYPE_EERO,                 "EERO Broadcast Packet" },
141 	/*
142 	 * NDISWAN on Windows translates Ethernet frames from higher-level
143 	 * protocols into PPP frames to hand to the PPP driver, and translates
144 	 * PPP frames from the PPP driver to hand to the higher-level protocols.
145 	 *
146 	 * Apparently the PPP driver, on at least some versions of Windows,
147 	 * passes frames for internal-to-PPP protocols up through NDISWAN;
148 	 * the protocol type field appears to be passed through unchanged
149 	 * (unlike what's done with, for example, the protocol type field
150 	 * for IP, which is mapped from its PPP value to its Ethernet value).
151 	 *
152 	 * This means that we may see, on Ethernet captures, frames for
153 	 * protocols internal to PPP, so we list as "Ethernet" protocol
154 	 * types the PPP protocol types we've seen.
155 	 */
156 	{ PPP_IPCP,                       "PPP IP Control Protocol" },
157 	{ PPP_LCP,                        "PPP Link Control Protocol" },
158 	{ PPP_PAP,                        "PPP Password Authentication Protocol" },
159 	{ PPP_CCP,                        "PPP Compression Control Protocol" },
160 	{ ETHERTYPE_LLT,                  "Veritas Low Latency Transport (not officially registered)" },
161 	{ ETHERTYPE_CFM,                  "IEEE 802.1ag Connectivity Fault Management (CFM) protocol" },
162 	{ ETHERTYPE_DCE,                  "Data Center Ethernet (DCE) protocol(Cisco)" },
163 	{ ETHERTYPE_FCOE,                 "Fibre Channel over Ethernet" },
164 	{ ETHERTYPE_IEEE80211_DATA_ENCAP, "IEEE 802.11 data encapsulation" },
165 	{ ETHERTYPE_LINX,                 "LINX IPC Protocol" },
166 	{ ETHERTYPE_FIP,                  "FCoE Initialization Protocol" },
167 	{ ETHERTYPE_MIH,                  "Media Independent Handover Protocol" },
168 	{ ETHERTYPE_ELMI,                 "Ethernet Local Management Interface (MEF16)" },
169 	{ ETHERTYPE_PTP,                  "PTPv2 over Ethernet (IEEE1588)" },
170 	{ ETHERTYPE_NCSI,                 "Network Controller Sideband Interface" },
171 	{ ETHERTYPE_PRP,                  "Parallel Redundancy Protocol (PRP) and HSR Supervision (IEC62439 Part 3)" },
172 	{ ETHERTYPE_FLIP,                 "Flow Layer Internal Protocol" },
173 	{ ETHERTYPE_ROCE,                 "RDMA over Converged Ethernet" },
174 	{ ETHERTYPE_TDMOE,                "Digium TDM over Ethernet Protocol" },
175 	{ ETHERTYPE_WAI,                  "WAI Authentication Protocol" },
176 	{ ETHERTYPE_VNTAG,                "VN-Tag" },
177 	{ ETHERTYPE_SEL_L2,               "Schweitzer Engineering Labs Layer 2 Protocol" },
178 	{ ETHERTYPE_HSR,                  "High-availability Seamless Redundancy (IEC62439 Part 3)" },
179 	{ ETHERTYPE_BPQ,                  "AX.25" },
180 	{ ETHERTYPE_CMD,                  "CiscoMetaData" },
181 	{ ETHERTYPE_GEONETWORKING,        "GeoNetworking" },
182 	{ ETHERTYPE_XIP,                  "eXpressive Internet Protocol" },
183 	{ ETHERTYPE_NWP,                  "Neighborhood Watch Protocol" },
184 	{ ETHERTYPE_BLUECOM,              "bluecom Protocol" },
185 	{ ETHERTYPE_QINQ_OLD,             "QinQ: old non-standard 802.1ad" },
186 	{ ETHERTYPE_TECMP,                "Technically Enhanced Capture Module Protocol (TECMP)" },
187 	{ ETHERTYPE_6LOWPAN,              "6LoWPAN" },
188 	{ ETHERTYPE_AVSP,                 "Arista Timestamp" },
189 	{ ETHERTYPE_ECPRI,                "eCPRI" },
190 	{ ETHERTYPE_CABLELABS,            "CableLabs Layer-3 Protocol" },
191 	{ ETHERTYPE_EXEH,                 "EXos internal Extra Header" },
192 	{ ETHERTYPE_ACIGLEAN,             "Cisco ACI ARP gleaning" },
193 	{ ETHERTYPE_IEEE_802_1CB,         "802.1CB Frame Replication and Elimination for Reliability" },
194 	{ 0, NULL }
195 };
196 
eth_prompt(packet_info * pinfo,gchar * result)197 static void eth_prompt(packet_info *pinfo, gchar* result)
198 {
199 	g_snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "Ethertype 0x%04x as",
200 		GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_ethertype, pinfo->curr_layer_num)));
201 }
202 
eth_value(packet_info * pinfo)203 static gpointer eth_value(packet_info *pinfo)
204 {
205 	return p_get_proto_data(pinfo->pool, pinfo, proto_ethertype, pinfo->curr_layer_num);
206 }
207 
208 static void add_dix_trailer(packet_info *pinfo, proto_tree *tree, proto_tree *fh_tree,
209 			    int trailer_id, tvbuff_t *tvb, tvbuff_t *next_tvb, int offset_after_etype,
210 			    guint length_before, gint fcs_len);
211 
212 /*
213 void
214 ethertype(guint16 etype, tvbuff_t *tvb, int offset_after_etype,
215 	  packet_info *pinfo, proto_tree *tree, proto_tree *fh_tree,
216 	  int etype_id, int trailer_id, int fcs_len)
217 */
218 static int
dissect_ethertype(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)219 dissect_ethertype(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
220 {
221 	const char	  *description;
222 	tvbuff_t	  *volatile next_tvb;
223 	guint		   length_before;
224 	gint		   captured_length, reported_length;
225 	volatile int	   dissector_found = 0;
226 	const char	  *volatile saved_proto;
227 	ethertype_data_t  *ethertype_data;
228 
229 	/* Reject the packet if data is NULL */
230 	if (data == NULL)
231 		return 0;
232 	ethertype_data = (ethertype_data_t*)data;
233 
234 	/* Get the captured length and reported length of the data
235 	   after the Ethernet type. */
236 	captured_length = tvb_captured_length_remaining(tvb, ethertype_data->payload_offset);
237 	reported_length = tvb_reported_length_remaining(tvb,
238 							ethertype_data->payload_offset);
239 
240 	/* With Cisco ACI gleaning, the rest of the packet is dissected for informational purposes only */
241 	if (ethertype_data->etype == ETHERTYPE_ACIGLEAN) {
242 
243 		guint gleantype, payload_etype;
244 
245 		col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "0x%04x", ethertype_data->etype);
246 		col_set_writable(pinfo->cinfo, COL_PROTOCOL, FALSE);
247 
248 		description = try_val_to_str(ethertype_data->etype, etype_vals);
249 		col_add_str(pinfo->cinfo, COL_INFO, description);
250 		col_set_writable(pinfo->cinfo, COL_INFO, FALSE);
251 		if (reported_length >= 1) {
252 			gleantype = (tvb_get_guint8(tvb, ethertype_data->payload_offset) & 0xF0) >> 4;
253 			switch (gleantype) {
254 			case 4: /* IPv4 */
255 				payload_etype = 0x0800;
256 				break;
257 			case 6: /* IPv6 */
258 				payload_etype = 0x86BB;
259 				break;
260 			default: /* ARP */
261 				payload_etype = 0x0806;
262 			}
263 			ethertype_data->etype = payload_etype;
264 		// FIXME: Add glean to protocol-stack in frame-header
265 		}
266 	}
267 
268 	/* Remember how much data there is after the Ethernet type,
269 	   including any trailer and FCS. */
270 	length_before = reported_length;
271 
272 	/* Construct a tvbuff for the payload after the Ethernet type.
273 	   If the FCS length is positive, remove the FCS.
274 	   (If it's zero, there's no FCS; if it's negative,
275 	   we don't know whether there's an FCS, so we'll
276 	   guess based on the length of the trailer.) */
277 	if (ethertype_data->fcs_len > 0) {
278 		if (captured_length >= 0 && reported_length >= 0) {
279 			if (reported_length >= ethertype_data->fcs_len)
280 				reported_length -= ethertype_data->fcs_len;
281 			if (captured_length > reported_length)
282 				captured_length = reported_length;
283 		}
284 	}
285 	next_tvb = tvb_new_subset_length_caplen(tvb, ethertype_data->payload_offset, captured_length,
286 				  reported_length);
287 
288 	p_add_proto_data(pinfo->pool, pinfo, proto_ethertype, pinfo->curr_layer_num, GUINT_TO_POINTER((guint)ethertype_data->etype));
289 
290 	/* Look for sub-dissector, and call it if found.
291 	   Catch exceptions, so that if the reported length of "next_tvb"
292 	   was reduced by some dissector before an exception was thrown,
293 	   we can still put in an item for the trailer. */
294 	saved_proto = pinfo->current_proto;
295 	TRY {
296 		dissector_found = dissector_try_uint(ethertype_dissector_table,
297 						     ethertype_data->etype, next_tvb, pinfo, tree);
298 	}
299 	CATCH_NONFATAL_ERRORS {
300 		/* Somebody threw an exception that means that there
301 		   was a problem dissecting the payload; that means
302 		   that a dissector was found, so we don't need to
303 		   dissect the payload as data or update the protocol
304 		   or info columns.
305 
306 		   Just show the exception and then drive on to show
307 		   the trailer, after noting that a dissector was found
308 		   and restoring the protocol value that was in effect
309 		   before we called the subdissector. */
310 		show_exception(next_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
311 
312 		dissector_found = 1;
313 		pinfo->current_proto = saved_proto;
314 	}
315 	ENDTRY;
316 
317 	if (!dissector_found) {
318 		/* No sub-dissector found.
319 		   Label rest of packet as "Data" */
320 		call_data_dissector(next_tvb, pinfo, tree);
321 
322 		/* Label protocol */
323 		col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "0x%04x", ethertype_data->etype);
324 
325 		description = try_val_to_str(ethertype_data->etype, etype_vals);
326 		if (description) {
327 			col_add_str(pinfo->cinfo, COL_INFO, description);
328 		}
329 	}
330 
331 	add_dix_trailer(pinfo, tree, ethertype_data->fh_tree, ethertype_data->trailer_id, tvb, next_tvb, ethertype_data->payload_offset,
332 			length_before, ethertype_data->fcs_len);
333 
334 	return tvb_captured_length(tvb);
335 }
336 
337 static void
add_dix_trailer(packet_info * pinfo,proto_tree * tree,proto_tree * fh_tree,int trailer_id,tvbuff_t * tvb,tvbuff_t * next_tvb,int offset_after_etype,guint length_before,gint fcs_len)338 add_dix_trailer(packet_info *pinfo, proto_tree *tree, proto_tree *fh_tree, int trailer_id,
339 		tvbuff_t *tvb, tvbuff_t *next_tvb, int offset_after_etype,
340 		guint length_before, gint fcs_len)
341 {
342 	guint		 length;
343 	tvbuff_t	*trailer_tvb;
344 
345 	/* OK, how much is there in that tvbuff now? */
346 	length = tvb_reported_length(next_tvb);
347 
348 	/* If there's less than there was before, what's left is
349 	   a trailer. */
350 	if (length < length_before) {
351 		/*
352 		 * Is any of the padding present in the tvbuff?
353 		 */
354 		if (tvb_offset_exists(tvb, offset_after_etype + length)) {
355 			/*
356 			 * Yes - create a tvbuff for the padding.
357 			 */
358 			trailer_tvb = tvb_new_subset_remaining(tvb,
359 							       offset_after_etype + length);
360 		} else {
361 			/*
362 			 * No - don't bother showing the trailer.
363 			 * XXX - show a Short Frame indication?
364 			 */
365 			trailer_tvb = NULL;
366 		}
367 	} else
368 		trailer_tvb = NULL;	/* no trailer */
369 
370 	add_ethernet_trailer(pinfo, tree, fh_tree, trailer_id, tvb, trailer_tvb, fcs_len);
371 }
372 
373 void
proto_register_ethertype(void)374 proto_register_ethertype(void)
375 {
376 	/* Decode As handling */
377 	static build_valid_func eth_da_build_value[1] = {eth_value};
378 	static decode_as_value_t eth_da_values = {eth_prompt, 1, eth_da_build_value};
379 	static decode_as_t ethertype_da = {"ethertype", "ethertype", 1, 0, &eth_da_values, NULL, NULL,
380 										decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL};
381 
382 
383 	proto_ethertype = proto_register_protocol("Ethertype", "Ethertype", "ethertype");
384 	/* This isn't a real protocol, so you can't disable its dissection. */
385 	proto_set_cant_toggle(proto_ethertype);
386 
387 	register_dissector("ethertype", dissect_ethertype, proto_ethertype);
388 
389 	/* subdissector code */
390 	ethertype_dissector_table = register_dissector_table("ethertype",
391 								"Ethertype", proto_ethertype, FT_UINT16, BASE_HEX);
392 	register_capture_dissector_table("ethertype", "Ethertype");
393 
394 	register_decode_as(&ethertype_da);
395 }
396 
397 /*
398  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
399  *
400  * Local variables:
401  * c-basic-offset: 8
402  * tab-width: 8
403  * indent-tabs-mode: t
404  * End:
405  *
406  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
407  * :indentSize=8:tabSize=8:noTabs=false:
408  */
409