2 * Routines for packet capture
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
33 #include <epan/packet.h>
34 #include <epan/dfilter/dfilter.h>
36 #include "ui/capture.h"
37 #include "caputils/capture_ifinfo.h"
38 #include <capchild/capture_sync.h>
39 #include "capture_info.h"
40 #include "ui/capture_ui_utils.h"
42 #include "caputils/capture-pcap-util.h"
43 #include <epan/prefs.h>
46 #include "caputils/capture-wpcap.h"
49 #include "ui/simple_dialog.h"
50 #include "ui/ui_util.h"
52 #include "wsutil/file_util.h"
53 #include "wsutil/str_util.h"
56 typedef struct if_stat_cache_item_s {
59 } if_stat_cache_item_t;
61 struct if_stat_cache_s {
63 ws_process_id fork_child;
64 GList *cache_list; /* List of if_stat_chache_entry_t */
67 /* this callback mechanism should possibly be replaced by the g_signal_...() stuff (if I only would know how :-) */
69 capture_callback_t cb_fct;
71 } capture_callback_data_t;
73 static GList *capture_callbacks = NULL;
76 capture_callback_invoke(int event, capture_session *cap_session)
78 capture_callback_data_t *cb;
79 GList *cb_item = capture_callbacks;
81 /* there should be at least one interested */
82 g_assert(cb_item != NULL);
84 while(cb_item != NULL) {
85 cb = (capture_callback_data_t *)cb_item->data;
86 cb->cb_fct(event, cap_session, cb->user_data);
87 cb_item = g_list_next(cb_item);
93 capture_callback_add(capture_callback_t func, gpointer user_data)
95 capture_callback_data_t *cb;
97 cb = (capture_callback_data_t *)g_malloc(sizeof(capture_callback_data_t));
99 cb->user_data = user_data;
101 capture_callbacks = g_list_append(capture_callbacks, cb);
105 capture_callback_remove(capture_callback_t func, gpointer user_data)
107 capture_callback_data_t *cb;
108 GList *cb_item = capture_callbacks;
110 while(cb_item != NULL) {
111 cb = (capture_callback_data_t *)cb_item->data;
112 if(cb->cb_fct == func && cb->user_data == user_data) {
113 capture_callbacks = g_list_remove(capture_callbacks, cb);
117 cb_item = g_list_next(cb_item);
120 g_assert_not_reached();
126 * @return TRUE if the capture starts successfully, FALSE otherwise.
129 capture_start(capture_options *capture_opts, capture_session *cap_session, info_data_t* cap_data, void(*update_cb)(void))
134 cap_session->state = CAPTURE_PREPARING;
135 cap_session->count = 0;
136 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Start ...");
137 source = get_iface_list_string(capture_opts, IFLIST_SHOW_FILTER);
138 cf_set_tempfile_source((capture_file *)cap_session->cf, source->str);
139 g_string_free(source, TRUE);
140 /* try to start the capture child process */
141 ret = sync_pipe_start(capture_opts, cap_session, cap_data, update_cb);
143 if(capture_opts->save_file != NULL) {
144 g_free(capture_opts->save_file);
145 capture_opts->save_file = NULL;
148 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Start failed.");
149 cap_session->state = CAPTURE_STOPPED;
151 /* the capture child might not respond shortly after bringing it up */
152 /* (for example: it will block if no input arrives from an input capture pipe (e.g. mkfifo)) */
154 /* to prevent problems, bring the main GUI into "capture mode" right after a successful */
155 /* spawn/exec of the capture child, without waiting for any response from it */
156 capture_callback_invoke(capture_cb_capture_prepared, cap_session);
158 if(capture_opts->show_info)
159 capture_info_open(cap_session, cap_data);
167 capture_stop(capture_session *cap_session)
169 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Stop ...");
171 capture_callback_invoke(capture_cb_capture_stopping, cap_session);
173 /* stop the capture child gracefully */
174 sync_pipe_stop(cap_session);
179 capture_restart(capture_session *cap_session)
181 capture_options *capture_opts = cap_session->capture_opts;
183 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Restart");
185 capture_opts->restart = TRUE;
186 capture_stop(cap_session);
191 capture_kill_child(capture_session *cap_session)
193 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "Capture Kill");
195 /* kill the capture child */
196 sync_pipe_kill(cap_session->fork_child);
199 /* We've succeeded in doing a (non real-time) capture; try to read it into a new capture file */
201 capture_input_read_all(capture_session *cap_session, gboolean is_tempfile,
202 gboolean drops_known, guint32 drops)
204 capture_options *capture_opts = cap_session->capture_opts;
207 /* Capture succeeded; attempt to open the capture file. */
208 if (cf_open((capture_file *)cap_session->cf, capture_opts->save_file, WTAP_TYPE_AUTO, is_tempfile, &err) != CF_OK) {
209 /* We're not doing a capture any more, so we don't have a save file. */
213 /* Set the read filter to NULL. */
214 /* XXX - this is odd here; try to put it somewhere where it fits better */
215 cf_set_rfcode((capture_file *)cap_session->cf, NULL);
217 /* Get the packet-drop statistics.
219 XXX - there are currently no packet-drop statistics stored
220 in libpcap captures, and that's what we're reading.
222 At some point, we will add support in Wiretap to return
223 packet-drop statistics for capture file formats that store it,
224 and will make "cf_read()" get those statistics from Wiretap.
225 We clear the statistics (marking them as "not known") in
226 "cf_open()", and "cf_read()" will only fetch them and mark
227 them as known if Wiretap supplies them, so if we get the
228 statistics now, after calling "cf_open()" but before calling
229 "cf_read()", the values we store will be used by "cf_read()".
231 If a future libpcap capture file format stores the statistics,
232 we'll put them into the capture file that we write, and will
233 thus not have to set them here - "cf_read()" will get them from
234 the file and use them. */
236 cf_set_drops_known((capture_file *)cap_session->cf, TRUE);
238 /* XXX - on some systems, libpcap doesn't bother filling in
239 "ps_ifdrop" - it doesn't even set it to zero - so we don't
240 bother looking at it.
242 Ideally, libpcap would have an interface that gave us
243 several statistics - perhaps including various interface
244 error statistics - and would tell us which of them it
245 supplies, allowing us to display only the ones it does. */
246 cf_set_drops((capture_file *)cap_session->cf, drops);
249 /* read in the packet data */
250 switch (cf_read((capture_file *)cap_session->cf, FALSE)) {
254 /* Just because we got an error, that doesn't mean we were unable
255 to read any of the file; we handle what we could get from the
259 case CF_READ_ABORTED:
260 /* User wants to quit program. Exit by leaving the main loop,
261 so that any quit functions we registered get called. */
262 main_window_nested_quit();
266 /* if we didn't capture even a single packet, close the file again */
267 if(cap_session->count == 0 && !capture_opts->restart) {
268 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
269 "%sNo packets captured.%s\n"
271 "As no data was captured, closing the %scapture file.\n"
274 "Help about capturing can be found at\n"
276 " https://wiki.wireshark.org/CaptureSetup"
279 "Wireless (Wi-Fi/WLAN):\n"
280 "Try to switch off promiscuous mode in the Capture Options"
283 simple_dialog_primary_start(), simple_dialog_primary_end(),
284 (cf_is_tempfile((capture_file *)cap_session->cf)) ? "temporary " : "");
285 cf_close((capture_file *)cap_session->cf);
291 /* capture child tells us we have a new (or the first) capture file */
293 capture_input_new_file(capture_session *cap_session, gchar *new_file)
295 capture_options *capture_opts = cap_session->capture_opts;
296 gboolean is_tempfile;
299 if(cap_session->state == CAPTURE_PREPARING) {
300 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture started");
302 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "File: \"%s\"", new_file);
304 g_assert(cap_session->state == CAPTURE_PREPARING || cap_session->state == CAPTURE_RUNNING);
306 /* free the old filename */
307 if(capture_opts->save_file != NULL) {
308 /* we start a new capture file, close the old one (if we had one before). */
309 /* (we can only have an open capture file in real_time_mode!) */
310 if( ((capture_file *) cap_session->cf)->state != FILE_CLOSED) {
311 if(capture_opts->real_time_mode) {
312 capture_callback_invoke(capture_cb_capture_update_finished, cap_session);
313 cf_finish_tail((capture_file *)cap_session->cf, &err);
314 cf_close((capture_file *)cap_session->cf);
316 capture_callback_invoke(capture_cb_capture_fixed_finished, cap_session);
319 g_free(capture_opts->save_file);
321 cf_set_tempfile((capture_file *)cap_session->cf, FALSE);
323 /* we didn't have a save_file before; must be a tempfile */
325 cf_set_tempfile((capture_file *)cap_session->cf, TRUE);
328 /* save the new filename */
329 capture_opts->save_file = g_strdup(new_file);
331 /* if we are in real-time mode, open the new file now */
332 if(capture_opts->real_time_mode) {
333 /* Attempt to open the capture file and set up to read from it. */
334 switch(cf_open((capture_file *)cap_session->cf, capture_opts->save_file, WTAP_TYPE_AUTO, is_tempfile, &err)) {
338 /* Don't unlink (delete) the save file - leave it around,
339 for debugging purposes. */
340 g_free(capture_opts->save_file);
341 capture_opts->save_file = NULL;
345 capture_callback_invoke(capture_cb_capture_prepared, cap_session);
348 if(capture_opts->show_info) {
349 if (!capture_info_new_file(new_file, cap_session->cap_data_info))
353 if(capture_opts->real_time_mode) {
354 capture_callback_invoke(capture_cb_capture_update_started, cap_session);
356 capture_callback_invoke(capture_cb_capture_fixed_started, cap_session);
358 cap_session->state = CAPTURE_RUNNING;
364 /* capture child tells us we have new packets to read */
366 capture_input_new_packets(capture_session *cap_session, int to_read)
368 capture_options *capture_opts = cap_session->capture_opts;
371 g_assert(capture_opts->save_file);
373 if(capture_opts->real_time_mode) {
374 /* Read from the capture file the number of records the child told us it added. */
375 switch (cf_continue_tail((capture_file *)cap_session->cf, to_read, &err)) {
379 /* Just because we got an error, that doesn't mean we were unable
380 to read any of the file; we handle what we could get from the
383 XXX - abort on a read error? */
384 capture_callback_invoke(capture_cb_capture_update_continue, cap_session);
387 case CF_READ_ABORTED:
388 /* Kill the child capture process; the user wants to exit, and we
389 shouldn't just leave it running. */
390 capture_kill_child(cap_session);
394 cf_fake_continue_tail((capture_file *)cap_session->cf);
396 capture_callback_invoke(capture_cb_capture_fixed_continue, cap_session);
399 /* update the main window so we get events (e.g. from the stop toolbar button) */
400 /* This causes a hang on Windows (see bug 7305). Do we need this on any platform? */
402 main_window_update();
405 if(capture_opts->show_info)
406 capture_info_new_packets(to_read, cap_session->cap_data_info);
410 /* Capture child told us how many dropped packets it counted.
413 capture_input_drops(capture_session *cap_session, guint32 dropped)
415 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "%u packet%s dropped", dropped, plurality(dropped, "", "s"));
417 g_assert(cap_session->state == CAPTURE_RUNNING);
419 cf_set_drops_known((capture_file *)cap_session->cf, TRUE);
420 cf_set_drops((capture_file *)cap_session->cf, dropped);
424 /* Capture child told us that an error has occurred while starting/running
426 The buffer we're handed has *two* null-terminated strings in it - a
427 primary message and a secondary message, one right after the other.
428 The secondary message might be a null string.
431 capture_input_error_message(capture_session *cap_session, char *error_msg,
432 char *secondary_error_msg)
434 gchar *safe_error_msg;
435 gchar *safe_secondary_error_msg;
437 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Error message from child: \"%s\", \"%s\"",
438 error_msg, secondary_error_msg);
440 g_assert(cap_session->state == CAPTURE_PREPARING || cap_session->state == CAPTURE_RUNNING);
442 safe_error_msg = simple_dialog_format_message(error_msg);
443 if (*secondary_error_msg != '\0') {
444 /* We have both primary and secondary messages. */
445 safe_secondary_error_msg = simple_dialog_format_message(secondary_error_msg);
446 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s\n\n%s",
447 simple_dialog_primary_start(), safe_error_msg,
448 simple_dialog_primary_end(), safe_secondary_error_msg);
449 g_free(safe_secondary_error_msg);
451 /* We have only a primary message. */
452 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s",
453 simple_dialog_primary_start(), safe_error_msg,
454 simple_dialog_primary_end());
456 g_free(safe_error_msg);
458 /* the capture child will close the sync_pipe if required, nothing to do for now */
461 /* Capture child told us that an error has occurred while parsing a
462 capture filter when starting/running the capture.
465 capture_input_cfilter_error_message(capture_session *cap_session, guint i,
468 capture_options *capture_opts = cap_session->capture_opts;
469 dfilter_t *rfcode = NULL;
472 gchar *safe_cfilter_error_msg;
473 interface_options interface_opts;
475 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture filter error message from child: \"%s\"", error_message);
477 g_assert(cap_session->state == CAPTURE_PREPARING || cap_session->state == CAPTURE_RUNNING);
478 g_assert(i < capture_opts->ifaces->len);
480 interface_opts = g_array_index(capture_opts->ifaces, interface_options, i);
481 safe_cfilter = simple_dialog_format_message(interface_opts.cfilter);
482 safe_descr = simple_dialog_format_message(interface_opts.descr);
483 safe_cfilter_error_msg = simple_dialog_format_message(error_message);
484 /* Did the user try a display filter? */
485 if (dfilter_compile(interface_opts.cfilter, &rfcode, NULL) && rfcode != NULL) {
486 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
487 "%sInvalid capture filter \"%s\" for interface %s.%s\n"
489 "That string looks like a valid display filter; however, it isn't a valid\n"
490 "capture filter (%s).\n"
492 "Note that display filters and capture filters don't have the same syntax,\n"
493 "so you can't use most display filter expressions as capture filters.\n"
495 "See the User's Guide for a description of the capture filter syntax.",
496 simple_dialog_primary_start(), safe_cfilter, safe_descr,
497 simple_dialog_primary_end(), safe_cfilter_error_msg);
498 dfilter_free(rfcode);
500 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
501 "%sInvalid capture filter \"%s\" for interface %s.%s\n"
503 "That string isn't a valid capture filter (%s).\n"
504 "See the User's Guide for a description of the capture filter syntax.",
505 simple_dialog_primary_start(), safe_cfilter, safe_descr,
506 simple_dialog_primary_end(), safe_cfilter_error_msg);
508 g_free(safe_cfilter_error_msg);
510 g_free(safe_cfilter);
512 /* the capture child will close the sync_pipe if required, nothing to do for now */
515 /* capture child closed its side of the pipe, do the required cleanup */
517 capture_input_closed(capture_session *cap_session, gchar *msg)
519 capture_options *capture_opts = cap_session->capture_opts;
522 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture stopped.");
523 g_assert(cap_session->state == CAPTURE_PREPARING || cap_session->state == CAPTURE_RUNNING);
526 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", msg);
528 if(cap_session->state == CAPTURE_PREPARING) {
529 /* We didn't start a capture; note that the attempt to start it
531 capture_callback_invoke(capture_cb_capture_failed, cap_session);
533 /* We started a capture; process what's left of the capture file if
534 we were in "update list of packets in real time" mode, or process
535 all of it if we weren't. */
536 if(capture_opts->real_time_mode) {
537 cf_read_status_t status;
539 /* Read what remains of the capture file. */
540 status = cf_finish_tail((capture_file *)cap_session->cf, &err);
542 /* Tell the GUI we are not doing a capture any more.
543 Must be done after the cf_finish_tail(), so file lengths are
544 correctly displayed */
545 capture_callback_invoke(capture_cb_capture_update_finished, cap_session);
547 /* Finish the capture. */
551 if (cap_session->count == 0 && !capture_opts->restart) {
552 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
553 "%sNo packets captured.%s\n"
555 "As no data was captured, closing the %scapture file.\n"
558 "Help about capturing can be found at\n"
560 " https://wiki.wireshark.org/CaptureSetup"
563 "Wireless (Wi-Fi/WLAN):\n"
564 "Try to switch off promiscuous mode in the Capture Options."
567 simple_dialog_primary_start(), simple_dialog_primary_end(),
568 cf_is_tempfile((capture_file *)cap_session->cf) ? "temporary " : "");
569 cf_close((capture_file *)cap_session->cf);
573 /* Just because we got an error, that doesn't mean we were unable
574 to read any of the file; we handle what we could get from the
578 case CF_READ_ABORTED:
579 /* Exit by leaving the main loop, so that any quit functions
580 we registered get called. */
585 /* first of all, we are not doing a capture any more */
586 capture_callback_invoke(capture_cb_capture_fixed_finished, cap_session);
588 /* this is a normal mode capture and if no error happened, read in the capture file data */
589 if(capture_opts->save_file != NULL) {
590 capture_input_read_all(cap_session, cf_is_tempfile((capture_file *)cap_session->cf),
591 cf_get_drops_known((capture_file *)cap_session->cf), cf_get_drops((capture_file *)cap_session->cf));
596 if(capture_opts->show_info)
597 capture_info_close(cap_session->cap_data_info);
599 cap_session->state = CAPTURE_STOPPED;
601 /* if we couldn't open a capture file, there's nothing more for us to do */
602 if(capture_opts->save_file == NULL) {
603 cf_close((capture_file *)cap_session->cf);
607 /* does the user wants to restart the current capture? */
608 if(capture_opts->restart) {
609 capture_opts->restart = FALSE;
611 ws_unlink(capture_opts->save_file);
613 /* If we have a ring buffer, the original save file has been overwritten
614 with the "ring filename". Restore it before starting again */
615 if ((capture_opts->multi_files_on) && (capture_opts->orig_save_file != NULL)) {
616 g_free(capture_opts->save_file);
617 capture_opts->save_file = g_strdup(capture_opts->orig_save_file);
620 /* if it was a tempfile, throw away the old filename (so it will become a tempfile again) */
621 if(cf_is_tempfile((capture_file *)cap_session->cf)) {
622 g_free(capture_opts->save_file);
623 capture_opts->save_file = NULL;
626 /* ... and start the capture again */
627 if (capture_opts->ifaces->len == 0) {
628 collect_ifaces(capture_opts);
631 /* close the currently loaded capture file */
632 cf_close((capture_file *)cap_session->cf);
634 capture_start(capture_opts, cap_session, cap_session->cap_data_info, NULL); /*XXX is this NULL ok or we need an update_cb???*/
636 /* We're not doing a capture any more, so we don't have a save file. */
637 g_free(capture_opts->save_file);
638 capture_opts->save_file = NULL;
643 capture_stat_start(capture_options *capture_opts) {
645 ws_process_id fork_child;
647 if_stat_cache_t *sc = NULL;
648 if_stat_cache_item_t *sc_item;
652 /* Fire up dumpcap. */
654 * XXX - on systems with BPF, the number of BPF devices limits the
655 * number of devices on which you can capture simultaneously.
659 * 1) this might fail if you run out of BPF devices
663 * 2) opening every interface could leave too few BPF devices
664 * for *other* programs.
666 * It also means the system could end up getting a lot of traffic
667 * that it has to pass through the networking stack and capture
668 * mechanism, so opening all the devices and presenting packet
669 * counts might not always be a good idea.
671 if (sync_interface_stats_open(&stat_fd, &fork_child, &msg, NULL) == 0) {
672 sc = (if_stat_cache_t *)g_malloc(sizeof(if_stat_cache_t));
673 sc->stat_fd = stat_fd;
674 sc->fork_child = fork_child;
675 sc->cache_list = NULL;
677 /* Initialize the cache */
678 for (i = 0; i < capture_opts->all_ifaces->len; i++) {
679 device = g_array_index(capture_opts->all_ifaces, interface_t, i);
680 if (device.type != IF_PIPE) {
681 sc_item = (if_stat_cache_item_t *)g_malloc0(sizeof(if_stat_cache_item_t));
682 sc_item->name = g_strdup(device.if_info.name);
683 sc->cache_list = g_list_append(sc->cache_list, sc_item);
687 g_free(msg); /* XXX: should we display this to the user ? */
692 #define MAX_STAT_LINE_LEN 500
695 capture_stat_cache_update(if_stat_cache_t *sc) {
696 gchar stat_line[MAX_STAT_LINE_LEN] = "";
699 if_stat_cache_item_t *sc_item;
704 while (sync_pipe_gets_nonblock(sc->stat_fd, stat_line, MAX_STAT_LINE_LEN) > 0) {
705 g_strstrip(stat_line);
706 stat_parts = g_strsplit(stat_line, "\t", 3);
707 if (stat_parts[0] == NULL || stat_parts[1] == NULL ||
708 stat_parts[2] == NULL) {
709 g_strfreev(stat_parts);
712 for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
713 sc_item = (if_stat_cache_item_t *)sc_entry->data;
714 if (strcmp(sc_item->name, stat_parts[0]) == 0) {
715 sc_item->ps.ps_recv = (u_int) strtoul(stat_parts[1], NULL, 10);
716 sc_item->ps.ps_drop = (u_int) strtoul(stat_parts[2], NULL, 10);
719 g_strfreev(stat_parts);
724 capture_stats(if_stat_cache_t *sc, char *ifname, struct pcap_stat *ps) {
726 if_stat_cache_item_t *sc_item;
728 if (!sc || !ifname || !ps) {
732 capture_stat_cache_update(sc);
733 for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
734 sc_item = (if_stat_cache_item_t *)sc_entry->data;
735 if (strcmp(sc_item->name, ifname) == 0) {
736 memcpy(ps, &sc_item->ps, sizeof(struct pcap_stat));
744 capture_stat_stop(if_stat_cache_t *sc) {
746 if_stat_cache_item_t *sc_item;
753 ret = sync_interface_stats_close(&sc->stat_fd, &sc->fork_child, &msg);
755 /* XXX - report failure? */
759 for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
760 sc_item = (if_stat_cache_item_t *)sc_entry->data;
761 g_free(sc_item->name);
764 g_list_free(sc->cache_list);
768 #endif /* HAVE_LIBPCAP */
771 * Editor modelines - https://www.wireshark.org/tools/modelines.html
776 * indent-tabs-mode: nil
779 * ex: set shiftwidth=2 tabstop=8 expandtab:
780 * :indentSize=2:tabSize=8:noTabs=true: