Ethereal-dev: [Ethereal-dev] [PATCH] pcap_set_datalink()/BIOCSDLT support
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: Brian Fundakowski Feldman <bfeldman@xxxxxxxxxxxxxxx>
Date: Fri, 31 Oct 2003 13:14:39 -0500
Since pcap(3) has recently grown the ability to select from multiple available data link types on some platforms, it's very useful for Ethereal to support switching to a non-default capture format. I've tested this on FreeBSD, which means that the HAVE_PCAP_DATALINK_VAL_TO_NAME part remains untested but present for a system which might have it. After you select an interface, you can check the "Change _data link type" box and then pull down to select a data link type or enter your own (in my case, they are all numbers corresponding to the DLT_ values in the system headers). The drop-down box isn't available (and the check box unchecks itself) if the current value of the interface entry can't be used to look up a set of data link types. The gtk_combo_set_value_in_list() should be removed if someone sees a need to be able to enter a DLT number manually when the list of named DLT constants is available on a platform with pcap_datalink_val_to_name()... not sure if that would be remotely useful though :) Does anyone have any thoughts? -- Brian Fundakowski Feldman | http://www.fla.fujitsu.com/ Software Specialist | Fujitsu Laboratories of America
--- aclocal.m4 Wed Jul 23 18:37:22 2003 +++ ../ethereal-0.9.12/aclocal.m4 Mon Oct 27 14:14:12 2003 @@ -339,6 +339,25 @@ AC_DEFINE(HAVE_LIBPCAP, 1, [Define to use libpcap library]) ], [AC_MSG_ERROR(Library libpcap not found.)], $SOCKET_LIBS $NSL_LIBS) + + # + # Check to see if we find "pcap_set_datalink" in "-lpcap". + # + AC_CHECK_LIB(pcap, pcap_set_datalink, + [ + AC_DEFINE(HAVE_PCAP_SET_DATALINK, 1, [Define to use pcap multiple data link types]) + ], [AC_MSG_RESULT(Multiple data link types not required.)], + $SOCKET_LIBS $NSL_LIBS $PCAP_LIBS) + + # + # Check to see if we find "pcap_datalink_val_to_name" in "-lpcap". + # + AC_CHECK_LIB(pcap, pcap_datalink_val_to_name, + [ + AC_DEFINE(HAVE_PCAP_DATALINK_VAL_TO_NAME, 1, [Define to use pcap data link name/type translation]) + ], [AC_MSG_RESULT(Data link name/type conversion not required.)], + $SOCKET_LIBS $NSL_LIBS $PCAP_LIBS) + AC_SUBST(PCAP_LIBS) ]) --- capture.c.orig Wed Jul 23 18:33:25 2003 +++ capture.c Wed Oct 29 12:41:09 2003 @@ -393,6 +393,11 @@ argv = add_arg(argv, &argc, ssnap); } + if (capture_opts.linktype) { + argv = add_arg(argv, &argc, "-y"); + argv = add_arg(argv, &argc, capture_opts.linktype); + } + if (capture_opts.has_autostop_filesize) { argv = add_arg(argv, &argc, "-a"); sprintf(sautostop_filesize,"filesize:%d",capture_opts.autostop_filesize); @@ -1578,6 +1583,15 @@ error message from pcap_open_live() */ open_err_str[0] = '\0'; #endif + } + + /* setting the data link type only works on real interfaces */ + if (capture_opts.linktype) { + if (set_pcap_linktype(pch, cfile.iface, capture_opts.linktype) != 0) { + snprintf(errmsg, sizeof errmsg, "Unable to set %s pcap link type (%s).", + capture_opts.linktype, strerror(errno)); + goto error; + } } /* capture filters only work on real interfaces */ --- capture.h.orig Tue Oct 28 17:20:03 2003 +++ capture.h Tue Oct 28 17:19:58 2003 @@ -51,6 +51,7 @@ guint32 ringbuffer_num_files; /* Number of ring buffer files */ gboolean has_ring_duration; /* TRUE if ring duration specified */ gint32 ringbuffer_duration; /* Switch file after n seconds */ + gchar *linktype; /* String of data link type to use */ } capture_options; extern capture_options capture_opts; --- gtk/capture_dlg.c.orig Sat May 17 12:33:02 2003 +++ gtk/capture_dlg.c Wed Oct 29 12:48:55 2003 @@ -55,6 +55,8 @@ /* Capture callback data keys */ #define E_CAP_IFACE_KEY "cap_iface" #define E_CAP_SNAP_CB_KEY "cap_snap_cb" +#define E_CAP_LT_CB_KEY "cap_lt_cb" +#define E_CAP_LT_SEL_KEY "cap_lt_sel" #define E_CAP_SNAP_SB_KEY "cap_snap_sb" #define E_CAP_PROMISC_KEY "cap_promisc" #define E_CAP_FILT_KEY "cap_filter_te" @@ -104,6 +106,9 @@ static void capture_prep_destroy_cb(GtkWidget *win, gpointer user_data); +static void +capture_prep_interface_changed_cb(GtkWidget *entry, gpointer parent_w); + void capture_stop_cb(GtkWidget *w _U_, gpointer d _U_) { @@ -124,6 +129,7 @@ GtkWidget *main_vb, *capture_fr, *capture_vb, *if_hb, *if_cb, *if_lb, + *linktype_hb, *linktype_cb, *linktype_sel, *snap_hb, *snap_cb, *snap_sb, *snap_lb, *promisc_cb, *filter_hb, *filter_bt, *filter_te, @@ -238,6 +244,29 @@ free_interface_list(if_list); + /* Linktype row */ + linktype_hb = gtk_hbox_new(FALSE, 3); + gtk_container_add(GTK_CONTAINER(capture_vb), linktype_hb); + gtk_widget_show(linktype_hb); + +#if GTK_MAJOR_VERSION < 2 + linktype_cb = dlg_check_button_new_with_label_with_mnemonic( + "Change _data link type", accel_group); +#else + linktype_cb = gtk_check_button_new_with_mnemonic("Change _data link type"); +#endif + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(linktype_cb), + capture_opts.linktype != NULL); + SIGNAL_CONNECT(linktype_cb, "toggled", capture_prep_adjust_sensitivity, cap_open_w); + SIGNAL_CONNECT(GTK_ENTRY(GTK_COMBO(if_cb)->entry), "changed", capture_prep_interface_changed_cb, cap_open_w); + gtk_box_pack_start(GTK_BOX(linktype_hb), linktype_cb, FALSE, FALSE, 0); + gtk_widget_show(linktype_cb); + + linktype_sel = gtk_combo_new(); + gtk_combo_set_value_in_list(GTK_COMBO(linktype_sel), TRUE, TRUE); + gtk_box_pack_start (GTK_BOX(linktype_hb), linktype_sel, FALSE, FALSE, 0); + gtk_widget_show(linktype_sel); + /* Capture length row */ snap_hb = gtk_hbox_new(FALSE, 3); gtk_container_add(GTK_CONTAINER(capture_vb), snap_hb); @@ -583,6 +612,8 @@ OBJECT_SET_DATA(cap_open_w, E_CAP_IFACE_KEY, if_cb); OBJECT_SET_DATA(cap_open_w, E_CAP_SNAP_CB_KEY, snap_cb); OBJECT_SET_DATA(cap_open_w, E_CAP_SNAP_SB_KEY, snap_sb); + OBJECT_SET_DATA(cap_open_w, E_CAP_LT_CB_KEY, linktype_cb); + OBJECT_SET_DATA(cap_open_w, E_CAP_LT_SEL_KEY, linktype_sel); OBJECT_SET_DATA(cap_open_w, E_CAP_PROMISC_KEY, promisc_cb); OBJECT_SET_DATA(cap_open_w, E_CAP_FILT_KEY, filter_te); OBJECT_SET_DATA(cap_open_w, E_CAP_FILE_TE_KEY, file_te); @@ -752,6 +783,7 @@ capture_prep_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w) { GtkWidget *if_cb, *snap_cb, *snap_sb, *promisc_cb, *filter_te, *file_te, *ringbuffer_on_tb, *ringbuffer_nbf_sb, + *linktype_cb, *linktype_sel, *sync_cb, *auto_scroll_cb, *count_cb, *count_sb, *filesize_cb, *filesize_sb, @@ -768,6 +800,8 @@ if_cb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CAP_IFACE_KEY); snap_cb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CAP_SNAP_CB_KEY); snap_sb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CAP_SNAP_SB_KEY); + linktype_cb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CAP_LT_CB_KEY); + linktype_sel = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CAP_LT_SEL_KEY); promisc_cb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CAP_PROMISC_KEY); filter_te = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CAP_FILT_KEY); file_te = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CAP_FILE_TE_KEY); @@ -807,6 +841,15 @@ cfile.iface = g_strdup(if_name); g_free(if_text); + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linktype_cb))) { + g_free(capture_opts.linktype); + capture_opts.linktype = g_strdup(gtk_entry_get_text( + GTK_ENTRY(GTK_COMBO(linktype_sel)->entry))); + } else { + g_free(capture_opts.linktype); + capture_opts.linktype = NULL; + } + capture_opts.has_snaplen = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(snap_cb)); if (capture_opts.has_snaplen) { @@ -943,6 +986,22 @@ cap_open_w = NULL; } +static void +capture_prep_interface_changed_cb(GtkWidget *entry _U_, gpointer parent_w) +{ + GtkWidget *linktype_cb; + + linktype_cb = OBJECT_GET_DATA(parent_w, E_CAP_LT_CB_KEY); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linktype_cb), FALSE); +} + +static void +do_g_free(gpointer tofree, gpointer dontfree _U_) +{ + + g_free(tofree); +} + /* * Adjust the sensitivity of various widgets as per the current setting * of other widgets. @@ -950,14 +1009,17 @@ static void capture_prep_adjust_sensitivity(GtkWidget *tb _U_, gpointer parent_w) { - GtkWidget *snap_cb, *snap_sb, + GtkWidget *if_cb, + *snap_cb, *snap_sb, *ringbuffer_on_tb, *ringbuffer_nbf_lb, *ringbuffer_nbf_sb, *sync_cb, *auto_scroll_cb, *count_cb, *count_sb, *filesize_cb, *filesize_sb, *filesize_lb, *duration_cb, *duration_sb, - *ring_duration_cb, *ring_duration_sb; + *ring_duration_cb, *ring_duration_sb, + *linktype_cb, *linktype_sel; + if_cb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CAP_IFACE_KEY); snap_cb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CAP_SNAP_CB_KEY); snap_sb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CAP_SNAP_SB_KEY); ringbuffer_on_tb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CAP_RING_ON_TB_KEY); @@ -974,6 +1036,39 @@ filesize_lb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CAP_FILESIZE_LB_KEY); duration_cb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CAP_DURATION_CB_KEY); duration_sb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CAP_DURATION_SB_KEY); + linktype_cb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CAP_LT_CB_KEY); + linktype_sel = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CAP_LT_SEL_KEY); + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linktype_cb))) { + gchar *curif; + + curif = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry)); + /* Windows uses /^.* ifname$/ */ + if (strrchr(curif, ' ') != NULL) + curif = strrchr(curif, ' ') + 1; + if (curif != NULL) { + GList *lt_list; + + lt_list = get_pcap_linktype_list(curif); + if (lt_list == NULL) { + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(linktype_cb), FALSE); + } else { + gtk_combo_set_popdown_strings(GTK_COMBO(linktype_sel), lt_list); + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(linktype_sel)->entry), + g_list_nth_data(lt_list, 0)); + g_list_foreach(lt_list, do_g_free, NULL); + g_list_free(lt_list); + } + } else { + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(linktype_cb), FALSE); + } + } + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linktype_cb))) { + gtk_widget_set_sensitive(GTK_WIDGET(linktype_sel), TRUE); + } else { + gtk_widget_set_sensitive(GTK_WIDGET(linktype_sel), FALSE); + gtk_list_clear_items(GTK_LIST(GTK_COMBO(linktype_sel)->list), 0, -1); + } /* The snapshot length spinbox is sensitive iff the "Limit each packet to" checkbox is on. */ --- gtk/main.c.orig Wed Oct 29 12:43:26 2003 +++ gtk/main.c Wed Oct 29 12:47:54 2003 @@ -1187,7 +1187,7 @@ fprintf(stderr, "\t[ -o <preference setting> ] ... [ -P <packet list height> ]\n"); fprintf(stderr, "\t[ -r <infile> ] [ -R <read filter> ] [ -s <snaplen> ] \n"); fprintf(stderr, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n"); - fprintf(stderr, "\t[ -w <savefile> ] [ <infile> ]\n"); + fprintf(stderr, "\t[ -w <savefile> ] [ -y <linktype> ] [ <infile> ]\n"); #else fprintf(stderr, "\n%s [ -vh ] [ -n ] [ -B <byte view height> ] [ -m <medium font> ]\n", PACKAGE); @@ -1473,7 +1473,7 @@ ethereal_tap_list *tli = NULL; gchar *tap_opt = NULL; -#define OPTSTRING_INIT "a:b:B:c:f:hi:klm:nN:o:pP:Qr:R:Ss:t:T:w:vz:" +#define OPTSTRING_INIT "a:b:B:c:f:hi:klm:nN:o:pP:Qr:R:Ss:t:T:w:vy:z:" #ifdef HAVE_LIBPCAP #ifdef WIN32 @@ -1616,6 +1616,7 @@ capture_opts.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES; capture_opts.has_ring_duration = FALSE; capture_opts.ringbuffer_duration = 1; + capture_opts.linktype = NULL; /* If this is a capture child process, it should pay no attention to the "prefs.capture_prom_mode" setting in the preferences file; @@ -1866,6 +1867,14 @@ arg_error = TRUE; #endif break; + case 'y': /* Set the pcap data link type */ +#ifdef HAVE_LIBPCAP + capture_opts.linktype = g_strdup(optarg); +#else + capture_option_specified = TRUE; + arg_error = TRUE; +#endif + break; #ifdef HAVE_LIBPCAP /* This is a hidden option supporting Sync mode, so we don't set * the error flags for the user in the non-libpcap case. --- pcap-util.c Wed Jul 9 21:20:13 2003 +++ ../ethereal-0.9.12/pcap-util.c Tue Oct 28 16:16:20 2003 @@ -31,6 +31,7 @@ #include <glib.h> #include <stdlib.h> +#include <limits.h> #include <string.h> #include <stdio.h> #include <errno.h> @@ -194,6 +195,87 @@ } /* + * Get the data-link types available for a libpcap device. + */ +GList * +get_pcap_linktype_list(char *devname) +{ + GList *linktype_list = NULL; + pcap_t *pch; + char err_buf[PCAP_ERRBUF_SIZE]; +#ifdef HAVE_PCAP_SET_DATALINK + int *linktypes; + int i, nlt, deflt; +#endif + + pch = pcap_open_live(devname, MIN_PACKET_SIZE, 0, 0, err_buf); + if (pch == NULL) + return NULL; + deflt = get_pcap_linktype(pch, devname); + /* TODO: Map link numbers to names (pcap_datalink_val_to_name). */ +#ifdef HAVE_PCAP_SET_DATALINK + nlt = pcap_list_datalinks(pch, &linktypes); + if (nlt > 0) { + for (i = 0; i < nlt; i++) { + char *typename; +#ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME + typename = pcap_datalink_val_to_name(linktypes[i]); + if (typename != NULL) + typename = g_strdup(typename)); + else +#endif + typename = g_strdup_printf("%d", linktypes[i]); + if (linktypes[i] == deflt) + linktype_list = g_list_prepend(linktype_list, + typename); + else + linktype_list = g_list_append(linktype_list, + typename); + } + free(linktypes); + } else +#endif + linktype_list = g_list_append(linktype_list, + g_strdup_printf("%d (not modifiable)", + get_pcap_linktype(pch, devname))); + + pcap_close(pch); + return linktype_list; +} + +/* Set the data link type on a pcap, including name/val translation. */ +int +set_pcap_linktype(pcap_t *pch, char *devname, char *linktype) +{ + int val; + +#ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME + val = pcap_datalink_name_to_val(linktype); + if (val == -1) { +#endif + long lval; + char *endptr; + + lval = strtol(linktype, &endptr, 10); + if (*endptr != '\0' || lval < INT_MIN || lval > INT_MAX) { + errno = EINVAL; + return -1; + } + val = (int)lval; +#ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME + } +#endif +#ifdef HAVE_PCAP_SET_DATALINK + return (pcap_set_datalink(pch, val)); +#else + if (get_pcap_linktype(pch, devname) == val) + return 0; + errno = EINVAL; + return -1; +#endif +} + +/* * If the ability to capture packets is added to Wiretap, these * routines should be moved to the Wiretap source (with * "get_interface_list()" and "free_interface_list()" renamed to --- pcap-util.h Wed Aug 28 20:40:05 2002 +++ ../ethereal-0.9.12/pcap-util.h Mon Oct 27 16:39:42 2003 @@ -32,6 +32,8 @@ #endif /* __cplusplus */ int get_pcap_linktype(pcap_t *pch, char *devname); +GList *get_pcap_linktype_list(char *devname); +int set_pcap_linktype(pcap_t *pch, char *devname, gchar *linktype); GList *get_interface_list(int *err, char *err_str); --- tethereal.c.orig Wed Oct 29 12:36:36 2003 +++ tethereal.c Wed Oct 29 13:03:07 2003 @@ -192,6 +192,7 @@ guint32 ringbuffer_num_files; /* Number of ring buffer files */ gboolean has_ring_duration; /* TRUE if ring duration specified */ gint32 ringbuffer_duration; /* Switch file after n seconds */ + gchar *linktype; /* String of data link type to use */ } capture_options; static capture_options capture_opts = { @@ -210,7 +211,8 @@ RINGBUFFER_MIN_NUM_FILES, /* default number of ring buffer files */ FALSE, /* Switch ring file after some */ - 0 /* specified time is off by default */ + 0, /* specified time is off by default */ + NULL /* Default to not change link type */ }; #ifdef SIGINFO @@ -236,7 +238,7 @@ fprintf(stderr, "\t[ -f <capture filter> ] [ -F <output file type> ] [ -i <interface> ]\n"); fprintf(stderr, "\t[ -N <resolving> ] [ -o <preference setting> ] ... [ -r <infile> ]\n"); fprintf(stderr, "\t[ -R <read filter> ] [ -s <snaplen> ] [ -t <time stamp format> ]\n"); - fprintf(stderr, "\t[ -w <savefile> ] [ -Z <statistics string> ]\n"); + fprintf(stderr, "\t[ -w <savefile> ] [ -y <link type> ] [ -Z <statistics string> ]\n"); #else fprintf(stderr, "\nt%s [ -vh ] [ -lnVx ]\n", PACKAGE); fprintf(stderr, "\t[ -d %s ] ...\n", decode_as_arg_template); @@ -841,7 +843,7 @@ get_runtime_version_info(runtime_info_str); /* Now get our args */ - while ((opt = getopt(argc, argv, "a:b:c:d:Df:F:hi:lnN:o:pqr:R:s:St:vw:Vxz:")) != -1) { + while ((opt = getopt(argc, argv, "a:b:c:d:Df:F:hi:lnN:o:pqr:R:s:St:vw:Vxy:z:")) != -1) { switch (opt) { case 'a': /* autostop criteria */ #ifdef HAVE_LIBPCAP @@ -1038,6 +1040,14 @@ break; case 'x': /* Print packet data in hex (and ASCII) */ print_hex = TRUE; + break; + case 'y': /* Set the pcap data link type */ +#ifdef HAVE_LIBPCAP + capture_opts.linktype = g_strdup(optarg); +#else + capture_option_specified = TRUE; + arg_error = TRUE; +#endif break; case 'z': for(tli=tap_list;tli;tli=tli->next){
- Follow-Ups:
- Re: [Ethereal-dev] [PATCH] pcap_set_datalink()/BIOCSDLT support
- From: Guy Harris
- Re: [Ethereal-dev] [PATCH] pcap_set_datalink()/BIOCSDLT support
- Prev by Date: Re: [Ethereal-dev] Lack of close button on Conversation windows
- Next by Date: Re: [Ethereal-dev] [PATCH] ACN pluging update
- Previous by thread: Re: [Ethereal-dev] H225 vendorIdentifier [PATCH]
- Next by thread: Re: [Ethereal-dev] [PATCH] pcap_set_datalink()/BIOCSDLT support
- Index(es):