Ethereal-dev: [ethereal-dev] Patch to make capture counts work right on non-Ethernet

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: guy@xxxxxxxxxx (Guy Harris)
Date: Wed, 3 Feb 1999 19:52:02 -0800 (PST)
In the dialog box Ethereal puts up while doing a capture, the counts are
wrong if you're capturing on an FDDI interface, and probably if you're
capturing on any other non-Ethernet interface (or even if it's on
Ethernet and there's 802.3 traffic).

Here's a fix that adds some "capture_XXX" routines that dissect packets
enough to figure out whether they're IPv4 packets or not and, if they
are, to figure out the IP type, and that has the capture code call the
top-level capture routines for the various link types.

Those routines could conceivably do other things, e.g. dissecting the
packets some more and updating a display of captured packets.

This change *does* lengthen the code path when capturing; note that
Microsoft's Network Monitor, by default, has all sorts of stuff it
displays while capturing (% network utilization, frames/sec, bytes/sec,a
nd broacasts/sec bars, counts of packets that went between particular
MAC addresses, etc.), but also has a "dedicated capture" mode where it
iconifies its main window and leaves up only a dialog box with a count
of frames captured and buttons to stop the capture, etc..  The intent of
that mode is to minimize the CPU used by Network Monitor; if the fixed
Ethereal dialog box uses too much CPU, we may want to have it just
display a total packet count.

I'll check this into CVS in a few days if nobody comments on it....

Index: capture.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/capture.c,v
retrieving revision 1.17
diff -c -r1.17 capture.c
*** capture.c	1999/02/02 02:53:24	1.17
--- capture.c	1999/02/04 02:39:24
***************
*** 394,407 ****
    bpf_u_int32 netnum, netmask;
    time_t      upd_time, cur_time;
    
!   ld.go    = TRUE;
!   ld.count = 0;
!   ld.max   = cf.count;
!   ld.tcp   = 0;
!   ld.udp   = 0;
!   ld.ospf  = 0;
!   ld.other = 0;
!   ld.pdh   = NULL;
  
    close_cap_file(&cf, info_bar, file_ctx);
  
--- 394,408 ----
    bpf_u_int32 netnum, netmask;
    time_t      upd_time, cur_time;
    
!   ld.go           = TRUE;
!   ld.counts.total = 0;
!   ld.max          = cf.count;
!   ld.linktype     = DLT_NULL;
!   ld.counts.tcp   = 0;
!   ld.counts.udp   = 0;
!   ld.counts.ospf  = 0;
!   ld.counts.other = 0;
!   ld.pdh          = NULL;
  
    close_cap_file(&cf, info_bar, file_ctx);
  
***************
*** 420,425 ****
--- 421,427 ----
          return;
        }
      }
+     ld.linktype = pcap_datalink(pch);
  
      if (cf.cfilter) {
        if (pcap_lookupnet (cf.iface, &netnum, &netmask, err_str) < 0) {
***************
*** 488,507 ****
  
          upd_time = cur_time;
  
!         sprintf(label_str, "Count: %d", ld.count);
          gtk_label_set(GTK_LABEL(count_lb), label_str);
  
!         sprintf(label_str, "TCP: %d (%.1f%%)", ld.tcp, pct(ld.tcp, ld.count));
          gtk_label_set(GTK_LABEL(tcp_lb), label_str);
  
!         sprintf(label_str, "UDP: %d (%.1f%%)", ld.udp, pct(ld.udp, ld.count));
          gtk_label_set(GTK_LABEL(udp_lb), label_str);
  
!         sprintf(label_str, "OSPF: %d (%.1f%%)", ld.ospf, pct(ld.ospf, ld.count));
          gtk_label_set(GTK_LABEL(ospf_lb), label_str);
  
!         sprintf(label_str, "Other: %d (%.1f%%)", ld.other,
!           pct(ld.other, ld.count));
          gtk_label_set(GTK_LABEL(other_lb), label_str);
        }
      }
--- 490,512 ----
  
          upd_time = cur_time;
  
!         sprintf(label_str, "Count: %d", ld.counts.total);
          gtk_label_set(GTK_LABEL(count_lb), label_str);
  
!         sprintf(label_str, "TCP: %d (%.1f%%)", ld.counts.tcp,
! 	   pct(ld.counts.tcp, ld.counts.total));
          gtk_label_set(GTK_LABEL(tcp_lb), label_str);
  
!         sprintf(label_str, "UDP: %d (%.1f%%)", ld.counts.udp,
! 	  pct(ld.counts.udp, ld.counts.total));
          gtk_label_set(GTK_LABEL(udp_lb), label_str);
  
!         sprintf(label_str, "OSPF: %d (%.1f%%)", ld.counts.ospf,
! 	  pct(ld.counts.ospf, ld.counts.total));
          gtk_label_set(GTK_LABEL(ospf_lb), label_str);
  
!         sprintf(label_str, "Other: %d (%.1f%%)", ld.counts.other,
!           pct(ld.counts.other, ld.counts.total));
          gtk_label_set(GTK_LABEL(other_lb), label_str);
        }
      }
***************
*** 544,591 ****
  capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
    const u_char *pd) {
    
-   guint16 etype;
-   guint8  iptype = 0;
-   gint    offset = 14;
-   
    loop_data *ld = (loop_data *) user;
    
!   if ((++ld->count >= ld->max) && (ld->max > 0)) 
    {
       ld->go = FALSE;
    }
    /* Currently, pcap_dumper_t is a FILE *.  Let's hope that doesn't change. */
    if (ld->pdh) pcap_dump((u_char *) ld->pdh, phdr, pd);
-   
-   etype = etype = (pd[12] << 8) | pd[13];
-   if (etype <= IEEE_802_3_MAX_LEN) {
-     etype = (pd[20] << 8) | pd[21];
-     offset = 22;
-   }
    
!   switch(etype){ 
!     case ETHERTYPE_IP:
!       iptype = pd[offset + 9];
!       switch (iptype) {
!         case IP_PROTO_TCP:
!           ld->tcp++;
!           break;
!         case IP_PROTO_UDP:
!           ld->udp++;
!           break;
!         case IP_PROTO_OSPF:
!           ld->ospf++;
!           break;
!         default:
!           ld->other++;
!         }
!         break;
!       case ETHERTYPE_IPX:
!       case ETHERTYPE_IPv6:
!       case ETHERTYPE_ATALK:
!       case ETHERTYPE_VINES:
!       case ETHERTYPE_ARP:
!       default:
!         ld->other++;
    }
  }
--- 549,581 ----
  capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
    const u_char *pd) {
    
    loop_data *ld = (loop_data *) user;
    
!   if ((++ld->counts.total >= ld->max) && (ld->max > 0)) 
    {
       ld->go = FALSE;
    }
    /* Currently, pcap_dumper_t is a FILE *.  Let's hope that doesn't change. */
    if (ld->pdh) pcap_dump((u_char *) ld->pdh, phdr, pd);
    
!   switch (ld->linktype) {
!     case DLT_EN10MB :
!       capture_eth(pd, phdr->caplen, &ld->counts);
!       break;
!     case DLT_FDDI :
!       capture_fddi(pd, phdr->caplen, &ld->counts);
!       break;
!     case DLT_IEEE802 :
!       capture_tr(pd, phdr->caplen, &ld->counts);
!       break;
!     case DLT_NULL :
!       capture_null(pd, phdr->caplen, &ld->counts);
!       break;
!     case DLT_PPP :
!       capture_ppp(pd, phdr->caplen, &ld->counts);
!       break;
!     case DLT_RAW :
!       capture_raw(pd, phdr->caplen, &ld->counts);
!       break;
    }
  }

Index: capture.h
===================================================================
RCS file: /usr/local/cvsroot/ethereal/capture.h,v
retrieving revision 1.3
diff -c -r1.3 capture.h
*** capture.h	1998/09/29 21:39:29	1.3
--- capture.h	1999/02/04 02:39:24
***************
*** 28,39 ****
  
  typedef struct _loop_data {
    gint           go;
-   gint           count;
    gint           max;
!   gint           tcp;
!   gint           udp;
!   gint           ospf;
!   gint           other;
    pcap_dumper_t *pdh;
  } loop_data;
  
--- 28,36 ----
  
  typedef struct _loop_data {
    gint           go;
    gint           max;
!   gint           linktype;
!   packet_counts  counts;
    pcap_dumper_t *pdh;
  } loop_data;
  

Index: ethereal.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/ethereal.c,v
retrieving revision 1.20
diff -c -r1.20 ethereal.c
*** ethereal.c	1999/01/04 07:39:14	1.20
--- ethereal.c	1999/02/04 02:39:29
***************
*** 65,72 ****
  #endif
  
  #include "ethereal.h"
