aboutsummaryrefslogtreecommitdiffstats
path: root/epan/tap.c
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2004-09-29 00:06:36 +0000
committerGuy Harris <guy@alum.mit.edu>2004-09-29 00:06:36 +0000
commit6472876ab34d2aa016e0b2afa0348d45ce551c86 (patch)
treed43921a8c5c3de76255c3c98ec29b5589838db95 /epan/tap.c
parent53ab91826b303f7091c411d03e6430c4558d1c99 (diff)
Move the tap infrastructure to the epan directory.
svn path=/trunk/; revision=12128
Diffstat (limited to 'epan/tap.c')
-rw-r--r--epan/tap.c432
1 files changed, 432 insertions, 0 deletions
diff --git a/epan/tap.c b/epan/tap.c
new file mode 100644
index 0000000000..e73ab58a6f
--- /dev/null
+++ b/epan/tap.c
@@ -0,0 +1,432 @@
+/* tap.c
+ * packet tap interface 2002 Ronnie Sahlberg
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#include <string.h>
+#include "epan/packet_info.h"
+#include "epan/dfilter/dfilter.h"
+#include <epan/tap.h>
+
+static gboolean tapping_is_active=FALSE;
+int num_tap_filters=0;
+
+typedef struct _tap_dissector_t {
+ struct _tap_dissector_t *next;
+ char *name;
+} tap_dissector_t;
+static tap_dissector_t *tap_dissector_list=NULL;
+
+/*
+ * This is the list of free and used packets queued for a tap.
+ * It is implemented here explicitely instead of using GLib objects
+ * in order to be as fast as possible as we need to build and tear down the
+ * queued list at least once for each packet we see, thus we must be able
+ * to build and tear it down as fast as possible.
+ */
+typedef struct _tap_packet_t {
+ struct _tap_packet_t *next;
+ int tap_id;
+ packet_info *pinfo;
+ void *tap_specific_data;
+} tap_packet_t;
+static tap_packet_t *tap_packet_list_free=NULL;
+static tap_packet_t *tap_packet_list_queue=NULL;
+#define TAP_PACKET_QUEUE_LEN 100
+
+
+typedef struct _tap_listener_t {
+ struct _tap_listener_t *next;
+ int tap_id;
+ int needs_redraw;
+ dfilter_t *code;
+ void *tapdata;
+ tap_reset_cb reset;
+ tap_packet_cb packet;
+ tap_draw_cb draw;
+} tap_listener_t;
+static volatile tap_listener_t *tap_listener_queue=NULL;
+
+/* **********************************************************************
+ * Init routine only called from epan at application startup
+ * ********************************************************************** */
+/* This function is called once when ethereal starts up and is used
+ to init any data structures we may need later.
+*/
+void
+tap_init(void)
+{
+ int i;
+ tap_packet_t *tpt;
+
+ for(i=0;i<TAP_PACKET_QUEUE_LEN;i++){
+ tpt=g_malloc(sizeof(tap_packet_t));
+ tpt->next=tap_packet_list_free;
+ tap_packet_list_free=tpt;
+ }
+ tap_packet_list_queue=NULL;
+
+ return;
+}
+
+
+
+/* **********************************************************************
+ * Functions called from dissector when made tappable
+ * ********************************************************************** */
+/* the following two functions are used from dissectors to
+ 1, register the ability to tap packets from this subdissector
+ 2, push packets encountered by the subdissector to anyone tapping
+*/
+
+/* This function registers that a dissector has the packet tap ability
+ available. The name parameter is the name of this tap and extensions can
+ use open_tap(char *name,... to specify that it wants to receive packets/
+ events from this tap.
+
+ This function is only to be called once, when the dissector initializes.
+
+ The return value from this call is later used as a parameter to the
+ tap_packet(unsinged int *tap_id,...
+ call so that the tap subsystem knows to which tap point this tapped
+ packet is associated.
+*/
+int
+register_tap(char *name)
+{
+ tap_dissector_t *td, *tdl;
+ int i;
+
+ td=g_malloc(sizeof(tap_dissector_t));
+ td->next=NULL;
+ td->name = g_strdup(name);
+
+ if(!tap_dissector_list){
+ tap_dissector_list=td;
+ i=1;
+ } else {
+ for(i=2,tdl=tap_dissector_list;tdl->next;i++,tdl=tdl->next)
+ ;
+ tdl->next=td;
+ }
+ return i;
+}
+
+
+/* Everytime the dissector has finished dissecting a packet (and all
+ subdissectors have returned) and if the dissector has been made "tappable"
+ it will push some data to everyone tapping this layer by a call
+ to tap_queue_packet().
+ The first parameter is the tap_id returned by the register_tap()
+ call for this dissector (so the tap system can keep track of who it came
+ from and who is listening to it)
+ The second is the packet_info structure which many tap readers will find
+ interesting.
+ The third argument is specific to each tap point or NULL if no additional
+ data is available to this tap. A tap point in say IP will probably want to
+ push the IP header structure here. Same thing for TCP and ONCRPC.
+
+ The pinfo and the specific pointer are what is supplied to every listener
+ in the read_callback() call made to every one currently listening to this
+ tap.
+
+ The tap reader is responsible to know how to parse any structure pointed
+ to by the tap specific data pointer.
+*/
+void
+tap_queue_packet(int tap_id, packet_info *pinfo, void *tap_specific_data)
+{
+ tap_packet_t *tpt;
+
+ if(!tapping_is_active){
+ return;
+ }
+
+ /* get a free tap_packet structure, this is CHEAP */
+ tpt=tap_packet_list_free;
+ tap_packet_list_free=tpt->next;
+ tpt->next=tap_packet_list_queue;
+ tap_packet_list_queue=tpt;
+
+ tpt->tap_id=tap_id;
+ tpt->pinfo=pinfo;
+ tpt->tap_specific_data=tap_specific_data;
+
+}
+
+
+
+
+
+/* **********************************************************************
+ * Functions used by file.c to drive the tap subsystem
+ * ********************************************************************** */
+/* This function is used to delete/initialize the tap queue and prime an
+ epan_dissect_t with all the filters for tap listeners.
+ To free the tap queue, we just prepend the used queue to the free queue.
+*/
+void
+tap_queue_init(epan_dissect_t *edt)
+{
+ tap_packet_t *tpt;
+ tap_listener_t *tl;
+
+ /* nothing to do, just return */
+ if(!tap_listener_queue){
+ return;
+ }
+
+ tapping_is_active=TRUE;
+ tpt=tap_packet_list_queue;
+ if(tpt){
+ for(;tpt->next;tpt=tpt->next)
+ ;
+
+ tpt->next=tap_packet_list_free;
+ tap_packet_list_free=tap_packet_list_queue;
+ tap_packet_list_queue=NULL;
+ }
+
+ /* loop over all tap listeners and build the list of all
+ interesting hf_fields */
+ for(tl=(tap_listener_t *)tap_listener_queue;tl;tl=tl->next){
+ if(tl->code){
+ epan_dissect_prime_dfilter(edt, tl->code);
+ }
+ }
+}
+
+/* this function is called after a packet has been fully dissected to push the tapped
+ data to all extensions that has callbacks registered.
+*/
+void
+tap_push_tapped_queue(epan_dissect_t *edt)
+{
+ tap_packet_t *tp;
+ tap_listener_t *tl;
+
+ /* nothing to do, just return */
+ if(!tapping_is_active){
+ return;
+ }
+
+ tapping_is_active=FALSE;
+
+ /* nothing to do, just return */
+ if(!tap_packet_list_queue){
+ return;
+ }
+
+ /* loop over all tap listeners and call the listener callback
+ for all packets that match the filter. */
+ for(tp=tap_packet_list_queue;tp;tp=tp->next){
+ for(tl=(tap_listener_t *)tap_listener_queue;tl;tl=tl->next){
+ if(tp->tap_id==tl->tap_id){
+ int passed=TRUE;
+ if(tl->code){
+ passed=dfilter_apply_edt(tl->code, edt);
+ }
+ if(passed && tl->packet){
+ tl->needs_redraw|=tl->packet(tl->tapdata, tp->pinfo, edt, tp->tap_specific_data);
+ }
+ }
+ }
+ }
+}
+
+/* This function is called when we need to reset all tap listeners, for example
+ when we open/start a new capture or if we need to rescan the packet list.
+*/
+void
+reset_tap_listeners(void)
+{
+ tap_listener_t *tl;
+
+ for(tl=(tap_listener_t *)tap_listener_queue;tl;tl=tl->next){
+ if(tl->reset){
+ tl->reset(tl->tapdata);
+ }
+ tl->needs_redraw=1;
+ }
+
+}
+
+
+/* This function is called when we need to redraw all tap listeners, for example
+ when we open/start a new capture or if we need to rescan the packet list.
+ this one should be called from a low priority thread say once every 3 seconds
+
+ If draw_all is true, redraw all aplications regardless if they have
+ changed or not.
+*/
+void
+draw_tap_listeners(gboolean draw_all)
+{
+ tap_listener_t *tl;
+
+ for(tl=(tap_listener_t *)tap_listener_queue;tl;tl=tl->next){
+ if(tl->needs_redraw || draw_all){
+ if(tl->draw){
+ tl->draw(tl->tapdata);
+ }
+ }
+ tl->needs_redraw=0;
+ }
+}
+
+
+
+/* **********************************************************************
+ * Functions used by tap to
+ * 1, register that a really simple extension is available for use by
+ * ethereal.
+ * 2, start tapping from a subdissector
+ * 3, close an already open tap
+ * ********************************************************************** */
+/* this function will return the tap_id for the specific protocol tap
+ or 0 if no such tap was found.
+ */
+int
+find_tap_id(char *name)
+{
+ tap_dissector_t *td;
+ int i;
+
+ for(i=1,td=tap_dissector_list;td;i++,td=td->next) {
+ if(!strcmp(td->name,name)){
+ return i;
+ }
+ }
+ return 0;
+}
+
+/* this function attaches the tap_listener to the named tap.
+ * function returns :
+ * NULL: ok.
+ * non-NULL: error, return value points to GString containing error
+ * message.
+ */
+GString *
+register_tap_listener(char *tapname, void *tapdata, char *fstring, tap_reset_cb reset, tap_packet_cb packet, tap_draw_cb draw)
+{
+ tap_listener_t *tl;
+ int tap_id;
+ GString *error_string;
+
+ tap_id=find_tap_id(tapname);
+ if(!tap_id){
+ error_string = g_string_new("");
+ g_string_sprintf(error_string, "Tap %s not found", tapname);
+ return error_string;
+ }
+
+ tl=g_malloc(sizeof(tap_listener_t));
+ tl->code=NULL;
+ tl->needs_redraw=1;
+ if(fstring){
+ if(!dfilter_compile(fstring, &tl->code)){
+ error_string = g_string_new("");
+ g_string_sprintf(error_string,
+ "Filter \"%s\" is invalid - %s",
+ fstring, dfilter_error_msg);
+ g_free(tl);
+ return error_string;
+ } else {
+ num_tap_filters++;
+ }
+ }
+
+ tl->tap_id=tap_id;
+ tl->tapdata=tapdata;
+ tl->reset=reset;
+ tl->packet=packet;
+ tl->draw=draw;
+ tl->next=(tap_listener_t *)tap_listener_queue;
+
+ tap_listener_queue=tl;
+
+ return NULL;
+}
+
+/* this function removes a tap listener
+ */
+void
+remove_tap_listener(void *tapdata)
+{
+ tap_listener_t *tl=NULL,*tl2;
+
+ if(!tap_listener_queue){
+ return;
+ }
+
+ if(tap_listener_queue->tapdata==tapdata){
+ tl=(tap_listener_t *)tap_listener_queue;
+ tap_listener_queue=tap_listener_queue->next;
+ } else {
+ for(tl2=(tap_listener_t *)tap_listener_queue;tl2->next;tl2=tl2->next){
+ if(tl2->next->tapdata==tapdata){
+ tl=tl2->next;
+ tl2->next=tl2->next->next;
+ break;
+ }
+
+ }
+ }
+
+ if(tl){
+ if(tl->code){
+ dfilter_free(tl->code);
+ num_tap_filters--;
+ }
+ g_free(tl);
+ }
+
+ return;
+}
+
+/*
+ * Return TRUE if we have tap listeners, FALSE otherwise.
+ * Checking "num_tap_filters" isn't the right way to check whether we need
+ * to do any dissection in order to run taps, as not all taps necessarily
+ * have filters, and "num_tap_filters" is the number of tap filters, not
+ * the number of tap listeners; it's only the right way to check whether
+ * we need to build a protocol tree when doing dissection.
+ */
+gboolean
+have_tap_listeners(void)
+{
+ return tap_listener_queue != NULL;
+}