sharkd: Add phs tap to sharkd
Add `phs` tap to `sharkd`, providing the same information as `tshark`'s `-z io,phs` option. Additionally, modify how `tshark -z io,phs` (and therefore `sharkd`'s new `phs` tap) handles packet comments (aka `pkt_comment` protocol frames). Previously, `pkt_comment` protocol frames were handled no differently from any other protocol in `io,phs`'s `tap_packet` callback `protohierstat_packet` but were skipped in its `tap_draw` callback `protohierstat_draw`. This behavior seems to have been first introduced in 80ae3708. For captures containing packet comments, this lead to surprising `tshark -z io,phs` output with multiple root-level `eth` trees. Below is example output of the old behavior for the `test/captures/protohier-with-comments.pcapng` capture in this repository with two packet comments, one on an ICMPv6 packet and another on an SSDP packet: # tshark -qz io,phs -r ./test/captures/protohier-with-comments.pcapng =================================================================== Protocol Hierarchy Statistics Filter: eth frames:113 bytes:21809 ipv6 frames:38 bytes:7456 icmpv6 frames:35 bytes:3574 udp frames:3 bytes:3882 data frames:3 bytes:3882 ip frames:69 bytes:13993 udp frames:59 bytes:13391 mdns frames:1 bytes:138 ssdp frames:29 bytes:8561 nbns frames:20 bytes:2200 nbdgm frames:1 bytes:248 smb frames:1 bytes:248 mailslot frames:1 bytes:248 browser frames:1 bytes:248 dhcp frames:4 bytes:1864 dns frames:4 bytes:380 igmp frames:10 bytes:602 arp frames:6 bytes:360 eth frames:2 bytes:377 ipv6 frames:1 bytes:110 icmpv6 frames:1 bytes:110 ip frames:1 bytes:267 udp frames:1 bytes:267 ssdp frames:1 bytes:267 =================================================================== Despite the comment in `phs_draw` in `ui/cli/tap-protohierstat.c`, this does not seem to match the behavior for PHS as shown in the GUI. The GUI seems to ignore the `pkt_comment` protocol frames and merges their children up a level. This commit tries to reproduce this behavior in the `tshark -z io,phs` output by ignoring `pkt_comment` protocol frames in `protohierstat_packet` instead of `protohierstat_draw`. The result is output like the following: # tshark -qz io,phs -r ./test/captures/protohier-with-comments.pcapng =================================================================== Protocol Hierarchy Statistics Filter: eth frames:115 bytes:22186 ipv6 frames:39 bytes:7566 icmpv6 frames:36 bytes:3684 udp frames:3 bytes:3882 data frames:3 bytes:3882 ip frames:70 bytes:14260 udp frames:60 bytes:13658 mdns frames:1 bytes:138 ssdp frames:30 bytes:8828 nbns frames:20 bytes:2200 nbdgm frames:1 bytes:248 smb frames:1 bytes:248 mailslot frames:1 bytes:248 browser frames:1 bytes:248 dhcp frames:4 bytes:1864 dns frames:4 bytes:380 igmp frames:10 bytes:602 arp frames:6 bytes:360 =================================================================== Note that there are no `pkt_comment` protocols and only a single root-level `eth` protocol. Additionally, the commented ICMPv6 and SSDP packets have been merged into the first `eth` tree, and the frame and byte counts have been incremented appropriately.
This commit is contained in:
parent
de5dc5dd23
commit
c96b79f105
@ -3056,6 +3056,7 @@ if(BUILD_sharkd)
|
||||
${APPLE_SYSTEM_CONFIGURATION_LIBRARY}
|
||||
${WIN_WS2_32_LIBRARY}
|
||||
${SPEEXDSP_LIBRARIES}
|
||||
${M_LIBRARIES}
|
||||
)
|
||||
set(sharkd_FILES
|
||||
#
|
||||
@ -3066,6 +3067,7 @@ if(BUILD_sharkd)
|
||||
sharkd.c
|
||||
sharkd_daemon.c
|
||||
sharkd_session.c
|
||||
${TSHARK_TAP_SRC}
|
||||
)
|
||||
set_executable_resources(sharkd "SharkD")
|
||||
add_executable(sharkd ${sharkd_FILES})
|
||||
|
100
sharkd_session.c
100
sharkd_session.c
@ -56,6 +56,7 @@
|
||||
#include <ui/rtp_stream.h>
|
||||
#include <ui/tap-rtp-common.h>
|
||||
#include <ui/tap-rtp-analysis.h>
|
||||
#include <ui/cli/tap-protohierstat.h>
|
||||
#include <wsutil/version_info.h>
|
||||
#include <epan/to_str.h>
|
||||
|
||||
@ -1031,6 +1032,11 @@ sharkd_session_process_info(void)
|
||||
sharkd_json_value_string("tap", "rtp-streams");
|
||||
json_dumper_end_object(&dumper);
|
||||
|
||||
json_dumper_begin_object(&dumper);
|
||||
sharkd_json_value_string("name", "Protocol Hierarchy Statistics");
|
||||
sharkd_json_value_string("tap", "phs");
|
||||
json_dumper_end_object(&dumper);
|
||||
|
||||
json_dumper_begin_object(&dumper);
|
||||
sharkd_json_value_string("name", "Expert Information");
|
||||
sharkd_json_value_string("tap", "expert");
|
||||
@ -2629,6 +2635,80 @@ sharkd_session_free_tap_srt_cb(void *arg)
|
||||
g_free(srt_data);
|
||||
}
|
||||
|
||||
struct sharkd_phs_req
|
||||
{
|
||||
const char *tap_name;
|
||||
phs_t *rs;
|
||||
};
|
||||
|
||||
static void
|
||||
sharkd_session_process_tap_phs_cb_aux(phs_t *rs)
|
||||
{
|
||||
for (; rs; rs = rs->sibling) {
|
||||
if (rs->protocol == -1) {
|
||||
return;
|
||||
}
|
||||
sharkd_json_object_open(NULL);
|
||||
sharkd_json_value_string("proto", rs->proto_name);
|
||||
sharkd_json_value_anyf("frames", "%u", rs->frames);
|
||||
sharkd_json_value_anyf("bytes", "%lu", rs->bytes);
|
||||
if (rs->child != NULL && rs->child->protocol != -1) {
|
||||
sharkd_json_array_open("protos");
|
||||
sharkd_session_process_tap_phs_cb_aux(rs->child);
|
||||
sharkd_json_array_close();
|
||||
}
|
||||
sharkd_json_object_close();
|
||||
}
|
||||
}
|
||||
|
||||
static tap_packet_status
|
||||
sharkd_session_packet_tap_phs_cb(void *pphs_req, packet_info *pinfo, epan_dissect_t *edt, const void *dummy, tap_flags_t flags)
|
||||
{
|
||||
struct sharkd_phs_req *phs_req = (struct sharkd_phs_req *)pphs_req;
|
||||
phs_t *rs = phs_req->rs;
|
||||
return protohierstat_packet(rs, pinfo, edt, dummy, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* sharkd_session_process_tap_phs_cb()
|
||||
*
|
||||
* Output phs tap:
|
||||
* (m) tap - tap name
|
||||
* (m) type - tap output type
|
||||
* (m) filter - tap filter argument
|
||||
* (m) protos - array of proto objects
|
||||
*
|
||||
* proto object:
|
||||
* (m) proto - protocol name
|
||||
* (m) frames - frame count
|
||||
* (m) bytes - bytes count
|
||||
* (o) protos - array of proto objects
|
||||
*/
|
||||
static void
|
||||
sharkd_session_process_tap_phs_cb(void *arg)
|
||||
{
|
||||
struct sharkd_phs_req *phs_req = (struct sharkd_phs_req *)arg;
|
||||
phs_t *rs = phs_req->rs;
|
||||
sharkd_json_object_open(NULL);
|
||||
sharkd_json_value_string("tap", phs_req->tap_name);
|
||||
sharkd_json_value_string("type", "phs");
|
||||
sharkd_json_value_string("filter", rs->filter ? rs->filter : "");
|
||||
sharkd_json_array_open("protos");
|
||||
sharkd_session_process_tap_phs_cb_aux(rs);
|
||||
sharkd_json_array_close();
|
||||
sharkd_json_object_close();
|
||||
}
|
||||
|
||||
static void
|
||||
sharkd_session_free_tap_phs_cb(void *arg)
|
||||
{
|
||||
struct sharkd_phs_req *phs_req = (struct sharkd_phs_req *)arg;
|
||||
phs_t *rs = phs_req->rs;
|
||||
free_phs(rs);
|
||||
g_free(phs_req);
|
||||
|
||||
}
|
||||
|
||||
struct sharkd_export_object_list
|
||||
{
|
||||
struct sharkd_export_object_list *next;
|
||||
@ -3247,6 +3327,26 @@ sharkd_session_process_tap(char *buf, const jsmntok_t *tokens, int count)
|
||||
tap_data = mcaststream_tapinfo;
|
||||
tap_free = sharkd_session_process_free_tap_multicast_cb;
|
||||
}
|
||||
else if (!strncmp(tok_tap, "phs", 3))
|
||||
{
|
||||
phs_t *rs;
|
||||
|
||||
pc_proto_id = proto_registrar_get_id_byname("pkt_comment");
|
||||
|
||||
rs = new_phs_t(NULL, tap_filter);
|
||||
|
||||
struct sharkd_phs_req *phs_req;
|
||||
phs_req = (struct sharkd_phs_req *)g_malloc0(sizeof(*phs_req));
|
||||
phs_req->tap_name = tok_tap;
|
||||
phs_req->rs = rs;
|
||||
|
||||
tap_error = register_tap_listener("frame", phs_req, tap_filter, TL_REQUIRES_PROTO_TREE, NULL,
|
||||
sharkd_session_packet_tap_phs_cb,
|
||||
sharkd_session_process_tap_phs_cb, NULL);
|
||||
|
||||
tap_data = phs_req;
|
||||
tap_free = sharkd_session_free_tap_phs_cb;
|
||||
}
|
||||
else
|
||||
{
|
||||
sharkd_json_error(
|
||||
|
BIN
test/captures/protohier-with-comments.pcapng
Normal file
BIN
test/captures/protohier-with-comments.pcapng
Normal file
Binary file not shown.
BIN
test/captures/protohier-without-comments.pcapng
Normal file
BIN
test/captures/protohier-without-comments.pcapng
Normal file
Binary file not shown.
@ -309,6 +309,195 @@ class TestSharkd:
|
||||
}},
|
||||
))
|
||||
|
||||
def test_sharkd_req_tap_phs(self, check_sharkd_session, capture_file):
|
||||
check_sharkd_session((
|
||||
{"jsonrpc":"2.0", "id":1, "method":"load",
|
||||
"params":{"file": capture_file('protohier-with-comments.pcapng')}
|
||||
},
|
||||
{"jsonrpc":"2.0", "id":2, "method":"tap", "params":{"tap0": "phs"}},
|
||||
{"jsonrpc":"2.0", "id":3, "method":"load",
|
||||
"params":{"file": capture_file('protohier-without-comments.pcapng')}
|
||||
},
|
||||
{"jsonrpc":"2.0", "id":4, "method":"tap", "params":{"tap0": "phs"}},
|
||||
), (
|
||||
{"jsonrpc":"2.0","id":1,"result":{"status":"OK"}},
|
||||
{"jsonrpc":"2.0","id":2,"result":{
|
||||
"taps":[{
|
||||
"tap":"phs",
|
||||
"type":"phs",
|
||||
"filter":"",
|
||||
"protos":[{
|
||||
"proto":"eth",
|
||||
"frames":115,
|
||||
"bytes":22186,
|
||||
"protos":[{
|
||||
"proto":"ipv6",
|
||||
"frames":39,
|
||||
"bytes":7566,
|
||||
"protos":[{
|
||||
"proto":"icmpv6",
|
||||
"frames":36,
|
||||
"bytes":3684
|
||||
},{
|
||||
"proto":"udp",
|
||||
"frames":3,
|
||||
"bytes":3882,
|
||||
"protos":[{
|
||||
"proto":"data",
|
||||
"frames":3,
|
||||
"bytes":3882
|
||||
}]
|
||||
}]
|
||||
},{
|
||||
"proto":"ip",
|
||||
"frames":70,
|
||||
"bytes":14260,
|
||||
"protos":[{
|
||||
"proto":"udp",
|
||||
"frames":60,
|
||||
"bytes":13658,
|
||||
"protos":[{
|
||||
"proto":"mdns",
|
||||
"frames":1,
|
||||
"bytes":138
|
||||
},{
|
||||
"proto":"ssdp",
|
||||
"frames":30,
|
||||
"bytes":8828
|
||||
},{
|
||||
"proto":"nbns",
|
||||
"frames":20,
|
||||
"bytes":2200
|
||||
},{
|
||||
"proto":"nbdgm",
|
||||
"frames":1,
|
||||
"bytes":248,
|
||||
"protos":[{
|
||||
"proto":"smb",
|
||||
"frames":1,
|
||||
"bytes":248,
|
||||
"protos":[{
|
||||
"proto":"mailslot",
|
||||
"frames":1,
|
||||
"bytes":248,
|
||||
"protos":[{
|
||||
"proto":"browser",
|
||||
"frames":1,
|
||||
"bytes":248
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
},{"proto":"dhcp",
|
||||
"frames":4,
|
||||
"bytes":1864
|
||||
},{
|
||||
"proto":"dns",
|
||||
"frames":4,
|
||||
"bytes":380
|
||||
}]
|
||||
},{
|
||||
"proto":"igmp",
|
||||
"frames":10,
|
||||
"bytes":602
|
||||
}]
|
||||
},{
|
||||
"proto":"arp",
|
||||
"frames":6,
|
||||
"bytes":360
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}},
|
||||
{"jsonrpc":"2.0","id":3,"result":{"status":"OK"}},
|
||||
{"jsonrpc":"2.0","id":4,"result":{
|
||||
"taps":[{
|
||||
"tap":"phs",
|
||||
"type":"phs",
|
||||
"filter":"",
|
||||
"protos":[{
|
||||
"proto":"eth",
|
||||
"frames":115,
|
||||
"bytes":22186,
|
||||
"protos":[{
|
||||
"proto":"ipv6",
|
||||
"frames":39,
|
||||
"bytes":7566,
|
||||
"protos":[{
|
||||
"proto":"icmpv6",
|
||||
"frames":36,
|
||||
"bytes":3684
|
||||
},{
|
||||
"proto":"udp",
|
||||
"frames":3,
|
||||
"bytes":3882,
|
||||
"protos":[{
|
||||
"proto":"data",
|
||||
"frames":3,
|
||||
"bytes":3882
|
||||
}]
|
||||
}]
|
||||
},{
|
||||
"proto":"ip",
|
||||
"frames":70,
|
||||
"bytes":14260,
|
||||
"protos":[{
|
||||
"proto":"udp",
|
||||
"frames":60,
|
||||
"bytes":13658,
|
||||
"protos":[{
|
||||
"proto":"mdns",
|
||||
"frames":1,
|
||||
"bytes":138
|
||||
},{
|
||||
"proto":"ssdp",
|
||||
"frames":30,
|
||||
"bytes":8828
|
||||
},{
|
||||
"proto":"nbns",
|
||||
"frames":20,
|
||||
"bytes":2200
|
||||
},{
|
||||
"proto":"nbdgm",
|
||||
"frames":1,
|
||||
"bytes":248,
|
||||
"protos":[{
|
||||
"proto":"smb",
|
||||
"frames":1,
|
||||
"bytes":248,
|
||||
"protos":[{
|
||||
"proto":"mailslot",
|
||||
"frames":1,
|
||||
"bytes":248,
|
||||
"protos":[{
|
||||
"proto":"browser",
|
||||
"frames":1,
|
||||
"bytes":248
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
},{"proto":"dhcp",
|
||||
"frames":4,
|
||||
"bytes":1864
|
||||
},{
|
||||
"proto":"dns",
|
||||
"frames":4,
|
||||
"bytes":380
|
||||
}]
|
||||
},{
|
||||
"proto":"igmp",
|
||||
"frames":10,
|
||||
"bytes":602
|
||||
}]
|
||||
},{
|
||||
"proto":"arp",
|
||||
"frames":6,
|
||||
"bytes":360
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}},
|
||||
))
|
||||
|
||||
def test_sharkd_req_follow_bad(self, check_sharkd_session, capture_file):
|
||||
# Unrecognized taps currently produce no output (not even err).
|
||||
check_sharkd_session((
|
||||
|
@ -21,25 +21,14 @@
|
||||
#include <epan/stat_tap_ui.h>
|
||||
|
||||
#include <wsutil/cmdarg_err.h>
|
||||
#include "tap-protohierstat.h"
|
||||
|
||||
static int pc_proto_id = -1;
|
||||
int pc_proto_id = -1;
|
||||
|
||||
void register_tap_listener_protohierstat(void);
|
||||
|
||||
typedef struct _phs_t {
|
||||
struct _phs_t *sibling;
|
||||
struct _phs_t *child;
|
||||
struct _phs_t *parent;
|
||||
char *filter;
|
||||
int protocol;
|
||||
const char *proto_name;
|
||||
guint32 frames;
|
||||
guint64 bytes;
|
||||
} phs_t;
|
||||
|
||||
|
||||
static phs_t *
|
||||
new_phs_t(phs_t *parent)
|
||||
phs_t *
|
||||
new_phs_t(phs_t *parent, const char *filter)
|
||||
{
|
||||
phs_t *rs;
|
||||
rs = g_new(phs_t, 1);
|
||||
@ -47,6 +36,9 @@ new_phs_t(phs_t *parent)
|
||||
rs->child = NULL;
|
||||
rs->parent = parent;
|
||||
rs->filter = NULL;
|
||||
if (filter != NULL) {
|
||||
rs->filter = g_strdup(filter);
|
||||
}
|
||||
rs->protocol = -1;
|
||||
rs->proto_name = NULL;
|
||||
rs->frames = 0;
|
||||
@ -54,8 +46,30 @@ new_phs_t(phs_t *parent)
|
||||
return rs;
|
||||
}
|
||||
|
||||
void
|
||||
free_phs(phs_t *rs)
|
||||
{
|
||||
if (!rs) {
|
||||
return;
|
||||
}
|
||||
if (rs->filter) {
|
||||
g_free(rs->filter);
|
||||
rs->filter = NULL;
|
||||
}
|
||||
if (rs->sibling)
|
||||
{
|
||||
free_phs(rs->sibling);
|
||||
rs->sibling = NULL;
|
||||
}
|
||||
if (rs->child)
|
||||
{
|
||||
free_phs(rs->child);
|
||||
rs->child = NULL;
|
||||
}
|
||||
g_free(rs);
|
||||
}
|
||||
|
||||
static tap_packet_status
|
||||
tap_packet_status
|
||||
protohierstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_, tap_flags_t flags _U_)
|
||||
{
|
||||
phs_t *rs = (phs_t *)prs;
|
||||
@ -76,13 +90,23 @@ protohierstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt, const v
|
||||
for (node=edt->tree->first_child; node; node=node->next) {
|
||||
fi = PNODE_FINFO(node);
|
||||
|
||||
/*
|
||||
* If the first child is a tree of comments, skip over it.
|
||||
* This keeps us from having a top-level "pkt_comment"
|
||||
* entry that represents a nonexistent protocol,
|
||||
* and matches how the GUI treats comments.
|
||||
*/
|
||||
if (G_UNLIKELY(fi->hfinfo->id == pc_proto_id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* first time we saw a protocol at this leaf */
|
||||
if (rs->protocol == -1) {
|
||||
rs->protocol = fi->hfinfo->id;
|
||||
rs->proto_name = fi->hfinfo->abbrev;
|
||||
rs->frames = 1;
|
||||
rs->bytes = pinfo->fd->pkt_len;
|
||||
rs->child = new_phs_t(rs);
|
||||
rs->child = new_phs_t(rs, NULL);
|
||||
rs = rs->child;
|
||||
continue;
|
||||
}
|
||||
@ -98,7 +122,7 @@ protohierstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt, const v
|
||||
if (!tmprs) {
|
||||
for (tmprs=rs; tmprs->sibling; tmprs=tmprs->sibling)
|
||||
;
|
||||
tmprs->sibling = new_phs_t(rs->parent);
|
||||
tmprs->sibling = new_phs_t(rs->parent, NULL);
|
||||
rs = tmprs->sibling;
|
||||
rs->protocol = fi->hfinfo->id;
|
||||
rs->proto_name = fi->hfinfo->abbrev;
|
||||
@ -110,7 +134,7 @@ protohierstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt, const v
|
||||
rs->bytes += pinfo->fd->pkt_len;
|
||||
|
||||
if (!rs->child) {
|
||||
rs->child = new_phs_t(rs);
|
||||
rs->child = new_phs_t(rs, NULL);
|
||||
}
|
||||
rs = rs->child;
|
||||
}
|
||||
@ -127,16 +151,6 @@ phs_draw(phs_t *rs, int indentation)
|
||||
if (rs->protocol == -1) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* If the first child is a tree of comments, skip over it.
|
||||
* This keeps us from having a top-level "pkt_comment"
|
||||
* entry that represents a nonexistent protocol,
|
||||
* and matches how the GUI treats comments.
|
||||
*/
|
||||
if (G_UNLIKELY(rs->protocol == pc_proto_id)) {
|
||||
phs_draw(rs->child, indentation);
|
||||
continue;
|
||||
}
|
||||
str[0] = 0;
|
||||
stroff = 0;
|
||||
for (i=0; i<indentation; i++) {
|
||||
@ -187,14 +201,12 @@ protohierstat_init(const char *opt_arg, void *userdata _U_)
|
||||
|
||||
pc_proto_id = proto_registrar_get_id_byname("pkt_comment");
|
||||
|
||||
rs = new_phs_t(NULL);
|
||||
rs->filter = g_strdup(filter);
|
||||
rs = new_phs_t(NULL, filter);
|
||||
|
||||
error_string = register_tap_listener("frame", rs, filter, TL_REQUIRES_PROTO_TREE, NULL, protohierstat_packet, protohierstat_draw, NULL);
|
||||
if (error_string) {
|
||||
/* error, we failed to attach to the tap. clean up */
|
||||
g_free(rs->filter);
|
||||
g_free(rs);
|
||||
free_phs(rs);
|
||||
|
||||
cmdarg_err("Couldn't register io,phs tap: %s",
|
||||
error_string->str);
|
||||
|
51
ui/cli/tap-protohierstat.h
Normal file
51
ui/cli/tap-protohierstat.h
Normal file
@ -0,0 +1,51 @@
|
||||
/** @file
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef __TAP_PROTO_HIER_STAT_H__
|
||||
#define __TAP_PROTO_HIER_STAT_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
extern int pc_proto_id;
|
||||
|
||||
typedef struct _phs_t {
|
||||
struct _phs_t *sibling;
|
||||
struct _phs_t *child;
|
||||
struct _phs_t *parent;
|
||||
char *filter;
|
||||
int protocol;
|
||||
const char *proto_name;
|
||||
guint32 frames;
|
||||
guint64 bytes;
|
||||
} phs_t;
|
||||
|
||||
extern phs_t * new_phs_t(phs_t *parent, const char *filter);
|
||||
extern void free_phs(phs_t *rs);
|
||||
extern tap_packet_status protohierstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_, tap_flags_t flags _U_);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __TAP_PROTO_HIER_STAT_H__ */
|
||||
|
||||
/*
|
||||
* Editor modelines - https://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:
|
||||
*/
|
Loading…
x
Reference in New Issue
Block a user