from Lars R
[obnox/wireshark/wip.git] / epan / tap.c
1 /* tap.c
2  * packet tap interface   2002 Ronnie Sahlberg
3  *
4  * $Id$
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  * 
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.
14  * 
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.
19  * 
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <stdio.h>
30
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34
35 #ifdef HAVE_NETINET_IN_H
36 # include <netinet/in.h>
37 #endif
38
39 #include <string.h>
40 #include "epan/packet_info.h"
41 #include "epan/dfilter/dfilter.h"
42 #include <epan/tap.h>
43
44 static gboolean tapping_is_active=FALSE;
45 int num_tap_filters=0;
46
47 typedef struct _tap_dissector_t {
48         struct _tap_dissector_t *next;
49         char *name;
50 } tap_dissector_t;
51 static tap_dissector_t *tap_dissector_list=NULL;
52
53 /*
54  * This is the list of free and used packets queued for a tap.
55  * It is implemented here explicitely instead of using GLib objects
56  * in order to be as fast as possible as we need to build and tear down the
57  * queued list at least once for each packet we see, thus we must be able
58  * to build and tear it down as fast as possible.
59  */
60 typedef struct _tap_packet_t {
61         int tap_id;
62         packet_info *pinfo;
63         const void *tap_specific_data;
64 } tap_packet_t;
65
66 #define TAP_PACKET_QUEUE_LEN 100
67 static tap_packet_t tap_packet_array[TAP_PACKET_QUEUE_LEN];
68 static guint tap_packet_index;
69
70 typedef struct _tap_listener_t {
71         struct _tap_listener_t *next;
72         int tap_id;
73         int needs_redraw;
74         dfilter_t *code;
75         void *tapdata;
76         tap_reset_cb reset;
77         tap_packet_cb packet;
78         tap_draw_cb draw;
79 } tap_listener_t;
80 static volatile tap_listener_t *tap_listener_queue=NULL;
81
82 /* structure to keep track of what tap listeners have registered
83    command-line arguments.
84  */
85 typedef struct _tap_cmd_arg {
86         struct _tap_cmd_arg *next;
87         char *cmd;
88         void (*func)(char *arg);
89 } tap_cmd_arg;
90 static tap_cmd_arg *tap_cmd_arg_list=NULL;
91
92 /* structure to keep track of what taps have been specified on the
93    command line.
94  */
95 typedef struct {
96         tap_cmd_arg *tca;
97         char *arg;
98 } tap_requested;
99 static GSList *taps_requested = NULL;
100
101 /* **********************************************************************
102  * Init routine only called from epan at application startup
103  * ********************************************************************** */
104 /* This function is called once when ethereal starts up and is used
105    to init any data structures we may need later.
106 */
107 void
108 tap_init(void)
109 {
110         tap_packet_index=0;
111
112         return;
113 }
114
115 /* **********************************************************************
116  * Function called from tap to register the tap's command-line argument
117  * and initialization routine
118  * ********************************************************************** */
119 void
120 register_tap_listener_cmd_arg(char *cmd, void (*func)(char *arg))
121 {
122         tap_cmd_arg *newtca;
123
124         newtca=malloc(sizeof(tap_cmd_arg));
125         newtca->next=tap_cmd_arg_list;
126         tap_cmd_arg_list=newtca;
127         newtca->cmd=cmd;
128         newtca->func=func;
129 }
130
131 /* **********************************************************************
132  * Function called for a tap command-line argument
133  * ********************************************************************** */
134 gboolean
135 process_tap_cmd_arg(char *optarg)
136 {
137         tap_cmd_arg *tca;
138         tap_requested *tr;
139
140         for(tca=tap_cmd_arg_list;tca;tca=tca->next){
141                 if(!strncmp(tca->cmd,optarg,strlen(tca->cmd))){
142                         tr=g_malloc(sizeof (tap_requested));
143                         tr->tca = tca;
144                         tr->arg=g_strdup(optarg);
145                         taps_requested=g_slist_append(taps_requested, tr);
146                         return TRUE;
147                 }
148         }
149         return FALSE;
150 }
151
152 /* **********************************************************************
153  * Function to list all possible tap command-line arguments
154  * ********************************************************************** */
155 void
156 list_tap_cmd_args(void)
157 {
158         tap_cmd_arg *tca;
159
160         for(tca=tap_cmd_arg_list;tca;tca=tca->next){
161                 fprintf(stderr,"     %s\n",tca->cmd);
162         }
163 }
164
165 /* **********************************************************************
166  * Function to process taps requested with command-line arguments
167  * ********************************************************************** */
168 void
169 start_requested_taps(void)
170 {
171         tap_requested *tr;
172
173         while(taps_requested){
174                 tr=taps_requested->data;
175                 (*tr->tca->func)(tr->arg);
176                 g_free(tr->arg);
177                 g_free(tr);
178                 taps_requested=g_slist_remove(taps_requested, tr);
179         }
180 }
181
182 /* **********************************************************************
183  * Functions called from dissector when made tappable
184  * ********************************************************************** */
185 /* the following two functions are used from dissectors to
186    1, register the ability to tap packets from this subdissector
187    2, push packets encountered by the subdissector to anyone tapping
188 */
189
190 /* This function registers that a dissector has the packet tap ability
191    available.  The name parameter is the name of this tap and extensions can
192    use open_tap(char *name,... to specify that it wants to receive packets/
193    events from this tap.
194
195    This function is only to be called once, when the dissector initializes.
196
197    The return value from this call is later used as a parameter to the
198    tap_packet(unsinged int *tap_id,...
199    call so that the tap subsystem knows to which tap point this tapped
200    packet is associated.
201 */  
202 int
203 register_tap(char *name)
204 {
205         tap_dissector_t *td, *tdl;
206         int i;
207
208         td=g_malloc(sizeof(tap_dissector_t));
209         td->next=NULL;
210         td->name = g_strdup(name);
211
212         if(!tap_dissector_list){
213                 tap_dissector_list=td;
214                 i=1;
215         } else {
216                 for(i=2,tdl=tap_dissector_list;tdl->next;i++,tdl=tdl->next)
217                         ;
218                 tdl->next=td;
219         }
220         return i;
221 }
222
223
224 /* Everytime the dissector has finished dissecting a packet (and all
225    subdissectors have returned) and if the dissector has been made "tappable"
226    it will push some data to everyone tapping this layer by a call
227    to tap_queue_packet().
228    The first parameter is the tap_id returned by the register_tap()
229    call for this dissector (so the tap system can keep track of who it came
230    from and who is listening to it)
231    The second is the packet_info structure which many tap readers will find
232    interesting.
233    The third argument is specific to each tap point or NULL if no additional 
234    data is available to this tap.  A tap point in say IP will probably want to
235    push the IP header structure here. Same thing for TCP and ONCRPC.
236   
237    The pinfo and the specific pointer are what is supplied to every listener
238    in the read_callback() call made to every one currently listening to this
239    tap.
240  
241    The tap reader is responsible to know how to parse any structure pointed 
242    to by the tap specific data pointer.
243 */
244 void 
245 tap_queue_packet(int tap_id, packet_info *pinfo, const void *tap_specific_data)
246 {
247         tap_packet_t *tpt;
248
249         if(!tapping_is_active){
250                 return;
251         }
252
253         tpt=&tap_packet_array[tap_packet_index];
254         tpt->tap_id=tap_id;
255         tpt->pinfo=pinfo;
256         tpt->tap_specific_data=tap_specific_data;
257         tap_packet_index++;
258 }
259
260
261
262
263
264 /* **********************************************************************
265  * Functions used by file.c to drive the tap subsystem
266  * ********************************************************************** */
267 /* This function is used to delete/initialize the tap queue and prime an
268    epan_dissect_t with all the filters for tap listeners.
269    To free the tap queue, we just prepend the used queue to the free queue.
270 */
271 void
272 tap_queue_init(epan_dissect_t *edt)
273 {
274         tap_listener_t *tl;
275
276         /* nothing to do, just return */
277         if(!tap_listener_queue){
278                 return;
279         }
280
281         tapping_is_active=TRUE;
282
283         tap_packet_index=0;
284
285         /* loop over all tap listeners and build the list of all
286            interesting hf_fields */
287         for(tl=(tap_listener_t *)tap_listener_queue;tl;tl=tl->next){
288                 if(tl->code){
289                         epan_dissect_prime_dfilter(edt, tl->code);
290                 }
291         }
292 }
293
294 /* this function is called after a packet has been fully dissected to push the tapped
295    data to all extensions that has callbacks registered.
296 */
297 void 
298 tap_push_tapped_queue(epan_dissect_t *edt)
299 {
300         tap_packet_t *tp;
301         tap_listener_t *tl;
302         guint i;
303
304         /* nothing to do, just return */
305         if(!tapping_is_active){
306                 return;
307         }
308
309         tapping_is_active=FALSE;
310
311         /* nothing to do, just return */
312         if(!tap_packet_index){
313                 return;
314         }
315
316         /* loop over all tap listeners and call the listener callback
317            for all packets that match the filter. */
318         for(i=0;i<tap_packet_index;i++){
319                 for(tl=(tap_listener_t *)tap_listener_queue;tl;tl=tl->next){
320                         tp=&tap_packet_array[i];
321                         if(tp->tap_id==tl->tap_id){
322                                 int passed=TRUE;
323                                 if(tl->code){
324                                         passed=dfilter_apply_edt(tl->code, edt);
325                                 }
326                                 if(passed && tl->packet){
327                                         tl->needs_redraw|=tl->packet(tl->tapdata, tp->pinfo, edt, tp->tap_specific_data);
328                                 }
329                         }
330                 }
331         }
332 }
333
334 /* This function is called when we need to reset all tap listeners, for example
335    when we open/start a new capture or if we need to rescan the packet list.
336 */
337 void
338 reset_tap_listeners(void)
339 {
340         tap_listener_t *tl;
341
342         for(tl=(tap_listener_t *)tap_listener_queue;tl;tl=tl->next){
343                 if(tl->reset){
344                         tl->reset(tl->tapdata);
345                 }
346                 tl->needs_redraw=1;
347         }
348
349 }
350
351
352 /* This function is called when we need to redraw all tap listeners, for example
353    when we open/start a new capture or if we need to rescan the packet list.
354    this one should be called from a low priority thread say once every 3 seconds
355  
356    If draw_all is true, redraw all aplications regardless if they have 
357    changed or not.
358 */
359 void
360 draw_tap_listeners(gboolean draw_all)
361 {
362         tap_listener_t *tl;
363
364         for(tl=(tap_listener_t *)tap_listener_queue;tl;tl=tl->next){
365                 if(tl->needs_redraw || draw_all){
366                         if(tl->draw){
367                                 tl->draw(tl->tapdata);
368                         }
369                 }
370                 tl->needs_redraw=0;
371         }
372 }
373
374
375
376 /* **********************************************************************
377  * Functions used by tap to
378  * 1, register that a really simple extension is available for use by
379  *    ethereal. 
380  * 2, start tapping from a subdissector 
381  * 3, close an already open tap
382  * ********************************************************************** */
383 /* this function will return the tap_id for the specific protocol tap
384    or 0 if no such tap was found.
385  */
386 int 
387 find_tap_id(char *name)
388 {
389         tap_dissector_t *td;
390         int i;
391
392         for(i=1,td=tap_dissector_list;td;i++,td=td->next) {
393                 if(!strcmp(td->name,name)){
394                         return i;
395                 }
396         }
397         return 0;
398 }
399
400 /* this function attaches the tap_listener to the named tap.
401  * function returns :
402  *     NULL: ok.
403  * non-NULL: error, return value points to GString containing error
404  *           message.
405  */
406 GString *
407 register_tap_listener(char *tapname, void *tapdata, char *fstring, tap_reset_cb reset, tap_packet_cb packet, tap_draw_cb draw)
408 {
409         tap_listener_t *tl;
410         int tap_id;
411         GString *error_string;
412
413         tap_id=find_tap_id(tapname);
414         if(!tap_id){
415                 error_string = g_string_new("");
416                 g_string_sprintf(error_string, "Tap %s not found", tapname);
417                 return error_string;
418         }
419
420         tl=g_malloc(sizeof(tap_listener_t));
421         tl->code=NULL;
422         tl->needs_redraw=1;
423         if(fstring){
424                 if(!dfilter_compile(fstring, &tl->code)){
425                         error_string = g_string_new("");
426                         g_string_sprintf(error_string,
427                             "Filter \"%s\" is invalid - %s",
428                             fstring, dfilter_error_msg);
429                         g_free(tl);
430                         return error_string;
431                 } else {
432                         num_tap_filters++;
433                 }
434         }
435
436         tl->tap_id=tap_id;
437         tl->tapdata=tapdata;
438         tl->reset=reset;
439         tl->packet=packet;
440         tl->draw=draw;
441         tl->next=(tap_listener_t *)tap_listener_queue;
442
443         tap_listener_queue=tl;
444
445         return NULL;
446 }
447
448 /* this function removes a tap listener
449  */
450 void
451 remove_tap_listener(void *tapdata)
452 {
453         tap_listener_t *tl=NULL,*tl2;
454
455         if(!tap_listener_queue){
456                 return;
457         }
458
459         if(tap_listener_queue->tapdata==tapdata){
460                 tl=(tap_listener_t *)tap_listener_queue;
461                 tap_listener_queue=tap_listener_queue->next;
462         } else {
463                 for(tl2=(tap_listener_t *)tap_listener_queue;tl2->next;tl2=tl2->next){
464                         if(tl2->next->tapdata==tapdata){
465                                 tl=tl2->next;
466                                 tl2->next=tl2->next->next;
467                                 break;
468                         }
469                         
470                 }
471         }
472
473         if(tl){
474                 if(tl->code){
475                         dfilter_free(tl->code);
476                         num_tap_filters--;
477                 }
478                 g_free(tl);
479         }
480
481         return;
482 }
483
484 /*
485  * Return TRUE if we have tap listeners, FALSE otherwise.
486  * Checking "num_tap_filters" isn't the right way to check whether we need
487  * to do any dissection in order to run taps, as not all taps necessarily
488  * have filters, and "num_tap_filters" is the number of tap filters, not
489  * the number of tap listeners; it's only the right way to check whether
490  * we need to build a protocol tree when doing dissection.
491  */
492 gboolean
493 have_tap_listeners(void)
494 {
495         return tap_listener_queue != NULL;
496 }