- #include "capture.h"
  #include "packet.h"
  #include "file.h"
  #include "menu.h"
  #include "etypes.h"
--- 65,72 ----
  #endif
  
  #include "ethereal.h"
  #include "packet.h"
+ #include "capture.h"
  #include "file.h"
  #include "menu.h"
  #include "etypes.h"

Index: ethertype.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/ethertype.c,v
retrieving revision 1.11
diff -c -r1.11 ethertype.c
*** ethertype.c	1998/12/19 00:12:19	1.11
--- ethertype.c	1999/02/04 02:39:29
***************
*** 62,67 ****
--- 62,81 ----
  }
  
  void
+ capture_ethertype(guint16 etype, int offset,
+ 		const u_char *pd, guint32 cap_len, packet_counts *ld)
+ {
+   switch (etype) {
+     case ETHERTYPE_IP:
+       capture_ip(pd, offset, cap_len, ld);
+       break;
+     default:
+       ld->other++;
+       break;
+   }
+ }
+ 
+ void
  ethertype(guint16 etype, int offset,
  		const u_char *pd, frame_data *fd, GtkTree *tree, GtkWidget
  		*fh_tree)
***************
*** 107,110 ****
        if (check_col(fd, COL_PROTOCOL)) { col_add_fstr(fd, COL_PROTOCOL, "0x%04x", etype); }
        break;
    }
!  }
--- 121,124 ----
        if (check_col(fd, COL_PROTOCOL)) { col_add_fstr(fd, COL_PROTOCOL, "0x%04x", etype); }
        break;
    }
! }

Index: menu.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/menu.c,v
retrieving revision 1.12
diff -c -r1.12 menu.c
*** menu.c	1998/12/27 20:46:45	1.12
--- menu.c	1999/02/04 02:39:30
***************
*** 36,43 ****
  
  #include "ethereal.h"
  #include "menu.h"
- #include "capture.h"
  #include "packet.h"
  #include "prefs.h"
  #include "print.h"
  #include "follow.h"
--- 36,43 ----
  
  #include "ethereal.h"
  #include "menu.h"
  #include "packet.h"
+ #include "capture.h"
  #include "prefs.h"
  #include "print.h"
  #include "follow.h"

Index: packet-eth.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-eth.c,v
retrieving revision 1.7
diff -c -r1.7 packet-eth.c
*** packet-eth.c	1998/11/17 04:28:52	1.7
--- packet-eth.c	1999/02/04 02:39:30
***************
*** 56,61 ****
--- 56,101 ----
  #define ETHERNET_SNAP	3
  
  void
+ capture_eth(const u_char *pd, guint32 cap_len, packet_counts *ld) {
+   guint16 etype;
+   int        offset = 14;
+   int   	ethhdr_type;	/* the type of ethernet frame */
+   
+   etype = (pd[12] << 8) | pd[13];
+ 
+ 	/* either ethernet802.3 or ethernet802.2 */
+   if (etype <= IEEE_802_3_MAX_LEN) {
+ 
+   /* Is there an 802.2 layer? I can tell by looking at the first 2
+      bytes after the 802.3 header. If they are 0xffff, then what
+      follows the 802.3 header is an IPX payload, meaning no 802.2.
+      (IPX/SPX is they only thing that can be contained inside a
+      straight 802.3 packet). A non-0xffff value means that there's an
+      802.2 layer inside the 802.3 layer */
+     if (pd[14] == 0xff && pd[15] == 0xff) {
+       ethhdr_type = ETHERNET_802_3;
+     }
+     else {
+       ethhdr_type = ETHERNET_802_2;
+     }
+   } else {
+     ethhdr_type = ETHERNET_II;
+   }
+ 
+   switch (ethhdr_type) {
+     case ETHERNET_802_3:
+       ld->other++;	/* IPX */
+       break;
+     case ETHERNET_802_2:
+       capture_llc(pd, offset, cap_len, ld);
+       break;
+     case ETHERNET_II:
+       capture_ethertype(etype, offset, pd, cap_len, ld);
+       break;
+   }
+ }
+ 
+ void
  dissect_eth(const u_char *pd, frame_data *fd, GtkTree *tree) {
    guint16    etype, length;
    int        offset = 14;
***************
*** 126,142 ****
      }
    }
  
