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