Ethereal-dev: Re: [ethereal-dev] Keeping state for SMB decodes

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

From: Guy Harris <gharris@xxxxxxxxxxxx>
Date: Sun, 17 Oct 1999 01:19:04 -0700
I've attached a patch, and the files "conversation.c" and
"conversation.h", as per my previous message.
? errs
? file.c.SAVE
? conversation.c
? conversation.h
Index: Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/ethereal/Makefile.am,v
retrieving revision 1.88
diff -c -r1.88 Makefile.am
*** Makefile.am	1999/10/15 17:00:46	1.88
--- Makefile.am	1999/10/17 08:02:58
***************
*** 39,44 ****
--- 39,46 ----
  	colors.h       \
  	column.c       \
  	column.h       \
+ 	conversation.c \
+ 	conversation.h \
  	dfilter-int.h  \
  	dfilter-grammar.y \
  	dfilter-scanner.l \
Index: file.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/file.c,v
retrieving revision 1.108
diff -c -r1.108 file.c
*** file.c	1999/10/12 05:00:47	1.108
--- file.c	1999/10/17 08:03:02
***************
*** 83,89 ****
--- 83,96 ----
  #include "gtk/proto_draw.h"
  #include "dfilter.h"
  #include "timestamp.h"
+ #include "conversation.h"
  
+ #ifndef __RESOLV_H__
+ #include "resolv.h"
+ #endif
+ 
+ #include "packet-ipv6.h"
+ 
  #include "packet-ncp.h"
  
  extern GtkWidget *packet_list, *prog_bar, *info_bar, *byte_view, *tree_view;
***************
*** 130,135 ****
--- 137,145 ----
       and fill in the information for this file. */
    close_cap_file(cf, info_bar, file_ctx);
  
+   /* Initialize the table of conversations. */
+   conversation_init();
+ 
    /* Initialize protocol-specific variables */
    ncp_init_protocol();
    smb_init_protocol();
***************
*** 524,537 ****
  /* To do: Add check_col checks to the col_add* routines */
  
  static void
! col_add_abs_time(frame_data *fd, gint el)
  {
    struct tm *tmp;
    time_t then;
  
    then = fd->abs_secs;
    tmp = localtime(&then);
!   col_add_fstr(fd, el, "%02d:%02d:%02d.%04ld",
      tmp->tm_hour,
      tmp->tm_min,
      tmp->tm_sec,
--- 534,547 ----
  /* To do: Add check_col checks to the col_add* routines */
  
  static void
! col_set_abs_time(frame_data *fd, int col)
  {
    struct tm *tmp;
    time_t then;
  
    then = fd->abs_secs;
    tmp = localtime(&then);
!   snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%02d:%02d:%02d.%04ld",
      tmp->tm_hour,
      tmp->tm_min,
      tmp->tm_sec,
***************
*** 539,592 ****
  }
  
  static void
! col_add_rel_time(frame_data *fd, gint el)
  {
!   col_add_fstr(fd, el, "%d.%06d", fd->rel_secs, fd->rel_usecs);
  }
  
  static void
! col_add_delta_time(frame_data *fd, gint el)
  {
!   col_add_fstr(fd, el, "%d.%06d", fd->del_secs, fd->del_usecs);
  }
  
  /* Add "command-line-specified" time. */
  static void
! col_add_cls_time(frame_data *fd)
  {
    switch (timestamp_type) {
      case ABSOLUTE:
!       col_add_abs_time(fd, COL_CLS_TIME);
        break;
  
      case RELATIVE:
!       col_add_rel_time(fd, COL_CLS_TIME);
        break;
  
      case DELTA:
!       col_add_delta_time(fd, COL_CLS_TIME);
        break;
    }
  }
  
  static void
  fill_in_columns(frame_data *fd)
  {
!   if (check_col(fd, COL_NUMBER))
!     col_add_fstr(fd, COL_NUMBER, "%u", fd->num);
  
!   /* Set any time stamp columns. */
!   if (check_col(fd, COL_CLS_TIME))
!     col_add_cls_time(fd);
!   if (check_col(fd, COL_ABS_TIME))
!     col_add_abs_time(fd, COL_ABS_TIME);
!   if (check_col(fd, COL_REL_TIME))
!     col_add_rel_time(fd, COL_REL_TIME);
!   if (check_col(fd, COL_DELTA_TIME))
!     col_add_delta_time(fd, COL_DELTA_TIME);
  
!   if (check_col(fd, COL_PACKET_LENGTH))
!     col_add_fstr(fd, COL_PACKET_LENGTH, "%d", fd->pkt_len);
  }
  
  static void
--- 549,722 ----
  }
  
  static void
! col_set_rel_time(frame_data *fd, int col)
  {
!   snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%d.%06d", fd->rel_secs,
!     fd->rel_usecs);
  }
  
  static void
! col_set_delta_time(frame_data *fd, int col)
  {
!   snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%d.%06d", fd->del_secs,
!     fd->del_usecs);
  }
  
  /* Add "command-line-specified" time. */
  static void
! col_set_cls_time(frame_data *fd, int col)
  {
    switch (timestamp_type) {
      case ABSOLUTE:
!       col_set_abs_time(fd, col);
        break;
  
      case RELATIVE:
!       col_set_rel_time(fd, col);
        break;
  
      case DELTA:
!       col_set_delta_time(fd, col);
        break;
    }
  }
  
  static void