- 	/* either ethernet802.3 or ethernet802.2 */
    switch (ethhdr_type) {
!   	case ETHERNET_802_3:
!   		dissect_ipx(pd, offset, fd, tree);
!   		return;
!   	case ETHERNET_802_2:
!   		dissect_llc(pd, offset, fd, tree);
!   		return;
    }
- 
-  	/* Ethernet_II */
-  	ethertype(etype, offset, pd, fd, tree, fh_tree);
  }
  
--- 166,181 ----
      }
    }
  
    switch (ethhdr_type) {
!     case ETHERNET_802_3:
!       dissect_ipx(pd, offset, fd, tree);
!       break;
!     case ETHERNET_802_2:
!       dissect_llc(pd, offset, fd, tree);
!       break;
!     case ETHERNET_II:
!       ethertype(etype, offset, pd, fd, tree, fh_tree);
!       break;
    }
  }
  

Index: packet-fddi.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-fddi.c,v
retrieving revision 1.8
diff -c -r1.8 packet-fddi.c
*** packet-fddi.c	1998/11/17 04:28:53	1.8
--- packet-fddi.c	1999/02/04 02:39:30
***************
*** 133,138 ****
--- 133,181 ----
    }
  }
  
+ void
+ capture_fddi(const u_char *pd, guint32 cap_len, packet_counts *ld) {
+   int        offset = 0, fc;
+ 
+   if (cap_len < FDDI_HEADER_SIZE) {
+     ld->other++;
+     return;
+   }
+   offset = FDDI_HEADER_SIZE;
+ 
+   fc = (int) pd[FDDI_P_FC];
+ 
+   switch (fc) {
+ 
+     /* From now, only 802.2 SNAP (Async. LCC frame) is supported */
+ 
+     case FDDI_FC_LLC_ASYNC + 0  :
+     case FDDI_FC_LLC_ASYNC + 1  :
+     case FDDI_FC_LLC_ASYNC + 2  :
+     case FDDI_FC_LLC_ASYNC + 3  :
+     case FDDI_FC_LLC_ASYNC + 4  :
+     case FDDI_FC_LLC_ASYNC + 5  :
+     case FDDI_FC_LLC_ASYNC + 6  :
+     case FDDI_FC_LLC_ASYNC + 7  :
+     case FDDI_FC_LLC_ASYNC + 8  :
+     case FDDI_FC_LLC_ASYNC + 9  :
+     case FDDI_FC_LLC_ASYNC + 10 :
+     case FDDI_FC_LLC_ASYNC + 11 :
+     case FDDI_FC_LLC_ASYNC + 12 :
+     case FDDI_FC_LLC_ASYNC + 13 :
+     case FDDI_FC_LLC_ASYNC + 14 :
+     case FDDI_FC_LLC_ASYNC + 15 :
+       capture_llc(pd, offset, cap_len, ld);
+       return;
+       
+     default :
+       ld->other++;
+       return;
+ 
+   } /* fc */
+ 
+ } /* capture_fddi */
+ 
  void dissect_fddi(const u_char *pd, frame_data *fd, GtkTree *tree) 
  {
    int        offset = 0, fc;
***************
*** 211,214 ****
    } /* fc */
  
  } /* dissect_fddi */
- 
--- 254,256 ----

Index: packet-ip.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-ip.c,v
retrieving revision 1.13
diff -c -r1.13 packet-ip.c
*** packet-ip.c	1998/12/29 04:05:35	1.13
--- packet-ip.c	1999/02/04 02:39:31
***************
*** 47,52 ****
--- 47,69 ----
  
  extern packet_info pi;
  
+ void
+ capture_ip(const u_char *pd, int offset, guint32 cap_len, packet_counts *ld) {
+   switch (pd[offset + 9]) {
+     case IP_PROTO_TCP:
+       ld->tcp++;
+       break;
+     case IP_PROTO_UDP:
+       ld->udp++;
+       break;
+     case IP_PROTO_OSPF:
+       ld->ospf++;
+       break;
+     default:
+       ld->other++;
+   }
+ }
+ 
  static void
  dissect_ipopt_security(GtkWidget *opt_tree, const char *name,
      const u_char *opd, int offset, guint optlen)

