HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / tap.c
blob7ac5e54bc620f1618e5601eaa687055014d8545a
1 /* tap.c
2 * packet tap interface 2002 Ronnie Sahlberg
4 * $Id$
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "config.h"
27 #include <stdio.h>
29 #ifdef HAVE_SYS_TYPES_H
30 # include <sys/types.h>
31 #endif
33 #ifdef HAVE_NETINET_IN_H
34 # include <netinet/in.h>
35 #endif
37 #include <string.h>
38 #include <epan/packet_info.h>
39 #include <epan/dfilter/dfilter.h>
40 #include <epan/tap.h>
42 static gboolean tapping_is_active=FALSE;
44 typedef struct _tap_dissector_t {
45 struct _tap_dissector_t *next;
46 char *name;
47 } tap_dissector_t;
48 static tap_dissector_t *tap_dissector_list=NULL;
51 * This is the list of free and used packets queued for a tap.
52 * It is implemented here explicitly instead of using GLib objects
53 * in order to be as fast as possible as we need to build and tear down the
54 * queued list at least once for each packet we see and thus we must be able
55 * to build and tear it down as fast as possible.
57 typedef struct _tap_packet_t {
58 int tap_id;
59 packet_info *pinfo;
60 const void *tap_specific_data;
61 } tap_packet_t;
63 #define TAP_PACKET_QUEUE_LEN 100
64 static tap_packet_t tap_packet_array[TAP_PACKET_QUEUE_LEN];
65 static guint tap_packet_index;
67 typedef struct _tap_listener_t {
68 struct _tap_listener_t *next;
69 int tap_id;
70 gboolean needs_redraw;
71 guint flags;
72 dfilter_t *code;
73 void *tapdata;
74 tap_reset_cb reset;
75 tap_packet_cb packet;
76 tap_draw_cb draw;
77 } tap_listener_t;
78 static volatile tap_listener_t *tap_listener_queue=NULL;
80 /* **********************************************************************
81 * Init routine only called from epan at application startup
82 * ********************************************************************** */
83 /* This function is called once when wireshark starts up and is used
84 to init any data structures we may need later.
86 void
87 tap_init(void)
89 tap_packet_index=0;
91 return;
94 /* **********************************************************************
95 * Functions called from dissector when made tappable
96 * ********************************************************************** */
97 /* the following two functions are used from dissectors to
98 1. register the ability to tap packets from this subdissector
99 2. push packets encountered by the subdissector to anyone tapping
102 /* This function registers that a dissector has the packet tap ability
103 available. The name parameter is the name of this tap and extensions can
104 use open_tap(char *name,... to specify that it wants to receive packets/
105 events from this tap.
107 This function is only to be called once, when the dissector initializes.
109 The return value from this call is later used as a parameter to the
110 tap_packet(unsigned int *tap_id,...
111 call so that the tap subsystem knows to which tap point this tapped
112 packet is associated.
115 register_tap(const char *name)
117 tap_dissector_t *td, *tdl;
118 int i, tap_id;
120 if(tap_dissector_list){
121 tap_id=find_tap_id(name);
122 if (tap_id)
123 return tap_id;
126 td=(tap_dissector_t *)g_malloc(sizeof(tap_dissector_t));
127 td->next=NULL;
128 td->name = g_strdup(name);
130 if(!tap_dissector_list){
131 tap_dissector_list=td;
132 i=1;
133 } else {
134 for(i=2,tdl=tap_dissector_list;tdl->next;i++,tdl=tdl->next)
136 tdl->next=td;
138 return i;
142 /* Everytime the dissector has finished dissecting a packet (and all
143 subdissectors have returned) and if the dissector has been made "tappable"
144 it will push some data to everyone tapping this layer by a call
145 to tap_queue_packet().
146 The first parameter is the tap_id returned by the register_tap()
147 call for this dissector (so the tap system can keep track of who it came
148 from and who is listening to it)
149 The second is the packet_info structure which many tap readers will find
150 interesting.
151 The third argument is specific to each tap point or NULL if no additional
152 data is available to this tap. A tap point in say IP will probably want to
153 push the IP header structure here. Same thing for TCP and ONCRPC.
155 The pinfo and the specific pointer are what is supplied to every listener
156 in the read_callback() call made to every one currently listening to this
157 tap.
159 The tap reader is responsible to know how to parse any structure pointed
160 to by the tap specific data pointer.
162 void
163 tap_queue_packet(int tap_id, packet_info *pinfo, const void *tap_specific_data)
165 tap_packet_t *tpt;
167 if(!tapping_is_active){
168 return;
171 * XXX - should we allocate this with an ep_allocator,
172 * rather than having a fixed maximum number of entries?
174 if(tap_packet_index >= TAP_PACKET_QUEUE_LEN){
175 g_warning("Too many taps queued");
176 return;
179 tpt=&tap_packet_array[tap_packet_index];
180 tpt->tap_id=tap_id;
181 tpt->pinfo=pinfo;
182 tpt->tap_specific_data=tap_specific_data;
183 tap_packet_index++;
190 /* **********************************************************************
191 * Functions used by file.c to drive the tap subsystem
192 * ********************************************************************** */
194 void tap_build_interesting (epan_dissect_t *edt)
196 tap_listener_t *tl;
198 /* nothing to do, just return */
199 if(!tap_listener_queue){
200 return;
203 /* loop over all tap listeners and build the list of all
204 interesting hf_fields */
205 for(tl=(tap_listener_t *)tap_listener_queue;tl;tl=tl->next){
206 if(tl->code){
207 epan_dissect_prime_dfilter(edt, tl->code);
212 /* This function is used to delete/initialize the tap queue and prime an
213 epan_dissect_t with all the filters for tap listeners.
214 To free the tap queue, we just prepend the used queue to the free queue.
216 void
217 tap_queue_init(epan_dissect_t *edt)
219 /* nothing to do, just return */
220 if(!tap_listener_queue){
221 return;
224 tapping_is_active=TRUE;
226 tap_packet_index=0;
228 tap_build_interesting (edt);
231 /* this function is called after a packet has been fully dissected to push the tapped
232 data to all extensions that has callbacks registered.
234 void
235 tap_push_tapped_queue(epan_dissect_t *edt)
237 tap_packet_t *tp;
238 tap_listener_t *tl;
239 guint i;
241 /* nothing to do, just return */
242 if(!tapping_is_active){
243 return;
246 tapping_is_active=FALSE;
248 /* nothing to do, just return */
249 if(!tap_packet_index){
250 return;
253 /* loop over all tap listeners and call the listener callback
254 for all packets that match the filter. */
255 for(i=0;i<tap_packet_index;i++){
256 for(tl=(tap_listener_t *)tap_listener_queue;tl;tl=tl->next){
257 tp=&tap_packet_array[i];
258 if(tp->tap_id==tl->tap_id){
259 gboolean passed=TRUE;
260 if(tl->code){
261 passed=dfilter_apply_edt(tl->code, edt);
263 if(passed && tl->packet){
264 tl->needs_redraw|=tl->packet(tl->tapdata, tp->pinfo, edt, tp->tap_specific_data);
272 /* This function can be used by a dissector to fetch any tapped data before
273 * returning.
274 * This can be useful if one wants to extract the data inside dissector BEFORE
275 * it exists as an alternative to the callbacks that are all called AFTER the
276 * dissection has completed.
278 * Example: SMB2 uses this mechanism to extract the data tapped from NTLMSSP
279 * containing the account and domain names before exiting.
280 * Note that the SMB2 tap listener specifies all three callbacks as NULL.
282 * Beware: when using this mechanism to extract the tapped data you can not
283 * use "filters" and should specify the "filter" as NULL when registering
284 * the tap listener.
286 const void *
287 fetch_tapped_data(int tap_id, int idx)
289 tap_packet_t *tp;
290 guint i;
292 /* nothing to do, just return */
293 if(!tapping_is_active){
294 return NULL;
297 /* nothing to do, just return */
298 if(!tap_packet_index){
299 return NULL;
302 /* loop over all tapped packets and return the one with index idx */
303 for(i=0;i<tap_packet_index;i++){
304 tp=&tap_packet_array[i];
305 if(tp->tap_id==tap_id){
306 if(!idx--){
307 return tp->tap_specific_data;
312 return NULL;
315 /* This function is called when we need to reset all tap listeners, for example
316 when we open/start a new capture or if we need to rescan the packet list.
318 void
319 reset_tap_listeners(void)
321 tap_listener_t *tl;
323 for(tl=(tap_listener_t *)tap_listener_queue;tl;tl=tl->next){
324 if(tl->reset){
325 tl->reset(tl->tapdata);
327 tl->needs_redraw=TRUE;
333 /* This function is called when we need to redraw all tap listeners, for example
334 when we open/start a new capture or if we need to rescan the packet list.
335 It should be called from a low priority thread say once every 3 seconds
337 If draw_all is true, redraw all aplications regardless if they have
338 changed or not.
340 void
341 draw_tap_listeners(gboolean draw_all)
343 tap_listener_t *tl;
345 for(tl=(tap_listener_t *)tap_listener_queue;tl;tl=tl->next){
346 if(tl->needs_redraw || draw_all){
347 if(tl->draw){
348 tl->draw(tl->tapdata);
351 tl->needs_redraw=FALSE;
357 /* **********************************************************************
358 * Functions used by tap to
359 * 1. register that a really simple extension is available for use by
360 * Wireshark.
361 * 2. start tapping from a subdissector
362 * 3. close an already open tap
363 * ********************************************************************** */
364 /* this function will return the tap_id for the specific protocol tap
365 or 0 if no such tap was found.
368 find_tap_id(const char *name)
370 tap_dissector_t *td;
371 int i;
373 for(i=1,td=tap_dissector_list;td;i++,td=td->next) {
374 if(!strcmp(td->name,name)){
375 return i;
378 return 0;
381 /* this function attaches the tap_listener to the named tap.
382 * function returns :
383 * NULL: ok.
384 * non-NULL: error, return value points to GString containing error
385 * message.
387 GString *
388 register_tap_listener(const char *tapname, void *tapdata, const char *fstring,
389 guint flags, tap_reset_cb reset, tap_packet_cb packet, tap_draw_cb draw)
391 tap_listener_t *tl;
392 int tap_id;
393 GString *error_string;
395 tap_id=find_tap_id(tapname);
396 if(!tap_id){
397 error_string = g_string_new("");
398 g_string_printf(error_string, "Tap %s not found", tapname);
399 return error_string;
402 tl=(tap_listener_t *)g_malloc(sizeof(tap_listener_t));
403 tl->code=NULL;
404 tl->needs_redraw=TRUE;
405 tl->flags=flags;
406 if(fstring){
407 if(!dfilter_compile(fstring, &tl->code)){
408 error_string = g_string_new("");
409 g_string_printf(error_string,
410 "Filter \"%s\" is invalid - %s",
411 fstring, dfilter_error_msg);
412 g_free(tl);
413 return error_string;
417 tl->tap_id=tap_id;
418 tl->tapdata=tapdata;
419 tl->reset=reset;
420 tl->packet=packet;
421 tl->draw=draw;
422 tl->next=(tap_listener_t *)tap_listener_queue;
424 tap_listener_queue=tl;
426 return NULL;
429 /* this function sets a new dfilter to a tap listener
431 GString *
432 set_tap_dfilter(void *tapdata, const char *fstring)
434 tap_listener_t *tl=NULL,*tl2;
435 GString *error_string;
437 if(!tap_listener_queue){
438 return NULL;
441 if(tap_listener_queue->tapdata==tapdata){
442 tl=(tap_listener_t *)tap_listener_queue;
443 } else {
444 for(tl2=(tap_listener_t *)tap_listener_queue;tl2->next;tl2=tl2->next){
445 if(tl2->next->tapdata==tapdata){
446 tl=tl2->next;
447 break;
453 if(tl){
454 if(tl->code){
455 dfilter_free(tl->code);
456 tl->code=NULL;
458 tl->needs_redraw=TRUE;
459 if(fstring){
460 if(!dfilter_compile(fstring, &tl->code)){
461 error_string = g_string_new("");
462 g_string_printf(error_string,
463 "Filter \"%s\" is invalid - %s",
464 fstring, dfilter_error_msg);
465 return error_string;
470 return NULL;
473 /* this function removes a tap listener
475 void
476 remove_tap_listener(void *tapdata)
478 tap_listener_t *tl=NULL,*tl2;
480 if(!tap_listener_queue){
481 return;
484 if(tap_listener_queue->tapdata==tapdata){
485 tl=(tap_listener_t *)tap_listener_queue;
486 tap_listener_queue=tap_listener_queue->next;
487 } else {
488 for(tl2=(tap_listener_t *)tap_listener_queue;tl2->next;tl2=tl2->next){
489 if(tl2->next->tapdata==tapdata){
490 tl=tl2->next;
491 tl2->next=tl2->next->next;
492 break;
498 if(tl){
499 if(tl->code){
500 dfilter_free(tl->code);
502 g_free(tl);
505 return;
509 * Return TRUE if we have one or more tap listeners that require dissection,
510 * FALSE otherwise.
512 gboolean
513 tap_listeners_require_dissection(void)
515 volatile tap_listener_t *tap_queue = tap_listener_queue;
517 while(tap_queue) {
518 if(!(tap_queue->flags & TL_IS_DISSECTOR_HELPER))
519 return TRUE;
521 tap_queue = tap_queue->next;
524 return FALSE;
528 /* Returns TRUE there is an active tap listener for the specified tap id. */
529 gboolean
530 have_tap_listener(int tap_id)
532 volatile tap_listener_t *tap_queue = tap_listener_queue;
534 while(tap_queue) {
535 if(tap_queue->tap_id == tap_id)
536 return TRUE;
538 tap_queue = tap_queue->next;
541 return FALSE;
545 * Return TRUE if we have any tap listeners with filters, FALSE otherwise.
547 gboolean
548 have_filtering_tap_listeners(void)
550 tap_listener_t *tl;
552 for(tl=(tap_listener_t *)tap_listener_queue;tl;tl=tl->next){
553 if(tl->code)
554 return TRUE;
556 return FALSE;
560 * Get the union of all the flags for all the tap listeners; that gives
561 * an indication of whether the protocol tree, or the columns, are
562 * required by any taps.
564 guint
565 union_of_tap_listener_flags(void)
567 tap_listener_t *tl;
568 guint flags = 0;
570 for(tl=(tap_listener_t *)tap_listener_queue;tl;tl=tl->next){
571 flags|=tl->flags;
573 return flags;