Rename address_to_str() to ep_address_to_str() because:
[obnox/wireshark/wip.git] / tap-iousers.c
1 /* tap-iousers.c
2  * iostat   2003 Ronnie Sahlberg
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
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 #include <string.h>
36 #include <epan/packet_info.h>
37 #include <epan/packet.h>
38 #include <epan/addr_resolv.h>
39 #include <epan/tap.h>
40 #include <epan/conversation.h>
41 #include <epan/stat_cmd_args.h>
42 #include "register.h"
43 #include <epan/dissectors/packet-ip.h>
44 #include <epan/dissectors/packet-ipx.h>
45 #include <epan/dissectors/packet-tcp.h>
46 #include <epan/dissectors/packet-udp.h>
47 #include <epan/dissectors/packet-eth.h>
48 #include <epan/dissectors/packet-sctp.h>
49 #include <epan/dissectors/packet-tr.h>
50 #include <epan/dissectors/packet-scsi.h>
51 #include <epan/dissectors/packet-fc.h>
52 #include <epan/dissectors/packet-fddi.h>
53
54 typedef struct _io_users_t {
55         const char *type;
56         char *filter;
57         struct _io_users_item_t *items;
58 } io_users_t;
59
60 typedef struct _io_users_item_t {
61         struct _io_users_item_t *next;
62         char *name1;
63         char *name2;
64         address addr1;
65         address addr2;
66         guint32 frames1;
67         guint32 frames2;
68         guint64 bytes1;
69         guint64 bytes2;
70 } io_users_item_t;
71
72
73 static int
74 iousers_udpip_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vudph)
75 {
76         io_users_t *iu=arg;
77         const e_udphdr *udph=vudph;
78         char name1[256],name2[256];
79         io_users_item_t *iui;
80         int direction=0;
81
82         if(udph->uh_sport>udph->uh_dport){
83                 direction=0;
84                 g_snprintf(name1,256,"%s:%s",ep_address_to_str(&udph->ip_src),get_udp_port(udph->uh_sport));
85                 g_snprintf(name2,256,"%s:%s",ep_address_to_str(&udph->ip_dst),get_udp_port(udph->uh_dport));
86         } else if(udph->uh_sport<udph->uh_dport){
87                 direction=1;
88                 g_snprintf(name2,256,"%s:%s",ep_address_to_str(&udph->ip_src),get_udp_port(udph->uh_sport));
89                 g_snprintf(name1,256,"%s:%s",ep_address_to_str(&udph->ip_dst),get_udp_port(udph->uh_dport));
90         } else if(CMP_ADDRESS(&udph->ip_src, &udph->ip_dst)>0){
91                 direction=0;
92                 g_snprintf(name1,256,"%s:%s",ep_address_to_str(&udph->ip_src),get_udp_port(udph->uh_sport));
93                 g_snprintf(name2,256,"%s:%s",ep_address_to_str(&udph->ip_dst),get_udp_port(udph->uh_dport));
94         } else {
95                 direction=1;
96                 g_snprintf(name2,256,"%s:%s",ep_address_to_str(&udph->ip_src),get_udp_port(udph->uh_sport));
97                 g_snprintf(name1,256,"%s:%s",ep_address_to_str(&udph->ip_dst),get_udp_port(udph->uh_dport));
98         }
99
100         for(iui=iu->items;iui;iui=iui->next){
101                 if((!strcmp(iui->name1, name1))
102                 && (!strcmp(iui->name2, name2)) ){
103                         break;
104                 }
105         }
106
107         if(!iui){
108                 iui=g_malloc(sizeof(io_users_item_t));
109                 iui->next=iu->items;
110                 iu->items=iui;
111 /*              iui->addr1=NULL;*/
112                 iui->name1=g_strdup(name1);
113 /*              iui->addr2=NULL;*/
114                 iui->name2=g_strdup(name2);
115                 iui->frames1=0;
116                 iui->frames2=0;
117                 iui->bytes1=0;
118                 iui->bytes2=0;
119         }
120
121         if(direction){
122                 iui->frames1++;
123                 iui->bytes1+=pinfo->fd->pkt_len;
124         } else {
125                 iui->frames2++;
126                 iui->bytes2+=pinfo->fd->pkt_len;
127         }
128
129         return 1;
130 }
131
132
133 static int
134 iousers_sctp_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vsctp)
135 {
136         io_users_t *iu=arg;
137         const struct _sctp_info* sctph = vsctp;
138         char name1[256],name2[256], s_sport[10], s_dport[10];
139         io_users_item_t *iui;
140         int direction=0;
141
142         g_snprintf(s_sport, sizeof s_sport, "%d",sctph->sport);
143         g_snprintf(s_dport, sizeof s_dport, "%d",sctph->dport);
144
145         if(sctph->sport > sctph->dport) {
146                 direction=0;
147                 g_snprintf(name1,256,"%s:%s",ep_address_to_str(&sctph->ip_src),s_sport);
148                 g_snprintf(name2,256,"%s:%s",ep_address_to_str(&sctph->ip_dst),s_dport);
149         } else if(sctph->sport < sctph->dport) {
150                 direction=1;
151                 g_snprintf(name1,256,"%s:%s",ep_address_to_str(&sctph->ip_src),s_sport);
152                 g_snprintf(name2,256,"%s:%s",ep_address_to_str(&sctph->ip_dst),s_dport);
153         } else {
154                 direction=0;
155                 g_snprintf(name1,256,"%s:%s",ep_address_to_str(&sctph->ip_src),s_sport);
156                 g_snprintf(name2,256,"%s:%s",ep_address_to_str(&sctph->ip_dst),s_dport);
157         }
158
159         for(iui=iu->items;iui;iui=iui->next){
160                 if((!strcmp(iui->name1, name1))
161                  && (!strcmp(iui->name2, name2)) ){
162                         break;
163                 }
164         }
165
166         if(!iui){
167                 iui=g_malloc(sizeof(io_users_item_t));
168                 iui->next=iu->items;
169                 iu->items=iui;
170 /*              iui->addr1=NULL;*/
171                 iui->name1=g_strdup(name1);
172 /*              iui->addr2=NULL;*/
173                 iui->name2=g_strdup(name2);
174                 iui->frames1=0;
175                 iui->frames2=0;
176                 iui->bytes1=0;
177                 iui->bytes2=0;
178         }
179
180         if(direction){
181                 iui->frames1++;
182                 iui->bytes1+=pinfo->fd->pkt_len;
183         } else {
184                 iui->frames2++;
185                 iui->bytes2+=pinfo->fd->pkt_len;
186         }
187
188         return 1;
189 }
190
191
192 static int
193 iousers_tcpip_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vtcph)
194 {
195         io_users_t *iu=arg;
196         const struct tcpheader *tcph=vtcph;
197         char name1[256],name2[256];
198         io_users_item_t *iui;
199         int direction=0;
200
201         if(tcph->th_sport>tcph->th_dport){
202                 direction=0;
203                 g_snprintf(name1,256,"%s:%s",ep_address_to_str(&tcph->ip_src),get_tcp_port(tcph->th_sport));
204                 g_snprintf(name2,256,"%s:%s",ep_address_to_str(&tcph->ip_dst),get_tcp_port(tcph->th_dport));
205         } else if(tcph->th_sport<tcph->th_dport){
206                 direction=1;
207                 g_snprintf(name2,256,"%s:%s",ep_address_to_str(&tcph->ip_src),get_tcp_port(tcph->th_sport));
208                 g_snprintf(name1,256,"%s:%s",ep_address_to_str(&tcph->ip_dst),get_tcp_port(tcph->th_dport));
209         } else if(CMP_ADDRESS(&tcph->ip_src, &tcph->ip_dst)>0){
210                 direction=0;
211                 g_snprintf(name1,256,"%s:%s",ep_address_to_str(&tcph->ip_src),get_tcp_port(tcph->th_sport));
212                 g_snprintf(name2,256,"%s:%s",ep_address_to_str(&tcph->ip_dst),get_tcp_port(tcph->th_dport));
213         } else {
214                 direction=1;
215                 g_snprintf(name2,256,"%s:%s",ep_address_to_str(&tcph->ip_src),get_tcp_port(tcph->th_sport));
216                 g_snprintf(name1,256,"%s:%s",ep_address_to_str(&tcph->ip_dst),get_tcp_port(tcph->th_dport));
217         }
218
219         for(iui=iu->items;iui;iui=iui->next){
220                 if((!strcmp(iui->name1, name1))
221                 && (!strcmp(iui->name2, name2)) ){
222                         break;
223                 }
224         }
225
226         if(!iui){
227                 iui=g_malloc(sizeof(io_users_item_t));
228                 iui->next=iu->items;
229                 iu->items=iui;
230 /*              iui->addr1=NULL;*/
231                 iui->name1=g_strdup(name1);
232 /*              iui->addr2=NULL;*/
233                 iui->name2=g_strdup(name2);
234                 iui->frames1=0;
235                 iui->frames2=0;
236                 iui->bytes1=0;
237                 iui->bytes2=0;
238         }
239
240         if(direction){
241                 iui->frames1++;
242                 iui->bytes1+=pinfo->fd->pkt_len;
243         } else {
244                 iui->frames2++;
245                 iui->bytes2+=pinfo->fd->pkt_len;
246         }
247
248         return 1;
249 }
250
251
252 static int
253 iousers_ip_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
254 {
255         io_users_t *iu=arg;
256         const ws_ip *iph=vip;
257         const address *addr1, *addr2;
258         io_users_item_t *iui;
259
260         if(CMP_ADDRESS(&iph->ip_src, &iph->ip_dst)>0){
261                 addr1=&iph->ip_src;
262                 addr2=&iph->ip_dst;
263         } else {
264                 addr2=&iph->ip_src;
265                 addr1=&iph->ip_dst;
266         }
267
268         for(iui=iu->items;iui;iui=iui->next){
269                 if((!CMP_ADDRESS(&iui->addr1, addr1))
270                 &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
271                         break;
272                 }
273         }
274
275         if(!iui){
276                 iui=g_malloc(sizeof(io_users_item_t));
277                 iui->next=iu->items;
278                 iu->items=iui;
279                 COPY_ADDRESS(&iui->addr1, addr1);
280                 iui->name1=g_strdup(ep_address_to_str(addr1));
281                 COPY_ADDRESS(&iui->addr2, addr2);
282                 iui->name2=g_strdup(ep_address_to_str(addr2));
283                 iui->frames1=0;
284                 iui->frames2=0;
285                 iui->bytes1=0;
286                 iui->bytes2=0;
287         }
288
289         if(!CMP_ADDRESS(&iph->ip_dst, &iui->addr1)){
290                 iui->frames1++;
291                 iui->bytes1+=pinfo->fd->pkt_len;
292         } else {
293                 iui->frames2++;
294                 iui->bytes2+=pinfo->fd->pkt_len;
295         }
296
297         return 1;
298 }
299
300 static int
301 iousers_ipx_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vipx)
302 {
303         io_users_t *iu=arg;
304         const ipxhdr_t *ipxh=vipx;
305         const address *addr1, *addr2;
306         io_users_item_t *iui;
307
308         if(CMP_ADDRESS(&ipxh->ipx_src, &ipxh->ipx_dst)>0){
309                 addr1=&ipxh->ipx_src;
310                 addr2=&ipxh->ipx_dst;
311         } else {
312                 addr2=&ipxh->ipx_src;
313                 addr1=&ipxh->ipx_dst;
314         }
315
316         for(iui=iu->items;iui;iui=iui->next){
317                 if((!CMP_ADDRESS(&iui->addr1, addr1))
318                 &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
319                         break;
320                 }
321         }
322
323         if(!iui){
324                 iui=g_malloc(sizeof(io_users_item_t));
325                 iui->next=iu->items;
326                 iu->items=iui;
327                 COPY_ADDRESS(&iui->addr1, addr1);
328                 iui->name1=g_strdup(ep_address_to_str(addr1));
329                 COPY_ADDRESS(&iui->addr2, addr2);
330                 iui->name2=g_strdup(ep_address_to_str(addr2));
331                 iui->frames1=0;
332                 iui->frames2=0;
333                 iui->bytes1=0;
334                 iui->bytes2=0;
335         }
336
337         if(!CMP_ADDRESS(&ipxh->ipx_dst, &iui->addr1)){
338                 iui->frames1++;
339                 iui->bytes1+=pinfo->fd->pkt_len;
340         } else {
341                 iui->frames2++;
342                 iui->bytes2+=pinfo->fd->pkt_len;
343         }
344
345         return 1;
346 }
347
348 static int
349 iousers_fc_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vfc)
350 {
351         io_users_t *iu=arg;
352         const fc_hdr *fchdr=vfc;
353         const address *addr1, *addr2;
354         io_users_item_t *iui;
355
356         if(CMP_ADDRESS(&fchdr->s_id, &fchdr->d_id)<0){
357                 addr1=&fchdr->s_id;
358                 addr2=&fchdr->d_id;
359         } else {
360                 addr2=&fchdr->s_id;
361                 addr1=&fchdr->d_id;
362         }
363
364         for(iui=iu->items;iui;iui=iui->next){
365                 if((!CMP_ADDRESS(&iui->addr1, addr1))
366                 &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
367                         break;
368                 }
369         }
370
371         if(!iui){
372                 iui=g_malloc(sizeof(io_users_item_t));
373                 iui->next=iu->items;
374                 iu->items=iui;
375                 COPY_ADDRESS(&iui->addr1, addr1);
376                 iui->name1=g_strdup(ep_address_to_str(addr1));
377                 COPY_ADDRESS(&iui->addr2, addr2);
378                 iui->name2=g_strdup(ep_address_to_str(addr2));
379                 iui->frames1=0;
380                 iui->frames2=0;
381                 iui->bytes1=0;
382                 iui->bytes2=0;
383         }
384
385         if(!CMP_ADDRESS(&fchdr->d_id,&iui->addr1)){
386                 iui->frames1++;
387                 iui->bytes1+=pinfo->fd->pkt_len;
388         } else {
389                 iui->frames2++;
390                 iui->bytes2+=pinfo->fd->pkt_len;
391         }
392
393         return 1;
394 }
395
396 static int
397 iousers_eth_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *veth)
398 {
399         io_users_t *iu=arg;
400         const eth_hdr *ehdr=veth;
401         const address *addr1, *addr2;
402         io_users_item_t *iui;
403
404         if(CMP_ADDRESS(&ehdr->src, &ehdr->dst)<0){
405                 addr1=&ehdr->src;
406                 addr2=&ehdr->dst;
407         } else {
408                 addr2=&ehdr->src;
409                 addr1=&ehdr->dst;
410         }
411
412         for(iui=iu->items;iui;iui=iui->next){
413                 if((!CMP_ADDRESS(&iui->addr1, addr1))
414                 &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
415                         break;
416                 }
417         }
418
419         if(!iui){
420                 iui=g_malloc(sizeof(io_users_item_t));
421                 iui->next=iu->items;
422                 iu->items=iui;
423                 COPY_ADDRESS(&iui->addr1, addr1);
424                 iui->name1=g_strdup(ep_address_to_str(addr1));
425                 COPY_ADDRESS(&iui->addr2, addr2);
426                 iui->name2=g_strdup(ep_address_to_str(addr2));
427                 iui->frames1=0;
428                 iui->frames2=0;
429                 iui->bytes1=0;
430                 iui->bytes2=0;
431         }
432
433         if(!CMP_ADDRESS(&ehdr->dst,&iui->addr1)){
434                 iui->frames1++;
435                 iui->bytes1+=pinfo->fd->pkt_len;
436         } else {
437                 iui->frames2++;
438                 iui->bytes2+=pinfo->fd->pkt_len;
439         }
440
441         return 1;
442 }
443
444 static int
445 iousers_fddi_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *veth)
446 {
447         io_users_t *iu=arg;
448         const fddi_hdr *ehdr=veth;
449         const address *addr1, *addr2;
450         io_users_item_t *iui;
451
452         if(CMP_ADDRESS(&ehdr->src, &ehdr->dst)<0){
453                 addr1=&ehdr->src;
454                 addr2=&ehdr->dst;
455         } else {
456                 addr2=&ehdr->src;
457                 addr1=&ehdr->dst;
458         }
459
460         for(iui=iu->items;iui;iui=iui->next){
461                 if((!CMP_ADDRESS(&iui->addr1, addr1))
462                 &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
463                         break;
464                 }
465         }
466
467         if(!iui){
468                 iui=g_malloc(sizeof(io_users_item_t));
469                 iui->next=iu->items;
470                 iu->items=iui;
471                 COPY_ADDRESS(&iui->addr1, addr1);
472                 iui->name1=g_strdup(ep_address_to_str(addr1));
473                 COPY_ADDRESS(&iui->addr2, addr2);
474                 iui->name2=g_strdup(ep_address_to_str(addr2));
475                 iui->frames1=0;
476                 iui->frames2=0;
477                 iui->bytes1=0;
478                 iui->bytes2=0;
479         }
480
481         if(!CMP_ADDRESS(&ehdr->dst,&iui->addr1)){
482                 iui->frames1++;
483                 iui->bytes1+=pinfo->fd->pkt_len;
484         } else {
485                 iui->frames2++;
486                 iui->bytes2+=pinfo->fd->pkt_len;
487         }
488
489         return 1;
490 }
491
492 static int
493 iousers_tr_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vtr)
494 {
495         io_users_t *iu=arg;
496         const tr_hdr *trhdr=vtr;
497         const address *addr1, *addr2;
498         io_users_item_t *iui;
499
500         if(CMP_ADDRESS(&trhdr->src, &trhdr->dst)<0){
501                 addr1=&trhdr->src;
502                 addr2=&trhdr->dst;
503         } else {
504                 addr2=&trhdr->src;
505                 addr1=&trhdr->dst;
506         }
507
508         for(iui=iu->items;iui;iui=iui->next){
509                 if((!CMP_ADDRESS(&iui->addr1, addr1))
510                 &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
511                         break;
512                 }
513         }
514
515         if(!iui){
516                 iui=g_malloc(sizeof(io_users_item_t));
517                 iui->next=iu->items;
518                 iu->items=iui;
519                 COPY_ADDRESS(&iui->addr1, addr1);
520                 iui->name1=g_strdup(ep_address_to_str(addr1));
521                 COPY_ADDRESS(&iui->addr2, addr2);
522                 iui->name2=g_strdup(ep_address_to_str(addr2));
523                 iui->frames1=0;
524                 iui->frames2=0;
525                 iui->bytes1=0;
526                 iui->bytes2=0;
527         }
528
529         if(!CMP_ADDRESS(&trhdr->dst,&iui->addr1)){
530                 iui->frames1++;
531                 iui->bytes1+=pinfo->fd->pkt_len;
532         } else {
533                 iui->frames2++;
534                 iui->bytes2+=pinfo->fd->pkt_len;
535         }
536
537         return 1;
538 }
539
540 static void
541 iousers_draw(void *arg)
542 {
543         io_users_t *iu = arg;
544         io_users_item_t *iui;
545         guint32 last_frames, max_frames;
546
547         printf("================================================================================\n");
548         printf("%s Conversations\n",iu->type);
549         printf("Filter:%s\n",iu->filter?iu->filter:"<No Filter>");
550         printf("                                               |       <-      | |       ->      | |     Total     |\n");
551         printf("                                               | Frames  Bytes | | Frames  Bytes | | Frames  Bytes |\n");
552         max_frames=0xffffffff;
553         do {
554                 last_frames=0;
555                 for(iui=iu->items;iui;iui=iui->next){
556                         guint32 tot_frames;
557                         tot_frames=iui->frames1+iui->frames2;
558
559                         if((tot_frames>last_frames)
560                         &&(tot_frames<max_frames)){
561                                 last_frames=tot_frames;
562                         }
563                 }
564                 for(iui=iu->items;iui;iui=iui->next){
565                         guint32 tot_frames;
566                         tot_frames=iui->frames1+iui->frames2;
567
568                         if(tot_frames==last_frames){
569                                 printf("%-20s <-> %-20s  %6d %9" G_GINT64_MODIFIER "d  %6d %9" G_GINT64_MODIFIER "d  %6d %9" G_GINT64_MODIFIER "d\n",
570                                         iui->name1, iui->name2,
571                                         iui->frames1, iui->bytes1,
572                                         iui->frames2, iui->bytes2,
573                                         iui->frames1+iui->frames2,
574                                         iui->bytes1+iui->bytes2
575                                 );
576                         }
577                 }
578                 max_frames=last_frames;
579         } while(last_frames);
580         printf("================================================================================\n");
581 }
582
583 static void
584 iousers_init(const char *optarg, void* userdata _U_)
585 {
586         const char *filter=NULL;
587         const char *tap_type, *tap_type_name;
588         tap_packet_cb packet_func;
589         io_users_t *iu=NULL;
590         GString *error_string;
591
592         if(!strncmp(optarg,"conv,eth",8)){
593                 if(optarg[8]==','){
594                         filter=optarg+9;
595                 } else {
596                         filter=NULL;
597                 }
598                 tap_type="eth";
599                 tap_type_name="Ethernet";
600                 packet_func=iousers_eth_packet;
601         } else if(!strncmp(optarg,"conv,fc",7)){
602                 if(optarg[7]==','){
603                         filter=optarg+8;
604                 } else {
605                         filter=NULL;
606                 }
607                 tap_type="fc";
608                 tap_type_name="Fibre Channel";
609                 packet_func=iousers_fc_packet;
610         } else if(!strncmp(optarg,"conv,fddi",9)){
611                 if(optarg[9]==','){
612                         filter=optarg+10;
613                 } else {
614                         filter=NULL;
615                 }
616                 tap_type="fddi";
617                 tap_type_name="FDDI";
618                 packet_func=iousers_fddi_packet;
619         } else if(!strncmp(optarg,"conv,tcp",8)){
620                 if(optarg[8]==','){
621                         filter=optarg+9;
622                 } else {
623                         filter=NULL;
624                 }
625                 tap_type="tcp";
626                 tap_type_name="TCP";
627                 packet_func=iousers_tcpip_packet;
628         } else if(!strncmp(optarg,"conv,udp",8)){
629                 if(optarg[8]==','){
630                         filter=optarg+9;
631                 } else {
632                         filter=NULL;
633                 }
634                 tap_type="udp";
635                 tap_type_name="UDP";
636                 packet_func=iousers_udpip_packet;
637         } else if(!strncmp(optarg,"conv,tr",7)){
638                 if(optarg[7]==','){
639                         filter=optarg+8;
640                 } else {
641                         filter=NULL;
642                 }
643                 tap_type="tr";
644                 tap_type_name="Token Ring";
645                 packet_func=iousers_tr_packet;
646         } else if(!strncmp(optarg,"conv,ipx",8)){
647                 if(optarg[8]==','){
648                         filter=optarg+9;
649                 } else {
650                         filter=NULL;
651                 }
652                 tap_type="ipx";
653                 tap_type_name="IPX";
654                 packet_func=iousers_ipx_packet;
655         } else if(!strncmp(optarg,"conv,ip",7)){
656                 if(optarg[7]==','){
657                         filter=optarg+8;
658                 } else {
659                         filter=NULL;
660                 }
661                 tap_type="ip";
662                 tap_type_name="IPv4";
663                 packet_func=iousers_ip_packet;
664         } else if(!strncmp(optarg,"conv,sctp",9)) {
665                 if(optarg[9]==','){
666                                 filter=optarg+10;
667                 } else {
668                         filter=NULL;
669                 }
670                 tap_type="sctp";
671                 tap_type_name="SCTP";
672                 packet_func=iousers_sctp_packet;
673         } else {
674                 fprintf(stderr, "tshark: invalid \"-z conv,<type>[,<filter>]\" argument\n");
675                 fprintf(stderr,"   <type> must be one of\n");
676                 fprintf(stderr,"      \"eth\"\n");
677                 fprintf(stderr,"      \"fc\"\n");
678                 fprintf(stderr,"      \"fddi\"\n");
679                 fprintf(stderr,"      \"ip\"\n");
680                 fprintf(stderr,"      \"ipx\"\n");
681                 fprintf(stderr,"      \"sctp\"\n");
682                 fprintf(stderr,"      \"tcp\"\n");
683                 fprintf(stderr,"      \"tr\"\n");
684                 fprintf(stderr,"      \"udp\"\n");
685                 exit(1);
686         }
687
688
689         iu=g_malloc(sizeof(io_users_t));
690         iu->items=NULL;
691         iu->type=tap_type_name;
692         if(filter){
693                 iu->filter=g_strdup(filter);
694         } else {
695                 iu->filter=NULL;
696         }
697
698         error_string=register_tap_listener(tap_type, iu, filter, 0, NULL, packet_func, iousers_draw);
699         if(error_string){
700                 if(iu->items){
701                         g_free(iu->items);
702                 }
703                 g_free(iu);
704                 fprintf(stderr, "tshark: Couldn't register conversations tap: %s\n",
705                     error_string->str);
706                 g_string_free(error_string, TRUE);
707                 exit(1);
708         }
709
710 }
711
712 void
713 register_tap_listener_iousers(void)
714 {
715         register_stat_cmd_arg("conv,", iousers_init, NULL);
716 }