Index: packet-llc.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-llc.c,v
retrieving revision 1.10
diff -c -r1.10 packet-llc.c
*** packet-llc.c	1998/11/17 04:28:56	1.10
--- packet-llc.c	1999/02/04 02:39:31
***************
*** 43,78 ****
  
  struct sap_info {
  	guint8	sap;
! 	void	(*func) (const u_char *, int, frame_data *, GtkTree *);
  	char	*text;
  };
  
  static struct sap_info	saps[] = {
! 	{ 0x00, NULL,		"NULL LSAP" },
! 	{ 0x02, NULL,		"LLC Sub-Layer Management Individual" },
! 	{ 0x03, NULL,		"LLC Sub-Layer Management Group" },
! 	{ 0x04, NULL,		"SNA Path Control Individual" },
! 	{ 0x05, NULL,		"SNA Path Control Group" },
! 	{ 0x06, dissect_ip,	"TCP/IP" },
! 	{ 0x08, NULL,		"SNA" },
! 	{ 0x0C, NULL,		"SNA" },
! 	{ 0x42, NULL,		"Spanning Tree BPDU" },
! 	{ 0x7F, NULL,		"ISO 802.2" },
! 	{ 0x80, NULL,		"XNS" },
! 	{ 0xAA, NULL,		"SNAP" },
! 	/*{ 0xBA, dissect_vines,	"Banyan Vines" },
! 	{ 0xBC, dissect_vines,	"Banyan Vines" },*/
! 	{ 0xBA, NULL,		"Banyan Vines" },
! 	{ 0xBC, NULL,		"Banyan Vines" },
! 	{ 0xE0, dissect_ipx,	"NetWare" },
! 	{ 0xF0, NULL,		"NetBIOS" },
! 	{ 0xF4, NULL,		"IBM Net Management Individual" },
! 	{ 0xF5, NULL,		"IBM Net Management Group" },
! 	{ 0xF8, NULL,		"Remote Program Load" },
! 	{ 0xFC, NULL,		"Remote Program Load" },
! 	{ 0xFE, dissect_osi,	"ISO Network Layer" },
! 	{ 0xFF, NULL,		"Global LSAP" },
! 	{ 0x00, NULL,		NULL }
  };
  
  
--- 43,79 ----
  
  struct sap_info {
  	guint8	sap;
! 	void	(*capture_func) (const u_char *, int, guint32, packet_counts *);
! 	void	(*dissect_func) (const u_char *, int, frame_data *, GtkTree *);
  	char	*text;
  };
  
  static struct sap_info	saps[] = {
! 	{ 0x00, NULL,		NULL,		"NULL LSAP" },
! 	{ 0x02, NULL,		NULL,		"LLC Sub-Layer Management Individual" },
! 	{ 0x03, NULL,		NULL,		"LLC Sub-Layer Management Group" },
! 	{ 0x04, NULL,		NULL,		"SNA Path Control Individual" },
! 	{ 0x05, NULL,		NULL,		"SNA Path Control Group" },
! 	{ 0x06, capture_ip,	dissect_ip,	"TCP/IP" },
! 	{ 0x08, NULL,		NULL,		"SNA" },
! 	{ 0x0C, NULL,		NULL,		"SNA" },
! 	{ 0x42, NULL,		NULL,		"Spanning Tree BPDU" },
! 	{ 0x7F, NULL,		NULL,		"ISO 802.2" },
! 	{ 0x80, NULL,		NULL,		"XNS" },
! 	{ 0xAA, NULL,		NULL,		"SNAP" },
! 	/*{ 0xBA, NULL,		dissect_vines,	"Banyan Vines" },
! 	{ 0xBC, NULL,		dissect_vines,	"Banyan Vines" },*/
! 	{ 0xBA, NULL,		NULL,		"Banyan Vines" },
! 	{ 0xBC, NULL,		NULL,		"Banyan Vines" },
! 	{ 0xE0, NULL,		dissect_ipx,	"NetWare" },
! 	{ 0xF0, NULL,		NULL,		"NetBIOS" },
! 	{ 0xF4, NULL,		NULL,		"IBM Net Management Individual" },
! 	{ 0xF5, NULL,		NULL,		"IBM Net Management Group" },
! 	{ 0xF8, NULL,		NULL,		"Remote Program Load" },
! 	{ 0xFC, NULL,		NULL,		"Remote Program Load" },
! 	{ 0xFE, NULL,		dissect_osi,	"ISO Network Layer" },
! 	{ 0xFF, NULL,		NULL,		"Global LSAP" },
! 	{ 0x00, NULL,		NULL,		NULL }
  };
  
  
***************
*** 90,107 ****
  }
  
  static void*
