2 * Routines for Multicast Source Discovery Protocol (MSDP) dissection.
5 * Copyright 2001, Heikki Vatiainen <hessu@cs.tut.fi>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
16 #include <epan/packet.h>
17 #include <epan/to_str.h>
18 #include <epan/expert.h>
20 void proto_register_msdp(void);
21 void proto_reg_handoff_msdp(void);
23 /* MSDP (Type-Length-Value) TLV types. The messages are a sequence of TLVs. */
28 MSDP_NOTIFICATION
, /* draft 10, but not RFC 3618 */
30 /* These are only assigned in MSDP spec. Their use is specified
32 MSDP_TRACE_IN_PROGRESS
,
36 static const value_string msdp_types
[] = {
37 { MSDP_SA
, "IPv4 Source-Active" },
38 { MSDP_SA_REQ
, "IPv4 Source-Active Request" },
39 { MSDP_SA_RSP
, "IPv4 Source-Active Response" },
40 { MSDP_KEEP_ALIVE
, "KeepAlive" },
41 { MSDP_NOTIFICATION
, "Notification" },
43 { MSDP_TRACE_IN_PROGRESS
, "MSDP traceroute in progress" },
44 { MSDP_TRACE_REPLY
, "MSDP traceroute reply" },
50 enum { MESSAGE_HEADER_ERROR
= 1,
52 SA_MESSAGE_SA_RESPONSE_ERROR
,
59 static const value_string error_vals
[] = {
60 { MESSAGE_HEADER_ERROR
, "Message Header Error" },
61 { SA_REQUEST_ERROR
, "SA-Request Error" },
62 { SA_MESSAGE_SA_RESPONSE_ERROR
, "SA-Message/SA-Response Error" },
63 { HOLD_TIMER_EXPIRED
, "Hold Timer Expired" },
64 { FSM_ERROR
, "Finite State Machine Error" },
65 { NOTIFICATION
, "Notification" },
71 /* Message Header Error subcodes */
72 static const value_string hdr_error_vals
[] = {
74 { 2, "Bad Message Length" },
75 { 3, "Bad Message Type" },
79 /* SA-Request Error subcodes (the O-bit is always clear) */
80 static const value_string sa_req_error_vals
[] = {
82 { 1, "Invalid Group" },
86 /* SA-Message/SA-Response Error subcodes */
87 static const value_string sa_msg_error_vals
[] = {
89 { 1, "Invalid Entry Count" },
90 { 2, "Invalid RP Address" },
91 { 3, "Invalid Group Address" },
92 { 4, "Invalid Source Address" },
93 { 5, "Invalid Sprefix Length" },
94 { 6, "Looping SA (Self is RP)" },
95 { 7, "Unknown Encapsulation" },
96 { 8, "Administrative Scope Boundary Violated" },
100 /* Finite State Machine Error subcodes (the O-bit is always clear) */
101 static const value_string fsm_error_vals
[] = {
103 { 1, "Unexpected Message Type FSM Error" },
108 * Hold Timer Expired subcodes (the O-bit is always clear):
109 * Notification subcodes (the O-bit is always clear):
110 * Cease subcodes (the O-bit is always clear):
112 * These have only "Unspecific" specified.
114 static const value_string sa_unspec_error_vals
[] = {
119 #define MSDP_PORT 639
121 /* Initialize the protocol and registered fields */
122 static int proto_msdp
;
123 static int hf_msdp_type
;
124 static int hf_msdp_length
;
126 static int hf_msdp_sa_entry_count
;
127 static int hf_msdp_sa_rp_addr
;
128 static int hf_msdp_sa_reserved
;
129 static int hf_msdp_sa_sprefix_len
;
130 static int hf_msdp_sa_group_addr
;
131 static int hf_msdp_sa_src_addr
;
133 static int hf_msdp_sa_req_res
;
134 static int hf_msdp_sa_req_group
;
136 static int hf_msdp_not_o
;
137 static int hf_msdp_not_error
;
138 static int hf_msdp_not_error_sub
;
140 static int hf_msdp_not_group_address
;
141 static int hf_msdp_not_rp_address
;
142 static int hf_msdp_not_source_address
;
143 static int hf_msdp_not_res
;
144 static int hf_msdp_not_entry_count
;
145 static int hf_msdp_not_sprefix_len
;
147 static int hf_msdp_tlv_contents
;
148 static int hf_msdp_trailing_junk
;
149 static int hf_msdp_unknown_data
;
152 static int ett_msdp_sa_entry
;
153 static int ett_msdp_sa_enc_data
;
154 static int ett_msdp_not_data
;
156 static expert_field ei_msdp_tlv_len_too_short
;
157 static expert_field ei_msdp_tlv_len_too_long
;
159 static dissector_handle_t msdp_handle
;
160 static dissector_handle_t ip_handle
;
164 dissect_msdp_sa(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
165 int *offset
, int length
, proto_item
*length_item
);
167 dissect_msdp_notification(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
168 int *offset
, uint16_t tlv_len
, proto_item
*length_item
);
172 // NOLINTNEXTLINE(misc-no-recursion)
173 dissect_msdp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
176 proto_tree
*msdp_tree
;
177 proto_item
*length_item
;
183 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "MSDP");
185 col_set_str(pinfo
->cinfo
, COL_INFO
, val_to_str_const(tvb_get_uint8(tvb
, 0),
187 "<Unknown MSDP TLV type>"));
189 ti
= proto_tree_add_item(tree
, proto_msdp
, tvb
, 0, -1, ENC_NA
);
190 msdp_tree
= proto_item_add_subtree(ti
, ett_msdp
);
193 increment_dissection_depth(pinfo
);
194 while (tvb_reported_length_remaining(tvb
, offset
) != 0) {
195 proto_tree_add_item_ret_uint(msdp_tree
, hf_msdp_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &type
);
196 length_item
= proto_tree_add_item_ret_uint(msdp_tree
, hf_msdp_length
, tvb
, offset
+ 1, 2, ENC_BIG_ENDIAN
, &length
);
198 expert_add_info_format(pinfo
, length_item
,
199 &ei_msdp_tlv_len_too_short
,
208 dissect_msdp_sa(tvb
, pinfo
, msdp_tree
, &offset
,
209 length
, length_item
);
213 * This type is mentioned in the RFC but the format
217 expert_add_info_format(pinfo
, length_item
,
218 &ei_msdp_tlv_len_too_short
,
219 "TLV length for IPv4 Source-Active Request < 8");
222 proto_tree_add_item(msdp_tree
, hf_msdp_sa_req_res
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
226 expert_add_info_format(pinfo
, length_item
,
227 &ei_msdp_tlv_len_too_short
,
228 "TLV length for IPv4 Source-Active Request < 8");
232 proto_tree_add_item(msdp_tree
, hf_msdp_sa_req_group
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
236 expert_add_info_format(pinfo
, length_item
,
237 &ei_msdp_tlv_len_too_long
,
238 "TLV length for KeepAlive > 8");
239 proto_tree_add_item(tree
, hf_msdp_trailing_junk
, tvb
, offset
, length
, ENC_NA
);
245 * This type is mentioned in the RFC but the format
248 dissect_msdp_sa(tvb
, pinfo
, msdp_tree
, &offset
,
249 length
, length_item
);
251 case MSDP_KEEP_ALIVE
:
253 expert_add_info_format(pinfo
, length_item
,
254 &ei_msdp_tlv_len_too_long
,
255 "TLV length for KeepAlive > 3");
256 proto_tree_add_item(tree
, hf_msdp_trailing_junk
, tvb
, offset
, length
, ENC_NA
);
260 case MSDP_NOTIFICATION
:
262 * This was in draft 10, but is reserved in the
265 dissect_msdp_notification(tvb
, pinfo
, msdp_tree
, &offset
, length
, length_item
);
269 proto_tree_add_item(msdp_tree
, hf_msdp_tlv_contents
, tvb
, offset
, length
, ENC_NA
);
274 decrement_dissection_depth(pinfo
);
276 return tvb_captured_length(tvb
);
279 /* Both Source-Active and Source-Active Response have the same format
280 * with one exception. Encapsulated multicast data is not allowed in
283 static void dissect_msdp_sa(tvbuff_t
*tvb
, packet_info
*pinfo
,
284 proto_tree
*tree
, int *offset
, int length
, proto_item
*length_item
)
289 expert_add_info_format(pinfo
, length_item
,
290 &ei_msdp_tlv_len_too_short
,
291 "TLV length for IPv4 Source-Active or Source-Active Response < 5");
294 proto_tree_add_item_ret_uint(tree
, hf_msdp_sa_entry_count
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
, &entries
);
299 expert_add_info_format(pinfo
, length_item
,
300 &ei_msdp_tlv_len_too_short
,
301 "TLV length for IPv4 Source-Active or Source-Active Response < 5");
305 proto_tree_add_item(tree
, hf_msdp_sa_rp_addr
, tvb
, *offset
, 4, ENC_BIG_ENDIAN
);
309 /* Put each of the (S,G) entries in their own subtree.
310 * This is probably visually better.
312 while (entries
-- > 0) {
313 proto_tree
*entry_tree
;
316 expert_add_info_format(pinfo
, length_item
,
317 &ei_msdp_tlv_len_too_short
,
318 "TLV length for IPv4 Source-Active or Source-Active Response too short");
322 entry_tree
= proto_tree_add_subtree_format(tree
, tvb
, *offset
, 12, ett_msdp_sa_entry
, NULL
,
323 "(S,G) block: %s/%u -> %s",
324 tvb_ip_to_str(pinfo
->pool
, tvb
, *offset
+ 8),
325 tvb_get_uint8(tvb
, *offset
+ 3),
326 tvb_ip_to_str(pinfo
->pool
, tvb
, *offset
+ 4));
328 proto_tree_add_item(entry_tree
, hf_msdp_sa_reserved
, tvb
, *offset
, 3, ENC_BIG_ENDIAN
);
331 proto_tree_add_item(entry_tree
, hf_msdp_sa_sprefix_len
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
334 proto_tree_add_item(entry_tree
, hf_msdp_sa_group_addr
, tvb
, *offset
, 4, ENC_BIG_ENDIAN
);
337 proto_tree_add_item(entry_tree
, hf_msdp_sa_src_addr
, tvb
, *offset
, 4, ENC_BIG_ENDIAN
);
343 * Check if an encapsulated multicast IPv4 packet follows
346 proto_tree
*enc_tree
;
350 enc_tree
= proto_tree_add_subtree_format(tree
, tvb
, *offset
, length
,
351 ett_msdp_sa_enc_data
, NULL
, "Encapsulated IPv4 packet: %u bytes",
354 reported_length
= tvb_reported_length_remaining(tvb
, *offset
);
355 DISSECTOR_ASSERT(reported_length
>= 0);
356 if (reported_length
> length
)
357 reported_length
= length
;
359 next_tvb
= tvb_new_subset_length(tvb
, *offset
, reported_length
);
360 /* Set the protocol and information columns read-only so
361 * that they reflect the MSDP packet rather than the
362 * encapsulated packet.
364 col_set_writable(pinfo
->cinfo
, COL_PROTOCOL
, false);
365 col_set_writable(pinfo
->cinfo
, COL_INFO
, false);
366 call_dissector(ip_handle
, next_tvb
, pinfo
, enc_tree
);
373 /* Note: updates *offset */
374 static void add_notification_data_ipv4addr(tvbuff_t
*tvb
, proto_tree
*tree
, int *offset
, int hf_addr
)
376 proto_tree_add_item(tree
, hf_msdp_not_res
, tvb
, *offset
, 3, ENC_BIG_ENDIAN
);
378 proto_tree_add_item(tree
, hf_addr
, tvb
, *offset
, 4, ENC_BIG_ENDIAN
);
384 // NOLINTNEXTLINE(misc-no-recursion)
385 static void dissect_msdp_notification(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int *offset
, uint16_t tlv_len
, proto_item
*length_item
)
387 uint8_t error
, error_sub
;
388 const value_string
*vals
;
393 expert_add_info_format(pinfo
, length_item
,
394 &ei_msdp_tlv_len_too_short
,
395 "TLV length for Notification < 4");
398 proto_tree_add_item(tree
, hf_msdp_not_o
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
399 proto_tree_add_item(tree
, hf_msdp_not_error
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
400 error
= tvb_get_uint8(tvb
, *offset
);
401 error
&= 0x7F; /* Error is 7-bit field. O-bit is bit 8 */
405 /* Depending on the Error Code, we collect the correct
406 * value_strings for the Error subcode
409 case MESSAGE_HEADER_ERROR
:
410 vals
= hdr_error_vals
;
412 case SA_REQUEST_ERROR
:
413 vals
= sa_req_error_vals
;
415 case SA_MESSAGE_SA_RESPONSE_ERROR
:
416 vals
= sa_msg_error_vals
;
419 vals
= fsm_error_vals
;
421 case HOLD_TIMER_EXPIRED
:
424 vals
= sa_unspec_error_vals
;
427 vals
= sa_unspec_error_vals
;
432 expert_add_info_format(pinfo
, length_item
,
433 &ei_msdp_tlv_len_too_short
,
434 "TLV length for Notification < 5");
437 error_sub
= tvb_get_uint8(tvb
, *offset
);
438 proto_tree_add_uint_format_value(tree
, hf_msdp_not_error_sub
, tvb
, *offset
, 1,
439 error_sub
, "%s (%u)",
440 val_to_str_const(error_sub
, vals
, "<Unknown Error subcode>"),
445 /* Do switch again, this time to dissect the data portion
449 case SA_REQUEST_ERROR
:
451 expert_add_info_format(pinfo
, length_item
,
452 &ei_msdp_tlv_len_too_short
,
453 "TLV length for Notification SA-Request Error < 12");
457 add_notification_data_ipv4addr(tvb
, tree
, offset
, hf_msdp_not_group_address
);
460 case SA_MESSAGE_SA_RESPONSE_ERROR
:
461 if (error_sub
== 0) {
463 } else if (error_sub
== 1) {
465 expert_add_info_format(pinfo
, length_item
,
466 &ei_msdp_tlv_len_too_short
,
467 "TLV length for Notification SA-Response Invalid Entry Count Error < 6");
470 proto_tree_add_item(tree
, hf_msdp_not_entry_count
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
474 } else if (error_sub
== 2) {
476 expert_add_info_format(pinfo
, length_item
,
477 &ei_msdp_tlv_len_too_short
,
478 "TLV length for Notification SA-Response Invalid RP Address Error < 12");
482 add_notification_data_ipv4addr(tvb
, tree
, offset
, hf_msdp_not_rp_address
);
485 } else if (error_sub
== 3 || error_sub
== 8) {
487 expert_add_info_format(pinfo
, length_item
,
488 &ei_msdp_tlv_len_too_short
,
489 "TLV length for Notification SA-Response %s Error < 12",
490 (error_sub
== 3) ? "Invalid Group Address"
491 : "Administrative Scope Boundary Violated");
495 add_notification_data_ipv4addr(tvb
, tree
, offset
, hf_msdp_not_group_address
);
498 } else if (error_sub
== 4) {
500 expert_add_info_format(pinfo
, length_item
,
501 &ei_msdp_tlv_len_too_short
,
502 "TLV length for Notification SA-Response Invalid Source Address Error < 12");
506 add_notification_data_ipv4addr(tvb
, tree
, offset
, hf_msdp_not_source_address
);
509 } else if (error_sub
== 5) {
511 expert_add_info_format(pinfo
, length_item
,
512 &ei_msdp_tlv_len_too_short
,
513 "TLV length for Notification SA-Response Invalid Sprefix Length Error < 6");
516 proto_tree_add_item(tree
, hf_msdp_not_sprefix_len
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
520 } else if (error_sub
== 6) {
522 reported_length
= tvb_reported_length_remaining(tvb
, *offset
);
523 DISSECTOR_ASSERT(reported_length
>= 0);
524 if (reported_length
> tlv_len
)
525 reported_length
= tlv_len
;
526 next_tvb
= tvb_new_subset_length(tvb
, *offset
, reported_length
);
527 dissect_msdp(next_tvb
, pinfo
, tree
, NULL
);
531 } else if (error_sub
== 7) {
533 reported_length
= tvb_reported_length_remaining(tvb
, *offset
);
534 DISSECTOR_ASSERT(reported_length
>= 0);
535 if (reported_length
> tlv_len
)
536 reported_length
= tlv_len
;
537 next_tvb
= tvb_new_subset_length(tvb
, *offset
, reported_length
);
538 dissect_msdp(next_tvb
, pinfo
, tree
, NULL
);
545 proto_tree_add_item(tree
, hf_msdp_unknown_data
, tvb
, *offset
, tlv_len
, ENC_NA
);
551 case MESSAGE_HEADER_ERROR
:
553 /* Data contains the message that had an error. Even a
554 * broken Notification message causes a Notification
555 * message with Error Code set to Notification to be
559 reported_length
= tvb_reported_length_remaining(tvb
, *offset
);
560 DISSECTOR_ASSERT(reported_length
>= 0);
561 if (reported_length
> tlv_len
)
562 reported_length
= tlv_len
;
563 next_tvb
= tvb_new_subset_length(tvb
, *offset
, reported_length
);
564 dissect_msdp(next_tvb
, pinfo
, tree
, NULL
);
570 case HOLD_TIMER_EXPIRED
:
572 /* Do nothing. These contain no data */
576 proto_tree_add_item(tree
, hf_msdp_unknown_data
, tvb
, *offset
, tlv_len
, ENC_NA
);
582 expert_add_info_format(pinfo
, length_item
,
583 &ei_msdp_tlv_len_too_long
,
584 "TLV length too long");
585 proto_tree_add_item(tree
, hf_msdp_trailing_junk
, tvb
, *offset
, tlv_len
, ENC_NA
);
593 proto_register_msdp(void)
595 static hf_register_info hf
[] = {
597 { "Type", "msdp.type",
598 FT_UINT8
, BASE_DEC
, VALS(msdp_types
), 0,
599 "MSDP TLV type", HFILL
}
602 { "Length", "msdp.length",
603 FT_UINT16
, BASE_DEC
, NULL
, 0,
604 "MSDP TLV Length", HFILL
}
606 { &hf_msdp_sa_entry_count
,
607 { "Entry Count", "msdp.sa.entry_count",
608 FT_UINT8
, BASE_DEC
, NULL
, 0,
609 "MSDP SA Entry Count", HFILL
}
611 { &hf_msdp_sa_rp_addr
,
612 { "RP Address", "msdp.sa.rp_addr",
613 FT_IPv4
, BASE_NONE
, NULL
, 0,
614 "Active source's RP address", HFILL
}
616 { &hf_msdp_sa_reserved
,
617 { "Reserved", "msdp.sa.reserved",
618 FT_UINT24
, BASE_HEX
, NULL
, 0,
619 "Transmitted as zeros and ignored by a receiver", HFILL
}
621 { &hf_msdp_sa_sprefix_len
,
622 { "Sprefix len", "msdp.sa.sprefix_len",
623 FT_UINT8
, BASE_DEC
, NULL
, 0,
624 "The route prefix length associated with source address", HFILL
}
626 { &hf_msdp_sa_group_addr
,
627 { "Group Address", "msdp.sa.group_addr",
628 FT_IPv4
, BASE_NONE
, NULL
, 0,
629 "The group address the active source has sent data to", HFILL
}
631 { &hf_msdp_sa_src_addr
,
632 { "Source Address", "msdp.sa.src_addr",
633 FT_IPv4
, BASE_NONE
, NULL
, 0,
634 "The IP address of the active source", HFILL
}
636 { &hf_msdp_sa_req_res
,
637 { "Reserved", "msdp.sa_req.res",
638 FT_UINT8
, BASE_HEX
, NULL
, 0,
639 "Transmitted as zeros and ignored by a receiver", HFILL
}
641 { &hf_msdp_sa_req_group
,
642 { "Group Address", "msdp.sa_req.group_addr",
643 FT_IPv4
, BASE_NONE
, NULL
, 0,
644 "The group address the MSDP peer is requesting", HFILL
}
647 { "Open-bit", "msdp.not.o",
648 FT_UINT8
, BASE_HEX
, NULL
, 0x80,
649 "If clear, the connection will be closed", HFILL
}
651 { &hf_msdp_not_error
,
652 { "Error Code", "msdp.not.error",
653 FT_UINT8
, BASE_DEC
, VALS(error_vals
), 0x7F,
654 "Indicates the type of Notification", HFILL
}
656 { &hf_msdp_not_error_sub
,
657 { "Error subcode", "msdp.not.error_sub",
658 FT_UINT8
, BASE_DEC
, NULL
, 0,
661 { &hf_msdp_not_group_address
,
662 { "Group address", "msdp.not.group_address",
663 FT_IPv4
, BASE_NONE
, NULL
, 0,
664 "Group address in Notification messages", HFILL
}
666 { &hf_msdp_not_rp_address
,
667 { "RP address", "msdp.not.rp_address",
668 FT_IPv4
, BASE_NONE
, NULL
, 0,
669 "RP address in Notification messages", HFILL
}
671 { &hf_msdp_not_source_address
,
672 { "Source address", "msdp.not.source_address",
673 FT_IPv4
, BASE_NONE
, NULL
, 0,
674 "Source address in Notification messages", HFILL
}
677 { "Reserved", "msdp.not.res",
678 FT_UINT24
, BASE_HEX
, NULL
, 0,
679 "Reserved field in Notification messages", HFILL
}
681 { &hf_msdp_not_entry_count
,
682 { "Entry Count", "msdp.not.entry_count",
683 FT_UINT24
, BASE_HEX
, NULL
, 0,
684 "Entry Count in Notification messages", HFILL
}
686 { &hf_msdp_not_sprefix_len
,
687 { "Sprefix len", "msdp.not.sprefix_len",
688 FT_UINT8
, BASE_DEC
, NULL
, 0,
689 "Source prefix length in Notification messages", HFILL
}
691 { &hf_msdp_tlv_contents
,
692 { "TLV contents", "msdp.tlv_contents",
693 FT_BYTES
, BASE_NONE
, NULL
, 0,
696 { &hf_msdp_trailing_junk
,
697 { "Trailing junk", "msdp.trailing_junk",
698 FT_BYTES
, BASE_NONE
, NULL
, 0,
701 { &hf_msdp_unknown_data
,
702 { "Unknown data", "msdp.unknown_data",
703 FT_BYTES
, BASE_NONE
, NULL
, 0,
708 static int *ett
[] = {
711 &ett_msdp_sa_enc_data
,
715 static ei_register_info ei
[] = {
716 { &ei_msdp_tlv_len_too_long
,
717 { "msdp.tlv_len.too_long", PI_PROTOCOL
, PI_WARN
,
718 "TLV length too long", EXPFILL
}
720 { &ei_msdp_tlv_len_too_short
,
721 { "msdp.tlv_len.too_short", PI_MALFORMED
, PI_ERROR
,
722 "TLV length too short", EXPFILL
}
726 expert_module_t
*expert_msdp
;
728 proto_msdp
= proto_register_protocol("Multicast Source Discovery Protocol",
730 msdp_handle
= register_dissector("msdp", dissect_msdp
, proto_msdp
);
732 proto_register_field_array(proto_msdp
, hf
, array_length(hf
));
733 proto_register_subtree_array(ett
, array_length(ett
));
734 expert_msdp
= expert_register_protocol(proto_msdp
);
735 expert_register_field_array(expert_msdp
, ei
, array_length(ei
));
739 proto_reg_handoff_msdp(void)
741 dissector_add_uint_with_preference("tcp.port", MSDP_PORT
, msdp_handle
);
743 ip_handle
= find_dissector_add_dependency("ip", proto_msdp
);
752 * indent-tabs-mode: nil
755 * ex: set shiftwidth=8 tabstop=8 expandtab:
756 * :indentSize=8:tabSize=8:noTabs=true: