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