! sap_func(u_char sap) {
  	int i=0;
  
  	while (saps[i].text != NULL) {
  		if (saps[i].sap == sap) {
! 			return saps[i].func;
  		}
  		i++;
  	}
  	return dissect_data;
  }
  
  static char*
  llc_org(const u_char *ptr) {
  
--- 91,121 ----
  }
  
  static void*
! sap_capture_func(u_char sap) {
  	int i=0;
  
  	while (saps[i].text != NULL) {
  		if (saps[i].sap == sap) {
! 			return saps[i].capture_func;
  		}
  		i++;
  	}
  	return dissect_data;
  }
  
+ static void*
+ sap_dissect_func(u_char sap) {
+ 	int i=0;
+ 
+ 	while (saps[i].text != NULL) {
+ 		if (saps[i].sap == sap) {
+ 			return saps[i].dissect_func;
+ 		}
+ 		i++;
+ 	}
+ 	return dissect_data;
+ }
+ 
  static char*
  llc_org(const u_char *ptr) {
  
***************
*** 118,123 ****
--- 132,166 ----
  }
  
  void
+ capture_llc(const u_char *pd, int offset, guint32 cap_len, packet_counts *ld) {
+ 
+ 	guint16		etype;
+ 	int		is_snap;
+ 	void		(*capture) (const u_char *, int, guint32, packet_counts *);
+ 
+ 	is_snap = (pd[offset] == 0xAA) && (pd[offset+1] == 0xAA);
+ 	if (is_snap) {
+ 		etype  = (pd[offset+6] << 8) | pd[offset+7];
+ 		offset += 8;
+ 		capture_ethertype(etype, offset, pd, cap_len, ld);
+ 	}		
+ 	else {
+ 		capture = sap_capture_func(pd[offset]);
+ 
+ 		/* non-SNAP */
+ 		offset += 3;
+ 
+ 		if (capture) {
+ 			capture(pd, offset, cap_len, ld);
+ 		}
+ 		else {
+ 			ld->other++;
+ 		}
+ 
+ 	}
+ }
+ 
+ void
  dissect_llc(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
  
  	GtkWidget	*llc_tree = NULL, *ti;
***************
*** 168,174 ****
  			col_add_fstr(fd, COL_INFO, "802.2 LLC (%s)", sap_text(pd[offset]));
  		}
  
! 		dissect = sap_func(pd[offset]);
  
  		/* non-SNAP */
  		offset += 3;
--- 211,217 ----
  			col_add_fstr(fd, COL_INFO, "802.2 LLC (%s)", sap_text(pd[offset]));
  		}
  
! 		dissect = sap_dissect_func(pd[offset]);
  
  		/* non-SNAP */
  		offset += 3;

Index: packet-null.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-null.c,v
retrieving revision 1.5
diff -c -r1.5 packet-null.c
*** packet-null.c	1998/11/17 04:29:00	1.5
--- packet-null.c	1999/02/04 02:39:31
***************
*** 40,45 ****
--- 40,76 ----
  #include "packet.h"
  
  void