+ col_set_addr(frame_data *fd, int col, address *addr, gboolean is_res)
+ {
+   u_int ipv4_addr;
+   struct e_in6_addr ipv6_addr;
+ 
+   switch (addr->type) {
+ 
+   case AT_ETHER:
+     if (is_res)
+       strncpy(fd->cinfo->col_data[col], get_ether_name(addr->data), COL_MAX_LEN);
+     else
+       strncpy(fd->cinfo->col_data[col], ether_to_str(addr->data), COL_MAX_LEN);
+     break;
+ 
+   case AT_IPv4:
+     memcpy(&ipv4_addr, addr->data, sizeof ipv4_addr);
+     if (is_res)
+       strncpy(fd->cinfo->col_data[col], get_hostname(ipv4_addr), COL_MAX_LEN);
+     else
+       strncpy(fd->cinfo->col_data[col], ip_to_str(addr->data), COL_MAX_LEN);
+     break;
+ 
+   case AT_IPv6:
+     memcpy(&ipv6_addr.s6_addr, addr->data, sizeof ipv6_addr.s6_addr);
+     if (is_res)
+       strncpy(fd->cinfo->col_data[col], get_hostname6(&ipv6_addr), COL_MAX_LEN);
+     else
+       strncpy(fd->cinfo->col_data[col], ip6_to_str(&ipv6_addr), COL_MAX_LEN);
+     break;
+ 
+   case AT_IPX:
+     strncpy(fd->cinfo->col_data[col],
+       ipx_addr_to_str(pntohl(&addr->data[0]), &addr->data[4]), COL_MAX_LEN);
+     break;
+ 
+   default:
+     break;
+   }
+   fd->cinfo->col_data[col][COL_MAX_LEN - 1] = '\0';
+ }
+ 
+ static void
  fill_in_columns(frame_data *fd)
  {
!   int i;
! 
!   for (i = 0; i < fd->cinfo->num_cols; i++) {
!     switch (fd->cinfo->col_fmt[i]) {
! 
!     case COL_NUMBER:
!       snprintf(fd->cinfo->col_data[i], COL_MAX_LEN, "%u", fd->num);
!       break;
! 
!     case COL_CLS_TIME:
!       col_set_cls_time(fd, i);
!       break;
! 
!     case COL_ABS_TIME:
!       col_set_abs_time(fd, i);
!       break;
! 
!     case COL_REL_TIME:
!       col_set_rel_time(fd, i);
!       break;
! 
!     case COL_DELTA_TIME:
!       col_set_delta_time(fd, i);
!       break;
! 
!     case COL_DEF_SRC:
!     case COL_RES_SRC:	/* COL_DEF_SRC is currently just like COL_RES_SRC */
!       col_set_addr(fd, i, &pi.src, TRUE);
!       break;
! 
!     case COL_UNRES_SRC:
!       col_set_addr(fd, i, &pi.src, FALSE);
!       break;
! 
!     case COL_DEF_DL_SRC:
!     case COL_RES_DL_SRC:
!       col_set_addr(fd, i, &pi.dl_src, TRUE);
!       break;
! 
!     case COL_UNRES_DL_SRC:
!       col_set_addr(fd, i, &pi.dl_src, FALSE);
!       break;
! 
!     case COL_DEF_NET_SRC:
!     case COL_RES_NET_SRC:
!       col_set_addr(fd, i, &pi.net_src, TRUE);
!       break;
! 
!     case COL_UNRES_NET_SRC:
!       col_set_addr(fd, i, &pi.net_src, FALSE);
!       break;
! 
!     case COL_DEF_DST:
!     case COL_RES_DST:	/* COL_DEF_DST is currently just like COL_RES_DST */
!       col_set_addr(fd, i, &pi.dst, TRUE);
!       break;
! 
!     case COL_UNRES_DST:
!       col_set_addr(fd, i, &pi.dst, FALSE);
!       break;
  
!     case COL_DEF_DL_DST:
!     case COL_RES_DL_DST:
!       col_set_addr(fd, i, &pi.dl_dst, TRUE);
!       break;
  
!     case COL_UNRES_DL_DST:
!       col_set_addr(fd, i, &pi.dl_dst, FALSE);
!       break;
! 
!     case COL_DEF_NET_DST:
!     case COL_RES_NET_DST:
!       col_set_addr(fd, i, &pi.net_dst, TRUE);
!       break;
! 
!     case COL_UNRES_NET_DST:
!       col_set_addr(fd, i, &pi.net_dst, FALSE);
!       break;
! 
!     case COL_PROTOCOL:	/* currently done by dissectors */
!     case COL_INFO:	/* currently done by dissectors */
!       break;
! 
!     case COL_PACKET_LENGTH:
!       snprintf(fd->cinfo->col_data[i], COL_MAX_LEN, "%d", fd->pkt_len);
!       break;
! 
!     case NUM_COL_FMTS:	/* keep compiler happy - shouldn't get here */
!       break;
!     }
!   }
  }
  
  static void
***************
*** 1072,1084 ****
          /* There are columns that show the time in the "command-line-specified"
             format; update them. */
          for (i = 0; i < cf->cinfo.num_cols; i++) {
-           cf->cinfo.col_data[i][0] = '\0';
-         }
-         col_add_cls_time(fd);
-         for (i = 0; i < cf->cinfo.num_cols; i++) {
            if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
              /* This is one of the columns that shows the time in
                 "command-line-specified" format; update it. */
              gtk_clist_set_text(GTK_CLIST(packet_list), fd->row, i,
  			  cf->cinfo.col_data[i]);
  	  }
--- 1202,1212 ----
          /* There are columns that show the time in the "command-line-specified"
             format; update them. */
          for (i = 0; i < cf->cinfo.num_cols; i++) {
            if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
              /* This is one of the columns that shows the time in
                 "command-line-specified" format; update it. */
+             cf->cinfo.col_data[i][0] = '\0';
+             col_set_cls_time(fd, i);
              gtk_clist_set_text(GTK_CLIST(packet_list), fd->row, i,
  			  cf->cinfo.col_data[i]);
  	  }
Index: follow.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/follow.c,v
retrieving revision 1.15
diff -c -r1.15 follow.c
*** follow.c	1999/09/09 02:42:25	1.15
--- follow.c	1999/10/17 08:03:02
***************
*** 50,56 ****
  
  gboolean incomplete_tcp_stream = FALSE;
  
! static u_long  ip_address[2];
  static u_int   tcp_port[2];
  
  static int check_fragments( int );
--- 50,56 ----
  
  gboolean incomplete_tcp_stream = FALSE;
  
! static guint32 ip_address[2];
  static u_int   tcp_port[2];
  
  static int check_fragments( int );
***************
*** 63,82 ****
  char* 
  build_follow_filter( packet_info *pi ) {
    char* buf = malloc(1024);
!   if( pi->ipproto == 6 ) {
!     /* TCP */
      sprintf( buf, 
  	     "(ip.addr eq %s and ip.addr eq %s) and (tcp.port eq %d and tcp.port eq %d)",
! 	     ip_to_str( (guint8 *) &pi->ip_src), 
! 	     ip_to_str( (guint8 *) &pi->ip_dst), 
  	     pi->srcport, pi->destport );
    }
    else { 
      free( buf );
      return NULL;
    }
!   ip_address[0] = pi->ip_src;
!   ip_address[1] = pi->ip_dst;
    tcp_port[0] = pi->srcport;
    tcp_port[1] = pi->destport;
    return buf;
--- 63,83 ----
  char* 
  build_follow_filter( packet_info *pi ) {
    char* buf = malloc(1024);
!   if( pi->net_src.type == AT_IPv4 && pi->net_dst.type == AT_IPv4
! 	&& pi->ipproto == 6 ) {
!     /* TCP over IPv4 */
      sprintf( buf, 
  	     "(ip.addr eq %s and ip.addr eq %s) and (tcp.port eq %d and tcp.port eq %d)",
! 	     ip_to_str( pi->net_src.data), 
! 	     ip_to_str( pi->net_dst.data), 
  	     pi->srcport, pi->destport );
    }
    else { 
      free( buf );
      return NULL;
    }
!   memcpy(&ip_address[0], pi->net_src.data, sizeof ip_address[0]);
!   memcpy(&ip_address[1], pi->net_dst.data, sizeof ip_address[1]);
    tcp_port[0] = pi->srcport;
    tcp_port[1] = pi->destport;
    return buf;
***************
*** 88,103 ****
  
  static tcp_frag *frags[2] = { 0, 0};
  static u_long seq[2];
! static u_long src[2] = { 0, 0 };
  
  void 
! reassemble_tcp( u_long sequence, u_long length, const char* data, u_long data_length, int synflag, u_long srcx, u_long dstx, u_int srcport, u_int dstport ) {
    int src_index, j, first = 0;
    u_long newseq;
    tcp_frag *tmp_frag;
    src_index = -1;
  
    /* first check if this packet should be processed */
    if ((srcx != ip_address[0] && srcx != ip_address[1]) ||
        (dstx != ip_address[0] && dstx != ip_address[1]) ||
        (srcport != tcp_port[0] && srcport != tcp_port[1]) ||
--- 89,111 ----
  
  static tcp_frag *frags[2] = { 0, 0};
  static u_long seq[2];
! static guint32 src[2] = { 0, 0 };
  
  void 
! reassemble_tcp( u_long sequence, u_long length, const char* data,
! 		u_long data_length, int synflag, address *net_src,
! 		address *net_dst, u_int srcport, u_int dstport ) {
!   guint32 srcx, dstx;
    int src_index, j, first = 0;
    u_long newseq;
    tcp_frag *tmp_frag;
    src_index = -1;
  
    /* first check if this packet should be processed */
+   if (net_src->type != AT_IPv4 || net_dst->type != AT_IPv4)
+     return;
+   memcpy(&srcx, net_src->data, sizeof srcx);
+   memcpy(&dstx, net_dst->data, sizeof dstx);
    if ((srcx != ip_address[0] && srcx != ip_address[1]) ||
        (dstx != ip_address[0] && dstx != ip_address[1]) ||
        (srcport != tcp_port[0] && srcport != tcp_port[1]) ||
Index: follow.h
===================================================================
RCS file: /usr/local/cvsroot/ethereal/follow.h,v
retrieving revision 1.5
diff -c -r1.5 follow.h
*** follow.h	1999/07/31 13:55:16	1.5
--- follow.h	1999/10/17 08:03:02
***************
*** 42,48 ****
  
  char* build_follow_filter( packet_info * );
  void reassemble_tcp( u_long, u_long, const char*, u_long, int, 
! 		     u_long, u_long, u_int, u_int );
  void  reset_tcp_reassembly( void );
  
  #endif
--- 42,48 ----
  
  char* build_follow_filter( packet_info * );
  void reassemble_tcp( u_long, u_long, const char*, u_long, int, 
! 		     address *, address *, u_int, u_int );
  void  reset_tcp_reassembly( void );
  
  #endif
Index: packet-eth.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-eth.c,v
retrieving revision 1.20
diff -c -r1.20 packet-eth.c
*** packet-eth.c	1999/10/12 06:20:04	1.20
--- packet-eth.c	1999/10/17 08:03:03
***************
*** 118,131 ****
      return;
    }
  
!   if (check_col(fd, COL_RES_DL_DST))
!     col_add_str(fd, COL_RES_DL_DST, get_ether_name((u_char *)&pd[offset+0]));
!   if (check_col(fd, COL_RES_DL_SRC))
!     col_add_str(fd, COL_RES_DL_SRC, get_ether_name((u_char *)&pd[offset+6]));
!   if (check_col(fd, COL_UNRES_DL_DST))
!     col_add_str(fd, COL_UNRES_DL_DST, ether_to_str((u_char *)&pd[offset+0]));
!   if (check_col(fd, COL_UNRES_DL_SRC))
!     col_add_str(fd, COL_UNRES_DL_SRC, ether_to_str((u_char *)&pd[offset+6]));
    if (check_col(fd, COL_PROTOCOL))
      col_add_str(fd, COL_PROTOCOL, "Ethernet");
  
--- 118,128 ----
      return;
    }
  
!   SET_ADDRESS(&pi.dl_src, AT_ETHER, 6, &pd[offset+6]);
!   SET_ADDRESS(&pi.src, AT_ETHER, 6, &pd[offset+6]);
!   SET_ADDRESS(&pi.dl_dst, AT_ETHER, 6, &pd[offset+0]);
!   SET_ADDRESS(&pi.dst, AT_ETHER, 6, &pd[offset+0]);
! 
    if (check_col(fd, COL_PROTOCOL))
      col_add_str(fd, COL_PROTOCOL, "Ethernet");
  
Index: packet-fddi.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-fddi.c,v
retrieving revision 1.23
diff -c -r1.23 packet-fddi.c
*** packet-fddi.c	1999/10/16 19:36:56	1.23
--- packet-fddi.c	1999/10/17 08:03:03
***************
*** 254,260 ****
    proto_tree *fh_tree;
    proto_item *ti;
    gchar      *fc_str;
!   u_char     src[6], dst[6];
    u_char     src_swapped[6], dst_swapped[6];
  
    if (fd->cap_len < FDDI_HEADER_SIZE) {
--- 254,260 ----
    proto_tree *fh_tree;
    proto_item *ti;
    gchar      *fc_str;
!   static u_char src[6], dst[6];
    u_char     src_swapped[6], dst_swapped[6];
  
    if (fd->cap_len < FDDI_HEADER_SIZE) {
***************
*** 275,288 ****
    fc = (int) pd[FDDI_P_FC];
    fc_str = fddifc_to_str(fc);
  
!   if (check_col(fd, COL_RES_DL_SRC))
!     col_add_str(fd, COL_RES_DL_SRC, get_ether_name(src));
!   if (check_col(fd, COL_RES_DL_DST))
!     col_add_str(fd, COL_RES_DL_DST, get_ether_name(dst));
!   if (check_col(fd, COL_UNRES_DL_SRC))
!     col_add_str(fd, COL_UNRES_DL_SRC, ether_to_str(src));
!   if (check_col(fd, COL_UNRES_DL_DST))
!     col_add_str(fd, COL_UNRES_DL_DST, ether_to_str(dst));
    if (check_col(fd, COL_PROTOCOL))
      col_add_str(fd, COL_PROTOCOL, "FDDI");
    if (check_col(fd, COL_INFO))
--- 275,287 ----
    fc = (int) pd[FDDI_P_FC];
    fc_str = fddifc_to_str(fc);
  
!   /* XXX - copy them to some buffer associated with "pi", rather than
!      just making "src" and "dst" static? */
!   SET_ADDRESS(&pi.dl_src, AT_ETHER, 6, &src[0]);
!   SET_ADDRESS(&pi.src, AT_ETHER, 6, &src[0]);
!   SET_ADDRESS(&pi.dl_dst, AT_ETHER, 6, &dst[0]);
!   SET_ADDRESS(&pi.dst, AT_ETHER, 6, &dst[0]);
! 
    if (check_col(fd, COL_PROTOCOL))
      col_add_str(fd, COL_PROTOCOL, "FDDI");
    if (check_col(fd, COL_INFO))
Index: packet-ip.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-ip.c,v
retrieving revision 1.56
diff -c -r1.56 packet-ip.c
*** packet-ip.c	1999/10/16 20:59:03	1.56
--- packet-ip.c	1999/10/17 08:03:07
***************
*** 173,178 ****
--- 173,192 ----
    guint32 ip_dst;
  } e_ip;
  
+ /* Offsets of fields within an IP header. */
+ #define	IPH_V_HL	0
+ #define	IPH_TOS		1
+ #define	IPH_LEN		2
+ #define	IPH_ID		4
+ #define	IPH_TTL		6
+ #define	IPH_OFF		8
+ #define	IPH_P		9
+ #define	IPH_SUM		10
+ #define	IPH_SRC		12
+ #define	IPH_DST		16
+ 
+ #define	IPH_MIN_LEN	20
+ 
  /* IP flags. */
  #define IP_CE		0x8000		/* Flag: "Congestion"		*/
  #define IP_DF		0x4000		/* Flag: "Don't Fragment"	*/
***************
*** 721,735 ****
  	    ipprotostr(iph.ip_p), iph.ip_p);
    }
  
-   if (check_col(fd, COL_RES_NET_SRC))
-     col_add_str(fd, COL_RES_NET_SRC, get_hostname(iph.ip_src));
-   if (check_col(fd, COL_UNRES_NET_SRC))
-     col_add_str(fd, COL_UNRES_NET_SRC, ip_to_str((guint8 *) &iph.ip_src));
-   if (check_col(fd, COL_RES_NET_DST))
-     col_add_str(fd, COL_RES_NET_DST, get_hostname(iph.ip_dst));
-   if (check_col(fd, COL_UNRES_NET_DST))
-     col_add_str(fd, COL_UNRES_NET_DST, ip_to_str((guint8 *) &iph.ip_dst));
-     
    if (tree) {
  
      switch (IPTOS_TOS(iph.ip_tos)) {
--- 735,740 ----
***************
*** 823,830 ****
    pi.ipproto = iph.ip_p;
    pi.iplen = iph.ip_len;
    pi.iphdrlen = lo_nibble(iph.ip_v_hl);
!   pi.ip_src = iph.ip_src;
!   pi.ip_dst = iph.ip_dst;
  
    /* Skip over header + options */
    offset += hlen;
--- 828,837 ----
    pi.ipproto = iph.ip_p;
    pi.iplen = iph.ip_len;
    pi.iphdrlen = lo_nibble(iph.ip_v_hl);
!   SET_ADDRESS(&pi.net_src, AT_IPv4, 4, &pd[offset + IPH_SRC]);
!   SET_ADDRESS(&pi.src, AT_IPv4, 4, &pd[offset + IPH_SRC]);
!   SET_ADDRESS(&pi.net_dst, AT_IPv4, 4, &pd[offset + IPH_DST]);
!   SET_ADDRESS(&pi.dst, AT_IPv4, 4, &pd[offset + IPH_DST]);
  
    /* Skip over header + options */
    offset += hlen;
Index: packet-ipv6.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-ipv6.c,v
retrieving revision 1.23
diff -c -r1.23 packet-ipv6.c
*** packet-ipv6.c	1999/10/15 16:59:12	1.23
--- packet-ipv6.c	1999/10/17 08:03:08
***************
*** 252,267 ****
  
    memcpy(&ipv6, (void *) &pd[offset], sizeof(ipv6)); 
  
    if (check_col(fd, COL_PROTOCOL))
      col_add_str(fd, COL_PROTOCOL, "IPv6");
-   if (check_col(fd, COL_RES_NET_SRC))
-     col_add_str(fd, COL_RES_NET_SRC, get_hostname6(&ipv6.ip6_src));
-   if (check_col(fd, COL_UNRES_NET_SRC))
-     col_add_str(fd, COL_UNRES_NET_SRC, ip6_to_str(&ipv6.ip6_src));
-   if (check_col(fd, COL_RES_NET_DST))
-     col_add_str(fd, COL_RES_NET_DST, get_hostname6(&ipv6.ip6_dst));
-   if (check_col(fd, COL_UNRES_NET_DST))
-     col_add_str(fd, COL_UNRES_NET_DST, ip6_to_str(&ipv6.ip6_dst));
  
    if (tree) {
      /* !!! specify length */
--- 252,264 ----
  
    memcpy(&ipv6, (void *) &pd[offset], sizeof(ipv6)); 
  
+   SET_ADDRESS(&pi.net_src, AT_IPv6, 16, &pd[offset + IP6H_SRC]);
+   SET_ADDRESS(&pi.src, AT_IPv6, 16, &pd[offset + IP6H_SRC]);
+   SET_ADDRESS(&pi.net_dst, AT_IPv6, 16, &pd[offset + IP6H_DST]);
+   SET_ADDRESS(&pi.dst, AT_IPv6, 16, &pd[offset + IP6H_DST]);
+ 
    if (check_col(fd, COL_PROTOCOL))
      col_add_str(fd, COL_PROTOCOL, "IPv6");
  
    if (tree) {
      /* !!! specify length */
Index: packet-ipv6.h
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-ipv6.h,v
retrieving revision 1.6
diff -c -r1.6 packet-ipv6.h
*** packet-ipv6.h	1999/10/14 05:41:30	1.6
--- packet-ipv6.h	1999/10/17 08:03:08
***************
*** 86,91 ****
--- 86,101 ----
  #define ip6_hlim	ip6_ctlun.ip6_un1.ip6_un1_hlim
  #define ip6_hops	ip6_ctlun.ip6_un1.ip6_un1_hlim
  
+ /* Offsets of fields within an IPv6 header. */
+ #define	IP6H_CTL	0
+ #define	IP6H_CTL_FLOW	0
+ #define	IP6H_CTL_PLEN	4
+ #define	IP6H_CTL_NXT	6
+ #define	IP6H_CTL_HLIM	7
+ #define	IP6H_CTL_VFC	0
+ #define	IP6H_SRC	8
+ #define	IP6H_DST	24
+ 
  #define IPV6_VERSION		0x60
  #define IPV6_VERSION_MASK	0xf0
  
Index: packet-ipx.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-ipx.c,v
retrieving revision 1.28
diff -c -r1.28 packet-ipx.c
*** packet-ipx.c	1999/10/12 06:20:10	1.28
--- packet-ipx.c	1999/10/17 08:03:10
***************
*** 256,262 ****
  	ipx_length = pntohs(&pd[offset+2]);
  
  	/* Length of IPX datagram plus headers above it. */
! 		len = ipx_length + offset;
  
  	/* Set the payload and captured-payload lengths to the minima of
  	   (the IPX length plus the length of the headers above it) and
--- 256,262 ----
  	ipx_length = pntohs(&pd[offset+2]);
  
  	/* Length of IPX datagram plus headers above it. */
! 	len = ipx_length + offset;
  
  	/* Set the payload and captured-payload lengths to the minima of
  	   (the IPX length plus the length of the headers above it) and
***************
*** 266,277 ****
  	if (pi.captured_len > len)
  		pi.captured_len = len;
  
! 	if (check_col(fd, COL_RES_DL_DST))
! 		col_add_str(fd, COL_RES_DL_DST,
! 				ipx_addr_to_str(pntohl(ipx_dnet), ipx_dnode));
! 	if (check_col(fd, COL_RES_DL_SRC))
! 		col_add_str(fd, COL_RES_DL_SRC,
! 				ipx_addr_to_str(pntohl(ipx_snet), ipx_snode));
  
  	if (check_col(fd, COL_PROTOCOL))
  		col_add_str(fd, COL_PROTOCOL, "IPX");
--- 266,275 ----
  	if (pi.captured_len > len)
  		pi.captured_len = len;
  
! 	SET_ADDRESS(&pi.net_src, AT_IPX, 10, &pd[offset+18]);
! 	SET_ADDRESS(&pi.src, AT_IPX, 10, &pd[offset+18]);
! 	SET_ADDRESS(&pi.net_dst, AT_IPX, 10, &pd[offset+6]);
! 	SET_ADDRESS(&pi.dst, AT_IPX, 10, &pd[offset+6]);
  
  	if (check_col(fd, COL_PROTOCOL))
  		col_add_str(fd, COL_PROTOCOL, "IPX");
Index: packet-smb.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-smb.c,v
retrieving revision 1.30
diff -c -r1.30 packet-smb.c
*** packet-smb.c	1999/10/16 20:26:37	1.30
--- packet-smb.c	1999/10/17 08:03:26
***************
*** 42,47 ****
--- 42,48 ----
  #include <string.h>
  #include <glib.h>
  #include "packet.h"
+ #include "conversation.h"
  #include "smb.h"
  #include "alignment.h"
  
***************
*** 60,67 ****
  int smb_packet_init_count = 200;
  
  struct smb_request_key {
!   guint32 ip_src, ip_dst;
!   guint16 port_src, port_dst;
    guint16 mid;
  };
  
--- 61,67 ----
  int smb_packet_init_count = 200;
  
  struct smb_request_key {
!   guint32 conversation;
    guint16 mid;
  };
  
***************
*** 74,97 ****
  GMemChunk *smb_request_keys = NULL;
  GMemChunk *smb_request_vals = NULL;
  
  /* Hash Functions */
  gint
  smb_equal(gconstpointer v, gconstpointer w)
  {
    struct smb_request_key *v1 = (struct smb_request_key *)v;
    struct smb_request_key *v2 = (struct smb_request_key *)w;
  
!   #if defined(DEBUG_SMB_HASH)
!   printf("Comparing %08X:%08X:%d:%d:%d\n      and %08X:%08X:%d:%d:%d\n",
! 	 v1 -> ip_src, v1 -> ip_dst, v1 -> port_src, v1 -> port_dst, v1 -> mid,
! 	 v2 -> ip_src, v2 -> ip_dst, v2 -> port_src, v2 -> port_dst, v2 -> mid);
!   #endif
! 
!   if (v1 -> ip_src   == v2 -> ip_src &&
!       v1 -> ip_dst   == v2 -> ip_dst &&
!       v1 -> port_src == v2 -> port_src &&
!       v1 -> port_dst == v2 -> port_dst &&
!       v1 -> mid      == v2 -> mid) {
  
      return 1;
  
--- 74,96 ----
  GMemChunk *smb_request_keys = NULL;
  GMemChunk *smb_request_vals = NULL;
  
+ #define DEBUG_SMB_HASH
+ 
  /* Hash Functions */
  gint
  smb_equal(gconstpointer v, gconstpointer w)
  {
    struct smb_request_key *v1 = (struct smb_request_key *)v;
    struct smb_request_key *v2 = (struct smb_request_key *)w;
+ 
+ #if defined(DEBUG_SMB_HASH)
+   printf("Comparing %08X:%u\n      and %08X:%u\n",
+ 	 v1 -> conversation, v1 -> mid,
+ 	 v2 -> conversation, v2 -> mid);
+ #endif
  
!   if (v1 -> conversation == v2 -> conversation &&
!       v1 -> mid          == v2 -> mid) {
  
      return 1;
  
***************
*** 106,117 ****
    struct smb_request_key *key = (struct smb_request_key *)v;
    guint val;
  
!   val = key -> ip_src + key -> ip_dst + key -> port_src + key -> port_dst +
!     key -> mid;
  
!   #if defined(DEBUG_SMB_HASH)
!   printf("SMB Hash calculated as %d\n", val);
!   #endif
  
    return val;
  
--- 105,115 ----
    struct smb_request_key *key = (struct smb_request_key *)v;
    guint val;
  
!   val = key -> conversation + key -> mid;
  
! #if defined(DEBUG_SMB_HASH)
!   printf("SMB Hash calculated as %u\n", val);
! #endif
  
    return val;
  
***************
*** 124,132 ****
  void
  smb_init_protocol(void)
  {
!   #if defined(DEBUG_SMB_HASH)
    printf("Initializing SMB hashtable area\n");
!   #endif
  
    if (smb_request_hash)
      g_hash_table_destroy(smb_request_hash);
--- 122,130 ----
  void
  smb_init_protocol(void)
  {
! #if defined(DEBUG_SMB_HASH)
    printf("Initializing SMB hashtable area\n");
! #endif
  
    if (smb_request_hash)
      g_hash_table_destroy(smb_request_hash);
***************
*** 8179,8184 ****
--- 8177,8183 ----
    return trans2_cmd_names[code];
  
  }
+ 
  void
  dissect_transact2_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)
  
***************
*** 8211,8241 ****
    guint16       DataCount;
    guint16       ByteCount;
    const char    *TransactName;
    struct smb_request_key      request_key, *new_request_key;
    struct smb_request_val      *request_val;
  
    /*
!    * Check for and insert entry in hash table if does not exist
!    * Since we want request and response to hash to the same, we make
!    * sure that src and dst swapped for response
     */
  
!   request_key.ip_src   = ((dirn == 0) ? pi.ip_src : pi.ip_dst);
!   request_key.ip_dst   = ((dirn == 0) ? pi.ip_dst : pi.ip_src);
!   request_key.port_src = ((dirn == 0) ? pi.srcport : pi.destport);
!   request_key.port_dst = ((dirn == 0) ? pi.destport : pi.srcport);
!   request_key.mid      = si.mid;
  
    request_val = (struct smb_request_val *) g_hash_table_lookup(smb_request_hash, &request_key);
  
    if (!request_val) { /* Create one */
  
      new_request_key = g_mem_chunk_alloc(smb_request_keys);
!     new_request_key -> ip_src   = ((dirn == 0) ? pi.ip_src : pi.ip_dst);
!     new_request_key -> ip_dst   = ((dirn == 0) ? pi.ip_dst : pi.ip_src);
!     new_request_key -> port_src = ((dirn == 0) ? pi.srcport : pi.destport);
!     new_request_key -> port_dst = ((dirn == 0) ? pi.destport : pi.srcport);
!     new_request_key -> mid      = si.mid;
  
      request_val = g_mem_chunk_alloc(smb_request_vals);
      request_val -> mid = si.mid;
--- 8210,8248 ----
    guint16       DataCount;
    guint16       ByteCount;
    const char    *TransactName;
+   guint32       conversation;
    struct smb_request_key      request_key, *new_request_key;
    struct smb_request_val      *request_val;
  
    /*
!    * Find out what conversation this packet is part of, or add it to a
!    * new conversation if it's not already part of one.
!    * XXX - this should really be done by the transport-layer protocol,
!    * although for connectionless transports, we may not want to do that
!    * unless we know some higher-level protocol will want it - or we
!    * may want to do it, so you can say e.g. "show only the packets in
!    * this UDP 'connection'".
!    *
!    * Note that we don't have to worry about the direction this packet
!    * was going - the conversation code handles that for us, treating
!    * packets from A:X to B:Y as being part of the same conversation as
!    * packets from B:Y to A:X.
     */
+   conversation = add_to_conversation(&pi.src, &pi.dst, pi.srcport, pi.destport);
  
!   /*
!    * Check for and insert entry in request hash table if does not exist
!    */
!   request_key.conversation = conversation;
!   request_key.mid          = si.mid;
  
    request_val = (struct smb_request_val *) g_hash_table_lookup(smb_request_hash, &request_key);
  
    if (!request_val) { /* Create one */
  
      new_request_key = g_mem_chunk_alloc(smb_request_keys);
!     new_request_key -> conversation = conversation;
!     new_request_key -> mid          = si.mid;
  
      request_val = g_mem_chunk_alloc(smb_request_vals);
      request_val -> mid = si.mid;
Index: packet-tcp.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-tcp.c,v
retrieving revision 1.37
diff -c -r1.37 packet-tcp.c
*** packet-tcp.c	1999/10/15 17:00:46	1.37
--- packet-tcp.c	1999/10/17 08:03:27
***************
*** 529,536 ****
          ( pd+offset ),			/* data */
          ( pi.captured_len - offset ),	/* captured data length */
          ( th.th_flags & TH_SYN ),	/* is syn set? */
!         pi.ip_src,
! 	pi.ip_dst,
  	pi.srcport,
  	pi.destport); 
    }
--- 529,536 ----
          ( pd+offset ),			/* data */
          ( pi.captured_len - offset ),	/* captured data length */
          ( th.th_flags & TH_SYN ),	/* is syn set? */
!         &pi.net_src,
! 	&pi.net_dst,
  	pi.srcport,
  	pi.destport); 
    }
Index: packet-tr.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-tr.c,v
retrieving revision 1.29
diff -c -r1.29 packet-tr.c
*** packet-tr.c	1999/10/12 06:20:18	1.29
--- packet-tr.c	1999/10/17 08:03:29
***************
*** 285,291 ****
  	guint16			trn_rseg[8];	/* routing registers */
  
  	/* non-source-routed version of source addr */
! 	guint8			trn_shost_nonsr[6];
  	int			x;
  	
  	/* Token-Ring Strings */
--- 285,291 ----
  	guint16			trn_rseg[8];	/* routing registers */
  
  	/* non-source-routed version of source addr */
! 	static guint8		trn_shost_nonsr[6];
  	int			x;
  	
  	/* Token-Ring Strings */
***************
*** 397,408 ****
                  }
  	}
  
  	/* information window */
- 	if (check_col(fd, COL_RES_DL_DST))
- 		col_add_str(fd, COL_RES_DL_DST,
- 		  ether_to_str((guint8 *)&pd[offset + 2]));
- 	if (check_col(fd, COL_RES_DL_SRC))
- 		col_add_str(fd, COL_RES_DL_SRC, ether_to_str(trn_shost_nonsr));
  	if (check_col(fd, COL_PROTOCOL))
  		col_add_str(fd, COL_PROTOCOL, "TR");
  	if (check_col(fd, COL_INFO))
--- 397,410 ----
                  }
  	}
  
+ 	/* XXX - copy it to some buffer associated with "pi", rather than
+ 	   just making "trn_shost_nonsr" static? */
+ 	SET_ADDRESS(&pi.dl_src, AT_ETHER, 6, &trn_shost_nonsr[0]);
+ 	SET_ADDRESS(&pi.src, AT_ETHER, 6, &trn_shost_nonsr[0]);
+ 	SET_ADDRESS(&pi.dl_dst, AT_ETHER, 6, &pd[offset + 2]);
+ 	SET_ADDRESS(&pi.dst, AT_ETHER, 6, &pd[offset + 2]);
+ 
  	/* information window */
  	if (check_col(fd, COL_PROTOCOL))
  		col_add_str(fd, COL_PROTOCOL, "TR");
  	if (check_col(fd, COL_INFO))
Index: packet.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet.c,v
retrieving revision 1.50
diff -c -r1.50 packet.c
*** packet.c	1999/10/15 20:32:57	1.50
--- packet.c	1999/10/17 08:03:30
***************
*** 682,687 ****
--- 682,699 ----
      }
  }
  	
+ void blank_packetinfo(void)
+ {
+   pi.dl_src.type = AT_NONE;
+   pi.dl_dst.type = AT_NONE;
+   pi.net_src.type = AT_NONE;
+   pi.net_dst.type = AT_NONE;
+   pi.src.type = AT_NONE;
+   pi.dst.type = AT_NONE;
+   pi.ipproto  = 0;
+   pi.srcport  = 0;
+   pi.destport = 0;
+ }
  
  /* this routine checks the frame type from the cf structure */
  void
***************
*** 721,726 ****
--- 733,740 ----
  		0, 0, fd->cap_len, "Capture Length: %d byte%s", fd->cap_len,
  		plurality(fd->cap_len, "", "s"));
  	}
+ 
+ 	blank_packetinfo();
  
  	/* Set the initial payload to the packet length, and the initial
  	   captured payload to the capture length (other protocols may
Index: packet.h
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet.h,v
retrieving revision 1.113
diff -c -r1.113 packet.h
*** packet.h	1999/10/15 20:32:57	1.113
--- packet.h	1999/10/17 08:03:32
***************
*** 106,111 ****
--- 106,117 ----
    gint           total;
  } packet_counts;
  
+ /* XXX - some of this stuff is used only while a packet is being dissected;
+    should we keep around a separate data structure for that, to save
+    memory?
+ 
+    Also, should the pseudo-header be supplied by Wiretap when you do a
+    seek-and-read, so that we don't have to save it for all frames? */
  typedef struct _frame_data {
    struct _frame_data *next; /* Next element in list */
    guint32      num;       /* Frame number */
***************
*** 125,141 ****
    union pseudo_header pseudo_header; /* "pseudo-header" from wiretap */
  } frame_data;
  
  typedef struct _packet_info {
!   int len;
!   int captured_len;
!   guint32 ip_src;
!   guint32 ip_dst;
    guint32 ipproto;
    guint32 srcport;
    guint32 destport;
    guint32 match_port;
!   int iplen;
!   int iphdrlen;
  } packet_info;
  
  extern packet_info pi;
--- 131,172 ----
    union pseudo_header pseudo_header; /* "pseudo-header" from wiretap */
  } frame_data;
  
+ /* Types of addresses Ethereal knows about. */
+ typedef enum {
+   AT_NONE,		/* no link-layer address */
+   AT_ETHER,		/* MAC (Ethernet, 802.x, FDDI) address */
+   AT_IPv4,		/* IPv4 */
+   AT_IPv6,		/* IPv6 */
+   AT_IPX		/* IPX */
+ } address_type;
+ 
+ typedef struct _address {
+   address_type  type;		/* type of address */
+   int           len;		/* length of address, in bytes */
+   const guint8 *data;		/* bytes that constitute address */
+ } address;
+ 
+ #define	SET_ADDRESS(addr, addr_type, addr_len, addr_data) { \
+ 	(addr)->type = (addr_type); \
+ 	(addr)->len = (addr_len); \
+ 	(addr)->data = (addr_data); \
+ 	}
+ 
  typedef struct _packet_info {
!   int     len;
!   int     captured_len;
!   address dl_src;		/* link-layer source address */
!   address dl_dst;		/* link-layer destination address */
!   address net_src;		/* network-layer source address */
!   address net_dst;		/* network-layer destination address */
!   address src;			/* source address (net if present, DL otherwise )*/
!   address dst;			/* destination address (net if present, DL otherwise )*/
    guint32 ipproto;
    guint32 srcport;
    guint32 destport;
    guint32 match_port;
!   int     iplen;
!   int     iphdrlen;
  } packet_info;
  
  extern packet_info pi;
***************
*** 377,382 ****
--- 408,414 ----
  gchar*     ip_to_str(const guint8 *);
  struct e_in6_addr;
  gchar*     ip6_to_str(struct e_in6_addr *);
+ gchar*     ipx_addr_to_str(guint32, const guint8 *);
  gchar*	   abs_time_to_str(struct timeval*);
  gchar*	   rel_time_to_str(struct timeval*);
  gchar*     time_secs_to_str(guint32);
***************
*** 408,417 ****
  void       col_add_str(frame_data *, gint, const gchar *);
  void       col_append_str(frame_data *, gint, gchar *);
  
- 
  void smb_init_protocol(void);
  
  void dissect_packet(const u_char *, frame_data *, proto_tree *);
  /*
   * Routines in packet-*.c
   * Routines should take three args: packet data *, cap_len, packet_counts *
--- 440,451 ----
  void       col_add_str(frame_data *, gint, const gchar *);
  void       col_append_str(frame_data *, gint, gchar *);
  
  void smb_init_protocol(void);
  
+ void blank_packetinfo(void);
+ 
  void dissect_packet(const u_char *, frame_data *, proto_tree *);
+ 
  /*
   * Routines in packet-*.c
   * Routines should take three args: packet data *, cap_len, packet_counts *
Index: resolv.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/resolv.c,v
retrieving revision 1.15
diff -c -r1.15 resolv.c
*** resolv.c	1999/10/14 06:55:10	1.15
--- resolv.c	1999/10/17 08:03:33
***************
*** 484,490 ****
  
  } /* get_ethbyname */
  
! static ether_t *get_ethbyaddr(u_char *addr)
  {
  
    ether_t *eth;
--- 484,490 ----
  
  } /* get_ethbyname */
  
! static ether_t *get_ethbyaddr(const u_char *addr)
  {
  
    ether_t *eth;
***************
*** 538,544 ****
  
  } /* add_manuf_name */
  
! static hashmanuf_t *manuf_name_lookup(u_char *addr)
  {
  
    hashmanuf_t *tp;
--- 538,544 ----
  
  } /* add_manuf_name */
  
! static hashmanuf_t *manuf_name_lookup(const u_char *addr)
  {
  
    hashmanuf_t *tp;
***************
*** 591,597 ****
  
  } /* add_eth_name */
  
! static u_char *eth_name_lookup(u_char *addr)
  {
    hashmanuf_t *manufp;
    hashether_t *tp;
--- 591,597 ----
  
  } /* add_eth_name */
  
! static u_char *eth_name_lookup(const u_char *addr)
  {
    hashmanuf_t *manufp;
    hashether_t *tp;
***************
*** 795,801 ****
  
  } /* get_tcp_port */
  
! extern u_char *get_ether_name(u_char *addr)
  {
    if (!g_resolving_actif)
      return ether_to_str((guint8 *)addr);
--- 795,801 ----
  
  } /* get_tcp_port */
  
! extern u_char *get_ether_name(const u_char *addr)
  {
    if (!g_resolving_actif)
      return ether_to_str((guint8 *)addr);
Index: resolv.h
===================================================================
RCS file: /usr/local/cvsroot/ethereal/resolv.h,v
retrieving revision 1.8
diff -c -r1.8 resolv.h
*** resolv.h	1999/10/15 03:11:52	1.8
--- resolv.h	1999/10/17 08:03:33
***************
*** 60,66 ****
  /* get_ether_name returns the logical name if found in ethers files else
     "<vendor>_%02x:%02x:%02x" if the vendor code is known else
     "%02x:%02x:%02x:%02x:%02x:%02x" */
! extern u_char *get_ether_name(u_char *addr);
  
  /* get_manuf_name returns the vendor name or "%02x:%02x:%02x" if not known */
  extern u_char *get_manuf_name(u_char *addr);
--- 60,66 ----
  /* get_ether_name returns the logical name if found in ethers files else
     "<vendor>_%02x:%02x:%02x" if the vendor code is known else
     "%02x:%02x:%02x:%02x:%02x:%02x" */
! extern u_char *get_ether_name(const u_char *addr);
  
  /* get_manuf_name returns the vendor name or "%02x:%02x:%02x" if not known */
  extern u_char *get_manuf_name(u_char *addr);
Index: gtk/main.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/gtk/main.c,v
retrieving revision 1.23
diff -c -r1.23 main.c
*** main.c	1999/10/15 20:33:06	1.23
--- main.c	1999/10/17 08:03:36
***************
*** 403,416 ****
    gtk_exit(0);
  }
  
- void blank_packetinfo() {
-   pi.ip_src   = 0;
-   pi.ip_dst   = 0;
-   pi.ipproto  = 0;
-   pi.srcport  = 0;
-   pi.destport = 0;
- }
- 
  /* call initialization routines at program startup time */
  static void
  ethereal_proto_init(void) {
--- 403,408 ----
/* conversation.c
 * Routines for building lists of packets that are part of a "conversation"
 *
 * $Id$
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxx>
 * Copyright 1998 Gerald Combs
 *
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <stdio.h>

#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif

#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif

#include <string.h>
#include <glib.h>
#include "packet.h"

static GHashTable *conversation_hashtable = NULL;
static GMemChunk *conversation_key_chunk = NULL;
static GMemChunk *conversation_val_chunk = NULL;

typedef struct conversation_key {
	struct conversation_key *next;
	address	src;
	address	dst;
	guint16	port_src;
	guint16	port_dst;
} conversation_key;

/*
 * Linked list of conversation keys, so we can, before freeing them all,
 * free the address data allocations associated with them.
 */
static conversation_key *conversation_keys;

typedef struct conversation_val {
	struct conversation_val *next;
	guint32	index;
} conversation_val;

static guint32 new_index;

static int conversation_init_count = 200;

/*
 * Compare two conversation keys.
 */
static gint
conversation_equal(gconstpointer v, gconstpointer w)
{
	conversation_key *v1 = (conversation_key *)v;
	conversation_key *v2 = (conversation_key *)w;

	/*
	 * We assume that a source and a destination address for a given
	 * packet in a conversation have the same type.
	 */
	if (v1->src.type != v2->src.type)
		return 0;	/* different types of addresses */

	if (v1->src.len == v2->src.len &&
	    memcmp(v1->src.data, v2->src.data, v1->src.len) == 0) {
		/*
		 * The first and second source addresses are the same.
		 */
		if (v1->dst.len == v2->dst.len &&
		    memcmp(v1->dst.data, v2->dst.data, v1->dst.len) == 0) {
			/*
			 * The first and second destination addresses
			 * are the same, so they're both going from
			 * the same machine and they're both going to
			 * the same machine.
			 */
			if (v1->port_src == v2->port_src &&
			    v1->port_dst == v2->port_dst) {
			    	/*
				 * The first and second source ports
				 * are the same, and the first and second
				 * destination ports are the same, so
				 * it's the same conversation, and the two
				 * address/port pairs are going in the same
				 * direction.
				 */
				return 1;
			}
		}
	} else if (v1->src.len == v2->dst.len &&
	    memcmp(v1->src.data, v2->dst.data, v1->src.len) == 0) {
		/*
		 * The first source address is the same as the second
		 * destination address.
		 */
		if (v1->dst.len == v2->src.len &&
		    memcmp(v1->dst.data, v2->src.data, v1->dst.len) == 0) {
			/*
			 * The first destination address is the same as
			 * the second source address, so they're going
			 * between the same machines, but in opposite
			 * directions.
			 */
			if (v1->port_src == v2->port_dst &&
			    v1->port_dst == v2->port_src) {
			    	/*
				 * The first source port is the same as
				 * the second destination port, and the
				 * first destination port is the same as
				 * the second source port, so it's
				 * the same conversation, and the two
				 * address/port pairs are going in
				 * opposite directions.
				 */
				return 1;
			}
		}
	}

	/*
	 * The addresses or the ports don't match.
	 */	
	return 0;
}

/*
 * Compute the hash value for a given set of source and destination
 * addresses and ports.
 */
static guint 
conversation_hash(gconstpointer v)
{
	conversation_key *key = (conversation_key *)v;
	guint hash_val;
	int i;

	hash_val = 0;
	for (i = 0; i < key->src.len; i++)
		hash_val += key->src.data[i];
	for (i = 0; i < key->dst.len; i++)
		hash_val += key->dst.data[i];
	hash_val += key->port_src + key->port_dst;

	return hash_val;
}

/*
 * Initialize some variables every time a file is loaded or re-loaded.
 * Destroy all existing conversations, and create a new hash table
 * for the conversations in the new file.
 */
void
conversation_init(void)
{
	conversation_key *key;

	/*
	 * Free the addresses associated with the conversation keys.
	 */
	for (key = conversation_keys; key != NULL; key = key->next) {
		/*
		 * Grr.  I guess the theory here is that freeing
		 * something sure as heck modifies it, so you
		 * want to ban attempts to free it, but, alas,
		 * if we make the "data" field of an "address"
		 * structure not a "const", the compiler whines if
		 * we try to make it point into the data for a packet,
		 * as that's a "const" array (and should be, as dissectors
		 * shouldn't trash it).
		 *
		 * So we cast the complaint into oblivion, and rely on
		 * the fact that these addresses are known to have had
		 * their data mallocated, i.e. they don't point into,
		 * say, the middle of the data for a packet.
		 */
		g_free((gpointer)key->src.data);
		g_free((gpointer)key->dst.data);
	}
	if (conversation_hashtable != NULL)
		g_hash_table_destroy(conversation_hashtable);
	if (conversation_key_chunk != NULL)
		g_mem_chunk_destroy(conversation_key_chunk);
	if (conversation_val_chunk != NULL)
		g_mem_chunk_destroy(conversation_val_chunk);

	conversation_hashtable = g_hash_table_new(conversation_hash,
	    conversation_equal);
	conversation_key_chunk = g_mem_chunk_new("conversation_key_chunk",
	    sizeof(conversation_key),
	    conversation_init_count * sizeof(struct conversation_key),
	    G_ALLOC_AND_FREE);
	conversation_val_chunk = g_mem_chunk_new("conversation_val_chunk",
	    sizeof(conversation_val),
	    conversation_init_count * sizeof(struct conversation_val),
	    G_ALLOC_AND_FREE);

	/*
	 * Start the conversation indices over at 0.
	 */
	new_index = 0;
}

/*
 * Copy an address, allocating a new buffer for the address data.
 */
static void
copy_address(address *to, address *from)
{
	guint8 *data;

	to->type = from->type;
	to->len = from->len;
	data = g_malloc(from->len);
	memcpy(data, from->data, from->len);
	to->data = data;
}

/*
 * Given source and destination addresses and ports for a packet, add
 * it to the conversation containing packets between those address/port
 * pairs, creating a new conversation if none exists between them.
 *
 * Returns an index to use to refer to the conversation.
 */
guint32
add_to_conversation(address *src, address *dst, guint16 src_port,
    guint16 dst_port)
{
	conversation_val *conversation;
	conversation_key key, *new_key;

	/*
	 * We don't make a copy of the address data, we just copy the
	 * pointer to it, as "key" disappears when we return.
	 */
	key.src = *src;
	key.dst = *dst;
	key.port_src = src_port;
	key.port_dst = dst_port;
	conversation =
	    (conversation_val *)g_hash_table_lookup(conversation_hashtable,
	    &key);
	if (conversation == NULL) {
		/*
		 * No such conversation yet.
		 * Allocate a new one.
		 * Here, we *do* have to copy the address data.
		 */
		new_key = g_mem_chunk_alloc(conversation_key_chunk);
		new_key->next = conversation_keys;
		conversation_keys = new_key;
		copy_address(&new_key->src, src);
		copy_address(&new_key->dst, dst);
		new_key->port_src = src_port;
		new_key->port_dst = dst_port;

		conversation = g_mem_chunk_alloc(conversation_val_chunk);
		conversation->index = new_index;
		new_index++;

		g_hash_table_insert(conversation_hashtable, new_key,
		    conversation);
	}
	return conversation->index;
}
/* conversation.h
 * Routines for building lists of packets that are part of a "conversation"
 *
 * $Id$
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxx>
 * Copyright 1998 Gerald Combs
 *
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

extern void conversation_init(void);
extern guint32 add_to_conversation(address *src, address *dst, guint16 src_port,
    guint16 dst_port);