diff options
author | sahlberg <sahlberg@f5534014-38df-0310-8fa8-9805f1628bb7> | 2002-09-04 09:40:29 +0000 |
---|---|---|
committer | sahlberg <sahlberg@f5534014-38df-0310-8fa8-9805f1628bb7> | 2002-09-04 09:40:29 +0000 |
commit | d877a68073c87e1086a91e09eb27fb689a888213 (patch) | |
tree | 90bdf086756c8f41361d49ed02ea7adfa1bbd84a /tap.c | |
parent | dae25046ab705aecb027589f760d57c5c26d8328 (diff) |
Tap api. tap is a simple api that can be used for arbitrary extensions.
One example extension is rpcstat.
Try -Z rpc,rtt,100003,3 as argument to tethereal when reading a capture
containing NFSv3 packets.
tap-rpcstat.[ch] is intended to demonstrate the api and can be used to
base other extensions on.
git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@6175 f5534014-38df-0310-8fa8-9805f1628bb7
Diffstat (limited to 'tap.c')
-rw-r--r-- | tap.c | 406 |
1 files changed, 406 insertions, 0 deletions
@@ -0,0 +1,406 @@ +/* tap.c + * packet tap interface 2002 Ronnie Sahlberg + * + * $Id: tap.c,v 1.1 2002/09/04 09:40:24 sahlberg Exp $ + * + * 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 "tap.h" + +int tapping_is_active=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; + void (*reset)(void *tapdata); + int (*packet)(void *tapdata, packet_info *pinfo, void *data); + void (*draw)(void *tapdata); +} tap_listener_t; +static tap_listener_t *tap_listener_queue=NULL; + +static union wtap_pseudo_header *l_pseudo_header=NULL; +static const u_char *l_buf=NULL; +static frame_data *l_fdata; + + +/* ********************************************************************** + * 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=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=malloc(sizeof(tap_dissector_t)); + td->next=NULL; + td->name=malloc(strlen(name)); + strcpy(td->name, 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_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; + } + +/*printf("tap_queue_packet %d %d\n",pinfo->fd->num,tapping_is_active);*/ + /* 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. + This is very cheap since we just prepend the used queue to the free queue. +*/ +void +tap_queue_init(union wtap_pseudo_header *pseudo_header, const u_char *buf, frame_data *fdata) +{ + tap_packet_t *tpt; + + l_pseudo_header=pseudo_header; + l_buf=buf; + l_fdata=fdata; + +/*printf("tap_queue_init\n");*/ + tapping_is_active=1; + + tpt=tap_packet_list_queue; + if(!tpt){ + return; + } + + 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; + +} + +/* 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(void) +{ + tap_packet_t *tp; + tap_listener_t *tl; + epan_dissect_t *edt; + + tapping_is_active=0; +/*printf("tap_push_tapped_queue\n");*/ + for(tp=tap_packet_list_queue;tp;tp=tp->next){ + for(tl=tap_listener_queue;tl;tl=tl->next){ + if(tp->tap_id==tl->tap_id){ + int passed=TRUE; + if(tl->code){ + edt=epan_dissect_new(TRUE, FALSE); + epan_dissect_prime_dfilter(edt, tl->code); + epan_dissect_run(edt, + l_pseudo_header, + l_buf, + l_fdata, + NULL); + passed=dfilter_apply_edt(tl->code, edt); + epan_dissect_free(edt); + } + if(passed && tl->packet){ + tl->needs_redraw|=tl->packet(tl->tapdata, tp->pinfo, tp->tap_specific_data); + } + } + } + } + + /*draw_tap_listeners();*/ /*XXX until we have a thread for this */ +} + +/* 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; + +/*printf("reset_tap_listeners\n");*/ + for(tl=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; + +/*printf("draw_tap_listeners\n");*/ + for(tl=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 the RS (Really Simple api) extension 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 : + * 0: ok. + * !0: error +*/ +int +register_tap_listener(char *tapname, void *tapdata, char *fstring, void (*reset)(void *tapdata), int (*packet)(void *tapdata, packet_info *pinfo, void *data), void (*draw)(void *tapdata)) +{ + tap_listener_t *tl; + int tap_id; + + tap_id=find_tap_id(tapname); + if(!tap_id){ + fprintf(stderr, "tap not found\n"); + exit(10); + } + + tl=g_malloc(sizeof(tap_listener_t)); + tl->code=NULL; + tl->needs_redraw=1; + if(fstring){ + if(!dfilter_compile(fstring ,&tl->code)){ + g_free(tl); + fprintf(stderr,"register_tap_listener(): %s\n", dfilter_error_msg); + return 1; + } + } + + tl->tap_id=tap_id; + tl->tapdata=tapdata; + tl->reset=reset; + tl->packet=packet; + tl->draw=draw; + tl->next=tap_listener_queue; + + tap_listener_queue=tl; + + return 0; +} + +/* 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_queue; + tap_listener_queue=tap_listener_queue->next; + } else { + for(tl2=tap_listener_queue;tl2->next;tl=tl2->next){ + if(tl2->next->tapdata==tapdata){ + tl=tl2->next; + tl2->next=tl2->next->next; + break; + } + + } + } + + if(tl->code){ + dfilter_free(tl->code); + } + g_free(tl); + return; +} + + |