+ capture_null( const u_char *pd, guint32 cap_len, packet_counts *ld ) {
+   e_nullhdr  nh;
+ 
+   memcpy((char *)&nh.null_family, (char *)&pd[2], sizeof(nh.null_family));
+ 
+   /* 
+   From what I've read in various sources, this is supposed to be an
+   address family, e.g. AF_INET.  However, a FreeBSD ISDN PPP dump that
+   Andreas Klemm sent to ethereal-dev has a packet type of DLT_NULL, and
+   the family bits look like PPP's protocol field.  A dump of the loopback
+   interface on my Linux box also has a link type of DLT_NULL (as it should
+   be), but the family bits look like ethernet's protocol type.  To
+   further  confuse matters, nobody seems to be paying attention to byte
+   order.
+   - gcc
+   */  
+    
+   switch (nh.null_family) {
+     case 0x0008:
+     case 0x0800:
+     case 0x0021:
+     case 0x2100:
+       capture_ip(pd, 4, cap_len, ld);
+       break;
+     default:
+       ld->other++;
+       break;
+   }
+ }
+ 
+ void
  dissect_null( const u_char *pd, frame_data *fd, GtkTree *tree ) {
    e_nullhdr  nh;
    GtkWidget *ti, *fh_tree;

Index: packet-ppp.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-ppp.c,v
retrieving revision 1.8
diff -c -r1.8 packet-ppp.c
*** packet-ppp.c	1998/11/17 04:29:03	1.8
--- packet-ppp.c	1999/02/04 02:39:32
***************
*** 62,67 ****
--- 62,79 ----
  #define PPP_CBCP	0xc029	/* Callback Control Protocol */
  
  void
+ capture_ppp( const u_char *pd, guint32 cap_len, packet_counts *ld ) {
+   switch (pntohs(&pd[2])) {
+     case PPP_IP:
+       capture_ip(pd, 4, cap_len, ld);
+       break;
+     default:
+       ld->other++;
+       break;
+   }
+ }
+ 
+ void
  dissect_ppp( const u_char *pd, frame_data *fd, GtkTree *tree ) {
    e_ppphdr   ph;
    GtkWidget *ti, *fh_tree;

Index: packet-raw.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-raw.c,v
retrieving revision 1.7
diff -c -r1.7 packet-raw.c
*** packet-raw.c	1998/11/17 04:29:04	1.7
--- packet-raw.c	1999/02/04 02:39:32
***************
*** 39,44 ****
--- 39,61 ----
  #include "packet.h"
  
  void
+ capture_raw( const u_char *pd, guint32 cap_len, packet_counts *ld ) {
+ 
+   /* So far, the only time we get raw connection types are with Linux and
+    * Irix PPP connections.  We can't tell what type of data is coming down
+    * the line, so our safest bet is IP. - GCC
+    */
+    
+   /* Currently, the Linux 2.1.xxx PPP driver passes back some of the header
+    * sometimes.  This check should be removed when 2.2 is out.
+    */
+   if (pd[0] == 0xff && pd[1] == 0x03)
+     capture_ip(pd, 4, cap_len, ld);
+   else
+     capture_ip(pd, 0, cap_len, ld);
+ }
+ 
+ void
  dissect_raw( const u_char *pd, frame_data *fd, GtkTree *tree ) {
    GtkWidget *ti, *fh_tree;
  
***************
*** 76,79 ****
    else
      dissect_ip(pd, 0, fd, tree);
  }
!     
--- 93,96 ----
    else
      dissect_ip(pd, 0, fd, tree);
  }
! 

Index: packet-tr.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-tr.c,v
retrieving revision 1.9
diff -c -r1.9 packet-tr.c
*** packet-tr.c	1999/01/08 04:42:43	1.9
--- packet-tr.c	1999/02/04 02:39:33
***************
*** 75,80 ****
--- 75,174 ----
  
  
  void
+ capture_tr(const u_char *pd, guint32 cap_len, packet_counts *ld) {
+ 
+ 	int			offset = 14;
+ 
+ 	int			source_routed = 0;
+ 	int			frame_type;
+ 	guint8			trn_rif_bytes;
+ 	guint8			actual_rif_bytes;
+ 
+ 	/* The trn_hdr struct, as separate variables */
+ 	guint8			trn_fc;		/* field control field */
+ 	guint8			trn_shost[6];	/* source host */
+ 
+ 	/* get the data */
+ 	memcpy(&trn_fc, &pd[1], sizeof(guint8));
+ 	memcpy(trn_shost, &pd[8], 6 * sizeof(guint8));
+ 
+ 	frame_type = (trn_fc & 192) >> 6;
+ 
+ 	/* if the high bit on the first byte of src hwaddr is 1, then
+ 		this packet is source-routed */
+ 	source_routed = trn_shost[0] & 128;
+ 
+ 	trn_rif_bytes = pd[14] & 31;
+ 
+ 	/* sometimes we have a RCF but no RIF... half source-routed? */
+ 	/* I'll check for 2 bytes of RIF and the 0x70 byte */
+ 	if (!source_routed) {
+ 		if (trn_rif_bytes == 2) {
+ 			source_routed = 1;
+ 		}
+ 		/* the Linux 2.0 TR code strips source-route bits in
+ 		 * order to test for SR. This can be removed from most
+ 		 * packets with oltr, but not all. So, I try to figure out
+ 		 * which packets should have been SR here. I'll check to
+ 		 * see if there's a SNAP or IPX field right after
+ 		 * my RIF fields.
+ 		 */
+ 		else if ( (
+ 			pd[0x0e + trn_rif_bytes] == 0xaa &&
+ 			pd[0x0f + trn_rif_bytes] == 0xaa &&
+ 			pd[0x10 + trn_rif_bytes] == 0x03) ||
+ 			  (
+ 			pd[0x0e + trn_rif_bytes] == 0xe0 &&
+ 			pd[0x0f + trn_rif_bytes] == 0xe0) ) {
+ 
+ 			source_routed = 1;
+ 		}
+ /*		else {
+ 			printf("0e+%d = %02X   0f+%d = %02X\n", trn_rif_bytes, pd[0x0e + trn_rif_bytes],
+ 					trn_rif_bytes, pd[0x0f + trn_rif_bytes]);
+ 		} */
+ 
+ 	}
+ 
+ 	if (source_routed) {
+ 		actual_rif_bytes = trn_rif_bytes;
+ 	}
+ 	else {
+ 		trn_rif_bytes = 0;
+ 		actual_rif_bytes = 0;
+ 	}
+ 
+ 	/* this is a silly hack for Linux 2.0.x. Read the comment below,
+ 	in front of the other #ifdef linux. If we're sniffing our own NIC,
+ 	 we get a full RIF, sometimes with garbage */
+ 	if ((source_routed && trn_rif_bytes == 2 && frame_type == 1) ||
+ 		(!source_routed && frame_type == 1)) {
+ 		/* look for SNAP or IPX only */
+ 		if ( (pd[0x20] == 0xaa && pd[0x21] == 0xaa && pd[0x22] == 03) ||
+ 			 (pd[0x20] == 0xe0 && pd[0x21] == 0xe0) ) {
+ 			actual_rif_bytes = 18;
+ 		}
+ 	}
+ 	offset += actual_rif_bytes;
+ 
+ 	/* The package is either MAC or LLC */
+ 	switch (frame_type) {
+ 		/* MAC */
+ 		case 0:
+ 			ld->other++;
+ 			break;
+ 		case 1:
+ 			capture_llc(pd, offset, cap_len, ld);
+ 			break;
+ 		default:
+ 			/* non-MAC, non-LLC, i.e., "Reserved" */
+ 			ld->other++;
+ 			break;
+ 	}
+ }
+ 
+ 
+ void
  dissect_tr(const u_char *pd, frame_data *fd, GtkTree *tree) {
  
  	GtkWidget	*fh_tree, *ti;

Index: packet.h
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet.h,v
retrieving revision 1.34
diff -c -r1.34 packet.h
*** packet.h	1999/01/28 21:29:36	1.34
--- packet.h	1999/02/04 02:39:34
***************
*** 68,73 ****
--- 68,81 ----
  
  #define COL_MAX_LEN 256
  
+ typedef struct _packet_counts {
+   gint           tcp;
+   gint           udp;
+   gint           ospf;
+   gint           other;
+   gint           total;
+ } packet_counts;
+ 
  typedef struct _frame_data {
    guint32      pkt_len;   /* Packet length */
    guint32      cap_len;   /* Amount actually captured */
***************
*** 529,534 ****
--- 537,563 ----
  
  /*
   * Routines in packet-*.c
+  * Routines should take three args: packet data *, cap_len, packet_counts *
+  * They should never modify the packet data.
+  */
+ void capture_eth(const u_char *, guint32, packet_counts *);
+ void capture_fddi(const u_char *, guint32, packet_counts *);
+ void capture_null(const u_char *, guint32, packet_counts *);
+ void capture_ppp(const u_char *, guint32, packet_counts *);
+ void capture_raw(const u_char *, guint32, packet_counts *);
+ void capture_tr(const u_char *, guint32, packet_counts *);
+ 
+ /*
+  * Routines in packet-*.c
+  * Routines should take four args: packet data *, offset, cap_len,
+  * packet_counts *
+  * They should never modify the packet data.
+  */
+ void capture_llc(const u_char *, int, guint32, packet_counts *);
+ void capture_ip(const u_char *, int, guint32, packet_counts *);
+ 
+ /*
+  * Routines in packet-*.c
   * Routines should take three args: packet data *, frame_data *, tree *
   * They should never modify the packet data.
   */
***************
*** 582,587 ****
--- 611,618 ----
  
  /* These functions are in ethertype.c */
  gchar *ethertype_to_str(guint16 etype, const char *fmt);
+ void capture_ethertype(guint16 etype, int offset,
+ 		const u_char *pd, guint32 cap_len, packet_counts *ld);
  void ethertype(guint16 etype, int offset,
  		const u_char *pd, frame_data *fd, GtkTree *tree,
  		GtkWidget *fh_tree);